Merge branch 'ppc-for-upstream' of git://github.com/agraf/qemu

* 'ppc-for-upstream' of git://github.com/agraf/qemu: (58 commits)
  target-ppc: Use NARROW_MODE macro for tlbie
  target-ppc: Use NARROW_MODE macro for addresses
  target-ppc: Use NARROW_MODE macro for comparisons
  target-ppc: Use NARROW_MODE macro for branches
  target-ppc: Fix add and subf carry generation in narrow mode
  target-ppc: Use QOM method dispatch for MMU fault handling
  target-ppc: Move ppc tlb_fill implementation into mmu_helper.c
  target-ppc: Split user only code out of mmu_helper.c
  mmu-hash64: Implement Virtual Page Class Key Protection
  mmu-hash*: Merge translate and fault handling functions
  mmu-hash*: Don't use full ppc_hash{32, 64}_translate() path for get_phys_page_debug()
  mmu-hash*: Correctly mask RPN from hash PTE
  mmu-hash*: Clean up real address calculation
  mmu-hash*: Clean up PTE flags update
  mmu-hash64: Factor SLB N bit into permissions bits
  mmu-hash*: Clean up permission checking
  mmu-hash32: Remove nx from context structure
  mmu-hash*: Don't update PTE flags when permission is denied
  mmu-hash32: Don't look up page tables on BAT permission error
  mmu-hash32: Cleanup BAT lookup
  ...
This commit is contained in:
Aurelien Jarno 2013-03-22 21:43:57 +01:00
commit d76bb73549
26 changed files with 1877 additions and 1308 deletions

View file

@ -781,7 +781,8 @@ static int cpu_gdb_write_register(CPUPPCState *env, uint8_t *mem_buf, int n)
/* fpscr */
if (gdb_has_xml)
return 0;
return 4;
store_fpscr(env, ldtul_p(mem_buf), 0xffffffff);
return sizeof(target_ulong);
}
}
return 0;

View file

@ -629,7 +629,7 @@ static void ppc_spapr_reset(void)
spapr->rtas_size);
/* Set up the entry state */
first_cpu_cpu = CPU(first_cpu);
first_cpu_cpu = ENV_GET_CPU(first_cpu);
first_cpu->gpr[3] = spapr->fdt_addr;
first_cpu->gpr[5] = 0;
first_cpu_cpu->halted = 0;
@ -779,6 +779,11 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
spapr->htab_shift++;
}
/* Set up Interrupt Controller before we create the VCPUs */
spapr->icp = xics_system_init(smp_cpus * kvmppc_smt_threads() / smp_threads,
XICS_IRQS);
spapr->next_irq = XICS_IRQ_BASE;
/* init CPUs */
if (cpu_model == NULL) {
cpu_model = kvm_enabled() ? "host" : "POWER7";
@ -791,6 +796,8 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
}
env = &cpu->env;
xics_cpu_setup(spapr->icp, cpu);
/* Set time-base frequency to 512 MHz */
cpu_ppc_tb_init(env, TIMEBASE_FREQ);
@ -830,11 +837,6 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
}
g_free(filename);
/* Set up Interrupt Controller */
spapr->icp = xics_system_init(XICS_IRQS);
spapr->next_irq = XICS_IRQ_BASE;
/* Set up EPOW events infrastructure */
spapr_events_init(spapr);
@ -856,7 +858,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
/* Set up PCI */
spapr_pci_rtas_init();
phb = spapr_create_phb(spapr, 0, "pci");
phb = spapr_create_phb(spapr, 0);
for (i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];

View file

@ -3,39 +3,7 @@
#include "sysemu/sysemu.h"
#include "helper_regs.h"
#include "hw/spapr.h"
#define HPTES_PER_GROUP 8
#define HPTE_V_SSIZE_SHIFT 62
#define HPTE_V_AVPN_SHIFT 7
#define HPTE_V_AVPN 0x3fffffffffffff80ULL
#define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
#define HPTE_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff80UL))
#define HPTE_V_BOLTED 0x0000000000000010ULL
#define HPTE_V_LOCK 0x0000000000000008ULL
#define HPTE_V_LARGE 0x0000000000000004ULL
#define HPTE_V_SECONDARY 0x0000000000000002ULL
#define HPTE_V_VALID 0x0000000000000001ULL
#define HPTE_R_PP0 0x8000000000000000ULL
#define HPTE_R_TS 0x4000000000000000ULL
#define HPTE_R_KEY_HI 0x3000000000000000ULL
#define HPTE_R_RPN_SHIFT 12
#define HPTE_R_RPN 0x3ffffffffffff000ULL
#define HPTE_R_FLAGS 0x00000000000003ffULL
#define HPTE_R_PP 0x0000000000000003ULL
#define HPTE_R_N 0x0000000000000004ULL
#define HPTE_R_G 0x0000000000000008ULL
#define HPTE_R_M 0x0000000000000010ULL
#define HPTE_R_I 0x0000000000000020ULL
#define HPTE_R_W 0x0000000000000040ULL
#define HPTE_R_WIMG 0x0000000000000078ULL
#define HPTE_R_C 0x0000000000000080ULL
#define HPTE_R_R 0x0000000000000100ULL
#define HPTE_R_KEY_LO 0x0000000000000e00ULL
#define HPTE_V_1TB_SEG 0x4000000000000000ULL
#define HPTE_V_VRMA_MASK 0x4001ffffff000000ULL
#include "mmu-hash64.h"
static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
target_ulong pte_index)
@ -44,17 +12,17 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
rb = (v & ~0x7fULL) << 16; /* AVA field */
va_low = pte_index >> 3;
if (v & HPTE_V_SECONDARY) {
if (v & HPTE64_V_SECONDARY) {
va_low = ~va_low;
}
/* xor vsid from AVA */
if (!(v & HPTE_V_1TB_SEG)) {
if (!(v & HPTE64_V_1TB_SEG)) {
va_low ^= v >> 12;
} else {
va_low ^= v >> 24;
}
va_low &= 0x7ff;
if (v & HPTE_V_LARGE) {
if (v & HPTE64_V_LARGE) {
rb |= 1; /* L field */
#if 0 /* Disable that P7 specific bit for now */
if (r & 0xff000) {
@ -84,10 +52,10 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong page_shift = 12;
target_ulong raddr;
target_ulong i;
uint8_t *hpte;
hwaddr hpte;
/* only handle 4k and 16M pages for now */
if (pteh & HPTE_V_LARGE) {
if (pteh & HPTE64_V_LARGE) {
#if 0 /* We don't support 64k pages yet */
if ((ptel & 0xf000) == 0x1000) {
/* 64k page */
@ -105,11 +73,11 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
}
raddr = (ptel & HPTE_R_RPN) & ~((1ULL << page_shift) - 1);
raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << page_shift) - 1);
if (raddr < spapr->ram_limit) {
/* Regular RAM - should have WIMG=0010 */
if ((ptel & HPTE_R_WIMG) != HPTE_R_M) {
if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
return H_PARAMETER;
}
} else {
@ -117,7 +85,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
/* FIXME: What WIMG combinations could be sensible for IO?
* For now we allow WIMG=010x, but are there others? */
/* FIXME: Should we check against registered IO addresses? */
if ((ptel & (HPTE_R_W | HPTE_R_I | HPTE_R_M)) != HPTE_R_I) {
if ((ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)) != HPTE64_R_I) {
return H_PARAMETER;
}
}
@ -129,26 +97,26 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
if (likely((flags & H_EXACT) == 0)) {
pte_index &= ~7ULL;
hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
hpte = pte_index * HASH_PTE_SIZE_64;
for (i = 0; ; ++i) {
if (i == 8) {
return H_PTEG_FULL;
}
if ((ldq_p(hpte) & HPTE_V_VALID) == 0) {
if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) {
break;
}
hpte += HASH_PTE_SIZE_64;
}
} else {
i = 0;
hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
if (ldq_p(hpte) & HPTE_V_VALID) {
hpte = pte_index * HASH_PTE_SIZE_64;
if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) {
return H_PTEG_FULL;
}
}
stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel);
ppc_hash64_store_hpte1(env, hpte, ptel);
/* eieio(); FIXME: need some sort of barrier for smp? */
stq_p(hpte, pteh);
ppc_hash64_store_hpte0(env, hpte, pteh);
args[0] = pte_index + i;
return H_SUCCESS;
@ -166,26 +134,26 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex,
target_ulong flags,
target_ulong *vp, target_ulong *rp)
{
uint8_t *hpte;
hwaddr hpte;
target_ulong v, r, rb;
if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
return REMOVE_PARM;
}
hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64);
hpte = ptex * HASH_PTE_SIZE_64;
v = ldq_p(hpte);
r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
v = ppc_hash64_load_hpte0(env, hpte);
r = ppc_hash64_load_hpte1(env, hpte);
if ((v & HPTE_V_VALID) == 0 ||
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
((flags & H_ANDCOND) && (v & avpn) != 0)) {
return REMOVE_NOT_FOUND;
}
*vp = v;
*rp = r;
stq_p(hpte, 0);
ppc_hash64_store_hpte0(env, hpte, 0);
rb = compute_tlbie_rb(v, r, ptex);
ppc_tlb_invalidate_one(env, rb);
return REMOVE_SUCCESS;
@ -271,7 +239,7 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
switch (ret) {
case REMOVE_SUCCESS:
*tsh |= (r & (HPTE_R_C | HPTE_R_R)) << 43;
*tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
break;
case REMOVE_PARM:
@ -292,34 +260,34 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong flags = args[0];
target_ulong pte_index = args[1];
target_ulong avpn = args[2];
uint8_t *hpte;
hwaddr hpte;
target_ulong v, r, rb;
if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
return H_PARAMETER;
}
hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
hpte = pte_index * HASH_PTE_SIZE_64;
v = ldq_p(hpte);
r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
v = ppc_hash64_load_hpte0(env, hpte);
r = ppc_hash64_load_hpte1(env, hpte);
if ((v & HPTE_V_VALID) == 0 ||
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
return H_NOT_FOUND;
}
r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
HPTE_R_KEY_HI | HPTE_R_KEY_LO);
r |= (flags << 55) & HPTE_R_PP0;
r |= (flags << 48) & HPTE_R_KEY_HI;
r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
r |= (flags << 55) & HPTE64_R_PP0;
r |= (flags << 48) & HPTE64_R_KEY_HI;
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
rb = compute_tlbie_rb(v, r, pte_index);
stq_p(hpte, v & ~HPTE_V_VALID);
ppc_hash64_store_hpte0(env, hpte, v & ~HPTE64_V_VALID);
ppc_tlb_invalidate_one(env, rb);
stq_p(hpte + (HASH_PTE_SIZE_64/2), r);
ppc_hash64_store_hpte1(env, hpte, r);
/* Don't need a memory barrier, due to qemu's global lock */
stq_p(hpte, v);
ppc_hash64_store_hpte0(env, hpte, v);
return H_SUCCESS;
}

