Skip to content

Commit 6fb95f7

Browse files
committed
Make vIRQ functions claim IRQs on first call
1 parent 2bb3468 commit 6fb95f7

File tree

3 files changed

+89
-119
lines changed

3 files changed

+89
-119
lines changed

core/system/inc/unvic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ extern uint32_t unvic_irq_priority_get(uint32_t irqn);
5252
extern int unvic_irq_level_get(void);
5353
extern int unvic_default(uint32_t isr_id);
5454

55-
extern void unvic_init(void);
55+
extern void unvic_init(uint32_t const * const user_vtor);
5656

5757
/** Perform a context switch-in as a result of an interrupt request.
5858
*

core/system/src/main.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include "unvic.h"
2222
#include "vmpu.h"
2323

24-
UVISOR_NOINLINE void uvisor_init_pre(void)
24+
UVISOR_NOINLINE void uvisor_init_pre(uint32_t const * const user_vtor)
2525
{
2626
/* Reset the uVisor own BSS section. */
2727
memset(&__bss_start__, 0, VMPU_REGION_SIZE(&__bss_start__, &__bss_end__));
@@ -30,7 +30,7 @@ UVISOR_NOINLINE void uvisor_init_pre(void)
3030
memcpy(&__data_start__, &__data_start_src__, VMPU_REGION_SIZE(&__data_start__, &__data_end__));
3131

3232
/* Initialize the unprivileged NVIC module. */
33-
unvic_init();
33+
unvic_init(user_vtor);
3434

3535
/* Initialize the debugging features. */
3636
DEBUG_INIT();
@@ -135,7 +135,7 @@ void main_entry(void)
135135
}
136136

137137
/* Early uVisor initialization. */
138-
uvisor_init_pre();
138+
uvisor_init_pre((uint32_t *) SCB->VTOR);
139139

