blob: 1c09532fe8e3f3aa60a41cc161e08171a20ea5eb [file] [log] [blame]
Andrew Walbran95458902018-11-13 18:56:06 +00001/*
2 * Copyright 2018 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "interrupts.h"
18
19#include <stdbool.h>
20#include <stdint.h>
21
22#include "hf/arch/cpu.h"
23
24#include "hf/dlog.h"
25
26#include "../msr.h"
27
28extern uint8_t vector_table_el1;
29
30void exception_setup()
31{
32 /* Set exception vector table. */
33 write_msr(VBAR_EL1, &vector_table_el1);
34
35 write_msr(ICC_CTLR_EL1, 0);
36}
37
38void interrupt_gic_setup()
39{
40 GICD_CTLR = 1u << 4 /* Enable affinity routing. */
41 | 1u << 1; /* Enable group 1 non-secure interrupts. */
42
43 /* Mark CPU as awake. */
44 GICR_WAKER &= ~(1u << 1);
45 while ((GICR_WAKER & (1u << 2)) != 0) {
46 dlog("Waiting for ChildrenAsleep==0\n");
47 }
48
49 /* Put interrupts into non-secure group 1. */
50 dlog("GICR_IGROUPR0 was %x\n", 0xffffffff, GICR_IGROUPR0);
51 GICR_IGROUPR0 = 0xffffffff;
52 dlog("wrote %x to GICR_IGROUPR0, got back %x\n", 0xffffffff,
53 GICR_IGROUPR0);
54 /* Enable non-secure group 1. */
55 write_msr(ICC_IGRPEN1_EL1, 0x00000001);
56 dlog("wrote %x to ICC_IGRPEN1_EL1, got back %x\n", 0x00000001,
57 read_msr(ICC_IGRPEN1_EL1));
58}
59
60void interrupt_enable(uint32_t intid, bool enable)
61{
62 if (enable) {
63 GICD_ISENABLER(intid / 32) |= 1 << (intid % 32);
64 if (intid < 32) {
65 GICR_ISENABLER0 |= 1 << intid;
66 }
67 } else {
68 GICD_ICENABLER(intid / 32) |= 1 << (intid % 32);
69 if (intid < 32) {
70 GICR_ICENABLER0 |= 1 << intid;
71 }
72 }
73}
74
75void interrupt_enable_all(bool enable)
76{
77 uint32_t i;
78 if (enable) {
79 GICR_ISENABLER0 = 0xffffffff;
80 for (i = 0; i < 32; ++i) {
81 GICD_ISENABLER(i) = 0xffffffff;
82 }
83 } else {
84 GICR_ICENABLER0 = 0x00000000;
85 for (i = 0; i < 32; ++i) {
86 GICD_ICENABLER(i) = 0x00000000;
87 }
88 }
89}
90
91void interrupt_set_priority_mask(uint8_t min_priority)
92{
93 write_msr(ICC_PMR_EL1, min_priority);
94}
95
96void interrupt_set_priority(uint32_t intid, uint8_t priority)
97{
98 GICD_IPRIORITYR(intid) = priority;
99}
100
101void interrupt_set_edge_triggered(uint32_t intid, bool edge_triggered)
102{
103 uint32_t bit = 1u << (intid % 16 * 2 + 1);
104 if (intid < 32) {
105 if (edge_triggered) {
106 GICR_ICFGR(intid / 16) |= bit;
107 } else {
108 GICR_ICFGR(intid / 16) &= ~bit;
109 }
110 } else {
111 if (edge_triggered) {
112 GICD_ICFGR(intid / 16) |= bit;
113 } else {
114 GICD_ICFGR(intid / 16) &= ~bit;
115 }
116 }
117}
118
119void interrupt_send_sgi(uint8_t intid, bool irm, uint8_t affinity3,
120 uint8_t affinity2, uint8_t affinity1,
121 uint16_t target_list)
122{
123 uint64_t sgi_register =
124 ((uint64_t)target_list) | ((uint64_t)affinity1 << 16) |
125 (((uint64_t)intid & 0x0f) << 24) | ((uint64_t)affinity2 << 32) |
126 ((uint64_t)irm << 40) | ((uint64_t)affinity3 << 48);
127 write_msr(ICC_SGI1R_EL1, sgi_register);
128}
129
130uint32_t interrupt_get_and_acknowledge()
131{
132 return read_msr(ICC_IAR1_EL1);
133}
134
135void interrupt_end(uint32_t intid)
136{
137 write_msr(ICC_EOIR1_EL1, intid);
138}
139
140void sync_current_exception(uintreg_t esr, uintreg_t elr)
141{
142 switch (esr >> 26) {
143 case 0x25: /* EC = 100101, Data abort. */
144 dlog("Data abort: pc=0x%x, esr=0x%x, ec=0x%x", elr, esr,
145 esr >> 26);
146 if (!(esr & (1u << 10))) { /* Check FnV bit. */
147 dlog(", far=0x%x", read_msr(far_el1));
148 } else {
149 dlog(", far=invalid");
150 }
151
152 dlog("\n");
153 for (;;) {
154 /* do nothing */
155 }
156
157 default:
158 dlog("Unknown current sync exception pc=0x%x, esr=0x%x, "
159 "ec=0x%x\n",
160 elr, esr, esr >> 26);
161 for (;;) {
162 /* do nothing */
163 }
164 }
165 for (;;) {
166 /* do nothing */
167 }
168}