task_size.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>
  4. #include <sys/mman.h>
  5. #include "longjmp.h"
  6. static jmp_buf buf;
  7. static void segfault(int sig)
  8. {
  9. longjmp(buf, 1);
  10. }
  11. static int page_ok(unsigned long page)
  12. {
  13. unsigned long *address = (unsigned long *) (page << UM_KERN_PAGE_SHIFT);
  14. unsigned long n = ~0UL;
  15. void *mapped = NULL;
  16. int ok = 0;
  17. /*
  18. * First see if the page is readable. If it is, it may still
  19. * be a VDSO, so we go on to see if it's writable. If not
  20. * then try mapping memory there. If that fails, then we're
  21. * still in the kernel area. As a sanity check, we'll fail if
  22. * the mmap succeeds, but gives us an address different from
  23. * what we wanted.
  24. */
  25. if (setjmp(buf) == 0)
  26. n = *address;
  27. else {
  28. mapped = mmap(address, UM_KERN_PAGE_SIZE,
  29. PROT_READ | PROT_WRITE,
  30. MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  31. if (mapped == MAP_FAILED)
  32. return 0;
  33. if (mapped != address)
  34. goto out;
  35. }
  36. /*
  37. * Now, is it writeable? If so, then we're in user address
  38. * space. If not, then try mprotecting it and try the write
  39. * again.
  40. */
  41. if (setjmp(buf) == 0) {
  42. *address = n;
  43. ok = 1;
  44. goto out;
  45. } else if (mprotect(address, UM_KERN_PAGE_SIZE,
  46. PROT_READ | PROT_WRITE) != 0)
  47. goto out;
  48. if (setjmp(buf) == 0) {
  49. *address = n;
  50. ok = 1;
  51. }
  52. out:
  53. if (mapped != NULL)
  54. munmap(mapped, UM_KERN_PAGE_SIZE);
  55. return ok;
  56. }
  57. unsigned long os_get_top_address(void)
  58. {
  59. struct sigaction sa, old;
  60. unsigned long bottom = 0;
  61. /*
  62. * A 32-bit UML on a 64-bit host gets confused about the VDSO at
  63. * 0xffffe000. It is mapped, is readable, can be reprotected writeable
  64. * and written. However, exec discovers later that it can't be
  65. * unmapped. So, just set the highest address to be checked to just
  66. * below it. This might waste some address space on 4G/4G 32-bit
  67. * hosts, but shouldn't hurt otherwise.
  68. */
  69. unsigned long top = 0xffffd000 >> UM_KERN_PAGE_SHIFT;
  70. unsigned long test, original;
  71. printf("Locating the bottom of the address space ... ");
  72. fflush(stdout);
  73. /*
  74. * We're going to be longjmping out of the signal handler, so
  75. * SA_DEFER needs to be set.
  76. */
  77. sa.sa_handler = segfault;
  78. sigemptyset(&sa.sa_mask);
  79. sa.sa_flags = SA_NODEFER;
  80. if (sigaction(SIGSEGV, &sa, &old)) {
  81. perror("os_get_top_address");
  82. exit(1);
  83. }
  84. /* Manually scan the address space, bottom-up, until we find
  85. * the first valid page (or run out of them).
  86. */
  87. for (bottom = 0; bottom < top; bottom++) {
  88. if (page_ok(bottom))
  89. break;
  90. }
  91. /* If we've got this far, we ran out of pages. */
  92. if (bottom == top) {
  93. fprintf(stderr, "Unable to determine bottom of address "
  94. "space.\n");
  95. exit(1);
  96. }
  97. printf("0x%x\n", bottom << UM_KERN_PAGE_SHIFT);
  98. printf("Locating the top of the address space ... ");
  99. fflush(stdout);
  100. original = bottom;
  101. /* This could happen with a 4G/4G split */
  102. if (page_ok(top))
  103. goto out;
  104. do {
  105. test = bottom + (top - bottom) / 2;
  106. if (page_ok(test))
  107. bottom = test;
  108. else
  109. top = test;
  110. } while (top - bottom > 1);
  111. out:
  112. /* Restore the old SIGSEGV handling */
  113. if (sigaction(SIGSEGV, &old, NULL)) {
  114. perror("os_get_top_address");
  115. exit(1);
  116. }
  117. top <<= UM_KERN_PAGE_SHIFT;
  118. printf("0x%x\n", top);
  119. return top;
  120. }