Tag edgar/xilinx-next-2018-05-29-v1.for-upstream
-----BEGIN PGP SIGNATURE----- iQEcBAABCAAGBQJbDRY2AAoJECnFlngPa8qDhSgH/jVtKCwHfLfMkFFy4++OP4S3 9VtJYNm5PX4QJrpRvpuDIzYU6B3WuYvwTyoNg4lbUy7IBR8zqa6b1+fz66S64N8o DgkTH6cLlirY52aJbVxLiSqOsCgAx8kWhcWIetraw1Q9tS2ur8pWqcsyawwPhFEo +Ck8rl8IvSlzxYWCKshipKliKOjLjrUlIcUlN7OrW+FN8qVCxhcGSVRGDEQVcFvF DtM/KI68x97rK8KSRSqHSC926/AV90cUxsz4KQcieL6Aj8bA4RDC0BtSTaV2GxrY DmaB9rsvlnb8y9awB6X7gcN4QrPpbp5h07B6eWxZRM2p83Tkg06oUZS1hrNW4zk= =uquA -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/edgar/tags/edgar/xilinx-next-2018-05-29-v1.for-upstream' into staging Tag edgar/xilinx-next-2018-05-29-v1.for-upstream # gpg: Signature made Tue 29 May 2018 09:58:30 BST # gpg: using RSA key 29C596780F6BCA83 # gpg: Good signature from "Edgar E. Iglesias (Xilinx key) <edgar.iglesias@xilinx.com>" # gpg: aka "Edgar E. Iglesias <edgar.iglesias@gmail.com>" # Primary key fingerprint: AC44 FEDC 14F7 F1EB EDBF 4151 29C5 9678 0F6B CA83 * remotes/edgar/tags/edgar/xilinx-next-2018-05-29-v1.for-upstream: (38 commits) target-microblaze: Consolidate MMU enabled checks target-microblaze: cpu_mmu_index: Fixup indentation target-microblaze: Use tcg_gen_movcond in eval_cond_jmp target-microblaze: Convert env_btarget to i64 target-microblaze: Remove argument b in eval_cc() target-microblaze: Use table based condition-codes conversion target-microblaze: mmu: Cleanup debug log messages target-microblaze: Simplify address computation using tcg_gen_addi_i32() target-microblaze: Allow address sizes between 32 and 64 bits target-microblaze: Add support for extended access to TLBLO target-microblaze: dec_msr: Plug a temp leak target-microblaze: mmu: Add a configurable output address mask target-microblaze: mmu: Prepare for 64-bit addresses target-microblaze: mmu: Remove unused register state target-microblaze: mmu: Add R_TBLX_MISS macros target-microblaze: Implement MFSE EAR target-microblaze: Add Extended Addressing target-microblaze: Setup for 64bit addressing target-microblaze: Make special registers 64-bit target-microblaze: dec_msr: Fix MTS to FSR ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e609fa71e8
1
configure
vendored
1
configure
vendored
@ -6844,6 +6844,7 @@ case "$target_name" in
|
||||
microblaze|microblazeel)
|
||||
TARGET_ARCH=microblaze
|
||||
bflt="yes"
|
||||
echo "TARGET_ABI32=y" >> $config_target_mak
|
||||
;;
|
||||
mips|mipsel)
|
||||
TARGET_ARCH=mips
|
||||
|
@ -105,7 +105,7 @@ void cpu_loop(CPUMBState *env)
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
default:
|
||||
printf ("Unhandled hw-exception: 0x%x\n",
|
||||
printf("Unhandled hw-exception: 0x%" PRIx64 "\n",
|
||||
env->sregs[SR_ESR] & ESR_EC_MASK);
|
||||
cpu_dump_state(cs, stderr, fprintf, 0);
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -72,6 +72,9 @@ static const struct {
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
/* If no specific version gets selected, default to the following. */
|
||||
#define DEFAULT_CPU_VERSION "10.0"
|
||||
|
||||
static void mb_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
@ -125,6 +128,7 @@ static void mb_cpu_reset(CPUState *s)
|
||||
env->mmu.c_mmu = 3;
|
||||
env->mmu.c_mmu_tlb_access = 3;
|
||||
env->mmu.c_mmu_zones = 16;
|
||||
env->mmu.c_addr_mask = MAKE_64BIT_MASK(0, cpu->cfg.addr_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -141,6 +145,7 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
CPUMBState *env = &cpu->env;
|
||||
uint8_t version_code = 0;
|
||||
const char *version;
|
||||
int i = 0;
|
||||
Error *local_err = NULL;
|
||||
|
||||
@ -150,6 +155,12 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu->cfg.addr_size < 32 || cpu->cfg.addr_size > 64) {
|
||||
error_setg(errp, "addr-size %d is out of range (32 - 64)",
|
||||
cpu->cfg.addr_size);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
|
||||
env->pvr.regs[0] = PVR0_USE_EXC_MASK \
|
||||
@ -162,8 +173,9 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
| PVR2_FPU_EXC_MASK \
|
||||
| 0;
|
||||
|
||||
for (i = 0; mb_cpu_lookup[i].name && cpu->cfg.version; i++) {
|
||||
if (strcmp(mb_cpu_lookup[i].name, cpu->cfg.version) == 0) {
|
||||
version = cpu->cfg.version ? cpu->cfg.version : DEFAULT_CPU_VERSION;
|
||||
for (i = 0; mb_cpu_lookup[i].name && version; i++) {
|
||||
if (strcmp(mb_cpu_lookup[i].name, version) == 0) {
|
||||
version_code = mb_cpu_lookup[i].version_id;
|
||||
break;
|
||||
}
|
||||
@ -195,8 +207,10 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
env->pvr.regs[5] |= cpu->cfg.dcache_writeback ?
|
||||
PVR5_DCACHE_WRITEBACK_MASK : 0;
|
||||
|
||||
env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */
|
||||
env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
|
||||
env->pvr.regs[10] = 0x0c000000 | /* Default to spartan 3a dsp family. */
|
||||
(cpu->cfg.addr_size - 32) << PVR10_ASIZE_SHIFT;
|
||||
env->pvr.regs[11] = (cpu->cfg.use_mmu ? PVR11_USE_MMU : 0) |
|
||||
16 << 17;
|
||||
|
||||
mcc->parent_realize(dev, errp);
|
||||
}
|
||||
@ -226,6 +240,14 @@ static Property mb_properties[] = {
|
||||
DEFINE_PROP_UINT32("base-vectors", MicroBlazeCPU, cfg.base_vectors, 0),
|
||||
DEFINE_PROP_BOOL("use-stack-protection", MicroBlazeCPU, cfg.stackprot,
|
||||
false),
|
||||
/*
|
||||
* This is the C_ADDR_SIZE synth-time configuration option of the
|
||||
* MicroBlaze cores. Supported values range between 32 and 64.
|
||||
*
|
||||
* When set to > 32, 32bit MicroBlaze can emit load/stores
|
||||
* with extended addressing.
|
||||
*/
|
||||
DEFINE_PROP_UINT8("addr-size", MicroBlazeCPU, cfg.addr_size, 32),
|
||||
/* If use-fpu > 0 - FPU is enabled
|
||||
* If use-fpu = 2 - Floating point conversion and square root instructions
|
||||
* are enabled
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "qemu-common.h"
|
||||
#include "cpu-qom.h"
|
||||
|
||||
#define TARGET_LONG_BITS 32
|
||||
#define TARGET_LONG_BITS 64
|
||||
|
||||
#define CPUArchState struct CPUMBState
|
||||
|
||||
@ -203,6 +203,7 @@ typedef struct CPUMBState CPUMBState;
|
||||
|
||||
/* Target family PVR mask */
|
||||
#define PVR10_TARGET_FAMILY_MASK 0xFF000000
|
||||
#define PVR10_ASIZE_SHIFT 18
|
||||
|
||||
/* MMU descrtiption */
|
||||
#define PVR11_USE_MMU 0xC0000000
|
||||
@ -238,19 +239,19 @@ typedef struct CPUMBState CPUMBState;
|
||||
struct CPUMBState {
|
||||
uint32_t debug;
|
||||
uint32_t btaken;
|
||||
uint32_t btarget;
|
||||
uint64_t btarget;
|
||||
uint32_t bimm;
|
||||
|
||||
uint32_t imm;
|
||||
uint32_t regs[33];
|
||||
uint32_t sregs[24];
|
||||
uint32_t regs[32];
|
||||
uint64_t sregs[14];
|
||||
float_status fp_status;
|
||||
/* Stack protectors. Yes, it's a hw feature. */
|
||||
uint32_t slr, shr;
|
||||
|
||||
/* lwx/swx reserved address */
|
||||
#define RES_ADDR_NONE 0xffffffff /* Use 0xffffffff to indicate no reservation */
|
||||
uint32_t res_addr;
|
||||
target_ulong res_addr;
|
||||
uint32_t res_val;
|
||||
|
||||
/* Internal flags. */
|
||||
@ -277,7 +278,7 @@ struct CPUMBState {
|
||||
/* These fields are preserved on reset. */
|
||||
|
||||
struct {
|
||||
uint32_t regs[16];
|
||||
uint32_t regs[13];
|
||||
} pvr;
|
||||
};
|
||||
|
||||
@ -297,6 +298,7 @@ struct MicroBlazeCPU {
|
||||
struct {
|
||||
bool stackprot;
|
||||
uint32_t base_vectors;
|
||||
uint8_t addr_size;
|
||||
uint8_t use_fpu;
|
||||
uint8_t use_hw_mul;
|
||||
bool use_barrel;
|
||||
@ -340,8 +342,8 @@ int cpu_mb_signal_handler(int host_signum, void *pinfo,
|
||||
/* FIXME: MB uses variable pages down to 1K but linux only uses 4k. */
|
||||
#define TARGET_PAGE_BITS 12
|
||||
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 32
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 64
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 64
|
||||
|
||||
#define CPU_RESOLVING_TYPE TYPE_MICROBLAZE_CPU
|
||||
|
||||
@ -358,12 +360,16 @@ int cpu_mb_signal_handler(int host_signum, void *pinfo,
|
||||
|
||||
static inline int cpu_mmu_index (CPUMBState *env, bool ifetch)
|
||||
{
|
||||
/* Are we in nommu mode?. */
|
||||
if (!(env->sregs[SR_MSR] & MSR_VM))
|
||||
return MMU_NOMMU_IDX;
|
||||
MicroBlazeCPU *cpu = mb_env_get_cpu(env);
|
||||
|
||||
if (env->sregs[SR_MSR] & MSR_UM)
|
||||
/* Are we in nommu mode?. */
|
||||
if (!(env->sregs[SR_MSR] & MSR_VM) || !cpu->cfg.use_mmu) {
|
||||
return MMU_NOMMU_IDX;
|
||||
}
|
||||
|
||||
if (env->sregs[SR_MSR] & MSR_UM) {
|
||||
return MMU_USER_IDX;
|
||||
}
|
||||
return MMU_KERNEL_IDX;
|
||||
}
|
||||
|
||||
|
@ -54,22 +54,12 @@ int mb_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
CPUMBState *env = &cpu->env;
|
||||
unsigned int hit;
|
||||
unsigned int mmu_available;
|
||||
int r = 1;
|
||||
int prot;
|
||||
|
||||
mmu_available = 0;
|
||||
if (cpu->cfg.use_mmu) {
|
||||
mmu_available = 1;
|
||||
if ((cpu->cfg.pvr == C_PVR_FULL) &&
|
||||
(env->pvr.regs[11] & PVR11_USE_MMU) != PVR11_USE_MMU) {
|
||||
mmu_available = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Translate if the MMU is available and enabled. */
|
||||
if (mmu_available && (env->sregs[SR_MSR] & MSR_VM)) {
|
||||
target_ulong vaddr, paddr;
|
||||
if (mmu_idx != MMU_NOMMU_IDX) {
|
||||
uint32_t vaddr, paddr;
|
||||
struct microblaze_mmu_lookup lu;
|
||||
|
||||
hit = mmu_translate(&env->mmu, &lu, address, rw, mmu_idx);
|
||||
@ -152,7 +142,8 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
env->sregs[SR_MSR] |= MSR_EIP;
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"hw exception at pc=%x ear=%x esr=%x iflags=%x\n",
|
||||
"hw exception at pc=%" PRIx64 " ear=%" PRIx64 " "
|
||||
"esr=%" PRIx64 " iflags=%x\n",
|
||||
env->sregs[SR_PC], env->sregs[SR_EAR],
|
||||
env->sregs[SR_ESR], env->iflags);
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
@ -175,7 +166,8 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
/* was the branch immprefixed?. */
|
||||
if (env->bimm) {
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"bimm exception at pc=%x iflags=%x\n",
|
||||
"bimm exception at pc=%" PRIx64 " "
|
||||
"iflags=%x\n",
|
||||
env->sregs[SR_PC], env->iflags);
|
||||
env->regs[17] -= 4;
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
@ -193,7 +185,8 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
env->sregs[SR_MSR] |= MSR_EIP;
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"exception at pc=%x ear=%x iflags=%x\n",
|
||||
"exception at pc=%" PRIx64 " ear=%" PRIx64 " "
|
||||
"iflags=%x\n",
|
||||
env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags);
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
env->iflags &= ~(IMM_FLAG | D_FLAG);
|
||||
@ -230,7 +223,8 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
}
|
||||
#endif
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"interrupt at pc=%x msr=%x %x iflags=%x\n",
|
||||
"interrupt at pc=%" PRIx64 " msr=%" PRIx64 " %x "
|
||||
"iflags=%x\n",
|
||||
env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
|
||||
|
||||
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \
|
||||
@ -248,7 +242,8 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
assert(!(env->iflags & D_FLAG));
|
||||
t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"break at pc=%x msr=%x %x iflags=%x\n",
|
||||
"break at pc=%" PRIx64 " msr=%" PRIx64 " %x "
|
||||
"iflags=%x\n",
|
||||
env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
@ -274,9 +269,10 @@ hwaddr mb_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
|
||||
CPUMBState *env = &cpu->env;
|
||||
target_ulong vaddr, paddr = 0;
|
||||
struct microblaze_mmu_lookup lu;
|
||||
int mmu_idx = cpu_mmu_index(env, false);
|
||||
unsigned int hit;
|
||||
|
||||
if (env->sregs[SR_MSR] & MSR_VM) {
|
||||
if (mmu_idx != MMU_NOMMU_IDX) {
|
||||
hit = mmu_translate(&env->mmu, &lu, addr, 0, 0);
|
||||
if (hit) {
|
||||
vaddr = addr & TARGET_PAGE_MASK;
|
||||
|
@ -25,12 +25,12 @@ DEF_HELPER_3(fcmp_ge, i32, env, i32, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_NO_RWG_SE, i32, i32, i32)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
DEF_HELPER_2(mmu_read, i32, env, i32)
|
||||
DEF_HELPER_3(mmu_write, void, env, i32, i32)
|
||||
DEF_HELPER_3(mmu_read, i32, env, i32, i32)
|
||||
DEF_HELPER_4(mmu_write, void, env, i32, i32, i32)
|
||||
#endif
|
||||
|
||||
DEF_HELPER_5(memalign, void, env, i32, i32, i32, i32)
|
||||
DEF_HELPER_2(stackprot, void, env, i32)
|
||||
DEF_HELPER_5(memalign, void, env, tl, i32, i32, i32)
|
||||
DEF_HELPER_2(stackprot, void, env, tl)
|
||||
|
||||
DEF_HELPER_2(get, i32, i32, i32)
|
||||
DEF_HELPER_3(put, void, i32, i32, i32)
|
||||
|
@ -22,8 +22,6 @@
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
#define D(x)
|
||||
|
||||
static unsigned int tlb_decode_size(unsigned int f)
|
||||
{
|
||||
static const unsigned int sizes[] = {
|
||||
@ -81,34 +79,29 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu,
|
||||
{
|
||||
unsigned int i, hit = 0;
|
||||
unsigned int tlb_ex = 0, tlb_wr = 0, tlb_zsel;
|
||||
unsigned int tlb_size;
|
||||
uint32_t tlb_tag, tlb_rpn, mask, t0;
|
||||
uint64_t tlb_tag, tlb_rpn, mask;
|
||||
uint32_t tlb_size, t0;
|
||||
|
||||
lu->err = ERR_MISS;
|
||||
for (i = 0; i < ARRAY_SIZE(mmu->rams[RAM_TAG]); i++) {
|
||||
uint32_t t, d;
|
||||
uint64_t t, d;
|
||||
|
||||
/* Lookup and decode. */
|
||||
t = mmu->rams[RAM_TAG][i];
|
||||
D(qemu_log("TLB %d valid=%d\n", i, t & TLB_VALID));
|
||||
if (t & TLB_VALID) {
|
||||
tlb_size = tlb_decode_size((t & TLB_PAGESZ_MASK) >> 7);
|
||||
if (tlb_size < TARGET_PAGE_SIZE) {
|
||||
qemu_log("%d pages not supported\n", tlb_size);
|
||||
qemu_log_mask(LOG_UNIMP, "%d pages not supported\n", tlb_size);
|
||||
abort();
|
||||
}
|
||||
|
||||
mask = ~(tlb_size - 1);
|
||||
mask = ~((uint64_t)tlb_size - 1);
|
||||
tlb_tag = t & TLB_EPN_MASK;
|
||||
if ((vaddr & mask) != (tlb_tag & mask)) {
|
||||
D(qemu_log("TLB %d vaddr=%x != tag=%x\n",
|
||||
i, vaddr & mask, tlb_tag & mask));
|
||||
continue;
|
||||
}
|
||||
if (mmu->tids[i]
|
||||
&& ((mmu->regs[MMU_R_PID] & 0xff) != mmu->tids[i])) {
|
||||
D(qemu_log("TLB %d pid=%x != tid=%x\n",
|
||||
i, mmu->regs[MMU_R_PID], mmu->tids[i]));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -123,7 +116,8 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu,
|
||||
t0 &= 0x3;
|
||||
|
||||
if (tlb_zsel > mmu->c_mmu_zones) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "tlb zone select out of range! %d\n", tlb_zsel);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"tlb zone select out of range! %d\n", tlb_zsel);
|
||||
t0 = 1; /* Ignore. */
|
||||
}
|
||||
|
||||
@ -164,6 +158,7 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu,
|
||||
tlb_rpn = d & TLB_RPN_MASK;
|
||||
|
||||
lu->vaddr = tlb_tag;
|
||||
lu->paddr = tlb_rpn & mmu->c_addr_mask;
|
||||
lu->paddr = tlb_rpn;
|
||||
lu->size = tlb_size;
|
||||
lu->err = ERR_HIT;
|
||||
@ -173,13 +168,14 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu,
|
||||
}
|
||||
}
|
||||
done:
|
||||
D(qemu_log("MMU vaddr=%x rw=%d tlb_wr=%d tlb_ex=%d hit=%d\n",
|
||||
vaddr, rw, tlb_wr, tlb_ex, hit));
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
"MMU vaddr=%" PRIx64 " rw=%d tlb_wr=%d tlb_ex=%d hit=%d\n",
|
||||
vaddr, rw, tlb_wr, tlb_ex, hit);
|
||||
return hit;
|
||||
}
|
||||
|
||||
/* Writes/reads to the MMU's special regs end up here. */
|
||||
uint32_t mmu_read(CPUMBState *env, uint32_t rn)
|
||||
uint32_t mmu_read(CPUMBState *env, bool ext, uint32_t rn)
|
||||
{
|
||||
unsigned int i;
|
||||
uint32_t r = 0;
|
||||
@ -188,50 +184,65 @@ uint32_t mmu_read(CPUMBState *env, uint32_t rn)
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "MMU access on MMU-less system\n");
|
||||
return 0;
|
||||
}
|
||||
if (ext && rn != MMU_R_TLBLO) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Extended access only to TLBLO.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (rn) {
|
||||
/* Reads to HI/LO trig reads from the mmu rams. */
|
||||
case MMU_R_TLBLO:
|
||||
case MMU_R_TLBHI:
|
||||
if (!(env->mmu.c_mmu_tlb_access & 1)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Invalid access to MMU reg %d\n", rn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
i = env->mmu.regs[MMU_R_TLBX] & 0xff;
|
||||
r = env->mmu.rams[rn & 1][i];
|
||||
r = extract64(env->mmu.rams[rn & 1][i], ext * 32, 32);
|
||||
if (rn == MMU_R_TLBHI)
|
||||
env->mmu.regs[MMU_R_PID] = env->mmu.tids[i];
|
||||
break;
|
||||
case MMU_R_PID:
|
||||
case MMU_R_ZPR:
|
||||
if (!(env->mmu.c_mmu_tlb_access & 1)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Invalid access to MMU reg %d\n", rn);
|
||||
return 0;
|
||||
}
|
||||
r = env->mmu.regs[rn];
|
||||
break;
|
||||
case MMU_R_TLBX:
|
||||
r = env->mmu.regs[rn];
|
||||
break;
|
||||
case MMU_R_TLBSX:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "TLBSX is write-only.\n");
|
||||
break;
|
||||
default:
|
||||
r = env->mmu.regs[rn];
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Invalid MMU register %d.\n", rn);
|
||||
break;
|
||||
}
|
||||
D(qemu_log("%s rn=%d=%x\n", __func__, rn, r));
|
||||
qemu_log_mask(CPU_LOG_MMU, "%s rn=%d=%x\n", __func__, rn, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
|
||||
void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v)
|
||||
{
|
||||
MicroBlazeCPU *cpu = mb_env_get_cpu(env);
|
||||
uint64_t tmp64;
|
||||
unsigned int i;
|
||||
D(qemu_log("%s rn=%d=%x old=%x\n", __func__, rn, v, env->mmu.regs[rn]));
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
"%s rn=%d=%x old=%x\n", __func__, rn, v, env->mmu.regs[rn]);
|
||||
|
||||
if (env->mmu.c_mmu < 2 || !env->mmu.c_mmu_tlb_access) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "MMU access on MMU-less system\n");
|
||||
return;
|
||||
}
|
||||
if (ext && rn != MMU_R_TLBLO) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Extended access only to TLBLO.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (rn) {
|
||||
/* Writes to HI/LO trig writes to the mmu rams. */
|
||||
@ -240,18 +251,19 @@ void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
|
||||
i = env->mmu.regs[MMU_R_TLBX] & 0xff;
|
||||
if (rn == MMU_R_TLBHI) {
|
||||
if (i < 3 && !(v & TLB_VALID) && qemu_loglevel_mask(~0))
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "invalidating index %x at pc=%x\n",
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"invalidating index %x at pc=%" PRIx64 "\n",
|
||||
i, env->sregs[SR_PC]);
|
||||
env->mmu.tids[i] = env->mmu.regs[MMU_R_PID] & 0xff;
|
||||
mmu_flush_idx(env, i);
|
||||
}
|
||||
env->mmu.rams[rn & 1][i] = v;
|
||||
|
||||
D(qemu_log("%s ram[%d][%d]=%x\n", __func__, rn & 1, i, v));
|
||||
tmp64 = env->mmu.rams[rn & 1][i];
|
||||
env->mmu.rams[rn & 1][i] = deposit64(tmp64, ext * 32, 32, v);
|
||||
break;
|
||||
case MMU_R_ZPR:
|
||||
if (env->mmu.c_mmu_tlb_access <= 1) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Invalid access to MMU reg %d\n", rn);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -264,7 +276,8 @@ void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
|
||||
break;
|
||||
case MMU_R_PID:
|
||||
if (env->mmu.c_mmu_tlb_access <= 1) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Invalid access to MMU reg %d\n", rn);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -283,7 +296,8 @@ void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
|
||||
int hit;
|
||||
|
||||
if (env->mmu.c_mmu_tlb_access <= 1) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Invalid access to MMU reg %d\n", rn);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -291,12 +305,13 @@ void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
|
||||
v & TLB_EPN_MASK, 0, cpu_mmu_index(env, false));
|
||||
if (hit) {
|
||||
env->mmu.regs[MMU_R_TLBX] = lu.idx;
|
||||
} else
|
||||
env->mmu.regs[MMU_R_TLBX] |= 0x80000000;
|
||||
} else {
|
||||
env->mmu.regs[MMU_R_TLBX] |= R_TBLX_MISS_MASK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
env->mmu.regs[rn] = v;
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Invalid MMU register %d.\n", rn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
#define RAM_TAG 0
|
||||
|
||||
/* Tag portion */
|
||||
#define TLB_EPN_MASK 0xFFFFFC00 /* Effective Page Number */
|
||||
#define TLB_EPN_MASK MAKE_64BIT_MASK(10, 64 - 10)
|
||||
#define TLB_PAGESZ_MASK 0x00000380
|
||||
#define TLB_PAGESZ(x) (((x) & 0x7) << 7)
|
||||
#define PAGESZ_1K 0
|
||||
@ -42,7 +42,7 @@
|
||||
#define TLB_VALID 0x00000040 /* Entry is valid */
|
||||
|
||||
/* Data portion */
|
||||
#define TLB_RPN_MASK 0xFFFFFC00 /* Real Page Number */
|
||||
#define TLB_RPN_MASK MAKE_64BIT_MASK(10, 64 - 10)
|
||||
#define TLB_PERM_MASK 0x00000300
|
||||
#define TLB_EX 0x00000200 /* Instruction execution allowed */
|
||||
#define TLB_WR 0x00000100 /* Writes permitted */
|
||||
@ -54,20 +54,25 @@
|
||||
#define TLB_M 0x00000002 /* Memory is coherent */
|
||||
#define TLB_G 0x00000001 /* Memory is guarded from prefetch */
|
||||
|
||||
/* TLBX */
|
||||
#define R_TBLX_MISS_SHIFT 31
|
||||
#define R_TBLX_MISS_MASK (1U << R_TBLX_MISS_SHIFT)
|
||||
|
||||
#define TLB_ENTRIES 64
|
||||
|
||||
struct microblaze_mmu
|
||||
{
|
||||
/* Data and tag brams. */
|
||||
uint32_t rams[2][TLB_ENTRIES];
|
||||
uint64_t rams[2][TLB_ENTRIES];
|
||||
/* We keep a separate ram for the tids to avoid the 48 bit tag width. */
|
||||
uint8_t tids[TLB_ENTRIES];
|
||||
/* Control flops. */
|
||||
uint32_t regs[8];
|
||||
uint32_t regs[3];
|
||||
|
||||
int c_mmu;
|
||||
int c_mmu_tlb_access;
|
||||
int c_mmu_zones;
|
||||
uint64_t c_addr_mask; /* Mask to apply to physical addresses. */
|
||||
};
|
||||
|
||||
struct microblaze_mmu_lookup
|
||||
@ -85,6 +90,6 @@ struct microblaze_mmu_lookup
|
||||
unsigned int mmu_translate(struct microblaze_mmu *mmu,
|
||||
struct microblaze_mmu_lookup *lu,
|
||||
target_ulong vaddr, int rw, int mmu_idx);
|
||||
uint32_t mmu_read(CPUMBState *env, uint32_t rn);
|
||||
void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v);
|
||||
uint32_t mmu_read(CPUMBState *env, bool ea, uint32_t rn);
|
||||
void mmu_write(CPUMBState *env, bool ea, uint32_t rn, uint32_t v);
|
||||
void mmu_init(struct microblaze_mmu *mmu);
|
||||
|
@ -94,16 +94,17 @@ void helper_debug(CPUMBState *env)
|
||||
{
|
||||
int i;
|
||||
|
||||
qemu_log("PC=%8.8x\n", env->sregs[SR_PC]);
|
||||
qemu_log("rmsr=%x resr=%x rear=%x debug[%x] imm=%x iflags=%x\n",
|
||||
qemu_log("PC=%" PRIx64 "\n", env->sregs[SR_PC]);
|
||||
qemu_log("rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " "
|
||||
"debug[%x] imm=%x iflags=%x\n",
|
||||
env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
|
||||
env->debug, env->imm, env->iflags);
|
||||
qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
|
||||
qemu_log("btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) eip=%d ie=%d\n",
|
||||
env->btaken, env->btarget,
|
||||
(env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
|
||||
(env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
|
||||
(env->sregs[SR_MSR] & MSR_EIP),
|
||||
(env->sregs[SR_MSR] & MSR_IE));
|
||||
(bool)(env->sregs[SR_MSR] & MSR_EIP),
|
||||
(bool)(env->sregs[SR_MSR] & MSR_IE));
|
||||
for (i = 0; i < 32; i++) {
|
||||
qemu_log("r%2.2d=%8.8x ", i, env->regs[i]);
|
||||
if ((i + 1) % 4 == 0)
|
||||
@ -439,12 +440,14 @@ uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void helper_memalign(CPUMBState *env, uint32_t addr, uint32_t dr, uint32_t wr,
|
||||
void helper_memalign(CPUMBState *env, target_ulong addr,
|
||||
uint32_t dr, uint32_t wr,
|
||||
uint32_t mask)
|
||||
{
|
||||
if (addr & mask) {
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"unaligned access addr=%x mask=%x, wr=%d dr=r%d\n",
|
||||
"unaligned access addr=" TARGET_FMT_lx
|
||||
" mask=%x, wr=%d dr=r%d\n",
|
||||
addr, mask, wr, dr);
|
||||
env->sregs[SR_EAR] = addr;
|
||||
env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \
|
||||
@ -459,10 +462,11 @@ void helper_memalign(CPUMBState *env, uint32_t addr, uint32_t dr, uint32_t wr,
|
||||
}
|
||||
}
|
||||
|
||||
void helper_stackprot(CPUMBState *env, uint32_t addr)
|
||||
void helper_stackprot(CPUMBState *env, target_ulong addr)
|
||||
{
|
||||
if (addr < env->slr || addr > env->shr) {
|
||||
qemu_log_mask(CPU_LOG_INT, "Stack protector violation at %x %x %x\n",
|
||||
qemu_log_mask(CPU_LOG_INT, "Stack protector violation at "
|
||||
TARGET_FMT_lx " %x %x\n",
|
||||
addr, env->slr, env->shr);
|
||||
env->sregs[SR_EAR] = addr;
|
||||
env->sregs[SR_ESR] = ESR_EC_STACKPROT;
|
||||
@ -472,14 +476,14 @@ void helper_stackprot(CPUMBState *env, uint32_t addr)
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* Writes/reads to the MMU's special regs end up here. */
|
||||
uint32_t helper_mmu_read(CPUMBState *env, uint32_t rn)
|
||||
uint32_t helper_mmu_read(CPUMBState *env, uint32_t ext, uint32_t rn)
|
||||
{
|
||||
return mmu_read(env, rn);
|
||||
return mmu_read(env, ext, rn);
|
||||
}
|
||||
|
||||
void helper_mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
|
||||
void helper_mmu_write(CPUMBState *env, uint32_t ext, uint32_t rn, uint32_t v)
|
||||
{
|
||||
mmu_write(env, rn, v);
|
||||
mmu_write(env, ext, rn, v);
|
||||
}
|
||||
|
||||
void mb_cpu_unassigned_access(CPUState *cs, hwaddr addr,
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user