All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/22] GICv3 emulation
@ 2016-05-26 14:55 Peter Maydell
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 01/22] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
                   ` (23 more replies)
  0 siblings, 24 replies; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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)

I have included the "support KVM save/restore" patches from Pavel,
reworked to use the new data structures, but they are only RFC
status because the kernel API is not yet final (there are a couple
of loose threads there to be followed up). Those patches are at the
end of the series; I think everything else is in a commitable state
(give or take code review).

Testing: I have confirmed that we can boot a Linux guest kernel,
but not tried any other GIC-using guest code. I've done some light
stress-testing using 'stress', and checked an SMP (2-cpu) boot.
I've also tested booting a guest kernel via UEFI.

Design: all the code here is in hw/intc/, split into several
files to avoid them being huge. The interface between the CPU
proper and the CPU interface is a bit ad-hoc (you can see the
awkward seams that result from the choice to think of the cpu
i/f as part of the GIC device rather than part of the CPU itself),
but I think that if you put the cpu i/f in the CPU you'd end up
with an ad-hoc interface and awkward seams in the other direction.
The GICv3 device currently assumes it is always connected to all
CPUs; we can change that later to allow some kind of QOM link
property to specify the CPUs explicitly, but I think this is OK
for now (and it's already a pretty huge set of code changes to
have to review).

Code review, testing, attempts to run guests other than Linux
welcome.

Changes v1->v2:
 * I have dropped the kernel bug workaround, since it didn't work for
   boots via UEFI anyway. This means that you will need kernel commit
   7c9b973061b0 (or its equivalent backports to stable) to boot a Linux
   guest with this emulated GICv3
 * make bitmaps and arrays be GIC_MAXIRQS in size rather than
   GIC_MAXSPIS in size; this uses an extra 512 bytes or so per
   vcpu, but makes bugs of the "forgot to add/subtract GIC_INTERNAL"
   variety less likely to happen (and indeed a few were found and fixed
   in making this change...)
 * fixed GICD_CTLR NS read to use correct bitmask
 * moved ARMELChangeHook related prototypes etc into cpu.h from cpu-qom.h
   (needed after Paolo's recent header reshuffles)
 * added missing 'inline' qualifier to arm_is_el3_or_mon()
 * fixed missing reset of GICD_NSACR
 * fixed icc_activate_irq() to call gicv3_redist_update() rather than
   gicv3_update() when it changes redistributor state
 * make sure (and assert) gicv3_update() isn't called for out of range irqs
 * add missing "bad num_irqs values" checks from gicv2 code

thanks
-- PMM



Pavel Fedin (5):
  target-arm: Add mp-affinity property for ARM CPU class
  hw/intc/arm_gicv3: Add state information
  hw/intc/arm_gicv3: Add vmstate descriptors
  NOT-FOR-UPSTREAM: kernel: Add definitions for GICv3 attributes
  RFC: hw/intc/arm_gicv3_kvm: Implement get/put functions

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           |  873 +++++++++++++++++++++++
 hw/intc/arm_gicv3_kvm.c            |  447 +++++++++++-
 hw/intc/arm_gicv3_redist.c         |  556 +++++++++++++++
 hw/intc/gicv3_internal.h           |  331 +++++++++
 include/hw/intc/arm_gicv3.h        |   32 +
 include/hw/intc/arm_gicv3_common.h |  216 +++++-
 include/migration/vmstate.h        |    6 +
 include/qemu/bitops.h              |  108 +++
 linux-headers/asm-arm64/kvm.h      |   17 +-
 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                |   68 ++
 trace-events                       |   41 ++
 22 files changed, 4719 insertions(+), 28 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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 01/22] migration: Define VMSTATE_UINT64_2DARRAY
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-07  3:32   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 02/22] bitops.h: Implement half-shuffle and half-unshuffle ops Peter Maydell
                   ` (22 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 include/migration/vmstate.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 30ecc44..aec9531 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -846,6 +846,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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 02/22] bitops.h: Implement half-shuffle and half-unshuffle ops
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 01/22] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-07  6:35   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 03/22] target-arm: Define new arm_is_el3_or_mon() function Peter Maydell
                   ` (21 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 include/qemu/bitops.h | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/test-bitops.c   |  68 +++++++++++++++++++++++++++++++
 2 files changed, 176 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 5050950..353fc98 100644
--- a/tests/test-bitops.c
+++ b/tests/test-bitops.c
@@ -66,10 +66,78 @@ 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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 03/22] target-arm: Define new arm_is_el3_or_mon() function
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 01/22] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 02/22] bitops.h: Implement half-shuffle and half-unshuffle ops Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-07  6:32   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 04/22] target-arm: Provide hook to tell GICv3 about changes of security state Peter Maydell
                   ` (20 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 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 c741b53..2fa1f41 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1133,8 +1133,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) {
@@ -1146,6 +1146,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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 04/22] target-arm: Provide hook to tell GICv3 about changes of security state
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (2 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 03/22] target-arm: Define new arm_is_el3_or_mon() function Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-14  1:49   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 05/22] target-arm: Add mp-affinity property for ARM CPU class Peter Maydell
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 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 2fa1f41..9b045af 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -504,6 +504,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
  *