140140
/* Run basic sanity checks. */
141141
if (vmpu_init_pre() == 0) {

core/system/src/unvic.c

Lines changed: 85 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ uint8_t g_nvic_prio_bits;
3232
* @internal
3333
*
3434
* If multiple disable-/re-enable-all functions are called in the same box, a
35-
* counter is respectively incremented/drecremented so that it never happens
35+
* counter is respectively incremented/decremented so that it never happens
3636
* that a nested function re-enables IRQs for the caller. */
3737
uint32_t g_irq_disable_all_counter[UVISOR_MAX_BOXES];
3838

@@ -68,7 +68,7 @@ void unvic_acl_add(uint8_t box_id, void *function, uint32_t irqn)
6868
uv = &g_unvic_vector[irqn];
6969

7070
/* check if IRQ entry is populated */
71-
if(uv->id || uv->hdlr)
71+
if(uv->id != UVISOR_BOX_ID_INVALID)
7272
{
7373
HALT_ERROR(PERMISSION_DENIED,
7474
"Permission denied: IRQ %d is owned by box %d\n\r", irqn,
@@ -80,9 +80,15 @@ void unvic_acl_add(uint8_t box_id, void *function, uint32_t irqn)
8080
uv->hdlr = function;
8181
}
8282

83+
#define UNVIC_ISR_OWNER_OTHER 0
84+
#define UNVIC_ISR_OWNER_NONE 1
85+
#define UNVIC_ISR_OWNER_SELF 2
86+
87+
/* @retval 0 you do not own this interrupt
88+
* @retval 1 you own or you can claim this interrupt
89+
*/
8390
static int unvic_acl_check(int irqn)
8491
{
85-
int is_irqn_registered;
8692
TIsrUVector *uv;
8793

8894
/* don't allow to modify uVisor-owned IRQs */
@@ -91,113 +97,83 @@ static int unvic_acl_check(int irqn)
9197
/* get vector entry */
9298
uv = &g_unvic_vector[irqn];
9399

94-
/* an IRQn slot is considered as registered if the ISR entry in the unprivileged
95-
* table is not 0 */
96-
is_irqn_registered = uv->hdlr ? 1 : 0;
100+
if (uv->id == g_active_box || uv->id == UVISOR_BOX_ID_INVALID) {
101+
return 1;
102+
}
103+
DPRINTF("Disallowed to access IRQ %d from box %d!\n\r", irqn, g_active_box);
104+
return 0;
105+
}
97106

98-
/* check if the same box that registered the IRQn is accessing it
99-
* note: if the vector entry for a certain IRQn is 0, it means that no secure
100-
* box claimed exclusive ownership for it. So, another box can claim it
101-
* if it is currently un-registered (that is, if the registered handler
102-
* is NULL) */
103-
if(uv->id != g_active_box && (uv->id || is_irqn_registered))
107+
/* @retval 0 you do not own this interrupt
108+
* @retval 1 you own this interrupt
109+
*/
110+
static int unvic_isr_register(uint32_t irqn)
111+
{
112+
int isr_status = unvic_acl_check(irqn);
113+
switch(isr_status)
104114
{
105-
HALT_ERROR(PERMISSION_DENIED,
106-
"Permission denied: IRQ %d is owned by box %d\n\r", irqn,
107-
uv->id);
115+
case UNVIC_ISR_OWNER_NONE:
116+
g_unvic_vector[irqn].id = g_active_box;
117+
DPRINTF("IRQ %d registered to box %d\n\r", irqn, g_active_box);
118+
case UNVIC_ISR_OWNER_SELF:
119+
return 1;
120+
default:
121+
break;
108122
}
109-
110-
return is_irqn_registered;
123+
return 0;
111124
}
112125

113126
void unvic_isr_set(uint32_t irqn, uint32_t vector)
114127
{
115128
/* verify IRQ access privileges */
116-
unvic_acl_check(irqn);
117-
118-
/* save unprivileged handler
119-
* note: if the handler is NULL the IRQn gets de-registered for the current
120-
* box, meaning that other boxes can still use it. In this way boxes
121-
* can share un-exclusive IRQs. A secure box should not do that if it
122-
* wants to hold exclusivity over an IRQn
123-
* note: when an IRQ is released (de-registered) the corresponding IRQn is
124-
* disabled, to ensure that no spurious interrupts are served */
125-
if (vector) {
126-
g_unvic_vector[irqn].id = g_active_box;
127-
}
128-
else {
129-
NVIC_DisableIRQ(irqn);
130-
g_unvic_vector[irqn].id = 0;
129+
if (!unvic_isr_register(irqn)) {
130+
return;
131131
}
132-
g_unvic_vector[irqn].hdlr = (TIsrVector) vector;
133-
134-
/* set default priority (SVC must always be higher) */
135-
NVIC_SetPriority(irqn, __UVISOR_NVIC_MIN_PRIORITY);
136132

137-
DPRINTF("IRQ %d %s box %d\n\r",
138-
irqn,
139-
vector ? "registered to" : "released by",
140-
g_active_box);
133+
/* save unprivileged handler */
134+
g_unvic_vector[irqn].hdlr = (TIsrVector) vector;
141135
}
142136

143137
uint32_t unvic_isr_get(uint32_t irqn)
144138
{
145139
/* verify IRQ access privileges */
146-
unvic_acl_check(irqn);
140+
if (!unvic_isr_register(irqn)) {
141+
return 0;
142+
}
147143

148144
return (uint32_t) g_unvic_vector[irqn].hdlr;
149145
}
150146

151147
void unvic_irq_enable(uint32_t irqn)
152148
{
153-
int is_irqn_registered;
154-
155149
/* verify IRQ access privileges */
156-
is_irqn_registered = unvic_acl_check(irqn);
157-
158-
/* Enable the IRQ, but only if IRQs are not globally disabled for the
159-
* currently active box. */
160-
if (is_irqn_registered) {
161-
/* If the counter of nested disable-all IRQs is set to 0, it means that
162-
* IRQs are not globally disabled for the current box. */
163-
if (!g_irq_disable_all_counter[g_active_box]) {
164-
DPRINTF("IRQ %d enabled\n\r", irqn);
165-
NVIC_EnableIRQ(irqn);
166-
} else {
167-
/* We do not enable the IRQ directly, but notify uVisor to enable it
168-
* when IRQs will be re-enabled globally for the current box. */
169-
g_unvic_vector[irqn].was_enabled = true;
170-
}
171-
return;
172-
}
173-
else if (UNVIC_IS_IRQ_ENABLED(irqn)) {
174-
DPRINTF("IRQ %d is unregistered; state unchanged\n\r", irqn);
150+
if (!unvic_isr_register(irqn)) {
175151
return;
176152
}
177-
else {
178-
HALT_ERROR(NOT_ALLOWED, "IRQ %d is unregistered; state cannot be changed", irqn);
153+
154+
/* If the counter of nested disable-all IRQs is set to 0, it means that
155+
* IRQs are not globally disabled for the current box. */
156+
if (!g_irq_disable_all_counter[g_active_box]) {
157+
DPRINTF("IRQ %d enabled\n\r", irqn);
158+
NVIC_EnableIRQ(irqn);
159+
} else {
160+
/* We do not enable the IRQ directly, but notify uVisor to enable it
161+
* when IRQs will be re-enabled globally for the current box. */
162+
g_unvic_vector[irqn].was_enabled = true;
179163
}
164+
return;
180165
}
181166

182167
void unvic_irq_disable(uint32_t irqn)
183168
{
184-
int is_irqn_registered;
185-
186169
/* verify IRQ access privileges */
187-
is_irqn_registered = unvic_acl_check(irqn);
188-
189-
if (is_irqn_registered) {
190-
DPRINTF("IRQ %d disabled, but still owned by box %d\n\r", irqn, g_unvic_vector[irqn].id);
191-
NVIC_DisableIRQ(irqn);
192-
return;
193-
}
194-
else if (!UNVIC_IS_IRQ_ENABLED(irqn)) {
195-
DPRINTF("IRQ %d is unregistered; state unchanged\n\r", irqn);
170+
if (!unvic_isr_register(irqn)) {
196171
return;
197172
}
198-
else {
199-
HALT_ERROR(NOT_ALLOWED, "IRQ %d is unregistered; state cannot be changed", irqn);
200-
}
173+
174+
DPRINTF("IRQ %d disabled, but still owned by box %d\n\r", irqn, g_unvic_vector[irqn].id);
175+
NVIC_DisableIRQ(irqn);
176+
return;
201177
}
202178

203179
/** Disable all interrupts for the currently active box.
@@ -296,77 +272,63 @@ void unvic_irq_enable_all(void)
296272

297273
void unvic_irq_pending_clr(uint32_t irqn)
298274
{
299-
int is_irqn_registered;
300-
301275
/* verify IRQ access privileges */
302-
is_irqn_registered = unvic_acl_check(irqn);
303-
304-
/* enable IRQ */
305-
if (is_irqn_registered) {
306-
DPRINTF("IRQ %d pending status cleared\n\r", irqn);
307-
NVIC_ClearPendingIRQ(irqn);
276+
if (!unvic_isr_register(irqn)) {
308277
return;
309278
}
310-
else {
311-
HALT_ERROR(NOT_ALLOWED, "IRQ %d is unregistered; state cannot be changed", irqn);
312-
}
279+
280+
/* clear pending IRQ */
281+
DPRINTF("IRQ %d pending status cleared\n\r", irqn);
282+
NVIC_ClearPendingIRQ(irqn);
313283
}
314284

315285
void unvic_irq_pending_set(uint32_t irqn)
316286
{
317-
int is_irqn_registered;
318-
319287
/* verify IRQ access privileges */
320-
is_irqn_registered = unvic_acl_check(irqn);
321-
322-
/* enable IRQ */
323-
if (is_irqn_registered) {
324-
DPRINTF("IRQ %d pending status set (will be served as soon as possible)\n\r", irqn);
325-
NVIC_SetPendingIRQ(irqn);
288+
if (!unvic_isr_register(irqn)) {
326289
return;
327290
}
328-
else {
329-
HALT_ERROR(NOT_ALLOWED, "IRQ %d is unregistered; state cannot be changed", irqn);
330-
}
291+
292+
/* set pending IRQ */
293+
DPRINTF("IRQ %d pending status set (will be served as soon as possible)\n\r", irqn);
294+
NVIC_SetPendingIRQ(irqn);
331295
}
332296

333297
uint32_t unvic_irq_pending_get(uint32_t irqn)
334298
{
335299
/* verify IRQ access privileges */
336-
unvic_acl_check(irqn);
300+
if (!unvic_isr_register(irqn)) {
301+
return 0;
302+
}
337303

338304
/* get priority for device specific interrupts */
339305
return NVIC_GetPendingIRQ(irqn);
340306
}
341307

342308
void unvic_irq_priority_set(uint32_t irqn, uint32_t priority)
343309
{
344-
int is_irqn_registered;
345-
346310
/* verify IRQ access privileges */
347-
is_irqn_registered = unvic_acl_check(irqn);
311+
if (!unvic_isr_register(irqn)) {
312+
return;
313+
}
348314

349315
/* check for maximum priority */
350316
if (priority > UVISOR_VIRQ_MAX_PRIORITY) {
351317
HALT_ERROR(NOT_ALLOWED, "NVIC priority overflow; max priority allowed: %d\n\r", UVISOR_VIRQ_MAX_PRIORITY);
352318
}
353319

354320
/* set priority for device specific interrupts */
355-
if (is_irqn_registered) {
356-
DPRINTF("IRQ %d priority set to %d (NVIC), %d (virtual)\n\r", irqn, __UVISOR_NVIC_MIN_PRIORITY + priority,
357-
priority);
358-
NVIC_SetPriority(irqn, __UVISOR_NVIC_MIN_PRIORITY + priority);
359-
return;
360-
}
361-
else {
362-
HALT_ERROR(NOT_ALLOWED, "IRQ %d is unregistered; state cannot be changed", irqn);
363-
}
321+
DPRINTF("IRQ %d priority set to %d (NVIC), %d (virtual)\n\r", irqn, __UVISOR_NVIC_MIN_PRIORITY + priority,
322+
priority);
323+
NVIC_SetPriority(irqn, __UVISOR_NVIC_MIN_PRIORITY + priority);
364324
}
365325

366326
uint32_t unvic_irq_priority_get(uint32_t irqn)
367327
{
368328
/* verify IRQ access privileges */
369-
unvic_acl_check(irqn);
329+
if (!unvic_isr_register(irqn)) {
330+
return 0;
331+
}
370332

371333
/* get priority for device specific interrupts */
372334
return NVIC_GetPriority(irqn) - __UVISOR_NVIC_MIN_PRIORITY;
@@ -560,7 +522,7 @@ void unvic_gateway_context_switch_out(uint32_t svc_sp, uint32_t msp)
560522
__set_CONTROL(__get_CONTROL() & ~2);
561523
}
562524

563-
void unvic_init(void)
525+
void unvic_init(uint32_t const * const user_vtor)
564526
{
565527
uint8_t prio_bits;
566528
uint8_t volatile *prio;
@@ -604,4 +566,12 @@ void unvic_init(void)
604566
* by IRQ number. For example, IRQ 0 has precedence over IRQ 1 if both have
605567
* the same priority level. */
606568
NVIC_SetPriorityGrouping(0);
569+
570+
/* Copy the user interrupt table into the handlers. */
571+
for (uint32_t ii=0; ii < NVIC_VECTORS; ii++) {
572+
g_unvic_vector[ii].id = UVISOR_BOX_ID_INVALID;
573+
g_unvic_vector[ii].hdlr = (TIsrVector) user_vtor[ii + NVIC_OFFSET];
574+
/* set default priority (SVC must always be higher) */
575+
NVIC_SetPriority(ii, __UVISOR_NVIC_MIN_PRIORITY);
576+
}
607577
}

0 commit comments

Comments
 (0)