View file

@ -521,46 +521,39 @@ static void xics_reset(void *opaque)
}
}
struct icp_state *xics_system_init(int nr_irqs)
void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
struct icp_server_state *ss = &icp->ss[cs->cpu_index];
assert(cs->cpu_index < icp->nr_servers);
switch (PPC_INPUT(env)) {
case PPC_FLAGS_INPUT_POWER7:
ss->output = env->irq_inputs[POWER7_INPUT_INT];
break;
case PPC_FLAGS_INPUT_970:
ss->output = env->irq_inputs[PPC970_INPUT_INT];
break;
default:
fprintf(stderr, "XICS interrupt controller does not support this CPU "
"bus model\n");
abort();
}
}
struct icp_state *xics_system_init(int nr_servers, int nr_irqs)
{
CPUPPCState *env;
CPUState *cpu;
int max_server_num;
struct icp_state *icp;
struct ics_state *ics;
max_server_num = -1;
for (env = first_cpu; env != NULL; env = env->next_cpu) {
cpu = CPU(ppc_env_get_cpu(env));
if (cpu->cpu_index > max_server_num) {
max_server_num = cpu->cpu_index;
}
}
icp = g_malloc0(sizeof(*icp));
icp->nr_servers = max_server_num + 1;
icp->nr_servers = nr_servers;
icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state));
for (env = first_cpu; env != NULL; env = env->next_cpu) {
cpu = CPU(ppc_env_get_cpu(env));
struct icp_server_state *ss = &icp->ss[cpu->cpu_index];
switch (PPC_INPUT(env)) {
case PPC_FLAGS_INPUT_POWER7:
ss->output = env->irq_inputs[POWER7_INPUT_INT];
break;
case PPC_FLAGS_INPUT_970:
ss->output = env->irq_inputs[PPC970_INPUT_INT];
break;
default:
hw_error("XICS interrupt model does not support this CPU bus "
"model\n");
exit(1);
}
}
ics = g_malloc0(sizeof(*ics));
ics->nr_irqs = nr_irqs;
ics->offset = XICS_IRQ_BASE;

View file

@ -518,6 +518,7 @@ static int spapr_phb_init(SysBusDevice *s)
{
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
PCIHostState *phb = PCI_HOST_BRIDGE(s);
const char *busname;
char *namebuf;
int i;
PCIBus *bus;
@ -575,9 +576,6 @@ static int spapr_phb_init(SysBusDevice *s)
}
sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid);
if (!sphb->busname) {
sphb->busname = sphb->dtbusname;
}
namebuf = alloca(strlen(sphb->dtbusname) + 32);
@ -621,7 +619,26 @@ static int spapr_phb_init(SysBusDevice *s)
&sphb->msiwindow);
}
bus = pci_register_bus(DEVICE(s), sphb->busname,
/*
* Selecting a busname is more complex than you'd think, due to
* interacting constraints. If the user has specified an id
* explicitly for the phb , then we want to use the qdev default
* of naming the bus based on the bridge device (so the user can
* then assign devices to it in the way they expect). For the
* first / default PCI bus (index=0) we want to use just "pci"
* because libvirt expects there to be a bus called, simply,
* "pci". Otherwise, we use the same name as in the device tree,
* since it's unique by construction, and makes the guest visible
* BUID clear.
*/
if (s->qdev.id) {
busname = NULL;
} else if (sphb->index == 0) {
busname = "pci";
} else {
busname = sphb->dtbusname;
}
bus = pci_register_bus(DEVICE(s), busname,
pci_spapr_set_irq, pci_spapr_map_irq, sphb,
&sphb->memspace, &sphb->iospace,
PCI_DEVFN(0, 0), PCI_NUM_PINS);
@ -663,7 +680,6 @@ static void spapr_phb_reset(DeviceState *qdev)
}
static Property spapr_phb_properties[] = {
DEFINE_PROP_STRING("busname", sPAPRPHBState, busname),
DEFINE_PROP_INT32("index", sPAPRPHBState, index, -1),
DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, -1),
DEFINE_PROP_HEX32("liobn", sPAPRPHBState, dma_liobn, -1),
@ -694,14 +710,12 @@ static const TypeInfo spapr_phb_info = {
.class_init = spapr_phb_class_init,
};
PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index,
const char *busname)
PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index)
{
DeviceState *dev;
dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
qdev_prop_set_uint32(dev, "index", index);
qdev_prop_set_string(dev, "busname", busname);
qdev_init_nofail(dev);
return PCI_HOST_BRIDGE(dev);

View file

@ -39,7 +39,6 @@ typedef struct sPAPRPHBState {
int32_t index;
uint64_t buid;
char *busname;
char *dtbusname;
MemoryRegion memspace, iospace;
@ -82,8 +81,7 @@ static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq);
}
PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index,
const char *busname);
PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index);
int spapr_populate_pci_dt(sPAPRPHBState *phb,
uint32_t xics_phandle,

View file

@ -35,6 +35,7 @@ struct icp_state;
qemu_irq xics_get_qirq(struct icp_state *icp, int irq);
void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi);
struct icp_state *xics_system_init(int nr_irqs);
struct icp_state *xics_system_init(int nr_servers, int nr_irqs);
void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu);
#endif /* __XICS_H__ */

View file

@ -2960,10 +2960,6 @@ static const MonitorDef monitor_defs[] = {
{ "xer", 0, &monitor_get_xer, },
{ "tbu", 0, &monitor_get_tbu, },
{ "tbl", 0, &monitor_get_tbl, },
#if defined(TARGET_PPC64)
/* Address space register */
{ "asr", offsetof(CPUPPCState, asr) },
#endif
/* Segment registers */
{ "sdr1", offsetof(CPUPPCState, spr[SPR_SDR1]) },
{ "sr0", offsetof(CPUPPCState, sr[0]) },

View file

@ -1,11 +1,14 @@
obj-y += cpu-models.o
obj-y += translate.o
obj-$(CONFIG_SOFTMMU) += machine.o
ifeq ($(CONFIG_SOFTMMU),y)
obj-y += machine.o mmu_helper.o mmu-hash32.o
obj-$(TARGET_PPC64) += mmu-hash64.o
endif
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
obj-y += excp_helper.o
obj-y += fpu_helper.o
obj-y += int_helper.o
obj-y += mmu_helper.o
obj-y += timebase_helper.o
obj-y += misc_helper.o
obj-y += mem_helper.o
obj-$(CONFIG_USER_ONLY) += user_only_helper.o

View file

@ -1101,9 +1101,9 @@
"PowerPC 7457A v1.2 (G4)")
/* 64 bits PowerPC */
#if defined (TARGET_PPC64)
#if defined(TODO)
POWERPC_DEF("620", CPU_POWERPC_620, 620,
"PowerPC 620")
#if defined(TODO)
POWERPC_DEF("630", CPU_POWERPC_630, 630,
"PowerPC 630 (POWER3)")
#endif

View file