@@ -641,6 +648,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)
@@ -2373,4 +2383,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 e3ea26f..d907598 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -6496,6 +6496,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 a125873..5d8ec43 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 0b29b9d..8021738 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -437,6 +437,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.  */
@@ -932,6 +934,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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 05/22] target-arm: Add mp-affinity property for ARM CPU class
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (3 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 04/22] target-arm: Provide hook to tell GICv3 about changes of security state Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-07  7:55   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 06/22] hw/intc/arm_gicv3: Add state information Peter Maydell
                   ` (18 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 06/22] hw/intc/arm_gicv3: Add state information
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (4 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 05/22] target-arm: Add mp-affinity property for ARM CPU class Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-07  7:51   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 07/22] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure Peter Maydell
                   ` (17 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 hw/intc/arm_gicv3_common.c         | 159 +++++++++++++++++++++++++++++-
 hw/intc/gicv3_internal.h           | 172 +++++++++++++++++++++++++++++++++
 include/hw/intc/arm_gicv3_common.h | 193 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 519 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..6d4327b 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,144 @@
 #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)
+#define GIC_BIT(nr) (1U << (nr))
+
+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 +179,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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 07/22] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (5 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 06/22] hw/intc/arm_gicv3: Add state information Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-07  8:33   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 08/22] hw/intc/arm_gicv3: Add vmstate descriptors Peter Maydell
                   ` (16 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 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 6d4327b..f01b616 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -135,6 +135,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 */
@@ -169,9 +171,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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 08/22] hw/intc/arm_gicv3: Add vmstate descriptors
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (6 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 07/22] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 09/22] hw/intc/arm_gicv3: ARM GICv3 device framework Peter Maydell
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 09/22] hw/intc/arm_gicv3: ARM GICv3 device framework
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (7 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 08/22] hw/intc/arm_gicv3: Add vmstate descriptors Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-07  9:01   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 10/22] hw/intc/arm_gicv3: Implement functions to identify next pending irq Peter Maydell
                   ` (14 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 10/22] hw/intc/arm_gicv3: Implement functions to identify next pending irq
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (8 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 09/22] hw/intc/arm_gicv3: ARM GICv3 device framework Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-08  1:57   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 11/22] hw/intc/arm_gicv3: Implement GICv3 distributor registers Peter Maydell
                   ` (13 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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..7c4bee6 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 redistributor 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..35c3c11 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);
+
+    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 f01b616..3ca0c9c 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -132,6 +132,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;
@@ -164,6 +170,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 {
@@ -199,6 +213,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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 11/22] hw/intc/arm_gicv3: Implement GICv3 distributor registers
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (9 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 10/22] hw/intc/arm_gicv3: Implement functions to identify next pending irq Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-13  6:27   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 12/22] hw/intc/arm_gicv3: Implement GICv3 redistributor registers Peter Maydell
                   ` (12 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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 | 852 +++++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/gicv3_internal.h |   4 +
 trace-events             |   6 +
 4 files changed, 863 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..6ccb4d9
--- /dev/null
+++ b/hw/intc/arm_gicv3_dist.c
@@ -0,0 +1,852 @@
+/*
+ * 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 (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) {
+            *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 (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) {
+            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 35c3c11..1f901ca 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 4450d8f..be67121 100644
--- a/trace-events
+++ b/trace-events
@@ -1916,3 +1916,9 @@ gic_set_irq(int irq, int level, int cpumask, int target) "irq %d level %d cpumas
 gic_update_bestirq(int cpu, int irq, int prio, int priority_mask, int running_priority) "cpu %d irq %d priority %d cpu priority mask %d cpu running priority %d"
 gic_update_set_irq(int cpu, const char *name, int level) "cpu[%d]: %s = %d"
 gic_acknowledge_irq(int cpu, int irq) "cpu %d acknowledged 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"
+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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 12/22] hw/intc/arm_gicv3: Implement GICv3 redistributor registers
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (10 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 11/22] hw/intc/arm_gicv3: Implement GICv3 distributor registers Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-14  3:09   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 13/22] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions Peter Maydell
                   ` (11 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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 | 495 +++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/gicv3_internal.h   |   4 +
 trace-events               |   6 +
 4 files changed, 506 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..18dc0c8
--- /dev/null
+++ b/hw/intc/arm_gicv3_redist.c
@@ -0,0 +1,495 @@
+/*
+ * 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 (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
+            *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 (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
+            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 1f901ca..39196fa 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 be67121..308d458 100644
--- a/trace-events
+++ b/trace-events
@@ -1922,3 +1922,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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 13/22] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (11 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 12/22] hw/intc/arm_gicv3: Implement GICv3 redistributor registers Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-13  7:19   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 14/22] hw/intc/arm_gicv3: Implement gicv3_set_irq() Peter Maydell
                   ` (10 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 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 7c4bee6..e8f6766 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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 14/22] hw/intc/arm_gicv3: Implement gicv3_set_irq()
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (12 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 13/22] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-13  7:49   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 15/22] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers Peter Maydell
                   ` (9 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 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 e8f6766..e770409 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 >= 16 && irq < 32);
+        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 6ccb4d9..1634974 100644
--- a/hw/intc/arm_gicv3_dist.c
+++ b/hw/intc/arm_gicv3_dist.c
@@ -850,3 +850,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 18dc0c8..16b3422 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -493,3 +493,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 39196fa..8ae6d66 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 308d458..c006723 100644
--- a/trace-events
+++ b/trace-events
@@ -1922,9 +1922,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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 15/22] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (13 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 14/22] hw/intc/arm_gicv3: Implement gicv3_set_irq() Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 16/22] hw/intc/arm_gicv3: Implement gicv3_cpuif_update() Peter Maydell
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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 e770409..aa5d33f 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 8ae6d66..bd96419 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 c006723..bfc7251 100644
--- a/trace-events
+++ b/trace-events
@@ -1917,6 +1917,22 @@ gic_update_bestirq(int cpu, int irq, int prio, int priority_mask, int running_pr
 gic_update_set_irq(int cpu, const char *name, int level) "cpu[%d]: %s = %d"
 gic_acknowledge_irq(int cpu, int irq) "cpu %d acknowledged irq %d"
 
+# 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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 16/22] hw/intc/arm_gicv3: Implement gicv3_cpuif_update()
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (14 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 15/22] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-13  7:56   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 17/22] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers Peter Maydell
                   ` (7 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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 bd96419..d06ef3e 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 bfc7251..e84cea9 100644
--- a/trace-events
+++ b/trace-events
@@ -1932,6 +1932,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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 17/22] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (15 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 16/22] hw/intc/arm_gicv3: Implement gicv3_cpuif_update() Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-14  6:24   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 18/22] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers Peter Maydell
                   ` (6 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 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 16b3422..13893d3 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)
 {
@@ -514,3 +521,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 d06ef3e..561849c 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 e84cea9..762f5a0 100644
--- a/trace-events
+++ b/trace-events
@@ -1934,6 +1934,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"
@@ -1948,3 +1949,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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 18/22] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (16 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 17/22] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 19/22] target-arm/machine.c: Allow user to request GICv3 emulation Peter Maydell
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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 561849c..fadd42d 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 762f5a0..6a9c7a8 100644
--- a/trace-events
+++ b/trace-events
@@ -1935,6 +1935,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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 19/22] target-arm/machine.c: Allow user to request GICv3 emulation
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (17 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 18/22] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-13 11:38   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 20/22] target-arm/monitor.c: Advertise emulated GICv3 in capabilities Peter Maydell
                   ` (4 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 20/22] target-arm/monitor.c: Advertise emulated GICv3 in capabilities
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (18 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 19/22] target-arm/machine.c: Allow user to request GICv3 emulation Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-13 11:40   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 21/22] NOT-FOR-UPSTREAM: kernel: Add definitions for GICv3 attributes Peter Maydell
                   ` (3 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, 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>
---
 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] 51+ messages in thread

* [Qemu-devel] [PATCH v2 21/22] NOT-FOR-UPSTREAM: kernel: Add definitions for GICv3 attributes
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (19 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 20/22] target-arm/monitor.c: Advertise emulated GICv3 in capabilities Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-06-13 11:51   ` Shannon Zhao
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 22/22] RFC: hw/intc/arm_gicv3_kvm: Implement get/put functions Peter Maydell
                   ` (2 subsequent siblings)
  23 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

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

This temporary patch adds kernel API definitions. Use proper header update
procedure after these features are released.

FIXME: not-for-upstream

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
 linux-headers/asm-arm64/kvm.h | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index 7d82d1f..c0924c4 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -180,14 +180,14 @@ struct kvm_arch_memory_slot {
 	KVM_REG_ARM64_SYSREG_ ## n ## _MASK)
 
 #define __ARM64_SYS_REG(op0,op1,crn,crm,op2) \
-	(KVM_REG_ARM64 | KVM_REG_ARM64_SYSREG | \
-	ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \
+	(ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \
 	ARM64_SYS_REG_SHIFT_MASK(op1, OP1) | \
 	ARM64_SYS_REG_SHIFT_MASK(crn, CRN) | \
 	ARM64_SYS_REG_SHIFT_MASK(crm, CRM) | \
 	ARM64_SYS_REG_SHIFT_MASK(op2, OP2))
 
-#define ARM64_SYS_REG(...) (__ARM64_SYS_REG(__VA_ARGS__) | KVM_REG_SIZE_U64)
+#define ARM64_SYS_REG(...) (__ARM64_SYS_REG(__VA_ARGS__) | KVM_REG_ARM64 | \
+			    KVM_REG_SIZE_U64 | KVM_REG_ARM64_SYSREG)
 
 #define KVM_REG_ARM_TIMER_CTL		ARM64_SYS_REG(3, 3, 14, 3, 1)
 #define KVM_REG_ARM_TIMER_CNT		ARM64_SYS_REG(3, 3, 14, 3, 2)
@@ -198,12 +198,21 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
 #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
 #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
-#define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
+#define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
 #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
 #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
 #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
+#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
+#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
+#define   KVM_DEV_ARM_VGIC_SYSREG_MASK	(KVM_REG_ARM64_SYSREG_OP0_MASK | \
+					 KVM_REG_ARM64_SYSREG_OP1_MASK | \
+					 KVM_REG_ARM64_SYSREG_CRN_MASK | \
+					 KVM_REG_ARM64_SYSREG_CRM_MASK | \
+					 KVM_REG_ARM64_SYSREG_OP2_MASK)
+#define   KVM_DEV_ARM_VGIC_SYSREG(op0,op1,crn,crm,op2) \
+					__ARM64_SYS_REG(op0,op1,crn,crm,op2)
 
 /* Device Control API on vcpu fd */
 #define KVM_ARM_VCPU_PMU_V3_CTRL	0
-- 
1.9.1

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

* [Qemu-devel] [PATCH v2 22/22] RFC: hw/intc/arm_gicv3_kvm: Implement get/put functions
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (20 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 21/22] NOT-FOR-UPSTREAM: kernel: Add definitions for GICv3 attributes Peter Maydell
@ 2016-05-26 14:55 ` Peter Maydell
  2016-05-30 11:15 ` [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Andrew Jones
  2016-06-06 14:42 ` [Qemu-devel] [Qemu-arm] " Peter Maydell
  23 siblings, 0 replies; 51+ messages in thread
From: Peter Maydell @ 2016-05-26 14:55 UTC (permalink / raw)
  To: qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

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

This actually implements pre_save and post_load methods for in-kernel
vGICv3.

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
[PMM:
 * use decimal, not 0bnnn
 * fixed typo in names of ICC_APR0R_EL1 and ICC_AP1R_EL1
 * completely rearranged the get and put functions to read and write
   the state in a natural order, rather than mixing distributor and
   redistributor state together]

FIXME: the kernel API is not final yet, so this can't be committed yet.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/arm_gicv3_kvm.c | 452 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 442 insertions(+), 10 deletions(-)

diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index d08808d..87d096e 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -23,8 +23,11 @@
 #include "qapi/error.h"
 #include "hw/intc/arm_gicv3_common.h"
 #include "hw/sysbus.h"
+#include "migration/migration.h"
+#include "qemu/error-report.h"
 #include "sysemu/kvm.h"
 #include "kvm_arm.h"
+#include "gicv3_internal.h"
 #include "vgic_common.h"
 
 #ifdef DEBUG_GICV3_KVM
@@ -43,6 +46,23 @@
 #define KVM_ARM_GICV3_GET_CLASS(obj) \
      OBJECT_GET_CLASS(KVMARMGICv3Class, (obj), TYPE_KVM_ARM_GICV3)
 
+#define ICC_PMR_EL1     \
+    KVM_DEV_ARM_VGIC_SYSREG(3, 0, 4, 6, 0)
+#define ICC_BPR0_EL1    \
+    KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 8, 3)
+#define ICC_AP0R_EL1(n) \
+    KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 8, 4 | n)
+#define ICC_AP1R_EL1(n) \
+    KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 9, n)
+#define ICC_BPR1_EL1    \
+    KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 3)
+#define ICC_CTLR_EL1    \
+    KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 4)
+#define ICC_IGRPEN0_EL1 \
+    KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 6)
+#define ICC_IGRPEN1_EL1 \
+    KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 7)
+
 typedef struct KVMARMGICv3Class {
     ARMGICv3CommonClass parent_class;
     DeviceRealize parent_realize;
@@ -56,16 +76,422 @@ static void kvm_arm_gicv3_set_irq(void *opaque, int irq, int level)
     kvm_arm_gic_set_irq(s->num_irq, irq, level);
 }
 
+#define KVM_VGIC_ATTR(reg, typer) \
+    ((typer & 0xFFFFFFFF00000000ULL) | (reg))
+
+static inline void kvm_gicd_access(GICv3State *s, int offset,
+                                   uint64_t *val, bool write)
+{
+    kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
+                      KVM_VGIC_ATTR(offset, 0),
+                      val, write);
+}
+
+static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu,
+                                   uint64_t *val, bool write)
+{
+    kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                      KVM_VGIC_ATTR(offset, s->cpu[cpu].gicr_typer),
+                      val, write);
+}
+
+static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu,
+                                   uint64_t *val, bool write)
+{
+    kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                      KVM_VGIC_ATTR(reg, s->cpu[cpu].gicr_typer),
+                      val, write);
+}
+
+/* Translate from the in-kernel field for an IRQ value to/from the qemu
+ * representation. Note that these are only expected to be used for
+ * SPIs (that is, for interrupts whose state is in the distributor
+ * rather than the redistributor).
+ */
+typedef void (*vgic_translate_fn)(GICv3State *s, int irq,
+                                  uint32_t *field, bool to_kernel);
+
+static void translate_edge_trigger(GICv3State *s, int irq,
+    uint32_t *field, bool to_kernel)
+{
+    if (to_kernel) {                                             \
+        *field = gicv3_gicd_edge_trigger_test(s, irq);           \
+    } else {                                                     \
+        gicv3_gicd_edge_trigger_replace(s, irq, *field);         \
+    }                                                            \
+}
+
+static void translate_priority(GICv3State *s, int irq,
+                               uint32_t *field, bool to_kernel)
+{
+    if (to_kernel) {
+        *field = s->gicd_ipriority[irq];
+    } else {
+        s->gicd_ipriority[irq] = *field;
+    }
+}
+
+/* Loop through each distributor IRQ related register; since bits
+ * corresponding to SPIs and PPIs are RAZ/WI when affinity routing
+ * is enabled, we skip those.
+ */
+#define for_each_dist_irq_reg(_irq, _max, _field_width) \
+    for (_irq = GIC_INTERNAL; _irq < _max; _irq += (32 / _field_width))
+
+/* Read a register group from the kernel VGIC */
+static void kvm_dist_get(GICv3State *s, uint32_t offset, int width,
+                         vgic_translate_fn translate_fn)
+{
+    uint64_t reg;
+    int j;
+    int irq;
+    uint32_t field;
+    int regsz = 32 / width; /* irqs per kernel register */
+
+    for_each_dist_irq_reg(irq, s->num_irq, width) {
+        kvm_gicd_access(s, offset, &reg, false);
+
+        for (j = 0; j < regsz; j++) {
+            field = extract32(reg, j * width, width);
+            translate_fn(s, irq + j, &field, false);
+        }
+        offset += 4;
+    }
+}
+
+/* Write a register group to the kernel VGIC */
+static void kvm_dist_put(GICv3State *s, uint32_t offset, int width,
+                         vgic_translate_fn translate_fn)
+{
+    uint64_t reg;
+    int j;
+    int irq;
+    uint32_t field;
+    int regsz = 32 / width; /* irqs per kernel register */
+
+    for_each_dist_irq_reg(irq, s->num_irq, width) {
+        reg = 0;
+        for (j = 0; j < regsz; j++) {
+            translate_fn(s, irq + j, &field, true);
+            reg = deposit32(reg, j * width, width, field);
+        }
+        kvm_gicd_access(s, offset, &reg, true);
+        offset += 4;
+    }
+}
+
+/* Read a bitmap register group from the kernel VGIC. */
+static void kvm_dist_getbmp(GICv3State *s, uint32_t offset, uint32_t *bmp)
+{
+    uint64_t reg;
+    int irq;
+
+    for_each_dist_irq_reg(irq, s->num_irq, 1) {
+        kvm_gicd_access(s, offset, &reg, false);
+        *gic_bmp_ptr32(bmp, irq) = reg;
+        offset += 4;
+    }
+}
+
+static void kvm_dist_putbmp(GICv3State *s, uint32_t offset,
+                            uint32_t clroffset, uint32_t *bmp)
+{
+    uint64_t reg;
+    int irq;
+
+    for_each_dist_irq_reg(irq, s->num_irq, 1) {
+        /* If this bitmap is a set/clear register pair, first write to the
+         * clear-reg to clear all bits before using the set-reg to write
+         * the 1 bits.
+         */
+        if (clroffset != 0) {
+            reg = 0;
+            kvm_gicd_access(s, clroffset, &reg, true);
+        }
+        reg = *gic_bmp_ptr32(bmp, irq);
+        kvm_gicd_access(s, offset, &reg, true);
+        offset += 4;
+    }
+}
+
+static void kvm_arm_gicv3_check(GICv3State *s)
+{
+    uint64_t reg;
+    uint32_t num_irq;
+
+    /* Sanity checking s->num_irq */
+    kvm_gicd_access(s, GICD_TYPER, &reg, false);
+    num_irq = ((reg & 0x1f) + 1) * 32;
+
+    if (num_irq < s->num_irq) {
+        error_report("Model requests %u IRQs, but kernel supports max %u",
+                     s->num_irq, num_irq);
+        abort();
+    }
+}
+
 static void kvm_arm_gicv3_put(GICv3State *s)
 {
-    /* TODO */
-    DPRINTF("Cannot put kernel gic state, no kernel interface\n");
+    uint64_t reg, redist_typer;
+    int ncpu, i;
+
+    kvm_arm_gicv3_check(s);
+
+    kvm_gicr_access(s, GICR_TYPER, 0, &redist_typer, false);
+
+    reg = s->gicd_ctlr;
+    kvm_gicd_access(s, GICD_CTLR, &reg, true);
+
+    if (redist_typer & GICR_TYPER_PLPIS) {
+        /* Set base addresses before LPIs are enabled by GICR_CTLR write */
+        for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+            GICv3CPUState *c = &s->cpu[ncpu];
+
+            reg = c->gicr_propbaser;
+            kvm_gicr_access(s, GICR_PROPBASER, ncpu, &reg, true);
+
+            reg = c->gicr_pendbaser;
+            if (!c->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) {
+                /* Setting PTZ is advised if LPIs are disabled, to reduce
+                 * GIC initialization time.
+                 */
+                reg |= GICR_PENDBASER_PTZ;
+            }
+            kvm_gicr_access(s, GICR_PENDBASER, ncpu, &reg, true);
+        }
+    }
+
+    /* Redistributor state (one per CPU) */
+
+    for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+        GICv3CPUState *c = &s->cpu[ncpu];
+
+        reg = c->gicr_ctlr;
+        kvm_gicr_access(s, GICR_CTLR, ncpu, &reg, true);
+
+        reg = c->gicr_statusr[GICV3_NS];
+        kvm_gicr_access(s, GICR_STATUSR, ncpu, &reg, true);
+
+        reg = c->gicr_waker;
+        kvm_gicr_access(s, GICR_WAKER, ncpu, &reg, true);
+
+        reg = c->gicr_igroupr0;
+        kvm_gicr_access(s, GICR_IGROUPR0, ncpu, &reg, true);
+
+        reg = ~0;
+        kvm_gicr_access(s, GICR_ICENABLER0, ncpu, &reg, true);
+        reg = c->gicr_ienabler0;
+        kvm_gicr_access(s, GICR_ISENABLER0, ncpu, &reg, true);
+
+        /* Restore config before pending so we treat level/edge correctly */
+        reg = half_shuffle32(c->edge_trigger >> 16) << 1;
+        kvm_gicr_access(s, GICR_ICFGR1, ncpu, &reg, true);
+
+        // TODO: there is no kernel API for reading/writing c->level
+
+        reg = ~0;
+        kvm_gicr_access(s, GICR_ICPENDR0, ncpu, &reg, true);
+        reg = c->gicr_ipendr0;
+        kvm_gicr_access(s, GICR_ISPENDR0, ncpu, &reg, true);
+
+        reg = ~0;
+        kvm_gicr_access(s, GICR_ICACTIVER0, ncpu, &reg, true);
+        reg = c->gicr_iactiver0;
+        kvm_gicr_access(s, GICR_ISACTIVER0, ncpu, &reg, true);
+
+        for (i = 0; i < GIC_INTERNAL; i += 4) {
+            reg = c->gicr_ipriorityr[i] |
+                (c->gicr_ipriorityr[i + 1] << 8) |
+                (c->gicr_ipriorityr[i + 2] << 16) |
+                (c->gicr_ipriorityr[i + 3] << 24);
+            kvm_gicr_access(s, GICR_IPRIORITYR + i, ncpu, &reg, true);
+        }
+    }
+
+    /* Distributor state (shared between all CPUs */
+
+    reg = s->gicd_statusr[GICV3_NS];
+    kvm_gicd_access(s, GICD_STATUSR, &reg, true);
+
+    /* s->enable bitmap -> GICD_ISENABLERn */
+    kvm_dist_putbmp(s, GICD_ISENABLER, GICD_ICENABLER, s->enabled);
+
+    /* s->group bitmap -> GICD_IGROUPRn */
+    kvm_dist_putbmp(s, GICD_IGROUPR, 0, s->group);
+
+    /* Restore targets before pending to ensure the pending state is set on
+     * the appropriate CPU interfaces in the kernel
+     */
+
+    /* s->gicd_irouter[irq] -> GICD_IROUTERn
+     * We can't use kvm_dist_put() here because the registers are 64-bit
+     */
+    for (i = GIC_INTERNAL; i < s->num_irq; i++) {
+        uint32_t offset = GICD_IROUTER + (sizeof(uint64_t) * i);
+
+        kvm_gicd_access(s, offset, &s->gicd_irouter[i], true);
+    }
+
+    /* s->trigger bitmap -> GICD_ICFGRn
+     * (restore configuration registers before pending IRQs so we treat
+     * level/edge correctly)
+     */
+    kvm_dist_put(s, GICD_ICFGR, 2, translate_edge_trigger);
+
+    // TODO: there is no kernel API for reading/writing s->level
+
+    /* s->pending bitmap -> GICD_ISPENDRn */
+    kvm_dist_putbmp(s, GICD_ISPENDR, GICD_ICPENDR, s->pending);
+
+    /* s->active bitmap -> GICD_ISACTIVERn */
+    kvm_dist_putbmp(s, GICD_ISACTIVER, GICD_ICACTIVER, s->active);
+
+    /* s->gicd_ipriority[] -> GICD_IPRIORITYRn */
+    kvm_dist_put(s, GICD_IPRIORITYR, 8, translate_priority);
+
+    /* CPU Interface state (one per CPU) */
+
+    for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+        GICv3CPUState *c = &s->cpu[ncpu];
+
+        kvm_gicc_access(s, ICC_CTLR_EL1, ncpu,
+                        &c->icc_ctlr_el1[GICV3_NS], true);
+        kvm_gicc_access(s, ICC_IGRPEN0_EL1, ncpu,
+                        &c->icc_igrpen[GICV3_G0], true);
+        kvm_gicc_access(s, ICC_IGRPEN1_EL1, ncpu,
+                        &c->icc_igrpen[GICV3_G1NS], true);
+        kvm_gicc_access(s, ICC_PMR_EL1, ncpu, &c->icc_pmr_el1, true);
+        kvm_gicc_access(s, ICC_BPR0_EL1, ncpu, &c->icc_bpr[GICV3_G0], true);
+        kvm_gicc_access(s, ICC_BPR1_EL1, ncpu, &c->icc_bpr[GICV3_G1NS], true);
+
+        for (i = 0; i < 4; i++) {
+            reg = c->icc_apr[GICV3_G0][i];
+            kvm_gicc_access(s, ICC_AP0R_EL1(i), ncpu, &reg, true);
+        }
+
+        for (i = 0; i < 4; i++) {
+            reg = c->icc_apr[GICV3_G1NS][i];
+            kvm_gicc_access(s, ICC_AP1R_EL1(i), ncpu, &reg, true);
+        }
+    }
 }
 
 static void kvm_arm_gicv3_get(GICv3State *s)
 {
-    /* TODO */
-    DPRINTF("Cannot get kernel gic state, no kernel interface\n");
+    uint64_t reg, redist_typer;
+    int ncpu, i;
+
+    kvm_arm_gicv3_check(s);
+
+    kvm_gicr_access(s, GICR_TYPER, 0, &redist_typer, false);
+
+    kvm_gicd_access(s, GICD_CTLR, &reg, false);
+    s->gicd_ctlr = reg;
+
+    /* Redistributor state (one per CPU) */
+
+    for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+        GICv3CPUState *c = &s->cpu[ncpu];
+
+        kvm_gicr_access(s, GICR_CTLR, ncpu, &reg, false);
+        c->gicr_ctlr = reg;
+
+        kvm_gicr_access(s, GICR_STATUSR, ncpu, &reg, false);
+        c->gicr_statusr[GICV3_NS] = reg;
+
+        kvm_gicr_access(s, GICR_WAKER, ncpu, &reg, false);
+        c->gicr_waker = reg;
+
+        kvm_gicr_access(s, GICR_IGROUPR0, ncpu, &reg, false);
+        c->gicr_igroupr0 = reg;
+        kvm_gicr_access(s, GICR_ISENABLER0, ncpu, &reg, false);
+        c->gicr_ienabler0 = reg;
+        kvm_gicr_access(s, GICR_ICFGR1, ncpu, &reg, false);
+        c->edge_trigger = half_unshuffle32(reg >> 1) << 16;
+        kvm_gicr_access(s, GICR_ISPENDR0, ncpu, &reg, false);
+        c->gicr_ipendr0 = reg;
+        kvm_gicr_access(s, GICR_ISACTIVER0, ncpu, &reg, false);
+        c->gicr_iactiver0 = reg;
+
+        for (i = 0; i < GIC_INTERNAL; i += 4) {
+            kvm_gicr_access(s, GICR_IPRIORITYR + i, ncpu, &reg, false);
+            c->gicr_ipriorityr[i] = extract32(reg, 0, 8);
+            c->gicr_ipriorityr[i + 1] = extract32(reg, 8, 8);
+            c->gicr_ipriorityr[i + 2] = extract32(reg, 16, 8);
+            c->gicr_ipriorityr[i + 3] = extract32(reg, 24, 8);
+        }
+    }
+
+    if (redist_typer & GICR_TYPER_PLPIS) {
+        for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+            GICv3CPUState *c = &s->cpu[ncpu];
+
+            kvm_gicr_access(s, GICR_PROPBASER, ncpu, &reg, false);
+            c->gicr_propbaser = reg;
+
+            kvm_gicr_access(s, GICR_PENDBASER, ncpu, &reg, false);
+            c->gicr_pendbaser = reg;
+        }
+    }
+
+    /* Distributor state (shared between all CPUs */
+
+    kvm_gicd_access(s, GICD_STATUSR, &reg, false);
+    s->gicd_statusr[GICV3_NS] = reg;
+
+    /* GICD_IGROUPRn -> s->group bitmap */
+    kvm_dist_getbmp(s, GICD_IGROUPR, s->group);
+
+    /* GICD_ISENABLERn -> s->enabled bitmap */
+    kvm_dist_getbmp(s, GICD_ISENABLER, s->enabled);
+
+    /* GICD_ISPENDRn -> s->pending bitmap */
+    kvm_dist_getbmp(s, GICD_ISPENDR, s->pending);
+
+    /* GICD_ISACTIVERn -> s->active bitmap */
+    kvm_dist_getbmp(s, GICD_ISACTIVER, s->active);
+
+    /* GICD_ICFGRn -> s->trigger bitmap */
+    kvm_dist_get(s, GICD_ICFGR, 2, translate_edge_trigger);
+
+    /* GICD_IPRIORITYRn -> s->gicd_ipriority[] */
+    kvm_dist_get(s, GICD_IPRIORITYR, 8, translate_priority);
+
+    /* GICD_IROUTERn -> s->gicd_irouter[irq] */
+    for (i = GIC_INTERNAL; i < s->num_irq; i++) {
+        uint32_t offset = GICD_IROUTER + (sizeof(reg) * i);
+
+        kvm_gicd_access(s, offset, &reg, false);
+        s->gicd_irouter[i] = reg;
+    }
+
+    /*****************************************************************
+     * CPU Interface(s) State
+     */
+
+    for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+        GICv3CPUState *c = &s->cpu[ncpu];
+
+        kvm_gicc_access(s, ICC_CTLR_EL1, ncpu,
+                        &c->icc_ctlr_el1[GICV3_NS], false);
+        kvm_gicc_access(s, ICC_IGRPEN0_EL1, ncpu,
+                        &c->icc_igrpen[GICV3_G0], false);
+        kvm_gicc_access(s, ICC_IGRPEN1_EL1, ncpu,
+                        &c->icc_igrpen[GICV3_G1NS], false);
+        kvm_gicc_access(s, ICC_PMR_EL1, ncpu, &c->icc_pmr_el1, false);
+        kvm_gicc_access(s, ICC_BPR0_EL1, ncpu, &c->icc_bpr[GICV3_G0], false);
+        kvm_gicc_access(s, ICC_BPR1_EL1, ncpu, &c->icc_bpr[GICV3_G1NS], false);
+
+        for (i = 0; i < 4; i++) {
+            kvm_gicc_access(s, ICC_AP0R_EL1(i), ncpu, &reg, false);
+            c->icc_apr[0][i] = reg;
+        }
+
+        for (i = 0; i < 4; i++) {
+            kvm_gicc_access(s, ICC_AP1R_EL1(i), ncpu, &reg, false);
+            c->icc_apr[1][i] = reg;
+        }
+    }
 }
 
 static void kvm_arm_gicv3_reset(DeviceState *dev)
@@ -76,6 +502,12 @@ static void kvm_arm_gicv3_reset(DeviceState *dev)
     DPRINTF("Reset\n");
 
     kgc->parent_reset(dev);
+
+    if (s->migration_blocker) {
+        DPRINTF("Cannot put kernel gic state, no kernel interface\n");
+        return;
+    }
+
     kvm_arm_gicv3_put(s);
 }
 
@@ -120,12 +552,12 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
     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);
+    if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
+                               GICD_CTLR)) {
+        error_setg(&s->migration_blocker, "This operating system kernel does "
+                                          "not support vGICv3 migration");
+        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] 51+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/22] GICv3 emulation
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (21 preceding siblings ...)
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 22/22] RFC: hw/intc/arm_gicv3_kvm: Implement get/put functions Peter Maydell
@ 2016-05-30 11:15 ` Andrew Jones
  2016-06-06 14:42 ` [Qemu-devel] [Qemu-arm] " Peter Maydell
  23 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-05-30 11:15 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, qemu-devel, patches, Shlomo Pongratz, Shlomo Pongratz,
	Pavel Fedin, Shannon Zhao, Christoffer Dall

On Thu, May 26, 2016 at 03:55:18PM +0100, 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 have included the "support KVM save/restore" patches from Pavel,
> reworked to use the new data structures, but they are only RFC
> status because the kernel API is not yet final (there are a couple
> of loose threads there to be followed up). Those patches are at the
> end of the series; I think everything else is in a commitable state
> (give or take code review).
> 
> Testing: I have confirmed that we can boot a Linux guest kernel,
> but not tried any other GIC-using guest code. I've done some light
> stress-testing using 'stress', and checked an SMP (2-cpu) boot.
> I've also tested booting a guest kernel via UEFI.
> 
> Design: all the code here is in hw/intc/, split into several
> files to avoid them being huge. The interface between the CPU
> proper and the CPU interface is a bit ad-hoc (you can see the
> awkward seams that result from the choice to think of the cpu
> i/f as part of the GIC device rather than part of the CPU itself),
> but I think that if you put the cpu i/f in the CPU you'd end up
> with an ad-hoc interface and awkward seams in the other direction.
> The GICv3 device currently assumes it is always connected to all
> CPUs; we can change that later to allow some kind of QOM link
> property to specify the CPUs explicitly, but I think this is OK
> for now (and it's already a pretty huge set of code changes to
> have to review).
> 
> Code review, testing, attempts to run guests other than Linux
> welcome.
> 
> Changes v1->v2:
>  * I have dropped the kernel bug workaround, since it didn't work for
>    boots via UEFI anyway. This means that you will need kernel commit
>    7c9b973061b0 (or its equivalent backports to stable) to boot a Linux
>    guest with this emulated GICv3
>  * make bitmaps and arrays be GIC_MAXIRQS in size rather than
>    GIC_MAXSPIS in size; this uses an extra 512 bytes or so per
>    vcpu, but makes bugs of the "forgot to add/subtract GIC_INTERNAL"
>    variety less likely to happen (and indeed a few were found and fixed
>    in making this change...)
>  * fixed GICD_CTLR NS read to use correct bitmask
>  * moved ARMELChangeHook related prototypes etc into cpu.h from cpu-qom.h
>    (needed after Paolo's recent header reshuffles)
>  * added missing 'inline' qualifier to arm_is_el3_or_mon()
>  * fixed missing reset of GICD_NSACR
>  * fixed icc_activate_irq() to call gicv3_redist_update() rather than
>    gicv3_update() when it changes redistributor state
>  * make sure (and assert) gicv3_update() isn't called for out of range irqs
>  * add missing "bad num_irqs values" checks from gicv2 code

I've lightly tested this with kvm-unit-tests (I say lightly, because
it only does IPI testing so far). Although I did try with 123 vcpus,
the max mach-virt currently supports. I'm not sure the testing is
enough to warrant any tested-by's. I mostly just advertising the
unit test, which is here
https://github.com/rhdrjones/kvm-unit-tests/commits/arm/gic

Also, below is a follow-on patch for mach-virt, which might be
of interest.

Thanks,
drew


From: Andrew Jones <drjones@redhat.com>
Date: Mon, 30 May 2016 12:58:26 +0200
Subject: [PATCH] hw/arm/virt: gicv3: use all target-list bits

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 hw/arm/virt.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index e77ed88afb8a2..753c9ff8ccd64 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1204,6 +1204,16 @@ static void machvirt_init(MachineState *machine)
         }
         cpuobj = object_new(object_class_get_name(oc));
 
+        /* Adjust MPIDR per the GIC's target-list size. */
+        if (gic_version == 3) {
+            CPUState *cs = CPU(cpuobj);
+            uint8_t Aff1 = cs->cpu_index / 16;
+            uint8_t Aff0 = cs->cpu_index % 16;
+
+            object_property_set_int(cpuobj, (Aff1 << ARM_AFF1_SHIFT) | Aff0,
+                                    "mp-affinity", NULL);
+        }
+
         /* Handle any CPU options specified by the user */
         cc->parse_features(CPU(cpuobj), cpuopts, &err);
         g_free(cpuopts);
-- 
2.4.11

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

* Re: [Qemu-devel] [Qemu-arm] [PATCH v2 00/22] GICv3 emulation
  2016-05-26 14:55 [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Peter Maydell
                   ` (22 preceding siblings ...)
  2016-05-30 11:15 ` [Qemu-devel] [PATCH v2 00/22] GICv3 emulation Andrew Jones
@ 2016-06-06 14:42 ` Peter Maydell
  23 siblings, 0 replies; 51+ messages in thread
From: Peter Maydell @ 2016-06-06 14:42 UTC (permalink / raw)
  To: qemu-arm, QEMU Developers
  Cc: Patch Tracking, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall

Ping ?

thanks
-- PMM

On 26 May 2016 at 15:55, Peter Maydell <peter.maydell@linaro.org> 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 have included the "support KVM save/restore" patches from Pavel,
> reworked to use the new data structures, but they are only RFC
> status because the kernel API is not yet final (there are a couple
> of loose threads there to be followed up). Those patches are at the
> end of the series; I think everything else is in a commitable state
> (give or take code review).
>
> Testing: I have confirmed that we can boot a Linux guest kernel,
> but not tried any other GIC-using guest code. I've done some light
> stress-testing using 'stress', and checked an SMP (2-cpu) boot.
> I've also tested booting a guest kernel via UEFI.
>
> Design: all the code here is in hw/intc/, split into several
> files to avoid them being huge. The interface between the CPU
> proper and the CPU interface is a bit ad-hoc (you can see the
> awkward seams that result from the choice to think of the cpu
> i/f as part of the GIC device rather than part of the CPU itself),
> but I think that if you put the cpu i/f in the CPU you'd end up
> with an ad-hoc interface and awkward seams in the other direction.
> The GICv3 device currently assumes it is always connected to all
> CPUs; we can change that later to allow some kind of QOM link
> property to specify the CPUs explicitly, but I think this is OK
> for now (and it's already a pretty huge set of code changes to
> have to review).
>
> Code review, testing, attempts to run guests other than Linux
> welcome.
>
> Changes v1->v2:
>  * I have dropped the kernel bug workaround, since it didn't work for
>    boots via UEFI anyway. This means that you will need kernel commit
>    7c9b973061b0 (or its equivalent backports to stable) to boot a Linux
>    guest with this emulated GICv3
>  * make bitmaps and arrays be GIC_MAXIRQS in size rather than
>    GIC_MAXSPIS in size; this uses an extra 512 bytes or so per
>    vcpu, but makes bugs of the "forgot to add/subtract GIC_INTERNAL"
>    variety less likely to happen (and indeed a few were found and fixed
>    in making this change...)
>  * fixed GICD_CTLR NS read to use correct bitmask
>  * moved ARMELChangeHook related prototypes etc into cpu.h from cpu-qom.h
>    (needed after Paolo's recent header reshuffles)
>  * added missing 'inline' qualifier to arm_is_el3_or_mon()
>  * fixed missing reset of GICD_NSACR
>  * fixed icc_activate_irq() to call gicv3_redist_update() rather than
>    gicv3_update() when it changes redistributor state
>  * make sure (and assert) gicv3_update() isn't called for out of range irqs
>  * add missing "bad num_irqs values" checks from gicv2 code
>
> thanks
> -- PMM
>
>
>
> Pavel Fedin (5):
>   target-arm: Add mp-affinity property for ARM CPU class
>   hw/intc/arm_gicv3: Add state information
>   hw/intc/arm_gicv3: Add vmstate descriptors
>   NOT-FOR-UPSTREAM: kernel: Add definitions for GICv3 attributes
>   RFC: hw/intc/arm_gicv3_kvm: Implement get/put functions
>
> 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           |  873 +++++++++++++++++++++++
>  hw/intc/arm_gicv3_kvm.c            |  447 +++++++++++-
>  hw/intc/arm_gicv3_redist.c         |  556 +++++++++++++++
>  hw/intc/gicv3_internal.h           |  331 +++++++++
>  include/hw/intc/arm_gicv3.h        |   32 +
>  include/hw/intc/arm_gicv3_common.h |  216 +++++-
>  include/migration/vmstate.h        |    6 +
>  include/qemu/bitops.h              |  108 +++
>  linux-headers/asm-arm64/kvm.h      |   17 +-
>  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                |   68 ++
>  trace-events                       |   41 ++
>  22 files changed, 4719 insertions(+), 28 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] 51+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/22] migration: Define VMSTATE_UINT64_2DARRAY
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 01/22] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
@ 2016-06-07  3:32   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-07  3:32 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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 30ecc44..aec9531 100644
> --- a/include/migration/vmstate.h
> +++ b/include/migration/vmstate.h
> @@ -846,6 +846,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)
>  
> 

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 03/22] target-arm: Define new arm_is_el3_or_mon() function
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 03/22] target-arm: Define new arm_is_el3_or_mon() function Peter Maydell
@ 2016-06-07  6:32   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-07  6:32 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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 c741b53..2fa1f41 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -1133,8 +1133,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) {
> @@ -1146,6 +1146,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);
>  }
>  
> 

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 02/22] bitops.h: Implement half-shuffle and half-unshuffle ops
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 02/22] bitops.h: Implement half-shuffle and half-unshuffle ops Peter Maydell
@ 2016-06-07  6:35   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-07  6:35 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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>
> ---
>  include/qemu/bitops.h | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  tests/test-bitops.c   |  68 +++++++++++++++++++++++++++++++
>  2 files changed, 176 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 5050950..353fc98 100644
> --- a/tests/test-bitops.c
> +++ b/tests/test-bitops.c
> @@ -66,10 +66,78 @@ static void test_sextract64(void)
>      }
>  }
>  
> +typedef struct {
> +    uint32_t unshuffled;
> +    uint32_t shuffled;
> +} Shuffle32Test;
> +
> +typedef struct {
> +    uint64_t unshuffled;
> +    uint64_t shuffled;
> +} Shuffle64Test;blank line
> +
> +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;
Miss blank line here and below.
Otherwise,
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>

