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 <dev/interrupt/arm_gic_hw_interface.h>
8#include <vm/pmm.h>
9#include <arch/arm64/hypervisor/gic/gicv2.h>
10#include <dev/interrupt/arm_gicv2_regs.h>
11
12// Representation of GICH registers. For details please refer to ARM Generic Interrupt
13// Controller Architecture Specification Version 2, 5.3 GIC virtual interface control
14// registers.
15typedef struct Gich {
16    uint32_t hcr;
17    uint32_t vtr;
18    uint32_t vmcr;
19    uint32_t reserved0;
20    uint32_t misr;
21    uint32_t reserved1[3];
22    uint64_t eisr;
23    uint32_t reserved2[2];
24    uint64_t elrsr;
25    uint32_t reserved3[46];
26    uint32_t apr;
27    uint32_t reserved4[3];
28    uint32_t lr[64];
29} __attribute__((__packed__)) Gich;
30
31static_assert(__offsetof(Gich, hcr) == 0x00, "");
32static_assert(__offsetof(Gich, vtr) == 0x04, "");
33static_assert(__offsetof(Gich, vmcr) == 0x08, "");
34static_assert(__offsetof(Gich, misr) == 0x10, "");
35static_assert(__offsetof(Gich, eisr) == 0x20, "");
36static_assert(__offsetof(Gich, elrsr) == 0x30, "");
37static_assert(__offsetof(Gich, apr) == 0xf0, "");
38static_assert(__offsetof(Gich, lr) == 0x100, "");
39
40static volatile Gich* gich = NULL;
41
42static uint32_t gicv2_read_gich_hcr() {
43    return gich->hcr;
44}
45
46static void gicv2_write_gich_hcr(uint32_t val) {
47    gich->hcr = val;
48}
49
50static uint32_t gicv2_read_gich_vtr() {
51    return gich->vtr;
52}
53
54static uint32_t gicv2_default_gich_vmcr() {
55    return GICH_VMCR_VPMR_MASK | GICH_VMCR_VENG0;
56}
57
58static uint32_t gicv2_read_gich_vmcr() {
59    return gich->vmcr;
60}
61
62static void gicv2_write_gich_vmcr(uint32_t val) {
63    gich->vmcr = val;
64}
65
66static uint32_t gicv2_read_gich_misr() {
67    return gich->misr;
68}
69
70static uint64_t gicv2_read_gich_elrsr() {
71    return gich->elrsr;
72}
73
74static uint32_t gicv2_read_gich_apr() {
75    return gich->apr;
76}
77
78static void gicv2_write_gich_apr(uint32_t val) {
79    gich->apr = val;
80}
81
82static uint64_t gicv2_read_gich_lr(uint32_t idx) {
83    return gich->lr[idx];
84}
85
86static void gicv2_write_gich_lr(uint32_t idx, uint64_t val) {
87    gich->lr[idx] = static_cast<uint32_t>(val);
88}
89
90static zx_status_t gicv2_get_gicv(paddr_t* gicv_paddr) {
91    // Check for presence of GICv2 virtualisation extensions.
92    if (GICV_OFFSET == 0)
93        return ZX_ERR_NOT_SUPPORTED;
94    *gicv_paddr = vaddr_to_paddr(reinterpret_cast<void*>(GICV_ADDRESS));
95    return ZX_OK;
96}
97
98static uint64_t gicv2_get_lr_from_vector(uint32_t vector) {
99    return (vector & GICH_LR_VIRTUAL_ID_MASK) | GICH_LR_PENDING;
100}
101
102static uint32_t gicv2_get_vector_from_lr(uint64_t lr) {
103    return lr & GICH_LR_VIRTUAL_ID_MASK;
104}
105
106static uint32_t gicv2_get_num_lrs() {
107    return (gicv2_read_gich_vtr() & GICH_VTR_LIST_REGS_MASK) + 1;
108}
109
110static const struct arm_gic_hw_interface_ops gic_hw_register_ops = {
111    .read_gich_hcr = gicv2_read_gich_hcr,
112    .write_gich_hcr = gicv2_write_gich_hcr,
113    .read_gich_vtr = gicv2_read_gich_vtr,
114    .default_gich_vmcr = gicv2_default_gich_vmcr,
115    .read_gich_vmcr = gicv2_read_gich_vmcr,
116    .write_gich_vmcr = gicv2_write_gich_vmcr,
117    .read_gich_misr = gicv2_read_gich_misr,
118    .read_gich_elrsr = gicv2_read_gich_elrsr,
119    .read_gich_apr = gicv2_read_gich_apr,
120    .write_gich_apr = gicv2_write_gich_apr,
121    .read_gich_lr = gicv2_read_gich_lr,
122    .write_gich_lr = gicv2_write_gich_lr,
123    .get_gicv = gicv2_get_gicv,
124    .get_lr_from_vector = gicv2_get_lr_from_vector,
125    .get_vector_from_lr = gicv2_get_vector_from_lr,
126    .get_num_lrs = gicv2_get_num_lrs,
127};
128
129void gicv2_hw_interface_register() {
130    // Populate GICH
131    gich = reinterpret_cast<volatile Gich*>(GICH_ADDRESS);
132    arm_gic_hw_interface_register(&gic_hw_register_ops);
133}
134