task_size.c 3.3 KB

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