Commit 54936004fddc52c321cb3f9a9a51140e782bed5d
1 parent
74c95119
mmap emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@158 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
9 changed files
with
646 additions
and
101 deletions
Makefile
| @@ -58,11 +58,11 @@ LDFLAGS+=-p | @@ -58,11 +58,11 @@ LDFLAGS+=-p | ||
| 58 | main.o: CFLAGS+=-p | 58 | main.o: CFLAGS+=-p |
| 59 | endif | 59 | endif |
| 60 | 60 | ||
| 61 | -OBJS= elfload.o main.o syscall.o signal.o vm86.o path.o | 61 | +OBJS= elfload.o main.o syscall.o mmap.o signal.o vm86.o path.o |
| 62 | SRCS:= $(OBJS:.o=.c) | 62 | SRCS:= $(OBJS:.o=.c) |
| 63 | OBJS+= libqemu.a | 63 | OBJS+= libqemu.a |
| 64 | 64 | ||
| 65 | -LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o | 65 | +LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o exec.o |
| 66 | # NOTE: the disassembler code is only needed for debugging | 66 | # NOTE: the disassembler code is only needed for debugging |
| 67 | LIBOBJS+=disas.o ppc-dis.o i386-dis.o alpha-dis.o dis-buf.o | 67 | LIBOBJS+=disas.o ppc-dis.o i386-dis.o alpha-dis.o dis-buf.o |
| 68 | 68 |
cpu-i386.h
| @@ -431,6 +431,30 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, | @@ -431,6 +431,30 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, | ||
| 431 | #define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ | 431 | #define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ |
| 432 | void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags); | 432 | void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags); |
| 433 | 433 | ||
| 434 | +/* page related stuff */ | ||
| 435 | +#define TARGET_PAGE_BITS 12 | ||
| 436 | +#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS) | ||
| 437 | +#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1) | ||
| 438 | +#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK) | ||
| 439 | + | ||
| 440 | +extern unsigned long real_host_page_size; | ||
| 441 | +extern unsigned long host_page_bits; | ||
| 442 | +extern unsigned long host_page_size; | ||
| 443 | +extern unsigned long host_page_mask; | ||
| 444 | + | ||
| 445 | +#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask) | ||
| 446 | + | ||
| 447 | +/* same as PROT_xxx */ | ||
| 448 | +#define PAGE_READ 0x0001 | ||
| 449 | +#define PAGE_WRITE 0x0002 | ||
| 450 | +#define PAGE_EXEC 0x0004 | ||
| 451 | +#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC) | ||
| 452 | +#define PAGE_VALID 0x0008 | ||
| 453 | + | ||
| 454 | +void page_dump(FILE *f); | ||
| 455 | +int page_get_flags(unsigned long address); | ||
| 456 | +void page_set_flags(unsigned long start, unsigned long end, int flags); | ||
| 457 | + | ||
| 434 | /* internal functions */ | 458 | /* internal functions */ |
| 435 | 459 | ||
| 436 | #define GEN_FLAG_CODE32_SHIFT 0 | 460 | #define GEN_FLAG_CODE32_SHIFT 0 |
| @@ -446,5 +470,6 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | @@ -446,5 +470,6 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
| 446 | int *gen_code_size_ptr, | 470 | int *gen_code_size_ptr, |
| 447 | uint8_t *pc_start, uint8_t *cs_base, int flags); | 471 | uint8_t *pc_start, uint8_t *cs_base, int flags); |
| 448 | void cpu_x86_tblocks_init(void); | 472 | void cpu_x86_tblocks_init(void); |
| 473 | +void page_init(void); | ||
| 449 | 474 | ||
| 450 | #endif /* CPU_I386_H */ | 475 | #endif /* CPU_I386_H */ |
exec.c
0 → 100644
| 1 | +/* | ||
| 2 | + * virtual page mapping | ||
| 3 | + * | ||
| 4 | + * Copyright (c) 2003 Fabrice Bellard | ||
| 5 | + * | ||
| 6 | + * This library is free software; you can redistribute it and/or | ||
| 7 | + * modify it under the terms of the GNU Lesser General Public | ||
| 8 | + * License as published by the Free Software Foundation; either | ||
| 9 | + * version 2 of the License, or (at your option) any later version. | ||
| 10 | + * | ||
| 11 | + * This library is distributed in the hope that it will be useful, | ||
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | + * Lesser General Public License for more details. | ||
| 15 | + * | ||
| 16 | + * You should have received a copy of the GNU Lesser General Public | ||
| 17 | + * License along with this library; if not, write to the Free Software | ||
| 18 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | + */ | ||
| 20 | +#include <stdlib.h> | ||
| 21 | +#include <stdio.h> | ||
| 22 | +#include <stdarg.h> | ||
| 23 | +#include <string.h> | ||
| 24 | +#include <errno.h> | ||
| 25 | +#include <unistd.h> | ||
| 26 | +#include <inttypes.h> | ||
| 27 | + | ||
| 28 | +#include "cpu-i386.h" | ||
| 29 | + | ||
| 30 | +/* XXX: pack the flags in the low bits of the pointer ? */ | ||
| 31 | +typedef struct PageDesc { | ||
| 32 | + struct TranslationBlock *first_tb; | ||
| 33 | + unsigned long flags; | ||
| 34 | +} PageDesc; | ||
| 35 | + | ||
| 36 | +#define L2_BITS 10 | ||
| 37 | +#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) | ||
| 38 | + | ||
| 39 | +#define L1_SIZE (1 << L1_BITS) | ||
| 40 | +#define L2_SIZE (1 << L2_BITS) | ||
| 41 | + | ||
| 42 | +unsigned long real_host_page_size; | ||
| 43 | +unsigned long host_page_bits; | ||
| 44 | +unsigned long host_page_size; | ||
| 45 | +unsigned long host_page_mask; | ||
| 46 | + | ||
| 47 | +static PageDesc *l1_map[L1_SIZE]; | ||
| 48 | + | ||
| 49 | +void page_init(void) | ||
| 50 | +{ | ||
| 51 | + /* NOTE: we can always suppose that host_page_size >= | ||
| 52 | + TARGET_PAGE_SIZE */ | ||
| 53 | + real_host_page_size = getpagesize(); | ||
| 54 | + if (host_page_size == 0) | ||
| 55 | + host_page_size = real_host_page_size; | ||
| 56 | + if (host_page_size < TARGET_PAGE_SIZE) | ||
| 57 | + host_page_size = TARGET_PAGE_SIZE; | ||
| 58 | + host_page_bits = 0; | ||
| 59 | + while ((1 << host_page_bits) < host_page_size) | ||
| 60 | + host_page_bits++; | ||
| 61 | + host_page_mask = ~(host_page_size - 1); | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +/* dump memory mappings */ | ||
| 65 | +void page_dump(FILE *f) | ||
| 66 | +{ | ||
| 67 | + unsigned long start, end; | ||
| 68 | + int i, j, prot, prot1; | ||
| 69 | + PageDesc *p; | ||
| 70 | + | ||
| 71 | + fprintf(f, "%-8s %-8s %-8s %s\n", | ||
| 72 | + "start", "end", "size", "prot"); | ||
| 73 | + start = -1; | ||
| 74 | + end = -1; | ||
| 75 | + prot = 0; | ||
| 76 | + for(i = 0; i <= L1_SIZE; i++) { | ||
| 77 | + if (i < L1_SIZE) | ||
| 78 | + p = l1_map[i]; | ||
| 79 | + else | ||
| 80 | + p = NULL; | ||
| 81 | + for(j = 0;j < L2_SIZE; j++) { | ||
| 82 | + if (!p) | ||
| 83 | + prot1 = 0; | ||
| 84 | + else | ||
| 85 | + prot1 = p[j].flags; | ||
| 86 | + if (prot1 != prot) { | ||
| 87 | + end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); | ||
| 88 | + if (start != -1) { | ||
| 89 | + fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", | ||
| 90 | + start, end, end - start, | ||
| 91 | + prot & PAGE_READ ? 'r' : '-', | ||
| 92 | + prot & PAGE_WRITE ? 'w' : '-', | ||
| 93 | + prot & PAGE_EXEC ? 'x' : '-'); | ||
| 94 | + } | ||
| 95 | + if (prot1 != 0) | ||
| 96 | + start = end; | ||
| 97 | + else | ||
| 98 | + start = -1; | ||
| 99 | + prot = prot1; | ||
| 100 | + } | ||
| 101 | + if (!p) | ||
| 102 | + break; | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | + | ||
| 108 | +static inline PageDesc *page_find_alloc(unsigned long address) | ||
| 109 | +{ | ||
| 110 | + unsigned int index; | ||
| 111 | + PageDesc **lp, *p; | ||
| 112 | + | ||
| 113 | + index = address >> TARGET_PAGE_BITS; | ||
| 114 | + lp = &l1_map[index >> L2_BITS]; | ||
| 115 | + p = *lp; | ||
| 116 | + if (!p) { | ||
| 117 | + /* allocate if not found */ | ||
| 118 | + p = malloc(sizeof(PageDesc) * L2_SIZE); | ||
| 119 | + memset(p, 0, sizeof(sizeof(PageDesc) * L2_SIZE)); | ||
| 120 | + *lp = p; | ||
| 121 | + } | ||
| 122 | + return p + (index & (L2_SIZE - 1)); | ||
| 123 | +} | ||
| 124 | + | ||
| 125 | +int page_get_flags(unsigned long address) | ||
| 126 | +{ | ||
| 127 | + unsigned int index; | ||
| 128 | + PageDesc *p; | ||
| 129 | + | ||
| 130 | + index = address >> TARGET_PAGE_BITS; | ||
| 131 | + p = l1_map[index >> L2_BITS]; | ||
| 132 | + if (!p) | ||
| 133 | + return 0; | ||
| 134 | + return p[index & (L2_SIZE - 1)].flags; | ||
| 135 | +} | ||
| 136 | + | ||
| 137 | +void page_set_flags(unsigned long start, unsigned long end, int flags) | ||
| 138 | +{ | ||
| 139 | + PageDesc *p; | ||
| 140 | + unsigned long addr; | ||
| 141 | + | ||
| 142 | + start = start & TARGET_PAGE_MASK; | ||
| 143 | + end = TARGET_PAGE_ALIGN(end); | ||
| 144 | + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { | ||
| 145 | + p = page_find_alloc(addr); | ||
| 146 | + p->flags = flags; | ||
| 147 | + } | ||
| 148 | +} |
linux-user/elfload.c
| @@ -95,8 +95,6 @@ struct exec | @@ -95,8 +95,6 @@ struct exec | ||
| 95 | #define ZMAGIC 0413 | 95 | #define ZMAGIC 0413 |
| 96 | #define QMAGIC 0314 | 96 | #define QMAGIC 0314 |
| 97 | 97 | ||
| 98 | -#define X86_STACK_TOP 0x7d000000 | ||
| 99 | - | ||
| 100 | /* max code+data+bss space allocated to elf interpreter */ | 98 | /* max code+data+bss space allocated to elf interpreter */ |
| 101 | #define INTERP_MAP_SIZE (32 * 1024 * 1024) | 99 | #define INTERP_MAP_SIZE (32 * 1024 * 1024) |
| 102 | 100 | ||
| @@ -123,23 +121,11 @@ struct exec | @@ -123,23 +121,11 @@ struct exec | ||
| 123 | #define PER_XENIX (0x0007 | STICKY_TIMEOUTS) | 121 | #define PER_XENIX (0x0007 | STICKY_TIMEOUTS) |
| 124 | 122 | ||
| 125 | /* Necessary parameters */ | 123 | /* Necessary parameters */ |
| 126 | -#define ALPHA_PAGE_SIZE 4096 | ||
| 127 | -#define X86_PAGE_SIZE 4096 | ||
| 128 | - | ||
| 129 | -#define ALPHA_PAGE_MASK (~(ALPHA_PAGE_SIZE-1)) | ||
| 130 | -#define X86_PAGE_MASK (~(X86_PAGE_SIZE-1)) | ||
| 131 | - | ||
| 132 | -#define ALPHA_PAGE_ALIGN(addr) ((((addr)+ALPHA_PAGE_SIZE)-1)&ALPHA_PAGE_MASK) | ||
| 133 | -#define X86_PAGE_ALIGN(addr) ((((addr)+X86_PAGE_SIZE)-1)&X86_PAGE_MASK) | ||
| 134 | - | ||
| 135 | #define NGROUPS 32 | 124 | #define NGROUPS 32 |
| 136 | 125 | ||
| 137 | -#define X86_ELF_EXEC_PAGESIZE X86_PAGE_SIZE | ||
| 138 | -#define X86_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(X86_ELF_EXEC_PAGESIZE-1)) | ||
| 139 | -#define X86_ELF_PAGEOFFSET(_v) ((_v) & (X86_ELF_EXEC_PAGESIZE-1)) | ||
| 140 | - | ||
| 141 | -#define ALPHA_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ALPHA_PAGE_SIZE-1)) | ||
| 142 | -#define ALPHA_ELF_PAGEOFFSET(_v) ((_v) & (ALPHA_PAGE_SIZE-1)) | 126 | +#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE |
| 127 | +#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) | ||
| 128 | +#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) | ||
| 143 | 129 | ||
| 144 | #define INTERPRETER_NONE 0 | 130 | #define INTERPRETER_NONE 0 |
| 145 | #define INTERPRETER_AOUT 1 | 131 | #define INTERPRETER_AOUT 1 |
| @@ -160,9 +146,6 @@ static inline void memcpy_tofs(void * to, const void * from, unsigned long n) | @@ -160,9 +146,6 @@ static inline void memcpy_tofs(void * to, const void * from, unsigned long n) | ||
| 160 | memcpy(to, from, n); | 146 | memcpy(to, from, n); |
| 161 | } | 147 | } |
| 162 | 148 | ||
| 163 | -//extern void * mmap4k(); | ||
| 164 | -#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f) | ||
| 165 | - | ||
| 166 | extern unsigned long x86_stack_size; | 149 | extern unsigned long x86_stack_size; |
| 167 | 150 | ||
| 168 | static int load_aout_interp(void * exptr, int interp_fd); | 151 | static int load_aout_interp(void * exptr, int interp_fd); |
| @@ -227,8 +210,8 @@ static void * get_free_page(void) | @@ -227,8 +210,8 @@ static void * get_free_page(void) | ||
| 227 | /* User-space version of kernel get_free_page. Returns a page-aligned | 210 | /* User-space version of kernel get_free_page. Returns a page-aligned |
| 228 | * page-sized chunk of memory. | 211 | * page-sized chunk of memory. |
| 229 | */ | 212 | */ |
| 230 | - retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE, | ||
| 231 | - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | 213 | + retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE, |
| 214 | + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | ||
| 232 | 215 | ||
| 233 | if((long)retval == -1) { | 216 | if((long)retval == -1) { |
| 234 | perror("get_free_page"); | 217 | perror("get_free_page"); |
| @@ -241,7 +224,7 @@ static void * get_free_page(void) | @@ -241,7 +224,7 @@ static void * get_free_page(void) | ||
| 241 | 224 | ||
| 242 | static void free_page(void * pageaddr) | 225 | static void free_page(void * pageaddr) |
| 243 | { | 226 | { |
| 244 | - (void)munmap(pageaddr, ALPHA_PAGE_SIZE); | 227 | + target_munmap((unsigned long)pageaddr, host_page_size); |
| 245 | } | 228 | } |
| 246 | 229 | ||
| 247 | /* | 230 | /* |
| @@ -272,9 +255,9 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, | @@ -272,9 +255,9 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, | ||
| 272 | while (len) { | 255 | while (len) { |
| 273 | --p; --tmp; --len; | 256 | --p; --tmp; --len; |
| 274 | if (--offset < 0) { | 257 | if (--offset < 0) { |
| 275 | - offset = p % X86_PAGE_SIZE; | ||
| 276 | - if (!(pag = (char *) page[p/X86_PAGE_SIZE]) && | ||
| 277 | - !(pag = (char *) page[p/X86_PAGE_SIZE] = | 258 | + offset = p % TARGET_PAGE_SIZE; |
| 259 | + if (!(pag = (char *) page[p/TARGET_PAGE_SIZE]) && | ||
| 260 | + !(pag = (char *) page[p/TARGET_PAGE_SIZE] = | ||
| 278 | (unsigned long *) get_free_page())) { | 261 | (unsigned long *) get_free_page())) { |
| 279 | return 0; | 262 | return 0; |
| 280 | } | 263 | } |
| @@ -390,21 +373,21 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, | @@ -390,21 +373,21 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, | ||
| 390 | * it for args, we'll use it for something else... | 373 | * it for args, we'll use it for something else... |
| 391 | */ | 374 | */ |
| 392 | size = x86_stack_size; | 375 | size = x86_stack_size; |
| 393 | - if (size < MAX_ARG_PAGES*X86_PAGE_SIZE) | ||
| 394 | - size = MAX_ARG_PAGES*X86_PAGE_SIZE; | ||
| 395 | - error = (unsigned long)mmap4k(NULL, | ||
| 396 | - size + X86_PAGE_SIZE, | ||
| 397 | - PROT_READ | PROT_WRITE, | ||
| 398 | - MAP_PRIVATE | MAP_ANONYMOUS, | ||
| 399 | - -1, 0); | 376 | + if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) |
| 377 | + size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; | ||
| 378 | + error = target_mmap(0, | ||
| 379 | + size + host_page_size, | ||
| 380 | + PROT_READ | PROT_WRITE, | ||
| 381 | + MAP_PRIVATE | MAP_ANONYMOUS, | ||
| 382 | + -1, 0); | ||
| 400 | if (error == -1) { | 383 | if (error == -1) { |
| 401 | perror("stk mmap"); | 384 | perror("stk mmap"); |
| 402 | exit(-1); | 385 | exit(-1); |
| 403 | } | 386 | } |
| 404 | /* we reserve one extra page at the top of the stack as guard */ | 387 | /* we reserve one extra page at the top of the stack as guard */ |
| 405 | - mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE); | 388 | + target_mprotect(error + size, host_page_size, PROT_NONE); |
| 406 | 389 | ||
| 407 | - stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE; | 390 | + stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; |
| 408 | p += stack_base; | 391 | p += stack_base; |
| 409 | 392 | ||
| 410 | if (bprm->loader) { | 393 | if (bprm->loader) { |
| @@ -416,10 +399,10 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, | @@ -416,10 +399,10 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, | ||
| 416 | if (bprm->page[i]) { | 399 | if (bprm->page[i]) { |
| 417 | info->rss++; | 400 | info->rss++; |
| 418 | 401 | ||
| 419 | - memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE); | 402 | + memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_PAGE_SIZE); |
| 420 | free_page((void *)bprm->page[i]); | 403 | free_page((void *)bprm->page[i]); |
| 421 | } | 404 | } |
| 422 | - stack_base += X86_PAGE_SIZE; | 405 | + stack_base += TARGET_PAGE_SIZE; |
| 423 | } | 406 | } |
| 424 | return p; | 407 | return p; |
| 425 | } | 408 | } |
| @@ -427,13 +410,13 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, | @@ -427,13 +410,13 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, | ||
| 427 | static void set_brk(unsigned long start, unsigned long end) | 410 | static void set_brk(unsigned long start, unsigned long end) |
| 428 | { | 411 | { |
| 429 | /* page-align the start and end addresses... */ | 412 | /* page-align the start and end addresses... */ |
| 430 | - start = ALPHA_PAGE_ALIGN(start); | ||
| 431 | - end = ALPHA_PAGE_ALIGN(end); | 413 | + start = HOST_PAGE_ALIGN(start); |
| 414 | + end = HOST_PAGE_ALIGN(end); | ||
| 432 | if (end <= start) | 415 | if (end <= start) |
| 433 | return; | 416 | return; |
| 434 | - if((long)mmap4k(start, end - start, | ||
| 435 | - PROT_READ | PROT_WRITE | PROT_EXEC, | ||
| 436 | - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { | 417 | + if(target_mmap(start, end - start, |
| 418 | + PROT_READ | PROT_WRITE | PROT_EXEC, | ||
| 419 | + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { | ||
| 437 | perror("cannot mmap brk"); | 420 | perror("cannot mmap brk"); |
| 438 | exit(-1); | 421 | exit(-1); |
| 439 | } | 422 | } |
| @@ -451,9 +434,9 @@ static void padzero(unsigned long elf_bss) | @@ -451,9 +434,9 @@ static void padzero(unsigned long elf_bss) | ||
| 451 | unsigned long nbyte; | 434 | unsigned long nbyte; |
| 452 | char * fpnt; | 435 | char * fpnt; |
| 453 | 436 | ||
| 454 | - nbyte = elf_bss & (ALPHA_PAGE_SIZE-1); /* was X86_PAGE_SIZE - JRP */ | 437 | + nbyte = elf_bss & (host_page_size-1); /* was TARGET_PAGE_SIZE - JRP */ |
| 455 | if (nbyte) { | 438 | if (nbyte) { |
| 456 | - nbyte = ALPHA_PAGE_SIZE - nbyte; | 439 | + nbyte = host_page_size - nbyte; |
| 457 | fpnt = (char *) elf_bss; | 440 | fpnt = (char *) elf_bss; |
| 458 | do { | 441 | do { |
| 459 | *fpnt++ = 0; | 442 | *fpnt++ = 0; |
| @@ -494,7 +477,7 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, | @@ -494,7 +477,7 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, | ||
| 494 | NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); | 477 | NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); |
| 495 | NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); | 478 | NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); |
| 496 | NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum)); | 479 | NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum)); |
| 497 | - NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(ALPHA_PAGE_SIZE)); | 480 | + NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); |
| 498 | NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr)); | 481 | NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr)); |
| 499 | NEW_AUX_ENT (AT_FLAGS, (target_ulong)0); | 482 | NEW_AUX_ENT (AT_FLAGS, (target_ulong)0); |
| 500 | NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry); | 483 | NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry); |
| @@ -554,7 +537,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | @@ -554,7 +537,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | ||
| 554 | 537 | ||
| 555 | /* Now read in all of the header information */ | 538 | /* Now read in all of the header information */ |
| 556 | 539 | ||
| 557 | - if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE) | 540 | + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) |
| 558 | return ~0UL; | 541 | return ~0UL; |
| 559 | 542 | ||
| 560 | elf_phdata = (struct elf_phdr *) | 543 | elf_phdata = (struct elf_phdr *) |
| @@ -594,9 +577,9 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | @@ -594,9 +577,9 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | ||
| 594 | if (interp_elf_ex->e_type == ET_DYN) { | 577 | if (interp_elf_ex->e_type == ET_DYN) { |
| 595 | /* in order to avoid harcoding the interpreter load | 578 | /* in order to avoid harcoding the interpreter load |
| 596 | address in qemu, we allocate a big enough memory zone */ | 579 | address in qemu, we allocate a big enough memory zone */ |
| 597 | - error = (unsigned long)mmap4k(NULL, INTERP_MAP_SIZE, | ||
| 598 | - PROT_NONE, MAP_PRIVATE | MAP_ANON, | ||
| 599 | - -1, 0); | 580 | + error = target_mmap(0, INTERP_MAP_SIZE, |
| 581 | + PROT_NONE, MAP_PRIVATE | MAP_ANON, | ||
| 582 | + -1, 0); | ||
| 600 | if (error == -1) { | 583 | if (error == -1) { |
| 601 | perror("mmap"); | 584 | perror("mmap"); |
| 602 | exit(-1); | 585 | exit(-1); |
| @@ -620,12 +603,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | @@ -620,12 +603,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | ||
| 620 | elf_type |= MAP_FIXED; | 603 | elf_type |= MAP_FIXED; |
| 621 | vaddr = eppnt->p_vaddr; | 604 | vaddr = eppnt->p_vaddr; |
| 622 | } | 605 | } |
| 623 | - error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr), | ||
| 624 | - eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr), | 606 | + error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), |
| 607 | + eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), | ||
| 625 | elf_prot, | 608 | elf_prot, |
| 626 | elf_type, | 609 | elf_type, |
| 627 | interpreter_fd, | 610 | interpreter_fd, |
| 628 | - eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr)); | 611 | + eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); |
| 629 | 612 | ||
| 630 | if (error > -1024UL) { | 613 | if (error > -1024UL) { |
| 631 | /* Real error */ | 614 | /* Real error */ |
| @@ -665,13 +648,13 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | @@ -665,13 +648,13 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, | ||
| 665 | * bss page. | 648 | * bss page. |
| 666 | */ | 649 | */ |
| 667 | padzero(elf_bss); | 650 | padzero(elf_bss); |
| 668 | - elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */ | 651 | + elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */ |
| 669 | 652 | ||
| 670 | /* Map the last of the bss segment */ | 653 | /* Map the last of the bss segment */ |
| 671 | if (last_bss > elf_bss) { | 654 | if (last_bss > elf_bss) { |
| 672 | - mmap4k(elf_bss, last_bss-elf_bss, | ||
| 673 | - PROT_READ|PROT_WRITE|PROT_EXEC, | ||
| 674 | - MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | 655 | + target_mmap(elf_bss, last_bss-elf_bss, |
| 656 | + PROT_READ|PROT_WRITE|PROT_EXEC, | ||
| 657 | + MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | ||
| 675 | } | 658 | } |
| 676 | free(elf_phdata); | 659 | free(elf_phdata); |
| 677 | 660 | ||
| @@ -742,7 +725,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | @@ -742,7 +725,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | ||
| 742 | unsigned int interpreter_type = INTERPRETER_NONE; | 725 | unsigned int interpreter_type = INTERPRETER_NONE; |
| 743 | unsigned char ibcs2_interpreter; | 726 | unsigned char ibcs2_interpreter; |
| 744 | int i; | 727 | int i; |
| 745 | - void * mapped_addr; | 728 | + unsigned long mapped_addr; |
| 746 | struct elf_phdr * elf_ppnt; | 729 | struct elf_phdr * elf_ppnt; |
| 747 | struct elf_phdr *elf_phdata; | 730 | struct elf_phdr *elf_phdata; |
| 748 | unsigned long elf_bss, k, elf_brk; | 731 | unsigned long elf_bss, k, elf_brk; |
| @@ -979,33 +962,32 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | @@ -979,33 +962,32 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | ||
| 979 | is because the brk will follow the loader, and is not movable. */ | 962 | is because the brk will follow the loader, and is not movable. */ |
| 980 | /* NOTE: for qemu, we do a big mmap to get enough space | 963 | /* NOTE: for qemu, we do a big mmap to get enough space |
| 981 | without harcoding any address */ | 964 | without harcoding any address */ |
| 982 | - error = (unsigned long)mmap4k(NULL, ET_DYN_MAP_SIZE, | ||
| 983 | - PROT_NONE, MAP_PRIVATE | MAP_ANON, | ||
| 984 | - -1, 0); | 965 | + error = target_mmap(0, ET_DYN_MAP_SIZE, |
| 966 | + PROT_NONE, MAP_PRIVATE | MAP_ANON, | ||
| 967 | + -1, 0); | ||
| 985 | if (error == -1) { | 968 | if (error == -1) { |
| 986 | perror("mmap"); | 969 | perror("mmap"); |
| 987 | exit(-1); | 970 | exit(-1); |
| 988 | } | 971 | } |
| 989 | - load_bias = X86_ELF_PAGESTART(error - elf_ppnt->p_vaddr); | 972 | + load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); |
| 990 | } | 973 | } |
| 991 | 974 | ||
| 992 | - error = (unsigned long)mmap4k( | ||
| 993 | - X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), | ||
| 994 | - (elf_ppnt->p_filesz + | ||
| 995 | - X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), | ||
| 996 | - elf_prot, | ||
| 997 | - (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), | ||
| 998 | - bprm->fd, | ||
| 999 | - (elf_ppnt->p_offset - | ||
| 1000 | - X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); | 975 | + error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), |
| 976 | + (elf_ppnt->p_filesz + | ||
| 977 | + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), | ||
| 978 | + elf_prot, | ||
| 979 | + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), | ||
| 980 | + bprm->fd, | ||
| 981 | + (elf_ppnt->p_offset - | ||
| 982 | + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); | ||
| 1001 | if (error == -1) { | 983 | if (error == -1) { |
| 1002 | perror("mmap"); | 984 | perror("mmap"); |
| 1003 | exit(-1); | 985 | exit(-1); |
| 1004 | } | 986 | } |
| 1005 | 987 | ||
| 1006 | #ifdef LOW_ELF_STACK | 988 | #ifdef LOW_ELF_STACK |
| 1007 | - if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) | ||
| 1008 | - elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr); | 989 | + if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) |
| 990 | + elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); | ||
| 1009 | #endif | 991 | #endif |
| 1010 | 992 | ||
| 1011 | if (!load_addr_set) { | 993 | if (!load_addr_set) { |
| @@ -1013,7 +995,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | @@ -1013,7 +995,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | ||
| 1013 | load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; | 995 | load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; |
| 1014 | if (elf_ex.e_type == ET_DYN) { | 996 | if (elf_ex.e_type == ET_DYN) { |
| 1015 | load_bias += error - | 997 | load_bias += error - |
| 1016 | - X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); | 998 | + TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); |
| 1017 | load_addr += load_bias; | 999 | load_addr += load_bias; |
| 1018 | } | 1000 | } |
| 1019 | } | 1001 | } |
| @@ -1108,8 +1090,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | @@ -1108,8 +1090,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r | ||
| 1108 | and some applications "depend" upon this behavior. | 1090 | and some applications "depend" upon this behavior. |
| 1109 | Since we do not have the power to recompile these, we | 1091 | Since we do not have the power to recompile these, we |
| 1110 | emulate the SVr4 behavior. Sigh. */ | 1092 | emulate the SVr4 behavior. Sigh. */ |
| 1111 | - mapped_addr = mmap4k(NULL, ALPHA_PAGE_SIZE, PROT_READ | PROT_EXEC, | ||
| 1112 | - MAP_FIXED | MAP_PRIVATE, -1, 0); | 1093 | + mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC, |
| 1094 | + MAP_FIXED | MAP_PRIVATE, -1, 0); | ||
| 1113 | } | 1095 | } |
| 1114 | 1096 | ||
| 1115 | #ifdef ELF_PLAT_INIT | 1097 | #ifdef ELF_PLAT_INIT |
| @@ -1137,7 +1119,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp, | @@ -1137,7 +1119,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp, | ||
| 1137 | int retval; | 1119 | int retval; |
| 1138 | int i; | 1120 | int i; |
| 1139 | 1121 | ||
| 1140 | - bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); | 1122 | + bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); |
| 1141 | for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ | 1123 | for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ |
| 1142 | bprm.page[i] = 0; | 1124 | bprm.page[i] = 0; |
| 1143 | retval = open(filename, O_RDONLY); | 1125 | retval = open(filename, O_RDONLY); |
linux-user/main.c
| @@ -231,13 +231,16 @@ void usage(void) | @@ -231,13 +231,16 @@ void usage(void) | ||
| 231 | "usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n" | 231 | "usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n" |
| 232 | "Linux x86 emulator\n" | 232 | "Linux x86 emulator\n" |
| 233 | "\n" | 233 | "\n" |
| 234 | - "-h print this help\n" | ||
| 235 | - "-d activate log (logfile=%s)\n" | ||
| 236 | - "-L path set the x86 elf interpreter prefix (default=%s)\n" | ||
| 237 | - "-s size set the x86 stack size in bytes (default=%ld)\n", | ||
| 238 | - DEBUG_LOGFILE, | 234 | + "-h print this help\n" |
| 235 | + "-L path set the x86 elf interpreter prefix (default=%s)\n" | ||
| 236 | + "-s size set the x86 stack size in bytes (default=%ld)\n" | ||
| 237 | + "\n" | ||
| 238 | + "debug options:\n" | ||
| 239 | + "-d activate log (logfile=%s)\n" | ||
| 240 | + "-p pagesize set the host page size to 'pagesize'\n", | ||
| 239 | interp_prefix, | 241 | interp_prefix, |
| 240 | - x86_stack_size); | 242 | + x86_stack_size, |
| 243 | + DEBUG_LOGFILE); | ||
| 241 | _exit(1); | 244 | _exit(1); |
| 242 | } | 245 | } |
| 243 | 246 | ||
| @@ -284,6 +287,13 @@ int main(int argc, char **argv) | @@ -284,6 +287,13 @@ int main(int argc, char **argv) | ||
| 284 | x86_stack_size *= 1024; | 287 | x86_stack_size *= 1024; |
| 285 | } else if (!strcmp(r, "L")) { | 288 | } else if (!strcmp(r, "L")) { |
| 286 | interp_prefix = argv[optind++]; | 289 | interp_prefix = argv[optind++]; |
| 290 | + } else if (!strcmp(r, "p")) { | ||
| 291 | + host_page_size = atoi(argv[optind++]); | ||
| 292 | + if (host_page_size == 0 || | ||
| 293 | + (host_page_size & (host_page_size - 1)) != 0) { | ||
| 294 | + fprintf(stderr, "page size must be a power of two\n"); | ||
| 295 | + exit(1); | ||
| 296 | + } | ||
| 287 | } else { | 297 | } else { |
| 288 | usage(); | 298 | usage(); |
| 289 | } | 299 | } |
| @@ -311,12 +321,18 @@ int main(int argc, char **argv) | @@ -311,12 +321,18 @@ int main(int argc, char **argv) | ||
| 311 | /* Scan interp_prefix dir for replacement files. */ | 321 | /* Scan interp_prefix dir for replacement files. */ |
| 312 | init_paths(interp_prefix); | 322 | init_paths(interp_prefix); |
| 313 | 323 | ||
| 324 | + /* NOTE: we need to init the CPU at this stage to get the | ||
| 325 | + host_page_size */ | ||
| 326 | + env = cpu_x86_init(); | ||
| 327 | + | ||
| 314 | if (elf_exec(filename, argv+optind, environ, regs, info) != 0) { | 328 | if (elf_exec(filename, argv+optind, environ, regs, info) != 0) { |
| 315 | printf("Error loading %s\n", filename); | 329 | printf("Error loading %s\n", filename); |
| 316 | _exit(1); | 330 | _exit(1); |
| 317 | } | 331 | } |
| 318 | 332 | ||
| 319 | if (loglevel) { | 333 | if (loglevel) { |
| 334 | + page_dump(logfile); | ||
| 335 | + | ||
| 320 | fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk); | 336 | fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk); |
| 321 | fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); | 337 | fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); |
| 322 | fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); | 338 | fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); |
| @@ -331,7 +347,6 @@ int main(int argc, char **argv) | @@ -331,7 +347,6 @@ int main(int argc, char **argv) | ||
| 331 | syscall_init(); | 347 | syscall_init(); |
| 332 | signal_init(); | 348 | signal_init(); |
| 333 | 349 | ||
| 334 | - env = cpu_x86_init(); | ||
| 335 | global_env = env; | 350 | global_env = env; |
| 336 | 351 | ||
| 337 | /* build Task State */ | 352 | /* build Task State */ |
linux-user/mmap.c
0 → 100644
| 1 | +/* | ||
| 2 | + * mmap support for qemu | ||
| 3 | + * | ||
| 4 | + * Copyright (c) 2003 Fabrice Bellard | ||
| 5 | + * | ||
| 6 | + * This program is free software; you can redistribute it and/or modify | ||
| 7 | + * it under the terms of the GNU General Public License as published by | ||
| 8 | + * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | + * (at your option) any later version. | ||
| 10 | + * | ||
| 11 | + * This program is distributed in the hope that it will be useful, | ||
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | + * GNU General Public License for more details. | ||
| 15 | + * | ||
| 16 | + * You should have received a copy of the GNU General Public License | ||
| 17 | + * along with this program; if not, write to the Free Software | ||
| 18 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 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 | +//#define DEBUG_MMAP | ||
| 31 | + | ||
| 32 | +/* NOTE: all the constants are the HOST ones */ | ||
| 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 & host_page_mask; | ||
| 57 | + host_end = HOST_PAGE_ALIGN(end); | ||
| 58 | + if (start > host_start) { | ||
| 59 | + /* handle host page containing start */ | ||
| 60 | + prot1 = prot; | ||
| 61 | + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { | ||
| 62 | + prot1 |= page_get_flags(addr); | ||
| 63 | + } | ||
| 64 | + ret = mprotect((void *)host_start, host_page_size, prot1 & PAGE_BITS); | ||
| 65 | + if (ret != 0) | ||
| 66 | + return ret; | ||
| 67 | + host_start += host_page_size; | ||
| 68 | + } | ||
| 69 | + if (end < host_end) { | ||
| 70 | + /* handle host page containing end (can be the same as first page) */ | ||
| 71 | + prot1 = prot; | ||
| 72 | + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { | ||
| 73 | + prot1 |= page_get_flags(addr); | ||
| 74 | + } | ||
| 75 | + ret = mprotect((void *)(host_end - host_page_size), host_page_size, | ||
| 76 | + prot1 & PAGE_BITS); | ||
| 77 | + if (ret != 0) | ||
| 78 | + return ret; | ||
| 79 | + host_end -= host_page_size; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + /* handle the pages in the middle */ | ||
| 83 | + if (host_start < host_end) { | ||
| 84 | + ret = mprotect((void *)host_start, host_end - host_start, prot); | ||
| 85 | + if (ret != 0) | ||
| 86 | + return ret; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + page_set_flags(start, start + len, prot | PAGE_VALID); | ||
| 90 | + return 0; | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | +/* map an incomplete host page */ | ||
| 94 | +int mmap_frag(unsigned long host_start, | ||
| 95 | + unsigned long start, unsigned long end, | ||
| 96 | + int prot, int flags, int fd, unsigned long offset) | ||
| 97 | +{ | ||
| 98 | + unsigned long host_end, ret, addr; | ||
| 99 | + int prot1, prot_new; | ||
| 100 | + | ||
| 101 | + host_end = host_start + host_page_size; | ||
| 102 | + | ||
| 103 | + /* get the protection of the target pages outside the mapping */ | ||
| 104 | + prot1 = 0; | ||
| 105 | + for(addr = host_start; addr < host_end; addr++) { | ||
| 106 | + if (addr < start || addr >= end) | ||
| 107 | + prot1 |= page_get_flags(addr); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + if (prot1 == 0) { | ||
| 111 | + /* no page was there, so we allocate one */ | ||
| 112 | + ret = (long)mmap((void *)host_start, host_page_size, prot, | ||
| 113 | + flags | MAP_ANONYMOUS, -1, 0); | ||
| 114 | + if (ret == -1) | ||
| 115 | + return ret; | ||
| 116 | + } | ||
| 117 | + prot1 &= PAGE_BITS; | ||
| 118 | + | ||
| 119 | + prot_new = prot | prot1; | ||
| 120 | + if (!(flags & MAP_ANONYMOUS)) { | ||
| 121 | + /* msync() won't work here, so we return an error if write is | ||
| 122 | + possible while it is a shared mapping */ | ||
| 123 | + if ((flags & MAP_TYPE) == MAP_SHARED && | ||
| 124 | + (prot & PROT_WRITE)) | ||
| 125 | + return -EINVAL; | ||
| 126 | + | ||
| 127 | + /* adjust protection to be able to read */ | ||
| 128 | + if (!(prot1 & PROT_WRITE)) | ||
| 129 | + mprotect((void *)host_start, host_page_size, prot1 | PROT_WRITE); | ||
| 130 | + | ||
| 131 | + /* read the corresponding file data */ | ||
| 132 | + pread(fd, (void *)start, end - start, offset); | ||
| 133 | + | ||
| 134 | + /* put final protection */ | ||
| 135 | + if (prot_new != (prot1 | PROT_WRITE)) | ||
| 136 | + mprotect((void *)host_start, host_page_size, prot_new); | ||
| 137 | + } else { | ||
| 138 | + /* just update the protection */ | ||
| 139 | + if (prot_new != prot1) { | ||
| 140 | + mprotect((void *)host_start, host_page_size, prot_new); | ||
| 141 | + } | ||
| 142 | + } | ||
| 143 | + return 0; | ||
| 144 | +} | ||
| 145 | + | ||
| 146 | +/* NOTE: all the constants are the HOST ones */ | ||
| 147 | +long target_mmap(unsigned long start, unsigned long len, int prot, | ||
| 148 | + int flags, int fd, unsigned long offset) | ||
| 149 | +{ | ||
| 150 | + unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len; | ||
| 151 | + | ||
| 152 | +#ifdef DEBUG_MMAP | ||
| 153 | + { | ||
| 154 | + printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=", | ||
| 155 | + start, len, | ||
| 156 | + prot & PROT_READ ? 'r' : '-', | ||
| 157 | + prot & PROT_WRITE ? 'w' : '-', | ||
| 158 | + prot & PROT_EXEC ? 'x' : '-'); | ||
| 159 | + if (flags & MAP_FIXED) | ||
| 160 | + printf("MAP_FIXED "); | ||
| 161 | + if (flags & MAP_ANONYMOUS) | ||
| 162 | + printf("MAP_ANON "); | ||
| 163 | + switch(flags & MAP_TYPE) { | ||
| 164 | + case MAP_PRIVATE: | ||
| 165 | + printf("MAP_PRIVATE "); | ||
| 166 | + break; | ||
| 167 | + case MAP_SHARED: | ||
| 168 | + printf("MAP_SHARED "); | ||
| 169 | + break; | ||
| 170 | + default: | ||
| 171 | + printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); | ||
| 172 | + break; | ||
| 173 | + } | ||
| 174 | + printf("fd=%d offset=%lx\n", fd, offset); | ||
| 175 | + } | ||
| 176 | +#endif | ||
| 177 | + | ||
| 178 | + if (offset & ~TARGET_PAGE_MASK) | ||
| 179 | + return -EINVAL; | ||
| 180 | + | ||
| 181 | + len = TARGET_PAGE_ALIGN(len); | ||
| 182 | + if (len == 0) | ||
| 183 | + return start; | ||
| 184 | + host_start = start & host_page_mask; | ||
| 185 | + | ||
| 186 | + if (!(flags & MAP_FIXED)) { | ||
| 187 | + if (host_page_size != real_host_page_size) { | ||
| 188 | + /* NOTE: this code is only for debugging with '-p' option */ | ||
| 189 | + /* reserve a memory area */ | ||
| 190 | + host_len = HOST_PAGE_ALIGN(len) + host_page_size - TARGET_PAGE_SIZE; | ||
| 191 | + host_start = (long)mmap((void *)host_start, host_len, PROT_NONE, | ||
| 192 | + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
| 193 | + if (host_start == -1) | ||
| 194 | + return host_start; | ||
| 195 | + host_end = host_start + host_len; | ||
| 196 | + start = HOST_PAGE_ALIGN(host_start); | ||
| 197 | + end = start + HOST_PAGE_ALIGN(len); | ||
| 198 | + if (start > host_start) | ||
| 199 | + munmap((void *)host_start, start - host_start); | ||
| 200 | + if (end < host_end) | ||
| 201 | + munmap((void *)end, host_end - end); | ||
| 202 | + /* use it as a fixed mapping */ | ||
| 203 | + flags |= MAP_FIXED; | ||
| 204 | + } else { | ||
| 205 | + /* if not fixed, no need to do anything */ | ||
| 206 | + host_offset = offset & host_page_mask; | ||
| 207 | + host_len = len + offset - host_offset; | ||
| 208 | + start = (long)mmap((void *)host_start, host_len, | ||
| 209 | + prot, flags, fd, host_offset); | ||
| 210 | + if (start == -1) | ||
| 211 | + return start; | ||
| 212 | + /* update start so that it points to the file position at 'offset' */ | ||
| 213 | + if (!(flags & MAP_ANONYMOUS)) | ||
| 214 | + start += offset - host_offset; | ||
| 215 | + goto the_end1; | ||
| 216 | + } | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + if (start & ~TARGET_PAGE_MASK) | ||
| 220 | + return -EINVAL; | ||
| 221 | + end = start + len; | ||
| 222 | + host_end = HOST_PAGE_ALIGN(end); | ||
| 223 | + | ||
| 224 | + /* worst case: we cannot map the file because the offset is not | ||
| 225 | + aligned, so we read it */ | ||
| 226 | + if (!(flags & MAP_ANONYMOUS) && | ||
| 227 | + (offset & ~host_page_mask) != (start & ~host_page_mask)) { | ||
| 228 | + /* msync() won't work here, so we return an error if write is | ||
| 229 | + possible while it is a shared mapping */ | ||
| 230 | + if ((flags & MAP_TYPE) == MAP_SHARED && | ||
| 231 | + (prot & PROT_WRITE)) | ||
| 232 | + return -EINVAL; | ||
| 233 | + retaddr = target_mmap(start, len, prot | PROT_WRITE, | ||
| 234 | + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, | ||
| 235 | + -1, 0); | ||
| 236 | + if (retaddr == -1) | ||
| 237 | + return retaddr; | ||
| 238 | + pread(fd, (void *)start, len, offset); | ||
| 239 | + if (!(prot & PROT_WRITE)) { | ||
| 240 | + ret = target_mprotect(start, len, prot); | ||
| 241 | + if (ret != 0) | ||
| 242 | + return ret; | ||
| 243 | + } | ||
| 244 | + goto the_end; | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + /* handle the start of the mapping */ | ||
| 248 | + if (start > host_start) { | ||
| 249 | + if (host_end == host_start + host_page_size) { | ||
| 250 | + /* one single host page */ | ||
| 251 | + ret = mmap_frag(host_start, start, end, | ||
| 252 | + prot, flags, fd, offset); | ||
| 253 | + if (ret == -1) | ||
| 254 | + return ret; | ||
| 255 | + goto the_end1; | ||
| 256 | + } | ||
| 257 | + ret = mmap_frag(host_start, start, host_start + host_page_size, | ||
| 258 | + prot, flags, fd, offset); | ||
| 259 | + if (ret == -1) | ||
| 260 | + return ret; | ||
| 261 | + host_start += host_page_size; | ||
| 262 | + } | ||
| 263 | + /* handle the end of the mapping */ | ||
| 264 | + if (end < host_end) { | ||
| 265 | + ret = mmap_frag(host_end - host_page_size, | ||
| 266 | + host_end - host_page_size, host_end, | ||
| 267 | + prot, flags, fd, | ||
| 268 | + offset + host_end - host_page_size - start); | ||
| 269 | + if (ret == -1) | ||
| 270 | + return ret; | ||
| 271 | + host_end -= host_page_size; | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + /* map the middle (easier) */ | ||
| 275 | + if (host_start < host_end) { | ||
| 276 | + ret = (long)mmap((void *)host_start, host_end - host_start, | ||
| 277 | + prot, flags, fd, offset + host_start - start); | ||
| 278 | + if (ret == -1) | ||
| 279 | + return ret; | ||
| 280 | + } | ||
| 281 | + the_end1: | ||
| 282 | + page_set_flags(start, start + len, prot | PAGE_VALID); | ||
| 283 | + the_end: | ||
| 284 | +#ifdef DEBUG_MMAP | ||
| 285 | + page_dump(stdout); | ||
| 286 | + printf("\n"); | ||
| 287 | +#endif | ||
| 288 | + return start; | ||
| 289 | +} | ||
| 290 | + | ||
| 291 | +int target_munmap(unsigned long start, unsigned long len) | ||
| 292 | +{ | ||
| 293 | + unsigned long end, host_start, host_end, addr; | ||
| 294 | + int prot, ret; | ||
| 295 | + | ||
| 296 | +#ifdef DEBUG_MMAP | ||
| 297 | + printf("munmap: start=0x%lx len=0x%lx\n", start, len); | ||
| 298 | +#endif | ||
| 299 | + if (start & ~TARGET_PAGE_MASK) | ||
| 300 | + return -EINVAL; | ||
| 301 | + len = TARGET_PAGE_ALIGN(len); | ||
| 302 | + if (len == 0) | ||
| 303 | + return -EINVAL; | ||
| 304 | + end = start + len; | ||
| 305 | + host_start = start & host_page_mask; | ||
| 306 | + host_end = HOST_PAGE_ALIGN(end); | ||
| 307 | + | ||
| 308 | + if (start > host_start) { | ||
| 309 | + /* handle host page containing start */ | ||
| 310 | + prot = 0; | ||
| 311 | + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { | ||
| 312 | + prot |= page_get_flags(addr); | ||
| 313 | + } | ||
| 314 | + if (prot != 0) | ||
| 315 | + host_start += host_page_size; | ||
| 316 | + } | ||
| 317 | + if (end < host_end) { | ||
| 318 | + /* handle host page containing end (can be the same as first page) */ | ||
| 319 | + prot = 0; | ||
| 320 | + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { | ||
| 321 | + prot |= page_get_flags(addr); | ||
| 322 | + } | ||
| 323 | + if (prot != 0) | ||
| 324 | + host_end -= host_page_size; | ||
| 325 | + } | ||
| 326 | + | ||
| 327 | + /* unmap what we can */ | ||
| 328 | + if (host_start < host_end) { | ||
| 329 | + ret = munmap((void *)host_start, host_end - host_start); | ||
| 330 | + if (ret != 0) | ||
| 331 | + return ret; | ||
| 332 | + } | ||
| 333 | + | ||
| 334 | + page_set_flags(start, start + len, 0); | ||
| 335 | + return 0; | ||
| 336 | +} | ||
| 337 | + | ||
| 338 | +/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED | ||
| 339 | + blocks which have been allocated starting on a host page */ | ||
| 340 | +long target_mremap(unsigned long old_addr, unsigned long old_size, | ||
| 341 | + unsigned long new_size, unsigned long flags, | ||
| 342 | + unsigned long new_addr) | ||
| 343 | +{ | ||
| 344 | + int prot; | ||
| 345 | + | ||
| 346 | + /* XXX: use 5 args syscall */ | ||
| 347 | + new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags); | ||
| 348 | + if (new_addr == -1) | ||
| 349 | + return new_addr; | ||
| 350 | + prot = page_get_flags(old_addr); | ||
| 351 | + page_set_flags(old_addr, old_addr + old_size, 0); | ||
| 352 | + page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); | ||
| 353 | + return new_addr; | ||
| 354 | +} | ||
| 355 | + | ||
| 356 | +int target_msync(unsigned long start, unsigned long len, int flags) | ||
| 357 | +{ | ||
| 358 | + unsigned long end; | ||
| 359 | + | ||
| 360 | + if (start & ~TARGET_PAGE_MASK) | ||
| 361 | + return -EINVAL; | ||
| 362 | + len = TARGET_PAGE_ALIGN(len); | ||
| 363 | + if (len == 0) | ||
| 364 | + return 0; | ||
| 365 | + end = start + len; | ||
| 366 | + | ||
| 367 | + start &= host_page_mask; | ||
| 368 | + return msync((void *)start, len, flags); | ||
| 369 | +} | ||
| 370 | + |
linux-user/qemu.h
| @@ -88,4 +88,14 @@ void handle_vm86_fault(CPUX86State *env); | @@ -88,4 +88,14 @@ void handle_vm86_fault(CPUX86State *env); | ||
| 88 | int do_vm86(CPUX86State *env, long subfunction, | 88 | int do_vm86(CPUX86State *env, long subfunction, |
| 89 | struct target_vm86plus_struct * target_v86); | 89 | struct target_vm86plus_struct * target_v86); |
| 90 | 90 | ||
| 91 | +/* mmap.c */ | ||
| 92 | +int target_mprotect(unsigned long start, unsigned long len, int prot); | ||
| 93 | +long target_mmap(unsigned long start, unsigned long len, int prot, | ||
| 94 | + int flags, int fd, unsigned long offset); | ||
| 95 | +int target_munmap(unsigned long start, unsigned long len); | ||
| 96 | +long target_mremap(unsigned long old_addr, unsigned long old_size, | ||
| 97 | + unsigned long new_size, unsigned long flags, | ||
| 98 | + unsigned long new_addr); | ||
| 99 | +int target_msync(unsigned long start, unsigned long len, int flags); | ||
| 100 | + | ||
| 91 | #endif | 101 | #endif |
linux-user/syscall.c
| @@ -64,11 +64,6 @@ | @@ -64,11 +64,6 @@ | ||
| 64 | 64 | ||
| 65 | //#define DEBUG | 65 | //#define DEBUG |
| 66 | 66 | ||
| 67 | -#ifndef PAGE_SIZE | ||
| 68 | -#define PAGE_SIZE 4096 | ||
| 69 | -#define PAGE_MASK ~(PAGE_SIZE - 1) | ||
| 70 | -#endif | ||
| 71 | - | ||
| 72 | //#include <linux/msdos_fs.h> | 67 | //#include <linux/msdos_fs.h> |
| 73 | #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) | 68 | #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) |
| 74 | #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) | 69 | #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) |
| @@ -153,7 +148,7 @@ static long do_brk(char *new_brk) | @@ -153,7 +148,7 @@ static long do_brk(char *new_brk) | ||
| 153 | if (new_brk < target_original_brk) | 148 | if (new_brk < target_original_brk) |
| 154 | return -ENOMEM; | 149 | return -ENOMEM; |
| 155 | 150 | ||
| 156 | - brk_page = (char *)(((unsigned long)target_brk + PAGE_SIZE - 1) & PAGE_MASK); | 151 | + brk_page = (char *)HOST_PAGE_ALIGN((unsigned long)target_brk); |
| 157 | 152 | ||
| 158 | /* If the new brk is less than this, set it and we're done... */ | 153 | /* If the new brk is less than this, set it and we're done... */ |
| 159 | if (new_brk < brk_page) { | 154 | if (new_brk < brk_page) { |
| @@ -162,11 +157,10 @@ static long do_brk(char *new_brk) | @@ -162,11 +157,10 @@ static long do_brk(char *new_brk) | ||
| 162 | } | 157 | } |
| 163 | 158 | ||
| 164 | /* We need to allocate more memory after the brk... */ | 159 | /* We need to allocate more memory after the brk... */ |
| 165 | - new_alloc_size = ((new_brk - brk_page + 1)+(PAGE_SIZE-1)) & PAGE_MASK; | ||
| 166 | - mapped_addr = get_errno((long)mmap((caddr_t)brk_page, new_alloc_size, | ||
| 167 | - PROT_READ|PROT_WRITE, | ||
| 168 | - MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); | ||
| 169 | - | 160 | + new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); |
| 161 | + mapped_addr = get_errno(target_mmap((unsigned long)brk_page, new_alloc_size, | ||
| 162 | + PROT_READ|PROT_WRITE, | ||
| 163 | + MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); | ||
| 170 | if (is_error(mapped_addr)) { | 164 | if (is_error(mapped_addr)) { |
| 171 | return mapped_addr; | 165 | return mapped_addr; |
| 172 | } else { | 166 | } else { |
| @@ -1709,7 +1703,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | @@ -1709,7 +1703,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | ||
| 1709 | v4 = tswap32(vptr[3]); | 1703 | v4 = tswap32(vptr[3]); |
| 1710 | v5 = tswap32(vptr[4]); | 1704 | v5 = tswap32(vptr[4]); |
| 1711 | v6 = tswap32(vptr[5]); | 1705 | v6 = tswap32(vptr[5]); |
| 1712 | - ret = get_errno((long)mmap((void *)v1, v2, v3, v4, v5, v6)); | 1706 | + ret = get_errno(target_mmap(v1, v2, v3, v4, v5, v6)); |
| 1713 | } | 1707 | } |
| 1714 | break; | 1708 | break; |
| 1715 | #endif | 1709 | #endif |
| @@ -1718,16 +1712,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | @@ -1718,16 +1712,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | ||
| 1718 | #else | 1712 | #else |
| 1719 | case TARGET_NR_mmap: | 1713 | case TARGET_NR_mmap: |
| 1720 | #endif | 1714 | #endif |
| 1721 | - ret = get_errno((long)mmap((void *)arg1, arg2, arg3, arg4, arg5, arg6)); | 1715 | + ret = get_errno(target_mmap(arg1, arg2, arg3, arg4, arg5, arg6)); |
| 1722 | break; | 1716 | break; |
| 1723 | case TARGET_NR_munmap: | 1717 | case TARGET_NR_munmap: |
| 1724 | - ret = get_errno(munmap((void *)arg1, arg2)); | 1718 | + ret = get_errno(target_munmap(arg1, arg2)); |
| 1725 | break; | 1719 | break; |
| 1726 | case TARGET_NR_mprotect: | 1720 | case TARGET_NR_mprotect: |
| 1727 | - ret = get_errno(mprotect((void *)arg1, arg2, arg3)); | 1721 | + ret = get_errno(target_mprotect(arg1, arg2, arg3)); |
| 1728 | break; | 1722 | break; |
| 1729 | case TARGET_NR_mremap: | 1723 | case TARGET_NR_mremap: |
| 1730 | - ret = get_errno((long)mremap((void *)arg1, arg2, arg3, arg4)); | 1724 | + ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5)); |
| 1731 | break; | 1725 | break; |
| 1732 | case TARGET_NR_msync: | 1726 | case TARGET_NR_msync: |
| 1733 | ret = get_errno(msync((void *)arg1, arg2, arg3)); | 1727 | ret = get_errno(msync((void *)arg1, arg2, arg3)); |
translate-i386.c
| @@ -3845,6 +3845,7 @@ CPUX86State *cpu_x86_init(void) | @@ -3845,6 +3845,7 @@ CPUX86State *cpu_x86_init(void) | ||
| 3845 | if (!inited) { | 3845 | if (!inited) { |
| 3846 | inited = 1; | 3846 | inited = 1; |
| 3847 | optimize_flags_init(); | 3847 | optimize_flags_init(); |
| 3848 | + page_init(); | ||
| 3848 | } | 3849 | } |
| 3849 | return env; | 3850 | return env; |
| 3850 | } | 3851 | } |