1 // SPDX-License-Identifier: GPL-2.0
12 static void segfault(int sig
)
17 static int page_ok(unsigned long page
)
19 unsigned long *address
= (unsigned long *) (page
<< UM_KERN_PAGE_SHIFT
);
20 unsigned long n
= ~0UL;
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
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
)
40 if (mapped
!= address
)
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
49 if (setjmp(buf
) == 0) {
53 } else if (mprotect(address
, UM_KERN_PAGE_SIZE
,
54 PROT_READ
| PROT_WRITE
) != 0)
57 if (setjmp(buf
) == 0) {
64 munmap(mapped
, UM_KERN_PAGE_SIZE
);
68 unsigned long os_get_top_address(void)
70 struct sigaction sa
, old
;
71 unsigned long bottom
= 0;
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.
80 unsigned long top
= 0xffffd000 >> UM_KERN_PAGE_SHIFT
;
81 unsigned long test
, original
;
83 printf("Locating the bottom of the address space ... ");
87 * We're going to be longjmping out of the signal handler, so
88 * SA_DEFER needs to be set.
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");
98 /* Manually scan the address space, bottom-up, until we find
99 * the first valid page (or run out of them).
101 for (bottom
= 0; bottom
< top
; bottom
++) {
106 /* If we've got this far, we ran out of pages. */
108 fprintf(stderr
, "Unable to determine bottom of address "
113 printf("0x%lx\n", bottom
<< UM_KERN_PAGE_SHIFT
);
114 printf("Locating the top of the address space ... ");
119 /* This could happen with a 4G/4G split */
124 test
= bottom
+ (top
- bottom
) / 2;
129 } while (top
- bottom
> 1);
132 /* Restore the old SIGSEGV handling */
133 if (sigaction(SIGSEGV
, &old
, NULL
)) {
134 perror("os_get_top_address");
137 top
<<= UM_KERN_PAGE_SHIFT
;
138 printf("0x%lx\n", top
);
145 unsigned long os_get_top_address(void)
147 /* The old value of CONFIG_TOP_ADDR */