All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 00/22] target-arm queue
@ 2016-06-17 14:25 Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 01/22] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
                   ` (22 more replies)
  0 siblings, 23 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

Nothing here except the GICv3 emulation, but I wanted to get it into
master this week, and nothing else has made it into target-arm.next.

thanks
-- PMM


The following changes since commit 98b5b7422fe1813040b499a4be415a9f514f1c10:

  Merge remote-tracking branch 'remotes/amit-migration/tags/migration-for-2.7-5' into staging (2016-06-17 14:09:46 +0100)

are available in the git repository at:


  git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20160617

for you to fetch changes up to f06765a94a31bdd8b65fc83fd91a6c3f8e8a1195:

  ACPI: ARM: Present GIC version in MADT table (2016-06-17 15:23:51 +0100)

----------------------------------------------------------------
target-arm queue:
 * GICv3 emulation

----------------------------------------------------------------
Andrew Jeffery (1):
      hw/timer: Add value matching support to aspeed_timer

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

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

Shannon Zhao (1):
      ACPI: ARM: Present GIC version in MADT table

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/arm/virt-acpi-build.c           |    1 +
 hw/intc/Makefile.objs              |    4 +
 hw/intc/arm_gicv3.c                |  400 +++++++++++
 hw/intc/arm_gicv3_common.c         |  225 +++++-
 hw/intc/arm_gicv3_cpuif.c          | 1346 ++++++++++++++++++++++++++++++++++++
 hw/intc/arm_gicv3_dist.c           |  879 +++++++++++++++++++++++
 hw/intc/arm_gicv3_kvm.c            |    8 +
 hw/intc/arm_gicv3_redist.c         |  562 +++++++++++++++
 hw/intc/gicv3_internal.h           |  331 +++++++++
 hw/timer/aspeed_timer.c            |  138 +++-
 include/hw/acpi/acpi-defs.h        |    4 +-
 include/hw/intc/arm_gicv3.h        |   32 +
 include/hw/intc/arm_gicv3_common.h |  215 +++++-
 include/hw/timer/aspeed_timer.h    |    5 +-
 include/migration/vmstate.h        |    6 +
 include/qemu/bitops.h              |  108 +++
 target-arm/cpu.c                   |   10 +
 target-arm/cpu.h                   |   47 +-
 target-arm/helper.c                |    2 +
 target-arm/internals.h             |    8 +
 target-arm/machine.c               |    3 +-
 target-arm/monitor.c               |    3 +-
 target-arm/op_helper.c             |    4 +
 tests/test-bitops.c                |   72 ++
 trace-events                       |   41 ++
 25 files changed, 4394 insertions(+), 60 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

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

* [Qemu-devel] [PULL 01/22] migration: Define VMSTATE_UINT64_2DARRAY
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 02/22] bitops.h: Implement half-shuffle and half-unshuffle ops Peter Maydell
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-2-git-send-email-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 6c65811..25ea58a 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -856,6 +856,12 @@ extern const VMStateInfo vmstate_info_bitmap;
 #define VMSTATE_UINT64_ARRAY(_f, _s, _n)                              \
     VMSTATE_UINT64_ARRAY_V(_f, _s, _n, 0)
 
+#define VMSTATE_UINT64_2DARRAY(_f, _s, _n1, _n2)                      \
+    VMSTATE_UINT64_2DARRAY_V(_f, _s, _n1, _n2, 0)
+
+#define VMSTATE_UINT64_2DARRAY_V(_f, _s, _n1, _n2, _v)                 \
+    VMSTATE_2DARRAY(_f, _s, _n1, _n2, _v, vmstate_info_uint64, uint64_t)
+
 #define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v)                         \
     VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int16, int16_t)
 
-- 
1.9.1

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

* [Qemu-devel] [PULL 02/22] bitops.h: Implement half-shuffle and half-unshuffle ops
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 01/22] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 03/22] target-arm: Define new arm_is_el3_or_mon() function Peter Maydell
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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

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

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

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

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

* [Qemu-devel] [PULL 03/22] target-arm: Define new arm_is_el3_or_mon() function
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 01/22] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 02/22] bitops.h: Implement half-shuffle and half-unshuffle ops Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 04/22] target-arm: Provide hook to tell GICv3 about changes of security state Peter Maydell
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-4-git-send-email-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 942aa36..325b737 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1146,8 +1146,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) {
@@ -1159,6 +1159,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] 24+ messages in thread

* [Qemu-devel] [PULL 04/22] target-arm: Provide hook to tell GICv3 about changes of security state
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (2 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 03/22] target-arm: Define new arm_is_el3_or_mon() function Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 05/22] target-arm: Add mp-affinity property for ARM CPU class Peter Maydell
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-5-git-send-email-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 325b737..7938ddc 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -515,6 +515,13 @@ typedef struct CPUARMState {
 } CPUARMState;
 
 /**
+ * ARMELChangeHook:
+ * type of a function which can be registered via arm_register_el_change_hook()
+ * to get callbacks when the CPU changes its exception level or mode.
+ */
+typedef void ARMELChangeHook(ARMCPU *cpu, void *opaque);
+
+/**
  * ARMCPU:
  * @env: #CPUARMState
  *
@@ -654,6 +661,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)
@@ -2386,4 +2396,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 c9730d6..35ff772 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -6503,6 +6503,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
         arm_cpu_do_interrupt_aarch32(cs);
     }
 
+    arm_call_el_change_hook(cpu);
+
     if (!kvm_enabled()) {
         cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
     }
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 728ecba..466be0b 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -479,4 +479,12 @@ bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
 void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write,
                                  int is_user, uintptr_t retaddr);
 
+/* Call the EL change hook if one has been registered */
+static inline void arm_call_el_change_hook(ARMCPU *cpu)
+{
+    if (cpu->el_change_hook) {
+        cpu->el_change_hook(cpu, cpu->el_change_hook_opaque);
+    }
+}
+
 #endif
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 35912a1..73da759 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -474,6 +474,8 @@ void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
 void HELPER(cpsr_write_eret)(CPUARMState *env, uint32_t val)
 {
     cpsr_write(env, val, CPSR_ERET_MASK, CPSRWriteExceptionReturn);
+
+    arm_call_el_change_hook(arm_env_get_cpu(env));
 }
 
 /* Access to user mode registers from privileged modes.  */
@@ -969,6 +971,8 @@ void HELPER(exception_return)(CPUARMState *env)
         env->pc = env->elr_el[cur_el];
     }
 
+    arm_call_el_change_hook(arm_env_get_cpu(env));
+
     return;
 
 illegal_return:
-- 
1.9.1

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

* [Qemu-devel] [PULL 05/22] target-arm: Add mp-affinity property for ARM CPU class
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (3 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 04/22] target-arm: Provide hook to tell GICv3 about changes of security state Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 06/22] hw/intc/arm_gicv3: Add state information Peter Maydell
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-6-git-send-email-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] 24+ messages in thread

* [Qemu-devel] [PULL 06/22] hw/intc/arm_gicv3: Add state information
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (4 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 05/22] target-arm: Add mp-affinity property for ARM CPU class Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 07/22] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure Peter Maydell
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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

diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index b9d3824..bf6949f 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -3,8 +3,9 @@
  *
  * Copyright (c) 2012 Linaro Limited
  * Copyright (c) 2015 Huawei.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
  * Written by Peter Maydell
- * Extended to 64 cores by Shlomo Pongratz
+ * Reworked for GICv3 by Shlomo Pongratz and Pavel Fedin
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,7 +23,10 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "qom/cpu.h"
 #include "hw/intc/arm_gicv3_common.h"
+#include "gicv3_internal.h"
+#include "hw/arm/linux-boot-if.h"
 
 static void gicv3_pre_save(void *opaque)
 {
@@ -90,6 +94,7 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
 static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
 {
     GICv3State *s = ARM_GICV3_COMMON(dev);
+    int i;
 
     /* revision property is actually reserved and currently used only in order
      * to keep the interface compatible with GICv2 code, avoiding extra
@@ -100,11 +105,155 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
         error_setg(errp, "unsupported GIC revision %d", s->revision);
         return;
     }
+
+    if (s->num_irq > GICV3_MAXIRQ) {
+        error_setg(errp,
+                   "requested %u interrupt lines exceeds GIC maximum %d",
+                   s->num_irq, GICV3_MAXIRQ);
+        return;
+    }
+    if (s->num_irq < GIC_INTERNAL) {
+        error_setg(errp,
+                   "requested %u interrupt lines is below GIC minimum %d",
+                   s->num_irq, GIC_INTERNAL);
+        return;
+    }
+
+    /* ITLinesNumber is represented as (N / 32) - 1, so this is an
+     * implementation imposed restriction, not an architectural one,
+     * so we don't have to deal with bitfields where only some of the
+     * bits in a 32-bit word should be valid.
+     */
+    if (s->num_irq % 32) {
+        error_setg(errp,
+                   "%d interrupt lines unsupported: not divisible by 32",
+                   s->num_irq);
+        return;
+    }
+
+    s->cpu = g_new0(GICv3CPUState, s->num_cpu);
+
+    for (i = 0; i < s->num_cpu; i++) {
+        CPUState *cpu = qemu_get_cpu(i);
+        uint64_t cpu_affid;
+        int last;
+
+        s->cpu[i].cpu = cpu;
+        s->cpu[i].gic = s;
+
+        /* Pre-construct the GICR_TYPER:
+         * For our implementation:
+         *  Top 32 bits are the affinity value of the associated CPU
+         *  CommonLPIAff == 01 (redistributors with same Aff3 share LPI table)
+         *  Processor_Number == CPU index starting from 0
+         *  DPGS == 0 (GICR_CTLR.DPG* not supported)
+         *  Last == 1 if this is the last redistributor in a series of
+         *            contiguous redistributor pages
+         *  DirectLPI == 0 (direct injection of LPIs not supported)
+         *  VLPIS == 0 (virtual LPIs not supported)
+         *  PLPIS == 0 (physical LPIs not supported)
+         */
+        cpu_affid = object_property_get_int(OBJECT(cpu), "mp-affinity", NULL);
+        last = (i == s->num_cpu - 1);
+
+        /* The CPU mp-affinity property is in MPIDR register format; squash
+         * the affinity bytes into 32 bits as the GICR_TYPER has them.
+         */
+        cpu_affid = (cpu_affid & 0xFF00000000ULL >> 8) | (cpu_affid & 0xFFFFFF);
+        s->cpu[i].gicr_typer = (cpu_affid << 32) |
+            (1 << 24) |
+            (i << 8) |
+            (last << 4);
+    }
 }
 
 static void arm_gicv3_common_reset(DeviceState *dev)
 {
-    /* TODO */
+    GICv3State *s = ARM_GICV3_COMMON(dev);
+    int i;
+
+    for (i = 0; i < s->num_cpu; i++) {
+        GICv3CPUState *cs = &s->cpu[i];
+
+        cs->level = 0;
+        cs->gicr_ctlr = 0;
+        cs->gicr_statusr[GICV3_S] = 0;
+        cs->gicr_statusr[GICV3_NS] = 0;
+        cs->gicr_waker = GICR_WAKER_ProcessorSleep | GICR_WAKER_ChildrenAsleep;
+        cs->gicr_propbaser = 0;
+        cs->gicr_pendbaser = 0;
+        /* If we're resetting a TZ-aware GIC as if secure firmware
+         * had set it up ready to start a kernel in non-secure, we
+         * need to set interrupts to group 1 so the kernel can use them.
+         * Otherwise they reset to group 0 like the hardware.
+         */
+        if (s->irq_reset_nonsecure) {
+            cs->gicr_igroupr0 = 0xffffffff;
+        } else {
+            cs->gicr_igroupr0 = 0;
+        }
+
+        cs->gicr_ienabler0 = 0;
+        cs->gicr_ipendr0 = 0;
+        cs->gicr_iactiver0 = 0;
+        cs->edge_trigger = 0xffff;
+        cs->gicr_igrpmodr0 = 0;
+        cs->gicr_nsacr = 0;
+        memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr));
+
+        /* State in the CPU interface must *not* be reset here, because it
+         * is part of the CPU's reset domain, not the GIC device's.
+         */
+    }
+
+    /* For our implementation affinity routing is always enabled */
+    if (s->security_extn) {
+        s->gicd_ctlr = GICD_CTLR_ARE_S | GICD_CTLR_ARE_NS;
+    } else {
+        s->gicd_ctlr = GICD_CTLR_DS | GICD_CTLR_ARE;
+    }
+
+    s->gicd_statusr[GICV3_S] = 0;
+    s->gicd_statusr[GICV3_NS] = 0;
+
+    memset(s->group, 0, sizeof(s->group));
+    memset(s->grpmod, 0, sizeof(s->grpmod));
+    memset(s->enabled, 0, sizeof(s->enabled));
+    memset(s->pending, 0, sizeof(s->pending));
+    memset(s->active, 0, sizeof(s->active));
+    memset(s->level, 0, sizeof(s->level));
+    memset(s->edge_trigger, 0, sizeof(s->edge_trigger));
+    memset(s->gicd_ipriority, 0, sizeof(s->gicd_ipriority));
+    memset(s->gicd_irouter, 0, sizeof(s->gicd_irouter));
+    memset(s->gicd_nsacr, 0, sizeof(s->gicd_nsacr));
+
+    if (s->irq_reset_nonsecure) {
+        /* If we're resetting a TZ-aware GIC as if secure firmware
+         * had set it up ready to start a kernel in non-secure, we
+         * need to set interrupts to group 1 so the kernel can use them.
+         * Otherwise they reset to group 0 like the hardware.
+         */
+        for (i = GIC_INTERNAL; i < s->num_irq; i++) {
+            gicv3_gicd_group_set(s, i);
+        }
+    }
+}
+
+static void arm_gic_common_linux_init(ARMLinuxBootIf *obj,
+                                      bool secure_boot)
+{
+    GICv3State *s = ARM_GICV3_COMMON(obj);
+
+    if (s->security_extn && !secure_boot) {
+        /* We're directly booting a kernel into NonSecure. If this GIC
+         * implements the security extensions then we must configure it
+         * to have all the interrupts be NonSecure (this is a job that
+         * is done by the Secure boot firmware in real hardware, and in
+         * this mode QEMU is acting as a minimalist firmware-and-bootloader
+         * equivalent).
+         */
+        s->irq_reset_nonsecure = true;
+    }
 }
 
 static Property arm_gicv3_common_properties[] = {
@@ -118,11 +267,13 @@ static Property arm_gicv3_common_properties[] = {
 static void arm_gicv3_common_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass);
 
     dc->reset = arm_gicv3_common_reset;
     dc->realize = arm_gicv3_common_realize;
     dc->props = arm_gicv3_common_properties;
     dc->vmsd = &vmstate_gicv3;
+    albifc->arm_linux_init = arm_gic_common_linux_init;
 }
 
 static const TypeInfo arm_gicv3_common_type = {
@@ -132,6 +283,10 @@ static const TypeInfo arm_gicv3_common_type = {
     .class_size = sizeof(ARMGICv3CommonClass),
     .class_init = arm_gicv3_common_class_init,
     .abstract = true,
+    .interfaces = (InterfaceInfo []) {
+        { TYPE_ARM_LINUX_BOOT_IF },
+        { },
+    },
 };
 
 static void register_types(void)
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
new file mode 100644
index 0000000..d23524b
--- /dev/null
+++ b/hw/intc/gicv3_internal.h
@@ -0,0 +1,172 @@
+/*
+ * ARM GICv3 support - internal interfaces
+ *
+ * Copyright (c) 2012 Linaro Limited
+ * Copyright (c) 2015 Huawei.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Written by Peter Maydell
+ * Reworked for GICv3 by Shlomo Pongratz and Pavel Fedin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_ARM_GICV3_INTERNAL_H
+#define QEMU_ARM_GICV3_INTERNAL_H
+
+#include "hw/intc/arm_gicv3_common.h"
+
+/* Distributor registers, as offsets from the distributor base address */
+#define GICD_CTLR            0x0000
+#define GICD_TYPER           0x0004
+#define GICD_IIDR            0x0008
+#define GICD_STATUSR         0x0010
+#define GICD_SETSPI_NSR      0x0040
+#define GICD_CLRSPI_NSR      0x0048
+#define GICD_SETSPI_SR       0x0050
+#define GICD_CLRSPI_SR       0x0058
+#define GICD_SEIR            0x0068
+#define GICD_IGROUPR         0x0080
+#define GICD_ISENABLER       0x0100
+#define GICD_ICENABLER       0x0180
+#define GICD_ISPENDR         0x0200
+#define GICD_ICPENDR         0x0280
+#define GICD_ISACTIVER       0x0300
+#define GICD_ICACTIVER       0x0380
+#define GICD_IPRIORITYR      0x0400
+#define GICD_ITARGETSR       0x0800
+#define GICD_ICFGR           0x0C00
+#define GICD_IGRPMODR        0x0D00
+#define GICD_NSACR           0x0E00
+#define GICD_SGIR            0x0F00
+#define GICD_CPENDSGIR       0x0F10
+#define GICD_SPENDSGIR       0x0F20
+#define GICD_IROUTER         0x6000
+#define GICD_IDREGS          0xFFD0
+
+/* GICD_CTLR fields  */
+#define GICD_CTLR_EN_GRP0           (1U << 0)
+#define GICD_CTLR_EN_GRP1NS         (1U << 1) /* GICv3 5.3.20 */
+#define GICD_CTLR_EN_GRP1S          (1U << 2)
+#define GICD_CTLR_EN_GRP1_ALL       (GICD_CTLR_EN_GRP1NS | GICD_CTLR_EN_GRP1S)
+/* Bit 4 is ARE if the system doesn't support TrustZone, ARE_S otherwise */
+#define GICD_CTLR_ARE               (1U << 4)
+#define GICD_CTLR_ARE_S             (1U << 4)
+#define GICD_CTLR_ARE_NS            (1U << 5)
+#define GICD_CTLR_DS                (1U << 6)
+#define GICD_CTLR_E1NWF             (1U << 7)
+#define GICD_CTLR_RWP               (1U << 31)
+
+/*
+ * Redistributor frame offsets from RD_base
+ */
+#define GICR_SGI_OFFSET 0x10000
+
+/*
+ * Redistributor registers, offsets from RD_base
+ */
+#define GICR_CTLR             0x0000
+#define GICR_IIDR             0x0004
+#define GICR_TYPER            0x0008
+#define GICR_STATUSR          0x0010
+#define GICR_WAKER            0x0014
+#define GICR_SETLPIR          0x0040
+#define GICR_CLRLPIR          0x0048
+#define GICR_PROPBASER        0x0070
+#define GICR_PENDBASER        0x0078
+#define GICR_INVLPIR          0x00A0
+#define GICR_INVALLR          0x00B0
+#define GICR_SYNCR            0x00C0
+#define GICR_IDREGS           0xFFD0
+
+/* SGI and PPI Redistributor registers, offsets from RD_base */
+#define GICR_IGROUPR0         (GICR_SGI_OFFSET + 0x0080)
+#define GICR_ISENABLER0       (GICR_SGI_OFFSET + 0x0100)
+#define GICR_ICENABLER0       (GICR_SGI_OFFSET + 0x0180)
+#define GICR_ISPENDR0         (GICR_SGI_OFFSET + 0x0200)
+#define GICR_ICPENDR0         (GICR_SGI_OFFSET + 0x0280)
+#define GICR_ISACTIVER0       (GICR_SGI_OFFSET + 0x0300)
+#define GICR_ICACTIVER0       (GICR_SGI_OFFSET + 0x0380)
+#define GICR_IPRIORITYR       (GICR_SGI_OFFSET + 0x0400)
+#define GICR_ICFGR0           (GICR_SGI_OFFSET + 0x0C00)
+#define GICR_ICFGR1           (GICR_SGI_OFFSET + 0x0C04)
+#define GICR_IGRPMODR0        (GICR_SGI_OFFSET + 0x0D00)
+#define GICR_NSACR            (GICR_SGI_OFFSET + 0x0E00)
+
+#define GICR_CTLR_ENABLE_LPIS        (1U << 0)
+#define GICR_CTLR_RWP                (1U << 3)
+#define GICR_CTLR_DPG0               (1U << 24)
+#define GICR_CTLR_DPG1NS             (1U << 25)
+#define GICR_CTLR_DPG1S              (1U << 26)
+#define GICR_CTLR_UWP                (1U << 31)
+
+#define GICR_TYPER_PLPIS             (1U << 0)
+#define GICR_TYPER_VLPIS             (1U << 1)
+#define GICR_TYPER_DIRECTLPI         (1U << 3)
+#define GICR_TYPER_LAST              (1U << 4)
+#define GICR_TYPER_DPGS              (1U << 5)
+#define GICR_TYPER_PROCNUM           (0xFFFFU << 8)
+#define GICR_TYPER_COMMONLPIAFF      (0x3 << 24)
+#define GICR_TYPER_AFFINITYVALUE     (0xFFFFFFFFULL << 32)
+
+#define GICR_WAKER_ProcessorSleep    (1U << 1)
+#define GICR_WAKER_ChildrenAsleep    (1U << 2)
+
+#define GICR_PROPBASER_OUTER_CACHEABILITY_MASK (7ULL << 56)
+#define GICR_PROPBASER_ADDR_MASK               (0xfffffffffULL << 12)
+#define GICR_PROPBASER_SHAREABILITY_MASK       (3U << 10)
+#define GICR_PROPBASER_CACHEABILITY_MASK       (7U << 7)
+#define GICR_PROPBASER_IDBITS_MASK             (0x1f)
+
+#define GICR_PENDBASER_PTZ                     (1ULL << 62)
+#define GICR_PENDBASER_OUTER_CACHEABILITY_MASK (7ULL << 56)
+#define GICR_PENDBASER_ADDR_MASK               (0xffffffffULL << 16)
+#define GICR_PENDBASER_SHAREABILITY_MASK       (3U << 10)
+#define GICR_PENDBASER_CACHEABILITY_MASK       (7U << 7)
+
+#define ICC_CTLR_EL1_CBPR           (1U << 0)
+#define ICC_CTLR_EL1_EOIMODE        (1U << 1)
+#define ICC_CTLR_EL1_PMHE           (1U << 6)
+#define ICC_CTLR_EL1_PRIBITS_SHIFT 8
+#define ICC_CTLR_EL1_IDBITS_SHIFT 11
+#define ICC_CTLR_EL1_SEIS           (1U << 14)
+#define ICC_CTLR_EL1_A3V            (1U << 15)
+
+#define ICC_PMR_PRIORITY_MASK    0xff
+#define ICC_BPR_BINARYPOINT_MASK 0x07
+#define ICC_IGRPEN_ENABLE        0x01
+
+#define ICC_CTLR_EL3_CBPR_EL1S (1U << 0)
+#define ICC_CTLR_EL3_CBPR_EL1NS (1U << 1)
+#define ICC_CTLR_EL3_EOIMODE_EL3 (1U << 2)
+#define ICC_CTLR_EL3_EOIMODE_EL1S (1U << 3)
+#define ICC_CTLR_EL3_EOIMODE_EL1NS (1U << 4)
+#define ICC_CTLR_EL3_RM (1U << 5)
+#define ICC_CTLR_EL3_PMHE (1U << 6)
+#define ICC_CTLR_EL3_PRIBITS_SHIFT 8
+#define ICC_CTLR_EL3_IDBITS_SHIFT 11
+#define ICC_CTLR_EL3_SEIS (1U << 14)
+#define ICC_CTLR_EL3_A3V (1U << 15)
+#define ICC_CTLR_EL3_NDS (1U << 17)
+
+/**
+ * gicv3_redist_affid:
+ *
+ * Return the 32-bit affinity ID of the CPU connected to this redistributor
+ */
+static inline uint32_t gicv3_redist_affid(GICv3CPUState *cs)
+{
+    return cs->gicr_typer >> 32;
+}
+
+#endif /* !QEMU_ARM_GIC_INTERNAL_H */
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index c2fd8da..bd364a7 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -3,8 +3,9 @@
  *
  * Copyright (c) 2012 Linaro Limited
  * Copyright (c) 2015 Huawei.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
  * Written by Peter Maydell
- * Extended to 64 cores by Shlomo Pongratz
+ * Reworked for GICv3 by Shlomo Pongratz and Pavel Fedin
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,7 +27,143 @@
 #include "hw/sysbus.h"
 #include "hw/intc/arm_gic_common.h"
 
-typedef struct GICv3State {
+/*
+ * Maximum number of possible interrupts, determined by the GIC architecture.
+ * Note that this does not include LPIs. When implemented, these should be
+ * dealt with separately.
+ */
+#define GICV3_MAXIRQ 1020
+#define GICV3_MAXSPI (GICV3_MAXIRQ - GIC_INTERNAL)
+
+/* Minimum BPR for Secure, or when security not enabled */
+#define GIC_MIN_BPR 0
+/* Minimum BPR for Nonsecure when security is enabled */
+#define GIC_MIN_BPR_NS (GIC_MIN_BPR + 1)
+
+/* For some distributor fields we want to model the array of 32-bit
+ * register values which hold various bitmaps corresponding to enabled,
+ * pending, etc bits. These macros and functions facilitate that; the
+ * APIs are generally modelled on the generic bitmap.h functions
+ * (which are unsuitable here because they use 'unsigned long' as the
+ * underlying storage type, which is very awkward when you need to
+ * access the data as 32-bit values.)
+ * Each bitmap contains a bit for each interrupt. Although there is
+ * space for the PPIs and SGIs, those bits (the first 32) are never
+ * used as that state lives in the redistributor. The unused bits are
+ * provided purely so that interrupt X's state is always in bit X; this
+ * avoids bugs where we forget to subtract GIC_INTERNAL from an
+ * interrupt number.
+ */
+#define GICV3_BMP_SIZE (DIV_ROUND_UP(GICV3_MAXIRQ, 32))
+
+#define GIC_DECLARE_BITMAP(name) \
+    uint32_t name[GICV3_BMP_SIZE]
+
+#define GIC_BIT_MASK(nr) (1U << ((nr) % 32))
+#define GIC_BIT_WORD(nr) ((nr) / 32)
+
+static inline void gic_bmp_set_bit(int nr, uint32_t *addr)
+{
+    uint32_t mask = GIC_BIT_MASK(nr);
+    uint32_t *p = addr + GIC_BIT_WORD(nr);
+
+    *p |= mask;
+}
+
+static inline void gic_bmp_clear_bit(int nr, uint32_t *addr)
+{
+    uint32_t mask = GIC_BIT_MASK(nr);
+    uint32_t *p = addr + GIC_BIT_WORD(nr);
+
+    *p &= ~mask;
+}
+
+static inline int gic_bmp_test_bit(int nr, const uint32_t *addr)
+{
+    return 1U & (addr[GIC_BIT_WORD(nr)] >> (nr & 31));
+}
+
+static inline void gic_bmp_replace_bit(int nr, uint32_t *addr, int val)
+{
+    uint32_t mask = GIC_BIT_MASK(nr);
+    uint32_t *p = addr + GIC_BIT_WORD(nr);
+
+    *p &= ~mask;
+    *p |= (val & 1U) << (nr % 32);
+}
+
+/* Return a pointer to the 32-bit word containing the specified bit. */
+static inline uint32_t *gic_bmp_ptr32(uint32_t *addr, int nr)
+{
+    return addr + GIC_BIT_WORD(nr);
+}
+
+typedef struct GICv3State GICv3State;
+typedef struct GICv3CPUState GICv3CPUState;
+
+/* Some CPU interface registers come in three flavours:
+ * Group0, Group1 (Secure) and Group1 (NonSecure)
+ * (where the latter two are exposed as a single banked system register).
+ * In the state struct they are implemented as a 3-element array which
+ * can be indexed into by the GICV3_G0, GICV3_G1 and GICV3_G1NS constants.
+ * If the CPU doesn't support EL3 then the G1 element is unused.
+ *
+ * These constants are also used to communicate the group to use for
+ * an interrupt or SGI when it is passed between the cpu interface and
+ * the redistributor or distributor. For those purposes the receiving end
+ * must be prepared to cope with a Group 1 Secure interrupt even if it does
+ * not have security support enabled, because security can be disabled
+ * independently in the CPU and in the GIC. In that case the receiver should
+ * treat an incoming Group 1 Secure interrupt as if it were Group 0.
+ * (This architectural requirement is why the _G1 element is the unused one
+ * in a no-EL3 CPU:  we would otherwise have to translate back and forth
+ * between (G0, G1NS) from the distributor and (G0, G1) in the CPU i/f.)
+ */
+#define GICV3_G0 0
+#define GICV3_G1 1
+#define GICV3_G1NS 2
+
+/* ICC_CTLR_EL1, GICD_STATUSR and GICR_STATUSR are banked but not
+ * group-related, so those indices are just 0 for S and 1 for NS.
+ * (If the CPU or the GIC, respectively, don't support the Security
+ * extensions then the S element is unused.)
+ */
+#define GICV3_S 0
+#define GICV3_NS 1
+
+struct GICv3CPUState {
+    GICv3State *gic;
+    CPUState *cpu;
+
+    /* Redistributor */
+    uint32_t level;                  /* Current IRQ level */
+    /* RD_base page registers */
+    uint32_t gicr_ctlr;
+    uint64_t gicr_typer;
+    uint32_t gicr_statusr[2];
+    uint32_t gicr_waker;
+    uint64_t gicr_propbaser;
+    uint64_t gicr_pendbaser;
+    /* SGI_base page registers */
+    uint32_t gicr_igroupr0;
+    uint32_t gicr_ienabler0;
+    uint32_t gicr_ipendr0;
+    uint32_t gicr_iactiver0;
+    uint32_t edge_trigger; /* ICFGR0 and ICFGR1 even bits */
+    uint32_t gicr_igrpmodr0;
+    uint32_t gicr_nsacr;
+    uint8_t gicr_ipriorityr[GIC_INTERNAL];
+
+    /* CPU interface */
+    uint64_t icc_ctlr_el1[2];
+    uint64_t icc_pmr_el1;
+    uint64_t icc_bpr[3];
+    uint64_t icc_apr[3][4];
+    uint64_t icc_igrpen[3];
+    uint64_t icc_ctlr_el3;
+};
+
+struct GICv3State {
     /*< private >*/
     SysBusDevice parent_obj;
     /*< public >*/
@@ -41,9 +178,58 @@ typedef struct GICv3State {
     uint32_t num_irq;
     uint32_t revision;
     bool security_extn;
+    bool irq_reset_nonsecure;
 
     int dev_fd; /* kvm device fd if backed by kvm vgic support */
-} GICv3State;
+    Error *migration_blocker;
+
+    /* Distributor */
+
+    /* for a GIC with the security extensions the NS banked version of this
+     * register is just an alias of bit 1 of the S banked version.
+     */
+    uint32_t gicd_ctlr;
+    uint32_t gicd_statusr[2];
+    GIC_DECLARE_BITMAP(group);        /* GICD_IGROUPR */
+    GIC_DECLARE_BITMAP(grpmod);       /* GICD_IGRPMODR */
+    GIC_DECLARE_BITMAP(enabled);      /* GICD_ISENABLER */
+    GIC_DECLARE_BITMAP(pending);      /* GICD_ISPENDR */
+    GIC_DECLARE_BITMAP(active);       /* GICD_ISACTIVER */
+    GIC_DECLARE_BITMAP(level);        /* Current level */
+    GIC_DECLARE_BITMAP(edge_trigger); /* GICD_ICFGR even bits */
+    uint8_t gicd_ipriority[GICV3_MAXIRQ];
+    uint64_t gicd_irouter[GICV3_MAXIRQ];
+    uint32_t gicd_nsacr[DIV_ROUND_UP(GICV3_MAXIRQ, 16)];
+
+    GICv3CPUState *cpu;
+};
+
+#define GICV3_BITMAP_ACCESSORS(BMP)                                     \
+    static inline void gicv3_gicd_##BMP##_set(GICv3State *s, int irq)   \
+    {                                                                   \
+        gic_bmp_set_bit(irq, s->BMP);                                   \
+    }                                                                   \
+    static inline int gicv3_gicd_##BMP##_test(GICv3State *s, int irq)   \
+    {                                                                   \
+        return gic_bmp_test_bit(irq, s->BMP);                           \
+    }                                                                   \
+    static inline void gicv3_gicd_##BMP##_clear(GICv3State *s, int irq) \
+    {                                                                   \
+        gic_bmp_clear_bit(irq, s->BMP);                                 \
+    }                                                                   \
+    static inline void gicv3_gicd_##BMP##_replace(GICv3State *s,        \
+                                                  int irq, int value)   \
+    {                                                                   \
+        gic_bmp_replace_bit(irq, s->BMP, value);                        \
+    }
+
+GICV3_BITMAP_ACCESSORS(group)
+GICV3_BITMAP_ACCESSORS(grpmod)
+GICV3_BITMAP_ACCESSORS(enabled)
+GICV3_BITMAP_ACCESSORS(pending)
+GICV3_BITMAP_ACCESSORS(active)
+GICV3_BITMAP_ACCESSORS(level)
+GICV3_BITMAP_ACCESSORS(edge_trigger)
 
 #define TYPE_ARM_GICV3_COMMON "arm-gicv3-common"
 #define ARM_GICV3_COMMON(obj) \
-- 
1.9.1

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

* [Qemu-devel] [PULL 07/22] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (5 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 06/22] hw/intc/arm_gicv3: Add state information Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 08/22] hw/intc/arm_gicv3: Add vmstate descriptors Peter Maydell
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-8-git-send-email-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 bd364a7..cc6ac74 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -134,6 +134,8 @@ typedef struct GICv3CPUState GICv3CPUState;
 struct GICv3CPUState {
     GICv3State *gic;
     CPUState *cpu;
+    qemu_irq parent_irq;
+    qemu_irq parent_fiq;
 
     /* Redistributor */
     uint32_t level;                  /* Current IRQ level */
@@ -168,9 +170,6 @@ struct GICv3State {
     SysBusDevice parent_obj;
     /*< public >*/
 
-    qemu_irq *parent_irq;
-    qemu_irq *parent_fiq;
-
     MemoryRegion iomem_dist; /* Distributor */
     MemoryRegion iomem_redist; /* Redistributors */
 
-- 
1.9.1

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

* [Qemu-devel] [PULL 08/22] hw/intc/arm_gicv3: Add vmstate descriptors
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (6 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 07/22] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 09/22] hw/intc/arm_gicv3: ARM GICv3 device framework Peter Maydell
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1465915112-29272-9-git-send-email-peter.maydell@linaro.org
[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    |  8 ++++++++
 2 files changed, 57 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..711fde3 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -26,6 +26,7 @@
 #include "sysemu/kvm.h"
 #include "kvm_arm.h"
 #include "vgic_common.h"
+#include "migration/migration.h"
 
 #ifdef DEBUG_GICV3_KVM
 #define DPRINTF(fmt, ...) \
@@ -119,6 +120,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] 24+ messages in thread

* [Qemu-devel] [PULL 09/22] hw/intc/arm_gicv3: ARM GICv3 device framework
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (7 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 08/22] hw/intc/arm_gicv3: Add vmstate descriptors Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 10/22] hw/intc/arm_gicv3: Implement functions to identify next pending irq Peter Maydell
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1465915112-29272-10-git-send-email-peter.maydell@linaro.org
[PMM: pulled this patch earlier in the sequence, and left
 some code out of it for a later patch]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 hw/intc/Makefile.objs       |  1 +
 hw/intc/arm_gicv3.c         | 74 +++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/gicv3_internal.h    | 24 +++++++++++++++
 include/hw/intc/arm_gicv3.h | 32 ++++++++++++++++++++
 4 files changed, 131 insertions(+)
 create mode 100644 hw/intc/arm_gicv3.c
 create mode 100644 include/hw/intc/arm_gicv3.h

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 0e47f0f..4e94fdd 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -13,6 +13,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
 common-obj-$(CONFIG_OPENPIC) += openpic.o
 
 obj-$(CONFIG_APIC) += apic.o apic_common.o
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
new file mode 100644
index 0000000..96e0d2f
--- /dev/null
+++ b/hw/intc/arm_gicv3.c
@@ -0,0 +1,74 @@
+/*
+ * ARM Generic Interrupt Controller v3
+ *
+ * Copyright (c) 2015 Huawei.
+ * Copyright (c) 2016 Linaro Limited
+ * Written by Shlomo Pongratz, Peter Maydell
+ *
+ * This code is licensed under the GPL, version 2 or (at your option)
+ * any later version.
+ */
+
+/* This file contains implementation code for an interrupt controller
+ * which implements the GICv3 architecture. Specifically this is where
+ * the device class itself and the functions for handling interrupts
+ * coming in and going out live.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/sysbus.h"
+#include "hw/intc/arm_gicv3.h"
+#include "gicv3_internal.h"
+
+/* Process a change in an external IRQ input. */
+static void gicv3_set_irq(void *opaque, int irq, int level)
+{
+    /* Meaning of the 'irq' parameter:
+     *  [0..N-1] : external interrupts
+     *  [N..N+31] : PPI (internal) interrupts for CPU 0
+     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
+     *  ...
+     */
+    /* Do nothing for now */
+}
+
+static void arm_gic_realize(DeviceState *dev, Error **errp)
+{
+    /* Device instance realize function for the GIC sysbus device */
+    GICv3State *s = ARM_GICV3(dev);
+    ARMGICv3Class *agc = ARM_GICV3_GET_CLASS(s);
+    Error *local_err = NULL;
+
+    agc->parent_realize(dev, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    gicv3_init_irqs_and_mmio(s, gicv3_set_irq, NULL);
+}
+
+static void arm_gicv3_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ARMGICv3Class *agc = ARM_GICV3_CLASS(klass);
+
+    agc->parent_realize = dc->realize;
+    dc->realize = arm_gic_realize;
+}
+
+static const TypeInfo arm_gicv3_info = {
+    .name = TYPE_ARM_GICV3,
+    .parent = TYPE_ARM_GICV3_COMMON,
+    .instance_size = sizeof(GICv3State),
+    .class_init = arm_gicv3_class_init,
+    .class_size = sizeof(ARMGICv3Class),
+};
+
+static void arm_gicv3_register_types(void)
+{
+    type_register_static(&arm_gicv3_info);
+}
+
+type_init(arm_gicv3_register_types)
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index d23524b..97c9d75 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -159,6 +159,30 @@
 #define ICC_CTLR_EL3_A3V (1U << 15)
 #define ICC_CTLR_EL3_NDS (1U << 17)
 
+static inline uint32_t gicv3_iidr(void)
+{
+    /* Return the Implementer Identification Register value
+     * for the emulated GICv3, as reported in GICD_IIDR and GICR_IIDR.
+     *
+     * We claim to be an ARM r0p0 with a zero ProductID.
+     * This is the same as an r0p0 GIC-500.
+     */
+    return 0x43b;
+}
+
+static inline uint32_t gicv3_idreg(int regoffset)
+{
+    /* Return the value of the CoreSight ID register at the specified
+     * offset from the first ID register (as found in the distributor
+     * and redistributor register banks).
+     * These values indicate an ARM implementation of a GICv3.
+     */
+    static const uint8_t gicd_ids[] = {
+        0x44, 0x00, 0x00, 0x00, 0x92, 0xB4, 0x3B, 0x00, 0x0D, 0xF0, 0x05, 0xB1
+    };
+    return gicd_ids[regoffset / 4];
+}
+
 /**
  * gicv3_redist_affid:
  *
diff --git a/include/hw/intc/arm_gicv3.h b/include/hw/intc/arm_gicv3.h
new file mode 100644
index 0000000..4a6fd85
--- /dev/null
+++ b/include/hw/intc/arm_gicv3.h
@@ -0,0 +1,32 @@
+/*
+ * ARM Generic Interrupt Controller v3
+ *
+ * Copyright (c) 2015 Huawei.
+ * Copyright (c) 2016 Linaro Limited
+ * Written by Shlomo Pongratz, Peter Maydell
+ *
+ * This code is licensed under the GPL, version 2 or (at your option)
+ * any later version.
+ */
+
+#ifndef HW_ARM_GICV3_H
+#define HW_ARM_GICV3_H
+
+#include "arm_gicv3_common.h"
+
+#define TYPE_ARM_GICV3 "arm-gicv3"
+#define ARM_GICV3(obj) OBJECT_CHECK(GICv3State, (obj), TYPE_ARM_GICV3)
+#define ARM_GICV3_CLASS(klass) \
+     OBJECT_CLASS_CHECK(ARMGICv3Class, (klass), TYPE_ARM_GICV3)
+#define ARM_GICV3_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(ARMGICv3Class, (obj), TYPE_ARM_GICV3)
+
+typedef struct ARMGICv3Class {
+    /*< private >*/
+    ARMGICv3CommonClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+} ARMGICv3Class;
+
+#endif
-- 
1.9.1

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

* [Qemu-devel] [PULL 10/22] hw/intc/arm_gicv3: Implement functions to identify next pending irq
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (8 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 09/22] hw/intc/arm_gicv3: ARM GICv3 device framework Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 11/22] hw/intc/arm_gicv3: Implement GICv3 distributor registers Peter Maydell
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-11-git-send-email-peter.maydell@linaro.org
---
 hw/intc/arm_gicv3.c                | 293 +++++++++++++++++++++++++++++++++++++
 hw/intc/arm_gicv3_common.c         |   9 ++
 hw/intc/gicv3_internal.h           | 121 +++++++++++++++
 include/hw/intc/arm_gicv3_common.h |  18 +++
 4 files changed, 441 insertions(+)

diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 96e0d2f..171d587 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -21,6 +21,287 @@
 #include "hw/intc/arm_gicv3.h"
 #include "gicv3_internal.h"
 
+static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio)
+{
+    /* Return true if this IRQ at this priority should take
+     * precedence over the current recorded highest priority
+     * pending interrupt for this CPU. We also return true if
+     * the current recorded highest priority pending interrupt
+     * is the same as this one (a property which the calling code
+     * relies on).
+     */
+    if (prio < cs->hppi.prio) {
+        return true;
+    }
+    /* If multiple pending interrupts have the same priority then it is an
+     * IMPDEF choice which of them to signal to the CPU. We choose to
+     * signal the one with the lowest interrupt number.
+     */
+    if (prio == cs->hppi.prio && irq <= cs->hppi.irq) {
+        return true;
+    }
+    return false;
+}
+
+static uint32_t gicd_int_pending(GICv3State *s, int irq)
+{
+    /* Recalculate which distributor interrupts are actually pending
+     * in the group of 32 interrupts starting at irq (which should be a multiple
+     * of 32), and return a 32-bit integer which has a bit set for each
+     * interrupt that is eligible to be signaled to the CPU interface.
+     *
+     * An interrupt is pending if:
+     *  + the PENDING latch is set OR it is level triggered and the input is 1
+     *  + its ENABLE bit is set
+     *  + the GICD enable bit for its group is set
+     * Conveniently we can bulk-calculate this with bitwise operations.
+     */
+    uint32_t pend, grpmask;
+    uint32_t pending = *gic_bmp_ptr32(s->pending, irq);
+    uint32_t edge_trigger = *gic_bmp_ptr32(s->edge_trigger, irq);
+    uint32_t level = *gic_bmp_ptr32(s->level, irq);
+    uint32_t group = *gic_bmp_ptr32(s->group, irq);
+    uint32_t grpmod = *gic_bmp_ptr32(s->grpmod, irq);
+    uint32_t enable = *gic_bmp_ptr32(s->enabled, irq);
+
+    pend = pending | (~edge_trigger & level);
+    pend &= enable;
+
+    if (s->gicd_ctlr & GICD_CTLR_DS) {
+        grpmod = 0;
+    }
+
+    grpmask = 0;
+    if (s->gicd_ctlr & GICD_CTLR_EN_GRP1NS) {
+        grpmask |= group;
+    }
+    if (s->gicd_ctlr & GICD_CTLR_EN_GRP1S) {
+        grpmask |= (~group & grpmod);
+    }
+    if (s->gicd_ctlr & GICD_CTLR_EN_GRP0) {
+        grpmask |= (~group & ~grpmod);
+    }
+    pend &= grpmask;
+
+    return pend;
+}
+
+static uint32_t gicr_int_pending(GICv3CPUState *cs)
+{
+    /* Recalculate which redistributor interrupts are actually pending,
+     * and return a 32-bit integer which has a bit set for each interrupt
+     * that is eligible to be signaled to the CPU interface.
+     *
+     * An interrupt is pending if:
+     *  + the PENDING latch is set OR it is level triggered and the input is 1
+     *  + its ENABLE bit is set
+     *  + the GICD enable bit for its group is set
+     * Conveniently we can bulk-calculate this with bitwise operations.
+     */
+    uint32_t pend, grpmask, grpmod;
+
+    pend = cs->gicr_ipendr0 | (~cs->edge_trigger & cs->level);
+    pend &= cs->gicr_ienabler0;
+
+    if (cs->gic->gicd_ctlr & GICD_CTLR_DS) {
+        grpmod = 0;
+    } else {
+        grpmod = cs->gicr_igrpmodr0;
+    }
+
+    grpmask = 0;
+    if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1NS) {
+        grpmask |= cs->gicr_igroupr0;
+    }
+    if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1S) {
+        grpmask |= (~cs->gicr_igroupr0 & grpmod);
+    }
+    if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP0) {
+        grpmask |= (~cs->gicr_igroupr0 & ~grpmod);
+    }
+    pend &= grpmask;
+
+    return pend;
+}
+
+/* Update the interrupt status after state in a redistributor
+ * or CPU interface has changed, but don't tell the CPU i/f.
+ */
+static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
+{
+    /* Find the highest priority pending interrupt among the
+     * redistributor interrupts (SGIs and PPIs).
+     */
+    bool seenbetter = false;
+    uint8_t prio;
+    int i;
+    uint32_t pend;
+
+    /* Find out which redistributor interrupts are eligible to be
+     * signaled to the CPU interface.
+     */
+    pend = gicr_int_pending(cs);
+
+    if (pend) {
+        for (i = 0; i < GIC_INTERNAL; i++) {
+            if (!(pend & (1 << i))) {
+                continue;
+            }
+            prio = cs->gicr_ipriorityr[i];
+            if (irqbetter(cs, i, prio)) {
+                cs->hppi.irq = i;
+                cs->hppi.prio = prio;
+                seenbetter = true;
+            }
+        }
+    }
+
+    if (seenbetter) {
+        cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
+    }
+
+    /* If the best interrupt we just found would preempt whatever
+     * was the previous best interrupt before this update, then
+     * we know it's definitely the best one now.
+     * If we didn't find an interrupt that would preempt the previous
+     * best, and the previous best is outside our range (or there was no
+     * previous pending interrupt at all), then that is still valid, and
+     * we leave it as the best.
+     * Otherwise, we need to do a full update (because the previous best
+     * interrupt has reduced in priority and any other interrupt could
+     * now be the new best one).
+     */
+    if (!seenbetter && cs->hppi.prio != 0xff && cs->hppi.irq < GIC_INTERNAL) {
+        gicv3_full_update_noirqset(cs->gic);
+    }
+}
+
+/* Update the GIC status after state in a redistributor or
+ * CPU interface has changed, and inform the CPU i/f of
+ * its new highest priority pending interrupt.
+ */
+void gicv3_redist_update(GICv3CPUState *cs)
+{
+    gicv3_redist_update_noirqset(cs);
+    gicv3_cpuif_update(cs);
+}
+
+/* Update the GIC status after state in the distributor has
+ * changed affecting @len interrupts starting at @start,
+ * but don't tell the CPU i/f.
+ */
+static void gicv3_update_noirqset(GICv3State *s, int start, int len)
+{
+    int i;
+    uint8_t prio;
+    uint32_t pend = 0;
+
+    assert(start >= GIC_INTERNAL);
+    assert(len > 0);
+
+    for (i = 0; i < s->num_cpu; i++) {
+        s->cpu[i].seenbetter = false;
+    }
+
+    /* Find the highest priority pending interrupt in this range. */
+    for (i = start; i < start + len; i++) {
+        GICv3CPUState *cs;
+
+        if (i == start || (i & 0x1f) == 0) {
+            /* Calculate the next 32 bits worth of pending status */
+            pend = gicd_int_pending(s, i & ~0x1f);
+        }
+
+        if (!(pend & (1 << (i & 0x1f)))) {
+            continue;
+        }
+        cs = s->gicd_irouter_target[i];
+        if (!cs) {
+            /* Interrupts targeting no implemented CPU should remain pending
+             * and not be forwarded to any CPU.
+             */
+            continue;
+        }
+        prio = s->gicd_ipriority[i];
+        if (irqbetter(cs, i, prio)) {
+            cs->hppi.irq = i;
+            cs->hppi.prio = prio;
+            cs->seenbetter = true;
+        }
+    }
+
+    /* If the best interrupt we just found would preempt whatever
+     * was the previous best interrupt before this update, then
+     * we know it's definitely the best one now.
+     * If we didn't find an interrupt that would preempt the previous
+     * best, and the previous best is outside our range (or there was
+     * no previous pending interrupt at all), then that
+     * is still valid, and we leave it as the best.
+     * Otherwise, we need to do a full update (because the previous best
+     * interrupt has reduced in priority and any other interrupt could
+     * now be the new best one).
+     */
+    for (i = 0; i < s->num_cpu; i++) {
+        GICv3CPUState *cs = &s->cpu[i];
+
+        if (cs->seenbetter) {
+            cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
+        }
+
+        if (!cs->seenbetter && cs->hppi.prio != 0xff &&
+            cs->hppi.irq >= start && cs->hppi.irq < start + len) {
+            gicv3_full_update_noirqset(s);
+            break;
+        }
+    }
+}
+
+void gicv3_update(GICv3State *s, int start, int len)
+{
+    int i;
+
+    gicv3_update_noirqset(s, start, len);
+    for (i = 0; i < s->num_cpu; i++) {
+        gicv3_cpuif_update(&s->cpu[i]);
+    }
+}
+
+void gicv3_full_update_noirqset(GICv3State *s)
+{
+    /* Completely recalculate the GIC status from scratch, but
+     * don't update any outbound IRQ lines.
+     */
+    int i;
+
+    for (i = 0; i < s->num_cpu; i++) {
+        s->cpu[i].hppi.prio = 0xff;
+    }
+
+    /* Note that we can guarantee that these functions will not
+     * recursively call back into gicv3_full_update(), because
+     * at each point the "previous best" is always outside the
+     * range we ask them to update.
+     */
+    gicv3_update_noirqset(s, GIC_INTERNAL, s->num_irq - GIC_INTERNAL);
+
+    for (i = 0; i < s->num_cpu; i++) {
+        gicv3_redist_update_noirqset(&s->cpu[i]);
+    }
+}
+
+void gicv3_full_update(GICv3State *s)
+{
+    /* Completely recalculate the GIC status from scratch, including
+     * updating outbound IRQ lines.
+     */
+    int i;
+
+    gicv3_full_update_noirqset(s);
+    for (i = 0; i < s->num_cpu; i++) {
+        gicv3_cpuif_update(&s->cpu[i]);
+    }
+}
+
 /* Process a change in an external IRQ input. */
 static void gicv3_set_irq(void *opaque, int irq, int level)
 {
@@ -33,6 +314,16 @@ static void gicv3_set_irq(void *opaque, int irq, int level)
     /* Do nothing for now */
 }
 
+static void arm_gicv3_post_load(GICv3State *s)
+{
+    /* Recalculate our cached idea of the current highest priority
+     * pending interrupt, but don't set IRQ or FIQ lines.
+     */
+    gicv3_full_update_noirqset(s);
+    /* Repopulate the cache of GICv3CPUState pointers for target CPUs */
+    gicv3_cache_all_target_cpustates(s);
+}
+
 static void arm_gic_realize(DeviceState *dev, Error **errp)
 {
     /* Device instance realize function for the GIC sysbus device */
@@ -52,8 +343,10 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
 static void arm_gicv3_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
     ARMGICv3Class *agc = ARM_GICV3_CLASS(klass);
 
+    agcc->post_load = arm_gicv3_post_load;
     agc->parent_realize = dc->realize;
     dc->realize = arm_gic_realize;
 }
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index d1714e4..0f8c4b8 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -246,6 +246,8 @@ static void arm_gicv3_common_reset(DeviceState *dev)
         cs->gicr_nsacr = 0;
         memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr));
 
+        cs->hppi.prio = 0xff;
+
         /* State in the CPU interface must *not* be reset here, because it
          * is part of the CPU's reset domain, not the GIC device's.
          */
@@ -271,6 +273,13 @@ static void arm_gicv3_common_reset(DeviceState *dev)
     memset(s->gicd_ipriority, 0, sizeof(s->gicd_ipriority));
     memset(s->gicd_irouter, 0, sizeof(s->gicd_irouter));
     memset(s->gicd_nsacr, 0, sizeof(s->gicd_nsacr));
+    /* GICD_IROUTER are UNKNOWN at reset so in theory the guest must
+     * write these to get sane behaviour and we need not populate the
+     * pointer cache here; however having the cache be different for
+     * "happened to be 0 from reset" and "guest wrote 0" would be
+     * too confusing.
+     */
+    gicv3_cache_all_target_cpustates(s);
 
     if (s->irq_reset_nonsecure) {
         /* If we're resetting a TZ-aware GIC as if secure firmware
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 97c9d75..2ee9eeb 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -159,6 +159,63 @@
 #define ICC_CTLR_EL3_A3V (1U << 15)
 #define ICC_CTLR_EL3_NDS (1U << 17)
 
+/* Functions internal to the emulated GICv3 */
+
+/**
+ * gicv3_redist_update:
+ * @cs: GICv3CPUState for this redistributor
+ *
+ * Recalculate the highest priority pending interrupt after a
+ * change to redistributor state, and inform the CPU accordingly.
+ */
+void gicv3_redist_update(GICv3CPUState *cs);
+
+/**
+ * gicv3_update:
+ * @s: GICv3State
+ * @start: first interrupt whose state changed
+ * @len: length of the range of interrupts whose state changed
+ *
+ * Recalculate the highest priority pending interrupts after a
+ * change to the distributor state affecting @len interrupts
+ * starting at @start, and inform the CPUs accordingly.
+ */
+void gicv3_update(GICv3State *s, int start, int len);
+
+/**
+ * gicv3_full_update_noirqset:
+ * @s: GICv3State
+ *
+ * Recalculate the cached information about highest priority
+ * pending interrupts, but don't inform the CPUs. This should be
+ * called after an incoming migration has loaded new state.
+ */
+void gicv3_full_update_noirqset(GICv3State *s);
+
+/**
+ * gicv3_full_update:
+ * @s: GICv3State
+ *
+ * Recalculate the highest priority pending interrupts after
+ * a change that could affect the status of all interrupts,
+ * and inform the CPUs accordingly.
+ */
+void gicv3_full_update(GICv3State *s);
+
+/**
+ * gicv3_cpuif_update:
+ * @cs: GICv3CPUState for the CPU to update
+ *
+ * Recalculate whether to assert the IRQ or FIQ lines after a change
+ * to the current highest priority pending interrupt, the CPU's
+ * current running priority or the CPU's current exception level or
+ * security state.
+ */
+static inline void gicv3_cpuif_update(GICv3CPUState *cs)
+{
+    /* This will be implemented in a later commit. */
+}
+
 static inline uint32_t gicv3_iidr(void)
 {
     /* Return the Implementer Identification Register value
@@ -184,6 +241,32 @@ static inline uint32_t gicv3_idreg(int regoffset)
 }
 
 /**
+ * gicv3_irq_group:
+ *
+ * Return the group which this interrupt is configured as (GICV3_G0,
+ * GICV3_G1 or GICV3_G1NS).
+ */
+static inline int gicv3_irq_group(GICv3State *s, GICv3CPUState *cs, int irq)
+{
+    bool grpbit, grpmodbit;
+
+    if (irq < GIC_INTERNAL) {
+        grpbit = extract32(cs->gicr_igroupr0, irq, 1);
+        grpmodbit = extract32(cs->gicr_igrpmodr0, irq, 1);
+    } else {
+        grpbit = gicv3_gicd_group_test(s, irq);
+        grpmodbit = gicv3_gicd_grpmod_test(s, irq);
+    }
+    if (grpbit) {
+        return GICV3_G1NS;
+    }
+    if (s->gicd_ctlr & GICD_CTLR_DS) {
+        return GICV3_G0;
+    }
+    return grpmodbit ? GICV3_G1 : GICV3_G0;
+}
+
+/**
  * gicv3_redist_affid:
  *
  * Return the 32-bit affinity ID of the CPU connected to this redistributor
@@ -193,4 +276,42 @@ static inline uint32_t gicv3_redist_affid(GICv3CPUState *cs)
     return cs->gicr_typer >> 32;
 }
 
+/**
+ * gicv3_cache_target_cpustate:
+ *
+ * Update the cached CPU state corresponding to the target for this interrupt
+ * (which is kept in s->gicd_irouter_target[]).
+ */
+static inline void gicv3_cache_target_cpustate(GICv3State *s, int irq)
+{
+    GICv3CPUState *cs = NULL;
+    int i;
+    uint32_t tgtaff = extract64(s->gicd_irouter[irq], 0, 24) |
+        extract64(s->gicd_irouter[irq], 32, 8) << 24;
+
+    for (i = 0; i < s->num_cpu; i++) {
+        if (s->cpu[i].gicr_typer >> 32 == tgtaff) {
+            cs = &s->cpu[i];
+            break;
+        }
+    }
+
+    s->gicd_irouter_target[irq] = cs;
+}
+
+/**
+ * gicv3_cache_all_target_cpustates:
+ *
+ * Populate the entire cache of CPU state pointers for interrupt targets
+ * (eg after inbound migration or CPU reset)
+ */
+static inline void gicv3_cache_all_target_cpustates(GICv3State *s)
+{
+    int irq;
+
+    for (irq = GIC_INTERNAL; irq < GICV3_MAXIRQ; irq++) {
+        gicv3_cache_target_cpustate(s, irq);
+    }
+}
+
 #endif /* !QEMU_ARM_GIC_INTERNAL_H */
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index cc6ac74..f72e499 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -131,6 +131,12 @@ typedef struct GICv3CPUState GICv3CPUState;
 #define GICV3_S 0
 #define GICV3_NS 1
 
+typedef struct {
+    int irq;
+    uint8_t prio;
+    int grp;
+} PendingIrq;
+
 struct GICv3CPUState {
     GICv3State *gic;
     CPUState *cpu;
@@ -163,6 +169,14 @@ struct GICv3CPUState {
     uint64_t icc_apr[3][4];
     uint64_t icc_igrpen[3];
     uint64_t icc_ctlr_el3;
+
+    /* Current highest priority pending interrupt for this CPU.
+     * This is cached information that can be recalculated from the
+     * real state above; it doesn't need to be migrated.
+     */
+    PendingIrq hppi;
+    /* This is temporary working state, to avoid a malloc in gicv3_update() */
+    bool seenbetter;
 };
 
 struct GICv3State {
@@ -198,6 +212,10 @@ struct GICv3State {
     GIC_DECLARE_BITMAP(edge_trigger); /* GICD_ICFGR even bits */
     uint8_t gicd_ipriority[GICV3_MAXIRQ];
     uint64_t gicd_irouter[GICV3_MAXIRQ];
+    /* Cached information: pointer to the cpu i/f for the CPUs specified
+     * in the IROUTER registers
+     */
+    GICv3CPUState *gicd_irouter_target[GICV3_MAXIRQ];
     uint32_t gicd_nsacr[DIV_ROUND_UP(GICV3_MAXIRQ, 16)];
 
     GICv3CPUState *cpu;
-- 
1.9.1

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

* [Qemu-devel] [PULL 11/22] hw/intc/arm_gicv3: Implement GICv3 distributor registers
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (9 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 10/22] hw/intc/arm_gicv3: Implement functions to identify next pending irq Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 12/22] hw/intc/arm_gicv3: Implement GICv3 redistributor registers Peter Maydell
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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

Implement the distributor registers of a GICv3.

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

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 4e94fdd..a173d29 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -14,6 +14,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
 common-obj-$(CONFIG_OPENPIC) += openpic.o
 
 obj-$(CONFIG_APIC) += apic.o apic_common.o
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
new file mode 100644
index 0000000..881d555
--- /dev/null
+++ b/hw/intc/arm_gicv3_dist.c
@@ -0,0 +1,858 @@
+/*
+ * ARM GICv3 emulation: Distributor
+ *
+ * Copyright (c) 2015 Huawei.
+ * Copyright (c) 2016 Linaro Limited.
+ * Written by Shlomo Pongratz, Peter Maydell
+ *
+ * This code is licensed under the GPL, version 2 or (at your option)
+ * any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "trace.h"
+#include "gicv3_internal.h"
+
+/* The GICD_NSACR registers contain a two bit field for each interrupt which
+ * allows the guest to give NonSecure code access to registers controlling
+ * Secure interrupts:
+ *  0b00: no access (NS accesses to bits for Secure interrupts will RAZ/WI)
+ *  0b01: NS r/w accesses permitted to ISPENDR, SETSPI_NSR, SGIR
+ *  0b10: as 0b01, and also r/w to ICPENDR, r/o to ISACTIVER/ICACTIVER,
+ *        and w/o to CLRSPI_NSR
+ *  0b11: as 0b10, and also r/w to IROUTER and ITARGETSR
+ *
+ * Given a (multiple-of-32) interrupt number, these mask functions return
+ * a mask word where each bit is 1 if the NSACR settings permit access
+ * to the interrupt. The mask returned can then be ORed with the GICD_GROUP
+ * word for this set of interrupts to give an overall mask.
+ */
+
+typedef uint32_t maskfn(GICv3State *s, int irq);
+
+static uint32_t mask_nsacr_ge1(GICv3State *s, int irq)
+{
+    /* Return a mask where each bit is set if the NSACR field is >= 1 */
+    uint64_t raw_nsacr = s->gicd_nsacr[irq / 16 + 1];
+
+    raw_nsacr = raw_nsacr << 32 | s->gicd_nsacr[irq / 16];
+    raw_nsacr = (raw_nsacr >> 1) | raw_nsacr;
+    return half_unshuffle64(raw_nsacr);
+}
+
+static uint32_t mask_nsacr_ge2(GICv3State *s, int irq)
+{
+    /* Return a mask where each bit is set if the NSACR field is >= 2 */
+    uint64_t raw_nsacr = s->gicd_nsacr[irq / 16 + 1];
+
+    raw_nsacr = raw_nsacr << 32 | s->gicd_nsacr[irq / 16];
+    raw_nsacr = raw_nsacr >> 1;
+    return half_unshuffle64(raw_nsacr);
+}
+
+/* We don't need a mask_nsacr_ge3() because IROUTER<n> isn't a bitmap register,
+ * but it would be implemented using:
+ *  raw_nsacr = (raw_nsacr >> 1) & raw_nsacr;
+ */
+
+static uint32_t mask_group_and_nsacr(GICv3State *s, MemTxAttrs attrs,
+                                     maskfn *maskfn, int irq)
+{
+    /* Return a 32-bit mask which should be applied for this set of 32
+     * interrupts; each bit is 1 if access is permitted by the
+     * combination of attrs.secure, GICD_GROUPR and GICD_NSACR.
+     */
+    uint32_t mask;
+
+    if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) {
+        /* bits for Group 0 or Secure Group 1 interrupts are RAZ/WI
+         * unless the NSACR bits permit access.
+         */
+        mask = *gic_bmp_ptr32(s->group, irq);
+        if (maskfn) {
+            mask |= maskfn(s, irq);
+        }
+        return mask;
+    }
+    return 0xFFFFFFFFU;
+}
+
+static int gicd_ns_access(GICv3State *s, int irq)
+{
+    /* Return the 2 bit NS_access<x> field from GICD_NSACR<n> for the
+     * specified interrupt.
+     */
+    if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+        return 0;
+    }
+    return extract32(s->gicd_nsacr[irq / 16], (irq % 16) * 2, 2);
+}
+
+static void gicd_write_set_bitmap_reg(GICv3State *s, MemTxAttrs attrs,
+                                      uint32_t *bmp,
+                                      maskfn *maskfn,
+                                      int offset, uint32_t val)
+{
+    /* Helper routine to implement writing to a "set-bitmap" register
+     * (GICD_ISENABLER, GICD_ISPENDR, etc).
+     * Semantics implemented here:
+     * RAZ/WI for SGIs, PPIs, unimplemented IRQs
+     * Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI.
+     * Writing 1 means "set bit in bitmap"; writing 0 is ignored.
+     * offset should be the offset in bytes of the register from the start
+     * of its group.
+     */
+    int irq = offset * 8;
+
+    if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+        return;
+    }
+    val &= mask_group_and_nsacr(s, attrs, maskfn, irq);
+    *gic_bmp_ptr32(bmp, irq) |= val;
+    gicv3_update(s, irq, 32);
+}
+
+static void gicd_write_clear_bitmap_reg(GICv3State *s, MemTxAttrs attrs,
+                                        uint32_t *bmp,
+                                        maskfn *maskfn,
+                                        int offset, uint32_t val)
+{
+    /* Helper routine to implement writing to a "clear-bitmap" register
+     * (GICD_ICENABLER, GICD_ICPENDR, etc).
+     * Semantics implemented here:
+     * RAZ/WI for SGIs, PPIs, unimplemented IRQs
+     * Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI.
+     * Writing 1 means "clear bit in bitmap"; writing 0 is ignored.
+     * offset should be the offset in bytes of the register from the start
+     * of its group.
+     */
+    int irq = offset * 8;
+
+    if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+        return;
+    }
+    val &= mask_group_and_nsacr(s, attrs, maskfn, irq);
+    *gic_bmp_ptr32(bmp, irq) &= ~val;
+    gicv3_update(s, irq, 32);
+}
+
+static uint32_t gicd_read_bitmap_reg(GICv3State *s, MemTxAttrs attrs,
+                                     uint32_t *bmp,
+                                     maskfn *maskfn,
+                                     int offset)
+{
+    /* Helper routine to implement reading a "set/clear-bitmap" register
+     * (GICD_ICENABLER, GICD_ISENABLER, GICD_ICPENDR, etc).
+     * Semantics implemented here:
+     * RAZ/WI for SGIs, PPIs, unimplemented IRQs
+     * Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI.
+     * offset should be the offset in bytes of the register from the start
+     * of its group.
+     */
+    int irq = offset * 8;
+    uint32_t val;
+
+    if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+        return 0;
+    }
+    val = *gic_bmp_ptr32(bmp, irq);
+    if (bmp == s->pending) {
+        /* The PENDING register is a special case -- for level triggered
+         * interrupts, the PENDING state is the logical OR of the state of
+         * the PENDING latch with the input line level.
+         */
+        uint32_t edge = *gic_bmp_ptr32(s->edge_trigger, irq);
+        uint32_t level = *gic_bmp_ptr32(s->level, irq);
+        val |= (~edge & level);
+    }
+    val &= mask_group_and_nsacr(s, attrs, maskfn, irq);
+    return val;
+}
+
+static uint8_t gicd_read_ipriorityr(GICv3State *s, MemTxAttrs attrs, int irq)
+{
+    /* Read the value of GICD_IPRIORITYR<n> for the specified interrupt,
+     * honouring security state (these are RAZ/WI for Group 0 or Secure
+     * Group 1 interrupts).
+     */
+    uint32_t prio;
+
+    if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+        return 0;
+    }
+
+    prio = s->gicd_ipriority[irq];
+
+    if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) {
+        if (!gicv3_gicd_group_test(s, irq)) {
+            /* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */
+            return 0;
+        }
+        /* NS view of the interrupt priority */
+        prio = (prio << 1) & 0xff;
+    }
+    return prio;
+}
+
+static void gicd_write_ipriorityr(GICv3State *s, MemTxAttrs attrs, int irq,
+                                  uint8_t value)
+{
+    /* Write the value of GICD_IPRIORITYR<n> for the specified interrupt,
+     * honouring security state (these are RAZ/WI for Group 0 or Secure
+     * Group 1 interrupts).
+     */
+    if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+        return;
+    }
+
+    if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) {
+        if (!gicv3_gicd_group_test(s, irq)) {
+            /* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */
+            return;
+        }
+        /* NS view of the interrupt priority */
+        value = 0x80 | (value >> 1);
+    }
+    s->gicd_ipriority[irq] = value;
+}
+
+static uint64_t gicd_read_irouter(GICv3State *s, MemTxAttrs attrs, int irq)
+{
+    /* Read the value of GICD_IROUTER<n> for the specified interrupt,
+     * honouring security state.
+     */
+    if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+        return 0;
+    }
+
+    if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) {
+        /* RAZ/WI for NS accesses to secure interrupts */
+        if (!gicv3_gicd_group_test(s, irq)) {
+            if (gicd_ns_access(s, irq) != 3) {
+                return 0;
+            }
+        }
+    }
+
+    return s->gicd_irouter[irq];
+}
+
+static void gicd_write_irouter(GICv3State *s, MemTxAttrs attrs, int irq,
+                               uint64_t val)
+{
+    /* Write the value of GICD_IROUTER<n> for the specified interrupt,
+     * honouring security state.
+     */
+    if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+        return;
+    }
+
+    if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) {
+        /* RAZ/WI for NS accesses to secure interrupts */
+        if (!gicv3_gicd_group_test(s, irq)) {
+            if (gicd_ns_access(s, irq) != 3) {
+                return;
+            }
+        }
+    }
+
+    s->gicd_irouter[irq] = val;
+    gicv3_cache_target_cpustate(s, irq);
+    gicv3_update(s, irq, 1);
+}
+
+static MemTxResult gicd_readb(GICv3State *s, hwaddr offset,
+                              uint64_t *data, MemTxAttrs attrs)
+{
+    /* Most GICv3 distributor registers do not support byte accesses. */
+    switch (offset) {
+    case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf:
+    case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf:
+    case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff:
+        /* This GIC implementation always has affinity routing enabled,
+         * so these registers are all RAZ/WI.
+         */
+        return MEMTX_OK;
+    case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff:
+        *data = gicd_read_ipriorityr(s, attrs, offset - GICD_IPRIORITYR);
+        return MEMTX_OK;
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+static MemTxResult gicd_writeb(GICv3State *s, hwaddr offset,
+                               uint64_t value, MemTxAttrs attrs)
+{
+    /* Most GICv3 distributor registers do not support byte accesses. */
+    switch (offset) {
+    case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf:
+    case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf:
+    case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff:
+        /* This GIC implementation always has affinity routing enabled,
+         * so these registers are all RAZ/WI.
+         */
+        return MEMTX_OK;
+    case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff:
+    {
+        int irq = offset - GICD_IPRIORITYR;
+
+        if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+            return MEMTX_OK;
+        }
+        gicd_write_ipriorityr(s, attrs, irq, value);
+        gicv3_update(s, irq, 1);
+        return MEMTX_OK;
+    }
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+static MemTxResult gicd_readw(GICv3State *s, hwaddr offset,
+                              uint64_t *data, MemTxAttrs attrs)
+{
+    /* Only GICD_SETSPI_NSR, GICD_CLRSPI_NSR, GICD_SETSPI_SR and GICD_SETSPI_NSR
+     * support 16 bit accesses, and those registers are all part of the
+     * optional message-based SPI feature which this GIC does not currently
+     * implement (ie for us GICD_TYPER.MBIS == 0), so for us they are
+     * reserved.
+     */
+    return MEMTX_ERROR;
+}
+
+static MemTxResult gicd_writew(GICv3State *s, hwaddr offset,
+                               uint64_t value, MemTxAttrs attrs)
+{
+    /* Only GICD_SETSPI_NSR, GICD_CLRSPI_NSR, GICD_SETSPI_SR and GICD_SETSPI_NSR
+     * support 16 bit accesses, and those registers are all part of the
+     * optional message-based SPI feature which this GIC does not currently
+     * implement (ie for us GICD_TYPER.MBIS == 0), so for us they are
+     * reserved.
+     */
+    return MEMTX_ERROR;
+}
+
+static MemTxResult gicd_readl(GICv3State *s, hwaddr offset,
+                              uint64_t *data, MemTxAttrs attrs)
+{
+    /* Almost all GICv3 distributor registers are 32-bit.
+     * Note that WO registers must return an UNKNOWN value on reads,
+     * not an abort.
+     */
+
+    switch (offset) {
+    case GICD_CTLR:
+        if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) {
+            /* The NS view of the GICD_CTLR sees only certain bits:
+             * + bit [31] (RWP) is an alias of the Secure bit [31]
+             * + bit [4] (ARE_NS) is an alias of Secure bit [5]
+             * + bit [1] (EnableGrp1A) is an alias of Secure bit [1] if
+             *   NS affinity routing is enabled, otherwise RES0
+             * + bit [0] (EnableGrp1) is an alias of Secure bit [1] if
+             *   NS affinity routing is not enabled, otherwise RES0
+             * Since for QEMU affinity routing is always enabled
+             * for both S and NS this means that bits [4] and [5] are
+             * both always 1, and we can simply make the NS view
+             * be bits 31, 4 and 1 of the S view.
+             */
+            *data = s->gicd_ctlr & (GICD_CTLR_ARE_S |
+                                    GICD_CTLR_EN_GRP1NS |
+                                    GICD_CTLR_RWP);
+        } else {
+            *data = s->gicd_ctlr;
+        }
+        return MEMTX_OK;
+    case GICD_TYPER:
+    {
+        /* For this implementation:
+         * No1N == 1 (1-of-N SPI interrupts not supported)
+         * A3V == 1 (non-zero values of Affinity level 3 supported)
+         * IDbits == 0xf (we support 16-bit interrupt identifiers)
+         * DVIS == 0 (Direct virtual LPI injection not supported)
+         * LPIS == 0 (LPIs not supported)
+         * MBIS == 0 (message-based SPIs not supported)
+         * SecurityExtn == 1 if security extns supported
+         * CPUNumber == 0 since for us ARE is always 1
+         * ITLinesNumber == (num external irqs / 32) - 1
+         */
+        int itlinesnumber = ((s->num_irq - GIC_INTERNAL) / 32) - 1;
+
+        *data = (1 << 25) | (1 << 24) | (s->security_extn << 10) |
+            (0xf << 19) | itlinesnumber;
+        return MEMTX_OK;
+    }
+    case GICD_IIDR:
+        /* We claim to be an ARM r0p0 with a zero ProductID.
+         * This is the same as an r0p0 GIC-500.
+         */
+        *data = gicv3_iidr();
+        return MEMTX_OK;
+    case GICD_STATUSR:
+        /* RAZ/WI for us (this is an optional register and our implementation
+         * does not track RO/WO/reserved violations to report them to the guest)
+         */
+        *data = 0;
+        return MEMTX_OK;
+    case GICD_IGROUPR ... GICD_IGROUPR + 0x7f:
+    {
+        int irq;
+
+        if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) {
+            *data = 0;
+            return MEMTX_OK;
+        }
+        /* RAZ/WI for SGIs, PPIs, unimplemented irqs */
+        irq = (offset - GICD_IGROUPR) * 8;
+        if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+            *data = 0;
+            return MEMTX_OK;
+        }
+        *data = *gic_bmp_ptr32(s->group, irq);
+        return MEMTX_OK;
+    }
+    case GICD_ISENABLER ... GICD_ISENABLER + 0x7f:
+        *data = gicd_read_bitmap_reg(s, attrs, s->enabled, NULL,
+                                     offset - GICD_ISENABLER);
+        return MEMTX_OK;
+    case GICD_ICENABLER ... GICD_ICENABLER + 0x7f:
+        *data = gicd_read_bitmap_reg(s, attrs, s->enabled, NULL,
+                                     offset - GICD_ICENABLER);
+        return MEMTX_OK;
+    case GICD_ISPENDR ... GICD_ISPENDR + 0x7f:
+        *data = gicd_read_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge1,
+                                     offset - GICD_ISPENDR);
+        return MEMTX_OK;
+    case GICD_ICPENDR ... GICD_ICPENDR + 0x7f:
+        *data = gicd_read_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge2,
+                                     offset - GICD_ICPENDR);
+        return MEMTX_OK;
+    case GICD_ISACTIVER ... GICD_ISACTIVER + 0x7f:
+        *data = gicd_read_bitmap_reg(s, attrs, s->active, mask_nsacr_ge2,
+                                     offset - GICD_ISACTIVER);
+        return MEMTX_OK;
+    case GICD_ICACTIVER ... GICD_ICACTIVER + 0x7f:
+        *data = gicd_read_bitmap_reg(s, attrs, s->active, mask_nsacr_ge2,
+                                     offset - GICD_ICACTIVER);
+        return MEMTX_OK;
+    case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff:
+    {
+        int i, irq = offset - GICD_IPRIORITYR;
+        uint32_t value = 0;
+
+        for (i = irq + 3; i >= irq; i--, value <<= 8) {
+            value |= gicd_read_ipriorityr(s, attrs, i);
+        }
+        *data = value;
+        return MEMTX_OK;
+    }
+    case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff:
+        /* RAZ/WI since affinity routing is always enabled */
+        *data = 0;
+        return MEMTX_OK;
+    case GICD_ICFGR ... GICD_ICFGR + 0xff:
+    {
+        /* Here only the even bits are used; odd bits are RES0 */
+        int irq = (offset - GICD_ICFGR) * 4;
+        uint32_t value = 0;
+
+        if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+            *data = 0;
+            return MEMTX_OK;
+        }
+
+        /* Since our edge_trigger bitmap is one bit per irq, we only need
+         * half of the 32-bit word, which we can then spread out
+         * into the odd bits.
+         */
+        value = *gic_bmp_ptr32(s->edge_trigger, irq & ~0x1f);
+        value &= mask_group_and_nsacr(s, attrs, NULL, irq & ~0x1f);
+        value = extract32(value, (irq & 0x1f) ? 16 : 0, 16);
+        value = half_shuffle32(value) << 1;
+        *data = value;
+        return MEMTX_OK;
+    }
+    case GICD_IGRPMODR ... GICD_IGRPMODR + 0xff:
+    {
+        int irq;
+
+        if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) {
+            /* RAZ/WI if security disabled, or if
+             * security enabled and this is an NS access
+             */
+            *data = 0;
+            return MEMTX_OK;
+        }
+        /* RAZ/WI for SGIs, PPIs, unimplemented irqs */
+        irq = (offset - GICD_IGRPMODR) * 8;
+        if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+            *data = 0;
+            return MEMTX_OK;
+        }
+        *data = *gic_bmp_ptr32(s->grpmod, irq);
+        return MEMTX_OK;
+    }
+    case GICD_NSACR ... GICD_NSACR + 0xff:
+    {
+        /* Two bits per interrupt */
+        int irq = (offset - GICD_NSACR) * 4;
+
+        if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+            *data = 0;
+            return MEMTX_OK;
+        }
+
+        if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) {
+            /* RAZ/WI if security disabled, or if
+             * security enabled and this is an NS access
+             */
+            *data = 0;
+            return MEMTX_OK;
+        }
+
+        *data = s->gicd_nsacr[irq / 16];
+        return MEMTX_OK;
+    }
+    case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf:
+    case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf:
+        /* RAZ/WI since affinity routing is always enabled */
+        *data = 0;
+        return MEMTX_OK;
+    case GICD_IROUTER ... GICD_IROUTER + 0x1fdf:
+    {
+        uint64_t r;
+        int irq = (offset - GICD_IROUTER) / 8;
+
+        r = gicd_read_irouter(s, attrs, irq);
+        if (offset & 7) {
+            *data = r >> 32;
+        } else {
+            *data = (uint32_t)r;
+        }
+        return MEMTX_OK;
+    }
+    case GICD_IDREGS ... GICD_IDREGS + 0x1f:
+        /* ID registers */
+        *data = gicv3_idreg(offset - GICD_IDREGS);
+        return MEMTX_OK;
+    case GICD_SGIR:
+        /* WO registers, return unknown value */
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid guest read from WO register at offset "
+                      TARGET_FMT_plx "\n", __func__, offset);
+        *data = 0;
+        return MEMTX_OK;
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+static MemTxResult gicd_writel(GICv3State *s, hwaddr offset,
+                               uint64_t value, MemTxAttrs attrs)
+{
+    /* Almost all GICv3 distributor registers are 32-bit. Note that
+     * RO registers must ignore writes, not abort.
+     */
+
+    switch (offset) {
+    case GICD_CTLR:
+    {
+        uint32_t mask;
+        /* GICv3 5.3.20 */
+        if (s->gicd_ctlr & GICD_CTLR_DS) {
+            /* With only one security state, E1NWF is RAZ/WI, DS is RAO/WI,
+             * ARE is RAO/WI (affinity routing always on), and only
+             * bits 0 and 1 (group enables) are writable.
+             */
+            mask = GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1NS;
+        } else {
+            if (attrs.secure) {
+                /* for secure access:
+                 * ARE_NS and ARE_S are RAO/WI (affinity routing always on)
+                 * E1NWF is RAZ/WI (we don't support enable-1-of-n-wakeup)
+                 *
+                 * We can only modify bits[2:0] (the group enables).
+                 */
+                mask = GICD_CTLR_DS | GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1_ALL;
+            } else {
+                /* For non secure access ARE_NS is RAO/WI and EnableGrp1
+                 * is RES0. The only writable bit is [1] (EnableGrp1A), which
+                 * is an alias of the Secure bit [1].
+                 */
+                mask = GICD_CTLR_EN_GRP1NS;
+            }
+        }
+        s->gicd_ctlr = (s->gicd_ctlr & ~mask) | (value & mask);
+        if (value & mask & GICD_CTLR_DS) {
+            /* We just set DS, so the ARE_NS and EnG1S bits are now RES0.
+             * Note that this is a one-way transition because if DS is set
+             * then it's not writeable, so it can only go back to 0 with a
+             * hardware reset.
+             */
+            s->gicd_ctlr &= ~(GICD_CTLR_EN_GRP1S | GICD_CTLR_ARE_NS);
+        }
+        gicv3_full_update(s);
+        return MEMTX_OK;
+    }
+    case GICD_STATUSR:
+        /* RAZ/WI for our implementation */
+        return MEMTX_OK;
+    case GICD_IGROUPR ... GICD_IGROUPR + 0x7f:
+    {
+        int irq;
+
+        if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) {
+            return MEMTX_OK;
+        }
+        /* RAZ/WI for SGIs, PPIs, unimplemented irqs */
+        irq = (offset - GICD_IGROUPR) * 8;
+        if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+            return MEMTX_OK;
+        }
+        *gic_bmp_ptr32(s->group, irq) = value;
+        gicv3_update(s, irq, 32);
+        return MEMTX_OK;
+    }
+    case GICD_ISENABLER ... GICD_ISENABLER + 0x7f:
+        gicd_write_set_bitmap_reg(s, attrs, s->enabled, NULL,
+                                  offset - GICD_ISENABLER, value);
+        return MEMTX_OK;
+    case GICD_ICENABLER ... GICD_ICENABLER + 0x7f:
+        gicd_write_clear_bitmap_reg(s, attrs, s->enabled, NULL,
+                                    offset - GICD_ICENABLER, value);
+        return MEMTX_OK;
+    case GICD_ISPENDR ... GICD_ISPENDR + 0x7f:
+        gicd_write_set_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge1,
+                                  offset - GICD_ISPENDR, value);
+        return MEMTX_OK;
+    case GICD_ICPENDR ... GICD_ICPENDR + 0x7f:
+        gicd_write_clear_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge2,
+                                    offset - GICD_ICPENDR, value);
+        return MEMTX_OK;
+    case GICD_ISACTIVER ... GICD_ISACTIVER + 0x7f:
+        gicd_write_set_bitmap_reg(s, attrs, s->active, NULL,
+                                  offset - GICD_ISACTIVER, value);
+        return MEMTX_OK;
+    case GICD_ICACTIVER ... GICD_ICACTIVER + 0x7f:
+        gicd_write_clear_bitmap_reg(s, attrs, s->active, NULL,
+                                    offset - GICD_ICACTIVER, value);
+        return MEMTX_OK;
+    case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff:
+    {
+        int i, irq = offset - GICD_IPRIORITYR;
+
+        if (irq < GIC_INTERNAL || irq + 3 >= s->num_irq) {
+            return MEMTX_OK;
+        }
+
+        for (i = irq; i < irq + 4; i++, value >>= 8) {
+            gicd_write_ipriorityr(s, attrs, i, value);
+        }
+        gicv3_update(s, irq, 4);
+        return MEMTX_OK;
+    }
+    case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff:
+        /* RAZ/WI since affinity routing is always enabled */
+        return MEMTX_OK;
+    case GICD_ICFGR ... GICD_ICFGR + 0xff:
+    {
+        /* Here only the odd bits are used; even bits are RES0 */
+        int irq = (offset - GICD_ICFGR) * 4;
+        uint32_t mask, oldval;
+
+        if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+            return MEMTX_OK;
+        }
+
+        /* Since our edge_trigger bitmap is one bit per irq, our input
+         * 32-bits will compress down into 16 bits which we need
+         * to write into the bitmap.
+         */
+        value = half_unshuffle32(value >> 1);
+        mask = mask_group_and_nsacr(s, attrs, NULL, irq & ~0x1f);
+        if (irq & 0x1f) {
+            value <<= 16;
+            mask &= 0xffff0000U;
+        } else {
+            mask &= 0xffff;
+        }
+        oldval = *gic_bmp_ptr32(s->edge_trigger, (irq & ~0x1f));
+        value = (oldval & ~mask) | (value & mask);
+        *gic_bmp_ptr32(s->edge_trigger, irq & ~0x1f) = value;
+        return MEMTX_OK;
+    }
+    case GICD_IGRPMODR ... GICD_IGRPMODR + 0xff:
+    {
+        int irq;
+
+        if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) {
+            /* RAZ/WI if security disabled, or if
+             * security enabled and this is an NS access
+             */
+            return MEMTX_OK;
+        }
+        /* RAZ/WI for SGIs, PPIs, unimplemented irqs */
+        irq = (offset - GICD_IGRPMODR) * 8;
+        if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+            return MEMTX_OK;
+        }
+        *gic_bmp_ptr32(s->grpmod, irq) = value;
+        gicv3_update(s, irq, 32);
+        return MEMTX_OK;
+    }
+    case GICD_NSACR ... GICD_NSACR + 0xff:
+    {
+        /* Two bits per interrupt */
+        int irq = (offset - GICD_NSACR) * 4;
+
+        if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+            return MEMTX_OK;
+        }
+
+        if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) {
+            /* RAZ/WI if security disabled, or if
+             * security enabled and this is an NS access
+             */
+            return MEMTX_OK;
+        }
+
+        s->gicd_nsacr[irq / 16] = value;
+        /* No update required as this only affects access permission checks */
+        return MEMTX_OK;
+    }
+    case GICD_SGIR:
+        /* RES0 if affinity routing is enabled */
+        return MEMTX_OK;
+    case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf:
+    case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf:
+        /* RAZ/WI since affinity routing is always enabled */
+        return MEMTX_OK;
+    case GICD_IROUTER ... GICD_IROUTER + 0x1fdf:
+    {
+        uint64_t r;
+        int irq = (offset - GICD_IROUTER) / 8;
+
+        if (irq < GIC_INTERNAL || irq >= s->num_irq) {
+            return MEMTX_OK;
+        }
+
+        /* Write half of the 64-bit register */
+        r = gicd_read_irouter(s, attrs, irq);
+        r = deposit64(r, (offset & 7) ? 32 : 0, 32, value);
+        gicd_write_irouter(s, attrs, irq, r);
+        return MEMTX_OK;
+    }
+    case GICD_IDREGS ... GICD_IDREGS + 0x1f:
+    case GICD_TYPER:
+    case GICD_IIDR:
+        /* RO registers, ignore the write */
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid guest write to RO register at offset "
+                      TARGET_FMT_plx "\n", __func__, offset);
+        return MEMTX_OK;
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+static MemTxResult gicd_writell(GICv3State *s, hwaddr offset,
+                                uint64_t value, MemTxAttrs attrs)
+{
+    /* Our only 64-bit registers are GICD_IROUTER<n> */
+    int irq;
+
+    switch (offset) {
+    case GICD_IROUTER ... GICD_IROUTER + 0x1fdf:
+        irq = (offset - GICD_IROUTER) / 8;
+        gicd_write_irouter(s, attrs, irq, value);
+        return MEMTX_OK;
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+static MemTxResult gicd_readll(GICv3State *s, hwaddr offset,
+                               uint64_t *data, MemTxAttrs attrs)
+{
+    /* Our only 64-bit registers are GICD_IROUTER<n> */
+    int irq;
+
+    switch (offset) {
+    case GICD_IROUTER ... GICD_IROUTER + 0x1fdf:
+        irq = (offset - GICD_IROUTER) / 8;
+        *data = gicd_read_irouter(s, attrs, irq);
+        return MEMTX_OK;
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data,
+                            unsigned size, MemTxAttrs attrs)
+{
+    GICv3State *s = (GICv3State *)opaque;
+    MemTxResult r;
+
+    switch (size) {
+    case 1:
+        r = gicd_readb(s, offset, data, attrs);
+        break;
+    case 2:
+        r = gicd_readw(s, offset, data, attrs);
+        break;
+    case 4:
+        r = gicd_readl(s, offset, data, attrs);
+        break;
+    case 8:
+        r = gicd_readll(s, offset, data, attrs);
+        break;
+    default:
+        r = MEMTX_ERROR;
+        break;
+    }
+
+    if (r == MEMTX_ERROR) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid guest read at offset " TARGET_FMT_plx
+                      "size %u\n", __func__, offset, size);
+        trace_gicv3_dist_badread(offset, size, attrs.secure);
+    } else {
+        trace_gicv3_dist_read(offset, *data, size, attrs.secure);
+    }
+    return r;
+}
+
+MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data,
+                             unsigned size, MemTxAttrs attrs)
+{
+    GICv3State *s = (GICv3State *)opaque;
+    MemTxResult r;
+
+    switch (size) {
+    case 1:
+        r = gicd_writeb(s, offset, data, attrs);
+        break;
+    case 2:
+        r = gicd_writew(s, offset, data, attrs);
+        break;
+    case 4:
+        r = gicd_writel(s, offset, data, attrs);
+        break;
+    case 8:
+        r = gicd_writell(s, offset, data, attrs);
+        break;
+    default:
+        r = MEMTX_ERROR;
+        break;
+    }
+
+    if (r == MEMTX_ERROR) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid guest write at offset " TARGET_FMT_plx
+                      "size %u\n", __func__, offset, size);
+        trace_gicv3_dist_badwrite(offset, data, size, attrs.secure);
+    } else {
+        trace_gicv3_dist_write(offset, data, size, attrs.secure);
+    }
+    return r;
+}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 2ee9eeb..7cb9926 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -201,6 +201,10 @@ void gicv3_full_update_noirqset(GICv3State *s);
  * and inform the CPUs accordingly.
  */
 void gicv3_full_update(GICv3State *s);
+MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data,
+                            unsigned size, MemTxAttrs attrs);
+MemTxResult gicv3_dist_write(void *opaque, hwaddr addr, uint64_t data,
+                             unsigned size, MemTxAttrs attrs);
 
 /**
  * gicv3_cpuif_update:
diff --git a/trace-events b/trace-events
index 17e901b..38030f8 100644
--- a/trace-events
+++ b/trace-events
@@ -2165,3 +2165,9 @@ e1000e_cfg_support_virtio(bool support) "Virtio header supported: %d"
 
 e1000e_vm_state_running(void) "VM state is running"
 e1000e_vm_state_stopped(void) "VM state is stopped"
+
+# hw/intc/arm_gicv3_dist.c
+gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
+gicv3_dist_badread(uint64_t offset, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " size %u secure %d: error"
+gicv3_dist_write(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
+gicv3_dist_badwrite(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
-- 
1.9.1

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

* [Qemu-devel] [PULL 12/22] hw/intc/arm_gicv3: Implement GICv3 redistributor registers
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (10 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 11/22] hw/intc/arm_gicv3: Implement GICv3 distributor registers Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 13/22] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions Peter Maydell
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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

Implement the redistributor registers of a GICv3.

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

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index a173d29..417db11 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -15,6 +15,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o
 common-obj-$(CONFIG_OPENPIC) += openpic.o
 
 obj-$(CONFIG_APIC) += apic.o apic_common.o
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
new file mode 100644
index 0000000..e0f23e1
--- /dev/null
+++ b/hw/intc/arm_gicv3_redist.c
@@ -0,0 +1,501 @@
+/*
+ * ARM GICv3 emulation: Redistributor
+ *
+ * Copyright (c) 2015 Huawei.
+ * Copyright (c) 2016 Linaro Limited.
+ * Written by Shlomo Pongratz, Peter Maydell
+ *
+ * This code is licensed under the GPL, version 2 or (at your option)
+ * any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "trace.h"
+#include "gicv3_internal.h"
+
+static uint32_t mask_group(GICv3CPUState *cs, MemTxAttrs attrs)
+{
+    /* Return a 32-bit mask which should be applied for this set of 32
+     * interrupts; each bit is 1 if access is permitted by the
+     * combination of attrs.secure and GICR_GROUPR. (GICR_NSACR does
+     * not affect config register accesses, unlike GICD_NSACR.)
+     */
+    if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
+        /* bits for Group 0 or Secure Group 1 interrupts are RAZ/WI */
+        return cs->gicr_igroupr0;
+    }
+    return 0xFFFFFFFFU;
+}
+
+static void gicr_write_set_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs,
+                                      uint32_t *reg, uint32_t val)
+{
+    /* Helper routine to implement writing to a "set-bitmap" register */
+    val &= mask_group(cs, attrs);
+    *reg |= val;
+    gicv3_redist_update(cs);
+}
+
+static void gicr_write_clear_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs,
+                                        uint32_t *reg, uint32_t val)
+{
+    /* Helper routine to implement writing to a "clear-bitmap" register */
+    val &= mask_group(cs, attrs);
+    *reg &= ~val;
+    gicv3_redist_update(cs);
+}
+
+static uint32_t gicr_read_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs,
+                                     uint32_t reg)
+{
+    reg &= mask_group(cs, attrs);
+    return reg;
+}
+
+static uint8_t gicr_read_ipriorityr(GICv3CPUState *cs, MemTxAttrs attrs,
+                                    int irq)
+{
+    /* Read the value of GICR_IPRIORITYR<n> for the specified interrupt,
+     * honouring security state (these are RAZ/WI for Group 0 or Secure
+     * Group 1 interrupts).
+     */
+    uint32_t prio;
+
+    prio = cs->gicr_ipriorityr[irq];
+
+    if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
+        if (!(cs->gicr_igroupr0 & (1U << irq))) {
+            /* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */
+            return 0;
+        }
+        /* NS view of the interrupt priority */
+        prio = (prio << 1) & 0xff;
+    }
+    return prio;
+}
+
+static void gicr_write_ipriorityr(GICv3CPUState *cs, MemTxAttrs attrs, int irq,
+                                  uint8_t value)
+{
+    /* Write the value of GICD_IPRIORITYR<n> for the specified interrupt,
+     * honouring security state (these are RAZ/WI for Group 0 or Secure
+     * Group 1 interrupts).
+     */
+    if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
+        if (!(cs->gicr_igroupr0 & (1U << irq))) {
+            /* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */
+            return;
+        }
+        /* NS view of the interrupt priority */
+        value = 0x80 | (value >> 1);
+    }
+    cs->gicr_ipriorityr[irq] = value;
+}
+
+static MemTxResult gicr_readb(GICv3CPUState *cs, hwaddr offset,
+                              uint64_t *data, MemTxAttrs attrs)
+{
+    switch (offset) {
+    case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f:
+        *data = gicr_read_ipriorityr(cs, attrs, offset - GICR_IPRIORITYR);
+        return MEMTX_OK;
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+static MemTxResult gicr_writeb(GICv3CPUState *cs, hwaddr offset,
+                               uint64_t value, MemTxAttrs attrs)
+{
+    switch (offset) {
+    case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f:
+        gicr_write_ipriorityr(cs, attrs, offset - GICR_IPRIORITYR, value);
+        gicv3_redist_update(cs);
+        return MEMTX_OK;
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+static MemTxResult gicr_readl(GICv3CPUState *cs, hwaddr offset,
+                              uint64_t *data, MemTxAttrs attrs)
+{
+    switch (offset) {
+    case GICR_CTLR:
+        *data = cs->gicr_ctlr;
+        return MEMTX_OK;
+    case GICR_IIDR:
+        *data = gicv3_iidr();
+        return MEMTX_OK;
+    case GICR_TYPER:
+        *data = extract64(cs->gicr_typer, 0, 32);
+        return MEMTX_OK;
+    case GICR_TYPER + 4:
+        *data = extract64(cs->gicr_typer, 32, 32);
+        return MEMTX_OK;
+    case GICR_STATUSR:
+        /* RAZ/WI for us (this is an optional register and our implementation
+         * does not track RO/WO/reserved violations to report them to the guest)
+         */
+        *data = 0;
+        return MEMTX_OK;
+    case GICR_WAKER:
+        *data = cs->gicr_waker;
+        return MEMTX_OK;
+    case GICR_PROPBASER:
+        *data = extract64(cs->gicr_propbaser, 0, 32);
+        return MEMTX_OK;
+    case GICR_PROPBASER + 4:
+        *data = extract64(cs->gicr_propbaser, 32, 32);
+        return MEMTX_OK;
+    case GICR_PENDBASER:
+        *data = extract64(cs->gicr_pendbaser, 0, 32);
+        return MEMTX_OK;
+    case GICR_PENDBASER + 4:
+        *data = extract64(cs->gicr_pendbaser, 32, 32);
+        return MEMTX_OK;
+    case GICR_IGROUPR0:
+        if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
+            *data = 0;
+            return MEMTX_OK;
+        }
+        *data = cs->gicr_igroupr0;
+        return MEMTX_OK;
+    case GICR_ISENABLER0:
+    case GICR_ICENABLER0:
+        *data = gicr_read_bitmap_reg(cs, attrs, cs->gicr_ienabler0);
+        return MEMTX_OK;
+    case GICR_ISPENDR0:
+    case GICR_ICPENDR0:
+    {
+        /* The pending register reads as the logical OR of the pending
+         * latch and the input line level for level-triggered interrupts.
+         */
+        uint32_t val = cs->gicr_ipendr0 | (~cs->edge_trigger & cs->level);
+        *data = gicr_read_bitmap_reg(cs, attrs, val);
+        return MEMTX_OK;
+    }
+    case GICR_ISACTIVER0:
+    case GICR_ICACTIVER0:
+        *data = gicr_read_bitmap_reg(cs, attrs, cs->gicr_iactiver0);
+        return MEMTX_OK;
+    case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f:
+    {
+        int i, irq = offset - GICR_IPRIORITYR;
+        uint32_t value = 0;
+
+        for (i = irq + 3; i >= irq; i--, value <<= 8) {
+            value |= gicr_read_ipriorityr(cs, attrs, i);
+        }
+        *data = value;
+        return MEMTX_OK;
+    }
+    case GICR_ICFGR0:
+    case GICR_ICFGR1:
+    {
+        /* Our edge_trigger bitmap is one bit per irq; take the correct
+         * half of it, and spread it out into the odd bits.
+         */
+        uint32_t value;
+
+        value = cs->edge_trigger & mask_group(cs, attrs);
+        value = extract32(value, (offset == GICR_ICFGR1) ? 16 : 0, 16);
+        value = half_shuffle32(value) << 1;
+        *data = value;
+        return MEMTX_OK;
+    }
+    case GICR_IGRPMODR0:
+        if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) {
+            /* RAZ/WI if security disabled, or if
+             * security enabled and this is an NS access
+             */
+            *data = 0;
+            return MEMTX_OK;
+        }
+        *data = cs->gicr_igrpmodr0;
+        return MEMTX_OK;
+    case GICR_NSACR:
+        if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) {
+            /* RAZ/WI if security disabled, or if
+             * security enabled and this is an NS access
+             */
+            *data = 0;
+            return MEMTX_OK;
+        }
+        *data = cs->gicr_nsacr;
+        return MEMTX_OK;
+    case GICR_IDREGS ... GICR_IDREGS + 0x1f:
+        *data = gicv3_idreg(offset - GICR_IDREGS);
+        return MEMTX_OK;
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
+                               uint64_t value, MemTxAttrs attrs)
+{
+    switch (offset) {
+    case GICR_CTLR:
+        /* For our implementation, GICR_TYPER.DPGS is 0 and so all
+         * the DPG bits are RAZ/WI. We don't do anything asynchronously,
+         * so UWP and RWP are RAZ/WI. And GICR_TYPER.LPIS is 0 (we don't
+         * implement LPIs) so Enable_LPIs is RES0. So there are no writable
+         * bits for us.
+         */
+        return MEMTX_OK;
+    case GICR_STATUSR:
+        /* RAZ/WI for our implementation */
+        return MEMTX_OK;
+    case GICR_WAKER:
+        /* Only the ProcessorSleep bit is writeable. When the guest sets
+         * it it requests that we transition the channel between the
+         * redistributor and the cpu interface to quiescent, and that
+         * we set the ChildrenAsleep bit once the inteface has reached the
+         * quiescent state.
+         * Setting the ProcessorSleep to 0 reverses the quiescing, and
+         * ChildrenAsleep is cleared once the transition is complete.
+         * Since our interface is not asynchronous, we complete these
+         * transitions instantaneously, so we set ChildrenAsleep to the
+         * same value as ProcessorSleep here.
+         */
+        value &= GICR_WAKER_ProcessorSleep;
+        if (value & GICR_WAKER_ProcessorSleep) {
+            value |= GICR_WAKER_ChildrenAsleep;
+        }
+        cs->gicr_waker = value;
+        return MEMTX_OK;
+    case GICR_PROPBASER:
+        cs->gicr_propbaser = deposit64(cs->gicr_propbaser, 0, 32, value);
+        return MEMTX_OK;
+    case GICR_PROPBASER + 4:
+        cs->gicr_propbaser = deposit64(cs->gicr_propbaser, 32, 32, value);
+        return MEMTX_OK;
+    case GICR_PENDBASER:
+        cs->gicr_pendbaser = deposit64(cs->gicr_pendbaser, 0, 32, value);
+        return MEMTX_OK;
+    case GICR_PENDBASER + 4:
+        cs->gicr_pendbaser = deposit64(cs->gicr_pendbaser, 32, 32, value);
+        return MEMTX_OK;
+    case GICR_IGROUPR0:
+        if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
+            return MEMTX_OK;
+        }
+        cs->gicr_igroupr0 = value;
+        gicv3_redist_update(cs);
+        return MEMTX_OK;
+    case GICR_ISENABLER0:
+        gicr_write_set_bitmap_reg(cs, attrs, &cs->gicr_ienabler0, value);
+        return MEMTX_OK;
+    case GICR_ICENABLER0:
+        gicr_write_clear_bitmap_reg(cs, attrs, &cs->gicr_ienabler0, value);
+        return MEMTX_OK;
+    case GICR_ISPENDR0:
+        gicr_write_set_bitmap_reg(cs, attrs, &cs->gicr_ipendr0, value);
+        return MEMTX_OK;
+    case GICR_ICPENDR0:
+        gicr_write_clear_bitmap_reg(cs, attrs, &cs->gicr_ipendr0, value);
+        return MEMTX_OK;
+    case GICR_ISACTIVER0:
+        gicr_write_set_bitmap_reg(cs, attrs, &cs->gicr_iactiver0, value);
+        return MEMTX_OK;
+    case GICR_ICACTIVER0:
+        gicr_write_clear_bitmap_reg(cs, attrs, &cs->gicr_iactiver0, value);
+        return MEMTX_OK;
+    case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f:
+    {
+        int i, irq = offset - GICR_IPRIORITYR;
+
+        for (i = irq; i < irq + 4; i++, value >>= 8) {
+            gicr_write_ipriorityr(cs, attrs, i, value);
+        }
+        gicv3_redist_update(cs);
+        return MEMTX_OK;
+    }
+    case GICR_ICFGR0:
+        /* Register is all RAZ/WI or RAO/WI bits */
+        return MEMTX_OK;
+    case GICR_ICFGR1:
+    {
+        uint32_t mask;
+
+        /* Since our edge_trigger bitmap is one bit per irq, our input
+         * 32-bits will compress down into 16 bits which we need
+         * to write into the bitmap.
+         */
+        value = half_unshuffle32(value >> 1) << 16;
+        mask = mask_group(cs, attrs) & 0xffff0000U;
+
+        cs->edge_trigger &= ~mask;
+        cs->edge_trigger |= (value & mask);
+
+        gicv3_redist_update(cs);
+        return MEMTX_OK;
+    }
+    case GICR_IGRPMODR0:
+        if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) {
+            /* RAZ/WI if security disabled, or if
+             * security enabled and this is an NS access
+             */
+            return MEMTX_OK;
+        }
+        cs->gicr_igrpmodr0 = value;
+        gicv3_redist_update(cs);
+        return MEMTX_OK;
+    case GICR_NSACR:
+        if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) {
+            /* RAZ/WI if security disabled, or if
+             * security enabled and this is an NS access
+             */
+            return MEMTX_OK;
+        }
+        cs->gicr_nsacr = value;
+        /* no update required as this only affects access permission checks */
+        return MEMTX_OK;
+    case GICR_IIDR:
+    case GICR_TYPER:
+    case GICR_IDREGS ... GICR_IDREGS + 0x1f:
+        /* RO registers, ignore the write */
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid guest write to RO register at offset "
+                      TARGET_FMT_plx "\n", __func__, offset);
+        return MEMTX_OK;
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+static MemTxResult gicr_readll(GICv3CPUState *cs, hwaddr offset,
+                               uint64_t *data, MemTxAttrs attrs)
+{
+    switch (offset) {
+    case GICR_TYPER:
+        *data = cs->gicr_typer;
+        return MEMTX_OK;
+    case GICR_PROPBASER:
+        *data = cs->gicr_propbaser;
+        return MEMTX_OK;
+    case GICR_PENDBASER:
+        *data = cs->gicr_pendbaser;
+        return MEMTX_OK;
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+static MemTxResult gicr_writell(GICv3CPUState *cs, hwaddr offset,
+                                uint64_t value, MemTxAttrs attrs)
+{
+    switch (offset) {
+    case GICR_PROPBASER:
+        cs->gicr_propbaser = value;
+        return MEMTX_OK;
+    case GICR_PENDBASER:
+        cs->gicr_pendbaser = value;
+        return MEMTX_OK;
+    case GICR_TYPER:
+        /* RO register, ignore the write */
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid guest write to RO register at offset "
+                      TARGET_FMT_plx "\n", __func__, offset);
+        return MEMTX_OK;
+    default:
+        return MEMTX_ERROR;
+    }
+}
+
+MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
+                              unsigned size, MemTxAttrs attrs)
+{
+    GICv3State *s = opaque;
+    GICv3CPUState *cs;
+    MemTxResult r;
+    int cpuidx;
+
+    /* This region covers all the redistributor pages; there are
+     * (for GICv3) two 64K pages per CPU. At the moment they are
+     * all contiguous (ie in this one region), though we might later
+     * want to allow splitting of redistributor pages into several
+     * blocks so we can support more CPUs.
+     */
+    cpuidx = offset / 0x20000;
+    offset %= 0x20000;
+    assert(cpuidx < s->num_cpu);
+
+    cs = &s->cpu[cpuidx];
+
+    switch (size) {
+    case 1:
+        r = gicr_readb(cs, offset, data, attrs);
+        break;
+    case 4:
+        r = gicr_readl(cs, offset, data, attrs);
+        break;
+    case 8:
+        r = gicr_readll(cs, offset, data, attrs);
+        break;
+    default:
+        r = MEMTX_ERROR;
+        break;
+    }
+
+    if (r == MEMTX_ERROR) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid guest read at offset " TARGET_FMT_plx
+                      "size %u\n", __func__, offset, size);
+        trace_gicv3_redist_badread(gicv3_redist_affid(cs), offset,
+                                   size, attrs.secure);
+    } else {
+        trace_gicv3_redist_read(gicv3_redist_affid(cs), offset, *data,
+                                size, attrs.secure);
+    }
+    return r;
+}
+
+MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
+                               unsigned size, MemTxAttrs attrs)
+{
+    GICv3State *s = opaque;
+    GICv3CPUState *cs;
+    MemTxResult r;
+    int cpuidx;
+
+    /* This region covers all the redistributor pages; there are
+     * (for GICv3) two 64K pages per CPU. At the moment they are
+     * all contiguous (ie in this one region), though we might later
+     * want to allow splitting of redistributor pages into several
+     * blocks so we can support more CPUs.
+     */
+    cpuidx = offset / 0x20000;
+    offset %= 0x20000;
+    assert(cpuidx < s->num_cpu);
+
+    cs = &s->cpu[cpuidx];
+
+    switch (size) {
+    case 1:
+        r = gicr_writeb(cs, offset, data, attrs);
+        break;
+    case 4:
+        r = gicr_writel(cs, offset, data, attrs);
+        break;
+    case 8:
+        r = gicr_writell(cs, offset, data, attrs);
+        break;
+    default:
+        r = MEMTX_ERROR;
+        break;
+    }
+
+    if (r == MEMTX_ERROR) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid guest write at offset " TARGET_FMT_plx
+                      "size %u\n", __func__, offset, size);
+        trace_gicv3_redist_badwrite(gicv3_redist_affid(cs), offset, data,
+                                    size, attrs.secure);
+    } else {
+        trace_gicv3_redist_write(gicv3_redist_affid(cs), offset, data,
+                                 size, attrs.secure);
+    }
+    return r;
+}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 7cb9926..b70e052 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -205,6 +205,10 @@ MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data,
                             unsigned size, MemTxAttrs attrs);
 MemTxResult gicv3_dist_write(void *opaque, hwaddr addr, uint64_t data,
                              unsigned size, MemTxAttrs attrs);
+MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
+                              unsigned size, MemTxAttrs attrs);
+MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
+                               unsigned size, MemTxAttrs attrs);
 
 /**
  * gicv3_cpuif_update:
diff --git a/trace-events b/trace-events
index 38030f8..518b547 100644
--- a/trace-events
+++ b/trace-events
@@ -2171,3 +2171,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] 24+ messages in thread

* [Qemu-devel] [PULL 13/22] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (11 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 12/22] hw/intc/arm_gicv3: Implement GICv3 redistributor registers Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 14/22] hw/intc/arm_gicv3: Implement gicv3_set_irq() Peter Maydell
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-14-git-send-email-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 171d587..4c1fbb6 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -324,6 +324,19 @@ static void arm_gicv3_post_load(GICv3State *s)
     gicv3_cache_all_target_cpustates(s);
 }
 
+static const MemoryRegionOps gic_ops[] = {
+    {
+        .read_with_attrs = gicv3_dist_read,
+        .write_with_attrs = gicv3_dist_write,
+        .endianness = DEVICE_NATIVE_ENDIAN,
+    },
+    {
+        .read_with_attrs = gicv3_redist_read,
+        .write_with_attrs = gicv3_redist_write,
+        .endianness = DEVICE_NATIVE_ENDIAN,
+    }
+};
+
 static void arm_gic_realize(DeviceState *dev, Error **errp)
 {
     /* Device instance realize function for the GIC sysbus device */
@@ -337,7 +350,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    gicv3_init_irqs_and_mmio(s, gicv3_set_irq, NULL);
+    gicv3_init_irqs_and_mmio(s, gicv3_set_irq, gic_ops);
 }
 
 static void arm_gicv3_class_init(ObjectClass *klass, void *data)
-- 
1.9.1

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

* [Qemu-devel] [PULL 14/22] hw/intc/arm_gicv3: Implement gicv3_set_irq()
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (12 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 13/22] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 15/22] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers Peter Maydell
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-15-git-send-email-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 4c1fbb6..65ebca2 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -311,7 +311,25 @@ static void gicv3_set_irq(void *opaque, int irq, int level)
      *  [N+32..N+63] : PPI (internal interrupts for CPU 1
      *  ...
      */
-    /* Do nothing for now */
+    GICv3State *s = opaque;
+
+    if (irq < (s->num_irq - GIC_INTERNAL)) {
+        /* external interrupt (SPI) */
+        gicv3_dist_set_irq(s, irq + GIC_INTERNAL, level);
+    } else {
+        /* per-cpu interrupt (PPI) */
+        int cpu;
+
+        irq -= (s->num_irq - GIC_INTERNAL);
+        cpu = irq / GIC_INTERNAL;
+        irq %= GIC_INTERNAL;
+        assert(cpu < s->num_cpu);
+        /* Raising SGIs via this function would be a bug in how the board
+         * model wires up interrupts.
+         */
+        assert(irq >= GIC_NR_SGIS);
+        gicv3_redist_set_irq(&s->cpu[cpu], irq, level);
+    }
 }
 
 static void arm_gicv3_post_load(GICv3State *s)
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
index 881d555..b977ae5 100644
--- a/hw/intc/arm_gicv3_dist.c
+++ b/hw/intc/arm_gicv3_dist.c
@@ -856,3 +856,24 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data,
     }
     return r;
 }
+
+void gicv3_dist_set_irq(GICv3State *s, int irq, int level)
+{
+    /* Update distributor state for a change in an external SPI input line */
+    if (level == gicv3_gicd_level_test(s, irq)) {
+        return;
+    }
+
+    trace_gicv3_dist_set_irq(irq, level);
+
+    gicv3_gicd_level_replace(s, irq, level);
+
+    if (level) {
+        /* 0->1 edges latch the pending bit for edge-triggered interrupts */
+        if (gicv3_gicd_edge_trigger_test(s, irq)) {
+            gicv3_gicd_pending_set(s, irq);
+        }
+    }
+
+    gicv3_update(s, irq, 1);
+}
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index e0f23e1..1130eee 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -499,3 +499,24 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
     }
     return r;
 }
+
+void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
+{
+    /* Update redistributor state for a change in an external PPI input line */
+    if (level == extract32(cs->level, irq, 1)) {
+        return;
+    }
+
+    trace_gicv3_redist_set_irq(gicv3_redist_affid(cs), irq, level);
+
+    cs->level = deposit32(cs->level, irq, 1, level);
+
+    if (level) {
+        /* 0->1 edges latch the pending bit for edge-triggered interrupts */
+        if (extract32(cs->edge_trigger, irq, 1)) {
+            cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 1);
+        }
+    }
+
+    gicv3_redist_update(cs);
+}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index b70e052..a6f443c 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -209,6 +209,8 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
                               unsigned size, MemTxAttrs attrs);
 MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
                                unsigned size, MemTxAttrs attrs);
+void gicv3_dist_set_irq(GICv3State *s, int irq, int level);
+void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level);
 
 /**
  * gicv3_cpuif_update:
diff --git a/trace-events b/trace-events
index 518b547..9fea54c 100644
--- a/trace-events
+++ b/trace-events
@@ -2171,9 +2171,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] 24+ messages in thread

* [Qemu-devel] [PULL 15/22] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (13 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 14/22] hw/intc/arm_gicv3: Implement gicv3_set_irq() Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 16/22] hw/intc/arm_gicv3: Implement gicv3_cpuif_update() Peter Maydell
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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

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

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-16-git-send-email-peter.maydell@linaro.org
---
 hw/intc/Makefile.objs     |   1 +
 hw/intc/arm_gicv3.c       |   2 +
 hw/intc/arm_gicv3_cpuif.c | 646 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/gicv3_internal.h  |   1 +
 trace-events              |  16 ++
 5 files changed, 666 insertions(+)
 create mode 100644 hw/intc/arm_gicv3_cpuif.c

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

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

* [Qemu-devel] [PULL 16/22] hw/intc/arm_gicv3: Implement gicv3_cpuif_update()
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (14 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 15/22] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 17/22] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers Peter Maydell
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-17-git-send-email-peter.maydell@linaro.org
---
 hw/intc/arm_gicv3_cpuif.c | 140 +++++++++++++++++++++++++++++++++++++++++++++-
 hw/intc/gicv3_internal.h  |   5 +-
 trace-events              |   2 +
 3 files changed, 142 insertions(+), 5 deletions(-)

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

* [Qemu-devel] [PULL 17/22] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (15 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 16/22] hw/intc/arm_gicv3: Implement gicv3_cpuif_update() Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 18/22] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers Peter Maydell
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-18-git-send-email-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 1130eee..55c25e8 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -27,6 +27,13 @@ static uint32_t mask_group(GICv3CPUState *cs, MemTxAttrs attrs)
     return 0xFFFFFFFFU;
 }
 
+static int gicr_ns_access(GICv3CPUState *cs, int irq)
+{
+    /* Return the 2 bit NSACR.NS_access field for this SGI */
+    assert(irq < 16);
+    return extract32(cs->gicr_nsacr, irq * 2, 2);
+}
+
 static void gicr_write_set_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs,
                                       uint32_t *reg, uint32_t val)
 {
@@ -520,3 +527,36 @@ void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
 
     gicv3_redist_update(cs);
 }
+
+void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns)
+{
+    /* Update redistributor state for a generated SGI */
+    int irqgrp = gicv3_irq_group(cs->gic, cs, irq);
+
+    /* If we are asked for a Secure Group 1 SGI and it's actually
+     * configured as Secure Group 0 this is OK (subject to the usual
+     * NSACR checks).
+     */
+    if (grp == GICV3_G1 && irqgrp == GICV3_G0) {
+        grp = GICV3_G0;
+    }
+
+    if (grp != irqgrp) {
+        return;
+    }
+
+    if (ns && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) {
+        /* If security is enabled we must test the NSACR bits */
+        int nsaccess = gicr_ns_access(cs, irq);
+
+        if ((irqgrp == GICV3_G0 && nsaccess < 1) ||
+            (irqgrp == GICV3_G1 && nsaccess < 2)) {
+            return;
+        }
+    }
+
+    /* OK, we can accept the SGI */
+    trace_gicv3_redist_send_sgi(gicv3_redist_affid(cs), irq);
+    cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 1);
+    gicv3_redist_update(cs);
+}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index e469599..8261bc0 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -211,6 +211,7 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
                                unsigned size, MemTxAttrs attrs);
 void gicv3_dist_set_irq(GICv3State *s, int irq, int level);
 void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level);
+void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns);
 void gicv3_init_cpuif(GICv3State *s);
 
 /**
diff --git a/trace-events b/trace-events
index 6aec711..0f3b9f8 100644
--- a/trace-events
+++ b/trace-events
@@ -2183,6 +2183,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"
@@ -2197,3 +2198,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] 24+ messages in thread

* [Qemu-devel] [PULL 18/22] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (16 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 17/22] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 19/22] target-arm/machine.c: Allow user to request GICv3 emulation Peter Maydell
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-19-git-send-email-peter.maydell@linaro.org
---
 hw/intc/arm_gicv3_cpuif.c | 437 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/gicv3_internal.h  |   5 +
 trace-events              |   7 +
 3 files changed, 449 insertions(+)

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

* [Qemu-devel] [PULL 19/22] target-arm/machine.c: Allow user to request GICv3 emulation
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (17 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 18/22] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 20/22] target-arm/monitor.c: Advertise emulated GICv3 in capabilities Peter Maydell
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-20-git-send-email-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] 24+ messages in thread

* [Qemu-devel] [PULL 20/22] target-arm/monitor.c: Advertise emulated GICv3 in capabilities
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (18 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 19/22] target-arm/machine.c: Allow user to request GICv3 emulation Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 21/22] hw/timer: Add value matching support to aspeed_timer Peter Maydell
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

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>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-21-git-send-email-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] 24+ messages in thread

* [Qemu-devel] [PULL 21/22] hw/timer: Add value matching support to aspeed_timer
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (19 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 20/22] target-arm/monitor.c: Advertise emulated GICv3 in capabilities Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 14:25 ` [Qemu-devel] [PULL 22/22] ACPI: ARM: Present GIC version in MADT table Peter Maydell
  2016-06-17 16:06 ` [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

From: Andrew Jeffery <andrew@aj.id.au>

Value matching allows Linux to boot with CONFIG_NO_HZ_IDLE=y on the
palmetto-bmc machine. Two match registers are provided for each timer.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Message-id: 1465974248-20434-1-git-send-email-andrew@aj.id.au
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/timer/aspeed_timer.c         | 138 +++++++++++++++++++++++++++++-----------
 include/hw/timer/aspeed_timer.h |   5 +-
 2 files changed, 104 insertions(+), 39 deletions(-)

diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index 4b94808..9b70ee0 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -10,12 +10,10 @@
  */
 
 #include "qemu/osdep.h"
-#include "hw/ptimer.h"
 #include "hw/sysbus.h"
 #include "hw/timer/aspeed_timer.h"
 #include "qemu-common.h"
 #include "qemu/bitops.h"
-#include "qemu/main-loop.h"
 #include "qemu/timer.h"
 #include "qemu/log.h"
 #include "trace.h"
@@ -77,21 +75,96 @@ static inline bool timer_can_pulse(AspeedTimer *t)
     return t->id >= TIMER_FIRST_CAP_PULSE;
 }
 
+static inline bool timer_external_clock(AspeedTimer *t)
+{
+    return timer_ctrl_status(t, op_external_clock);
+}
+
+static uint32_t clock_rates[] = { TIMER_CLOCK_APB_HZ, TIMER_CLOCK_EXT_HZ };
+
+static inline uint32_t calculate_rate(struct AspeedTimer *t)
+{
+    return clock_rates[timer_external_clock(t)];
+}
+
+static inline uint32_t calculate_ticks(struct AspeedTimer *t, uint64_t now_ns)
+{
+    uint64_t delta_ns = now_ns - MIN(now_ns, t->start);
+    uint32_t rate = calculate_rate(t);
+    uint64_t ticks = muldiv64(delta_ns, rate, NANOSECONDS_PER_SECOND);
+
+    return t->reload - MIN(t->reload, ticks);
+}
+
+static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks)
+{
+    uint64_t delta_ns;
+    uint64_t delta_ticks;
+
+    delta_ticks = t->reload - MIN(t->reload, ticks);
+    delta_ns = muldiv64(delta_ticks, NANOSECONDS_PER_SECOND, calculate_rate(t));
+
+    return t->start + delta_ns;
+}
+
+static uint64_t calculate_next(struct AspeedTimer *t)
+{
+    uint64_t next = 0;
+    uint32_t rate = calculate_rate(t);
+
+    while (!next) {
+        /* We don't know the relationship between the values in the match
+         * registers, so sort using MAX/MIN/zero. We sort in that order as the
+         * timer counts down to zero. */
+        uint64_t seq[] = {
+            calculate_time(t, MAX(t->match[0], t->match[1])),
+            calculate_time(t, MIN(t->match[0], t->match[1])),
+            calculate_time(t, 0),
+        };
+        uint64_t reload_ns;
+        uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+        if (now < seq[0]) {
+            next = seq[0];
+        } else if (now < seq[1]) {
+            next = seq[1];
+        } else if (now < seq[2]) {
+            next = seq[2];
+        } else {
+            reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate);
+            t->start = now - ((now - t->start) % reload_ns);
+        }
+    }
+
+    return next;
+}
+
 static void aspeed_timer_expire(void *opaque)
 {
     AspeedTimer *t = opaque;
+    bool interrupt = false;
+    uint32_t ticks;
 
-    /* Only support interrupts on match values of zero for the moment - this is
-     * sufficient to boot an aspeed_defconfig Linux kernel.
-     *
-     * TODO: matching on arbitrary values (see e.g. hw/timer/a9gtimer.c)
-     */
-    bool match = !(t->match[0] && t->match[1]);
-    bool interrupt = timer_overflow_interrupt(t) || match;
-    if (timer_enabled(t) && interrupt) {
+    if (!timer_enabled(t)) {
+        return;
+    }
+
+    ticks = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+
+    if (!ticks) {
+        interrupt = timer_overflow_interrupt(t) || !t->match[0] || !t->match[1];
+    } else if (ticks <= MIN(t->match[0], t->match[1])) {
+        interrupt = true;
+    } else if (ticks <= MAX(t->match[0], t->match[1])) {
+        interrupt = true;
+    }
+
+    if (interrupt) {
         t->level = !t->level;
         qemu_set_irq(t->irq, t->level);
     }
+
+    timer_mod(&t->timer, calculate_next(t));
 }
 
 static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
@@ -100,7 +173,7 @@ static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
 
     switch (reg) {
     case TIMER_REG_STATUS:
-        value = ptimer_get_count(t->timer);
+        value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
         break;
     case TIMER_REG_RELOAD:
         value = t->reload;
@@ -160,24 +233,22 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
     switch (reg) {
     case TIMER_REG_STATUS:
         if (timer_enabled(t)) {
-            ptimer_set_count(t->timer, value);
+            uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+            int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now);
+            uint32_t rate = calculate_rate(t);
+
+            t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
+            timer_mod(&t->timer, calculate_next(t));
         }
         break;
     case TIMER_REG_RELOAD:
         t->reload = value;
-        ptimer_set_limit(t->timer, value, 1);
         break;
     case TIMER_REG_MATCH_FIRST:
     case TIMER_REG_MATCH_SECOND:
-        if (value) {
-            /* Non-zero match values are unsupported. As such an interrupt will
-             * always be triggered when the timer reaches zero even if the
-             * overflow interrupt control bit is clear.
-             */
-            qemu_log_mask(LOG_UNIMP, "%s: Match value unsupported by device: "
-                    "0x%" PRIx32 "\n", __func__, value);
-        } else {
-            t->match[reg - 2] = value;
+        t->match[reg - 2] = value;
+        if (timer_enabled(t)) {
+            timer_mod(&t->timer, calculate_next(t));
         }
         break;
     default:
@@ -196,21 +267,16 @@ static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable)
 {
     trace_aspeed_timer_ctrl_enable(t->id, enable);
     if (enable) {
-        ptimer_run(t->timer, 0);
+        t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        timer_mod(&t->timer, calculate_next(t));
     } else {
-        ptimer_stop(t->timer);
-        ptimer_set_limit(t->timer, t->reload, 1);
+        timer_del(&t->timer);
     }
 }
 
 static void aspeed_timer_ctrl_external_clock(AspeedTimer *t, bool enable)
 {
     trace_aspeed_timer_ctrl_external_clock(t->id, enable);
-    if (enable) {
-        ptimer_set_freq(t->timer, TIMER_CLOCK_EXT_HZ);
-    } else {
-        ptimer_set_freq(t->timer, TIMER_CLOCK_APB_HZ);
-    }
 }
 
 static void aspeed_timer_ctrl_overflow_interrupt(AspeedTimer *t, bool enable)
@@ -351,12 +417,10 @@ static const MemoryRegionOps aspeed_timer_ops = {
 
 static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id)
 {
-    QEMUBH *bh;
     AspeedTimer *t = &s->timers[id];
 
     t->id = id;
-    bh = qemu_bh_new(aspeed_timer_expire, t);
-    t->timer = ptimer_init(bh);
+    timer_init_ns(&t->timer, QEMU_CLOCK_VIRTUAL, aspeed_timer_expire, t);
 }
 
 static void aspeed_timer_realize(DeviceState *dev, Error **errp)
@@ -399,12 +463,12 @@ static void aspeed_timer_reset(DeviceState *dev)
 
 static const VMStateDescription vmstate_aspeed_timer = {
     .name = "aspeed.timer",
-    .version_id = 1,
-    .minimum_version_id = 1,
+    .version_id = 2,
+    .minimum_version_id = 2,
     .fields = (VMStateField[]) {
         VMSTATE_UINT8(id, AspeedTimer),
         VMSTATE_INT32(level, AspeedTimer),
-        VMSTATE_PTIMER(timer, AspeedTimer),
+        VMSTATE_TIMER(timer, AspeedTimer),
         VMSTATE_UINT32(reload, AspeedTimer),
         VMSTATE_UINT32_ARRAY(match, AspeedTimer, 2),
         VMSTATE_END_OF_LIST()
@@ -419,7 +483,7 @@ static const VMStateDescription vmstate_aspeed_timer_state = {
         VMSTATE_UINT32(ctrl, AspeedTimerCtrlState),
         VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState),
         VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState,
-                             ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer,
+                             ASPEED_TIMER_NR_TIMERS, 2, vmstate_aspeed_timer,
                              AspeedTimer),
         VMSTATE_END_OF_LIST()
     }
diff --git a/include/hw/timer/aspeed_timer.h b/include/hw/timer/aspeed_timer.h
index 44dc2f8..bd6c1a7 100644
--- a/include/hw/timer/aspeed_timer.h
+++ b/include/hw/timer/aspeed_timer.h
@@ -22,7 +22,7 @@
 #ifndef ASPEED_TIMER_H
 #define ASPEED_TIMER_H
 
-#include "hw/ptimer.h"
+#include "qemu/timer.h"
 
 #define ASPEED_TIMER(obj) \
     OBJECT_CHECK(AspeedTimerCtrlState, (obj), TYPE_ASPEED_TIMER);
@@ -33,15 +33,16 @@ typedef struct AspeedTimer {
     qemu_irq irq;
 
     uint8_t id;
+    QEMUTimer timer;
 
     /**
      * Track the line level as the ASPEED timers implement edge triggered
      * interrupts, signalling with both the rising and falling edge.
      */
     int32_t level;
-    ptimer_state *timer;
     uint32_t reload;
     uint32_t match[2];
+    uint64_t start;
 } AspeedTimer;
 
 typedef struct AspeedTimerCtrlState {
-- 
1.9.1

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

* [Qemu-devel] [PULL 22/22] ACPI: ARM: Present GIC version in MADT table
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (20 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 21/22] hw/timer: Add value matching support to aspeed_timer Peter Maydell
@ 2016-06-17 14:25 ` Peter Maydell
  2016-06-17 16:06 ` [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 14:25 UTC (permalink / raw)
  To: qemu-devel

From: Shannon Zhao <shannon.zhao@linaro.org>

In ACPI 5.1 Errata, it adds GIC version in GIC distributor structure.
This is useful for guest kernel to identify which version GIC hardware
is. Update GIC distributor structure and present GIC version in MADT
table.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Reviewed-by: Andrew Jones <drjones@redhat.com>
Message-id: 1465960955-17388-1-git-send-email-zhaoshenglong@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/virt-acpi-build.c    | 1 +
 include/hw/acpi/acpi-defs.h | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 1fa0581..28fc59c 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -523,6 +523,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
     gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR;
     gicd->length = sizeof(*gicd);
     gicd->base_address = memmap[VIRT_GIC_DIST].base;
+    gicd->version = guest_info->gic_version;
 
     for (i = 0; i < guest_info->smp_cpus; i++) {
         AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data,
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index 850a962..ea9be0b 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -367,7 +367,9 @@ struct AcpiMadtGenericDistributor {
     uint32_t gic_id;
     uint64_t base_address;
     uint32_t global_irq_base;
-    uint32_t reserved2;
+    /* ACPI 5.1 Errata 1228 Present GIC version in MADT table */
+    uint8_t version;
+    uint8_t reserved2[3];
 } QEMU_PACKED;
 
 typedef struct AcpiMadtGenericDistributor AcpiMadtGenericDistributor;
-- 
1.9.1

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

* Re: [Qemu-devel] [PULL 00/22] target-arm queue
  2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
                   ` (21 preceding siblings ...)
  2016-06-17 14:25 ` [Qemu-devel] [PULL 22/22] ACPI: ARM: Present GIC version in MADT table Peter Maydell
@ 2016-06-17 16:06 ` Peter Maydell
  22 siblings, 0 replies; 24+ messages in thread