@ -68,6 +68,10 @@ typedef struct PowerPCCPUClass {
#endif
void (*init_proc)(CPUPPCState *env);
int (*check_pow)(CPUPPCState *env);
#if defined(CONFIG_SOFTMMU)
int (*handle_mmu_fault)(CPUPPCState *env, target_ulong eaddr, int rwx,
int mmu_idx);
#endif
} PowerPCCPUClass;
/**

View file

@ -113,13 +113,13 @@ enum powerpc_mmu_t {
#if defined(TARGET_PPC64)
#define POWERPC_MMU_64 0x00010000
#define POWERPC_MMU_1TSEG 0x00020000
#define POWERPC_MMU_AMR 0x00040000
/* 64 bits PowerPC MMU */
POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001,
/* 620 variant (no segment exceptions) */
POWERPC_MMU_620 = POWERPC_MMU_64 | 0x00000002,
/* Architecture 2.06 variant */
POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003,
/* Architecture 2.06 "degraded" (no 1T segments) */
POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
| POWERPC_MMU_AMR | 0x00000003,
/* Architecture 2.06 "degraded" (no 1T segments or AMR) */
POWERPC_MMU_2_06d = POWERPC_MMU_64 | 0x00000003,
#endif /* defined(TARGET_PPC64) */
};
@ -396,36 +396,12 @@ union ppc_tlb_t {
#define SDR_64_HTABSIZE 0x000000000000001FULL
#endif /* defined(TARGET_PPC64 */
#define HASH_PTE_SIZE_32 8
#define HASH_PTE_SIZE_64 16
typedef struct ppc_slb_t ppc_slb_t;
struct ppc_slb_t {
uint64_t esid;
uint64_t vsid;
};
/* Bits in the SLB ESID word */
#define SLB_ESID_ESID 0xFFFFFFFFF0000000ULL
#define SLB_ESID_V 0x0000000008000000ULL /* valid */
/* Bits in the SLB VSID word */
#define SLB_VSID_SHIFT 12
#define SLB_VSID_SHIFT_1T 24
#define SLB_VSID_SSIZE_SHIFT 62
#define SLB_VSID_B 0xc000000000000000ULL
#define SLB_VSID_B_256M 0x0000000000000000ULL
#define SLB_VSID_B_1T 0x4000000000000000ULL
#define SLB_VSID_VSID 0x3FFFFFFFFFFFF000ULL
#define SLB_VSID_PTEM (SLB_VSID_B | SLB_VSID_VSID)
#define SLB_VSID_KS 0x0000000000000800ULL
#define SLB_VSID_KP 0x0000000000000400ULL
#define SLB_VSID_N 0x0000000000000200ULL /* no-execute */
#define SLB_VSID_L 0x0000000000000100ULL
#define SLB_VSID_C 0x0000000000000080ULL /* class */
#define SLB_VSID_LP 0x0000000000000030ULL
#define SLB_VSID_ATTR 0x0000000000000FFFULL
#define SEGMENT_SHIFT_256M 28
#define SEGMENT_MASK_256M (~((1ULL << SEGMENT_SHIFT_256M) - 1))
@ -965,8 +941,6 @@ struct CPUPPCState {
/* MMU context - only relevant for full system emulation */
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
/* Address space register */
target_ulong asr;
/* PowerPC 64 SLB area */
ppc_slb_t slb[64];
int slb_nr;
@ -1105,20 +1079,6 @@ do { \
env->wdt_period[3] = (d_); \
} while (0)
#if !defined(CONFIG_USER_ONLY)
/* Context used internally during MMU translations */
typedef struct mmu_ctx_t mmu_ctx_t;
struct mmu_ctx_t {
hwaddr raddr; /* Real address */
hwaddr eaddr; /* Effective address */
int prot; /* Protection bits */
hwaddr hash[2]; /* Pagetable hash values */
target_ulong ptem; /* Virtual segment ID | API */
int key; /* Access key */
int nx; /* Non-execute area */
};
#endif
#include "cpu-qom.h"
/*****************************************************************************/
@ -1130,17 +1090,14 @@ int cpu_ppc_exec (CPUPPCState *s);
is returned if the signal was handled by the virtual CPU. */
int cpu_ppc_signal_handler (int host_signum, void *pinfo,
void *puc);
int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
int mmu_idx);
#define cpu_handle_mmu_fault cpu_ppc_handle_mmu_fault
void ppc_hw_interrupt (CPUPPCState *env);
#if defined(CONFIG_USER_ONLY)
int cpu_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx);
#endif
#if !defined(CONFIG_USER_ONLY)
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
#if defined(TARGET_PPC64)
void ppc_store_asr (CPUPPCState *env, target_ulong value);
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
#endif /* defined(TARGET_PPC64) */
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr (CPUPPCState *env, target_ulong value);
@ -1172,14 +1129,13 @@ void store_40x_dbcr0 (CPUPPCState *env, uint32_t val);
void store_40x_sler (CPUPPCState *env, uint32_t val);
void store_booke_tcr (CPUPPCState *env, target_ulong val);
void store_booke_tsr (CPUPPCState *env, target_ulong val);
int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
hwaddr *raddrp, target_ulong address,
uint32_t pid);
void ppc_tlb_invalidate_all (CPUPPCState *env);
void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
#endif
#endif
void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask);
static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn)
{
uint64_t gprv;
@ -1270,6 +1226,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_601_UDECR (0x006)
#define SPR_LR (0x008)
#define SPR_CTR (0x009)
#define SPR_UAMR (0x00C)
#define SPR_DSCR (0x011)
#define SPR_DSISR (0x012)
#define SPR_DAR (0x013) /* DAE for PowerPC 601 */
@ -1307,6 +1264,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_MPC_CMPH (0x09B)
#define SPR_MPC_LCTRL1 (0x09C)
#define SPR_MPC_LCTRL2 (0x09D)
#define SPR_UAMOR (0x09D)
#define SPR_MPC_ICTRL (0x09E)
#define SPR_MPC_BAR (0x09F)
#define SPR_VRSAVE (0x100)
@ -1489,11 +1447,9 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_RCPU_MI_RBA2 (0x302)
#define SPR_MPC_MI_AP (0x302)
#define SPR_PERF3 (0x303)
#define SPR_620_PMC1R (0x303)
#define SPR_RCPU_MI_RBA3 (0x303)
#define SPR_MPC_MI_EPN (0x303)
#define SPR_PERF4 (0x304)
#define SPR_620_PMC2R (0x304)
#define SPR_PERF5 (0x305)
#define SPR_MPC_MI_TWC (0x305)
#define SPR_PERF6 (0x306)
@ -1509,7 +1465,6 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_RCPU_L2U_RBA2 (0x30A)
#define SPR_MPC_MD_AP (0x30A)
#define SPR_PERFB (0x30B)
#define SPR_620_MMCR0R (0x30B)
#define SPR_RCPU_L2U_RBA3 (0x30B)
#define SPR_MPC_MD_EPN (0x30B)
#define SPR_PERFC (0x30C)
@ -1524,9 +1479,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_UPERF1 (0x311)
#define SPR_UPERF2 (0x312)
#define SPR_UPERF3 (0x313)
#define SPR_620_PMC1W (0x313)
#define SPR_UPERF4 (0x314)
#define SPR_620_PMC2W (0x314)
#define SPR_UPERF5 (0x315)
#define SPR_UPERF6 (0x316)
#define SPR_UPERF7 (0x317)
@ -1534,7 +1487,6 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_UPERF9 (0x319)
#define SPR_UPERFA (0x31A)
#define SPR_UPERFB (0x31B)
#define SPR_620_MMCR0W (0x31B)
#define SPR_UPERFC (0x31C)
#define SPR_UPERFD (0x31D)
#define SPR_UPERFE (0x31E)
@ -1606,49 +1558,33 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_USDA (0x3AF)
#define SPR_40x_ZPR (0x3B0)
#define SPR_BOOKE_MAS7 (0x3B0)
#define SPR_620_PMR0 (0x3B0)
#define SPR_MMCR2 (0x3B0)
#define SPR_PMC5 (0x3B1)
#define SPR_40x_PID (0x3B1)
#define SPR_620_PMR1 (0x3B1)
#define SPR_PMC6 (0x3B2)
#define SPR_440_MMUCR (0x3B2)
#define SPR_620_PMR2 (0x3B2)
#define SPR_4xx_CCR0 (0x3B3)
#define SPR_BOOKE_EPLC (0x3B3)
#define SPR_620_PMR3 (0x3B3)
#define SPR_405_IAC3 (0x3B4)
#define SPR_BOOKE_EPSC (0x3B4)
#define SPR_620_PMR4 (0x3B4)
#define SPR_405_IAC4 (0x3B5)
#define SPR_620_PMR5 (0x3B5)
#define SPR_405_DVC1 (0x3B6)
#define SPR_620_PMR6 (0x3B6)
#define SPR_405_DVC2 (0x3B7)
#define SPR_620_PMR7 (0x3B7)
#define SPR_BAMR (0x3B7)
#define SPR_MMCR0 (0x3B8)
#define SPR_620_PMR8 (0x3B8)
#define SPR_PMC1 (0x3B9)
#define SPR_40x_SGR (0x3B9)
#define SPR_620_PMR9 (0x3B9)
#define SPR_PMC2 (0x3BA)
#define SPR_40x_DCWR (0x3BA)
#define SPR_620_PMRA (0x3BA)
#define SPR_SIAR (0x3BB)
#define SPR_405_SLER (0x3BB)
#define SPR_620_PMRB (0x3BB)
#define SPR_MMCR1 (0x3BC)
#define SPR_405_SU0R (0x3BC)
#define SPR_620_PMRC (0x3BC)
#define SPR_401_SKR (0x3BC)
#define SPR_PMC3 (0x3BD)
#define SPR_405_DBCR1 (0x3BD)
#define SPR_620_PMRD (0x3BD)
#define SPR_PMC4 (0x3BE)
#define SPR_620_PMRE (0x3BE)
#define SPR_SDA (0x3BF)
#define SPR_620_PMRF (0x3BF)
#define SPR_403_VTBL (0x3CC)
#define SPR_403_VTBU (0x3CD)
#define SPR_DMISS (0x3D0)
@ -1716,15 +1652,12 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_LDSTCR (0x3F8)
#define SPR_L2PMCR (0x3F8)
#define SPR_750FX_HID2 (0x3F8)
#define SPR_620_BUSCSR (0x3F8)
#define SPR_Exxx_L1FINV0 (0x3F8)
#define SPR_L2CR (0x3F9)
#define SPR_620_L2CR (0x3F9)
#define SPR_L3CR (0x3FA)
#define SPR_750_TDCH (0x3FA)
#define SPR_IABR2 (0x3FA)
#define SPR_40x_DCCR (0x3FA)
#define SPR_620_L2SR (0x3FA)
#define SPR_ICTC (0x3FB)
#define SPR_40x_ICCR (0x3FB)
#define SPR_THRM1 (0x3FC)

View file

@ -463,6 +463,11 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
fpscr_set_rounding_mode(env);
}
void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
{
helper_store_fpscr(env, arg, mask);
}
void helper_float_check_status(CPUPPCState *env)
{
if (env->exception_index == POWERPC_EXCP_PROGRAM &&

View file

@ -382,7 +382,6 @@ DEF_HELPER_1(load_601_rtcl, tl, env)
DEF_HELPER_1(load_601_rtcu, tl, env)
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
DEF_HELPER_2(store_asr, void, env, tl)
DEF_HELPER_1(load_purr, tl, env)
#endif
DEF_HELPER_2(store_sdr1, void, env, tl)

View file

@ -32,6 +32,7 @@
#include "sysemu/device_tree.h"
#include "hw/sysbus.h"
#include "hw/spapr.h"
#include "mmu-hash64.h"
#include "hw/sysbus.h"
#include "hw/spapr.h"
@ -1077,7 +1078,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
dprintf("handle halt\n");
ret = kvmppc_handle_halt(cpu);
break;
#ifdef CONFIG_PSERIES
#if defined(TARGET_PPC64)
case KVM_EXIT_PAPR_HCALL:
dprintf("handle PAPR hypercall\n");
run->papr_hcall.ret = spapr_hypercall(cpu,

View file

@ -37,7 +37,7 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_be32s(f, &fpscr);
qemu_put_sbe32s(f, &env->access_type);
#if defined(TARGET_PPC64)
qemu_put_betls(f, &env->asr);
qemu_put_betls(f, &env->spr[SPR_ASR]);
qemu_put_sbe32s(f, &env->slb_nr);
#endif
qemu_put_betls(f, &env->spr[SPR_SDR1]);
@ -125,7 +125,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
env->fpscr = fpscr;
qemu_get_sbe32s(f, &env->access_type);
#if defined(TARGET_PPC64)
qemu_get_betls(f, &env->asr);
qemu_get_betls(f, &env->spr[SPR_ASR]);
qemu_get_sbe32s(f, &env->slb_nr);
#endif
qemu_get_betls(f, &sdr1);

View file

@ -252,41 +252,3 @@ STVE(stvewx, cpu_stl_data, bswap32, u32)
#undef HI_IDX
#undef LO_IDX
/*****************************************************************************/
/* Softmmu support */
#if !defined(CONFIG_USER_ONLY)
#define MMUSUFFIX _mmu
#define SHIFT 0
#include "exec/softmmu_template.h"
#define SHIFT 1
#include "exec/softmmu_template.h"
#define SHIFT 2
#include "exec/softmmu_template.h"
#define SHIFT 3
#include "exec/softmmu_template.h"
/* 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(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
uintptr_t retaddr)
{
int ret;
ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (unlikely(ret != 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
cpu_restore_state(env, retaddr);
}
helper_raise_exception_err(env, env->exception_index, env->error_code);
}
}
#endif /* !CONFIG_USER_ONLY */

View file

@ -35,12 +35,6 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
env->spr[sprn]);
}
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
void helper_store_asr(CPUPPCState *env, target_ulong val)
{
ppc_store_asr(env, val);
}
#endif
void helper_store_sdr1(CPUPPCState *env, target_ulong val)
{

560
target-ppc/mmu-hash32.c Normal file
View file

@ -0,0 +1,560 @@
/*
* PowerPC MMU, TLB and BAT emulation helpers for QEMU.
*
* Copyright (c) 2003-2007 Jocelyn Mayer
* Copyright (c) 2013 David Gibson, IBM Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
#include "helper.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "mmu-hash32.h"
//#define DEBUG_MMU
//#define DEBUG_BAT
#ifdef DEBUG_MMU
# define LOG_MMU(...) qemu_log(__VA_ARGS__)
# define LOG_MMU_STATE(env) log_cpu_state((env), 0)
#else
# define LOG_MMU(...) do { } while (0)
# define LOG_MMU_STATE(...) do { } while (0)
#endif
#ifdef DEBUG_BATS
# define LOG_BATS(...) qemu_log(__VA_ARGS__)
#else
# define LOG_BATS(...) do { } while (0)
#endif
struct mmu_ctx_hash32 {
hwaddr raddr; /* Real address */
int prot; /* Protection bits */
int key; /* Access key */
};
static int ppc_hash32_pp_prot(int key, int pp, int nx)
{
int prot;
if (key == 0) {
switch (pp) {
case 0x0:
case 0x1:
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
break;
case 0x3:
prot = PAGE_READ;
break;
default:
abort();
}
} else {
switch (pp) {
case 0x0:
prot = 0;
break;
case 0x1:
case 0x3:
prot = PAGE_READ;
break;
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
break;
default:
abort();
}
}
if (nx == 0) {
prot |= PAGE_EXEC;
}
return prot;
}
static int ppc_hash32_pte_prot(CPUPPCState *env,
target_ulong sr, ppc_hash_pte32_t pte)
{
unsigned pp, key;
key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
pp = pte.pte1 & HPTE32_R_PP;
return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX));
}
static target_ulong hash32_bat_size(CPUPPCState *env,
target_ulong batu, target_ulong batl)
{
if ((msr_pr && !(batu & BATU32_VP))
|| (!msr_pr && !(batu & BATU32_VS))) {
return 0;
}
return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
}
static int hash32_bat_prot(CPUPPCState *env,
target_ulong batu, target_ulong batl)
{
int pp, prot;
prot = 0;
pp = batl & BATL32_PP;
if (pp != 0) {
prot = PAGE_READ | PAGE_EXEC;
if (pp == 0x2) {
prot |= PAGE_WRITE;
}
}
return prot;
}
static target_ulong hash32_bat_601_size(CPUPPCState *env,
target_ulong batu, target_ulong batl)
{
if (!(batl & BATL32_601_V)) {
return 0;
}
return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17);
}
static int hash32_bat_601_prot(CPUPPCState *env,
target_ulong batu, target_ulong batl)
{
int key, pp;
pp = batu & BATU32_601_PP;
if (msr_pr == 0) {
key = !!(batu & BATU32_601_KS);
} else {
key = !!(batu & BATU32_601_KP);
}
return ppc_hash32_pp_prot(key, pp, 0);
}
static hwaddr ppc_hash32_bat_lookup(CPUPPCState *env, target_ulong ea, int rwx,
int *prot)
{
target_ulong *BATlt, *BATut;
int i;
LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
rwx == 2 ? 'I' : 'D', ea);
if (rwx == 2) {
BATlt = env->IBAT[1];
BATut = env->IBAT[0];
} else {
BATlt = env->DBAT[1];
BATut = env->DBAT[0];
}
for (i = 0; i < env->nb_BATs; i++) {
target_ulong batu = BATut[i];
target_ulong batl = BATlt[i];
target_ulong mask;
if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
mask = hash32_bat_601_size(env, batu, batl);
} else {
mask = hash32_bat_size(env, batu, batl);
}
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n", __func__,
type == ACCESS_CODE ? 'I' : 'D', i, ea, batu, batl);
if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
hwaddr raddr = (batl & mask) | (ea & ~mask);
if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
*prot = hash32_bat_601_prot(env, batu, batl);
} else {
*prot = hash32_bat_prot(env, batu, batl);
}
return raddr & TARGET_PAGE_MASK;
}
}
/* No hit */
#if defined(DEBUG_BATS)
if (qemu_log_enabled()) {
LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
for (i = 0; i < 4; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
BEPIu = *BATu & BATU32_BEPIU;
BEPIl = *BATu & BATU32_BEPIL;
bl = (*BATu & 0x00001FFC) << 15;
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
TARGET_FMT_lx " " TARGET_FMT_lx "\n",
__func__, type == ACCESS_CODE ? 'I' : 'D', i, ea,
*BATu, *BATl, BEPIu, BEPIl, bl);
}
}
#endif
return -1;
}
static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
target_ulong eaddr, int rwx,
hwaddr *raddr, int *prot)
{
int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
LOG_MMU("direct store...\n");
if ((sr & 0x1FF00000) >> 20 == 0x07f) {
/* Memory-forced I/O controller interface access */
/* If T=1 and BUID=x'07F', the 601 performs a memory access
* to SR[28-31] LA[4-31], bypassing all protection mechanisms.
*/
*raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
return 0;
}
if (rwx == 2) {
/* No code fetch is allowed in direct-store areas */
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x10000000;
return 1;
}
switch (env->access_type) {
case ACCESS_INT:
/* Integer load/store : only access allowed */
break;
case ACCESS_FLOAT:
/* Floating point load/store */
env->exception_index = POWERPC_EXCP_ALIGN;
env->error_code = POWERPC_EXCP_ALIGN_FP;
env->spr[SPR_DAR] = eaddr;
return 1;
case ACCESS_RES:
/* lwarx, ldarx or srwcx. */
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
if (rwx == 1) {
env->spr[SPR_DSISR] = 0x06000000;
} else {
env->spr[SPR_DSISR] = 0x04000000;
}
return 1;
case ACCESS_CACHE:
/* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
/* Should make the instruction do no-op.
* As it already do no-op, it's quite easy :-)
*/
*raddr = eaddr;
return 0;
case ACCESS_EXT:
/* eciwx or ecowx */
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
if (rwx == 1) {
env->spr[SPR_DSISR] = 0x06100000;
} else {
env->spr[SPR_DSISR] = 0x04100000;
}
return 1;
default:
qemu_log("ERROR: instruction should not need "
"address translation\n");
abort();
}
if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) {
*raddr = eaddr;
return 0;
} else {
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
if (rwx == 1) {
env->spr[SPR_DSISR] = 0x0a000000;
} else {
env->spr[SPR_DSISR] = 0x08000000;
}
return 1;
}
}
hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
{
return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
}
static hwaddr ppc_hash32_pteg_search(CPUPPCState *env, hwaddr pteg_off,
bool secondary, target_ulong ptem,
ppc_hash_pte32_t *pte)
{
hwaddr pte_offset = pteg_off;
target_ulong pte0, pte1;
int i;
for (i = 0; i < HPTES_PER_GROUP; i++) {
pte0 = ppc_hash32_load_hpte0(env, pte_offset);
pte1 = ppc_hash32_load_hpte1(env, pte_offset);
if ((pte0 & HPTE32_V_VALID)
&& (secondary == !!(pte0 & HPTE32_V_SECONDARY))
&& HPTE32_V_COMPARE(pte0, ptem)) {
pte->pte0 = pte0;
pte->pte1 = pte1;
return pte_offset;
}
pte_offset += HASH_PTE_SIZE_32;
}
return -1;
}
static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env,
target_ulong sr, target_ulong eaddr,
ppc_hash_pte32_t *pte)
{
hwaddr pteg_off, pte_offset;
hwaddr hash;
uint32_t vsid, pgidx, ptem;
vsid = sr & SR32_VSID;
pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
hash = vsid ^ pgidx;
ptem = (vsid << 7) | (pgidx >> 10);
/* Page address translation */
LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
" hash " TARGET_FMT_plx "\n",
env->htab_base, env->htab_mask, hash);
/* Primary PTEG lookup */
LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=%" PRIx32 " ptem=%" PRIx32
" hash=" TARGET_FMT_plx "\n",
env->htab_base, env->htab_mask, vsid, ptem, hash);
pteg_off = get_pteg_offset32(env, hash);
pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, pte);
if (pte_offset == -1) {
/* Secondary PTEG lookup */
LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=%" PRIx32 " api=%" PRIx32
" hash=" TARGET_FMT_plx "\n", env->htab_base,
env->htab_mask, vsid, ptem, ~hash);
pteg_off = get_pteg_offset32(env, ~hash);
pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, pte);
}
return pte_offset;
}
static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
target_ulong eaddr)
{
hwaddr rpn = pte.pte1 & HPTE32_R_RPN;
hwaddr mask = ~TARGET_PAGE_MASK;
return (rpn & ~mask) | (eaddr & mask);
}
int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr, int rwx,
int mmu_idx)
{
target_ulong sr;
hwaddr pte_offset;
ppc_hash_pte32_t pte;
int prot;
uint32_t new_pte1;
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
hwaddr raddr;
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
/* 1. Handle real mode accesses */
if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
/* Translation is off */
raddr = eaddr;
tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
TARGET_PAGE_SIZE);
return 0;
}
/* 2. Check Block Address Translation entries (BATs) */
if (env->nb_BATs != 0) {
raddr = ppc_hash32_bat_lookup(env, eaddr, rwx, &prot);
if (raddr != -1) {
if (need_prot[rwx] & ~prot) {
if (rwx == 2) {
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x08000000;
} else {
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
if (rwx == 1) {
env->spr[SPR_DSISR] = 0x0a000000;
} else {
env->spr[SPR_DSISR] = 0x08000000;
}
}
return 1;
}
tlb_set_page(env, eaddr & TARGET_PAGE_MASK,
raddr & TARGET_PAGE_MASK, prot, mmu_idx,
TARGET_PAGE_SIZE);
return 0;
}
}
/* 3. Look up the Segment Register */
sr = env->sr[eaddr >> 28];
/* 4. Handle direct store segments */
if (sr & SR32_T) {
if (ppc_hash32_direct_store(env, sr, eaddr, rwx,
&raddr, &prot) == 0) {
tlb_set_page(env, eaddr & TARGET_PAGE_MASK,
raddr & TARGET_PAGE_MASK, prot, mmu_idx,
TARGET_PAGE_SIZE);
return 0;
} else {
return 1;
}
}
/* 5. Check for segment level no-execute violation */
if ((rwx == 2) && (sr & SR32_NX)) {
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x10000000;
return 1;
}
/* 6. Locate the PTE in the hash table */
pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
if (pte_offset == -1) {
if (rwx == 2) {
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x40000000;
} else {
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
if (rwx == 1) {
env->spr[SPR_DSISR] = 0x42000000;
} else {
env->spr[SPR_DSISR] = 0x40000000;
}
}
return 1;
}
LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
/* 7. Check access permissions */
prot = ppc_hash32_pte_prot(env, sr, pte);
if (need_prot[rwx] & ~prot) {
/* Access right violation */
LOG_MMU("PTE access rejected\n");
if (rwx == 2) {
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x08000000;
} else {
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
if (rwx == 1) {
env->spr[SPR_DSISR] = 0x0a000000;
} else {
env->spr[SPR_DSISR] = 0x08000000;
}
}
return 1;
}
LOG_MMU("PTE access granted !\n");
/* 8. Update PTE referenced and changed bits if necessary */
new_pte1 = pte.pte1 | HPTE32_R_R; /* set referenced bit */
if (rwx == 1) {
new_pte1 |= HPTE32_R_C; /* set changed (dirty) bit */
} else {
/* Treat the page as read-only for now, so that a later write
* will pass through this function again to set the C bit */
prot &= ~PAGE_WRITE;
}
if (new_pte1 != pte.pte1) {
ppc_hash32_store_hpte1(env, pte_offset, new_pte1);
}
/* 9. Determine the real address from the PTE */
raddr = ppc_hash32_pte_raddr(sr, pte, eaddr);
tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
prot, mmu_idx, TARGET_PAGE_SIZE);
return 0;
}
hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong eaddr)
{
target_ulong sr;
hwaddr pte_offset;
ppc_hash_pte32_t pte;
int prot;
if (msr_dr == 0) {
/* Translation is off */
return eaddr;
}
if (env->nb_BATs != 0) {
hwaddr raddr = ppc_hash32_bat_lookup(env, eaddr, 0, &prot);
if (raddr != -1) {
return raddr;
}
}
sr = env->sr[eaddr >> 28];
if (sr & SR32_T) {
/* FIXME: Add suitable debug support for Direct Store segments */
return -1;
}
pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
if (pte_offset == -1) {
return -1;
}
return ppc_hash32_pte_raddr(sr, pte, eaddr) & TARGET_PAGE_MASK;
}

