mirror of
https://github.com/qemu/qemu.git
synced 2024-12-12 21:23:36 +08:00
target/i386/tcg: Enable page walking from MMIO memory
CXL emulation of interleave requires read and write hooks due to requirement for subpage granularity. The Linux kernel stack now enables using this memory as conventional memory in a separate NUMA node. If a process is deliberately forced to run from that node $ numactl --membind=1 ls the page table walk on i386 fails. Useful part of backtrace: (cpu=cpu@entry=0x555556fd9000, fmt=fmt@entry=0x555555fe3378 "cpu_io_recompile: could not find TB for pc=%p") at ../../cpu-target.c:359 (retaddr=0, addr=19595792376, attrs=..., xlat=<optimized out>, cpu=0x555556fd9000, out_offset=<synthetic pointer>) at ../../accel/tcg/cputlb.c:1339 (cpu=0x555556fd9000, full=0x7fffee0d96e0, ret_be=ret_be@entry=0, addr=19595792376, size=size@entry=8, mmu_idx=4, type=MMU_DATA_LOAD, ra=0) at ../../accel/tcg/cputlb.c:2030 (cpu=cpu@entry=0x555556fd9000, p=p@entry=0x7ffff56fddc0, mmu_idx=<optimized out>, type=type@entry=MMU_DATA_LOAD, memop=<optimized out>, ra=ra@entry=0) at ../../accel/tcg/cputlb.c:2356 (cpu=cpu@entry=0x555556fd9000, addr=addr@entry=19595792376, oi=oi@entry=52, ra=ra@entry=0, access_type=access_type@entry=MMU_DATA_LOAD) at ../../accel/tcg/cputlb.c:2439 at ../../accel/tcg/ldst_common.c.inc:301 at ../../target/i386/tcg/sysemu/excp_helper.c:173 (err=0x7ffff56fdf80, out=0x7ffff56fdf70, mmu_idx=0, access_type=MMU_INST_FETCH, addr=18446744072116178925, env=0x555556fdb7c0) at ../../target/i386/tcg/sysemu/excp_helper.c:578 (cs=0x555556fd9000, addr=18446744072116178925, size=<optimized out>, access_type=MMU_INST_FETCH, mmu_idx=0, probe=<optimized out>, retaddr=0) at ../../target/i386/tcg/sysemu/excp_helper.c:604 Avoid this by plumbing the address all the way down from x86_cpu_tlb_fill() where is available as retaddr to the actual accessors which provide it to probe_access_full() which already handles MMIO accesses. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2180 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2220 Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Suggested-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Gregory Price <gregory.price@memverge.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Message-ID: <20240307155304.31241-2-Jonathan.Cameron@huawei.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
This commit is contained in:
parent
096ae430a7
commit
9dab7bbb01
@ -59,14 +59,14 @@ typedef struct PTETranslate {
|
||||
hwaddr gaddr;
|
||||
} PTETranslate;
|
||||
|
||||
static bool ptw_translate(PTETranslate *inout, hwaddr addr)
|
||||
static bool ptw_translate(PTETranslate *inout, hwaddr addr, uint64_t ra)
|
||||
{
|
||||
CPUTLBEntryFull *full;
|
||||
int flags;
|
||||
|
||||
inout->gaddr = addr;
|
||||
flags = probe_access_full(inout->env, addr, 0, MMU_DATA_STORE,
|
||||
inout->ptw_idx, true, &inout->haddr, &full, 0);
|
||||
inout->ptw_idx, true, &inout->haddr, &full, ra);
|
||||
|
||||
if (unlikely(flags & TLB_INVALID_MASK)) {
|
||||
TranslateFault *err = inout->err;
|
||||
@ -82,20 +82,20 @@ static bool ptw_translate(PTETranslate *inout, hwaddr addr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline uint32_t ptw_ldl(const PTETranslate *in)
|
||||
static inline uint32_t ptw_ldl(const PTETranslate *in, uint64_t ra)
|
||||
{
|
||||
if (likely(in->haddr)) {
|
||||
return ldl_p(in->haddr);
|
||||
}
|
||||
return cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0);
|
||||
return cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, ra);
|
||||
}
|
||||
|
||||
static inline uint64_t ptw_ldq(const PTETranslate *in)
|
||||
static inline uint64_t ptw_ldq(const PTETranslate *in, uint64_t ra)
|
||||
{
|
||||
if (likely(in->haddr)) {
|
||||
return ldq_p(in->haddr);
|
||||
}
|
||||
return cpu_ldq_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0);
|
||||
return cpu_ldq_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, ra);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -132,7 +132,8 @@ static inline bool ptw_setl(const PTETranslate *in, uint32_t old, uint32_t set)
|
||||
}
|
||||
|
||||
static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
TranslateResult *out, TranslateFault *err)
|
||||
TranslateResult *out, TranslateFault *err,
|
||||
uint64_t ra)
|
||||
{
|
||||
const target_ulong addr = in->addr;
|
||||
const int pg_mode = in->pg_mode;
|
||||
@ -164,11 +165,11 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 5
|
||||
*/
|
||||
pte_addr = (in->cr3 & ~0xfff) + (((addr >> 48) & 0x1ff) << 3);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
restart_5:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@ -188,11 +189,11 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 4
|
||||
*/
|
||||
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 39) & 0x1ff) << 3);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
restart_4:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@ -208,11 +209,11 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 3
|
||||
*/
|
||||
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
restart_3_lma:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@ -235,12 +236,12 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 3
|
||||
*/
|
||||
pte_addr = (in->cr3 & 0xffffffe0ULL) + ((addr >> 27) & 0x18);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
rsvd_mask |= PG_HI_USER_MASK;
|
||||
restart_3_nolma:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@ -257,11 +258,11 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 2
|
||||
*/
|
||||
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
restart_2_pae:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@ -283,10 +284,10 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 1
|
||||
*/
|
||||
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
pte = ptw_ldq(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@ -301,11 +302,11 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 2
|
||||
*/
|
||||
pte_addr = (in->cr3 & 0xfffff000ULL) + ((addr >> 20) & 0xffc);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
restart_2_nopae:
|
||||
pte = ptw_ldl(&pte_trans);
|
||||
pte = ptw_ldl(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@ -330,10 +331,10 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
|
||||
* Page table level 1
|
||||
*/
|
||||
pte_addr = (pte & ~0xfffu) + ((addr >> 10) & 0xffc);
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
if (!ptw_translate(&pte_trans, pte_addr, ra)) {
|
||||
return false;
|
||||
}
|
||||
pte = ptw_ldl(&pte_trans);
|
||||
pte = ptw_ldl(&pte_trans, ra);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
@ -526,7 +527,8 @@ static G_NORETURN void raise_stage2(CPUX86State *env, TranslateFault *err,
|
||||
|
||||
static bool get_physical_address(CPUX86State *env, vaddr addr,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
TranslateResult *out, TranslateFault *err)
|
||||
TranslateResult *out, TranslateFault *err,
|
||||
uint64_t ra)
|
||||
{
|
||||
TranslateParams in;
|
||||
bool use_stage2 = env->hflags2 & HF2_NPT_MASK;
|
||||
@ -546,7 +548,7 @@ static bool get_physical_address(CPUX86State *env, vaddr addr,
|
||||
env->nested_pg_mode & PG_MODE_LMA ? MMU_USER64_IDX : MMU_USER32_IDX;
|
||||
in.ptw_idx = MMU_PHYS_IDX;
|
||||
|
||||
if (!mmu_translate(env, &in, out, err)) {
|
||||
if (!mmu_translate(env, &in, out, err, ra)) {
|
||||
err->stage2 = S2_GPA;
|
||||
return false;
|
||||
}
|
||||
@ -577,7 +579,7 @@ static bool get_physical_address(CPUX86State *env, vaddr addr,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return mmu_translate(env, &in, out, err);
|
||||
return mmu_translate(env, &in, out, err, ra);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -597,7 +599,8 @@ bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
|
||||
TranslateResult out;
|
||||
TranslateFault err;
|
||||
|
||||
if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err)) {
|
||||
if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err,
|
||||
retaddr)) {
|
||||
/*
|
||||
* Even if 4MB pages, we map only one 4KB page in the cache to
|
||||
* avoid filling it too fast.
|
||||
|
Loading…
Reference in New Issue
Block a user