All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
@ 2016-06-14 14:38 Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 01/20] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
                   ` (21 more replies)
  0 siblings, 22 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

This series implements emulation of the GICv3 interrupt controller.
It is based to some extent on previous patches from Shlomo and
Pavel, but the bulk of it has turned out to be new code. (The
combination of changing the underlying data structures, adding
support for TrustZone and implementing proper GICv3 behaviour rather
than borrowing fragments of GICv2 emulation code meant there wasn't
much left to reuse.) I've tried to reflect this in the various
authorship credits on the patches, but please let me know if you
feel I got anything miscredited one way or the other.

Key points about the GICv3 emulated here:
 * "non-legacy" only, ie system registers and affinity routing
 * TrustZone is implemented
 * no virtualization support
 * only the "core" GICv3, so no LPI support (via ITS or otherwise)
 * no attempt to work around the Linux guest kernel bug fixed
   in commit 7c9b973061b0 (so you need that fix for your guest to
   boot with this GICv3)

Changes v2->v3: (all pretty minor)
 * add missing blank lines in tests/test-bitops.c
 * fixed erroneous comment
 * fixed missing shift in gicv3_cache_target_cpustate()
 * tweaked assertion in gicv3_set_irq()
 * corrected condition governing when GICD_NSACR and GICR_NSACR are RAZ/WI
 * dropped the RFC KVM save/restore patches for now
   (they wouldn't have changed and aren't going to get into QEMU 2.7
   since the kernel side of the interface is not going to hit the
   kernel's merge window; will pick them back up later)

The following patches are the only ones that still need review:

08    hw/intc/arm_gicv3: Add vmstate descriptors
10    hw/intc/arm_gicv3: Implement functions to identify next pending irq
11    hw/intc/arm_gicv3: Implement GICv3 distributor registers
12    hw/intc/arm_gicv3: Implement GICv3 redistributor registers
15    hw/intc/arm_gicv3: Implement GICv3 CPU interface registers
16    hw/intc/arm_gicv3: Implement gicv3_cpuif_update()
18    hw/intc/arm_gicv3: Add IRQ handling CPU interface registers


thanks
-- PMM

Pavel Fedin (3):
  target-arm: Add mp-affinity property for ARM CPU class
  hw/intc/arm_gicv3: Add state information
  hw/intc/arm_gicv3: Add vmstate descriptors

Peter Maydell (14):
  migration: Define VMSTATE_UINT64_2DARRAY
  bitops.h: Implement half-shuffle and half-unshuffle ops
  target-arm: Define new arm_is_el3_or_mon() function
  target-arm: Provide hook to tell GICv3 about changes of security state
  hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure
  hw/intc/arm_gicv3: Implement functions to identify next pending irq
  hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions
  hw/intc/arm_gicv3: Implement gicv3_set_irq()
  hw/intc/arm_gicv3: Implement GICv3 CPU interface registers
  hw/intc/arm_gicv3: Implement gicv3_cpuif_update()
  hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers
  hw/intc/arm_gicv3: Add IRQ handling CPU interface registers
  target-arm/machine.c: Allow user to request GICv3 emulation
  target-arm/monitor.c: Advertise emulated GICv3 in capabilities

Shlomo Pongratz (3):
  hw/intc/arm_gicv3: ARM GICv3 device framework
  hw/intc/arm_gicv3: Implement GICv3 distributor registers
  hw/intc/arm_gicv3: Implement GICv3 redistributor registers

 hw/intc/Makefile.objs              |    4 +
 hw/intc/arm_gicv3.c                |  400 +++++++++++
 hw/intc/arm_gicv3_common.c         |  225 +++++-
 hw/intc/arm_gicv3_cpuif.c          | 1346 ++++++++++++++++++++++++++++++++++++
 hw/intc/arm_gicv3_dist.c           |  879 +++++++++++++++++++++++
 hw/intc/arm_gicv3_kvm.c            |    7 +
 hw/intc/arm_gicv3_redist.c         |  562 +++++++++++++++
 hw/intc/gicv3_internal.h           |  331 +++++++++
 include/hw/intc/arm_gicv3.h        |   32 +
 include/hw/intc/arm_gicv3_common.h |  215 +++++-
 include/migration/vmstate.h        |    6 +
 include/qemu/bitops.h              |  108 +++
 target-arm/cpu.c                   |   10 +
 target-arm/cpu.h                   |   47 +-
 target-arm/helper.c                |    2 +
 target-arm/internals.h             |    8 +
 target-arm/machine.c               |    3 +-
 target-arm/monitor.c               |    3 +-
 target-arm/op_helper.c             |    4 +
 tests/test-bitops.c                |   72 ++
 trace-events                       |   41 ++
 21 files changed, 4285 insertions(+), 20 deletions(-)
 create mode 100644 hw/intc/arm_gicv3.c
 create mode 100644 hw/intc/arm_gicv3_cpuif.c
 create mode 100644 hw/intc/arm_gicv3_dist.c
 create mode 100644 hw/intc/arm_gicv3_redist.c
 create mode 100644 hw/intc/gicv3_internal.h
 create mode 100644 include/hw/intc/arm_gicv3.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 01/20] migration: Define VMSTATE_UINT64_2DARRAY
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 02/20] bitops.h: Implement half-shuffle and half-unshuffle ops Peter Maydell
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Define a VMSTATE_UINT64_2DARRAY macro, to go with the ones we
already have for other type sizes.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 include/migration/vmstate.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 6c65811..25ea58a 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -856,6 +856,12 @@ extern const VMStateInfo vmstate_info_bitmap;
 #define VMSTATE_UINT64_ARRAY(_f, _s, _n)                              \
     VMSTATE_UINT64_ARRAY_V(_f, _s, _n, 0)
 
+#define VMSTATE_UINT64_2DARRAY(_f, _s, _n1, _n2)                      \
+    VMSTATE_UINT64_2DARRAY_V(_f, _s, _n1, _n2, 0)
+
+#define VMSTATE_UINT64_2DARRAY_V(_f, _s, _n1, _n2, _v)                 \
+    VMSTATE_2DARRAY(_f, _s, _n1, _n2, _v, vmstate_info_uint64, uint64_t)
+
 #define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v)                         \
     VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int16, int16_t)
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 02/20] bitops.h: Implement half-shuffle and half-unshuffle ops
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 01/20] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 03/20] target-arm: Define new arm_is_el3_or_mon() function Peter Maydell
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

A half-shuffle operation takes a word with zeros in the high half:
 0000 0000 0000 0000 ABCD EFGH IJKL MNOP
and spreads the bits out so they are in every other bit of the word:
 0A0B 0C0D 0E0F 0G0H 0I0J 0K0L 0M0N 0O0P
A half-unshuffle performs the reverse operation.

Provide functions in bitops.h which implement these operations
for 32-bit and 64-bit inputs, and add tests for them.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 include/qemu/bitops.h | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/test-bitops.c   |  72 +++++++++++++++++++++++++++++++++
 2 files changed, 180 insertions(+)

diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index 755fdd1..15418a8 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.h
@@ -428,4 +428,112 @@ static inline uint64_t deposit64(uint64_t value, int start, int length,
     return (value & ~mask) | ((fieldval << start) & mask);
 }
 
+/**
+ * half_shuffle32:
+ * @value: 32-bit value (of which only the bottom 16 bits are of interest)
+ *
+ * Given an input value:
+ *  xxxx xxxx xxxx xxxx ABCD EFGH IJKL MNOP
+ * return the value where the bottom 16 bits are spread out into
+ * the odd bits in the word, and the even bits are zeroed:
+ *  0A0B 0C0D 0E0F 0G0H 0I0J 0K0L 0M0N 0O0P
+ *
+ * Any bits set in the top half of the input are ignored.
+ *
+ * Returns: the shuffled bits.
+ */
+static inline uint32_t half_shuffle32(uint32_t x)
+{
+    /* This algorithm is from _Hacker's Delight_ section 7-2 "Shuffling Bits".
+     * It ignores any bits set in the top half of the input.
+     */
+    x = ((x & 0xFF00) << 8) | (x & 0x00FF);
+    x = ((x << 4) | x) & 0x0F0F0F0F;
+    x = ((x << 2) | x) & 0x33333333;
+    x = ((x << 1) | x) & 0x55555555;
+    return x;
+}
+
+/**
+ * half_shuffle64:
+ * @value: 64-bit value (of which only the bottom 32 bits are of interest)
+ *
+ * Given an input value:
+ *  xxxx xxxx xxxx .... xxxx xxxx ABCD EFGH IJKL MNOP QRST UVWX YZab cdef
+ * return the value where the bottom 32 bits are spread out into
+ * the odd bits in the word, and the even bits are zeroed:
+ *  0A0B 0C0D 0E0F 0G0H 0I0J 0K0L 0M0N .... 0U0V 0W0X 0Y0Z 0a0b 0c0d 0e0f
+ *
+ * Any bits set in the top half of the input are ignored.
+ *
+ * Returns: the shuffled bits.
+ */
+static inline uint64_t half_shuffle64(uint64_t x)
+{
+    /* This algorithm is from _Hacker's Delight_ section 7-2 "Shuffling Bits".
+     * It ignores any bits set in the top half of the input.
+     */
+    x = ((x & 0xFFFF0000ULL) << 16) | (x & 0xFFFF);
+    x = ((x << 8) | x) & 0x00FF00FF00FF00FFULL;
+    x = ((x << 4) | x) & 0x0F0F0F0F0F0F0F0FULL;
+    x = ((x << 2) | x) & 0x3333333333333333ULL;
+    x = ((x << 1) | x) & 0x5555555555555555ULL;
+    return x;
+}
+
+/**
+ * half_unshuffle32:
+ * @value: 32-bit value (of which only the odd bits are of interest)
+ *
+ * Given an input value:
+ *  xAxB xCxD xExF xGxH xIxJ xKxL xMxN xOxP
+ * return the value where all the odd bits are compressed down
+ * into the low half of the word, and the high half is zeroed:
+ *  0000 0000 0000 0000 ABCD EFGH IJKL MNOP
+ *
+ * Any even bits set in the input are ignored.
+ *
+ * Returns: the unshuffled bits.
+ */
+static inline uint32_t half_unshuffle32(uint32_t x)
+{
+    /* This algorithm is from _Hacker's Delight_ section 7-2 "Shuffling Bits".
+     * where it is called an inverse half shuffle.
+     */
+    x &= 0x55555555;
+    x = ((x >> 1) | x) & 0x33333333;
+    x = ((x >> 2) | x) & 0x0F0F0F0F;
+    x = ((x >> 4) | x) & 0x00FF00FF;
+    x = ((x >> 8) | x) & 0x0000FFFF;
+    return x;
+}
+
+/**
+ * half_unshuffle64:
+ * @value: 64-bit value (of which only the odd bits are of interest)
+ *
+ * Given an input value:
+ *  xAxB xCxD xExF xGxH xIxJ xKxL xMxN .... xUxV xWxX xYxZ xaxb xcxd xexf
+ * return the value where all the odd bits are compressed down
+ * into the low half of the word, and the high half is zeroed:
+ *  0000 0000 0000 .... 0000 0000 ABCD EFGH IJKL MNOP QRST UVWX YZab cdef
+ *
+ * Any even bits set in the input are ignored.
+ *
+ * Returns: the unshuffled bits.
+ */
+static inline uint64_t half_unshuffle64(uint64_t x)
+{
+    /* This algorithm is from _Hacker's Delight_ section 7-2 "Shuffling Bits".
+     * where it is called an inverse half shuffle.
+     */
+    x &= 0x5555555555555555ULL;
+    x = ((x >> 1) | x) & 0x3333333333333333ULL;
+    x = ((x >> 2) | x) & 0x0F0F0F0F0F0F0F0FULL;
+    x = ((x >> 4) | x) & 0x00FF00FF00FF00FFULL;
+    x = ((x >> 8) | x) & 0x0000FFFF0000FFFFULL;
+    x = ((x >> 16) | x) & 0x00000000FFFFFFFFULL;
+    return x;
+}
+
 #endif
diff --git a/tests/test-bitops.c b/tests/test-bitops.c
index eb19a36..5a791d2 100644
--- a/tests/test-bitops.c
+++ b/tests/test-bitops.c
@@ -65,10 +65,82 @@ static void test_sextract64(void)
     }
 }
 
+typedef struct {
+    uint32_t unshuffled;
+    uint32_t shuffled;
+} Shuffle32Test;
+
+typedef struct {
+    uint64_t unshuffled;
+    uint64_t shuffled;
+} Shuffle64Test;
+
+static const Shuffle32Test test_shuffle32_data[] = {
+    { 0x0000FFFF, 0x55555555 },
+    { 0x000081C5, 0x40015011 },
+};
+
+static const Shuffle64Test test_shuffle64_data[] = {
+    { 0x00000000FFFFFFFFULL, 0x5555555555555555ULL },
+    { 0x00000000493AB02CULL, 0x1041054445000450ULL },
+};
+
+static void test_half_shuffle32(void)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(test_shuffle32_data); i++) {
+        const Shuffle32Test *test = &test_shuffle32_data[i];
+        uint32_t r = half_shuffle32(test->unshuffled);
+
+        g_assert_cmpint(r, ==, test->shuffled);
+    }
+}
+
+static void test_half_shuffle64(void)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(test_shuffle64_data); i++) {
+        const Shuffle64Test *test = &test_shuffle64_data[i];
+        uint64_t r = half_shuffle64(test->unshuffled);
+
+        g_assert_cmpint(r, ==, test->shuffled);
+    }
+}
+
+static void test_half_unshuffle32(void)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(test_shuffle32_data); i++) {
+        const Shuffle32Test *test = &test_shuffle32_data[i];
+        uint32_t r = half_unshuffle32(test->shuffled);
+
+        g_assert_cmpint(r, ==, test->unshuffled);
+    }
+}
+
+static void test_half_unshuffle64(void)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(test_shuffle64_data); i++) {
+        const Shuffle64Test *test = &test_shuffle64_data[i];
+        uint64_t r = half_unshuffle64(test->shuffled);
+
+        g_assert_cmpint(r, ==, test->unshuffled);
+    }
+}
+
 int main(int argc, char **argv)
 {
     g_test_init(&argc, &argv, NULL);
     g_test_add_func("/bitops/sextract32", test_sextract32);
     g_test_add_func("/bitops/sextract64", test_sextract64);
+    g_test_add_func("/bitops/half_shuffle32", test_half_shuffle32);
+    g_test_add_func("/bitops/half_shuffle64", test_half_shuffle64);
+    g_test_add_func("/bitops/half_unshuffle32", test_half_unshuffle32);
+    g_test_add_func("/bitops/half_unshuffle64", test_half_unshuffle64);
     return g_test_run();
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 03/20] target-arm: Define new arm_is_el3_or_mon() function
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 01/20] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 02/20] bitops.h: Implement half-shuffle and half-unshuffle ops Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 04/20] target-arm: Provide hook to tell GICv3 about changes of security state Peter Maydell
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

The GICv3 system registers need to know if the CPU is AArch64
in EL3 or AArch32 in Monitor mode. This happens to be the first
part of the check for arm_is_secure(), so factor it out into a
new arm_is_el3_or_mon() function that the GIC can also use.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 target-arm/cpu.h | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 17d8051..2c2b8f7 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1144,8 +1144,8 @@ static inline bool arm_is_secure_below_el3(CPUARMState *env)
     }
 }
 
-/* Return true if the processor is in secure state */
-static inline bool arm_is_secure(CPUARMState *env)
+/* Return true if the CPU is AArch64 EL3 or AArch32 Mon */
+static inline bool arm_is_el3_or_mon(CPUARMState *env)
 {
     if (arm_feature(env, ARM_FEATURE_EL3)) {
         if (is_a64(env) && extract32(env->pstate, 2, 2) == 3) {
@@ -1157,6 +1157,15 @@ static inline bool arm_is_secure(CPUARMState *env)
             return true;
         }
     }
+    return false;
+}
+
+/* Return true if the processor is in secure state */
+static inline bool arm_is_secure(CPUARMState *env)
+{
+    if (arm_is_el3_or_mon(env)) {
+        return true;
+    }
     return arm_is_secure_below_el3(env);
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 04/20] target-arm: Provide hook to tell GICv3 about changes of security state
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (2 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 03/20] target-arm: Define new arm_is_el3_or_mon() function Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 05/20] target-arm: Add mp-affinity property for ARM CPU class Peter Maydell
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

The GICv3 CPU interface needs to know when the CPU it is attached
to makes an exception level or mode transition that changes the
security state, because whether it is asserting IRQ or FIQ can change
depending on these things. Provide a mechanism for letting the GICv3
device register a hook to be called on such changes.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 target-arm/cpu.c       |  9 +++++++++
 target-arm/cpu.h       | 34 ++++++++++++++++++++++++++++++++++
 target-arm/helper.c    |  2 ++
 target-arm/internals.h |  8 ++++++++
 target-arm/op_helper.c |  4 ++++
 5 files changed, 57 insertions(+)

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 3fd0743..0eaa907 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -51,6 +51,15 @@ static bool arm_cpu_has_work(CPUState *cs)
          | CPU_INTERRUPT_EXITTB);
 }
 
+void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHook *hook,
+                                 void *opaque)
+{
+    /* We currently only support registering a single hook function */
+    assert(!cpu->el_change_hook);
+    cpu->el_change_hook = hook;
+    cpu->el_change_hook_opaque = opaque;
+}
+
 static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
 {
     /* Reset a single ARMCPRegInfo register */
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 2c2b8f7..1c06090 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -515,6 +515,13 @@ typedef struct CPUARMState {
 } CPUARMState;
 
 /**
+ * ARMELChangeHook:
+ * type of a function which can be registered via arm_register_el_change_hook()
+ * to get callbacks when the CPU changes its exception level or mode.
+ */
+typedef void ARMELChangeHook(ARMCPU *cpu, void *opaque);
+
+/**
  * ARMCPU:
  * @env: #CPUARMState
  *
@@ -652,6 +659,9 @@ struct ARMCPU {
     /* DCZ blocksize, in log_2(words), ie low 4 bits of DCZID_EL0 */
     uint32_t dcz_blocksize;
     uint64_t rvbar;
+
+    ARMELChangeHook *el_change_hook;
+    void *el_change_hook_opaque;
 };
 
 static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
@@ -2384,4 +2394,28 @@ static inline AddressSpace *arm_addressspace(CPUState *cs, MemTxAttrs attrs)
 }
 #endif
 
+/**
+ * arm_register_el_change_hook:
+ * Register a hook function which will be called back whenever this
+ * CPU changes exception level or mode. The hook function will be
+ * passed a pointer to the ARMCPU and the opaque data pointer passed
+ * to this function when the hook was registered.
+ *
+ * Note that we currently only support registering a single hook function,
+ * and will assert if this function is called twice.
+ * This facility is intended for the use of the GICv3 emulation.
+ */
+void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHook *hook,
+                                 void *opaque);
+
+/**
+ * arm_get_el_change_hook_opaque:
+ * Return the opaque data that will be used by the el_change_hook
+ * for this CPU.
+ */
+static inline void *arm_get_el_change_hook_opaque(ARMCPU *cpu)
+{
+    return cpu->el_change_hook_opaque;
+}
+
 #endif
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 862e780..2ea210e 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -6500,6 +6500,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
         arm_cpu_do_interrupt_aarch32(cs);
     }
 
+    arm_call_el_change_hook(cpu);
+
     if (!kvm_enabled()) {
         cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
     }
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 728ecba..466be0b 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -479,4 +479,12 @@ bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
 void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write,
                                  int is_user, uintptr_t retaddr);
 
+/* Call the EL change hook if one has been registered */
+static inline void arm_call_el_change_hook(ARMCPU *cpu)
+{
+    if (cpu->el_change_hook) {
+        cpu->el_change_hook(cpu, cpu->el_change_hook_opaque);
+    }
+}
+
 #endif
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 35912a1..73da759 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -474,6 +474,8 @@ void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
 void HELPER(cpsr_write_eret)(CPUARMState *env, uint32_t val)
 {
     cpsr_write(env, val, CPSR_ERET_MASK, CPSRWriteExceptionReturn);
+
+    arm_call_el_change_hook(arm_env_get_cpu(env));
 }
 
 /* Access to user mode registers from privileged modes.  */
@@ -969,6 +971,8 @@ void HELPER(exception_return)(CPUARMState *env)
         env->pc = env->elr_el[cur_el];
     }
 
+    arm_call_el_change_hook(arm_env_get_cpu(env));
+
     return;
 
 illegal_return:
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 05/20] target-arm: Add mp-affinity property for ARM CPU class
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (3 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 04/20] target-arm: Provide hook to tell GICv3 about changes of security state Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 06/20] hw/intc/arm_gicv3: Add state information Peter Maydell
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

From: Pavel Fedin <p.fedin@samsung.com>

This allows to override default affinity IDs on a per-machine basis, and
possibility to retrieve IDs will be used by vGICv3 live migration code.

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 target-arm/cpu.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 0eaa907..ce8b8f4 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -1415,6 +1415,7 @@ static Property arm_cpu_properties[] = {
     DEFINE_PROP_BOOL("start-powered-off", ARMCPU, start_powered_off, false),
     DEFINE_PROP_UINT32("psci-conduit", ARMCPU, psci_conduit, 0),
     DEFINE_PROP_UINT32("midr", ARMCPU, midr, 0),
+    DEFINE_PROP_UINT64("mp-affinity", ARMCPU, mp_affinity, 0),
     DEFINE_PROP_END_OF_LIST()
 };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 06/20] hw/intc/arm_gicv3: Add state information
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (4 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 05/20] target-arm: Add mp-affinity property for ARM CPU class Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 07/20] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure Peter Maydell
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

From: Pavel Fedin <p.fedin@samsung.com>

Add state information to GICv3 object structure and implement
arm_gicv3_common_reset().

This commit includes accessor functions for the fields which are
stored as bitmaps in uint32_t arrays.

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
[PMM: significantly overhauled:
 * Add missing qom/cpu.h include
 * Remove legacy-only state fields (we can add them later if/when we add
   legacy emulation)
 * Use arrays of uint32_t to store the various distributor bitmaps,
   and provide accessor functions for the various set/test/etc operations
 * Add various missing register offset #defines
 * Accessor macros which combine distributor and redistributor behaviour
   removed
 * Fields in state structures renamed to match architectural register names
 * Corrected the reset value for GICR_IENABLER0 since we don't support
   legacy mode
 * Added ARM_LINUX_BOOT_IF interface for "we are directly booting a kernel in
   non-secure" so that we can fake up the firmware-mandated reconfiguration
   only when we need it
]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 hw/intc/arm_gicv3_common.c         | 159 +++++++++++++++++++++++++++++-
 hw/intc/gicv3_internal.h           | 172 +++++++++++++++++++++++++++++++++
 include/hw/intc/arm_gicv3_common.h | 192 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 518 insertions(+), 5 deletions(-)
 create mode 100644 hw/intc/gicv3_internal.h

diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index b9d3824..bf6949f 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -3,8 +3,9 @@
  *
  * Copyright (c) 2012 Linaro Limited
  * Copyright (c) 2015 Huawei.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
  * Written by Peter Maydell
- * Extended to 64 cores by Shlomo Pongratz
+ * 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
@@ -22,7 +23,10 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "qom/cpu.h"
 #include "hw/intc/arm_gicv3_common.h"
+#include "gicv3_internal.h"
+#include "hw/arm/linux-boot-if.h"
 
 static void gicv3_pre_save(void *opaque)
 {
@@ -90,6 +94,7 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
 static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
 {
     GICv3State *s = ARM_GICV3_COMMON(dev);
+    int i;
 
     /* revision property is actually reserved and currently used only in order
      * to keep the interface compatible with GICv2 code, avoiding extra
@@ -100,11 +105,155 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
         error_setg(errp, "unsupported GIC revision %d", s->revision);
         return;
     }
+
+    if (s->num_irq > GICV3_MAXIRQ) {
+        error_setg(errp,
+                   "requested %u interrupt lines exceeds GIC maximum %d",
+                   s->num_irq, GICV3_MAXIRQ);
+        return;
+    }
+    if (s->num_irq < GIC_INTERNAL) {
+        error_setg(errp,
+                   "requested %u interrupt lines is below GIC minimum %d",
+                   s->num_irq, GIC_INTERNAL);
+        return;
+    }
+
+    /* ITLinesNumber is represented as (N / 32) - 1, so this is an
+     * implementation imposed restriction, not an architectural one,
+     * so we don't have to deal with bitfields where only some of the
+     * bits in a 32-bit word should be valid.
+     */
+    if (s->num_irq % 32) {
+        error_setg(errp,
+                   "%d interrupt lines unsupported: not divisible by 32",
+                   s->num_irq);
+        return;
+    }
+
+    s->cpu = g_new0(GICv3CPUState, s->num_cpu);
+
+    for (i = 0; i < s->num_cpu; i++) {
+        CPUState *cpu = qemu_get_cpu(i);
+        uint64_t cpu_affid;
+        int last;
+
+        s->cpu[i].cpu = cpu;
+        s->cpu[i].gic = s;
+
+        /* Pre-construct the GICR_TYPER:
+         * For our implementation:
+         *  Top 32 bits are the affinity value of the associated CPU
+         *  CommonLPIAff == 01 (redistributors with same Aff3 share LPI table)
+         *  Processor_Number == CPU index starting from 0
+         *  DPGS == 0 (GICR_CTLR.DPG* not supported)
+         *  Last == 1 if this is the last redistributor in a series of
+         *            contiguous redistributor pages
+         *  DirectLPI == 0 (direct injection of LPIs not supported)
+         *  VLPIS == 0 (virtual LPIs not supported)
+         *  PLPIS == 0 (physical LPIs not supported)
+         */
+        cpu_affid = object_property_get_int(OBJECT(cpu), "mp-affinity", NULL);
+        last = (i == s->num_cpu - 1);
+
+        /* The CPU mp-affinity property is in MPIDR register format; squash
+         * the affinity bytes into 32 bits as the GICR_TYPER has them.
+         */
+        cpu_affid = (cpu_affid & 0xFF00000000ULL >> 8) | (cpu_affid & 0xFFFFFF);
+        s->cpu[i].gicr_typer = (cpu_affid << 32) |
+            (1 << 24) |
+            (i << 8) |
+            (last << 4);
+    }
 }
 
 static void arm_gicv3_common_reset(DeviceState *dev)
 {
-    /* TODO */
+    GICv3State *s = ARM_GICV3_COMMON(dev);
+    int i;
+
+    for (i = 0; i < s->num_cpu; i++) {
+        GICv3CPUState *cs = &s->cpu[i];
+
+        cs->level = 0;
+        cs->gicr_ctlr = 0;
+        cs->gicr_statusr[GICV3_S] = 0;
+        cs->gicr_statusr[GICV3_NS] = 0;
+        cs->gicr_waker = GICR_WAKER_ProcessorSleep | GICR_WAKER_ChildrenAsleep;
+        cs->gicr_propbaser = 0;
+        cs->gicr_pendbaser = 0;
+        /* If we're resetting a TZ-aware GIC as if secure firmware
+         * had set it up ready to start a kernel in non-secure, we
+         * need to set interrupts to group 1 so the kernel can use them.
+         * Otherwise they reset to group 0 like the hardware.
+         */
+        if (s->irq_reset_nonsecure) {
+            cs->gicr_igroupr0 = 0xffffffff;
+        } else {
+            cs->gicr_igroupr0 = 0;
+        }
+
+        cs->gicr_ienabler0 = 0;
+        cs->gicr_ipendr0 = 0;
+        cs->gicr_iactiver0 = 0;
+        cs->edge_trigger = 0xffff;
+        cs->gicr_igrpmodr0 = 0;
+        cs->gicr_nsacr = 0;
+        memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr));
+
+        /* State in the CPU interface must *not* be reset here, because it
+         * is part of the CPU's reset domain, not the GIC device's.
+         */
+    }
+
+    /* For our implementation affinity routing is always enabled */
+    if (s->security_extn) {
+        s->gicd_ctlr = GICD_CTLR_ARE_S | GICD_CTLR_ARE_NS;
+    } else {
+        s->gicd_ctlr = GICD_CTLR_DS | GICD_CTLR_ARE;
+    }
+
+    s->gicd_statusr[GICV3_S] = 0;
+    s->gicd_statusr[GICV3_NS] = 0;
+
+    memset(s->group, 0, sizeof(s->group));
+    memset(s->grpmod, 0, sizeof(s->grpmod));
+    memset(s->enabled, 0, sizeof(s->enabled));
+    memset(s->pending, 0, sizeof(s->pending));
+    memset(s->active, 0, sizeof(s->active));
+    memset(s->level, 0, sizeof(s->level));
+    memset(s->edge_trigger, 0, sizeof(s->edge_trigger));
+    memset(s->gicd_ipriority, 0, sizeof(s->gicd_ipriority));
+    memset(s->gicd_irouter, 0, sizeof(s->gicd_irouter));
+    memset(s->gicd_nsacr, 0, sizeof(s->gicd_nsacr));
+
+    if (s->irq_reset_nonsecure) {
+        /* If we're resetting a TZ-aware GIC as if secure firmware
+         * had set it up ready to start a kernel in non-secure, we
+         * need to set interrupts to group 1 so the kernel can use them.
+         * Otherwise they reset to group 0 like the hardware.
+         */
+        for (i = GIC_INTERNAL; i < s->num_irq; i++) {
+            gicv3_gicd_group_set(s, i);
+        }
+    }
+}
+
+static void arm_gic_common_linux_init(ARMLinuxBootIf *obj,
+                                      bool secure_boot)
+{
+    GICv3State *s = ARM_GICV3_COMMON(obj);
+
+    if (s->security_extn && !secure_boot) {
+        /* We're directly booting a kernel into NonSecure. If this GIC
+         * implements the security extensions then we must configure it
+         * to have all the interrupts be NonSecure (this is a job that
+         * is done by the Secure boot firmware in real hardware, and in
+         * this mode QEMU is acting as a minimalist firmware-and-bootloader
+         * equivalent).
+         */
+        s->irq_reset_nonsecure = true;
+    }
 }
 
 static Property arm_gicv3_common_properties[] = {
@@ -118,11 +267,13 @@ static Property arm_gicv3_common_properties[] = {
 static void arm_gicv3_common_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass);
 
     dc->reset = arm_gicv3_common_reset;
     dc->realize = arm_gicv3_common_realize;
     dc->props = arm_gicv3_common_properties;
     dc->vmsd = &vmstate_gicv3;
+    albifc->arm_linux_init = arm_gic_common_linux_init;
 }
 
 static const TypeInfo arm_gicv3_common_type = {
@@ -132,6 +283,10 @@ static const TypeInfo arm_gicv3_common_type = {
     .class_size = sizeof(ARMGICv3CommonClass),
     .class_init = arm_gicv3_common_class_init,
     .abstract = true,
+    .interfaces = (InterfaceInfo []) {
+        { TYPE_ARM_LINUX_BOOT_IF },
+        { },
+    },
 };
 
 static void register_types(void)
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
new file mode 100644
index 0000000..d23524b
--- /dev/null
+++ b/hw/intc/gicv3_internal.h
@@ -0,0 +1,172 @@
+/*
+ * 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)
+
+/**
+ * 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;
+}
+
+#endif /* !QEMU_ARM_GIC_INTERNAL_H */
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index c2fd8da..bd364a7 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -3,8 +3,9 @@
  *
  * Copyright (c) 2012 Linaro Limited
  * Copyright (c) 2015 Huawei.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
  * Written by Peter Maydell
- * Extended to 64 cores by Shlomo Pongratz
+ * 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
@@ -26,7 +27,143 @@
 #include "hw/sysbus.h"
 #include "hw/intc/arm_gic_common.h"
 
-typedef struct GICv3State {
+/*
+ * Maximum number of possible interrupts, determined by the GIC architecture.
+ * Note that this does not include LPIs. When implemented, these should be
+ * dealt with separately.
+ */
+#define GICV3_MAXIRQ 1020
+#define GICV3_MAXSPI (GICV3_MAXIRQ - GIC_INTERNAL)
+
+/* Minimum BPR for Secure, or when security not enabled */
+#define GIC_MIN_BPR 0
+/* Minimum BPR for Nonsecure when security is enabled */
+#define GIC_MIN_BPR_NS (GIC_MIN_BPR + 1)
+
+/* For some distributor fields we want to model the array of 32-bit
+ * register values which hold various bitmaps corresponding to enabled,
+ * pending, etc bits. These macros and functions facilitate that; the
+ * APIs are generally modelled on the generic bitmap.h functions
+ * (which are unsuitable here because they use 'unsigned long' as the
+ * underlying storage type, which is very awkward when you need to
+ * access the data as 32-bit values.)
+ * Each bitmap contains a bit for each interrupt. Although there is
+ * space for the PPIs and SGIs, those bits (the first 32) are never
+ * used as that state lives in the redistributor. The unused bits are
+ * provided purely so that interrupt X's state is always in bit X; this
+ * avoids bugs where we forget to subtract GIC_INTERNAL from an
+ * interrupt number.
+ */
+#define GICV3_BMP_SIZE (DIV_ROUND_UP(GICV3_MAXIRQ, 32))
+
+#define GIC_DECLARE_BITMAP(name) \
+    uint32_t name[GICV3_BMP_SIZE]
+
+#define GIC_BIT_MASK(nr) (1U << ((nr) % 32))
+#define GIC_BIT_WORD(nr) ((nr) / 32)
+
+static inline void gic_bmp_set_bit(int nr, uint32_t *addr)
+{
+    uint32_t mask = GIC_BIT_MASK(nr);
+    uint32_t *p = addr + GIC_BIT_WORD(nr);
+
+    *p |= mask;
+}
+
+static inline void gic_bmp_clear_bit(int nr, uint32_t *addr)
+{
+    uint32_t mask = GIC_BIT_MASK(nr);
+    uint32_t *p = addr + GIC_BIT_WORD(nr);
+
+    *p &= ~mask;
+}
+
+static inline int gic_bmp_test_bit(int nr, const uint32_t *addr)
+{
+    return 1U & (addr[GIC_BIT_WORD(nr)] >> (nr & 31));
+}
+
+static inline void gic_bmp_replace_bit(int nr, uint32_t *addr, int val)
+{
+    uint32_t mask = GIC_BIT_MASK(nr);
+    uint32_t *p = addr + GIC_BIT_WORD(nr);
+
+    *p &= ~mask;
+    *p |= (val & 1U) << (nr % 32);
+}
+
+/* Return a pointer to the 32-bit word containing the specified bit. */
+static inline uint32_t *gic_bmp_ptr32(uint32_t *addr, int nr)
+{
+    return addr + GIC_BIT_WORD(nr);
+}
+
+typedef struct GICv3State GICv3State;
+typedef struct GICv3CPUState GICv3CPUState;
+
+/* Some CPU interface registers come in three flavours:
+ * Group0, Group1 (Secure) and Group1 (NonSecure)
+ * (where the latter two are exposed as a single banked system register).
+ * In the state struct they are implemented as a 3-element array which
+ * can be indexed into by the GICV3_G0, GICV3_G1 and GICV3_G1NS constants.
+ * If the CPU doesn't support EL3 then the G1 element is unused.
+ *
+ * These constants are also used to communicate the group to use for
+ * an interrupt or SGI when it is passed between the cpu interface and
+ * the redistributor or distributor. For those purposes the receiving end
+ * must be prepared to cope with a Group 1 Secure interrupt even if it does
+ * not have security support enabled, because security can be disabled
+ * independently in the CPU and in the GIC. In that case the receiver should
+ * treat an incoming Group 1 Secure interrupt as if it were Group 0.
+ * (This architectural requirement is why the _G1 element is the unused one
+ * in a no-EL3 CPU:  we would otherwise have to translate back and forth
+ * between (G0, G1NS) from the distributor and (G0, G1) in the CPU i/f.)
+ */
+#define GICV3_G0 0
+#define GICV3_G1 1
+#define GICV3_G1NS 2
+
+/* ICC_CTLR_EL1, GICD_STATUSR and GICR_STATUSR are banked but not
+ * group-related, so those indices are just 0 for S and 1 for NS.
+ * (If the CPU or the GIC, respectively, don't support the Security
+ * extensions then the S element is unused.)
+ */
+#define GICV3_S 0
+#define GICV3_NS 1
+
+struct GICv3CPUState {
+    GICv3State *gic;
+    CPUState *cpu;
+
+    /* Redistributor */
+    uint32_t level;                  /* Current IRQ level */
+    /* RD_base page registers */
+    uint32_t gicr_ctlr;
+    uint64_t gicr_typer;
+    uint32_t gicr_statusr[2];
+    uint32_t gicr_waker;
+    uint64_t gicr_propbaser;
+    uint64_t gicr_pendbaser;
+    /* SGI_base page registers */
+    uint32_t gicr_igroupr0;
+    uint32_t gicr_ienabler0;
+    uint32_t gicr_ipendr0;
+    uint32_t gicr_iactiver0;
+    uint32_t edge_trigger; /* ICFGR0 and ICFGR1 even bits */
+    uint32_t gicr_igrpmodr0;
+    uint32_t gicr_nsacr;
+    uint8_t gicr_ipriorityr[GIC_INTERNAL];
+
+    /* CPU interface */
+    uint64_t icc_ctlr_el1[2];
+    uint64_t icc_pmr_el1;
+    uint64_t icc_bpr[3];
+    uint64_t icc_apr[3][4];
+    uint64_t icc_igrpen[3];
+    uint64_t icc_ctlr_el3;
+};
+
+struct GICv3State {
     /*< private >*/
     SysBusDevice parent_obj;
     /*< public >*/
@@ -41,9 +178,58 @@ typedef struct GICv3State {
     uint32_t num_irq;
     uint32_t revision;
     bool security_extn;
+    bool irq_reset_nonsecure;
 
     int dev_fd; /* kvm device fd if backed by kvm vgic support */
-} GICv3State;
+    Error *migration_blocker;
+
+    /* Distributor */
+
+    /* for a GIC with the security extensions the NS banked version of this
+     * register is just an alias of bit 1 of the S banked version.
+     */
+    uint32_t gicd_ctlr;
+    uint32_t gicd_statusr[2];
+    GIC_DECLARE_BITMAP(group);        /* GICD_IGROUPR */
+    GIC_DECLARE_BITMAP(grpmod);       /* GICD_IGRPMODR */
+    GIC_DECLARE_BITMAP(enabled);      /* GICD_ISENABLER */
+    GIC_DECLARE_BITMAP(pending);      /* GICD_ISPENDR */
+    GIC_DECLARE_BITMAP(active);       /* GICD_ISACTIVER */
+    GIC_DECLARE_BITMAP(level);        /* Current level */
+    GIC_DECLARE_BITMAP(edge_trigger); /* GICD_ICFGR even bits */
+    uint8_t gicd_ipriority[GICV3_MAXIRQ];
+    uint64_t gicd_irouter[GICV3_MAXIRQ];
+    uint32_t gicd_nsacr[DIV_ROUND_UP(GICV3_MAXIRQ, 16)];
+
+    GICv3CPUState *cpu;
+};
+
+#define GICV3_BITMAP_ACCESSORS(BMP)                                     \
+    static inline void gicv3_gicd_##BMP##_set(GICv3State *s, int irq)   \
+    {                                                                   \
+        gic_bmp_set_bit(irq, s->BMP);                                   \
+    }                                                                   \
+    static inline int gicv3_gicd_##BMP##_test(GICv3State *s, int irq)   \
+    {                                                                   \
+        return gic_bmp_test_bit(irq, s->BMP);                           \
+    }                                                                   \
+    static inline void gicv3_gicd_##BMP##_clear(GICv3State *s, int irq) \
+    {                                                                   \
+        gic_bmp_clear_bit(irq, s->BMP);                                 \
+    }                                                                   \
+    static inline void gicv3_gicd_##BMP##_replace(GICv3State *s,        \
+                                                  int irq, int value)   \
+    {                                                                   \
+        gic_bmp_replace_bit(irq, s->BMP, value);                        \
+    }
+
+GICV3_BITMAP_ACCESSORS(group)
+GICV3_BITMAP_ACCESSORS(grpmod)
+GICV3_BITMAP_ACCESSORS(enabled)
+GICV3_BITMAP_ACCESSORS(pending)
+GICV3_BITMAP_ACCESSORS(active)
+GICV3_BITMAP_ACCESSORS(level)
+GICV3_BITMAP_ACCESSORS(edge_trigger)
 
 #define TYPE_ARM_GICV3_COMMON "arm-gicv3-common"
 #define ARM_GICV3_COMMON(obj) \
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 07/20] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (5 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 06/20] hw/intc/arm_gicv3: Add state information Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 08/20] hw/intc/arm_gicv3: Add vmstate descriptors Peter Maydell
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Move the GICv3 parent_irq and parent_fiq pointers into the
GICv3CPUState structure rather than giving them their own array.
This will make it easy to assert the IRQ and FIQ lines for a
particular CPU interface without having to know or calculate
the CPU index for the GICv3CPUState we are working on.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 hw/intc/arm_gicv3_common.c         | 7 ++-----
 include/hw/intc/arm_gicv3_common.h | 5 ++---
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index bf6949f..1557833 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -72,14 +72,11 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
     i = s->num_irq - GIC_INTERNAL + GIC_INTERNAL * s->num_cpu;
     qdev_init_gpio_in(DEVICE(s), handler, i);
 
-    s->parent_irq = g_malloc(s->num_cpu * sizeof(qemu_irq));
-    s->parent_fiq = g_malloc(s->num_cpu * sizeof(qemu_irq));
-
     for (i = 0; i < s->num_cpu; i++) {
-        sysbus_init_irq(sbd, &s->parent_irq[i]);
+        sysbus_init_irq(sbd, &s->cpu[i].parent_irq);
     }
     for (i = 0; i < s->num_cpu; i++) {
-        sysbus_init_irq(sbd, &s->parent_fiq[i]);
+        sysbus_init_irq(sbd, &s->cpu[i].parent_fiq);
     }
 
     memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s,
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index bd364a7..cc6ac74 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -134,6 +134,8 @@ typedef struct GICv3CPUState GICv3CPUState;
 struct GICv3CPUState {
     GICv3State *gic;
     CPUState *cpu;
+    qemu_irq parent_irq;
+    qemu_irq parent_fiq;
 
     /* Redistributor */
     uint32_t level;                  /* Current IRQ level */
@@ -168,9 +170,6 @@ struct GICv3State {
     SysBusDevice parent_obj;
     /*< public >*/
 
-    qemu_irq *parent_irq;
-    qemu_irq *parent_fiq;
-
     MemoryRegion iomem_dist; /* Distributor */
     MemoryRegion iomem_redist; /* Redistributors */
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 08/20] hw/intc/arm_gicv3: Add vmstate descriptors
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (6 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 07/20] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-15  2:30   ` Shannon Zhao
  2016-06-16  2:12   ` Shannon Zhao
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 09/20] hw/intc/arm_gicv3: ARM GICv3 device framework Peter Maydell
                   ` (13 subsequent siblings)
  21 siblings, 2 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

