Merge tag 'pull-tcg-20230806-3' of https://gitlab.com/rth7680/qemu into staging
accel/tcg: Do not issue misaligned i/o
accel/tcg: Call save_iotlb_data from io_readx
gdbstub: use 0 ("any process") on packets with no PID
linux-user: Fixes for MAP_FIXED_NOREPLACE
linux-user: Fixes for brk
linux-user: Set V in ELF_HWCAP for RISC-V
*-user: Remove last_brk as unused
# -----BEGIN PGP SIGNATURE-----
#
# iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmTQMPsdHHJpY2hhcmQu
# aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/rmQf/az6d6X4iom0Hch19
# U4BkoNP7NQB2Rue/avjP6Vy6yATDEPgIA5vcPcub+jYsCyEasRRCD1d4odxZp7Cr
# MLoeX6dC+iGg0N7i3S1DSpZBqsRv/4+YE5ibPjYnZlv0F7re1L89yw4doj5OPN1w
# 1p8bpTxA2+s/FOxgfKLSyZR4yMJ4jWKeH+em6qjEBXEAMSiE6u0S+Kt3bAO8amdo
# 86e5d16F4sjs4kXMTEp9myNoXN/aRsWd1stzebQK+uV6qQQsdkIkMLZmZ8+o158A
# QEuWpV8yoMxhXUsnjkNGbL5S3r2WDJpM6WbWxtjs1xOAaygYCOicXh+sqRefgyH/
# 0NQQRw==
# =4I5/
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun 06 Aug 2023 04:47:07 PM PDT
# gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg: issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate]
* tag 'pull-tcg-20230806-3' of https://gitlab.com/rth7680/qemu:
bsd-user: Remove last_brk
linux-user: Remove last_brk
linux-user: Properly set image_info.brk in flatload
linux-user: Do not align brk with host page size
linux-user: Do nothing if too small brk is specified
linux-user: Use MAP_FIXED_NOREPLACE for do_brk()
linux-user: Do not call get_errno() in do_brk()
linux-user: Fix MAP_FIXED_NOREPLACE on old kernels
linux-user: Unset MAP_FIXED_NOREPLACE for host
linux-user/elfload: Set V in ELF_HWCAP for RISC-V
configure: Fix linux-user host detection for riscv64
gdbstub: use 0 ("any process") on packets with no PID
accel/tcg: Call save_iotlb_data from io_readx as well
accel/tcg: Do not issue misaligned i/o
accel/tcg: Issue wider aligned i/o in do_{ld,st}_mmio_*
accel/tcg: Adjust parameters and locking with do_{ld,st}_mmio_*
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index ba44501..d68fa68 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1363,6 +1363,21 @@
}
}
+/*
+ * 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 @@
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 @@
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 @@
/**
* 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 @@
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 @@
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 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 @@
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 @@
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 @@
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 @@
/**
* 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);
- 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);
- }
+ 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);
+
return val_le;
}
@@ -2698,7 +2779,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 b62a69b..8e148a2 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -214,8 +214,6 @@
#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 edf9602..8f2d6a3 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -232,7 +232,6 @@
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 afb25fd..98dc782 100755
--- a/configure
+++ b/configure
@@ -469,6 +469,13 @@
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 @@
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 ce8b42e..e74ecc7 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -537,7 +537,7 @@
/* 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 861ec07..36e4026 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1710,7 +1710,8 @@
#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 @@
* 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 5efec26..8f5e9f4 100644
--- a/linux-user/flatload.c
+++ b/linux-user/flatload.c
@@ -811,7 +811,7 @@
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 dba67ff..556956c 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -920,8 +920,6 @@
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 a5dfb56..eb04fab 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -263,7 +263,11 @@
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 @@
#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 @@
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 @@
/* 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 802794d..2046a23 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -29,7 +29,6 @@
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 95727a8..7c2c2f6 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -802,93 +802,52 @@
}
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;
- }
+ 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 == 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);
-
+ 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 3fc986f..7265c2c 100644
--- a/linux-user/user-mmap.h
+++ b/linux-user/user-mmap.h
@@ -26,7 +26,6 @@
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);