Version:  2.0.40 2.2.26 2.4.37 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16

Linux/arch/x86/um/os-Linux/task_size.c

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us