From: Pavel Fedin <p.fedin@samsung.com>

Add state structure descriptors for the GICv3 state. We mark
the KVM GICv3 device as having a migration blocker until the
code to save and restore the state in the kernel is implemented.

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
[PMM: Adjust to renamed struct fields; switched to using uint32_t
 array backed bitmaps; add migration blocker setting]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/arm_gicv3_common.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-
 hw/intc/arm_gicv3_kvm.c    |  7 +++++++
 2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 1557833..d1714e4 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -49,11 +49,59 @@ static int gicv3_post_load(void *opaque, int version_id)
     return 0;
 }
 
+static const VMStateDescription vmstate_gicv3_cpu = {
+    .name = "arm_gicv3_cpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(level, GICv3CPUState),
+        VMSTATE_UINT32(gicr_ctlr, GICv3CPUState),
+        VMSTATE_UINT32_ARRAY(gicr_statusr, GICv3CPUState, 2),
+        VMSTATE_UINT32(gicr_waker, GICv3CPUState),
+        VMSTATE_UINT64(gicr_propbaser, GICv3CPUState),
+        VMSTATE_UINT64(gicr_pendbaser, GICv3CPUState),
+        VMSTATE_UINT32(gicr_igroupr0, GICv3CPUState),
+        VMSTATE_UINT32(gicr_ienabler0, GICv3CPUState),
+        VMSTATE_UINT32(gicr_ipendr0, GICv3CPUState),
+        VMSTATE_UINT32(gicr_iactiver0, GICv3CPUState),
+        VMSTATE_UINT32(edge_trigger, GICv3CPUState),
+        VMSTATE_UINT32(gicr_igrpmodr0, GICv3CPUState),
+        VMSTATE_UINT32(gicr_nsacr, GICv3CPUState),
+        VMSTATE_UINT8_ARRAY(gicr_ipriorityr, GICv3CPUState, GIC_INTERNAL),
+        VMSTATE_UINT64_ARRAY(icc_ctlr_el1, GICv3CPUState, 2),
+        VMSTATE_UINT64(icc_pmr_el1, GICv3CPUState),
+        VMSTATE_UINT64_ARRAY(icc_bpr, GICv3CPUState, 3),
+        VMSTATE_UINT64_2DARRAY(icc_apr, GICv3CPUState, 3, 4),
+        VMSTATE_UINT64_ARRAY(icc_igrpen, GICv3CPUState, 3),
+        VMSTATE_UINT64(icc_ctlr_el3, GICv3CPUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_gicv3 = {
     .name = "arm_gicv3",
-    .unmigratable = 1,
+    .version_id = 1,
+    .minimum_version_id = 1,
     .pre_save = gicv3_pre_save,
     .post_load = gicv3_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(gicd_ctlr, GICv3State),
+        VMSTATE_UINT32_ARRAY(gicd_statusr, GICv3State, 2),
+        VMSTATE_UINT32_ARRAY(group, GICv3State, GICV3_BMP_SIZE),
+        VMSTATE_UINT32_ARRAY(grpmod, GICv3State, GICV3_BMP_SIZE),
+        VMSTATE_UINT32_ARRAY(enabled, GICv3State, GICV3_BMP_SIZE),
+        VMSTATE_UINT32_ARRAY(pending, GICv3State, GICV3_BMP_SIZE),
+        VMSTATE_UINT32_ARRAY(active, GICv3State, GICV3_BMP_SIZE),
+        VMSTATE_UINT32_ARRAY(level, GICv3State, GICV3_BMP_SIZE),
+        VMSTATE_UINT32_ARRAY(edge_trigger, GICv3State, GICV3_BMP_SIZE),
+        VMSTATE_UINT8_ARRAY(gicd_ipriority, GICv3State, GICV3_MAXIRQ),
+        VMSTATE_UINT64_ARRAY(gicd_irouter, GICv3State, GICV3_MAXIRQ),
+        VMSTATE_UINT32_ARRAY(gicd_nsacr, GICv3State,
+                             DIV_ROUND_UP(GICV3_MAXIRQ, 16)),
+        VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, GICv3State, num_cpu,
+                                             vmstate_gicv3_cpu, GICv3CPUState),
+        VMSTATE_END_OF_LIST()
+    }
 };
 
 void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index acc1730..d08808d 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -119,6 +119,13 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
                             KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd);
     kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
                             KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd);
+
+    /* Block migration of a KVM GICv3 device: the API for saving and restoring
+     * the state in the kernel is not yet finalised in the kernel or
+     * implemented in QEMU.
+     */
+    error_setg(&s->migration_blocker, "vGICv3 migration is not implemented");
+    migrate_add_blocker(s->migration_blocker);
 }
 
 static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 09/20] hw/intc/arm_gicv3: ARM GICv3 device framework
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (7 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 08/20] hw/intc/arm_gicv3: Add vmstate descriptors Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 10/20] hw/intc/arm_gicv3: Implement functions to identify next pending irq Peter Maydell
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

From: Shlomo Pongratz <shlomo.pongratz@huawei.com>

This patch includes the device class itself, some ID register
value functions which will be needed by both distributor
and redistributor, and some skeleton functions for handling
interrupts coming in and going out, which will be filled in
in a subsequent patch.

Signed-off-by: Shlomo Pongratz <shlomo.pongratz@huawei.com>
[PMM: pulled this patch earlier in the sequence, and left
 some code out of it for a later patch]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 hw/intc/Makefile.objs       |  1 +
 hw/intc/arm_gicv3.c         | 74 +++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/gicv3_internal.h    | 24 +++++++++++++++
 include/hw/intc/arm_gicv3.h | 32 ++++++++++++++++++++
 4 files changed, 131 insertions(+)
 create mode 100644 hw/intc/arm_gicv3.c
 create mode 100644 include/hw/intc/arm_gicv3.h

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 0e47f0f..4e94fdd 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -13,6 +13,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
 common-obj-$(CONFIG_OPENPIC) += openpic.o
 
 obj-$(CONFIG_APIC) += apic.o apic_common.o
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
new file mode 100644
index 0000000..96e0d2f
--- /dev/null
+++ b/hw/intc/arm_gicv3.c
@@ -0,0 +1,74 @@
+/*
+ * 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"
+
+/* 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
+     *  ...
+     */
+    /* Do nothing for now */
+}
+
+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, NULL);
+}
+
+static void arm_gicv3_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ARMGICv3Class *agc = ARM_GICV3_CLASS(klass);
+
+    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)
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index d23524b..97c9d75 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -159,6 +159,30 @@
 #define ICC_CTLR_EL3_A3V (1U << 15)
 #define ICC_CTLR_EL3_NDS (1U << 17)
 
+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_redist_affid:
  *
diff --git a/include/hw/intc/arm_gicv3.h b/include/hw/intc/arm_gicv3.h
new file mode 100644
index 0000000..4a6fd85
--- /dev/null
+++ b/include/hw/intc/arm_gicv3.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
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 10/20] hw/intc/arm_gicv3: Implement functions to identify next pending irq
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (8 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 09/20] hw/intc/arm_gicv3: ARM GICv3 device framework Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-15  2:35   ` Shannon Zhao
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 11/20] hw/intc/arm_gicv3: Implement GICv3 distributor registers Peter Maydell
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Implement the GICv3 logic to recalculate the highest priority pending
interrupt for each CPU after some part of the GIC state has changed.
We avoid unnecessary full recalculation where possible.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/arm_gicv3.c                | 293 +++++++++++++++++++++++++++++++++++++
 hw/intc/arm_gicv3_common.c         |   9 ++
 hw/intc/gicv3_internal.h           | 121 +++++++++++++++
 include/hw/intc/arm_gicv3_common.h |  18 +++
 4 files changed, 441 insertions(+)

diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 96e0d2f..171d587 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -21,6 +21,287 @@
 #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)
 {
@@ -33,6 +314,16 @@ static void gicv3_set_irq(void *opaque, int irq, int level)
     /* Do nothing for now */
 }
 
+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 void arm_gic_realize(DeviceState *dev, Error **errp)
 {
     /* Device instance realize function for the GIC sysbus device */
@@ -52,8 +343,10 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
 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;
 }
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index d1714e4..0f8c4b8 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -246,6 +246,8 @@ static void arm_gicv3_common_reset(DeviceState *dev)
         cs->gicr_nsacr = 0;
         memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr));
 
+        cs->hppi.prio = 0xff;
+
         /* State in the CPU interface must *not* be reset here, because it
          * is part of the CPU's reset domain, not the GIC device's.
          */
@@ -271,6 +273,13 @@ static void arm_gicv3_common_reset(DeviceState *dev)
     memset(s->gicd_ipriority, 0, sizeof(s->gicd_ipriority));
     memset(s->gicd_irouter, 0, sizeof(s->gicd_irouter));
     memset(s->gicd_nsacr, 0, sizeof(s->gicd_nsacr));
+    /* GICD_IROUTER are UNKNOWN at reset so in theory the guest must
+     * write these to get sane behaviour and we need not populate the
+     * pointer cache here; however having the cache be different for
+     * "happened to be 0 from reset" and "guest wrote 0" would be
+     * too confusing.
+     */
+    gicv3_cache_all_target_cpustates(s);
 
     if (s->irq_reset_nonsecure) {
         /* If we're resetting a TZ-aware GIC as if secure firmware
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 97c9d75..2ee9eeb 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -159,6 +159,63 @@
 #define ICC_CTLR_EL3_A3V (1U << 15)
 #define ICC_CTLR_EL3_NDS (1U << 17)
 
+/* 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);
+
+/**
+ * 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.
+ */
+static inline void gicv3_cpuif_update(GICv3CPUState *cs)
+{
+    /* This will be implemented in a later commit. */
+}
+
 static inline uint32_t gicv3_iidr(void)
 {
     /* Return the Implementer Identification Register value
@@ -184,6 +241,32 @@ static inline uint32_t gicv3_idreg(int regoffset)
 }
 
 /**
+ * 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
@@ -193,4 +276,42 @@ 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 */
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index cc6ac74..f72e499 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -131,6 +131,12 @@ typedef struct GICv3CPUState GICv3CPUState;
 #define GICV3_S 0
 #define GICV3_NS 1
 
+typedef struct {
+    int irq;
+    uint8_t prio;
+    int grp;
+} PendingIrq;
+
 struct GICv3CPUState {
     GICv3State *gic;
     CPUState *cpu;
@@ -163,6 +169,14 @@ struct GICv3CPUState {
     uint64_t icc_apr[3][4];
     uint64_t icc_igrpen[3];
     uint64_t icc_ctlr_el3;
+
+    /* Current highest priority pending interrupt for this CPU.
+     * This is cached information that can be recalculated from the
+     * real state above; it doesn't need to be migrated.
+     */
+    PendingIrq hppi;
+    /* This is temporary working state, to avoid a malloc in gicv3_update() */
+    bool seenbetter;
 };
 
 struct GICv3State {
@@ -198,6 +212,10 @@ struct GICv3State {
     GIC_DECLARE_BITMAP(edge_trigger); /* GICD_ICFGR even bits */
     uint8_t gicd_ipriority[GICV3_MAXIRQ];
     uint64_t gicd_irouter[GICV3_MAXIRQ];
+    /* Cached information: pointer to the cpu i/f for the CPUs specified
+     * in the IROUTER registers
+     */
+    GICv3CPUState *gicd_irouter_target[GICV3_MAXIRQ];
     uint32_t gicd_nsacr[DIV_ROUND_UP(GICV3_MAXIRQ, 16)];
 
     GICv3CPUState *cpu;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 11/20] hw/intc/arm_gicv3: Implement GICv3 distributor registers
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (9 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 10/20] hw/intc/arm_gicv3: Implement functions to identify next pending irq Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-15  2:36   ` Shannon Zhao
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 12/20] hw/intc/arm_gicv3: Implement GICv3 redistributor registers Peter Maydell
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

From: Shlomo Pongratz <shlomo.pongratz@huawei.com>

Implement the distributor registers of a GICv3.

Signed-off-by: Shlomo Pongratz <shlomo.pongratz@huawei.com>
[PMM: significantly overhauled/rewritten:
 * use the new bitmap data structures
 * restructure register read/write to handle different width accesses
   natively, since almost all registers are 32-bit only, rather
   than implementing everything as byte accesses
 * implemented security extension support
]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/Makefile.objs    |   1 +
 hw/intc/arm_gicv3_dist.c | 858 +++++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/gicv3_internal.h |   4 +
 trace-events             |   6 +
 4 files changed, 869 insertions(+)
 create mode 100644 hw/intc/arm_gicv3_dist.c

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 4e94fdd..a173d29 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -14,6 +14,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
 common-obj-$(CONFIG_OPENPIC) += openpic.o
 
 obj-$(CONFIG_APIC) += apic.o apic_common.o
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
new file mode 100644
index 0000000..881d555
--- /dev/null
+++ b/hw/intc/arm_gicv3_dist.c
@@ -0,0 +1,858 @@
+/*
+ * 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;
+}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 2ee9eeb..7cb9926 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -201,6 +201,10 @@ void gicv3_full_update_noirqset(GICv3State *s);
  * 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);
 
 /**
  * gicv3_cpuif_update:
diff --git a/trace-events b/trace-events
index 421d89f..f295d86 100644
--- a/trace-events
+++ b/trace-events
@@ -2163,3 +2163,9 @@ e1000e_cfg_support_virtio(bool support) "Virtio header supported: %d"
 
 e1000e_vm_state_running(void) "VM state is running"
 e1000e_vm_state_stopped(void) "VM state is stopped"
+
+# hw/intc/arm_gicv3_dist.c
+gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
+gicv3_dist_badread(uint64_t offset, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " size %u secure %d: error"
+gicv3_dist_write(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
+gicv3_dist_badwrite(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 12/20] hw/intc/arm_gicv3: Implement GICv3 redistributor registers
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (10 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 11/20] hw/intc/arm_gicv3: Implement GICv3 distributor registers Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-15  2:42   ` Shannon Zhao
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 13/20] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions Peter Maydell
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

From: Shlomo Pongratz <shlomo.pongratz@huawei.com>

Implement the redistributor registers of a GICv3.

Signed-off-by: Shlomo Pongratz <shlomo.pongratz@huawei.com>
[PMM: significantly overhauled/rewritten:
 * use the new data structures
 * restructure register read/write to handle different width accesses
   natively, since almost all registers are 32-bit only, rather
   than implementing everything as byte accesses
 * implemented security extension support
]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/Makefile.objs      |   1 +
 hw/intc/arm_gicv3_redist.c | 501 +++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/gicv3_internal.h   |   4 +
 trace-events               |   6 +
 4 files changed, 512 insertions(+)
 create mode 100644 hw/intc/arm_gicv3_redist.c

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index a173d29..417db11 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -15,6 +15,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o
 common-obj-$(CONFIG_OPENPIC) += openpic.o
 
 obj-$(CONFIG_APIC) += apic.o apic_common.o
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
new file mode 100644
index 0000000..e0f23e1
--- /dev/null
+++ b/hw/intc/arm_gicv3_redist.c
@@ -0,0 +1,501 @@
+/*
+ * 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 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;
+}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 7cb9926..b70e052 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -205,6 +205,10 @@ 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);
 
 /**
  * gicv3_cpuif_update:
diff --git a/trace-events b/trace-events
index f295d86..c88be1a 100644
--- a/trace-events
+++ b/trace-events
@@ -2169,3 +2169,9 @@ gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GIC
 gicv3_dist_badread(uint64_t offset, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " size %u secure %d: error"
 gicv3_dist_write(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
 gicv3_dist_badwrite(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
+
+# hw/intc/arm_gicv3_redist.c
+gicv3_redist_read(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
+gicv3_redist_badread(uint32_t cpu, uint64_t offset, unsigned size, bool secure) "GICv3 redistributor %x read: offset 0x%" PRIx64 " size %u secure %d: error"
+gicv3_redist_write(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
+gicv3_redist_badwrite(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 13/20] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (11 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 12/20] hw/intc/arm_gicv3: Implement GICv3 redistributor registers Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 14/20] hw/intc/arm_gicv3: Implement gicv3_set_irq() Peter Maydell
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Wire up the MMIO functions exposed by the distributor and the
redistributor into MMIO regions exposed by the GICv3 device.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 hw/intc/arm_gicv3.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 171d587..4c1fbb6 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -324,6 +324,19 @@ static void arm_gicv3_post_load(GICv3State *s)
     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 */
@@ -337,7 +350,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    gicv3_init_irqs_and_mmio(s, gicv3_set_irq, NULL);
+    gicv3_init_irqs_and_mmio(s, gicv3_set_irq, gic_ops);
 }
 
 static void arm_gicv3_class_init(ObjectClass *klass, void *data)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 14/20] hw/intc/arm_gicv3: Implement gicv3_set_irq()
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (12 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 13/20] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 15/20] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers Peter Maydell
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Implement the code which updates the GIC state when an interrupt
input into the GIC is asserted.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 hw/intc/arm_gicv3.c        | 20 +++++++++++++++++++-
 hw/intc/arm_gicv3_dist.c   | 21 +++++++++++++++++++++
 hw/intc/arm_gicv3_redist.c | 21 +++++++++++++++++++++
 hw/intc/gicv3_internal.h   |  2 ++
 trace-events               |  2 ++
 5 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 4c1fbb6..65ebca2 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -311,7 +311,25 @@ static void gicv3_set_irq(void *opaque, int irq, int level)
      *  [N+32..N+63] : PPI (internal interrupts for CPU 1
      *  ...
      */
-    /* Do nothing for now */
+    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)
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
index 881d555..b977ae5 100644
--- a/hw/intc/arm_gicv3_dist.c
+++ b/hw/intc/arm_gicv3_dist.c
@@ -856,3 +856,24 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data,
     }
     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);
+}
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index e0f23e1..1130eee 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -499,3 +499,24 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
     }
     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);