> +    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();
>  }
> 

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 06/22] hw/intc/arm_gicv3: Add state information
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 06/22] hw/intc/arm_gicv3: Add state information Peter Maydell
@ 2016-06-07  7:51   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-07  7:51 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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>
[...]
> +#define GIC_BIT_MASK(nr) (1U << ((nr) % 32))
> +#define GIC_BIT_WORD(nr) ((nr) / 32)
> +#define GIC_BIT(nr) (1U << (nr))
It seems the GIC_BIT(nr) is not used.

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

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 05/22] target-arm: Add mp-affinity property for ARM CPU class
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 05/22] target-arm: Add mp-affinity property for ARM CPU class Peter Maydell
@ 2016-06-07  7:55   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-07  7:55 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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()
>  };
>  
> 

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 07/22] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 07/22] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure Peter Maydell
@ 2016-06-07  8:33   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-07  8:33 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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 6d4327b..f01b616 100644
> --- a/include/hw/intc/arm_gicv3_common.h
> +++ b/include/hw/intc/arm_gicv3_common.h
> @@ -135,6 +135,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 */
> @@ -169,9 +171,6 @@ struct GICv3State {
>      SysBusDevice parent_obj;
>      /*< public >*/
>  
> -    qemu_irq *parent_irq;
> -    qemu_irq *parent_fiq;
> -
>      MemoryRegion iomem_dist; /* Distributor */
>      MemoryRegion iomem_redist; /* Redistributors */
>  
> 

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 09/22] hw/intc/arm_gicv3: ARM GICv3 device framework
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 09/22] hw/intc/arm_gicv3: ARM GICv3 device framework Peter Maydell
@ 2016-06-07  9:01   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-07  9:01 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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
> 

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 10/22] hw/intc/arm_gicv3: Implement functions to identify next pending irq
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 10/22] hw/intc/arm_gicv3: Implement functions to identify next pending irq Peter Maydell
@ 2016-06-08  1:57   ` Shannon Zhao
  2016-06-09 15:24     ` Peter Maydell
  0 siblings, 1 reply; 51+ messages in thread