102
target-ppc/mmu-hash32.h Normal file
View file

@ -0,0 +1,102 @@
#if !defined (__MMU_HASH32_H__)
#define __MMU_HASH32_H__
#ifndef CONFIG_USER_ONLY
hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash);
hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr);
int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx);
/*
* Segment register definitions
*/
#define SR32_T 0x80000000
#define SR32_KS 0x40000000
#define SR32_KP 0x20000000
#define SR32_NX 0x10000000
#define SR32_VSID 0x00ffffff
/*
* Block Address Translation (BAT) definitions
*/
#define BATU32_BEPI 0xfffe0000
#define BATU32_BL 0x00001ffc
#define BATU32_VS 0x00000002
#define BATU32_VP 0x00000001
#define BATL32_BRPN 0xfffe0000
#define BATL32_WIMG 0x00000078
#define BATL32_PP 0x00000003
/* PowerPC 601 has slightly different BAT registers */
#define BATU32_601_KS 0x00000008
#define BATU32_601_KP 0x00000004
#define BATU32_601_PP 0x00000003
#define BATL32_601_V 0x00000040
#define BATL32_601_BL 0x0000003f
/*
* Hash page table definitions
*/
#define HPTES_PER_GROUP 8
#define HASH_PTE_SIZE_32 8
#define HASH_PTEG_SIZE_32 (HASH_PTE_SIZE_32 * HPTES_PER_GROUP)
#define HPTE32_V_VALID 0x80000000
#define HPTE32_V_VSID 0x7fffff80
#define HPTE32_V_SECONDARY 0x00000040
#define HPTE32_V_API 0x0000003f
#define HPTE32_V_COMPARE(x, y) (!(((x) ^ (y)) & 0x7fffffbf))
#define HPTE32_R_RPN 0xfffff000
#define HPTE32_R_R 0x00000100
#define HPTE32_R_C 0x00000080
#define HPTE32_R_W 0x00000040
#define HPTE32_R_I 0x00000020
#define HPTE32_R_M 0x00000010
#define HPTE32_R_G 0x00000008
#define HPTE32_R_WIMG 0x00000078
#define HPTE32_R_PP 0x00000003
static inline target_ulong ppc_hash32_load_hpte0(CPUPPCState *env,
hwaddr pte_offset)
{
assert(!env->external_htab); /* Not supported on 32-bit for now */
return ldl_phys(env->htab_base + pte_offset);
}
static inline target_ulong ppc_hash32_load_hpte1(CPUPPCState *env,
hwaddr pte_offset)
{
assert(!env->external_htab); /* Not supported on 32-bit for now */
return ldl_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_32/2);
}
static inline void ppc_hash32_store_hpte0(CPUPPCState *env,
hwaddr pte_offset, target_ulong pte0)
{
assert(!env->external_htab); /* Not supported on 32-bit for now */
stl_phys(env->htab_base + pte_offset, pte0);
}
static inline void ppc_hash32_store_hpte1(CPUPPCState *env,
hwaddr pte_offset, target_ulong pte1)
{
assert(!env->external_htab); /* Not supported on 32-bit for now */
stl_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_32/2, pte1);
}
typedef struct {
uint32_t pte0, pte1;
} ppc_hash_pte32_t;
#endif /* CONFIG_USER_ONLY */
#endif /* __MMU_HASH32_H__ */