+}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index b70e052..a6f443c 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -209,6 +209,8 @@ 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);
 
 /**
  * gicv3_cpuif_update:
diff --git a/trace-events b/trace-events
index c88be1a..3aa8cce 100644
--- a/trace-events
+++ b/trace-events
@@ -2169,9 +2169,11 @@ gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GIC
 gicv3_dist_badread(uint64_t offset, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " size %u secure %d: error"
 gicv3_dist_write(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
 gicv3_dist_badwrite(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
+gicv3_dist_set_irq(int irq, int level) "GICv3 distributor interrupt %d level changed to %d"
 
 # hw/intc/arm_gicv3_redist.c
 gicv3_redist_read(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
 gicv3_redist_badread(uint32_t cpu, uint64_t offset, unsigned size, bool secure) "GICv3 redistributor %x read: offset 0x%" PRIx64 " size %u secure %d: error"
 gicv3_redist_write(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
 gicv3_redist_badwrite(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
+gicv3_redist_set_irq(uint32_t cpu, int irq, int level) "GICv3 redistributor %x interrupt %d level changed to %d"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 15/20] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (13 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 14/20] hw/intc/arm_gicv3: Implement gicv3_set_irq() Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-15  2:45   ` Shannon Zhao
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 16/20] hw/intc/arm_gicv3: Implement gicv3_cpuif_update() Peter Maydell
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Implement the CPU interface registers for the GICv3; these are
CPU system registers, not MMIO registers.

This commit implements all the registers which are simple
accessors for GIC state, but not those which act as interfaces
for acknowledging, dismissing or generating interrupts. (Those
will be added in a later commit.)

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/Makefile.objs     |   1 +
 hw/intc/arm_gicv3.c       |   2 +
 hw/intc/arm_gicv3_cpuif.c | 646 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/gicv3_internal.h  |   1 +
 trace-events              |  16 ++
 5 files changed, 666 insertions(+)
 create mode 100644 hw/intc/arm_gicv3_cpuif.c

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 417db11..c7bbf88 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -35,3 +35,4 @@ obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
 obj-$(CONFIG_S390_FLIC) += s390_flic.o
 obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
 obj-$(CONFIG_ASPEED_SOC) += aspeed_vic.o
+obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 65ebca2..8a6c647 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -369,6 +369,8 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
     }
 
     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)
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
new file mode 100644
index 0000000..e112646
--- /dev/null
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -0,0 +1,646 @@
+/*
+ * ARM Generic Interrupt Controller v3
+ *
+ * Copyright (c) 2016 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This code is licensed under the GPL, version 2 or (at your option)
+ * any later version.
+ */
+
+/* This file contains the code for the system register interface
+ * portions of the GICv3.
+ */
+
+#include "qemu/osdep.h"
+#include "trace.h"
+#include "gicv3_internal.h"
+#include "cpu.h"
+
+static GICv3CPUState *icc_cs_from_env(CPUARMState *env)
+{
+    /* Given the CPU, find the right GICv3CPUState struct.
+     * Since we registered the CPU interface with the EL change hook as
+     * the opaque pointer, we can just directly get from the CPU to it.
+     */
+    return arm_get_el_change_hook_opaque(arm_env_get_cpu(env));
+}
+
+static bool gicv3_use_ns_bank(CPUARMState *env)
+{
+    /* Return true if we should use the NonSecure bank for a banked GIC
+     * CPU interface register. Note that this differs from the
+     * access_secure_reg() function because GICv3 banked registers are
+     * banked even for AArch64, unlike the other CPU system registers.
+     */
+    return !arm_is_secure_below_el3(env);
+}
+
+static uint64_t icc_pmr_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    uint32_t value = cs->icc_pmr_el1;
+
+    if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env) &&
+        (env->cp15.scr_el3 & SCR_FIQ)) {
+        /* NS access and Group 0 is inaccessible to NS: return the
+         * NS view of the current priority
+         */
+        if (value & 0x80) {
+            /* Secure priorities not visible to NS */
+            value = 0;
+        } else if (value != 0xff) {
+            value = (value << 1) & 0xff;
+        }
+    }
+
+    trace_gicv3_icc_pmr_read(gicv3_redist_affid(cs), value);
+
+    return value;
+}
+
+static void icc_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                          uint64_t value)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+
+    trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value);
+
+    value &= 0xff;
+
+    if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env) &&
+        (env->cp15.scr_el3 & SCR_FIQ)) {
+        /* NS access and Group 0 is inaccessible to NS: return the
+         * NS view of the current priority
+         */
+        if (!(cs->icc_pmr_el1 & 0x80)) {
+            /* Current PMR in the secure range, don't allow NS to change it */
+            return;
+        }
+        value = (value >> 1) & 0x80;
+    }
+    cs->icc_pmr_el1 = value;
+    gicv3_cpuif_update(cs);
+}
+
+static uint64_t icc_bpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    int grp = (ri->crm == 8) ? GICV3_G0 : GICV3_G1;
+    bool satinc = false;
+    uint64_t bpr;
+
+    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
+        grp = GICV3_G1NS;
+    }
+
+    if (grp == GICV3_G1 && !arm_is_el3_or_mon(env) &&
+        (cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_CBPR)) {
+        /* CBPR_EL1S means secure EL1 or AArch32 EL3 !Mon BPR1 accesses
+         * modify BPR0
+         */
+        grp = GICV3_G0;
+    }
+
+    if (grp == GICV3_G1NS && arm_current_el(env) < 3 &&
+        (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR)) {
+        /* reads return bpr0 + 1 sat to 7, writes ignored */
+        grp = GICV3_G0;
+        satinc = true;
+    }
+
+    bpr = cs->icc_bpr[grp];
+    if (satinc) {
+        bpr++;
+        bpr = MIN(bpr, 7);
+    }
+
+    trace_gicv3_icc_bpr_read(gicv3_redist_affid(cs), bpr);
+
+    return bpr;
+}
+
+static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                          uint64_t value)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    int grp = (ri->crm == 8) ? GICV3_G0 : GICV3_G1;
+
+    trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value);
+
+    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
+        grp = GICV3_G1NS;
+    }
+
+    if (grp == GICV3_G1 && !arm_is_el3_or_mon(env) &&
+        (cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_CBPR)) {
+        /* CBPR_EL1S means secure EL1 or AArch32 EL3 !Mon BPR1 accesses
+         * modify BPR0
+         */
+        grp = GICV3_G0;
+    }
+
+    if (grp == GICV3_G1NS && arm_current_el(env) < 3 &&
+        (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR)) {
+        /* reads return bpr0 + 1 sat to 7, writes ignored */
+        return;
+    }
+
+    cs->icc_bpr[grp] = value & 7;
+    gicv3_cpuif_update(cs);
+}
+
+static uint64_t icc_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    uint64_t value;
+
+    int regno = ri->opc2 & 3;
+    int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1;
+
+    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
+        grp = GICV3_G1NS;
+    }
+
+    value = cs->icc_apr[grp][regno];
+
+    trace_gicv3_icc_ap_read(regno, gicv3_redist_affid(cs), value);
+    return value;
+}
+
+static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                         uint64_t value)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+
+    int regno = ri->opc2 & 3;
+    int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1;
+
+    trace_gicv3_icc_ap_write(regno, gicv3_redist_affid(cs), value);
+
+    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
+        grp = GICV3_G1NS;
+    }
+
+    /* It's not possible to claim that a Non-secure interrupt is active
+     * at a priority outside the Non-secure range (128..255), since this
+     * would otherwise allow malicious NS code to block delivery of S interrupts
+     * by writing a bad value to these registers.
+     */
+    if (grp == GICV3_G1NS && regno < 2 && arm_feature(env, ARM_FEATURE_EL3)) {
+        return;
+    }
+
+    cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU;
+    gicv3_cpuif_update(cs);
+}
+
+static uint64_t icc_igrpen_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    int grp = ri->opc2 & 1 ? GICV3_G1 : GICV3_G0;
+    uint64_t value;
+
+    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
+        grp = GICV3_G1NS;
+    }
+
+    value = cs->icc_igrpen[grp];
+    trace_gicv3_icc_igrpen_read(gicv3_redist_affid(cs), value);
+    return value;
+}
+
+static void icc_igrpen_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                             uint64_t value)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    int grp = ri->opc2 & 1 ? GICV3_G1 : GICV3_G0;
+
+    trace_gicv3_icc_igrpen_write(gicv3_redist_affid(cs), value);
+
+    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
+        grp = GICV3_G1NS;
+    }
+
+    cs->icc_igrpen[grp] = value & ICC_IGRPEN_ENABLE;
+    gicv3_cpuif_update(cs);
+}
+
+static uint64_t icc_igrpen1_el3_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+
+    /* IGRPEN1_EL3 bits 0 and 1 are r/w aliases into IGRPEN1_EL1 NS and S */
+    return cs->icc_igrpen[GICV3_G1NS] | (cs->icc_igrpen[GICV3_G1] << 1);
+}
+
+static void icc_igrpen1_el3_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                                  uint64_t value)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+
+    trace_gicv3_icc_igrpen1_el3_write(gicv3_redist_affid(cs), value);
+
+    /* IGRPEN1_EL3 bits 0 and 1 are r/w aliases into IGRPEN1_EL1 NS and S */
+    cs->icc_igrpen[GICV3_G1NS] = extract32(value, 0, 1);
+    cs->icc_igrpen[GICV3_G1] = extract32(value, 1, 1);
+    gicv3_cpuif_update(cs);
+}
+
+static uint64_t icc_ctlr_el1_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    int bank = gicv3_use_ns_bank(env) ? GICV3_NS : GICV3_S;
+    uint64_t value;
+
+    value = cs->icc_ctlr_el1[bank];
+    trace_gicv3_icc_ctlr_read(gicv3_redist_affid(cs), value);
+    return value;
+}
+
+static void icc_ctlr_el1_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                               uint64_t value)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    int bank = gicv3_use_ns_bank(env) ? GICV3_NS : GICV3_S;
+    uint64_t mask;
+
+    trace_gicv3_icc_ctlr_write(gicv3_redist_affid(cs), value);
+
+    /* Only CBPR and EOIMODE can be RW;
+     * for us PMHE is RAZ/WI (we don't implement 1-of-N interrupts or
+     * the asseciated priority-based routing of them);
+     * if EL3 is implemented and GICD_CTLR.DS == 0, then PMHE and CBPR are RO.
+     */
+    if (arm_feature(env, ARM_FEATURE_EL3) &&
+        ((cs->gic->gicd_ctlr & GICD_CTLR_DS) == 0)) {
+        mask = ICC_CTLR_EL1_EOIMODE;
+    } else {
+        mask = ICC_CTLR_EL1_CBPR | ICC_CTLR_EL1_EOIMODE;
+    }
+
+    cs->icc_ctlr_el1[bank] &= ~mask;
+    cs->icc_ctlr_el1[bank] |= (value & mask);
+    gicv3_cpuif_update(cs);
+}
+
+
+static uint64_t icc_ctlr_el3_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    uint64_t value;
+
+    value = cs->icc_ctlr_el3;
+    if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_EOIMODE) {
+        value |= ICC_CTLR_EL3_EOIMODE_EL1NS;
+    }
+    if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR) {
+        value |= ICC_CTLR_EL3_CBPR_EL1NS;
+    }
+    if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_EOIMODE) {
+        value |= ICC_CTLR_EL3_EOIMODE_EL1S;
+    }
+    if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR) {
+        value |= ICC_CTLR_EL3_CBPR_EL1S;
+    }
+
+    trace_gicv3_icc_ctlr_el3_read(gicv3_redist_affid(cs), value);
+    return value;
+}
+
+static void icc_ctlr_el3_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                               uint64_t value)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    uint64_t mask;
+
+    trace_gicv3_icc_ctlr_el3_write(gicv3_redist_affid(cs), value);
+
+    /* *_EL1NS and *_EL1S bits are aliases into the ICC_CTLR_EL1 bits. */
+    cs->icc_ctlr_el1[GICV3_NS] &= (ICC_CTLR_EL1_CBPR | ICC_CTLR_EL1_EOIMODE);
+    if (value & ICC_CTLR_EL3_EOIMODE_EL1NS) {
+        cs->icc_ctlr_el1[GICV3_NS] |= ICC_CTLR_EL1_EOIMODE;
+    }
+    if (value & ICC_CTLR_EL3_CBPR_EL1NS) {
+        cs->icc_ctlr_el1[GICV3_NS] |= ICC_CTLR_EL1_CBPR;
+    }
+
+    cs->icc_ctlr_el1[GICV3_S] &= (ICC_CTLR_EL1_CBPR | ICC_CTLR_EL1_EOIMODE);
+    if (value & ICC_CTLR_EL3_EOIMODE_EL1S) {
+        cs->icc_ctlr_el1[GICV3_S] |= ICC_CTLR_EL1_EOIMODE;
+    }
+    if (value & ICC_CTLR_EL3_CBPR_EL1S) {
+        cs->icc_ctlr_el1[GICV3_S] |= ICC_CTLR_EL1_CBPR;
+    }
+
+    /* The only bit stored in icc_ctlr_el3 which is writeable is EOIMODE_EL3: */
+    mask = ICC_CTLR_EL3_EOIMODE_EL3;
+
+    cs->icc_ctlr_el3 &= ~mask;
+    cs->icc_ctlr_el3 |= (value & mask);
+    gicv3_cpuif_update(cs);
+}
+
+static CPAccessResult gicv3_irqfiq_access(CPUARMState *env,
+                                          const ARMCPRegInfo *ri, bool isread)
+{
+    CPAccessResult r = CP_ACCESS_OK;
+
+    if ((env->cp15.scr_el3 & (SCR_FIQ | SCR_IRQ)) == (SCR_FIQ | SCR_IRQ)) {
+        switch (arm_current_el(env)) {
+        case 1:
+            if (arm_is_secure_below_el3(env) ||
+                ((env->cp15.hcr_el2 & (HCR_IMO | HCR_FMO)) == 0)) {
+                r = CP_ACCESS_TRAP_EL3;
+            }
+            break;
+        case 2:
+            r = CP_ACCESS_TRAP_EL3;
+            break;
+        case 3:
+            if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
+                r = CP_ACCESS_TRAP_EL3;
+            }
+        default:
+            g_assert_not_reached();
+        }
+    }
+
+    if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
+        r = CP_ACCESS_TRAP;
+    }
+    return r;
+}
+
+static CPAccessResult gicv3_fiq_access(CPUARMState *env,
+                                       const ARMCPRegInfo *ri, bool isread)
+{
+    CPAccessResult r = CP_ACCESS_OK;
+
+    if (env->cp15.scr_el3 & SCR_FIQ) {
+        switch (arm_current_el(env)) {
+        case 1:
+            if (arm_is_secure_below_el3(env) ||
+                ((env->cp15.hcr_el2 & HCR_FMO) == 0)) {
+                r = CP_ACCESS_TRAP_EL3;
+            }
+            break;
+        case 2:
+            r = CP_ACCESS_TRAP_EL3;
+            break;
+        case 3:
+            if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
+                r = CP_ACCESS_TRAP_EL3;
+            }
+        default:
+            g_assert_not_reached();
+        }
+    }
+
+    if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
+        r = CP_ACCESS_TRAP;
+    }
+    return r;
+}
+
+static CPAccessResult gicv3_irq_access(CPUARMState *env,
+                                       const ARMCPRegInfo *ri, bool isread)
+{
+    CPAccessResult r = CP_ACCESS_OK;
+
+    if (env->cp15.scr_el3 & SCR_IRQ) {
+        switch (arm_current_el(env)) {
+        case 1:
+            if (arm_is_secure_below_el3(env) ||
+                ((env->cp15.hcr_el2 & HCR_IMO) == 0)) {
+                r = CP_ACCESS_TRAP_EL3;
+            }
+            break;
+        case 2:
+            r = CP_ACCESS_TRAP_EL3;
+            break;
+        case 3:
+            if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
+                r = CP_ACCESS_TRAP_EL3;
+            }
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    }
+
+    if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
+        r = CP_ACCESS_TRAP;
+    }
+    return r;
+}
+
+static void icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+
+    cs->icc_ctlr_el1[GICV3_S] = ICC_CTLR_EL1_A3V |
+        (1 << ICC_CTLR_EL1_IDBITS_SHIFT) |
+        (7 << ICC_CTLR_EL1_PRIBITS_SHIFT);
+    cs->icc_ctlr_el1[GICV3_NS] = ICC_CTLR_EL1_A3V |
+        (1 << ICC_CTLR_EL1_IDBITS_SHIFT) |
+        (7 << ICC_CTLR_EL1_PRIBITS_SHIFT);
+    cs->icc_pmr_el1 = 0;
+    cs->icc_bpr[GICV3_G0] = GIC_MIN_BPR;
+    cs->icc_bpr[GICV3_G1] = GIC_MIN_BPR;
+    if (arm_feature(env, ARM_FEATURE_EL3)) {
+        cs->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR_NS;
+    } else {
+        cs->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR;
+    }
+    memset(cs->icc_apr, 0, sizeof(cs->icc_apr));
+    memset(cs->icc_igrpen, 0, sizeof(cs->icc_igrpen));
+    cs->icc_ctlr_el3 = ICC_CTLR_EL3_NDS | ICC_CTLR_EL3_A3V |
+        (1 << ICC_CTLR_EL3_IDBITS_SHIFT) |
+        (7 << ICC_CTLR_EL3_PRIBITS_SHIFT);
+}
+
+static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
+    { .name = "ICC_PMR_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 6, .opc2 = 0,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_irqfiq_access,
+      .readfn = icc_pmr_read,
+      .writefn = icc_pmr_write,
+      /* We hang the whole cpu interface reset routine off here
+       * rather than parcelling it out into one little function
+       * per register
+       */
+      .resetfn = icc_reset,
+    },
+    { .name = "ICC_BPR0_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 3,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_fiq_access,
+      .fieldoffset = offsetof(GICv3CPUState, icc_bpr[GICV3_G0]),
+      .writefn = icc_bpr_write,
+    },
+    { .name = "ICC_AP0R0_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 4,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_fiq_access,
+      .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][0]),
+      .writefn = icc_ap_write,
+    },
+    { .name = "ICC_AP0R1_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 5,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_fiq_access,
+      .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][1]),
+      .writefn = icc_ap_write,
+    },
+    { .name = "ICC_AP0R2_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 6,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_fiq_access,
+      .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][2]),
+      .writefn = icc_ap_write,
+    },
+    { .name = "ICC_AP0R3_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 7,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_fiq_access,
+      .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][3]),
+      .writefn = icc_ap_write,
+    },
+    /* All the ICC_AP1R*_EL1 registers are banked */
+    { .name = "ICC_AP1R0_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 0,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_irq_access,
+      .readfn = icc_ap_read,
+      .writefn = icc_ap_write,
+    },
+    { .name = "ICC_AP1R1_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 1,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_irq_access,
+      .readfn = icc_ap_read,
+      .writefn = icc_ap_write,
+    },
+    { .name = "ICC_AP1R2_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 2,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_irq_access,
+      .readfn = icc_ap_read,
+      .writefn = icc_ap_write,
+    },
+    { .name = "ICC_AP1R3_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 3,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_irq_access,
+      .readfn = icc_ap_read,
+      .writefn = icc_ap_write,
+    },
+    /* This register is banked */
+    { .name = "ICC_BPR1_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 3,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_irq_access,
+      .readfn = icc_bpr_read,
+      .writefn = icc_bpr_write,
+    },
+    /* This register is banked */
+    { .name = "ICC_CTLR_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 4,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_irqfiq_access,
+      .readfn = icc_ctlr_el1_read,
+      .writefn = icc_ctlr_el1_write,
+    },
+    { .name = "ICC_SRE_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 5,
+      .type = ARM_CP_NO_RAW | ARM_CP_CONST,
+      .access = PL1_RW,
+      /* We don't support IRQ/FIQ bypass and system registers are
+       * always enabled, so all our bits are RAZ/WI or RAO/WI.
+       * This register is banked but since it's constant we don't
+       * need to do anything special.
+       */
+      .resetvalue = 0x7,
+    },
+    { .name = "ICC_IGRPEN0_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 6,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_fiq_access,
+      .fieldoffset = offsetof(GICv3CPUState, icc_igrpen[GICV3_G0]),
+      .writefn = icc_igrpen_write,
+    },
+    /* This register is banked */
+    { .name = "ICC_IGRPEN1_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 7,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_RW, .accessfn = gicv3_irq_access,
+      .readfn = icc_igrpen_read,
+      .writefn = icc_igrpen_write,
+    },
+    { .name = "ICC_SRE_EL2", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 5,
+      .type = ARM_CP_NO_RAW | ARM_CP_CONST,
+      .access = PL2_RW,
+      /* We don't support IRQ/FIQ bypass and system registers are
+       * always enabled, so all our bits are RAZ/WI or RAO/WI.
+       */
+      .resetvalue = 0xf,
+    },
+    { .name = "ICC_CTLR_EL3", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 6, .crn = 12, .crm = 12, .opc2 = 4,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL3_RW,
+      .fieldoffset = offsetof(GICv3CPUState, icc_ctlr_el3),
+      .readfn = icc_ctlr_el3_read,
+      .writefn = icc_ctlr_el3_write,
+    },
+    { .name = "ICC_SRE_EL3", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 6, .crn = 12, .crm = 12, .opc2 = 5,
+      .type = ARM_CP_NO_RAW | ARM_CP_CONST,
+      .access = PL3_RW,
+      /* We don't support IRQ/FIQ bypass and system registers are
+       * always enabled, so all our bits are RAZ/WI or RAO/WI.
+       */
+      .resetvalue = 0xf,
+    },
+    { .name = "ICC_IGRPEN1_EL3", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 6, .crn = 12, .crm = 12, .opc2 = 7,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL3_RW,
+      .readfn = icc_igrpen1_el3_read,
+      .writefn = icc_igrpen1_el3_write,
+    },
+    REGINFO_SENTINEL
+};
+
+static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque)
+{
+    /* Do nothing for now. */
+}
+
+void gicv3_init_cpuif(GICv3State *s)
+{
+    /* Called from the GICv3 realize function; register our system
+     * registers with the CPU
+     */
+    int i;
+
+    for (i = 0; i < s->num_cpu; i++) {
+        ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i));
+        GICv3CPUState *cs = &s->cpu[i];
+
+        /* Note that we can't just use the GICv3CPUState as an opaque pointer
+         * in define_arm_cp_regs_with_opaque(), because when we're called back
+         * it might be with code translated by CPU 0 but run by CPU 1, in
+         * which case we'd get the wrong value.
+         * So instead we define the regs with no ri->opaque info, and
+         * get back to the GICv3CPUState from the ARMCPU by reading back
+         * the opaque pointer from the el_change_hook, which we're going
+         * to need to register anyway.
+         */
+        define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
+        arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs);
+    }
+}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index a6f443c..13f951c 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -211,6 +211,7 @@ 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_init_cpuif(GICv3State *s);
 
 /**
  * gicv3_cpuif_update:
diff --git a/trace-events b/trace-events
index 3aa8cce..baf12ba 100644
--- a/trace-events
+++ b/trace-events
@@ -2164,6 +2164,22 @@ e1000e_cfg_support_virtio(bool support) "Virtio header supported: %d"
 e1000e_vm_state_running(void) "VM state is running"
 e1000e_vm_state_stopped(void) "VM state is stopped"
 
+# hw/intc/arm_gicv3_cpuif.c
+gicv3_icc_pmr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_PMR read cpu %x value 0x%" PRIx64
+gicv3_icc_pmr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_PMR write cpu %x value 0x%" PRIx64
+gicv3_icc_bpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_BPR read cpu %x value 0x%" PRIx64
+gicv3_icc_bpr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_BPR write cpu %x value 0x%" PRIx64
+gicv3_icc_ap_read(int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR read cpu %x value 0x%" PRIx64
+gicv3_icc_ap_write(int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR write cpu %x value 0x%" PRIx64
+gicv3_icc_igrpen_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN read cpu %x value 0x%" PRIx64
+gicv3_icc_igrpen_write(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN write cpu %x value 0x%" PRIx64
+gicv3_icc_igrpen1_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN1_EL3 read cpu %x value 0x%" PRIx64
+gicv3_icc_igrpen1_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN1_EL3 write cpu %x value 0x%" PRIx64
+gicv3_icc_ctlr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR read cpu %x value 0x%" PRIx64
+gicv3_icc_ctlr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR write cpu %x value 0x%" PRIx64
+gicv3_icc_ctlr_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 read cpu %x value 0x%" PRIx64
+gicv3_icc_ctlr_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 write cpu %x value 0x%" PRIx64
+
 # hw/intc/arm_gicv3_dist.c
 gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
 gicv3_dist_badread(uint64_t offset, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " size %u secure %d: error"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 16/20] hw/intc/arm_gicv3: Implement gicv3_cpuif_update()
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (14 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 15/20] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-15  2:47   ` Shannon Zhao
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 17/20] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers Peter Maydell
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Implement the gicv3_cpuif_update() function which deals with correctly
asserting IRQ and FIQ based on the current running priority of the CPU,
the priority of the highest priority pending interrupt and the CPU's
current exception level and security state.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/arm_gicv3_cpuif.c | 140 +++++++++++++++++++++++++++++++++++++++++++++-
 hw/intc/gicv3_internal.h  |   5 +-
 trace-events              |   2 +
 3 files changed, 142 insertions(+), 5 deletions(-)

diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index e112646..7faf3c0 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -36,6 +36,142 @@ static bool gicv3_use_ns_bank(CPUARMState *env)
     return !arm_is_secure_below_el3(env);
 }
 
+static int icc_highest_active_prio(GICv3CPUState *cs)
+{
+    /* Calculate the current running priority based on the set bits
+     * in the Active Priority Registers.
+     */
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) {
+        uint32_t apr = cs->icc_apr[GICV3_G0][i] |
+            cs->icc_apr[GICV3_G1][i] | cs->icc_apr[GICV3_G1NS][i];
+
+        if (!apr) {
+            continue;
+        }
+        return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1);
+    }
+    /* No current active interrupts: return idle priority */
+    return 0xff;
+}
+
+static uint32_t icc_gprio_mask(GICv3CPUState *cs, int group)
+{
+    /* Return a mask word which clears the subpriority bits from
+     * a priority value for an interrupt in the specified group.
+     * This depends on the BPR value:
+     *  a BPR of 0 means the group priority bits are [7:1];
+     *  a BPR of 1 means they are [7:2], and so on down to
+     *  a BPR of 7 meaning no group priority bits at all.
+     * Which BPR to use depends on the group of the interrupt and
+     * the current ICC_CTLR.CBPR settings.
+     */
+    if ((group == GICV3_G1 && cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_CBPR) ||
+        (group == GICV3_G1NS &&
+         cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR)) {
+        group = GICV3_G0;
+    }
+
+    return ~0U << ((cs->icc_bpr[group] & 7) + 1);
+}
+
+static bool icc_no_enabled_hppi(GICv3CPUState *cs)
+{
+    /* Return true if there is no pending interrupt, or the
+     * highest priority pending interrupt is in a group which has been
+     * disabled at the CPU interface by the ICC_IGRPEN* register enable bits.
+     */
+    return cs->hppi.prio == 0xff || (cs->icc_igrpen[cs->hppi.grp] == 0);
+}
+
+static bool icc_hppi_can_preempt(GICv3CPUState *cs)
+{
+    /* Return true if we have a pending interrupt of sufficient
+     * priority to preempt.
+     */
+    int rprio;
+    uint32_t mask;
+
+    if (icc_no_enabled_hppi(cs)) {
+        return false;
+    }
+
+    if (cs->hppi.prio >= cs->icc_pmr_el1) {
+        /* Priority mask masks this interrupt */
+        return false;
+    }
+
+    rprio = icc_highest_active_prio(cs);
+    if (rprio == 0xff) {
+        /* No currently running interrupt so we can preempt */
+        return true;
+    }
+
+    mask = icc_gprio_mask(cs, cs->hppi.grp);
+
+    /* We only preempt a running interrupt if the pending interrupt's
+     * group priority is sufficient (the subpriorities are not considered).
+     */
+    if ((cs->hppi.prio & mask) < (rprio & mask)) {
+        return true;
+    }
+
+    return false;
+}
+
+void gicv3_cpuif_update(GICv3CPUState *cs)
+{
+    /* Tell the CPU about its highest priority pending interrupt */
+    int irqlevel = 0;
+    int fiqlevel = 0;
+    ARMCPU *cpu = ARM_CPU(cs->cpu);
+    CPUARMState *env = &cpu->env;
+
+    trace_gicv3_cpuif_update(gicv3_redist_affid(cs), cs->hppi.irq,
+                             cs->hppi.grp, cs->hppi.prio);
+
+    if (cs->hppi.grp == GICV3_G1 && !arm_feature(env, ARM_FEATURE_EL3)) {
+        /* If a Security-enabled GIC sends a G1S interrupt to a
+         * Security-disabled CPU, we must treat it as if it were G0.
+         */
+        cs->hppi.grp = GICV3_G0;
+    }
+
+    if (icc_hppi_can_preempt(cs)) {
+        /* We have an interrupt: should we signal it as IRQ or FIQ?
+         * This is described in the GICv3 spec section 4.6.2.
+         */
+        bool isfiq;
+
+        switch (cs->hppi.grp) {
+        case GICV3_G0:
+            isfiq = true;
+            break;
+        case GICV3_G1:
+            isfiq = (!arm_is_secure(env) ||
+                     (arm_current_el(env) == 3 && arm_el_is_aa64(env, 3)));
+            break;
+        case GICV3_G1NS:
+            isfiq = arm_is_secure(env);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+
+        if (isfiq) {
+            fiqlevel = 1;
+        } else {
+            irqlevel = 1;
+        }
+    }
+
+    trace_gicv3_cpuif_set_irqs(gicv3_redist_affid(cs), fiqlevel, irqlevel);
+
+    qemu_set_irq(cs->parent_fiq, fiqlevel);
+    qemu_set_irq(cs->parent_irq, irqlevel);
+}
+
 static uint64_t icc_pmr_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     GICv3CPUState *cs = icc_cs_from_env(env);
@@ -617,7 +753,9 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
 
 static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque)
 {
-    /* Do nothing for now. */
+    GICv3CPUState *cs = opaque;
+
+    gicv3_cpuif_update(cs);
 }
 
 void gicv3_init_cpuif(GICv3State *s)
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 13f951c..e469599 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -222,10 +222,7 @@ void gicv3_init_cpuif(GICv3State *s);
  * current running priority or the CPU's current exception level or
  * security state.
  */
-static inline void gicv3_cpuif_update(GICv3CPUState *cs)
-{
-    /* This will be implemented in a later commit. */
-}
+void gicv3_cpuif_update(GICv3CPUState *cs);
 
 static inline uint32_t gicv3_iidr(void)
 {
diff --git a/trace-events b/trace-events
index baf12ba..c8fb467 100644
--- a/trace-events
+++ b/trace-events
@@ -2179,6 +2179,8 @@ gicv3_icc_ctlr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR read cpu %x valu
 gicv3_icc_ctlr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR write cpu %x value 0x%" PRIx64
 gicv3_icc_ctlr_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 read cpu %x value 0x%" PRIx64
 gicv3_icc_ctlr_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 write cpu %x value 0x%" PRIx64
+gicv3_cpuif_update(uint32_t cpuid, int irq, int grp, int prio) "GICv3 CPU i/f %x HPPI update: irq %d group %d prio %d"
+gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f %x HPPI update: setting FIQ %d IRQ %d"
 
 # hw/intc/arm_gicv3_dist.c
 gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 17/20] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (15 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 16/20] hw/intc/arm_gicv3: Implement gicv3_cpuif_update() Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 18/20] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers Peter Maydell
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Implement the registers in the GICv3 CPU interface which generate
new SGI interrupts.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 hw/intc/arm_gicv3_cpuif.c  | 125 +++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/arm_gicv3_redist.c |  40 +++++++++++++++
 hw/intc/gicv3_internal.h   |   1 +
 trace-events               |   2 +
 4 files changed, 168 insertions(+)

diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 7faf3c0..a368dbb 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -331,6 +331,95 @@ static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
     gicv3_cpuif_update(cs);
 }
 
+static void icc_generate_sgi(CPUARMState *env, GICv3CPUState *cs,
+                             uint64_t value, int grp, bool ns)
+{
+    GICv3State *s = cs->gic;
+
+    /* Extract Aff3/Aff2/Aff1 and shift into the bottom 24 bits */
+    uint64_t aff = extract64(value, 48, 8) << 16 |
+        extract64(value, 32, 8) << 8 |
+        extract64(value, 16, 8);
+    uint32_t targetlist = extract64(value, 0, 16);
+    uint32_t irq = extract64(value, 24, 4);
+    bool irm = extract64(value, 40, 1);
+    int i;
+
+    if (grp == GICV3_G1 && s->gicd_ctlr & GICD_CTLR_DS) {
+        /* If GICD_CTLR.DS == 1, the Distributor treats Secure Group 1
+         * interrupts as Group 0 interrupts and must send Secure Group 0
+         * interrupts to the target CPUs.
+         */
+        grp = GICV3_G0;
+    }
+
+    trace_gicv3_icc_generate_sgi(gicv3_redist_affid(cs), irq, irm,
+                                 aff, targetlist);
+
+    for (i = 0; i < s->num_cpu; i++) {
+        GICv3CPUState *ocs = &s->cpu[i];
+
+        if (irm) {
+            /* IRM == 1 : route to all CPUs except self */
+            if (cs == ocs) {
+                continue;
+            }
+        } else {
+            /* IRM == 0 : route to Aff3.Aff2.Aff1.n for all n in [0..15]
+             * where the corresponding bit is set in targetlist
+             */
+            int aff0;
+
+            if (ocs->gicr_typer >> 40 != aff) {
+                continue;
+            }
+            aff0 = extract64(ocs->gicr_typer, 32, 8);
+            if (aff0 > 15 || extract32(targetlist, aff0, 1) == 0) {
+                continue;
+            }
+        }
+
+        /* The redistributor will check against its own GICR_NSACR as needed */
+        gicv3_redist_send_sgi(ocs, grp, irq, ns);
+    }
+}
+
+static void icc_sgi0r_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                           uint64_t value)
+{
+    /* Generate Secure Group 0 SGI. */
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    bool ns = !arm_is_secure(env);
+
+    icc_generate_sgi(env, cs, value, GICV3_G0, ns);
+}
+
+static void icc_sgi1r_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                           uint64_t value)
+{
+    /* Generate Group 1 SGI for the current Security state */
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    int grp;
+    bool ns = !arm_is_secure(env);
+
+    grp = ns ? GICV3_G1NS : GICV3_G1;
+    icc_generate_sgi(env, cs, value, grp, ns);
+}
+
+static void icc_asgi1r_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                             uint64_t value)
+{
+    /* Generate Group 1 SGI for the Security state that is not
+     * the current state
+     */
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    int grp;
+    bool ns = !arm_is_secure(env);
+
+    grp = ns ? GICV3_G1 : GICV3_G1NS;
+    icc_generate_sgi(env, cs, value, grp, ns);
+}
+
 static uint64_t icc_igrpen_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     GICv3CPUState *cs = icc_cs_from_env(env);
@@ -673,6 +762,42 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
       .readfn = icc_ap_read,
       .writefn = icc_ap_write,
     },
+    { .name = "ICC_SGI1R_EL1", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 5,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_W, .accessfn = gicv3_irqfiq_access,
+      .writefn = icc_sgi1r_write,
+    },
+    { .name = "ICC_SGI1R",
+      .cp = 15, .opc1 = 0, .crm = 12,
+      .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_W, .accessfn = gicv3_irqfiq_access,
+      .writefn = icc_sgi1r_write,
+    },
+    { .name = "ICC_ASGI1R_EL1", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 6,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_W, .accessfn = gicv3_irqfiq_access,
+      .writefn = icc_asgi1r_write,
+    },
+    { .name = "ICC_ASGI1R",
+      .cp = 15, .opc1 = 1, .crm = 12,
+      .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_W, .accessfn = gicv3_irqfiq_access,
+      .writefn = icc_asgi1r_write,
+    },
+    { .name = "ICC_SGI0R_EL1", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 7,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_W, .accessfn = gicv3_irqfiq_access,
+      .writefn = icc_sgi0r_write,
+    },
+    { .name = "ICC_SGI0R",
+      .cp = 15, .opc1 = 2, .crm = 12,
+      .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_W, .accessfn = gicv3_irqfiq_access,
+      .writefn = icc_sgi0r_write,
+    },
     /* This register is banked */
     { .name = "ICC_BPR1_EL1", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 3,
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 1130eee..55c25e8 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -27,6 +27,13 @@ static uint32_t mask_group(GICv3CPUState *cs, MemTxAttrs attrs)
     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)
 {
@@ -520,3 +527,36 @@ void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
 
     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);
+}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index e469599..8261bc0 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -211,6 +211,7 @@ 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);
 
 /**
diff --git a/trace-events b/trace-events
index c8fb467..0372c5b 100644
--- a/trace-events
+++ b/trace-events
@@ -2181,6 +2181,7 @@ gicv3_icc_ctlr_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 read cpu
 gicv3_icc_ctlr_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 write cpu %x value 0x%" PRIx64
 gicv3_cpuif_update(uint32_t cpuid, int irq, int grp, int prio) "GICv3 CPU i/f %x HPPI update: irq %d group %d prio %d"
 gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f %x HPPI update: setting FIQ %d IRQ %d"
+gicv3_icc_generate_sgi(uint32_t cpuid, int irq, int irm, uint32_t aff, uint32_t targetlist) "GICv3 CPU i/f %x generating SGI %d IRM %d target affinity 0x%xxx targetlist 0x%x"
 
 # hw/intc/arm_gicv3_dist.c
 gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
@@ -2195,3 +2196,4 @@ gicv3_redist_badread(uint32_t cpu, uint64_t offset, unsigned size, bool secure)
 gicv3_redist_write(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
 gicv3_redist_badwrite(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
 gicv3_redist_set_irq(uint32_t cpu, int irq, int level) "GICv3 redistributor %x interrupt %d level changed to %d"
+gicv3_redist_send_sgi(uint32_t cpu, int irq) "GICv3 redistributor %x pending SGI %d"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 18/20] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (16 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 17/20] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-15  3:15   ` Shannon Zhao
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 19/20] target-arm/machine.c: Allow user to request GICv3 emulation Peter Maydell
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Add the CPU interface registers which deal with acknowledging
and dismissing interrupts.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/arm_gicv3_cpuif.c | 437 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/gicv3_internal.h  |   5 +
 trace-events              |   7 +
 3 files changed, 449 insertions(+)

diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index a368dbb..5b2972e 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -219,6 +219,297 @@ static void icc_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri,
     gicv3_cpuif_update(cs);
 }
 
+static void icc_activate_irq(GICv3CPUState *cs, int irq)
+{
+    /* Move the interrupt from the Pending state to Active, and update
+     * the Active Priority Registers
+     */
+    uint32_t mask = icc_gprio_mask(cs, cs->hppi.grp);
+    int prio = cs->hppi.prio & mask;
+    int aprbit = prio >> 1;
+    int regno = aprbit / 32;
+    int regbit = aprbit % 32;
+
+    cs->icc_apr[cs->hppi.grp][regno] |= (1 << regbit);
+
+    if (irq < GIC_INTERNAL) {
+        cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 1);
+        cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 0);
+        gicv3_redist_update(cs);
+    } else {
+        gicv3_gicd_active_set(cs->gic, irq);
+        gicv3_gicd_pending_clear(cs->gic, irq);
+        gicv3_update(cs->gic, irq, 1);
+    }
+}
+
+static uint64_t icc_hppir0_value(GICv3CPUState *cs, CPUARMState *env)
+{
+    /* Return the highest priority pending interrupt register value
+     * for group 0.
+     */
+    bool irq_is_secure;
+
+    if (cs->hppi.prio == 0xff) {
+        return INTID_SPURIOUS;
+    }
+
+    /* Check whether we can return the interrupt or if we should return
+     * a special identifier, as per the CheckGroup0ForSpecialIdentifiers
+     * pseudocode. (We can simplify a little because for us ICC_SRE_EL1.RM
+     * is always zero.)
+     */
+    irq_is_secure = (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) &&
+                     (cs->hppi.grp != GICV3_G1NS));
+
+    if (cs->hppi.grp != GICV3_G0 && !arm_is_el3_or_mon(env)) {
+        return INTID_SPURIOUS;
+    }
+    if (irq_is_secure && !arm_is_secure(env)) {
+        /* Secure interrupts not visible to Nonsecure */
+        return INTID_SPURIOUS;
+    }
+
+    if (cs->hppi.grp != GICV3_G0) {
+        /* Indicate to EL3 that there's a Group 1 interrupt for the other
+         * state pending.
+         */
+        return irq_is_secure ? INTID_SECURE : INTID_NONSECURE;
+    }
+
+    return cs->hppi.irq;
+}
+
+static uint64_t icc_hppir1_value(GICv3CPUState *cs, CPUARMState *env)
+{
+    /* Return the highest priority pending interrupt register value
+     * for group 1.
+     */
+    bool irq_is_secure;
+
+    if (cs->hppi.prio == 0xff) {
+        return INTID_SPURIOUS;
+    }
+
+    /* Check whether we can return the interrupt or if we should return
+     * a special identifier, as per the CheckGroup1ForSpecialIdentifiers
+     * pseudocode. (We can simplify a little because for us ICC_SRE_EL1.RM
+     * is always zero.)
+     */
+    irq_is_secure = (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) &&
+                     (cs->hppi.grp != GICV3_G1NS));
+
+    if (cs->hppi.grp == GICV3_G0) {
+        /* Group 0 interrupts not visible via HPPIR1 */
+        return INTID_SPURIOUS;
+    }
+    if (irq_is_secure) {
+        if (!arm_is_secure(env)) {
+            /* Secure interrupts not visible in Non-secure */
+            return INTID_SPURIOUS;
+        }
+    } else if (!arm_is_el3_or_mon(env) && arm_is_secure(env)) {
+        /* Group 1 non-secure interrupts not visible in Secure EL1 */
+        return INTID_SPURIOUS;
+    }
+
+    return cs->hppi.irq;
+}
+
+static uint64_t icc_iar0_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    uint64_t intid;
+
+    if (!icc_hppi_can_preempt(cs)) {
+        intid = INTID_SPURIOUS;
+    } else {
+        intid = icc_hppir0_value(cs, env);
+    }
+
+    if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) {
+        icc_activate_irq(cs, intid);
+    }
+
+    trace_gicv3_icc_iar0_read(gicv3_redist_affid(cs), intid);
+    return intid;
+}
+
+static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    uint64_t intid;
+
+    if (!icc_hppi_can_preempt(cs)) {
+        intid = INTID_SPURIOUS;
+    } else {
+        intid = icc_hppir1_value(cs, env);
+    }
+
+    if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) {
+        icc_activate_irq(cs, intid);
+    }
+
+    trace_gicv3_icc_iar1_read(gicv3_redist_affid(cs), intid);
+    return intid;
+}
+
+static void icc_drop_prio(GICv3CPUState *cs, int grp)
+{
+    /* Drop the priority of the currently active interrupt in
+     * the specified group.
+     *
+     * Note that we can guarantee (because of the requirement to nest
+     * ICC_IAR reads [which activate an interrupt and raise priority]
+     * with ICC_EOIR writes [which drop the priority for the interrupt])
+     * that the interrupt we're being called for is the highest priority
+     * active interrupt, meaning that it has the lowest set bit in the
+     * APR registers.
+     *
+     * If the guest does not honour the ordering constraints then the
+     * behaviour of the GIC is UNPREDICTABLE, which for us means that
+     * the values of the APR registers might become incorrect and the
+     * running priority will be wrong, so interrupts that should preempt
+     * might not do so, and interrupts that should not preempt might do so.
+     */
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(cs->icc_apr[grp]); i++) {
+        uint64_t *papr = &cs->icc_apr[grp][i];
+
+        if (!*papr) {
+            continue;
+        }
+        /* Clear the lowest set bit */
+        *papr &= *papr - 1;
+        break;
+    }
+
+    /* running priority change means we need an update for this cpu i/f */
+    gicv3_cpuif_update(cs);
+}
+
+static bool icc_eoi_split(CPUARMState *env, GICv3CPUState *cs)
+{
+    /* Return true if we should split priority drop and interrupt
+     * deactivation, ie whether the relevant EOIMode bit is set.
+     */
+    if (arm_is_el3_or_mon(env)) {
+        return cs->icc_ctlr_el3 & ICC_CTLR_EL3_EOIMODE_EL3;
+    }
+    if (arm_is_secure_below_el3(env)) {
+        return cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_EOIMODE;
+    } else {
+        return cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_EOIMODE;
+    }
+}
+
+static int icc_highest_active_group(GICv3CPUState *cs)
+{
+    /* Return the group with the highest priority active interrupt.
+     * We can do this by just comparing the APRs to see which one
+     * has the lowest set bit.
+     * (If more than one group is active at the same priority then
+     * we're in UNPREDICTABLE territory.)
+     */
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) {
+        int g0ctz = ctz32(cs->icc_apr[GICV3_G0][i]);
+        int g1ctz = ctz32(cs->icc_apr[GICV3_G1][i]);
+        int g1nsctz = ctz32(cs->icc_apr[GICV3_G1NS][i]);
+
+        if (g1nsctz < g0ctz && g1nsctz < g1ctz) {
+            return GICV3_G1NS;
+        }
+        if (g1ctz < g0ctz) {
+            return GICV3_G1;
+        }
+        if (g0ctz < 32) {
+            return GICV3_G0;
+        }
+    }
+    /* No set active bits? UNPREDICTABLE; return -1 so the caller
+     * ignores the spurious EOI attempt.
+     */
+    return -1;
+}
+
+static void icc_deactivate_irq(GICv3CPUState *cs, int irq)
+{
+    if (irq < GIC_INTERNAL) {
+        cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 0);
+        gicv3_redist_update(cs);
+    } else {
+        gicv3_gicd_active_clear(cs->gic, irq);
+        gicv3_update(cs->gic, irq, 1);
+    }
+}
+
+static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                           uint64_t value)
+{
+    /* End of Interrupt */
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    int irq = value & 0xffffff;
+    int grp;
+
+    trace_gicv3_icc_eoir_write(gicv3_redist_affid(cs), value);
+
+    if (ri->crm == 8) {
+        /* EOIR0 */
+        grp = GICV3_G0;
+    } else {
+        /* EOIR1 */
+        if (arm_is_secure(env)) {
+            grp = GICV3_G1;
+        } else {
+            grp = GICV3_G1NS;
+        }
+    }
+
+    if (irq >= cs->gic->num_irq) {
+        /* This handles two cases:
+         * 1. If software writes the ID of a spurious interrupt [ie 1020-1023]
+         * to the GICC_EOIR, the GIC ignores that write.
+         * 2. If software writes the number of a non-existent interrupt
+         * this must be a subcase of "value written does not match the last
+         * valid interrupt value read from the Interrupt Acknowledge
+         * register" and so this is UNPREDICTABLE. We choose to ignore it.
+         */
+        return;
+    }
+
+    if (icc_highest_active_group(cs) != grp) {
+        return;
+    }
+
+    icc_drop_prio(cs, grp);
+
+    if (!icc_eoi_split(env, cs)) {
+        /* Priority drop and deactivate not split: deactivate irq now */
+        icc_deactivate_irq(cs, irq);
+    }
+}
+
+static uint64_t icc_hppir0_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    uint64_t value = icc_hppir0_value(cs, env);
+
+    trace_gicv3_icc_hppir0_read(gicv3_redist_affid(cs), value);
+    return value;
+}
+
+static uint64_t icc_hppir1_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    uint64_t value = icc_hppir1_value(cs, env);
+
+    trace_gicv3_icc_hppir1_read(gicv3_redist_affid(cs), value);
+    return value;
+}
+
 static uint64_t icc_bpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     GICv3CPUState *cs = icc_cs_from_env(env);
