~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/um/os-Linux/task_size.c

Version: ~ [ linux-5.1-rc5 ] ~ [ linux-5.0.7 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.34 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.111 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.168 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.178 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.138 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.65 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp