mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20190510' into staging
Add CPUClass::tlb_fill. Improve tlb_vaddr_to_host for use by ARM SVE no-fault loads. # gpg: Signature made Fri 10 May 2019 19:48:37 BST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-tcg-20190510: (27 commits) tcg: Use tlb_fill probe from tlb_vaddr_to_host tcg: Remove CPUClass::handle_mmu_fault tcg: Use CPUClass::tlb_fill in cputlb.c target/xtensa: Convert to CPUClass::tlb_fill target/unicore32: Convert to CPUClass::tlb_fill target/tricore: Convert to CPUClass::tlb_fill target/tilegx: Convert to CPUClass::tlb_fill target/sparc: Convert to CPUClass::tlb_fill target/sh4: Convert to CPUClass::tlb_fill target/s390x: Convert to CPUClass::tlb_fill target/riscv: Convert to CPUClass::tlb_fill target/ppc: Convert to CPUClass::tlb_fill target/openrisc: Convert to CPUClass::tlb_fill target/nios2: Convert to CPUClass::tlb_fill target/moxie: Convert to CPUClass::tlb_fill target/mips: Convert to CPUClass::tlb_fill target/mips: Tidy control flow in mips_cpu_handle_mmu_fault target/mips: Pass a valid error to raise_mmu_exception for user-only target/microblaze: Convert to CPUClass::tlb_fill target/m68k: Convert to CPUClass::tlb_fill ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+80
-8
@@ -855,6 +855,25 @@ static inline ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
|
||||
return ram_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: tlb_fill() can trigger a resize of the TLB. This means that all of the
|
||||
* caller's prior references to the TLB table (e.g. CPUTLBEntry pointers) must
|
||||
* be discarded and looked up again (e.g. via tlb_entry()).
|
||||
*/
|
||||
static void tlb_fill(CPUState *cpu, target_ulong addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
bool ok;
|
||||
|
||||
/*
|
||||
* This is not a probe, so only valid return is success; failure
|
||||
* should result in exception + longjmp to the cpu loop.
|
||||
*/
|
||||
ok = cc->tlb_fill(cpu, addr, size, access_type, mmu_idx, false, retaddr);
|
||||
assert(ok);
|
||||
}
|
||||
|
||||
static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
|
||||
int mmu_idx, target_ulong addr, uintptr_t retaddr,
|
||||
MMUAccessType access_type, int size)
|
||||
@@ -938,6 +957,16 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
|
||||
}
|
||||
}
|
||||
|
||||
static inline target_ulong tlb_read_ofs(CPUTLBEntry *entry, size_t ofs)
|
||||
{
|
||||
#if TCG_OVERSIZED_GUEST
|
||||
return *(target_ulong *)((uintptr_t)entry + ofs);
|
||||
#else
|
||||
/* ofs might correspond to .addr_write, so use atomic_read */
|
||||
return atomic_read((target_ulong *)((uintptr_t)entry + ofs));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return true if ADDR is present in the victim tlb, and has been copied
|
||||
back to the main tlb. */
|
||||
static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index,
|
||||
@@ -948,14 +977,7 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index,
|
||||
assert_cpu_is_self(ENV_GET_CPU(env));
|
||||
for (vidx = 0; vidx < CPU_VTLB_SIZE; ++vidx) {
|
||||
CPUTLBEntry *vtlb = &env->tlb_v_table[mmu_idx][vidx];
|
||||
target_ulong cmp;
|
||||
|
||||
/* elt_ofs might correspond to .addr_write, so use atomic_read */
|
||||
#if TCG_OVERSIZED_GUEST
|
||||
cmp = *(target_ulong *)((uintptr_t)vtlb + elt_ofs);
|
||||
#else
|
||||
cmp = atomic_read((target_ulong *)((uintptr_t)vtlb + elt_ofs));
|
||||
#endif
|
||||
target_ulong cmp = tlb_read_ofs(vtlb, elt_ofs);
|
||||
|
||||
if (cmp == page) {
|
||||
/* Found entry in victim tlb, swap tlb and iotlb. */
|
||||
@@ -1039,6 +1061,56 @@ void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx,
|
||||
}
|
||||
}
|
||||
|
||||
void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
|
||||
MMUAccessType access_type, int mmu_idx)
|
||||
{
|
||||
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
|
||||
uintptr_t tlb_addr, page;
|
||||
size_t elt_ofs;
|
||||
|
||||
switch (access_type) {
|
||||
case MMU_DATA_LOAD:
|
||||
elt_ofs = offsetof(CPUTLBEntry, addr_read);
|
||||
break;
|
||||
case MMU_DATA_STORE:
|
||||
elt_ofs = offsetof(CPUTLBEntry, addr_write);
|
||||
break;
|
||||
case MMU_INST_FETCH:
|
||||
elt_ofs = offsetof(CPUTLBEntry, addr_code);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
page = addr & TARGET_PAGE_MASK;
|
||||
tlb_addr = tlb_read_ofs(entry, elt_ofs);
|
||||
|
||||
if (!tlb_hit_page(tlb_addr, page)) {
|
||||
uintptr_t index = tlb_index(env, mmu_idx, addr);
|
||||
|
||||
if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs, page)) {
|
||||
CPUState *cs = ENV_GET_CPU(env);
|
||||
CPUClass *cc = CPU_GET_CLASS(cs);
|
||||
|
||||
if (!cc->tlb_fill(cs, addr, 0, access_type, mmu_idx, true, 0)) {
|
||||
/* Non-faulting page table read failed. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* TLB resize via tlb_fill may have moved the entry. */
|
||||
entry = tlb_entry(env, mmu_idx, addr);
|
||||
}
|
||||
tlb_addr = tlb_read_ofs(entry, elt_ofs);
|
||||
}
|
||||
|
||||
if (tlb_addr & ~TARGET_PAGE_MASK) {
|
||||
/* IO access */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void *)((uintptr_t)addr + entry->addend);
|
||||
}
|
||||
|
||||
/* Probe for a read-modify-write atomic operation. Do not allow unaligned
|
||||
* operations, or io operations to proceed. Return the host address. */
|
||||
static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
|
||||
|
||||
+9
-27
@@ -63,8 +63,8 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||
{
|
||||
CPUState *cpu = current_cpu;
|
||||
CPUClass *cc;
|
||||
int ret;
|
||||
unsigned long address = (unsigned long)info->si_addr;
|
||||
MMUAccessType access_type;
|
||||
|
||||
/* We must handle PC addresses from two different sources:
|
||||
* a call return address and a signal frame address.
|
||||
@@ -147,35 +147,17 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||
are still valid segv ones */
|
||||
address = h2g_nocheck(address);
|
||||
|
||||
cc = CPU_GET_CLASS(cpu);
|
||||
/* see if it is an MMU fault */
|
||||
g_assert(cc->handle_mmu_fault);
|
||||
ret = cc->handle_mmu_fault(cpu, address, 0, is_write, MMU_USER_IDX);
|
||||
|
||||
if (ret == 0) {
|
||||
/* The MMU fault was handled without causing real CPU fault.
|
||||
* Retain helper_retaddr for a possible second fault.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* All other paths lead to cpu_exit; clear helper_retaddr
|
||||
* for next execution.
|
||||
/*
|
||||
* There is no way the target can handle this other than raising
|
||||
* an exception. Undo signal and retaddr state prior to longjmp.
|
||||
*/
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
helper_retaddr = 0;
|
||||
|
||||
if (ret < 0) {
|
||||
return 0; /* not an MMU fault */
|
||||
}
|
||||
|
||||
/* Now we have a real cpu fault. */
|
||||
cpu_restore_state(cpu, pc, true);
|
||||
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
cpu_loop_exit(cpu);
|
||||
|
||||
/* never comes here */
|
||||
return 1;
|
||||
cc = CPU_GET_CLASS(cpu);
|
||||
access_type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD;
|
||||
cc->tlb_fill(cpu, address, 0, access_type, MMU_USER_IDX, false, pc);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
+10
-40
@@ -433,50 +433,20 @@ static inline CPUTLBEntry *tlb_entry(CPUArchState *env, uintptr_t mmu_idx,
|
||||
* @mmu_idx: MMU index to use for lookup
|
||||
*
|
||||
* Look up the specified guest virtual index in the TCG softmmu TLB.
|
||||
* If the TLB contains a host virtual address suitable for direct RAM
|
||||
* access, then return it. Otherwise (TLB miss, TLB entry is for an
|
||||
* I/O access, etc) return NULL.
|
||||
*
|
||||
* This is the equivalent of the initial fast-path code used by
|
||||
* TCG backends for guest load and store accesses.
|
||||
* If we can translate a host virtual address suitable for direct RAM
|
||||
* access, without causing a guest exception, then return it.
|
||||
* Otherwise (TLB entry is for an I/O access, guest software
|
||||
* TLB fill required, etc) return NULL.
|
||||
*/
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static inline void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
|
||||
int access_type, int mmu_idx)
|
||||
MMUAccessType access_type, int mmu_idx)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
return g2h(addr);
|
||||
#else
|
||||
CPUTLBEntry *tlbentry = tlb_entry(env, mmu_idx, addr);
|
||||
abi_ptr tlb_addr;
|
||||
uintptr_t haddr;
|
||||
|
||||
switch (access_type) {
|
||||
case 0:
|
||||
tlb_addr = tlbentry->addr_read;
|
||||
break;
|
||||
case 1:
|
||||
tlb_addr = tlb_addr_write(tlbentry);
|
||||
break;
|
||||
case 2:
|
||||
tlb_addr = tlbentry->addr_code;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (!tlb_hit(tlb_addr, addr)) {
|
||||
/* TLB entry is for a different page */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tlb_addr & ~TARGET_PAGE_MASK) {
|
||||
/* IO access */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
haddr = addr + tlbentry->addend;
|
||||
return (void *)haddr;
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
}
|
||||
#else
|
||||
void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
|
||||
MMUAccessType access_type, int mmu_idx);
|
||||
#endif
|
||||
|
||||
#endif /* CPU_LDST_H */
|
||||
|
||||
@@ -474,15 +474,6 @@ static inline void assert_no_pages_locked(void)
|
||||
*/
|
||||
struct MemoryRegionSection *iotlb_to_section(CPUState *cpu,
|
||||
hwaddr index, MemTxAttrs attrs);
|
||||
|
||||
/*
|
||||
* Note: tlb_fill() can trigger a resize of the TLB. This means that all of the
|
||||
* caller's prior references to the TLB table (e.g. CPUTLBEntry pointers) must
|
||||
* be discarded and looked up again (e.g. via tlb_entry()).
|
||||
*/
|
||||
void tlb_fill(CPUState *cpu, target_ulong addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
+9
-3
@@ -117,7 +117,12 @@ struct TranslationBlock;
|
||||
* This always includes at least the program counter; some targets
|
||||
* will need to do more. If this hook is not implemented then the
|
||||
* default is to call @set_pc(tb->pc).
|
||||
* @handle_mmu_fault: Callback for handling an MMU fault.
|
||||
* @tlb_fill: Callback for handling a softmmu tlb miss or user-only
|
||||
* address fault. For system mode, if the access is valid, call
|
||||
* tlb_set_page and return true; if the access is invalid, and
|
||||
* probe is true, return false; otherwise raise an exception and
|
||||
* do not return. For user-only mode, always raise an exception
|
||||
* and do not return.
|
||||
* @get_phys_page_debug: Callback for obtaining a physical address.
|
||||
* @get_phys_page_attrs_debug: Callback for obtaining a physical address and the
|
||||
* associated memory transaction attributes to use for the access.
|
||||
@@ -189,8 +194,9 @@ typedef struct CPUClass {
|
||||
Error **errp);
|
||||
void (*set_pc)(CPUState *cpu, vaddr value);
|
||||
void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb);
|
||||
int (*handle_mmu_fault)(CPUState *cpu, vaddr address, int size, int rw,
|
||||
int mmu_index);
|
||||
bool (*tlb_fill)(CPUState *cpu, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr);
|
||||
hwaddr (*get_phys_page_attrs_debug)(CPUState *cpu, vaddr addr,
|
||||
MemTxAttrs *attrs);
|
||||
|
||||
+2
-3
@@ -225,9 +225,8 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->set_pc = alpha_cpu_set_pc;
|
||||
cc->gdb_read_register = alpha_cpu_gdb_read_register;
|
||||
cc->gdb_write_register = alpha_cpu_gdb_write_register;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
cc->handle_mmu_fault = alpha_cpu_handle_mmu_fault;
|
||||
#else
|
||||
cc->tlb_fill = alpha_cpu_tlb_fill;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
cc->do_transaction_failed = alpha_cpu_do_transaction_failed;
|
||||
cc->do_unaligned_access = alpha_cpu_do_unaligned_access;
|
||||
cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug;
|
||||
|
||||
+3
-2
@@ -475,8 +475,9 @@ void alpha_cpu_list(void);
|
||||
is returned if the signal was handled by the virtual CPU. */
|
||||
int cpu_alpha_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc);
|
||||
int alpha_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, int rw,
|
||||
int mmu_idx);
|
||||
bool alpha_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
void QEMU_NORETURN dynamic_excp(CPUAlphaState *, uintptr_t, int, int);
|
||||
void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t);
|
||||
|
||||
|
||||
+15
-9
@@ -104,14 +104,15 @@ void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val)
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size,
|
||||
int rw, int mmu_idx)
|
||||
bool alpha_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
AlphaCPU *cpu = ALPHA_CPU(cs);
|
||||
|
||||
cs->exception_index = EXCP_MMFAULT;
|
||||
cpu->env.trap_arg0 = address;
|
||||
return 1;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
#else
|
||||
/* Returns the OSF/1 entMM failure indication, or -1 on success. */
|
||||
@@ -248,26 +249,31 @@ hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
|
||||
return (fail >= 0 ? -1 : phys);
|
||||
}
|
||||
|
||||
int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, int size, int rw,
|
||||
int mmu_idx)
|
||||
bool alpha_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
AlphaCPU *cpu = ALPHA_CPU(cs);
|
||||
CPUAlphaState *env = &cpu->env;
|
||||
target_ulong phys;
|
||||
int prot, fail;
|
||||
|
||||
fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
|
||||
fail = get_physical_address(env, addr, 1 << access_type,
|
||||
mmu_idx, &phys, &prot);
|
||||
if (unlikely(fail >= 0)) {
|
||||
if (probe) {
|
||||
return false;
|
||||
}
|
||||
cs->exception_index = EXCP_MMFAULT;
|
||||
env->trap_arg0 = addr;
|
||||
env->trap_arg1 = fail;
|
||||
env->trap_arg2 = (rw == 2 ? -1 : rw);
|
||||
return 1;
|
||||
env->trap_arg2 = (access_type == MMU_INST_FETCH ? -1 : access_type);
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
|
||||
prot, mmu_idx, TARGET_PAGE_SIZE);
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
#endif /* USER_ONLY */
|
||||
|
||||
|
||||
@@ -62,20 +62,4 @@ void alpha_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
env->error_code = 0;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
/* try to fill the TLB and return an exception if error. If retaddr is
|
||||
NULL, it means that the function was called in C code (i.e. not
|
||||
from generated code or from helper.c) */
|
||||
/* XXX: fix it to restore all registers */
|
||||
void tlb_fill(CPUState *cs, target_ulong addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = alpha_cpu_handle_mmu_fault(cs, addr, size, access_type, mmu_idx);
|
||||
if (unlikely(ret != 0)) {
|
||||
/* Exception index and error code are already set */
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_USER_ONLY */
|
||||
|
||||
+2
-20
@@ -2133,23 +2133,6 @@ static Property arm_cpu_properties[] = {
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static int arm_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size,
|
||||
int rw, int mmu_idx)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
CPUARMState *env = &cpu->env;
|
||||
|
||||
env->exception.vaddress = address;
|
||||
if (rw == 2) {
|
||||
cs->exception_index = EXCP_PREFETCH_ABORT;
|
||||
} else {
|
||||
cs->exception_index = EXCP_DATA_ABORT;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static gchar *arm_gdb_arch_name(CPUState *cs)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
@@ -2182,9 +2165,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->synchronize_from_tb = arm_cpu_synchronize_from_tb;
|
||||
cc->gdb_read_register = arm_cpu_gdb_read_register;
|
||||
cc->gdb_write_register = arm_cpu_gdb_write_register;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
cc->handle_mmu_fault = arm_cpu_handle_mmu_fault;
|
||||
#else
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
cc->do_interrupt = arm_cpu_do_interrupt;
|
||||
cc->do_unaligned_access = arm_cpu_do_unaligned_access;
|
||||
cc->do_transaction_failed = arm_cpu_do_transaction_failed;
|
||||
@@ -2209,6 +2190,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->disas_set_info = arm_disas_set_info;
|
||||
#ifdef CONFIG_TCG
|
||||
cc->tcg_initialize = arm_translate_init;
|
||||
cc->tlb_fill = arm_cpu_tlb_fill;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+53
-37
@@ -12596,43 +12596,6 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address,
|
||||
}
|
||||
}
|
||||
|
||||
/* Walk the page table and (if the mapping exists) add the page
|
||||
* to the TLB. Return false on success, or true on failure. Populate
|
||||
* fsr with ARM DFSR/IFSR fault register format value on failure.
|
||||
*/
|
||||
bool arm_tlb_fill(CPUState *cs, vaddr address,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
ARMMMUFaultInfo *fi)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
CPUARMState *env = &cpu->env;
|
||||
hwaddr phys_addr;
|
||||
target_ulong page_size;
|
||||
int prot;
|
||||
int ret;
|
||||
MemTxAttrs attrs = {};
|
||||
|
||||
ret = get_phys_addr(env, address, access_type,
|
||||
core_to_arm_mmu_idx(env, mmu_idx), &phys_addr,
|
||||
&attrs, &prot, &page_size, fi, NULL);
|
||||
if (!ret) {
|
||||
/*
|
||||
* Map a single [sub]page. Regions smaller than our declared
|
||||
* target page size are handled specially, so for those we
|
||||
* pass in the exact addresses.
|
||||
*/
|
||||
if (page_size >= TARGET_PAGE_SIZE) {
|
||||
phys_addr &= TARGET_PAGE_MASK;
|
||||
address &= TARGET_PAGE_MASK;
|
||||
}
|
||||
tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
|
||||
prot, mmu_idx, page_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
|
||||
MemTxAttrs *attrs)
|
||||
{
|
||||
@@ -13111,6 +13074,59 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
|
||||
|
||||
#endif
|
||||
|
||||
bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
cpu->env.exception.vaddress = address;
|
||||
if (access_type == MMU_INST_FETCH) {
|
||||
cs->exception_index = EXCP_PREFETCH_ABORT;
|
||||
} else {
|
||||
cs->exception_index = EXCP_DATA_ABORT;
|
||||
}
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
#else
|
||||
hwaddr phys_addr;
|
||||
target_ulong page_size;
|
||||
int prot, ret;
|
||||
MemTxAttrs attrs = {};
|
||||
ARMMMUFaultInfo fi = {};
|
||||
|
||||
/*
|
||||
* Walk the page table and (if the mapping exists) add the page
|
||||
* to the TLB. On success, return true. Otherwise, if probing,
|
||||
* return false. Otherwise populate fsr with ARM DFSR/IFSR fault
|
||||
* register format, and signal the fault.
|
||||
*/
|
||||
ret = get_phys_addr(&cpu->env, address, access_type,
|
||||
core_to_arm_mmu_idx(&cpu->env, mmu_idx),
|
||||
&phys_addr, &attrs, &prot, &page_size, &fi, NULL);
|
||||
if (likely(!ret)) {
|
||||
/*
|
||||
* Map a single [sub]page. Regions smaller than our declared
|
||||
* target page size are handled specially, so for those we
|
||||
* pass in the exact addresses.
|
||||
*/
|
||||
if (page_size >= TARGET_PAGE_SIZE) {
|
||||
phys_addr &= TARGET_PAGE_MASK;
|
||||
address &= TARGET_PAGE_MASK;
|
||||
}
|
||||
tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
|
||||
prot, mmu_idx, page_size);
|
||||
return true;
|
||||
} else if (probe) {
|
||||
return false;
|
||||
} else {
|
||||
/* now we have a real cpu fault */
|
||||
cpu_restore_state(cs, retaddr, true);
|
||||
arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
|
||||
{
|
||||
/* Implement DC ZVA, which zeroes a fixed-length block of memory.
|
||||
|
||||
@@ -761,10 +761,12 @@ static inline bool arm_extabort_type(MemTxResult result)
|
||||
return result != MEMTX_DECODE_ERROR;
|
||||
}
|
||||
|
||||
/* Do a page table walk and add page to TLB if possible */
|
||||
bool arm_tlb_fill(CPUState *cpu, vaddr address,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
ARMMMUFaultInfo *fi);
|
||||
bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
|
||||
void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
|
||||
int mmu_idx, ARMMMUFaultInfo *fi) QEMU_NORETURN;
|
||||
|
||||
/* Return true if the stage 1 translation regime is using LPAE format page
|
||||
* tables */
|
||||
|
||||
+4
-25
@@ -126,8 +126,8 @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn,
|
||||
return syn;
|
||||
}
|
||||
|
||||
static void deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
|
||||
int mmu_idx, ARMMMUFaultInfo *fi)
|
||||
void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
|
||||
int mmu_idx, ARMMMUFaultInfo *fi)
|
||||
{
|
||||
CPUARMState *env = &cpu->env;
|
||||
int target_el;
|
||||
@@ -179,27 +179,6 @@ static void deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
|
||||
raise_exception(env, exc, syn, target_el);
|
||||
}
|
||||
|
||||
/* try to fill the TLB and return an exception if error. If retaddr is
|
||||
* NULL, it means that the function was called in C code (i.e. not
|
||||
* from generated code or from helper.c)
|
||||
*/
|
||||
void tlb_fill(CPUState *cs, target_ulong addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
bool ret;
|
||||
ARMMMUFaultInfo fi = {};
|
||||
|
||||
ret = arm_tlb_fill(cs, addr, access_type, mmu_idx, &fi);
|
||||
if (unlikely(ret)) {
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
|
||||
/* now we have a real cpu fault */
|
||||
cpu_restore_state(cs, retaddr, true);
|
||||
|
||||
deliver_fault(cpu, addr, access_type, mmu_idx, &fi);
|
||||
}
|
||||
}
|
||||
|
||||
/* Raise a data fault alignment exception for the specified virtual address */
|
||||
void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
|
||||
MMUAccessType access_type,
|
||||
@@ -212,7 +191,7 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
|
||||
cpu_restore_state(cs, retaddr, true);
|
||||
|
||||
fi.type = ARMFault_Alignment;
|
||||
deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi);
|
||||
arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi);
|
||||
}
|
||||
|
||||
/* arm_cpu_do_transaction_failed: handle a memory system error response
|
||||
@@ -233,7 +212,7 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
|
||||
fi.ea = arm_extabort_type(response);
|
||||
fi.type = ARMFault_SyncExternal;
|
||||
deliver_fault(cpu, addr, access_type, mmu_idx, &fi);
|
||||
arm_deliver_fault(cpu, addr, access_type, mmu_idx, &fi);
|
||||
}
|
||||
|
||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
||||
|
||||
@@ -4598,11 +4598,7 @@ static void sve_ldnf1_r(CPUARMState *env, void *vg, const target_ulong addr,
|
||||
* in the real world, obviously.)
|
||||
*
|
||||
* Then there are the annoying special cases with watchpoints...
|
||||
*
|
||||
* TODO: Add a form of tlb_fill that does not raise an exception,
|
||||
* with a form of tlb_vaddr_to_host and a set of loads to match.
|
||||
* The non_fault_vaddr_to_host would handle everything, usually,
|
||||
* and the loads would handle the iomem path for watchpoints.
|
||||
* TODO: Add a form of non-faulting loads using cc->tlb_fill(probe=true).
|
||||
*/
|
||||
host = tlb_vaddr_to_host(env, addr + mem_off, MMU_DATA_LOAD, mmu_idx);
|
||||
split = max_for_page(addr, mem_off, mem_max);
|
||||
|
||||
+2
-3
@@ -269,9 +269,8 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->set_pc = cris_cpu_set_pc;
|
||||
cc->gdb_read_register = cris_cpu_gdb_read_register;
|
||||
cc->gdb_write_register = cris_cpu_gdb_write_register;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
cc->handle_mmu_fault = cris_cpu_handle_mmu_fault;
|
||||
#else
|
||||
cc->tlb_fill = cris_cpu_tlb_fill;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
cc->get_phys_page_debug = cris_cpu_get_phys_page_debug;
|
||||
dc->vmsd = &vmstate_cris_cpu;
|
||||
#endif
|
||||
|
||||
+3
-2
@@ -281,8 +281,9 @@ static inline int cpu_mmu_index (CPUCRISState *env, bool ifetch)
|
||||
return !!(env->pregs[PR_CCS] & U_FLAG);
|
||||
}
|
||||
|
||||
int cris_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, int rw,
|
||||
int mmu_idx);
|
||||
bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
|
||||
/* Support function regs. */
|
||||
#define SFR_RW_GC_CFG 0][0
|
||||
|
||||
+31
-30
@@ -24,6 +24,7 @@
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
||||
|
||||
//#define CRIS_HELPER_DEBUG
|
||||
@@ -53,15 +54,15 @@ void crisv10_cpu_do_interrupt(CPUState *cs)
|
||||
cris_cpu_do_interrupt(cs);
|
||||
}
|
||||
|
||||
int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
|
||||
int mmu_idx)
|
||||
bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
CRISCPU *cpu = CRIS_CPU(cs);
|
||||
|
||||
cs->exception_index = 0xaa;
|
||||
cpu->env.pregs[PR_EDA] = address;
|
||||
cpu_dump_state(cs, stderr, 0);
|
||||
return 1;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_USER_ONLY */
|
||||
@@ -76,33 +77,19 @@ static void cris_shift_ccs(CPUCRISState *env)
|
||||
env->pregs[PR_CCS] = ccs;
|
||||
}
|
||||
|
||||
int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
|
||||
int mmu_idx)
|
||||
bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
CRISCPU *cpu = CRIS_CPU(cs);
|
||||
CPUCRISState *env = &cpu->env;
|
||||
struct cris_mmu_result res;
|
||||
int prot, miss;
|
||||
int r = -1;
|
||||
target_ulong phy;
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU, "%s addr=%" VADDR_PRIx " pc=%x rw=%x\n",
|
||||
__func__, address, env->pc, rw);
|
||||
miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK,
|
||||
rw, mmu_idx, 0);
|
||||
if (miss) {
|
||||
if (cs->exception_index == EXCP_BUSFAULT) {
|
||||
cpu_abort(cs,
|
||||
"CRIS: Illegal recursive bus fault."
|
||||
"addr=%" VADDR_PRIx " rw=%d\n",
|
||||
address, rw);
|
||||
}
|
||||
|
||||
env->pregs[PR_EDA] = address;
|
||||
cs->exception_index = EXCP_BUSFAULT;
|
||||
env->fault_vector = res.bf_vec;
|
||||
r = 1;
|
||||
} else {
|
||||
access_type, mmu_idx, 0);
|
||||
if (likely(!miss)) {
|
||||
/*
|
||||
* Mask off the cache selection bit. The ETRAX busses do not
|
||||
* see the top bit.
|
||||
@@ -111,15 +98,29 @@ int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
|
||||
prot = res.prot;
|
||||
tlb_set_page(cs, address & TARGET_PAGE_MASK, phy,
|
||||
prot, mmu_idx, TARGET_PAGE_SIZE);
|
||||
r = 0;
|
||||
return true;
|
||||
}
|
||||
if (r > 0) {
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
"%s returns %d irqreq=%x addr=%" VADDR_PRIx " phy=%x vec=%x"
|
||||
" pc=%x\n", __func__, r, cs->interrupt_request, address,
|
||||
res.phy, res.bf_vec, env->pc);
|
||||
|
||||
if (probe) {
|
||||
return false;
|
||||
}
|
||||
return r;
|
||||
|
||||
if (cs->exception_index == EXCP_BUSFAULT) {
|
||||
cpu_abort(cs, "CRIS: Illegal recursive bus fault."
|
||||
"addr=%" VADDR_PRIx " access_type=%d\n",
|
||||
address, access_type);
|
||||
}
|
||||
|
||||
env->pregs[PR_EDA] = address;
|
||||
cs->exception_index = EXCP_BUSFAULT;
|
||||
env->fault_vector = res.bf_vec;
|
||||
if (retaddr) {
|
||||
if (cpu_restore_state(cs, retaddr, true)) {
|
||||
/* Evaluate flags after retranslation. */
|
||||
helper_top_evaluate_flags(env);
|
||||
}
|
||||
}
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void crisv10_cpu_do_interrupt(CPUState *cs)
|
||||
|
||||
@@ -37,34 +37,6 @@
|
||||
#define D_LOG(...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* Try to fill the TLB and return an exception if error. If retaddr is
|
||||
NULL, it means that the function was called in C code (i.e. not
|
||||
from generated code or from helper.c) */
|
||||
void tlb_fill(CPUState *cs, target_ulong addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
CRISCPU *cpu = CRIS_CPU(cs);
|
||||
CPUCRISState *env = &cpu->env;
|
||||
int ret;
|
||||
|
||||
D_LOG("%s pc=%x tpc=%x ra=%p\n", __func__,
|
||||
env->pc, env->pregs[PR_EDA], (void *)retaddr);
|
||||
ret = cris_cpu_handle_mmu_fault(cs, addr, size, access_type, mmu_idx);
|
||||
if (unlikely(ret)) {
|
||||
if (retaddr) {
|
||||
/* now we have a real cpu fault */
|
||||
if (cpu_restore_state(cs, retaddr, true)) {
|
||||
/* Evaluate flags after retranslation. */
|
||||
helper_top_evaluate_flags(env);
|
||||
}
|
||||
}
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void helper_raise_exception(CPUCRISState *env, uint32_t index)
|
||||
{
|
||||
CPUState *cs = CPU(cris_env_get_cpu(env));
|
||||
|
||||
+2
-3
@@ -163,9 +163,8 @@ static void hppa_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->synchronize_from_tb = hppa_cpu_synchronize_from_tb;
|
||||
cc->gdb_read_register = hppa_cpu_gdb_read_register;
|
||||
cc->gdb_write_register = hppa_cpu_gdb_write_register;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
cc->handle_mmu_fault = hppa_cpu_handle_mmu_fault;
|
||||
#else
|
||||
cc->tlb_fill = hppa_cpu_tlb_fill;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
cc->get_phys_page_debug = hppa_cpu_get_phys_page_debug;
|
||||
dc->vmsd = &vmstate_hppa_cpu;
|
||||
#endif
|
||||
|
||||
+4
-4
@@ -360,10 +360,10 @@ int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
void hppa_cpu_do_interrupt(CPUState *cpu);
|
||||
bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||
void hppa_cpu_dump_state(CPUState *cs, FILE *f, int);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
int hppa_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size,
|
||||
int rw, int midx);
|
||||
#else
|
||||
bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
|
||||
int type, hwaddr *pphys, int *pprot);
|
||||
extern const MemoryRegionOps hppa_io_eir_ops;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user