Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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