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