@@ -331,6 +622,104 @@ static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
     gicv3_cpuif_update(cs);
 }
 
+static void icc_dir_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                          uint64_t value)
+{
+    /* Deactivate interrupt */
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    int irq = value & 0xffffff;
+    bool irq_is_secure, single_sec_state, irq_is_grp0;
+    bool route_fiq_to_el3, route_irq_to_el3, route_fiq_to_el2, route_irq_to_el2;
+
+    trace_gicv3_icc_dir_write(gicv3_redist_affid(cs), value);
+
+    if (irq >= cs->gic->num_irq) {
+        /* Also catches special interrupt numbers and LPIs */
+        return;
+    }
+
+    if (!icc_eoi_split(env, cs)) {
+        return;
+    }
+
+    int grp = gicv3_irq_group(cs->gic, cs, irq);
+
+    single_sec_state = cs->gic->gicd_ctlr & GICD_CTLR_DS;
+    irq_is_secure = !single_sec_state && (grp != GICV3_G1NS);
+    irq_is_grp0 = grp == GICV3_G0;
+
+    /* Check whether we're allowed to deactivate this interrupt based
+     * on its group and the current CPU state.
+     * These checks are laid out to correspond to the spec's pseudocode.
+     */
+    route_fiq_to_el3 = env->cp15.scr_el3 & SCR_FIQ;
+    route_irq_to_el3 = env->cp15.scr_el3 & SCR_IRQ;
+    /* No need to include !IsSecure in route_*_to_el2 as it's only
+     * tested in cases where we know !IsSecure is true.
+     */
+    route_fiq_to_el2 = env->cp15.hcr_el2 & HCR_FMO;
+    route_irq_to_el2 = env->cp15.hcr_el2 & HCR_FMO;
+
+    switch (arm_current_el(env)) {
+    case 3:
+        break;
+    case 2:
+        if (single_sec_state && irq_is_grp0 && !route_fiq_to_el3) {
+            break;
+        }
+        if (!irq_is_secure && !irq_is_grp0 && !route_irq_to_el3) {
+            break;
+        }
+        return;
+    case 1:
+        if (!arm_is_secure_below_el3(env)) {
+            if (single_sec_state && irq_is_grp0 &&
+                !route_fiq_to_el3 && !route_fiq_to_el2) {
+                break;
+            }
+            if (!irq_is_secure && !irq_is_grp0 &&
+                !route_irq_to_el3 && !route_irq_to_el2) {
+                break;
+            }
+        } else {
+            if (irq_is_grp0 && !route_fiq_to_el3) {
+                break;
+            }
+            if (!irq_is_grp0 &&
+                (!irq_is_secure || !single_sec_state) &&
+                !route_irq_to_el3) {
+                break;
+            }
+        }
+        return;
+    default:
+        g_assert_not_reached();
+    }
+
+    icc_deactivate_irq(cs, irq);
+}
+
+static uint64_t icc_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    GICv3CPUState *cs = icc_cs_from_env(env);
+    int prio = icc_highest_active_prio(cs);
+
+    if (arm_feature(env, ARM_FEATURE_EL3) &&
+        !arm_is_secure(env) && (env->cp15.scr_el3 & SCR_FIQ)) {
+        /* NS GIC access and Group 0 is inaccessible to NS */
+        if (prio & 0x80) {
+            /* NS mustn't see priorities in the Secure half of the range */
+            prio = 0;
+        } else if (prio != 0xff) {
+            /* Non-idle priority: show the Non-secure view of it */
+            prio = (prio << 1) & 0xff;
+        }
+    }
+
+    trace_gicv3_icc_rpr_read(gicv3_redist_affid(cs), prio);
+    return prio;
+}
+
 static void icc_generate_sgi(CPUARMState *env, GICv3CPUState *cs,
                              uint64_t value, int grp, bool ns)
 {
@@ -698,6 +1087,24 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
        */
       .resetfn = icc_reset,
     },
+    { .name = "ICC_IAR0_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 0,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_R, .accessfn = gicv3_fiq_access,
+      .readfn = icc_iar0_read,
+    },
+    { .name = "ICC_EOIR0_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 1,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_W, .accessfn = gicv3_fiq_access,
+      .writefn = icc_eoir_write,
+    },
+    { .name = "ICC_HPPIR0_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 2,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_R, .accessfn = gicv3_fiq_access,
+      .readfn = icc_hppir0_read,
+    },
     { .name = "ICC_BPR0_EL1", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 3,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
@@ -762,6 +1169,18 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
       .readfn = icc_ap_read,
       .writefn = icc_ap_write,
     },
+    { .name = "ICC_DIR_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 1,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_W, .accessfn = gicv3_irqfiq_access,
+      .writefn = icc_dir_write,
+    },
+    { .name = "ICC_RPR_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 3,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_R, .accessfn = gicv3_irqfiq_access,
+      .readfn = icc_rpr_read,
+    },
     { .name = "ICC_SGI1R_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 5,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
@@ -798,6 +1217,24 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
       .access = PL1_W, .accessfn = gicv3_irqfiq_access,
       .writefn = icc_sgi0r_write,
     },
