Added IVY support for kmalloc, mptables, pci, string.h (string.h from Zach)
[akaros.git] / kern / src / mptables.c
1 #include <arch/mmu.h>
2 #include <arch/x86.h>
3 #include <arch/smp.h>
4 #include <arch/apic.h>
5 #include <arch/ioapic.h>
6
7
8 #include <ros/memlayout.h>
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <pmap.h>
13 #include <kmalloc.h>
14
15 #include <mptables.h>
16 #include <pci.h>
17
18 /* Basic MP Tables Parser
19  *
20  * Memory Locations and table structs taken from FreeBSD's mptable.c and modified.
21  *
22  * Put cool text here
23  * 
24  * TODO: Extended table support
25  * TODO: KMALLOC null checks
26  * TODO: Error checking, pci device not found, etc.
27  */
28
29
30 tableEntry basetableEntryTypes[] =
31 {
32     { 0, 20, "Processor" },
33     { 1,  8, "Bus" },
34     { 2,  8, "I/O APIC" },
35     { 3,  8, "I/O INT" },
36     { 4,  8, "Local INT" }
37 };
38
39 // Important global items
40 enum interrupt_modes current_interrupt_mode;
41
42 proc_entry *COUNT(mp_entries_count[PROC]) mp_proc_entries;
43 bus_entry *COUNT(mp_entries_count[BUS]) mp_bus_entries;
44 ioapic_entry *COUNT(mp_entries_count[IOAPIC]) mp_ioapic_entries;
45 int_entry *COUNT(mp_entries_count[INT]) mp_int_entries;
46 int_entry *COUNT(mp_entries_count[LINT]) mp_lint_entries; // Not a type. lint entries == int entries
47
48
49 int mp_entries_count[NUM_ENTRY_TYPES]; // How large each array is.
50
51 pci_int_group pci_int_groups[PCI_MAX_BUS][PCI_MAX_DEV];
52 isa_int_entry isa_int_entries[NUM_IRQS];
53 ioapic_entry ioapic_entries[IOAPIC_MAX_ID];
54
55 void mptables_parse() {
56         
57         mpfps_t *mpfps;
58         
59         // Memsets.
60         // Setup the indexable ioapic array.
61         // YOU MUST check the flag field to see if its 0. If 0, unusable.
62         // Ths is defined by MPTables, and I leaverage this with the memset below.
63         memset(ioapic_entries, 0, sizeof(ioapic_entries));
64         
65         // We define an IOAPIC ID over 255 to be invalid.
66         memset(pci_int_groups, 0xFF, sizeof(pci_int_groups));
67         memset(isa_int_entries, 0xFF, sizeof(isa_int_entries));
68         
69         
70         mptables_info("Starting MPTables Parsing...\n");
71         
72         // Basic struct:
73         //      1) Find floating pointer
74         //      2) Go to addr referenced by floating pointer
75         //      3) Read table header info
76         
77         // We now have to search through 3 address regions searching for a magic string.
78         
79         // I unrolled this loop because I thought it was easier to read. This can be 
80         // easily packed into a for loop on an array.
81         
82         // Note: The pointer can actually be elsewhere. See the FBSD MPTables implimentation for more info
83         // Just doesn't make sense right now to check more places.
84         
85         // Search the BIOS ROM Address Space (MOST LIKELY)
86         mptables_dump("-->Searching BIOS ROM Area...\n");
87         mpfps = find_floating_pointer((physaddr_t)KADDR(BIOS_ROM_BASE), (physaddr_t)KADDR(BIOS_ROM_BOUND));
88         
89         if (mpfps == NULL) {
90                 
91                 // Search the EBDA UNTESTED
92                 
93                 // First, we have to find the darn EBDA Addr.
94                 // This USSUALLY works. May be some cases where it doesnt.
95                 // See osdev x86 mem-map for more information
96                 physaddr_t ebda_base = read_mmreg32((uint32_t)KADDR(EBDA_POINTER));
97                 
98                 if (ebda_base) {
99                         ebda_base = ebda_base << 4;
100                         ebda_base = (physaddr_t)KADDR(ebda_base);
101                         physaddr_t ebda_bound = ebda_base + EBDA_SIZE - sizeof(mpfps_t);
102                         
103                         mptables_dump("-->Searching EBDA...\n");
104                         mpfps = find_floating_pointer(ebda_base, ebda_bound);
105                 }
106         }
107
108         if (mpfps == NULL) {
109                 // Search the last KB of system memory UNTESTED
110                 // Note: Will only be there if it not in the EBDA. So this must be called after the EBDA check.
111                 // This logic is ripped from mptables without much understanding. No machine to test it on.
112                 
113                 physaddr_t top_of_mem = read_mmreg32((uint32_t)KADDR(TOPOFMEM_POINTER));
114                 
115                 if (top_of_mem) {
116                         --top_of_mem;
117                         top_of_mem = top_of_mem * 1024;
118                         
119                         top_of_mem = (physaddr_t)KADDR(top_of_mem);
120                 
121                 mptables_dump("-->Searching top of (real mode) Ram...\n");
122                         mpfps = find_floating_pointer(top_of_mem, top_of_mem + 1024 - sizeof(mpfps_t));
123                 }
124         }
125         
126         if (mpfps == NULL) {
127                 // Search the last KB of system memory based on a 640K limited, due to CMOS lying
128                 // Note: Will only be there if it not in the EBDA. So this must be called after the EBDA check.
129                                 
130                 physaddr_t top_of_mem = DEFAULT_TOPOFMEM;
131                 
132                 if (top_of_mem) {
133                                 
134                         top_of_mem = top_of_mem - 1024;
135                         
136                         top_of_mem = (physaddr_t)KADDR(top_of_mem);
137                 
138                 mptables_dump("-->Searching top of (real mode) Ram 640K cap, incase CMOS lied...\n");
139                         mpfps = find_floating_pointer(top_of_mem, top_of_mem + 1024 - sizeof(mpfps_t));
140                 }
141         }
142
143         // If we can't find the pointer, it means we are running on a non-mp compliant machine.
144         // This is bad. We can't do interrupts the way we want.
145         // We could have this trigger a MODE in which we operate using the standard PIC, if we really wanted.
146         if (mpfps == NULL) {
147                 panic("MPTABLES Not found. IOAPIC and interrupts will not function properly. <Insert whale held up by smaller birds here>");
148         }
149         
150         mptables_info("-->MPTables Floating Pointer Structure found @ KVA 0x%p.\n", mpfps);
151         
152         mptables_info("-->Current Interrupt Mode: ");
153         // Identify our interrupt mode
154         if (mpfps->mpfb2 & IMCRP_MASK) {
155                 current_interrupt_mode = PIC;
156                 mptables_info("PIC\n");
157         }
158         else {
159                 current_interrupt_mode = VW;
160                 mptables_info("Virtual Wire\n");
161         }
162         
163         configuration_parse((physaddr_t)KADDR((uint32_t)(mpfps->pap)));
164         
165         proc_parse();
166         bus_parse();
167         ioapic_parse();
168         int_parse();
169         lint_parse();
170         
171 }
172
173 // Searches the given address range, starting at addr first, to (including) last, for the mptables pointer.
174 // Does not esure base/bounds are sane.
175 mpfps_t *find_floating_pointer(physaddr_t base, physaddr_t bound) {
176
177         uint32_t count = (bound - base + sizeof(mpfps_t))/sizeof(mpfps_t);
178
179         // This trusted count was authorized with the blessing of Zach.
180         // Blame Intel and the MP Spec for making me do this cast.
181         mpfps_t* mpfps = (mpfps_t* COUNT(count)) TC(base);
182
183         // Loop over the entire range looking for the signature. The signature is ascii _MP_, which is
184         //  stored in the given MP_SIG
185         while ( ((physaddr_t)mpfps <= bound) && (read_mmreg32((uint32_t)(mpfps->signature)) != MP_SIG)) {
186                 mpfps++;
187         }
188         
189         if ((physaddr_t)mpfps > bound) 
190                 return NULL;
191         
192         // Now perform a checksum on the float
193         if (checksum((physaddr_t)mpfps, sizeof(mpfps_t) * mpfps->length) == FALSE) {
194                 mptables_dump("-->Failed a MPTables Floating Pointer Structure checksum @ KVA 0x%p.\n", mpfps);
195                 
196                 // If we fail we need to keep checking. But if we are on the last addr
197                 //      we just fail.
198                 if ((physaddr_t)mpfps == bound)
199                         return NULL;
200                 
201                 return find_floating_pointer((physaddr_t)(mpfps + 1), bound);
202         }
203         
204         return mpfps;
205 }
206
207 bool checksum(physaddr_t addr, uint32_t len) {
208         // MP Table checksums must add up to 0.
209         uint8_t checksum = 0;
210         
211         // Yet another trusted cast. 
212         // See comment at start of find_floating_pointer
213         uint8_t *addr_p = (uint8_t* COUNT(len)) TC(addr);
214
215         for (int i = 0; i < len; i++)
216                 checksum += *(addr_p + i);
217
218         return (checksum == 0);
219 }
220
221 // Go over the configuration table and parse / load the data into the global variables
222 // NOTE: This uses kmalloc. Might be cleaner (but less flexable) to allocate fixed amounts
223 //      set to high numbers.
224 void configuration_parse(physaddr_t conf_addr) {
225         
226         int num_processed[NUM_ENTRY_TYPES];
227         
228         // Another. See comment at start of find_floating_pointer
229         mpcth_t *mpcth = (mpcth_t* COUNT(1)) TC(conf_addr);
230         
231         for (int i = 0; i < NUM_ENTRY_TYPES; i++) {
232                 mp_entries_count[i] = num_processed[i] = 0;
233         }
234                 
235         // Do 1 pass to figure out how much space to allocate.
236         uint16_t num_entries = mpcth->entry_count;
237         uint16_t mpct_length = mpcth->base_table_length;
238         uint16_t entry_length = mpct_length - sizeof(mpcth);
239         
240         // Now perform a checksum on the configuration table
241         if (checksum((physaddr_t)mpcth, mpct_length) == FALSE) {
242                 panic("FAILED MP CONFIGURATION CHECKSUM.");
243         }
244         
245         uint8_t * COUNT(entry_length) entry_base = (uint8_t* COUNT(entry_length)) TC(mpcth + 1);
246         uint8_t * BND(entry_base, entry_base + entry_length) current_addr = entry_base;
247         
248         for (int i = 0; i < num_entries; i++) {
249                 uint8_t current_type = *current_addr;
250                 if (current_type >= NUM_ENTRY_TYPES)
251                         panic("CORRUPT MPTABLES CONFIGURATION ENTRY");
252                         
253                 mp_entries_count[current_type]++;
254                 current_addr += basetableEntryTypes[current_type].length;
255         }
256         
257         // Allocate the correct space in the arrays (unrolled for ivy reasons)
258         mp_proc_entries = kmalloc(mp_entries_count[PROC] * basetableEntryTypes[PROC].length , 0);
259         mp_bus_entries = kmalloc(mp_entries_count[BUS] * basetableEntryTypes[BUS].length , 0);
260         mp_ioapic_entries = kmalloc(mp_entries_count[IOAPIC] * basetableEntryTypes[IOAPIC].length , 0);
261         mp_int_entries = kmalloc(mp_entries_count[INT] * basetableEntryTypes[INT].length , 0);
262         mp_lint_entries = kmalloc(mp_entries_count[LINT] * basetableEntryTypes[LINT].length , 0);
263         
264         current_addr = entry_base;
265         
266         for (int i = 0; i < num_entries; i++) {
267                 uint8_t current_type = *((uint8_t*)current_addr);
268                 if (current_type >= NUM_ENTRY_TYPES)
269                         panic("CORRUPT MPTABLES CONFIGURATION ENTRY.. after we already checked? Huh.");
270                 
271                 if (num_processed[current_type] >= mp_entries_count[current_type])
272                         panic("MPTABLES LIED ABOUT NUMBER OF ENTRIES. NO IDEA WHAT TO DO!");
273                 
274                 switch (current_type) {
275                         case PROC:
276                                 memcpy( &mp_proc_entries[num_processed[PROC]], 
277                                                 current_addr,  
278                                                 basetableEntryTypes[PROC].length);
279                                 break;
280                         
281                         case BUS:
282                                 memcpy( &mp_bus_entries[num_processed[BUS]], 
283                                                 current_addr,  
284                                                 basetableEntryTypes[BUS].length);
285                                 break;
286                         case IOAPIC:
287                                 memcpy( &mp_ioapic_entries[num_processed[IOAPIC]], 
288                                                 // This is needed due to the void* in the entry
289                                                 //  no clean way of doing this. Sorry Zach.
290                                                 (ioapic_entry* COUNT(1)) TC(current_addr),  
291                                                 basetableEntryTypes[IOAPIC].length);
292                                 break;
293                         case INT:
294                                 memcpy( &mp_int_entries[num_processed[INT]], 
295                                                 current_addr,  
296                                                 basetableEntryTypes[INT].length);
297                                 break;
298                         case LINT:
299                                 memcpy( &mp_lint_entries[num_processed[LINT]], 
300                                                 (void*)current_addr,  
301                                                 basetableEntryTypes[LINT].length);
302                                 break;
303                                                 
304                         default: panic("UNKNOWN ENTRY TYPE");
305                 }
306
307                 num_processed[current_type]++;
308                 current_addr += basetableEntryTypes[current_type].length;
309         }
310         
311         // We'd do extended table support stuff here (or alter the loop above)
312         
313         // We now have all of our entries copied into a single structure we can index into. Yay.
314 }
315
316 void proc_parse() {
317         // For now, we don't do anything with the processor entries. Just print them.
318         
319         for (int i = 0; i < mp_entries_count[PROC]; i++){
320                 mptables_dump("Proc entry %u\n", i);
321                 mptables_dump("-->type: %x\n", mp_proc_entires[i].type);
322                 mptables_dump("-->apicID: %x\n", mp_proc_entires[i].apicID);
323                 mptables_dump("-->apicVersion: %x\n", mp_proc_entires[i].apicVersion);
324                 mptables_dump("-->cpuFlags: %x\n", mp_proc_entires[i].cpuFlags);
325                 mptables_dump("-->cpuSignaure: %x\n", mp_proc_entires[i].cpuSignature);
326                 mptables_dump("-->featureFlags: %x\n", mp_proc_entires[i].featureFlags);
327         }
328         
329         mptables_dump("\n");
330 }
331
332 void bus_parse() {
333         // Do we need to sort this?
334         // For now, don't. We assume the index into this structure matches the type.
335         // This seems to be implied from the configuration
336         
337         for (int i = 0; i < mp_entries_count[BUS]; i++){
338                 if (i != mp_bus_entries[i].busID) 
339                         panic("Oh noes! We need to sort entries. The MP Spec lied! Ok lied is too strong a word, it implied.");
340                         
341                 mptables_dump("Bus entry %u\n", i);
342                 mptables_dump("-->type: %x\n", mp_bus_entries[i].type);
343                 mptables_dump("-->BusID: %x\n", mp_bus_entries[i].busID);
344                 mptables_dump("-->Bus: %c%c%c\n", mp_bus_entries[i].busType[0], mp_bus_entries[i].busType[1], mp_bus_entries[i].busType[2]);
345         
346         }
347         
348         mptables_dump("\n");
349 }
350
351 void ioapic_parse() {
352
353         // Note: We don't check if the apicFlags is 0. If zero, unusable
354         // This should be done elsewhere.
355         
356         num_ioapics = mp_entries_count[IOAPIC];
357         
358         for (int i = 0; i < mp_entries_count[IOAPIC]; i++){
359                 mptables_dump("IOAPIC entry %u\n", i);
360                 mptables_dump("-->type: %x\n", mp_ioapic_entries[i].type);
361                 mptables_dump("-->apicID: %x\n", mp_ioapic_entries[i].apicID);
362                 mptables_dump("-->apicVersion: %x\n", mp_ioapic_entries[i].apicVersion);
363                 mptables_dump("-->apicFlags: %x\n", mp_ioapic_entries[i].apicFlags);
364                 mptables_dump("-->apicAddress: %p\n", mp_ioapic_entries[i].apicAddress);
365                 
366                 if (mp_ioapic_entries[i].apicID > max_ioapic_id)
367                         max_ioapic_id = mp_ioapic_entries[i].apicID;
368         }
369         mptables_dump("\n");
370         
371         for (int i = 0; i < mp_entries_count[IOAPIC]; i++) {
372                 memcpy((void*)(ioapic_entries + mp_ioapic_entries[i].apicID), (void*)(mp_ioapic_entries + i), sizeof(ioapic_entry));
373         }
374 }
375
376 void int_parse() {
377         // create a massive array, tied together with bus/dev, for indexing
378         
379         for (int i = 0; i < mp_entries_count[INT]; i++){
380                 mptables_dump("Interrupt entry %u\n", i);
381                 mptables_dump("-->type: %x\n", mp_int_entries[i].type);
382                 mptables_dump("-->intType: %x\n", mp_int_entries[i].intType);
383                 mptables_dump("-->intFlags: %x\n", mp_int_entries[i].intFlags);
384                 mptables_dump("-->srcBusID: %u\n", mp_int_entries[i].srcBusID);
385                 mptables_dump("-->srcDevice: %u (PCI ONLY)\n", (mp_int_entries[i].srcBusIRQ >> 2) & 0x1F);
386                 mptables_dump("-->srcBusIRQ: %x\n", mp_int_entries[i].srcBusIRQ);
387                 mptables_dump("-->dstApicID: %u\n", mp_int_entries[i].dstApicID);
388                 mptables_dump("-->dstApicINT: %u\n", mp_int_entries[i].dstApicINT);
389                                         
390         }
391         mptables_dump("\n");
392
393         // Populate the PCI/ISA structure with the interrupt entries.
394         for (int i = 0; i < mp_entries_count[INT]; i++) {
395                 if (strncmp(mp_bus_entries[mp_int_entries[i].srcBusID].busType, "PCI", 3) == 0) {
396                         int bus_idx, dev_idx, int_idx;
397                         bus_idx = mp_int_entries[i].srcBusID;
398                         dev_idx = (mp_int_entries[i].srcBusIRQ >> 2) & 0x1F;
399                         int_idx = mp_int_entries[i].srcBusIRQ & 0x3;
400                         pci_int_groups[bus_idx][dev_idx].intn[int_idx].dstApicID = mp_int_entries[i].dstApicID;
401                         pci_int_groups[bus_idx][dev_idx].intn[int_idx].dstApicINT = mp_int_entries[i].dstApicINT;
402                 }
403                 
404                 if (strncmp(mp_bus_entries[mp_int_entries[i].srcBusID].busType, "ISA", 3) == 0) {
405                         int irq = mp_int_entries[i].srcBusIRQ;
406                         int int_type = mp_int_entries[i].intType;
407                         
408                         if (int_type == 3) {
409                                 // THIS IS WHERE THE PIC CONNECTS TO THE IOAPIC
410                                 // WE DON'T CURRENTLY DO ANYTHING WITH THIS, BUT SHOULD WE NEED TO
411                                 // HERES WHERE TO LOOK!
412                                 // WE MUST NOT PLACE THIS INTO OUR TABLE AS IRQ HAS NO REAL MEANING AFAPK
413                                 continue;
414                                 
415                                 // Note. On the dev boxes the pit and pic both claim to be on irq 0
416                                 // However the pit and the pic are on different ioapic entries.
417                                 // Seems odd. Not sure whats up with this. Paul assumes the IRQ has no meaning
418                                 // in regards to the pic... which makes sense.
419                         }
420                                                 
421                         if ((isa_int_entries[irq].dstApicID != 0xFFFF) && 
422                                  ((isa_int_entries[irq].dstApicID != mp_int_entries[i].dstApicID) 
423                                    || (isa_int_entries[irq].dstApicINT != mp_int_entries[i].dstApicINT)))
424                                 panic("SAME IRQ MAPS TO DIFFERENT IOAPIC/INTN'S. THIS DEFIES LOGIC.");
425                         
426                         isa_int_entries[irq].dstApicID = mp_int_entries[i].dstApicID;
427                         isa_int_entries[irq].dstApicINT = mp_int_entries[i].dstApicINT;
428                 }                       
429         }
430 }
431
432 void lint_parse() {
433         // For now, we don't do anything with the local interrupt entries
434         
435         for (int i = 0; i < mp_entries_count[LINT]; i++){
436                 mptables_dump("Local Interrupt entry %u\n", i);
437                 mptables_dump("-->type: %x\n", mp_lint_entries[i].type);
438                 mptables_dump("-->intType: %x\n", mp_lint_entries[i].intType);
439                 mptables_dump("-->srcBusID: %x\n", mp_lint_entries[i].srcBusID);
440                 mptables_dump("-->srcBusIRQ: %x\n", mp_lint_entries[i].srcBusIRQ);
441                 mptables_dump("-->dstApicID: %p\n", mp_lint_entries[i].dstApicID);
442                 mptables_dump("-->dstApicINT: %p\n", mp_lint_entries[i].dstApicINT);
443                 
444         }
445 }