From: Peter Maydell @ 2016-06-17 16:06 UTC (permalink / raw)
  To: QEMU Developers

On 17 June 2016 at 15:25, Peter Maydell <peter.maydell@linaro.org> wrote:
> Nothing here except the GICv3 emulation, but I wanted to get it into
> master this week, and nothing else has made it into target-arm.next.
>
> thanks
> -- PMM
>
>
> The following changes since commit 98b5b7422fe1813040b499a4be415a9f514f1c10:
>
>   Merge remote-tracking branch 'remotes/amit-migration/tags/migration-for-2.7-5' into staging (2016-06-17 14:09:46 +0100)
>
> are available in the git repository at:
>
>
>   git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20160617
>
> for you to fetch changes up to f06765a94a31bdd8b65fc83fd91a6c3f8e8a1195:
>
>   ACPI: ARM: Present GIC version in MADT table (2016-06-17 15:23:51 +0100)
>
> ----------------------------------------------------------------
> target-arm queue:
>  * GICv3 emulation

Applied, thanks.

-- PMM

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

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

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-17 14:25 [Qemu-devel] [PULL 00/22] target-arm queue Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 01/22] migration: Define VMSTATE_UINT64_2DARRAY Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 02/22] bitops.h: Implement half-shuffle and half-unshuffle ops Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 03/22] target-arm: Define new arm_is_el3_or_mon() function Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 04/22] target-arm: Provide hook to tell GICv3 about changes of security state Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 05/22] target-arm: Add mp-affinity property for ARM CPU class Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 06/22] hw/intc/arm_gicv3: Add state information Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 07/22] hw/intc/arm_gicv3: Move irq lines into GICv3CPUState structure Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 08/22] hw/intc/arm_gicv3: Add vmstate descriptors Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 09/22] hw/intc/arm_gicv3: ARM GICv3 device framework Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 10/22] hw/intc/arm_gicv3: Implement functions to identify next pending irq Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 11/22] hw/intc/arm_gicv3: Implement GICv3 distributor registers Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 12/22] hw/intc/arm_gicv3: Implement GICv3 redistributor registers Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 13/22] hw/intc/arm_gicv3: Wire up distributor and redistributor MMIO regions Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 14/22] hw/intc/arm_gicv3: Implement gicv3_set_irq() Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 15/22] hw/intc/arm_gicv3: Implement GICv3 CPU interface registers Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 16/22] hw/intc/arm_gicv3: Implement gicv3_cpuif_update() Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 17/22] hw/intc/arm_gicv3: Implement CPU i/f SGI generation registers Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 18/22] hw/intc/arm_gicv3: Add IRQ handling CPU interface registers Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 19/22] target-arm/machine.c: Allow user to request GICv3 emulation Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 20/22] target-arm/monitor.c: Advertise emulated GICv3 in capabilities Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 21/22] hw/timer: Add value matching support to aspeed_timer Peter Maydell
2016-06-17 14:25 ` [Qemu-devel] [PULL 22/22] ACPI: ARM: Present GIC version in MADT table Peter Maydell
2016-06-17 16:06 ` [Qemu-devel] [PULL 00/22] target-arm queue 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.