From 71c6cacb241689bbf99d54467dc2ae6912ffdab9 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:11:59 +0000 Subject: [PATCH 01/31] openpic: symbolicize some magic numbers Deefine symbolic names for some register bits, and use some that have already been defined. Also convert some register values from hex to decimal when it improves readability. IPVP_PRIORITY_MASK is corrected from (0x1F << 16) to (0xF << 16), in conjunction with making wider use of the symbolic name. I looked at Freescale and IBM MPIC docs and at the base OpenPIC spec, and all three had priority as 4 bits rather than 5. Plus, the magic nubmer that is being replaced with symbolic values treated the field as 4 bits wide. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 54 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 9c956b9dcc..eff1eee010 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -124,6 +124,11 @@ #define VENI_GENERIC 0x00000000 /* Generic Vendor ID */ +#define GLBC_RESET 0x80000000 + +#define TIBC_CI 0x80000000 /* count inhibit */ +#define TICC_TOG 0x80000000 /* toggles when decrement to zero */ + #define IDR_EP_SHIFT 31 #define IDR_EP_MASK (1 << IDR_EP_SHIFT) #define IDR_CI0_SHIFT 30 @@ -190,11 +195,15 @@ typedef struct IRQ_src_t { #define IPVP_SENSE_SHIFT 22 #define IPVP_SENSE_MASK (1 << IPVP_SENSE_SHIFT) -#define IPVP_PRIORITY_MASK (0x1F << 16) +#define IPVP_PRIORITY_MASK (0xF << 16) #define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) #define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) #define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) +/* IDE[EP/CI] are only for FSL MPIC prior to v4.0 */ +#define IDE_EP 0x80000000 /* external pin */ +#define IDE_CI 0x40000000 /* critical interrupt */ + typedef struct IRQ_dst_t { uint32_t pctp; /* CPU current task priority */ uint32_t pcsr; /* CPU sensitivity register */ @@ -375,7 +384,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); return; } - if (src->ide == 0x00000000) { + if (src->ide == 0) { /* No target */ DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); return; @@ -432,13 +441,13 @@ static void openpic_reset(DeviceState *d) OpenPICState *opp = FROM_SYSBUS(typeof (*opp), sysbus_from_qdev(d)); int i; - opp->glbc = 0x80000000; + opp->glbc = GLBC_RESET; /* Initialise controller registers */ opp->frep = ((opp->nb_irqs -1) << FREP_NIRQ_SHIFT) | ((opp->nb_cpus -1) << FREP_NCPU_SHIFT) | (opp->vid << FREP_VID_SHIFT); - opp->pint = 0x00000000; + opp->pint = 0; opp->spve = -1 & opp->spve_mask; opp->tifr = opp->tifr_reset; /* Initialise IRQ sources */ @@ -448,7 +457,7 @@ static void openpic_reset(DeviceState *d) } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { - opp->dst[i].pctp = 0x0000000F; + opp->dst[i].pctp = 15; opp->dst[i].pcsr = 0x00000000; memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); opp->dst[i].raised.next = -1; @@ -457,11 +466,11 @@ static void openpic_reset(DeviceState *d) } /* Initialise timers */ for (i = 0; i < MAX_TMR; i++) { - opp->timers[i].ticc = 0x00000000; - opp->timers[i].tibc = 0x80000000; + opp->timers[i].ticc = 0; + opp->timers[i].tibc = TIBC_CI; } /* Go out of RESET state */ - opp->glbc = 0x00000000; + opp->glbc = 0; } static inline uint32_t read_IRQreg_ide(OpenPICState *opp, int n_IRQ) @@ -478,7 +487,7 @@ static inline void write_IRQreg_ide(OpenPICState *opp, int n_IRQ, uint32_t val) { uint32_t tmp; - tmp = val & 0xC0000000; + tmp = val & (IDE_EP | IDE_CI); tmp |= val & ((1ULL << MAX_CPU) - 1); opp->src[n_IRQ].ide = tmp; DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); @@ -488,8 +497,8 @@ static inline void write_IRQreg_ipvp(OpenPICState *opp, int n_IRQ, uint32_t val) { /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000) - | (val & 0x800F00FF); + opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & IPVP_ACTIVITY_MASK) | + (val & (IPVP_MASK_MASK | IPVP_PRIORITY_MASK | IPVP_VECTOR_MASK)); openpic_update_irq(opp, n_IRQ); DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val, opp->src[n_IRQ].ipvp); @@ -521,7 +530,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, case 0x1000: /* FREP */ break; case 0x1020: /* GLBC */ - if (val & 0x80000000) { + if (val & GLBC_RESET) { openpic_reset(&opp->busdev.qdev); } break; @@ -634,10 +643,11 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, case 0x00: /* TICC (GTCCR) */ break; case 0x10: /* TIBC (GTBCR) */ - if ((opp->timers[idx].ticc & 0x80000000) != 0 && - (val & 0x80000000) == 0 && - (opp->timers[idx].tibc & 0x80000000) != 0) - opp->timers[idx].ticc &= ~0x80000000; + if ((opp->timers[idx].ticc & TICC_TOG) != 0 && + (val & TIBC_CI) == 0 && + (opp->timers[idx].tibc & TIBC_CI) != 0) { + opp->timers[idx].ticc &= ~TICC_TOG; + } opp->timers[idx].tibc = val; break; case 0x20: /* TIVP (GTIVPR) */ @@ -1190,9 +1200,9 @@ static int openpic_init(SysBusDevice *dev) opp->vid = VID_REVISION_1_2; opp->veni = VENI_GENERIC; opp->spve_mask = 0xFFFF; - opp->tifr_reset = 0x00000000; - opp->ipvp_reset = 0x80000000; - opp->ide_reset = 0x00000001; + opp->tifr_reset = 0; + opp->ipvp_reset = IPVP_MASK_MASK; + opp->ide_reset = 1 << 0; opp->max_irq = FSL_MPIC_20_MAX_IRQ; opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ; opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ; @@ -1206,9 +1216,9 @@ static int openpic_init(SysBusDevice *dev) opp->vid = VID_REVISION_1_3; opp->veni = VENI_GENERIC; opp->spve_mask = 0xFF; - opp->tifr_reset = 0x003F7A00; - opp->ipvp_reset = 0xA0000000; - opp->ide_reset = 0x00000000; + opp->tifr_reset = 4160000; + opp->ipvp_reset = IPVP_MASK_MASK | IPVP_MODE_MASK; + opp->ide_reset = 0; opp->max_irq = RAVEN_MAX_IRQ; opp->irq_ipi0 = RAVEN_IPI_IRQ; opp->irq_tim0 = RAVEN_TMR_IRQ; From c975330ec4f5674f2899331f914c04ecba6edf26 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:12:00 +0000 Subject: [PATCH 02/31] openpic: remove pcsr (CPU sensitivity register) I could not find this register in any spec (FSL, IBM, or OpenPIC) and the code doesn't do anything with it but initialize, save, or restore it. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index eff1eee010..44f7cc4731 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -206,7 +206,6 @@ typedef struct IRQ_src_t { typedef struct IRQ_dst_t { uint32_t pctp; /* CPU current task priority */ - uint32_t pcsr; /* CPU sensitivity register */ IRQ_queue_t raised; IRQ_queue_t servicing; qemu_irq *irqs; @@ -458,7 +457,6 @@ static void openpic_reset(DeviceState *d) /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { opp->dst[i].pctp = 15; - opp->dst[i].pcsr = 0x00000000; memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); opp->dst[i].raised.next = -1; memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); @@ -1083,7 +1081,6 @@ static void openpic_save(QEMUFile* f, void *opaque) for (i = 0; i < opp->nb_cpus; i++) { qemu_put_be32s(f, &opp->dst[i].pctp); - qemu_put_be32s(f, &opp->dst[i].pcsr); openpic_save_IRQ_queue(f, &opp->dst[i].raised); openpic_save_IRQ_queue(f, &opp->dst[i].servicing); } @@ -1130,7 +1127,6 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) for (i = 0; i < opp->nb_cpus; i++) { qemu_get_be32s(f, &opp->dst[i].pctp); - qemu_get_be32s(f, &opp->dst[i].pcsr); openpic_load_IRQ_queue(f, &opp->dst[i].raised); openpic_load_IRQ_queue(f, &opp->dst[i].servicing); } From 0fe04622c11a4f131070196ad5cd97ce94d9c33b Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:12:01 +0000 Subject: [PATCH 03/31] openpic: support large vectors on FSL mpic Previously only the spurious vector was sized appropriately to the openpic model. Also, instances of "IPVP_VECTOR(opp->spve)" were replace with just "opp->spve", as opp->spve is already just a vector and not an IVPR. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 44f7cc4731..f0877fae5e 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -51,7 +51,6 @@ #define MAX_CPU 15 #define MAX_SRC 256 #define MAX_TMR 4 -#define VECTOR_BITS 8 #define MAX_IPI 4 #define MAX_MSI 8 #define MAX_IRQ (MAX_SRC + MAX_IPI + MAX_TMR) @@ -197,8 +196,7 @@ typedef struct IRQ_src_t { #define IPVP_PRIORITY_MASK (0xF << 16) #define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) -#define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) -#define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) +#define IPVP_VECTOR(opp, _ipvpr_) ((_ipvpr_) & (opp)->vector_mask) /* IDE[EP/CI] are only for FSL MPIC prior to v4.0 */ #define IDE_EP 0x80000000 /* external pin */ @@ -221,7 +219,7 @@ typedef struct OpenPICState { uint32_t nb_irqs; uint32_t vid; uint32_t veni; /* Vendor identification register */ - uint32_t spve_mask; + uint32_t vector_mask; uint32_t tifr_reset; uint32_t ipvp_reset; uint32_t ide_reset; @@ -447,7 +445,7 @@ static void openpic_reset(DeviceState *d) (opp->vid << FREP_VID_SHIFT); opp->pint = 0; - opp->spve = -1 & opp->spve_mask; + opp->spve = -1 & opp->vector_mask; opp->tifr = opp->tifr_reset; /* Initialise IRQ sources */ for (i = 0; i < opp->max_irq; i++) { @@ -496,7 +494,7 @@ static inline void write_IRQreg_ipvp(OpenPICState *opp, int n_IRQ, uint32_t val) /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ /* ACTIVITY bit is read-only */ opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & IPVP_ACTIVITY_MASK) | - (val & (IPVP_MASK_MASK | IPVP_PRIORITY_MASK | IPVP_VECTOR_MASK)); + (val & (IPVP_MASK_MASK | IPVP_PRIORITY_MASK | opp->vector_mask)); openpic_update_irq(opp, n_IRQ); DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val, opp->src[n_IRQ].ipvp); @@ -559,7 +557,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, } break; case 0x10E0: /* SPVE */ - opp->spve = val & opp->spve_mask; + opp->spve = val & opp->vector_mask; break; default: break; @@ -896,7 +894,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, DPRINTF("PIAC: irq=%d\n", n_IRQ); if (n_IRQ == -1) { /* No more interrupt pending */ - retval = IPVP_VECTOR(opp->spve); + retval = opp->spve; } else { src = &opp->src[n_IRQ]; if (!(src->ipvp & IPVP_ACTIVITY_MASK) || @@ -906,11 +904,11 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, * and the pending IRQ isn't allowed anymore */ src->ipvp &= ~IPVP_ACTIVITY_MASK; - retval = IPVP_VECTOR(opp->spve); + retval = opp->spve; } else { /* IRQ enter servicing state */ IRQ_setbit(&dst->servicing, n_IRQ); - retval = IPVP_VECTOR(src->ipvp); + retval = IPVP_VECTOR(opp, src->ipvp); } IRQ_resetbit(&dst->raised, n_IRQ); dst->raised.next = -1; @@ -1195,7 +1193,7 @@ static int openpic_init(SysBusDevice *dev) opp->nb_irqs = 80; opp->vid = VID_REVISION_1_2; opp->veni = VENI_GENERIC; - opp->spve_mask = 0xFFFF; + opp->vector_mask = 0xFFFF; opp->tifr_reset = 0; opp->ipvp_reset = IPVP_MASK_MASK; opp->ide_reset = 1 << 0; @@ -1211,7 +1209,7 @@ static int openpic_init(SysBusDevice *dev) opp->nb_irqs = RAVEN_MAX_EXT; opp->vid = VID_REVISION_1_3; opp->veni = VENI_GENERIC; - opp->spve_mask = 0xFF; + opp->vector_mask = 0xFF; opp->tifr_reset = 4160000; opp->ipvp_reset = IPVP_MASK_MASK | IPVP_MODE_MASK; opp->ide_reset = 0; From 0d4046833ba44c5f29e5dcce2dde0a6202225e59 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:12:03 +0000 Subject: [PATCH 04/31] openpic: BRR1 is not a CPU-specific register. It's in the address range that normally contains a magic redirection to the CPU-specific region of the curretn CPU, but it isn't actually a per-CPU register. On real hardware BRR1 shows up only at 0x40000, not at 0x60000 or other non-magic per-CPU areas. Plus, this makes it possible to read the register on the QEMU command line with "xp". Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index f0877fae5e..337dbf5a44 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -587,6 +587,8 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) retval = 0x00000000; break; case 0x00: /* Block Revision Register1 (BRR1) */ + retval = opp->brr1; + break; case 0x40: case 0x50: case 0x60: @@ -878,9 +880,6 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { - case 0x00: /* Block Revision Register1 (BRR1) */ - retval = opp->brr1; - break; case 0x80: /* PCTP */ retval = dst->pctp; break; From a26a7b38331dc14893a66fbe78f34afab153d6b2 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:12:04 +0000 Subject: [PATCH 05/31] openpic: s/opp->nb_irqs -1/opp->nb_cpus - 1/ "opp->nb_irqs-1" would have been a minor coding style error, but putting in one space but not the other makes it look confusingly like a numeric literal "-1". Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 337dbf5a44..10dbdf7863 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -440,8 +440,8 @@ static void openpic_reset(DeviceState *d) opp->glbc = GLBC_RESET; /* Initialise controller registers */ - opp->frep = ((opp->nb_irqs -1) << FREP_NIRQ_SHIFT) | - ((opp->nb_cpus -1) << FREP_NCPU_SHIFT) | + opp->frep = ((opp->nb_irqs - 1) << FREP_NIRQ_SHIFT) | + ((opp->nb_cpus - 1) << FREP_NCPU_SHIFT) | (opp->vid << FREP_VID_SHIFT); opp->pint = 0; From c3203fa5b2c17a1c446e44c87788fef21b4af5f4 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:12:02 +0000 Subject: [PATCH 06/31] openpic: don't crash on a register access without a CPU context If we access a register via the QEMU memory inspection commands (e.g. "xp") rather than from guest code, we won't have a CPU context. Gracefully fail to access the register in that case, rather than crashing. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/openpic.c b/hw/openpic.c index 10dbdf7863..93e8208075 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -161,7 +161,11 @@ static inline int test_bit(uint32_t *field, int bit) static int get_current_cpu(void) { - return cpu_single_env->cpu_index; + if (!cpu_single_env) { + return -1; + } + + return cpu_single_env->cpu_index; } static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, @@ -810,6 +814,11 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx, addr, val); + + if (idx < 0) { + return; + } + if (addr & 0xF) return; dst = &opp->dst[idx]; @@ -875,6 +884,11 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr); retval = 0xFFFFFFFF; + + if (idx < 0) { + return retval; + } + if (addr & 0xF) return retval; dst = &opp->dst[idx]; From d56af005dc3d6354bd39411e8446b415bbcf86b8 Mon Sep 17 00:00:00 2001 From: Bharat Bhushan Date: Tue, 18 Dec 2012 01:13:58 +0000 Subject: [PATCH 07/31] powerpc: linux header sync script includes epapr_hcalls.h epapr_hcalls.h is now referenced by kvm_para.h. so this is needed for QEMU to get compiled on powerpc. Signed-off-by: Bharat Bhushan Signed-off-by: Alexander Graf --- scripts/update-linux-headers.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh index 4c7b566fdf..120a694313 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -54,6 +54,9 @@ for arch in $ARCHLIST; do if [ $arch = x86 ]; then cp "$tmpdir/include/asm/hyperv.h" "$output/linux-headers/asm-x86" fi + if [ $arch = powerpc ]; then + cp "$tmpdir/include/asm/epapr_hcalls.h" "$output/linux-headers/asm-powerpc/" + fi done rm -rf "$output/linux-headers/linux" From af7e9e74c6a62a5bcd911726a9e88d28b61490e0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 20 Dec 2012 17:30:58 +0100 Subject: [PATCH 08/31] openpic: fix coding style issues This patch fixes the following coding style violations: - structs have to be typedef and be CamelCase - if()s are always surrounded by curly braces Signed-off-by: Alexander Graf --- hw/openpic.c | 100 ++++++++++++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 93e8208075..55e96d1334 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -173,19 +173,19 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx); -typedef struct IRQ_queue_t { +typedef struct IRQQueue { uint32_t queue[BF_WIDTH(MAX_IRQ)]; int next; int priority; int pending; /* nr of pending bits in queue */ -} IRQ_queue_t; +} IRQQueue; -typedef struct IRQ_src_t { +typedef struct IRQSource { uint32_t ipvp; /* IRQ vector/priority register */ uint32_t ide; /* IRQ destination register */ int last_cpu; int pending; /* TRUE if IRQ is pending */ -} IRQ_src_t; +} IRQSource; #define IPVP_MASK_SHIFT 31 #define IPVP_MASK_MASK (1 << IPVP_MASK_SHIFT) @@ -206,12 +206,12 @@ typedef struct IRQ_src_t { #define IDE_EP 0x80000000 /* external pin */ #define IDE_CI 0x40000000 /* critical interrupt */ -typedef struct IRQ_dst_t { +typedef struct IRQDest { uint32_t pctp; /* CPU current task priority */ - IRQ_queue_t raised; - IRQ_queue_t servicing; + IRQQueue raised; + IRQQueue servicing; qemu_irq *irqs; -} IRQ_dst_t; +} IRQDest; typedef struct OpenPICState { SysBusDevice busdev; @@ -239,9 +239,9 @@ typedef struct OpenPICState { uint32_t spve; /* Spurious vector register */ uint32_t tifr; /* Timer frequency reporting register */ /* Source registers */ - IRQ_src_t src[MAX_IRQ]; + IRQSource src[MAX_IRQ]; /* Local registers per output pin */ - IRQ_dst_t dst[MAX_CPU]; + IRQDest dst[MAX_CPU]; uint32_t nb_cpus; /* Timer registers */ struct { @@ -258,26 +258,26 @@ typedef struct OpenPICState { uint32_t irq_msi; } OpenPICState; -static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src); +static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQSource *src); -static inline void IRQ_setbit(IRQ_queue_t *q, int n_IRQ) +static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) { q->pending++; set_bit(q->queue, n_IRQ); } -static inline void IRQ_resetbit(IRQ_queue_t *q, int n_IRQ) +static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ) { q->pending--; reset_bit(q->queue, n_IRQ); } -static inline int IRQ_testbit(IRQ_queue_t *q, int n_IRQ) +static inline int IRQ_testbit(IRQQueue *q, int n_IRQ) { return test_bit(q->queue, n_IRQ); } -static void IRQ_check(OpenPICState *opp, IRQ_queue_t *q) +static void IRQ_check(OpenPICState *opp, IRQQueue *q) { int next, i; int priority; @@ -306,7 +306,7 @@ out: q->priority = priority; } -static int IRQ_get_next(OpenPICState *opp, IRQ_queue_t *q) +static int IRQ_get_next(OpenPICState *opp, IRQQueue *q) { if (q->next == -1) { /* XXX: optimize */ @@ -318,8 +318,8 @@ static int IRQ_get_next(OpenPICState *opp, IRQ_queue_t *q) static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) { - IRQ_dst_t *dst; - IRQ_src_t *src; + IRQDest *dst; + IRQSource *src; int priority; dst = &opp->dst[n_CPU]; @@ -360,7 +360,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) /* update pic state because registers for n_IRQ have changed value */ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) { - IRQ_src_t *src; + IRQSource *src; int i; src = &opp->src[n_IRQ]; @@ -404,8 +404,9 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) } else { /* Distributed delivery mode */ for (i = src->last_cpu + 1; i != src->last_cpu; i++) { - if (i == opp->nb_cpus) + if (i == opp->nb_cpus) { i = 0; + } if (src->ide & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); src->last_cpu = i; @@ -418,7 +419,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) static void openpic_set_irq(void *opaque, int n_IRQ, int level) { OpenPICState *opp = opaque; - IRQ_src_t *src; + IRQSource *src; src = &opp->src[n_IRQ]; DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", @@ -431,8 +432,9 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) } } else { /* edge-sensitive irq */ - if (level) + if (level) { src->pending = 1; + } } openpic_update_irq(opp, n_IRQ); } @@ -459,9 +461,9 @@ static void openpic_reset(DeviceState *d) /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { opp->dst[i].pctp = 15; - memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); + memset(&opp->dst[i].raised, 0, sizeof(IRQQueue)); opp->dst[i].raised.next = -1; - memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); + memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue)); opp->dst[i].servicing.next = -1; } /* Initialise timers */ @@ -508,12 +510,13 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { OpenPICState *opp = opaque; - IRQ_dst_t *dst; + IRQDest *dst; int idx; DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) + if (addr & 0xF) { return; + } switch (addr) { case 0x00: /* Block Revision Register1 (BRR1) is Readonly */ break; @@ -575,8 +578,9 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); retval = 0xFFFFFFFF; - if (addr & 0xF) + if (addr & 0xF) { return retval; + } switch (addr) { case 0x1000: /* FREP */ retval = opp->frep; @@ -631,8 +635,9 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, int idx; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); - if (addr & 0xF) + if (addr & 0xF) { return; + } idx = (addr >> 6) & 0x3; addr = addr & 0x30; @@ -705,8 +710,9 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, int idx; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); - if (addr & 0xF) + if (addr & 0xF) { return; + } addr = addr & 0xFFF0; idx = addr >> 5; if (addr & 0x10) { @@ -726,8 +732,9 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) DPRINTF("%s: addr %08x\n", __func__, addr); retval = 0xFFFFFFFF; - if (addr & 0xF) + if (addr & 0xF) { return retval; + } addr = addr & 0xFFF0; idx = addr >> 5; if (addr & 0x10) { @@ -808,8 +815,8 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx) { OpenPICState *opp = opaque; - IRQ_src_t *src; - IRQ_dst_t *dst; + IRQSource *src; + IRQDest *dst; int s_IRQ, n_IRQ; DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx, @@ -819,8 +826,9 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, return; } - if (addr & 0xF) + if (addr & 0xF) { return; + } dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { @@ -877,8 +885,8 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, int idx) { OpenPICState *opp = opaque; - IRQ_src_t *src; - IRQ_dst_t *dst; + IRQSource *src; + IRQDest *dst; uint32_t retval; int n_IRQ; @@ -889,8 +897,9 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, return retval; } - if (addr & 0xF) + if (addr & 0xF) { return retval; + } dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { @@ -1059,7 +1068,7 @@ static const MemoryRegionOps openpic_msi_ops_be = { }, }; -static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) +static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q) { unsigned int i; @@ -1102,7 +1111,7 @@ static void openpic_save(QEMUFile* f, void *opaque) } } -static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) +static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q) { unsigned int i; @@ -1118,8 +1127,9 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) OpenPICState *opp = (OpenPICState *)opaque; unsigned int i; - if (version_id != 1) + if (version_id != 1) { return -EINVAL; + } qemu_get_be32s(f, &opp->glbc); qemu_get_be32s(f, &opp->veni); @@ -1150,7 +1160,7 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) return 0; } -static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src) +static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQSource *src) { int n_ci = IDR_CI0_SHIFT - n_CPU; @@ -1161,19 +1171,19 @@ static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src) } } -struct memreg { +typedef struct MemReg { const char *name; MemoryRegionOps const *ops; bool map; hwaddr start_addr; ram_addr_t size; -}; +} MemReg; static int openpic_init(SysBusDevice *dev) { OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev); int i, j; - struct memreg list_le[] = { + MemReg list_le[] = { {"glb", &openpic_glb_ops_le, true, OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, {"tmr", &openpic_tmr_ops_le, true, @@ -1185,7 +1195,7 @@ static int openpic_init(SysBusDevice *dev) {"cpu", &openpic_cpu_ops_le, true, OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, }; - struct memreg list_be[] = { + MemReg list_be[] = { {"glb", &openpic_glb_ops_be, true, OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, {"tmr", &openpic_tmr_ops_be, true, @@ -1197,7 +1207,7 @@ static int openpic_init(SysBusDevice *dev) {"cpu", &openpic_cpu_ops_be, true, OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, }; - struct memreg *list; + MemReg *list; switch (opp->model) { case OPENPIC_MODEL_FSL_MPIC_20: From 88a78d9093917096feffeba66802be27d0e64ead Mon Sep 17 00:00:00 2001 From: Bharat Bhushan Date: Thu, 27 Dec 2012 19:16:51 +0000 Subject: [PATCH 09/31] PPC: Reset qemu timers when guest reset This patch install the timer reset handler. This will be called when the guest is reset. Signed-off-by: Bharat Bhushan [agraf: adjust for QOM'ification] Signed-off-by: Alexander Graf --- hw/ppc_booke.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c index 4483b8d292..25a4e91b69 100644 --- a/hw/ppc_booke.c +++ b/hw/ppc_booke.c @@ -237,6 +237,17 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val) } +static void ppc_booke_timer_reset_handle(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + env->spr[SPR_BOOKE_TSR] = 0; + env->spr[SPR_BOOKE_TCR] = 0; + + booke_update_irq(cpu); +} + void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) { ppc_tb_t *tb_env; @@ -257,4 +268,6 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu); booke_timer->wdt_timer = qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu); + + qemu_register_reset(ppc_booke_timer_reset_handle, cpu); } From beb526b12134a6b6744125deec5a7fe24a8f92e3 Mon Sep 17 00:00:00 2001 From: Samuel Seay Date: Wed, 2 Jan 2013 10:53:46 +0000 Subject: [PATCH 10/31] PPC: fix segfault in signal handling code Removed h2g() macro around the ka->_sa_handler due to the _sa_handler being a guest memory address. Changed the __put_user to put_user as it was attempting to put a value at the stack address but the new address is a guest memory address, __put_user is for host memory addresses. Signed-off-by: Samuel Seay Reviewed-by: Peter Maydell [agraf: change subject line, reformat commit message] Signed-off-by: Alexander Graf --- linux-user/signal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 95e2ffa007..c43b8ac30a 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -4584,7 +4584,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, signal = current_exec_domain_sig(sig); - err |= __put_user(h2g(ka->_sa_handler), &sc->handler); + err |= __put_user(ka->_sa_handler, &sc->handler); err |= __put_user(set->sig[0], &sc->oldmask); #if defined(TARGET_PPC64) err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]); @@ -4606,7 +4606,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, /* Create a stack frame for the caller of the handler. */ newsp = frame_addr - SIGNAL_FRAMESIZE; - err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp); + err |= put_user(env->gpr[1], newsp, target_ulong); if (err) goto sigsegv; From 4c4f0e4801ac79632d03867c88aafc90b4ce503c Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:38 +0000 Subject: [PATCH 11/31] openpic: fix debug prints Fix various format errors when debug prints are enabled. Also cause error checking to happen even when debug prints are not enabled, and consistently use 0x for hex output. Signed-off-by: Scott Wood [agraf: adjust for more recent code base, prettify DPRINTF macro] Signed-off-by: Alexander Graf --- hw/openpic.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 55e96d1334..9243e70db8 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -43,11 +43,17 @@ //#define DEBUG_OPENPIC #ifdef DEBUG_OPENPIC -#define DPRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0) +static const int debug_openpic = 1; #else -#define DPRINTF(fmt, ...) do { } while (0) +static const int debug_openpic = 0; #endif +#define DPRINTF(fmt, ...) do { \ + if (debug_openpic) { \ + printf(fmt , ## __VA_ARGS__); \ + } \ + } while (0) + #define MAX_CPU 15 #define MAX_SRC 256 #define MAX_TMR 4 @@ -422,7 +428,7 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) IRQSource *src; src = &opp->src[n_IRQ]; - DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", + DPRINTF("openpic: set irq %d = %d ipvp=0x%08x\n", n_IRQ, level, src->ipvp); if (src->ipvp & IPVP_SENSE_MASK) { /* level-sensitive irq */ @@ -513,7 +519,8 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, IRQDest *dst; int idx; - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + __func__, addr, val); if (addr & 0xF) { return; } @@ -576,7 +583,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) OpenPICState *opp = opaque; uint32_t retval; - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); retval = 0xFFFFFFFF; if (addr & 0xF) { return retval; @@ -623,7 +630,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) default: break; } - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -634,7 +641,8 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, OpenPICState *opp = opaque; int idx; - DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + __func__, addr, val); if (addr & 0xF) { return; } @@ -672,7 +680,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) uint32_t retval = -1; int idx; - DPRINTF("%s: addr %08x\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); if (addr & 0xF) { goto out; } @@ -698,7 +706,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) } out: - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -709,7 +717,8 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, OpenPICState *opp = opaque; int idx; - DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + __func__, addr, val); if (addr & 0xF) { return; } @@ -730,7 +739,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) uint32_t retval; int idx; - DPRINTF("%s: addr %08x\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); retval = 0xFFFFFFFF; if (addr & 0xF) { return retval; @@ -744,7 +753,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) /* EXVP / IFEVP / IEEVP */ retval = read_IRQreg_ipvp(opp, idx); } - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -756,7 +765,8 @@ static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val, int idx = opp->irq_msi; int srs, ibs; - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); + DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", + __func__, addr, val); if (addr & 0xF) { return; } @@ -781,7 +791,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) uint64_t r = 0; int i, srs; - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); if (addr & 0xF) { return -1; } @@ -819,7 +829,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, IRQDest *dst; int s_IRQ, n_IRQ; - DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx, + DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx, addr, val); if (idx < 0) { @@ -890,7 +900,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, uint32_t retval; int n_IRQ; - DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr); + DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr); retval = 0xFFFFFFFF; if (idx < 0) { @@ -958,7 +968,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, default: break; } - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } From e99fd8af63a1692a1159cba8fa4943f2589adf97 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:39 +0000 Subject: [PATCH 12/31] openpic: lower interrupt when reading the MSI register This will stop things from breaking once it's properly treated as a level-triggered interrupt. Note that it's the MPIC's MSI cascade interrupts that are level-triggered; the individual MSIs are edge-triggered. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/openpic.c b/hw/openpic.c index 9243e70db8..f4df66dc10 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -810,6 +810,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) r = opp->msi[srs].msir; /* Clear on read */ opp->msi[srs].msir = 0; + openpic_set_irq(opp, opp->irq_msi + srs, 0); break; case 0x120: /* MSISR */ for (i = 0; i < MAX_MSI; i++) { From a1bb73849fbd7d992b6ac2cf30c034244fb2299d Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:41 +0000 Subject: [PATCH 13/31] ppc/booke: fix crit/mcheck/debug exceptions Book E does not play games with certain bits of xSRR1 being MSR save bits and others being error status. xSRR1 is the old MSR, period. This was causing things like MSR[CE] to be lost, even in the saved version, as soon as you take an exception. rfci/rfdi/rfmci are fixed to pass the actual xSRR1 register contents, rather than the register number. Put FIXME comments on the hack that is "asrr0/1". The whole point of separate exception levels is so that you can, for example, take a machine check or debug interrupt without corrupting critical-level operations. The right xSRR0/1 set needs to be chosen based on CPU type flags. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- target-ppc/excp_helper.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 5e34ad08a8..41037a7e26 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -84,7 +84,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) " => %08x (%02x)\n", env->nip, excp, env->error_code); /* new srr1 value excluding must-be-zero bits */ - msr = env->msr & ~0x783f0000ULL; + if (excp_model == POWERPC_EXCP_BOOKE) { + msr = env->msr; + } else { + msr = env->msr & ~0x783f0000ULL; + } /* new interrupt handler msr */ new_msr = env->msr & ((target_ulong)1 << MSR_ME); @@ -145,6 +149,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) srr1 = SPR_40x_SRR3; break; case POWERPC_EXCP_BOOKE: + /* FIXME: choose one or the other based on CPU type */ srr0 = SPR_BOOKE_MCSRR0; srr1 = SPR_BOOKE_MCSRR1; asrr0 = SPR_BOOKE_CSRR0; @@ -275,6 +280,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) case POWERPC_EXCP_DEBUG: /* Debug interrupt */ switch (excp_model) { case POWERPC_EXCP_BOOKE: + /* FIXME: choose one or the other based on CPU type */ srr0 = SPR_BOOKE_DSRR0; srr1 = SPR_BOOKE_DSRR1; asrr0 = SPR_BOOKE_CSRR0; @@ -836,8 +842,13 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, void helper_rfi(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], - ~((target_ulong)0x783F0000), 1); + if (env->excp_model == POWERPC_EXCP_BOOKE) { + do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0), 0); + } else { + do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0x783F0000), 1); + } } #if defined(TARGET_PPC64) @@ -864,20 +875,22 @@ void helper_40x_rfci(CPUPPCState *env) void helper_rfci(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1, - ~((target_ulong)0x3FFF0000), 0); + do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1], + ~((target_ulong)0), 0); } void helper_rfdi(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1, - ~((target_ulong)0x3FFF0000), 0); + /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ + do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1], + ~((target_ulong)0), 0); } void helper_rfmci(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1, - ~((target_ulong)0x3FFF0000), 0); + /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ + do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1], + ~((target_ulong)0), 0); } #endif From be7c236fa2e59090d7cd0193ca3f225c331d5f81 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:42 +0000 Subject: [PATCH 14/31] openpic: make register names correspond better with hw docs The base openpic specification doesn't provide abbreviated register names, so it's somewhat understandable that the QEMU code made up its own, except that most of the names that QEMU used didn't correspond to the terminology used by any implementation I could find. In some cases, like PCTP, the phrase "processor current task priority" could be found in the openpic spec when describing the concept, but the register itself was labelled "current task priority register" and every implementation seems to use either CTPR or the full phrase. In other cases, individual implementations disagree on what to call the register. The implementations I have documentation for are Freescale, Raven (MCP750), and IBM. The Raven docs tend to not use abbreviations at all. The IBM MPIC isn't implemented in QEMU. Thus, where there's disagreement I chose to use the Freescale abbreviations. Signed-off-by: Scott Wood [agraf: rebase on current state of the code] Signed-off-by: Alexander Graf --- hw/openpic.c | 352 +++++++++++++++++++++++++-------------------------- 1 file changed, 176 insertions(+), 176 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index f4df66dc10..6362497237 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -63,7 +63,7 @@ static const int debug_openpic = 0; #define VID 0x03 /* MPIC version ID */ /* OpenPIC capability flags */ -#define OPENPIC_FLAG_IDE_CRIT (1 << 0) +#define OPENPIC_FLAG_IDR_CRIT (1 << 0) /* OpenPIC address map */ #define OPENPIC_GLB_REG_START 0x0 @@ -120,19 +120,19 @@ static const int debug_openpic = 0; #define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */ #define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */ -#define FREP_NIRQ_SHIFT 16 -#define FREP_NCPU_SHIFT 8 -#define FREP_VID_SHIFT 0 +#define FRR_NIRQ_SHIFT 16 +#define FRR_NCPU_SHIFT 8 +#define FRR_VID_SHIFT 0 #define VID_REVISION_1_2 2 #define VID_REVISION_1_3 3 -#define VENI_GENERIC 0x00000000 /* Generic Vendor ID */ +#define VIR_GENERIC 0x00000000 /* Generic Vendor ID */ -#define GLBC_RESET 0x80000000 +#define GCR_RESET 0x80000000 -#define TIBC_CI 0x80000000 /* count inhibit */ -#define TICC_TOG 0x80000000 /* toggles when decrement to zero */ +#define TBCR_CI 0x80000000 /* count inhibit */ +#define TCCR_TOG 0x80000000 /* toggles when decrement to zero */ #define IDR_EP_SHIFT 31 #define IDR_EP_MASK (1 << IDR_EP_SHIFT) @@ -187,33 +187,33 @@ typedef struct IRQQueue { } IRQQueue; typedef struct IRQSource { - uint32_t ipvp; /* IRQ vector/priority register */ - uint32_t ide; /* IRQ destination register */ + uint32_t ivpr; /* IRQ vector/priority register */ + uint32_t idr; /* IRQ destination register */ int last_cpu; int pending; /* TRUE if IRQ is pending */ } IRQSource; -#define IPVP_MASK_SHIFT 31 -#define IPVP_MASK_MASK (1 << IPVP_MASK_SHIFT) -#define IPVP_ACTIVITY_SHIFT 30 -#define IPVP_ACTIVITY_MASK (1 << IPVP_ACTIVITY_SHIFT) -#define IPVP_MODE_SHIFT 29 -#define IPVP_MODE_MASK (1 << IPVP_MODE_SHIFT) -#define IPVP_POLARITY_SHIFT 23 -#define IPVP_POLARITY_MASK (1 << IPVP_POLARITY_SHIFT) -#define IPVP_SENSE_SHIFT 22 -#define IPVP_SENSE_MASK (1 << IPVP_SENSE_SHIFT) +#define IVPR_MASK_SHIFT 31 +#define IVPR_MASK_MASK (1 << IVPR_MASK_SHIFT) +#define IVPR_ACTIVITY_SHIFT 30 +#define IVPR_ACTIVITY_MASK (1 << IVPR_ACTIVITY_SHIFT) +#define IVPR_MODE_SHIFT 29 +#define IVPR_MODE_MASK (1 << IVPR_MODE_SHIFT) +#define IVPR_POLARITY_SHIFT 23 +#define IVPR_POLARITY_MASK (1 << IVPR_POLARITY_SHIFT) +#define IVPR_SENSE_SHIFT 22 +#define IVPR_SENSE_MASK (1 << IVPR_SENSE_SHIFT) -#define IPVP_PRIORITY_MASK (0xF << 16) -#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) -#define IPVP_VECTOR(opp, _ipvpr_) ((_ipvpr_) & (opp)->vector_mask) +#define IVPR_PRIORITY_MASK (0xF << 16) +#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16)) +#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask) -/* IDE[EP/CI] are only for FSL MPIC prior to v4.0 */ -#define IDE_EP 0x80000000 /* external pin */ -#define IDE_CI 0x40000000 /* critical interrupt */ +/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */ +#define IDR_EP 0x80000000 /* external pin */ +#define IDR_CI 0x40000000 /* critical interrupt */ typedef struct IRQDest { - uint32_t pctp; /* CPU current task priority */ + uint32_t ctpr; /* CPU current task priority */ IRQQueue raised; IRQQueue servicing; qemu_irq *irqs; @@ -228,22 +228,22 @@ typedef struct OpenPICState { uint32_t flags; uint32_t nb_irqs; uint32_t vid; - uint32_t veni; /* Vendor identification register */ + uint32_t vir; /* Vendor identification register */ uint32_t vector_mask; - uint32_t tifr_reset; - uint32_t ipvp_reset; - uint32_t ide_reset; + uint32_t tfrr_reset; + uint32_t ivpr_reset; + uint32_t idr_reset; uint32_t brr1; /* Sub-regions */ MemoryRegion sub_io_mem[5]; /* Global registers */ - uint32_t frep; /* Feature reporting register */ - uint32_t glbc; /* Global configuration register */ - uint32_t pint; /* Processor initialization register */ + uint32_t frr; /* Feature reporting register */ + uint32_t gcr; /* Global configuration register */ + uint32_t pir; /* Processor initialization register */ uint32_t spve; /* Spurious vector register */ - uint32_t tifr; /* Timer frequency reporting register */ + uint32_t tfrr; /* Timer frequency reporting register */ /* Source registers */ IRQSource src[MAX_IRQ]; /* Local registers per output pin */ @@ -251,8 +251,8 @@ typedef struct OpenPICState { uint32_t nb_cpus; /* Timer registers */ struct { - uint32_t ticc; /* Global timer current count register */ - uint32_t tibc; /* Global timer base count register */ + uint32_t tccr; /* Global timer current count register */ + uint32_t tbcr; /* Global timer base count register */ } timers[MAX_TMR]; /* Shared MSI registers */ struct { @@ -298,11 +298,11 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q) for (i = 0; i < opp->max_irq; i++) { if (IRQ_testbit(q, i)) { - DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", - i, IPVP_PRIORITY(opp->src[i].ipvp), priority); - if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { + DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", + i, IVPR_PRIORITY(opp->src[i].ivpr), priority); + if (IVPR_PRIORITY(opp->src[i].ivpr) > priority) { next = i; - priority = IPVP_PRIORITY(opp->src[i].ipvp); + priority = IVPR_PRIORITY(opp->src[i].ivpr); } } } @@ -330,8 +330,8 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) dst = &opp->dst[n_CPU]; src = &opp->src[n_IRQ]; - priority = IPVP_PRIORITY(src->ipvp); - if (priority <= dst->pctp) { + priority = IVPR_PRIORITY(src->ivpr); + if (priority <= dst->ctpr) { /* Too low priority */ DPRINTF("%s: IRQ %d has too low priority on CPU %d\n", __func__, n_IRQ, n_CPU); @@ -343,7 +343,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) __func__, n_IRQ, n_CPU); return; } - src->ipvp |= IPVP_ACTIVITY_MASK; + src->ivpr |= IVPR_ACTIVITY_MASK; IRQ_setbit(&dst->raised, n_IRQ); if (priority < dst->raised.priority) { /* An higher priority IRQ is already raised */ @@ -376,34 +376,34 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); return; } - if (src->ipvp & IPVP_MASK_MASK) { + if (src->ivpr & IVPR_MASK_MASK) { /* Interrupt source is disabled */ DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); return; } - if (IPVP_PRIORITY(src->ipvp) == 0) { + if (IVPR_PRIORITY(src->ivpr) == 0) { /* Priority set to zero */ DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ); return; } - if (src->ipvp & IPVP_ACTIVITY_MASK) { + if (src->ivpr & IVPR_ACTIVITY_MASK) { /* IRQ already active */ DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); return; } - if (src->ide == 0) { + if (src->idr == 0) { /* No target */ DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); return; } - if (src->ide == (1 << src->last_cpu)) { + if (src->idr == (1 << src->last_cpu)) { /* Only one CPU is allowed to receive this IRQ */ IRQ_local_pipe(opp, src->last_cpu, n_IRQ); - } else if (!(src->ipvp & IPVP_MODE_MASK)) { + } else if (!(src->ivpr & IVPR_MODE_MASK)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { - if (src->ide & (1 << i)) { + if (src->idr & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); } } @@ -413,7 +413,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) if (i == opp->nb_cpus) { i = 0; } - if (src->ide & (1 << i)) { + if (src->idr & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); src->last_cpu = i; break; @@ -428,13 +428,13 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) IRQSource *src; src = &opp->src[n_IRQ]; - DPRINTF("openpic: set irq %d = %d ipvp=0x%08x\n", - n_IRQ, level, src->ipvp); - if (src->ipvp & IPVP_SENSE_MASK) { + DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n", + n_IRQ, level, src->ivpr); + if (src->ivpr & IVPR_SENSE_MASK) { /* level-sensitive irq */ src->pending = level; if (!level) { - src->ipvp &= ~IPVP_ACTIVITY_MASK; + src->ivpr &= ~IVPR_ACTIVITY_MASK; } } else { /* edge-sensitive irq */ @@ -450,23 +450,23 @@ static void openpic_reset(DeviceState *d) OpenPICState *opp = FROM_SYSBUS(typeof (*opp), sysbus_from_qdev(d)); int i; - opp->glbc = GLBC_RESET; + opp->gcr = GCR_RESET; /* Initialise controller registers */ - opp->frep = ((opp->nb_irqs - 1) << FREP_NIRQ_SHIFT) | - ((opp->nb_cpus - 1) << FREP_NCPU_SHIFT) | - (opp->vid << FREP_VID_SHIFT); + opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) | + ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) | + (opp->vid << FRR_VID_SHIFT); - opp->pint = 0; + opp->pir = 0; opp->spve = -1 & opp->vector_mask; - opp->tifr = opp->tifr_reset; + opp->tfrr = opp->tfrr_reset; /* Initialise IRQ sources */ for (i = 0; i < opp->max_irq; i++) { - opp->src[i].ipvp = opp->ipvp_reset; - opp->src[i].ide = opp->ide_reset; + opp->src[i].ivpr = opp->ivpr_reset; + opp->src[i].idr = opp->idr_reset; } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { - opp->dst[i].pctp = 15; + opp->dst[i].ctpr = 15; memset(&opp->dst[i].raised, 0, sizeof(IRQQueue)); opp->dst[i].raised.next = -1; memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue)); @@ -474,42 +474,42 @@ static void openpic_reset(DeviceState *d) } /* Initialise timers */ for (i = 0; i < MAX_TMR; i++) { - opp->timers[i].ticc = 0; - opp->timers[i].tibc = TIBC_CI; + opp->timers[i].tccr = 0; + opp->timers[i].tbcr = TBCR_CI; } /* Go out of RESET state */ - opp->glbc = 0; + opp->gcr = 0; } -static inline uint32_t read_IRQreg_ide(OpenPICState *opp, int n_IRQ) +static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ) { - return opp->src[n_IRQ].ide; + return opp->src[n_IRQ].idr; } -static inline uint32_t read_IRQreg_ipvp(OpenPICState *opp, int n_IRQ) +static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ) { - return opp->src[n_IRQ].ipvp; + return opp->src[n_IRQ].ivpr; } -static inline void write_IRQreg_ide(OpenPICState *opp, int n_IRQ, uint32_t val) +static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) { uint32_t tmp; - tmp = val & (IDE_EP | IDE_CI); + tmp = val & (IDR_EP | IDR_CI); tmp |= val & ((1ULL << MAX_CPU) - 1); - opp->src[n_IRQ].ide = tmp; - DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); + opp->src[n_IRQ].idr = tmp; + DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].idr); } -static inline void write_IRQreg_ipvp(OpenPICState *opp, int n_IRQ, uint32_t val) +static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) { /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & IPVP_ACTIVITY_MASK) | - (val & (IPVP_MASK_MASK | IPVP_PRIORITY_MASK | opp->vector_mask)); + opp->src[n_IRQ].ivpr = (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | + (val & (IVPR_MASK_MASK | IVPR_PRIORITY_MASK | opp->vector_mask)); openpic_update_irq(opp, n_IRQ); - DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val, - opp->src[n_IRQ].ipvp); + DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val, + opp->src[n_IRQ].ivpr); } static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, @@ -537,37 +537,37 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, case 0xB0: openpic_cpu_write_internal(opp, addr, val, get_current_cpu()); break; - case 0x1000: /* FREP */ + case 0x1000: /* FRR */ break; - case 0x1020: /* GLBC */ - if (val & GLBC_RESET) { + case 0x1020: /* GCR */ + if (val & GCR_RESET) { openpic_reset(&opp->busdev.qdev); } break; - case 0x1080: /* VENI */ + case 0x1080: /* VIR */ break; - case 0x1090: /* PINT */ + case 0x1090: /* PIR */ for (idx = 0; idx < opp->nb_cpus; idx++) { - if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) { + if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) { DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx); dst = &opp->dst[idx]; qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]); - } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) { + } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) { DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx); dst = &opp->dst[idx]; qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]); } } - opp->pint = val; + opp->pir = val; break; - case 0x10A0: /* IPI_IPVP */ + case 0x10A0: /* IPI_IVPR */ case 0x10B0: case 0x10C0: case 0x10D0: { int idx; idx = (addr - 0x10A0) >> 4; - write_IRQreg_ipvp(opp, opp->irq_ipi0 + idx, val); + write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val); } break; case 0x10E0: /* SPVE */ @@ -589,16 +589,16 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) return retval; } switch (addr) { - case 0x1000: /* FREP */ - retval = opp->frep; + case 0x1000: /* FRR */ + retval = opp->frr; break; - case 0x1020: /* GLBC */ - retval = opp->glbc; + case 0x1020: /* GCR */ + retval = opp->gcr; break; - case 0x1080: /* VENI */ - retval = opp->veni; + case 0x1080: /* VIR */ + retval = opp->vir; break; - case 0x1090: /* PINT */ + case 0x1090: /* PIR */ retval = 0x00000000; break; case 0x00: /* Block Revision Register1 (BRR1) */ @@ -614,14 +614,14 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) case 0xB0: retval = openpic_cpu_read_internal(opp, addr, get_current_cpu()); break; - case 0x10A0: /* IPI_IPVP */ + case 0x10A0: /* IPI_IVPR */ case 0x10B0: case 0x10C0: case 0x10D0: { int idx; idx = (addr - 0x10A0) >> 4; - retval = read_IRQreg_ipvp(opp, opp->irq_ipi0 + idx); + retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx); } break; case 0x10E0: /* SPVE */ @@ -650,26 +650,26 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, addr = addr & 0x30; if (addr == 0x0) { - /* TIFR (TFRR) */ - opp->tifr = val; + /* TFRR */ + opp->tfrr = val; return; } switch (addr & 0x30) { - case 0x00: /* TICC (GTCCR) */ + case 0x00: /* TCCR */ break; - case 0x10: /* TIBC (GTBCR) */ - if ((opp->timers[idx].ticc & TICC_TOG) != 0 && - (val & TIBC_CI) == 0 && - (opp->timers[idx].tibc & TIBC_CI) != 0) { - opp->timers[idx].ticc &= ~TICC_TOG; + case 0x10: /* TBCR */ + if ((opp->timers[idx].tccr & TCCR_TOG) != 0 && + (val & TBCR_CI) == 0 && + (opp->timers[idx].tbcr & TBCR_CI) != 0) { + opp->timers[idx].tccr &= ~TCCR_TOG; } - opp->timers[idx].tibc = val; + opp->timers[idx].tbcr = val; break; - case 0x20: /* TIVP (GTIVPR) */ - write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val); + case 0x20: /* TVPR */ + write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val); break; - case 0x30: /* TIDE (GTIDR) */ - write_IRQreg_ide(opp, opp->irq_tim0 + idx, val); + case 0x30: /* TDR */ + write_IRQreg_idr(opp, opp->irq_tim0 + idx, val); break; } } @@ -686,22 +686,22 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) } idx = (addr >> 6) & 0x3; if (addr == 0x0) { - /* TIFR (TFRR) */ - retval = opp->tifr; + /* TFRR */ + retval = opp->tfrr; goto out; } switch (addr & 0x30) { - case 0x00: /* TICC (GTCCR) */ - retval = opp->timers[idx].ticc; + case 0x00: /* TCCR */ + retval = opp->timers[idx].tccr; break; - case 0x10: /* TIBC (GTBCR) */ - retval = opp->timers[idx].tibc; + case 0x10: /* TBCR */ + retval = opp->timers[idx].tbcr; break; - case 0x20: /* TIPV (TIPV) */ - retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx); + case 0x20: /* TIPV */ + retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx); break; case 0x30: /* TIDE (TIDR) */ - retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx); + retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx); break; } @@ -726,10 +726,10 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, idx = addr >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - write_IRQreg_ide(opp, idx, val); + write_IRQreg_idr(opp, idx, val); } else { /* EXVP / IFEVP / IEEVP */ - write_IRQreg_ipvp(opp, idx, val); + write_IRQreg_ivpr(opp, idx, val); } } @@ -748,10 +748,10 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) idx = addr >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_ide(opp, idx); + retval = read_IRQreg_idr(opp, idx); } else { /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ipvp(opp, idx); + retval = read_IRQreg_ivpr(opp, idx); } DPRINTF("%s: => 0x%08x\n", __func__, retval); @@ -849,22 +849,22 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, case 0x70: idx = (addr - 0x40) >> 4; /* we use IDE as mask which CPUs to deliver the IPI to still. */ - write_IRQreg_ide(opp, opp->irq_ipi0 + idx, - opp->src[opp->irq_ipi0 + idx].ide | val); + write_IRQreg_idr(opp, opp->irq_ipi0 + idx, + opp->src[opp->irq_ipi0 + idx].idr | val); openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); break; - case 0x80: /* PCTP */ - dst->pctp = val & 0x0000000F; + case 0x80: /* CTPR */ + dst->ctpr = val & 0x0000000F; break; case 0x90: /* WHOAMI */ /* Read-only register */ break; - case 0xA0: /* PIAC */ + case 0xA0: /* IACK */ /* Read-only register */ break; - case 0xB0: /* PEOI */ - DPRINTF("PEOI\n"); + case 0xB0: /* EOI */ + DPRINTF("EOI\n"); s_IRQ = IRQ_get_next(opp, &dst->servicing); IRQ_resetbit(&dst->servicing, s_IRQ); dst->servicing.next = -1; @@ -875,7 +875,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, src = &opp->src[n_IRQ]; if (n_IRQ != -1 && (s_IRQ == -1 || - IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) { + IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", idx, n_IRQ); openpic_irq_raise(opp, idx, src); @@ -914,56 +914,56 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { - case 0x80: /* PCTP */ - retval = dst->pctp; + case 0x80: /* CTPR */ + retval = dst->ctpr; break; case 0x90: /* WHOAMI */ retval = idx; break; - case 0xA0: /* PIAC */ + case 0xA0: /* IACK */ DPRINTF("Lower OpenPIC INT output\n"); qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); n_IRQ = IRQ_get_next(opp, &dst->raised); - DPRINTF("PIAC: irq=%d\n", n_IRQ); + DPRINTF("IACK: irq=%d\n", n_IRQ); if (n_IRQ == -1) { /* No more interrupt pending */ retval = opp->spve; } else { src = &opp->src[n_IRQ]; - if (!(src->ipvp & IPVP_ACTIVITY_MASK) || - !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) { + if (!(src->ivpr & IVPR_ACTIVITY_MASK) || + !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { /* - Spurious level-sensitive IRQ * - Priorities has been changed * and the pending IRQ isn't allowed anymore */ - src->ipvp &= ~IPVP_ACTIVITY_MASK; + src->ivpr &= ~IVPR_ACTIVITY_MASK; retval = opp->spve; } else { /* IRQ enter servicing state */ IRQ_setbit(&dst->servicing, n_IRQ); - retval = IPVP_VECTOR(opp, src->ipvp); + retval = IVPR_VECTOR(opp, src->ivpr); } IRQ_resetbit(&dst->raised, n_IRQ); dst->raised.next = -1; - if (!(src->ipvp & IPVP_SENSE_MASK)) { + if (!(src->ivpr & IVPR_SENSE_MASK)) { /* edge-sensitive IRQ */ - src->ipvp &= ~IPVP_ACTIVITY_MASK; + src->ivpr &= ~IVPR_ACTIVITY_MASK; src->pending = 0; } if ((n_IRQ >= opp->irq_ipi0) && (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) { - src->ide &= ~(1 << idx); - if (src->ide && !(src->ipvp & IPVP_SENSE_MASK)) { + src->idr &= ~(1 << idx); + if (src->idr && !(src->ivpr & IVPR_SENSE_MASK)) { /* trigger on CPUs that didn't know about it yet */ openpic_set_irq(opp, n_IRQ, 1); openpic_set_irq(opp, n_IRQ, 0); /* if all CPUs knew about it, set active bit again */ - src->ipvp |= IPVP_ACTIVITY_MASK; + src->ivpr |= IVPR_ACTIVITY_MASK; } } } break; - case 0xB0: /* PEOI */ + case 0xB0: /* EOI */ retval = 0; break; default: @@ -1095,15 +1095,15 @@ static void openpic_save(QEMUFile* f, void *opaque) OpenPICState *opp = (OpenPICState *)opaque; unsigned int i; - qemu_put_be32s(f, &opp->glbc); - qemu_put_be32s(f, &opp->veni); - qemu_put_be32s(f, &opp->pint); + qemu_put_be32s(f, &opp->gcr); + qemu_put_be32s(f, &opp->vir); + qemu_put_be32s(f, &opp->pir); qemu_put_be32s(f, &opp->spve); - qemu_put_be32s(f, &opp->tifr); + qemu_put_be32s(f, &opp->tfrr); for (i = 0; i < opp->max_irq; i++) { - qemu_put_be32s(f, &opp->src[i].ipvp); - qemu_put_be32s(f, &opp->src[i].ide); + qemu_put_be32s(f, &opp->src[i].ivpr); + qemu_put_be32s(f, &opp->src[i].idr); qemu_put_sbe32s(f, &opp->src[i].last_cpu); qemu_put_sbe32s(f, &opp->src[i].pending); } @@ -1111,14 +1111,14 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_put_be32s(f, &opp->dst[i].pctp); + qemu_put_be32s(f, &opp->dst[i].ctpr); openpic_save_IRQ_queue(f, &opp->dst[i].raised); openpic_save_IRQ_queue(f, &opp->dst[i].servicing); } for (i = 0; i < MAX_TMR; i++) { - qemu_put_be32s(f, &opp->timers[i].ticc); - qemu_put_be32s(f, &opp->timers[i].tibc); + qemu_put_be32s(f, &opp->timers[i].tccr); + qemu_put_be32s(f, &opp->timers[i].tbcr); } } @@ -1142,15 +1142,15 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) return -EINVAL; } - qemu_get_be32s(f, &opp->glbc); - qemu_get_be32s(f, &opp->veni); - qemu_get_be32s(f, &opp->pint); + qemu_get_be32s(f, &opp->gcr); + qemu_get_be32s(f, &opp->vir); + qemu_get_be32s(f, &opp->pir); qemu_get_be32s(f, &opp->spve); - qemu_get_be32s(f, &opp->tifr); + qemu_get_be32s(f, &opp->tfrr); for (i = 0; i < opp->max_irq; i++) { - qemu_get_be32s(f, &opp->src[i].ipvp); - qemu_get_be32s(f, &opp->src[i].ide); + qemu_get_be32s(f, &opp->src[i].ivpr); + qemu_get_be32s(f, &opp->src[i].idr); qemu_get_sbe32s(f, &opp->src[i].last_cpu); qemu_get_sbe32s(f, &opp->src[i].pending); } @@ -1158,14 +1158,14 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_get_be32s(f, &opp->dst[i].pctp); + qemu_get_be32s(f, &opp->dst[i].ctpr); openpic_load_IRQ_queue(f, &opp->dst[i].raised); openpic_load_IRQ_queue(f, &opp->dst[i].servicing); } for (i = 0; i < MAX_TMR; i++) { - qemu_get_be32s(f, &opp->timers[i].ticc); - qemu_get_be32s(f, &opp->timers[i].tibc); + qemu_get_be32s(f, &opp->timers[i].tccr); + qemu_get_be32s(f, &opp->timers[i].tbcr); } return 0; @@ -1175,7 +1175,7 @@ static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQSource *src) { int n_ci = IDR_CI0_SHIFT - n_CPU; - if ((opp->flags & OPENPIC_FLAG_IDE_CRIT) && (src->ide & (1 << n_ci))) { + if ((opp->flags & OPENPIC_FLAG_IDR_CRIT) && (src->idr & (1 << n_ci))) { qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]); } else { qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); @@ -1223,14 +1223,14 @@ static int openpic_init(SysBusDevice *dev) switch (opp->model) { case OPENPIC_MODEL_FSL_MPIC_20: default: - opp->flags |= OPENPIC_FLAG_IDE_CRIT; + opp->flags |= OPENPIC_FLAG_IDR_CRIT; opp->nb_irqs = 80; opp->vid = VID_REVISION_1_2; - opp->veni = VENI_GENERIC; + opp->vir = VIR_GENERIC; opp->vector_mask = 0xFFFF; - opp->tifr_reset = 0; - opp->ipvp_reset = IPVP_MASK_MASK; - opp->ide_reset = 1 << 0; + opp->tfrr_reset = 0; + opp->ivpr_reset = IVPR_MASK_MASK; + opp->idr_reset = 1 << 0; opp->max_irq = FSL_MPIC_20_MAX_IRQ; opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ; opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ; @@ -1242,11 +1242,11 @@ static int openpic_init(SysBusDevice *dev) case OPENPIC_MODEL_RAVEN: opp->nb_irqs = RAVEN_MAX_EXT; opp->vid = VID_REVISION_1_3; - opp->veni = VENI_GENERIC; + opp->vir = VIR_GENERIC; opp->vector_mask = 0xFF; - opp->tifr_reset = 4160000; - opp->ipvp_reset = IPVP_MASK_MASK | IPVP_MODE_MASK; - opp->ide_reset = 0; + opp->tfrr_reset = 4160000; + opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK; + opp->idr_reset = 0; opp->max_irq = RAVEN_MAX_IRQ; opp->irq_ipi0 = RAVEN_IPI_IRQ; opp->irq_tim0 = RAVEN_TMR_IRQ; From 5e22c276de982dd26ebc4424c8d4592cce1baab9 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:43 +0000 Subject: [PATCH 15/31] openpic: rework critical interrupt support Critical interrupts on FSL MPIC are not supposed to pay attention to priority, IACK, EOI, etc. On the currently modeled version it's not supposed to pay attention to the mask bit either. Also reorganize to make it easier to implement newer FSL MPIC models, which encode interrupt level information differently and support mcheck as well as crit, and to reduce problems for later patches in this set. Still missing is the ability to lower the CINT signal to the core, as IACK/EOI is not used. This will come with general IRQ-source-driven lowering in the next patch. New state is added which is not serialized, but instead is recomputed in openpic_load() by calling the appropriate write_IRQreg function. This should have the side effect of causing the IRQ outputs to be raised appropriately on load, which was missing. The serialization format is altered by swapping ivpr and idr (we'd like IDR to be restored before we run the IVPR logic), and moving interrupts to the end (so that other state has been restored by the time we run the IDR/IVPR logic. Serialization for this driver is not yet in a state where backwards compatibility is reasonable (assuming it works at all), and the current serialization format was not built for extensibility. Signed-off-by: Scott Wood [agraf: fix for current code state] Signed-off-by: Alexander Graf --- hw/openpic.c | 110 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 34 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 6362497237..fe6cf67956 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -189,7 +189,9 @@ typedef struct IRQQueue { typedef struct IRQSource { uint32_t ivpr; /* IRQ vector/priority register */ uint32_t idr; /* IRQ destination register */ + uint32_t destmask; /* bitmap of CPU destinations */ int last_cpu; + int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */ int pending; /* TRUE if IRQ is pending */ } IRQSource; @@ -264,8 +266,6 @@ typedef struct OpenPICState { uint32_t irq_msi; } OpenPICState; -static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQSource *src); - static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) { q->pending++; @@ -330,6 +330,19 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) dst = &opp->dst[n_CPU]; src = &opp->src[n_IRQ]; + + if (src->output != OPENPIC_OUTPUT_INT) { + /* On Freescale MPIC, critical interrupts ignore priority, + * IACK, EOI, etc. Before MPIC v4.1 they also ignore + * masking. + */ + src->ivpr |= IVPR_ACTIVITY_MASK; + DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n", + __func__, src->output, n_CPU, n_IRQ); + qemu_irq_raise(opp->dst[n_CPU].irqs[src->output]); + return; + } + priority = IVPR_PRIORITY(src->ivpr); if (priority <= dst->ctpr) { /* Too low priority */ @@ -360,7 +373,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) return; } DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ); - openpic_irq_raise(opp, n_CPU, src); + qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); } /* update pic state because registers for n_IRQ have changed value */ @@ -403,7 +416,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) } else if (!(src->ivpr & IVPR_MODE_MASK)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { - if (src->idr & (1 << i)) { + if (src->destmask & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); } } @@ -413,7 +426,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) if (i == opp->nb_cpus) { i = 0; } - if (src->idr & (1 << i)) { + if (src->destmask & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); src->last_cpu = i; break; @@ -493,12 +506,45 @@ static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ) static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) { - uint32_t tmp; + IRQSource *src = &opp->src[n_IRQ]; + uint32_t normal_mask = (1UL << opp->nb_cpus) - 1; + uint32_t crit_mask = 0; + uint32_t mask = normal_mask; + int crit_shift = IDR_EP_SHIFT - opp->nb_cpus; + int i; - tmp = val & (IDR_EP | IDR_CI); - tmp |= val & ((1ULL << MAX_CPU) - 1); - opp->src[n_IRQ].idr = tmp; - DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].idr); + if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { + crit_mask = mask << crit_shift; + mask |= crit_mask | IDR_EP; + } + + src->idr = val & mask; + DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr); + + if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { + if (src->idr & crit_mask) { + if (src->idr & normal_mask) { + DPRINTF("%s: IRQ configured for multiple output types, using " + "critical\n", __func__); + } + + src->output = OPENPIC_OUTPUT_CINT; + src->destmask = 0; + + for (i = 0; i < opp->nb_cpus; i++) { + int n_ci = IDR_CI0_SHIFT - i; + + if (src->idr & (1UL << n_ci)) { + src->destmask |= 1UL << i; + } + } + } else { + src->output = OPENPIC_OUTPUT_INT; + src->destmask = src->idr & normal_mask; + } + } else { + src->destmask = src->idr; + } } static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) @@ -878,7 +924,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", idx, n_IRQ); - openpic_irq_raise(opp, idx, src); + qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]); } break; default: @@ -1101,13 +1147,6 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_be32s(f, &opp->spve); qemu_put_be32s(f, &opp->tfrr); - for (i = 0; i < opp->max_irq; i++) { - qemu_put_be32s(f, &opp->src[i].ivpr); - qemu_put_be32s(f, &opp->src[i].idr); - qemu_put_sbe32s(f, &opp->src[i].last_cpu); - qemu_put_sbe32s(f, &opp->src[i].pending); - } - qemu_put_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { @@ -1120,6 +1159,13 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_be32s(f, &opp->timers[i].tccr); qemu_put_be32s(f, &opp->timers[i].tbcr); } + + for (i = 0; i < opp->max_irq; i++) { + qemu_put_be32s(f, &opp->src[i].ivpr); + qemu_put_be32s(f, &opp->src[i].idr); + qemu_put_sbe32s(f, &opp->src[i].last_cpu); + qemu_put_sbe32s(f, &opp->src[i].pending); + } } static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q) @@ -1148,13 +1194,6 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->spve); qemu_get_be32s(f, &opp->tfrr); - for (i = 0; i < opp->max_irq; i++) { - qemu_get_be32s(f, &opp->src[i].ivpr); - qemu_get_be32s(f, &opp->src[i].idr); - qemu_get_sbe32s(f, &opp->src[i].last_cpu); - qemu_get_sbe32s(f, &opp->src[i].pending); - } - qemu_get_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { @@ -1168,18 +1207,21 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->timers[i].tbcr); } - return 0; -} + for (i = 0; i < opp->max_irq; i++) { + uint32_t val; -static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQSource *src) -{ - int n_ci = IDR_CI0_SHIFT - n_CPU; + val = qemu_get_be32(f); + write_IRQreg_idr(opp, i, val); + val = qemu_get_be32(f); + write_IRQreg_ivpr(opp, i, val); - if ((opp->flags & OPENPIC_FLAG_IDR_CRIT) && (src->idr & (1 << n_ci))) { - qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]); - } else { - qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); + qemu_get_be32s(f, &opp->src[i].ivpr); + qemu_get_be32s(f, &opp->src[i].idr); + qemu_get_sbe32s(f, &opp->src[i].last_cpu); + qemu_get_sbe32s(f, &opp->src[i].pending); } + + return 0; } typedef struct MemReg { From eb4384278417297661663c54e01c0f0ffec0a9e3 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:44 +0000 Subject: [PATCH 16/31] openpic: make ctpr signed Other priorities are signed, so avoid comparisons between signed and unsigned. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index fe6cf67956..824b8fd2c2 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -215,7 +215,7 @@ typedef struct IRQSource { #define IDR_CI 0x40000000 /* critical interrupt */ typedef struct IRQDest { - uint32_t ctpr; /* CPU current task priority */ + int32_t ctpr; /* CPU current task priority */ IRQQueue raised; IRQQueue servicing; qemu_irq *irqs; @@ -1150,7 +1150,7 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_put_be32s(f, &opp->dst[i].ctpr); + qemu_put_sbe32s(f, &opp->dst[i].ctpr); openpic_save_IRQ_queue(f, &opp->dst[i].raised); openpic_save_IRQ_queue(f, &opp->dst[i].servicing); } @@ -1197,7 +1197,7 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_get_be32s(f, &opp->dst[i].ctpr); + qemu_get_sbe32s(f, &opp->dst[i].ctpr); openpic_load_IRQ_queue(f, &opp->dst[i].raised); openpic_load_IRQ_queue(f, &opp->dst[i].servicing); } From 72c1da2ca72af50e6536d0cd9c6db758f66cd7c2 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:45 +0000 Subject: [PATCH 17/31] openpic/fsl: critical interrupts ignore mask before v4.1 Signed-off-by: Scott Wood [agraf: make bool :1] Signed-off-by: Alexander Graf --- hw/openpic.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/openpic.c b/hw/openpic.c index 824b8fd2c2..ac5027a5a0 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -193,6 +193,7 @@ typedef struct IRQSource { int last_cpu; int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */ int pending; /* TRUE if IRQ is pending */ + bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ } IRQSource; #define IVPR_MASK_SHIFT 31 @@ -389,7 +390,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); return; } - if (src->ivpr & IVPR_MASK_MASK) { + if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) { /* Interrupt source is disabled */ DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); return; @@ -529,6 +530,7 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) } src->output = OPENPIC_OUTPUT_CINT; + src->nomask = true; src->destmask = 0; for (i = 0; i < opp->nb_cpus; i++) { @@ -540,6 +542,7 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) } } else { src->output = OPENPIC_OUTPUT_INT; + src->nomask = false; src->destmask = src->idr & normal_mask; } } else { From 3c94378e2c500b6211e95d7457f4a9959955c3d1 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:46 +0000 Subject: [PATCH 18/31] openpic: always call IRQ_check from IRQ_get_next Previously the code relied on the queue's "next" field getting set to -1 sometime between an update to the bitmap, and the next call to IRQ_get_next. Sometimes this happened after the update. Sometimes it happened before the check. Sometimes it didn't happen at all. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index ac5027a5a0..19e6280023 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -315,10 +315,8 @@ out: static int IRQ_get_next(OpenPICState *opp, IRQQueue *q) { - if (q->next == -1) { - /* XXX: optimize */ - IRQ_check(opp, q); - } + /* XXX: optimize */ + IRQ_check(opp, q); return q->next; } @@ -365,7 +363,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) __func__, n_IRQ, dst->raised.next, n_CPU); return; } - IRQ_get_next(opp, &dst->raised); + IRQ_check(opp, &dst->raised); if (IRQ_get_next(opp, &dst->servicing) != -1 && priority <= dst->servicing.priority) { DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", @@ -916,7 +914,6 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, DPRINTF("EOI\n"); s_IRQ = IRQ_get_next(opp, &dst->servicing); IRQ_resetbit(&dst->servicing, s_IRQ); - dst->servicing.next = -1; /* Set up next servicing IRQ */ s_IRQ = IRQ_get_next(opp, &dst->servicing); /* Check queued interrupts. */ @@ -993,7 +990,6 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, retval = IVPR_VECTOR(opp, src->ivpr); } IRQ_resetbit(&dst->raised, n_IRQ); - dst->raised.next = -1; if (!(src->ivpr & IVPR_SENSE_MASK)) { /* edge-sensitive IRQ */ src->ivpr &= ~IVPR_ACTIVITY_MASK; From 47f73749c61765f7a898ac88f11995368740da10 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:47 +0000 Subject: [PATCH 19/31] Revert "openpic: Accelerate pending irq search" This reverts commit a9bd83f4c65de0058659ede009fa1a241f379edd. This counting approach is not robust against setting a bit that was already set, or clearing a bit that was already clear. Perhaps that is considered a bug, but besides the lack of any documentation for that restriction, it's a pretty unpleasant way for the problem to manifest itself. It could be made more robust by testing the current value of the bit before changing the count, but a later patch speeds up IRQ_check in all cases, not just when there's nothing pending. Hopefully that should be adequate to address performance concerns. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 19e6280023..2c238fba4b 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -183,7 +183,6 @@ typedef struct IRQQueue { uint32_t queue[BF_WIDTH(MAX_IRQ)]; int next; int priority; - int pending; /* nr of pending bits in queue */ } IRQQueue; typedef struct IRQSource { @@ -269,13 +268,11 @@ typedef struct OpenPICState { static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) { - q->pending++; set_bit(q->queue, n_IRQ); } static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ) { - q->pending--; reset_bit(q->queue, n_IRQ); } @@ -291,12 +288,6 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q) next = -1; priority = -1; - - if (!q->pending) { - /* IRQ bitmap is empty */ - goto out; - } - for (i = 0; i < opp->max_irq; i++) { if (IRQ_testbit(q, i)) { DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", @@ -307,8 +298,6 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q) } } } - -out: q->next = next; q->priority = priority; } From e69a17f65e9f12f33c48b04a789e49d40a8993f5 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:48 +0000 Subject: [PATCH 20/31] openpic: use standard bitmap operations Besides the private implementation being redundant, namespace collisions prevented the use of other things in bitops.h. Serialization does get a bit more awkward, unfortunately, since the standard bitmap operations are "unsigned long" rather than "uint32_t", though in exchange we will get faster queue lookups on 64-bit hosts once we search a word at a time. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 55 +++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 2c238fba4b..b54308d042 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -39,6 +39,7 @@ #include "openpic.h" #include "sysbus.h" #include "pci/msi.h" +#include "qemu/bitops.h" //#define DEBUG_OPENPIC @@ -147,24 +148,6 @@ static const int debug_openpic = 0; #define MSIIR_IBS_SHIFT 24 #define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT) -#define BF_WIDTH(_bits_) \ -(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8)) - -static inline void set_bit(uint32_t *field, int bit) -{ - field[bit >> 5] |= 1 << (bit & 0x1F); -} - -static inline void reset_bit(uint32_t *field, int bit) -{ - field[bit >> 5] &= ~(1 << (bit & 0x1F)); -} - -static inline int test_bit(uint32_t *field, int bit) -{ - return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0; -} - static int get_current_cpu(void) { if (!cpu_single_env) { @@ -180,7 +163,10 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx); typedef struct IRQQueue { - uint32_t queue[BF_WIDTH(MAX_IRQ)]; + /* Round up to the nearest 64 IRQs so that the queue length + * won't change when moving between 32 and 64 bit hosts. + */ + unsigned long queue[BITS_TO_LONGS((MAX_IRQ + 63) & ~63)]; int next; int priority; } IRQQueue; @@ -268,17 +254,17 @@ typedef struct OpenPICState { static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) { - set_bit(q->queue, n_IRQ); + set_bit(n_IRQ, q->queue); } static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ) { - reset_bit(q->queue, n_IRQ); + clear_bit(n_IRQ, q->queue); } static inline int IRQ_testbit(IRQQueue *q, int n_IRQ) { - return test_bit(q->queue, n_IRQ); + return test_bit(n_IRQ, q->queue); } static void IRQ_check(OpenPICState *opp, IRQQueue *q) @@ -1117,8 +1103,16 @@ static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q) { unsigned int i; - for (i = 0; i < BF_WIDTH(MAX_IRQ); i++) - qemu_put_be32s(f, &q->queue[i]); + for (i = 0; i < ARRAY_SIZE(q->queue); i++) { + /* Always put the lower half of a 64-bit long first, in case we + * restore on a 32-bit host. The least significant bits correspond + * to lower IRQ numbers in the bitmap. + */ + qemu_put_be32(f, (uint32_t)q->queue[i]); +#if LONG_MAX > 0x7FFFFFFF + qemu_put_be32(f, (uint32_t)(q->queue[i] >> 32)); +#endif + } qemu_put_sbe32s(f, &q->next); qemu_put_sbe32s(f, &q->priority); @@ -1160,8 +1154,17 @@ static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q) { unsigned int i; - for (i = 0; i < BF_WIDTH(MAX_IRQ); i++) - qemu_get_be32s(f, &q->queue[i]); + for (i = 0; i < ARRAY_SIZE(q->queue); i++) { + unsigned long val; + + val = qemu_get_be32(f); +#if LONG_MAX > 0x7FFFFFFF + val <<= 32; + val |= qemu_get_be32(f); +#endif + + q->queue[i] = val; + } qemu_get_sbe32s(f, &q->next); qemu_get_sbe32s(f, &q->priority); From 65b9d0d5659687ebb85b1305ac70b3a84df16e5a Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:50 +0000 Subject: [PATCH 21/31] openpic: add some bounds checking for IRQ numbers The two checks with abort() guard against potential QEMU-internal problems, but the EOI check stops the guest from causing updates to queue position -1 and other havoc if it writes EOI with no interrupt in service. Signed-off-by: Scott Wood [agraf: remove hunk in code that didn't get applied yet] Signed-off-by: Alexander Graf --- hw/openpic.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/openpic.c b/hw/openpic.c index b54308d042..35a7fe383b 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -414,6 +414,11 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) OpenPICState *opp = opaque; IRQSource *src; + if (n_IRQ >= MAX_IRQ) { + fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ); + abort(); + } + src = &opp->src[n_IRQ]; DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n", n_IRQ, level, src->ivpr); @@ -888,6 +893,12 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, case 0xB0: /* EOI */ DPRINTF("EOI\n"); s_IRQ = IRQ_get_next(opp, &dst->servicing); + + if (s_IRQ < 0) { + DPRINTF("%s: EOI with no interrupt in service\n", __func__); + break; + } + IRQ_resetbit(&dst->servicing, s_IRQ); /* Set up next servicing IRQ */ s_IRQ = IRQ_get_next(opp, &dst->servicing); From 6c5e84c25fc70717c410150b23c765bedf0af52d Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 3 Jan 2013 13:25:37 +0000 Subject: [PATCH 22/31] openpic: fix sense and priority bits Previously, the sense and priority bits were masked off when writing to IVPR, and all interrupts were treated as edge-triggered (despite the existence of code for handling level-triggered interrupts). Polarity is implemented only as storage. We don't simulate the bad effects that you'd get on real hardware if you set this incorrectly, but at least the guest sees the right thing when it reads back the register. Sense now controls level/edge on FSL external interrupts (and all interrupts on non-FSL MPIC). FSL internal interrupts do not have a sense bit (reads as zero), but are level. FSL timers and IPIs do not have sense or polarity bits (read as zero), and are edge-triggered. To accommodate FSL internal interrupts, QEMU's internal notion of whether an interrupt is level-triggered is separated from the IVPR bit. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 35a7fe383b..66179c22cb 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -162,6 +162,12 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx); +typedef enum IRQType { + IRQ_TYPE_NORMAL = 0, + IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */ + IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */ +} IRQType; + typedef struct IRQQueue { /* Round up to the nearest 64 IRQs so that the queue length * won't change when moving between 32 and 64 bit hosts. @@ -178,6 +184,8 @@ typedef struct IRQSource { int last_cpu; int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */ int pending; /* TRUE if IRQ is pending */ + IRQType type; + bool level:1; /* level-triggered */ bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ } IRQSource; @@ -422,7 +430,7 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) src = &opp->src[n_IRQ]; DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n", n_IRQ, level, src->ivpr); - if (src->ivpr & IVPR_SENSE_MASK) { + if (src->level) { /* level-sensitive irq */ src->pending = level; if (!level) { @@ -455,6 +463,19 @@ static void openpic_reset(DeviceState *d) for (i = 0; i < opp->max_irq; i++) { opp->src[i].ivpr = opp->ivpr_reset; opp->src[i].idr = opp->idr_reset; + + switch (opp->src[i].type) { + case IRQ_TYPE_NORMAL: + opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK); + break; + + case IRQ_TYPE_FSLINT: + opp->src[i].ivpr |= IVPR_POLARITY_MASK; + break; + + case IRQ_TYPE_FSLSPECIAL: + break; + } } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { @@ -530,10 +551,36 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) { - /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ + uint32_t mask; + + /* NOTE when implementing newer FSL MPIC models: starting with v4.0, + * the polarity bit is read-only on internal interrupts. + */ + mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK | + IVPR_POLARITY_MASK | opp->vector_mask; + /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ivpr = (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | - (val & (IVPR_MASK_MASK | IVPR_PRIORITY_MASK | opp->vector_mask)); + opp->src[n_IRQ].ivpr = + (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask); + + /* For FSL internal interrupts, The sense bit is reserved and zero, + * and the interrupt is always level-triggered. Timers and IPIs + * have no sense or polarity bits, and are edge-triggered. + */ + switch (opp->src[n_IRQ].type) { + case IRQ_TYPE_NORMAL: + opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK); + break; + + case IRQ_TYPE_FSLINT: + opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK; + break; + + case IRQ_TYPE_FSLSPECIAL: + opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK); + break; + } + openpic_update_irq(opp, n_IRQ); DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val, opp->src[n_IRQ].ivpr); @@ -976,7 +1023,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, retval = IVPR_VECTOR(opp, src->ivpr); } IRQ_resetbit(&dst->raised, n_IRQ); - if (!(src->ivpr & IVPR_SENSE_MASK)) { + if (!src->level) { /* edge-sensitive IRQ */ src->ivpr &= ~IVPR_ACTIVITY_MASK; src->pending = 0; @@ -984,7 +1031,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, if ((n_IRQ >= opp->irq_ipi0) && (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) { src->idr &= ~(1 << idx); - if (src->idr && !(src->ivpr & IVPR_SENSE_MASK)) { + if (src->idr && !src->level) { /* trigger on CPUs that didn't know about it yet */ openpic_set_irq(opp, n_IRQ, 1); openpic_set_irq(opp, n_IRQ, 0); @@ -1282,7 +1329,25 @@ static int openpic_init(SysBusDevice *dev) opp->brr1 = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN; msi_supported = true; list = list_be; + + for (i = 0; i < FSL_MPIC_20_MAX_EXT; i++) { + opp->src[i].level = false; + } + + /* Internal interrupts, including message and MSI */ + for (i = 16; i < MAX_SRC; i++) { + opp->src[i].type = IRQ_TYPE_FSLINT; + opp->src[i].level = true; + } + + /* timers and IPIs */ + for (i = MAX_SRC; i < MAX_IRQ; i++) { + opp->src[i].type = IRQ_TYPE_FSLSPECIAL; + opp->src[i].level = false; + } + break; + case OPENPIC_MODEL_RAVEN: opp->nb_irqs = RAVEN_MAX_EXT; opp->vid = VID_REVISION_1_3; From 4417c73305f60e46a2370bcaf3635981f5dbc050 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 3 Jan 2013 13:25:38 +0000 Subject: [PATCH 23/31] openpic: IRQ_check: search the queue a word at a time Search the queue more efficiently by first looking for a non-zero word, and then using the common bit-searching function to find the bit within the word. It would be even nicer if bitops_ffsl() could be hooked up to the compiler intrinsic so that bit-searching instructions could be used, but that's another matter. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 66179c22cb..7645d6770e 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -277,21 +277,25 @@ static inline int IRQ_testbit(IRQQueue *q, int n_IRQ) static void IRQ_check(OpenPICState *opp, IRQQueue *q) { - int next, i; - int priority; + int irq = -1; + int next = -1; + int priority = -1; - next = -1; - priority = -1; - for (i = 0; i < opp->max_irq; i++) { - if (IRQ_testbit(q, i)) { - DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", - i, IVPR_PRIORITY(opp->src[i].ivpr), priority); - if (IVPR_PRIORITY(opp->src[i].ivpr) > priority) { - next = i; - priority = IVPR_PRIORITY(opp->src[i].ivpr); - } + for (;;) { + irq = find_next_bit(q->queue, opp->max_irq, irq + 1); + if (irq == opp->max_irq) { + break; + } + + DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", + irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority); + + if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) { + next = irq; + priority = IVPR_PRIORITY(opp->src[irq].ivpr); } } + q->next = next; q->priority = priority; } From a898a8fc96a071189206218b39b5db99531f5c8b Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 3 Jan 2013 13:25:39 +0000 Subject: [PATCH 24/31] openpic: move IACK to its own function Besides making the code cleaner, we will need a separate way to access IACK in order to implement EPR (external proxy) interrupt delivery. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 95 +++++++++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 42 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 7645d6770e..374f80e880 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -975,14 +975,64 @@ static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val, openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12); } + +static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) +{ + IRQSource *src; + int retval, irq; + + DPRINTF("Lower OpenPIC INT output\n"); + qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); + + irq = IRQ_get_next(opp, &dst->raised); + DPRINTF("IACK: irq=%d\n", irq); + + if (irq == -1) { + /* No more interrupt pending */ + return opp->spve; + } + + src = &opp->src[irq]; + if (!(src->ivpr & IVPR_ACTIVITY_MASK) || + !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { + /* - Spurious level-sensitive IRQ + * - Priorities has been changed + * and the pending IRQ isn't allowed anymore + */ + src->ivpr &= ~IVPR_ACTIVITY_MASK; + retval = opp->spve; + } else { + /* IRQ enter servicing state */ + IRQ_setbit(&dst->servicing, irq); + retval = IVPR_VECTOR(opp, src->ivpr); + } + IRQ_resetbit(&dst->raised, irq); + if (!src->level) { + /* edge-sensitive IRQ */ + src->ivpr &= ~IVPR_ACTIVITY_MASK; + src->pending = 0; + } + + if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + MAX_IPI))) { + src->idr &= ~(1 << cpu); + if (src->idr && !src->level) { + /* trigger on CPUs that didn't know about it yet */ + openpic_set_irq(opp, irq, 1); + openpic_set_irq(opp, irq, 0); + /* if all CPUs knew about it, set active bit again */ + src->ivpr |= IVPR_ACTIVITY_MASK; + } + } + + return retval; +} + static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, int idx) { OpenPICState *opp = opaque; - IRQSource *src; IRQDest *dst; uint32_t retval; - int n_IRQ; DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr); retval = 0xFFFFFFFF; @@ -1004,46 +1054,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, retval = idx; break; case 0xA0: /* IACK */ - DPRINTF("Lower OpenPIC INT output\n"); - qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); - n_IRQ = IRQ_get_next(opp, &dst->raised); - DPRINTF("IACK: irq=%d\n", n_IRQ); - if (n_IRQ == -1) { - /* No more interrupt pending */ - retval = opp->spve; - } else { - src = &opp->src[n_IRQ]; - if (!(src->ivpr & IVPR_ACTIVITY_MASK) || - !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { - /* - Spurious level-sensitive IRQ - * - Priorities has been changed - * and the pending IRQ isn't allowed anymore - */ - src->ivpr &= ~IVPR_ACTIVITY_MASK; - retval = opp->spve; - } else { - /* IRQ enter servicing state */ - IRQ_setbit(&dst->servicing, n_IRQ); - retval = IVPR_VECTOR(opp, src->ivpr); - } - IRQ_resetbit(&dst->raised, n_IRQ); - if (!src->level) { - /* edge-sensitive IRQ */ - src->ivpr &= ~IVPR_ACTIVITY_MASK; - src->pending = 0; - } - - if ((n_IRQ >= opp->irq_ipi0) && (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) { - src->idr &= ~(1 << idx); - if (src->idr && !src->level) { - /* trigger on CPUs that didn't know about it yet */ - openpic_set_irq(opp, n_IRQ, 1); - openpic_set_irq(opp, n_IRQ, 0); - /* if all CPUs knew about it, set active bit again */ - src->ivpr |= IVPR_ACTIVITY_MASK; - } - } - } + retval = openpic_iack(opp, dst, idx); break; case 0xB0: /* EOI */ retval = 0; From 9f1d4b1d6939d39fe570d886f6a651f4764bcbcb Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 3 Jan 2013 13:25:40 +0000 Subject: [PATCH 25/31] openpic: fix CTPR and de-assertion of interrupts Properly implement level-triggered interrupts by withdrawing an interrupt from the raised queue if the interrupt source de-asserts. Also withdraw from the raised queue if the interrupt becomes masked. When CTPR is written, check whether we need to raise or lower the interrupt output. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 183 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 124 insertions(+), 59 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 374f80e880..e773d680f4 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -213,6 +213,9 @@ typedef struct IRQDest { IRQQueue raised; IRQQueue servicing; qemu_irq *irqs; + + /* Count of IRQ sources asserting on non-INT outputs */ + uint32_t outputs_active[OPENPIC_OUTPUT_NB]; } IRQDest; typedef struct OpenPICState { @@ -308,7 +311,8 @@ static int IRQ_get_next(OpenPICState *opp, IRQQueue *q) return q->next; } -static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) +static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, + bool active, bool was_active) { IRQDest *dst; IRQSource *src; @@ -317,79 +321,113 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) dst = &opp->dst[n_CPU]; src = &opp->src[n_IRQ]; + DPRINTF("%s: IRQ %d active %d was %d\n", + __func__, n_IRQ, active, was_active); + if (src->output != OPENPIC_OUTPUT_INT) { + DPRINTF("%s: output %d irq %d active %d was %d count %d\n", + __func__, src->output, n_IRQ, active, was_active, + dst->outputs_active[src->output]); + /* On Freescale MPIC, critical interrupts ignore priority, * IACK, EOI, etc. Before MPIC v4.1 they also ignore * masking. */ - src->ivpr |= IVPR_ACTIVITY_MASK; - DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n", - __func__, src->output, n_CPU, n_IRQ); - qemu_irq_raise(opp->dst[n_CPU].irqs[src->output]); + if (active) { + if (!was_active && dst->outputs_active[src->output]++ == 0) { + DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n", + __func__, src->output, n_CPU, n_IRQ); + qemu_irq_raise(dst->irqs[src->output]); + } + } else { + if (was_active && --dst->outputs_active[src->output] == 0) { + DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n", + __func__, src->output, n_CPU, n_IRQ); + qemu_irq_lower(dst->irqs[src->output]); + } + } + return; } priority = IVPR_PRIORITY(src->ivpr); - if (priority <= dst->ctpr) { - /* Too low priority */ - DPRINTF("%s: IRQ %d has too low priority on CPU %d\n", - __func__, n_IRQ, n_CPU); - return; - } - if (IRQ_testbit(&dst->raised, n_IRQ)) { - /* Interrupt miss */ - DPRINTF("%s: IRQ %d was missed on CPU %d\n", - __func__, n_IRQ, n_CPU); - return; - } - src->ivpr |= IVPR_ACTIVITY_MASK; - IRQ_setbit(&dst->raised, n_IRQ); - if (priority < dst->raised.priority) { - /* An higher priority IRQ is already raised */ - DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n", - __func__, n_IRQ, dst->raised.next, n_CPU); - return; + + /* Even if the interrupt doesn't have enough priority, + * it is still raised, in case ctpr is lowered later. + */ + if (active) { + IRQ_setbit(&dst->raised, n_IRQ); + } else { + IRQ_resetbit(&dst->raised, n_IRQ); } + IRQ_check(opp, &dst->raised); - if (IRQ_get_next(opp, &dst->servicing) != -1 && - priority <= dst->servicing.priority) { - DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", - __func__, n_IRQ, dst->servicing.next, n_CPU); - /* Already servicing a higher priority IRQ */ - return; + + if (active && priority <= dst->ctpr) { + DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n", + __func__, n_IRQ, priority, dst->ctpr, n_CPU); + active = 0; + } + + if (active) { + if (IRQ_get_next(opp, &dst->servicing) >= 0 && + priority <= dst->servicing.priority) { + DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", + __func__, n_IRQ, dst->servicing.next, n_CPU); + } else { + DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n", + __func__, n_CPU, n_IRQ, dst->raised.next); + qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); + } + } else { + IRQ_get_next(opp, &dst->servicing); + if (dst->raised.priority > dst->ctpr && + dst->raised.priority > dst->servicing.priority) { + DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n", + __func__, n_IRQ, dst->raised.next, dst->raised.priority, + dst->ctpr, dst->servicing.priority, n_CPU); + /* IRQ line stays asserted */ + } else { + DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n", + __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU); + qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); + } } - DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ); - qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); } /* update pic state because registers for n_IRQ have changed value */ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) { IRQSource *src; + bool active, was_active; int i; src = &opp->src[n_IRQ]; + active = src->pending; - if (!src->pending) { - /* no irq pending */ - DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); - return; - } if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) { /* Interrupt source is disabled */ DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); + active = false; + } + + was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK); + + /* + * We don't have a similar check for already-active because + * ctpr may have changed and we need to withdraw the interrupt. + */ + if (!active && !was_active) { + DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ); return; } - if (IVPR_PRIORITY(src->ivpr) == 0) { - /* Priority set to zero */ - DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ); - return; - } - if (src->ivpr & IVPR_ACTIVITY_MASK) { - /* IRQ already active */ - DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); - return; + + if (active) { + src->ivpr |= IVPR_ACTIVITY_MASK; + } else { + src->ivpr &= ~IVPR_ACTIVITY_MASK; } + if (src->idr == 0) { /* No target */ DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); @@ -398,12 +436,12 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) if (src->idr == (1 << src->last_cpu)) { /* Only one CPU is allowed to receive this IRQ */ - IRQ_local_pipe(opp, src->last_cpu, n_IRQ); + IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active); } else if (!(src->ivpr & IVPR_MODE_MASK)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { if (src->destmask & (1 << i)) { - IRQ_local_pipe(opp, i, n_IRQ); + IRQ_local_pipe(opp, i, n_IRQ, active, was_active); } } } else { @@ -413,7 +451,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) i = 0; } if (src->destmask & (1 << i)) { - IRQ_local_pipe(opp, i, n_IRQ); + IRQ_local_pipe(opp, i, n_IRQ, active, was_active); src->last_cpu = i; break; } @@ -437,16 +475,25 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) if (src->level) { /* level-sensitive irq */ src->pending = level; - if (!level) { - src->ivpr &= ~IVPR_ACTIVITY_MASK; - } + openpic_update_irq(opp, n_IRQ); } else { /* edge-sensitive irq */ if (level) { src->pending = 1; + openpic_update_irq(opp, n_IRQ); + } + + if (src->output != OPENPIC_OUTPUT_INT) { + /* Edge-triggered interrupts shouldn't be used + * with non-INT delivery, but just in case, + * try to make it do something sane rather than + * cause an interrupt storm. This is close to + * what you'd probably see happen in real hardware. + */ + src->pending = 0; + openpic_update_irq(opp, n_IRQ); } } - openpic_update_irq(opp, n_IRQ); } static void openpic_reset(DeviceState *d) @@ -934,6 +981,21 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, break; case 0x80: /* CTPR */ dst->ctpr = val & 0x0000000F; + + DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n", + __func__, idx, dst->ctpr, dst->raised.priority, + dst->servicing.priority); + + if (dst->raised.priority <= dst->ctpr) { + DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n", + __func__, idx); + qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); + } else if (dst->raised.priority > dst->servicing.priority) { + DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n", + __func__, idx, dst->raised.next); + qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); + } + break; case 0x90: /* WHOAMI */ /* Read-only register */ @@ -995,22 +1057,21 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) src = &opp->src[irq]; if (!(src->ivpr & IVPR_ACTIVITY_MASK) || !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { - /* - Spurious level-sensitive IRQ - * - Priorities has been changed - * and the pending IRQ isn't allowed anymore - */ - src->ivpr &= ~IVPR_ACTIVITY_MASK; + fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n", + __func__, irq, dst->ctpr, src->ivpr); + openpic_update_irq(opp, irq); retval = opp->spve; } else { /* IRQ enter servicing state */ IRQ_setbit(&dst->servicing, irq); retval = IVPR_VECTOR(opp, src->ivpr); } - IRQ_resetbit(&dst->raised, irq); + if (!src->level) { /* edge-sensitive IRQ */ src->ivpr &= ~IVPR_ACTIVITY_MASK; src->pending = 0; + IRQ_resetbit(&dst->raised, irq); } if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + MAX_IPI))) { @@ -1208,6 +1269,8 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_sbe32s(f, &opp->dst[i].ctpr); openpic_save_IRQ_queue(f, &opp->dst[i].raised); openpic_save_IRQ_queue(f, &opp->dst[i].servicing); + qemu_put_buffer(f, (uint8_t *)&opp->dst[i].outputs_active, + sizeof(opp->dst[i].outputs_active)); } for (i = 0; i < MAX_TMR; i++) { @@ -1264,6 +1327,8 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_sbe32s(f, &opp->dst[i].ctpr); openpic_load_IRQ_queue(f, &opp->dst[i].raised); openpic_load_IRQ_queue(f, &opp->dst[i].servicing); + qemu_get_buffer(f, (uint8_t *)&opp->dst[i].outputs_active, + sizeof(opp->dst[i].outputs_active)); } for (i = 0; i < MAX_TMR; i++) { From d4834ff9b72d7b89181e88b1a481564cb750c1b5 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 4 Jan 2013 10:04:19 +0100 Subject: [PATCH 26/31] kvm: Update kernel headers Corresponding kvm.git hash: 18eb54cf4a Signed-off-by: Alexander Graf --- linux-headers/asm-powerpc/epapr_hcalls.h | 98 ++++++++++++++++++++++++ linux-headers/asm-powerpc/kvm.h | 86 +++++++++++++++++++++ linux-headers/asm-powerpc/kvm_para.h | 13 ++-- linux-headers/linux/kvm.h | 21 +++-- linux-headers/linux/kvm_para.h | 6 +- linux-headers/linux/vfio.h | 6 +- linux-headers/linux/virtio_config.h | 6 +- linux-headers/linux/virtio_ring.h | 6 +- 8 files changed, 219 insertions(+), 23 deletions(-) create mode 100644 linux-headers/asm-powerpc/epapr_hcalls.h diff --git a/linux-headers/asm-powerpc/epapr_hcalls.h b/linux-headers/asm-powerpc/epapr_hcalls.h new file mode 100644 index 0000000000..06f724786a --- /dev/null +++ b/linux-headers/asm-powerpc/epapr_hcalls.h @@ -0,0 +1,98 @@ +/* + * ePAPR hcall interface + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Author: Timur Tabi + * + * This file is provided under a dual BSD/GPL license. When using or + * redistributing this file, you may do so under either license. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_POWERPC_EPAPR_HCALLS_H +#define _ASM_POWERPC_EPAPR_HCALLS_H + +#define EV_BYTE_CHANNEL_SEND 1 +#define EV_BYTE_CHANNEL_RECEIVE 2 +#define EV_BYTE_CHANNEL_POLL 3 +#define EV_INT_SET_CONFIG 4 +#define EV_INT_GET_CONFIG 5 +#define EV_INT_SET_MASK 6 +#define EV_INT_GET_MASK 7 +#define EV_INT_IACK 9 +#define EV_INT_EOI 10 +#define EV_INT_SEND_IPI 11 +#define EV_INT_SET_TASK_PRIORITY 12 +#define EV_INT_GET_TASK_PRIORITY 13 +#define EV_DOORBELL_SEND 14 +#define EV_MSGSND 15 +#define EV_IDLE 16 + +/* vendor ID: epapr */ +#define EV_LOCAL_VENDOR_ID 0 /* for private use */ +#define EV_EPAPR_VENDOR_ID 1 +#define EV_FSL_VENDOR_ID 2 /* Freescale Semiconductor */ +#define EV_IBM_VENDOR_ID 3 /* IBM */ +#define EV_GHS_VENDOR_ID 4 /* Green Hills Software */ +#define EV_ENEA_VENDOR_ID 5 /* Enea */ +#define EV_WR_VENDOR_ID 6 /* Wind River Systems */ +#define EV_AMCC_VENDOR_ID 7 /* Applied Micro Circuits */ +#define EV_KVM_VENDOR_ID 42 /* KVM */ + +/* The max number of bytes that a byte channel can send or receive per call */ +#define EV_BYTE_CHANNEL_MAX_BYTES 16 + + +#define _EV_HCALL_TOKEN(id, num) (((id) << 16) | (num)) +#define EV_HCALL_TOKEN(hcall_num) _EV_HCALL_TOKEN(EV_EPAPR_VENDOR_ID, hcall_num) + +/* epapr return codes */ +#define EV_SUCCESS 0 +#define EV_EPERM 1 /* Operation not permitted */ +#define EV_ENOENT 2 /* Entry Not Found */ +#define EV_EIO 3 /* I/O error occured */ +#define EV_EAGAIN 4 /* The operation had insufficient + * resources to complete and should be + * retried + */ +#define EV_ENOMEM 5 /* There was insufficient memory to + * complete the operation */ +#define EV_EFAULT 6 /* Bad guest address */ +#define EV_ENODEV 7 /* No such device */ +#define EV_EINVAL 8 /* An argument supplied to the hcall + was out of range or invalid */ +#define EV_INTERNAL 9 /* An internal error occured */ +#define EV_CONFIG 10 /* A configuration error was detected */ +#define EV_INVALID_STATE 11 /* The object is in an invalid state */ +#define EV_UNIMPLEMENTED 12 /* Unimplemented hypercall */ +#define EV_BUFFER_OVERFLOW 13 /* Caller-supplied buffer too small */ + +#endif /* _ASM_POWERPC_EPAPR_HCALLS_H */ diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 1bea4d8ea6..2fba8a66fb 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -221,6 +221,12 @@ struct kvm_sregs { __u32 dbsr; /* KVM_SREGS_E_UPDATE_DBSR */ __u32 dbcr[3]; + /* + * iac/dac registers are 64bit wide, while this API + * interface provides only lower 32 bits on 64 bit + * processors. ONE_REG interface is added for 64bit + * iac/dac registers. + */ __u32 iac[4]; __u32 dac[2]; __u32 dvc[2]; @@ -325,6 +331,86 @@ struct kvm_book3e_206_tlb_params { __u32 reserved[8]; }; +/* For KVM_PPC_GET_HTAB_FD */ +struct kvm_get_htab_fd { + __u64 flags; + __u64 start_index; + __u64 reserved[2]; +}; + +/* Values for kvm_get_htab_fd.flags */ +#define KVM_GET_HTAB_BOLTED_ONLY ((__u64)0x1) +#define KVM_GET_HTAB_WRITE ((__u64)0x2) + +/* + * Data read on the file descriptor is formatted as a series of + * records, each consisting of a header followed by a series of + * `n_valid' HPTEs (16 bytes each), which are all valid. Following + * those valid HPTEs there are `n_invalid' invalid HPTEs, which + * are not represented explicitly in the stream. The same format + * is used for writing. + */ +struct kvm_get_htab_header { + __u32 index; + __u16 n_valid; + __u16 n_invalid; +}; + #define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1) +#define KVM_REG_PPC_IAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2) +#define KVM_REG_PPC_IAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3) +#define KVM_REG_PPC_IAC3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x4) +#define KVM_REG_PPC_IAC4 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x5) +#define KVM_REG_PPC_DAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x6) +#define KVM_REG_PPC_DAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x7) +#define KVM_REG_PPC_DABR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8) +#define KVM_REG_PPC_DSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9) +#define KVM_REG_PPC_PURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa) +#define KVM_REG_PPC_SPURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb) +#define KVM_REG_PPC_DAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc) +#define KVM_REG_PPC_DSISR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd) +#define KVM_REG_PPC_AMR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xe) +#define KVM_REG_PPC_UAMOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xf) + +#define KVM_REG_PPC_MMCR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x10) +#define KVM_REG_PPC_MMCR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x11) +#define KVM_REG_PPC_MMCRA (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x12) + +#define KVM_REG_PPC_PMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x18) +#define KVM_REG_PPC_PMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x19) +#define KVM_REG_PPC_PMC3 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1a) +#define KVM_REG_PPC_PMC4 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1b) +#define KVM_REG_PPC_PMC5 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1c) +#define KVM_REG_PPC_PMC6 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1d) +#define KVM_REG_PPC_PMC7 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1e) +#define KVM_REG_PPC_PMC8 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1f) + +/* 32 floating-point registers */ +#define KVM_REG_PPC_FPR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x20) +#define KVM_REG_PPC_FPR(n) (KVM_REG_PPC_FPR0 + (n)) +#define KVM_REG_PPC_FPR31 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3f) + +/* 32 VMX/Altivec vector registers */ +#define KVM_REG_PPC_VR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x40) +#define KVM_REG_PPC_VR(n) (KVM_REG_PPC_VR0 + (n)) +#define KVM_REG_PPC_VR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x5f) + +/* 32 double-width FP registers for VSX */ +/* High-order halves overlap with FP regs */ +#define KVM_REG_PPC_VSR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x60) +#define KVM_REG_PPC_VSR(n) (KVM_REG_PPC_VSR0 + (n)) +#define KVM_REG_PPC_VSR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x7f) + +/* FP and vector status/control registers */ +#define KVM_REG_PPC_FPSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x80) +#define KVM_REG_PPC_VSCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x81) + +/* Virtual processor areas */ +/* For SLB & DTL, address in high (first) half, length in low half */ +#define KVM_REG_PPC_VPA_ADDR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x82) +#define KVM_REG_PPC_VPA_SLB (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x83) +#define KVM_REG_PPC_VPA_DTL (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x84) + +#define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85) #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/linux-headers/asm-powerpc/kvm_para.h b/linux-headers/asm-powerpc/kvm_para.h index 5e04383a1d..7e64f575f6 100644 --- a/linux-headers/asm-powerpc/kvm_para.h +++ b/linux-headers/asm-powerpc/kvm_para.h @@ -17,8 +17,8 @@ * Authors: Hollis Blanchard */ -#ifndef _UAPI__POWERPC_KVM_PARA_H__ -#define _UAPI__POWERPC_KVM_PARA_H__ +#ifndef __POWERPC_KVM_PARA_H__ +#define __POWERPC_KVM_PARA_H__ #include @@ -75,9 +75,10 @@ struct kvm_vcpu_arch_shared { }; #define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */ -#define HC_VENDOR_KVM (42 << 16) -#define HC_EV_SUCCESS 0 -#define HC_EV_UNIMPLEMENTED 12 + +#define KVM_HCALL_TOKEN(num) _EV_HCALL_TOKEN(EV_KVM_VENDOR_ID, num) + +#include #define KVM_FEATURE_MAGIC_PAGE 1 @@ -87,4 +88,4 @@ struct kvm_vcpu_arch_shared { #define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1) -#endif /* _UAPI__POWERPC_KVM_PARA_H__ */ +#endif /* __POWERPC_KVM_PARA_H__ */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 81d2feb7ab..bfdbf4d1ad 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -167,10 +167,15 @@ struct kvm_pit_config { #define KVM_EXIT_OSI 18 #define KVM_EXIT_PAPR_HCALL 19 #define KVM_EXIT_S390_UCONTROL 20 +#define KVM_EXIT_WATCHDOG 21 /* For KVM_EXIT_INTERNAL_ERROR */ -#define KVM_INTERNAL_ERROR_EMULATION 1 -#define KVM_INTERNAL_ERROR_SIMUL_EX 2 +/* Emulate instruction failed. */ +#define KVM_INTERNAL_ERROR_EMULATION 1 +/* Encounter unexpected simultaneous exceptions. */ +#define KVM_INTERNAL_ERROR_SIMUL_EX 2 +/* Encounter unexpected vm-exit due to delivery event. */ +#define KVM_INTERNAL_ERROR_DELIVERY_EV 3 /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ struct kvm_run { @@ -477,6 +482,8 @@ struct kvm_ppc_smmu_info { struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ]; }; +#define KVM_PPC_PVINFO_FLAGS_EV_IDLE (1<<0) + #define KVMIO 0xAE /* machine type bits, to be used as argument to KVM_CREATE_VM */ @@ -626,6 +633,8 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_READONLY_MEM 81 #endif #define KVM_CAP_IRQFD_RESAMPLE 82 +#define KVM_CAP_PPC_BOOKE_WATCHDOG 83 +#define KVM_CAP_PPC_HTAB_FD 84 #ifdef KVM_CAP_IRQ_ROUTING @@ -848,6 +857,11 @@ struct kvm_s390_ucas_mapping { #define KVM_PPC_GET_SMMU_INFO _IOR(KVMIO, 0xa6, struct kvm_ppc_smmu_info) /* Available with KVM_CAP_PPC_ALLOC_HTAB */ #define KVM_PPC_ALLOCATE_HTAB _IOWR(KVMIO, 0xa7, __u32) +#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce) +/* Available with KVM_CAP_RMA */ +#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma) +/* Available with KVM_CAP_PPC_HTAB_FD */ +#define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd) /* * ioctls for vcpu fds @@ -911,9 +925,6 @@ struct kvm_s390_ucas_mapping { /* Available with KVM_CAP_XCRS */ #define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs) #define KVM_SET_XCRS _IOW(KVMIO, 0xa7, struct kvm_xcrs) -#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce) -/* Available with KVM_CAP_RMA */ -#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma) /* Available with KVM_CAP_SW_TLB */ #define KVM_DIRTY_TLB _IOW(KVMIO, 0xaa, struct kvm_dirty_tlb) /* Available with KVM_CAP_ONE_REG */ diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h index cea2c5c72d..7bdcf93c1d 100644 --- a/linux-headers/linux/kvm_para.h +++ b/linux-headers/linux/kvm_para.h @@ -1,5 +1,5 @@ -#ifndef _UAPI__LINUX_KVM_PARA_H -#define _UAPI__LINUX_KVM_PARA_H +#ifndef __LINUX_KVM_PARA_H +#define __LINUX_KVM_PARA_H /* * This header file provides a method for making a hypercall to the host @@ -25,4 +25,4 @@ */ #include -#endif /* _UAPI__LINUX_KVM_PARA_H */ +#endif /* __LINUX_KVM_PARA_H */ diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index 4758d1bfcf..f787b727a9 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -8,8 +8,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef _UAPIVFIO_H -#define _UAPIVFIO_H +#ifndef VFIO_H +#define VFIO_H #include #include @@ -365,4 +365,4 @@ struct vfio_iommu_type1_dma_unmap { #define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14) -#endif /* _UAPIVFIO_H */ +#endif /* VFIO_H */ diff --git a/linux-headers/linux/virtio_config.h b/linux-headers/linux/virtio_config.h index b7cda390fd..4f51d8f3af 100644 --- a/linux-headers/linux/virtio_config.h +++ b/linux-headers/linux/virtio_config.h @@ -1,5 +1,5 @@ -#ifndef _UAPI_LINUX_VIRTIO_CONFIG_H -#define _UAPI_LINUX_VIRTIO_CONFIG_H +#ifndef _LINUX_VIRTIO_CONFIG_H +#define _LINUX_VIRTIO_CONFIG_H /* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so * anyone can use the definitions to implement compatible drivers/servers. * @@ -51,4 +51,4 @@ * suppressed them? */ #define VIRTIO_F_NOTIFY_ON_EMPTY 24 -#endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */ +#endif /* _LINUX_VIRTIO_CONFIG_H */ diff --git a/linux-headers/linux/virtio_ring.h b/linux-headers/linux/virtio_ring.h index 921694a084..1b333e2536 100644 --- a/linux-headers/linux/virtio_ring.h +++ b/linux-headers/linux/virtio_ring.h @@ -1,5 +1,5 @@ -#ifndef _UAPI_LINUX_VIRTIO_RING_H -#define _UAPI_LINUX_VIRTIO_RING_H +#ifndef _LINUX_VIRTIO_RING_H +#define _LINUX_VIRTIO_RING_H /* An interface for efficient virtio implementation, currently for use by KVM * and lguest, but hopefully others soon. Do NOT change this since it will * break existing servers and clients. @@ -160,4 +160,4 @@ static __inline__ int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old); } -#endif /* _UAPI_LINUX_VIRTIO_RING_H */ +#endif /* _LINUX_VIRTIO_RING_H */ From 1a61a9ae61cdf7b7d24c3eb711fe772c196c235e Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Thu, 3 Jan 2013 12:37:02 +0000 Subject: [PATCH 27/31] PPC: KVM: set has-idle in guest device tree On e500mc, the platform doesn't provide a way for the CPU to go idle. To still not uselessly burn CPU time, expose an idle hypercall to the guest if kvm supports it. Signed-off-by: Stuart Yoder [agraf: adjust for current code base, add patch description, fix non-kvm case] Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 4 ++++ target-ppc/kvm.c | 38 +++++++++++++++++++++++++++++--------- target-ppc/kvm_ppc.h | 6 ++++++ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index b262f31e5a..5d70618f72 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -225,6 +225,10 @@ static int ppce500_load_device_tree(CPUPPCState *env, kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions", hypercall, sizeof(hypercall)); + /* if KVM supports the idle hcall, set property indicating this */ + if (kvmppc_get_hasidle(env)) { + qemu_devtree_setprop(fdt, "/hypervisor", "has-idle", NULL, 0); + } } /* Create CPU nodes */ diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 436ca474ff..9fe949fbec 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -989,18 +989,38 @@ uint32_t kvmppc_get_dfp(void) return kvmppc_read_int_cpu_dt("ibm,dfp"); } -int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - CPUState *cs = CPU(cpu); - uint32_t *hc = (uint32_t*)buf; - - struct kvm_ppc_pvinfo pvinfo; +static int kvmppc_get_pvinfo(CPUPPCState *env, struct kvm_ppc_pvinfo *pvinfo) + { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + CPUState *cs = CPU(cpu); if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO) && - !kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, &pvinfo)) { - memcpy(buf, pvinfo.hcall, buf_len); + !kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, pvinfo)) { + return 0; + } + return 1; +} + +int kvmppc_get_hasidle(CPUPPCState *env) +{ + struct kvm_ppc_pvinfo pvinfo; + + if (!kvmppc_get_pvinfo(env, &pvinfo) && + (pvinfo.flags & KVM_PPC_PVINFO_FLAGS_EV_IDLE)) { + return 1; + } + + return 0; +} + +int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) +{ + uint32_t *hc = (uint32_t*)buf; + struct kvm_ppc_pvinfo pvinfo; + + if (!kvmppc_get_pvinfo(env, &pvinfo)) { + memcpy(buf, pvinfo.hcall, buf_len); return 0; } diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 31eb9e6f22..9b0d500b50 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -19,6 +19,7 @@ uint32_t kvmppc_get_tbfreq(void); uint64_t kvmppc_get_clockfreq(void); uint32_t kvmppc_get_vmx(void); uint32_t kvmppc_get_dfp(void); +int kvmppc_get_hasidle(CPUPPCState *env); int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level); void kvmppc_set_papr(PowerPCCPU *cpu); @@ -55,6 +56,11 @@ static inline uint32_t kvmppc_get_dfp(void) return 0; } +static inline int kvmppc_get_hasidle(CPUPPCState *env) +{ + return 0; +} + static inline int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) { return -1; From 68c2dd70068fe82a1989d0d5b70a1ab400bde19a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 4 Jan 2013 11:21:04 +0100 Subject: [PATCH 28/31] PPC: Bring EPR support closer to reality We already used to support the external proxy facility of FSL MPICs, but only implemented it halfway correctly. This patch adds support for * dynamic enablement of the EPR facility * interrupt acknowledgement only when the interrupt is delivered This way the implementation now is closer to real hardware. Signed-off-by: Alexander Graf --- hw/openpic.c | 21 +++++++++++++++++++++ hw/ppc/e500.c | 4 ++-- target-ppc/Makefile.objs | 1 - target-ppc/cpu.h | 4 +++- target-ppc/excp_helper.c | 4 ++++ target-ppc/helper.h | 1 - target-ppc/mpic_helper.c | 35 ----------------------------------- target-ppc/translate_init.c | 7 +------ 8 files changed, 31 insertions(+), 46 deletions(-) delete mode 100644 target-ppc/mpic_helper.c diff --git a/hw/openpic.c b/hw/openpic.c index e773d680f4..3b20a39ab5 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -131,6 +131,9 @@ static const int debug_openpic = 0; #define VIR_GENERIC 0x00000000 /* Generic Vendor ID */ #define GCR_RESET 0x80000000 +#define GCR_MODE_PASS 0x00000000 +#define GCR_MODE_MIXED 0x20000000 +#define GCR_MODE_PROXY 0x60000000 #define TBCR_CI 0x80000000 /* count inhibit */ #define TCCR_TOG 0x80000000 /* toggles when decrement to zero */ @@ -233,6 +236,7 @@ typedef struct OpenPICState { uint32_t ivpr_reset; uint32_t idr_reset; uint32_t brr1; + uint32_t mpic_mode_mask; /* Sub-regions */ MemoryRegion sub_io_mem[5]; @@ -667,6 +671,20 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, case 0x1020: /* GCR */ if (val & GCR_RESET) { openpic_reset(&opp->busdev.qdev); + } else if (opp->mpic_mode_mask) { + CPUArchState *env; + int mpic_proxy = 0; + + opp->gcr &= ~opp->mpic_mode_mask; + opp->gcr |= val & opp->mpic_mode_mask; + + /* Set external proxy mode */ + if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { + mpic_proxy = 1; + } + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->mpic_proxy = mpic_proxy; + } } break; case 0x1080: /* VIR */ @@ -1407,6 +1425,9 @@ static int openpic_init(SysBusDevice *dev) opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ; opp->irq_msi = FSL_MPIC_20_MSI_IRQ; opp->brr1 = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN; + /* XXX really only available as of MPIC 4.0 */ + opp->mpic_mode_mask = GCR_MODE_PROXY; + msi_supported = true; list = list_be; diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 5d70618f72..3a9e1c7b43 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -497,8 +497,8 @@ void ppce500_init(PPCE500Params *params) irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; env->spr[SPR_BOOKE_PIR] = env->cpu_index = i; - env->mpic_cpu_base = MPC8544_CCSRBAR_BASE + - MPC8544_MPIC_REGS_OFFSET + 0x20000; + env->mpic_iack = MPC8544_CCSRBAR_BASE + + MPC8544_MPIC_REGS_OFFSET + 0x200A0; ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 237a0ed4f7..6c11ef84b7 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -9,4 +9,3 @@ obj-y += mmu_helper.o obj-y += timebase_helper.o obj-y += misc_helper.o obj-y += mem_helper.o -obj-y += mpic_helper.o diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e88ebe00d4..dc5145bf39 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1067,7 +1067,9 @@ struct CPUPPCState { target_ulong ivor_mask; target_ulong ivpr_mask; target_ulong hreset_vector; - hwaddr mpic_cpu_base; + hwaddr mpic_iack; + /* true when the external proxy facility mode is enabled */ + bool mpic_proxy; #endif /* Those resources are used only during code translation */ diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 41037a7e26..0a1ac86a42 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -178,6 +178,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) if (lpes0 == 1) { new_msr |= (target_ulong)MSR_HVB; } + if (env->mpic_proxy) { + /* IACK the IRQ on delivery */ + env->spr[SPR_BOOKE_EPR] = ldl_phys(env->mpic_iack); + } goto store_next; case POWERPC_EXCP_ALIGN: /* Alignment exception */ if (lpes1 == 0) { diff --git a/target-ppc/helper.h b/target-ppc/helper.h index d2e9a55f28..83139d5225 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -405,7 +405,6 @@ DEF_HELPER_2(store_40x_dbcr0, void, env, tl) DEF_HELPER_2(store_40x_sler, void, env, tl) DEF_HELPER_2(store_booke_tcr, void, env, tl) DEF_HELPER_2(store_booke_tsr, void, env, tl) -DEF_HELPER_1(load_epr, tl, env) DEF_HELPER_3(store_ibatl, void, env, i32, tl) DEF_HELPER_3(store_ibatu, void, env, i32, tl) DEF_HELPER_3(store_dbatl, void, env, i32, tl) diff --git a/target-ppc/mpic_helper.c b/target-ppc/mpic_helper.c deleted file mode 100644 index 2c6a4d30a9..0000000000 --- a/target-ppc/mpic_helper.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * PowerPC emulation helpers for QEMU. - * - * Copyright (c) 2003-2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ -#include "cpu.h" -#include "helper.h" - -/*****************************************************************************/ -/* SPR accesses */ - -#if !defined(CONFIG_USER_ONLY) -/* - * This is an ugly helper for EPR, which is basically the same as accessing - * the IACK (PIAC) register on the MPIC. Because we model the MPIC as a device - * that can only talk to the CPU through MMIO, let's access it that way! - */ -target_ulong helper_load_epr(CPUPPCState *env) -{ - return ldl_phys(env->mpic_cpu_base + 0xA0); -} -#endif diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 42ed748b59..e2eeb87650 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4493,11 +4493,6 @@ static void spr_read_mas73(void *opaque, int gprn, int sprn) tcg_temp_free(mas7); } -static void spr_load_epr(void *opaque, int gprn, int sprn) -{ - gen_helper_load_epr(cpu_gpr[gprn], cpu_env); -} - #endif enum fsl_e500_version { @@ -4656,7 +4651,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) 0x00000000); spr_register(env, SPR_BOOKE_EPR, "EPR", SPR_NOACCESS, SPR_NOACCESS, - &spr_load_epr, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX better abstract into Emb.xxx features */ if (version == fsl_e5500) { From 2985b86b5c9c068af203bd912309af033112039a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 6 Jan 2013 08:31:30 +0000 Subject: [PATCH 29/31] target-ppc: Slim conversion of model definitions to QOM subclasses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the model list is highly macrofied, keep ppc_def_t for now and save a pointer to it in PowerPCCPUClass. This results in a flat list of subclasses including aliases, to be refined later. Move cpu_ppc_init() to translate_init.c and drop helper.c. Long-term the idea is to turn translate_init.c into a standalone cpu.c. Inline cpu_ppc_usable() into type registration. Split cpu_ppc_register() in two by code movement into the initfn and by turning the remaining part into a realizefn. Move qemu_init_vcpu() call into the new realizefn and adapt create_ppc_opcodes() to return an Error. Change ppc_find_by_pvr() -> ppc_cpu_class_by_pvr(). Change ppc_find_by_name() -> ppc_cpu_class_by_name(). Turn -cpu host into its own subclass. This requires to move the kvm_enabled() check in ppc_cpu_class_by_name() to avoid the class being found via the normal name lookup in the !kvm_enabled() case. Turn kvmppc_host_cpu_def() into the class_init and add an initfn that asserts KVM is in fact enabled. Implement -cpu ? and the QMP equivalent in terms of subclasses. This newly exposes -cpu host to the user, ordered last for -cpu ?. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 3 +- target-ppc/cpu-qom.h | 5 + target-ppc/cpu.h | 4 - target-ppc/helper.c | 50 ----- target-ppc/kvm.c | 37 +++- target-ppc/kvm_ppc.h | 8 +- target-ppc/translate_init.c | 353 ++++++++++++++++++++++++------------ 7 files changed, 280 insertions(+), 180 deletions(-) delete mode 100644 target-ppc/helper.c diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 6c11ef84b7..a028dcdcd0 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -1,7 +1,6 @@ -obj-y += translate.o helper.o +obj-y += translate.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o -obj-y += helper.o obj-y += excp_helper.o obj-y += fpu_helper.o obj-y += int_helper.o diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index fb6b5a4119..b338f8fb56 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -50,6 +50,9 @@ typedef struct PowerPCCPUClass { /*< public >*/ void (*parent_reset)(CPUState *cpu); + + /* TODO inline fields here */ + ppc_def_t *info; } PowerPCCPUClass; /** @@ -73,5 +76,7 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env) #define ENV_GET_CPU(e) CPU(ppc_env_get_cpu(e)) +PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr); + #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index dc5145bf39..953146eeba 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1158,10 +1158,6 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value); void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); -const ppc_def_t *ppc_find_by_pvr(uint32_t pvr); -const ppc_def_t *cpu_ppc_find_by_name (const char *name); -int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def); - /* Time-base and decrementer management */ #ifndef NO_CPU_IO_DEFS uint64_t cpu_ppc_load_tbl (CPUPPCState *env); diff --git a/target-ppc/helper.c b/target-ppc/helper.c deleted file mode 100644 index 103855afe0..0000000000 --- a/target-ppc/helper.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * PowerPC emulation helpers for QEMU. - * - * Copyright (c) 2003-2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "cpu.h" -#include "helper_regs.h" -#include "sysemu/kvm.h" -#include "kvm_ppc.h" -#include "sysemu/cpus.h" - -PowerPCCPU *cpu_ppc_init(const char *cpu_model) -{ - PowerPCCPU *cpu; - CPUPPCState *env; - const ppc_def_t *def; - - def = cpu_ppc_find_by_name(cpu_model); - if (!def) { - return NULL; - } - - cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU)); - env = &cpu->env; - - if (tcg_enabled()) { - ppc_translate_init(); - } - - env->cpu_model_str = cpu_model; - cpu_ppc_register_internal(env, def); - - qemu_init_vcpu(env); - - return cpu; -} diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 9fe949fbec..ce7d69b403 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -1230,18 +1230,29 @@ static void alter_insns(uint64_t *word, uint64_t flags, bool on) } } -const ppc_def_t *kvmppc_host_cpu_def(void) +static void kvmppc_host_cpu_initfn(Object *obj) { + assert(kvm_enabled()); +} + +static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); uint32_t host_pvr = mfpvr(); - const ppc_def_t *base_spec; + PowerPCCPUClass *pvr_pcc; ppc_def_t *spec; uint32_t vmx = kvmppc_get_vmx(); uint32_t dfp = kvmppc_get_dfp(); - base_spec = ppc_find_by_pvr(host_pvr); - spec = g_malloc0(sizeof(*spec)); - memcpy(spec, base_spec, sizeof(*spec)); + + pvr_pcc = ppc_cpu_class_by_pvr(host_pvr); + if (pvr_pcc != NULL) { + memcpy(spec, pvr_pcc->info, sizeof(*spec)); + } + pcc->info = spec; + /* Override the display name for -cpu ? and QMP */ + pcc->info->name = "host"; /* Now fix up the spec with information we can query from the host */ @@ -1254,8 +1265,6 @@ const ppc_def_t *kvmppc_host_cpu_def(void) /* Only override when we know what the host supports */ alter_insns(&spec->insns_flags2, PPC2_DFP, dfp); } - - return spec; } int kvmppc_fixup_cpu(CPUPPCState *env) @@ -1285,3 +1294,17 @@ int kvm_arch_on_sigbus(int code, void *addr) { return 1; } + +static const TypeInfo kvm_host_cpu_type_info = { + .name = TYPE_HOST_POWERPC_CPU, + .parent = TYPE_POWERPC_CPU, + .instance_init = kvmppc_host_cpu_initfn, + .class_init = kvmppc_host_cpu_class_init, +}; + +static void kvm_ppc_register_types(void) +{ + type_register_static(&kvm_host_cpu_type_info); +} + +type_init(kvm_ppc_register_types) diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 9b0d500b50..4b2172360a 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -11,6 +11,8 @@ #include "exec/memory.h" +#define TYPE_HOST_POWERPC_CPU "host-" TYPE_POWERPC_CPU + void kvmppc_init(void); #ifdef CONFIG_KVM @@ -31,7 +33,6 @@ int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); int kvmppc_reset_htab(int shift_hint); uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); #endif /* !CONFIG_USER_ONLY */ -const ppc_def_t *kvmppc_host_cpu_def(void); int kvmppc_fixup_cpu(CPUPPCState *env); #else @@ -121,11 +122,6 @@ static inline int kvmppc_update_sdr1(CPUPPCState *env) #endif /* !CONFIG_USER_ONLY */ -static inline const ppc_def_t *kvmppc_host_cpu_def(void) -{ - return NULL; -} - static inline int kvmppc_fixup_cpu(CPUPPCState *env) { return -1; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index e2eeb87650..2b03756ee1 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9792,8 +9792,11 @@ static void fix_opcode_tables (opc_handler_t **ppc_opcodes) } /*****************************************************************************/ -static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def) +static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp) { + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env = &cpu->env; + const ppc_def_t *def = pcc->info; opcode_t *opc; fill_new_table(env->opcodes, 0x40); @@ -9801,18 +9804,16 @@ static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def) if (((opc->handler.type & def->insns_flags) != 0) || ((opc->handler.type2 & def->insns_flags2) != 0)) { if (register_insn(env->opcodes, opc) < 0) { - printf("*** ERROR initializing PowerPC instruction " - "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, - opc->opc3); - return -1; + error_setg(errp, "ERROR initializing PowerPC instruction " + "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, + opc->opc3); + return; } } } fix_opcode_tables(env->opcodes); fflush(stdout); fflush(stderr); - - return 0; } #if defined(PPC_DUMP_CPU) @@ -10026,53 +10027,31 @@ static int ppc_fixup_cpu(CPUPPCState *env) return 0; } -int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) +static void ppc_cpu_realize(Object *obj, Error **errp) { - env->msr_mask = def->msr_mask; - env->mmu_model = def->mmu_model; - env->excp_model = def->excp_model; - env->bus_model = def->bus_model; - env->insns_flags = def->insns_flags; - env->insns_flags2 = def->insns_flags2; - env->flags = def->flags; - env->bfd_mach = def->bfd_mach; - env->check_pow = def->check_pow; - -#if defined(TARGET_PPC64) - if (def->sps) - env->sps = *def->sps; - else if (env->mmu_model & POWERPC_MMU_64) { - /* Use default sets of page sizes */ - static const struct ppc_segment_page_sizes defsps = { - .sps = { - { .page_shift = 12, /* 4K */ - .slb_enc = 0, - .enc = { { .page_shift = 12, .pte_enc = 0 } } - }, - { .page_shift = 24, /* 16M */ - .slb_enc = 0x100, - .enc = { { .page_shift = 24, .pte_enc = 0 } } - }, - }, - }; - env->sps = defsps; - } -#endif /* defined(TARGET_PPC64) */ + PowerPCCPU *cpu = POWERPC_CPU(obj); + CPUPPCState *env = &cpu->env; + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + ppc_def_t *def = pcc->info; + Error *local_err = NULL; if (kvm_enabled()) { if (kvmppc_fixup_cpu(env) != 0) { - fprintf(stderr, "Unable to virtualize selected CPU with KVM\n"); - exit(1); + error_setg(errp, "Unable to virtualize selected CPU with KVM"); + return; } } else { if (ppc_fixup_cpu(env) != 0) { - fprintf(stderr, "Unable to emulate selected CPU with TCG\n"); - exit(1); + error_setg(errp, "Unable to emulate selected CPU with TCG"); + return; } } - if (create_ppc_opcodes(env, def) < 0) - return -1; + create_ppc_opcodes(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } init_ppc_proc(env, def); if (def->insns_flags & PPC_FLOAT) { @@ -10088,6 +10067,8 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) 34, "power-spe.xml", 0); } + qemu_init_vcpu(env); + #if defined(PPC_DUMP_CPU) { const char *mmu_model, *excp_model, *bus_model; @@ -10249,50 +10230,65 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) dump_ppc_sprs(env); fflush(stdout); #endif - - return 0; } -static bool ppc_cpu_usable(const ppc_def_t *def) +static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b) { -#if defined(TARGET_PPCEMB) - /* When using the ppcemb target, we only support 440 style cores */ - if (def->mmu_model != POWERPC_MMU_BOOKE) { - return false; - } -#endif + ObjectClass *oc = (ObjectClass *)a; + uint32_t pvr = *(uint32_t *)b; + PowerPCCPUClass *pcc = (PowerPCCPUClass *)a; - return true; + /* -cpu host does a PVR lookup during construction */ + if (unlikely(strcmp(object_class_get_name(oc), + TYPE_HOST_POWERPC_CPU) == 0)) { + return -1; + } + + return pcc->info->pvr == pvr ? 0 : -1; } -const ppc_def_t *ppc_find_by_pvr(uint32_t pvr) +PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr) { - int i; + GSList *list, *item; + PowerPCCPUClass *pcc = NULL; - for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; - } - - /* If we have an exact match, we're done */ - if (pvr == ppc_defs[i].pvr) { - return &ppc_defs[i]; - } + list = object_class_get_list(TYPE_POWERPC_CPU, false); + item = g_slist_find_custom(list, &pvr, ppc_cpu_compare_class_pvr); + if (item != NULL) { + pcc = POWERPC_CPU_CLASS(item->data); } + g_slist_free(list); - return NULL; + return pcc; +} + +static gint ppc_cpu_compare_class_name(gconstpointer a, gconstpointer b) +{ + ObjectClass *oc = (ObjectClass *)a; + const char *name = b; + + if (strncasecmp(name, object_class_get_name(oc), strlen(name)) == 0 && + strcmp(object_class_get_name(oc) + strlen(name), + "-" TYPE_POWERPC_CPU) == 0) { + return 0; + } + return -1; } #include -const ppc_def_t *cpu_ppc_find_by_name (const char *name) +static ObjectClass *ppc_cpu_class_by_name(const char *name) { - const ppc_def_t *ret; + GSList *list, *item; + ObjectClass *ret = NULL; const char *p; - int i, max, len; + int i, len; - if (kvm_enabled() && (strcasecmp(name, "host") == 0)) { - return kvmppc_host_cpu_def(); + if (strcasecmp(name, "host") == 0) { + if (kvm_enabled()) { + ret = object_class_by_name(TYPE_HOST_POWERPC_CPU); + } + return ret; } /* Check if the given name is a PVR */ @@ -10307,65 +10303,154 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name) if (!qemu_isxdigit(*p++)) break; } - if (i == 8) - return ppc_find_by_pvr(strtoul(name, NULL, 16)); - } - ret = NULL; - max = ARRAY_SIZE(ppc_defs); - for (i = 0; i < max; i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; + if (i == 8) { + ret = OBJECT_CLASS(ppc_cpu_class_by_pvr(strtoul(name, NULL, 16))); + return ret; } + } - if (strcasecmp(name, ppc_defs[i].name) == 0) { - ret = &ppc_defs[i]; - break; - } + list = object_class_get_list(TYPE_POWERPC_CPU, false); + item = g_slist_find_custom(list, name, ppc_cpu_compare_class_name); + if (item != NULL) { + ret = OBJECT_CLASS(item->data); } + g_slist_free(list); return ret; } -void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) +PowerPCCPU *cpu_ppc_init(const char *cpu_model) { - int i, max; + PowerPCCPU *cpu; + CPUPPCState *env; + ObjectClass *oc; + Error *err = NULL; - max = ARRAY_SIZE(ppc_defs); - for (i = 0; i < max; i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; - } - - (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n", - ppc_defs[i].name, ppc_defs[i].pvr); + oc = ppc_cpu_class_by_name(cpu_model); + if (oc == NULL) { + return NULL; } + + cpu = POWERPC_CPU(object_new(object_class_get_name(oc))); + env = &cpu->env; + + if (tcg_enabled()) { + ppc_translate_init(); + } + + env->cpu_model_str = cpu_model; + + ppc_cpu_realize(OBJECT(cpu), &err); + if (err != NULL) { + fprintf(stderr, "%s\n", error_get_pretty(err)); + error_free(err); + object_delete(OBJECT(cpu)); + return NULL; + } + + return cpu; +} + +/* Sort by PVR, ordering special case "host" last. */ +static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + ObjectClass *oc_a = (ObjectClass *)a; + ObjectClass *oc_b = (ObjectClass *)b; + PowerPCCPUClass *pcc_a = POWERPC_CPU_CLASS(oc_a); + PowerPCCPUClass *pcc_b = POWERPC_CPU_CLASS(oc_b); + const char *name_a = object_class_get_name(oc_a); + const char *name_b = object_class_get_name(oc_b); + + if (strcmp(name_a, TYPE_HOST_POWERPC_CPU) == 0) { + return 1; + } else if (strcmp(name_b, TYPE_HOST_POWERPC_CPU) == 0) { + return -1; + } else { + /* Avoid an integer overflow during subtraction */ + if (pcc_a->info->pvr < pcc_b->info->pvr) { + return -1; + } else if (pcc_a->info->pvr > pcc_b->info->pvr) { + return 1; + } else { + return 0; + } + } +} + +static void ppc_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CPUListState *s = user_data; + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", + pcc->info->name, pcc->info->pvr); +} + +void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ + CPUListState s = { + .file = f, + .cpu_fprintf = cpu_fprintf, + }; + GSList *list; + + list = object_class_get_list(TYPE_POWERPC_CPU, false); + list = g_slist_sort(list, ppc_cpu_list_compare); + g_slist_foreach(list, ppc_cpu_list_entry, &s); + g_slist_free(list); +} + +static void ppc_cpu_defs_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CpuDefinitionInfoList **first = user_data; + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + CpuDefinitionInfoList *entry; + CpuDefinitionInfo *info; + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(pcc->info->name); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = *first; + *first = entry; } CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) { CpuDefinitionInfoList *cpu_list = NULL; - int i; + GSList *list; - for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { - CpuDefinitionInfoList *entry; - CpuDefinitionInfo *info; - - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; - } - - info = g_malloc0(sizeof(*info)); - info->name = g_strdup(ppc_defs[i].name); - - entry = g_malloc0(sizeof(*entry)); - entry->value = info; - entry->next = cpu_list; - cpu_list = entry; - } + list = object_class_get_list(TYPE_POWERPC_CPU, false); + g_slist_foreach(list, ppc_cpu_defs_entry, &cpu_list); + g_slist_free(list); return cpu_list; } +static void ppc_cpu_def_class_init(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + ppc_def_t *info = data; + + pcc->info = info; +} + +static void ppc_cpu_register_model(const ppc_def_t *def) +{ + TypeInfo type_info = { + .parent = TYPE_POWERPC_CPU, + .class_init = ppc_cpu_def_class_init, + .class_data = (void *)def, + }; + + type_info.name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, def->name), + type_register(&type_info); + g_free((gpointer)type_info.name); +} + /* CPUClass::reset() */ static void ppc_cpu_reset(CPUState *s) { @@ -10434,9 +10519,42 @@ static void ppc_cpu_reset(CPUState *s) static void ppc_cpu_initfn(Object *obj) { PowerPCCPU *cpu = POWERPC_CPU(obj); + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; + ppc_def_t *def = pcc->info; cpu_exec_init(env); + + env->msr_mask = def->msr_mask; + env->mmu_model = def->mmu_model; + env->excp_model = def->excp_model; + env->bus_model = def->bus_model; + env->insns_flags = def->insns_flags; + env->insns_flags2 = def->insns_flags2; + env->flags = def->flags; + env->bfd_mach = def->bfd_mach; + env->check_pow = def->check_pow; + +#if defined(TARGET_PPC64) + if (def->sps) { + env->sps = *def->sps; + } else if (env->mmu_model & POWERPC_MMU_64) { + /* Use default sets of page sizes */ + static const struct ppc_segment_page_sizes defsps = { + .sps = { + { .page_shift = 12, /* 4K */ + .slb_enc = 0, + .enc = { { .page_shift = 12, .pte_enc = 0 } } + }, + { .page_shift = 24, /* 16M */ + .slb_enc = 0x100, + .enc = { { .page_shift = 24, .pte_enc = 0 } } + }, + }, + }; + env->sps = defsps; + } +#endif /* defined(TARGET_PPC64) */ } static void ppc_cpu_class_init(ObjectClass *oc, void *data) @@ -10453,14 +10571,27 @@ static const TypeInfo ppc_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(PowerPCCPU), .instance_init = ppc_cpu_initfn, - .abstract = false, + .abstract = true, .class_size = sizeof(PowerPCCPUClass), .class_init = ppc_cpu_class_init, }; static void ppc_cpu_register_types(void) { + int i; + type_register_static(&ppc_cpu_type_info); + + for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { + const ppc_def_t *def = &ppc_defs[i]; +#if defined(TARGET_PPCEMB) + /* When using the ppcemb target, we only support 440 style cores */ + if (def->mmu_model != POWERPC_MMU_BOOKE) { + continue; + } +#endif + ppc_cpu_register_model(def); + } } type_init(ppc_cpu_register_types) From 1b7ce68fb45b97a9eaf71eeb81d2b4f4ea6bf4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 6 Jan 2013 08:31:31 +0000 Subject: [PATCH 30/31] target-ppc: Error out for -cpu host on unknown PVR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we silently exited, with subclasses we got an opcode warning. Instead, explicitly tell the user what's wrong. An indication for this is -cpu ? showing "host" with an all-zero PVR. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index ce7d69b403..4846acfc0d 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -1232,7 +1232,15 @@ static void alter_insns(uint64_t *word, uint64_t flags, bool on) static void kvmppc_host_cpu_initfn(Object *obj) { + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(obj); + assert(kvm_enabled()); + + if (pcc->info->pvr != mfpvr()) { + fprintf(stderr, "Your host CPU is unsupported.\n" + "Please choose a supported model instead, see -cpu ?.\n"); + exit(1); + } } static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) From 61993a67128095946ed5df51c3c20748182d8efc Mon Sep 17 00:00:00 2001 From: Samuel Seay Date: Fri, 4 Jan 2013 14:35:48 +0000 Subject: [PATCH 31/31] PPC: linux-user: Calculate context pointer explicitly Peter Maydell recommended the change to be more proper. The result was tested and shows coming up with the same proper value. Signed-off-by: Samuel Seay [agraf: change subject] Signed-off-by: Alexander Graf --- linux-user/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index c43b8ac30a..bb08a9354e 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -4614,7 +4614,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, /* Set up registers for signal handler. */ env->gpr[1] = newsp; env->gpr[3] = signal; - env->gpr[4] = (target_ulong) h2g(sc); + env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx); env->nip = (target_ulong) ka->_sa_handler; /* Signal handlers are entered in big-endian mode. */ env->msr &= ~MSR_LE;