From: Shannon Zhao @ 2016-06-08  1:57 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, 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>
> ---
>  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..7c4bee6 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 redistributor interrupts are actually pending
s/redistributor/distributor/

> +     * 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..35c3c11 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;
Maybe it could be written like below:
    if (s->gicd_ctlr & GICD_CTLR_DS || !grpmodbit) {
        return GICV3_G0;
    }
    return GICV3_G1;

> +}
> +
> +/**
>   * 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);
This should be 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 f01b616..3ca0c9c 100644
> --- a/include/hw/intc/arm_gicv3_common.h
> +++ b/include/hw/intc/arm_gicv3_common.h
> @@ -132,6 +132,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;
> @@ -164,6 +170,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 {
> @@ -199,6 +213,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] 51+ messages in thread

* Re: [Qemu-devel] [PATCH v2 10/22] hw/intc/arm_gicv3: Implement functions to identify next pending irq
  2016-06-08  1:57   ` Shannon Zhao
@ 2016-06-09 15:24     ` Peter Maydell
  0 siblings, 0 replies; 51+ messages in thread
From: Peter Maydell @ 2016-06-09 15:24 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: qemu-arm, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

On 8 June 2016 at 02:57, Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>
>
> On 2016/5/26 22:55, 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>

>> +static uint32_t gicd_int_pending(GICv3State *s, int irq)
>> +{
>> +    /* Recalculate which redistributor interrupts are actually pending
> s/redistributor/distributor/

Fixed.

>> +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;
> Maybe it could be written like below:
>     if (s->gicd_ctlr & GICD_CTLR_DS || !grpmodbit) {
>         return GICV3_G0;
>     }
>     return GICV3_G1;

I think I prefer the way it is currently, as it better
matches what we're trying to say:
 * if security is disabled, there is no grpmodbit, so always G0
 * otherwise, look at grpmodbit to determine G1 vs G0

>> +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);
> This should be extract64(s->gicd_irouter[irq], 32, 8) << 24

Oops. Fixed.

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v2 11/22] hw/intc/arm_gicv3: Implement GICv3 distributor registers
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 11/22] hw/intc/arm_gicv3: Implement GICv3 distributor registers Peter Maydell
@ 2016-06-13  6:27   ` Shannon Zhao
  2016-06-13  9:04     ` Peter Maydell
  0 siblings, 1 reply; 51+ messages in thread
From: Shannon Zhao @ 2016-06-13  6:27 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> +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 */
Here this check assure this interrupt belongs to Group 0 and NS access
is not permitted, so it should return 0. But it doesn't say anything
about Secure Group 1.

