aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2022-01-04 07:23:27 -0800
committerRichard Henderson <richard.henderson@linaro.org>2022-01-04 07:23:27 -0800
commit67e41fe0cfb62e6cdfa659f0155417d17e5274ea (patch)
tree239a4e8288cb91ee1ddabb02bd1dd5efbc6b8c04
parentb5a3d8bc9146ba22a25116cb748c97341bf99737 (diff)
parent0625c7760d5451d7436ef0738f763c6bb5141919 (diff)
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>
-rw-r--r--hw/pci-host/pnv_phb3.c3
-rw-r--r--hw/pci-host/pnv_phb4.c16
-rw-r--r--hw/pci-host/pnv_phb4_pec.c3
-rw-r--r--hw/ppc/mpc8544_guts.c9
-rw-r--r--hw/ppc/pnv.c2
-rw-r--r--hw/ppc/ppc.c67
-rw-r--r--hw/ppc/ppc405_uc.c2
-rw-r--r--hw/ppc/ppc4xx_devs.c39
-rw-r--r--hw/ppc/ppc4xx_pci.c11
-rw-r--r--hw/ppc/trace-events7
-rw-r--r--include/hw/pci-host/pnv_phb4.h2
-rw-r--r--target/ppc/cpu.h5
-rw-r--r--target/ppc/cpu_init.c34
-rw-r--r--target/ppc/excp_helper.c187
-rw-r--r--target/ppc/fpu_helper.c5
-rw-r--r--target/ppc/helper.h2
-rw-r--r--target/ppc/helper_regs.c2
-rw-r--r--target/ppc/machine.c2
-rw-r--r--target/ppc/mmu-radix64.c60
-rw-r--r--target/ppc/mmu-radix64.h1
-rw-r--r--target/ppc/mmu_common.c164
-rw-r--r--target/ppc/mmu_helper.c97
-rw-r--r--target/ppc/power8-pmu.c238
-rw-r--r--target/ppc/power8-pmu.h14
-rw-r--r--target/ppc/spr_tcg.h3
-rw-r--r--target/ppc/timebase_helper.c10
-rw-r--r--target/ppc/translate.c20
-rw-r--r--tests/tcg/ppc64/Makefile.target4
-rw-r--r--tests/tcg/ppc64le/Makefile.target4
-rw-r--r--tests/tcg/ppc64le/non_signalling_xscv.c37
30 files changed, 604 insertions, 446 deletions
diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c
index c6e7871ecb..c78084cce7 100644
--- a/hw/pci-host/pnv_phb3.c
+++ b/hw/pci-host/pnv_phb3.c
@@ -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);
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 1fbf7328f5..5ba26e250a 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -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;
}
diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c
index 24a3adcae3..f3e4fa0c82 100644
--- a/hw/pci-host/pnv_phb4_pec.c
+++ b/hw/pci-host/pnv_phb4_pec.c
@@ -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)) {
diff --git a/hw/ppc/mpc8544_guts.c b/hw/ppc/mpc8544_guts.c
index e8d2d51c20..a26e83d048 100644
--- a/hw/ppc/mpc8544_guts.c
+++ b/hw/ppc/mpc8544_guts.c
@@ -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;
}
}
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 29ee0d0f08..9de8b83530 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -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;
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 818d757985..bb5bee9a33 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -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;
}
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index ec97b22bd0..8aacd275a6 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -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);
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index 980c48944f..e7d82ae501 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -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;
diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c
index 304a29349c..5df97e6d15 100644
--- a/hw/ppc/ppc4xx_pci.c
+++ b/hw/ppc/ppc4xx_pci.c
@@ -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;
}
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index ada644652d..5c0a215cad 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -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
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index 60de3031a6..4a19338db3 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -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;
};
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index fc66c3561d..f20d4ffa6d 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -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);
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 06ef15cd9e..cc93bff3fa 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -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)
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index f90e616aac..a779dc936a 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -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);
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 700c79156b..e5c29b53b8 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -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);
}
/*
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index fb6cac38b4..f9c72dcd50 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -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)
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index b847928842..8671b7bb69 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -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
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index 93972df58e..756d8de5d8 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -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)
diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 5b0e62e676..040c055bff 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -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;
+}
diff --git a/target/ppc/mmu-radix64.h b/target/ppc/mmu-radix64.h
index b70357cf34..4c768aa5cc 100644
--- a/target/ppc/mmu-radix64.h
+++ b/target/ppc/mmu-radix64.h
@@ -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
diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 4e278365ca..91270c1f17 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -34,29 +34,7 @@
#include "mmu-book3s-v3.h"
#include "mmu-radix64.h"
-/* #define DEBUG_MMU */
-/* #define DEBUG_BATS */
-/* #define DEBUG_SOFTWARE_TLB */
/* #define DUMP_PAGE_TABLES */
-/* #define FLUSH_ALL_TLBS */
-
-#ifdef DEBUG_MMU
-# define LOG_MMU_STATE(cpu) log_cpu_state_mask(CPU_LOG_MMU, (cpu), 0)
-#else
-# define LOG_MMU_STATE(cpu) do { } while (0)
-#endif
-
-#ifdef DEBUG_SOFTWARE_TLB
-# define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
-#else
-# define LOG_SWTLB(...) do { } while (0)
-#endif
-
-#ifdef DEBUG_BATS
-# define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
-#else
-# define LOG_BATS(...) do { } while (0)
-#endif
void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
{
@@ -231,18 +209,20 @@ static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
tlb = &env->tlb.tlb6[nr];
/* This test "emulates" the PTE index match for hardware TLBs */
if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
- LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
- "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
- pte_is_valid(tlb->pte0) ? "valid" : "inval",
- tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
+ qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s [" TARGET_FMT_lx
+ " " TARGET_FMT_lx "] <> " TARGET_FMT_lx "\n",
+ nr, env->nb_tlb,
+ pte_is_valid(tlb->pte0) ? "valid" : "inval",
+ tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
continue;
}
- LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
- TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
- pte_is_valid(tlb->pte0) ? "valid" : "inval",
- tlb->EPN, eaddr, tlb->pte1,
- access_type == MMU_DATA_STORE ? 'S' : 'L',
- access_type == MMU_INST_FETCH ? 'I' : 'D');
+ qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s " TARGET_FMT_lx " <> "
+ TARGET_FMT_lx " " TARGET_FMT_lx " %c %c\n",
+ nr, env->nb_tlb,
+ pte_is_valid(tlb->pte0) ? "valid" : "inval",
+ tlb->EPN, eaddr, tlb->pte1,
+ access_type == MMU_DATA_STORE ? 'S' : 'L',
+ access_type == MMU_INST_FETCH ? 'I' : 'D');
switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1,
0, access_type)) {
case -3:
@@ -272,8 +252,9 @@ static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
}
if (best != -1) {
done:
- LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
- ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
+ qemu_log_mask(CPU_LOG_MMU, "found TLB at addr " TARGET_FMT_plx
+ " prot=%01x ret=%d\n",
+ ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
/* Update page flags */
pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, access_type);
}
@@ -317,7 +298,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
int ret = -1;
bool ifetch = access_type == MMU_INST_FETCH;
- LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
+ qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
ifetch ? 'I' : 'D', virtual);
if (ifetch) {
BATlt = env->IBAT[1];
@@ -332,9 +313,9 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
BEPIu = *BATu & 0xF0000000;
BEPIl = *BATu & 0x0FFE0000;
bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
- LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
- " BATl " TARGET_FMT_lx "\n", __func__,
- ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl);
+ qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx " BATu "
+ TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__,
+ ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl);
if ((virtual & 0xF0000000) == BEPIu &&
((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
/* BAT matches */
@@ -347,32 +328,33 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
ctx->prot = prot;
ret = check_prot(ctx->prot, access_type);
if (ret == 0) {
- LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
- i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
- ctx->prot & PAGE_WRITE ? 'W' : '-');
+ qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " TARGET_FMT_plx
+ " prot=%c%c\n", i, ctx->raddr,
+ ctx->prot & PAGE_READ ? 'R' : '-',
+ ctx->prot & PAGE_WRITE ? 'W' : '-');
}
break;
}
}
}
if (ret < 0) {
-#if defined(DEBUG_BATS)
if (qemu_log_enabled()) {
- LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
+ qemu_log_mask(CPU_LOG_MMU, "no BAT match for "
+ TARGET_FMT_lx ":\n", virtual);
for (i = 0; i < 4; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
BEPIu = *BATu & 0xF0000000;
BEPIl = *BATu & 0x0FFE0000;
bl = (*BATu & 0x00001FFC) << 15;
- LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
- " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
- TARGET_FMT_lx " " TARGET_FMT_lx "\n",
- __func__, ifetch ? 'I' : 'D', i, virtual,
- *BATu, *BATl, BEPIu, BEPIl, bl);
+ qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v "
+ TARGET_FMT_lx " BATu " TARGET_FMT_lx
+ " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
+ TARGET_FMT_lx " " TARGET_FMT_lx "\n",
+ __func__, ifetch ? 'I' : 'D', i, virtual,
+ *BATu, *BATl, BEPIu, BEPIl, bl);
}
}
-#endif
}
/* No hit */
return ret;
@@ -401,11 +383,12 @@ static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
vsid = sr & 0x00FFFFFF;
target_page_bits = TARGET_PAGE_BITS;
qemu_log_mask(CPU_LOG_MMU,
- "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
- " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
- " ir=%d dr=%d pr=%d %d t=%d\n",
- eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
- (int)msr_dr, pr != 0 ? 1 : 0, access_type == MMU_DATA_STORE, type);
+ "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
+ " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
+ " ir=%d dr=%d pr=%d %d t=%d\n",
+ eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
+ (int)msr_dr, pr != 0 ? 1 : 0,
+ access_type == MMU_DATA_STORE, type);
pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
hash = vsid ^ pgidx;
ctx->ptem = (vsid << 7) | (pgidx >> 10);
@@ -536,9 +519,10 @@ int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
return -1;
}
mask = ~(tlb->size - 1);
- LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
- " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
- mask, (uint32_t)tlb->PID, tlb->prot);
+ qemu_log_mask(CPU_LOG_MMU, "%s: TLB %d address " TARGET_FMT_lx
+ " PID %u <=> " TARGET_FMT_lx " " 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;
@@ -575,8 +559,9 @@ static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
}
zsel = (tlb->attr >> 4) & 0xF;
zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
- LOG_SWTLB("%s: TLB %d zsel %d zpr %d ty %d attr %08x\n",
- __func__, i, zsel, zpr, access_type, tlb->attr);
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s: TLB %d zsel %d zpr %d ty %d attr %08x\n",
+ __func__, i, zsel, zpr, access_type, tlb->attr);
/* Check execute enable bit */
switch (zpr) {
case 0x2:
@@ -610,14 +595,16 @@ static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
}
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);
+ qemu_log_mask(CPU_LOG_MMU, "%s: access granted " TARGET_FMT_lx
+ " => " TARGET_FMT_plx
+ " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+ ret);
return 0;
}
}
- LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
- " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+ qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx
+ " => " TARGET_FMT_plx
+ " %d %d\n", __func__, address, raddr, ctx->prot, ret);
return ret;
}
@@ -646,7 +633,7 @@ static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
goto found_tlb;
}
- LOG_SWTLB("%s: TLB entry not found\n", __func__);
+ qemu_log_mask(CPU_LOG_MMU, "%s: TLB entry not found\n", __func__);
return -1;
found_tlb:
@@ -659,17 +646,17 @@ found_tlb:
/* Check the address space */
if ((access_type == MMU_INST_FETCH ? msr_ir : msr_dr) != (tlb->attr & 1)) {
- LOG_SWTLB("%s: AS doesn't match\n", __func__);
+ qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
return -1;
}
*prot = prot2;
if (prot2 & prot_for_access_type(access_type)) {
- LOG_SWTLB("%s: good TLB!\n", __func__);
+ qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
return 0;
}
- LOG_SWTLB("%s: no prot match: %x\n", __func__, prot2);
+ qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, prot2);
return access_type == MMU_INST_FETCH ? -3 : -2;
}
@@ -694,12 +681,13 @@ static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
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);
+ qemu_log_mask(CPU_LOG_MMU, "%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);
+ qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx
+ " => " TARGET_FMT_plx " %d %d\n", __func__,
+ address, raddr, ctx->prot, ret);
}
return ret;
@@ -734,10 +722,11 @@ int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
}
mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
- LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
- PRIx64 " mask=0x%" HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%"
- PRIx32 "\n", __func__, address, pid, tlb->mas1, tlb->mas2, mask,
- tlb->mas7_3, tlb->mas8);
+ qemu_log_mask(CPU_LOG_MMU, "%s: TLB ADDR=0x" TARGET_FMT_lx
+ " PID=0x%x MAS1=0x%x MAS2=0x%" PRIx64 " mask=0x%"
+ HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%" PRIx32 "\n",
+ __func__, address, pid, tlb->mas1, tlb->mas2, mask,
+ tlb->mas7_3, tlb->mas8);
/* Check PID */
tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
@@ -838,7 +827,7 @@ static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
}
}
- LOG_SWTLB("%s: TLB entry not found\n", __func__);
+ qemu_log_mask(CPU_LOG_MMU, "%s: TLB entry not found\n", __func__);
return -1;
found_tlb:
@@ -873,17 +862,17 @@ found_tlb:
}
if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
- LOG_SWTLB("%s: AS doesn't match\n", __func__);
+ qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
return -1;
}
*prot = prot2;
if (prot2 & prot_for_access_type(access_type)) {
- LOG_SWTLB("%s: good TLB!\n", __func__);
+ qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
return 0;
}
- LOG_SWTLB("%s: no prot match: %x\n", __func__, prot2);
+ qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, prot2);
return access_type == MMU_INST_FETCH ? -3 : -2;
}
@@ -919,12 +908,13 @@ 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);
+ qemu_log_mask(CPU_LOG_MMU, "%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);
+ qemu_log_mask(CPU_LOG_MMU, "%s: access refused " TARGET_FMT_lx
+ " => " TARGET_FMT_plx " %d %d\n", __func__, address,
+ raddr, ctx->prot, ret);
}
return ret;
@@ -1338,7 +1328,7 @@ static bool ppc_jumbo_xlate(PowerPCCPU *cpu, vaddr eaddr,
}
if (guest_visible) {
- LOG_MMU_STATE(cs);
+ log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
if (type == ACCESS_CODE) {
switch (ret) {
case -1:
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index 2ec3d203a0..59df6952ae 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -36,23 +36,8 @@
#include "exec/helper-proto.h"
#include "exec/cpu_ldst.h"
-/* #define DEBUG_BATS */
-/* #define DEBUG_SOFTWARE_TLB */
-/* #define DUMP_PAGE_TABLES */
/* #define FLUSH_ALL_TLBS */
-#ifdef DEBUG_SOFTWARE_TLB
-# define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
-#else
-# define LOG_SWTLB(...) do { } while (0)
-#endif
-
-#ifdef DEBUG_BATS
-# define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
-#else
-# define LOG_BATS(...) do { } while (0)
-#endif
-
/*****************************************************************************/
/* PowerPC MMU emulation */
@@ -89,8 +74,8 @@ static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
tlb = &env->tlb.tlb6[nr];
if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
- LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
- env->nb_tlb, eaddr);
+ qemu_log_mask(CPU_LOG_MMU, "TLB invalidate %d/%d "
+ TARGET_FMT_lx "\n", nr, env->nb_tlb, eaddr);
pte_invalidate(&tlb->pte0);
tlb_flush_page(cs, tlb->EPN);
}
@@ -115,8 +100,9 @@ static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
tlb = &env->tlb.tlb6[nr];
- LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
- " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
+ qemu_log_mask(CPU_LOG_MMU, "Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 "
+ TARGET_FMT_lx " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb,
+ EPN, pte0, pte1);
/* Invalidate any pending reference in QEMU for this virtual address */
ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
tlb->pte0 = pte0;
@@ -204,25 +190,27 @@ static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
end = base + mask + 0x00020000;
if (((end - base) >> TARGET_PAGE_BITS) > 1024) {
/* Flushing 1024 4K pages is slower than a complete flush */
- LOG_BATS("Flush all BATs\n");
+ qemu_log_mask(CPU_LOG_MMU, "Flush all BATs\n");
tlb_flush(cs);
- LOG_BATS("Flush done\n");
+ qemu_log_mask(CPU_LOG_MMU, "Flush done\n");
return;
}
- LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
- TARGET_FMT_lx ")\n", base, end, mask);
+ qemu_log_mask(CPU_LOG_MMU, "Flush BAT from " TARGET_FMT_lx
+ " to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n",
+ base, end, mask);
for (page = base; page != end; page += TARGET_PAGE_SIZE) {
tlb_flush_page(cs, page);
}
- LOG_BATS("Flush done\n");
+ qemu_log_mask(CPU_LOG_MMU, "Flush done\n");
}
#endif
static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
target_ulong value)
{
- LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
- nr, ul == 0 ? 'u' : 'l', value, env->nip);
+ qemu_log_mask(CPU_LOG_MMU, "Set %cBAT%d%c to " TARGET_FMT_lx " ("
+ TARGET_FMT_lx ")\n", ID, nr, ul == 0 ? 'u' : 'l',
+ value, env->nip);
}
void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
@@ -550,9 +538,9 @@ static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
}
way = (env->spr[SPR_SRR1] >> 17) & 1;
(void)EPN; /* avoid a compiler warning */
- LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
- " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
- RPN, way);
+ qemu_log_mask(CPU_LOG_MMU, "%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx
+ " PTE0 " TARGET_FMT_lx " PTE1 " TARGET_FMT_lx " way %d\n",
+ __func__, new_EPN, EPN, CMP, RPN, way);
/* Store this TLB */
ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
way, is_code, CMP, RPN);
@@ -721,15 +709,17 @@ void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
ppcemb_tlb_t *tlb;
target_ulong page, end;
- LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
+ qemu_log_mask(CPU_LOG_MMU, "%s entry %d val " TARGET_FMT_lx "\n",
+ __func__, (int)entry,
val);
entry &= PPC4XX_TLB_ENTRY_MASK;
tlb = &env->tlb.tlbe[entry];
/* Invalidate previous TLB (if it's valid) */
if (tlb->prot & PAGE_VALID) {
end = tlb->EPN + tlb->size;
- LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
- TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
+ qemu_log_mask(CPU_LOG_MMU, "%s: invalidate old TLB %d start "
+ TARGET_FMT_lx " end " TARGET_FMT_lx "\n", __func__,
+ (int)entry, tlb->EPN, end);
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
tlb_flush_page(cs, page);
}
@@ -758,18 +748,20 @@ void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
tlb->prot &= ~PAGE_VALID;
}
tlb->PID = env->spr[SPR_40x_PID]; /* PID */
- LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
- " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
- (int)entry, tlb->RPN, tlb->EPN, tlb->size,
- tlb->prot & PAGE_READ ? 'r' : '-',
- tlb->prot & PAGE_WRITE ? 'w' : '-',
- tlb->prot & PAGE_EXEC ? 'x' : '-',
- tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
+ qemu_log_mask(CPU_LOG_MMU, "%s: set up TLB %d RPN " TARGET_FMT_plx
+ " EPN " TARGET_FMT_lx " size " TARGET_FMT_lx
+ " prot %c%c%c%c PID %d\n", __func__,
+ (int)entry, tlb->RPN, tlb->EPN, tlb->size,
+ tlb->prot & PAGE_READ ? 'r' : '-',
+ tlb->prot & PAGE_WRITE ? 'w' : '-',
+ tlb->prot & PAGE_EXEC ? 'x' : '-',
+ tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
/* Invalidate new TLB (if valid) */
if (tlb->prot & PAGE_VALID) {
end = tlb->EPN + tlb->size;
- LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
- TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
+ qemu_log_mask(CPU_LOG_MMU, "%s: invalidate TLB %d start "
+ TARGET_FMT_lx " end " TARGET_FMT_lx "\n", __func__,
+ (int)entry, tlb->EPN, end);
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
tlb_flush_page(cs, page);
}
@@ -781,8 +773,8 @@ void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
{
ppcemb_tlb_t *tlb;
- LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
- val);
+ qemu_log_mask(CPU_LOG_MMU, "%s entry %i val " TARGET_FMT_lx "\n",
+ __func__, (int)entry, val);
entry &= PPC4XX_TLB_ENTRY_MASK;
tlb = &env->tlb.tlbe[entry];
tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
@@ -794,13 +786,14 @@ void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
if (val & PPC4XX_TLBLO_WR) {
tlb->prot |= PAGE_WRITE;
}
- LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
- " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
- (int)entry, tlb->RPN, tlb->EPN, tlb->size,
- tlb->prot & PAGE_READ ? 'r' : '-',
- tlb->prot & PAGE_WRITE ? 'w' : '-',
- tlb->prot & PAGE_EXEC ? 'x' : '-',
- tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
+ qemu_log_mask(CPU_LOG_MMU, "%s: set up TLB %d RPN " TARGET_FMT_plx
+ " EPN " TARGET_FMT_lx
+ " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
+ (int)entry, tlb->RPN, tlb->EPN, tlb->size,
+ tlb->prot & PAGE_READ ? 'r' : '-',
+ tlb->prot & PAGE_WRITE ? 'w' : '-',
+ tlb->prot & PAGE_EXEC ? 'x' : '-',
+ tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
}
target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
@@ -816,8 +809,8 @@ void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
target_ulong EPN, RPN, size;
int do_flush_tlbs;
- LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
- __func__, word, (int)entry, value);
+ qemu_log_mask(CPU_LOG_MMU, "%s word %d entry %d value " TARGET_FMT_lx "\n",
+ __func__, word, (int)entry, value);
do_flush_tlbs = 0;
entry &= 0x3F;
tlb = &env->tlb.tlbe[entry];
diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
index 08d1902cd5..236e8e66e9 100644
--- a/target/ppc/power8-pmu.c
+++ b/target/ppc/power8-pmu.c
@@ -11,8 +11,6 @@
*/
#include "qemu/osdep.h"
-
-#include "power8-pmu.h"
#include "cpu.h"
#include "helper_regs.h"
#include "exec/exec-all.h"
@@ -20,24 +18,12 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "hw/ppc/ppc.h"
+#include "power8-pmu.h"
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
#define PMC_COUNTER_NEGATIVE_VAL 0x80000000UL
-static bool pmc_is_inactive(CPUPPCState *env, int sprn)
-{
- if (env->spr[SPR_POWER_MMCR0] & MMCR0_FC) {
- return true;
- }
-
- if (sprn < SPR_POWER_PMC5) {
- return env->spr[SPR_POWER_MMCR0] & MMCR0_FC14;
- }
-
- return env->spr[SPR_POWER_MMCR0] & MMCR0_FC56;
-}
-
static bool pmc_has_overflow_enabled(CPUPPCState *env, int sprn)
{
if (sprn == SPR_POWER_PMC1) {
@@ -47,135 +33,115 @@ static bool pmc_has_overflow_enabled(CPUPPCState *env, int sprn)
return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE;
}
-/*
- * For PMCs 1-4, IBM POWER chips has support for an implementation
- * dependent event, 0x1E, that enables cycle counting. The Linux kernel
- * makes extensive use of 0x1E, so let's also support it.
- *
- * Likewise, event 0x2 is an implementation-dependent event that IBM
- * POWER chips implement (at least since POWER8) that is equivalent to
- * PM_INST_CMPL. Let's support this event on PMCs 1-4 as well.
- */
-static PMUEventType pmc_get_event(CPUPPCState *env, int sprn)
+void pmu_update_summaries(CPUPPCState *env)
{
- uint8_t mmcr1_evt_extr[] = { MMCR1_PMC1EVT_EXTR, MMCR1_PMC2EVT_EXTR,
- MMCR1_PMC3EVT_EXTR, MMCR1_PMC4EVT_EXTR };
- PMUEventType evt_type = PMU_EVENT_INVALID;
- uint8_t pmcsel;
- int i;
-
- if (pmc_is_inactive(env, sprn)) {
- return PMU_EVENT_INACTIVE;
- }
-
- if (sprn == SPR_POWER_PMC5) {
- return PMU_EVENT_INSTRUCTIONS;
- }
+ target_ulong mmcr0 = env->spr[SPR_POWER_MMCR0];
+ target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1];
+ int ins_cnt = 0;
+ int cyc_cnt = 0;
- if (sprn == SPR_POWER_PMC6) {
- return PMU_EVENT_CYCLES;
+ if (mmcr0 & MMCR0_FC) {
+ goto hflags_calc;
}
- i = sprn - SPR_POWER_PMC1;
- pmcsel = extract64(env->spr[SPR_POWER_MMCR1], mmcr1_evt_extr[i],
- MMCR1_EVT_SIZE);
-
- switch (pmcsel) {
- case 0x2:
- evt_type = PMU_EVENT_INSTRUCTIONS;
- break;
- case 0x1E:
- evt_type = PMU_EVENT_CYCLES;
- break;
- case 0xF0:
- /*
- * PMC1SEL = 0xF0 is the architected PowerISA v3.1
- * event that counts cycles using PMC1.
- */
- if (sprn == SPR_POWER_PMC1) {
- evt_type = PMU_EVENT_CYCLES;
- }
- break;
- case 0xFA:
- /*
- * PMC4SEL = 0xFA is the "instructions completed
- * with run latch set" event.
- */
- if (sprn == SPR_POWER_PMC4) {
- evt_type = PMU_EVENT_INSN_RUN_LATCH;
- }
- break;
- case 0xFE:
- /*
- * PMC1SEL = 0xFE is the architected PowerISA v3.1
- * event to sample instructions using PMC1.
- */
- if (sprn == SPR_POWER_PMC1) {
- evt_type = PMU_EVENT_INSTRUCTIONS;
+ if (!(mmcr0 & MMCR0_FC14) && mmcr1 != 0) {
+ target_ulong sel;
+
+ sel = extract64(mmcr1, MMCR1_PMC1EVT_EXTR, MMCR1_EVT_SIZE);
+ switch (sel) {
+ case 0x02:
+ case 0xfe:
+ ins_cnt |= 1 << 1;
+ break;
+ case 0x1e:
+ case 0xf0:
+ cyc_cnt |= 1 << 1;
+ break;
}
- break;
- default:
- break;
- }
- return evt_type;
-}
+ sel = extract64(mmcr1, MMCR1_PMC2EVT_EXTR, MMCR1_EVT_SIZE);
+ ins_cnt |= (sel == 0x02) << 2;
+ cyc_cnt |= (sel == 0x1e) << 2;
-bool pmu_insn_cnt_enabled(CPUPPCState *env)
-{
- int sprn;
+ sel = extract64(mmcr1, MMCR1_PMC3EVT_EXTR, MMCR1_EVT_SIZE);
+ ins_cnt |= (sel == 0x02) << 3;
+ cyc_cnt |= (sel == 0x1e) << 3;
- for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC5; sprn++) {
- if (pmc_get_event(env, sprn) == PMU_EVENT_INSTRUCTIONS ||
- pmc_get_event(env, sprn) == PMU_EVENT_INSN_RUN_LATCH) {
- return true;
- }
+ sel = extract64(mmcr1, MMCR1_PMC4EVT_EXTR, MMCR1_EVT_SIZE);
+ ins_cnt |= ((sel == 0xfa) || (sel == 0x2)) << 4;
+ cyc_cnt |= (sel == 0x1e) << 4;
}
- return false;
+ ins_cnt |= !(mmcr0 & MMCR0_FC56) << 5;
+ cyc_cnt |= !(mmcr0 & MMCR0_FC56) << 6;
+
+ hflags_calc:
+ env->pmc_ins_cnt = ins_cnt;
+ env->pmc_cyc_cnt = cyc_cnt;
+ env->hflags = deposit32(env->hflags, HFLAGS_INSN_CNT, 1, ins_cnt != 0);
}
static bool pmu_increment_insns(CPUPPCState *env, uint32_t num_insns)
{
+ target_ulong mmcr0 = env->spr[SPR_POWER_MMCR0];
+ unsigned ins_cnt = env->pmc_ins_cnt;
bool overflow_triggered = false;
- int sprn;
-
- /* PMC6 never counts instructions */
- for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC5; sprn++) {
- PMUEventType evt_type = pmc_get_event(env, sprn);
- bool insn_event = evt_type == PMU_EVENT_INSTRUCTIONS ||
- evt_type == PMU_EVENT_INSN_RUN_LATCH;
-
- if (pmc_is_inactive(env, sprn) || !insn_event) {
- continue;
+ target_ulong tmp;
+
+ if (unlikely(ins_cnt & 0x1e)) {
+ if (ins_cnt & (1 << 1)) {
+ tmp = env->spr[SPR_POWER_PMC1];
+ tmp += num_insns;
+ if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMC1CE)) {
+ tmp = PMC_COUNTER_NEGATIVE_VAL;
+ overflow_triggered = true;
+ }
+ env->spr[SPR_POWER_PMC1] = tmp;
}
- if (evt_type == PMU_EVENT_INSTRUCTIONS) {
- env->spr[sprn] += num_insns;
+ if (ins_cnt & (1 << 2)) {
+ tmp = env->spr[SPR_POWER_PMC2];
+ tmp += num_insns;
+ if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
+ tmp = PMC_COUNTER_NEGATIVE_VAL;
+ overflow_triggered = true;
+ }
+ env->spr[SPR_POWER_PMC2] = tmp;
}
- if (evt_type == PMU_EVENT_INSN_RUN_LATCH &&
- env->spr[SPR_CTRL] & CTRL_RUN) {
- env->spr[sprn] += num_insns;
+ if (ins_cnt & (1 << 3)) {
+ tmp = env->spr[SPR_POWER_PMC3];
+ tmp += num_insns;
+ if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
+ tmp = PMC_COUNTER_NEGATIVE_VAL;
+ overflow_triggered = true;
+ }
+ env->spr[SPR_POWER_PMC3] = tmp;
}
- if (env->spr[sprn] >= PMC_COUNTER_NEGATIVE_VAL &&
- pmc_has_overflow_enabled(env, sprn)) {
+ if (ins_cnt & (1 << 4)) {
+ target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1];
+ int sel = extract64(mmcr1, MMCR1_PMC4EVT_EXTR, MMCR1_EVT_SIZE);
+ if (sel == 0x02 || (env->spr[SPR_CTRL] & CTRL_RUN)) {
+ tmp = env->spr[SPR_POWER_PMC4];
+ tmp += num_insns;
+ if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
+ tmp = PMC_COUNTER_NEGATIVE_VAL;
+ overflow_triggered = true;
+ }
+ env->spr[SPR_POWER_PMC4] = tmp;
+ }
+ }
+ }
+ if (ins_cnt & (1 << 5)) {
+ tmp = env->spr[SPR_POWER_PMC5];
+ tmp += num_insns;
+ if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
+ tmp = PMC_COUNTER_NEGATIVE_VAL;
overflow_triggered = true;
-
- /*
- * The real PMU will always trigger a counter overflow with
- * PMC_COUNTER_NEGATIVE_VAL. We don't have an easy way to
- * do that since we're counting block of instructions at
- * the end of each translation block, and we're probably
- * passing this value at this point.
- *
- * Let's write PMC_COUNTER_NEGATIVE_VAL to the overflowed
- * counter to simulate what the real hardware would do.
- */
- env->spr[sprn] = PMC_COUNTER_NEGATIVE_VAL;
}
+ env->spr[SPR_POWER_PMC5] = tmp;
}
return overflow_triggered;
@@ -185,18 +151,16 @@ static void pmu_update_cycles(CPUPPCState *env)
{
uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint64_t time_delta = now - env->pmu_base_time;
- int sprn;
+ int sprn, cyc_cnt = env->pmc_cyc_cnt;
for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC6; sprn++) {
- if (pmc_get_event(env, sprn) != PMU_EVENT_CYCLES) {
- continue;
+ if (cyc_cnt & (1 << (sprn - SPR_POWER_PMC1 + 1))) {
+ /*
+ * The pseries and powernv clock runs at 1Ghz, meaning
+ * that 1 nanosec equals 1 cycle.
+ */
+ env->spr[sprn] += time_delta;
}
-
- /*
- * The pseries and powernv clock runs at 1Ghz, meaning
- * that 1 nanosec equals 1 cycle.
- */
- env->spr[sprn] += time_delta;
}
/* Update base_time for future calculations */
@@ -225,7 +189,7 @@ static void pmc_update_overflow_timer(CPUPPCState *env, int sprn)
return;
}
- if (pmc_get_event(env, sprn) != PMU_EVENT_CYCLES ||
+ if (!(env->pmc_cyc_cnt & (1 << (sprn - SPR_POWER_PMC1 + 1))) ||
!pmc_has_overflow_enabled(env, sprn)) {
/* Overflow timer is not needed for this counter */
timer_del(pmc_overflow_timer);
@@ -233,7 +197,7 @@ static void pmc_update_overflow_timer(CPUPPCState *env, int sprn)
}
if (env->spr[sprn] >= PMC_COUNTER_NEGATIVE_VAL) {
- timeout = 0;
+ timeout = 0;
} else {
timeout = PMC_COUNTER_NEGATIVE_VAL - env->spr[sprn];
}
@@ -260,12 +224,18 @@ static void pmu_update_overflow_timers(CPUPPCState *env)
void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
{
+ bool hflags_pmcc0 = (value & MMCR0_PMCC0) != 0;
+ bool hflags_pmcc1 = (value & MMCR0_PMCC1) != 0;
+
pmu_update_cycles(env);
env->spr[SPR_POWER_MMCR0] = value;
- /* MMCR0 writes can change HFLAGS_PMCCCLEAR and HFLAGS_INSN_CNT */
- hreg_compute_hflags(env);
+ /* MMCR0 writes can change HFLAGS_PMCC[01] and HFLAGS_INSN_CNT */
+ env->hflags = deposit32(env->hflags, HFLAGS_PMCC0, 1, hflags_pmcc0);
+ env->hflags = deposit32(env->hflags, HFLAGS_PMCC1, 1, hflags_pmcc1);
+
+ pmu_update_summaries(env);
/* Update cycle overflow timers with the current MMCR0 state */
pmu_update_overflow_timers(env);
@@ -278,7 +248,7 @@ void helper_store_mmcr1(CPUPPCState *env, uint64_t value)
env->spr[SPR_POWER_MMCR1] = value;
/* MMCR1 writes can change HFLAGS_INSN_CNT */
- hreg_compute_hflags(env);
+ pmu_update_summaries(env);
}
target_ulong helper_read_pmc(CPUPPCState *env, uint32_t sprn)
diff --git a/target/ppc/power8-pmu.h b/target/ppc/power8-pmu.h
index 3ee4b4cda5..a839199561 100644
--- a/target/ppc/power8-pmu.h
+++ b/target/ppc/power8-pmu.h
@@ -13,14 +13,12 @@
#ifndef POWER8_PMU
#define POWER8_PMU
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "exec/exec-all.h"
-#include "exec/helper-proto.h"
-#include "qemu/error-report.h"
-#include "qemu/main-loop.h"
-
void cpu_ppc_pmu_init(CPUPPCState *env);
-bool pmu_insn_cnt_enabled(CPUPPCState *env);
+
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+void pmu_update_summaries(CPUPPCState *env);
+#else
+static inline void pmu_update_summaries(CPUPPCState *env) { }
+#endif
#endif
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index f98d97c0ba..89ff111724 100644
--- a/target/ppc/spr_tcg.h
+++ b/target/ppc/spr_tcg.h
@@ -87,6 +87,9 @@ void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn);
void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn);
void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn);
void spr_write_40x_sler(DisasContext *ctx, int sprn, int gprn);
+void spr_write_40x_tcr(DisasContext *ctx, int sprn, int gprn);
+void spr_write_40x_tsr(DisasContext *ctx, int sprn, int gprn);
+void spr_write_40x_pid(DisasContext *ctx, int sprn, int gprn);
void spr_write_booke_tcr(DisasContext *ctx, int sprn, int gprn);
void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn);
void spr_read_403_pbr(DisasContext *ctx, int gprn, int sprn);
diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
index 8ff4080eb9..af378318c1 100644
--- a/target/ppc/timebase_helper.c
+++ b/target/ppc/timebase_helper.c
@@ -144,6 +144,16 @@ void helper_store_40x_pit(CPUPPCState *env, target_ulong val)
store_40x_pit(env, val);
}
+void helper_store_40x_tcr(CPUPPCState *env, target_ulong val)
+{
+ store_40x_tcr(env, val);
+}
+
+void helper_store_40x_tsr(CPUPPCState *env, target_ulong val)
+{
+ store_40x_tsr(env, val);
+}
+
void helper_store_booke_tcr(CPUPPCState *env, target_ulong val)
{
store_booke_tcr(env, val);
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 114456148c..cb8ab4d676 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -878,6 +878,26 @@ void spr_write_40x_sler(DisasContext *ctx, int sprn, int gprn)
gen_helper_store_40x_sler(cpu_env, cpu_gpr[gprn]);
}
+void spr_write_40x_tcr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_40x_tcr(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_40x_tsr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_40x_tsr(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_40x_pid(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xFF);
+ gen_store_spr(SPR_40x_PID, t0);
+ tcg_temp_free(t0);
+}
+
void spr_write_booke_tcr(DisasContext *ctx, int sprn, int gprn)
{
gen_icount_io_start(ctx);
diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target
index 8f4c7ac4ed..0368007028 100644
--- a/tests/tcg/ppc64/Makefile.target
+++ b/tests/tcg/ppc64/Makefile.target
@@ -6,9 +6,9 @@ VPATH += $(SRC_PATH)/tests/tcg/ppc64
VPATH += $(SRC_PATH)/tests/tcg/ppc64le
ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER8_VECTOR),)
-PPC64_TESTS=bcdsub
+PPC64_TESTS=bcdsub non_signalling_xscv
endif
-bcdsub: CFLAGS += -mpower8-vector
+$(PPC64_TESTS): CFLAGS += -mpower8-vector
PPC64_TESTS += byte_reverse
PPC64_TESTS += mtfsf
diff --git a/tests/tcg/ppc64le/Makefile.target b/tests/tcg/ppc64le/Makefile.target
index e031f65adc..480ff0898d 100644
--- a/tests/tcg/ppc64le/Makefile.target
+++ b/tests/tcg/ppc64le/Makefile.target
@@ -5,9 +5,9 @@
VPATH += $(SRC_PATH)/tests/tcg/ppc64le
ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER8_VECTOR),)
-PPC64LE_TESTS=bcdsub
+PPC64LE_TESTS=bcdsub non_signalling_xscv
endif
-bcdsub: CFLAGS += -mpower8-vector
+$(PPC64LE_TESTS): CFLAGS += -mpower8-vector
ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER10),)
PPC64LE_TESTS += byte_reverse
diff --git a/tests/tcg/ppc64le/non_signalling_xscv.c b/tests/tcg/ppc64le/non_signalling_xscv.c
new file mode 100644
index 0000000000..91e25cad46
--- /dev/null
+++ b/tests/tcg/ppc64le/non_signalling_xscv.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#define TEST(INSN, B_HI, B_LO, T_HI, T_LO) \
+ do { \
+ uint64_t th, tl, bh = B_HI, bl = B_LO; \
+ asm("mtvsrd 0, %2\n\t" \
+ "mtvsrd 1, %3\n\t" \
+ "xxmrghd 0, 0, 1\n\t" \
+ INSN " 0, 0\n\t" \
+ "mfvsrd %0, 0\n\t" \
+ "xxswapd 0, 0\n\t" \
+ "mfvsrd %1, 0\n\t" \
+ : "=r" (th), "=r" (tl) \
+ : "r" (bh), "r" (bl) \
+ : "vs0", "vs1"); \
+ printf(INSN "(0x%016" PRIx64 "%016" PRIx64 ") = 0x%016" PRIx64 \
+ "%016" PRIx64 "\n", bh, bl, th, tl); \
+ assert(th == T_HI && tl == T_LO); \
+ } while (0)
+
+int main(void)
+{
+ /* SNaN shouldn't be silenced */
+ TEST("xscvspdpn", 0x7fbfffff00000000ULL, 0x0, 0x7ff7ffffe0000000ULL, 0x0);
+ TEST("xscvdpspn", 0x7ff7ffffffffffffULL, 0x0, 0x7fbfffff7fbfffffULL, 0x0);
+
+ /*
+ * SNaN inputs having no significant bits in the upper 23 bits of the
+ * signifcand will return Infinity as the result.
+ */
+ TEST("xscvdpspn", 0x7ff000001fffffffULL, 0x0, 0x7f8000007f800000ULL, 0x0);
+
+ return 0;
+}