Browse Source
* GICv3 emulation -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJXZAgcAAoJEDwlJe0UNgze+xMP/371ot4BlUUkVSKIBaSuq3pd C5jqozcHo8+HObIdGJ2sP6ksiL5tdOFyhjSGm9jU4ERMGepzMI7Ztt1Ox2IGMvK1 +1dG2pdXZZnFa9RmYXZ+tQQA+th/bvAL3utXnuAq/rMuXCG8BB5Q3o5R88W2P9IY Xkr3RHSG57Sy5bR85TGiJDnANmS7VdpCK8T8CjKLye9XbQ7jec52jN5JKl4Q1H9y KWGJu/Q0ffJGePZa4aZXtgVQSVFyqXXRj+cZKV3lrbztfVoC76TfG/ga0djPuCVH HKCZLADiM1LahTrlMtEWsne3zkwyxwWdidDRshOPzM0gyoiPOPS8Im9n9liUEE+B 4igXd7xS+UXlXHJqYlGdZOQV8EU4123hEkrMY/eI50c/UYzCV281YBlVzL+zD+13 WDIotuX/yF1Rt//MUPeHOQFauRgYa8epFNSHatPGyfU7HFxR+9ErB1IOR79atZAs wbaA0FvJV/TeBTEZ41YhW21FbdfK4tGztEIZyz5RL8IPp6JXtWi3Ir/zzPcdD6xm FjKaMoXpNjuvE2KZKFpeLiNuNeOIRhdVjiwAI4B/eiSLJ1gHEPzuhnMm8uVF/7uf LWt73h+b1pXhcWtxLS4cgxza+QSfs5PDXPhO8gisxiqE86mmuJBx22UvlHoN2iDq jN8TGsubo/qqmEkexVBX =1ZVZ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160617' into staging target-arm queue: * GICv3 emulation # gpg: Signature made Fri 17 Jun 2016 15:24:28 BST # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20160617: (22 commits) ACPI: ARM: Present GIC version in MADT table hw/timer: Add value matching support to aspeed_timer target-arm/monitor.c: Advertise emulated GICv3 in capabilities target-arm/machine.c: Allow user to request GICv3 emulation hw/intc/arm_gicv3: Add IRQ handling CPU interface registers hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers hw/intc/arm_gicv3: Implement gicv3_cpuif_update() hw/intc/arm_gicv3: Implement GICv3 CPU interface registers hw/intc/arm_gicv3: Implement gicv3_set_irq() hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions hw/intc/arm_gicv3: Implement GICv3 redistributor registers hw/intc/arm_gicv3: Implement GICv3 distributor registers hw/intc/arm_gicv3: Implement functions to identify next pending irq hw/intc/arm_gicv3: ARM GICv3 device framework hw/intc/arm_gicv3: Add vmstate descriptors hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure hw/intc/arm_gicv3: Add state information target-arm: Add mp-affinity property for ARM CPU class target-arm: Provide hook to tell GICv3 about changes of security state target-arm: Define new arm_is_el3_or_mon() function ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>pull/42/head
25 changed files with 4394 additions and 60 deletions
@ -0,0 +1,400 @@ |
|||
/*
|
|||
* ARM Generic Interrupt Controller v3 |
|||
* |
|||
* Copyright (c) 2015 Huawei. |
|||
* Copyright (c) 2016 Linaro Limited |
|||
* Written by Shlomo Pongratz, Peter Maydell |
|||
* |
|||
* This code is licensed under the GPL, version 2 or (at your option) |
|||
* any later version. |
|||
*/ |
|||
|
|||
/* This file contains implementation code for an interrupt controller
|
|||
* which implements the GICv3 architecture. Specifically this is where |
|||
* the device class itself and the functions for handling interrupts |
|||
* coming in and going out live. |
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include "qapi/error.h" |
|||
#include "hw/sysbus.h" |
|||
#include "hw/intc/arm_gicv3.h" |
|||
#include "gicv3_internal.h" |
|||
|
|||
static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio) |
|||
{ |
|||
/* Return true if this IRQ at this priority should take
|
|||
* precedence over the current recorded highest priority |
|||
* pending interrupt for this CPU. We also return true if |
|||
* the current recorded highest priority pending interrupt |
|||
* is the same as this one (a property which the calling code |
|||
* relies on). |
|||
*/ |
|||
if (prio < cs->hppi.prio) { |
|||
return true; |
|||
} |
|||
/* If multiple pending interrupts have the same priority then it is an
|
|||
* IMPDEF choice which of them to signal to the CPU. We choose to |
|||
* signal the one with the lowest interrupt number. |
|||
*/ |
|||
if (prio == cs->hppi.prio && irq <= cs->hppi.irq) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
static uint32_t gicd_int_pending(GICv3State *s, int irq) |
|||
{ |
|||
/* Recalculate which distributor interrupts are actually pending
|
|||
* in the group of 32 interrupts starting at irq (which should be a multiple |
|||
* of 32), and return a 32-bit integer which has a bit set for each |
|||
* interrupt that is eligible to be signaled to the CPU interface. |
|||
* |
|||
* An interrupt is pending if: |
|||
* + the PENDING latch is set OR it is level triggered and the input is 1 |
|||
* + its ENABLE bit is set |
|||
* + the GICD enable bit for its group is set |
|||
* Conveniently we can bulk-calculate this with bitwise operations. |
|||
*/ |
|||
uint32_t pend, grpmask; |
|||
uint32_t pending = *gic_bmp_ptr32(s->pending, irq); |
|||
uint32_t edge_trigger = *gic_bmp_ptr32(s->edge_trigger, irq); |
|||
uint32_t level = *gic_bmp_ptr32(s->level, irq); |
|||
uint32_t group = *gic_bmp_ptr32(s->group, irq); |
|||
uint32_t grpmod = *gic_bmp_ptr32(s->grpmod, irq); |
|||
uint32_t enable = *gic_bmp_ptr32(s->enabled, irq); |
|||
|
|||
pend = pending | (~edge_trigger & level); |
|||
pend &= enable; |
|||
|
|||
if (s->gicd_ctlr & GICD_CTLR_DS) { |
|||
grpmod = 0; |
|||
} |
|||
|
|||
grpmask = 0; |
|||
if (s->gicd_ctlr & GICD_CTLR_EN_GRP1NS) { |
|||
grpmask |= group; |
|||
} |
|||
if (s->gicd_ctlr & GICD_CTLR_EN_GRP1S) { |
|||
grpmask |= (~group & grpmod); |
|||
} |
|||
if (s->gicd_ctlr & GICD_CTLR_EN_GRP0) { |
|||
grpmask |= (~group & ~grpmod); |
|||
} |
|||
pend &= grpmask; |
|||
|
|||
return pend; |
|||
} |
|||
|
|||
static uint32_t gicr_int_pending(GICv3CPUState *cs) |
|||
{ |
|||
/* Recalculate which redistributor interrupts are actually pending,
|
|||
* and return a 32-bit integer which has a bit set for each interrupt |
|||
* that is eligible to be signaled to the CPU interface. |
|||
* |
|||
* An interrupt is pending if: |
|||
* + the PENDING latch is set OR it is level triggered and the input is 1 |
|||
* + its ENABLE bit is set |
|||
* + the GICD enable bit for its group is set |
|||
* Conveniently we can bulk-calculate this with bitwise operations. |
|||
*/ |
|||
uint32_t pend, grpmask, grpmod; |
|||
|
|||
pend = cs->gicr_ipendr0 | (~cs->edge_trigger & cs->level); |
|||
pend &= cs->gicr_ienabler0; |
|||
|
|||
if (cs->gic->gicd_ctlr & GICD_CTLR_DS) { |
|||
grpmod = 0; |
|||
} else { |
|||
grpmod = cs->gicr_igrpmodr0; |
|||
} |
|||
|
|||
grpmask = 0; |
|||
if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1NS) { |
|||
grpmask |= cs->gicr_igroupr0; |
|||
} |
|||
if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1S) { |
|||
grpmask |= (~cs->gicr_igroupr0 & grpmod); |
|||
} |
|||
if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP0) { |
|||
grpmask |= (~cs->gicr_igroupr0 & ~grpmod); |
|||
} |
|||
pend &= grpmask; |
|||
|
|||
return pend; |
|||
} |
|||
|
|||
/* Update the interrupt status after state in a redistributor
|
|||
* or CPU interface has changed, but don't tell the CPU i/f. |
|||
*/ |
|||
static void gicv3_redist_update_noirqset(GICv3CPUState *cs) |
|||
{ |
|||
/* Find the highest priority pending interrupt among the
|
|||
* redistributor interrupts (SGIs and PPIs). |
|||
*/ |
|||
bool seenbetter = false; |
|||
uint8_t prio; |
|||
int i; |
|||
uint32_t pend; |
|||
|
|||
/* Find out which redistributor interrupts are eligible to be
|
|||
* signaled to the CPU interface. |
|||
*/ |
|||
pend = gicr_int_pending(cs); |
|||
|
|||
if (pend) { |
|||
for (i = 0; i < GIC_INTERNAL; i++) { |
|||
if (!(pend & (1 << i))) { |
|||
continue; |
|||
} |
|||
prio = cs->gicr_ipriorityr[i]; |
|||
if (irqbetter(cs, i, prio)) { |
|||
cs->hppi.irq = i; |
|||
cs->hppi.prio = prio; |
|||
seenbetter = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (seenbetter) { |
|||
cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq); |
|||
} |
|||
|
|||
/* If the best interrupt we just found would preempt whatever
|
|||
* was the previous best interrupt before this update, then |
|||
* we know it's definitely the best one now. |
|||
* If we didn't find an interrupt that would preempt the previous |
|||
* best, and the previous best is outside our range (or there was no |
|||
* previous pending interrupt at all), then that is still valid, and |
|||
* we leave it as the best. |
|||
* Otherwise, we need to do a full update (because the previous best |
|||
* interrupt has reduced in priority and any other interrupt could |
|||
* now be the new best one). |
|||
*/ |
|||
if (!seenbetter && cs->hppi.prio != 0xff && cs->hppi.irq < GIC_INTERNAL) { |
|||
gicv3_full_update_noirqset(cs->gic); |
|||
} |
|||
} |
|||
|
|||
/* Update the GIC status after state in a redistributor or
|
|||
* CPU interface has changed, and inform the CPU i/f of |
|||
* its new highest priority pending interrupt. |
|||
*/ |
|||
void gicv3_redist_update(GICv3CPUState *cs) |
|||
{ |
|||
gicv3_redist_update_noirqset(cs); |
|||
gicv3_cpuif_update(cs); |
|||
} |
|||
|
|||
/* Update the GIC status after state in the distributor has
|
|||
* changed affecting @len interrupts starting at @start, |
|||
* but don't tell the CPU i/f. |
|||
*/ |
|||
static void gicv3_update_noirqset(GICv3State *s, int start, int len) |
|||
{ |
|||
int i; |
|||
uint8_t prio; |
|||
uint32_t pend = 0; |
|||
|
|||
assert(start >= GIC_INTERNAL); |
|||
assert(len > 0); |
|||
|
|||
for (i = 0; i < s->num_cpu; i++) { |
|||
s->cpu[i].seenbetter = false; |
|||
} |
|||
|
|||
/* Find the highest priority pending interrupt in this range. */ |
|||
for (i = start; i < start + len; i++) { |
|||
GICv3CPUState *cs; |
|||
|
|||
if (i == start || (i & 0x1f) == 0) { |
|||
/* Calculate the next 32 bits worth of pending status */ |
|||
pend = gicd_int_pending(s, i & ~0x1f); |
|||
} |
|||
|
|||
if (!(pend & (1 << (i & 0x1f)))) { |
|||
continue; |
|||
} |
|||
cs = s->gicd_irouter_target[i]; |
|||
if (!cs) { |
|||
/* Interrupts targeting no implemented CPU should remain pending
|
|||
* and not be forwarded to any CPU. |
|||
*/ |
|||
continue; |
|||
} |
|||
prio = s->gicd_ipriority[i]; |
|||
if (irqbetter(cs, i, prio)) { |
|||
cs->hppi.irq = i; |
|||
cs->hppi.prio = prio; |
|||
cs->seenbetter = true; |
|||
} |
|||
} |
|||
|
|||
/* If the best interrupt we just found would preempt whatever
|
|||
* was the previous best interrupt before this update, then |
|||
* we know it's definitely the best one now. |
|||
* If we didn't find an interrupt that would preempt the previous |
|||
* best, and the previous best is outside our range (or there was |
|||
* no previous pending interrupt at all), then that |
|||
* is still valid, and we leave it as the best. |
|||
* Otherwise, we need to do a full update (because the previous best |
|||
* interrupt has reduced in priority and any other interrupt could |
|||
* now be the new best one). |
|||
*/ |
|||
for (i = 0; i < s->num_cpu; i++) { |
|||
GICv3CPUState *cs = &s->cpu[i]; |
|||
|
|||
if (cs->seenbetter) { |
|||
cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq); |
|||
} |
|||
|
|||
if (!cs->seenbetter && cs->hppi.prio != 0xff && |
|||
cs->hppi.irq >= start && cs->hppi.irq < start + len) { |
|||
gicv3_full_update_noirqset(s); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void gicv3_update(GICv3State *s, int start, int len) |
|||
{ |
|||
int i; |
|||
|
|||
gicv3_update_noirqset(s, start, len); |
|||
for (i = 0; i < s->num_cpu; i++) { |
|||
gicv3_cpuif_update(&s->cpu[i]); |
|||
} |
|||
} |
|||
|
|||
void gicv3_full_update_noirqset(GICv3State *s) |
|||
{ |
|||
/* Completely recalculate the GIC status from scratch, but
|
|||
* don't update any outbound IRQ lines. |
|||
*/ |
|||
int i; |
|||
|
|||
for (i = 0; i < s->num_cpu; i++) { |
|||
s->cpu[i].hppi.prio = 0xff; |
|||
} |
|||
|
|||
/* Note that we can guarantee that these functions will not
|
|||
* recursively call back into gicv3_full_update(), because |
|||
* at each point the "previous best" is always outside the |
|||
* range we ask them to update. |
|||
*/ |
|||
gicv3_update_noirqset(s, GIC_INTERNAL, s->num_irq - GIC_INTERNAL); |
|||
|
|||
for (i = 0; i < s->num_cpu; i++) { |
|||
gicv3_redist_update_noirqset(&s->cpu[i]); |
|||
} |
|||
} |
|||
|
|||
void gicv3_full_update(GICv3State *s) |
|||
{ |
|||
/* Completely recalculate the GIC status from scratch, including
|
|||
* updating outbound IRQ lines. |
|||
*/ |
|||
int i; |
|||
|
|||
gicv3_full_update_noirqset(s); |
|||
for (i = 0; i < s->num_cpu; i++) { |
|||
gicv3_cpuif_update(&s->cpu[i]); |
|||
} |
|||
} |
|||
|
|||
/* Process a change in an external IRQ input. */ |
|||
static void gicv3_set_irq(void *opaque, int irq, int level) |
|||
{ |
|||
/* Meaning of the 'irq' parameter:
|
|||
* [0..N-1] : external interrupts |
|||
* [N..N+31] : PPI (internal) interrupts for CPU 0 |
|||
* [N+32..N+63] : PPI (internal interrupts for CPU 1 |
|||
* ... |
|||
*/ |
|||
GICv3State *s = opaque; |
|||
|
|||
if (irq < (s->num_irq - GIC_INTERNAL)) { |
|||
/* external interrupt (SPI) */ |
|||
gicv3_dist_set_irq(s, irq + GIC_INTERNAL, level); |
|||
} else { |
|||
/* per-cpu interrupt (PPI) */ |
|||
int cpu; |
|||
|
|||
irq -= (s->num_irq - GIC_INTERNAL); |
|||
cpu = irq / GIC_INTERNAL; |
|||
irq %= GIC_INTERNAL; |
|||
assert(cpu < s->num_cpu); |
|||
/* Raising SGIs via this function would be a bug in how the board
|
|||
* model wires up interrupts. |
|||
*/ |
|||
assert(irq >= GIC_NR_SGIS); |
|||
gicv3_redist_set_irq(&s->cpu[cpu], irq, level); |
|||
} |
|||
} |
|||
|
|||
static void arm_gicv3_post_load(GICv3State *s) |
|||
{ |
|||
/* Recalculate our cached idea of the current highest priority
|
|||
* pending interrupt, but don't set IRQ or FIQ lines. |
|||
*/ |
|||
gicv3_full_update_noirqset(s); |
|||
/* Repopulate the cache of GICv3CPUState pointers for target CPUs */ |
|||
gicv3_cache_all_target_cpustates(s); |
|||
} |
|||
|
|||
static const MemoryRegionOps gic_ops[] = { |
|||
{ |
|||
.read_with_attrs = gicv3_dist_read, |
|||
.write_with_attrs = gicv3_dist_write, |
|||
.endianness = DEVICE_NATIVE_ENDIAN, |
|||
}, |
|||
{ |
|||
.read_with_attrs = gicv3_redist_read, |
|||
.write_with_attrs = gicv3_redist_write, |
|||
.endianness = DEVICE_NATIVE_ENDIAN, |
|||
} |
|||
}; |
|||
|
|||
static void arm_gic_realize(DeviceState *dev, Error **errp) |
|||
{ |
|||
/* Device instance realize function for the GIC sysbus device */ |
|||
GICv3State *s = ARM_GICV3(dev); |
|||
ARMGICv3Class *agc = ARM_GICV3_GET_CLASS(s); |
|||
Error *local_err = NULL; |
|||
|
|||
agc->parent_realize(dev, &local_err); |
|||
if (local_err) { |
|||
error_propagate(errp, local_err); |
|||
return; |
|||
} |
|||
|
|||
gicv3_init_irqs_and_mmio(s, gicv3_set_irq, gic_ops); |
|||
|
|||
gicv3_init_cpuif(s); |
|||
} |
|||
|
|||
static void arm_gicv3_class_init(ObjectClass *klass, void *data) |
|||
{ |
|||
DeviceClass *dc = DEVICE_CLASS(klass); |
|||
ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); |
|||
ARMGICv3Class *agc = ARM_GICV3_CLASS(klass); |
|||
|
|||
agcc->post_load = arm_gicv3_post_load; |
|||
agc->parent_realize = dc->realize; |
|||
dc->realize = arm_gic_realize; |
|||
} |
|||
|
|||
static const TypeInfo arm_gicv3_info = { |
|||
.name = TYPE_ARM_GICV3, |
|||
.parent = TYPE_ARM_GICV3_COMMON, |
|||
.instance_size = sizeof(GICv3State), |
|||
.class_init = arm_gicv3_class_init, |
|||
.class_size = sizeof(ARMGICv3Class), |
|||
}; |
|||
|
|||
static void arm_gicv3_register_types(void) |
|||
{ |
|||
type_register_static(&arm_gicv3_info); |
|||
} |
|||
|
|||
type_init(arm_gicv3_register_types) |
|||
File diff suppressed because it is too large
@ -0,0 +1,879 @@ |
|||
/*
|
|||
* ARM GICv3 emulation: Distributor |
|||
* |
|||
* Copyright (c) 2015 Huawei. |
|||
* Copyright (c) 2016 Linaro Limited. |
|||
* Written by Shlomo Pongratz, Peter Maydell |
|||
* |
|||
* This code is licensed under the GPL, version 2 or (at your option) |
|||
* any later version. |
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include "trace.h" |
|||
#include "gicv3_internal.h" |
|||
|
|||
/* The GICD_NSACR registers contain a two bit field for each interrupt which
|
|||
* allows the guest to give NonSecure code access to registers controlling |
|||
* Secure interrupts: |
|||
* 0b00: no access (NS accesses to bits for Secure interrupts will RAZ/WI) |
|||
* 0b01: NS r/w accesses permitted to ISPENDR, SETSPI_NSR, SGIR |
|||
* 0b10: as 0b01, and also r/w to ICPENDR, r/o to ISACTIVER/ICACTIVER, |
|||
* and w/o to CLRSPI_NSR |
|||
* 0b11: as 0b10, and also r/w to IROUTER and ITARGETSR |
|||
* |
|||
* Given a (multiple-of-32) interrupt number, these mask functions return |
|||
* a mask word where each bit is 1 if the NSACR settings permit access |
|||
* to the interrupt. The mask returned can then be ORed with the GICD_GROUP |
|||
* word for this set of interrupts to give an overall mask. |
|||
*/ |
|||
|
|||
typedef uint32_t maskfn(GICv3State *s, int irq); |
|||
|
|||
static uint32_t mask_nsacr_ge1(GICv3State *s, int irq) |
|||
{ |
|||
/* Return a mask where each bit is set if the NSACR field is >= 1 */ |
|||
uint64_t raw_nsacr = s->gicd_nsacr[irq / 16 + 1]; |
|||
|
|||
raw_nsacr = raw_nsacr << 32 | s->gicd_nsacr[irq / 16]; |
|||
raw_nsacr = (raw_nsacr >> 1) | raw_nsacr; |
|||
return half_unshuffle64(raw_nsacr); |
|||
} |
|||
|
|||
static uint32_t mask_nsacr_ge2(GICv3State *s, int irq) |
|||
{ |
|||
/* Return a mask where each bit is set if the NSACR field is >= 2 */ |
|||
uint64_t raw_nsacr = s->gicd_nsacr[irq / 16 + 1]; |
|||
|
|||
raw_nsacr = raw_nsacr << 32 | s->gicd_nsacr[irq / 16]; |
|||
raw_nsacr = raw_nsacr >> 1; |
|||
return half_unshuffle64(raw_nsacr); |
|||
} |
|||
|
|||
/* We don't need a mask_nsacr_ge3() because IROUTER<n> isn't a bitmap register,
|
|||
* but it would be implemented using: |
|||
* raw_nsacr = (raw_nsacr >> 1) & raw_nsacr; |
|||
*/ |
|||
|
|||
static uint32_t mask_group_and_nsacr(GICv3State *s, MemTxAttrs attrs, |
|||
maskfn *maskfn, int irq) |
|||
{ |
|||
/* Return a 32-bit mask which should be applied for this set of 32
|
|||
* interrupts; each bit is 1 if access is permitted by the |
|||
* combination of attrs.secure, GICD_GROUPR and GICD_NSACR. |
|||
*/ |
|||
uint32_t mask; |
|||
|
|||
if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { |
|||
/* bits for Group 0 or Secure Group 1 interrupts are RAZ/WI
|
|||
* unless the NSACR bits permit access. |
|||
*/ |
|||
mask = *gic_bmp_ptr32(s->group, irq); |
|||
if (maskfn) { |
|||
mask |= maskfn(s, irq); |
|||
} |
|||
return mask; |
|||
} |
|||
return 0xFFFFFFFFU; |
|||
} |
|||
|
|||
static int gicd_ns_access(GICv3State *s, int irq) |
|||
{ |
|||
/* Return the 2 bit NS_access<x> field from GICD_NSACR<n> for the
|
|||
* specified interrupt. |
|||
*/ |
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return 0; |
|||
} |
|||
return extract32(s->gicd_nsacr[irq / 16], (irq % 16) * 2, 2); |
|||
} |
|||
|
|||
static void gicd_write_set_bitmap_reg(GICv3State *s, MemTxAttrs attrs, |
|||
uint32_t *bmp, |
|||
maskfn *maskfn, |
|||
int offset, uint32_t val) |
|||
{ |
|||
/* Helper routine to implement writing to a "set-bitmap" register
|
|||
* (GICD_ISENABLER, GICD_ISPENDR, etc). |
|||
* Semantics implemented here: |
|||
* RAZ/WI for SGIs, PPIs, unimplemented IRQs |
|||
* Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI. |
|||
* Writing 1 means "set bit in bitmap"; writing 0 is ignored. |
|||
* offset should be the offset in bytes of the register from the start |
|||
* of its group. |
|||
*/ |
|||
int irq = offset * 8; |
|||
|
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return; |
|||
} |
|||
val &= mask_group_and_nsacr(s, attrs, maskfn, irq); |
|||
*gic_bmp_ptr32(bmp, irq) |= val; |
|||
gicv3_update(s, irq, 32); |
|||
} |
|||
|
|||
static void gicd_write_clear_bitmap_reg(GICv3State *s, MemTxAttrs attrs, |
|||
uint32_t *bmp, |
|||
maskfn *maskfn, |
|||
int offset, uint32_t val) |
|||
{ |
|||
/* Helper routine to implement writing to a "clear-bitmap" register
|
|||
* (GICD_ICENABLER, GICD_ICPENDR, etc). |
|||
* Semantics implemented here: |
|||
* RAZ/WI for SGIs, PPIs, unimplemented IRQs |
|||
* Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI. |
|||
* Writing 1 means "clear bit in bitmap"; writing 0 is ignored. |
|||
* offset should be the offset in bytes of the register from the start |
|||
* of its group. |
|||
*/ |
|||
int irq = offset * 8; |
|||
|
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return; |
|||
} |
|||
val &= mask_group_and_nsacr(s, attrs, maskfn, irq); |
|||
*gic_bmp_ptr32(bmp, irq) &= ~val; |
|||
gicv3_update(s, irq, 32); |
|||
} |
|||
|
|||
static uint32_t gicd_read_bitmap_reg(GICv3State *s, MemTxAttrs attrs, |
|||
uint32_t *bmp, |
|||
maskfn *maskfn, |
|||
int offset) |
|||
{ |
|||
/* Helper routine to implement reading a "set/clear-bitmap" register
|
|||
* (GICD_ICENABLER, GICD_ISENABLER, GICD_ICPENDR, etc). |
|||
* Semantics implemented here: |
|||
* RAZ/WI for SGIs, PPIs, unimplemented IRQs |
|||
* Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI. |
|||
* offset should be the offset in bytes of the register from the start |
|||
* of its group. |
|||
*/ |
|||
int irq = offset * 8; |
|||
uint32_t val; |
|||
|
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return 0; |
|||
} |
|||
val = *gic_bmp_ptr32(bmp, irq); |
|||
if (bmp == s->pending) { |
|||
/* The PENDING register is a special case -- for level triggered
|
|||
* interrupts, the PENDING state is the logical OR of the state of |
|||
* the PENDING latch with the input line level. |
|||
*/ |
|||
uint32_t edge = *gic_bmp_ptr32(s->edge_trigger, irq); |
|||
uint32_t level = *gic_bmp_ptr32(s->level, irq); |
|||
val |= (~edge & level); |
|||
} |
|||
val &= mask_group_and_nsacr(s, attrs, maskfn, irq); |
|||
return val; |
|||
} |
|||
|
|||
static uint8_t gicd_read_ipriorityr(GICv3State *s, MemTxAttrs attrs, int irq) |
|||
{ |
|||
/* Read the value of GICD_IPRIORITYR<n> for the specified interrupt,
|
|||
* honouring security state (these are RAZ/WI for Group 0 or Secure |
|||
* Group 1 interrupts). |
|||
*/ |
|||
uint32_t prio; |
|||
|
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return 0; |
|||
} |
|||
|
|||
prio = s->gicd_ipriority[irq]; |
|||
|
|||
if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { |
|||
if (!gicv3_gicd_group_test(s, irq)) { |
|||
/* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */ |
|||
return 0; |
|||
} |
|||
/* NS view of the interrupt priority */ |
|||
prio = (prio << 1) & 0xff; |
|||
} |
|||
return prio; |
|||
} |
|||
|
|||
static void gicd_write_ipriorityr(GICv3State *s, MemTxAttrs attrs, int irq, |
|||
uint8_t value) |
|||
{ |
|||
/* Write the value of GICD_IPRIORITYR<n> for the specified interrupt,
|
|||
* honouring security state (these are RAZ/WI for Group 0 or Secure |
|||
* Group 1 interrupts). |
|||
*/ |
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return; |
|||
} |
|||
|
|||
if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { |
|||
if (!gicv3_gicd_group_test(s, irq)) { |
|||
/* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */ |
|||
return; |
|||
} |
|||
/* NS view of the interrupt priority */ |
|||
value = 0x80 | (value >> 1); |
|||
} |
|||
s->gicd_ipriority[irq] = value; |
|||
} |
|||
|
|||
static uint64_t gicd_read_irouter(GICv3State *s, MemTxAttrs attrs, int irq) |
|||
{ |
|||
/* Read the value of GICD_IROUTER<n> for the specified interrupt,
|
|||
* honouring security state. |
|||
*/ |
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return 0; |
|||
} |
|||
|
|||
if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { |
|||
/* RAZ/WI for NS accesses to secure interrupts */ |
|||
if (!gicv3_gicd_group_test(s, irq)) { |
|||
if (gicd_ns_access(s, irq) != 3) { |
|||
return 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return s->gicd_irouter[irq]; |
|||
} |
|||
|
|||
static void gicd_write_irouter(GICv3State *s, MemTxAttrs attrs, int irq, |
|||
uint64_t val) |
|||
{ |
|||
/* Write the value of GICD_IROUTER<n> for the specified interrupt,
|
|||
* honouring security state. |
|||
*/ |
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return; |
|||
} |
|||
|
|||
if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { |
|||
/* RAZ/WI for NS accesses to secure interrupts */ |
|||
if (!gicv3_gicd_group_test(s, irq)) { |
|||
if (gicd_ns_access(s, irq) != 3) { |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
|
|||
s->gicd_irouter[irq] = val; |
|||
gicv3_cache_target_cpustate(s, irq); |
|||
gicv3_update(s, irq, 1); |
|||
} |
|||
|
|||
static MemTxResult gicd_readb(GICv3State *s, hwaddr offset, |
|||
uint64_t *data, MemTxAttrs attrs) |
|||
{ |
|||
/* Most GICv3 distributor registers do not support byte accesses. */ |
|||
switch (offset) { |
|||
case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf: |
|||
case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf: |
|||
case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff: |
|||
/* This GIC implementation always has affinity routing enabled,
|
|||
* so these registers are all RAZ/WI. |
|||
*/ |
|||
return MEMTX_OK; |
|||
case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: |
|||
*data = gicd_read_ipriorityr(s, attrs, offset - GICD_IPRIORITYR); |
|||
return MEMTX_OK; |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
static MemTxResult gicd_writeb(GICv3State *s, hwaddr offset, |
|||
uint64_t value, MemTxAttrs attrs) |
|||
{ |
|||
/* Most GICv3 distributor registers do not support byte accesses. */ |
|||
switch (offset) { |
|||
case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf: |
|||
case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf: |
|||
case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff: |
|||
/* This GIC implementation always has affinity routing enabled,
|
|||
* so these registers are all RAZ/WI. |
|||
*/ |
|||
return MEMTX_OK; |
|||
case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: |
|||
{ |
|||
int irq = offset - GICD_IPRIORITYR; |
|||
|
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return MEMTX_OK; |
|||
} |
|||
gicd_write_ipriorityr(s, attrs, irq, value); |
|||
gicv3_update(s, irq, 1); |
|||
return MEMTX_OK; |
|||
} |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
static MemTxResult gicd_readw(GICv3State *s, hwaddr offset, |
|||
uint64_t *data, MemTxAttrs attrs) |
|||
{ |
|||
/* Only GICD_SETSPI_NSR, GICD_CLRSPI_NSR, GICD_SETSPI_SR and GICD_SETSPI_NSR
|
|||
* support 16 bit accesses, and those registers are all part of the |
|||
* optional message-based SPI feature which this GIC does not currently |
|||
* implement (ie for us GICD_TYPER.MBIS == 0), so for us they are |
|||
* reserved. |
|||
*/ |
|||
return MEMTX_ERROR; |
|||
} |
|||
|
|||
static MemTxResult gicd_writew(GICv3State *s, hwaddr offset, |
|||
uint64_t value, MemTxAttrs attrs) |
|||
{ |
|||
/* Only GICD_SETSPI_NSR, GICD_CLRSPI_NSR, GICD_SETSPI_SR and GICD_SETSPI_NSR
|
|||
* support 16 bit accesses, and those registers are all part of the |
|||
* optional message-based SPI feature which this GIC does not currently |
|||
* implement (ie for us GICD_TYPER.MBIS == 0), so for us they are |
|||
* reserved. |
|||
*/ |
|||
return MEMTX_ERROR; |
|||
} |
|||
|
|||
static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, |
|||
uint64_t *data, MemTxAttrs attrs) |
|||
{ |
|||
/* Almost all GICv3 distributor registers are 32-bit.
|
|||
* Note that WO registers must return an UNKNOWN value on reads, |
|||
* not an abort. |
|||
*/ |
|||
|
|||
switch (offset) { |
|||
case GICD_CTLR: |
|||
if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { |
|||
/* The NS view of the GICD_CTLR sees only certain bits:
|
|||
* + bit [31] (RWP) is an alias of the Secure bit [31] |
|||
* + bit [4] (ARE_NS) is an alias of Secure bit [5] |
|||
* + bit [1] (EnableGrp1A) is an alias of Secure bit [1] if |
|||
* NS affinity routing is enabled, otherwise RES0 |
|||
* + bit [0] (EnableGrp1) is an alias of Secure bit [1] if |
|||
* NS affinity routing is not enabled, otherwise RES0 |
|||
* Since for QEMU affinity routing is always enabled |
|||
* for both S and NS this means that bits [4] and [5] are |
|||
* both always 1, and we can simply make the NS view |
|||
* be bits 31, 4 and 1 of the S view. |
|||
*/ |
|||
*data = s->gicd_ctlr & (GICD_CTLR_ARE_S | |
|||
GICD_CTLR_EN_GRP1NS | |
|||
GICD_CTLR_RWP); |
|||
} else { |
|||
*data = s->gicd_ctlr; |
|||
} |
|||
return MEMTX_OK; |
|||
case GICD_TYPER: |
|||
{ |
|||
/* For this implementation:
|
|||
* No1N == 1 (1-of-N SPI interrupts not supported) |
|||
* A3V == 1 (non-zero values of Affinity level 3 supported) |
|||
* IDbits == 0xf (we support 16-bit interrupt identifiers) |
|||
* DVIS == 0 (Direct virtual LPI injection not supported) |
|||
* LPIS == 0 (LPIs not supported) |
|||
* MBIS == 0 (message-based SPIs not supported) |
|||
* SecurityExtn == 1 if security extns supported |
|||
* CPUNumber == 0 since for us ARE is always 1 |
|||
* ITLinesNumber == (num external irqs / 32) - 1 |
|||
*/ |
|||
int itlinesnumber = ((s->num_irq - GIC_INTERNAL) / 32) - 1; |
|||
|
|||
*data = (1 << 25) | (1 << 24) | (s->security_extn << 10) | |
|||
(0xf << 19) | itlinesnumber; |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_IIDR: |
|||
/* We claim to be an ARM r0p0 with a zero ProductID.
|
|||
* This is the same as an r0p0 GIC-500. |
|||
*/ |
|||
*data = gicv3_iidr(); |
|||
return MEMTX_OK; |
|||
case GICD_STATUSR: |
|||
/* RAZ/WI for us (this is an optional register and our implementation
|
|||
* does not track RO/WO/reserved violations to report them to the guest) |
|||
*/ |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
case GICD_IGROUPR ... GICD_IGROUPR + 0x7f: |
|||
{ |
|||
int irq; |
|||
|
|||
if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
} |
|||
/* RAZ/WI for SGIs, PPIs, unimplemented irqs */ |
|||
irq = (offset - GICD_IGROUPR) * 8; |
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
} |
|||
*data = *gic_bmp_ptr32(s->group, irq); |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_ISENABLER ... GICD_ISENABLER + 0x7f: |
|||
*data = gicd_read_bitmap_reg(s, attrs, s->enabled, NULL, |
|||
offset - GICD_ISENABLER); |
|||
return MEMTX_OK; |
|||
case GICD_ICENABLER ... GICD_ICENABLER + 0x7f: |
|||
*data = gicd_read_bitmap_reg(s, attrs, s->enabled, NULL, |
|||
offset - GICD_ICENABLER); |
|||
return MEMTX_OK; |
|||
case GICD_ISPENDR ... GICD_ISPENDR + 0x7f: |
|||
*data = gicd_read_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge1, |
|||
offset - GICD_ISPENDR); |
|||
return MEMTX_OK; |
|||
case GICD_ICPENDR ... GICD_ICPENDR + 0x7f: |
|||
*data = gicd_read_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge2, |
|||
offset - GICD_ICPENDR); |
|||
return MEMTX_OK; |
|||
case GICD_ISACTIVER ... GICD_ISACTIVER + 0x7f: |
|||
*data = gicd_read_bitmap_reg(s, attrs, s->active, mask_nsacr_ge2, |
|||
offset - GICD_ISACTIVER); |
|||
return MEMTX_OK; |
|||
case GICD_ICACTIVER ... GICD_ICACTIVER + 0x7f: |
|||
*data = gicd_read_bitmap_reg(s, attrs, s->active, mask_nsacr_ge2, |
|||
offset - GICD_ICACTIVER); |
|||
return MEMTX_OK; |
|||
case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: |
|||
{ |
|||
int i, irq = offset - GICD_IPRIORITYR; |
|||
uint32_t value = 0; |
|||
|
|||
for (i = irq + 3; i >= irq; i--, value <<= 8) { |
|||
value |= gicd_read_ipriorityr(s, attrs, i); |
|||
} |
|||
*data = value; |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff: |
|||
/* RAZ/WI since affinity routing is always enabled */ |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
case GICD_ICFGR ... GICD_ICFGR + 0xff: |
|||
{ |
|||
/* Here only the even bits are used; odd bits are RES0 */ |
|||
int irq = (offset - GICD_ICFGR) * 4; |
|||
uint32_t value = 0; |
|||
|
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
} |
|||
|
|||
/* Since our edge_trigger bitmap is one bit per irq, we only need
|
|||
* half of the 32-bit word, which we can then spread out |
|||
* into the odd bits. |
|||
*/ |
|||
value = *gic_bmp_ptr32(s->edge_trigger, irq & ~0x1f); |
|||
value &= mask_group_and_nsacr(s, attrs, NULL, irq & ~0x1f); |
|||
value = extract32(value, (irq & 0x1f) ? 16 : 0, 16); |
|||
value = half_shuffle32(value) << 1; |
|||
*data = value; |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_IGRPMODR ... GICD_IGRPMODR + 0xff: |
|||
{ |
|||
int irq; |
|||
|
|||
if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { |
|||
/* RAZ/WI if security disabled, or if
|
|||
* security enabled and this is an NS access |
|||
*/ |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
} |
|||
/* RAZ/WI for SGIs, PPIs, unimplemented irqs */ |
|||
irq = (offset - GICD_IGRPMODR) * 8; |
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
} |
|||
*data = *gic_bmp_ptr32(s->grpmod, irq); |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_NSACR ... GICD_NSACR + 0xff: |
|||
{ |
|||
/* Two bits per interrupt */ |
|||
int irq = (offset - GICD_NSACR) * 4; |
|||
|
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
} |
|||
|
|||
if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { |
|||
/* RAZ/WI if security disabled, or if
|
|||
* security enabled and this is an NS access |
|||
*/ |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
} |
|||
|
|||
*data = s->gicd_nsacr[irq / 16]; |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf: |
|||
case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf: |
|||
/* RAZ/WI since affinity routing is always enabled */ |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: |
|||
{ |
|||
uint64_t r; |
|||
int irq = (offset - GICD_IROUTER) / 8; |
|||
|
|||
r = gicd_read_irouter(s, attrs, irq); |
|||
if (offset & 7) { |
|||
*data = r >> 32; |
|||
} else { |
|||
*data = (uint32_t)r; |
|||
} |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_IDREGS ... GICD_IDREGS + 0x1f: |
|||
/* ID registers */ |
|||
*data = gicv3_idreg(offset - GICD_IDREGS); |
|||
return MEMTX_OK; |
|||
case GICD_SGIR: |
|||
/* WO registers, return unknown value */ |
|||
qemu_log_mask(LOG_GUEST_ERROR, |
|||
"%s: invalid guest read from WO register at offset " |
|||
TARGET_FMT_plx "\n", __func__, offset); |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
static MemTxResult gicd_writel(GICv3State *s, hwaddr offset, |
|||
uint64_t value, MemTxAttrs attrs) |
|||
{ |
|||
/* Almost all GICv3 distributor registers are 32-bit. Note that
|
|||
* RO registers must ignore writes, not abort. |
|||
*/ |
|||
|
|||
switch (offset) { |
|||
case GICD_CTLR: |
|||
{ |
|||
uint32_t mask; |
|||
/* GICv3 5.3.20 */ |
|||
if (s->gicd_ctlr & GICD_CTLR_DS) { |
|||
/* With only one security state, E1NWF is RAZ/WI, DS is RAO/WI,
|
|||
* ARE is RAO/WI (affinity routing always on), and only |
|||
* bits 0 and 1 (group enables) are writable. |
|||
*/ |
|||
mask = GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1NS; |
|||
} else { |
|||
if (attrs.secure) { |
|||
/* for secure access:
|
|||
* ARE_NS and ARE_S are RAO/WI (affinity routing always on) |
|||
* E1NWF is RAZ/WI (we don't support enable-1-of-n-wakeup) |
|||
* |
|||
* We can only modify bits[2:0] (the group enables). |
|||
*/ |
|||
mask = GICD_CTLR_DS | GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1_ALL; |
|||
} else { |
|||
/* For non secure access ARE_NS is RAO/WI and EnableGrp1
|
|||
* is RES0. The only writable bit is [1] (EnableGrp1A), which |
|||
* is an alias of the Secure bit [1]. |
|||
*/ |
|||
mask = GICD_CTLR_EN_GRP1NS; |
|||
} |
|||
} |
|||
s->gicd_ctlr = (s->gicd_ctlr & ~mask) | (value & mask); |
|||
if (value & mask & GICD_CTLR_DS) { |
|||
/* We just set DS, so the ARE_NS and EnG1S bits are now RES0.
|
|||
* Note that this is a one-way transition because if DS is set |
|||
* then it's not writeable, so it can only go back to 0 with a |
|||
* hardware reset. |
|||
*/ |
|||
s->gicd_ctlr &= ~(GICD_CTLR_EN_GRP1S | GICD_CTLR_ARE_NS); |
|||
} |
|||
gicv3_full_update(s); |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_STATUSR: |
|||
/* RAZ/WI for our implementation */ |
|||
return MEMTX_OK; |
|||
case GICD_IGROUPR ... GICD_IGROUPR + 0x7f: |
|||
{ |
|||
int irq; |
|||
|
|||
if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { |
|||
return MEMTX_OK; |
|||
} |
|||
/* RAZ/WI for SGIs, PPIs, unimplemented irqs */ |
|||
irq = (offset - GICD_IGROUPR) * 8; |
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return MEMTX_OK; |
|||
} |
|||
*gic_bmp_ptr32(s->group, irq) = value; |
|||
gicv3_update(s, irq, 32); |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_ISENABLER ... GICD_ISENABLER + 0x7f: |
|||
gicd_write_set_bitmap_reg(s, attrs, s->enabled, NULL, |
|||
offset - GICD_ISENABLER, value); |
|||
return MEMTX_OK; |
|||
case GICD_ICENABLER ... GICD_ICENABLER + 0x7f: |
|||
gicd_write_clear_bitmap_reg(s, attrs, s->enabled, NULL, |
|||
offset - GICD_ICENABLER, value); |
|||
return MEMTX_OK; |
|||
case GICD_ISPENDR ... GICD_ISPENDR + 0x7f: |
|||
gicd_write_set_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge1, |
|||
offset - GICD_ISPENDR, value); |
|||
return MEMTX_OK; |
|||
case GICD_ICPENDR ... GICD_ICPENDR + 0x7f: |
|||
gicd_write_clear_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge2, |
|||
offset - GICD_ICPENDR, value); |
|||
return MEMTX_OK; |
|||
case GICD_ISACTIVER ... GICD_ISACTIVER + 0x7f: |
|||
gicd_write_set_bitmap_reg(s, attrs, s->active, NULL, |
|||
offset - GICD_ISACTIVER, value); |
|||
return MEMTX_OK; |
|||
case GICD_ICACTIVER ... GICD_ICACTIVER + 0x7f: |
|||
gicd_write_clear_bitmap_reg(s, attrs, s->active, NULL, |
|||
offset - GICD_ICACTIVER, value); |
|||
return MEMTX_OK; |
|||
case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: |
|||
{ |
|||
int i, irq = offset - GICD_IPRIORITYR; |
|||
|
|||
if (irq < GIC_INTERNAL || irq + 3 >= s->num_irq) { |
|||
return MEMTX_OK; |
|||
} |
|||
|
|||
for (i = irq; i < irq + 4; i++, value >>= 8) { |
|||
gicd_write_ipriorityr(s, attrs, i, value); |
|||
} |
|||
gicv3_update(s, irq, 4); |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff: |
|||
/* RAZ/WI since affinity routing is always enabled */ |
|||
return MEMTX_OK; |
|||
case GICD_ICFGR ... GICD_ICFGR + 0xff: |
|||
{ |
|||
/* Here only the odd bits are used; even bits are RES0 */ |
|||
int irq = (offset - GICD_ICFGR) * 4; |
|||
uint32_t mask, oldval; |
|||
|
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return MEMTX_OK; |
|||
} |
|||
|
|||
/* Since our edge_trigger bitmap is one bit per irq, our input
|
|||
* 32-bits will compress down into 16 bits which we need |
|||
* to write into the bitmap. |
|||
*/ |
|||
value = half_unshuffle32(value >> 1); |
|||
mask = mask_group_and_nsacr(s, attrs, NULL, irq & ~0x1f); |
|||
if (irq & 0x1f) { |
|||
value <<= 16; |
|||
mask &= 0xffff0000U; |
|||
} else { |
|||
mask &= 0xffff; |
|||
} |
|||
oldval = *gic_bmp_ptr32(s->edge_trigger, (irq & ~0x1f)); |
|||
value = (oldval & ~mask) | (value & mask); |
|||
*gic_bmp_ptr32(s->edge_trigger, irq & ~0x1f) = value; |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_IGRPMODR ... GICD_IGRPMODR + 0xff: |
|||
{ |
|||
int irq; |
|||
|
|||
if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { |
|||
/* RAZ/WI if security disabled, or if
|
|||
* security enabled and this is an NS access |
|||
*/ |
|||
return MEMTX_OK; |
|||
} |
|||
/* RAZ/WI for SGIs, PPIs, unimplemented irqs */ |
|||
irq = (offset - GICD_IGRPMODR) * 8; |
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return MEMTX_OK; |
|||
} |
|||
*gic_bmp_ptr32(s->grpmod, irq) = value; |
|||
gicv3_update(s, irq, 32); |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_NSACR ... GICD_NSACR + 0xff: |
|||
{ |
|||
/* Two bits per interrupt */ |
|||
int irq = (offset - GICD_NSACR) * 4; |
|||
|
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return MEMTX_OK; |
|||
} |
|||
|
|||
if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { |
|||
/* RAZ/WI if security disabled, or if
|
|||
* security enabled and this is an NS access |
|||
*/ |
|||
return MEMTX_OK; |
|||
} |
|||
|
|||
s->gicd_nsacr[irq / 16] = value; |
|||
/* No update required as this only affects access permission checks */ |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_SGIR: |
|||
/* RES0 if affinity routing is enabled */ |
|||
return MEMTX_OK; |
|||
case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf: |
|||
case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf: |
|||
/* RAZ/WI since affinity routing is always enabled */ |
|||
return MEMTX_OK; |
|||
case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: |
|||
{ |
|||
uint64_t r; |
|||
int irq = (offset - GICD_IROUTER) / 8; |
|||
|
|||
if (irq < GIC_INTERNAL || irq >= s->num_irq) { |
|||
return MEMTX_OK; |
|||
} |
|||
|
|||
/* Write half of the 64-bit register */ |
|||
r = gicd_read_irouter(s, attrs, irq); |
|||
r = deposit64(r, (offset & 7) ? 32 : 0, 32, value); |
|||
gicd_write_irouter(s, attrs, irq, r); |
|||
return MEMTX_OK; |
|||
} |
|||
case GICD_IDREGS ... GICD_IDREGS + 0x1f: |
|||
case GICD_TYPER: |
|||
case GICD_IIDR: |
|||
/* RO registers, ignore the write */ |
|||
qemu_log_mask(LOG_GUEST_ERROR, |
|||
"%s: invalid guest write to RO register at offset " |
|||
TARGET_FMT_plx "\n", __func__, offset); |
|||
return MEMTX_OK; |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
static MemTxResult gicd_writell(GICv3State *s, hwaddr offset, |
|||
uint64_t value, MemTxAttrs attrs) |
|||
{ |
|||
/* Our only 64-bit registers are GICD_IROUTER<n> */ |
|||
int irq; |
|||
|
|||
switch (offset) { |
|||
case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: |
|||
irq = (offset - GICD_IROUTER) / 8; |
|||
gicd_write_irouter(s, attrs, irq, value); |
|||
return MEMTX_OK; |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
static MemTxResult gicd_readll(GICv3State *s, hwaddr offset, |
|||
uint64_t *data, MemTxAttrs attrs) |
|||
{ |
|||
/* Our only 64-bit registers are GICD_IROUTER<n> */ |
|||
int irq; |
|||
|
|||
switch (offset) { |
|||
case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: |
|||
irq = (offset - GICD_IROUTER) / 8; |
|||
*data = gicd_read_irouter(s, attrs, irq); |
|||
return MEMTX_OK; |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, |
|||
unsigned size, MemTxAttrs attrs) |
|||
{ |
|||
GICv3State *s = (GICv3State *)opaque; |
|||
MemTxResult r; |
|||
|
|||
switch (size) { |
|||
case 1: |
|||
r = gicd_readb(s, offset, data, attrs); |
|||
break; |
|||
case 2: |
|||
r = gicd_readw(s, offset, data, attrs); |
|||
break; |
|||
case 4: |
|||
r = gicd_readl(s, offset, data, attrs); |
|||
break; |
|||
case 8: |
|||
r = gicd_readll(s, offset, data, attrs); |
|||
break; |
|||
default: |
|||
r = MEMTX_ERROR; |
|||
break; |
|||
} |
|||
|
|||
if (r == MEMTX_ERROR) { |
|||
qemu_log_mask(LOG_GUEST_ERROR, |
|||
"%s: invalid guest read at offset " TARGET_FMT_plx |
|||
"size %u\n", __func__, offset, size); |
|||
trace_gicv3_dist_badread(offset, size, attrs.secure); |
|||
} else { |
|||
trace_gicv3_dist_read(offset, *data, size, attrs.secure); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data, |
|||
unsigned size, MemTxAttrs attrs) |
|||
{ |
|||
GICv3State *s = (GICv3State *)opaque; |
|||
MemTxResult r; |
|||
|
|||
switch (size) { |
|||
case 1: |
|||
r = gicd_writeb(s, offset, data, attrs); |
|||
break; |
|||
case 2: |
|||
r = gicd_writew(s, offset, data, attrs); |
|||
break; |
|||
case 4: |
|||
r = gicd_writel(s, offset, data, attrs); |
|||
break; |
|||
case 8: |
|||
r = gicd_writell(s, offset, data, attrs); |
|||
break; |
|||
default: |
|||
r = MEMTX_ERROR; |
|||
break; |
|||
} |
|||
|
|||
if (r == MEMTX_ERROR) { |
|||
qemu_log_mask(LOG_GUEST_ERROR, |
|||
"%s: invalid guest write at offset " TARGET_FMT_plx |
|||
"size %u\n", __func__, offset, size); |
|||
trace_gicv3_dist_badwrite(offset, data, size, attrs.secure); |
|||
} else { |
|||
trace_gicv3_dist_write(offset, data, size, attrs.secure); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
void gicv3_dist_set_irq(GICv3State *s, int irq, int level) |
|||
{ |
|||
/* Update distributor state for a change in an external SPI input line */ |
|||
if (level == gicv3_gicd_level_test(s, irq)) { |
|||
return; |
|||
} |
|||
|
|||
trace_gicv3_dist_set_irq(irq, level); |
|||
|
|||
gicv3_gicd_level_replace(s, irq, level); |
|||
|
|||
if (level) { |
|||
/* 0->1 edges latch the pending bit for edge-triggered interrupts */ |
|||
if (gicv3_gicd_edge_trigger_test(s, irq)) { |
|||
gicv3_gicd_pending_set(s, irq); |
|||
} |
|||
} |
|||
|
|||
gicv3_update(s, irq, 1); |
|||
} |
|||
@ -0,0 +1,562 @@ |
|||
/*
|
|||
* ARM GICv3 emulation: Redistributor |
|||
* |
|||
* Copyright (c) 2015 Huawei. |
|||
* Copyright (c) 2016 Linaro Limited. |
|||
* Written by Shlomo Pongratz, Peter Maydell |
|||
* |
|||
* This code is licensed under the GPL, version 2 or (at your option) |
|||
* any later version. |
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include "trace.h" |
|||
#include "gicv3_internal.h" |
|||
|
|||
static uint32_t mask_group(GICv3CPUState *cs, MemTxAttrs attrs) |
|||
{ |
|||
/* Return a 32-bit mask which should be applied for this set of 32
|
|||
* interrupts; each bit is 1 if access is permitted by the |
|||
* combination of attrs.secure and GICR_GROUPR. (GICR_NSACR does |
|||
* not affect config register accesses, unlike GICD_NSACR.) |
|||
*/ |
|||
if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { |
|||
/* bits for Group 0 or Secure Group 1 interrupts are RAZ/WI */ |
|||
return cs->gicr_igroupr0; |
|||
} |
|||
return 0xFFFFFFFFU; |
|||
} |
|||
|
|||
static int gicr_ns_access(GICv3CPUState *cs, int irq) |
|||
{ |
|||
/* Return the 2 bit NSACR.NS_access field for this SGI */ |
|||
assert(irq < 16); |
|||
return extract32(cs->gicr_nsacr, irq * 2, 2); |
|||
} |
|||
|
|||
static void gicr_write_set_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs, |
|||
uint32_t *reg, uint32_t val) |
|||
{ |
|||
/* Helper routine to implement writing to a "set-bitmap" register */ |
|||
val &= mask_group(cs, attrs); |
|||
*reg |= val; |
|||
gicv3_redist_update(cs); |
|||
} |
|||
|
|||
static void gicr_write_clear_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs, |
|||
uint32_t *reg, uint32_t val) |
|||
{ |
|||
/* Helper routine to implement writing to a "clear-bitmap" register */ |
|||
val &= mask_group(cs, attrs); |
|||
*reg &= ~val; |
|||
gicv3_redist_update(cs); |
|||
} |
|||
|
|||
static uint32_t gicr_read_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs, |
|||
uint32_t reg) |
|||
{ |
|||
reg &= mask_group(cs, attrs); |
|||
return reg; |
|||
} |
|||
|
|||
static uint8_t gicr_read_ipriorityr(GICv3CPUState *cs, MemTxAttrs attrs, |
|||
int irq) |
|||
{ |
|||
/* Read the value of GICR_IPRIORITYR<n> for the specified interrupt,
|
|||
* honouring security state (these are RAZ/WI for Group 0 or Secure |
|||
* Group 1 interrupts). |
|||
*/ |
|||
uint32_t prio; |
|||
|
|||
prio = cs->gicr_ipriorityr[irq]; |
|||
|
|||
if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { |
|||
if (!(cs->gicr_igroupr0 & (1U << irq))) { |
|||
/* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */ |
|||
return 0; |
|||
} |
|||
/* NS view of the interrupt priority */ |
|||
prio = (prio << 1) & 0xff; |
|||
} |
|||
return prio; |
|||
} |
|||
|
|||
static void gicr_write_ipriorityr(GICv3CPUState *cs, MemTxAttrs attrs, int irq, |
|||
uint8_t value) |
|||
{ |
|||
/* Write the value of GICD_IPRIORITYR<n> for the specified interrupt,
|
|||
* honouring security state (these are RAZ/WI for Group 0 or Secure |
|||
* Group 1 interrupts). |
|||
*/ |
|||
if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { |
|||
if (!(cs->gicr_igroupr0 & (1U << irq))) { |
|||
/* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */ |
|||
return; |
|||
} |
|||
/* NS view of the interrupt priority */ |
|||
value = 0x80 | (value >> 1); |
|||
} |
|||
cs->gicr_ipriorityr[irq] = value; |
|||
} |
|||
|
|||
static MemTxResult gicr_readb(GICv3CPUState *cs, hwaddr offset, |
|||
uint64_t *data, MemTxAttrs attrs) |
|||
{ |
|||
switch (offset) { |
|||
case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f: |
|||
*data = gicr_read_ipriorityr(cs, attrs, offset - GICR_IPRIORITYR); |
|||
return MEMTX_OK; |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
static MemTxResult gicr_writeb(GICv3CPUState *cs, hwaddr offset, |
|||
uint64_t value, MemTxAttrs attrs) |
|||
{ |
|||
switch (offset) { |
|||
case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f: |
|||
gicr_write_ipriorityr(cs, attrs, offset - GICR_IPRIORITYR, value); |
|||
gicv3_redist_update(cs); |
|||
return MEMTX_OK; |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
static MemTxResult gicr_readl(GICv3CPUState *cs, hwaddr offset, |
|||
uint64_t *data, MemTxAttrs attrs) |
|||
{ |
|||
switch (offset) { |
|||
case GICR_CTLR: |
|||
*data = cs->gicr_ctlr; |
|||
return MEMTX_OK; |
|||
case GICR_IIDR: |
|||
*data = gicv3_iidr(); |
|||
return MEMTX_OK; |
|||
case GICR_TYPER: |
|||
*data = extract64(cs->gicr_typer, 0, 32); |
|||
return MEMTX_OK; |
|||
case GICR_TYPER + 4: |
|||
*data = extract64(cs->gicr_typer, 32, 32); |
|||
return MEMTX_OK; |
|||
case GICR_STATUSR: |
|||
/* RAZ/WI for us (this is an optional register and our implementation
|
|||
* does not track RO/WO/reserved violations to report them to the guest) |
|||
*/ |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
case GICR_WAKER: |
|||
*data = cs->gicr_waker; |
|||
return MEMTX_OK; |
|||
case GICR_PROPBASER: |
|||
*data = extract64(cs->gicr_propbaser, 0, 32); |
|||
return MEMTX_OK; |
|||
case GICR_PROPBASER + 4: |
|||
*data = extract64(cs->gicr_propbaser, 32, 32); |
|||
return MEMTX_OK; |
|||
case GICR_PENDBASER: |
|||
*data = extract64(cs->gicr_pendbaser, 0, 32); |
|||
return MEMTX_OK; |
|||
case GICR_PENDBASER + 4: |
|||
*data = extract64(cs->gicr_pendbaser, 32, 32); |
|||
return MEMTX_OK; |
|||
case GICR_IGROUPR0: |
|||
if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
} |
|||
*data = cs->gicr_igroupr0; |
|||
return MEMTX_OK; |
|||
case GICR_ISENABLER0: |
|||
case GICR_ICENABLER0: |
|||
*data = gicr_read_bitmap_reg(cs, attrs, cs->gicr_ienabler0); |
|||
return MEMTX_OK; |
|||
case GICR_ISPENDR0: |
|||
case GICR_ICPENDR0: |
|||
{ |
|||
/* The pending register reads as the logical OR of the pending
|
|||
* latch and the input line level for level-triggered interrupts. |
|||
*/ |
|||
uint32_t val = cs->gicr_ipendr0 | (~cs->edge_trigger & cs->level); |
|||
*data = gicr_read_bitmap_reg(cs, attrs, val); |
|||
return MEMTX_OK; |
|||
} |
|||
case GICR_ISACTIVER0: |
|||
case GICR_ICACTIVER0: |
|||
*data = gicr_read_bitmap_reg(cs, attrs, cs->gicr_iactiver0); |
|||
return MEMTX_OK; |
|||
case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f: |
|||
{ |
|||
int i, irq = offset - GICR_IPRIORITYR; |
|||
uint32_t value = 0; |
|||
|
|||
for (i = irq + 3; i >= irq; i--, value <<= 8) { |
|||
value |= gicr_read_ipriorityr(cs, attrs, i); |
|||
} |
|||
*data = value; |
|||
return MEMTX_OK; |
|||
} |
|||
case GICR_ICFGR0: |
|||
case GICR_ICFGR1: |
|||
{ |
|||
/* Our edge_trigger bitmap is one bit per irq; take the correct
|
|||
* half of it, and spread it out into the odd bits. |
|||
*/ |
|||
uint32_t value; |
|||
|
|||
value = cs->edge_trigger & mask_group(cs, attrs); |
|||
value = extract32(value, (offset == GICR_ICFGR1) ? 16 : 0, 16); |
|||
value = half_shuffle32(value) << 1; |
|||
*data = value; |
|||
return MEMTX_OK; |
|||
} |
|||
case GICR_IGRPMODR0: |
|||
if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { |
|||
/* RAZ/WI if security disabled, or if
|
|||
* security enabled and this is an NS access |
|||
*/ |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
} |
|||
*data = cs->gicr_igrpmodr0; |
|||
return MEMTX_OK; |
|||
case GICR_NSACR: |
|||
if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { |
|||
/* RAZ/WI if security disabled, or if
|
|||
* security enabled and this is an NS access |
|||
*/ |
|||
*data = 0; |
|||
return MEMTX_OK; |
|||
} |
|||
*data = cs->gicr_nsacr; |
|||
return MEMTX_OK; |
|||
case GICR_IDREGS ... GICR_IDREGS + 0x1f: |
|||
*data = gicv3_idreg(offset - GICR_IDREGS); |
|||
return MEMTX_OK; |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, |
|||
uint64_t value, MemTxAttrs attrs) |
|||
{ |
|||
switch (offset) { |
|||
case GICR_CTLR: |
|||
/* For our implementation, GICR_TYPER.DPGS is 0 and so all
|
|||
* the DPG bits are RAZ/WI. We don't do anything asynchronously, |
|||
* so UWP and RWP are RAZ/WI. And GICR_TYPER.LPIS is 0 (we don't |
|||
* implement LPIs) so Enable_LPIs is RES0. So there are no writable |
|||
* bits for us. |
|||
*/ |
|||
return MEMTX_OK; |
|||
case GICR_STATUSR: |
|||
/* RAZ/WI for our implementation */ |
|||
return MEMTX_OK; |
|||
case GICR_WAKER: |
|||
/* Only the ProcessorSleep bit is writeable. When the guest sets
|
|||
* it it requests that we transition the channel between the |
|||
* redistributor and the cpu interface to quiescent, and that |
|||
* we set the ChildrenAsleep bit once the inteface has reached the |
|||
* quiescent state. |
|||
* Setting the ProcessorSleep to 0 reverses the quiescing, and |
|||
* ChildrenAsleep is cleared once the transition is complete. |
|||
* Since our interface is not asynchronous, we complete these |
|||
* transitions instantaneously, so we set ChildrenAsleep to the |
|||
* same value as ProcessorSleep here. |
|||
*/ |
|||
value &= GICR_WAKER_ProcessorSleep; |
|||
if (value & GICR_WAKER_ProcessorSleep) { |
|||
value |= GICR_WAKER_ChildrenAsleep; |
|||
} |
|||
cs->gicr_waker = value; |
|||
return MEMTX_OK; |
|||
case GICR_PROPBASER: |
|||
cs->gicr_propbaser = deposit64(cs->gicr_propbaser, 0, 32, value); |
|||
return MEMTX_OK; |
|||
case GICR_PROPBASER + 4: |
|||
cs->gicr_propbaser = deposit64(cs->gicr_propbaser, 32, 32, value); |
|||
return MEMTX_OK; |
|||
case GICR_PENDBASER: |
|||
cs->gicr_pendbaser = deposit64(cs->gicr_pendbaser, 0, 32, value); |
|||
return MEMTX_OK; |
|||
case GICR_PENDBASER + 4: |
|||
cs->gicr_pendbaser = deposit64(cs->gicr_pendbaser, 32, 32, value); |
|||
return MEMTX_OK; |
|||
case GICR_IGROUPR0: |
|||
if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { |
|||
return MEMTX_OK; |
|||
} |
|||
cs->gicr_igroupr0 = value; |
|||
gicv3_redist_update(cs); |
|||
return MEMTX_OK; |
|||
case GICR_ISENABLER0: |
|||
gicr_write_set_bitmap_reg(cs, attrs, &cs->gicr_ienabler0, value); |
|||
return MEMTX_OK; |
|||
case GICR_ICENABLER0: |
|||
gicr_write_clear_bitmap_reg(cs, attrs, &cs->gicr_ienabler0, value); |
|||
return MEMTX_OK; |
|||
case GICR_ISPENDR0: |
|||
gicr_write_set_bitmap_reg(cs, attrs, &cs->gicr_ipendr0, value); |
|||
return MEMTX_OK; |
|||
case GICR_ICPENDR0: |
|||
gicr_write_clear_bitmap_reg(cs, attrs, &cs->gicr_ipendr0, value); |
|||
return MEMTX_OK; |
|||
case GICR_ISACTIVER0: |
|||
gicr_write_set_bitmap_reg(cs, attrs, &cs->gicr_iactiver0, value); |
|||
return MEMTX_OK; |
|||
case GICR_ICACTIVER0: |
|||
gicr_write_clear_bitmap_reg(cs, attrs, &cs->gicr_iactiver0, value); |
|||
return MEMTX_OK; |
|||
case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f: |
|||
{ |
|||
int i, irq = offset - GICR_IPRIORITYR; |
|||
|
|||
for (i = irq; i < irq + 4; i++, value >>= 8) { |
|||
gicr_write_ipriorityr(cs, attrs, i, value); |
|||
} |
|||
gicv3_redist_update(cs); |
|||
return MEMTX_OK; |
|||
} |
|||
case GICR_ICFGR0: |
|||
/* Register is all RAZ/WI or RAO/WI bits */ |
|||
return MEMTX_OK; |
|||
case GICR_ICFGR1: |
|||
{ |
|||
uint32_t mask; |
|||
|
|||
/* Since our edge_trigger bitmap is one bit per irq, our input
|
|||
* 32-bits will compress down into 16 bits which we need |
|||
* to write into the bitmap. |
|||
*/ |
|||
value = half_unshuffle32(value >> 1) << 16; |
|||
mask = mask_group(cs, attrs) & 0xffff0000U; |
|||
|
|||
cs->edge_trigger &= ~mask; |
|||
cs->edge_trigger |= (value & mask); |
|||
|
|||
gicv3_redist_update(cs); |
|||
return MEMTX_OK; |
|||
} |
|||
case GICR_IGRPMODR0: |
|||
if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { |
|||
/* RAZ/WI if security disabled, or if
|
|||
* security enabled and this is an NS access |
|||
*/ |
|||
return MEMTX_OK; |
|||
} |
|||
cs->gicr_igrpmodr0 = value; |
|||
gicv3_redist_update(cs); |
|||
return MEMTX_OK; |
|||
case GICR_NSACR: |
|||
if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { |
|||
/* RAZ/WI if security disabled, or if
|
|||
* security enabled and this is an NS access |
|||
*/ |
|||
return MEMTX_OK; |
|||
} |
|||
cs->gicr_nsacr = value; |
|||
/* no update required as this only affects access permission checks */ |
|||
return MEMTX_OK; |
|||
case GICR_IIDR: |
|||
case GICR_TYPER: |
|||
case GICR_IDREGS ... GICR_IDREGS + 0x1f: |
|||
/* RO registers, ignore the write */ |
|||
qemu_log_mask(LOG_GUEST_ERROR, |
|||
"%s: invalid guest write to RO register at offset " |
|||
TARGET_FMT_plx "\n", __func__, offset); |
|||
return MEMTX_OK; |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
static MemTxResult gicr_readll(GICv3CPUState *cs, hwaddr offset, |
|||
uint64_t *data, MemTxAttrs attrs) |
|||
{ |
|||
switch (offset) { |
|||
case GICR_TYPER: |
|||
*data = cs->gicr_typer; |
|||
return MEMTX_OK; |
|||
case GICR_PROPBASER: |
|||
*data = cs->gicr_propbaser; |
|||
return MEMTX_OK; |
|||
case GICR_PENDBASER: |
|||
*data = cs->gicr_pendbaser; |
|||
return MEMTX_OK; |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
static MemTxResult gicr_writell(GICv3CPUState *cs, hwaddr offset, |
|||
uint64_t value, MemTxAttrs attrs) |
|||
{ |
|||
switch (offset) { |
|||
case GICR_PROPBASER: |
|||
cs->gicr_propbaser = value; |
|||
return MEMTX_OK; |
|||
case GICR_PENDBASER: |
|||
cs->gicr_pendbaser = value; |
|||
return MEMTX_OK; |
|||
case GICR_TYPER: |
|||
/* RO register, ignore the write */ |
|||
qemu_log_mask(LOG_GUEST_ERROR, |
|||
"%s: invalid guest write to RO register at offset " |
|||
TARGET_FMT_plx "\n", __func__, offset); |
|||
return MEMTX_OK; |
|||
default: |
|||
return MEMTX_ERROR; |
|||
} |
|||
} |
|||
|
|||
MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data, |
|||
unsigned size, MemTxAttrs attrs) |
|||
{ |
|||
GICv3State *s = opaque; |
|||
GICv3CPUState *cs; |
|||
MemTxResult r; |
|||
int cpuidx; |
|||
|
|||
/* This region covers all the redistributor pages; there are
|
|||
* (for GICv3) two 64K pages per CPU. At the moment they are |
|||
* all contiguous (ie in this one region), though we might later |
|||
* want to allow splitting of redistributor pages into several |
|||
* blocks so we can support more CPUs. |
|||
*/ |
|||
cpuidx = offset / 0x20000; |
|||
offset %= 0x20000; |
|||
assert(cpuidx < s->num_cpu); |
|||
|
|||
cs = &s->cpu[cpuidx]; |
|||
|
|||
switch (size) { |
|||
case 1: |
|||
r = gicr_readb(cs, offset, data, attrs); |
|||
break; |
|||
case 4: |
|||
r = gicr_readl(cs, offset, data, attrs); |
|||
break; |
|||
case 8: |
|||
r = gicr_readll(cs, offset, data, attrs); |
|||
break; |
|||
default: |
|||
r = MEMTX_ERROR; |
|||
break; |
|||
} |
|||
|
|||
if (r == MEMTX_ERROR) { |
|||
qemu_log_mask(LOG_GUEST_ERROR, |
|||
"%s: invalid guest read at offset " TARGET_FMT_plx |
|||
"size %u\n", __func__, offset, size); |
|||
trace_gicv3_redist_badread(gicv3_redist_affid(cs), offset, |
|||
size, attrs.secure); |
|||
} else { |
|||
trace_gicv3_redist_read(gicv3_redist_affid(cs), offset, *data, |
|||
size, attrs.secure); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, |
|||
unsigned size, MemTxAttrs attrs) |
|||
{ |
|||
GICv3State *s = opaque; |
|||
GICv3CPUState *cs; |
|||
MemTxResult r; |
|||
int cpuidx; |
|||
|
|||
/* This region covers all the redistributor pages; there are
|
|||
* (for GICv3) two 64K pages per CPU. At the moment they are |
|||
* all contiguous (ie in this one region), though we might later |
|||
* want to allow splitting of redistributor pages into several |
|||
* blocks so we can support more CPUs. |
|||
*/ |
|||
cpuidx = offset / 0x20000; |
|||
offset %= 0x20000; |
|||
assert(cpuidx < s->num_cpu); |
|||
|
|||
cs = &s->cpu[cpuidx]; |
|||
|
|||
switch (size) { |
|||
case 1: |
|||
r = gicr_writeb(cs, offset, data, attrs); |
|||
break; |
|||
case 4: |
|||
r = gicr_writel(cs, offset, data, attrs); |
|||
break; |
|||
case 8: |
|||
r = gicr_writell(cs, offset, data, attrs); |
|||
break; |
|||
default: |
|||
r = MEMTX_ERROR; |
|||
break; |
|||
} |
|||
|
|||
if (r == MEMTX_ERROR) { |
|||
qemu_log_mask(LOG_GUEST_ERROR, |
|||
"%s: invalid guest write at offset " TARGET_FMT_plx |
|||
"size %u\n", __func__, offset, size); |
|||
trace_gicv3_redist_badwrite(gicv3_redist_affid(cs), offset, data, |
|||
size, attrs.secure); |
|||
} else { |
|||
trace_gicv3_redist_write(gicv3_redist_affid(cs), offset, data, |
|||
size, attrs.secure); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level) |
|||
{ |
|||
/* Update redistributor state for a change in an external PPI input line */ |
|||
if (level == extract32(cs->level, irq, 1)) { |
|||
return; |
|||
} |
|||
|
|||
trace_gicv3_redist_set_irq(gicv3_redist_affid(cs), irq, level); |
|||
|
|||
cs->level = deposit32(cs->level, irq, 1, level); |
|||
|
|||
if (level) { |
|||
/* 0->1 edges latch the pending bit for edge-triggered interrupts */ |
|||
if (extract32(cs->edge_trigger, irq, 1)) { |
|||
cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 1); |
|||
} |
|||
} |
|||
|
|||
gicv3_redist_update(cs); |
|||
} |
|||
|
|||
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns) |
|||
{ |
|||
/* Update redistributor state for a generated SGI */ |
|||
int irqgrp = gicv3_irq_group(cs->gic, cs, irq); |
|||
|
|||
/* If we are asked for a Secure Group 1 SGI and it's actually
|
|||
* configured as Secure Group 0 this is OK (subject to the usual |
|||
* NSACR checks). |
|||
*/ |
|||
if (grp == GICV3_G1 && irqgrp == GICV3_G0) { |
|||
grp = GICV3_G0; |
|||
} |
|||
|
|||
if (grp != irqgrp) { |
|||
return; |
|||
} |
|||
|
|||
if (ns && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { |
|||
/* If security is enabled we must test the NSACR bits */ |
|||
int nsaccess = gicr_ns_access(cs, irq); |
|||
|
|||
if ((irqgrp == GICV3_G0 && nsaccess < 1) || |
|||
(irqgrp == GICV3_G1 && nsaccess < 2)) { |
|||
return; |
|||
} |
|||
} |
|||
|
|||
/* OK, we can accept the SGI */ |
|||
trace_gicv3_redist_send_sgi(gicv3_redist_affid(cs), irq); |
|||
cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 1); |
|||
gicv3_redist_update(cs); |
|||
} |
|||
@ -0,0 +1,331 @@ |
|||
/*
|
|||
* ARM GICv3 support - internal interfaces |
|||
* |
|||
* Copyright (c) 2012 Linaro Limited |
|||
* Copyright (c) 2015 Huawei. |
|||
* Copyright (c) 2015 Samsung Electronics Co., Ltd. |
|||
* Written by Peter Maydell |
|||
* Reworked for GICv3 by Shlomo Pongratz and Pavel Fedin |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program 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 General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License along |
|||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#ifndef QEMU_ARM_GICV3_INTERNAL_H |
|||
#define QEMU_ARM_GICV3_INTERNAL_H |
|||
|
|||
#include "hw/intc/arm_gicv3_common.h" |
|||
|
|||
/* Distributor registers, as offsets from the distributor base address */ |
|||
#define GICD_CTLR 0x0000 |
|||
#define GICD_TYPER 0x0004 |
|||
#define GICD_IIDR 0x0008 |
|||
#define GICD_STATUSR 0x0010 |
|||
#define GICD_SETSPI_NSR 0x0040 |
|||
#define GICD_CLRSPI_NSR 0x0048 |
|||
#define GICD_SETSPI_SR 0x0050 |
|||
#define GICD_CLRSPI_SR 0x0058 |
|||
#define GICD_SEIR 0x0068 |
|||
#define GICD_IGROUPR 0x0080 |
|||
#define GICD_ISENABLER 0x0100 |
|||
#define GICD_ICENABLER 0x0180 |
|||
#define GICD_ISPENDR 0x0200 |
|||
#define GICD_ICPENDR 0x0280 |
|||
#define GICD_ISACTIVER 0x0300 |
|||
#define GICD_ICACTIVER 0x0380 |
|||
#define GICD_IPRIORITYR 0x0400 |
|||
#define GICD_ITARGETSR 0x0800 |
|||
#define GICD_ICFGR 0x0C00 |
|||
#define GICD_IGRPMODR 0x0D00 |
|||
#define GICD_NSACR 0x0E00 |
|||
#define GICD_SGIR 0x0F00 |
|||
#define GICD_CPENDSGIR 0x0F10 |
|||
#define GICD_SPENDSGIR 0x0F20 |
|||
#define GICD_IROUTER 0x6000 |
|||
#define GICD_IDREGS 0xFFD0 |
|||
|
|||
/* GICD_CTLR fields */ |
|||
#define GICD_CTLR_EN_GRP0 (1U << 0) |
|||
#define GICD_CTLR_EN_GRP1NS (1U << 1) /* GICv3 5.3.20 */ |
|||
#define GICD_CTLR_EN_GRP1S (1U << 2) |
|||
#define GICD_CTLR_EN_GRP1_ALL (GICD_CTLR_EN_GRP1NS | GICD_CTLR_EN_GRP1S) |
|||
/* Bit 4 is ARE if the system doesn't support TrustZone, ARE_S otherwise */ |
|||
#define GICD_CTLR_ARE (1U << 4) |
|||
#define GICD_CTLR_ARE_S (1U << 4) |
|||
#define GICD_CTLR_ARE_NS (1U << 5) |
|||
#define GICD_CTLR_DS (1U << 6) |
|||
#define GICD_CTLR_E1NWF (1U << 7) |
|||
#define GICD_CTLR_RWP (1U << 31) |
|||
|
|||
/*
|
|||
* Redistributor frame offsets from RD_base |
|||
*/ |
|||
#define GICR_SGI_OFFSET 0x10000 |
|||
|
|||
/*
|
|||
* Redistributor registers, offsets from RD_base |
|||
*/ |
|||
#define GICR_CTLR 0x0000 |
|||
#define GICR_IIDR 0x0004 |
|||
#define GICR_TYPER 0x0008 |
|||
#define GICR_STATUSR 0x0010 |
|||
#define GICR_WAKER 0x0014 |
|||
#define GICR_SETLPIR 0x0040 |
|||
#define GICR_CLRLPIR 0x0048 |
|||
#define GICR_PROPBASER 0x0070 |
|||
#define GICR_PENDBASER 0x0078 |
|||
#define GICR_INVLPIR 0x00A0 |
|||
#define GICR_INVALLR 0x00B0 |
|||
#define GICR_SYNCR 0x00C0 |
|||
#define GICR_IDREGS 0xFFD0 |
|||
|
|||
/* SGI and PPI Redistributor registers, offsets from RD_base */ |
|||
#define GICR_IGROUPR0 (GICR_SGI_OFFSET + 0x0080) |
|||
#define GICR_ISENABLER0 (GICR_SGI_OFFSET + 0x0100) |
|||
#define GICR_ICENABLER0 (GICR_SGI_OFFSET + 0x0180) |
|||
#define GICR_ISPENDR0 (GICR_SGI_OFFSET + 0x0200) |
|||
#define GICR_ICPENDR0 (GICR_SGI_OFFSET + 0x0280) |
|||
#define GICR_ISACTIVER0 (GICR_SGI_OFFSET + 0x0300) |
|||
#define GICR_ICACTIVER0 (GICR_SGI_OFFSET + 0x0380) |
|||
#define GICR_IPRIORITYR (GICR_SGI_OFFSET + 0x0400) |
|||
#define GICR_ICFGR0 (GICR_SGI_OFFSET + 0x0C00) |
|||
#define GICR_ICFGR1 (GICR_SGI_OFFSET + 0x0C04) |
|||
#define GICR_IGRPMODR0 (GICR_SGI_OFFSET + 0x0D00) |
|||
#define GICR_NSACR (GICR_SGI_OFFSET + 0x0E00) |
|||
|
|||
#define GICR_CTLR_ENABLE_LPIS (1U << 0) |
|||
#define GICR_CTLR_RWP (1U << 3) |
|||
#define GICR_CTLR_DPG0 (1U << 24) |
|||
#define GICR_CTLR_DPG1NS (1U << 25) |
|||
#define GICR_CTLR_DPG1S (1U << 26) |
|||
#define GICR_CTLR_UWP (1U << 31) |
|||
|
|||
#define GICR_TYPER_PLPIS (1U << 0) |
|||
#define GICR_TYPER_VLPIS (1U << 1) |
|||
#define GICR_TYPER_DIRECTLPI (1U << 3) |
|||
#define GICR_TYPER_LAST (1U << 4) |
|||
#define GICR_TYPER_DPGS (1U << 5) |
|||
#define GICR_TYPER_PROCNUM (0xFFFFU << 8) |
|||
#define GICR_TYPER_COMMONLPIAFF (0x3 << 24) |
|||
#define GICR_TYPER_AFFINITYVALUE (0xFFFFFFFFULL << 32) |
|||
|
|||
#define GICR_WAKER_ProcessorSleep (1U << 1) |
|||
#define GICR_WAKER_ChildrenAsleep (1U << 2) |
|||
|
|||
#define GICR_PROPBASER_OUTER_CACHEABILITY_MASK (7ULL << 56) |
|||
#define GICR_PROPBASER_ADDR_MASK (0xfffffffffULL << 12) |
|||
#define GICR_PROPBASER_SHAREABILITY_MASK (3U << 10) |
|||
#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7) |
|||
#define GICR_PROPBASER_IDBITS_MASK (0x1f) |
|||
|
|||
#define GICR_PENDBASER_PTZ (1ULL << 62) |
|||
#define GICR_PENDBASER_OUTER_CACHEABILITY_MASK (7ULL << 56) |
|||
#define GICR_PENDBASER_ADDR_MASK (0xffffffffULL << 16) |
|||
#define GICR_PENDBASER_SHAREABILITY_MASK (3U << 10) |
|||
#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7) |
|||
|
|||
#define ICC_CTLR_EL1_CBPR (1U << 0) |
|||
#define ICC_CTLR_EL1_EOIMODE (1U << 1) |
|||
#define ICC_CTLR_EL1_PMHE (1U << 6) |
|||
#define ICC_CTLR_EL1_PRIBITS_SHIFT 8 |
|||
#define ICC_CTLR_EL1_IDBITS_SHIFT 11 |
|||
#define ICC_CTLR_EL1_SEIS (1U << 14) |
|||
#define ICC_CTLR_EL1_A3V (1U << 15) |
|||
|
|||
#define ICC_PMR_PRIORITY_MASK 0xff |
|||
#define ICC_BPR_BINARYPOINT_MASK 0x07 |
|||
#define ICC_IGRPEN_ENABLE 0x01 |
|||
|
|||
#define ICC_CTLR_EL3_CBPR_EL1S (1U << 0) |
|||
#define ICC_CTLR_EL3_CBPR_EL1NS (1U << 1) |
|||
#define ICC_CTLR_EL3_EOIMODE_EL3 (1U << 2) |
|||
#define ICC_CTLR_EL3_EOIMODE_EL1S (1U << 3) |
|||
#define ICC_CTLR_EL3_EOIMODE_EL1NS (1U << 4) |
|||
#define ICC_CTLR_EL3_RM (1U << 5) |
|||
#define ICC_CTLR_EL3_PMHE (1U << 6) |
|||
#define ICC_CTLR_EL3_PRIBITS_SHIFT 8 |
|||
#define ICC_CTLR_EL3_IDBITS_SHIFT 11 |
|||
#define ICC_CTLR_EL3_SEIS (1U << 14) |
|||
#define ICC_CTLR_EL3_A3V (1U << 15) |
|||
#define ICC_CTLR_EL3_NDS (1U << 17) |
|||
|
|||
/* Special interrupt IDs */ |
|||
#define INTID_SECURE 1020 |
|||
#define INTID_NONSECURE 1021 |
|||
#define INTID_SPURIOUS 1023 |
|||
|
|||
/* Functions internal to the emulated GICv3 */ |
|||
|
|||
/**
|
|||
* gicv3_redist_update: |
|||
* @cs: GICv3CPUState for this redistributor |
|||
* |
|||
* Recalculate the highest priority pending interrupt after a |
|||
* change to redistributor state, and inform the CPU accordingly. |
|||
*/ |
|||
void gicv3_redist_update(GICv3CPUState *cs); |
|||
|
|||
/**
|
|||
* gicv3_update: |
|||
* @s: GICv3State |
|||
* @start: first interrupt whose state changed |
|||
* @len: length of the range of interrupts whose state changed |
|||
* |
|||
* Recalculate the highest priority pending interrupts after a |
|||
* change to the distributor state affecting @len interrupts |
|||
* starting at @start, and inform the CPUs accordingly. |
|||
*/ |
|||
void gicv3_update(GICv3State *s, int start, int len); |
|||
|
|||
/**
|
|||
* gicv3_full_update_noirqset: |
|||
* @s: GICv3State |
|||
* |
|||
* Recalculate the cached information about highest priority |
|||
* pending interrupts, but don't inform the CPUs. This should be |
|||
* called after an incoming migration has loaded new state. |
|||
*/ |
|||
void gicv3_full_update_noirqset(GICv3State *s); |
|||
|
|||
/**
|
|||
* gicv3_full_update: |
|||
* @s: GICv3State |
|||
* |
|||
* Recalculate the highest priority pending interrupts after |
|||
* a change that could affect the status of all interrupts, |
|||
* and inform the CPUs accordingly. |
|||
*/ |
|||
void gicv3_full_update(GICv3State *s); |
|||
MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, |
|||
unsigned size, MemTxAttrs attrs); |
|||
MemTxResult gicv3_dist_write(void *opaque, hwaddr addr, uint64_t data, |
|||
unsigned size, MemTxAttrs attrs); |
|||
MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data, |
|||
unsigned size, MemTxAttrs attrs); |
|||
MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, |
|||
unsigned size, MemTxAttrs attrs); |
|||
void gicv3_dist_set_irq(GICv3State *s, int irq, int level); |
|||
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level); |
|||
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns); |
|||
void gicv3_init_cpuif(GICv3State *s); |
|||
|
|||
/**
|
|||
* gicv3_cpuif_update: |
|||
* @cs: GICv3CPUState for the CPU to update |
|||
* |
|||
* Recalculate whether to assert the IRQ or FIQ lines after a change |
|||
* to the current highest priority pending interrupt, the CPU's |
|||
* current running priority or the CPU's current exception level or |
|||
* security state. |
|||
*/ |
|||
void gicv3_cpuif_update(GICv3CPUState *cs); |
|||
|
|||
static inline uint32_t gicv3_iidr(void) |
|||
{ |
|||
/* Return the Implementer Identification Register value
|
|||
* for the emulated GICv3, as reported in GICD_IIDR and GICR_IIDR. |
|||
* |
|||
* We claim to be an ARM r0p0 with a zero ProductID. |
|||
* This is the same as an r0p0 GIC-500. |
|||
*/ |
|||
return 0x43b; |
|||
} |
|||
|
|||
static inline uint32_t gicv3_idreg(int regoffset) |
|||
{ |
|||
/* Return the value of the CoreSight ID register at the specified
|
|||
* offset from the first ID register (as found in the distributor |
|||
* and redistributor register banks). |
|||
* These values indicate an ARM implementation of a GICv3. |
|||
*/ |
|||
static const uint8_t gicd_ids[] = { |
|||
0x44, 0x00, 0x00, 0x00, 0x92, 0xB4, 0x3B, 0x00, 0x0D, 0xF0, 0x05, 0xB1 |
|||
}; |
|||
return gicd_ids[regoffset / 4]; |
|||
} |
|||
|
|||
/**
|
|||
* gicv3_irq_group: |
|||
* |
|||
* Return the group which this interrupt is configured as (GICV3_G0, |
|||
* GICV3_G1 or GICV3_G1NS). |
|||
*/ |
|||
static inline int gicv3_irq_group(GICv3State *s, GICv3CPUState *cs, int irq) |
|||
{ |
|||
bool grpbit, grpmodbit; |
|||
|
|||
if (irq < GIC_INTERNAL) { |
|||
grpbit = extract32(cs->gicr_igroupr0, irq, 1); |
|||
grpmodbit = extract32(cs->gicr_igrpmodr0, irq, 1); |
|||
} else { |
|||
grpbit = gicv3_gicd_group_test(s, irq); |
|||
grpmodbit = gicv3_gicd_grpmod_test(s, irq); |
|||
} |
|||
if (grpbit) { |
|||
return GICV3_G1NS; |
|||
} |
|||
if (s->gicd_ctlr & GICD_CTLR_DS) { |
|||
return GICV3_G0; |
|||
} |
|||
return grpmodbit ? GICV3_G1 : GICV3_G0; |
|||
} |
|||
|
|||
/**
|
|||
* gicv3_redist_affid: |
|||
* |
|||
* Return the 32-bit affinity ID of the CPU connected to this redistributor |
|||
*/ |
|||
static inline uint32_t gicv3_redist_affid(GICv3CPUState *cs) |
|||
{ |
|||
return cs->gicr_typer >> 32; |
|||
} |
|||
|
|||
/**
|
|||
* gicv3_cache_target_cpustate: |
|||
* |
|||
* Update the cached CPU state corresponding to the target for this interrupt |
|||
* (which is kept in s->gicd_irouter_target[]). |
|||
*/ |
|||
static inline void gicv3_cache_target_cpustate(GICv3State *s, int irq) |
|||
{ |
|||
GICv3CPUState *cs = NULL; |
|||
int i; |
|||
uint32_t tgtaff = extract64(s->gicd_irouter[irq], 0, 24) | |
|||
extract64(s->gicd_irouter[irq], 32, 8) << 24; |
|||
|
|||
for (i = 0; i < s->num_cpu; i++) { |
|||
if (s->cpu[i].gicr_typer >> 32 == tgtaff) { |
|||
cs = &s->cpu[i]; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
s->gicd_irouter_target[irq] = cs; |
|||
} |
|||
|
|||
/**
|
|||
* gicv3_cache_all_target_cpustates: |
|||
* |
|||
* Populate the entire cache of CPU state pointers for interrupt targets |
|||
* (eg after inbound migration or CPU reset) |
|||
*/ |
|||
static inline void gicv3_cache_all_target_cpustates(GICv3State *s) |
|||
{ |
|||
int irq; |
|||
|
|||
for (irq = GIC_INTERNAL; irq < GICV3_MAXIRQ; irq++) { |
|||
gicv3_cache_target_cpustate(s, irq); |
|||
} |
|||
} |
|||
|
|||
#endif /* !QEMU_ARM_GIC_INTERNAL_H */ |
|||
@ -0,0 +1,32 @@ |
|||
/*
|
|||
* ARM Generic Interrupt Controller v3 |
|||
* |
|||
* Copyright (c) 2015 Huawei. |
|||
* Copyright (c) 2016 Linaro Limited |
|||
* Written by Shlomo Pongratz, Peter Maydell |
|||
* |
|||
* This code is licensed under the GPL, version 2 or (at your option) |
|||
* any later version. |
|||
*/ |
|||
|
|||
#ifndef HW_ARM_GICV3_H |
|||
#define HW_ARM_GICV3_H |
|||
|
|||
#include "arm_gicv3_common.h" |
|||
|
|||
#define TYPE_ARM_GICV3 "arm-gicv3" |
|||
#define ARM_GICV3(obj) OBJECT_CHECK(GICv3State, (obj), TYPE_ARM_GICV3) |
|||
#define ARM_GICV3_CLASS(klass) \ |
|||
OBJECT_CLASS_CHECK(ARMGICv3Class, (klass), TYPE_ARM_GICV3) |
|||
#define ARM_GICV3_GET_CLASS(obj) \ |
|||
OBJECT_GET_CLASS(ARMGICv3Class, (obj), TYPE_ARM_GICV3) |
|||
|
|||
typedef struct ARMGICv3Class { |
|||
/*< private >*/ |
|||
ARMGICv3CommonClass parent_class; |
|||
/*< public >*/ |
|||
|
|||
DeviceRealize parent_realize; |
|||
} ARMGICv3Class; |
|||
|
|||
#endif |
|||
Loading…
Reference in new issue