> +            return 0;
> +        }
> +        /* NS view of the interrupt priority */
> +        prio = (prio << 1) & 0xff;
> +    }
So maybe here it should check if attrs.secure is true and the Group is
1, then return 0.

> +    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 */
Same here.

> +            return;
> +        }
> +        /* NS view of the interrupt priority */
> +        value = 0x80 | (value >> 1);
> +    }
> +    s->gicd_ipriority[irq] = value;
> +}

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 13/22] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 13/22] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions Peter Maydell
@ 2016-06-13  7:19   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-13  7:19 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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 7c4bee6..e8f6766 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)
> 

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 14/22] hw/intc/arm_gicv3: Implement gicv3_set_irq()
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 14/22] hw/intc/arm_gicv3: Implement gicv3_set_irq() Peter Maydell
@ 2016-06-13  7:49   ` Shannon Zhao
  2016-06-13  9:07     ` Peter Maydell
  0 siblings, 1 reply; 51+ messages in thread
From: Shannon Zhao @ 2016-06-13  7:49 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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>
> ---
>  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 e8f6766..e770409 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 >= 16 && irq < 32);
Nit: Use GIC_NR_SGIS instead and irq < 32 is unnecessary.

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

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 16/22] hw/intc/arm_gicv3: Implement gicv3_cpuif_update()
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 16/22] hw/intc/arm_gicv3: Implement gicv3_cpuif_update() Peter Maydell
@ 2016-06-13  7:56   ` Shannon Zhao
  2016-06-13  9:10     ` Peter Maydell
  0 siblings, 1 reply; 51+ messages in thread
