diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index ba44501a7c..d68fa6867c 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1363,6 +1363,21 @@ static inline void cpu_transaction_failed(CPUState *cpu, hwaddr physaddr, } } +/* + * Save a potentially trashed CPUTLBEntryFull for later lookup by plugin. + * This is read by tlb_plugin_lookup if the fulltlb entry doesn't match + * because of the side effect of io_writex changing memory layout. + */ +static void save_iotlb_data(CPUState *cs, MemoryRegionSection *section, + hwaddr mr_offset) +{ +#ifdef CONFIG_PLUGIN + SavedIOTLB *saved = &cs->saved_iotlb; + saved->section = section; + saved->mr_offset = mr_offset; +#endif +} + static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full, int mmu_idx, vaddr addr, uintptr_t retaddr, MMUAccessType access_type, MemOp op) @@ -1382,6 +1397,12 @@ static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full, cpu_io_recompile(cpu, retaddr); } + /* + * The memory_region_dispatch may trigger a flush/resize + * so for plugins we save the iotlb_data just in case. + */ + save_iotlb_data(cpu, section, mr_offset); + { QEMU_IOTHREAD_LOCK_GUARD(); r = memory_region_dispatch_read(mr, mr_offset, &val, op, full->attrs); @@ -1398,21 +1419,6 @@ static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full, return val; } -/* - * Save a potentially trashed CPUTLBEntryFull for later lookup by plugin. - * This is read by tlb_plugin_lookup if the fulltlb entry doesn't match - * because of the side effect of io_writex changing memory layout. - */ -static void save_iotlb_data(CPUState *cs, MemoryRegionSection *section, - hwaddr mr_offset) -{ -#ifdef CONFIG_PLUGIN - SavedIOTLB *saved = &cs->saved_iotlb; - saved->section = section; - saved->mr_offset = mr_offset; -#endif -} - static void io_writex(CPUArchState *env, CPUTLBEntryFull *full, int mmu_idx, uint64_t val, vaddr addr, uintptr_t retaddr, MemOp op) @@ -2066,27 +2072,55 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, /** * do_ld_mmio_beN: * @env: cpu context - * @p: translation parameters + * @full: page parameters * @ret_be: accumulated data + * @addr: virtual address + * @size: number of bytes * @mmu_idx: virtual address context * @ra: return address into tcg generated code, or 0 + * Context: iothread lock held * - * Load @p->size bytes from @p->addr, which is memory-mapped i/o. + * Load @size bytes from @addr, which is memory-mapped i/o. * The bytes are concatenated in big-endian order with @ret_be. */ -static uint64_t do_ld_mmio_beN(CPUArchState *env, MMULookupPageData *p, - uint64_t ret_be, int mmu_idx, - MMUAccessType type, uintptr_t ra) +static uint64_t do_ld_mmio_beN(CPUArchState *env, CPUTLBEntryFull *full, + uint64_t ret_be, vaddr addr, int size, + int mmu_idx, MMUAccessType type, uintptr_t ra) { - CPUTLBEntryFull *full = p->full; - vaddr addr = p->addr; - int i, size = p->size; + uint64_t t; - QEMU_IOTHREAD_LOCK_GUARD(); - for (i = 0; i < size; i++) { - uint8_t x = io_readx(env, full, mmu_idx, addr + i, ra, type, MO_UB); - ret_be = (ret_be << 8) | x; - } + tcg_debug_assert(size > 0 && size <= 8); + do { + /* Read aligned pieces up to 8 bytes. */ + switch ((size | (int)addr) & 7) { + case 1: + case 3: + case 5: + case 7: + t = io_readx(env, full, mmu_idx, addr, ra, type, MO_UB); + ret_be = (ret_be << 8) | t; + size -= 1; + addr += 1; + break; + case 2: + case 6: + t = io_readx(env, full, mmu_idx, addr, ra, type, MO_BEUW); + ret_be = (ret_be << 16) | t; + size -= 2; + addr += 2; + break; + case 4: + t = io_readx(env, full, mmu_idx, addr, ra, type, MO_BEUL); + ret_be = (ret_be << 32) | t; + size -= 4; + addr += 4; + break; + case 0: + return io_readx(env, full, mmu_idx, addr, ra, type, MO_BEUQ); + default: + qemu_build_not_reached(); + } + } while (size); return ret_be; } @@ -2232,7 +2266,9 @@ static uint64_t do_ld_beN(CPUArchState *env, MMULookupPageData *p, unsigned tmp, half_size; if (unlikely(p->flags & TLB_MMIO)) { - return do_ld_mmio_beN(env, p, ret_be, mmu_idx, type, ra); + QEMU_IOTHREAD_LOCK_GUARD(); + return do_ld_mmio_beN(env, p->full, ret_be, p->addr, p->size, + mmu_idx, type, ra); } /* @@ -2281,11 +2317,11 @@ static Int128 do_ld16_beN(CPUArchState *env, MMULookupPageData *p, MemOp atom; if (unlikely(p->flags & TLB_MMIO)) { - p->size = size - 8; - a = do_ld_mmio_beN(env, p, a, mmu_idx, MMU_DATA_LOAD, ra); - p->addr += p->size; - p->size = 8; - b = do_ld_mmio_beN(env, p, 0, mmu_idx, MMU_DATA_LOAD, ra); + QEMU_IOTHREAD_LOCK_GUARD(); + a = do_ld_mmio_beN(env, p->full, a, p->addr, size - 8, + mmu_idx, MMU_DATA_LOAD, ra); + b = do_ld_mmio_beN(env, p->full, 0, p->addr + 8, 8, + mmu_idx, MMU_DATA_LOAD, ra); return int128_make128(b, a); } @@ -2340,16 +2376,20 @@ static uint8_t do_ld_1(CPUArchState *env, MMULookupPageData *p, int mmu_idx, static uint16_t do_ld_2(CPUArchState *env, MMULookupPageData *p, int mmu_idx, MMUAccessType type, MemOp memop, uintptr_t ra) { - uint64_t ret; + uint16_t ret; if (unlikely(p->flags & TLB_MMIO)) { - return io_readx(env, p->full, mmu_idx, p->addr, ra, type, memop); - } - - /* Perform the load host endian, then swap if necessary. */ - ret = load_atom_2(env, ra, p->haddr, memop); - if (memop & MO_BSWAP) { - ret = bswap16(ret); + QEMU_IOTHREAD_LOCK_GUARD(); + ret = do_ld_mmio_beN(env, p->full, 0, p->addr, 2, mmu_idx, type, ra); + if ((memop & MO_BSWAP) == MO_LE) { + ret = bswap16(ret); + } + } else { + /* Perform the load host endian, then swap if necessary. */ + ret = load_atom_2(env, ra, p->haddr, memop); + if (memop & MO_BSWAP) { + ret = bswap16(ret); + } } return ret; } @@ -2360,13 +2400,17 @@ static uint32_t do_ld_4(CPUArchState *env, MMULookupPageData *p, int mmu_idx, uint32_t ret; if (unlikely(p->flags & TLB_MMIO)) { - return io_readx(env, p->full, mmu_idx, p->addr, ra, type, memop); - } - - /* Perform the load host endian. */ - ret = load_atom_4(env, ra, p->haddr, memop); - if (memop & MO_BSWAP) { - ret = bswap32(ret); + QEMU_IOTHREAD_LOCK_GUARD(); + ret = do_ld_mmio_beN(env, p->full, 0, p->addr, 4, mmu_idx, type, ra); + if ((memop & MO_BSWAP) == MO_LE) { + ret = bswap32(ret); + } + } else { + /* Perform the load host endian. */ + ret = load_atom_4(env, ra, p->haddr, memop); + if (memop & MO_BSWAP) { + ret = bswap32(ret); + } } return ret; } @@ -2377,13 +2421,17 @@ static uint64_t do_ld_8(CPUArchState *env, MMULookupPageData *p, int mmu_idx, uint64_t ret; if (unlikely(p->flags & TLB_MMIO)) { - return io_readx(env, p->full, mmu_idx, p->addr, ra, type, memop); - } - - /* Perform the load host endian. */ - ret = load_atom_8(env, ra, p->haddr, memop); - if (memop & MO_BSWAP) { - ret = bswap64(ret); + QEMU_IOTHREAD_LOCK_GUARD(); + ret = do_ld_mmio_beN(env, p->full, 0, p->addr, 8, mmu_idx, type, ra); + if ((memop & MO_BSWAP) == MO_LE) { + ret = bswap64(ret); + } + } else { + /* Perform the load host endian. */ + ret = load_atom_8(env, ra, p->haddr, memop); + if (memop & MO_BSWAP) { + ret = bswap64(ret); + } } return ret; } @@ -2531,20 +2579,22 @@ static Int128 do_ld16_mmu(CPUArchState *env, vaddr addr, cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD, &l); if (likely(!crosspage)) { - /* Perform the load host endian. */ if (unlikely(l.page[0].flags & TLB_MMIO)) { QEMU_IOTHREAD_LOCK_GUARD(); - a = io_readx(env, l.page[0].full, l.mmu_idx, addr, - ra, MMU_DATA_LOAD, MO_64); - b = io_readx(env, l.page[0].full, l.mmu_idx, addr + 8, - ra, MMU_DATA_LOAD, MO_64); - ret = int128_make128(HOST_BIG_ENDIAN ? b : a, - HOST_BIG_ENDIAN ? a : b); + a = do_ld_mmio_beN(env, l.page[0].full, 0, addr, 8, + l.mmu_idx, MMU_DATA_LOAD, ra); + b = do_ld_mmio_beN(env, l.page[0].full, 0, addr + 8, 8, + l.mmu_idx, MMU_DATA_LOAD, ra); + ret = int128_make128(b, a); + if ((l.memop & MO_BSWAP) == MO_LE) { + ret = bswap128(ret); + } } else { + /* Perform the load host endian. */ ret = load_atom_16(env, ra, l.page[0].haddr, l.memop); - } - if (l.memop & MO_BSWAP) { - ret = bswap128(ret); + if (l.memop & MO_BSWAP) { + ret = bswap128(ret); + } } return ret; } @@ -2664,26 +2714,57 @@ Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, /** * do_st_mmio_leN: * @env: cpu context - * @p: translation parameters + * @full: page parameters * @val_le: data to store + * @addr: virtual address + * @size: number of bytes * @mmu_idx: virtual address context * @ra: return address into tcg generated code, or 0 + * Context: iothread lock held * - * Store @p->size bytes at @p->addr, which is memory-mapped i/o. + * Store @size bytes at @addr, which is memory-mapped i/o. * The bytes to store are extracted in little-endian order from @val_le; * return the bytes of @val_le beyond @p->size that have not been stored. */ -static uint64_t do_st_mmio_leN(CPUArchState *env, MMULookupPageData *p, - uint64_t val_le, int mmu_idx, uintptr_t ra) +static uint64_t do_st_mmio_leN(CPUArchState *env, CPUTLBEntryFull *full, + uint64_t val_le, vaddr addr, int size, + int mmu_idx, uintptr_t ra) { - CPUTLBEntryFull *full = p->full; - vaddr addr = p->addr; - int i, size = p->size; + tcg_debug_assert(size > 0 && size <= 8); + + do { + /* Store aligned pieces up to 8 bytes. */ + switch ((size | (int)addr) & 7) { + case 1: + case 3: + case 5: + case 7: + io_writex(env, full, mmu_idx, val_le, addr, ra, MO_UB); + val_le >>= 8; + size -= 1; + addr += 1; + break; + case 2: + case 6: + io_writex(env, full, mmu_idx, val_le, addr, ra, MO_LEUW); + val_le >>= 16; + size -= 2; + addr += 2; + break; + case 4: + io_writex(env, full, mmu_idx, val_le, addr, ra, MO_LEUL); + val_le >>= 32; + size -= 4; + addr += 4; + break; + case 0: + io_writex(env, full, mmu_idx, val_le, addr, ra, MO_LEUQ); + return 0; + default: + qemu_build_not_reached(); + } + } while (size); - QEMU_IOTHREAD_LOCK_GUARD(); - for (i = 0; i < size; i++, val_le >>= 8) { - io_writex(env, full, mmu_idx, val_le, addr + i, ra, MO_UB); - } return val_le; } @@ -2698,7 +2779,9 @@ static uint64_t do_st_leN(CPUArchState *env, MMULookupPageData *p, unsigned tmp, half_size; if (unlikely(p->flags & TLB_MMIO)) { - return do_st_mmio_leN(env, p, val_le, mmu_idx, ra); + QEMU_IOTHREAD_LOCK_GUARD(); + return do_st_mmio_leN(env, p->full, val_le, p->addr, + p->size, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { return val_le >> (p->size * 8); } @@ -2751,11 +2834,11 @@ static uint64_t do_st16_leN(CPUArchState *env, MMULookupPageData *p, MemOp atom; if (unlikely(p->flags & TLB_MMIO)) { - p->size = 8; - do_st_mmio_leN(env, p, int128_getlo(val_le), mmu_idx, ra); - p->size = size - 8; - p->addr += 8; - return do_st_mmio_leN(env, p, int128_gethi(val_le), mmu_idx, ra); + QEMU_IOTHREAD_LOCK_GUARD(); + do_st_mmio_leN(env, p->full, int128_getlo(val_le), + p->addr, 8, mmu_idx, ra); + return do_st_mmio_leN(env, p->full, int128_gethi(val_le), + p->addr + 8, size - 8, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { return int128_gethi(val_le) >> ((size - 8) * 8); } @@ -2811,7 +2894,11 @@ static void do_st_2(CPUArchState *env, MMULookupPageData *p, uint16_t val, int mmu_idx, MemOp memop, uintptr_t ra) { if (unlikely(p->flags & TLB_MMIO)) { - io_writex(env, p->full, mmu_idx, val, p->addr, ra, memop); + if ((memop & MO_BSWAP) != MO_LE) { + val = bswap16(val); + } + QEMU_IOTHREAD_LOCK_GUARD(); + do_st_mmio_leN(env, p->full, val, p->addr, 2, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { @@ -2827,7 +2914,11 @@ static void do_st_4(CPUArchState *env, MMULookupPageData *p, uint32_t val, int mmu_idx, MemOp memop, uintptr_t ra) { if (unlikely(p->flags & TLB_MMIO)) { - io_writex(env, p->full, mmu_idx, val, p->addr, ra, memop); + if ((memop & MO_BSWAP) != MO_LE) { + val = bswap32(val); + } + QEMU_IOTHREAD_LOCK_GUARD(); + do_st_mmio_leN(env, p->full, val, p->addr, 4, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { @@ -2843,7 +2934,11 @@ static void do_st_8(CPUArchState *env, MMULookupPageData *p, uint64_t val, int mmu_idx, MemOp memop, uintptr_t ra) { if (unlikely(p->flags & TLB_MMIO)) { - io_writex(env, p->full, mmu_idx, val, p->addr, ra, memop); + if ((memop & MO_BSWAP) != MO_LE) { + val = bswap64(val); + } + QEMU_IOTHREAD_LOCK_GUARD(); + do_st_mmio_leN(env, p->full, val, p->addr, 8, mmu_idx, ra); } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { @@ -2966,22 +3061,22 @@ static void do_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { - /* Swap to host endian if necessary, then store. */ - if (l.memop & MO_BSWAP) { - val = bswap128(val); - } if (unlikely(l.page[0].flags & TLB_MMIO)) { - QEMU_IOTHREAD_LOCK_GUARD(); - if (HOST_BIG_ENDIAN) { - b = int128_getlo(val), a = int128_gethi(val); - } else { - a = int128_getlo(val), b = int128_gethi(val); + if ((l.memop & MO_BSWAP) != MO_LE) { + val = bswap128(val); } - io_writex(env, l.page[0].full, l.mmu_idx, a, addr, ra, MO_64); - io_writex(env, l.page[0].full, l.mmu_idx, b, addr + 8, ra, MO_64); + a = int128_getlo(val); + b = int128_gethi(val); + QEMU_IOTHREAD_LOCK_GUARD(); + do_st_mmio_leN(env, l.page[0].full, a, addr, 8, l.mmu_idx, ra); + do_st_mmio_leN(env, l.page[0].full, b, addr + 8, 8, l.mmu_idx, ra); } else if (unlikely(l.page[0].flags & TLB_DISCARD_WRITE)) { /* nothing */ } else { + /* Swap to host endian if necessary, then store. */ + if (l.memop & MO_BSWAP) { + val = bswap128(val); + } store_atom_16(env, ra, l.page[0].haddr, l.memop, val); } return; diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index b62a69bd07..8e148a2ea3 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -214,8 +214,6 @@ static int mmap_frag(abi_ulong real_start, #endif abi_ulong mmap_next_start = TASK_UNMAPPED_BASE; -unsigned long last_brk; - /* * Subroutine of mmap_find_vma, used when we have pre-allocated a chunk of guest * address space. diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index edf9602f9b..8f2d6a3c78 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -232,7 +232,6 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, abi_ulong new_size, unsigned long flags, abi_ulong new_addr); int target_msync(abi_ulong start, abi_ulong len, int flags); -extern unsigned long last_brk; extern abi_ulong mmap_next_start; abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size); void TSA_NO_TSA mmap_fork_start(void); diff --git a/configure b/configure index afb25fd558..98dc78280e 100755 --- a/configure +++ b/configure @@ -469,6 +469,13 @@ else echo "WARNING: unrecognized host CPU, proceeding with 'uname -m' output '$cpu'" fi +case "$cpu" in + riscv*) + host_arch=riscv ;; + *) + host_arch="$cpu" ;; +esac + # Normalise host CPU name and set multilib cflags. The canonicalization # isn't really necessary, because the architectures that we check for # should not hit the 'uname -m' case, but better safe than sorry. @@ -803,7 +810,7 @@ default_target_list="" mak_wilds="" if [ "$linux_user" != no ]; then - if [ "$targetos" = linux ] && [ -d "$source_path/linux-user/include/host/$cpu" ]; then + if [ "$targetos" = linux ] && [ -d "$source_path/linux-user/include/host/$host_arch" ]; then linux_user=yes elif [ "$linux_user" = yes ]; then error_exit "linux-user not supported on this architecture" diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index ce8b42eb15..e74ecc78cc 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -537,7 +537,7 @@ static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf, /* Skip '.' */ buf++; } else { - p = 1; + p = 0; } ret = qemu_strtoul(buf, &buf, 16, &t); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 861ec07abc..36e4026f05 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1710,7 +1710,8 @@ static uint32_t get_elf_hwcap(void) #define MISA_BIT(EXT) (1 << (EXT - 'A')) RISCVCPU *cpu = RISCV_CPU(thread_cpu); uint32_t mask = MISA_BIT('I') | MISA_BIT('M') | MISA_BIT('A') - | MISA_BIT('F') | MISA_BIT('D') | MISA_BIT('C'); + | MISA_BIT('F') | MISA_BIT('D') | MISA_BIT('C') + | MISA_BIT('V'); return cpu->env.misa_ext & mask; #undef MISA_BIT @@ -3678,8 +3679,8 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) * to mmap pages in this space. */ if (info->reserve_brk) { - abi_ulong start_brk = HOST_PAGE_ALIGN(info->brk); - abi_ulong end_brk = HOST_PAGE_ALIGN(info->brk + info->reserve_brk); + abi_ulong start_brk = TARGET_PAGE_ALIGN(info->brk); + abi_ulong end_brk = TARGET_PAGE_ALIGN(info->brk + info->reserve_brk); target_munmap(start_brk, end_brk - start_brk); } diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 5efec2630e..8f5e9f489b 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -811,7 +811,7 @@ int load_flt_binary(struct linux_binprm *bprm, struct image_info *info) info->end_code = libinfo[0].start_code + libinfo[0].text_len; info->start_data = libinfo[0].start_data; info->end_data = libinfo[0].end_data; - info->start_brk = libinfo[0].start_brk; + info->brk = libinfo[0].start_brk; info->start_stack = sp; info->stack_limit = libinfo[0].start_brk; info->entry = start_addr; diff --git a/linux-user/main.c b/linux-user/main.c index dba67ffa36..556956c363 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -920,8 +920,6 @@ int main(int argc, char **argv, char **envp) fprintf(f, "page layout changed following binary load\n"); page_dump(f); - fprintf(f, "start_brk 0x" TARGET_ABI_FMT_lx "\n", - info->start_brk); fprintf(f, "end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code); fprintf(f, "start_code 0x" TARGET_ABI_FMT_lx "\n", diff --git a/linux-user/mmap.c b/linux-user/mmap.c index a5dfb56545..eb04fab8ab 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -263,7 +263,11 @@ static bool mmap_frag(abi_ulong real_start, abi_ulong start, abi_ulong last, void *p = mmap(host_start, qemu_host_page_size, target_to_host_prot(prot), flags | MAP_ANONYMOUS, -1, 0); - if (p == MAP_FAILED) { + if (p != host_start) { + if (p != MAP_FAILED) { + munmap(p, qemu_host_page_size); + errno = EEXIST; + } return false; } prot_old = prot; @@ -310,8 +314,6 @@ static bool mmap_frag(abi_ulong real_start, abi_ulong start, abi_ulong last, #endif abi_ulong mmap_next_start = TASK_UNMAPPED_BASE; -unsigned long last_brk; - /* * Subroutine of mmap_find_vma, used when we have pre-allocated * a chunk of guest address space. @@ -603,11 +605,26 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, goto fail; } - /* Validate that the chosen range is empty. */ - if ((flags & MAP_FIXED_NOREPLACE) - && !page_check_range_empty(start, last)) { - errno = EEXIST; - goto fail; + if (flags & MAP_FIXED_NOREPLACE) { + /* Validate that the chosen range is empty. */ + if (!page_check_range_empty(start, last)) { + errno = EEXIST; + goto fail; + } + + /* + * With reserved_va, the entire address space is mmaped in the + * host to ensure it isn't accidentally used for something else. + * We have just checked that the guest address is not mapped + * within the guest, but need to replace the host reservation. + * + * Without reserved_va, despite the guest address check above, + * keep MAP_FIXED_NOREPLACE so that the guest does not overwrite + * any host address mappings. + */ + if (reserved_va) { + flags = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED; + } } /* @@ -672,17 +689,25 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, /* map the middle (easier) */ if (real_start < real_last) { - void *p; + void *p, *want_p; off_t offset1; + size_t len1; if (flags & MAP_ANONYMOUS) { offset1 = 0; } else { offset1 = offset + real_start - start; } - p = mmap(g2h_untagged(real_start), real_last - real_start + 1, - target_to_host_prot(target_prot), flags, fd, offset1); - if (p == MAP_FAILED) { + len1 = real_last - real_start + 1; + want_p = g2h_untagged(real_start); + + p = mmap(want_p, len1, target_to_host_prot(target_prot), + flags, fd, offset1); + if (p != want_p) { + if (p != MAP_FAILED) { + munmap(p, len1); + errno = EEXIST; + } goto fail; } passthrough_start = real_start; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 802794db63..2046a23037 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -29,7 +29,6 @@ struct image_info { abi_ulong end_code; abi_ulong start_data; abi_ulong end_data; - abi_ulong start_brk; abi_ulong brk; abi_ulong reserve_brk; abi_ulong start_mmap; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 95727a816a..7c2c2f6e2f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -802,93 +802,52 @@ static inline int host_to_target_sock_type(int host_type) } static abi_ulong target_brk, initial_target_brk; -static abi_ulong brk_page; void target_set_brk(abi_ulong new_brk) { target_brk = TARGET_PAGE_ALIGN(new_brk); initial_target_brk = target_brk; - brk_page = HOST_PAGE_ALIGN(target_brk); } /* do_brk() must return target values and target errnos. */ abi_long do_brk(abi_ulong brk_val) { abi_long mapped_addr; - abi_ulong new_alloc_size; - abi_ulong new_brk, new_host_brk_page; + abi_ulong new_brk; + abi_ulong old_brk; /* brk pointers are always untagged */ - /* return old brk value if brk_val unchanged or zero */ - if (!brk_val || brk_val == target_brk) { + /* do not allow to shrink below initial brk value */ + if (brk_val < initial_target_brk) { return target_brk; } - /* do not allow to shrink below initial brk value */ - if (brk_val < initial_target_brk) { - brk_val = initial_target_brk; - } - new_brk = TARGET_PAGE_ALIGN(brk_val); - new_host_brk_page = HOST_PAGE_ALIGN(brk_val); + old_brk = TARGET_PAGE_ALIGN(target_brk); - /* brk_val and old target_brk might be on the same page */ - if (new_brk == TARGET_PAGE_ALIGN(target_brk)) { - /* empty remaining bytes in (possibly larger) host page */ - memset(g2h_untagged(new_brk), 0, new_host_brk_page - new_brk); + /* new and old target_brk might be on the same page */ + if (new_brk == old_brk) { target_brk = brk_val; return target_brk; } /* Release heap if necesary */ - if (new_brk < target_brk) { - /* empty remaining bytes in (possibly larger) host page */ - memset(g2h_untagged(new_brk), 0, new_host_brk_page - new_brk); - - /* free unused host pages and set new brk_page */ - target_munmap(new_host_brk_page, brk_page - new_host_brk_page); - brk_page = new_host_brk_page; + if (new_brk < old_brk) { + target_munmap(new_brk, old_brk - new_brk); target_brk = brk_val; return target_brk; } - /* We need to allocate more memory after the brk... Note that - * we don't use MAP_FIXED because that will map over the top of - * any existing mapping (like the one with the host libc or qemu - * itself); instead we treat "mapped but at wrong address" as - * a failure and unmap again. - */ - if (new_host_brk_page > brk_page) { - new_alloc_size = new_host_brk_page - brk_page; - mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, - PROT_READ|PROT_WRITE, - MAP_ANON|MAP_PRIVATE, 0, 0)); - } else { - new_alloc_size = 0; - mapped_addr = brk_page; - } - - if (mapped_addr == brk_page) { - /* Heap contents are initialized to zero, as for anonymous - * mapped pages. Technically the new pages are already - * initialized to zero since they *are* anonymous mapped - * pages, however we have to take care with the contents that - * come from the remaining part of the previous page: it may - * contains garbage data due to a previous heap usage (grown - * then shrunken). */ - memset(g2h_untagged(brk_page), 0, HOST_PAGE_ALIGN(brk_page) - brk_page); + mapped_addr = target_mmap(old_brk, new_brk - old_brk, + PROT_READ | PROT_WRITE, + MAP_FIXED_NOREPLACE | MAP_ANON | MAP_PRIVATE, + -1, 0); + if (mapped_addr == old_brk) { target_brk = brk_val; - brk_page = new_host_brk_page; return target_brk; - } else if (mapped_addr != -1) { - /* Mapped but at wrong address, meaning there wasn't actually - * enough space for this brk. - */ - target_munmap(mapped_addr, new_alloc_size); - mapped_addr = -1; } #if defined(TARGET_ALPHA) diff --git a/linux-user/user-mmap.h b/linux-user/user-mmap.h index 3fc986f92f..7265c2c116 100644 --- a/linux-user/user-mmap.h +++ b/linux-user/user-mmap.h @@ -26,7 +26,6 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, abi_ulong new_size, unsigned long flags, abi_ulong new_addr); abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice); -extern unsigned long last_brk; extern abi_ulong mmap_next_start; abi_ulong mmap_find_vma(abi_ulong, abi_ulong, abi_ulong); void mmap_fork_start(void);