+    { .name = "ICC_IAR1_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 0,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_R, .accessfn = gicv3_irq_access,
+      .readfn = icc_iar1_read,
+    },
+    { .name = "ICC_EOIR1_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 1,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_W, .accessfn = gicv3_irq_access,
+      .writefn = icc_eoir_write,
+    },
+    { .name = "ICC_HPPIR1_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 2,
+      .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .access = PL1_R, .accessfn = gicv3_irq_access,
+      .readfn = icc_hppir1_read,
+    },
     /* This register is banked */
     { .name = "ICC_BPR1_EL1", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 3,
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 8261bc0..6ce5d49 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -159,6 +159,11 @@
 #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 */
 
 /**
diff --git a/trace-events b/trace-events
index 0372c5b..8f8ff04 100644
--- a/trace-events
+++ b/trace-events
@@ -2182,6 +2182,13 @@ gicv3_icc_ctlr_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 write c
 gicv3_cpuif_update(uint32_t cpuid, int irq, int grp, int prio) "GICv3 CPU i/f %x HPPI update: irq %d group %d prio %d"
 gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f %x HPPI update: setting FIQ %d IRQ %d"
 gicv3_icc_generate_sgi(uint32_t cpuid, int irq, int irm, uint32_t aff, uint32_t targetlist) "GICv3 CPU i/f %x generating SGI %d IRM %d target affinity 0x%xxx targetlist 0x%x"
+gicv3_icc_iar0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR0 read cpu %x value 0x%" PRIx64
+gicv3_icc_iar1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR1 read cpu %x value 0x%" PRIx64
+gicv3_icc_eoir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_EOIR write cpu %x value 0x%" PRIx64
+gicv3_icc_hppir0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR0 read cpu %x value 0x%" PRIx64
+gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu %x value 0x%" PRIx64
+gicv3_icc_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_DIR write cpu %x value 0x%" PRIx64
+gicv3_icc_rpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_RPR read cpu %x value 0x%" PRIx64
 
 # hw/intc/arm_gicv3_dist.c
 gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 19/20] target-arm/machine.c: Allow user to request GICv3 emulation
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (17 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 18/20] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 20/20] target-arm/monitor.c: Advertise emulated GICv3 in capabilities Peter Maydell
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Now we have an emulated GICv3, remove the restriction in
gicv3_class_name() so that the user can request a GICv3 with
-machine gic-version=3 even when not using KVM.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 target-arm/machine.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/target-arm/machine.c b/target-arm/machine.c
index 2f45260..2dbeb82 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -342,8 +342,7 @@ const char *gicv3_class_name(void)
                      "platform");
 #endif
     } else {
-        /* TODO: Software emulation is not implemented yet */
-        error_report("KVM is currently required for GICv3 emulation");
+        return "arm-gicv3";
     }
 
     exit(1);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [Qemu-devel] [PATCH v3 20/20] target-arm/monitor.c: Advertise emulated GICv3 in capabilities
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (18 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 19/20] target-arm/machine.c: Allow user to request GICv3 emulation Peter Maydell
@ 2016-06-14 14:38 ` Peter Maydell
  2016-06-15  2:52 ` [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Shannon Zhao
  2016-06-15  8:53 ` Shannon Zhao
  21 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-14 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Now we have an emulated GICv3 we should advertise it via the
capabilities in the monitor protocol.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 target-arm/monitor.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/target-arm/monitor.c b/target-arm/monitor.c
index 1ee59a2..299cb80 100644
--- a/target-arm/monitor.c
+++ b/target-arm/monitor.c
@@ -72,8 +72,7 @@ GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
     GICCapability *v2 = gic_cap_new(2), *v3 = gic_cap_new(3);
 
     v2->emulated = true;
-    /* TODO: we'd change to true after we get emulated GICv3. */
-    v3->emulated = false;
+    v3->emulated = true;
 
     gic_cap_kvm_probe(v2, v3);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 08/20] hw/intc/arm_gicv3: Add vmstate descriptors
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 08/20] hw/intc/arm_gicv3: Add vmstate descriptors Peter Maydell
@ 2016-06-15  2:30   ` Shannon Zhao
  2016-06-16  2:12   ` Shannon Zhao
  1 sibling, 0 replies; 64+ messages in thread
From: Shannon Zhao @ 2016-06-15  2:30 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/6/14 22:38, Peter Maydell wrote:
> From: Pavel Fedin <p.fedin@samsung.com>
> 
> Add state structure descriptors for the GICv3 state. We mark
> the KVM GICv3 device as having a migration blocker until the
> code to save and restore the state in the kernel is implemented.
> 
> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> [PMM: Adjust to renamed struct fields; switched to using uint32_t
>  array backed bitmaps; add migration blocker setting]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>

> ---
>  hw/intc/arm_gicv3_common.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-
>  hw/intc/arm_gicv3_kvm.c    |  7 +++++++
>  2 files changed, 56 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
> index 1557833..d1714e4 100644
> --- a/hw/intc/arm_gicv3_common.c
> +++ b/hw/intc/arm_gicv3_common.c
> @@ -49,11 +49,59 @@ static int gicv3_post_load(void *opaque, int version_id)
>      return 0;
>  }
>  
> +static const VMStateDescription vmstate_gicv3_cpu = {
> +    .name = "arm_gicv3_cpu",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(level, GICv3CPUState),
> +        VMSTATE_UINT32(gicr_ctlr, GICv3CPUState),
> +        VMSTATE_UINT32_ARRAY(gicr_statusr, GICv3CPUState, 2),
> +        VMSTATE_UINT32(gicr_waker, GICv3CPUState),
> +        VMSTATE_UINT64(gicr_propbaser, GICv3CPUState),
> +        VMSTATE_UINT64(gicr_pendbaser, GICv3CPUState),
> +        VMSTATE_UINT32(gicr_igroupr0, GICv3CPUState),
> +        VMSTATE_UINT32(gicr_ienabler0, GICv3CPUState),
> +        VMSTATE_UINT32(gicr_ipendr0, GICv3CPUState),
> +        VMSTATE_UINT32(gicr_iactiver0, GICv3CPUState),
> +        VMSTATE_UINT32(edge_trigger, GICv3CPUState),
> +        VMSTATE_UINT32(gicr_igrpmodr0, GICv3CPUState),
> +        VMSTATE_UINT32(gicr_nsacr, GICv3CPUState),
> +        VMSTATE_UINT8_ARRAY(gicr_ipriorityr, GICv3CPUState, GIC_INTERNAL),
> +        VMSTATE_UINT64_ARRAY(icc_ctlr_el1, GICv3CPUState, 2),
> +        VMSTATE_UINT64(icc_pmr_el1, GICv3CPUState),
> +        VMSTATE_UINT64_ARRAY(icc_bpr, GICv3CPUState, 3),
> +        VMSTATE_UINT64_2DARRAY(icc_apr, GICv3CPUState, 3, 4),
> +        VMSTATE_UINT64_ARRAY(icc_igrpen, GICv3CPUState, 3),
> +        VMSTATE_UINT64(icc_ctlr_el3, GICv3CPUState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>  static const VMStateDescription vmstate_gicv3 = {
>      .name = "arm_gicv3",
> -    .unmigratable = 1,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
>      .pre_save = gicv3_pre_save,
>      .post_load = gicv3_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(gicd_ctlr, GICv3State),
> +        VMSTATE_UINT32_ARRAY(gicd_statusr, GICv3State, 2),
> +        VMSTATE_UINT32_ARRAY(group, GICv3State, GICV3_BMP_SIZE),
> +        VMSTATE_UINT32_ARRAY(grpmod, GICv3State, GICV3_BMP_SIZE),
> +        VMSTATE_UINT32_ARRAY(enabled, GICv3State, GICV3_BMP_SIZE),
> +        VMSTATE_UINT32_ARRAY(pending, GICv3State, GICV3_BMP_SIZE),
> +        VMSTATE_UINT32_ARRAY(active, GICv3State, GICV3_BMP_SIZE),
> +        VMSTATE_UINT32_ARRAY(level, GICv3State, GICV3_BMP_SIZE),
> +        VMSTATE_UINT32_ARRAY(edge_trigger, GICv3State, GICV3_BMP_SIZE),
> +        VMSTATE_UINT8_ARRAY(gicd_ipriority, GICv3State, GICV3_MAXIRQ),
> +        VMSTATE_UINT64_ARRAY(gicd_irouter, GICv3State, GICV3_MAXIRQ),
> +        VMSTATE_UINT32_ARRAY(gicd_nsacr, GICv3State,
> +                             DIV_ROUND_UP(GICV3_MAXIRQ, 16)),
> +        VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, GICv3State, num_cpu,
> +                                             vmstate_gicv3_cpu, GICv3CPUState),
> +        VMSTATE_END_OF_LIST()
> +    }
>  };
>  
>  void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
> diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
> index acc1730..d08808d 100644
> --- a/hw/intc/arm_gicv3_kvm.c
> +++ b/hw/intc/arm_gicv3_kvm.c
> @@ -119,6 +119,13 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
>                              KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd);
>      kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
>                              KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd);
> +
> +    /* Block migration of a KVM GICv3 device: the API for saving and restoring
> +     * the state in the kernel is not yet finalised in the kernel or
> +     * implemented in QEMU.
> +     */
> +    error_setg(&s->migration_blocker, "vGICv3 migration is not implemented");
> +    migrate_add_blocker(s->migration_blocker);
>  }
>  
>  static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
> 

-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 10/20] hw/intc/arm_gicv3: Implement functions to identify next pending irq
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 10/20] hw/intc/arm_gicv3: Implement functions to identify next pending irq Peter Maydell
@ 2016-06-15  2:35   ` Shannon Zhao
  0 siblings, 0 replies; 64+ messages in thread
From: Shannon Zhao @ 2016-06-15  2:35 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/6/14 22:38, Peter Maydell wrote:
> Implement the GICv3 logic to recalculate the highest priority pending
> interrupt for each CPU after some part of the GIC state has changed.
> We avoid unnecessary full recalculation where possible.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>

> ---
>  hw/intc/arm_gicv3.c                | 293 +++++++++++++++++++++++++++++++++++++
>  hw/intc/arm_gicv3_common.c         |   9 ++
>  hw/intc/gicv3_internal.h           | 121 +++++++++++++++
>  include/hw/intc/arm_gicv3_common.h |  18 +++
>  4 files changed, 441 insertions(+)
> 
> diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
> index 96e0d2f..171d587 100644
> --- a/hw/intc/arm_gicv3.c
> +++ b/hw/intc/arm_gicv3.c
> @@ -21,6 +21,287 @@
>  #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)
>  {
> @@ -33,6 +314,16 @@ static void gicv3_set_irq(void *opaque, int irq, int level)
>      /* Do nothing for now */
>  }
>  
> +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 void arm_gic_realize(DeviceState *dev, Error **errp)
>  {
>      /* Device instance realize function for the GIC sysbus device */
> @@ -52,8 +343,10 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
>  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;
>  }
> diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
> index d1714e4..0f8c4b8 100644
> --- a/hw/intc/arm_gicv3_common.c
> +++ b/hw/intc/arm_gicv3_common.c
> @@ -246,6 +246,8 @@ static void arm_gicv3_common_reset(DeviceState *dev)
>          cs->gicr_nsacr = 0;
>          memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr));
>  
> +        cs->hppi.prio = 0xff;
> +
>          /* State in the CPU interface must *not* be reset here, because it
>           * is part of the CPU's reset domain, not the GIC device's.
>           */
> @@ -271,6 +273,13 @@ static void arm_gicv3_common_reset(DeviceState *dev)
>      memset(s->gicd_ipriority, 0, sizeof(s->gicd_ipriority));
>      memset(s->gicd_irouter, 0, sizeof(s->gicd_irouter));
>      memset(s->gicd_nsacr, 0, sizeof(s->gicd_nsacr));
> +    /* GICD_IROUTER are UNKNOWN at reset so in theory the guest must
> +     * write these to get sane behaviour and we need not populate the
> +     * pointer cache here; however having the cache be different for
> +     * "happened to be 0 from reset" and "guest wrote 0" would be
> +     * too confusing.
> +     */
> +    gicv3_cache_all_target_cpustates(s);
>  
>      if (s->irq_reset_nonsecure) {
>          /* If we're resetting a TZ-aware GIC as if secure firmware
> diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
> index 97c9d75..2ee9eeb 100644
> --- a/hw/intc/gicv3_internal.h
> +++ b/hw/intc/gicv3_internal.h
> @@ -159,6 +159,63 @@
>  #define ICC_CTLR_EL3_A3V (1U << 15)
>  #define ICC_CTLR_EL3_NDS (1U << 17)
>  
> +/* 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);
> +
> +/**
> + * 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.
> + */
> +static inline void gicv3_cpuif_update(GICv3CPUState *cs)
> +{
> +    /* This will be implemented in a later commit. */
> +}
> +
>  static inline uint32_t gicv3_iidr(void)
>  {
>      /* Return the Implementer Identification Register value
> @@ -184,6 +241,32 @@ static inline uint32_t gicv3_idreg(int regoffset)
>  }
>  
>  /**
> + * 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
> @@ -193,4 +276,42 @@ 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 */
> diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
> index cc6ac74..f72e499 100644
> --- a/include/hw/intc/arm_gicv3_common.h
> +++ b/include/hw/intc/arm_gicv3_common.h
> @@ -131,6 +131,12 @@ typedef struct GICv3CPUState GICv3CPUState;
>  #define GICV3_S 0
>  #define GICV3_NS 1
>  
> +typedef struct {
> +    int irq;
> +    uint8_t prio;
> +    int grp;
> +} PendingIrq;
> +
>  struct GICv3CPUState {
>      GICv3State *gic;
>      CPUState *cpu;
> @@ -163,6 +169,14 @@ struct GICv3CPUState {
>      uint64_t icc_apr[3][4];
>      uint64_t icc_igrpen[3];
>      uint64_t icc_ctlr_el3;
> +
> +    /* Current highest priority pending interrupt for this CPU.
> +     * This is cached information that can be recalculated from the
> +     * real state above; it doesn't need to be migrated.
> +     */
> +    PendingIrq hppi;
> +    /* This is temporary working state, to avoid a malloc in gicv3_update() */
> +    bool seenbetter;
>  };
>  
>  struct GICv3State {
> @@ -198,6 +212,10 @@ struct GICv3State {
>      GIC_DECLARE_BITMAP(edge_trigger); /* GICD_ICFGR even bits */
>      uint8_t gicd_ipriority[GICV3_MAXIRQ];
>      uint64_t gicd_irouter[GICV3_MAXIRQ];
> +    /* Cached information: pointer to the cpu i/f for the CPUs specified
> +     * in the IROUTER registers
> +     */
> +    GICv3CPUState *gicd_irouter_target[GICV3_MAXIRQ];
>      uint32_t gicd_nsacr[DIV_ROUND_UP(GICV3_MAXIRQ, 16)];
>  
>      GICv3CPUState *cpu;
> 

-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 11/20] hw/intc/arm_gicv3: Implement GICv3 distributor registers
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 11/20] hw/intc/arm_gicv3: Implement GICv3 distributor registers Peter Maydell
@ 2016-06-15  2:36   ` Shannon Zhao
  0 siblings, 0 replies; 64+ messages in thread
From: Shannon Zhao @ 2016-06-15  2:36 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/6/14 22:38, Peter Maydell wrote:
> From: Shlomo Pongratz <shlomo.pongratz@huawei.com>
> 
> Implement the distributor registers of a GICv3.
> 
> Signed-off-by: Shlomo Pongratz <shlomo.pongratz@huawei.com>
> [PMM: significantly overhauled/rewritten:
>  * use the new bitmap data structures
>  * restructure register read/write to handle different width accesses
>    natively, since almost all registers are 32-bit only, rather
>    than implementing everything as byte accesses
>  * implemented security extension support
> ]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>

> ---
>  hw/intc/Makefile.objs    |   1 +
>  hw/intc/arm_gicv3_dist.c | 858 +++++++++++++++++++++++++++++++++++++++++++++++
>  hw/intc/gicv3_internal.h |   4 +
>  trace-events             |   6 +
>  4 files changed, 869 insertions(+)
>  create mode 100644 hw/intc/arm_gicv3_dist.c
> 
> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
> index 4e94fdd..a173d29 100644
> --- a/hw/intc/Makefile.objs
> +++ b/hw/intc/Makefile.objs
> @@ -14,6 +14,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
>  common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
>  common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
>  common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
> +common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
>  common-obj-$(CONFIG_OPENPIC) += openpic.o
>  
>  obj-$(CONFIG_APIC) += apic.o apic_common.o
> diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
> new file mode 100644
> index 0000000..881d555
> --- /dev/null
> +++ b/hw/intc/arm_gicv3_dist.c
> @@ -0,0 +1,858 @@
> +/*
> + * 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;
> +}
> diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
> index 2ee9eeb..7cb9926 100644
> --- a/hw/intc/gicv3_internal.h
> +++ b/hw/intc/gicv3_internal.h
> @@ -201,6 +201,10 @@ void gicv3_full_update_noirqset(GICv3State *s);
>   * 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);
>  
>  /**
>   * gicv3_cpuif_update:
> diff --git a/trace-events b/trace-events
> index 421d89f..f295d86 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -2163,3 +2163,9 @@ e1000e_cfg_support_virtio(bool support) "Virtio header supported: %d"
>  
>  e1000e_vm_state_running(void) "VM state is running"
>  e1000e_vm_state_stopped(void) "VM state is stopped"
> +
> +# hw/intc/arm_gicv3_dist.c
> +gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
> +gicv3_dist_badread(uint64_t offset, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " size %u secure %d: error"
> +gicv3_dist_write(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
> +gicv3_dist_badwrite(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
> 

-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 12/20] hw/intc/arm_gicv3: Implement GICv3 redistributor registers
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 12/20] hw/intc/arm_gicv3: Implement GICv3 redistributor registers Peter Maydell
@ 2016-06-15  2:42   ` Shannon Zhao
  0 siblings, 0 replies; 64+ messages in thread
From: Shannon Zhao @ 2016-06-15  2:42 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/6/14 22:38, Peter Maydell wrote:
> From: Shlomo Pongratz <shlomo.pongratz@huawei.com>
> 
> Implement the redistributor registers of a GICv3.
> 
> Signed-off-by: Shlomo Pongratz <shlomo.pongratz@huawei.com>
> [PMM: significantly overhauled/rewritten:
>  * use the new data structures
>  * restructure register read/write to handle different width accesses
>    natively, since almost all registers are 32-bit only, rather
>    than implementing everything as byte accesses
>  * implemented security extension support
> ]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>

> ---
>  hw/intc/Makefile.objs      |   1 +
>  hw/intc/arm_gicv3_redist.c | 501 +++++++++++++++++++++++++++++++++++++++++++++
>  hw/intc/gicv3_internal.h   |   4 +
>  trace-events               |   6 +
>  4 files changed, 512 insertions(+)
>  create mode 100644 hw/intc/arm_gicv3_redist.c
> 
> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
> index a173d29..417db11 100644
> --- a/hw/intc/Makefile.objs
> +++ b/hw/intc/Makefile.objs
> @@ -15,6 +15,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
>  common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
>  common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
>  common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
> +common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o
>  common-obj-$(CONFIG_OPENPIC) += openpic.o
>  
>  obj-$(CONFIG_APIC) += apic.o apic_common.o
> diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
> new file mode 100644
> index 0000000..e0f23e1
> --- /dev/null
> +++ b/hw/intc/arm_gicv3_redist.c
> @@ -0,0 +1,501 @@
> +/*
> + * 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 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;
> +}
> diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
> index 7cb9926..b70e052 100644
> --- a/hw/intc/gicv3_internal.h
> +++ b/hw/intc/gicv3_internal.h
> @@ -205,6 +205,10 @@ 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);
>  
>  /**
>   * gicv3_cpuif_update:
> diff --git a/trace-events b/trace-events
> index f295d86..c88be1a 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -2169,3 +2169,9 @@ gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GIC
>  gicv3_dist_badread(uint64_t offset, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " size %u secure %d: error"
>  gicv3_dist_write(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
>  gicv3_dist_badwrite(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
> +
> +# hw/intc/arm_gicv3_redist.c
> +gicv3_redist_read(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
> +gicv3_redist_badread(uint32_t cpu, uint64_t offset, unsigned size, bool secure) "GICv3 redistributor %x read: offset 0x%" PRIx64 " size %u secure %d: error"
> +gicv3_redist_write(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
> +gicv3_redist_badwrite(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
> 

-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 15/20] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 15/20] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers Peter Maydell
@ 2016-06-15  2:45   ` Shannon Zhao
  0 siblings, 0 replies; 64+ messages in thread
From: Shannon Zhao @ 2016-06-15  2:45 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/6/14 22:38, Peter Maydell wrote:
> Implement the CPU interface registers for the GICv3; these are
> CPU system registers, not MMIO registers.
> 
> This commit implements all the registers which are simple
> accessors for GIC state, but not those which act as interfaces
> for acknowledging, dismissing or generating interrupts. (Those
> will be added in a later commit.)
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>

> ---
>  hw/intc/Makefile.objs     |   1 +
>  hw/intc/arm_gicv3.c       |   2 +
>  hw/intc/arm_gicv3_cpuif.c | 646 ++++++++++++++++++++++++++++++++++++++++++++++
>  hw/intc/gicv3_internal.h  |   1 +
>  trace-events              |  16 ++
>  5 files changed, 666 insertions(+)
>  create mode 100644 hw/intc/arm_gicv3_cpuif.c
> 
> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
> index 417db11..c7bbf88 100644
> --- a/hw/intc/Makefile.objs
> +++ b/hw/intc/Makefile.objs
> @@ -35,3 +35,4 @@ obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
>  obj-$(CONFIG_S390_FLIC) += s390_flic.o
>  obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
>  obj-$(CONFIG_ASPEED_SOC) += aspeed_vic.o
> +obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o
> diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
> index 65ebca2..8a6c647 100644
> --- a/hw/intc/arm_gicv3.c
> +++ b/hw/intc/arm_gicv3.c
> @@ -369,6 +369,8 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
>      }
>  
>      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)
> diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
> new file mode 100644
> index 0000000..e112646
> --- /dev/null
> +++ b/hw/intc/arm_gicv3_cpuif.c
> @@ -0,0 +1,646 @@
> +/*
> + * ARM Generic Interrupt Controller v3
> + *
> + * Copyright (c) 2016 Linaro Limited
> + * Written by Peter Maydell
> + *
> + * This code is licensed under the GPL, version 2 or (at your option)
> + * any later version.
> + */
> +
> +/* This file contains the code for the system register interface
> + * portions of the GICv3.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "trace.h"
> +#include "gicv3_internal.h"
> +#include "cpu.h"
> +
> +static GICv3CPUState *icc_cs_from_env(CPUARMState *env)
> +{
> +    /* Given the CPU, find the right GICv3CPUState struct.
> +     * Since we registered the CPU interface with the EL change hook as
> +     * the opaque pointer, we can just directly get from the CPU to it.
> +     */
> +    return arm_get_el_change_hook_opaque(arm_env_get_cpu(env));
> +}
> +
> +static bool gicv3_use_ns_bank(CPUARMState *env)
> +{
> +    /* Return true if we should use the NonSecure bank for a banked GIC
> +     * CPU interface register. Note that this differs from the
> +     * access_secure_reg() function because GICv3 banked registers are
> +     * banked even for AArch64, unlike the other CPU system registers.
> +     */
> +    return !arm_is_secure_below_el3(env);
> +}
> +
> +static uint64_t icc_pmr_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    uint32_t value = cs->icc_pmr_el1;
> +
> +    if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env) &&
> +        (env->cp15.scr_el3 & SCR_FIQ)) {
> +        /* NS access and Group 0 is inaccessible to NS: return the
> +         * NS view of the current priority
> +         */
> +        if (value & 0x80) {
> +            /* Secure priorities not visible to NS */
> +            value = 0;
> +        } else if (value != 0xff) {
> +            value = (value << 1) & 0xff;
> +        }
> +    }
> +
> +    trace_gicv3_icc_pmr_read(gicv3_redist_affid(cs), value);
> +
> +    return value;
> +}
> +
> +static void icc_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                          uint64_t value)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +
> +    trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value);
> +
> +    value &= 0xff;
> +
> +    if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env) &&
> +        (env->cp15.scr_el3 & SCR_FIQ)) {
> +        /* NS access and Group 0 is inaccessible to NS: return the
> +         * NS view of the current priority
> +         */
> +        if (!(cs->icc_pmr_el1 & 0x80)) {
> +            /* Current PMR in the secure range, don't allow NS to change it */
> +            return;
> +        }
> +        value = (value >> 1) & 0x80;
> +    }
> +    cs->icc_pmr_el1 = value;
> +    gicv3_cpuif_update(cs);
> +}
> +
> +static uint64_t icc_bpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    int grp = (ri->crm == 8) ? GICV3_G0 : GICV3_G1;
> +    bool satinc = false;
> +    uint64_t bpr;
> +
> +    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
> +        grp = GICV3_G1NS;
> +    }
> +
> +    if (grp == GICV3_G1 && !arm_is_el3_or_mon(env) &&
> +        (cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_CBPR)) {
> +        /* CBPR_EL1S means secure EL1 or AArch32 EL3 !Mon BPR1 accesses
> +         * modify BPR0
> +         */
> +        grp = GICV3_G0;
> +    }
> +
> +    if (grp == GICV3_G1NS && arm_current_el(env) < 3 &&
> +        (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR)) {
> +        /* reads return bpr0 + 1 sat to 7, writes ignored */
> +        grp = GICV3_G0;
> +        satinc = true;
> +    }
> +
> +    bpr = cs->icc_bpr[grp];
> +    if (satinc) {
> +        bpr++;
> +        bpr = MIN(bpr, 7);
> +    }
> +
> +    trace_gicv3_icc_bpr_read(gicv3_redist_affid(cs), bpr);
> +
> +    return bpr;
> +}
> +
> +static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                          uint64_t value)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    int grp = (ri->crm == 8) ? GICV3_G0 : GICV3_G1;
> +
> +    trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value);
> +
> +    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
> +        grp = GICV3_G1NS;
> +    }
> +
> +    if (grp == GICV3_G1 && !arm_is_el3_or_mon(env) &&
> +        (cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_CBPR)) {
> +        /* CBPR_EL1S means secure EL1 or AArch32 EL3 !Mon BPR1 accesses
> +         * modify BPR0
> +         */
> +        grp = GICV3_G0;
> +    }
> +
> +    if (grp == GICV3_G1NS && arm_current_el(env) < 3 &&
> +        (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR)) {
> +        /* reads return bpr0 + 1 sat to 7, writes ignored */
> +        return;
> +    }
> +
> +    cs->icc_bpr[grp] = value & 7;
> +    gicv3_cpuif_update(cs);
> +}
> +
> +static uint64_t icc_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    uint64_t value;
> +
> +    int regno = ri->opc2 & 3;
> +    int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1;
> +
> +    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
> +        grp = GICV3_G1NS;
> +    }
> +
> +    value = cs->icc_apr[grp][regno];
> +
> +    trace_gicv3_icc_ap_read(regno, gicv3_redist_affid(cs), value);
> +    return value;
> +}
> +
> +static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                         uint64_t value)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +
> +    int regno = ri->opc2 & 3;
> +    int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1;
> +
> +    trace_gicv3_icc_ap_write(regno, gicv3_redist_affid(cs), value);
> +
> +    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
> +        grp = GICV3_G1NS;
> +    }
> +
> +    /* It's not possible to claim that a Non-secure interrupt is active
> +     * at a priority outside the Non-secure range (128..255), since this
> +     * would otherwise allow malicious NS code to block delivery of S interrupts
> +     * by writing a bad value to these registers.
> +     */
> +    if (grp == GICV3_G1NS && regno < 2 && arm_feature(env, ARM_FEATURE_EL3)) {
> +        return;
> +    }
> +
> +    cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU;
> +    gicv3_cpuif_update(cs);
> +}
> +
> +static uint64_t icc_igrpen_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    int grp = ri->opc2 & 1 ? GICV3_G1 : GICV3_G0;
> +    uint64_t value;
> +
> +    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
> +        grp = GICV3_G1NS;
> +    }
> +
> +    value = cs->icc_igrpen[grp];
> +    trace_gicv3_icc_igrpen_read(gicv3_redist_affid(cs), value);
> +    return value;
> +}
> +
> +static void icc_igrpen_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                             uint64_t value)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    int grp = ri->opc2 & 1 ? GICV3_G1 : GICV3_G0;
> +
> +    trace_gicv3_icc_igrpen_write(gicv3_redist_affid(cs), value);
> +
> +    if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) {
> +        grp = GICV3_G1NS;
> +    }
> +
> +    cs->icc_igrpen[grp] = value & ICC_IGRPEN_ENABLE;
> +    gicv3_cpuif_update(cs);
> +}
> +
> +static uint64_t icc_igrpen1_el3_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +
> +    /* IGRPEN1_EL3 bits 0 and 1 are r/w aliases into IGRPEN1_EL1 NS and S */
> +    return cs->icc_igrpen[GICV3_G1NS] | (cs->icc_igrpen[GICV3_G1] << 1);
> +}
> +
> +static void icc_igrpen1_el3_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                                  uint64_t value)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +
> +    trace_gicv3_icc_igrpen1_el3_write(gicv3_redist_affid(cs), value);
> +
> +    /* IGRPEN1_EL3 bits 0 and 1 are r/w aliases into IGRPEN1_EL1 NS and S */
> +    cs->icc_igrpen[GICV3_G1NS] = extract32(value, 0, 1);
> +    cs->icc_igrpen[GICV3_G1] = extract32(value, 1, 1);
> +    gicv3_cpuif_update(cs);
> +}
> +
> +static uint64_t icc_ctlr_el1_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    int bank = gicv3_use_ns_bank(env) ? GICV3_NS : GICV3_S;
> +    uint64_t value;
> +
> +    value = cs->icc_ctlr_el1[bank];
> +    trace_gicv3_icc_ctlr_read(gicv3_redist_affid(cs), value);
> +    return value;
> +}
> +
> +static void icc_ctlr_el1_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                               uint64_t value)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    int bank = gicv3_use_ns_bank(env) ? GICV3_NS : GICV3_S;
> +    uint64_t mask;
> +
> +    trace_gicv3_icc_ctlr_write(gicv3_redist_affid(cs), value);
> +
> +    /* Only CBPR and EOIMODE can be RW;
> +     * for us PMHE is RAZ/WI (we don't implement 1-of-N interrupts or
> +     * the asseciated priority-based routing of them);
> +     * if EL3 is implemented and GICD_CTLR.DS == 0, then PMHE and CBPR are RO.
> +     */
> +    if (arm_feature(env, ARM_FEATURE_EL3) &&
> +        ((cs->gic->gicd_ctlr & GICD_CTLR_DS) == 0)) {
> +        mask = ICC_CTLR_EL1_EOIMODE;
> +    } else {
> +        mask = ICC_CTLR_EL1_CBPR | ICC_CTLR_EL1_EOIMODE;
> +    }
> +
> +    cs->icc_ctlr_el1[bank] &= ~mask;
> +    cs->icc_ctlr_el1[bank] |= (value & mask);
> +    gicv3_cpuif_update(cs);
> +}
> +
> +
> +static uint64_t icc_ctlr_el3_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    uint64_t value;
> +
> +    value = cs->icc_ctlr_el3;
> +    if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_EOIMODE) {
> +        value |= ICC_CTLR_EL3_EOIMODE_EL1NS;
> +    }
> +    if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR) {
> +        value |= ICC_CTLR_EL3_CBPR_EL1NS;
> +    }
> +    if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_EOIMODE) {
> +        value |= ICC_CTLR_EL3_EOIMODE_EL1S;
> +    }
> +    if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR) {
> +        value |= ICC_CTLR_EL3_CBPR_EL1S;
> +    }
> +
> +    trace_gicv3_icc_ctlr_el3_read(gicv3_redist_affid(cs), value);
> +    return value;
> +}
> +
> +static void icc_ctlr_el3_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                               uint64_t value)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    uint64_t mask;
> +
> +    trace_gicv3_icc_ctlr_el3_write(gicv3_redist_affid(cs), value);
> +
> +    /* *_EL1NS and *_EL1S bits are aliases into the ICC_CTLR_EL1 bits. */
> +    cs->icc_ctlr_el1[GICV3_NS] &= (ICC_CTLR_EL1_CBPR | ICC_CTLR_EL1_EOIMODE);
> +    if (value & ICC_CTLR_EL3_EOIMODE_EL1NS) {
> +        cs->icc_ctlr_el1[GICV3_NS] |= ICC_CTLR_EL1_EOIMODE;
> +    }
> +    if (value & ICC_CTLR_EL3_CBPR_EL1NS) {
> +        cs->icc_ctlr_el1[GICV3_NS] |= ICC_CTLR_EL1_CBPR;
> +    }
> +
> +    cs->icc_ctlr_el1[GICV3_S] &= (ICC_CTLR_EL1_CBPR | ICC_CTLR_EL1_EOIMODE);
> +    if (value & ICC_CTLR_EL3_EOIMODE_EL1S) {
> +        cs->icc_ctlr_el1[GICV3_S] |= ICC_CTLR_EL1_EOIMODE;
> +    }
> +    if (value & ICC_CTLR_EL3_CBPR_EL1S) {
> +        cs->icc_ctlr_el1[GICV3_S] |= ICC_CTLR_EL1_CBPR;
> +    }
> +
> +    /* The only bit stored in icc_ctlr_el3 which is writeable is EOIMODE_EL3: */
> +    mask = ICC_CTLR_EL3_EOIMODE_EL3;
> +
> +    cs->icc_ctlr_el3 &= ~mask;
> +    cs->icc_ctlr_el3 |= (value & mask);
> +    gicv3_cpuif_update(cs);
> +}
> +
> +static CPAccessResult gicv3_irqfiq_access(CPUARMState *env,
> +                                          const ARMCPRegInfo *ri, bool isread)
> +{
> +    CPAccessResult r = CP_ACCESS_OK;
> +
> +    if ((env->cp15.scr_el3 & (SCR_FIQ | SCR_IRQ)) == (SCR_FIQ | SCR_IRQ)) {
> +        switch (arm_current_el(env)) {
> +        case 1:
> +            if (arm_is_secure_below_el3(env) ||
> +                ((env->cp15.hcr_el2 & (HCR_IMO | HCR_FMO)) == 0)) {
> +                r = CP_ACCESS_TRAP_EL3;
> +            }
> +            break;
> +        case 2:
> +            r = CP_ACCESS_TRAP_EL3;
> +            break;
> +        case 3:
> +            if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
> +                r = CP_ACCESS_TRAP_EL3;
> +            }
> +        default:
> +            g_assert_not_reached();
> +        }
> +    }
> +
> +    if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
> +        r = CP_ACCESS_TRAP;
> +    }
> +    return r;
> +}
> +
> +static CPAccessResult gicv3_fiq_access(CPUARMState *env,
> +                                       const ARMCPRegInfo *ri, bool isread)
> +{
> +    CPAccessResult r = CP_ACCESS_OK;
> +
> +    if (env->cp15.scr_el3 & SCR_FIQ) {
> +        switch (arm_current_el(env)) {
> +        case 1:
> +            if (arm_is_secure_below_el3(env) ||
> +                ((env->cp15.hcr_el2 & HCR_FMO) == 0)) {
> +                r = CP_ACCESS_TRAP_EL3;
> +            }
> +            break;
> +        case 2:
> +            r = CP_ACCESS_TRAP_EL3;
> +            break;
> +        case 3:
> +            if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
> +                r = CP_ACCESS_TRAP_EL3;
> +            }
> +        default:
> +            g_assert_not_reached();
> +        }
> +    }
> +
> +    if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
> +        r = CP_ACCESS_TRAP;
> +    }
> +    return r;
> +}
> +
> +static CPAccessResult gicv3_irq_access(CPUARMState *env,
> +                                       const ARMCPRegInfo *ri, bool isread)
> +{
> +    CPAccessResult r = CP_ACCESS_OK;
> +
> +    if (env->cp15.scr_el3 & SCR_IRQ) {
> +        switch (arm_current_el(env)) {
> +        case 1:
> +            if (arm_is_secure_below_el3(env) ||
> +                ((env->cp15.hcr_el2 & HCR_IMO) == 0)) {
> +                r = CP_ACCESS_TRAP_EL3;
> +            }
> +            break;
> +        case 2:
> +            r = CP_ACCESS_TRAP_EL3;
> +            break;
> +        case 3:
> +            if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
> +                r = CP_ACCESS_TRAP_EL3;
> +            }
> +            break;
> +        default:
> +            g_assert_not_reached();
> +        }
> +    }
> +
> +    if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
> +        r = CP_ACCESS_TRAP;
> +    }
> +    return r;
> +}
> +
> +static void icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +
> +    cs->icc_ctlr_el1[GICV3_S] = ICC_CTLR_EL1_A3V |
> +        (1 << ICC_CTLR_EL1_IDBITS_SHIFT) |
> +        (7 << ICC_CTLR_EL1_PRIBITS_SHIFT);
> +    cs->icc_ctlr_el1[GICV3_NS] = ICC_CTLR_EL1_A3V |
> +        (1 << ICC_CTLR_EL1_IDBITS_SHIFT) |
> +        (7 << ICC_CTLR_EL1_PRIBITS_SHIFT);
> +    cs->icc_pmr_el1 = 0;
> +    cs->icc_bpr[GICV3_G0] = GIC_MIN_BPR;
> +    cs->icc_bpr[GICV3_G1] = GIC_MIN_BPR;
> +    if (arm_feature(env, ARM_FEATURE_EL3)) {
> +        cs->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR_NS;
> +    } else {
> +        cs->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR;
> +    }
> +    memset(cs->icc_apr, 0, sizeof(cs->icc_apr));
> +    memset(cs->icc_igrpen, 0, sizeof(cs->icc_igrpen));
> +    cs->icc_ctlr_el3 = ICC_CTLR_EL3_NDS | ICC_CTLR_EL3_A3V |
> +        (1 << ICC_CTLR_EL3_IDBITS_SHIFT) |
> +        (7 << ICC_CTLR_EL3_PRIBITS_SHIFT);
> +}
> +
> +static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
> +    { .name = "ICC_PMR_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 6, .opc2 = 0,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_irqfiq_access,
> +      .readfn = icc_pmr_read,
> +      .writefn = icc_pmr_write,
> +      /* We hang the whole cpu interface reset routine off here
> +       * rather than parcelling it out into one little function
> +       * per register
> +       */
> +      .resetfn = icc_reset,
> +    },
> +    { .name = "ICC_BPR0_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 3,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_fiq_access,
> +      .fieldoffset = offsetof(GICv3CPUState, icc_bpr[GICV3_G0]),
> +      .writefn = icc_bpr_write,
> +    },
> +    { .name = "ICC_AP0R0_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 4,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_fiq_access,
> +      .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][0]),
> +      .writefn = icc_ap_write,
> +    },
> +    { .name = "ICC_AP0R1_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 5,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_fiq_access,
> +      .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][1]),
> +      .writefn = icc_ap_write,
> +    },
> +    { .name = "ICC_AP0R2_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 6,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_fiq_access,
> +      .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][2]),
> +      .writefn = icc_ap_write,
> +    },
> +    { .name = "ICC_AP0R3_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 7,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_fiq_access,
> +      .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][3]),
> +      .writefn = icc_ap_write,
> +    },
> +    /* All the ICC_AP1R*_EL1 registers are banked */
> +    { .name = "ICC_AP1R0_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 0,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_irq_access,
> +      .readfn = icc_ap_read,
> +      .writefn = icc_ap_write,
> +    },
> +    { .name = "ICC_AP1R1_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 1,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_irq_access,
> +      .readfn = icc_ap_read,
> +      .writefn = icc_ap_write,
> +    },
> +    { .name = "ICC_AP1R2_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 2,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_irq_access,
> +      .readfn = icc_ap_read,
> +      .writefn = icc_ap_write,
> +    },
> +    { .name = "ICC_AP1R3_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 3,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_irq_access,
> +      .readfn = icc_ap_read,
> +      .writefn = icc_ap_write,
> +    },
> +    /* This register is banked */
> +    { .name = "ICC_BPR1_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 3,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_irq_access,
> +      .readfn = icc_bpr_read,
> +      .writefn = icc_bpr_write,
> +    },
> +    /* This register is banked */
> +    { .name = "ICC_CTLR_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 4,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_irqfiq_access,
> +      .readfn = icc_ctlr_el1_read,
> +      .writefn = icc_ctlr_el1_write,
> +    },
> +    { .name = "ICC_SRE_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 5,
> +      .type = ARM_CP_NO_RAW | ARM_CP_CONST,
> +      .access = PL1_RW,
> +      /* We don't support IRQ/FIQ bypass and system registers are
> +       * always enabled, so all our bits are RAZ/WI or RAO/WI.
> +       * This register is banked but since it's constant we don't
> +       * need to do anything special.
> +       */
> +      .resetvalue = 0x7,
> +    },
> +    { .name = "ICC_IGRPEN0_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 6,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_fiq_access,
> +      .fieldoffset = offsetof(GICv3CPUState, icc_igrpen[GICV3_G0]),
> +      .writefn = icc_igrpen_write,
> +    },
> +    /* This register is banked */
> +    { .name = "ICC_IGRPEN1_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 7,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_RW, .accessfn = gicv3_irq_access,
> +      .readfn = icc_igrpen_read,
> +      .writefn = icc_igrpen_write,
> +    },
> +    { .name = "ICC_SRE_EL2", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 5,
> +      .type = ARM_CP_NO_RAW | ARM_CP_CONST,
> +      .access = PL2_RW,
> +      /* We don't support IRQ/FIQ bypass and system registers are
> +       * always enabled, so all our bits are RAZ/WI or RAO/WI.
> +       */
> +      .resetvalue = 0xf,
> +    },
> +    { .name = "ICC_CTLR_EL3", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 6, .crn = 12, .crm = 12, .opc2 = 4,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL3_RW,
> +      .fieldoffset = offsetof(GICv3CPUState, icc_ctlr_el3),
> +      .readfn = icc_ctlr_el3_read,
> +      .writefn = icc_ctlr_el3_write,
> +    },
> +    { .name = "ICC_SRE_EL3", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 6, .crn = 12, .crm = 12, .opc2 = 5,
> +      .type = ARM_CP_NO_RAW | ARM_CP_CONST,
> +      .access = PL3_RW,
> +      /* We don't support IRQ/FIQ bypass and system registers are
> +       * always enabled, so all our bits are RAZ/WI or RAO/WI.
> +       */
> +      .resetvalue = 0xf,
> +    },
> +    { .name = "ICC_IGRPEN1_EL3", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 6, .crn = 12, .crm = 12, .opc2 = 7,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL3_RW,
> +      .readfn = icc_igrpen1_el3_read,
> +      .writefn = icc_igrpen1_el3_write,
> +    },
> +    REGINFO_SENTINEL
> +};
> +
> +static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque)
> +{
> +    /* Do nothing for now. */
> +}
> +
> +void gicv3_init_cpuif(GICv3State *s)
> +{
> +    /* Called from the GICv3 realize function; register our system
> +     * registers with the CPU
> +     */
> +    int i;
> +
> +    for (i = 0; i < s->num_cpu; i++) {
> +        ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i));
> +        GICv3CPUState *cs = &s->cpu[i];
> +
> +        /* Note that we can't just use the GICv3CPUState as an opaque pointer
> +         * in define_arm_cp_regs_with_opaque(), because when we're called back
> +         * it might be with code translated by CPU 0 but run by CPU 1, in
> +         * which case we'd get the wrong value.
> +         * So instead we define the regs with no ri->opaque info, and
> +         * get back to the GICv3CPUState from the ARMCPU by reading back
> +         * the opaque pointer from the el_change_hook, which we're going
> +         * to need to register anyway.
> +         */
> +        define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
> +        arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs);
> +    }
> +}
> diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
> index a6f443c..13f951c 100644
> --- a/hw/intc/gicv3_internal.h
> +++ b/hw/intc/gicv3_internal.h
> @@ -211,6 +211,7 @@ 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_init_cpuif(GICv3State *s);
>  
>  /**
>   * gicv3_cpuif_update:
> diff --git a/trace-events b/trace-events
> index 3aa8cce..baf12ba 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -2164,6 +2164,22 @@ e1000e_cfg_support_virtio(bool support) "Virtio header supported: %d"
>  e1000e_vm_state_running(void) "VM state is running"
>  e1000e_vm_state_stopped(void) "VM state is stopped"
>  
> +# hw/intc/arm_gicv3_cpuif.c
> +gicv3_icc_pmr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_PMR read cpu %x value 0x%" PRIx64
> +gicv3_icc_pmr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_PMR write cpu %x value 0x%" PRIx64
> +gicv3_icc_bpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_BPR read cpu %x value 0x%" PRIx64
> +gicv3_icc_bpr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_BPR write cpu %x value 0x%" PRIx64
> +gicv3_icc_ap_read(int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR read cpu %x value 0x%" PRIx64
> +gicv3_icc_ap_write(int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR write cpu %x value 0x%" PRIx64
> +gicv3_icc_igrpen_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN read cpu %x value 0x%" PRIx64
> +gicv3_icc_igrpen_write(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN write cpu %x value 0x%" PRIx64
> +gicv3_icc_igrpen1_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN1_EL3 read cpu %x value 0x%" PRIx64
> +gicv3_icc_igrpen1_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN1_EL3 write cpu %x value 0x%" PRIx64
> +gicv3_icc_ctlr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR read cpu %x value 0x%" PRIx64
> +gicv3_icc_ctlr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR write cpu %x value 0x%" PRIx64
> +gicv3_icc_ctlr_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 read cpu %x value 0x%" PRIx64
> +gicv3_icc_ctlr_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 write cpu %x value 0x%" PRIx64
> +
>  # hw/intc/arm_gicv3_dist.c
>  gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
>  gicv3_dist_badread(uint64_t offset, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " size %u secure %d: error"
> 

-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 16/20] hw/intc/arm_gicv3: Implement gicv3_cpuif_update()
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 16/20] hw/intc/arm_gicv3: Implement gicv3_cpuif_update() Peter Maydell
@ 2016-06-15  2:47   ` Shannon Zhao
  0 siblings, 0 replies; 64+ messages in thread
From: Shannon Zhao @ 2016-06-15  2:47 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/6/14 22:38, Peter Maydell wrote:
> Implement the gicv3_cpuif_update() function which deals with correctly
> asserting IRQ and FIQ based on the current running priority of the CPU,
> the priority of the highest priority pending interrupt and the CPU's
> current exception level and security state.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>

> ---
>  hw/intc/arm_gicv3_cpuif.c | 140 +++++++++++++++++++++++++++++++++++++++++++++-
>  hw/intc/gicv3_internal.h  |   5 +-
>  trace-events              |   2 +
>  3 files changed, 142 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
> index e112646..7faf3c0 100644
> --- a/hw/intc/arm_gicv3_cpuif.c
> +++ b/hw/intc/arm_gicv3_cpuif.c
> @@ -36,6 +36,142 @@ static bool gicv3_use_ns_bank(CPUARMState *env)
>      return !arm_is_secure_below_el3(env);
>  }
>  
> +static int icc_highest_active_prio(GICv3CPUState *cs)
> +{
> +    /* Calculate the current running priority based on the set bits
> +     * in the Active Priority Registers.
> +     */
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) {
> +        uint32_t apr = cs->icc_apr[GICV3_G0][i] |
> +            cs->icc_apr[GICV3_G1][i] | cs->icc_apr[GICV3_G1NS][i];
> +
> +        if (!apr) {
> +            continue;
> +        }
> +        return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1);
> +    }
> +    /* No current active interrupts: return idle priority */
> +    return 0xff;
> +}
> +
> +static uint32_t icc_gprio_mask(GICv3CPUState *cs, int group)
> +{
> +    /* Return a mask word which clears the subpriority bits from
> +     * a priority value for an interrupt in the specified group.
> +     * This depends on the BPR value:
> +     *  a BPR of 0 means the group priority bits are [7:1];
> +     *  a BPR of 1 means they are [7:2], and so on down to
> +     *  a BPR of 7 meaning no group priority bits at all.
> +     * Which BPR to use depends on the group of the interrupt and
> +     * the current ICC_CTLR.CBPR settings.
> +     */
> +    if ((group == GICV3_G1 && cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_CBPR) ||
> +        (group == GICV3_G1NS &&
> +         cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR)) {
> +        group = GICV3_G0;
> +    }
> +
> +    return ~0U << ((cs->icc_bpr[group] & 7) + 1);
> +}
> +
> +static bool icc_no_enabled_hppi(GICv3CPUState *cs)
> +{
> +    /* Return true if there is no pending interrupt, or the
> +     * highest priority pending interrupt is in a group which has been
> +     * disabled at the CPU interface by the ICC_IGRPEN* register enable bits.
> +     */
> +    return cs->hppi.prio == 0xff || (cs->icc_igrpen[cs->hppi.grp] == 0);
> +}
> +
> +static bool icc_hppi_can_preempt(GICv3CPUState *cs)
> +{
> +    /* Return true if we have a pending interrupt of sufficient
> +     * priority to preempt.
> +     */
> +    int rprio;
> +    uint32_t mask;
> +
> +    if (icc_no_enabled_hppi(cs)) {
> +        return false;
> +    }
> +
> +    if (cs->hppi.prio >= cs->icc_pmr_el1) {
> +        /* Priority mask masks this interrupt */
> +        return false;
> +    }
> +
> +    rprio = icc_highest_active_prio(cs);
> +    if (rprio == 0xff) {
> +        /* No currently running interrupt so we can preempt */
> +        return true;
> +    }
> +
> +    mask = icc_gprio_mask(cs, cs->hppi.grp);
> +
> +    /* We only preempt a running interrupt if the pending interrupt's
> +     * group priority is sufficient (the subpriorities are not considered).
> +     */
> +    if ((cs->hppi.prio & mask) < (rprio & mask)) {
> +        return true;
> +    }
> +
> +    return false;
> +}
> +
> +void gicv3_cpuif_update(GICv3CPUState *cs)
> +{
> +    /* Tell the CPU about its highest priority pending interrupt */
> +    int irqlevel = 0;
> +    int fiqlevel = 0;
> +    ARMCPU *cpu = ARM_CPU(cs->cpu);
> +    CPUARMState *env = &cpu->env;
> +
> +    trace_gicv3_cpuif_update(gicv3_redist_affid(cs), cs->hppi.irq,
> +                             cs->hppi.grp, cs->hppi.prio);
> +
> +    if (cs->hppi.grp == GICV3_G1 && !arm_feature(env, ARM_FEATURE_EL3)) {
> +        /* If a Security-enabled GIC sends a G1S interrupt to a
> +         * Security-disabled CPU, we must treat it as if it were G0.
> +         */
> +        cs->hppi.grp = GICV3_G0;
> +    }
> +
> +    if (icc_hppi_can_preempt(cs)) {
> +        /* We have an interrupt: should we signal it as IRQ or FIQ?
> +         * This is described in the GICv3 spec section 4.6.2.
> +         */
> +        bool isfiq;
> +
> +        switch (cs->hppi.grp) {
> +        case GICV3_G0:
> +            isfiq = true;
> +            break;
> +        case GICV3_G1:
> +            isfiq = (!arm_is_secure(env) ||
> +                     (arm_current_el(env) == 3 && arm_el_is_aa64(env, 3)));
> +            break;
> +        case GICV3_G1NS:
> +            isfiq = arm_is_secure(env);
> +            break;
> +        default:
> +            g_assert_not_reached();
> +        }
> +
> +        if (isfiq) {
> +            fiqlevel = 1;
> +        } else {
> +            irqlevel = 1;
> +        }
> +    }
> +
> +    trace_gicv3_cpuif_set_irqs(gicv3_redist_affid(cs), fiqlevel, irqlevel);
> +
> +    qemu_set_irq(cs->parent_fiq, fiqlevel);
> +    qemu_set_irq(cs->parent_irq, irqlevel);
> +}
> +
>  static uint64_t icc_pmr_read(CPUARMState *env, const ARMCPRegInfo *ri)
>  {
>      GICv3CPUState *cs = icc_cs_from_env(env);
> @@ -617,7 +753,9 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
>  
>  static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque)
>  {
> -    /* Do nothing for now. */
> +    GICv3CPUState *cs = opaque;
> +
> +    gicv3_cpuif_update(cs);
>  }
>  
>  void gicv3_init_cpuif(GICv3State *s)
> diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
> index 13f951c..e469599 100644
> --- a/hw/intc/gicv3_internal.h
> +++ b/hw/intc/gicv3_internal.h
> @@ -222,10 +222,7 @@ void gicv3_init_cpuif(GICv3State *s);
>   * current running priority or the CPU's current exception level or
>   * security state.
>   */
> -static inline void gicv3_cpuif_update(GICv3CPUState *cs)
> -{
> -    /* This will be implemented in a later commit. */
> -}
> +void gicv3_cpuif_update(GICv3CPUState *cs);
>  
>  static inline uint32_t gicv3_iidr(void)
>  {
> diff --git a/trace-events b/trace-events
> index baf12ba..c8fb467 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -2179,6 +2179,8 @@ gicv3_icc_ctlr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR read cpu %x valu
>  gicv3_icc_ctlr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR write cpu %x value 0x%" PRIx64
>  gicv3_icc_ctlr_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 read cpu %x value 0x%" PRIx64
>  gicv3_icc_ctlr_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 write cpu %x value 0x%" PRIx64
> +gicv3_cpuif_update(uint32_t cpuid, int irq, int grp, int prio) "GICv3 CPU i/f %x HPPI update: irq %d group %d prio %d"
> +gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f %x HPPI update: setting FIQ %d IRQ %d"
>  
>  # hw/intc/arm_gicv3_dist.c
>  gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
> 

-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (19 preceding siblings ...)
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 20/20] target-arm/monitor.c: Advertise emulated GICv3 in capabilities Peter Maydell
@ 2016-06-15  2:52 ` Shannon Zhao
  2016-06-15  8:53 ` Shannon Zhao
  21 siblings, 0 replies; 64+ messages in thread
From: Shannon Zhao @ 2016-06-15  2:52 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/6/14 22:38, Peter Maydell wrote:
> This series implements emulation of the GICv3 interrupt controller.
> It is based to some extent on previous patches from Shlomo and
> Pavel, but the bulk of it has turned out to be new code. (The
> combination of changing the underlying data structures, adding
> support for TrustZone and implementing proper GICv3 behaviour rather
> than borrowing fragments of GICv2 emulation code meant there wasn't
> much left to reuse.) I've tried to reflect this in the various
> authorship credits on the patches, but please let me know if you
> feel I got anything miscredited one way or the other.
> 
> Key points about the GICv3 emulated here:
>  * "non-legacy" only, ie system registers and affinity routing
>  * TrustZone is implemented
>  * no virtualization support
>  * only the "core" GICv3, so no LPI support (via ITS or otherwise)
>  * no attempt to work around the Linux guest kernel bug fixed
>    in commit 7c9b973061b0 (so you need that fix for your guest to
>    boot with this GICv3)
> 

I've tested this series using a linux kernel with single vcpu and 123
vcpus and also tested with UEFI.

Tested-by: Shannon Zhao <shannon.zhao@linaro.org>