From: Shannon Zhao @ 2016-06-13  7:56 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> +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);
Does it need to set both fiq and irq for one interrupt? I think it
should be called differently based on the value of isfiq.

Thanks,
-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 11/22] hw/intc/arm_gicv3: Implement GICv3 distributor registers
  2016-06-13  6:27   ` Shannon Zhao
@ 2016-06-13  9:04     ` Peter Maydell
  2016-06-13  9:35       ` Shannon Zhao
  0 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-06-13  9:04 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: qemu-arm, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

On 13 June 2016 at 07:27, Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>
>
> On 2016/5/26 22:55, Peter Maydell wrote:
>> +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 */
> Here this check assure this interrupt belongs to Group 0 and NS access
> is not permitted, so it should return 0. But it doesn't say anything
> about Secure Group 1.

We're testing the GICD_IGROUPR bit here. If DS is zero (security
enabled), then IGROUPR == 0 means "Group 0 or Secure Group 1", which
is what the comment says we're testing. (If you care which of 0 and S1
it is then you look at IGRPMODR, but for security checks like these
we don't need to.)

>> +            return 0;
>> +        }
>> +        /* NS view of the interrupt priority */
>> +        prio = (prio << 1) & 0xff;
>> +    }
> So maybe here it should check if attrs.secure is true and the Group is
> 1, then return 0.

I'm confused. If attrs.secure is true this is a secure access which
should be allowed to see anything, shouldn't it?

>> +    return prio;
>> +}

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v2 14/22] hw/intc/arm_gicv3: Implement gicv3_set_irq()
  2016-06-13  7:49   ` Shannon Zhao
