From 53a5960aadd542dd27b8705ac30df154557d5ffc Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 25 Mar 2006 19:31:22 +0000 Subject: Avoid accessing guest memory directly in usermode emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1790 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mmap.c | 164 +++++++++++++++++++++++++++++------------------------- 1 file changed, 88 insertions(+), 76 deletions(-) (limited to 'linux-user/mmap.c') diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 948f2f6..0c90625 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -29,10 +29,10 @@ //#define DEBUG_MMAP -/* NOTE: all the constants are the HOST ones */ -int target_mprotect(unsigned long start, unsigned long len, int prot) +/* NOTE: all the constants are the HOST ones, but addresses are target. */ +int target_mprotect(target_ulong start, target_ulong len, int prot) { - unsigned long end, host_start, host_end, addr; + target_ulong end, host_start, host_end, addr; int prot1, ret; #ifdef DEBUG_MMAP @@ -67,7 +67,7 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) } end = host_end; } - ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS); + ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS); if (ret != 0) return ret; host_start += qemu_host_page_size; @@ -77,7 +77,7 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } - ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size, + ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size, prot1 & PAGE_BITS); if (ret != 0) return ret; @@ -86,7 +86,7 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) /* handle the pages in the middle */ if (host_start < host_end) { - ret = mprotect((void *)host_start, host_end - host_start, prot); + ret = mprotect(g2h(host_start), host_end - host_start, prot); if (ret != 0) return ret; } @@ -95,28 +95,31 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) } /* map an incomplete host page */ -int mmap_frag(unsigned long host_start, - unsigned long start, unsigned long end, - int prot, int flags, int fd, unsigned long offset) +static int mmap_frag(target_ulong real_start, + target_ulong start, target_ulong end, + int prot, int flags, int fd, target_ulong offset) { - unsigned long host_end, ret, addr; + target_ulong real_end, ret, addr; + void *host_start; int prot1, prot_new; - host_end = host_start + qemu_host_page_size; + real_end = real_start + qemu_host_page_size; + host_start = g2h(real_start); /* get the protection of the target pages outside the mapping */ prot1 = 0; - for(addr = host_start; addr < host_end; addr++) { + for(addr = real_start; addr < real_end; addr++) { if (addr < start || addr >= end) prot1 |= page_get_flags(addr); } if (prot1 == 0) { /* no page was there, so we allocate one */ - ret = (long)mmap((void *)host_start, qemu_host_page_size, prot, + ret = (long)mmap(host_start, qemu_host_page_size, prot, flags | MAP_ANONYMOUS, -1, 0); if (ret == -1) return ret; + prot1 = prot; } prot1 &= PAGE_BITS; @@ -130,31 +133,35 @@ int mmap_frag(unsigned long host_start, /* adjust protection to be able to read */ if (!(prot1 & PROT_WRITE)) - mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE); + mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE); /* read the corresponding file data */ - pread(fd, (void *)start, end - start, offset); + pread(fd, g2h(start), end - start, offset); /* put final protection */ if (prot_new != (prot1 | PROT_WRITE)) - mprotect((void *)host_start, qemu_host_page_size, prot_new); + mprotect(host_start, qemu_host_page_size, prot_new); } else { /* just update the protection */ if (prot_new != prot1) { - mprotect((void *)host_start, qemu_host_page_size, prot_new); + mprotect(host_start, qemu_host_page_size, prot_new); } } return 0; } /* NOTE: all the constants are the HOST ones */ -long target_mmap(unsigned long start, unsigned long len, int prot, - int flags, int fd, unsigned long offset) +long target_mmap(target_ulong start, target_ulong len, int prot, + int flags, int fd, target_ulong offset) { - unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len; + target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; + long host_start; #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ defined(__ia64) - static unsigned long last_start = 0x40000000; + static target_ulong last_start = 0x40000000; +#elif defined(__CYGWIN__) + /* Cygwin doesn't have a whole lot of address space. */ + static target_ulong last_start = 0x18000000; #endif #ifdef DEBUG_MMAP @@ -191,45 +198,49 @@ long target_mmap(unsigned long start, unsigned long len, int prot, len = TARGET_PAGE_ALIGN(len); if (len == 0) return start; - host_start = start & qemu_host_page_mask; + real_start = start & qemu_host_page_mask; if (!(flags & MAP_FIXED)) { #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ - defined(__ia64) + defined(__ia64) || defined(__CYGWIN__) /* tell the kenel to search at the same place as i386 */ - if (host_start == 0) { - host_start = last_start; + if (real_start == 0) { + real_start = last_start; last_start += HOST_PAGE_ALIGN(len); } #endif if (qemu_host_page_size != qemu_real_host_page_size) { /* NOTE: this code is only for debugging with '-p' option */ + /* ??? Can also occur when TARGET_PAGE_SIZE > host page size. */ /* reserve a memory area */ + /* ??? This needs fixing for remapping. */ +abort(); host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE; - host_start = (long)mmap((void *)host_start, host_len, PROT_NONE, + real_start = (long)mmap(g2h(real_start), host_len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (host_start == -1) - return host_start; - host_end = host_start + host_len; - start = HOST_PAGE_ALIGN(host_start); + if (real_start == -1) + return real_start; + real_end = real_start + host_len; + start = HOST_PAGE_ALIGN(real_start); end = start + HOST_PAGE_ALIGN(len); - if (start > host_start) - munmap((void *)host_start, start - host_start); - if (end < host_end) - munmap((void *)end, host_end - end); + if (start > real_start) + munmap((void *)real_start, start - real_start); + if (end < real_end) + munmap((void *)end, real_end - end); /* use it as a fixed mapping */ flags |= MAP_FIXED; } else { /* if not fixed, no need to do anything */ host_offset = offset & qemu_host_page_mask; host_len = len + offset - host_offset; - start = (long)mmap((void *)host_start, host_len, - prot, flags, fd, host_offset); - if (start == -1) - return start; + host_start = (long)mmap(real_start ? g2h(real_start) : NULL, + host_len, prot, flags, fd, host_offset); + if (host_start == -1) + return host_start; /* update start so that it points to the file position at 'offset' */ if (!(flags & MAP_ANONYMOUS)) - start += offset - host_offset; + host_start += offset - host_offset; + start = h2g(host_start); goto the_end1; } } @@ -239,7 +250,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, return -1; } end = start + len; - host_end = HOST_PAGE_ALIGN(end); + real_end = HOST_PAGE_ALIGN(end); /* worst case: we cannot map the file because the offset is not aligned, so we read it */ @@ -257,7 +268,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, -1, 0); if (retaddr == -1) return retaddr; - pread(fd, (void *)start, len, offset); + pread(fd, g2h(start), len, offset); if (!(prot & PROT_WRITE)) { ret = target_mprotect(start, len, prot); if (ret != 0) @@ -267,40 +278,40 @@ long target_mmap(unsigned long start, unsigned long len, int prot, } /* handle the start of the mapping */ - if (start > host_start) { - if (host_end == host_start + qemu_host_page_size) { + if (start > real_start) { + if (real_end == real_start + qemu_host_page_size) { /* one single host page */ - ret = mmap_frag(host_start, start, end, + ret = mmap_frag(real_start, start, end, prot, flags, fd, offset); if (ret == -1) return ret; goto the_end1; } - ret = mmap_frag(host_start, start, host_start + qemu_host_page_size, + ret = mmap_frag(real_start, start, real_start + qemu_host_page_size, prot, flags, fd, offset); if (ret == -1) return ret; - host_start += qemu_host_page_size; + real_start += qemu_host_page_size; } /* handle the end of the mapping */ - if (end < host_end) { - ret = mmap_frag(host_end - qemu_host_page_size, - host_end - qemu_host_page_size, host_end, + if (end < real_end) { + ret = mmap_frag(real_end - qemu_host_page_size, + real_end - qemu_host_page_size, real_end, prot, flags, fd, - offset + host_end - qemu_host_page_size - start); + offset + real_end - qemu_host_page_size - start); if (ret == -1) return ret; - host_end -= qemu_host_page_size; + real_end -= qemu_host_page_size; } /* map the middle (easier) */ - if (host_start < host_end) { + if (real_start < real_end) { unsigned long offset1; if (flags & MAP_ANONYMOUS) offset1 = 0; else - offset1 = offset + host_start - start; - ret = (long)mmap((void *)host_start, host_end - host_start, + offset1 = offset + real_start - start; + ret = (long)mmap(g2h(real_start), real_end - real_start, prot, flags, fd, offset1); if (ret == -1) return ret; @@ -316,9 +327,9 @@ long target_mmap(unsigned long start, unsigned long len, int prot, return start; } -int target_munmap(unsigned long start, unsigned long len) +int target_munmap(target_ulong start, target_ulong len) { - unsigned long end, host_start, host_end, addr; + target_ulong end, real_start, real_end, addr; int prot, ret; #ifdef DEBUG_MMAP @@ -330,36 +341,36 @@ int target_munmap(unsigned long start, unsigned long len) if (len == 0) return -EINVAL; end = start + len; - host_start = start & qemu_host_page_mask; - host_end = HOST_PAGE_ALIGN(end); + real_start = start & qemu_host_page_mask; + real_end = HOST_PAGE_ALIGN(end); - if (start > host_start) { + if (start > real_start) { /* handle host page containing start */ prot = 0; - for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } - if (host_end == host_start + qemu_host_page_size) { - for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + if (real_end == real_start + qemu_host_page_size) { + for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } - end = host_end; + end = real_end; } if (prot != 0) - host_start += qemu_host_page_size; + real_start += qemu_host_page_size; } - if (end < host_end) { + if (end < real_end) { prot = 0; - for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } if (prot != 0) - host_end -= qemu_host_page_size; + real_end -= qemu_host_page_size; } /* unmap what we can */ - if (host_start < host_end) { - ret = munmap((void *)host_start, host_end - host_start); + if (real_start < real_end) { + ret = munmap((void *)real_start, real_end - real_start); if (ret != 0) return ret; } @@ -370,25 +381,26 @@ int target_munmap(unsigned long start, unsigned long len) /* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED blocks which have been allocated starting on a host page */ -long target_mremap(unsigned long old_addr, unsigned long old_size, - unsigned long new_size, unsigned long flags, - unsigned long new_addr) +long target_mremap(target_ulong old_addr, target_ulong old_size, + target_ulong new_size, unsigned long flags, + target_ulong new_addr) { int prot; /* XXX: use 5 args syscall */ - new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags); + new_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); if (new_addr == -1) return new_addr; + new_addr = h2g(new_addr); prot = page_get_flags(old_addr); page_set_flags(old_addr, old_addr + old_size, 0); page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); return new_addr; } -int target_msync(unsigned long start, unsigned long len, int flags) +int target_msync(target_ulong start, target_ulong len, int flags) { - unsigned long end; + target_ulong end; if (start & ~TARGET_PAGE_MASK) return -EINVAL; @@ -400,6 +412,6 @@ int target_msync(unsigned long start, unsigned long len, int flags) return 0; start &= qemu_host_page_mask; - return msync((void *)start, end - start, flags); + return msync(g2h(start), end - start, flags); } -- cgit v1.1