546
target-ppc/mmu-hash64.c Normal file
View file

@ -0,0 +1,546 @@
/*
* PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
*
* Copyright (c) 2003-2007 Jocelyn Mayer
* Copyright (c) 2013 David Gibson, IBM Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
#include "helper.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "mmu-hash64.h"
//#define DEBUG_MMU
//#define DEBUG_SLB
#ifdef DEBUG_MMU
# define LOG_MMU(...) qemu_log(__VA_ARGS__)
# define LOG_MMU_STATE(env) log_cpu_state((env), 0)
#else
# define LOG_MMU(...) do { } while (0)
# define LOG_MMU_STATE(...) do { } while (0)
#endif
#ifdef DEBUG_SLB
# define LOG_SLB(...) qemu_log(__VA_ARGS__)
#else
# define LOG_SLB(...) do { } while (0)
#endif
/*
* SLB handling
*/
static ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
{
uint64_t esid_256M, esid_1T;
int n;
LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
for (n = 0; n < env->slb_nr; n++) {
ppc_slb_t *slb = &env->slb[n];
LOG_SLB("%s: slot %d %016" PRIx64 " %016"
PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
/* We check for 1T matches on all MMUs here - if the MMU
* doesn't have 1T segment support, we will have prevented 1T
* entries from being inserted in the slbmte code. */
if (((slb->esid == esid_256M) &&
((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
|| ((slb->esid == esid_1T) &&
((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
return slb;
}
}
return NULL;
}
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
{
int i;
uint64_t slbe, slbv;
cpu_synchronize_state(env);
cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
for (i = 0; i < env->slb_nr; i++) {
slbe = env->slb[i].esid;
slbv = env->slb[i].vsid;
if (slbe == 0 && slbv == 0) {
continue;
}
cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
i, slbe, slbv);
}
}
void helper_slbia(CPUPPCState *env)
{
int n, do_invalidate;
do_invalidate = 0;
/* XXX: Warning: slbia never invalidates the first segment */
for (n = 1; n < env->slb_nr; n++) {
ppc_slb_t *slb = &env->slb[n];
if (slb->esid & SLB_ESID_V) {
slb->esid &= ~SLB_ESID_V;
/* XXX: given the fact that segment size is 256 MB or 1TB,
* and we still don't have a tlb_flush_mask(env, n, mask)
* in QEMU, we just invalidate all TLBs
*/
do_invalidate = 1;
}
}
if (do_invalidate) {
tlb_flush(env, 1);
}
}
void helper_slbie(CPUPPCState *env, target_ulong addr)
{
ppc_slb_t *slb;
slb = slb_lookup(env, addr);
if (!slb) {
return;
}
if (slb->esid & SLB_ESID_V) {
slb->esid &= ~SLB_ESID_V;
/* XXX: given the fact that segment size is 256 MB or 1TB,
* and we still don't have a tlb_flush_mask(env, n, mask)
* in QEMU, we just invalidate all TLBs
*/
tlb_flush(env, 1);
}
}
int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
{
int slot = rb & 0xfff;
ppc_slb_t *slb = &env->slb[slot];
if (rb & (0x1000 - env->slb_nr)) {
return -1; /* Reserved bits set or slot too high */
}
if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
return -1; /* Bad segment size */
}
if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
return -1; /* 1T segment on MMU that doesn't support it */
}
/* Mask out the slot number as we store the entry */
slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
slb->vsid = rs;
LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
" %016" PRIx64 "\n", __func__, slot, rb, rs,
slb->esid, slb->vsid);
return 0;
}
static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb,
target_ulong *rt)
{
int slot = rb & 0xfff;
ppc_slb_t *slb = &env->slb[slot];
if (slot >= env->slb_nr) {
return -1;
}
*rt = slb->esid;
return 0;
}
static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb,
target_ulong *rt)
{
int slot = rb & 0xfff;
ppc_slb_t *slb = &env->slb[slot];
if (slot >= env->slb_nr) {
return -1;
}
*rt = slb->vsid;
return 0;
}
void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
{
if (ppc_store_slb(env, rb, rs) < 0) {
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL);
}
}
target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
{
target_ulong rt = 0;
if (ppc_load_slb_esid(env, rb, &rt) < 0) {
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL);
}
return rt;
}
target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
{
target_ulong rt = 0;
if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL);
}
return rt;
}
/*
* 64-bit hash table MMU handling
*/
static int ppc_hash64_pte_prot(CPUPPCState *env,
ppc_slb_t *slb, ppc_hash_pte64_t pte)
{
unsigned pp, key;
/* Some pp bit combinations have undefined behaviour, so default
* to no access in those cases */
int prot = 0;
key = !!(msr_pr ? (slb->vsid & SLB_VSID_KP)
: (slb->vsid & SLB_VSID_KS));
pp = (pte.pte1 & HPTE64_R_PP) | ((pte.pte1 & HPTE64_R_PP0) >> 61);
if (key == 0) {
switch (pp) {
case 0x0:
case 0x1:
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
break;
case 0x3:
case 0x6:
prot = PAGE_READ;
break;
}
} else {
switch (pp) {
case 0x0:
case 0x6:
prot = 0;
break;
case 0x1:
case 0x3:
prot = PAGE_READ;
break;
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
break;
}
}
/* No execute if either noexec or guarded bits set */
if (!(pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G)
|| (slb->vsid & SLB_VSID_N)) {
prot |= PAGE_EXEC;
}
return prot;
}
static int ppc_hash64_amr_prot(CPUPPCState *env, ppc_hash_pte64_t pte)
{
int key, amrbits;
int prot = PAGE_EXEC;
/* Only recent MMUs implement Virtual Page Class Key Protection */
if (!(env->mmu_model & POWERPC_MMU_AMR)) {
return PAGE_READ | PAGE_WRITE | PAGE_EXEC;
}
key = HPTE64_R_KEY(pte.pte1);
amrbits = (env->spr[SPR_AMR] >> 2*(31 - key)) & 0x3;
/* fprintf(stderr, "AMR protection: key=%d AMR=0x%" PRIx64 "\n", key, */
/* env->spr[SPR_AMR]); */
if (amrbits & 0x2) {
prot |= PAGE_WRITE;
}
if (amrbits & 0x1) {
prot |= PAGE_READ;
}
return prot;
}
static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off,
bool secondary, target_ulong ptem,
ppc_hash_pte64_t *pte)
{
hwaddr pte_offset = pteg_off;
target_ulong pte0, pte1;
int i;
for (i = 0; i < HPTES_PER_GROUP; i++) {
pte0 = ppc_hash64_load_hpte0(env, pte_offset);
pte1 = ppc_hash64_load_hpte1(env, pte_offset);
if ((pte0 & HPTE64_V_VALID)
&& (secondary == !!(pte0 & HPTE64_V_SECONDARY))
&& HPTE64_V_COMPARE(pte0, ptem)) {
pte->pte0 = pte0;
pte->pte1 = pte1;
return pte_offset;
}
pte_offset += HASH_PTE_SIZE_64;
}
return -1;
}
static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
ppc_slb_t *slb, target_ulong eaddr,
ppc_hash_pte64_t *pte)
{
hwaddr pteg_off, pte_offset;
hwaddr hash;
uint64_t vsid, epnshift, epnmask, epn, ptem;
/* Page size according to the SLB, which we use to generate the
* EPN for hash table lookup.. When we implement more recent MMU
* extensions this might be different from the actual page size
* encoded in the PTE */
epnshift = (slb->vsid & SLB_VSID_L)
? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
epnmask = ~((1ULL << epnshift) - 1);
if (slb->vsid & SLB_VSID_B) {
/* 1TB segment */
vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
epn = (eaddr & ~SEGMENT_MASK_1T) & epnmask;
hash = vsid ^ (vsid << 25) ^ (epn >> epnshift);
} else {
/* 256M segment */
vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
epn = (eaddr & ~SEGMENT_MASK_256M) & epnmask;
hash = vsid ^ (epn >> epnshift);
}
ptem = (slb->vsid & SLB_VSID_PTEM) | ((epn >> 16) & HPTE64_V_AVPN);
/* Page address translation */
LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
" hash " TARGET_FMT_plx "\n",
env->htab_base, env->htab_mask, hash);
/* Primary PTEG lookup */
LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n",
env->htab_base, env->htab_mask, vsid, ptem, hash);
pteg_off = (hash * HASH_PTEG_SIZE_64) & env->htab_mask;
pte_offset = ppc_hash64_pteg_search(env, pteg_off, 0, ptem, pte);
if (pte_offset == -1) {
/* Secondary PTEG lookup */
LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n", env->htab_base,
env->htab_mask, vsid, ptem, ~hash);
pteg_off = (~hash * HASH_PTEG_SIZE_64) & env->htab_mask;
pte_offset = ppc_hash64_pteg_search(env, pteg_off, 1, ptem, pte);
}
return pte_offset;
}
static hwaddr ppc_hash64_pte_raddr(ppc_slb_t *slb, ppc_hash_pte64_t pte,
target_ulong eaddr)
{
hwaddr rpn = pte.pte1 & HPTE64_R_RPN;
/* FIXME: Add support for SLLP extended page sizes */
int target_page_bits = (slb->vsid & SLB_VSID_L)
? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
hwaddr mask = (1ULL << target_page_bits) - 1;
return (rpn & ~mask) | (eaddr & mask);
}
int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr,
int rwx, int mmu_idx)
{
ppc_slb_t *slb;
hwaddr pte_offset;
ppc_hash_pte64_t pte;
int pp_prot, amr_prot, prot;
uint64_t new_pte1;
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
hwaddr raddr;
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
/* 1. Handle real mode accesses */
if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
/* Translation is off */
/* In real mode the top 4 effective address bits are ignored */
raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
TARGET_PAGE_SIZE);
return 0;
}
/* 2. Translation is on, so look up the SLB */
slb = slb_lookup(env, eaddr);
if (!slb) {
if (rwx == 2) {
env->exception_index = POWERPC_EXCP_ISEG;
env->error_code = 0;
} else {
env->exception_index = POWERPC_EXCP_DSEG;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
}
return 1;
}
/* 3. Check for segment level no-execute violation */
if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x10000000;
return 1;
}
/* 4. Locate the PTE in the hash table */
pte_offset = ppc_hash64_htab_lookup(env, slb, eaddr, &pte);
if (pte_offset == -1) {
if (rwx == 2) {
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x40000000;
} else {
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
if (rwx == 1) {
env->spr[SPR_DSISR] = 0x42000000;
} else {
env->spr[SPR_DSISR] = 0x40000000;
}
}
return 1;
}
LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
/* 5. Check access permissions */
pp_prot = ppc_hash64_pte_prot(env, slb, pte);
amr_prot = ppc_hash64_amr_prot(env, pte);
prot = pp_prot & amr_prot;
if ((need_prot[rwx] & ~prot) != 0) {
/* Access right violation */
LOG_MMU("PTE access rejected\n");
if (rwx == 2) {
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x08000000;
} else {
target_ulong dsisr = 0;
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
if (need_prot[rwx] & ~pp_prot) {
dsisr |= 0x08000000;
}
if (rwx == 1) {
dsisr |= 0x02000000;
}
if (need_prot[rwx] & ~amr_prot) {
dsisr |= 0x00200000;
}
env->spr[SPR_DSISR] = dsisr;
}
return 1;
}
LOG_MMU("PTE access granted !\n");
/* 6. Update PTE referenced and changed bits if necessary */
new_pte1 = pte.pte1 | HPTE64_R_R; /* set referenced bit */
if (rwx == 1) {
new_pte1 |= HPTE64_R_C; /* set changed (dirty) bit */
} else {
/* Treat the page as read-only for now, so that a later write
* will pass through this function again to set the C bit */
prot &= ~PAGE_WRITE;
}
if (new_pte1 != pte.pte1) {
ppc_hash64_store_hpte1(env, pte_offset, new_pte1);
}
/* 7. Determine the real address from the PTE */
raddr = ppc_hash64_pte_raddr(slb, pte, eaddr);
tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
prot, mmu_idx, TARGET_PAGE_SIZE);
return 0;
}
hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
{
ppc_slb_t *slb;
hwaddr pte_offset;
ppc_hash_pte64_t pte;
if (msr_dr == 0) {
/* In real mode the top 4 effective address bits are ignored */
return addr & 0x0FFFFFFFFFFFFFFFULL;
}
slb = slb_lookup(env, addr);
if (!slb) {
return -1;
}
pte_offset = ppc_hash64_htab_lookup(env, slb, addr, &pte);
if (pte_offset == -1) {
return -1;
}
return ppc_hash64_pte_raddr(slb, pte, addr) & TARGET_PAGE_MASK;
}