@ 2016-06-13  9:07     ` Peter Maydell
  0 siblings, 0 replies; 51+ messages in thread
From: Peter Maydell @ 2016-06-13  9:07 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: qemu-arm, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

On 13 June 2016 at 08:49, Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>
>
> On 2016/5/26 22:55, Peter Maydell wrote:
>> 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>
>> ---
>>  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 e8f6766..e770409 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 >= 16 && irq < 32);
> Nit: Use GIC_NR_SGIS instead and irq < 32 is unnecessary.

Fixed, thanks.

-- PMM

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

* Re: [Qemu-devel] [PATCH v2 16/22] hw/intc/arm_gicv3: Implement gicv3_cpuif_update()
  2016-06-13  7:56   ` Shannon Zhao
@ 2016-06-13  9:10     ` Peter Maydell
  0 siblings, 0 replies; 51+ messages in thread
From: Peter Maydell @ 2016-06-13  9:10 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: qemu-arm, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

On 13 June 2016 at 08:56, Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>
>
> On 2016/5/26 22:55, Peter Maydell wrote:
>> +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);
> Does it need to set both fiq and irq for one interrupt? I think it
> should be called differently based on the value of isfiq.

If the state of the CPU changes then an asserted interrupt may
switch from "must assert FIQ" to "must assert IRQ". This means
we need to call qemu_set_irq() for both (in one case with a 0
level and in the other case with a 1 level); we can't just ignore
the IRQ/FIQ line which doesn't apply to this interrupt.
There's also the case of "icc_hppi_can_preempt() returns false" where
we need to make both calls with a 0 level, so we can't simplify to
one call with isfiq and one call with !isfiq.

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v2 11/22] hw/intc/arm_gicv3: Implement GICv3 distributor registers
  2016-06-13  9:04     ` Peter Maydell
@ 2016-06-13  9:35       ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-13  9:35 UTC (permalink / raw)
  To: Peter Maydell
  Cc: qemu-arm, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall



On 2016/6/13 17:04, Peter Maydell wrote:
> On 13 June 2016 at 07:27, Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>> >
>> >
>> > On 2016/5/26 22:55, Peter Maydell wrote:
>>> >> +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 */
>> > Here this check assure this interrupt belongs to Group 0 and NS access
>> > is not permitted, so it should return 0. But it doesn't say anything
>> > about Secure Group 1.
> We're testing the GICD_IGROUPR bit here. If DS is zero (security
> enabled), then IGROUPR == 0 means "Group 0 or Secure Group 1", which
> is what the comment says we're testing. (If you care which of 0 and S1
> it is then you look at IGRPMODR, but for security checks like these
> we don't need to.)
> 
Oh, right.

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 19/22] target-arm/machine.c: Allow user to request GICv3 emulation
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 19/22] target-arm/machine.c: Allow user to request GICv3 emulation Peter Maydell
@ 2016-06-13 11:38   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-13 11:38 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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);
> 

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 20/22] target-arm/monitor.c: Advertise emulated GICv3 in capabilities
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 20/22] target-arm/monitor.c: Advertise emulated GICv3 in capabilities Peter Maydell
@ 2016-06-13 11:40   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-13 11:40 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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);
>  
> 

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 21/22] NOT-FOR-UPSTREAM: kernel: Add definitions for GICv3 attributes
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 21/22] NOT-FOR-UPSTREAM: kernel: Add definitions for GICv3 attributes Peter Maydell
@ 2016-06-13 11:51   ` Shannon Zhao
  2016-06-13 12:02     ` Peter Maydell
  0 siblings, 1 reply; 51+ messages in thread
From: Shannon Zhao @ 2016-06-13 11:51 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> From: Pavel Fedin <p.fedin@samsung.com>
> 
> This temporary patch adds kernel API definitions. Use proper header update
> procedure after these features are released.
> 
> FIXME: not-for-upstream

