Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/um/os-Linux/sys-i386/task_size.c
10821 views
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
8
static jmp_buf buf;
9
10
static void segfault(int sig)
11
{
12
longjmp(buf, 1);
13
}
14
15
static 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
66
unsigned 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
129
out:
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
}
140
141