124
target-ppc/mmu-hash64.h Normal file
View file

@ -0,0 +1,124 @@
#if !defined (__MMU_HASH64_H__)
#define __MMU_HASH64_H__
#ifndef CONFIG_USER_ONLY
#ifdef TARGET_PPC64
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr);
int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx);
#endif
/*
* SLB definitions
*/
/* Bits in the SLB ESID word */
#define SLB_ESID_ESID 0xFFFFFFFFF0000000ULL
#define SLB_ESID_V 0x0000000008000000ULL /* valid */
/* Bits in the SLB VSID word */
#define SLB_VSID_SHIFT 12
#define SLB_VSID_SHIFT_1T 24
#define SLB_VSID_SSIZE_SHIFT 62
#define SLB_VSID_B 0xc000000000000000ULL
#define SLB_VSID_B_256M 0x0000000000000000ULL
#define SLB_VSID_B_1T 0x4000000000000000ULL
#define SLB_VSID_VSID 0x3FFFFFFFFFFFF000ULL
#define SLB_VSID_PTEM (SLB_VSID_B | SLB_VSID_VSID)
#define SLB_VSID_KS 0x0000000000000800ULL
#define SLB_VSID_KP 0x0000000000000400ULL
#define SLB_VSID_N 0x0000000000000200ULL /* no-execute */
#define SLB_VSID_L 0x0000000000000100ULL
#define SLB_VSID_C 0x0000000000000080ULL /* class */
#define SLB_VSID_LP 0x0000000000000030ULL
#define SLB_VSID_ATTR 0x0000000000000FFFULL
/*
* Hash page table definitions
*/
#define HPTES_PER_GROUP 8
#define HASH_PTE_SIZE_64 16
#define HASH_PTEG_SIZE_64 (HASH_PTE_SIZE_64 * HPTES_PER_GROUP)
#define HPTE64_V_SSIZE_SHIFT 62
#define HPTE64_V_AVPN_SHIFT 7
#define HPTE64_V_AVPN 0x3fffffffffffff80ULL
#define HPTE64_V_AVPN_VAL(x) (((x) & HPTE64_V_AVPN) >> HPTE64_V_AVPN_SHIFT)
#define HPTE64_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff80ULL))
#define HPTE64_V_LARGE 0x0000000000000004ULL
#define HPTE64_V_SECONDARY 0x0000000000000002ULL
#define HPTE64_V_VALID 0x0000000000000001ULL
#define HPTE64_R_PP0 0x8000000000000000ULL
#define HPTE64_R_TS 0x4000000000000000ULL
#define HPTE64_R_KEY_HI 0x3000000000000000ULL
#define HPTE64_R_RPN_SHIFT 12
#define HPTE64_R_RPN 0x0ffffffffffff000ULL
#define HPTE64_R_FLAGS 0x00000000000003ffULL
#define HPTE64_R_PP 0x0000000000000003ULL
#define HPTE64_R_N 0x0000000000000004ULL
#define HPTE64_R_G 0x0000000000000008ULL
#define HPTE64_R_M 0x0000000000000010ULL
#define HPTE64_R_I 0x0000000000000020ULL
#define HPTE64_R_W 0x0000000000000040ULL
#define HPTE64_R_WIMG 0x0000000000000078ULL
#define HPTE64_R_C 0x0000000000000080ULL
#define HPTE64_R_R 0x0000000000000100ULL
#define HPTE64_R_KEY_LO 0x0000000000000e00ULL
#define HPTE64_R_KEY(x) ((((x) & HPTE64_R_KEY_HI) >> 60) | \
(((x) & HPTE64_R_KEY_LO) >> 9))
#define HPTE64_V_1TB_SEG 0x4000000000000000ULL
#define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL
static inline target_ulong ppc_hash64_load_hpte0(CPUPPCState *env,
hwaddr pte_offset)
{
if (env->external_htab) {
return ldq_p(env->external_htab + pte_offset);
} else {
return ldq_phys(env->htab_base + pte_offset);
}
}
static inline target_ulong ppc_hash64_load_hpte1(CPUPPCState *env,
hwaddr pte_offset)
{
if (env->external_htab) {
return ldq_p(env->external_htab + pte_offset + HASH_PTE_SIZE_64/2);
} else {
return ldq_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_64/2);
}
}
static inline void ppc_hash64_store_hpte0(CPUPPCState *env,
hwaddr pte_offset, target_ulong pte0)
{
if (env->external_htab) {
stq_p(env->external_htab + pte_offset, pte0);
} else {
stq_phys(env->htab_base + pte_offset, pte0);
}
}
static inline void ppc_hash64_store_hpte1(CPUPPCState *env,
hwaddr pte_offset, target_ulong pte1)
{
if (env->external_htab) {
stq_p(env->external_htab + pte_offset + HASH_PTE_SIZE_64/2, pte1);
} else {
stq_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_64/2, pte1);
}
}
typedef struct {
uint64_t pte0, pte1;
} ppc_hash_pte64_t;
#endif /* CONFIG_USER_ONLY */
#endif /* !defined (__MMU_HASH64_H__) */