Peter, What's your plan for this patch and next one? GICv3 emulation
doesn't depend on them, right? If so, you can consider put them into
another series. So this series could not be blocked by them.

Thanks,
-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 21/22] NOT-FOR-UPSTREAM: kernel: Add definitions for GICv3 attributes
  2016-06-13 11:51   ` Shannon Zhao
@ 2016-06-13 12:02     ` Peter Maydell
  0 siblings, 0 replies; 51+ messages in thread
From: Peter Maydell @ 2016-06-13 12:02 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: qemu-arm, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

On 13 June 2016 at 12:51, Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>
>
> On 2016/5/26 22:55, Peter Maydell wrote:
>> From: Pavel Fedin <p.fedin@samsung.com>
>>
>> This temporary patch adds kernel API definitions. Use proper header update
>> procedure after these features are released.
>>
>> FIXME: not-for-upstream
>
> Peter, What's your plan for this patch and next one? GICv3 emulation
> doesn't depend on them, right? If so, you can consider put them into
> another series. So this series could not be blocked by them.

Yes, I provide them in this series as a sort of FYI/RFC, but
won't put them into master as part of this series.

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v2 04/22] target-arm: Provide hook to tell GICv3 about changes of security state
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 04/22] target-arm: Provide hook to tell GICv3 about changes of security state Peter Maydell
@ 2016-06-14  1:49   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-14  1:49 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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 2fa1f41..9b045af 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -504,6 +504,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
>   *
> @@ -641,6 +648,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)
> @@ -2373,4 +2383,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 e3ea26f..d907598 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -6496,6 +6496,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 a125873..5d8ec43 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 0b29b9d..8021738 100644
> --- a/target-arm/op_helper.c
> +++ b/target-arm/op_helper.c
> @@ -437,6 +437,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.  */
> @@ -932,6 +934,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:
> 

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 12/22] hw/intc/arm_gicv3: Implement GICv3 redistributor registers
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 12/22] hw/intc/arm_gicv3: Implement GICv3 redistributor registers Peter Maydell
@ 2016-06-14  3:09   ` Shannon Zhao
  2016-06-14 12:25     ` Peter Maydell
  0 siblings, 1 reply; 51+ messages in thread
From: Shannon Zhao @ 2016-06-14  3:09 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, 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>
> ---
>  hw/intc/Makefile.objs      |   1 +
>  hw/intc/arm_gicv3_redist.c | 495 +++++++++++++++++++++++++++++++++++++++++++++
>  hw/intc/gicv3_internal.h   |   4 +
>  trace-events               |   6 +
>  4 files changed, 506 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..18dc0c8
> --- /dev/null
> +++ b/hw/intc/arm_gicv3_redist.c
> @@ -0,0 +1,495 @@
> +/*
> + * 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);
GICv3 SPEC says when GICD_CTLR.DS == 0, for GICD_ICENABLER<n> bits
corresponding to Group 0 and Secure Group 1 interrupts are RAZ/WI to
Non-secure accesses. But for GICR_ICENABLER0 all bits are RAZ/WI to
Non-secure accesses. It doesn't care the interrupt Group. If so,
gicr_read_bitmap_reg() wrongly uses the return value of mask_group() as
the mask.

> +        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);
For GICR_ICFGR0, it doesn't need to use mask_group() as mask because the
SPEC doesn't say it's RAZ/WI to a Group 0 or Secure Group 1 interrupt.

> +        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 (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
> +            *data = 0;
> +            return MEMTX_OK;
> +        }
> +        *data = cs->gicr_nsacr;
Look like this is not consistent with the SPEC.
The SPEC says
"When GICD_CTLR.DS == 1, this register is RAZ/WI.
When GICD_CTLR.DS == 0, this register is Secure, and is RAZ/WI to
Non-secure accesses."

So when GICD_CTLR.DS == 1, it should make *data = 0.

> +        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 (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
> +            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;
> +    }
> +}
> +

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 17/22] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers
  2016-05-26 14:55 ` [Qemu-devel] [PATCH v2 17/22] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers Peter Maydell
@ 2016-06-14  6:24   ` Shannon Zhao
  0 siblings, 0 replies; 51+ messages in thread
From: Shannon Zhao @ 2016-06-14  6:24 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel
  Cc: patches, Shlomo Pongratz, Shlomo Pongratz, Pavel Fedin,
	Shannon Zhao, Christoffer Dall



On 2016/5/26 22:55, Peter Maydell wrote:
> 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 16b3422..13893d3 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)
>  {
> @@ -514,3 +521,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 d06ef3e..561849c 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 e84cea9..762f5a0 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -1934,6 +1934,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"
> @@ -1948,3 +1949,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"
> 

-- 
Shannon

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

* Re: [Qemu-devel] [PATCH v2 12/22] hw/intc/arm_gicv3: Implement GICv3 redistributor registers
  2016-06-14  3:09   ` Shannon Zhao
@ 2016-06-14 12:25     ` Peter Maydell
  2016-06-14 12:28       ` Peter Maydell
  0 siblings, 1 reply; 51+ messages in thread
From: Peter Maydell @ 2016-06-14 12:25 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: qemu-arm, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

On 14 June 2016 at 04:09, Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>
>
> On 2016/5/26 22:55, Peter Maydell wrote:
>> Implement the redistributor registers of a GICv3.

>> +    case GICR_ISENABLER0:
>> +    case GICR_ICENABLER0:
>> +        *data = gicr_read_bitmap_reg(cs, attrs, cs->gicr_ienabler0);

> GICv3 SPEC says when GICD_CTLR.DS == 0, for GICD_ICENABLER<n> bits
> corresponding to Group 0 and Secure Group 1 interrupts are RAZ/WI to
> Non-secure accesses. But for GICR_ICENABLER0 all bits are RAZ/WI to
> Non-secure accesses. It doesn't care the interrupt Group. If so,
> gicr_read_bitmap_reg() wrongly uses the return value of mask_group() as
> the mask.

The spec says for GICR_ICENABLER0 "When GICD_CTLR.DS == 0, bits corresponding
to Secure SGIs and PPIs are RAZ/WI to Non-secure accesses". So we are
correct to look at the group bit I think.

>> +        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);
> For GICR_ICFGR0, it doesn't need to use mask_group() as mask because the
> SPEC doesn't say it's RAZ/WI to a Group 0 or Secure Group 1 interrupt.

This is a bug in the GICv3 spec which will be fixed in a newer
rev of the document. GICR_ICFGR0 should say that "When GICD_CTLR.DS==0,
a register bit that corresponds to a Group 0 or Secure Group 1
interrupt is RAZ/WI to Non-secure accesses".

>> +        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 (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
>> +            *data = 0;
>> +            return MEMTX_OK;
>> +        }
>> +        *data = cs->gicr_nsacr;
> Look like this is not consistent with the SPEC.
> The SPEC says
> "When GICD_CTLR.DS == 1, this register is RAZ/WI.
> When GICD_CTLR.DS == 0, this register is Secure, and is RAZ/WI to
> Non-secure accesses."
>
> So when GICD_CTLR.DS == 1, it should make *data = 0.

Agreed. This should have the same kind of condition as 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;

(similarly for writes)

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v2 12/22] hw/intc/arm_gicv3: Implement GICv3 redistributor registers
  2016-06-14 12:25     ` Peter Maydell
@ 2016-06-14 12:28       ` Peter Maydell
  0 siblings, 0 replies; 51+ messages in thread
From: Peter Maydell @ 2016-06-14 12:28 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: qemu-arm, QEMU Developers, Patch Tracking, Shlomo Pongratz,
	Shlomo Pongratz, Pavel Fedin, Shannon Zhao, Christoffer Dall

On 14 June 2016 at 13:25, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 14 June 2016 at 04:09, Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>>> +    case GICR_NSACR:
>>> +        if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
>>> +            *data = 0;
>>> +            return MEMTX_OK;
>>> +        }
>>> +        *data = cs->gicr_nsacr;
>> Look like this is not consistent with the SPEC.
>> The SPEC says
>> "When GICD_CTLR.DS == 1, this register is RAZ/WI.
>> When GICD_CTLR.DS == 0, this register is Secure, and is RAZ/WI to
>> Non-secure accesses."
>>
>> So when GICD_CTLR.DS == 1, it should make *data = 0.
>
> Agreed. This should have the same kind of condition as 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;
>
> (similarly for writes)

This also applies to GICD_NSACR.

thanks
-- PMM

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

end of thread, other threads:[~2016-06-14 12:29 UTC | newest]

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

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.