mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'pull-ppc-20220104' of https://github.com/legoater/qemu into staging
ppc 7.0 queue: * Cleanup of PowerNV PHBs (Daniel and Cedric) * Cleanup and fixes for PPC405 machine (Cedric) * Fix for xscvspdpn (Matheus) * Rework of powerpc exception handling 1/n (Fabiano) * Optimisation for PMU (Richard and Daniel) # gpg: Signature made Mon 03 Jan 2022 11:04:06 PM PST # gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1 # gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1 * tag 'pull-ppc-20220104' of https://github.com/legoater/qemu: (26 commits) target/ppc: do not call hreg_compute_hflags() in helper_store_mmcr0() target/ppc: Use env->pnc_cyc_cnt target/ppc: Rewrite pmu_increment_insns target/ppc: Cache per-pmc insn and cycle count settings target/ppc: powerpc_excp: Stop passing excp_model around target/ppc: powerpc_excp: Move system call vectored code together target/ppc: powerpc_excp: Set vector earlier target/ppc: powerpc_excp: Add excp_vectors bounds check target/ppc: powerpc_excp: Set alternate SRRs directly target/ppc: do not silence snan in xscvspdpn ppc/ppc405: Dump specific registers ppc/ppc405: Introduce a store helper for SPR_40x_PID ppc/ppc405: Fix timer initialization ppc/ppc405: Rework ppc_40x_timers_init() to use a PowerPCCPU ppc/ppc405: Restore TCR and STR write handlers ppc/ppc405: Activate MMU logs ppc/ppc4xx: Convert printfs() target/ppc: Print out literal exception names in logs target/ppc: Remove static inline target/ppc: Check effective address validity ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
@@ -1045,7 +1045,8 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_init(&phb->pci_mmio, OBJECT(phb), "pci-mmio",
|
||||
PCI_MMIO_TOTAL_SIZE);
|
||||
|
||||
pci->bus = pci_register_root_bus(dev, "root-bus",
|
||||
pci->bus = pci_register_root_bus(dev,
|
||||
dev->id ? dev->id : NULL,
|
||||
pnv_phb3_set_irq, pnv_phb3_map_irq, phb,
|
||||
&phb->pci_mmio, &phb->pci_io,
|
||||
0, 4, TYPE_PNV_PHB3_ROOT_BUS);
|
||||
|
||||
+1
-15
@@ -1201,7 +1201,7 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_init(&phb->pci_mmio, OBJECT(phb), name,
|
||||
PCI_MMIO_TOTAL_SIZE);
|
||||
|
||||
pci->bus = pci_register_root_bus(dev, "root-bus",
|
||||
pci->bus = pci_register_root_bus(dev, dev->id,
|
||||
pnv_phb4_set_irq, pnv_phb4_map_irq, phb,
|
||||
&phb->pci_mmio, &phb->pci_io,
|
||||
0, 4, TYPE_PNV_PHB4_ROOT_BUS);
|
||||
@@ -1230,18 +1230,6 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
|
||||
phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
|
||||
}
|
||||
|
||||
static void pnv_phb4_reset(DeviceState *dev)
|
||||
{
|
||||
PnvPHB4 *phb = PNV_PHB4(dev);
|
||||
PCIDevice *root_dev = PCI_DEVICE(&phb->root);
|
||||
|
||||
/*
|
||||
* Configure PCI device id at reset using a property.
|
||||
*/
|
||||
pci_config_set_vendor_id(root_dev->config, PCI_VENDOR_ID_IBM);
|
||||
pci_config_set_device_id(root_dev->config, phb->device_id);
|
||||
}
|
||||
|
||||
static const char *pnv_phb4_root_bus_path(PCIHostState *host_bridge,
|
||||
PCIBus *rootbus)
|
||||
{
|
||||
@@ -1274,7 +1262,6 @@ static Property pnv_phb4_properties[] = {
|
||||
DEFINE_PROP_UINT32("index", PnvPHB4, phb_id, 0),
|
||||
DEFINE_PROP_UINT32("chip-id", PnvPHB4, chip_id, 0),
|
||||
DEFINE_PROP_UINT64("version", PnvPHB4, version, 0),
|
||||
DEFINE_PROP_UINT16("device-id", PnvPHB4, device_id, 0),
|
||||
DEFINE_PROP_LINK("stack", PnvPHB4, stack, TYPE_PNV_PHB4_PEC_STACK,
|
||||
PnvPhb4PecStack *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@@ -1291,7 +1278,6 @@ static void pnv_phb4_class_init(ObjectClass *klass, void *data)
|
||||
device_class_set_props(dc, pnv_phb4_properties);
|
||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||
dc->user_creatable = false;
|
||||
dc->reset = pnv_phb4_reset;
|
||||
|
||||
xfc->notify = pnv_phb4_xive_notify;
|
||||
}
|
||||
|
||||
@@ -527,7 +527,6 @@ static void pnv_pec_class_init(ObjectClass *klass, void *data)
|
||||
pecc->stk_compat = stk_compat;
|
||||
pecc->stk_compat_size = sizeof(stk_compat);
|
||||
pecc->version = PNV_PHB4_VERSION;
|
||||
pecc->device_id = PNV_PHB4_DEVICE_ID;
|
||||
pecc->num_stacks = pnv_pec_num_stacks;
|
||||
}
|
||||
|
||||
@@ -587,8 +586,6 @@ static void pnv_pec_stk_realize(DeviceState *dev, Error **errp)
|
||||
&error_fatal);
|
||||
object_property_set_int(OBJECT(&stack->phb), "version", pecc->version,
|
||||
&error_fatal);
|
||||
object_property_set_int(OBJECT(&stack->phb), "device-id", pecc->device_id,
|
||||
&error_fatal);
|
||||
object_property_set_link(OBJECT(&stack->phb), "stack", OBJECT(stack),
|
||||
&error_abort);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&stack->phb), errp)) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/sysbus.h"
|
||||
@@ -82,7 +83,9 @@ static uint64_t mpc8544_guts_read(void *opaque, hwaddr addr,
|
||||
value = env->spr[SPR_E500_SVR];
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Unknown register 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -101,8 +104,8 @@ static void mpc8544_guts_write(void *opaque, hwaddr addr,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "guts: Unknown register write: %x = %x\n",
|
||||
(int)addr, (unsigned)value);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Unknown register 0x%" HWADDR_PRIx
|
||||
" = 0x%" PRIx64 "\n", __func__, addr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1314,7 +1314,7 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
k->chip_cfam_id = 0x120d304980000000ull; /* P8 Naples DD1.0 */
|
||||
k->cores_mask = POWER8_CORE_MASK;
|
||||
k->num_phbs = 3;
|
||||
k->num_phbs = 4;
|
||||
k->core_pir = pnv_chip_core_pir_p8;
|
||||
k->intc_create = pnv_chip_power8_intc_create;
|
||||
k->intc_reset = pnv_chip_power8_intc_reset;
|
||||
|
||||
+44
-23
@@ -1124,14 +1124,12 @@ struct ppc40x_timer_t {
|
||||
/* Fixed interval timer */
|
||||
static void cpu_4xx_fit_cb (void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu;
|
||||
CPUPPCState *env;
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
ppc_tb_t *tb_env;
|
||||
ppc40x_timer_t *ppc40x_timer;
|
||||
uint64_t now, next;
|
||||
|
||||
env = opaque;
|
||||
cpu = env_archcpu(env);
|
||||
tb_env = env->tb_env;
|
||||
ppc40x_timer = tb_env->opaque;
|
||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
@@ -1193,13 +1191,11 @@ static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
|
||||
|
||||
static void cpu_4xx_pit_cb (void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu;
|
||||
CPUPPCState *env;
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
ppc_tb_t *tb_env;
|
||||
ppc40x_timer_t *ppc40x_timer;
|
||||
|
||||
env = opaque;
|
||||
cpu = env_archcpu(env);
|
||||
tb_env = env->tb_env;
|
||||
ppc40x_timer = tb_env->opaque;
|
||||
env->spr[SPR_40x_TSR] |= 1 << 27;
|
||||
@@ -1216,14 +1212,12 @@ static void cpu_4xx_pit_cb (void *opaque)
|
||||
/* Watchdog timer */
|
||||
static void cpu_4xx_wdt_cb (void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu;
|
||||
CPUPPCState *env;
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
ppc_tb_t *tb_env;
|
||||
ppc40x_timer_t *ppc40x_timer;
|
||||
uint64_t now, next;
|
||||
|
||||
env = opaque;
|
||||
cpu = env_archcpu(env);
|
||||
tb_env = env->tb_env;
|
||||
ppc40x_timer = tb_env->opaque;
|
||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
@@ -1300,6 +1294,31 @@ target_ulong load_40x_pit (CPUPPCState *env)
|
||||
return cpu_ppc_load_decr(env);
|
||||
}
|
||||
|
||||
void store_40x_tsr(CPUPPCState *env, target_ulong val)
|
||||
{
|
||||
PowerPCCPU *cpu = env_archcpu(env);
|
||||
|
||||
trace_ppc40x_store_tcr(val);
|
||||
|
||||
env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
|
||||
if (val & 0x80000000) {
|
||||
ppc_set_irq(cpu, PPC_INTERRUPT_PIT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void store_40x_tcr(CPUPPCState *env, target_ulong val)
|
||||
{
|
||||
PowerPCCPU *cpu = env_archcpu(env);
|
||||
ppc_tb_t *tb_env;
|
||||
|
||||
trace_ppc40x_store_tsr(val);
|
||||
|
||||
tb_env = env->tb_env;
|
||||
env->spr[SPR_40x_TCR] = val & 0xFFC00000;
|
||||
start_stop_pit(env, tb_env, 1);
|
||||
cpu_4xx_wdt_cb(cpu);
|
||||
}
|
||||
|
||||
static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
|
||||
{
|
||||
CPUPPCState *env = opaque;
|
||||
@@ -1316,24 +1335,26 @@ clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
|
||||
{
|
||||
ppc_tb_t *tb_env;
|
||||
ppc40x_timer_t *ppc40x_timer;
|
||||
PowerPCCPU *cpu = env_archcpu(env);
|
||||
|
||||
trace_ppc40x_timers_init(freq);
|
||||
|
||||
tb_env = g_malloc0(sizeof(ppc_tb_t));
|
||||
ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t));
|
||||
|
||||
env->tb_env = tb_env;
|
||||
tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
|
||||
ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t));
|
||||
tb_env->tb_freq = freq;
|
||||
tb_env->decr_freq = freq;
|
||||
tb_env->opaque = ppc40x_timer;
|
||||
trace_ppc40x_timers_init(freq);
|
||||
if (ppc40x_timer != NULL) {
|
||||
/* We use decr timer for PIT */
|
||||
tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, env);
|
||||
ppc40x_timer->fit_timer =
|
||||
timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, env);
|
||||
ppc40x_timer->wdt_timer =
|
||||
timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, env);
|
||||
ppc40x_timer->decr_excp = decr_excp;
|
||||
}
|
||||
|
||||
/* We use decr timer for PIT */
|
||||
tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, cpu);
|
||||
ppc40x_timer->fit_timer =
|
||||
timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, cpu);
|
||||
ppc40x_timer->wdt_timer =
|
||||
timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, cpu);
|
||||
ppc40x_timer->decr_excp = decr_excp;
|
||||
|
||||
return &ppc_40x_set_tb_clk;
|
||||
}
|
||||
|
||||
@@ -1461,8 +1461,6 @@ PowerPCCPU *ppc405ep_init(MemoryRegion *address_space_mem,
|
||||
ppc4xx_pob_init(env);
|
||||
/* OBP arbitrer */
|
||||
ppc4xx_opba_init(0xef600600);
|
||||
/* Initialize timers */
|
||||
ppc_booke_timers_init(cpu, sysclk, 0);
|
||||
/* Universal interrupt controller */
|
||||
uicdev = qdev_new(TYPE_PPC_UIC);
|
||||
uicsbd = SYS_BUS_DEVICE(uicdev);
|
||||
|
||||
+11
-28
@@ -35,14 +35,7 @@
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
/*#define DEBUG_UIC*/
|
||||
|
||||
#ifdef DEBUG_UIC
|
||||
# define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
|
||||
#else
|
||||
# define LOG_UIC(...) do { } while (0)
|
||||
#endif
|
||||
#include "trace.h"
|
||||
|
||||
static void ppc4xx_reset(void *opaque)
|
||||
{
|
||||
@@ -137,8 +130,9 @@ static uint32_t sdram_bcr (hwaddr ram_base,
|
||||
bcr = 0x000C0000;
|
||||
break;
|
||||
default:
|
||||
printf("%s: invalid RAM size " TARGET_FMT_plx "\n", __func__,
|
||||
ram_size);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__,
|
||||
ram_size);
|
||||
return 0x00000000;
|
||||
}
|
||||
bcr |= ram_base & 0xFF800000;
|
||||
@@ -171,10 +165,8 @@ static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i,
|
||||
{
|
||||
if (sdram->bcr[i] & 0x00000001) {
|
||||
/* Unmap RAM */
|
||||
#ifdef DEBUG_SDRAM
|
||||
printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
|
||||
__func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
|
||||
#endif
|
||||
trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]),
|
||||
sdram_size(sdram->bcr[i]));
|
||||
memory_region_del_subregion(get_system_memory(),
|
||||
&sdram->containers[i]);
|
||||
memory_region_del_subregion(&sdram->containers[i],
|
||||
@@ -183,10 +175,7 @@ static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i,
|
||||
}
|
||||
sdram->bcr[i] = bcr & 0xFFDEE001;
|
||||
if (enabled && (bcr & 0x00000001)) {
|
||||
#ifdef DEBUG_SDRAM
|
||||
printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
|
||||
__func__, sdram_base(bcr), sdram_size(bcr));
|
||||
#endif
|
||||
trace_ppc4xx_sdram_unmap(sdram_base(bcr), sdram_size(bcr));
|
||||
memory_region_init(&sdram->containers[i], NULL, "sdram-containers",
|
||||
sdram_size(bcr));
|
||||
memory_region_add_subregion(&sdram->containers[i], 0,
|
||||
@@ -216,10 +205,8 @@ static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sdram->nbanks; i++) {
|
||||
#ifdef DEBUG_SDRAM
|
||||
printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
|
||||
__func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
|
||||
#endif
|
||||
trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]),
|
||||
sdram_size(sdram->bcr[i]));
|
||||
memory_region_del_subregion(get_system_memory(),
|
||||
&sdram->ram_memories[i]);
|
||||
}
|
||||
@@ -316,16 +303,12 @@ static void dcr_write_sdram (void *opaque, int dcrn, uint32_t val)
|
||||
case 0x20: /* SDRAM_CFG */
|
||||
val &= 0xFFE00000;
|
||||
if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
|
||||
#ifdef DEBUG_SDRAM
|
||||
printf("%s: enable SDRAM controller\n", __func__);
|
||||
#endif
|
||||
trace_ppc4xx_sdram_enable("enable");
|
||||
/* validate all RAM mappings */
|
||||
sdram_map_bcr(sdram);
|
||||
sdram->status &= ~0x80000000;
|
||||
} else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
|
||||
#ifdef DEBUG_SDRAM
|
||||
printf("%s: disable SDRAM controller\n", __func__);
|
||||
#endif
|
||||
trace_ppc4xx_sdram_enable("disable");
|
||||
/* invalidate all RAM mappings */
|
||||
sdram_unmap_bcr(sdram);
|
||||
sdram->status |= 0x80000000;
|
||||
|
||||
+7
-4
@@ -20,6 +20,7 @@
|
||||
* 4xx SoCs, such as the 440EP. */
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/ppc/ppc.h"
|
||||
#include "hw/ppc/ppc4xx.h"
|
||||
@@ -152,8 +153,9 @@ static void ppc4xx_pci_reg_write4(void *opaque, hwaddr offset,
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: unhandled PCI internal register 0x%lx\n", __func__,
|
||||
(unsigned long)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: unhandled PCI internal register 0x%" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -218,8 +220,9 @@ static uint64_t ppc4xx_pci_reg_read4(void *opaque, hwaddr offset,
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: invalid PCI internal register 0x%lx\n", __func__,
|
||||
(unsigned long)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid PCI internal register 0x%" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
value = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,8 @@ ppc4xx_pit_start(uint64_t reload) "PIT 0x%016" PRIx64
|
||||
ppc4xx_pit(uint32_t ar, uint32_t ir, uint64_t tcr, uint64_t tsr, uint64_t reload) "ar %d ir %d TCR 0x%" PRIx64 " TSR 0x%" PRIx64 " PIT 0x%016" PRIx64
|
||||
ppc4xx_wdt(uint64_t tcr, uint64_t tsr) "TCR 0x%" PRIx64 " TSR 0x%" PRIx64
|
||||
ppc40x_store_pit(uint64_t value) "val 0x%" PRIx64
|
||||
ppc40x_store_tcr(uint64_t value) "val 0x%" PRIx64
|
||||
ppc40x_store_tsr(uint64_t value) "val 0x%" PRIx64
|
||||
ppc40x_set_tb_clk(uint32_t value) "new frequency %" PRIu32
|
||||
ppc40x_timers_init(uint32_t value) "frequency %" PRIu32
|
||||
|
||||
@@ -164,3 +166,8 @@ ppc4xx_gpt_init(uint64_t addr) "offet 0x%" PRIx64
|
||||
|
||||
ppc405ep_clocks_compute(const char *param, uint32_t param2, uint32_t val) "%s 0x%1" PRIx32 " %d"
|
||||
ppc405ep_clocks_setup(const char *trace) "%s"
|
||||
|
||||
# ppc4xx_devs.c
|
||||
ppc4xx_sdram_enable(const char *trace) "%s SDRAM controller"
|
||||
ppc4xx_sdram_unmap(uint64_t addr, uint64_t size) "Unmap RAM area 0x%" PRIx64 " size 0x%" PRIx64
|
||||
ppc4xx_sdram_map(uint64_t addr, uint64_t size) "Map RAM area 0x%" PRIx64 " size 0x%" PRIx64
|
||||
|
||||
@@ -84,7 +84,6 @@ struct PnvPHB4 {
|
||||
uint32_t phb_id;
|
||||
|
||||
uint64_t version;
|
||||
uint16_t device_id;
|
||||
|
||||
char bus_path[8];
|
||||
|
||||
@@ -222,7 +221,6 @@ struct PnvPhb4PecClass {
|
||||
const char *stk_compat;
|
||||
int stk_compat_size;
|
||||
uint64_t version;
|
||||
uint64_t device_id;
|
||||
const uint32_t *num_stacks;
|
||||
};
|
||||
|
||||
|
||||
@@ -1144,6 +1144,9 @@ struct CPUPPCState {
|
||||
/* Other registers */
|
||||
target_ulong spr[1024]; /* special purpose registers */
|
||||
ppc_spr_t spr_cb[1024];
|
||||
/* Composite status for PMC[1-6] enabled and counting insns or cycles. */
|
||||
uint8_t pmc_ins_cnt;
|
||||
uint8_t pmc_cyc_cnt;
|
||||
/* Vector status and control register, minus VSCR_SAT */
|
||||
uint32_t vscr;
|
||||
/* VSX registers (including FP and AVR) */
|
||||
@@ -1399,6 +1402,8 @@ target_ulong load_40x_pit(CPUPPCState *env);
|
||||
void store_40x_pit(CPUPPCState *env, target_ulong val);
|
||||
void store_40x_dbcr0(CPUPPCState *env, uint32_t val);
|
||||
void store_40x_sler(CPUPPCState *env, uint32_t val);
|
||||
void store_40x_tcr(CPUPPCState *env, target_ulong val);
|
||||
void store_40x_tsr(CPUPPCState *env, target_ulong val);
|
||||
void store_booke_tcr(CPUPPCState *env, target_ulong val);
|
||||
void store_booke_tsr(CPUPPCState *env, target_ulong val);
|
||||
void ppc_tlb_invalidate_all(CPUPPCState *env);
|
||||
|
||||
+25
-9
@@ -1440,11 +1440,11 @@ static void register_40x_sprs(CPUPPCState *env)
|
||||
0x00000000);
|
||||
spr_register(env, SPR_40x_TCR, "TCR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_booke_tcr,
|
||||
&spr_read_generic, &spr_write_40x_tcr,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_40x_TSR, "TSR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_booke_tsr,
|
||||
&spr_read_generic, &spr_write_40x_tsr,
|
||||
0x00000000);
|
||||
}
|
||||
|
||||
@@ -1454,7 +1454,7 @@ static void register_405_sprs(CPUPPCState *env)
|
||||
/* MMU */
|
||||
spr_register(env, SPR_40x_PID, "PID",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
&spr_read_generic, &spr_write_40x_pid,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_4xx_CCR0, "CCR0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
@@ -8313,6 +8313,7 @@ static void ppc_cpu_reset(DeviceState *dev)
|
||||
#endif /* CONFIG_TCG */
|
||||
#endif
|
||||
|
||||
pmu_update_summaries(env);
|
||||
hreg_compute_hflags(env);
|
||||
env->reserve_addr = (target_ulong)-1ULL;
|
||||
/* Be sure no exception or interrupt is pending */
|
||||
@@ -8648,16 +8649,17 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
env->spr[SPR_SPRG4], env->spr[SPR_SPRG5],
|
||||
env->spr[SPR_SPRG6], env->spr[SPR_SPRG7]);
|
||||
|
||||
switch (env->excp_model) {
|
||||
#if defined(TARGET_PPC64)
|
||||
if (env->excp_model == POWERPC_EXCP_POWER7 ||
|
||||
env->excp_model == POWERPC_EXCP_POWER8 ||
|
||||
env->excp_model == POWERPC_EXCP_POWER9 ||
|
||||
env->excp_model == POWERPC_EXCP_POWER10) {
|
||||
case POWERPC_EXCP_POWER7:
|
||||
case POWERPC_EXCP_POWER8:
|
||||
case POWERPC_EXCP_POWER9:
|
||||
case POWERPC_EXCP_POWER10:
|
||||
qemu_fprintf(f, "HSRR0 " TARGET_FMT_lx " HSRR1 " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
if (env->excp_model == POWERPC_EXCP_BOOKE) {
|
||||
case POWERPC_EXCP_BOOKE:
|
||||
qemu_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],
|
||||
@@ -8688,6 +8690,20 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
* IVORs are left out as they are large and do not change often --
|
||||
* they can be read with "p $ivor0", "p $ivor1", etc.
|
||||
*/
|
||||
break;
|
||||
case POWERPC_EXCP_40x:
|
||||
qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
|
||||
" ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
|
||||
env->spr[SPR_40x_ESR], env->spr[SPR_40x_DEAR]);
|
||||
|
||||
qemu_fprintf(f, " EVPR " TARGET_FMT_lx " SRR2 " TARGET_FMT_lx
|
||||
" SRR3 " TARGET_FMT_lx " PID " TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_40x_EVPR], env->spr[SPR_40x_SRR2],
|
||||
env->spr[SPR_40x_SRR3], env->spr[SPR_40x_PID]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
|
||||
+125
-62
@@ -36,7 +36,79 @@
|
||||
/* Exception processing */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
static inline void dump_syscall(CPUPPCState *env)
|
||||
static const char *powerpc_excp_name(int excp)
|
||||
{
|
||||
switch (excp) {
|
||||
case POWERPC_EXCP_CRITICAL: return "CRITICAL";
|
||||
case POWERPC_EXCP_MCHECK: return "MCHECK";
|
||||
case POWERPC_EXCP_DSI: return "DSI";
|
||||
case POWERPC_EXCP_ISI: return "ISI";
|
||||
case POWERPC_EXCP_EXTERNAL: return "EXTERNAL";
|
||||
case POWERPC_EXCP_ALIGN: return "ALIGN";
|
||||
case POWERPC_EXCP_PROGRAM: return "PROGRAM";
|
||||
case POWERPC_EXCP_FPU: return "FPU";
|
||||
case POWERPC_EXCP_SYSCALL: return "SYSCALL";
|
||||
case POWERPC_EXCP_APU: return "APU";
|
||||
case POWERPC_EXCP_DECR: return "DECR";
|
||||
case POWERPC_EXCP_FIT: return "FIT";
|
||||
case POWERPC_EXCP_WDT: return "WDT";
|
||||
case POWERPC_EXCP_DTLB: return "DTLB";
|
||||
case POWERPC_EXCP_ITLB: return "ITLB";
|
||||
case POWERPC_EXCP_DEBUG: return "DEBUG";
|
||||
case POWERPC_EXCP_SPEU: return "SPEU";
|
||||
case POWERPC_EXCP_EFPDI: return "EFPDI";
|
||||
case POWERPC_EXCP_EFPRI: return "EFPRI";
|
||||
case POWERPC_EXCP_EPERFM: return "EPERFM";
|
||||
case POWERPC_EXCP_DOORI: return "DOORI";
|
||||
case POWERPC_EXCP_DOORCI: return "DOORCI";
|
||||
case POWERPC_EXCP_GDOORI: return "GDOORI";
|
||||
case POWERPC_EXCP_GDOORCI: return "GDOORCI";
|
||||
case POWERPC_EXCP_HYPPRIV: return "HYPPRIV";
|
||||
case POWERPC_EXCP_RESET: return "RESET";
|
||||
case POWERPC_EXCP_DSEG: return "DSEG";
|
||||
case POWERPC_EXCP_ISEG: return "ISEG";
|
||||
case POWERPC_EXCP_HDECR: return "HDECR";
|
||||
case POWERPC_EXCP_TRACE: return "TRACE";
|
||||
case POWERPC_EXCP_HDSI: return "HDSI";
|
||||
case POWERPC_EXCP_HISI: return "HISI";
|
||||
case POWERPC_EXCP_HDSEG: return "HDSEG";
|
||||
case POWERPC_EXCP_HISEG: return "HISEG";
|
||||
case POWERPC_EXCP_VPU: return "VPU";
|
||||
case POWERPC_EXCP_PIT: return "PIT";
|
||||
case POWERPC_EXCP_IO: return "IO";
|
||||
case POWERPC_EXCP_RUNM: return "RUNM";
|
||||
case POWERPC_EXCP_EMUL: return "EMUL";
|
||||
case POWERPC_EXCP_IFTLB: return "IFTLB";
|
||||
case POWERPC_EXCP_DLTLB: return "DLTLB";
|
||||
case POWERPC_EXCP_DSTLB: return "DSTLB";
|
||||
case POWERPC_EXCP_FPA: return "FPA";
|
||||
case POWERPC_EXCP_DABR: return "DABR";
|
||||
case POWERPC_EXCP_IABR: return "IABR";
|
||||
case POWERPC_EXCP_SMI: return "SMI";
|
||||
case POWERPC_EXCP_PERFM: return "PERFM";
|
||||
case POWERPC_EXCP_THERM: return "THERM";
|
||||
case POWERPC_EXCP_VPUA: return "VPUA";
|
||||
case POWERPC_EXCP_SOFTP: return "SOFTP";
|
||||
case POWERPC_EXCP_MAINT: return "MAINT";
|
||||
case POWERPC_EXCP_MEXTBR: return "MEXTBR";
|
||||
case POWERPC_EXCP_NMEXTBR: return "NMEXTBR";
|
||||
case POWERPC_EXCP_ITLBE: return "ITLBE";
|
||||
case POWERPC_EXCP_DTLBE: return "DTLBE";
|
||||
case POWERPC_EXCP_VSXU: return "VSXU";
|
||||
case POWERPC_EXCP_FU: return "FU";
|
||||
case POWERPC_EXCP_HV_EMU: return "HV_EMU";
|
||||
case POWERPC_EXCP_HV_MAINT: return "HV_MAINT";
|
||||
case POWERPC_EXCP_HV_FU: return "HV_FU";
|
||||
case POWERPC_EXCP_SDOOR: return "SDOOR";
|
||||
case POWERPC_EXCP_SDOOR_HV: return "SDOOR_HV";
|
||||
case POWERPC_EXCP_HVIRT: return "HVIRT";
|
||||
case POWERPC_EXCP_SYSCALL_VECTORED: return "SYSCALL_VECTORED";
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_syscall(CPUPPCState *env)
|
||||
{
|
||||
qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
|
||||
" r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
|
||||
@@ -48,7 +120,7 @@ static inline void dump_syscall(CPUPPCState *env)
|
||||
ppc_dump_gpr(env, 8), env->nip);
|
||||
}
|
||||
|
||||
static inline void dump_hcall(CPUPPCState *env)
|
||||
static void dump_hcall(CPUPPCState *env)
|
||||
{
|
||||
qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
|
||||
" r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
|
||||
@@ -161,7 +233,7 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
|
||||
* | a | h | 11 | 1 | 1 | h |
|
||||
* +--------------------------------------------------------------------+
|
||||
*/
|
||||
static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
|
||||
static void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
|
||||
target_ulong msr,
|
||||
target_ulong *new_msr,
|
||||
target_ulong *vector)
|
||||
@@ -258,7 +330,7 @@ static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
|
||||
static void powerpc_set_excp_state(PowerPCCPU *cpu,
|
||||
target_ulong vector, target_ulong msr)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
@@ -293,15 +365,21 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
|
||||
* Note that this function should be greatly optimized when called
|
||||
* with a constant excp, from ppc_hw_interrupt
|
||||
*/
|
||||
static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
static void powerpc_excp(PowerPCCPU *cpu, int excp)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int excp_model = env->excp_model;
|
||||
target_ulong msr, new_msr, vector;
|
||||
int srr0, srr1, asrr0, asrr1, lev = -1;
|
||||
int srr0, srr1, lev = -1;
|
||||
|
||||
if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
|
||||
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
|
||||
}
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
|
||||
" => %08x (%02x)\n", env->nip, excp, env->error_code);
|
||||
" => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
|
||||
excp, env->error_code);
|
||||
|
||||
/* new srr1 value excluding must-be-zero bits */
|
||||
if (excp_model == POWERPC_EXCP_BOOKE) {
|
||||
@@ -319,8 +397,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
/* target registers */
|
||||
srr0 = SPR_SRR0;
|
||||
srr1 = SPR_SRR1;
|
||||
asrr0 = -1;
|
||||
asrr1 = -1;
|
||||
|
||||
/*
|
||||
* check for special resume at 0x100 from doze/nap/sleep/winkle on
|
||||
@@ -354,10 +430,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
}
|
||||
#endif
|
||||
|
||||
vector = env->excp_vectors[excp];
|
||||
if (vector == (target_ulong)-1ULL) {
|
||||
cpu_abort(cs, "Raised an exception without defined vector %d\n",
|
||||
excp);
|
||||
}
|
||||
|
||||
vector |= env->excp_prefix;
|
||||
|
||||
switch (excp) {
|
||||
case POWERPC_EXCP_NONE:
|
||||
/* Should never happen */
|
||||
return;
|
||||
case POWERPC_EXCP_CRITICAL: /* Critical input */
|
||||
switch (excp_model) {
|
||||
case POWERPC_EXCP_40x:
|
||||
@@ -410,8 +491,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
/* FIXME: choose one or the other based on CPU type */
|
||||
srr0 = SPR_BOOKE_MCSRR0;
|
||||
srr1 = SPR_BOOKE_MCSRR1;
|
||||
asrr0 = SPR_BOOKE_CSRR0;
|
||||
asrr1 = SPR_BOOKE_CSRR1;
|
||||
|
||||
env->spr[SPR_BOOKE_CSRR0] = env->nip;
|
||||
env->spr[SPR_BOOKE_CSRR1] = msr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -542,6 +624,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
env->nip += 4;
|
||||
new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
|
||||
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
||||
|
||||
vector += lev * 0x20;
|
||||
|
||||
env->lr = env->nip;
|
||||
env->ctr = msr;
|
||||
break;
|
||||
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
|
||||
case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
|
||||
@@ -570,8 +657,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
/* FIXME: choose one or the other based on CPU type */
|
||||
srr0 = SPR_BOOKE_DSRR0;
|
||||
srr1 = SPR_BOOKE_DSRR1;
|
||||
asrr0 = SPR_BOOKE_CSRR0;
|
||||
asrr1 = SPR_BOOKE_CSRR1;
|
||||
|
||||
env->spr[SPR_BOOKE_CSRR0] = env->nip;
|
||||
env->spr[SPR_BOOKE_CSRR1] = msr;
|
||||
|
||||
/* DBSR already modified by caller */
|
||||
} else {
|
||||
cpu_abort(cs, "Debug exception triggered on unsupported model\n");
|
||||
@@ -830,22 +919,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
}
|
||||
#endif
|
||||
|
||||
vector = env->excp_vectors[excp];
|
||||
if (vector == (target_ulong)-1ULL) {
|
||||
cpu_abort(cs, "Raised an exception without defined vector %d\n",
|
||||
excp);
|
||||
}
|
||||
|
||||
vector |= env->excp_prefix;
|
||||
|
||||
/* If any alternate SRR register are defined, duplicate saved values */
|
||||
if (asrr0 != -1) {
|
||||
env->spr[asrr0] = env->nip;
|
||||
}
|
||||
if (asrr1 != -1) {
|
||||
env->spr[asrr1] = msr;
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
if (excp_model == POWERPC_EXCP_BOOKE) {
|
||||
if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
|
||||
@@ -869,14 +942,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
|
||||
/* Save MSR */
|
||||
env->spr[srr1] = msr;
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
} else {
|
||||
vector += lev * 0x20;
|
||||
|
||||
env->lr = env->nip;
|
||||
env->ctr = msr;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This can update new_msr and vector if AIL applies */
|
||||
@@ -888,9 +953,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
void ppc_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
powerpc_excp(cpu, env->excp_model, cs->exception_index);
|
||||
powerpc_excp(cpu, cs->exception_index);
|
||||
}
|
||||
|
||||
static void ppc_hw_interrupt(CPUPPCState *env)
|
||||
@@ -901,20 +965,20 @@ static void ppc_hw_interrupt(CPUPPCState *env)
|
||||
/* External reset */
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_RESET);
|
||||
return;
|
||||
}
|
||||
/* Machine check exception */
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
|
||||
return;
|
||||
}
|
||||
#if 0 /* TODO */
|
||||
/* External debug exception */
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -934,7 +998,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
|
||||
if ((async_deliver || msr_hv == 0) && hdice) {
|
||||
/* HDEC clears on delivery */
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_HDECR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -944,7 +1008,7 @@ static void ppc_hw_interrupt(CPUPPCState *env)
|
||||
/* LPCR will be clear when not supported so this will work */
|
||||
bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
|
||||
if ((async_deliver || msr_hv == 0) && hvice) {
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -956,14 +1020,14 @@ static void ppc_hw_interrupt(CPUPPCState *env)
|
||||
/* HEIC blocks delivery to the hypervisor */
|
||||
if ((async_deliver && !(heic && msr_hv && !msr_pr)) ||
|
||||
(env->has_hv_mode && msr_hv == 0 && !lpes0)) {
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (msr_ce != 0) {
|
||||
/* External critical interrupt */
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -971,24 +1035,24 @@ static void ppc_hw_interrupt(CPUPPCState *env)
|
||||
/* Watchdog timer on embedded PowerPC */
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_WDT);
|
||||
return;
|
||||
}
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
|
||||
return;
|
||||
}
|
||||
/* Fixed interval timer on embedded PowerPC */
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_FIT);
|
||||
return;
|
||||
}
|
||||
/* Programmable interval timer on embedded PowerPC */
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_PIT);
|
||||
return;
|
||||
}
|
||||
/* Decrementer exception */
|
||||
@@ -996,32 +1060,32 @@ static void ppc_hw_interrupt(CPUPPCState *env)
|
||||
if (ppc_decr_clear_on_delivery(env)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
|
||||
}
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_DECR);
|
||||
return;
|
||||
}
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
|
||||
if (is_book3s_arch2x(env)) {
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
|
||||
} else {
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_DOORI);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
|
||||
return;
|
||||
}
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_PERFM);
|
||||
return;
|
||||
}
|
||||
/* Thermal interrupt */
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_THERM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1046,9 +1110,8 @@ static void ppc_hw_interrupt(CPUPPCState *env)
|
||||
void ppc_cpu_do_system_reset(CPUState *cs)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
|
||||
powerpc_excp(cpu, POWERPC_EXCP_RESET);
|
||||
}
|
||||
|
||||
void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
|
||||
@@ -1167,7 +1230,7 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
#endif /* CONFIG_TCG */
|
||||
|
||||
static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
|
||||
static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
|
||||
@@ -2816,10 +2816,7 @@ uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb)
|
||||
|
||||
uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb)
|
||||
{
|
||||
float_status tstat = env->fp_status;
|
||||
set_float_exception_flags(0, &tstat);
|
||||
|
||||
return float32_to_float64(xb >> 32, &tstat);
|
||||
return helper_todouble(xb >> 32);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -706,6 +706,8 @@ DEF_HELPER_2(store_hid0_601, void, env, tl)
|
||||
DEF_HELPER_3(store_403_pbr, void, env, i32, tl)
|
||||
DEF_HELPER_FLAGS_1(load_40x_pit, TCG_CALL_NO_RWG, tl, env)
|
||||
DEF_HELPER_FLAGS_2(store_40x_pit, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(store_40x_tcr, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(store_40x_tsr, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_2(store_40x_dbcr0, void, env, tl)
|
||||
DEF_HELPER_2(store_40x_sler, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(store_booke_tcr, TCG_CALL_NO_RWG, void, env, tl)
|
||||
|
||||
@@ -123,7 +123,7 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
if (pmu_insn_cnt_enabled(env)) {
|
||||
if (env->pmc_ins_cnt) {
|
||||
hflags |= 1 << HFLAGS_INSN_CNT;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "kvm_ppc.h"
|
||||
#include "power8-pmu.h"
|
||||
|
||||
static void post_load_update_msr(CPUPPCState *env)
|
||||
{
|
||||
@@ -19,6 +20,7 @@ static void post_load_update_msr(CPUPPCState *env)
|
||||
*/
|
||||
env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB);
|
||||
ppc_store_msr(env, msr);
|
||||
pmu_update_summaries(env);
|
||||
}
|
||||
|
||||
static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
|
||||
|
||||
@@ -32,6 +32,11 @@ static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env,
|
||||
vaddr eaddr,
|
||||
uint64_t *lpid, uint64_t *pid)
|
||||
{
|
||||
/* When EA(2:11) are nonzero, raise a segment interrupt */
|
||||
if (eaddr & ~R_EADDR_VALID_MASK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (msr_hv) { /* MSR[HV] -> Hypervisor/bare metal */
|
||||
switch (eaddr & R_EADDR_QUADRANT) {
|
||||
case R_EADDR_QUADRANT0:
|
||||
@@ -97,12 +102,22 @@ static void ppc_radix64_raise_segi(PowerPCCPU *cpu, MMUAccessType access_type,
|
||||
env->error_code = 0;
|
||||
}
|
||||
|
||||
static inline const char *access_str(MMUAccessType access_type)
|
||||
{
|
||||
return access_type == MMU_DATA_LOAD ? "reading" :
|
||||
(access_type == MMU_DATA_STORE ? "writing" : "execute");
|
||||
}
|
||||
|
||||
static void ppc_radix64_raise_si(PowerPCCPU *cpu, MMUAccessType access_type,
|
||||
vaddr eaddr, uint32_t cause)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx" cause %08x\n",
|
||||
__func__, access_str(access_type),
|
||||
eaddr, cause);
|
||||
|
||||
switch (access_type) {
|
||||
case MMU_INST_FETCH:
|
||||
/* Instruction Storage Interrupt */
|
||||
@@ -130,6 +145,11 @@ static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type,
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx" 0x%"
|
||||
HWADDR_PRIx" cause %08x\n",
|
||||
__func__, access_str(access_type),
|
||||
eaddr, g_raddr, cause);
|
||||
|
||||
switch (access_type) {
|
||||
case MMU_INST_FETCH:
|
||||
/* H Instruction Storage Interrupt */
|
||||
@@ -306,6 +326,15 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu,
|
||||
hwaddr pte_addr;
|
||||
uint64_t pte;
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx
|
||||
" mmu_idx %u (prot %c%c%c) 0x%"HWADDR_PRIx"\n",
|
||||
__func__, access_str(access_type),
|
||||
eaddr, mmu_idx,
|
||||
*h_prot & PAGE_READ ? 'r' : '-',
|
||||
*h_prot & PAGE_WRITE ? 'w' : '-',
|
||||
*h_prot & PAGE_EXEC ? 'x' : '-',
|
||||
g_raddr);
|
||||
|
||||
*h_page_size = PRTBE_R_GET_RTS(pate.dw0);
|
||||
/* No valid pte or access denied due to protection */
|
||||
if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB,
|
||||
@@ -343,6 +372,11 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
|
||||
hwaddr h_raddr, pte_addr;
|
||||
int ret;
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx
|
||||
" mmu_idx %u pid %"PRIu64"\n",
|
||||
__func__, access_str(access_type),
|
||||
eaddr, mmu_idx, pid);
|
||||
|
||||
/* Index Process Table by PID to Find Corresponding Process Table Entry */
|
||||
offset = pid * sizeof(struct prtb_entry);
|
||||
size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
|
||||
@@ -468,9 +502,10 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
|
||||
* | = On | Process Scoped | Scoped |
|
||||
* +-------------+----------------+---------------+
|
||||
*/
|
||||
bool ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
|
||||
hwaddr *raddr, int *psizep, int *protp, int mmu_idx,
|
||||
bool guest_visible)
|
||||
static bool ppc_radix64_xlate_impl(PowerPCCPU *cpu, vaddr eaddr,
|
||||
MMUAccessType access_type, hwaddr *raddr,
|
||||
int *psizep, int *protp, int mmu_idx,
|
||||
bool guest_visible)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
uint64_t lpid, pid;
|
||||
@@ -588,3 +623,22 @@ bool ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
|
||||
hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
|
||||
bool guest_visible)
|
||||
{
|
||||
bool ret = ppc_radix64_xlate_impl(cpu, eaddr, access_type, raddrp,
|
||||
psizep, protp, mmu_idx, guest_visible);
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx
|
||||
" mmu_idx %u (prot %c%c%c) -> 0x%"HWADDR_PRIx"\n",
|
||||
__func__, access_str(access_type),
|
||||
eaddr, mmu_idx,
|
||||
*protp & PAGE_READ ? 'r' : '-',
|
||||
*protp & PAGE_WRITE ? 'w' : '-',
|
||||
*protp & PAGE_EXEC ? 'x' : '-',
|
||||
*raddrp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
/* Radix Quadrants */
|
||||
#define R_EADDR_MASK 0x3FFFFFFFFFFFFFFF
|
||||
#define R_EADDR_VALID_MASK 0xC00FFFFFFFFFFFFF
|
||||
#define R_EADDR_QUADRANT 0xC000000000000000
|
||||
#define R_EADDR_QUADRANT0 0x0000000000000000
|
||||
#define R_EADDR_QUADRANT1 0x4000000000000000
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user