task_size.c 2.8 KB

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