1 // Copyright 2018 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6
7 #include <arch/arm64/hypervisor/gic/el2.h>
8 #include <arch/arm64/hypervisor/gic/gicv3.h>
9 #include <arch/ops.h>
10 #include <dev/interrupt/arm_gic_hw_interface.h>
11 #include <dev/interrupt/arm_gicv3_regs.h>
12
13 static constexpr uint32_t kNumAprs = 4;
14 static constexpr uint32_t kNumLrs = 16;
15
gicv3_write_gich_hcr(uint32_t val)16 static void gicv3_write_gich_hcr(uint32_t val) {
17 arm64_el2_gicv3_write_gich_hcr(val);
18 }
19
gicv3_read_gich_vtr()20 static uint32_t gicv3_read_gich_vtr() {
21 return arm64_el2_gicv3_read_gich_vtr();
22 }
23
gicv3_default_gich_vmcr()24 static uint32_t gicv3_default_gich_vmcr() {
25 // From ARM GIC v3/v4, Section 8.4.8: VFIQEn - In implementations where the
26 // Non-secure copy of ICC_SRE_EL1.SRE is always 1, this bit is RES 1.
27 return ICH_VMCR_VPMR | ICH_VMCR_VFIQEN | ICH_VMCR_VENG1;
28 }
29
gicv3_read_gich_vmcr()30 static uint32_t gicv3_read_gich_vmcr() {
31 return arm64_el2_gicv3_read_gich_vmcr();
32 }
33
gicv3_write_gich_vmcr(uint32_t val)34 static void gicv3_write_gich_vmcr(uint32_t val) {
35 arm64_el2_gicv3_write_gich_vmcr(val);
36 }
37
gicv3_read_gich_misr()38 static uint32_t gicv3_read_gich_misr() {
39 return arm64_el2_gicv3_read_gich_misr();
40 }
41
gicv3_read_gich_elrsr()42 static uint64_t gicv3_read_gich_elrsr() {
43 return arm64_el2_gicv3_read_gich_elrsr();
44 }
45
gicv3_read_gich_apr(uint32_t idx)46 static uint32_t gicv3_read_gich_apr(uint32_t idx) {
47 DEBUG_ASSERT(idx < kNumAprs);
48 return arm64_el2_gicv3_read_gich_apr(idx);
49 }
50
gicv3_write_gich_apr(uint32_t idx,uint32_t val)51 static void gicv3_write_gich_apr(uint32_t idx, uint32_t val) {
52 DEBUG_ASSERT(idx < kNumAprs);
53 arm64_el2_gicv3_write_gich_apr(val, idx);
54 }
55
gicv3_read_gich_lr(uint32_t idx)56 static uint64_t gicv3_read_gich_lr(uint32_t idx) {
57 DEBUG_ASSERT(idx < kNumLrs);
58 return arm64_el2_gicv3_read_gich_lr(idx);
59 }
60
gicv3_write_gich_lr(uint32_t idx,uint64_t val)61 static void gicv3_write_gich_lr(uint32_t idx, uint64_t val) {
62 DEBUG_ASSERT(idx < kNumLrs);
63 if (val & ICH_LR_HARDWARE) {
64 // We are adding a physical interrupt to a list register, therefore we
65 // mark the physical interrupt as active on the physical distributor so
66 // that the guest can deactivate it directly.
67 uint32_t vector = ICH_LR_VIRTUAL_ID(val);
68 uint32_t reg = vector / 32;
69 uint32_t mask = 1u << (vector % 32);
70 // Since we use affinity routing, if this vector is associated with an
71 // SGI or PPI, we should talk to the redistributor for the current CPU.
72 if (vector < 32) {
73 cpu_num_t cpu_num = arch_curr_cpu_num();
74 GICREG(0, GICR_ISACTIVER0(cpu_num)) = mask;
75 } else {
76 GICREG(0, GICD_ISACTIVER(reg)) = mask;
77 }
78 }
79 arm64_el2_gicv3_write_gich_lr(val, idx);
80 }
81
gicv3_get_gicv(paddr_t * gicv_paddr)82 static zx_status_t gicv3_get_gicv(paddr_t* gicv_paddr) {
83 // Check for presence of GICv3 virtualisation extensions.
84 // We return ZX_ERR_NOT_FOUND since this API is used to get
85 // address of GICV base to map it to guest
86 // On GICv3 we do not need to map this region, since we use system registers
87 return ZX_ERR_NOT_FOUND;
88 }
89
gicv3_get_lr_from_vector(bool hw,uint8_t prio,uint32_t vector)90 static uint64_t gicv3_get_lr_from_vector(bool hw, uint8_t prio, uint32_t vector) {
91 uint64_t lr = ICH_LR_PENDING | ICH_LR_GROUP1 | ICH_LR_PRIORITY(prio) |
92 ICH_LR_VIRTUAL_ID(vector);
93 if (hw) {
94 lr |= ICH_LR_HARDWARE | ICH_LR_PHYSICAL_ID(vector);
95 }
96 return lr;
97 }
98
gicv3_get_vector_from_lr(uint64_t lr)99 static uint32_t gicv3_get_vector_from_lr(uint64_t lr) {
100 return lr & ICH_LR_VIRTUAL_ID(UINT64_MAX);
101 }
102
gicv3_get_num_pres()103 static uint32_t gicv3_get_num_pres() {
104 return ICH_VTR_PRES(gicv3_read_gich_vtr());
105 }
106
gicv3_get_num_lrs()107 static uint32_t gicv3_get_num_lrs() {
108 return ICH_VTR_LRS(gicv3_read_gich_vtr());
109 }
110
111 static const struct arm_gic_hw_interface_ops gic_hw_register_ops = {
112 .write_gich_hcr = gicv3_write_gich_hcr,
113 .read_gich_vtr = gicv3_read_gich_vtr,
114 .default_gich_vmcr = gicv3_default_gich_vmcr,
115 .read_gich_vmcr = gicv3_read_gich_vmcr,
116 .write_gich_vmcr = gicv3_write_gich_vmcr,
117 .read_gich_misr = gicv3_read_gich_misr,
118 .read_gich_elrsr = gicv3_read_gich_elrsr,
119 .read_gich_apr = gicv3_read_gich_apr,
120 .write_gich_apr = gicv3_write_gich_apr,
121 .read_gich_lr = gicv3_read_gich_lr,
122 .write_gich_lr = gicv3_write_gich_lr,
123 .get_gicv = gicv3_get_gicv,
124 .get_lr_from_vector = gicv3_get_lr_from_vector,
125 .get_vector_from_lr = gicv3_get_vector_from_lr,
126 .get_num_pres = gicv3_get_num_pres,
127 .get_num_lrs = gicv3_get_num_lrs,
128 };
129
gicv3_hw_interface_register()130 void gicv3_hw_interface_register() {
131 arm_gic_hw_interface_register(&gic_hw_register_ops);
132 }
133