Thanks,
-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 18/20] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 18/20] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers Peter Maydell
@ 2016-06-15  3:15   ` Shannon Zhao
  0 siblings, 0 replies; 64+ messages in thread
From: Shannon Zhao @ 2016-06-15  3:15 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/6/14 22:38, Peter Maydell wrote:
> Add the CPU interface registers which deal with acknowledging
> and dismissing interrupts.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>

> ---
>  hw/intc/arm_gicv3_cpuif.c | 437 ++++++++++++++++++++++++++++++++++++++++++++++
>  hw/intc/gicv3_internal.h  |   5 +
>  trace-events              |   7 +
>  3 files changed, 449 insertions(+)
> 
> diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
> index a368dbb..5b2972e 100644
> --- a/hw/intc/arm_gicv3_cpuif.c
> +++ b/hw/intc/arm_gicv3_cpuif.c
> @@ -219,6 +219,297 @@ static void icc_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>      gicv3_cpuif_update(cs);
>  }
>  
> +static void icc_activate_irq(GICv3CPUState *cs, int irq)
> +{
> +    /* Move the interrupt from the Pending state to Active, and update
> +     * the Active Priority Registers
> +     */
> +    uint32_t mask = icc_gprio_mask(cs, cs->hppi.grp);
> +    int prio = cs->hppi.prio & mask;
> +    int aprbit = prio >> 1;
> +    int regno = aprbit / 32;
> +    int regbit = aprbit % 32;
> +
> +    cs->icc_apr[cs->hppi.grp][regno] |= (1 << regbit);
> +
> +    if (irq < GIC_INTERNAL) {
> +        cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 1);
> +        cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 0);
> +        gicv3_redist_update(cs);
> +    } else {
> +        gicv3_gicd_active_set(cs->gic, irq);
> +        gicv3_gicd_pending_clear(cs->gic, irq);
> +        gicv3_update(cs->gic, irq, 1);
> +    }
> +}
> +
> +static uint64_t icc_hppir0_value(GICv3CPUState *cs, CPUARMState *env)
> +{
> +    /* Return the highest priority pending interrupt register value
> +     * for group 0.
> +     */
> +    bool irq_is_secure;
> +
> +    if (cs->hppi.prio == 0xff) {
> +        return INTID_SPURIOUS;
> +    }
> +
> +    /* Check whether we can return the interrupt or if we should return
> +     * a special identifier, as per the CheckGroup0ForSpecialIdentifiers
> +     * pseudocode. (We can simplify a little because for us ICC_SRE_EL1.RM
> +     * is always zero.)
> +     */
> +    irq_is_secure = (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) &&
> +                     (cs->hppi.grp != GICV3_G1NS));
> +
> +    if (cs->hppi.grp != GICV3_G0 && !arm_is_el3_or_mon(env)) {
> +        return INTID_SPURIOUS;
> +    }
> +    if (irq_is_secure && !arm_is_secure(env)) {
> +        /* Secure interrupts not visible to Nonsecure */
> +        return INTID_SPURIOUS;
> +    }
> +
> +    if (cs->hppi.grp != GICV3_G0) {
> +        /* Indicate to EL3 that there's a Group 1 interrupt for the other
> +         * state pending.
> +         */
> +        return irq_is_secure ? INTID_SECURE : INTID_NONSECURE;
> +    }
> +
> +    return cs->hppi.irq;
> +}
> +
> +static uint64_t icc_hppir1_value(GICv3CPUState *cs, CPUARMState *env)
> +{
> +    /* Return the highest priority pending interrupt register value
> +     * for group 1.
> +     */
> +    bool irq_is_secure;
> +
> +    if (cs->hppi.prio == 0xff) {
> +        return INTID_SPURIOUS;
> +    }
> +
> +    /* Check whether we can return the interrupt or if we should return
> +     * a special identifier, as per the CheckGroup1ForSpecialIdentifiers
> +     * pseudocode. (We can simplify a little because for us ICC_SRE_EL1.RM
> +     * is always zero.)
> +     */
> +    irq_is_secure = (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) &&
> +                     (cs->hppi.grp != GICV3_G1NS));
> +
> +    if (cs->hppi.grp == GICV3_G0) {
> +        /* Group 0 interrupts not visible via HPPIR1 */
> +        return INTID_SPURIOUS;
> +    }
> +    if (irq_is_secure) {
> +        if (!arm_is_secure(env)) {
> +            /* Secure interrupts not visible in Non-secure */
> +            return INTID_SPURIOUS;
> +        }
> +    } else if (!arm_is_el3_or_mon(env) && arm_is_secure(env)) {
> +        /* Group 1 non-secure interrupts not visible in Secure EL1 */
> +        return INTID_SPURIOUS;
> +    }
> +
> +    return cs->hppi.irq;
> +}
> +
> +static uint64_t icc_iar0_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    uint64_t intid;
> +
> +    if (!icc_hppi_can_preempt(cs)) {
> +        intid = INTID_SPURIOUS;
> +    } else {
> +        intid = icc_hppir0_value(cs, env);
> +    }
> +
> +    if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) {
> +        icc_activate_irq(cs, intid);
> +    }
> +
> +    trace_gicv3_icc_iar0_read(gicv3_redist_affid(cs), intid);
> +    return intid;
> +}
> +
> +static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    uint64_t intid;
> +
> +    if (!icc_hppi_can_preempt(cs)) {
> +        intid = INTID_SPURIOUS;
> +    } else {
> +        intid = icc_hppir1_value(cs, env);
> +    }
> +
> +    if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) {
> +        icc_activate_irq(cs, intid);
> +    }
> +
> +    trace_gicv3_icc_iar1_read(gicv3_redist_affid(cs), intid);
> +    return intid;
> +}
> +
> +static void icc_drop_prio(GICv3CPUState *cs, int grp)
> +{
> +    /* Drop the priority of the currently active interrupt in
> +     * the specified group.
> +     *
> +     * Note that we can guarantee (because of the requirement to nest
> +     * ICC_IAR reads [which activate an interrupt and raise priority]
> +     * with ICC_EOIR writes [which drop the priority for the interrupt])
> +     * that the interrupt we're being called for is the highest priority
> +     * active interrupt, meaning that it has the lowest set bit in the
> +     * APR registers.
> +     *
> +     * If the guest does not honour the ordering constraints then the
> +     * behaviour of the GIC is UNPREDICTABLE, which for us means that
> +     * the values of the APR registers might become incorrect and the
> +     * running priority will be wrong, so interrupts that should preempt
> +     * might not do so, and interrupts that should not preempt might do so.
> +     */
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(cs->icc_apr[grp]); i++) {
> +        uint64_t *papr = &cs->icc_apr[grp][i];
> +
> +        if (!*papr) {
> +            continue;
> +        }
> +        /* Clear the lowest set bit */
> +        *papr &= *papr - 1;
> +        break;
> +    }
> +
> +    /* running priority change means we need an update for this cpu i/f */
> +    gicv3_cpuif_update(cs);
> +}
> +
> +static bool icc_eoi_split(CPUARMState *env, GICv3CPUState *cs)
> +{
> +    /* Return true if we should split priority drop and interrupt
> +     * deactivation, ie whether the relevant EOIMode bit is set.
> +     */
> +    if (arm_is_el3_or_mon(env)) {
> +        return cs->icc_ctlr_el3 & ICC_CTLR_EL3_EOIMODE_EL3;
> +    }
> +    if (arm_is_secure_below_el3(env)) {
> +        return cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_EOIMODE;
> +    } else {
> +        return cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_EOIMODE;
> +    }
> +}
> +
> +static int icc_highest_active_group(GICv3CPUState *cs)
> +{
> +    /* Return the group with the highest priority active interrupt.
> +     * We can do this by just comparing the APRs to see which one
> +     * has the lowest set bit.
> +     * (If more than one group is active at the same priority then
> +     * we're in UNPREDICTABLE territory.)
> +     */
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) {
> +        int g0ctz = ctz32(cs->icc_apr[GICV3_G0][i]);
> +        int g1ctz = ctz32(cs->icc_apr[GICV3_G1][i]);
> +        int g1nsctz = ctz32(cs->icc_apr[GICV3_G1NS][i]);
> +
> +        if (g1nsctz < g0ctz && g1nsctz < g1ctz) {
> +            return GICV3_G1NS;
> +        }
> +        if (g1ctz < g0ctz) {
> +            return GICV3_G1;
> +        }
> +        if (g0ctz < 32) {
> +            return GICV3_G0;
> +        }
> +    }
> +    /* No set active bits? UNPREDICTABLE; return -1 so the caller
> +     * ignores the spurious EOI attempt.
> +     */
> +    return -1;
> +}
> +
> +static void icc_deactivate_irq(GICv3CPUState *cs, int irq)
> +{
> +    if (irq < GIC_INTERNAL) {
> +        cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 0);
> +        gicv3_redist_update(cs);
> +    } else {
> +        gicv3_gicd_active_clear(cs->gic, irq);
> +        gicv3_update(cs->gic, irq, 1);
> +    }
> +}
> +
> +static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                           uint64_t value)
> +{
> +    /* End of Interrupt */
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    int irq = value & 0xffffff;
> +    int grp;
> +
> +    trace_gicv3_icc_eoir_write(gicv3_redist_affid(cs), value);
> +
> +    if (ri->crm == 8) {
> +        /* EOIR0 */
> +        grp = GICV3_G0;
> +    } else {
> +        /* EOIR1 */
> +        if (arm_is_secure(env)) {
> +            grp = GICV3_G1;
> +        } else {
> +            grp = GICV3_G1NS;
> +        }
> +    }
> +
> +    if (irq >= cs->gic->num_irq) {
> +        /* This handles two cases:
> +         * 1. If software writes the ID of a spurious interrupt [ie 1020-1023]
> +         * to the GICC_EOIR, the GIC ignores that write.
> +         * 2. If software writes the number of a non-existent interrupt
> +         * this must be a subcase of "value written does not match the last
> +         * valid interrupt value read from the Interrupt Acknowledge
> +         * register" and so this is UNPREDICTABLE. We choose to ignore it.
> +         */
> +        return;
> +    }
> +
> +    if (icc_highest_active_group(cs) != grp) {
> +        return;
> +    }
> +
> +    icc_drop_prio(cs, grp);
> +
> +    if (!icc_eoi_split(env, cs)) {
> +        /* Priority drop and deactivate not split: deactivate irq now */
> +        icc_deactivate_irq(cs, irq);
> +    }
> +}
> +
> +static uint64_t icc_hppir0_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    uint64_t value = icc_hppir0_value(cs, env);
> +
> +    trace_gicv3_icc_hppir0_read(gicv3_redist_affid(cs), value);
> +    return value;
> +}
> +
> +static uint64_t icc_hppir1_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    uint64_t value = icc_hppir1_value(cs, env);
> +
> +    trace_gicv3_icc_hppir1_read(gicv3_redist_affid(cs), value);
> +    return value;
> +}
> +
>  static uint64_t icc_bpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
>  {
>      GICv3CPUState *cs = icc_cs_from_env(env);
> @@ -331,6 +622,104 @@ static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
>      gicv3_cpuif_update(cs);
>  }
>  
> +static void icc_dir_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                          uint64_t value)
> +{
> +    /* Deactivate interrupt */
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    int irq = value & 0xffffff;
> +    bool irq_is_secure, single_sec_state, irq_is_grp0;
> +    bool route_fiq_to_el3, route_irq_to_el3, route_fiq_to_el2, route_irq_to_el2;
> +
> +    trace_gicv3_icc_dir_write(gicv3_redist_affid(cs), value);
> +
> +    if (irq >= cs->gic->num_irq) {
> +        /* Also catches special interrupt numbers and LPIs */
> +        return;
> +    }
> +
> +    if (!icc_eoi_split(env, cs)) {
> +        return;
> +    }
> +
> +    int grp = gicv3_irq_group(cs->gic, cs, irq);
> +
> +    single_sec_state = cs->gic->gicd_ctlr & GICD_CTLR_DS;
> +    irq_is_secure = !single_sec_state && (grp != GICV3_G1NS);
> +    irq_is_grp0 = grp == GICV3_G0;
> +
> +    /* Check whether we're allowed to deactivate this interrupt based
> +     * on its group and the current CPU state.
> +     * These checks are laid out to correspond to the spec's pseudocode.
> +     */
> +    route_fiq_to_el3 = env->cp15.scr_el3 & SCR_FIQ;
> +    route_irq_to_el3 = env->cp15.scr_el3 & SCR_IRQ;
> +    /* No need to include !IsSecure in route_*_to_el2 as it's only
> +     * tested in cases where we know !IsSecure is true.
> +     */
> +    route_fiq_to_el2 = env->cp15.hcr_el2 & HCR_FMO;
> +    route_irq_to_el2 = env->cp15.hcr_el2 & HCR_FMO;
> +
> +    switch (arm_current_el(env)) {
> +    case 3:
> +        break;
> +    case 2:
> +        if (single_sec_state && irq_is_grp0 && !route_fiq_to_el3) {
> +            break;
> +        }
> +        if (!irq_is_secure && !irq_is_grp0 && !route_irq_to_el3) {
> +            break;
> +        }
> +        return;
> +    case 1:
> +        if (!arm_is_secure_below_el3(env)) {
> +            if (single_sec_state && irq_is_grp0 &&
> +                !route_fiq_to_el3 && !route_fiq_to_el2) {
> +                break;
> +            }
> +            if (!irq_is_secure && !irq_is_grp0 &&
> +                !route_irq_to_el3 && !route_irq_to_el2) {
> +                break;
> +            }
> +        } else {
> +            if (irq_is_grp0 && !route_fiq_to_el3) {
> +                break;
> +            }
> +            if (!irq_is_grp0 &&
> +                (!irq_is_secure || !single_sec_state) &&
> +                !route_irq_to_el3) {
> +                break;
> +            }
> +        }
> +        return;
> +    default:
> +        g_assert_not_reached();
> +    }
> +
> +    icc_deactivate_irq(cs, irq);
> +}
> +
> +static uint64_t icc_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    GICv3CPUState *cs = icc_cs_from_env(env);
> +    int prio = icc_highest_active_prio(cs);
> +
> +    if (arm_feature(env, ARM_FEATURE_EL3) &&
> +        !arm_is_secure(env) && (env->cp15.scr_el3 & SCR_FIQ)) {
> +        /* NS GIC access and Group 0 is inaccessible to NS */
> +        if (prio & 0x80) {
> +            /* NS mustn't see priorities in the Secure half of the range */
> +            prio = 0;
> +        } else if (prio != 0xff) {
> +            /* Non-idle priority: show the Non-secure view of it */
> +            prio = (prio << 1) & 0xff;
> +        }
> +    }
> +
> +    trace_gicv3_icc_rpr_read(gicv3_redist_affid(cs), prio);
> +    return prio;
> +}
> +
>  static void icc_generate_sgi(CPUARMState *env, GICv3CPUState *cs,
>                               uint64_t value, int grp, bool ns)
>  {
> @@ -698,6 +1087,24 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
>         */
>        .resetfn = icc_reset,
>      },
> +    { .name = "ICC_IAR0_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 0,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_R, .accessfn = gicv3_fiq_access,
> +      .readfn = icc_iar0_read,
> +    },
> +    { .name = "ICC_EOIR0_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 1,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_W, .accessfn = gicv3_fiq_access,
> +      .writefn = icc_eoir_write,
> +    },
> +    { .name = "ICC_HPPIR0_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 2,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_R, .accessfn = gicv3_fiq_access,
> +      .readfn = icc_hppir0_read,
> +    },
>      { .name = "ICC_BPR0_EL1", .state = ARM_CP_STATE_BOTH,
>        .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 3,
>        .type = ARM_CP_IO | ARM_CP_NO_RAW,
> @@ -762,6 +1169,18 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
>        .readfn = icc_ap_read,
>        .writefn = icc_ap_write,
>      },
> +    { .name = "ICC_DIR_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 1,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_W, .accessfn = gicv3_irqfiq_access,
> +      .writefn = icc_dir_write,
> +    },
> +    { .name = "ICC_RPR_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 3,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_R, .accessfn = gicv3_irqfiq_access,
> +      .readfn = icc_rpr_read,
> +    },
>      { .name = "ICC_SGI1R_EL1", .state = ARM_CP_STATE_AA64,
>        .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 5,
>        .type = ARM_CP_IO | ARM_CP_NO_RAW,
> @@ -798,6 +1217,24 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
>        .access = PL1_W, .accessfn = gicv3_irqfiq_access,
>        .writefn = icc_sgi0r_write,
>      },
> +    { .name = "ICC_IAR1_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 0,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_R, .accessfn = gicv3_irq_access,
> +      .readfn = icc_iar1_read,
> +    },
> +    { .name = "ICC_EOIR1_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 1,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_W, .accessfn = gicv3_irq_access,
> +      .writefn = icc_eoir_write,
> +    },
> +    { .name = "ICC_HPPIR1_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 2,
> +      .type = ARM_CP_IO | ARM_CP_NO_RAW,
> +      .access = PL1_R, .accessfn = gicv3_irq_access,
> +      .readfn = icc_hppir1_read,
> +    },
>      /* This register is banked */
>      { .name = "ICC_BPR1_EL1", .state = ARM_CP_STATE_BOTH,
>        .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 3,
> diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
> index 8261bc0..6ce5d49 100644
> --- a/hw/intc/gicv3_internal.h
> +++ b/hw/intc/gicv3_internal.h
> @@ -159,6 +159,11 @@
>  #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 */
>  
>  /**
> diff --git a/trace-events b/trace-events
> index 0372c5b..8f8ff04 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -2182,6 +2182,13 @@ gicv3_icc_ctlr_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 write c
>  gicv3_cpuif_update(uint32_t cpuid, int irq, int grp, int prio) "GICv3 CPU i/f %x HPPI update: irq %d group %d prio %d"
>  gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f %x HPPI update: setting FIQ %d IRQ %d"
>  gicv3_icc_generate_sgi(uint32_t cpuid, int irq, int irm, uint32_t aff, uint32_t targetlist) "GICv3 CPU i/f %x generating SGI %d IRM %d target affinity 0x%xxx targetlist 0x%x"
> +gicv3_icc_iar0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR0 read cpu %x value 0x%" PRIx64
> +gicv3_icc_iar1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR1 read cpu %x value 0x%" PRIx64
> +gicv3_icc_eoir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_EOIR write cpu %x value 0x%" PRIx64
> +gicv3_icc_hppir0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR0 read cpu %x value 0x%" PRIx64
> +gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu %x value 0x%" PRIx64
> +gicv3_icc_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_DIR write cpu %x value 0x%" PRIx64
> +gicv3_icc_rpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_RPR read cpu %x value 0x%" PRIx64
>  
>  # hw/intc/arm_gicv3_dist.c
>  gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
> 

-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
                   ` (20 preceding siblings ...)
  2016-06-15  2:52 ` [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Shannon Zhao
@ 2016-06-15  8:53 ` Shannon Zhao
  2016-06-15  9:20   ` Andrew Jones
  2016-06-21 14:45   ` Andrew Jones
  21 siblings, 2 replies; 64+ messages in thread
From: Shannon Zhao @ 2016-06-15  8:53 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/6/14 22:38, Peter Maydell wrote:
> This series implements emulation of the GICv3 interrupt controller.
> It is based to some extent on previous patches from Shlomo and
> Pavel, but the bulk of it has turned out to be new code. (The
> combination of changing the underlying data structures, adding
> support for TrustZone and implementing proper GICv3 behaviour rather
> than borrowing fragments of GICv2 emulation code meant there wasn't
> much left to reuse.) I've tried to reflect this in the various
> authorship credits on the patches, but please let me know if you
> feel I got anything miscredited one way or the other.
> 
> Key points about the GICv3 emulated here:
>  * "non-legacy" only, ie system registers and affinity routing
>  * TrustZone is implemented
>  * no virtualization support
>  * only the "core" GICv3, so no LPI support (via ITS or otherwise)
>  * no attempt to work around the Linux guest kernel bug fixed
>    in commit 7c9b973061b0 (so you need that fix for your guest to
>    boot with this GICv3)
Hi Peter,

I have another test with a freebsd guest. When I specify gic-version=3
at the QEMU command line, the guest can't start. But with gic-version=2
it's fine. And if I use gic-version=3 with kvm, the guest boots well too.

It hangs with below log:
[Bds]=============Begin Load Options Dumping ...=============
  Driver Options:
  SysPrep Options:
  Boot Options:
    Boot0000: UiApp              0x0109
    Boot0001: EFI Internal Shell                 0x0001
    Boot0002: UEFI Misc Device           0x0001
    Boot0003: UEFI Misc Device 2                 0x0001
    Boot0004: UEFI Misc Device 3                 0x0001
    Boot0005: UEFI PXEv4 (MAC:525400123456)              0x0001
  PlatformRecovery Options:
    PlatformRecovery0000: Default PlatformRecovery               0x0001
[Bds]=============End Load Options Dumping=============
[Bds]BdsWait ...Zzzzzzzzzzzz...
[Bds]BdsWait(3)..Zzzz...


The QEMU command line is:
qemu-system-aarch64 \
-m 4096M -cpu cortex-a57 -M virt,gic-version=3 -smp 1 \
-bios QEMU_EFI.fd -serial telnet::4445,server -nographic \
-drive
if=none,file=FreeBSD-11.0-ALPHA3-arm64-aarch64-20160528-r301815.qcow2,id=hd0
\
-device virtio-blk-device,drive=hd0 \
-device virtio-net-device,netdev=net0 \
-netdev user,id=net0

The QEMU_EFI.fd is built on edk2 commit ID 8f88f02 and the disk Image
file is downloaded from
http://www2.tw.freebsd.org/FreeBSD/snapshots/VM-IMAGES/11.0-ALPHA3/aarch64/20160528/FreeBSD-11.0-ALPHA3-arm64-aarch64-20160528-r301815.qcow2.xz

Thanks,
-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-15  8:53 ` Shannon Zhao
@ 2016-06-15  9:20   ` Andrew Jones
  2016-06-15 10:06     ` Peter Maydell
  2016-06-21 14:45   ` Andrew Jones
  1 sibling, 1 reply; 64+ messages in thread
From: Andrew Jones @ 2016-06-15  9:20 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: Peter Maydell, qemu-devel, patches, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

On Wed, Jun 15, 2016 at 04:53:35PM +0800, Shannon Zhao wrote:
> 
> 
> On 2016/6/14 22:38, Peter Maydell wrote:
> > This series implements emulation of the GICv3 interrupt controller.
> > It is based to some extent on previous patches from Shlomo and
> > Pavel, but the bulk of it has turned out to be new code. (The
> > combination of changing the underlying data structures, adding
> > support for TrustZone and implementing proper GICv3 behaviour rather
> > than borrowing fragments of GICv2 emulation code meant there wasn't
> > much left to reuse.) I've tried to reflect this in the various
> > authorship credits on the patches, but please let me know if you
> > feel I got anything miscredited one way or the other.
> > 
> > Key points about the GICv3 emulated here:
> >  * "non-legacy" only, ie system registers and affinity routing
> >  * TrustZone is implemented
> >  * no virtualization support
> >  * only the "core" GICv3, so no LPI support (via ITS or otherwise)
> >  * no attempt to work around the Linux guest kernel bug fixed
> >    in commit 7c9b973061b0 (so you need that fix for your guest to
> >    boot with this GICv3)
> Hi Peter,
> 
> I have another test with a freebsd guest. When I specify gic-version=3
> at the QEMU command line, the guest can't start. But with gic-version=2
> it's fine. And if I use gic-version=3 with kvm, the guest boots well too.
> 
> It hangs with below log:
> [Bds]=============Begin Load Options Dumping ...=============
>   Driver Options:
>   SysPrep Options:
>   Boot Options:
>     Boot0000: UiApp              0x0109
>     Boot0001: EFI Internal Shell                 0x0001
>     Boot0002: UEFI Misc Device           0x0001
>     Boot0003: UEFI Misc Device 2                 0x0001
>     Boot0004: UEFI Misc Device 3                 0x0001
>     Boot0005: UEFI PXEv4 (MAC:525400123456)              0x0001
>   PlatformRecovery Options:
>     PlatformRecovery0000: Default PlatformRecovery               0x0001
> [Bds]=============End Load Options Dumping=============
> [Bds]BdsWait ...Zzzzzzzzzzzz...
> [Bds]BdsWait(3)..Zzzz...
> 
> 
> The QEMU command line is:
> qemu-system-aarch64 \
> -m 4096M -cpu cortex-a57 -M virt,gic-version=3 -smp 1 \
> -bios QEMU_EFI.fd -serial telnet::4445,server -nographic \
> -drive
> if=none,file=FreeBSD-11.0-ALPHA3-arm64-aarch64-20160528-r301815.qcow2,id=hd0
> \
> -device virtio-blk-device,drive=hd0 \
> -device virtio-net-device,netdev=net0 \
> -netdev user,id=net0
> 
> The QEMU_EFI.fd is built on edk2 commit ID 8f88f02 and the disk Image
> file is downloaded from
> http://www2.tw.freebsd.org/FreeBSD/snapshots/VM-IMAGES/11.0-ALPHA3/aarch64/20160528/FreeBSD-11.0-ALPHA3-arm64-aarch64-20160528-r301815.qcow2.xz

There may be a bug in the freebsd kernel. Maybe they need the equivalent
of Linux's 7c9b973061 "irqchip/gic-v3: Configure all interrupts as
non-secure Group-1". You could add the hack back that was in the initial
posting of this series to see if that "fixes" things.

drew

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-15  9:20   ` Andrew Jones
@ 2016-06-15 10:06     ` Peter Maydell
  2016-06-15 10:10       ` Peter Maydell
  0 siblings, 1 reply; 64+ messages in thread
From: Peter Maydell @ 2016-06-15 10:06 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Shannon Zhao, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

On 15 June 2016 at 10:20, Andrew Jones <drjones@redhat.com> wrote:
> There may be a bug in the freebsd kernel. Maybe they need the equivalent
> of Linux's 7c9b973061 "irqchip/gic-v3: Configure all interrupts as
> non-secure Group-1". You could add the hack back that was in the initial
> posting of this series to see if that "fixes" things.

I agree it's possible this is a freebsd bug, but the hack patch
won't help here because we're booting via EFI.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-15 10:06     ` Peter Maydell
@ 2016-06-15 10:10       ` Peter Maydell
  2016-06-15 14:02         ` Shannon Zhao
                           ` (2 more replies)
  0 siblings, 3 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-15 10:10 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Shannon Zhao, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

On 15 June 2016 at 11:06, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 15 June 2016 at 10:20, Andrew Jones <drjones@redhat.com> wrote:
>> There may be a bug in the freebsd kernel. Maybe they need the equivalent
>> of Linux's 7c9b973061 "irqchip/gic-v3: Configure all interrupts as
>> non-secure Group-1". You could add the hack back that was in the initial
>> posting of this series to see if that "fixes" things.
>
> I agree it's possible this is a freebsd bug, but the hack patch
> won't help here because we're booting via EFI.

A quick scan through http://fxr.watson.org/fxr/source/arm64/arm64/gic_v3.c
doesn't seem to show it setting the IGROUPR registers anywhere,
so it probably is a guest bug. (You can use "-d 'trace:gicv3*'" to
enable the tracepoints for the GIC which would let you check whether
the guest ever tries to write to the group config registers.)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-15 10:10       ` Peter Maydell
@ 2016-06-15 14:02         ` Shannon Zhao
  2016-06-15 14:06           ` Peter Maydell
  2016-06-16  2:17         ` Shannon Zhao
  2016-06-22 18:09         ` Ed Maste
  2 siblings, 1 reply; 64+ messages in thread
From: Shannon Zhao @ 2016-06-15 14:02 UTC (permalink / raw)
  To: Peter Maydell, Andrew Jones
  Cc: Shannon Zhao, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Christoffer Dall

On 2016年06月15日 18:10, Peter Maydell wrote:
> On 15 June 2016 at 11:06, Peter Maydell <peter.maydell@linaro.org> wrote:
>> > On 15 June 2016 at 10:20, Andrew Jones <drjones@redhat.com> wrote:
>>> >> There may be a bug in the freebsd kernel. Maybe they need the equivalent
>>> >> of Linux's 7c9b973061 "irqchip/gic-v3: Configure all interrupts as
>>> >> non-secure Group-1". You could add the hack back that was in the initial
>>> >> posting of this series to see if that "fixes" things.
>> >
>> > I agree it's possible this is a freebsd bug, but the hack patch
>> > won't help here because we're booting via EFI.
> A quick scan through http://fxr.watson.org/fxr/source/arm64/arm64/gic_v3.c
> doesn't seem to show it setting the IGROUPR registers anywhere,
> so it probably is a guest bug. (You can use "-d 'trace:gicv3*'" to
> enable the tracepoints for the GIC which would let you check whether
> the guest ever tries to write to the group config registers.)
I'll try tomorrow. By the way, if we disable secure extension, will the
problem disappear?

Thanks,
-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-15 14:02         ` Shannon Zhao
@ 2016-06-15 14:06           ` Peter Maydell
  0 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-15 14:06 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: Andrew Jones, Shannon Zhao, QEMU Developers, Patch Tracking,
	Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin, Christoffer Dall

On 15 June 2016 at 15:02, Shannon Zhao <shannon.zhao@linaro.org> wrote:
> I'll try tomorrow. By the way, if we disable secure extension, will the
> problem disappear?

No; it's because the secure extension is disabled that the problem
exists. If security is disabled then the guest gets to use both
group 0 and group 1 IRQs (and if it wants to use IRQs as all group
1 it must configure them itself). If security is enabled then the
guest will always being using group 1 IRQs, and the secure firmware
is what will configure the IRQs for the NS guest as group 1
(since the group registers aren't accessible to NS). So if the
guest forgets to configure the IRQ groups it will work fine
in a system with the security extensions, but won't boot in one
without. [It will also boot OK in KVM because of a KVM bug/misfeature
where KVM's GICv3 only emulates group 1 interrupts.]

thanks
-- PMM

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 08/20] hw/intc/arm_gicv3: Add vmstate descriptors
  2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 08/20] hw/intc/arm_gicv3: Add vmstate descriptors Peter Maydell
  2016-06-15  2:30   ` Shannon Zhao
@ 2016-06-16  2:12   ` Shannon Zhao
  2016-06-16 14:23     ` Peter Maydell
  1 sibling, 1 reply; 64+ messages in thread
From: Shannon Zhao @ 2016-06-16  2:12 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/6/14 22:38, Peter Maydell wrote:
> diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
> index acc1730..d08808d 100644
> --- a/hw/intc/arm_gicv3_kvm.c
> +++ b/hw/intc/arm_gicv3_kvm.c

miss adding #include "migration/migration.h"
otherwise there is a compiling error:
 error: implicit declaration of function 'migrate_add_blocker'
[-Werror=implicit-function-declaration]

> @@ -119,6 +119,13 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
>                              KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd);
>      kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
>                              KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd);
> +
> +    /* Block migration of a KVM GICv3 device: the API for saving and restoring
> +     * the state in the kernel is not yet finalised in the kernel or
> +     * implemented in QEMU.
> +     */
> +    error_setg(&s->migration_blocker, "vGICv3 migration is not implemented");
> +    migrate_add_blocker(s->migration_blocker);
>  }
>  
>  static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
> 

-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-15 10:10       ` Peter Maydell
  2016-06-15 14:02         ` Shannon Zhao
@ 2016-06-16  2:17         ` Shannon Zhao
  2016-06-22 18:09         ` Ed Maste
  2 siblings, 0 replies; 64+ messages in thread
From: Shannon Zhao @ 2016-06-16  2:17 UTC (permalink / raw)
  To: Peter Maydell, Andrew Jones
  Cc: QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

[-- Attachment #1: Type: text/plain, Size: 1103 bytes --]



On 2016/6/15 18:10, Peter Maydell wrote:
> On 15 June 2016 at 11:06, Peter Maydell <peter.maydell@linaro.org> wrote:
>> > On 15 June 2016 at 10:20, Andrew Jones <drjones@redhat.com> wrote:
>>> >> There may be a bug in the freebsd kernel. Maybe they need the equivalent
>>> >> of Linux's 7c9b973061 "irqchip/gic-v3: Configure all interrupts as
>>> >> non-secure Group-1". You could add the hack back that was in the initial
>>> >> posting of this series to see if that "fixes" things.
>> >
>> > I agree it's possible this is a freebsd bug, but the hack patch
>> > won't help here because we're booting via EFI.
> A quick scan through http://fxr.watson.org/fxr/source/arm64/arm64/gic_v3.c
> doesn't seem to show it setting the IGROUPR registers anywhere,
> so it probably is a guest bug. (You can use "-d 'trace:gicv3*'" to
> enable the tracepoints for the GIC which would let you check whether
> the guest ever tries to write to the group config registers.)

I use "-d 'trace:gicv3*'" as you said. Attachment is the trace log. Look
like it doesn't write to GICD_IGROUPR registers.

Thanks,
-- 
Shannon

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gicv3_trace.txt --]
[-- Type: text/plain; charset="gb18030"; name="gicv3_trace.txt", Size: 32894 bytes --]

3145@1466069678.305134:gicv3_dist_read GICv3 distributor read: offset 0x4 data 0x3780007 size 4 secure 0
3145@1466069678.305423:gicv3_dist_read GICv3 distributor read: offset 0x0 data 0x50 size 4 secure 0
3145@1466069678.305498:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.305506:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.305511:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.305516:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.305521:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.305526:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.305530:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.305534:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.305538:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.305542:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.305546:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.305550:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.305555:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.305558:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.305562:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.305566:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.305570:gicv3_dist_write GICv3 distributor write: offset 0x0 data 0x50 size 4 secure 0
3145@1466069678.307067:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069678.307078:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069678.307456:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.307467:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.307472:gicv3_redist_write GICv3 redistributor 0 write: offset 0x10180 data 0x1 size 4 secure 0
3145@1466069678.307792:gicv3_dist_read GICv3 distributor read: offset 0x400 data 0x0 size 4 secure 0
3145@1466069678.307868:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.307874:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.307878:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.307882:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.307886:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.307890:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.307894:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.307897:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.307901:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.307905:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.307908:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.307912:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.307916:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.307920:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.307923:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.307927:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.307931:gicv3_dist_write GICv3 distributor write: offset 0x400 data 0x80 size 4 secure 0
3145@1466069678.308089:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069678.308096:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069678.308105:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308111:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308115:gicv3_redist_write GICv3 redistributor 0 write: offset 0x10180 data 0x2 size 4 secure 0
3145@1466069678.308124:gicv3_dist_read GICv3 distributor read: offset 0x400 data 0x0 size 4 secure 0
3145@1466069678.308133:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308138:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308142:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308146:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308150:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308153:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308157:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308161:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308165:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308169:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308172:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308176:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308179:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308183:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308187:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308191:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308195:gicv3_dist_write GICv3 distributor write: offset 0x400 data 0x8000 size 4 secure 0
3145@1466069678.308208:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069678.308213:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069678.308223:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308228:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308231:gicv3_redist_write GICv3 redistributor 0 write: offset 0x10180 data 0x4 size 4 secure 0
3145@1466069678.308240:gicv3_dist_read GICv3 distributor read: offset 0x400 data 0x0 size 4 secure 0
3145@1466069678.308249:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308254:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308258:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308261:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308265:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308269:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308273:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308277:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308280:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308284:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308288:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308292:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308295:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308299:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308303:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308306:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308310:gicv3_dist_write GICv3 distributor write: offset 0x400 data 0x800000 size 4 secure 0
3145@1466069678.308323:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069678.308329:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069678.308338:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308343:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308346:gicv3_redist_write GICv3 redistributor 0 write: offset 0x10180 data 0x8 size 4 secure 0
3145@1466069678.308355:gicv3_dist_read GICv3 distributor read: offset 0x400 data 0x0 size 4 secure 0
3145@1466069678.308364:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308368:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308372:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308376:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308380:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308383:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308387:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308391:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308395:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308398:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308402:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308406:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308409:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308413:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308417:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308420:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308424:gicv3_dist_write GICv3 distributor write: offset 0x400 data 0x80000000 size 4 secure 0
3145@1466069678.308437:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069678.308442:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069678.308451:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308456:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308460:gicv3_redist_write GICv3 redistributor 0 write: offset 0x10180 data 0x10 size 4 secure 0
3145@1466069678.308468:gicv3_dist_read GICv3 distributor read: offset 0x404 data 0x0 size 4 secure 0
3145@1466069678.308477:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308482:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308485:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308490:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308493:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308497:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308501:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308504:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308508:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308512:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308515:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308519:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308523:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308527:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308530:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308534:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308537:gicv3_dist_write GICv3 distributor write: offset 0x404 data 0x80 size 4 secure 0
3145@1466069678.308550:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069678.308556:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069678.308565:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308569:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308573:gicv3_redist_write GICv3 redistributor 0 write: offset 0x10180 data 0x20 size 4 secure 0
3145@1466069678.308582:gicv3_dist_read GICv3 distributor read: offset 0x404 data 0x0 size 4 secure 0
3145@1466069678.308591:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308595:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308599:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308603:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308607:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308611:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308614:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308618:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308621:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308625:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308629:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308633:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308636:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308640:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308644:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308648:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308651:gicv3_dist_write GICv3 distributor write: offset 0x404 data 0x8000 size 4 secure 0
3145@1466069678.308664:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069678.308670:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069678.308679:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308684:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308687:gicv3_redist_write GICv3 redistributor 0 write: offset 0x10180 data 0x40 size 4 secure 0
3145@1466069678.308696:gicv3_dist_read GICv3 distributor read: offset 0x404 data 0x0 size 4 secure 0
3145@1466069678.308705:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308710:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308714:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308717:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.308721:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.308725:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 03145@1466069678.319249:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319278:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319283:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319287:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319291:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319294:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319298:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319302:gicv3_dist_write GICv3 distributor write: offset 0x47c data 0x80000000 size 4 secure 0
3145@1466069678.319317:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069678.319322:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069678.319331:gicv3_redist_badwrite GICv3 redistributor 0 write: offset 0x10190 data 0x1 size 4 secure 0: error
3145@1466069678.319341:gicv3_dist_read GICv3 distributor read: offset 0x480 data 0x0 size 4 secure 0
3145@1466069678.319349:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319354:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319358:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319361:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319365:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319369:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319372:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319376:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319379:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319383:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319386:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319390:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319393:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319397:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319401:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319404:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319408:gicv3_dist_write GICv3 distributor write: offset 0x480 data 0x80 size 4 secure 0
3145@1466069678.319420:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069678.319426:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069678.319434:gicv3_redist_badwrite GICv3 redistributor 0 write: offset 0x10190 data 0x2 size 4 secure 0: error
3145@1466069678.319443:gicv3_dist_read GICv3 distributor read: offset 0x480 data 0x8000 size 4 secure 0
3145@1466069678.319452:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319456:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319460:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319464:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319467:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319471:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319474:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319478:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.319482:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.319485:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 03145@1466069678.331274:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331279:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331283:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331290:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331294:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331298:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331302:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331305:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331309:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331313:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331316:gicv3_dist_write GICv3 distributor write: offset 0x6140 data 0x80000000 size 4 secure 0
3145@1466069678.331326:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331330:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331334:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331338:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331341:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331345:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331349:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331352:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331356:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331360:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331363:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331367:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331370:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331374:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331378:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331381:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331385:gicv3_dist_write GICv3 distributor write: offset 0x6148 data 0x80000000 size 4 secure 0
3145@1466069678.331393:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331397:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331401:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331405:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331408:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331412:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331416:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331419:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331423:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331427:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331430:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331434:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331438:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331441:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331445:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331448:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331452:gicv3_dist_write GICv3 distributor write: offset 0x6150 data 0x80000000 size 4 secure 0
3145@1466069678.331460:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331464:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331468:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331471:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331475:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331479:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331482:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331486:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331489:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331493:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331496:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331500:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331503:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331507:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331510:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331514:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331518:gicv3_dist_write GICv3 distributor write: offset 0x6158 data 0x80000000 size 4 secure 0
3145@1466069678.331525:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331530:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331533:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331537:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331540:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331544:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331548:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331551:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331555:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331558:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331562:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331565:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331569:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331572:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331576:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331579:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331583:gicv3_dist_write GICv3 distributor write: offset 0x6160 data 0x80000000 size 4 secure 0
3145@1466069678.331591:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331595:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331599:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331602:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.331606:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.331609:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 03145@1466069678.343357:gicv3_dist_read GICv3 distributor read: offset 0x0 data 0x50 size 4 secure 0
3145@1466069678.343375:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069678.343380:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.343384:gicv3_cpuif_update GICv3 CPU i/f 1 HPPI update: irq 0 group 0 prio 255
3145@1466069678.343388:gicv3_cpuif_set_irqs GICv3 CPU i/f 1 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.343392:gicv3_cpuif_update GICv3 CPU i/f 2 HPPI update: irq 0 group 0 prio 255
3145@1466069678.343396:gicv3_cpuif_set_irqs GICv3 CPU i/f 2 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.343399:gicv3_cpuif_update GICv3 CPU i/f 3 HPPI update: irq 0 group 0 prio 255
3145@1466069678.343403:gicv3_cpuif_set_irqs GICv3 CPU i/f 3 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.343407:gicv3_cpuif_update GICv3 CPU i/f 4 HPPI update: irq 0 group 0 prio 255
3145@1466069678.343411:gicv3_cpuif_set_irqs GICv3 CPU i/f 4 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.343414:gicv3_cpuif_update GICv3 CPU i/f 5 HPPI update: irq 0 group 0 prio 255
3145@1466069678.343418:gicv3_cpuif_set_irqs GICv3 CPU i/f 5 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.343421:gicv3_cpuif_update GICv3 CPU i/f 6 HPPI update: irq 0 group 0 prio 255
3145@1466069678.343425:gicv3_cpuif_set_irqs GICv3 CPU i/f 6 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.343429:gicv3_cpuif_update GICv3 CPU i/f 7 HPPI update: irq 0 group 0 prio 255
3145@1466069678.343432:gicv3_cpuif_set_irqs GICv3 CPU i/f 7 HPPI update: setting FIQ 0 IRQ 0
3145@1466069678.343436:gicv3_dist_write GICv3 distributor write: offset 0x0 data 0x52 size 4 secure 0
3145@1466069679.735047:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069679.735069:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069679.735273:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069679.735282:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069679.735288:gicv3_redist_write GICv3 redistributor 0 write: offset 0x10100 data 0x8000000 size 4 secure 0
3145@1466069679.735771:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069679.735779:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069679.735789:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069679.735795:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069679.735799:gicv3_redist_write GICv3 redistributor 0 write: offset 0x10100 data 0x4000000 size 4 secure 0
3145@1466069679.736103:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069679.736110:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069679.736120:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069679.736126:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069679.736130:gicv3_redist_write GICv3 redistributor 0 write: offset 0x10100 data 0x20000000 size 4 secure 0
3145@1466069679.736429:gicv3_redist_read GICv3 redistributor 0 read: offset 0x8 data 0x1000000 size 4 secure 0
3145@1466069679.736437:gicv3_redist_read GICv3 redistributor 0 read: offset 0xc data 0x0 size 4 secure 0
3145@1466069679.736446:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069679.736452:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0
3145@1466069679.736455:gicv3_redist_write GICv3 redistributor 0 write: offset 0x10100 data 0x40000000 size 4 secure 0
3145@1466069679.747805:gicv3_redist_set_irq GICv3 redistributor 0 interrupt 27 level changed to 1
3145@1466069679.747820:gicv3_cpuif_update GICv3 CPU i/f 0 HPPI update: irq 0 group 0 prio 255
3145@1466069679.747825:gicv3_cpuif_set_irqs GICv3 CPU i/f 0 HPPI update: setting FIQ 0 IRQ 0

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 08/20] hw/intc/arm_gicv3: Add vmstate descriptors
  2016-06-16  2:12   ` Shannon Zhao
