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-----

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>
This commit is contained in:
Richard Henderson 2023-08-06 16:47:48 -07:00
commit 9400601a68
12 changed files with 257 additions and 177 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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);

9
configure vendored
View File

@ -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"

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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",

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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);