File diff suppressed because it is too large Load diff

View file

@ -204,6 +204,13 @@ typedef struct DisasContext {
int singlestep_enabled;
} DisasContext;
/* True when active word size < size of target_long. */
#ifdef TARGET_PPC64
# define NARROW_MODE(C) (!(C)->sf_mode)
#else
# define NARROW_MODE(C) 0
#endif
struct opc_handler_t {
/* invalid bits for instruction 1 (Rc(opcode) == 0) */
uint32_t inval1;
@ -260,12 +267,10 @@ static inline void gen_set_access_type(DisasContext *ctx, int access_type)
static inline void gen_update_nip(DisasContext *ctx, target_ulong nip)
{
#if defined(TARGET_PPC64)
if (ctx->sf_mode)
tcg_gen_movi_tl(cpu_nip, nip);
else
#endif
tcg_gen_movi_tl(cpu_nip, (uint32_t)nip);
if (NARROW_MODE(ctx)) {
nip = (uint32_t)nip;
}
tcg_gen_movi_tl(cpu_nip, nip);
}
static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
@ -627,7 +632,6 @@ static inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf)
tcg_temp_free(t0);
}
#if defined(TARGET_PPC64)
static inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf)
{
TCGv t0, t1;
@ -651,68 +655,62 @@ static inline void gen_op_cmpi32(TCGv arg0, target_ulong arg1, int s, int crf)
gen_op_cmp32(arg0, t0, s, crf);
tcg_temp_free(t0);
}
#endif
static inline void gen_set_Rc0(DisasContext *ctx, TCGv reg)
{
#if defined(TARGET_PPC64)
if (!(ctx->sf_mode))
if (NARROW_MODE(ctx)) {
gen_op_cmpi32(reg, 0, 1, 0);
else
#endif
} else {
gen_op_cmpi(reg, 0, 1, 0);
}
}
/* cmp */
static void gen_cmp(DisasContext *ctx)
{
#if defined(TARGET_PPC64)
if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
1, crfD(ctx->opcode));
else
#endif
} else {
gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
1, crfD(ctx->opcode));
}
}
/* cmpi */
static void gen_cmpi(DisasContext *ctx)
{
#if defined(TARGET_PPC64)
if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode),
1, crfD(ctx->opcode));
else
#endif
} else {
gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode),
1, crfD(ctx->opcode));
}
}
/* cmpl */
static void gen_cmpl(DisasContext *ctx)
{
#if defined(TARGET_PPC64)
if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
0, crfD(ctx->opcode));
else
#endif
} else {
gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
0, crfD(ctx->opcode));
}
}
/* cmpli */
static void gen_cmpli(DisasContext *ctx)
{
#if defined(TARGET_PPC64)
if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
if (NARROW_MODE(ctx) || !(ctx->opcode & 0x00200000)) {
gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode),
0, crfD(ctx->opcode));
else
#endif
} else {
gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode),
0, crfD(ctx->opcode));
}
}
/* isel (PowerPC 2.03 specification) */
@ -756,11 +754,9 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
tcg_gen_andc_tl(cpu_ov, cpu_ov, t0);
}
tcg_temp_free(t0);
#if defined(TARGET_PPC64)
if (!ctx->sf_mode) {
if (NARROW_MODE(ctx)) {
tcg_gen_ext32s_tl(cpu_ov, cpu_ov);
}
#endif
tcg_gen_shri_tl(cpu_ov, cpu_ov, TARGET_LONG_BITS - 1);
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
}
@ -778,14 +774,26 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
}
if (compute_ca) {
TCGv zero = tcg_const_tl(0);
if (add_ca) {
tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, cpu_ca, zero);
tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, arg2, zero);
if (NARROW_MODE(ctx)) {
TCGv t1 = tcg_temp_new();
tcg_gen_ext32u_tl(t1, arg2);
tcg_gen_ext32u_tl(t0, arg1);
tcg_gen_add_tl(t0, t0, t1);
tcg_temp_free(t1);
if (add_ca) {
tcg_gen_add_tl(t0, t0, cpu_ca);
}
tcg_gen_shri_tl(cpu_ca, t0, 32);
} else {
tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero);
TCGv zero = tcg_const_tl(0);
if (add_ca) {
tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, cpu_ca, zero);
tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, arg2, zero);
} else {
tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero);
}
tcg_temp_free(zero);
}
tcg_temp_free(zero);
} else {
tcg_gen_add_tl(t0, arg1, arg2);
if (add_ca) {
@ -1114,14 +1122,25 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
{
TCGv t0 = ret;
if (((add_ca && compute_ca) || compute_ov)
&& (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) {
if (compute_ov && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) {
t0 = tcg_temp_new();
}
if (add_ca) {
/* dest = ~arg1 + arg2 + ca. */
if (compute_ca) {
if (compute_ca) {
/* dest = ~arg1 + arg2 [+ ca]. */
if (NARROW_MODE(ctx)) {
TCGv inv1 = tcg_temp_new();
tcg_gen_not_tl(inv1, arg1);
tcg_gen_ext32u_tl(t0, arg2);
tcg_gen_ext32u_tl(inv1, inv1);
if (add_ca) {
tcg_gen_add_tl(t0, t0, cpu_ca);
} else {
tcg_gen_addi_tl(t0, t0, 1);
}
tcg_gen_add_tl(t0, t0, inv1);
tcg_gen_shri_tl(cpu_ca, t0, 32);
} else if (add_ca) {
TCGv zero, inv1 = tcg_temp_new();
tcg_gen_not_tl(inv1, arg1);
zero = tcg_const_tl(0);
@ -1130,14 +1149,16 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
tcg_temp_free(zero);
tcg_temp_free(inv1);
} else {
tcg_gen_sub_tl(t0, arg2, arg1);
tcg_gen_add_tl(t0, t0, cpu_ca);
tcg_gen_subi_tl(t0, t0, 1);
}
} else {
if (compute_ca) {
tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1);
tcg_gen_sub_tl(t0, arg2, arg1);
}
} else if (add_ca) {
/* Since we're ignoring carry-out, we can simplify the
standard ~arg1 + arg2 + ca to arg2 - arg1 + ca - 1. */
tcg_gen_sub_tl(t0, arg2, arg1);
tcg_gen_add_tl(t0, t0, cpu_ca);
tcg_gen_subi_tl(t0, t0, 1);
} else {
tcg_gen_sub_tl(t0, arg2, arg1);
}
@ -2311,45 +2332,37 @@ static inline void gen_addr_imm_index(DisasContext *ctx, TCGv EA,
simm &= ~maskl;
if (rA(ctx->opcode) == 0) {
#if defined(TARGET_PPC64)
if (!ctx->sf_mode) {
tcg_gen_movi_tl(EA, (uint32_t)simm);
} else
#endif
if (NARROW_MODE(ctx)) {
simm = (uint32_t)simm;
}
tcg_gen_movi_tl(EA, simm);
} else if (likely(simm != 0)) {
tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], simm);
#if defined(TARGET_PPC64)
if (!ctx->sf_mode) {
if (NARROW_MODE(ctx)) {
tcg_gen_ext32u_tl(EA, EA);
}
#endif
} else {
#if defined(TARGET_PPC64)
if (!ctx->sf_mode) {
if (NARROW_MODE(ctx)) {
tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
} else
#endif
tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
} else {
tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
}
}
}
static inline void gen_addr_reg_index(DisasContext *ctx, TCGv EA)
{
if (rA(ctx->opcode) == 0) {
#if defined(TARGET_PPC64)
if (!ctx->sf_mode) {
if (NARROW_MODE(ctx)) {
tcg_gen_ext32u_tl(EA, cpu_gpr[rB(ctx->opcode)]);
} else
#endif
tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]);
} else {
tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]);
}
} else {
tcg_gen_add_tl(EA, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
#if defined(TARGET_PPC64)
if (!ctx->sf_mode) {
if (NARROW_MODE(ctx)) {
tcg_gen_ext32u_tl(EA, EA);
}
#endif
}
}
@ -2357,13 +2370,10 @@ static inline void gen_addr_register(DisasContext *ctx, TCGv EA)
{
if (rA(ctx->opcode) == 0) {
tcg_gen_movi_tl(EA, 0);
} else if (NARROW_MODE(ctx)) {
tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
} else {
#if defined(TARGET_PPC64)
if (!ctx->sf_mode) {
tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
} else
#endif
tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
}
}
@ -2371,11 +2381,9 @@ static inline void gen_addr_add(DisasContext *ctx, TCGv ret, TCGv arg1,
target_long val)
{
tcg_gen_addi_tl(ret, arg1, val);
#if defined(TARGET_PPC64)
if (!ctx->sf_mode) {
if (NARROW_MODE(ctx)) {
tcg_gen_ext32u_tl(ret, ret);
}
#endif
}
static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask)
@ -3320,10 +3328,9 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
{
TranslationBlock *tb;
tb = ctx->tb;
#if defined(TARGET_PPC64)
if (!ctx->sf_mode)
if (NARROW_MODE(ctx)) {
dest = (uint32_t) dest;
#endif
}
if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
likely(!ctx->singlestep_enabled)) {
tcg_gen_goto_tb(n);
@ -3351,12 +3358,10 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
static inline void gen_setlr(DisasContext *ctx, target_ulong nip)
{
#if defined(TARGET_PPC64)
if (ctx->sf_mode == 0)
tcg_gen_movi_tl(cpu_lr, (uint32_t)nip);
else
#endif
tcg_gen_movi_tl(cpu_lr, nip);
if (NARROW_MODE(ctx)) {
nip = (uint32_t)nip;
}
tcg_gen_movi_tl(cpu_lr, nip);
}
/* b ba bl bla */
@ -3366,18 +3371,16 @@ static void gen_b(DisasContext *ctx)
ctx->exception = POWERPC_EXCP_BRANCH;
/* sign extend LI */
#if defined(TARGET_PPC64)
if (ctx->sf_mode)
li = ((int64_t)LI(ctx->opcode) << 38) >> 38;
else
#endif
li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
if (likely(AA(ctx->opcode) == 0))
li = LI(ctx->opcode);
li = (li ^ 0x02000000) - 0x02000000;
if (likely(AA(ctx->opcode) == 0)) {
target = ctx->nip + li - 4;
else
} else {
target = li;
if (LK(ctx->opcode))
}
if (LK(ctx->opcode)) {
gen_setlr(ctx, ctx->nip);
}
gen_update_cfar(ctx, ctx->nip);
gen_goto_tb(ctx, 0, target);
}
@ -3413,12 +3416,11 @@ static inline void gen_bcond(DisasContext *ctx, int type)
return;
}
tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
#if defined(TARGET_PPC64)
if (!ctx->sf_mode)
if (NARROW_MODE(ctx)) {
tcg_gen_ext32u_tl(temp, cpu_ctr);
else
#endif
} else {
tcg_gen_mov_tl(temp, cpu_ctr);
}
if (bo & 0x2) {
tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1);
} else {
@ -3452,20 +3454,14 @@ static inline void gen_bcond(DisasContext *ctx, int type)
gen_set_label(l1);
gen_goto_tb(ctx, 1, ctx->nip);
} else {
#if defined(TARGET_PPC64)
if (!(ctx->sf_mode))
if (NARROW_MODE(ctx)) {
tcg_gen_andi_tl(cpu_nip, target, (uint32_t)~3);
else
#endif
} else {
tcg_gen_andi_tl(cpu_nip, target, ~3);
}
tcg_gen_exit_tb(0);
gen_set_label(l1);
#if defined(TARGET_PPC64)
if (!(ctx->sf_mode))
tcg_gen_movi_tl(cpu_nip, (uint32_t)ctx->nip);
else
#endif
tcg_gen_movi_tl(cpu_nip, ctx->nip);
gen_update_nip(ctx, ctx->nip);
tcg_gen_exit_tb(0);
}
}
@ -4324,15 +4320,14 @@ static void gen_tlbie(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
#if defined(TARGET_PPC64)
if (!ctx->sf_mode) {
if (NARROW_MODE(ctx)) {
TCGv t0 = tcg_temp_new();
tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
gen_helper_tlbie(cpu_env, t0);
tcg_temp_free(t0);
} else
#endif
} else {
gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
}
#endif
}
@ -7577,11 +7572,9 @@ static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh)
tcg_gen_movi_tl(EA, uimm << sh);
} else {
tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh);
#if defined(TARGET_PPC64)
if (!ctx->sf_mode) {
if (NARROW_MODE(ctx)) {
tcg_gen_ext32u_tl(EA, EA);
}
#endif
}
}
@ -9428,7 +9421,6 @@ void cpu_dump_state (CPUPPCState *env, FILE *f, fprintf_function cpu_fprintf,
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
#if defined(TARGET_PPC64)
case POWERPC_MMU_620:
case POWERPC_MMU_64B:
#endif
cpu_fprintf(f, " SDR1 " TARGET_FMT_lx "\n", env->spr[SPR_SDR1]);

View file

@ -25,6 +25,8 @@
#include "sysemu/arch_init.h"
#include "sysemu/cpus.h"
#include "cpu-models.h"
#include "mmu-hash32.h"
#include "mmu-hash64.h"
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
@ -365,7 +367,6 @@ static void spr_write_sdr1 (void *opaque, int sprn, int gprn)
}
/* 64 bits PowerPC specific SPRs */
/* ASR */
#if defined(TARGET_PPC64)
static void spr_read_hior (void *opaque, int gprn, int sprn)
{
@ -379,16 +380,6 @@ static void spr_write_hior (void *opaque, int sprn, int gprn)
tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix));
tcg_temp_free(t0);
}
static void spr_read_asr (void *opaque, int gprn, int sprn)
{
tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, asr));
}
static void spr_write_asr (void *opaque, int sprn, int gprn)
{
gen_helper_store_asr(cpu_env, cpu_gpr[gprn]);
}
#endif
#endif
@ -1028,6 +1019,54 @@ static void gen_spr_7xx (CPUPPCState *env)
0x00000000);
}
#ifdef TARGET_PPC64
#ifndef CONFIG_USER_ONLY
static void spr_read_uamr (void *opaque, int gprn, int sprn)
{
gen_load_spr(cpu_gpr[gprn], SPR_AMR);
spr_load_dump_spr(SPR_AMR);
}
static void spr_write_uamr (void *opaque, int sprn, int gprn)
{
gen_store_spr(SPR_AMR, cpu_gpr[gprn]);
spr_store_dump_spr(SPR_AMR);
}
static void spr_write_uamr_pr (void *opaque, int sprn, int gprn)
{
TCGv t0 = tcg_temp_new();
gen_load_spr(t0, SPR_UAMOR);
tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
gen_store_spr(SPR_AMR, t0);
spr_store_dump_spr(SPR_AMR);
}
#endif /* CONFIG_USER_ONLY */
static void gen_spr_amr (CPUPPCState *env)
{
#ifndef CONFIG_USER_ONLY
/* Virtual Page Class Key protection */
/* The AMR is accessible either via SPR 13 or SPR 29. 13 is
* userspace accessible, 29 is privileged. So we only need to set
* the kvm ONE_REG id on one of them, we use 29 */
spr_register(env, SPR_UAMR, "UAMR",
&spr_read_uamr, &spr_write_uamr_pr,
&spr_read_uamr, &spr_write_uamr,
0);
spr_register_kvm(env, SPR_AMR, "AMR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_AMR, 0xffffffffffffffffULL);
spr_register_kvm(env, SPR_UAMOR, "UAMOR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_UAMOR, 0);
#endif /* !CONFIG_USER_ONLY */
}
#endif /* TARGET_PPC64 */
static void gen_spr_thrm (CPUPPCState *env)
{
/* Thermal management */
@ -2151,173 +2190,6 @@ static void gen_spr_compress (CPUPPCState *env)
0x00000000);
}
#if defined (TARGET_PPC64)
/* SPR specific to PowerPC 620 */
static void gen_spr_620 (CPUPPCState *env)
{
/* Processor identification */
spr_register(env, SPR_PIR, "PIR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_pir,
0x00000000);
spr_register(env, SPR_ASR, "ASR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_asr, &spr_write_asr,
0x00000000);
/* Breakpoints */
/* XXX : not implemented */
spr_register(env, SPR_IABR, "IABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_DABR, "DABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_SIAR, "SIAR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_SDA, "SDA",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMC1R, "PMC1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_620_PMC1W, "PMC1",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMC2R, "PMC2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_620_PMC2W, "PMC2",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_MMCR0R, "MMCR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_620_MMCR0W, "MMCR0",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, &spr_write_generic,
0x00000000);
/* External access control */
/* XXX : not implemented */
spr_register(env, SPR_EAR, "EAR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
#if 0 // XXX: check this
/* XXX : not implemented */
spr_register(env, SPR_620_PMR0, "PMR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMR1, "PMR1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMR2, "PMR2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMR3, "PMR3",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMR4, "PMR4",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMR5, "PMR5",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMR6, "PMR6",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMR7, "PMR7",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMR8, "PMR8",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMR9, "PMR9",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMRA, "PMR10",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMRB, "PMR11",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMRC, "PMR12",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMRD, "PMR13",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMRE, "PMR14",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_PMRF, "PMR15",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
#endif
/* XXX : not implemented */
spr_register(env, SPR_620_BUSCSR, "BUSCSR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_L2CR, "L2CR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_620_L2SR, "L2SR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
#endif /* defined (TARGET_PPC64) */
static void gen_spr_5xx_8xx (CPUPPCState *env)
{
/* Exception processing */
@ -2993,31 +2865,6 @@ static void init_excp_604 (CPUPPCState *env)
#endif
}
#if defined(TARGET_PPC64)
static void init_excp_620 (CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100;
env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200;
env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300;
env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400;
env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600;
env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700;
env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800;
env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900;
env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00;
env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00;
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->hreset_excp_prefix = 0xFFF00000UL;
/* Hardware reset vector */
env->hreset_vector = 0x0000000000000100ULL;
#endif
}
#endif /* defined(TARGET_PPC64) */
static void init_excp_7x0 (CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
@ -4951,6 +4798,9 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000000FD70ULL;
pcc->mmu_model = POWERPC_MMU_601;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_601;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_601;
@ -4985,7 +4835,9 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000000FD70ULL;
pcc->mmu_model = POWERPC_MMU_601;
pcc->excp_model = POWERPC_EXCP_601;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_601;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK;
@ -5192,6 +5044,9 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_604;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_604;
@ -5258,6 +5113,9 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_604;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_604;
@ -5311,6 +5169,9 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@ -5372,6 +5233,9 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@ -5556,6 +5420,9 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@ -5621,6 +5488,9 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@ -5691,6 +5561,9 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@ -5761,6 +5634,9 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@ -5953,6 +5829,9 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000205FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_74xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_7400;
@ -6019,6 +5898,9 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000205FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_74xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_7400;
@ -6725,6 +6607,9 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x900000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@ -6835,6 +6720,9 @@ POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x800000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@ -6933,6 +6821,9 @@ POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x800000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@ -7031,6 +6922,9 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x900000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@ -7075,6 +6969,7 @@ static void init_proc_POWER7 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000); /* TOFIX */
gen_spr_amr(env);
/* XXX : not implemented */
spr_register(env, SPR_CTRL, "SPR_CTRLT",
SPR_NOACCESS, SPR_NOACCESS,
@ -7122,6 +7017,9 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX;
pcc->msr_mask = 0x800000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_2_06;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
#endif
pcc->excp_model = POWERPC_EXCP_POWER7;
pcc->bus_model = PPC_FLAGS_INPUT_POWER7;
pcc->bfd_mach = bfd_mach_ppc64;
@ -7129,55 +7027,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR;
}
static void init_proc_620 (CPUPPCState *env)
{
gen_spr_ne_601(env);
gen_spr_620(env);
/* Time base */
gen_tbl(env);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
gen_low_BATs(env);
init_excp_620(env);
env->dcache_line_size = 64;
env->icache_line_size = 64;
/* Allocate hardware IRQ controller */
ppc6xx_irq_init(env);
}
POWERPC_FAMILY(620)(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
dc->desc = "PowerPC 620";
pcc->init_proc = init_proc_620;
pcc->check_pow = check_pow_nocheck; /* Check this */
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
PPC_FLOAT_STFIWX |
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
PPC_SEGMENT | PPC_EXTERN |
PPC_64B | PPC_SLBI;
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x800000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_620;
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc64;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK;
}
#endif /* defined (TARGET_PPC64) */
@ -7693,7 +7542,7 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 8;
}
if (n == 32) {
/* FPSCR not implemented */
helper_store_fpscr(env, ldl_p(mem_buf), 0xffffffff);
return 4;
}
return 0;
@ -7915,9 +7764,6 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
case POWERPC_MMU_64B:
mmu_model = "PowerPC 64";
break;
case POWERPC_MMU_620:
mmu_model = "PowerPC 620";
break;
#endif
default:
mmu_model = "Unknown or invalid";

View file

@ -0,0 +1,44 @@
/*
* PowerPC MMU stub handling for user mode emulation
*
* Copyright (c) 2003-2007 Jocelyn Mayer
* Copyright (c) 2013 David Gibson, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
int cpu_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx)
{
int exception, error_code;
if (rw == 2) {
exception = POWERPC_EXCP_ISI;
error_code = 0x40000000;
} else {
exception = POWERPC_EXCP_DSI;
error_code = 0x40000000;
if (rw) {
error_code |= 0x02000000;
}
env->spr[SPR_DAR] = address;
env->spr[SPR_DSISR] = error_code;
}
env->exception_index = exception;
env->error_code = error_code;
return 1;
}