@ 2016-06-16 14:23     ` Peter Maydell
  0 siblings, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-16 14:23 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

On 16 June 2016 at 03:12, Shannon Zhao <zhaoshenglong@huawei.com> wrote:
> On 2016/6/14 22:38, Peter Maydell wrote:
>> diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
>> index acc1730..d08808d 100644
>> --- a/hw/intc/arm_gicv3_kvm.c
>> +++ b/hw/intc/arm_gicv3_kvm.c
>
> miss adding #include "migration/migration.h"
> otherwise there is a compiling error:
>  error: implicit declaration of function 'migrate_add_blocker'
> [-Werror=implicit-function-declaration]

Oops, thanks. Since this was the only problem I've just added
the missing #include and will put this now completely-reviewed
v3 patchset into target-arm.next, rather than sending a v4.

Thanks for reviewing this!

-- PMM

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-15  8:53 ` Shannon Zhao
  2016-06-15  9:20   ` Andrew Jones
@ 2016-06-21 14:45   ` Andrew Jones
  2016-06-21 14:55     ` Peter Maydell
  1 sibling, 1 reply; 64+ messages in thread
From: Andrew Jones @ 2016-06-21 14:45 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: Peter Maydell, qemu-devel, patches, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall,
	lersek

On Wed, Jun 15, 2016 at 04:53:35PM +0800, Shannon Zhao wrote:
> 
> 
> On 2016/6/14 22:38, Peter Maydell wrote:
> > This series implements emulation of the GICv3 interrupt controller.
> > It is based to some extent on previous patches from Shlomo and
> > Pavel, but the bulk of it has turned out to be new code. (The
> > combination of changing the underlying data structures, adding
> > support for TrustZone and implementing proper GICv3 behaviour rather
> > than borrowing fragments of GICv2 emulation code meant there wasn't
> > much left to reuse.) I've tried to reflect this in the various
> > authorship credits on the patches, but please let me know if you
> > feel I got anything miscredited one way or the other.
> > 
> > Key points about the GICv3 emulated here:
> >  * "non-legacy" only, ie system registers and affinity routing
> >  * TrustZone is implemented
> >  * no virtualization support
> >  * only the "core" GICv3, so no LPI support (via ITS or otherwise)
> >  * no attempt to work around the Linux guest kernel bug fixed
> >    in commit 7c9b973061b0 (so you need that fix for your guest to
> >    boot with this GICv3)
> Hi Peter,
> 
> I have another test with a freebsd guest. When I specify gic-version=3
> at the QEMU command line, the guest can't start. But with gic-version=2
> it's fine. And if I use gic-version=3 with kvm, the guest boots well too.
> 
> It hangs with below log:
> [Bds]=============Begin Load Options Dumping ...=============
>   Driver Options:
>   SysPrep Options:
>   Boot Options:
>     Boot0000: UiApp              0x0109
>     Boot0001: EFI Internal Shell                 0x0001
>     Boot0002: UEFI Misc Device           0x0001
>     Boot0003: UEFI Misc Device 2                 0x0001
>     Boot0004: UEFI Misc Device 3                 0x0001
>     Boot0005: UEFI PXEv4 (MAC:525400123456)              0x0001
>   PlatformRecovery Options:
>     PlatformRecovery0000: Default PlatformRecovery               0x0001
> [Bds]=============End Load Options Dumping=============
> [Bds]BdsWait ...Zzzzzzzzzzzz...
> [Bds]BdsWait(3)..Zzzz...

I can reproduce this exact output with the latest version of AAVMF,
built on commit 988715a.

Shannon,

What UEFI did you use when you tested it and it worked?

(CC'ing Laszlo)

Thanks,
drew

> 
> 
> The QEMU command line is:
> qemu-system-aarch64 \
> -m 4096M -cpu cortex-a57 -M virt,gic-version=3 -smp 1 \
> -bios QEMU_EFI.fd -serial telnet::4445,server -nographic \
> -drive
> if=none,file=FreeBSD-11.0-ALPHA3-arm64-aarch64-20160528-r301815.qcow2,id=hd0
> \
> -device virtio-blk-device,drive=hd0 \
> -device virtio-net-device,netdev=net0 \
> -netdev user,id=net0
> 
> The QEMU_EFI.fd is built on edk2 commit ID 8f88f02 and the disk Image
> file is downloaded from
> http://www2.tw.freebsd.org/FreeBSD/snapshots/VM-IMAGES/11.0-ALPHA3/aarch64/20160528/FreeBSD-11.0-ALPHA3-arm64-aarch64-20160528-r301815.qcow2.xz
> 
> Thanks,
> -- 
> Shannon
> 
> 

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-21 14:45   ` Andrew Jones
@ 2016-06-21 14:55     ` Peter Maydell
  2016-06-21 15:12       ` Andrew Jones
  0 siblings, 1 reply; 64+ messages in thread
From: Peter Maydell @ 2016-06-21 14:55 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Shannon Zhao, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall,
	Laszlo Ersek

On 21 June 2016 at 15:45, Andrew Jones <drjones@redhat.com> wrote:
> On Wed, Jun 15, 2016 at 04:53:35PM +0800, Shannon Zhao wrote:
>> I have another test with a freebsd guest. When I specify gic-version=3
>> at the QEMU command line, the guest can't start. But with gic-version=2
>> it's fine. And if I use gic-version=3 with kvm, the guest boots well too.
>>
>> It hangs with below log:
>> [Bds]=============Begin Load Options Dumping ...=============
>>   Driver Options:
>>   SysPrep Options:
>>   Boot Options:
>>     Boot0000: UiApp              0x0109
>>     Boot0001: EFI Internal Shell                 0x0001
>>     Boot0002: UEFI Misc Device           0x0001
>>     Boot0003: UEFI Misc Device 2                 0x0001
>>     Boot0004: UEFI Misc Device 3                 0x0001
>>     Boot0005: UEFI PXEv4 (MAC:525400123456)              0x0001
>>   PlatformRecovery Options:
>>     PlatformRecovery0000: Default PlatformRecovery               0x0001
>> [Bds]=============End Load Options Dumping=============
>> [Bds]BdsWait ...Zzzzzzzzzzzz...
>> [Bds]BdsWait(3)..Zzzz...
>
> I can reproduce this exact output with the latest version of AAVMF,
> built on commit 988715a.

I thought we'd decided this was a FreeBSD bug? Or does UEFI itself
use interrupts here and not set them up properly?

thanks
-- PMM

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-21 14:55     ` Peter Maydell
@ 2016-06-21 15:12       ` Andrew Jones
  2016-06-21 17:15         ` Andrew Jones
  0 siblings, 1 reply; 64+ messages in thread
From: Andrew Jones @ 2016-06-21 15:12 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Patch Tracking, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	QEMU Developers, Shannon Zhao, Shannon Zhao, Laszlo Ersek,
	Christoffer Dall

On Tue, Jun 21, 2016 at 03:55:46PM +0100, Peter Maydell wrote:
> On 21 June 2016 at 15:45, Andrew Jones <drjones@redhat.com> wrote:
> > On Wed, Jun 15, 2016 at 04:53:35PM +0800, Shannon Zhao wrote:
> >> I have another test with a freebsd guest. When I specify gic-version=3
> >> at the QEMU command line, the guest can't start. But with gic-version=2
> >> it's fine. And if I use gic-version=3 with kvm, the guest boots well too.
> >>
> >> It hangs with below log:
> >> [Bds]=============Begin Load Options Dumping ...=============
> >>   Driver Options:
> >>   SysPrep Options:
> >>   Boot Options:
> >>     Boot0000: UiApp              0x0109
> >>     Boot0001: EFI Internal Shell                 0x0001
> >>     Boot0002: UEFI Misc Device           0x0001
> >>     Boot0003: UEFI Misc Device 2                 0x0001
> >>     Boot0004: UEFI Misc Device 3                 0x0001
> >>     Boot0005: UEFI PXEv4 (MAC:525400123456)              0x0001
> >>   PlatformRecovery Options:
> >>     PlatformRecovery0000: Default PlatformRecovery               0x0001
> >> [Bds]=============End Load Options Dumping=============
> >> [Bds]BdsWait ...Zzzzzzzzzzzz...
> >> [Bds]BdsWait(3)..Zzzz...
> >
> > I can reproduce this exact output with the latest version of AAVMF,
> > built on commit 988715a.
> 
> I thought we'd decided this was a FreeBSD bug? Or does UEFI itself
> use interrupts here and not set them up properly?

Looks like AAVMF. I'm using RHEL for AArch64 kernel, which does
work with tcg,gic-version=3 -kernel boots, kvm,gic-version=3 boots,
and bare-metal gicv3 boots.

Thanks,
drew

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-21 15:12       ` Andrew Jones
@ 2016-06-21 17:15         ` Andrew Jones
  2016-06-21 17:17           ` Peter Maydell
  2016-06-21 17:18           ` Andrew Jones
  0 siblings, 2 replies; 64+ messages in thread
From: Andrew Jones @ 2016-06-21 17:15 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Patch Tracking, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	QEMU Developers, Shannon Zhao, Shannon Zhao, Laszlo Ersek,
	Christoffer Dall

On Tue, Jun 21, 2016 at 05:12:02PM +0200, Andrew Jones wrote:
> On Tue, Jun 21, 2016 at 03:55:46PM +0100, Peter Maydell wrote:
> > On 21 June 2016 at 15:45, Andrew Jones <drjones@redhat.com> wrote:
> > > On Wed, Jun 15, 2016 at 04:53:35PM +0800, Shannon Zhao wrote:
> > >> I have another test with a freebsd guest. When I specify gic-version=3
> > >> at the QEMU command line, the guest can't start. But with gic-version=2
> > >> it's fine. And if I use gic-version=3 with kvm, the guest boots well too.
> > >>
> > >> It hangs with below log:
> > >> [Bds]=============Begin Load Options Dumping ...=============
> > >>   Driver Options:
> > >>   SysPrep Options:
> > >>   Boot Options:
> > >>     Boot0000: UiApp              0x0109
> > >>     Boot0001: EFI Internal Shell                 0x0001
> > >>     Boot0002: UEFI Misc Device           0x0001
> > >>     Boot0003: UEFI Misc Device 2                 0x0001
> > >>     Boot0004: UEFI Misc Device 3                 0x0001
> > >>     Boot0005: UEFI PXEv4 (MAC:525400123456)              0x0001
> > >>   PlatformRecovery Options:
> > >>     PlatformRecovery0000: Default PlatformRecovery               0x0001
> > >> [Bds]=============End Load Options Dumping=============
> > >> [Bds]BdsWait ...Zzzzzzzzzzzz...
> > >> [Bds]BdsWait(3)..Zzzz...
> > >
> > > I can reproduce this exact output with the latest version of AAVMF,
> > > built on commit 988715a.
> > 
> > I thought we'd decided this was a FreeBSD bug? Or does UEFI itself
> > use interrupts here and not set them up properly?
> 
> Looks like AAVMF. I'm using RHEL for AArch64 kernel, which does
> work with tcg,gic-version=3 -kernel boots, kvm,gic-version=3 boots,
> and bare-metal gicv3 boots.
>

Laszlo asked me to reply again, this time with Ard on CC, and with
some more details.

Issue:
 AAVMF boot under gicv3 emulation, e.g.
  -machine virt,accel=tcg,gic-version=3 

fails with the above message. gicv3 emulation is not yet in master,
but can be built from

 git://git.linaro.org/people/pmaydell/qemu-arm.git staging

Shannon reported successful boots of UEFI, but I don't know what
build he used. The AAVMF I'm using is based on upstream commit
988715a3a7.

Thanks,
drew

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-21 17:15         ` Andrew Jones
@ 2016-06-21 17:17           ` Peter Maydell
  2016-06-21 17:18           ` Andrew Jones
  1 sibling, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-21 17:17 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Patch Tracking, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	QEMU Developers, Shannon Zhao, Shannon Zhao, Laszlo Ersek,
	Christoffer Dall

On 21 June 2016 at 18:15, Andrew Jones <drjones@redhat.com> wrote:
> Laszlo asked me to reply again, this time with Ard on CC, and with
> some more details.
>
> Issue:
>  AAVMF boot under gicv3 emulation, e.g.
>   -machine virt,accel=tcg,gic-version=3
>
> fails with the above message. gicv3 emulation is not yet in master

It is now in master.

>  git://git.linaro.org/people/pmaydell/qemu-arm.git staging

Don't use 'staging', that is "whatever random pull request I
am currently testing" and therefore can be arbitrarily busted...

thanks
-- PMM

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-21 17:15         ` Andrew Jones
  2016-06-21 17:17           ` Peter Maydell
@ 2016-06-21 17:18           ` Andrew Jones
  2016-06-21 17:21             ` Peter Maydell
  1 sibling, 1 reply; 64+ messages in thread
From: Andrew Jones @ 2016-06-21 17:18 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Patch Tracking, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	QEMU Developers, Shannon Zhao, Shannon Zhao, Laszlo Ersek,
	Christoffer Dall, ard.biesheuvel


