Embed ISRs at known address
[viridis.git] / kernel / acpi.c
1 /* vim: set ts=4 sw=4 sts=4 et : */
2
3 #include <kernel.h>
4 #include <map.h>
5 #include <vsalloc.h>
6 #include <smp.h>
7
8 struct rsdp {
9     char sig[8];
10     u8 checksum;
11     char oem_id[6];
12     u8 rev;
13     u32 rsdt_pa;
14     u32 length;
15     u64 xsdt_pa;
16     u8 extd_checksum;
17 } __attribute__ ((packed));
18
19 struct description_header {
20     char sig[4];
21     u32 length;
22     u8 revision;
23     u8 checksum;
24     char oem_id[6];
25     char oem_table_id[8];
26     u32 oem_revision;
27     u32 creator_id;
28     u32 creator_revision;       /* 36 */
29 } __attribute__ ((packed));
30
31 #define APIC_TYPE_LAPIC         0
32 #define APIC_TYPE_IOAPIC        1
33 #define APIC_TYPE_ISO           2
34 #define APIC_TYPE_NMI           3
35 #define APIC_TYPE_LAPIC_NMI     4
36 #define APIC_TYPE_LAPIC_AO      5
37 #define APIC_TYPE_IOSAPIC       6
38 #define APIC_TYPE_LSAPIC        7
39 #define APIC_TYPE_PLATIS        8
40 #define APIC_TYPE_X2APIC        9
41 #define APIC_TYPE_X2NMI         10
42 #define APIC_TYPE_GICC          11
43 #define APIC_TYPE_GICD          12
44 #define APIC_TYPE_GICMSI        13
45 #define APIC_TYPE_GICR          14
46 #define APIC_TYPE_GICITS        15
47
48 char *apic_types[] = {
49     "LAPIC", "IOAPIC", "ISO", "NMI", "LAPIC_NMI", "LAPIC_AO", "IOSAPIC",
50     "LSAPIC", "PLATIS", "X2APIC", "X2NMI",
51     "GICC", "GICD", "GICMSI", "GICR", "GICITS"
52 };
53
54 struct apic_entry {
55     u32 lapic_addr;
56     u32 flags;
57 } __attribute__ ((packed));
58
59 #define APIC_FLAG_PCAT_COMPAT 1
60
61 struct lapic_entry {
62     u8 type;
63     u8 len;
64     u8 apic_uid;
65     u8 apic_id;
66     u32 flags;
67 } __attribute__ ((packed));
68
69 #define LAPIC_FLAGS_ENABLED 1
70
71 void acpi_apic_handler(struct description_header *hdr, void *entry_ptr)
72 {
73     struct apic_entry *entry = entry_ptr;
74     int cpus = 0;
75
76     u8 *intcons = (u8 *) (((u64) entry) + sizeof(struct apic_entry));
77     int length =
78         hdr->length - (sizeof(struct description_header) +
79                        sizeof(struct apic_entry));
80     int cur_byte = 0;
81
82     while (cur_byte < length) {
83         u8 type = intcons[cur_byte];
84
85         if (type == APIC_TYPE_LAPIC) {
86             struct lapic_entry *lapic = (void *)&intcons[cur_byte];
87
88             if (lapic->flags & LAPIC_FLAGS_ENABLED) {
89                 smp_wake(lapic->apic_id);
90                 cpus++;
91             }
92         }
93
94         cur_byte += intcons[cur_byte + 1];
95     }
96
97     printk("%d CPUs detected\n", cpus);
98 }
99
100 struct acpi_section_handler {
101     char match_sig[4];
102     void (*handler) (struct description_header * hdr, void *end_ptr);
103 };
104
105 struct acpi_section_handler handlers[] = {
106     {
107      .match_sig = {'A', 'P', 'I', 'C'},
108      .handler = acpi_apic_handler,
109      },
110     {
111      .handler = NULL}
112 };
113
114 void __acpi_handle_table(u32 pa)
115 {
116     void *allocation = vsalloc("ACPI", 0, 1);
117     struct description_header *hdr;
118     struct acpi_section_handler *cur = handlers;
119
120     map_pages((u64) allocation, pa, 1);
121     hdr = (struct description_header *)((u64) allocation + PAGE_ALIGN_OFF(pa));
122
123     while (cur->handler) {
124         if ((hdr->sig[0] == cur->match_sig[0]) &&
125             (hdr->sig[1] == cur->match_sig[1]) &&
126             (hdr->sig[2] == cur->match_sig[2]) &&
127             (hdr->sig[3] == cur->match_sig[3])) {
128
129             cur->handler(hdr,
130                          (void *)((u64) hdr +
131                                   sizeof(struct description_header)));
132
133             break;
134         }
135         cur++;
136     }
137
138     unmap_pages((u64) allocation, 1);
139     vfree(allocation, 1);
140 }
141
142 int acpi_init(void)
143 {
144     struct description_header *hdr;
145     struct rsdp *rsdp;
146     u32 *entries;
147
148     int ret = 0;
149     int i;
150
151     rsdp = platform->find_rsdp(platform);
152
153     if (!rsdp)
154         return -1;
155
156     hdr = vsalloc("ACPI", 0, 1);
157
158     map_pages((u64) hdr, rsdp->rsdt_pa, 1);
159     hdr =
160         (struct description_header *)((u64) hdr +
161                                       PAGE_ALIGN_OFF(rsdp->rsdt_pa));
162
163     entries = (u32 *) ((u64) hdr + sizeof(struct description_header));
164     for (i = 0; i < ((hdr->length - sizeof(struct description_header)) / 4); i++)
165         __acpi_handle_table(entries[i]);
166
167     unmap_pages((u64) hdr, 1);
168     vfree(hdr, 1);
169
170     return ret;
171 }