Merge branch 'ppc-next' of git://repo.or.cz/qemu/agraf
* 'ppc-next' of git://repo.or.cz/qemu/agraf: PPC: Qdev'ify e500 pci PPC MPC7544DS: Use new TLB helper function PPC: Implement e500 (FSL) MMU PPC: Add another 64 bits to instruction feature mask PPC: Add GS MSR definition PPC: Make MPC8544DS emulation work w/o KVM PPC: Make MPC8544DS obey -cpu switch Fix off-by-one error in sizing pSeries hcall table ppc64: Fix out-of-tree builds kvm: ppc: warn user on PAGE_SIZE mismatch kvm: ppc: detect old headers monitor: add PPC BookE SPRs kvm: ppc: fixes for KVM_SET_SREGS on init ppc64: Don't try to build sPAPR RTAS on Darwin Place pseries vty devices at addresses more similar to existing machines Make pSeries 'model' property more closely resemble real hardware pseries: Increase maximum CPUs to 256
This commit is contained in:
commit
091959defe
22
configure
vendored
22
configure
vendored
@ -1833,6 +1833,21 @@ recent kvm-kmod from http://sourceforge.net/projects/kvm."
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# test for ppc kvm pvr setting
|
||||
|
||||
if test "$kvm" = "yes" && test "$cpu" = "ppc" -o "$cpu" = "ppc64"; then
|
||||
cat > $TMPC <<EOF
|
||||
#include <asm/kvm.h>
|
||||
int main(void) { struct kvm_sregs s; s.pvr = 0; return 0; }
|
||||
EOF
|
||||
if compile_prog "$kvm_cflags" "" ; then
|
||||
kvm_ppc_pvr=yes
|
||||
else
|
||||
kvm_ppc_pvr=no
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# test for vhost net
|
||||
|
||||
@ -2602,7 +2617,7 @@ if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
|
||||
"$softmmu" = yes ; then
|
||||
roms="optionrom"
|
||||
fi
|
||||
if test "$cpu" = "ppc64" ; then
|
||||
if test "$cpu" = "ppc64" -a "$targetos" != "Darwin" ; then
|
||||
roms="$roms spapr-rtas"
|
||||
fi
|
||||
|
||||
@ -3324,6 +3339,9 @@ case "$target_arch2" in
|
||||
if test $vhost_net = "yes" ; then
|
||||
echo "CONFIG_VHOST_NET=y" >> $config_target_mak
|
||||
fi
|
||||
if test $kvm_ppc_pvr = "yes" ; then
|
||||
echo "CONFIG_KVM_PPC_PVR=y" >> $config_target_mak
|
||||
fi
|
||||
fi
|
||||
esac
|
||||
if test "$target_bigendian" = "yes" ; then
|
||||
@ -3524,11 +3542,13 @@ done # for target in $targets
|
||||
|
||||
# build tree in object directory in case the source is not in the current directory
|
||||
DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
|
||||
DIRS="$DIRS pc-bios/spapr-rtas"
|
||||
DIRS="$DIRS roms/seabios roms/vgabios"
|
||||
DIRS="$DIRS fsdev ui"
|
||||
FILES="Makefile tests/Makefile"
|
||||
FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
|
||||
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
|
||||
FILES="$FILES pc-bios/spapr-rtas/Makefile"
|
||||
FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
|
||||
for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.rom $source_path/pc-bios/*.dtb $source_path/pc-bios/openbios-*; do
|
||||
FILES="$FILES pc-bios/`basename $bios_file`"
|
||||
|
12
hw/ppc.c
12
hw/ppc.c
@ -452,6 +452,10 @@ uint64_t cpu_ppc_load_tbl (CPUState *env)
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
uint64_t tb;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
return env->spr[SPR_TBL];
|
||||
}
|
||||
|
||||
tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
|
||||
LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
|
||||
|
||||
@ -471,6 +475,10 @@ static inline uint32_t _cpu_ppc_load_tbu(CPUState *env)
|
||||
|
||||
uint32_t cpu_ppc_load_tbu (CPUState *env)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
return env->spr[SPR_TBU];
|
||||
}
|
||||
|
||||
return _cpu_ppc_load_tbu(env);
|
||||
}
|
||||
|
||||
@ -616,6 +624,10 @@ uint32_t cpu_ppc_load_decr (CPUState *env)
|
||||
{
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
return env->spr[SPR_DECR];
|
||||
}
|
||||
|
||||
return _cpu_ppc_load_decr(env, tb_env->decr_next);
|
||||
}
|
||||
|
||||
|
22
hw/ppce500.h
22
hw/ppce500.h
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* QEMU PowerPC E500 emulation shared definitions
|
||||
*
|
||||
* Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Author: Yu Liu, <yu.liu@freescale.com>
|
||||
*
|
||||
* This file is derived from hw/ppc440.h
|
||||
* the copyright for that material belongs to the original owners.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#if !defined(PPC_E500_H)
|
||||
#define PPC_E500_H
|
||||
|
||||
PCIBus *ppce500_pci_init(qemu_irq *pic, target_phys_addr_t registers);
|
||||
|
||||
#endif /* !defined(PPC_E500_H) */
|
@ -28,9 +28,10 @@
|
||||
#include "kvm_ppc.h"
|
||||
#include "device_tree.h"
|
||||
#include "openpic.h"
|
||||
#include "ppce500.h"
|
||||
#include "ppc.h"
|
||||
#include "loader.h"
|
||||
#include "elf.h"
|
||||
#include "sysbus.h"
|
||||
|
||||
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
|
||||
#define UIMAGE_LOAD_BASE 0
|
||||
@ -50,6 +51,12 @@
|
||||
#define MPC8544_PCI_IO 0xE1000000
|
||||
#define MPC8544_PCI_IOLEN 0x10000
|
||||
|
||||
struct boot_info
|
||||
{
|
||||
uint32_t dt_base;
|
||||
uint32_t entry;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_FDT
|
||||
static int mpc8544_copy_soc_cell(void *fdt, const char *node, const char *prop)
|
||||
{
|
||||
@ -82,7 +89,7 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
|
||||
{
|
||||
int ret = -1;
|
||||
#ifdef CONFIG_FDT
|
||||
uint32_t mem_reg_property[] = {0, ramsize};
|
||||
uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
|
||||
char *filename;
|
||||
int fdt_size;
|
||||
void *fdt;
|
||||
@ -103,15 +110,19 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "couldn't set /memory/reg\n");
|
||||
|
||||
ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
|
||||
initrd_base);
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
|
||||
if (initrd_size) {
|
||||
ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
|
||||
initrd_base);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
|
||||
}
|
||||
|
||||
ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
|
||||
(initrd_base + initrd_size));
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
|
||||
ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
|
||||
(initrd_base + initrd_size));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
|
||||
}
|
||||
}
|
||||
|
||||
ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
|
||||
kernel_cmdline);
|
||||
@ -145,6 +156,13 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
|
||||
|
||||
mpc8544_copy_soc_cell(fdt, buf, "clock-frequency");
|
||||
mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency");
|
||||
} else {
|
||||
const uint32_t freq = 400000000;
|
||||
|
||||
qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544@0",
|
||||
"clock-frequency", freq);
|
||||
qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544@0",
|
||||
"timebase-frequency", freq);
|
||||
}
|
||||
|
||||
ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
|
||||
@ -156,6 +174,35 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */
|
||||
static void mmubooke_create_initial_mapping(CPUState *env,
|
||||
target_ulong va,
|
||||
target_phys_addr_t pa)
|
||||
{
|
||||
ppcemb_tlb_t *tlb = booke206_get_tlbe(env, 1, 0, 0);
|
||||
|
||||
tlb->attr = 0;
|
||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||
tlb->size = 256 * 1024 * 1024;
|
||||
tlb->EPN = va & TARGET_PAGE_MASK;
|
||||
tlb->RPN = pa & TARGET_PAGE_MASK;
|
||||
tlb->PID = 0;
|
||||
}
|
||||
|
||||
static void mpc8544ds_cpu_reset(void *opaque)
|
||||
{
|
||||
CPUState *env = opaque;
|
||||
struct boot_info *bi = env->load_info;
|
||||
|
||||
cpu_reset(env);
|
||||
|
||||
/* Set initial guest state. */
|
||||
env->gpr[1] = (16<<20) - 8;
|
||||
env->gpr[3] = bi->dt_base;
|
||||
env->nip = bi->entry;
|
||||
mmubooke_create_initial_mapping(env, 0, 0);
|
||||
}
|
||||
|
||||
static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename,
|
||||
@ -175,15 +222,28 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
target_long initrd_size=0;
|
||||
int i=0;
|
||||
unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
|
||||
qemu_irq *irqs, *mpic, *pci_irqs;
|
||||
qemu_irq *irqs, *mpic;
|
||||
DeviceState *dev;
|
||||
struct boot_info *boot_info;
|
||||
|
||||
/* Setup CPU */
|
||||
env = cpu_ppc_init("e500v2_v30");
|
||||
if (cpu_model == NULL) {
|
||||
cpu_model = "e500v2_v30";
|
||||
}
|
||||
|
||||
env = cpu_ppc_init(cpu_model);
|
||||
if (!env) {
|
||||
fprintf(stderr, "Unable to initialize CPU!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* XXX register timer? */
|
||||
ppc_emb_timers_init(env, 400000000, PPC_INTERRUPT_DECR);
|
||||
ppc_dcr_init(env, NULL, NULL);
|
||||
|
||||
/* Register reset handler */
|
||||
qemu_register_reset(mpc8544ds_cpu_reset, env);
|
||||
|
||||
/* Fixup Memory size on a alignment boundary */
|
||||
ram_size &= ~(RAM_SIZES_ALIGN - 1);
|
||||
|
||||
@ -211,12 +271,11 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
}
|
||||
|
||||
/* PCI */
|
||||
pci_irqs = qemu_malloc(sizeof(qemu_irq) * 4);
|
||||
pci_irqs[0] = mpic[pci_irq_nrs[0]];
|
||||
pci_irqs[1] = mpic[pci_irq_nrs[1]];
|
||||
pci_irqs[2] = mpic[pci_irq_nrs[2]];
|
||||
pci_irqs[3] = mpic[pci_irq_nrs[3]];
|
||||
pci_bus = ppce500_pci_init(pci_irqs, MPC8544_PCI_REGS_BASE);
|
||||
dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
|
||||
mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
|
||||
mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
|
||||
NULL);
|
||||
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
|
||||
if (!pci_bus)
|
||||
printf("couldn't create PCI controller!\n");
|
||||
|
||||
@ -259,8 +318,13 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
}
|
||||
}
|
||||
|
||||
boot_info = qemu_mallocz(sizeof(struct boot_info));
|
||||
|
||||
/* If we're loading a kernel directly, we must load the device tree too. */
|
||||
if (kernel_filename) {
|
||||
#ifndef CONFIG_FDT
|
||||
cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
|
||||
#endif
|
||||
dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
|
||||
if (mpc8544_load_device_tree(dt_base, ram_size,
|
||||
initrd_base, initrd_size, kernel_cmdline) < 0) {
|
||||
@ -268,17 +332,14 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Set initial guest state. */
|
||||
env->gpr[1] = (16<<20) - 8;
|
||||
env->gpr[3] = dt_base;
|
||||
env->nip = entry;
|
||||
/* XXX we currently depend on KVM to create some initial TLB entries. */
|
||||
boot_info->entry = entry;
|
||||
boot_info->dt_base = dt_base;
|
||||
}
|
||||
env->load_info = boot_info;
|
||||
|
||||
if (kvm_enabled())
|
||||
if (kvm_enabled()) {
|
||||
kvmppc_init();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static QEMUMachine mpc8544ds_machine = {
|
||||
|
134
hw/ppce500_pci.c
134
hw/ppce500_pci.c
@ -15,7 +15,6 @@
|
||||
*/
|
||||
|
||||
#include "hw.h"
|
||||
#include "ppce500.h"
|
||||
#include "pci.h"
|
||||
#include "pci_host.h"
|
||||
#include "bswap.h"
|
||||
@ -29,7 +28,8 @@
|
||||
#define PCIE500_CFGADDR 0x0
|
||||
#define PCIE500_CFGDATA 0x4
|
||||
#define PCIE500_REG_BASE 0xC00
|
||||
#define PCIE500_REG_SIZE (0x1000 - PCIE500_REG_BASE)
|
||||
#define PCIE500_ALL_SIZE 0x1000
|
||||
#define PCIE500_REG_SIZE (PCIE500_ALL_SIZE - PCIE500_REG_BASE)
|
||||
|
||||
#define PPCE500_PCI_CONFIG_ADDR 0x0
|
||||
#define PPCE500_PCI_CONFIG_DATA 0x4
|
||||
@ -73,11 +73,15 @@ struct pci_inbound {
|
||||
};
|
||||
|
||||
struct PPCE500PCIState {
|
||||
PCIHostState pci_state;
|
||||
struct pci_outbound pob[PPCE500_PCI_NR_POBS];
|
||||
struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
|
||||
uint32_t gasket_time;
|
||||
PCIHostState pci_state;
|
||||
PCIDevice *pci_dev;
|
||||
qemu_irq irq[4];
|
||||
/* mmio maps */
|
||||
int cfgaddr;
|
||||
int cfgdata;
|
||||
int reg;
|
||||
};
|
||||
|
||||
typedef struct PPCE500PCIState PPCE500PCIState;
|
||||
@ -250,7 +254,6 @@ static const VMStateDescription vmstate_ppce500_pci = {
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPCE500PCIState),
|
||||
VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1,
|
||||
vmstate_pci_outbound, struct pci_outbound),
|
||||
VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1,
|
||||
@ -260,60 +263,73 @@ static const VMStateDescription vmstate_ppce500_pci = {
|
||||
}
|
||||
};
|
||||
|
||||
PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
|
||||
static void e500_pci_map(SysBusDevice *dev, target_phys_addr_t base)
|
||||
{
|
||||
PPCE500PCIState *controller;
|
||||
PCIDevice *d;
|
||||
int index;
|
||||
static int ppce500_pci_id;
|
||||
PCIHostState *h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
|
||||
PPCE500PCIState *s = DO_UPCAST(PPCE500PCIState, pci_state, h);
|
||||
|
||||
controller = qemu_mallocz(sizeof(PPCE500PCIState));
|
||||
|
||||
controller->pci_state.bus = pci_register_bus(NULL, "pci",
|
||||
mpc85xx_pci_set_irq,
|
||||
mpc85xx_pci_map_irq,
|
||||
pci_irqs, PCI_DEVFN(0x11, 0),
|
||||
4);
|
||||
d = pci_register_device(controller->pci_state.bus,
|
||||
"host bridge", sizeof(PCIDevice),
|
||||
0, NULL, NULL);
|
||||
|
||||
pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_FREESCALE);
|
||||
pci_config_set_device_id(d->config, PCI_DEVICE_ID_MPC8533E);
|
||||
pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_POWERPC);
|
||||
|
||||
controller->pci_dev = d;
|
||||
|
||||
/* CFGADDR */
|
||||
index = pci_host_conf_register_mmio(&controller->pci_state,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
if (index < 0)
|
||||
goto free;
|
||||
cpu_register_physical_memory(registers + PCIE500_CFGADDR, 4, index);
|
||||
|
||||
/* CFGDATA */
|
||||
index = pci_host_data_register_mmio(&controller->pci_state,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
if (index < 0)
|
||||
goto free;
|
||||
cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index);
|
||||
|
||||
index = cpu_register_io_memory(e500_pci_reg_read,
|
||||
e500_pci_reg_write, controller,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
if (index < 0)
|
||||
goto free;
|
||||
cpu_register_physical_memory(registers + PCIE500_REG_BASE,
|
||||
PCIE500_REG_SIZE, index);
|
||||
|
||||
/* XXX load/save code not tested. */
|
||||
vmstate_register(&d->qdev, ppce500_pci_id++, &vmstate_ppce500_pci,
|
||||
controller);
|
||||
|
||||
return controller->pci_state.bus;
|
||||
|
||||
free:
|
||||
printf("%s error\n", __func__);
|
||||
qemu_free(controller);
|
||||
return NULL;
|
||||
cpu_register_physical_memory(base + PCIE500_CFGADDR, 4, s->cfgaddr);
|
||||
cpu_register_physical_memory(base + PCIE500_CFGDATA, 4, s->cfgdata);
|
||||
cpu_register_physical_memory(base + PCIE500_REG_BASE, PCIE500_REG_SIZE,
|
||||
s->reg);
|
||||
}
|
||||
|
||||
static int e500_pcihost_initfn(SysBusDevice *dev)
|
||||
{
|
||||
PCIHostState *h;
|
||||
PPCE500PCIState *s;
|
||||
PCIBus *b;
|
||||
int i;
|
||||
|
||||
h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
|
||||
s = DO_UPCAST(PPCE500PCIState, pci_state, h);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
|
||||
sysbus_init_irq(dev, &s->irq[i]);
|
||||
}
|
||||
|
||||
b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, mpc85xx_pci_set_irq,
|
||||
mpc85xx_pci_map_irq, s->irq, PCI_DEVFN(0x11, 0), 4);
|
||||
s->pci_state.bus = b;
|
||||
|
||||
pci_create_simple(b, 0, "e500-host-bridge");
|
||||
|
||||
s->cfgaddr = pci_host_conf_register_mmio(&s->pci_state, DEVICE_BIG_ENDIAN);
|
||||
s->cfgdata = pci_host_data_register_mmio(&s->pci_state,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
s->reg = cpu_register_io_memory(e500_pci_reg_read, e500_pci_reg_write, s,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
sysbus_init_mmio_cb(dev, PCIE500_ALL_SIZE, e500_pci_map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int e500_host_bridge_initfn(PCIDevice *dev)
|
||||
{
|
||||
pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_FREESCALE);
|
||||
pci_config_set_device_id(dev->config, PCI_DEVICE_ID_MPC8533E);
|
||||
pci_config_set_class(dev->config, PCI_CLASS_PROCESSOR_POWERPC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PCIDeviceInfo e500_host_bridge_info = {
|
||||
.qdev.name = "e500-host-bridge",
|
||||
.qdev.desc = "Host bridge",
|
||||
.qdev.size = sizeof(PCIDevice),
|
||||
.init = e500_host_bridge_initfn,
|
||||
};
|
||||
|
||||
static SysBusDeviceInfo e500_pcihost_info = {
|
||||
.init = e500_pcihost_initfn,
|
||||
.qdev.name = "e500-pcihost",
|
||||
.qdev.size = sizeof(PPCE500PCIState),
|
||||
.qdev.vmsd = &vmstate_ppce500_pci,
|
||||
};
|
||||
|
||||
static void e500_pci_register(void)
|
||||
{
|
||||
sysbus_register_withprop(&e500_pcihost_info);
|
||||
pci_qdev_register(&e500_host_bridge_info);
|
||||
}
|
||||
device_init(e500_pci_register);
|
||||
|
@ -51,7 +51,7 @@
|
||||
|
||||
#define TIMEBASE_FREQ 512000000ULL
|
||||
|
||||
#define MAX_CPUS 32
|
||||
#define MAX_CPUS 256
|
||||
#define XICS_IRQS 1024
|
||||
|
||||
sPAPREnvironment *spapr;
|
||||
@ -93,7 +93,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
|
||||
/* Root node */
|
||||
_FDT((fdt_begin_node(fdt, "")));
|
||||
_FDT((fdt_property_string(fdt, "device_type", "chrp")));
|
||||
_FDT((fdt_property_string(fdt, "model", "qemu,emulated-pSeries-LPAR")));
|
||||
_FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)")));
|
||||
|
||||
_FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
|
||||
_FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
|
||||
@ -362,8 +362,9 @@ static void ppc_spapr_init(ram_addr_t ram_size,
|
||||
|
||||
for (i = 0; i < MAX_SERIAL_PORTS; i++, irq++) {
|
||||
if (serial_hds[i]) {
|
||||
spapr_vty_create(spapr->vio_bus, i, serial_hds[i],
|
||||
xics_find_qirq(spapr->icp, irq), irq);
|
||||
spapr_vty_create(spapr->vio_bus, SPAPR_VTY_BASE_ADDRESS + i,
|
||||
serial_hds[i], xics_find_qirq(spapr->icp, irq),
|
||||
irq);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -455,8 +455,8 @@ static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr,
|
||||
nret, rtas_r3 + 12 + 4*nargs);
|
||||
}
|
||||
|
||||
spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
|
||||
spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE];
|
||||
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
|
||||
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
|
||||
|
||||
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
|
||||
{
|
||||
|
@ -44,7 +44,8 @@ static void rtas_display_character(sPAPREnvironment *spapr,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
uint8_t c = rtas_ld(args, 0);
|
||||
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, 0);
|
||||
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus,
|
||||
SPAPR_VTY_BASE_ADDRESS);
|
||||
|
||||
if (!sdev) {
|
||||
rtas_st(rets, 0, -1);
|
||||
|
@ -32,6 +32,8 @@ enum VIOsPAPR_TCEAccess {
|
||||
SPAPR_TCE_RW = 3,
|
||||
};
|
||||
|
||||
#define SPAPR_VTY_BASE_ADDRESS 0x30000000
|
||||
|
||||
struct VIOsPAPRDevice;
|
||||
|
||||
typedef struct VIOsPAPR_RTCE {
|
||||
|
@ -603,6 +603,11 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
|
||||
if (err) {
|
||||
fprintf(stderr, "%s: error registering prefix slot: %s\n",
|
||||
__func__, strerror(-err));
|
||||
#ifdef TARGET_PPC
|
||||
fprintf(stderr, "%s: This is probably because your kernel's " \
|
||||
"PAGE_SIZE is too big. Please try to use 4k " \
|
||||
"PAGE_SIZE!\n", __func__);
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
71
monitor.c
71
monitor.c
@ -3466,7 +3466,76 @@ static const MonitorDef monitor_defs[] = {
|
||||
{ "sr13", offsetof(CPUState, sr[13]) },
|
||||
{ "sr14", offsetof(CPUState, sr[14]) },
|
||||
{ "sr15", offsetof(CPUState, sr[15]) },
|
||||
/* Too lazy to put BATs and SPRs ... */
|
||||
/* Too lazy to put BATs... */
|
||||
{ "pvr", offsetof(CPUState, spr[SPR_PVR]) },
|
||||
|
||||
{ "srr0", offsetof(CPUState, spr[SPR_SRR0]) },
|
||||
{ "srr1", offsetof(CPUState, spr[SPR_SRR1]) },
|
||||
{ "sprg0", offsetof(CPUState, spr[SPR_SPRG0]) },
|
||||
{ "sprg1", offsetof(CPUState, spr[SPR_SPRG1]) },
|
||||
{ "sprg2", offsetof(CPUState, spr[SPR_SPRG2]) },
|
||||
{ "sprg3", offsetof(CPUState, spr[SPR_SPRG3]) },
|
||||
{ "sprg4", offsetof(CPUState, spr[SPR_SPRG4]) },
|
||||
{ "sprg5", offsetof(CPUState, spr[SPR_SPRG5]) },
|
||||
{ "sprg6", offsetof(CPUState, spr[SPR_SPRG6]) },
|
||||
{ "sprg7", offsetof(CPUState, spr[SPR_SPRG7]) },
|
||||
{ "pid", offsetof(CPUState, spr[SPR_BOOKE_PID]) },
|
||||
{ "csrr0", offsetof(CPUState, spr[SPR_BOOKE_CSRR0]) },
|
||||
{ "csrr1", offsetof(CPUState, spr[SPR_BOOKE_CSRR1]) },
|
||||
{ "esr", offsetof(CPUState, spr[SPR_BOOKE_ESR]) },
|
||||
{ "dear", offsetof(CPUState, spr[SPR_BOOKE_DEAR]) },
|
||||
{ "mcsr", offsetof(CPUState, spr[SPR_BOOKE_MCSR]) },
|
||||
{ "tsr", offsetof(CPUState, spr[SPR_BOOKE_TSR]) },
|
||||
{ "tcr", offsetof(CPUState, spr[SPR_BOOKE_TCR]) },
|
||||
{ "vrsave", offsetof(CPUState, spr[SPR_VRSAVE]) },
|
||||
{ "pir", offsetof(CPUState, spr[SPR_BOOKE_PIR]) },
|
||||
{ "mcsrr0", offsetof(CPUState, spr[SPR_BOOKE_MCSRR0]) },
|
||||
{ "mcsrr1", offsetof(CPUState, spr[SPR_BOOKE_MCSRR1]) },
|
||||
{ "decar", offsetof(CPUState, spr[SPR_BOOKE_DECAR]) },
|
||||
{ "ivpr", offsetof(CPUState, spr[SPR_BOOKE_IVPR]) },
|
||||
{ "epcr", offsetof(CPUState, spr[SPR_BOOKE_EPCR]) },
|
||||
{ "sprg8", offsetof(CPUState, spr[SPR_BOOKE_SPRG8]) },
|
||||
{ "ivor0", offsetof(CPUState, spr[SPR_BOOKE_IVOR0]) },
|
||||
{ "ivor1", offsetof(CPUState, spr[SPR_BOOKE_IVOR1]) },
|
||||
{ "ivor2", offsetof(CPUState, spr[SPR_BOOKE_IVOR2]) },
|
||||
{ "ivor3", offsetof(CPUState, spr[SPR_BOOKE_IVOR3]) },
|
||||
{ "ivor4", offsetof(CPUState, spr[SPR_BOOKE_IVOR4]) },
|
||||
{ "ivor5", offsetof(CPUState, spr[SPR_BOOKE_IVOR5]) },
|
||||
{ "ivor6", offsetof(CPUState, spr[SPR_BOOKE_IVOR6]) },
|
||||
{ "ivor7", offsetof(CPUState, spr[SPR_BOOKE_IVOR7]) },
|
||||
{ "ivor8", offsetof(CPUState, spr[SPR_BOOKE_IVOR8]) },
|
||||
{ "ivor9", offsetof(CPUState, spr[SPR_BOOKE_IVOR9]) },
|
||||
{ "ivor10", offsetof(CPUState, spr[SPR_BOOKE_IVOR10]) },
|
||||
{ "ivor11", offsetof(CPUState, spr[SPR_BOOKE_IVOR11]) },
|
||||
{ "ivor12", offsetof(CPUState, spr[SPR_BOOKE_IVOR12]) },
|
||||
{ "ivor13", offsetof(CPUState, spr[SPR_BOOKE_IVOR13]) },
|
||||
{ "ivor14", offsetof(CPUState, spr[SPR_BOOKE_IVOR14]) },
|
||||
{ "ivor15", offsetof(CPUState, spr[SPR_BOOKE_IVOR15]) },
|
||||
{ "ivor32", offsetof(CPUState, spr[SPR_BOOKE_IVOR32]) },
|
||||
{ "ivor33", offsetof(CPUState, spr[SPR_BOOKE_IVOR33]) },
|
||||
{ "ivor34", offsetof(CPUState, spr[SPR_BOOKE_IVOR34]) },
|
||||
{ "ivor35", offsetof(CPUState, spr[SPR_BOOKE_IVOR35]) },
|
||||
{ "ivor36", offsetof(CPUState, spr[SPR_BOOKE_IVOR36]) },
|
||||
{ "ivor37", offsetof(CPUState, spr[SPR_BOOKE_IVOR37]) },
|
||||
{ "mas0", offsetof(CPUState, spr[SPR_BOOKE_MAS0]) },
|
||||
{ "mas1", offsetof(CPUState, spr[SPR_BOOKE_MAS1]) },
|
||||
{ "mas2", offsetof(CPUState, spr[SPR_BOOKE_MAS2]) },
|
||||
{ "mas3", offsetof(CPUState, spr[SPR_BOOKE_MAS3]) },
|
||||
{ "mas4", offsetof(CPUState, spr[SPR_BOOKE_MAS4]) },
|
||||
{ "mas6", offsetof(CPUState, spr[SPR_BOOKE_MAS6]) },
|
||||
{ "mas7", offsetof(CPUState, spr[SPR_BOOKE_MAS7]) },
|
||||
{ "mmucfg", offsetof(CPUState, spr[SPR_MMUCFG]) },
|
||||
{ "tlb0cfg", offsetof(CPUState, spr[SPR_BOOKE_TLB0CFG]) },
|
||||
{ "tlb1cfg", offsetof(CPUState, spr[SPR_BOOKE_TLB1CFG]) },
|
||||
{ "epr", offsetof(CPUState, spr[SPR_BOOKE_EPR]) },
|
||||
{ "eplc", offsetof(CPUState, spr[SPR_BOOKE_EPLC]) },
|
||||
{ "epsc", offsetof(CPUState, spr[SPR_BOOKE_EPSC]) },
|
||||
{ "svr", offsetof(CPUState, spr[SPR_E500_SVR]) },
|
||||
{ "mcar", offsetof(CPUState, spr[SPR_Exxx_MCAR]) },
|
||||
{ "pid1", offsetof(CPUState, spr[SPR_BOOKE_PID1]) },
|
||||
{ "pid2", offsetof(CPUState, spr[SPR_BOOKE_PID2]) },
|
||||
{ "hid0", offsetof(CPUState, spr[SPR_HID0]) },
|
||||
|
||||
#elif defined(TARGET_SPARC)
|
||||
{ "g0", offsetof(CPUState, gregs[0]) },
|
||||
{ "g1", offsetof(CPUState, gregs[1]) },
|
||||
|
308
target-ppc/cpu.h
308
target-ppc/cpu.h
@ -108,8 +108,8 @@ enum powerpc_mmu_t {
|
||||
POWERPC_MMU_MPC8xx = 0x00000007,
|
||||
/* BookE MMU model */
|
||||
POWERPC_MMU_BOOKE = 0x00000008,
|
||||
/* BookE FSL MMU model */
|
||||
POWERPC_MMU_BOOKE_FSL = 0x00000009,
|
||||
/* BookE 2.06 MMU model */
|
||||
POWERPC_MMU_BOOKE206 = 0x00000009,
|
||||
/* PowerPC 601 MMU model (specific BATs format) */
|
||||
POWERPC_MMU_601 = 0x0000000A,
|
||||
#if defined(TARGET_PPC64)
|
||||
@ -420,6 +420,7 @@ struct ppc_slb_t {
|
||||
#define MSR_CM 31 /* Computation mode for BookE hflags */
|
||||
#define MSR_ICM 30 /* Interrupt computation mode for BookE */
|
||||
#define MSR_THV 29 /* hypervisor state for 32 bits PowerPC hflags */
|
||||
#define MSR_GS 28 /* guest state for BookE */
|
||||
#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */
|
||||
#define MSR_VR 25 /* altivec available x hflags */
|
||||
#define MSR_SPE 25 /* SPE enable for BookE x hflags */
|
||||
@ -457,6 +458,7 @@ struct ppc_slb_t {
|
||||
#define msr_cm ((env->msr >> MSR_CM) & 1)
|
||||
#define msr_icm ((env->msr >> MSR_ICM) & 1)
|
||||
#define msr_thv ((env->msr >> MSR_THV) & 1)
|
||||
#define msr_gs ((env->msr >> MSR_GS) & 1)
|
||||
#define msr_ucle ((env->msr >> MSR_UCLE) & 1)
|
||||
#define msr_vr ((env->msr >> MSR_VR) & 1)
|
||||
#define msr_spe ((env->msr >> MSR_SPE) & 1)
|
||||
@ -605,6 +607,224 @@ enum {
|
||||
#define vscr_nj (((env->vscr) >> VSCR_NJ) & 0x1)
|
||||
#define vscr_sat (((env->vscr) >> VSCR_SAT) & 0x1)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* BookE e500 MMU registers */
|
||||
|
||||
#define MAS0_NV_SHIFT 0
|
||||
#define MAS0_NV_MASK (0xfff << MAS0_NV_SHIFT)
|
||||
|
||||
#define MAS0_WQ_SHIFT 12
|
||||
#define MAS0_WQ_MASK (3 << MAS0_WQ_SHIFT)
|
||||
/* Write TLB entry regardless of reservation */
|
||||
#define MAS0_WQ_ALWAYS (0 << MAS0_WQ_SHIFT)
|
||||
/* Write TLB entry only already in use */
|
||||
#define MAS0_WQ_COND (1 << MAS0_WQ_SHIFT)
|
||||
/* Clear TLB entry */
|
||||
#define MAS0_WQ_CLR_RSRV (2 << MAS0_WQ_SHIFT)
|
||||
|
||||
#define MAS0_HES_SHIFT 14
|
||||
#define MAS0_HES (1 << MAS0_HES_SHIFT)
|
||||
|
||||
#define MAS0_ESEL_SHIFT 16
|
||||
#define MAS0_ESEL_MASK (0xfff << MAS0_ESEL_SHIFT)
|
||||
|
||||
#define MAS0_TLBSEL_SHIFT 28
|
||||
#define MAS0_TLBSEL_MASK (3 << MAS0_TLBSEL_SHIFT)
|
||||
#define MAS0_TLBSEL_TLB0 (0 << MAS0_TLBSEL_SHIFT)
|
||||
#define MAS0_TLBSEL_TLB1 (1 << MAS0_TLBSEL_SHIFT)
|
||||
#define MAS0_TLBSEL_TLB2 (2 << MAS0_TLBSEL_SHIFT)
|
||||
#define MAS0_TLBSEL_TLB3 (3 << MAS0_TLBSEL_SHIFT)
|
||||
|
||||
#define MAS0_ATSEL_SHIFT 31
|
||||
#define MAS0_ATSEL (1 << MAS0_ATSEL_SHIFT)
|
||||
#define MAS0_ATSEL_TLB 0
|
||||
#define MAS0_ATSEL_LRAT MAS0_ATSEL
|
||||
|
||||
#define MAS1_TSIZE_SHIFT 8
|
||||
#define MAS1_TSIZE_MASK (0xf << MAS1_TSIZE_SHIFT)
|
||||
|
||||
#define MAS1_TS_SHIFT 12
|
||||
#define MAS1_TS (1 << MAS1_TS_SHIFT)
|
||||
|
||||
#define MAS1_IND_SHIFT 13
|
||||
#define MAS1_IND (1 << MAS1_IND_SHIFT)
|
||||
|
||||
#define MAS1_TID_SHIFT 16
|
||||
#define MAS1_TID_MASK (0x3fff << MAS1_TID_SHIFT)
|
||||
|
||||
#define MAS1_IPROT_SHIFT 30
|
||||
#define MAS1_IPROT (1 << MAS1_IPROT_SHIFT)
|
||||
|
||||
#define MAS1_VALID_SHIFT 31
|
||||
#define MAS1_VALID 0x80000000
|
||||
|
||||
#define MAS2_EPN_SHIFT 12
|
||||
#define MAS2_EPN_MASK (0xfffff << MAS2_EPN_SHIFT)
|
||||
|
||||
#define MAS2_ACM_SHIFT 6
|
||||
#define MAS2_ACM (1 << MAS2_ACM_SHIFT)
|
||||
|
||||
#define MAS2_VLE_SHIFT 5
|
||||
#define MAS2_VLE (1 << MAS2_VLE_SHIFT)
|
||||
|
||||
#define MAS2_W_SHIFT 4
|
||||
#define MAS2_W (1 << MAS2_W_SHIFT)
|
||||
|
||||
#define MAS2_I_SHIFT 3
|
||||
#define MAS2_I (1 << MAS2_I_SHIFT)
|
||||
|
||||
#define MAS2_M_SHIFT 2
|
||||
#define MAS2_M (1 << MAS2_M_SHIFT)
|
||||
|
||||
#define MAS2_G_SHIFT 1
|
||||
#define MAS2_G (1 << MAS2_G_SHIFT)
|
||||
|
||||
#define MAS2_E_SHIFT 0
|
||||
#define MAS2_E (1 << MAS2_E_SHIFT)
|
||||
|
||||
#define MAS3_RPN_SHIFT 12
|
||||
#define MAS3_RPN_MASK (0xfffff << MAS3_RPN_SHIFT)
|
||||
|
||||
#define MAS3_U0 0x00000200
|
||||
#define MAS3_U1 0x00000100
|
||||
#define MAS3_U2 0x00000080
|
||||
#define MAS3_U3 0x00000040
|
||||
#define MAS3_UX 0x00000020
|
||||
#define MAS3_SX 0x00000010
|
||||
#define MAS3_UW 0x00000008
|
||||
#define MAS3_SW 0x00000004
|
||||
#define MAS3_UR 0x00000002
|
||||
#define MAS3_SR 0x00000001
|
||||
#define MAS3_SPSIZE_SHIFT 1
|
||||
#define MAS3_SPSIZE_MASK (0x3e << MAS3_SPSIZE_SHIFT)
|
||||
|
||||
#define MAS4_TLBSELD_SHIFT MAS0_TLBSEL_SHIFT
|
||||
#define MAS4_TLBSELD_MASK MAS0_TLBSEL_MASK
|
||||
#define MAS4_TIDSELD_MASK 0x00030000
|
||||
#define MAS4_TIDSELD_PID0 0x00000000
|
||||
#define MAS4_TIDSELD_PID1 0x00010000
|
||||
#define MAS4_TIDSELD_PID2 0x00020000
|
||||
#define MAS4_TIDSELD_PIDZ 0x00030000
|
||||
#define MAS4_INDD 0x00008000 /* Default IND */
|
||||
#define MAS4_TSIZED_SHIFT MAS1_TSIZE_SHIFT
|
||||
#define MAS4_TSIZED_MASK MAS1_TSIZE_MASK
|
||||
#define MAS4_ACMD 0x00000040
|
||||
#define MAS4_VLED 0x00000020
|
||||
#define MAS4_WD 0x00000010
|
||||
#define MAS4_ID 0x00000008
|
||||
#define MAS4_MD 0x00000004
|
||||
#define MAS4_GD 0x00000002
|
||||
#define MAS4_ED 0x00000001
|
||||
#define MAS4_WIMGED_MASK 0x0000001f /* Default WIMGE */
|
||||
#define MAS4_WIMGED_SHIFT 0
|
||||
|
||||
#define MAS5_SGS 0x80000000
|
||||
#define MAS5_SLPID_MASK 0x00000fff
|
||||
|
||||
#define MAS6_SPID0 0x3fff0000
|
||||
#define MAS6_SPID1 0x00007ffe
|
||||
#define MAS6_ISIZE(x) MAS1_TSIZE(x)
|
||||
#define MAS6_SAS 0x00000001
|
||||
#define MAS6_SPID MAS6_SPID0
|
||||
#define MAS6_SIND 0x00000002 /* Indirect page */
|
||||
#define MAS6_SIND_SHIFT 1
|
||||
#define MAS6_SPID_MASK 0x3fff0000
|
||||
#define MAS6_SPID_SHIFT 16
|
||||
#define MAS6_ISIZE_MASK 0x00000f80
|
||||
#define MAS6_ISIZE_SHIFT 7
|
||||
|
||||
#define MAS7_RPN 0xffffffff
|
||||
|
||||
#define MAS8_TGS 0x80000000
|
||||
#define MAS8_VF 0x40000000
|
||||
#define MAS8_TLBPID 0x00000fff
|
||||
|
||||
/* Bit definitions for MMUCFG */
|
||||
#define MMUCFG_MAVN 0x00000003 /* MMU Architecture Version Number */
|
||||
#define MMUCFG_MAVN_V1 0x00000000 /* v1.0 */
|
||||
#define MMUCFG_MAVN_V2 0x00000001 /* v2.0 */
|
||||
#define MMUCFG_NTLBS 0x0000000c /* Number of TLBs */
|
||||
#define MMUCFG_PIDSIZE 0x000007c0 /* PID Reg Size */
|
||||
#define MMUCFG_TWC 0x00008000 /* TLB Write Conditional (v2.0) */
|
||||
#define MMUCFG_LRAT 0x00010000 /* LRAT Supported (v2.0) */
|
||||
#define MMUCFG_RASIZE 0x00fe0000 /* Real Addr Size */
|
||||
#define MMUCFG_LPIDSIZE 0x0f000000 /* LPID Reg Size */
|
||||
|
||||
/* Bit definitions for MMUCSR0 */
|
||||
#define MMUCSR0_TLB1FI 0x00000002 /* TLB1 Flash invalidate */
|
||||
#define MMUCSR0_TLB0FI 0x00000004 /* TLB0 Flash invalidate */
|
||||
#define MMUCSR0_TLB2FI 0x00000040 /* TLB2 Flash invalidate */
|
||||
#define MMUCSR0_TLB3FI 0x00000020 /* TLB3 Flash invalidate */
|
||||
#define MMUCSR0_TLBFI (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
|
||||
MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
|
||||
#define MMUCSR0_TLB0PS 0x00000780 /* TLB0 Page Size */
|
||||
#define MMUCSR0_TLB1PS 0x00007800 /* TLB1 Page Size */
|
||||
#define MMUCSR0_TLB2PS 0x00078000 /* TLB2 Page Size */
|
||||
#define MMUCSR0_TLB3PS 0x00780000 /* TLB3 Page Size */
|
||||
|
||||
/* TLBnCFG encoding */
|
||||
#define TLBnCFG_N_ENTRY 0x00000fff /* number of entries */
|
||||
#define TLBnCFG_HES 0x00002000 /* HW select supported */
|
||||
#define TLBnCFG_AVAIL 0x00004000 /* variable page size */
|
||||
#define TLBnCFG_IPROT 0x00008000 /* IPROT supported */
|
||||
#define TLBnCFG_GTWE 0x00010000 /* Guest can write */
|
||||
#define TLBnCFG_IND 0x00020000 /* IND entries supported */
|
||||
#define TLBnCFG_PT 0x00040000 /* Can load from page table */
|
||||
#define TLBnCFG_MINSIZE 0x00f00000 /* Minimum Page Size (v1.0) */
|
||||
#define TLBnCFG_MINSIZE_SHIFT 20
|
||||
#define TLBnCFG_MAXSIZE 0x000f0000 /* Maximum Page Size (v1.0) */
|
||||
#define TLBnCFG_MAXSIZE_SHIFT 16
|
||||
#define TLBnCFG_ASSOC 0xff000000 /* Associativity */
|
||||
#define TLBnCFG_ASSOC_SHIFT 24
|
||||
|
||||
/* TLBnPS encoding */
|
||||
#define TLBnPS_4K 0x00000004
|
||||
#define TLBnPS_8K 0x00000008
|
||||
#define TLBnPS_16K 0x00000010
|
||||
#define TLBnPS_32K 0x00000020
|
||||
#define TLBnPS_64K 0x00000040
|
||||
#define TLBnPS_128K 0x00000080
|
||||
#define TLBnPS_256K 0x00000100
|
||||
#define TLBnPS_512K 0x00000200
|
||||
#define TLBnPS_1M 0x00000400
|
||||
#define TLBnPS_2M 0x00000800
|
||||
#define TLBnPS_4M 0x00001000
|
||||
#define TLBnPS_8M 0x00002000
|
||||
#define TLBnPS_16M 0x00004000
|
||||
#define TLBnPS_32M 0x00008000
|
||||
#define TLBnPS_64M 0x00010000
|
||||
#define TLBnPS_128M 0x00020000
|
||||
#define TLBnPS_256M 0x00040000
|
||||
#define TLBnPS_512M 0x00080000
|
||||
#define TLBnPS_1G 0x00100000
|
||||
#define TLBnPS_2G 0x00200000
|
||||
#define TLBnPS_4G 0x00400000
|
||||
#define TLBnPS_8G 0x00800000
|
||||
#define TLBnPS_16G 0x01000000
|
||||
#define TLBnPS_32G 0x02000000
|
||||
#define TLBnPS_64G 0x04000000
|
||||
#define TLBnPS_128G 0x08000000
|
||||
#define TLBnPS_256G 0x10000000
|
||||
|
||||
/* tlbilx action encoding */
|
||||
#define TLBILX_T_ALL 0
|
||||
#define TLBILX_T_TID 1
|
||||
#define TLBILX_T_FULLMATCH 3
|
||||
#define TLBILX_T_CLASS0 4
|
||||
#define TLBILX_T_CLASS1 5
|
||||
#define TLBILX_T_CLASS2 6
|
||||
#define TLBILX_T_CLASS3 7
|
||||
|
||||
/* BookE 2.06 helper defines */
|
||||
|
||||
#define BOOKE206_FLUSH_TLB0 (1 << 0)
|
||||
#define BOOKE206_FLUSH_TLB1 (1 << 1)
|
||||
#define BOOKE206_FLUSH_TLB2 (1 << 2)
|
||||
#define BOOKE206_FLUSH_TLB3 (1 << 3)
|
||||
|
||||
/* number of possible TLBs */
|
||||
#define BOOKE206_MAX_TLBN 4
|
||||
|
||||
/*****************************************************************************/
|
||||
/* The whole PowerPC CPU context */
|
||||
#define NB_MMU_MODES 3
|
||||
@ -676,7 +896,7 @@ struct CPUPPCState {
|
||||
int nb_BATs;
|
||||
target_ulong DBAT[2][8];
|
||||
target_ulong IBAT[2][8];
|
||||
/* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */
|
||||
/* PowerPC TLB registers (for 4xx, e500 and 60x software driven TLBs) */
|
||||
int nb_tlb; /* Total number of TLB */
|
||||
int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
|
||||
int nb_ways; /* Number of ways in the TLB set */
|
||||
@ -720,6 +940,7 @@ struct CPUPPCState {
|
||||
int bfd_mach;
|
||||
uint32_t flags;
|
||||
uint64_t insns_flags;
|
||||
uint64_t insns_flags2;
|
||||
|
||||
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
|
||||
target_phys_addr_t vpa;
|
||||
@ -853,6 +1074,10 @@ 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);
|
||||
void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot);
|
||||
int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
|
||||
target_phys_addr_t *raddrp, target_ulong address,
|
||||
uint32_t pid, int ext, int i);
|
||||
void ppc_tlb_invalidate_all (CPUPPCState *env);
|
||||
void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
|
||||
#if defined(TARGET_PPC64)
|
||||
@ -1016,6 +1241,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
|
||||
#define SPR_HSPRG1 (0x131)
|
||||
#define SPR_HDSISR (0x132)
|
||||
#define SPR_HDAR (0x133)
|
||||
#define SPR_BOOKE_EPCR (0x133)
|
||||
#define SPR_SPURR (0x134)
|
||||
#define SPR_BOOKE_DBCR0 (0x134)
|
||||
#define SPR_IBCR (0x135)
|
||||
@ -1543,6 +1769,11 @@ enum {
|
||||
PPC_DCRUX = 0x4000000000000000ULL,
|
||||
/* popcntw and popcntd instructions */
|
||||
PPC_POPCNTWD = 0x8000000000000000ULL,
|
||||
|
||||
/* extended type values */
|
||||
|
||||
/* BookE 2.06 PowerPC specification */
|
||||
PPC2_BOOKE206 = 0x0000000000000001ULL,
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -1695,6 +1926,77 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
static inline int booke206_tlbe_id(CPUState *env, ppcemb_tlb_t *tlbe)
|
||||
{
|
||||
ulong tlbel = (ulong)tlbe;
|
||||
ulong tlbl = (ulong)env->tlb;
|
||||
|
||||
return (tlbel - tlbl) / sizeof(env->tlb[0]);
|
||||
}
|
||||
|
||||
static inline int booke206_tlb_size(CPUState *env, int tlbn)
|
||||
{
|
||||
uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
|
||||
int r = tlbncfg & TLBnCFG_N_ENTRY;
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int booke206_tlb_ways(CPUState *env, int tlbn)
|
||||
{
|
||||
uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
|
||||
int r = tlbncfg >> TLBnCFG_ASSOC_SHIFT;
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int booke206_tlbe_to_tlbn(CPUState *env, ppcemb_tlb_t *tlbe)
|
||||
{
|
||||
int id = booke206_tlbe_id(env, tlbe);
|
||||
int end = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
|
||||
end += booke206_tlb_size(env, i);
|
||||
if (id < end) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
cpu_abort(env, "Unknown TLBe: %d\n", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int booke206_tlbe_to_way(CPUState *env, ppcemb_tlb_t *tlb)
|
||||
{
|
||||
int tlbn = booke206_tlbe_to_tlbn(env, tlb);
|
||||
int tlbid = booke206_tlbe_id(env, tlb);
|
||||
return tlbid & (booke206_tlb_ways(env, tlbn) - 1);
|
||||
}
|
||||
|
||||
static inline ppcemb_tlb_t *booke206_get_tlbe(CPUState *env, const int tlbn,
|
||||
target_ulong ea, int way)
|
||||
{
|
||||
int r;
|
||||
uint32_t ways = booke206_tlb_ways(env, tlbn);
|
||||
int ways_bits = ffs(ways) - 1;
|
||||
int tlb_bits = ffs(booke206_tlb_size(env, tlbn)) - 1;
|
||||
int i;
|
||||
|
||||
way &= ways - 1;
|
||||
ea >>= MAS2_EPN_SHIFT;
|
||||
ea &= (1 << (tlb_bits - ways_bits)) - 1;
|
||||
r = (ea << ways_bits) | way;
|
||||
|
||||
/* bump up to tlbn index */
|
||||
for (i = 0; i < tlbn; i++) {
|
||||
r += booke206_tlb_size(env, i);
|
||||
}
|
||||
|
||||
return &env->tlb[r].tlbe;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extern void (*cpu_ppc_hypercall)(CPUState *);
|
||||
|
||||
#endif /* !defined (__CPU_PPC_H__) */
|
||||
|
@ -993,10 +993,10 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
|
||||
}
|
||||
|
||||
/* Generic TLB check function for embedded PowerPC implementations */
|
||||
static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
|
||||
target_phys_addr_t *raddrp,
|
||||
target_ulong address, uint32_t pid, int ext,
|
||||
int i)
|
||||
int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
|
||||
target_phys_addr_t *raddrp,
|
||||
target_ulong address, uint32_t pid, int ext,
|
||||
int i)
|
||||
{
|
||||
target_ulong mask;
|
||||
|
||||
@ -1006,8 +1006,8 @@ static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
|
||||
}
|
||||
mask = ~(tlb->size - 1);
|
||||
LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
|
||||
" " TARGET_FMT_lx " %u\n", __func__, i, address, pid, tlb->EPN,
|
||||
mask, (uint32_t)tlb->PID);
|
||||
" " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
|
||||
mask, (uint32_t)tlb->PID, tlb->prot);
|
||||
/* Check PID */
|
||||
if (tlb->PID != 0 && tlb->PID != pid)
|
||||
return -1;
|
||||
@ -1153,48 +1153,164 @@ void store_40x_sler (CPUPPCState *env, uint32_t val)
|
||||
env->spr[SPR_405_SLER] = val;
|
||||
}
|
||||
|
||||
static inline int mmubooke_check_tlb (CPUState *env, ppcemb_tlb_t *tlb,
|
||||
target_phys_addr_t *raddr, int *prot,
|
||||
target_ulong address, int rw,
|
||||
int access_type, int i)
|
||||
{
|
||||
int ret, _prot;
|
||||
|
||||
if (ppcemb_tlb_check(env, tlb, raddr, address,
|
||||
env->spr[SPR_BOOKE_PID],
|
||||
!env->nb_pids, i) >= 0) {
|
||||
goto found_tlb;
|
||||
}
|
||||
|
||||
if (env->spr[SPR_BOOKE_PID1] &&
|
||||
ppcemb_tlb_check(env, tlb, raddr, address,
|
||||
env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
|
||||
goto found_tlb;
|
||||
}
|
||||
|
||||
if (env->spr[SPR_BOOKE_PID2] &&
|
||||
ppcemb_tlb_check(env, tlb, raddr, address,
|
||||
env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
|
||||
goto found_tlb;
|
||||
}
|
||||
|
||||
LOG_SWTLB("%s: TLB entry not found\n", __func__);
|
||||
return -1;
|
||||
|
||||
found_tlb:
|
||||
|
||||
if (msr_pr != 0) {
|
||||
_prot = tlb->prot & 0xF;
|
||||
} else {
|
||||
_prot = (tlb->prot >> 4) & 0xF;
|
||||
}
|
||||
|
||||
/* Check the address space */
|
||||
if (access_type == ACCESS_CODE) {
|
||||
if (msr_ir != (tlb->attr & 1)) {
|
||||
LOG_SWTLB("%s: AS doesn't match\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*prot = _prot;
|
||||
if (_prot & PAGE_EXEC) {
|
||||
LOG_SWTLB("%s: good TLB!\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
|
||||
ret = -3;
|
||||
} else {
|
||||
if (msr_dr != (tlb->attr & 1)) {
|
||||
LOG_SWTLB("%s: AS doesn't match\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*prot = _prot;
|
||||
if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
|
||||
LOG_SWTLB("%s: found TLB!\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
|
||||
ret = -2;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
target_ulong address, int rw,
|
||||
int access_type)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
target_phys_addr_t raddr;
|
||||
int i, prot, ret;
|
||||
int i, ret;
|
||||
|
||||
ret = -1;
|
||||
raddr = (target_phys_addr_t)-1ULL;
|
||||
for (i = 0; i < env->nb_tlb; i++) {
|
||||
tlb = &env->tlb[i].tlbe;
|
||||
if (ppcemb_tlb_check(env, tlb, &raddr, address,
|
||||
env->spr[SPR_BOOKE_PID], 1, i) < 0)
|
||||
continue;
|
||||
if (msr_pr != 0)
|
||||
prot = tlb->prot & 0xF;
|
||||
else
|
||||
prot = (tlb->prot >> 4) & 0xF;
|
||||
/* Check the address space */
|
||||
if (access_type == ACCESS_CODE) {
|
||||
if (msr_ir != (tlb->attr & 1))
|
||||
continue;
|
||||
ctx->prot = prot;
|
||||
if (prot & PAGE_EXEC) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
ret = -3;
|
||||
} else {
|
||||
if (msr_dr != (tlb->attr & 1))
|
||||
continue;
|
||||
ctx->prot = prot;
|
||||
if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
ret = -2;
|
||||
ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
|
||||
access_type, i);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret >= 0)
|
||||
|
||||
if (ret >= 0) {
|
||||
ctx->raddr = raddr;
|
||||
LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
|
||||
" %d %d\n", __func__, address, ctx->raddr, ctx->prot,
|
||||
ret);
|
||||
} else {
|
||||
LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
|
||||
" %d %d\n", __func__, address, raddr, ctx->prot, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot)
|
||||
{
|
||||
int tlb_size;
|
||||
int i, j;
|
||||
ppc_tlb_t *tlb = env->tlb;
|
||||
|
||||
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
|
||||
if (flags & (1 << i)) {
|
||||
tlb_size = booke206_tlb_size(env, i);
|
||||
for (j = 0; j < tlb_size; j++) {
|
||||
if (!check_iprot || !(tlb[j].tlbe.attr & MAS1_IPROT)) {
|
||||
tlb[j].tlbe.prot = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
tlb += booke206_tlb_size(env, i);
|
||||
}
|
||||
|
||||
tlb_flush(env, 1);
|
||||
}
|
||||
|
||||
static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx,
|
||||
target_ulong address, int rw,
|
||||
int access_type)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
target_phys_addr_t raddr;
|
||||
int i, j, ret;
|
||||
|
||||
ret = -1;
|
||||
raddr = (target_phys_addr_t)-1ULL;
|
||||
|
||||
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
|
||||
int ways = booke206_tlb_ways(env, i);
|
||||
|
||||
for (j = 0; j < ways; j++) {
|
||||
tlb = booke206_get_tlbe(env, i, address, j);
|
||||
ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
|
||||
access_type, j);
|
||||
if (ret != -1) {
|
||||
goto found_tlb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found_tlb:
|
||||
|
||||
if (ret >= 0) {
|
||||
ctx->raddr = raddr;
|
||||
LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
|
||||
" %d %d\n", __func__, address, ctx->raddr, ctx->prot,
|
||||
ret);
|
||||
} else {
|
||||
LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
|
||||
" %d %d\n", __func__, address, raddr, ctx->prot, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1254,9 +1370,8 @@ static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MPC8xx MMU model is not implemented\n");
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE_FSL:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "BookE FSL MMU model not implemented\n");
|
||||
case POWERPC_MMU_BOOKE206:
|
||||
cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
|
||||
break;
|
||||
default:
|
||||
cpu_abort(env, "Unknown or invalid MMU model\n");
|
||||
@ -1281,6 +1396,9 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
|
||||
IS and DS bits only affect the address space. */
|
||||
ret = mmubooke_get_physical_address(env, ctx, eaddr,
|
||||
rw, access_type);
|
||||
} else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
|
||||
ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
|
||||
access_type);
|
||||
} else {
|
||||
/* No address translation. */
|
||||
ret = check_physical(env, ctx, eaddr, rw);
|
||||
@ -1314,14 +1432,14 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
|
||||
ret = mmubooke_get_physical_address(env, ctx, eaddr,
|
||||
rw, access_type);
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE206:
|
||||
ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
|
||||
access_type);
|
||||
break;
|
||||
case POWERPC_MMU_MPC8xx:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MPC8xx MMU model is not implemented\n");
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE_FSL:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "BookE FSL MMU model not implemented\n");
|
||||
return -1;
|
||||
case POWERPC_MMU_REAL:
|
||||
cpu_abort(env, "PowerPC in real mode do not do any translation\n");
|
||||
return -1;
|
||||
@ -1348,6 +1466,46 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
|
||||
return ctx.raddr & TARGET_PAGE_MASK;
|
||||
}
|
||||
|
||||
static void booke206_update_mas_tlb_miss(CPUState *env, target_ulong address,
|
||||
int rw)
|
||||
{
|
||||
env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
|
||||
env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
|
||||
env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
|
||||
env->spr[SPR_BOOKE_MAS3] = 0;
|
||||
env->spr[SPR_BOOKE_MAS6] = 0;
|
||||
env->spr[SPR_BOOKE_MAS7] = 0;
|
||||
|
||||
/* AS */
|
||||
if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
|
||||
env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
|
||||
env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
|
||||
}
|
||||
|
||||
env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
|
||||
env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
|
||||
|
||||
switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
|
||||
case MAS4_TIDSELD_PID0:
|
||||
env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
|
||||
break;
|
||||
case MAS4_TIDSELD_PID1:
|
||||
env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
|
||||
break;
|
||||
case MAS4_TIDSELD_PID2:
|
||||
env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
|
||||
break;
|
||||
}
|
||||
|
||||
env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
|
||||
|
||||
/* next victim logic */
|
||||
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
|
||||
env->last_way++;
|
||||
env->last_way &= booke206_tlb_ways(env, 0) - 1;
|
||||
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
|
||||
}
|
||||
|
||||
/* Perform address translation */
|
||||
int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
int mmu_idx, int is_softmmu)
|
||||
@ -1403,15 +1561,14 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
env->exception_index = POWERPC_EXCP_ISI;
|
||||
env->error_code = 0x40000000;
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE206:
|
||||
booke206_update_mas_tlb_miss(env, address, rw);
|
||||
/* fall through */
|
||||
case POWERPC_MMU_BOOKE:
|
||||
env->exception_index = POWERPC_EXCP_ITLB;
|
||||
env->error_code = 0;
|
||||
env->spr[SPR_BOOKE_DEAR] = address;
|
||||
return -1;
|
||||
case POWERPC_MMU_BOOKE_FSL:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "BookE FSL MMU model is not implemented\n");
|
||||
return -1;
|
||||
case POWERPC_MMU_MPC8xx:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MPC8xx MMU model is not implemented\n");
|
||||
@ -1432,7 +1589,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
break;
|
||||
case -3:
|
||||
/* No execute protection violation */
|
||||
if (env->mmu_model == POWERPC_MMU_BOOKE) {
|
||||
if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
|
||||
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
|
||||
env->spr[SPR_BOOKE_ESR] = 0x00000000;
|
||||
}
|
||||
env->exception_index = POWERPC_EXCP_ISI;
|
||||
@ -1522,16 +1680,15 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MPC8xx MMU model is not implemented\n");
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE206:
|
||||
booke206_update_mas_tlb_miss(env, address, rw);
|
||||
/* fall through */
|
||||
case POWERPC_MMU_BOOKE:
|
||||
env->exception_index = POWERPC_EXCP_DTLB;
|
||||
env->error_code = 0;
|
||||
env->spr[SPR_BOOKE_DEAR] = address;
|
||||
env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
|
||||
return -1;
|
||||
case POWERPC_MMU_BOOKE_FSL:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "BookE FSL MMU model is not implemented\n");
|
||||
return -1;
|
||||
case POWERPC_MMU_REAL:
|
||||
cpu_abort(env, "PowerPC in real mode should never raise "
|
||||
"any MMU exceptions\n");
|
||||
@ -1551,7 +1708,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
if (rw) {
|
||||
env->spr[SPR_40x_ESR] |= 0x00800000;
|
||||
}
|
||||
} else if (env->mmu_model == POWERPC_MMU_BOOKE) {
|
||||
} else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
|
||||
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
|
||||
env->spr[SPR_BOOKE_DEAR] = address;
|
||||
env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
|
||||
} else {
|
||||
@ -1822,10 +1980,8 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
|
||||
case POWERPC_MMU_BOOKE:
|
||||
tlb_flush(env, 1);
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE_FSL:
|
||||
/* XXX: TODO */
|
||||
if (!kvm_enabled())
|
||||
cpu_abort(env, "BookE MMU model is not implemented\n");
|
||||
case POWERPC_MMU_BOOKE206:
|
||||
booke206_flush_tlb(env, -1, 0);
|
||||
break;
|
||||
case POWERPC_MMU_32B:
|
||||
case POWERPC_MMU_601:
|
||||
@ -1869,9 +2025,9 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "BookE MMU model is not implemented\n");
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE_FSL:
|
||||
case POWERPC_MMU_BOOKE206:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "BookE FSL MMU model is not implemented\n");
|
||||
cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
|
||||
break;
|
||||
case POWERPC_MMU_32B:
|
||||
case POWERPC_MMU_601:
|
||||
@ -2589,7 +2745,8 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
|
||||
env->exception_index = POWERPC_EXCP_NONE;
|
||||
env->error_code = 0;
|
||||
|
||||
if (env->mmu_model == POWERPC_MMU_BOOKE) {
|
||||
if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
|
||||
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
|
||||
/* XXX: The BookE changes address space when switching modes,
|
||||
we should probably implement that as different MMU indexes,
|
||||
but for the moment we do it the slow way and flush all. */
|
||||
|
@ -334,6 +334,12 @@ DEF_HELPER_1(4xx_tlbsx, tl, tl)
|
||||
DEF_HELPER_2(440_tlbre, tl, i32, tl)
|
||||
DEF_HELPER_3(440_tlbwe, void, i32, tl, tl)
|
||||
DEF_HELPER_1(440_tlbsx, tl, tl)
|
||||
DEF_HELPER_0(booke206_tlbre, void)
|
||||
DEF_HELPER_0(booke206_tlbwe, void)
|
||||
DEF_HELPER_1(booke206_tlbsx, void, tl)
|
||||
DEF_HELPER_1(booke206_tlbivax, void, tl)
|
||||
DEF_HELPER_1(booke206_tlbflush, void, i32)
|
||||
DEF_HELPER_2(booke_setpid, void, i32, tl)
|
||||
DEF_HELPER_1(6xx_tlbd, void, tl)
|
||||
DEF_HELPER_1(6xx_tlbi, void, tl)
|
||||
DEF_HELPER_1(74xx_tlbd, void, tl)
|
||||
|
182
target-ppc/kvm.c
182
target-ppc/kvm.c
@ -2,6 +2,7 @@
|
||||
* PowerPC implementation of KVM hooks
|
||||
*
|
||||
* Copyright IBM Corp. 2007
|
||||
* Copyright (C) 2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Jerone Young <jyoung5@us.ibm.com>
|
||||
@ -43,6 +44,10 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
|
||||
|
||||
static int cap_interrupt_unset = false;
|
||||
static int cap_interrupt_level = false;
|
||||
static int cap_segstate;
|
||||
#ifdef KVM_CAP_PPC_BOOKE_SREGS
|
||||
static int cap_booke_sregs;
|
||||
#endif
|
||||
|
||||
/* XXX We have a race condition where we actually have a level triggered
|
||||
* interrupt, but the infrastructure can't expose that yet, so the guest
|
||||
@ -68,6 +73,12 @@ int kvm_arch_init(KVMState *s)
|
||||
#ifdef KVM_CAP_PPC_IRQ_LEVEL
|
||||
cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL);
|
||||
#endif
|
||||
#ifdef KVM_CAP_PPC_SEGSTATE
|
||||
cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE);
|
||||
#endif
|
||||
#ifdef KVM_CAP_PPC_BOOKE_SREGS
|
||||
cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS);
|
||||
#endif
|
||||
|
||||
if (!cap_interrupt_level) {
|
||||
fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
|
||||
@ -77,13 +88,50 @@ int kvm_arch_init(KVMState *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_arch_sync_sregs(CPUState *cenv)
|
||||
{
|
||||
struct kvm_sregs sregs;
|
||||
int ret;
|
||||
|
||||
if (cenv->excp_model == POWERPC_EXCP_BOOKE) {
|
||||
/* What we're really trying to say is "if we're on BookE, we use
|
||||
the native PVR for now". This is the only sane way to check
|
||||
it though, so we potentially confuse users that they can run
|
||||
BookE guests on BookS. Let's hope nobody dares enough :) */
|
||||
return 0;
|
||||
} else {
|
||||
if (!cap_segstate) {
|
||||
fprintf(stderr, "kvm error: missing PVR setting capability\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_KVM_PPC_PVR)
|
||||
if (1) {
|
||||
fprintf(stderr, "kvm error: missing PVR setting capability\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = kvm_vcpu_ioctl(cenv, KVM_GET_SREGS, &sregs);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KVM_PPC_PVR
|
||||
sregs.pvr = cenv->spr[SPR_PVR];
|
||||
#endif
|
||||
return kvm_vcpu_ioctl(cenv, KVM_SET_SREGS, &sregs);
|
||||
}
|
||||
|
||||
int kvm_arch_init_vcpu(CPUState *cenv)
|
||||
{
|
||||
int ret = 0;
|
||||
struct kvm_sregs sregs;
|
||||
int ret;
|
||||
|
||||
sregs.pvr = cenv->spr[SPR_PVR];
|
||||
ret = kvm_vcpu_ioctl(cenv, KVM_SET_SREGS, &sregs);
|
||||
ret = kvm_arch_sync_sregs(cenv);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
idle_timer = qemu_new_timer_ns(vm_clock, kvm_kick_env, cenv);
|
||||
|
||||
@ -122,6 +170,8 @@ int kvm_arch_put_registers(CPUState *env, int level)
|
||||
regs.sprg6 = env->spr[SPR_SPRG6];
|
||||
regs.sprg7 = env->spr[SPR_SPRG7];
|
||||
|
||||
regs.pid = env->spr[SPR_BOOKE_PID];
|
||||
|
||||
for (i = 0;i < 32; i++)
|
||||
regs.gpr[i] = env->gpr[i];
|
||||
|
||||
@ -136,15 +186,18 @@ int kvm_arch_get_registers(CPUState *env)
|
||||
{
|
||||
struct kvm_regs regs;
|
||||
struct kvm_sregs sregs;
|
||||
uint32_t cr;
|
||||
int i, ret;
|
||||
|
||||
ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cr = regs.cr;
|
||||
for (i = 7; i >= 0; i--) {
|
||||
env->crf[i] = cr & 15;
|
||||
cr >>= 4;
|
||||
}
|
||||
|
||||
env->ctr = regs.ctr;
|
||||
env->lr = regs.lr;
|
||||
@ -164,11 +217,124 @@ int kvm_arch_get_registers(CPUState *env)
|
||||
env->spr[SPR_SPRG6] = regs.sprg6;
|
||||
env->spr[SPR_SPRG7] = regs.sprg7;
|
||||
|
||||
env->spr[SPR_BOOKE_PID] = regs.pid;
|
||||
|
||||
for (i = 0;i < 32; i++)
|
||||
env->gpr[i] = regs.gpr[i];
|
||||
|
||||
#ifdef KVM_CAP_PPC_BOOKE_SREGS
|
||||
if (cap_booke_sregs) {
|
||||
ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (sregs.u.e.features & KVM_SREGS_E_BASE) {
|
||||
env->spr[SPR_BOOKE_CSRR0] = sregs.u.e.csrr0;
|
||||
env->spr[SPR_BOOKE_CSRR1] = sregs.u.e.csrr1;
|
||||
env->spr[SPR_BOOKE_ESR] = sregs.u.e.esr;
|
||||
env->spr[SPR_BOOKE_DEAR] = sregs.u.e.dear;
|
||||
env->spr[SPR_BOOKE_MCSR] = sregs.u.e.mcsr;
|
||||
env->spr[SPR_BOOKE_TSR] = sregs.u.e.tsr;
|
||||
env->spr[SPR_BOOKE_TCR] = sregs.u.e.tcr;
|
||||
env->spr[SPR_DECR] = sregs.u.e.dec;
|
||||
env->spr[SPR_TBL] = sregs.u.e.tb & 0xffffffff;
|
||||
env->spr[SPR_TBU] = sregs.u.e.tb >> 32;
|
||||
env->spr[SPR_VRSAVE] = sregs.u.e.vrsave;
|
||||
}
|
||||
|
||||
if (sregs.u.e.features & KVM_SREGS_E_ARCH206) {
|
||||
env->spr[SPR_BOOKE_PIR] = sregs.u.e.pir;
|
||||
env->spr[SPR_BOOKE_MCSRR0] = sregs.u.e.mcsrr0;
|
||||
env->spr[SPR_BOOKE_MCSRR1] = sregs.u.e.mcsrr1;
|
||||
env->spr[SPR_BOOKE_DECAR] = sregs.u.e.decar;
|
||||
env->spr[SPR_BOOKE_IVPR] = sregs.u.e.ivpr;
|
||||
}
|
||||
|
||||
if (sregs.u.e.features & KVM_SREGS_E_64) {
|
||||
env->spr[SPR_BOOKE_EPCR] = sregs.u.e.epcr;
|
||||
}
|
||||
|
||||
if (sregs.u.e.features & KVM_SREGS_E_SPRG8) {
|
||||
env->spr[SPR_BOOKE_SPRG8] = sregs.u.e.sprg8;
|
||||
}
|
||||
|
||||
if (sregs.u.e.features & KVM_SREGS_E_IVOR) {
|
||||
env->spr[SPR_BOOKE_IVOR0] = sregs.u.e.ivor_low[0];
|
||||
env->spr[SPR_BOOKE_IVOR1] = sregs.u.e.ivor_low[1];
|
||||
env->spr[SPR_BOOKE_IVOR2] = sregs.u.e.ivor_low[2];
|
||||
env->spr[SPR_BOOKE_IVOR3] = sregs.u.e.ivor_low[3];
|
||||
env->spr[SPR_BOOKE_IVOR4] = sregs.u.e.ivor_low[4];
|
||||
env->spr[SPR_BOOKE_IVOR5] = sregs.u.e.ivor_low[5];
|
||||
env->spr[SPR_BOOKE_IVOR6] = sregs.u.e.ivor_low[6];
|
||||
env->spr[SPR_BOOKE_IVOR7] = sregs.u.e.ivor_low[7];
|
||||
env->spr[SPR_BOOKE_IVOR8] = sregs.u.e.ivor_low[8];
|
||||
env->spr[SPR_BOOKE_IVOR9] = sregs.u.e.ivor_low[9];
|
||||
env->spr[SPR_BOOKE_IVOR10] = sregs.u.e.ivor_low[10];
|
||||
env->spr[SPR_BOOKE_IVOR11] = sregs.u.e.ivor_low[11];
|
||||
env->spr[SPR_BOOKE_IVOR12] = sregs.u.e.ivor_low[12];
|
||||
env->spr[SPR_BOOKE_IVOR13] = sregs.u.e.ivor_low[13];
|
||||
env->spr[SPR_BOOKE_IVOR14] = sregs.u.e.ivor_low[14];
|
||||
env->spr[SPR_BOOKE_IVOR15] = sregs.u.e.ivor_low[15];
|
||||
|
||||
if (sregs.u.e.features & KVM_SREGS_E_SPE) {
|
||||
env->spr[SPR_BOOKE_IVOR32] = sregs.u.e.ivor_high[0];
|
||||
env->spr[SPR_BOOKE_IVOR33] = sregs.u.e.ivor_high[1];
|
||||
env->spr[SPR_BOOKE_IVOR34] = sregs.u.e.ivor_high[2];
|
||||
}
|
||||
|
||||
if (sregs.u.e.features & KVM_SREGS_E_PM) {
|
||||
env->spr[SPR_BOOKE_IVOR35] = sregs.u.e.ivor_high[3];
|
||||
}
|
||||
|
||||
if (sregs.u.e.features & KVM_SREGS_E_PC) {
|
||||
env->spr[SPR_BOOKE_IVOR36] = sregs.u.e.ivor_high[4];
|
||||
env->spr[SPR_BOOKE_IVOR37] = sregs.u.e.ivor_high[5];
|
||||
}
|
||||
}
|
||||
|
||||
if (sregs.u.e.features & KVM_SREGS_E_ARCH206_MMU) {
|
||||
env->spr[SPR_BOOKE_MAS0] = sregs.u.e.mas0;
|
||||
env->spr[SPR_BOOKE_MAS1] = sregs.u.e.mas1;
|
||||
env->spr[SPR_BOOKE_MAS2] = sregs.u.e.mas2;
|
||||
env->spr[SPR_BOOKE_MAS3] = sregs.u.e.mas7_3 & 0xffffffff;
|
||||
env->spr[SPR_BOOKE_MAS4] = sregs.u.e.mas4;
|
||||
env->spr[SPR_BOOKE_MAS6] = sregs.u.e.mas6;
|
||||
env->spr[SPR_BOOKE_MAS7] = sregs.u.e.mas7_3 >> 32;
|
||||
env->spr[SPR_MMUCFG] = sregs.u.e.mmucfg;
|
||||
env->spr[SPR_BOOKE_TLB0CFG] = sregs.u.e.tlbcfg[0];
|
||||
env->spr[SPR_BOOKE_TLB1CFG] = sregs.u.e.tlbcfg[1];
|
||||
}
|
||||
|
||||
if (sregs.u.e.features & KVM_SREGS_EXP) {
|
||||
env->spr[SPR_BOOKE_EPR] = sregs.u.e.epr;
|
||||
}
|
||||
|
||||
if (sregs.u.e.features & KVM_SREGS_E_PD) {
|
||||
env->spr[SPR_BOOKE_EPLC] = sregs.u.e.eplc;
|
||||
env->spr[SPR_BOOKE_EPSC] = sregs.u.e.epsc;
|
||||
}
|
||||
|
||||
if (sregs.u.e.impl_id == KVM_SREGS_E_IMPL_FSL) {
|
||||
env->spr[SPR_E500_SVR] = sregs.u.e.impl.fsl.svr;
|
||||
env->spr[SPR_Exxx_MCAR] = sregs.u.e.impl.fsl.mcar;
|
||||
env->spr[SPR_HID0] = sregs.u.e.impl.fsl.hid0;
|
||||
|
||||
if (sregs.u.e.impl.fsl.features & KVM_SREGS_E_FSL_PIDn) {
|
||||
env->spr[SPR_BOOKE_PID1] = sregs.u.e.impl.fsl.pid1;
|
||||
env->spr[SPR_BOOKE_PID2] = sregs.u.e.impl.fsl.pid2;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef KVM_CAP_PPC_SEGSTATE
|
||||
if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_SEGSTATE)) {
|
||||
if (cap_segstate) {
|
||||
ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ppc_store_sdr1(env, sregs.u.s.sdr1);
|
||||
|
||||
/* Sync SLB */
|
||||
|
@ -4206,4 +4206,300 @@ target_ulong helper_440_tlbsx (target_ulong address)
|
||||
return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
|
||||
}
|
||||
|
||||
/* PowerPC BookE 2.06 TLB management */
|
||||
|
||||
static ppcemb_tlb_t *booke206_cur_tlb(CPUState *env)
|
||||
{
|
||||
uint32_t tlbncfg = 0;
|
||||
int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
|
||||
int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
|
||||
int tlb;
|
||||
|
||||
tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
|
||||
tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
|
||||
|
||||
if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
|
||||
cpu_abort(env, "we don't support HES yet\n");
|
||||
}
|
||||
|
||||
return booke206_get_tlbe(env, tlb, ea, esel);
|
||||
}
|
||||
|
||||
static inline target_phys_addr_t booke206_tlb_to_page_size(int size)
|
||||
{
|
||||
return (1 << (size << 1)) << 10;
|
||||
}
|
||||
|
||||
static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
|
||||
{
|
||||
return (ffs(size >> 10) - 1) >> 1;
|
||||
}
|
||||
|
||||
void helper_booke_setpid(uint32_t pidn, target_ulong pid)
|
||||
{
|
||||
env->spr[pidn] = pid;
|
||||
/* changing PIDs mean we're in a different address space now */
|
||||
tlb_flush(env, 1);
|
||||
}
|
||||
|
||||
void helper_booke206_tlbwe(void)
|
||||
{
|
||||
uint32_t tlbncfg, tlbn;
|
||||
ppcemb_tlb_t *tlb;
|
||||
target_phys_addr_t rpn;
|
||||
int tlbe_size;
|
||||
|
||||
switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
|
||||
case MAS0_WQ_ALWAYS:
|
||||
/* good to go, write that entry */
|
||||
break;
|
||||
case MAS0_WQ_COND:
|
||||
/* XXX check if reserved */
|
||||
if (0) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case MAS0_WQ_CLR_RSRV:
|
||||
/* XXX clear entry */
|
||||
return;
|
||||
default:
|
||||
/* no idea what to do */
|
||||
return;
|
||||
}
|
||||
|
||||
if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
|
||||
!msr_gs) {
|
||||
/* XXX we don't support direct LRAT setting yet */
|
||||
fprintf(stderr, "cpu: don't support LRAT setting yet\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
|
||||
tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
|
||||
|
||||
tlb = booke206_cur_tlb(env);
|
||||
|
||||
if (msr_gs) {
|
||||
cpu_abort(env, "missing HV implementation\n");
|
||||
} else {
|
||||
rpn = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
|
||||
(env->spr[SPR_BOOKE_MAS3] & 0xfffff000);
|
||||
}
|
||||
tlb->RPN = rpn;
|
||||
|
||||
tlb->PID = (env->spr[SPR_BOOKE_MAS1] & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
|
||||
if (tlbncfg & TLBnCFG_AVAIL) {
|
||||
tlbe_size = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK)
|
||||
>> MAS1_TSIZE_SHIFT;
|
||||
} else {
|
||||
tlbe_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
|
||||
}
|
||||
|
||||
tlb->size = booke206_tlb_to_page_size(tlbe_size);
|
||||
tlb->EPN = (uint32_t)(env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
|
||||
tlb->attr = env->spr[SPR_BOOKE_MAS2] & (MAS2_ACM | MAS2_VLE | MAS2_W |
|
||||
MAS2_I | MAS2_M | MAS2_G | MAS2_E)
|
||||
<< 1;
|
||||
|
||||
if (tlbncfg & TLBnCFG_IPROT) {
|
||||
tlb->attr |= env->spr[SPR_BOOKE_MAS1] & MAS1_IPROT;
|
||||
}
|
||||
tlb->attr |= (env->spr[SPR_BOOKE_MAS3] &
|
||||
((MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3)) << 8);
|
||||
if (env->spr[SPR_BOOKE_MAS1] & MAS1_TS) {
|
||||
tlb->attr |= 1;
|
||||
}
|
||||
|
||||
tlb->prot = 0;
|
||||
|
||||
if (env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) {
|
||||
tlb->prot |= PAGE_VALID;
|
||||
}
|
||||
if (env->spr[SPR_BOOKE_MAS3] & MAS3_UX) {
|
||||
tlb->prot |= PAGE_EXEC;
|
||||
}
|
||||
if (env->spr[SPR_BOOKE_MAS3] & MAS3_SX) {
|
||||
tlb->prot |= PAGE_EXEC << 4;
|
||||
}
|
||||
if (env->spr[SPR_BOOKE_MAS3] & MAS3_UW) {
|
||||
tlb->prot |= PAGE_WRITE;
|
||||
}
|
||||
if (env->spr[SPR_BOOKE_MAS3] & MAS3_SW) {
|
||||
tlb->prot |= PAGE_WRITE << 4;
|
||||
}
|
||||
if (env->spr[SPR_BOOKE_MAS3] & MAS3_UR) {
|
||||
tlb->prot |= PAGE_READ;
|
||||
}
|
||||
if (env->spr[SPR_BOOKE_MAS3] & MAS3_SR) {
|
||||
tlb->prot |= PAGE_READ << 4;
|
||||
}
|
||||
|
||||
if (tlb->size == TARGET_PAGE_SIZE) {
|
||||
tlb_flush_page(env, tlb->EPN);
|
||||
} else {
|
||||
tlb_flush(env, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void booke206_tlb_to_mas(CPUState *env, ppcemb_tlb_t *tlb)
|
||||
{
|
||||
int tlbn = booke206_tlbe_to_tlbn(env, tlb);
|
||||
int way = booke206_tlbe_to_way(env, tlb);
|
||||
|
||||
env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
|
||||
env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
|
||||
|
||||
env->spr[SPR_BOOKE_MAS1] = MAS1_VALID;
|
||||
env->spr[SPR_BOOKE_MAS2] = 0;
|
||||
|
||||
env->spr[SPR_BOOKE_MAS7] = (uint64_t)tlb->RPN >> 32;
|
||||
env->spr[SPR_BOOKE_MAS3] = tlb->RPN;
|
||||
env->spr[SPR_BOOKE_MAS1] |= tlb->PID << MAS1_TID_SHIFT;
|
||||
env->spr[SPR_BOOKE_MAS1] |= booke206_page_size_to_tlb(tlb->size)
|
||||
<< MAS1_TSIZE_SHIFT;
|
||||
env->spr[SPR_BOOKE_MAS1] |= tlb->attr & MAS1_IPROT;
|
||||
if (tlb->attr & 1) {
|
||||
env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
|
||||
}
|
||||
|
||||
env->spr[SPR_BOOKE_MAS2] = tlb->EPN;
|
||||
env->spr[SPR_BOOKE_MAS2] |= (tlb->attr >> 1) &
|
||||
(MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E);
|
||||
|
||||
if (tlb->prot & PAGE_EXEC) {
|
||||
env->spr[SPR_BOOKE_MAS3] |= MAS3_UX;
|
||||
}
|
||||
if (tlb->prot & (PAGE_EXEC << 4)) {
|
||||
env->spr[SPR_BOOKE_MAS3] |= MAS3_SX;
|
||||
}
|
||||
if (tlb->prot & PAGE_WRITE) {
|
||||
env->spr[SPR_BOOKE_MAS3] |= MAS3_UW;
|
||||
}
|
||||
if (tlb->prot & (PAGE_WRITE << 4)) {
|
||||
env->spr[SPR_BOOKE_MAS3] |= MAS3_SW;
|
||||
}
|
||||
if (tlb->prot & PAGE_READ) {
|
||||
env->spr[SPR_BOOKE_MAS3] |= MAS3_UR;
|
||||
}
|
||||
if (tlb->prot & (PAGE_READ << 4)) {
|
||||
env->spr[SPR_BOOKE_MAS3] |= MAS3_SR;
|
||||
}
|
||||
|
||||
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
|
||||
}
|
||||
|
||||
void helper_booke206_tlbre(void)
|
||||
{
|
||||
ppcemb_tlb_t *tlb = NULL;
|
||||
|
||||
tlb = booke206_cur_tlb(env);
|
||||
booke206_tlb_to_mas(env, tlb);
|
||||
}
|
||||
|
||||
void helper_booke206_tlbsx(target_ulong address)
|
||||
{
|
||||
ppcemb_tlb_t *tlb = NULL;
|
||||
int i, j;
|
||||
target_phys_addr_t raddr;
|
||||
uint32_t spid, sas;
|
||||
|
||||
spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
|
||||
sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
|
||||
|
||||
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
|
||||
int ways = booke206_tlb_ways(env, i);
|
||||
|
||||
for (j = 0; j < ways; j++) {
|
||||
tlb = booke206_get_tlbe(env, i, address, j);
|
||||
|
||||
if (ppcemb_tlb_check(env, tlb, &raddr, address, spid, 0, j)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sas != (tlb->attr & MAS6_SAS)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
booke206_tlb_to_mas(env, tlb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* no entry found, fill with defaults */
|
||||
env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
|
||||
env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
|
||||
env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
|
||||
env->spr[SPR_BOOKE_MAS3] = 0;
|
||||
env->spr[SPR_BOOKE_MAS7] = 0;
|
||||
|
||||
if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
|
||||
env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
|
||||
}
|
||||
|
||||
env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
|
||||
<< MAS1_TID_SHIFT;
|
||||
|
||||
/* next victim logic */
|
||||
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
|
||||
env->last_way++;
|
||||
env->last_way &= booke206_tlb_ways(env, 0) - 1;
|
||||
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
|
||||
}
|
||||
|
||||
static inline void booke206_invalidate_ea_tlb(CPUState *env, int tlbn,
|
||||
uint32_t ea)
|
||||
{
|
||||
int i;
|
||||
int ways = booke206_tlb_ways(env, tlbn);
|
||||
|
||||
for (i = 0; i < ways; i++) {
|
||||
ppcemb_tlb_t *tlb = booke206_get_tlbe(env, tlbn, ea, i);
|
||||
target_phys_addr_t masked_ea = ea & ~(tlb->size - 1);
|
||||
if ((tlb->EPN == (masked_ea >> MAS2_EPN_SHIFT)) &&
|
||||
!(tlb->attr & MAS1_IPROT)) {
|
||||
tlb->prot = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void helper_booke206_tlbivax(target_ulong address)
|
||||
{
|
||||
if (address & 0x4) {
|
||||
/* flush all entries */
|
||||
if (address & 0x8) {
|
||||
/* flush all of TLB1 */
|
||||
booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
|
||||
} else {
|
||||
/* flush all of TLB0 */
|
||||
booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (address & 0x8) {
|
||||
/* flush TLB1 entries */
|
||||
booke206_invalidate_ea_tlb(env, 1, address);
|
||||
tlb_flush(env, 1);
|
||||
} else {
|
||||
/* flush TLB0 entries */
|
||||
booke206_invalidate_ea_tlb(env, 0, address);
|
||||
tlb_flush_page(env, address & MAS2_EPN_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_booke206_tlbflush(uint32_t type)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if (type & 2) {
|
||||
flags |= BOOKE206_FLUSH_TLB1;
|
||||
}
|
||||
|
||||
if (type & 4) {
|
||||
flags |= BOOKE206_FLUSH_TLB0;
|
||||
}
|
||||
|
||||
booke206_flush_tlb(env, flags, 1);
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
@ -2,6 +2,7 @@
|
||||
* PowerPC emulation for qemu: main translation routines.
|
||||
*
|
||||
* Copyright (c) 2003-2007 Jocelyn Mayer
|
||||
* Copyright (C) 2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -200,6 +201,8 @@ struct opc_handler_t {
|
||||
uint32_t inval;
|
||||
/* instruction type */
|
||||
uint64_t type;
|
||||
/* extended instruction type */
|
||||
uint64_t type2;
|
||||
/* handler */
|
||||
void (*handler)(DisasContext *ctx);
|
||||
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
|
||||
@ -313,10 +316,16 @@ static inline void gen_sync_exception(DisasContext *ctx)
|
||||
}
|
||||
|
||||
#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
|
||||
GEN_OPCODE(name, opc1, opc2, opc3, inval, type)
|
||||
GEN_OPCODE(name, opc1, opc2, opc3, inval, type, PPC_NONE)
|
||||
|
||||
#define GEN_HANDLER_E(name, opc1, opc2, opc3, inval, type, type2) \
|
||||
GEN_OPCODE(name, opc1, opc2, opc3, inval, type, type2)
|
||||
|
||||
#define GEN_HANDLER2(name, onam, opc1, opc2, opc3, inval, type) \
|
||||
GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type)
|
||||
GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, PPC_NONE)
|
||||
|
||||
#define GEN_HANDLER2_E(name, onam, opc1, opc2, opc3, inval, type, type2) \
|
||||
GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, type2)
|
||||
|
||||
typedef struct opcode_t {
|
||||
unsigned char opc1, opc2, opc3;
|
||||
@ -456,7 +465,7 @@ static inline target_ulong MASK(uint32_t start, uint32_t end)
|
||||
/* PowerPC instructions table */
|
||||
|
||||
#if defined(DO_PPC_STATISTICS)
|
||||
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
|
||||
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2) \
|
||||
{ \
|
||||
.opc1 = op1, \
|
||||
.opc2 = op2, \
|
||||
@ -465,12 +474,13 @@ static inline target_ulong MASK(uint32_t start, uint32_t end)
|
||||
.handler = { \
|
||||
.inval = invl, \
|
||||
.type = _typ, \
|
||||
.type2 = _typ2, \
|
||||
.handler = &gen_##name, \
|
||||
.oname = stringify(name), \
|
||||
}, \
|
||||
.oname = stringify(name), \
|
||||
}
|
||||
#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ) \
|
||||
#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ, _typ2) \
|
||||
{ \
|
||||
.opc1 = op1, \
|
||||
.opc2 = op2, \
|
||||
@ -479,13 +489,14 @@ static inline target_ulong MASK(uint32_t start, uint32_t end)
|
||||
.handler = { \
|
||||
.inval = invl, \
|
||||
.type = _typ, \
|
||||
.type2 = _typ2, \
|
||||
.handler = &gen_##name, \
|
||||
.oname = onam, \
|
||||
}, \
|
||||
.oname = onam, \
|
||||
}
|
||||
#else
|
||||
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
|
||||
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2) \
|
||||
{ \
|
||||
.opc1 = op1, \
|
||||
.opc2 = op2, \
|
||||
@ -494,11 +505,12 @@ static inline target_ulong MASK(uint32_t start, uint32_t end)
|
||||
.handler = { \
|
||||
.inval = invl, \
|
||||
.type = _typ, \
|
||||
.type2 = _typ2, \
|
||||
.handler = &gen_##name, \
|
||||
}, \
|
||||
.oname = stringify(name), \
|
||||
}
|
||||
#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ) \
|
||||
#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ, _typ2) \
|
||||
{ \
|
||||
.opc1 = op1, \
|
||||
.opc2 = op2, \
|
||||
@ -507,6 +519,7 @@ static inline target_ulong MASK(uint32_t start, uint32_t end)
|
||||
.handler = { \
|
||||
.inval = invl, \
|
||||
.type = _typ, \
|
||||
.type2 = _typ2, \
|
||||
.handler = &gen_##name, \
|
||||
}, \
|
||||
.oname = onam, \
|
||||
@ -533,6 +546,7 @@ static void gen_invalid(DisasContext *ctx)
|
||||
static opc_handler_t invalid_handler = {
|
||||
.inval = 0xFFFFFFFF,
|
||||
.type = PPC_NONE,
|
||||
.type2 = PPC_NONE,
|
||||
.handler = gen_invalid,
|
||||
};
|
||||
|
||||
@ -5974,6 +5988,80 @@ static void gen_tlbwe_440(DisasContext *ctx)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* TLB management - PowerPC BookE 2.06 implementation */
|
||||
|
||||
/* tlbre */
|
||||
static void gen_tlbre_booke206(DisasContext *ctx)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
#else
|
||||
if (unlikely(!ctx->mem_idx)) {
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
return;
|
||||
}
|
||||
|
||||
gen_helper_booke206_tlbre();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* tlbsx - tlbsx. */
|
||||
static void gen_tlbsx_booke206(DisasContext *ctx)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
#else
|
||||
TCGv t0;
|
||||
if (unlikely(!ctx->mem_idx)) {
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rA(ctx->opcode)) {
|
||||
t0 = tcg_temp_new();
|
||||
tcg_gen_mov_tl(t0, cpu_gpr[rD(ctx->opcode)]);
|
||||
} else {
|
||||
t0 = tcg_const_tl(0);
|
||||
}
|
||||
|
||||
tcg_gen_add_tl(t0, t0, cpu_gpr[rB(ctx->opcode)]);
|
||||
gen_helper_booke206_tlbsx(t0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* tlbwe */
|
||||
static void gen_tlbwe_booke206(DisasContext *ctx)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
#else
|
||||
if (unlikely(!ctx->mem_idx)) {
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
return;
|
||||
}
|
||||
gen_helper_booke206_tlbwe();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gen_tlbivax_booke206(DisasContext *ctx)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
#else
|
||||
TCGv t0;
|
||||
if (unlikely(!ctx->mem_idx)) {
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
return;
|
||||
}
|
||||
|
||||
t0 = tcg_temp_new();
|
||||
gen_addr_reg_index(ctx, t0);
|
||||
|
||||
gen_helper_booke206_tlbivax(t0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* wrtee */
|
||||
static void gen_wrtee(DisasContext *ctx)
|
||||
{
|
||||
@ -8420,7 +8508,7 @@ GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT),
|
||||
GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON),
|
||||
GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON),
|
||||
GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP),
|
||||
GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE),
|
||||
GEN_HANDLER_E(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE, PPC2_BOOKE206),
|
||||
GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI),
|
||||
GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI),
|
||||
GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB),
|
||||
@ -8429,12 +8517,23 @@ GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB),
|
||||
GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE),
|
||||
GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE),
|
||||
GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE),
|
||||
GEN_HANDLER2_E(tlbre_booke206, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001,
|
||||
PPC_NONE, PPC2_BOOKE206),
|
||||
GEN_HANDLER2_E(tlbsx_booke206, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000,
|
||||
PPC_NONE, PPC2_BOOKE206),
|
||||
GEN_HANDLER2_E(tlbwe_booke206, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001,
|
||||
PPC_NONE, PPC2_BOOKE206),
|
||||
GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001,
|
||||
PPC_NONE, PPC2_BOOKE206),
|
||||
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
|
||||
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
|
||||
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),
|
||||
GEN_HANDLER(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, PPC_BOOKE),
|
||||
GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE),
|
||||
GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE),
|
||||
GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801,
|
||||
PPC_BOOKE, PPC2_BOOKE206),
|
||||
GEN_HANDLER_E(msync, 0x1F, 0x16, 0x12, 0x03FFF801,
|
||||
PPC_BOOKE, PPC2_BOOKE206),
|
||||
GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
|
||||
PPC_BOOKE, PPC2_BOOKE206),
|
||||
GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC),
|
||||
GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC),
|
||||
GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC),
|
||||
@ -9124,9 +9223,84 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
|
||||
}
|
||||
cpu_fprintf(f, "FPSCR %08x\n", env->fpscr);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
cpu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx " SDR1 "
|
||||
TARGET_FMT_lx "\n", env->spr[SPR_SRR0], env->spr[SPR_SRR1],
|
||||
env->spr[SPR_SDR1]);
|
||||
cpu_fprintf(f, " SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx
|
||||
" PVR " TARGET_FMT_lx " VRSAVE " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_SRR0], env->spr[SPR_SRR1],
|
||||
env->spr[SPR_PVR], env->spr[SPR_VRSAVE]);
|
||||
|
||||
cpu_fprintf(f, "SPRG0 " TARGET_FMT_lx " SPRG1 " TARGET_FMT_lx
|
||||
" SPRG2 " TARGET_FMT_lx " SPRG3 " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_SPRG0], env->spr[SPR_SPRG1],
|
||||
env->spr[SPR_SPRG2], env->spr[SPR_SPRG3]);
|
||||
|
||||
cpu_fprintf(f, "SPRG4 " TARGET_FMT_lx " SPRG5 " TARGET_FMT_lx
|
||||
" SPRG6 " TARGET_FMT_lx " SPRG7 " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_SPRG4], env->spr[SPR_SPRG5],
|
||||
env->spr[SPR_SPRG6], env->spr[SPR_SPRG7]);
|
||||
|
||||
if (env->excp_model == POWERPC_EXCP_BOOKE) {
|
||||
cpu_fprintf(f, "CSRR0 " TARGET_FMT_lx " CSRR1 " TARGET_FMT_lx
|
||||
" MCSRR0 " TARGET_FMT_lx " MCSRR1 " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
|
||||
env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
|
||||
|
||||
cpu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
|
||||
" ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_BOOKE_TCR], env->spr[SPR_BOOKE_TSR],
|
||||
env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]);
|
||||
|
||||
cpu_fprintf(f, " PIR " TARGET_FMT_lx " DECAR " TARGET_FMT_lx
|
||||
" IVPR " TARGET_FMT_lx " EPCR " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_BOOKE_PIR], env->spr[SPR_BOOKE_DECAR],
|
||||
env->spr[SPR_BOOKE_IVPR], env->spr[SPR_BOOKE_EPCR]);
|
||||
|
||||
cpu_fprintf(f, " MCSR " TARGET_FMT_lx " SPRG8 " TARGET_FMT_lx
|
||||
" EPR " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_BOOKE_MCSR], env->spr[SPR_BOOKE_SPRG8],
|
||||
env->spr[SPR_BOOKE_EPR]);
|
||||
|
||||
/* FSL-specific */
|
||||
cpu_fprintf(f, " MCAR " TARGET_FMT_lx " PID1 " TARGET_FMT_lx
|
||||
" PID2 " TARGET_FMT_lx " SVR " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_Exxx_MCAR], env->spr[SPR_BOOKE_PID1],
|
||||
env->spr[SPR_BOOKE_PID2], env->spr[SPR_E500_SVR]);
|
||||
|
||||
/*
|
||||
* IVORs are left out as they are large and do not change often --
|
||||
* they can be read with "p $ivor0", "p $ivor1", etc.
|
||||
*/
|
||||
}
|
||||
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_32B:
|
||||
case POWERPC_MMU_601:
|
||||
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]);
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE206:
|
||||
cpu_fprintf(f, " MAS0 " TARGET_FMT_lx " MAS1 " TARGET_FMT_lx
|
||||
" MAS2 " TARGET_FMT_lx " MAS3 " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1],
|
||||
env->spr[SPR_BOOKE_MAS2], env->spr[SPR_BOOKE_MAS3]);
|
||||
|
||||
cpu_fprintf(f, " MAS4 " TARGET_FMT_lx " MAS6 " TARGET_FMT_lx
|
||||
" MAS7 " TARGET_FMT_lx " PID " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_BOOKE_MAS4], env->spr[SPR_BOOKE_MAS6],
|
||||
env->spr[SPR_BOOKE_MAS7], env->spr[SPR_BOOKE_PID]);
|
||||
|
||||
cpu_fprintf(f, "MMUCFG " TARGET_FMT_lx " TLB0CFG " TARGET_FMT_lx
|
||||
" TLB1CFG " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_MMUCFG], env->spr[SPR_BOOKE_TLB0CFG],
|
||||
env->spr[SPR_BOOKE_TLB1CFG]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef RGPL
|
||||
|
@ -37,6 +37,7 @@ struct ppc_def_t {
|
||||
uint32_t pvr;
|
||||
uint32_t svr;
|
||||
uint64_t insns_flags;
|
||||
uint64_t insns_flags2;
|
||||
uint64_t msr_mask;
|
||||
powerpc_mmu_t mmu_model;
|
||||
powerpc_excp_t excp_model;
|
||||
@ -1354,6 +1355,31 @@ static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
static void spr_write_e500_l1csr0 (void *opaque, int sprn, int gprn)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[gprn], ~256);
|
||||
gen_store_spr(sprn, t0);
|
||||
tcg_temp_free(t0);
|
||||
}
|
||||
|
||||
static void spr_write_booke206_mmucsr0 (void *opaque, int sprn, int gprn)
|
||||
{
|
||||
TCGv t0 = tcg_const_i32(sprn);
|
||||
gen_helper_booke206_tlbflush(t0);
|
||||
tcg_temp_free(t0);
|
||||
}
|
||||
|
||||
static void spr_write_booke_pid (void *opaque, int sprn, int gprn)
|
||||
{
|
||||
TCGv t0 = tcg_const_i32(sprn);
|
||||
gen_helper_booke_setpid(t0, cpu_gpr[gprn]);
|
||||
tcg_temp_free(t0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void gen_spr_usprgh (CPUPPCState *env)
|
||||
{
|
||||
spr_register(env, SPR_USPRG4, "USPRG4",
|
||||
@ -1493,7 +1519,7 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask)
|
||||
}
|
||||
spr_register(env, SPR_BOOKE_PID, "PID",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
&spr_read_generic, &spr_write_booke_pid,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_BOOKE_TCR, "TCR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
@ -1535,8 +1561,19 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask)
|
||||
0x00000000);
|
||||
}
|
||||
|
||||
/* FSL storage control registers */
|
||||
static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
|
||||
static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize,
|
||||
uint32_t maxsize, uint32_t flags,
|
||||
uint32_t nentries)
|
||||
{
|
||||
return (assoc << TLBnCFG_ASSOC_SHIFT) |
|
||||
(minsize << TLBnCFG_MINSIZE_SHIFT) |
|
||||
(maxsize << TLBnCFG_MAXSIZE_SHIFT) |
|
||||
flags | nentries;
|
||||
}
|
||||
|
||||
/* BookE 2.06 storage control registers */
|
||||
static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask,
|
||||
uint32_t *tlbncfg)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
const char *mas_names[8] = {
|
||||
@ -1562,14 +1599,14 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_PID1, "PID1",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
&spr_read_generic, &spr_write_booke_pid,
|
||||
0x00000000);
|
||||
}
|
||||
if (env->nb_pids > 2) {
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_PID2, "PID2",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
&spr_read_generic, &spr_write_booke_pid,
|
||||
0x00000000);
|
||||
}
|
||||
/* XXX : not implemented */
|
||||
@ -1577,45 +1614,38 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
0x00000000); /* TOFIX */
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_MMUCSR0, "MMUCSR0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000); /* TOFIX */
|
||||
switch (env->nb_ways) {
|
||||
case 4:
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
0x00000000); /* TOFIX */
|
||||
tlbncfg[3]);
|
||||
/* Fallthru */
|
||||
case 3:
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
0x00000000); /* TOFIX */
|
||||
tlbncfg[2]);
|
||||
/* Fallthru */
|
||||
case 2:
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
0x00000000); /* TOFIX */
|
||||
tlbncfg[1]);
|
||||
/* Fallthru */
|
||||
case 1:
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
0x00000000); /* TOFIX */
|
||||
tlbncfg[0]);
|
||||
/* Fallthru */
|
||||
case 0:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
gen_spr_usprgh(env);
|
||||
}
|
||||
|
||||
/* SPR specific to PowerPC 440 implementation */
|
||||
@ -3201,6 +3231,7 @@ static int check_pow_hid0_74xx (CPUPPCState *env)
|
||||
PPC_CACHE_DCBZ | \
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_4xx_COMMON | PPC_40x_EXCP)
|
||||
#define POWERPC_INSNS2_401 (PPC_NONE)
|
||||
#define POWERPC_MSRM_401 (0x00000000000FD201ULL)
|
||||
#define POWERPC_MMU_401 (POWERPC_MMU_REAL)
|
||||
#define POWERPC_EXCP_401 (POWERPC_EXCP_40x)
|
||||
@ -3230,6 +3261,7 @@ static void init_proc_401 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
|
||||
PPC_4xx_COMMON | PPC_40x_EXCP)
|
||||
#define POWERPC_INSNS2_401x2 (PPC_NONE)
|
||||
#define POWERPC_MSRM_401x2 (0x00000000001FD231ULL)
|
||||
#define POWERPC_MMU_401x2 (POWERPC_MMU_SOFT_4xx_Z)
|
||||
#define POWERPC_EXCP_401x2 (POWERPC_EXCP_40x)
|
||||
@ -3266,6 +3298,7 @@ static void init_proc_401x2 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
|
||||
PPC_4xx_COMMON | PPC_40x_EXCP)
|
||||
#define POWERPC_INSNS2_401x3 (PPC_NONE)
|
||||
#define POWERPC_MSRM_401x3 (0x00000000001FD631ULL)
|
||||
#define POWERPC_MMU_401x3 (POWERPC_MMU_SOFT_4xx_Z)
|
||||
#define POWERPC_EXCP_401x3 (POWERPC_EXCP_40x)
|
||||
@ -3298,6 +3331,7 @@ static void init_proc_401x3 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
|
||||
PPC_4xx_COMMON | PPC_40x_EXCP)
|
||||
#define POWERPC_INSNS2_IOP480 (PPC_NONE)
|
||||
#define POWERPC_MSRM_IOP480 (0x00000000001FD231ULL)
|
||||
#define POWERPC_MMU_IOP480 (POWERPC_MMU_SOFT_4xx_Z)
|
||||
#define POWERPC_EXCP_IOP480 (POWERPC_EXCP_40x)
|
||||
@ -3333,6 +3367,7 @@ static void init_proc_IOP480 (CPUPPCState *env)
|
||||
PPC_CACHE_DCBZ | \
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_4xx_COMMON | PPC_40x_EXCP)
|
||||
#define POWERPC_INSNS2_403 (PPC_NONE)
|
||||
#define POWERPC_MSRM_403 (0x000000000007D00DULL)
|
||||
#define POWERPC_MMU_403 (POWERPC_MMU_REAL)
|
||||
#define POWERPC_EXCP_403 (POWERPC_EXCP_40x)
|
||||
@ -3363,6 +3398,7 @@ static void init_proc_403 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
|
||||
PPC_4xx_COMMON | PPC_40x_EXCP)
|
||||
#define POWERPC_INSNS2_403GCX (PPC_NONE)
|
||||
#define POWERPC_MSRM_403GCX (0x000000000007D00DULL)
|
||||
#define POWERPC_MMU_403GCX (POWERPC_MMU_SOFT_4xx_Z)
|
||||
#define POWERPC_EXCP_403GCX (POWERPC_EXCP_40x)
|
||||
@ -3411,6 +3447,7 @@ static void init_proc_403GCX (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
|
||||
PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP)
|
||||
#define POWERPC_INSNS2_405 (PPC_NONE)
|
||||
#define POWERPC_MSRM_405 (0x000000000006E630ULL)
|
||||
#define POWERPC_MMU_405 (POWERPC_MMU_SOFT_4xx)
|
||||
#define POWERPC_EXCP_405 (POWERPC_EXCP_40x)
|
||||
@ -3458,6 +3495,7 @@ static void init_proc_405 (CPUPPCState *env)
|
||||
PPC_MEM_TLBSYNC | PPC_MFTB | \
|
||||
PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \
|
||||
PPC_440_SPEC)
|
||||
#define POWERPC_INSNS2_440EP (PPC_NONE)
|
||||
#define POWERPC_MSRM_440EP (0x000000000006D630ULL)
|
||||
#define POWERPC_MMU_440EP (POWERPC_MMU_BOOKE)
|
||||
#define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE)
|
||||
@ -3538,6 +3576,7 @@ static void init_proc_440EP (CPUPPCState *env)
|
||||
PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_MFTB | \
|
||||
PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \
|
||||
PPC_440_SPEC)
|
||||
#define POWERPC_INSNS2_440GP (PPC_NONE)
|
||||
#define POWERPC_MSRM_440GP (0x000000000006FF30ULL)
|
||||
#define POWERPC_MMU_440GP (POWERPC_MMU_BOOKE)
|
||||
#define POWERPC_EXCP_440GP (POWERPC_EXCP_BOOKE)
|
||||
@ -3600,6 +3639,7 @@ static void init_proc_440GP (CPUPPCState *env)
|
||||
PPC_MEM_TLBSYNC | PPC_MFTB | \
|
||||
PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \
|
||||
PPC_440_SPEC)
|
||||
#define POWERPC_INSNS2_440x4 (PPC_NONE)
|
||||
#define POWERPC_MSRM_440x4 (0x000000000006FF30ULL)
|
||||
#define POWERPC_MMU_440x4 (POWERPC_MMU_BOOKE)
|
||||
#define POWERPC_EXCP_440x4 (POWERPC_EXCP_BOOKE)
|
||||
@ -3662,6 +3702,7 @@ static void init_proc_440x4 (CPUPPCState *env)
|
||||
PPC_MEM_TLBSYNC | PPC_MFTB | \
|
||||
PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \
|
||||
PPC_440_SPEC)
|
||||
#define POWERPC_INSNS2_440x5 (PPC_NONE)
|
||||
#define POWERPC_MSRM_440x5 (0x000000000006FF30ULL)
|
||||
#define POWERPC_MMU_440x5 (POWERPC_MMU_BOOKE)
|
||||
#define POWERPC_EXCP_440x5 (POWERPC_EXCP_BOOKE)
|
||||
@ -3742,6 +3783,7 @@ static void init_proc_440x5 (CPUPPCState *env)
|
||||
PPC_MEM_TLBSYNC | PPC_TLBIVA | \
|
||||
PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \
|
||||
PPC_440_SPEC)
|
||||
#define POWERPC_INSNS2_460 (PPC_NONE)
|
||||
#define POWERPC_MSRM_460 (0x000000000006FF30ULL)
|
||||
#define POWERPC_MMU_460 (POWERPC_MMU_BOOKE)
|
||||
#define POWERPC_EXCP_460 (POWERPC_EXCP_BOOKE)
|
||||
@ -3831,6 +3873,7 @@ static void init_proc_460 (CPUPPCState *env)
|
||||
PPC_MEM_TLBSYNC | PPC_TLBIVA | \
|
||||
PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \
|
||||
PPC_440_SPEC)
|
||||
#define POWERPC_INSNS2_460F (PPC_NONE)
|
||||
#define POWERPC_MSRM_460 (0x000000000006FF30ULL)
|
||||
#define POWERPC_MMU_460F (POWERPC_MMU_BOOKE)
|
||||
#define POWERPC_EXCP_460F (POWERPC_EXCP_BOOKE)
|
||||
@ -3913,6 +3956,7 @@ static void init_proc_460F (CPUPPCState *env)
|
||||
PPC_MEM_EIEIO | PPC_MEM_SYNC | \
|
||||
PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX | \
|
||||
PPC_MFTB)
|
||||
#define POWERPC_INSNS2_MPC5xx (PPC_NONE)
|
||||
#define POWERPC_MSRM_MPC5xx (0x000000000001FF43ULL)
|
||||
#define POWERPC_MMU_MPC5xx (POWERPC_MMU_REAL)
|
||||
#define POWERPC_EXCP_MPC5xx (POWERPC_EXCP_603)
|
||||
@ -3939,6 +3983,7 @@ static void init_proc_MPC5xx (CPUPPCState *env)
|
||||
#define POWERPC_INSNS_MPC8xx (PPC_INSNS_BASE | PPC_STRING | \
|
||||
PPC_MEM_EIEIO | PPC_MEM_SYNC | \
|
||||
PPC_CACHE_ICBI | PPC_MFTB)
|
||||
#define POWERPC_INSNS2_MPC8xx (PPC_NONE)
|
||||
#define POWERPC_MSRM_MPC8xx (0x000000000001F673ULL)
|
||||
#define POWERPC_MMU_MPC8xx (POWERPC_MMU_MPC8xx)
|
||||
#define POWERPC_EXCP_MPC8xx (POWERPC_EXCP_603)
|
||||
@ -3970,6 +4015,7 @@ static void init_proc_MPC8xx (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_G2 (PPC_NONE)
|
||||
#define POWERPC_MSRM_G2 (0x000000000006FFF2ULL)
|
||||
#define POWERPC_MMU_G2 (POWERPC_MMU_SOFT_6xx)
|
||||
//#define POWERPC_EXCP_G2 (POWERPC_EXCP_G2)
|
||||
@ -4027,6 +4073,7 @@ static void init_proc_G2 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_G2LE (PPC_NONE)
|
||||
#define POWERPC_MSRM_G2LE (0x000000000007FFF3ULL)
|
||||
#define POWERPC_MMU_G2LE (POWERPC_MMU_SOFT_6xx)
|
||||
#define POWERPC_EXCP_G2LE (POWERPC_EXCP_G2)
|
||||
@ -4093,8 +4140,9 @@ static void init_proc_G2LE (CPUPPCState *env)
|
||||
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
|
||||
PPC_MEM_TLBSYNC | PPC_TLBIVAX | \
|
||||
PPC_BOOKE)
|
||||
#define POWERPC_INSNS2_e200 (PPC_NONE)
|
||||
#define POWERPC_MSRM_e200 (0x000000000606FF30ULL)
|
||||
#define POWERPC_MMU_e200 (POWERPC_MMU_BOOKE_FSL)
|
||||
#define POWERPC_MMU_e200 (POWERPC_MMU_BOOKE206)
|
||||
#define POWERPC_EXCP_e200 (POWERPC_EXCP_BOOKE)
|
||||
#define POWERPC_INPUT_e200 (PPC_FLAGS_INPUT_BookE)
|
||||
#define POWERPC_BFDM_e200 (bfd_mach_ppc_860)
|
||||
@ -4115,7 +4163,7 @@ static void init_proc_e200 (CPUPPCState *env)
|
||||
&spr_read_spefscr, &spr_write_spefscr,
|
||||
0x00000000);
|
||||
/* Memory management */
|
||||
gen_spr_BookE_FSL(env, 0x0000005D);
|
||||
gen_spr_BookE206(env, 0x0000005D, NULL);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_HID0, "HID0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
@ -4186,6 +4234,11 @@ static void init_proc_e200 (CPUPPCState *env)
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_MMUCSR0, "MMUCSR0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000); /* TOFIX */
|
||||
spr_register(env, SPR_BOOKE_DSRR0, "DSRR0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
@ -4213,6 +4266,7 @@ static void init_proc_e200 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_e300 (PPC_NONE)
|
||||
#define POWERPC_MSRM_e300 (0x000000000007FFF3ULL)
|
||||
#define POWERPC_MMU_e300 (POWERPC_MMU_SOFT_6xx)
|
||||
#define POWERPC_EXCP_e300 (POWERPC_EXCP_603)
|
||||
@ -4262,10 +4316,10 @@ static void init_proc_e300 (CPUPPCState *env)
|
||||
PPC_WRTEE | PPC_RFDI | \
|
||||
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
|
||||
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
|
||||
PPC_MEM_TLBSYNC | PPC_TLBIVAX | \
|
||||
PPC_BOOKE)
|
||||
PPC_MEM_TLBSYNC | PPC_TLBIVAX)
|
||||
#define POWERPC_INSNS2_e500v1 (PPC2_BOOKE206)
|
||||
#define POWERPC_MSRM_e500v1 (0x000000000606FF30ULL)
|
||||
#define POWERPC_MMU_e500v1 (POWERPC_MMU_BOOKE_FSL)
|
||||
#define POWERPC_MMU_e500v1 (POWERPC_MMU_BOOKE206)
|
||||
#define POWERPC_EXCP_e500v1 (POWERPC_EXCP_BOOKE)
|
||||
#define POWERPC_INPUT_e500v1 (PPC_FLAGS_INPUT_BookE)
|
||||
#define POWERPC_BFDM_e500v1 (bfd_mach_ppc_860)
|
||||
@ -4273,7 +4327,7 @@ static void init_proc_e300 (CPUPPCState *env)
|
||||
POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \
|
||||
POWERPC_FLAG_BUS_CLK)
|
||||
#define check_pow_e500v1 check_pow_hid0
|
||||
#define init_proc_e500v1 init_proc_e500
|
||||
#define init_proc_e500v1 init_proc_e500v1
|
||||
|
||||
/* e500v2 core */
|
||||
#define POWERPC_INSNS_e500v2 (PPC_INSNS_BASE | PPC_ISEL | \
|
||||
@ -4281,10 +4335,10 @@ static void init_proc_e300 (CPUPPCState *env)
|
||||
PPC_WRTEE | PPC_RFDI | \
|
||||
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
|
||||
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
|
||||
PPC_MEM_TLBSYNC | PPC_TLBIVAX | \
|
||||
PPC_BOOKE)
|
||||
PPC_MEM_TLBSYNC | PPC_TLBIVAX)
|
||||
#define POWERPC_INSNS2_e500v2 (PPC2_BOOKE206)
|
||||
#define POWERPC_MSRM_e500v2 (0x000000000606FF30ULL)
|
||||
#define POWERPC_MMU_e500v2 (POWERPC_MMU_BOOKE_FSL)
|
||||
#define POWERPC_MMU_e500v2 (POWERPC_MMU_BOOKE206)
|
||||
#define POWERPC_EXCP_e500v2 (POWERPC_EXCP_BOOKE)
|
||||
#define POWERPC_INPUT_e500v2 (PPC_FLAGS_INPUT_BookE)
|
||||
#define POWERPC_BFDM_e500v2 (bfd_mach_ppc_860)
|
||||
@ -4292,13 +4346,23 @@ static void init_proc_e300 (CPUPPCState *env)
|
||||
POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \
|
||||
POWERPC_FLAG_BUS_CLK)
|
||||
#define check_pow_e500v2 check_pow_hid0
|
||||
#define init_proc_e500v2 init_proc_e500
|
||||
#define init_proc_e500v2 init_proc_e500v2
|
||||
|
||||
static void init_proc_e500 (CPUPPCState *env)
|
||||
static void init_proc_e500 (CPUPPCState *env, int version)
|
||||
{
|
||||
uint32_t tlbncfg[2];
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int i;
|
||||
#endif
|
||||
|
||||
/* Time base */
|
||||
gen_tbl(env);
|
||||
gen_spr_BookE(env, 0x0000000F0000FD7FULL);
|
||||
/*
|
||||
* XXX The e500 doesn't implement IVOR7 and IVOR9, but doesn't
|
||||
* complain when accessing them.
|
||||
* gen_spr_BookE(env, 0x0000000F0000FD7FULL);
|
||||
*/
|
||||
gen_spr_BookE(env, 0x0000000F0000FFFFULL);
|
||||
/* Processor identification */
|
||||
spr_register(env, SPR_BOOKE_PIR, "PIR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
@ -4312,8 +4376,24 @@ static void init_proc_e500 (CPUPPCState *env)
|
||||
/* Memory management */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
env->nb_pids = 3;
|
||||
env->nb_ways = 2;
|
||||
env->id_tlbs = 0;
|
||||
switch (version) {
|
||||
case 1:
|
||||
/* e500v1 */
|
||||
tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256);
|
||||
tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
|
||||
break;
|
||||
case 2:
|
||||
/* e500v2 */
|
||||
tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
|
||||
tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
|
||||
break;
|
||||
default:
|
||||
cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
|
||||
}
|
||||
#endif
|
||||
gen_spr_BookE_FSL(env, 0x0000005F);
|
||||
gen_spr_BookE206(env, 0x000000DF, tlbncfg);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_HID0, "HID0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
@ -4362,23 +4442,13 @@ static void init_proc_e500 (CPUPPCState *env)
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
&spr_read_generic, &spr_write_e500_l1csr0,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_Exxx_L1CSR1, "L1CSR1",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
@ -4387,11 +4457,18 @@ static void init_proc_e500 (CPUPPCState *env)
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_MMUCSR0, "MMUCSR0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_booke206_mmucsr0,
|
||||
0x00000000);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
env->nb_tlb = 64;
|
||||
env->nb_ways = 1;
|
||||
env->id_tlbs = 0;
|
||||
env->nb_tlb = 0;
|
||||
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
|
||||
env->nb_tlb += booke206_tlb_size(env, i);
|
||||
}
|
||||
#endif
|
||||
|
||||
init_excp_e200(env);
|
||||
env->dcache_line_size = 32;
|
||||
env->icache_line_size = 32;
|
||||
@ -4399,6 +4476,16 @@ static void init_proc_e500 (CPUPPCState *env)
|
||||
ppce500_irq_init(env);
|
||||
}
|
||||
|
||||
static void init_proc_e500v1(CPUPPCState *env)
|
||||
{
|
||||
init_proc_e500(env, 1);
|
||||
}
|
||||
|
||||
static void init_proc_e500v2(CPUPPCState *env)
|
||||
{
|
||||
init_proc_e500(env, 2);
|
||||
}
|
||||
|
||||
/* Non-embedded PowerPC */
|
||||
|
||||
/* POWER : same as 601, without mfmsr, mfsr */
|
||||
@ -4414,6 +4501,7 @@ static void init_proc_e500 (CPUPPCState *env)
|
||||
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_601 (PPC_NONE)
|
||||
#define POWERPC_MSRM_601 (0x000000000000FD70ULL)
|
||||
#define POWERPC_MSRR_601 (0x0000000000001040ULL)
|
||||
//#define POWERPC_MMU_601 (POWERPC_MMU_601)
|
||||
@ -4466,6 +4554,7 @@ static void init_proc_601 (CPUPPCState *env)
|
||||
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_601v (PPC_NONE)
|
||||
#define POWERPC_MSRM_601v (0x000000000000FD70ULL)
|
||||
#define POWERPC_MSRR_601v (0x0000000000001040ULL)
|
||||
#define POWERPC_MMU_601v (POWERPC_MMU_601)
|
||||
@ -4493,6 +4582,7 @@ static void init_proc_601v (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC | \
|
||||
PPC_SEGMENT | PPC_602_SPEC)
|
||||
#define POWERPC_INSNS2_602 (PPC_NONE)
|
||||
#define POWERPC_MSRM_602 (0x0000000000C7FF73ULL)
|
||||
/* XXX: 602 MMU is quite specific. Should add a special case */
|
||||
#define POWERPC_MMU_602 (POWERPC_MMU_SOFT_6xx)
|
||||
@ -4538,6 +4628,7 @@ static void init_proc_602 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_603 (PPC_NONE)
|
||||
#define POWERPC_MSRM_603 (0x000000000007FF73ULL)
|
||||
#define POWERPC_MMU_603 (POWERPC_MMU_SOFT_6xx)
|
||||
//#define POWERPC_EXCP_603 (POWERPC_EXCP_603)
|
||||
@ -4582,6 +4673,7 @@ static void init_proc_603 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_603E (PPC_NONE)
|
||||
#define POWERPC_MSRM_603E (0x000000000007FF73ULL)
|
||||
#define POWERPC_MMU_603E (POWERPC_MMU_SOFT_6xx)
|
||||
//#define POWERPC_EXCP_603E (POWERPC_EXCP_603E)
|
||||
@ -4631,6 +4723,7 @@ static void init_proc_603E (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_604 (PPC_NONE)
|
||||
#define POWERPC_MSRM_604 (0x000000000005FF77ULL)
|
||||
#define POWERPC_MMU_604 (POWERPC_MMU_32B)
|
||||
//#define POWERPC_EXCP_604 (POWERPC_EXCP_604)
|
||||
@ -4669,6 +4762,7 @@ static void init_proc_604 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_604E (PPC_NONE)
|
||||
#define POWERPC_MSRM_604E (0x000000000005FF77ULL)
|
||||
#define POWERPC_MMU_604E (POWERPC_MMU_32B)
|
||||
#define POWERPC_EXCP_604E (POWERPC_EXCP_604)
|
||||
@ -4727,6 +4821,7 @@ static void init_proc_604E (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_740 (PPC_NONE)
|
||||
#define POWERPC_MSRM_740 (0x000000000005FF77ULL)
|
||||
#define POWERPC_MMU_740 (POWERPC_MMU_32B)
|
||||
#define POWERPC_EXCP_740 (POWERPC_EXCP_7x0)
|
||||
@ -4772,6 +4867,7 @@ static void init_proc_740 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_750 (PPC_NONE)
|
||||
#define POWERPC_MSRM_750 (0x000000000005FF77ULL)
|
||||
#define POWERPC_MMU_750 (POWERPC_MMU_32B)
|
||||
#define POWERPC_EXCP_750 (POWERPC_EXCP_7x0)
|
||||
@ -4863,6 +4959,7 @@ static void init_proc_750 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_750cl (PPC_NONE)
|
||||
#define POWERPC_MSRM_750cl (0x000000000005FF77ULL)
|
||||
#define POWERPC_MMU_750cl (POWERPC_MMU_32B)
|
||||
#define POWERPC_EXCP_750cl (POWERPC_EXCP_7x0)
|
||||
@ -5001,6 +5098,7 @@ static void init_proc_750cl (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_750cx (PPC_NONE)
|
||||
#define POWERPC_MSRM_750cx (0x000000000005FF77ULL)
|
||||
#define POWERPC_MMU_750cx (POWERPC_MMU_32B)
|
||||
#define POWERPC_EXCP_750cx (POWERPC_EXCP_7x0)
|
||||
@ -5058,6 +5156,7 @@ static void init_proc_750cx (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_750fx (PPC_NONE)
|
||||
#define POWERPC_MSRM_750fx (0x000000000005FF77ULL)
|
||||
#define POWERPC_MMU_750fx (POWERPC_MMU_32B)
|
||||
#define POWERPC_EXCP_750fx (POWERPC_EXCP_7x0)
|
||||
@ -5120,6 +5219,7 @@ static void init_proc_750fx (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_750gx (PPC_NONE)
|
||||
#define POWERPC_MSRM_750gx (0x000000000005FF77ULL)
|
||||
#define POWERPC_MMU_750gx (POWERPC_MMU_32B)
|
||||
#define POWERPC_EXCP_750gx (POWERPC_EXCP_7x0)
|
||||
@ -5182,6 +5282,7 @@ static void init_proc_750gx (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_745 (PPC_NONE)
|
||||
#define POWERPC_MSRM_745 (0x000000000005FF77ULL)
|
||||
#define POWERPC_MMU_745 (POWERPC_MMU_SOFT_6xx)
|
||||
#define POWERPC_EXCP_745 (POWERPC_EXCP_7x5)
|
||||
@ -5235,6 +5336,7 @@ static void init_proc_745 (CPUPPCState *env)
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO | \
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN)
|
||||
#define POWERPC_INSNS2_755 (PPC_NONE)
|
||||
#define POWERPC_MSRM_755 (0x000000000005FF77ULL)
|
||||
#define POWERPC_MMU_755 (POWERPC_MMU_SOFT_6xx)
|
||||
#define POWERPC_EXCP_755 (POWERPC_EXCP_7x5)
|
||||
@ -5303,6 +5405,7 @@ static void init_proc_755 (CPUPPCState *env)
|
||||
PPC_MEM_TLBIA | \
|
||||
PPC_SEGMENT | PPC_EXTERN | \
|
||||
PPC_ALTIVEC)
|
||||
#define POWERPC_INSNS2_7400 (PPC_NONE)
|
||||
#define POWERPC_MSRM_7400 (0x000000000205FF77ULL)
|
||||
#define POWERPC_MMU_7400 (POWERPC_MMU_32B)
|
||||
#define POWERPC_EXCP_7400 (POWERPC_EXCP_74xx)
|
||||
@ -5355,6 +5458,7 @@ static void init_proc_7400 (CPUPPCState *env)
|
||||
PPC_MEM_TLBIA | \
|
||||
PPC_SEGMENT | PPC_EXTERN | \
|
||||
PPC_ALTIVEC)
|
||||
#define POWERPC_INSNS2_7410 (PPC_NONE)
|
||||
#define POWERPC_MSRM_7410 (0x000000000205FF77ULL)
|
||||
#define POWERPC_MMU_7410 (POWERPC_MMU_32B)
|
||||
#define POWERPC_EXCP_7410 (POWERPC_EXCP_74xx)
|
||||
@ -5413,6 +5517,7 @@ static void init_proc_7410 (CPUPPCState *env)
|
||||
PPC_MEM_TLBIA | PPC_74xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN | \
|
||||
PPC_ALTIVEC)
|
||||
#define POWERPC_INSNS2_7440 (PPC_NONE)
|
||||
#define POWERPC_MSRM_7440 (0x000000000205FF77ULL)
|
||||
#define POWERPC_MMU_7440 (POWERPC_MMU_SOFT_74xx)
|
||||
#define POWERPC_EXCP_7440 (POWERPC_EXCP_74xx)
|
||||
@ -5498,6 +5603,7 @@ static void init_proc_7440 (CPUPPCState *env)
|
||||
PPC_MEM_TLBIA | PPC_74xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN | \
|
||||
PPC_ALTIVEC)
|
||||
#define POWERPC_INSNS2_7450 (PPC_NONE)
|
||||
#define POWERPC_MSRM_7450 (0x000000000205FF77ULL)
|
||||
#define POWERPC_MMU_7450 (POWERPC_MMU_SOFT_74xx)
|
||||
#define POWERPC_EXCP_7450 (POWERPC_EXCP_74xx)
|
||||
@ -5609,6 +5715,7 @@ static void init_proc_7450 (CPUPPCState *env)
|
||||
PPC_MEM_TLBIA | PPC_74xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN | \
|
||||
PPC_ALTIVEC)
|
||||
#define POWERPC_INSNS2_7445 (PPC_NONE)
|
||||
#define POWERPC_MSRM_7445 (0x000000000205FF77ULL)
|
||||
#define POWERPC_MMU_7445 (POWERPC_MMU_SOFT_74xx)
|
||||
#define POWERPC_EXCP_7445 (POWERPC_EXCP_74xx)
|
||||
@ -5723,6 +5830,7 @@ static void init_proc_7445 (CPUPPCState *env)
|
||||
PPC_MEM_TLBIA | PPC_74xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN | \
|
||||
PPC_ALTIVEC)
|
||||
#define POWERPC_INSNS2_7455 (PPC_NONE)
|
||||
#define POWERPC_MSRM_7455 (0x000000000205FF77ULL)
|
||||
#define POWERPC_MMU_7455 (POWERPC_MMU_SOFT_74xx)
|
||||
#define POWERPC_EXCP_7455 (POWERPC_EXCP_74xx)
|
||||
@ -5839,6 +5947,7 @@ static void init_proc_7455 (CPUPPCState *env)
|
||||
PPC_MEM_TLBIA | PPC_74xx_TLB | \
|
||||
PPC_SEGMENT | PPC_EXTERN | \
|
||||
PPC_ALTIVEC)
|
||||
#define POWERPC_INSNS2_7457 (PPC_NONE)
|
||||
#define POWERPC_MSRM_7457 (0x000000000205FF77ULL)
|
||||
#define POWERPC_MMU_7457 (POWERPC_MMU_SOFT_74xx)
|
||||
#define POWERPC_EXCP_7457 (POWERPC_EXCP_74xx)
|
||||
@ -5978,6 +6087,7 @@ static void init_proc_7457 (CPUPPCState *env)
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_64B | PPC_ALTIVEC | \
|
||||
PPC_SEGMENT_64B | PPC_SLBI)
|
||||
#define POWERPC_INSNS2_970 (PPC_NONE)
|
||||
#define POWERPC_MSRM_970 (0x900000000204FF36ULL)
|
||||
#define POWERPC_MMU_970 (POWERPC_MMU_64B)
|
||||
//#define POWERPC_EXCP_970 (POWERPC_EXCP_970)
|
||||
@ -6073,6 +6183,7 @@ static void init_proc_970 (CPUPPCState *env)
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_64B | PPC_ALTIVEC | \
|
||||
PPC_SEGMENT_64B | PPC_SLBI)
|
||||
#define POWERPC_INSNS2_970FX (PPC_NONE)
|
||||
#define POWERPC_MSRM_970FX (0x800000000204FF36ULL)
|
||||
#define POWERPC_MMU_970FX (POWERPC_MMU_64B)
|
||||
#define POWERPC_EXCP_970FX (POWERPC_EXCP_970)
|
||||
@ -6174,6 +6285,7 @@ static void init_proc_970FX (CPUPPCState *env)
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_64B | PPC_ALTIVEC | \
|
||||
PPC_SEGMENT_64B | PPC_SLBI)
|
||||
#define POWERPC_INSNS2_970GX (PPC_NONE)
|
||||
#define POWERPC_MSRM_970GX (0x800000000204FF36ULL)
|
||||
#define POWERPC_MMU_970GX (POWERPC_MMU_64B)
|
||||
#define POWERPC_EXCP_970GX (POWERPC_EXCP_970)
|
||||
@ -6263,6 +6375,7 @@ static void init_proc_970GX (CPUPPCState *env)
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_64B | PPC_ALTIVEC | \
|
||||
PPC_SEGMENT_64B | PPC_SLBI)
|
||||
#define POWERPC_INSNS2_970MP (PPC_NONE)
|
||||
#define POWERPC_MSRM_970MP (0x900000000204FF36ULL)
|
||||
#define POWERPC_MMU_970MP (POWERPC_MMU_64B)
|
||||
#define POWERPC_EXCP_970MP (POWERPC_EXCP_970)
|
||||
@ -6354,6 +6467,7 @@ static void init_proc_970MP (CPUPPCState *env)
|
||||
PPC_64B | PPC_ALTIVEC | \
|
||||
PPC_SEGMENT_64B | PPC_SLBI | \
|
||||
PPC_POPCNTB | PPC_POPCNTWD)
|
||||
#define POWERPC_INSNS2_POWER7 (PPC_NONE)
|
||||
#define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL)
|
||||
#define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06)
|
||||
#define POWERPC_EXCP_POWER7 (POWERPC_EXCP_POWER7)
|
||||
@ -6424,6 +6538,7 @@ static void init_proc_POWER7 (CPUPPCState *env)
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \
|
||||
PPC_SEGMENT | PPC_EXTERN | \
|
||||
PPC_64B | PPC_SLBI)
|
||||
#define POWERPC_INSNS2_620 (PPC_NONE)
|
||||
#define POWERPC_MSRM_620 (0x800000000005FF77ULL)
|
||||
//#define POWERPC_MMU_620 (POWERPC_MMU_620)
|
||||
#define POWERPC_EXCP_620 (POWERPC_EXCP_970)
|
||||
@ -6459,6 +6574,7 @@ static void init_proc_620 (CPUPPCState *env)
|
||||
/* Default 32 bits PowerPC target will be 604 */
|
||||
#define CPU_POWERPC_PPC32 CPU_POWERPC_604
|
||||
#define POWERPC_INSNS_PPC32 POWERPC_INSNS_604
|
||||
#define POWERPC_INSNS2_PPC32 POWERPC_INSNS2_604
|
||||
#define POWERPC_MSRM_PPC32 POWERPC_MSRM_604
|
||||
#define POWERPC_MMU_PPC32 POWERPC_MMU_604
|
||||
#define POWERPC_EXCP_PPC32 POWERPC_EXCP_604
|
||||
@ -6471,6 +6587,7 @@ static void init_proc_620 (CPUPPCState *env)
|
||||
/* Default 64 bits PowerPC target will be 970 FX */
|
||||
#define CPU_POWERPC_PPC64 CPU_POWERPC_970FX
|
||||
#define POWERPC_INSNS_PPC64 POWERPC_INSNS_970FX
|
||||
#define POWERPC_INSNS2_PPC64 POWERPC_INSNS2_970FX
|
||||
#define POWERPC_MSRM_PPC64 POWERPC_MSRM_970FX
|
||||
#define POWERPC_MMU_PPC64 POWERPC_MMU_970FX
|
||||
#define POWERPC_EXCP_PPC64 POWERPC_EXCP_970FX
|
||||
@ -6482,27 +6599,29 @@ static void init_proc_620 (CPUPPCState *env)
|
||||
|
||||
/* Default PowerPC target will be PowerPC 32 */
|
||||
#if defined (TARGET_PPC64) && 0 // XXX: TODO
|
||||
#define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC64
|
||||
#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC64
|
||||
#define POWERPC_MSRM_DEFAULT POWERPC_MSRM_PPC64
|
||||
#define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC64
|
||||
#define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC64
|
||||
#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC64
|
||||
#define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC64
|
||||
#define POWERPC_FLAG_DEFAULT POWERPC_FLAG_PPC64
|
||||
#define check_pow_DEFAULT check_pow_PPC64
|
||||
#define init_proc_DEFAULT init_proc_PPC64
|
||||
#define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC64
|
||||
#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC64
|
||||
#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC64
|
||||
#define POWERPC_MSRM_DEFAULT POWERPC_MSRM_PPC64
|
||||
#define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC64
|
||||
#define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC64
|
||||
#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC64
|
||||
#define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC64
|
||||
#define POWERPC_FLAG_DEFAULT POWERPC_FLAG_PPC64
|
||||
#define check_pow_DEFAULT check_pow_PPC64
|
||||
#define init_proc_DEFAULT init_proc_PPC64
|
||||
#else
|
||||
#define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC32
|
||||
#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC32
|
||||
#define POWERPC_MSRM_DEFAULT POWERPC_MSRM_PPC32
|
||||
#define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC32
|
||||
#define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC32
|
||||
#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC32
|
||||
#define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC32
|
||||
#define POWERPC_FLAG_DEFAULT POWERPC_FLAG_PPC32
|
||||
#define check_pow_DEFAULT check_pow_PPC32
|
||||
#define init_proc_DEFAULT init_proc_PPC32
|
||||
#define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC32
|
||||
#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC32
|
||||
#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC32
|
||||
#define POWERPC_MSRM_DEFAULT POWERPC_MSRM_PPC32
|
||||
#define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC32
|
||||
#define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC32
|
||||
#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC32
|
||||
#define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC32
|
||||
#define POWERPC_FLAG_DEFAULT POWERPC_FLAG_PPC32
|
||||
#define check_pow_DEFAULT check_pow_PPC32
|
||||
#define init_proc_DEFAULT init_proc_PPC32
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -7351,18 +7470,19 @@ enum {
|
||||
/* PowerPC CPU definitions */
|
||||
#define POWERPC_DEF_SVR(_name, _pvr, _svr, _type) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
.pvr = _pvr, \
|
||||
.svr = _svr, \
|
||||
.insns_flags = glue(POWERPC_INSNS_,_type), \
|
||||
.msr_mask = glue(POWERPC_MSRM_,_type), \
|
||||
.mmu_model = glue(POWERPC_MMU_,_type), \
|
||||
.excp_model = glue(POWERPC_EXCP_,_type), \
|
||||
.bus_model = glue(POWERPC_INPUT_,_type), \
|
||||
.bfd_mach = glue(POWERPC_BFDM_,_type), \
|
||||
.flags = glue(POWERPC_FLAG_,_type), \
|
||||
.init_proc = &glue(init_proc_,_type), \
|
||||
.check_pow = &glue(check_pow_,_type), \
|
||||
.name = _name, \
|
||||
.pvr = _pvr, \
|
||||
.svr = _svr, \
|
||||
.insns_flags = glue(POWERPC_INSNS_,_type), \
|
||||
.insns_flags2 = glue(POWERPC_INSNS2_,_type), \
|
||||
.msr_mask = glue(POWERPC_MSRM_,_type), \
|
||||
.mmu_model = glue(POWERPC_MMU_,_type), \
|
||||
.excp_model = glue(POWERPC_EXCP_,_type), \
|
||||
.bus_model = glue(POWERPC_INPUT_,_type), \
|
||||
.bfd_mach = glue(POWERPC_BFDM_,_type), \
|
||||
.flags = glue(POWERPC_FLAG_,_type), \
|
||||
.init_proc = &glue(init_proc_,_type), \
|
||||
.check_pow = &glue(check_pow_,_type), \
|
||||
}
|
||||
#define POWERPC_DEF(_name, _pvr, _type) \
|
||||
POWERPC_DEF_SVR(_name, _pvr, POWERPC_SVR_NONE, _type)
|
||||
@ -9437,7 +9557,8 @@ static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def)
|
||||
|
||||
fill_new_table(env->opcodes, 0x40);
|
||||
for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) {
|
||||
if ((opc->handler.type & def->insns_flags) != 0) {
|
||||
if (((opc->handler.type & def->insns_flags) != 0) ||
|
||||
((opc->handler.type2 & def->insns_flags2) != 0)) {
|
||||
if (register_insn(env->opcodes, opc) < 0) {
|
||||
printf("*** ERROR initializing PowerPC instruction "
|
||||
"0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
|
||||
@ -9650,6 +9771,7 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
|
||||
env->excp_model = def->excp_model;
|
||||
env->bus_model = def->bus_model;
|
||||
env->insns_flags = def->insns_flags;
|
||||
env->insns_flags2 = def->insns_flags2;
|
||||
env->flags = def->flags;
|
||||
env->bfd_mach = def->bfd_mach;
|
||||
env->check_pow = def->check_pow;
|
||||
@ -9699,8 +9821,8 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
|
||||
case POWERPC_MMU_BOOKE:
|
||||
mmu_model = "PowerPC BookE";
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE_FSL:
|
||||
mmu_model = "PowerPC BookE FSL";
|
||||
case POWERPC_MMU_BOOKE206:
|
||||
mmu_model = "PowerPC BookE 2.06";
|
||||
break;
|
||||
case POWERPC_MMU_601:
|
||||
mmu_model = "PowerPC 601";
|
||||
|
Loading…
Reference in New Issue
Block a user