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

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. segfault
  2. page_ok
  3. os_get_top_address
  4. os_get_top_address

   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

/* [<][>][^][v][top][bottom][index][help] */