Why oh why does mutt ask me who to CC after composing the mail instead
of before (after is when I've forgotten...) Maybe there's some config
I can change. OK, this time with Ard really on CC.

On Tue, Jun 21, 2016 at 07:15:57PM +0200, Andrew Jones wrote:
> On Tue, Jun 21, 2016 at 05:12:02PM +0200, Andrew Jones wrote:
> > On Tue, Jun 21, 2016 at 03:55:46PM +0100, Peter Maydell wrote:
> > > On 21 June 2016 at 15:45, Andrew Jones <drjones@redhat.com> wrote:
> > > > On Wed, Jun 15, 2016 at 04:53:35PM +0800, Shannon Zhao wrote:
> > > >> I have another test with a freebsd guest. When I specify gic-version=3
> > > >> at the QEMU command line, the guest can't start. But with gic-version=2
> > > >> it's fine. And if I use gic-version=3 with kvm, the guest boots well too.
> > > >>
> > > >> It hangs with below log:
> > > >> [Bds]=============Begin Load Options Dumping ...=============
> > > >>   Driver Options:
> > > >>   SysPrep Options:
> > > >>   Boot Options:
> > > >>     Boot0000: UiApp              0x0109
> > > >>     Boot0001: EFI Internal Shell                 0x0001
> > > >>     Boot0002: UEFI Misc Device           0x0001
> > > >>     Boot0003: UEFI Misc Device 2                 0x0001
> > > >>     Boot0004: UEFI Misc Device 3                 0x0001
> > > >>     Boot0005: UEFI PXEv4 (MAC:525400123456)              0x0001
> > > >>   PlatformRecovery Options:
> > > >>     PlatformRecovery0000: Default PlatformRecovery               0x0001
> > > >> [Bds]=============End Load Options Dumping=============
> > > >> [Bds]BdsWait ...Zzzzzzzzzzzz...
> > > >> [Bds]BdsWait(3)..Zzzz...
> > > >
> > > > I can reproduce this exact output with the latest version of AAVMF,
> > > > built on commit 988715a.
> > > 
> > > I thought we'd decided this was a FreeBSD bug? Or does UEFI itself
> > > use interrupts here and not set them up properly?
> > 
> > Looks like AAVMF. I'm using RHEL for AArch64 kernel, which does
> > work with tcg,gic-version=3 -kernel boots, kvm,gic-version=3 boots,
> > and bare-metal gicv3 boots.
> >
> 
> Laszlo asked me to reply again, this time with Ard on CC, and with
> some more details.
> 
> Issue:
>  AAVMF boot under gicv3 emulation, e.g.
>   -machine virt,accel=tcg,gic-version=3 
> 
> fails with the above message. gicv3 emulation is not yet in master,
> but can be built from
> 
>  git://git.linaro.org/people/pmaydell/qemu-arm.git staging
> 
> Shannon reported successful boots of UEFI, but I don't know what
> build he used. The AAVMF I'm using is based on upstream commit
> 988715a3a7.
> 
> Thanks,
> drew

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-21 17:18           ` Andrew Jones
@ 2016-06-21 17:21             ` Peter Maydell
  2016-06-21 19:45               ` Laszlo Ersek
  0 siblings, 1 reply; 64+ messages in thread
From: Peter Maydell @ 2016-06-21 17:21 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Patch Tracking, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	QEMU Developers, Shannon Zhao, Shannon Zhao, Laszlo Ersek,
	Christoffer Dall, Ard Biesheuvel

On 21 June 2016 at 18:18, Andrew Jones <drjones@redhat.com> wrote:
>
> Why oh why does mutt ask me who to CC after composing the mail instead
> of before (after is when I've forgotten...) Maybe there's some config
> I can change. OK, this time with Ard really on CC.

Heh. Let me repeat my other message:

The GICv3 emulation is in upstream QEMU master, so use that.
Don't use the 'staging' branch in my personal git tree, that is
"whatever random pull request I am currently testing" and therefore
can be arbitrarily busted...

and add a note I forgot to mention: my primary hypothesis is that
the problem here is "guest does not write to the GICD_IGROUPR and
GICR_IGROUPR registers to program the interrupts it's using as
group 1, but still expects to get IRQs rather than FIQs".

thanks
-- PMM

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-21 17:21             ` Peter Maydell
@ 2016-06-21 19:45               ` Laszlo Ersek
  2016-06-21 19:53                 ` Peter Maydell
  0 siblings, 1 reply; 64+ messages in thread
From: Laszlo Ersek @ 2016-06-21 19:45 UTC (permalink / raw)
  To: Peter Maydell, Andrew Jones
  Cc: Patch Tracking, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	QEMU Developers, Shannon Zhao, Shannon Zhao, Christoffer Dall,
	Ard Biesheuvel

On 06/21/16 19:21, Peter Maydell wrote:
> On 21 June 2016 at 18:18, Andrew Jones <drjones@redhat.com> wrote:
>>
>> Why oh why does mutt ask me who to CC after composing the mail instead
>> of before (after is when I've forgotten...) Maybe there's some config
>> I can change. OK, this time with Ard really on CC.
> 
> Heh. Let me repeat my other message:
> 
> The GICv3 emulation is in upstream QEMU master, so use that.
> Don't use the 'staging' branch in my personal git tree, that is
> "whatever random pull request I am currently testing" and therefore
> can be arbitrarily busted...
> 
> and add a note I forgot to mention: my primary hypothesis is that
> the problem here is "guest does not write to the GICD_IGROUPR and
> GICR_IGROUPR registers to program the interrupts it's using as
> group 1, but still expects to get IRQs rather than FIQs".

... and it (or whatever else is the root cause) seems to manifest in
either the Stall() UEFI boot service, or in UEFI timer events. (This
seems to follow from the last debug log entry from Shannon:

[Bds]BdsWait(3)..Zzzz...
)

... Just to make it clear: does it reproduce with KVM? Or is that
untested perhaps (due to lack of GICv3 hardware e.g.)?

Thanks
Laszlo

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-21 19:45               ` Laszlo Ersek
@ 2016-06-21 19:53                 ` Peter Maydell
  2016-06-22  1:42                   ` Shannon Zhao
  0 siblings, 1 reply; 64+ messages in thread
From: Peter Maydell @ 2016-06-21 19:53 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: Andrew Jones, Patch Tracking, Shlomo Pongratz, Shlomo Pongratz,
	Pavel Fedin, QEMU Developers, Shannon Zhao, Shannon Zhao,
	Christoffer Dall, Ard Biesheuvel

On 21 June 2016 at 20:45, Laszlo Ersek <lersek@redhat.com> wrote:
> On 06/21/16 19:21, Peter Maydell wrote:
>> and add a note I forgot to mention: my primary hypothesis is that
>> the problem here is "guest does not write to the GICD_IGROUPR and
>> GICR_IGROUPR registers to program the interrupts it's using as
>> group 1, but still expects to get IRQs rather than FIQs".
>
> ... and it (or whatever else is the root cause) seems to manifest in
> either the Stall() UEFI boot service, or in UEFI timer events. (This
> seems to follow from the last debug log entry from Shannon:
>
> [Bds]BdsWait(3)..Zzzz...
> )
>
> ... Just to make it clear: does it reproduce with KVM? Or is that
> untested perhaps (due to lack of GICv3 hardware e.g.)?

Upthread Shannon said it worked with KVM enabled. Note that
KVM's GICv3 emulation is incorrect in that it does not support
interrupt groups, so all interrupt groups are Group 1 and
generate IRQ even if the guest doesn't do anything to
configure them.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-21 19:53                 ` Peter Maydell
@ 2016-06-22  1:42                   ` Shannon Zhao
  2016-06-22  7:43                     ` Andrew Jones
  0 siblings, 1 reply; 64+ messages in thread
From: Shannon Zhao @ 2016-06-22  1:42 UTC (permalink / raw)
  To: Peter Maydell, Laszlo Ersek
  Cc: Andrew Jones, Patch Tracking, Shlomo Pongratz, Shlomo Pongratz,
	Pavel Fedin, QEMU Developers, Shannon Zhao, Christoffer Dall,
	Ard Biesheuvel



On 2016/6/22 3:53, Peter Maydell wrote:
> On 21 June 2016 at 20:45, Laszlo Ersek <lersek@redhat.com> wrote:
>> > On 06/21/16 19:21, Peter Maydell wrote:
>>> >> and add a note I forgot to mention: my primary hypothesis is that
>>> >> the problem here is "guest does not write to the GICD_IGROUPR and
>>> >> GICR_IGROUPR registers to program the interrupts it's using as
>>> >> group 1, but still expects to get IRQs rather than FIQs".
>> >
>> > ... and it (or whatever else is the root cause) seems to manifest in
>> > either the Stall() UEFI boot service, or in UEFI timer events. (This
>> > seems to follow from the last debug log entry from Shannon:
>> >
>> > [Bds]BdsWait(3)..Zzzz...
>> > )
>> >
>> > ... Just to make it clear: does it reproduce with KVM? Or is that
>> > untested perhaps (due to lack of GICv3 hardware e.g.)?
> Upthread Shannon said it worked with KVM enabled. Note that
> KVM's GICv3 emulation is incorrect in that it does not support
> interrupt groups, so all interrupt groups are Group 1 and
> generate IRQ even if the guest doesn't do anything to
> configure them.
It does work with KVM enabled. It also works with UEFI and the upstream
linux kernel while it doesn't work with UEFI and a FreeBSD guest since
the FreeBSD doesn't correctly set the IGROUPR, I think.

I can't find the commit ID of the UEFI I use but I used the upsream
codes of June 15.
Andrew, I suggest you use the QEMU mainline which includes the GICv3
emulation and the guest kernel with the commit 7c9b973061.

Thanks,
-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-22  1:42                   ` Shannon Zhao
@ 2016-06-22  7:43                     ` Andrew Jones
  2016-06-22  8:27                       ` Shannon Zhao
  0 siblings, 1 reply; 64+ messages in thread
From: Andrew Jones @ 2016-06-22  7:43 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: Peter Maydell, Laszlo Ersek, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Ard Biesheuvel, Pavel Fedin, QEMU Developers,
	Shannon Zhao, Christoffer Dall

On Wed, Jun 22, 2016 at 09:42:29AM +0800, Shannon Zhao wrote:
> 
> 
> On 2016/6/22 3:53, Peter Maydell wrote:
> > On 21 June 2016 at 20:45, Laszlo Ersek <lersek@redhat.com> wrote:
> >> > On 06/21/16 19:21, Peter Maydell wrote:
> >>> >> and add a note I forgot to mention: my primary hypothesis is that
> >>> >> the problem here is "guest does not write to the GICD_IGROUPR and
> >>> >> GICR_IGROUPR registers to program the interrupts it's using as
> >>> >> group 1, but still expects to get IRQs rather than FIQs".
> >> >
> >> > ... and it (or whatever else is the root cause) seems to manifest in
> >> > either the Stall() UEFI boot service, or in UEFI timer events. (This
> >> > seems to follow from the last debug log entry from Shannon:
> >> >
> >> > [Bds]BdsWait(3)..Zzzz...
> >> > )
> >> >
> >> > ... Just to make it clear: does it reproduce with KVM? Or is that
> >> > untested perhaps (due to lack of GICv3 hardware e.g.)?
> > Upthread Shannon said it worked with KVM enabled. Note that
> > KVM's GICv3 emulation is incorrect in that it does not support
> > interrupt groups, so all interrupt groups are Group 1 and
> > generate IRQ even if the guest doesn't do anything to
> > configure them.
> It does work with KVM enabled. It also works with UEFI and the upstream
> linux kernel while it doesn't work with UEFI and a FreeBSD guest since
> the FreeBSD doesn't correctly set the IGROUPR, I think.

Doesn't appear to be FreeBSD specific, as I'm using a Linux kernel and
can reproduce. Besides, it doesn't even make it to grub.

> 
> I can't find the commit ID of the UEFI I use but I used the upsream
> codes of June 15.
> Andrew, I suggest you use the QEMU mainline which includes the GICv3
> emulation and the guest kernel with the commit 7c9b973061.

Yeah, I hadn't noticed that gicv3 made it to mainline. I've switched
to that now. My guest kernel does have 7c9b973061 (I backported it to
the RHELSA kernel)

My complete AAVMF.verbose log is here
https://paste.fedoraproject.org/383004/46658133/

Thanks,
drew

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-22  7:43                     ` Andrew Jones
@ 2016-06-22  8:27                       ` Shannon Zhao
  2016-06-22  9:09                         ` Andrew Jones
  0 siblings, 1 reply; 64+ messages in thread
From: Shannon Zhao @ 2016-06-22  8:27 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Peter Maydell, Laszlo Ersek, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Ard Biesheuvel, Pavel Fedin, QEMU Developers,
	Shannon Zhao, Christoffer Dall



On 2016/6/22 15:43, Andrew Jones wrote:
> On Wed, Jun 22, 2016 at 09:42:29AM +0800, Shannon Zhao wrote:
>> > 
>> > 
>> > On 2016/6/22 3:53, Peter Maydell wrote:
>>> > > On 21 June 2016 at 20:45, Laszlo Ersek <lersek@redhat.com> wrote:
>>>>> > >> > On 06/21/16 19:21, Peter Maydell wrote:
>>>>>>> > >>> >> and add a note I forgot to mention: my primary hypothesis is that
>>>>>>> > >>> >> the problem here is "guest does not write to the GICD_IGROUPR and
>>>>>>> > >>> >> GICR_IGROUPR registers to program the interrupts it's using as
>>>>>>> > >>> >> group 1, but still expects to get IRQs rather than FIQs".
>>>>> > >> >
>>>>> > >> > ... and it (or whatever else is the root cause) seems to manifest in
>>>>> > >> > either the Stall() UEFI boot service, or in UEFI timer events. (This
>>>>> > >> > seems to follow from the last debug log entry from Shannon:
>>>>> > >> >
>>>>> > >> > [Bds]BdsWait(3)..Zzzz...
>>>>> > >> > )
>>>>> > >> >
>>>>> > >> > ... Just to make it clear: does it reproduce with KVM? Or is that
>>>>> > >> > untested perhaps (due to lack of GICv3 hardware e.g.)?
>>> > > Upthread Shannon said it worked with KVM enabled. Note that
>>> > > KVM's GICv3 emulation is incorrect in that it does not support
>>> > > interrupt groups, so all interrupt groups are Group 1 and
>>> > > generate IRQ even if the guest doesn't do anything to
>>> > > configure them.
>> > It does work with KVM enabled. It also works with UEFI and the upstream
>> > linux kernel while it doesn't work with UEFI and a FreeBSD guest since
>> > the FreeBSD doesn't correctly set the IGROUPR, I think.
> Doesn't appear to be FreeBSD specific, as I'm using a Linux kernel and
> can reproduce. Besides, it doesn't even make it to grub.
> 
>> > 
>> > I can't find the commit ID of the UEFI I use but I used the upsream
>> > codes of June 15.
>> > Andrew, I suggest you use the QEMU mainline which includes the GICv3
>> > emulation and the guest kernel with the commit 7c9b973061.
> Yeah, I hadn't noticed that gicv3 made it to mainline. I've switched
> to that now. My guest kernel does have 7c9b973061 (I backported it to
> the RHELSA kernel)

I just used a new UEFI binary which is built on 8f88f02 and the upstream
linux kernel. It boots as well.
Could you try the upstream linux kernel?

Thanks,
-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-22  8:27                       ` Shannon Zhao
@ 2016-06-22  9:09                         ` Andrew Jones
  2016-06-22 15:23                           ` Laszlo Ersek
  0 siblings, 1 reply; 64+ messages in thread
From: Andrew Jones @ 2016-06-22  9:09 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: Peter Maydell, Ard Biesheuvel, Shlomo Pongratz, Shlomo Pongratz,
	Patch Tracking, Pavel Fedin, QEMU Developers, Shannon Zhao,
	Laszlo Ersek, Christoffer Dall

On Wed, Jun 22, 2016 at 04:27:35PM +0800, Shannon Zhao wrote:
> 
> 
> On 2016/6/22 15:43, Andrew Jones wrote:
> > On Wed, Jun 22, 2016 at 09:42:29AM +0800, Shannon Zhao wrote:
> >> > 
> >> > 
> >> > On 2016/6/22 3:53, Peter Maydell wrote:
> >>> > > On 21 June 2016 at 20:45, Laszlo Ersek <lersek@redhat.com> wrote:
> >>>>> > >> > On 06/21/16 19:21, Peter Maydell wrote:
> >>>>>>> > >>> >> and add a note I forgot to mention: my primary hypothesis is that
> >>>>>>> > >>> >> the problem here is "guest does not write to the GICD_IGROUPR and
> >>>>>>> > >>> >> GICR_IGROUPR registers to program the interrupts it's using as
> >>>>>>> > >>> >> group 1, but still expects to get IRQs rather than FIQs".
> >>>>> > >> >
> >>>>> > >> > ... and it (or whatever else is the root cause) seems to manifest in
> >>>>> > >> > either the Stall() UEFI boot service, or in UEFI timer events. (This
> >>>>> > >> > seems to follow from the last debug log entry from Shannon:
> >>>>> > >> >
> >>>>> > >> > [Bds]BdsWait(3)..Zzzz...
> >>>>> > >> > )
> >>>>> > >> >
> >>>>> > >> > ... Just to make it clear: does it reproduce with KVM? Or is that
> >>>>> > >> > untested perhaps (due to lack of GICv3 hardware e.g.)?
> >>> > > Upthread Shannon said it worked with KVM enabled. Note that
> >>> > > KVM's GICv3 emulation is incorrect in that it does not support
> >>> > > interrupt groups, so all interrupt groups are Group 1 and
> >>> > > generate IRQ even if the guest doesn't do anything to
> >>> > > configure them.
> >> > It does work with KVM enabled. It also works with UEFI and the upstream
> >> > linux kernel while it doesn't work with UEFI and a FreeBSD guest since
> >> > the FreeBSD doesn't correctly set the IGROUPR, I think.
> > Doesn't appear to be FreeBSD specific, as I'm using a Linux kernel and
> > can reproduce. Besides, it doesn't even make it to grub.
> > 
> >> > 
> >> > I can't find the commit ID of the UEFI I use but I used the upsream
> >> > codes of June 15.
> >> > Andrew, I suggest you use the QEMU mainline which includes the GICv3
> >> > emulation and the guest kernel with the commit 7c9b973061.
> > Yeah, I hadn't noticed that gicv3 made it to mainline. I've switched
> > to that now. My guest kernel does have 7c9b973061 (I backported it to
> > the RHELSA kernel)
> 
> I just used a new UEFI binary which is built on 8f88f02 and the upstream
> linux kernel. It boots as well.
> Could you try the upstream linux kernel?

It doesn't even make it to grub, so the kernel doesn't matter. I'm getting
the impression that you're using both UEFI and -kernel to boot, when
booting Linux, but not when booting FreeBSD. Indeed, if I add -kernel to
my cmdline, then I can boot the RHELSA kernel as well. So this looks like
an AAVMF launching grub issue (or just a grub issue).

Thanks,
drew

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-22  9:09                         ` Andrew Jones
@ 2016-06-22 15:23                           ` Laszlo Ersek
  0 siblings, 0 replies; 64+ messages in thread
From: Laszlo Ersek @ 2016-06-22 15:23 UTC (permalink / raw)
  To: Andrew Jones, Shannon Zhao
  Cc: Peter Maydell, Ard Biesheuvel, Shlomo Pongratz, Shlomo Pongratz,
	Patch Tracking, Pavel Fedin, QEMU Developers, Shannon Zhao,
	Christoffer Dall

On 06/22/16 11:09, Andrew Jones wrote:
> On Wed, Jun 22, 2016 at 04:27:35PM +0800, Shannon Zhao wrote:
>>
>>
>> On 2016/6/22 15:43, Andrew Jones wrote:
>>> On Wed, Jun 22, 2016 at 09:42:29AM +0800, Shannon Zhao wrote:
>>>>>
>>>>>
>>>>> On 2016/6/22 3:53, Peter Maydell wrote:
>>>>>>> On 21 June 2016 at 20:45, Laszlo Ersek <lersek@redhat.com> wrote:
>>>>>>>>>>> On 06/21/16 19:21, Peter Maydell wrote:
>>>>>>>>>>>>>>> and add a note I forgot to mention: my primary hypothesis is that
>>>>>>>>>>>>>>> the problem here is "guest does not write to the GICD_IGROUPR and
>>>>>>>>>>>>>>> GICR_IGROUPR registers to program the interrupts it's using as
>>>>>>>>>>>>>>> group 1, but still expects to get IRQs rather than FIQs".
>>>>>>>>>>>
>>>>>>>>>>> ... and it (or whatever else is the root cause) seems to manifest in
>>>>>>>>>>> either the Stall() UEFI boot service, or in UEFI timer events. (This
>>>>>>>>>>> seems to follow from the last debug log entry from Shannon:
>>>>>>>>>>>
>>>>>>>>>>> [Bds]BdsWait(3)..Zzzz...
>>>>>>>>>>> )
>>>>>>>>>>>
>>>>>>>>>>> ... Just to make it clear: does it reproduce with KVM? Or is that
>>>>>>>>>>> untested perhaps (due to lack of GICv3 hardware e.g.)?
>>>>>>> Upthread Shannon said it worked with KVM enabled. Note that
>>>>>>> KVM's GICv3 emulation is incorrect in that it does not support
>>>>>>> interrupt groups, so all interrupt groups are Group 1 and
>>>>>>> generate IRQ even if the guest doesn't do anything to
>>>>>>> configure them.
>>>>> It does work with KVM enabled. It also works with UEFI and the upstream
>>>>> linux kernel while it doesn't work with UEFI and a FreeBSD guest since
>>>>> the FreeBSD doesn't correctly set the IGROUPR, I think.
>>> Doesn't appear to be FreeBSD specific, as I'm using a Linux kernel and
>>> can reproduce. Besides, it doesn't even make it to grub.
>>>
>>>>>
>>>>> I can't find the commit ID of the UEFI I use but I used the upsream
>>>>> codes of June 15.
>>>>> Andrew, I suggest you use the QEMU mainline which includes the GICv3
>>>>> emulation and the guest kernel with the commit 7c9b973061.
>>> Yeah, I hadn't noticed that gicv3 made it to mainline. I've switched
>>> to that now. My guest kernel does have 7c9b973061 (I backported it to
>>> the RHELSA kernel)
>>
>> I just used a new UEFI binary which is built on 8f88f02 and the upstream
>> linux kernel. It boots as well.
>> Could you try the upstream linux kernel?
> 
> It doesn't even make it to grub, so the kernel doesn't matter. I'm getting
> the impression that you're using both UEFI and -kernel to boot, when
> booting Linux, but not when booting FreeBSD. Indeed, if I add -kernel to
> my cmdline, then I can boot the RHELSA kernel as well. So this looks like
> an AAVMF launching grub issue (or just a grub issue).

The difference is that with -kernel, the firmware doesn't go as far into
the BDS code as without it. The firmware code that exposes the GICv3
configuration issue is not reached when you launch QEMU with -kernel.

The GICv3 is incorrectly configured just the same, but with -kernel, the
first thing that would expose it is the kernel, and (AIUI) Peter fixed
that already.

Anyway, please see / test Ard's edk2 patch that you all were CC'd on.

Thanks!
Laszlo

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-15 10:10       ` Peter Maydell
  2016-06-15 14:02         ` Shannon Zhao
  2016-06-16  2:17         ` Shannon Zhao
@ 2016-06-22 18:09         ` Ed Maste
  2016-06-22 20:53           ` Peter Maydell
  2 siblings, 1 reply; 64+ messages in thread
From: Ed Maste @ 2016-06-22 18:09 UTC (permalink / raw)
  To: Peter Maydell; +Cc: QEMU Developers

On 15 June 2016 at 06:10, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> A quick scan through http://fxr.watson.org/fxr/source/arm64/arm64/gic_v3.c
> doesn't seem to show it setting the IGROUPR registers anywhere,
> so it probably is a guest bug. (You can use "-d 'trace:gicv3*'" to
> enable the tracepoints for the GIC which would let you check whether
> the guest ever tries to write to the group config registers.)

Is there a prebuilt QEMU_EFI.fd available somewhere for testing a
FreeBSD change to address this? I've been using the prebuilt ones from
https://wiki.linaro.org/LEG/UEFIforQEMU and the latest one I had did
not start with gic-version=3.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-22 18:09         ` Ed Maste
@ 2016-06-22 20:53           ` Peter Maydell
  2016-06-22 21:45             ` Ed Maste
  2016-06-23 11:36             ` Laszlo Ersek
  0 siblings, 2 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-22 20:53 UTC (permalink / raw)
  To: Ed Maste; +Cc: QEMU Developers, Laszlo Ersek, Ard Biesheuvel

On 22 June 2016 at 19:09, Ed Maste <emaste@freebsd.org> wrote:
> On 15 June 2016 at 06:10, Peter Maydell <peter.maydell@linaro.org> wrote:
>>
>> A quick scan through http://fxr.watson.org/fxr/source/arm64/arm64/gic_v3.c
>> doesn't seem to show it setting the IGROUPR registers anywhere,
>> so it probably is a guest bug. (You can use "-d 'trace:gicv3*'" to
>> enable the tracepoints for the GIC which would let you check whether
>> the guest ever tries to write to the group config registers.)
>
> Is there a prebuilt QEMU_EFI.fd available somewhere for testing a
> FreeBSD change to address this? I've been using the prebuilt ones from
> https://wiki.linaro.org/LEG/UEFIforQEMU and the latest one I had did
> not start with gic-version=3.

Yeah, it looks like the same bug is also present in UEFI itself
(it's super popular!). Laszlo, Ard, do you have a prebuilt
UEFI binary with Ard's fix?

Probably you'll find that if UEFI is configuring the GIC interrupt
groups FreeBSD will boot even without doing it itself, but I
think ideally FreeBSD shouldn't assume the bootloader's done
that job for it.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-22 20:53           ` Peter Maydell
@ 2016-06-22 21:45             ` Ed Maste
  2016-06-22 21:56               ` Peter Maydell
  2016-06-23  1:42               ` Shannon Zhao
  2016-06-23 11:36             ` Laszlo Ersek
  1 sibling, 2 replies; 64+ messages in thread
From: Ed Maste @ 2016-06-22 21:45 UTC (permalink / raw)
  To: Peter Maydell
  Cc: QEMU Developers, Laszlo Ersek, Ard Biesheuvel, zhaoshenglong

On 22 June 2016 at 16:53, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> Yeah, it looks like the same bug is also present in UEFI itself
> (it's super popular!). Laszlo, Ard, do you have a prebuilt
> UEFI binary with Ard's fix?
>
> Probably you'll find that if UEFI is configuring the GIC interrupt
> groups FreeBSD will boot even without doing it itself, but I
> think ideally FreeBSD shouldn't assume the bootloader's done
> that job for it.

Oh, good point. Indeed FreeBSD should not make this assumption. I'm
not sure how I'd test the FreeBSD fix then though (booting w/o the
UEFI firmware doing this configuration).

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-22 21:45             ` Ed Maste
@ 2016-06-22 21:56               ` Peter Maydell
  2016-06-23  1:42               ` Shannon Zhao
  1 sibling, 0 replies; 64+ messages in thread
From: Peter Maydell @ 2016-06-22 21:56 UTC (permalink / raw)
  To: Ed Maste; +Cc: QEMU Developers, Laszlo Ersek, Ard Biesheuvel, Shannon Zhao

On 22 June 2016 at 22:45, Ed Maste <emaste@freebsd.org> wrote:
> On 22 June 2016 at 16:53, Peter Maydell <peter.maydell@linaro.org> wrote:
>>
>> Yeah, it looks like the same bug is also present in UEFI itself
>> (it's super popular!). Laszlo, Ard, do you have a prebuilt
>> UEFI binary with Ard's fix?
>>
>> Probably you'll find that if UEFI is configuring the GIC interrupt
>> groups FreeBSD will boot even without doing it itself, but I
>> think ideally FreeBSD shouldn't assume the bootloader's done
>> that job for it.
>
> Oh, good point. Indeed FreeBSD should not make this assumption. I'm
> not sure how I'd test the FreeBSD fix then though (booting w/o the
> UEFI firmware doing this configuration).

Mmm, tricky. I guess you could hack UEFI to only put the
interrupts it is itself using into group 1 (presumably
the timer interrupt). [I'm guessing FreeBSD doesn't
support Linux-kernel-boot-protocol, or you could use
-kernel.]

-- PMM

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-22 21:45             ` Ed Maste
  2016-06-22 21:56               ` Peter Maydell
@ 2016-06-23  1:42               ` Shannon Zhao
  1 sibling, 0 replies; 64+ messages in thread
From: Shannon Zhao @ 2016-06-23  1:42 UTC (permalink / raw)
  To: Ed Maste, Peter Maydell; +Cc: QEMU Developers, Laszlo Ersek, Ard Biesheuvel



On 2016/6/23 5:45, Ed Maste wrote:
> On 22 June 2016 at 16:53, Peter Maydell <peter.maydell@linaro.org> wrote:
>>
>> Yeah, it looks like the same bug is also present in UEFI itself
>> (it's super popular!). Laszlo, Ard, do you have a prebuilt
>> UEFI binary with Ard's fix?
>>
>> Probably you'll find that if UEFI is configuring the GIC interrupt
>> groups FreeBSD will boot even without doing it itself,
I try this with Ard's patch. Looks like UEFI already loader guest kernel
not like berfore. But the FreeBSD kernel still hangs.

FreeBSD/arm64 EFI loader, Revision 1.1
(root@releng2.nyi.freebsd.org, Sat Jun 11 17:18:43 UTC 2016)
Loading /boot/defaults/loader.conf
/boot/kernel/kernel data=0x704ca8+0x32db74 syms=[0x8+0xda1c0+0x8+0xd6db0]
/boot/entropy size=0x1000

Hit [Enter] to boot immediately, or any other key for command prompt.
Booting [/boot/kernel/kernel]...
Using DTB provided by EFI at 0x13ffb9000.
KDB: debugger backends: ddb
KDB: current backend: ddb
Copyright (c) 1992-2016 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
        The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 11.0-ALPHA3 #0 r301815: Sat Jun 11 17:22:24 UTC 2016

root@releng2.nyi.freebsd.org:/usr/obj/arm64.aarch64/usr/src/sys/GENERIC
arm64
FreeBSD clang version 3.8.0 (tags/RELEASE_380/final 262564) (based on
LLVM 3.8.0)
WARNING: WITNESS option enabled, expect reduced performance.

Thanks,
-- 
Shannon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-22 20:53           ` Peter Maydell
  2016-06-22 21:45             ` Ed Maste
@ 2016-06-23 11:36             ` Laszlo Ersek
  2016-06-23 12:07               ` Andrew Jones
  2016-06-23 14:18               ` Ed Maste
  1 sibling, 2 replies; 64+ messages in thread
From: Laszlo Ersek @ 2016-06-23 11:36 UTC (permalink / raw)
  To: Peter Maydell, Ed Maste; +Cc: QEMU Developers, Ard Biesheuvel

On 06/22/16 22:53, Peter Maydell wrote:
> On 22 June 2016 at 19:09, Ed Maste <emaste@freebsd.org> wrote:
>> On 15 June 2016 at 06:10, Peter Maydell <peter.maydell@linaro.org> wrote:
>>>
>>> A quick scan through http://fxr.watson.org/fxr/source/arm64/arm64/gic_v3.c
>>> doesn't seem to show it setting the IGROUPR registers anywhere,
>>> so it probably is a guest bug. (You can use "-d 'trace:gicv3*'" to
>>> enable the tracepoints for the GIC which would let you check whether
>>> the guest ever tries to write to the group config registers.)
>>
>> Is there a prebuilt QEMU_EFI.fd available somewhere for testing a
>> FreeBSD change to address this? I've been using the prebuilt ones from
>> https://wiki.linaro.org/LEG/UEFIforQEMU and the latest one I had did
>> not start with gic-version=3.
> 
> Yeah, it looks like the same bug is also present in UEFI itself
> (it's super popular!). Laszlo, Ard, do you have a prebuilt
> UEFI binary with Ard's fix?

I just put up one here, in case it's still needed:

http://people.redhat.com/~lersek/82a5e88f-f1e1-42e2-8462-66974c9cbfff/

Thanks
Laszlo

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-23 11:36             ` Laszlo Ersek
@ 2016-06-23 12:07               ` Andrew Jones
  2016-06-23 14:18               ` Ed Maste
  1 sibling, 0 replies; 64+ messages in thread
From: Andrew Jones @ 2016-06-23 12:07 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: Peter Maydell, Ed Maste, QEMU Developers, Ard Biesheuvel

On Thu, Jun 23, 2016 at 01:36:40PM +0200, Laszlo Ersek wrote:
> On 06/22/16 22:53, Peter Maydell wrote:
> > On 22 June 2016 at 19:09, Ed Maste <emaste@freebsd.org> wrote:
> >> On 15 June 2016 at 06:10, Peter Maydell <peter.maydell@linaro.org> wrote:
> >>>
> >>> A quick scan through http://fxr.watson.org/fxr/source/arm64/arm64/gic_v3.c
> >>> doesn't seem to show it setting the IGROUPR registers anywhere,
> >>> so it probably is a guest bug. (You can use "-d 'trace:gicv3*'" to
> >>> enable the tracepoints for the GIC which would let you check whether
> >>> the guest ever tries to write to the group config registers.)
> >>
> >> Is there a prebuilt QEMU_EFI.fd available somewhere for testing a
> >> FreeBSD change to address this? I've been using the prebuilt ones from
> >> https://wiki.linaro.org/LEG/UEFIforQEMU and the latest one I had did
> >> not start with gic-version=3.
> > 
> > Yeah, it looks like the same bug is also present in UEFI itself
> > (it's super popular!). Laszlo, Ard, do you have a prebuilt
> > UEFI binary with Ard's fix?
> 
> I just put up one here, in case it's still needed:
> 
> http://people.redhat.com/~lersek/82a5e88f-f1e1-42e2-8462-66974c9cbfff/

Thanks Laszlo! /me was procrastinating the building of edk2...

Test result: PASS

drew

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-23 11:36             ` Laszlo Ersek
  2016-06-23 12:07               ` Andrew Jones
@ 2016-06-23 14:18               ` Ed Maste
  2016-06-23 14:52                 ` Laszlo Ersek
  1 sibling, 1 reply; 64+ messages in thread
From: Ed Maste @ 2016-06-23 14:18 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: Peter Maydell, QEMU Developers, Ard Biesheuvel

On 23 June 2016 at 07:36, Laszlo Ersek <lersek@redhat.com> wrote:
> On 06/22/16 22:53, Peter Maydell wrote:
>> On 22 June 2016 at 19:09, Ed Maste <emaste@freebsd.org> wrote:
>>> On 15 June 2016 at 06:10, Peter Maydell <peter.maydell@linaro.org> wrote:
>>>>
>>>> A quick scan through http://fxr.watson.org/fxr/source/arm64/arm64/gic_v3.c
>>>> doesn't seem to show it setting the IGROUPR registers anywhere,
>>>> so it probably is a guest bug. (You can use "-d 'trace:gicv3*'" to
>>>> enable the tracepoints for the GIC which would let you check whether
>>>> the guest ever tries to write to the group config registers.)
>>>
>>> Is there a prebuilt QEMU_EFI.fd available somewhere for testing a
>>> FreeBSD change to address this? I've been using the prebuilt ones from
>>> https://wiki.linaro.org/LEG/UEFIforQEMU and the latest one I had did
>>> not start with gic-version=3.
>>
>> Yeah, it looks like the same bug is also present in UEFI itself
>> (it's super popular!). Laszlo, Ard, do you have a prebuilt
>> UEFI binary with Ard's fix?
>
> I just put up one here, in case it's still needed:
>
> http://people.redhat.com/~lersek/82a5e88f-f1e1-42e2-8462-66974c9cbfff/

Thank you. I ran your QEMU_EFI.fd with gic_version=3 and UEFI and
FreeBSD start up successfully (as expected, based on the discussion in
this thread).

It sounds like we'll need to build a hacked UEFI build as Peter
Maydell suggested in order to actually test a FreeBSD fix when we have
it.

-Ed

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-23 14:18               ` Ed Maste
@ 2016-06-23 14:52                 ` Laszlo Ersek
  2016-06-23 20:03                   ` Ard Biesheuvel
  0 siblings, 1 reply; 64+ messages in thread
From: Laszlo Ersek @ 2016-06-23 14:52 UTC (permalink / raw)
  To: Ed Maste; +Cc: Peter Maydell, QEMU Developers, Ard Biesheuvel

On 06/23/16 16:18, Ed Maste wrote:
> On 23 June 2016 at 07:36, Laszlo Ersek <lersek@redhat.com> wrote:
>> On 06/22/16 22:53, Peter Maydell wrote:
>>> On 22 June 2016 at 19:09, Ed Maste <emaste@freebsd.org> wrote:
>>>> On 15 June 2016 at 06:10, Peter Maydell <peter.maydell@linaro.org> wrote:
>>>>>
>>>>> A quick scan through http://fxr.watson.org/fxr/source/arm64/arm64/gic_v3.c
>>>>> doesn't seem to show it setting the IGROUPR registers anywhere,
>>>>> so it probably is a guest bug. (You can use "-d 'trace:gicv3*'" to
>>>>> enable the tracepoints for the GIC which would let you check whether
>>>>> the guest ever tries to write to the group config registers.)
>>>>
>>>> Is there a prebuilt QEMU_EFI.fd available somewhere for testing a
>>>> FreeBSD change to address this? I've been using the prebuilt ones from
>>>> https://wiki.linaro.org/LEG/UEFIforQEMU and the latest one I had did
>>>> not start with gic-version=3.
>>>
>>> Yeah, it looks like the same bug is also present in UEFI itself
>>> (it's super popular!). Laszlo, Ard, do you have a prebuilt
>>> UEFI binary with Ard's fix?
>>
>> I just put up one here, in case it's still needed:
>>
>> http://people.redhat.com/~lersek/82a5e88f-f1e1-42e2-8462-66974c9cbfff/
> 
> Thank you. I ran your QEMU_EFI.fd with gic_version=3 and UEFI and
> FreeBSD start up successfully (as expected, based on the discussion in
> this thread).
> 
> It sounds like we'll need to build a hacked UEFI build as Peter
> Maydell suggested in order to actually test a FreeBSD fix when we have
> it.

Ah, sorry, I failed to understand this nuance from the discussion
(although I quoted it myself -- sorry I'm not having a great day today).
So apparently you need a recent enough firmware binary that *starts*
with gicv3, but doesn't configure the gicv3 as otherwise needed, so you
can reproduce the FreeBSD bug, and verify the FreeBSD bugfix, while
booting with UEFI.

Ard's patch has just been committed to upstream edk2 (c7fefb690661 --
<https://github.com/tianocore/edk2/commits/master>), but I can build a
binary for you right before it (at
bf57a42a0e2cf1c68e9db2f61c82ce93c806ab07)...

http://people.redhat.com/~lersek/82a5e88f-f1e1-42e2-8462-66974c9cbfff/QEMU_EFI.fd.bf57a42a0e2c

Thanks
Laszlo

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-23 14:52                 ` Laszlo Ersek
@ 2016-06-23 20:03                   ` Ard Biesheuvel
  2016-06-23 20:33                     ` Peter Maydell
  0 siblings, 1 reply; 64+ messages in thread
From: Ard Biesheuvel @ 2016-06-23 20:03 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: Ed Maste, Peter Maydell, QEMU Developers

On 23 June 2016 at 16:52, Laszlo Ersek <lersek@redhat.com> wrote:
> On 06/23/16 16:18, Ed Maste wrote:
>> On 23 June 2016 at 07:36, Laszlo Ersek <lersek@redhat.com> wrote:
>>> On 06/22/16 22:53, Peter Maydell wrote:
>>>> On 22 June 2016 at 19:09, Ed Maste <emaste@freebsd.org> wrote:
>>>>> On 15 June 2016 at 06:10, Peter Maydell <peter.maydell@linaro.org> wrote:
>>>>>>
>>>>>> A quick scan through http://fxr.watson.org/fxr/source/arm64/arm64/gic_v3.c
>>>>>> doesn't seem to show it setting the IGROUPR registers anywhere,
>>>>>> so it probably is a guest bug. (You can use "-d 'trace:gicv3*'" to
>>>>>> enable the tracepoints for the GIC which would let you check whether
>>>>>> the guest ever tries to write to the group config registers.)
>>>>>
>>>>> Is there a prebuilt QEMU_EFI.fd available somewhere for testing a
>>>>> FreeBSD change to address this? I've been using the prebuilt ones from
>>>>> https://wiki.linaro.org/LEG/UEFIforQEMU and the latest one I had did
>>>>> not start with gic-version=3.
>>>>
>>>> Yeah, it looks like the same bug is also present in UEFI itself
>>>> (it's super popular!). Laszlo, Ard, do you have a prebuilt
>>>> UEFI binary with Ard's fix?
>>>
>>> I just put up one here, in case it's still needed:
>>>
>>> http://people.redhat.com/~lersek/82a5e88f-f1e1-42e2-8462-66974c9cbfff/
>>
>> Thank you. I ran your QEMU_EFI.fd with gic_version=3 and UEFI and
>> FreeBSD start up successfully (as expected, based on the discussion in
>> this thread).
>>
>> It sounds like we'll need to build a hacked UEFI build as Peter
>> Maydell suggested in order to actually test a FreeBSD fix when we have
>> it.
>
> Ah, sorry, I failed to understand this nuance from the discussion
> (although I quoted it myself -- sorry I'm not having a great day today).
> So apparently you need a recent enough firmware binary that *starts*
> with gicv3, but doesn't configure the gicv3 as otherwise needed, so you
> can reproduce the FreeBSD bug, and verify the FreeBSD bugfix, while
> booting with UEFI.
>
> Ard's patch has just been committed to upstream edk2 (c7fefb690661 --
> <https://github.com/tianocore/edk2/commits/master>), but I can build a
> binary for you right before it (at
> bf57a42a0e2cf1c68e9db2f61c82ce93c806ab07)...
>
> http://people.redhat.com/~lersek/82a5e88f-f1e1-42e2-8462-66974c9cbfff/QEMU_EFI.fd.bf57a42a0e2c
>

Thanks, but that image will never make it to the FreeBSD bootloader,
given that it requires the GIC to be operational.

It should not be that difficult to revert the changes to the GIC
registers that my patch adds when it hands over to the OS loader, but
if the FreeBSD code then simply pokes the same values into the same
registers, I am not convinced this is a useful test case. The fact
that FreeBSD can only load via UEFI actually suggests that it may not
require this fix in the first place, since UEFI is guaranteed to leave
the GIC in a usable state for the OS if it runs from the same
exception level, and there are no other boot methods supported by
FreeBSD on AArch64

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-23 20:03                   ` Ard Biesheuvel
@ 2016-06-23 20:33                     ` Peter Maydell
  2016-06-24  8:16                       ` Ard Biesheuvel
  0 siblings, 1 reply; 64+ messages in thread
From: Peter Maydell @ 2016-06-23 20:33 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: Laszlo Ersek, Ed Maste, QEMU Developers

On 23 June 2016 at 21:03, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> UEFI is guaranteed to leave
> the GIC in a usable state for the OS if it runs from the same
> exception level

For a no-security-extensions system, leaving the interrupts
in Group 0 is still "a usable state for the OS", because
the OS will receive FIQ (and if it doesn't want the
interrupts to be FIQ it's able to reconfigure them).
Does the UEFI contract with the OS specifically guarantee
group 1, or does it just guarantee "anything that the OS
can't set up itself will be set up" ?

(for instance a future version of UEFI could hypothetically
decide to run its timer interrupt as Group 0 via FIQ.)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/20] GICv3 emulation
  2016-06-23 20:33                     ` Peter Maydell
@ 2016-06-24  8:16                       ` Ard Biesheuvel
  0 siblings, 0 replies; 64+ messages in thread
From: Ard Biesheuvel @ 2016-06-24  8:16 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Laszlo Ersek, Ed Maste, QEMU Developers

On 23 June 2016 at 22:33, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 23 June 2016 at 21:03, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>> UEFI is guaranteed to leave
>> the GIC in a usable state for the OS if it runs from the same
>> exception level
>
> For a no-security-extensions system, leaving the interrupts
> in Group 0 is still "a usable state for the OS", because
> the OS will receive FIQ (and if it doesn't want the
> interrupts to be FIQ it's able to reconfigure them).
> Does the UEFI contract with the OS specifically guarantee
> group 1, or does it just guarantee "anything that the OS
> can't set up itself will be set up" ?
>

The UEFI spec does not define anything beyond

"""
Use the highest 64 bit non secure privilege level available;
Non-secure EL2 (Hyp) or Non-
secure EL1(Kernel).
"""

and it is implied (although not mentioned specifically) that the OS is
invoked at the same exception level that UEFI runs at, and so UEFI is
not expected to run in a context where it can configure GIC state that
the OS will not be able to configure for itself.

> (for instance a future version of UEFI could hypothetically
> decide to run its timer interrupt as Group 0 via FIQ.)
>

Unlikely, but true.

So you are right: the spec does not cover the GIC state at the
handover point to the OS, and so the OS should equally be able to cope
with configurations that require it to perform configuration on the
GIC that it wouldn't have to do when running on the non-secure side of
a system that implements EL3, even if we know that the OS will only
ever boot via UEFI.

-- 
Ard.

^ permalink raw reply	[flat|nested] 64+ messages in thread

end of thread, other threads:[~2016-06-24  8:16 UTC | newest]

Thread overview: 64+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-14 14:38 [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 01/20] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 02/20] bitops.h: Implement half-shuffle and half-unshuffle ops Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 03/20] target-arm: Define new arm_is_el3_or_mon() function Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 04/20] target-arm: Provide hook to tell GICv3 about changes of security state Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 05/20] target-arm: Add mp-affinity property for ARM CPU class Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 06/20] hw/intc/arm_gicv3: Add state information Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 07/20] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 08/20] hw/intc/arm_gicv3: Add vmstate descriptors Peter Maydell
2016-06-15  2:30   ` Shannon Zhao
2016-06-16  2:12   ` Shannon Zhao
2016-06-16 14:23     ` Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 09/20] hw/intc/arm_gicv3: ARM GICv3 device framework Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 10/20] hw/intc/arm_gicv3: Implement functions to identify next pending irq Peter Maydell
2016-06-15  2:35   ` Shannon Zhao
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 11/20] hw/intc/arm_gicv3: Implement GICv3 distributor registers Peter Maydell
2016-06-15  2:36   ` Shannon Zhao
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 12/20] hw/intc/arm_gicv3: Implement GICv3 redistributor registers Peter Maydell
2016-06-15  2:42   ` Shannon Zhao
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 13/20] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 14/20] hw/intc/arm_gicv3: Implement gicv3_set_irq() Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 15/20] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers Peter Maydell
2016-06-15  2:45   ` Shannon Zhao
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 16/20] hw/intc/arm_gicv3: Implement gicv3_cpuif_update() Peter Maydell
2016-06-15  2:47   ` Shannon Zhao
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 17/20] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 18/20] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers Peter Maydell
2016-06-15  3:15   ` Shannon Zhao
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 19/20] target-arm/machine.c: Allow user to request GICv3 emulation Peter Maydell
2016-06-14 14:38 ` [Qemu-devel] [PATCH v3 20/20] target-arm/monitor.c: Advertise emulated GICv3 in capabilities Peter Maydell
2016-06-15  2:52 ` [Qemu-devel] [PATCH v3 00/20] GICv3 emulation Shannon Zhao
2016-06-15  8:53 ` Shannon Zhao
2016-06-15  9:20   ` Andrew Jones
2016-06-15 10:06     ` Peter Maydell
2016-06-15 10:10       ` Peter Maydell
2016-06-15 14:02         ` Shannon Zhao
2016-06-15 14:06           ` Peter Maydell
2016-06-16  2:17         ` Shannon Zhao
2016-06-22 18:09         ` Ed Maste
2016-06-22 20:53           ` Peter Maydell
2016-06-22 21:45             ` Ed Maste
2016-06-22 21:56               ` Peter Maydell
2016-06-23  1:42               ` Shannon Zhao
2016-06-23 11:36             ` Laszlo Ersek
2016-06-23 12:07               ` Andrew Jones
2016-06-23 14:18               ` Ed Maste
2016-06-23 14:52                 ` Laszlo Ersek
2016-06-23 20:03                   ` Ard Biesheuvel
2016-06-23 20:33                     ` Peter Maydell
2016-06-24  8:16                       ` Ard Biesheuvel
2016-06-21 14:45   ` Andrew Jones
2016-06-21 14:55     ` Peter Maydell
2016-06-21 15:12       ` Andrew Jones
2016-06-21 17:15         ` Andrew Jones
2016-06-21 17:17           ` Peter Maydell
2016-06-21 17:18           ` Andrew Jones
2016-06-21 17:21             ` Peter Maydell
2016-06-21 19:45               ` Laszlo Ersek
2016-06-21 19:53                 ` Peter Maydell
2016-06-22  1:42                   ` Shannon Zhao
2016-06-22  7:43                     ` Andrew Jones
2016-06-22  8:27                       ` Shannon Zhao
2016-06-22  9:09                         ` Andrew Jones
2016-06-22 15:23                           ` Laszlo Ersek

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.