1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <stdlib.h>
21: #include <stdio.h>
22: #include <stdarg.h>
23: #include <string.h>
24: #include <unistd.h>
25: #include <errno.h>
26: #include <sys/mman.h>
27:
28: #include "qemu.h"
29:
30:
31:
32:
33: int target_mprotect(unsigned long start, unsigned long len, int prot)
34: {
35: unsigned long end, host_start, host_end, addr;
36: int prot1, ret;
37:
38: #ifdef DEBUG_MMAP
39: printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len,
40: prot & PROT_READ ? 'r' : '-',
41: prot & PROT_WRITE ? 'w' : '-',
42: prot & PROT_EXEC ? 'x' : '-');
43: #endif
44:
45: if ((start & ~TARGET_PAGE_MASK) != 0)
46: return -EINVAL;
47: len = TARGET_PAGE_ALIGN(len);
48: end = start + len;
49: if (end < start)
50: return -EINVAL;
51: if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
52: return -EINVAL;
53: if (len == 0)
54: return 0;
55:
56: host_start = start & qemu_host_page_mask;
57: host_end = HOST_PAGE_ALIGN(end);
58: if (start > host_start) {
59:
60: prot1 = prot;
61: for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
62: prot1 |= page_get_flags(addr);
63: }
64: if (host_end == host_start + qemu_host_page_size) {
65: for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
66: prot1 |= page_get_flags(addr);
67: }
68: end = host_end;
69: }
70: ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS);
71: if (ret != 0)
72: return ret;
73: host_start += qemu_host_page_size;
74: }
75: if (end < host_end) {
76: prot1 = prot;
77: for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
78: prot1 |= page_get_flags(addr);
79: }
80: ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size,
81: prot1 & PAGE_BITS);
82: if (ret != 0)
83: return ret;
84: host_end -= qemu_host_page_size;
85: }
86:
87:
88: if (host_start < host_end) {
89: ret = mprotect((void *)host_start, host_end - host_start, prot);
90: if (ret != 0)
91: return ret;
92: }
93: page_set_flags(start, start + len, prot | PAGE_VALID);
94: return 0;
95: }
96:
97:
98: int mmap_frag(unsigned long host_start,
99: unsigned long start, unsigned long end,
100: int prot, int flags, int fd, unsigned long offset)
101: {
102: unsigned long host_end, ret, addr;
103: int prot1, prot_new;
104:
105: host_end = host_start + qemu_host_page_size;
106:
107:
108: prot1 = 0;
109: for(addr = host_start; addr < host_end; addr++) {
110: if (addr < start || addr >= end)
111: prot1 |= page_get_flags(addr);
112: }
113:
114: if (prot1 == 0) {
115:
116: ret = (long)mmap((void *)host_start, qemu_host_page_size, prot,
117: flags | MAP_ANONYMOUS, -1, 0);
118: if (ret == -1)
119: return ret;
120: }
121: prot1 &= PAGE_BITS;
122:
123: prot_new = prot | prot1;
124: if (!(flags & MAP_ANONYMOUS)) {
125:
126:
127: #ifndef __APPLE__
128: if ((flags & MAP_TYPE) == MAP_SHARED &&
129: #else
130: if ((flags & MAP_SHARED) &&
131: #endif
132: (prot & PROT_WRITE))
133: return -EINVAL;
134:
135:
136: if (!(prot1 & PROT_WRITE))
137: mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE);
138:
139:
140: pread(fd, (void *)start, end - start, offset);
141:
142:
143: if (prot_new != (prot1 | PROT_WRITE))
144: mprotect((void *)host_start, qemu_host_page_size, prot_new);
145: } else {
146:
147: if (prot_new != prot1) {
148: mprotect((void *)host_start, qemu_host_page_size, prot_new);
149: }
150: }
151: return 0;
152: }
153:
154:
155: long target_mmap(unsigned long start, unsigned long len, int prot,
156: int flags, int fd, unsigned long offset)
157: {
158: unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
159: #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
160: static unsigned long last_start = 0x40000000;
161: #endif
162:
163: #ifdef DEBUG_MMAP
164: {
165: printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=",
166: start, len,
167: prot & PROT_READ ? 'r' : '-',
168: prot & PROT_WRITE ? 'w' : '-',
169: prot & PROT_EXEC ? 'x' : '-');
170: if (flags & MAP_FIXED)
171: printf("MAP_FIXED ");
172: if (flags & MAP_ANONYMOUS)
173: printf("MAP_ANON ");
174: #ifndef MAP_TYPE
175: # define MAP_TYPE 0x3
176: #endif
177: switch(flags & MAP_TYPE) {
178: case MAP_PRIVATE:
179: printf("MAP_PRIVATE ");
180: break;
181: case MAP_SHARED:
182: printf("MAP_SHARED ");
183: break;
184: default:
185: printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
186: break;
187: }
188: printf("fd=%d offset=%lx\n", fd, offset);
189: }
190: #endif
191:
192: if (offset & ~TARGET_PAGE_MASK)
193: return -EINVAL;
194:
195: len = TARGET_PAGE_ALIGN(len);
196: if (len == 0)
197: return start;
198: host_start = start & qemu_host_page_mask;
199:
200: if (!(flags & MAP_FIXED)) {
201: #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
202:
203: if (host_start == 0) {
204: host_start = last_start;
205: last_start += HOST_PAGE_ALIGN(len);
206: }
207: #endif
208: if (qemu_host_page_size != qemu_real_host_page_size) {
209:
210:
211: host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE;
212: host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
213: MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
214: if (host_start == -1)
215: return host_start;
216: host_end = host_start + host_len;
217: start = HOST_PAGE_ALIGN(host_start);
218: end = start + HOST_PAGE_ALIGN(len);
219: if (start > host_start)
220: munmap((void *)host_start, start - host_start);
221: if (end < host_end)
222: munmap((void *)end, host_end - end);
223:
224: flags |= MAP_FIXED;
225: } else {
226:
227: host_offset = offset & qemu_host_page_mask;
228: host_len = len + offset - host_offset;
229: start = (long)mmap((void *)host_start, host_len,
230: prot, flags, fd, host_offset);
231: if (start == -1)
232: return start;
233:
234: if (!(flags & MAP_ANONYMOUS))
235: start += offset - host_offset;
236: goto the_end1;
237: }
238: }
239:
240: if (start & ~TARGET_PAGE_MASK)
241: return -EINVAL;
242: end = start + len;
243: host_end = HOST_PAGE_ALIGN(end);
244:
245:
246:
247: if (!(flags & MAP_ANONYMOUS) &&
248: (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
249:
250:
251: #ifndef __APPLE__
252: if ((flags & MAP_TYPE) == MAP_SHARED &&
253: #else
254: if ((flags & MAP_SHARED) &&
255: #endif
256: (prot & PROT_WRITE))
257: return -EINVAL;
258: retaddr = target_mmap(start, len, prot | PROT_WRITE,
259: MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
260: -1, 0);
261: if (retaddr == -1)
262: return retaddr;
263: pread(fd, (void *)start, len, offset);
264: if (!(prot & PROT_WRITE)) {
265: ret = target_mprotect(start, len, prot);
266: if (ret != 0)
267: return ret;
268: }
269: goto the_end;
270: }
271:
272:
273: if (start > host_start) {
274: if (host_end == host_start + qemu_host_page_size) {
275:
276: ret = mmap_frag(host_start, start, end,
277: prot, flags, fd, offset);
278: if (ret == -1)
279: return ret;
280: goto the_end1;
281: }
282: ret = mmap_frag(host_start, start, host_start + qemu_host_page_size,
283: prot, flags, fd, offset);
284: if (ret == -1)
285: return ret;
286: host_start += qemu_host_page_size;
287: }
288:
289: if (end < host_end) {
290: ret = mmap_frag(host_end - qemu_host_page_size,
291: host_end - qemu_host_page_size, host_end,
292: prot, flags, fd,
293: offset + host_end - qemu_host_page_size - start);
294: if (ret == -1)
295: return ret;
296: host_end -= qemu_host_page_size;
297: }
298:
299:
300: if (host_start < host_end) {
301: unsigned long offset1;
302: if (flags & MAP_ANONYMOUS)
303: offset1 = 0;
304: else
305: offset1 = offset + host_start - start;
306: ret = (long)mmap((void *)host_start, host_end - host_start,
307: prot, flags, fd, offset1);
308: if (ret == -1)
309: return ret;
310: }
311: the_end1:
312: page_set_flags(start, start + len, prot | PAGE_VALID);
313: the_end:
314: #ifdef DEBUG_MMAP
315: printf("target_mmap: ret=0x%lx\n", (long)start);
316: page_dump(stdout);
317: printf("\n");
318: #endif
319: return start;
320: }
321:
322: int target_munmap(unsigned long start, unsigned long len)
323: {
324: unsigned long end, host_start, host_end, addr;
325: int prot, ret;
326:
327: #ifdef DEBUG_MMAP
328: printf("munmap: start=0x%lx len=0x%lx\n", start, len);
329: #endif
330: if (start & ~TARGET_PAGE_MASK)
331: return -EINVAL;
332: len = TARGET_PAGE_ALIGN(len);
333: if (len == 0)
334: return -EINVAL;
335: end = start + len;
336: host_start = start & qemu_host_page_mask;
337: host_end = HOST_PAGE_ALIGN(end);
338:
339: if (start > host_start) {
340:
341: prot = 0;
342: for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
343: prot |= page_get_flags(addr);
344: }
345: if (host_end == host_start + qemu_host_page_size) {
346: for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
347: prot |= page_get_flags(addr);
348: }
349: end = host_end;
350: }
351: if (prot != 0)
352: host_start += qemu_host_page_size;
353: }
354: if (end < host_end) {
355: prot = 0;
356: for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
357: prot |= page_get_flags(addr);
358: }
359: if (prot != 0)
360: host_end -= qemu_host_page_size;
361: }
362:
363:
364: if (host_start < host_end) {
365: ret = munmap((void *)host_start, host_end - host_start);
366: if (ret != 0)
367: return ret;
368: }
369:
370: page_set_flags(start, start + len, 0);
371: return 0;
372: }
373:
374:
375:
376: long target_mremap(unsigned long old_addr, unsigned long old_size,
377: unsigned long new_size, unsigned long flags,
378: unsigned long new_addr)
379: {
380: #ifndef __APPLE__
381:
382: new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags);
383: if (new_addr == -1)
384: return new_addr;
385: prot = page_get_flags(old_addr);
386: page_set_flags(old_addr, old_addr + old_size, 0);
387: page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
388: return new_addr;
389: #else
390: qerror("target_mremap: unsupported\n");
391: #endif
392:
393: }
394:
395: int target_msync(unsigned long start, unsigned long len, int flags)
396: {
397: unsigned long end;
398:
399: if (start & ~TARGET_PAGE_MASK)
400: return -EINVAL;
401: len = TARGET_PAGE_ALIGN(len);
402: end = start + len;
403: if (end < start)
404: return -EINVAL;
405: if (end == start)
406: return 0;
407:
408: start &= qemu_host_page_mask;
409: return msync((void *)start, end - start, flags);
410: }
411: