LCOV - code coverage report
Current view: top level - arch/x86/um/os-Linux - task_size.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2 2 100.0 %
Date: 2023-08-24 13:40:31 Functions: 1 1 100.0 %

          Line data    Source code
       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           5 : unsigned long os_get_top_address(void)
     146             : {
     147             :         /* The old value of CONFIG_TOP_ADDR */
     148           5 :         return 0x7fc0002000;
     149             : }
     150             : 
     151             : #endif

Generated by: LCOV version 1.14