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:
commit
9400601a68
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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
9
configure
vendored
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user