This repository has been archived by the owner on Jan 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
irq_handler.c
129 lines (104 loc) · 2.87 KB
/
irq_handler.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "basic.h"
#include "type.h"
#include "debug.h"
#include "timer.h"
#include "port.h"
#include "gic.h"
#include "vcpu.h"
#include "virtual_gic.h"
#include "cortexa7.h"
#include "memory_manage.h"
#include "logger.h"
#include "schedule.h"
#include "timer_event.h"
#include "hcr.h"
#include "hyp_call.h"
#include "cp_access.h"
#include "cpsr.h"
#include "rbtree.h"
extern UW test_vcpu_id;
extern char* sleep_vector;
int tmp_irq_no = -1;
static tree_t *tree; // irq_num -> handler function
typedef struct {
void (*func)(UW ,void *);
void *arg;
} handler_t;
handler_t hdlr[512];
UW hdlr_num = 0;
static int handler_comp(void *a, void *b){
W na = (W)a;
W nb = (W)b;
return nb-na;
}
static void ht_handle(UW eoir, void *arg){
htimer_clear();
timer_event_tick();
OUTW(GICC_EOIR,eoir);
OUTW(GICC_DIR,eoir);
return;
}
static void vmi_handle(UW eoir, void *arg){
T_VCPU *vcpu = vcpu_get_executing();
virtual_gic_maintenance(vcpu->vm->vgic, vcpu->vid);
OUTW(GICC_EOIR,eoir);
OUTW(GICC_DIR,eoir);
}
static void nstimer_handle(UW eoir, void *arg){
if(ptimer_get_value() >= ptimer_get_cmp_value() ){
virtual_gic_send_hardware_int(vcpu_get_last()->vm->vgic, eoir);
OUTW(GICC_EOIR,eoir);
} else {
OUTW(GICC_EOIR,eoir);
OUTW(GICC_DIR,eoir);
}
}
static void vtimer_handle(UW eoir, void *arg){
if(vtimer_get_value() >= vtimer_get_cmp_value() ){
virtual_gic_send_hardware_int(vcpu_get_last()->vm->vgic, eoir);
OUTW(GICC_EOIR,eoir);
} else {
OUTW(GICC_EOIR,eoir);
OUTW(GICC_DIR,eoir);
}
}
void irq_handler_init(void){
tree = rbtree_alloc(handler_comp);
irq_handler_register(IRQ_ID_HT, ht_handle, NULL);
irq_handler_register(IRQ_ID_VMI, vmi_handle, NULL);
irq_handler_register(IRQ_ID_NSPT, nstimer_handle, NULL);
irq_handler_register(IRQ_ID_VT, vtimer_handle, NULL);
}
void irq_handler_register(UW irq_no, void (*func)(UW, void *), void *arg){
handler_t *h = &(hdlr[hdlr_num++]);
h->func = func;
h->arg = arg;
rbtree_insert(tree, (void *)irq_no, (void *)h);
}
void irq_handler(UW eoir){
UW irq_no = eoir & 0x3ff;
tmp_irq_no = irq_no;
node_t *node;
if((node = rbtree_search(tree, (void *)irq_no))!=NULL){
handler_t *handler = (handler_t *)node->val;
handler->func(eoir, handler->arg);
} else {
tv_abort("unknown irq!\n");
}
T_VCPU *prev = vcpu_get_executing();
if(scheduler_get_flag()){
vcpu_preemption(scheduler_get_operations()->schedule());
}
if(prev!=NULL){
while(vcpu_get_executing()==NULL){
Asm("mcr p15, 4, %0, c12, c0, 0\n"
"ldr lr, =1f\n"
"dsb\n"
"cpsie aif\n"
"wfi\n"
"1: nop"
::"r"(&sleep_vector)
:"lr");
}
}
}