a45ce7e2dfcc4d7f8a03389f445df3628225499e
[lunaix-os.git] / lunaix-os / arch / i386 / exceptions / i386_isrm.c
1 #include <hal/acpi/acpi.h>
2 #include <hal/ioapic.h>
3
4 #include <lunaix/isrm.h>
5 #include <lunaix/spike.h>
6
7 /*
8     total: 256 ivs
9     0~31: reserved for sys use (x32)
10     32~47: reserved for os use (x16)
11     48~  : free to allocate for external hardware use. (x208)
12 */
13
14 static char iv_bmp[(IV_MAX - IV_BASE) / 8];
15 static isr_cb handlers[IV_MAX];
16
17 extern void
18 intr_routine_fallback(const isr_param* param);
19
20 void
21 isrm_init()
22 {
23     for (size_t i = 0; i < 256; i++) {
24         handlers[i] = intr_routine_fallback;
25     }
26 }
27
28 static inline int
29 __ivalloc_within(size_t a, size_t b, isr_cb handler)
30 {
31     a = (a - IV_BASE) / 8;
32     b = (b - IV_BASE) / 8;
33
34     for (size_t i = a; i < b; i++) {
35         u8_t chunk = iv_bmp[i], j = 0;
36
37         if (chunk == 0xff)
38             continue;
39
40         while ((chunk & 0x1)) {
41             chunk >>= 1;
42             j++;
43         }
44
45         iv_bmp[i] |= 1 << j;
46
47         int iv = IV_BASE + i * 8 + j;
48         handlers[iv] = handler ? handler : intr_routine_fallback;
49
50         return iv;
51     }
52
53     return 0;
54 }
55
56 int
57 isrm_ivosalloc(isr_cb handler)
58 {
59     return __ivalloc_within(IV_BASE, IV_EX, handler);
60 }
61
62 int
63 isrm_ivexalloc(isr_cb handler)
64 {
65     return __ivalloc_within(IV_EX, IV_MAX, handler);
66 }
67
68 void
69 isrm_ivfree(int iv)
70 {
71     assert(iv < 256);
72
73     if (iv >= IV_BASE) {
74         iv_bmp[(iv - IV_BASE) / 8] &= ~(1 << ((iv - IV_BASE) % 8));
75     }
76
77     handlers[iv] = intr_routine_fallback;
78 }
79
80 int
81 isrm_bindirq(int irq, isr_cb irq_handler)
82 {
83     int iv;
84     if (!(iv = isrm_ivexalloc(irq_handler))) {
85         panickf("out of IV resource. (irq=%d)", irq);
86         return 0; // never reach
87     }
88
89     // PC_AT_IRQ_RTC -> RTC_TIMER_IV, fixed, edge trigged, polarity=high,
90     // physical, APIC ID 0
91     ioapic_redirect(acpi_gistranslate(irq), iv, 0, IOAPIC_DELMOD_FIXED);
92
93     return iv;
94 }
95
96 void
97 isrm_bindiv(int iv, isr_cb handler)
98 {
99     assert(iv < 256);
100
101     if (iv >= IV_BASE) {
102         iv_bmp[(iv - IV_BASE) / 8] |= 1 << ((iv - IV_BASE) % 8);
103     }
104
105     handlers[iv] = handler;
106 }
107
108 isr_cb
109 isrm_get(int iv)
110 {
111     assert(iv < 256);
112
113     return handlers[iv];
114 }