Rewrote most of newlib_backend to be more "robust". Added sycall server to tree
[akaros.git] / kern / src / mptables.c
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * See LICENSE for details.
4  */
5
6 #include <arch/ioapic.h>
7 #include <pci.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <kmalloc.h>
11 #include <arch/x86.h>
12
13 #include <mptables.h>
14
15 /** @file
16  * @brief Basic MP Tables Parser
17  *
18  * This file is responsible for locating, checksuming, and parsing the 
19  * MultiProcessor Specification Tables.
20  *
21  * See Intel Multiprocessor Specification for more info
22  *
23  * @author Paul Pearce <pearce@eecs.berkeley.edu>
24  *
25  * @todo Extended table support (why?)
26  * @todo Expanded error checking?
27  * @todo virtaddr_t to match physaddr_t support?
28  */
29
30 // Important global items
31 enum interrupt_modes current_interrupt_mode;
32
33 proc_entry_t    *COUNT(mp_entries_count[PROC])   mp_proc_entries = NULL;
34 bus_entry_t             *COUNT(mp_entries_count[BUS])    mp_bus_entries = NULL;
35 ioapic_entry_t  *COUNT(mp_entries_count[IOAPIC]) mp_ioapic_entries = NULL;
36 int_entry_t             *COUNT(mp_entries_count[INT])    mp_int_entries = NULL;
37 int_entry_t             *COUNT(mp_entries_count[LINT])   mp_lint_entries = NULL; 
38 // ^ Not a typo. lint entries == int entries, so We just use that.
39
40
41 int mp_entries_count[NUM_ENTRY_TYPES]; // How large each array is.
42
43 pci_int_device_t pci_int_devices[PCI_MAX_BUS][PCI_MAX_DEV];
44 isa_int_entry_t isa_int_entries[NUM_IRQS];
45 ioapic_entry_t ioapic_entries[IOAPIC_MAX_ID];
46
47
48 /** @brief Entry function to the mptable parser. Calling this function results in the parsing of the tables and setup of all structures
49  *
50  * This function does the following:
51  *      - Search various locations in memory for the MP Floating Structure 
52  *  - Checkum the floating structure to make sure its valid
53  *  - Locate the MP Configuration Header, and checksum it
54  *  - Locate all entries of type proc, bus, ioapic, int, lint
55  *  - Parse the above entries and form the data structures that the rest of the system relies upon
56  */
57 void mptables_parse() {
58         
59         // Before we do anything. We didn't pack our structs because BSD didnt. Make sure we're sane.
60         if (    (sizeof(proc_entry_t)   != entry_types[PROC].length) || 
61                         (sizeof(bus_entry_t)    != entry_types[BUS].length) || 
62                         (sizeof(ioapic_entry_t) != entry_types[IOAPIC].length) || 
63                         (sizeof(int_entry_t)    != entry_types[INT].length) || 
64                         (sizeof(mpfps_t)                != MPFPS_SIZE) ||
65                         (sizeof(mpcth_t)                != MPCTH_SIZE) )
66                                 panic("MPTable structure sizes out of sync with spec");
67                         
68                         
69         mpfps_t *mpfps;
70         
71         // Memsets to initalize all our structures to invalid entries
72         
73         /* Setup the indexable ioapic array.
74          * YOU MUST check the flag field to see if its 0. If 0, unusable.
75          * This is defined by MPTables, and I leaverage this with the memset below to set invalid
76          */
77         memset(ioapic_entries, 0, sizeof(ioapic_entries));
78         
79         // We define an IOAPIC DEST ID of 0xFF (>=256) to be invalid. Pack with all 1's.
80         memset(pci_int_devices, 0xFF, sizeof(pci_int_devices));
81         memset(isa_int_entries, 0xFF, sizeof(isa_int_entries));
82         
83         
84         mptables_info("Starting MPTables Parsing...\n");
85         
86         /*  Basic procedure:
87          *      1) Find floating pointer
88          *      2) Go to addr referenced by floating pointer
89          *      3) Read table header info
90          *
91          * We now have to search through 3 address regions searching for a magic string.
92          *
93          *
94          * Note: The pointer can actually be elsewhere. See the FBSD MPTables implimentation for more info
95          * Just doesn't make sense right now to check more places.
96          */
97         
98         // Search the BIOS ROM Address Space (MOST LIKELY)
99         mptables_dump("-->Searching BIOS ROM Area...\n");
100         mpfps = find_floating_pointer((physaddr_t)KADDR(BIOS_ROM_BASE), (physaddr_t)KADDR(BIOS_ROM_BOUND));
101         
102         if (mpfps == NULL) {
103                 
104                 /* Search the EBDA UNTESTED, haven't found something that uses this.
105                  *
106                  * First, we have to find the EBDA Addr.
107                  * This USSUALLY works (based on third hand info). May be some cases where it doesnt.
108                  * See osdev x86 mem-map for more information
109                  */
110                 physaddr_t ebda_base = READ_FROM_STORED_PHYSADDR32(EBDA_POINTER);
111                 
112                 if (ebda_base) {
113                         ebda_base = ebda_base << 4;
114                         ebda_base = (physaddr_t)KADDR(ebda_base);
115                         physaddr_t ebda_bound = ebda_base + EBDA_SIZE - sizeof(mpfps_t);
116                         
117                         mptables_dump("-->Searching EBDA...\n");
118                         mpfps = find_floating_pointer(ebda_base, ebda_bound);
119                 }
120         }
121
122         if (mpfps == NULL) {
123                 /* Search the last KB of system memory UNTESTED
124                  * Note: Will only be there if it not in the EBDA. So this must be called after the EBDA check.
125                  * This logic is ripped from mptables without much understanding. No machine to test it on.
126                  */
127                 
128                 physaddr_t top_of_mem = READ_FROM_STORED_PHYSADDR32(TOPOFMEM_POINTER);
129                 
130                 if (top_of_mem) {
131                         --top_of_mem;
132                         top_of_mem = top_of_mem * 1024;
133                         
134                         top_of_mem = (physaddr_t)KADDR(top_of_mem);
135                 
136                 mptables_dump("-->Searching top of (real mode) Ram...\n");
137                         mpfps = find_floating_pointer(top_of_mem, top_of_mem + 1024 - sizeof(mpfps_t));
138                 }
139         }
140         
141         if (mpfps == NULL) {
142                 /* Search the last KB of system memory based on a 640K limited, due to CMOS lying
143                  * Note: Will only be there if it not in the EBDA. So this must be called after the EBDA check.
144                  * This IS tested. Thanks VirtualBox!
145                  */
146                                 
147                 physaddr_t top_of_mem = DEFAULT_TOPOFMEM;
148                 
149                 if (top_of_mem) {
150                                 
151                         top_of_mem = top_of_mem - 1024;
152                         
153                         top_of_mem = (physaddr_t)KADDR(top_of_mem);
154                 
155                 mptables_dump("-->Searching top of (real mode) Ram 640K cap, incase CMOS lied...\n");
156                         mpfps = find_floating_pointer(top_of_mem, top_of_mem + 1024 - sizeof(mpfps_t));
157                 }
158         }
159
160         /* If we can't find the pointer, it means we are running on a non-mp compliant machine.
161          * This is bad. We can't do interrupts the way we want.
162          * We could have this trigger a MODE in which we operate using the standard PIC, if we really wanted...
163          */
164         if (mpfps == NULL) {
165                 panic("MPTABLES Not found. IOAPIC and interrupts will not function properly. <Insert whale held up by smaller birds here>");
166         }
167         
168         mptables_info("-->MPTables Floating Pointer Structure found @ KVA 0x%p.\n", mpfps);
169         
170         mptables_info("-->Current Interrupt Mode: ");
171         // Identify our interrupt mode
172         if (mpfps->mpfb2 & IMCRP_MASK) {
173                 current_interrupt_mode = PIC;
174                 mptables_info("PIC\n");
175                 // TODO: Do SOMETHING here. We've never found such a system (they are generally ancient). Should we just panic?
176         }
177         else {
178                 current_interrupt_mode = VW;
179                 mptables_info("Virtual Wire\n");
180         }
181         
182         configuration_parse((physaddr_t)KADDR((uint32_t)(mpfps->pap)));
183         
184         proc_parse();
185         bus_parse();
186         ioapic_parse();
187         int_parse();
188         lint_parse();
189         
190 }
191
192
193 /** @brief Take the given memory range and search for the MP Floating Structure
194  * 
195  * This function will look at every sizeof(mpfps_t) chunch of memory for a given 4byte value (_MP_)
196  * until bound is reached (inclusive).
197  *
198  * Note: Doesn't ensure bounds are sane. This shouldnt be an issue as this function should be priviate to mptables_parse()
199  *
200  * @param[in] base      The base (kernel virtual) address we start looking at
201  * @param[in] bound The bound (inclusive kernel virtual) address we stop looking at
202  * 
203  * @return MPFPS The virtual address of the base of the floating point structure
204  * @return NULL No floating point structure exists in this range
205  */
206 mpfps_t *find_floating_pointer(physaddr_t base, physaddr_t bound) {
207
208         uint32_t count = (bound - base + sizeof(mpfps_t))/sizeof(mpfps_t);
209
210         // This trusted count was authorized with the blessing of Zach.
211         // Blame Intel and the MP Spec for making me do this cast.
212         mpfps_t* mpfps = (mpfps_t* COUNT(count)) TC(base);
213
214         // Loop over the entire range looking for the signature. The signature is ascii _MP_, which is
215         //  stored in the given MP_SIG
216         while ( ((physaddr_t)mpfps <= bound) && (READ_FROM_STORED_VIRTADDR32(mpfps->signature) != MP_SIG)) {
217                 mpfps++;
218         }
219         
220         if ((physaddr_t)mpfps > bound) 
221                 return NULL;
222         
223         // Now perform a checksum on the float
224         if (checksum((physaddr_t)mpfps, sizeof(mpfps_t) * mpfps->length) == FALSE) {
225                 mptables_dump("-->Failed a MPTables Floating Pointer Structure checksum @ KVA 0x%p.\n", mpfps);
226                 
227                 // If we fail we need to keep checking. But if we are on the last addr
228                 //      we just fail.
229                 if ((physaddr_t)mpfps == bound)
230                         return NULL;
231                 
232                 return find_floating_pointer((physaddr_t)(mpfps + 1), bound);
233         }
234         
235         return mpfps;
236 }
237
238 /** @brief Perform the mptable checksum on the memory given by addr and len
239  *
240  * This function will take len bytes of memory starting at the (kernel virtual)
241  * address addr and sum them together. If the result is 0, the checksum is valid. 
242  *
243  * @param[in] addr      The base (kernel virtual) address we start checking 
244  * @param[in] len       How many bytes to look at
245  * 
246  * @return TRUE Valid checksum
247  * @return FALSE Invalid checksum
248  */
249 bool checksum(physaddr_t addr, uint32_t len) {
250         // MP Table checksums must add up to 0.
251         uint8_t checksum = 0;
252         
253         // Yet another trusted cast. 
254         // See comment at start of find_floating_pointer
255         uint8_t *addr_p = (uint8_t* COUNT(len)) TC(addr);
256
257         for (int i = 0; i < len; i++)
258                 checksum += *(addr_p + i);
259
260         return (checksum == 0);
261 }
262
263 /** @brief Parse the configuration MP Table given a valid address to the base of the table
264  *
265  * This function begin examining a given (kernel virtual) address assuming it is the base 
266  * of the configuration table. It will determine the size of the table, and then loop over
267  * each entry in the table, loading all entires into the correct corresponding data structures
268  *
269  * @param[in] conf_addr         The base (kernel virtual) address of the configuration table
270  */     
271 void configuration_parse(physaddr_t conf_addr) {
272         
273         int num_processed[NUM_ENTRY_TYPES];
274         
275         // Another. See comment at start of find_floating_pointer
276         mpcth_t *mpcth = (mpcth_t* COUNT(1)) TC(conf_addr);
277         
278         for (int i = 0; i < NUM_ENTRY_TYPES; i++) {
279                 mp_entries_count[i] = num_processed[i] = 0;
280         }
281                 
282         // Do 1 pass to figure out how much space to allocate.
283         // Note: Length here means length in bytes. This is from the mp spec.
284         uint16_t num_entries = mpcth->entry_count;
285         uint16_t mpct_length = mpcth->base_table_length;
286         uint16_t entries_length = mpct_length - sizeof(mpcth);
287         
288         // Now perform a checksum on the configuration table
289         if (checksum((physaddr_t)mpcth, mpct_length) == FALSE) {
290                 panic("FAILED MP CONFIGURATION CHECKSUM.");
291         }
292         
293         uint8_t * COUNT(entries_length) entry_base = (uint8_t* COUNT(entries_length)) TC(mpcth + 1);
294         uint8_t * BND(entry_base, entry_base + entries_length) current_addr = entry_base;
295         
296         for (int i = 0; i < num_entries; i++) {
297                 uint8_t current_type = *current_addr;
298                 if (current_type >= NUM_ENTRY_TYPES)
299                         panic("CORRUPT MPTABLES CONFIGURATION ENTRY");
300                         
301                 mp_entries_count[current_type]++;
302                 current_addr += entry_types[current_type].length;
303         }
304         
305         // Allocate the correct space in the arrays (unrolled for ivy reasons)
306         if (mp_entries_count[PROC] != 0) {
307                 mp_proc_entries = kmalloc(mp_entries_count[PROC] * entry_types[PROC].length , 0);
308                 if (mp_proc_entries == NULL)
309                         panic("Failed to allocate space for mp_proc_entires");
310         }
311
312         if (mp_entries_count[BUS] != 0) {
313                 mp_bus_entries = kmalloc(mp_entries_count[BUS] * entry_types[BUS].length , 0);
314                 if (mp_bus_entries == NULL)
315                         panic("Failed to allocate space for mp_bus_entires");
316         }
317
318         if (mp_entries_count[IOAPIC] != 0) {
319                 mp_ioapic_entries = kmalloc(mp_entries_count[IOAPIC] * entry_types[IOAPIC].length , 0);
320                 if (mp_ioapic_entries == NULL)
321                         panic("Failed to allocate space for mp_ioapic_entires");
322         }
323         
324         if (mp_entries_count[INT] != 0) {
325                 mp_int_entries = kmalloc(mp_entries_count[INT] * entry_types[INT].length , 0);
326                 if (mp_int_entries == NULL)
327                         panic("Failed to allocate space for mp_int_entires");
328         }
329
330         if (mp_entries_count[LINT] != 0) {
331                 mp_lint_entries = kmalloc(mp_entries_count[LINT] * entry_types[LINT].length , 0);
332                 if (mp_lint_entries == NULL)
333                         panic("Failed to allocate space for mp_lint_entires");
334         }
335         
336         current_addr = entry_base;
337         
338         for (int i = 0; i < num_entries; i++) {
339                 uint8_t current_type = *((uint8_t*)current_addr);
340                 if (current_type >= NUM_ENTRY_TYPES)
341                         panic("CORRUPT MPTABLES CONFIGURATION ENTRY.. after we already checked? Huh.");
342                 
343                 if (num_processed[current_type] >= mp_entries_count[current_type])
344                         panic("MPTABLES LIED ABOUT NUMBER OF ENTRIES. NO IDEA WHAT TO DO!");
345                 
346                 switch (current_type) {
347                         case PROC:
348                                 memcpy( &mp_proc_entries[num_processed[PROC]], 
349                                                 current_addr,  
350                                                 entry_types[PROC].length);
351                                 break;
352                         
353                         case BUS:
354                                 memcpy( &mp_bus_entries[num_processed[BUS]], 
355                                                 current_addr,  
356                                                 entry_types[BUS].length);
357                                 break;
358                         case IOAPIC:
359                                 memcpy( &mp_ioapic_entries[num_processed[IOAPIC]], 
360                                                 // This is needed due to the void* in the entry
361                                                 //  no clean way of doing this. Sorry Zach.
362                                                 (ioapic_entry_t* COUNT(1)) TC(current_addr),  
363                                                 entry_types[IOAPIC].length);
364                                 break;
365                         case INT:
366                                 memcpy( &mp_int_entries[num_processed[INT]], 
367                                                 current_addr,  
368                                                 entry_types[INT].length);
369                                 break;
370                         case LINT:
371                                 memcpy( &mp_lint_entries[num_processed[LINT]], 
372                                                 (void*)current_addr,  
373                                                 entry_types[LINT].length);
374                                 break;
375                                                 
376                         default: panic("UNKNOWN ENTRY TYPE");
377                 }
378
379                 num_processed[current_type]++;
380                 current_addr += entry_types[current_type].length;
381         }
382         
383         // We'd do extended table support stuff here (or alter the loop above)
384         
385         // We now have all of our entries copied into a single structure we can index into. Yay.
386 }
387
388 /** @brief Parse all processor mptable entires
389  *
390  * This function will loop over the raw proc entry structure and parse it into a usable form.
391  * This currently just prints stuff if dumping is enabled.
392  */
393 void proc_parse() {
394         // For now, we don't do anything with the processor entries. Just print them.
395         
396         for (int i = 0; i < mp_entries_count[PROC]; i++){
397                 mptables_dump("Proc entry %u\n", i);
398                 mptables_dump("-->type: %x\n", mp_proc_entires[i].type);
399                 mptables_dump("-->apic ID: %x\n", mp_proc_entires[i].apic_id);
400                 mptables_dump("-->apic Version: %x\n", mp_proc_entires[i].apic_version);
401                 mptables_dump("-->cpu Flags: %x\n", mp_proc_entires[i].cpu_flags);
402                 mptables_dump("-->cpu Signaure: %x\n", mp_proc_entires[i].cpu_signature);
403                 mptables_dump("-->feature Flags: %x\n", mp_proc_entires[i].feature_flags);
404         }
405         
406         mptables_dump("\n");
407 }
408
409 /** @brief Parse all bus mptable entires
410  *
411  * This function will loop over the raw bus entry structure and parse it into a usable form
412  * This currently just prints stuff if dumping is enabled. (With a basic sanity check).
413  */
414 void bus_parse() {
415         // Do we need to sort this?
416         // For now, don't. We assume the index into this structure matches the type.
417         // This seems to be implied from the configuration
418         
419         for (int i = 0; i < mp_entries_count[BUS]; i++){
420                 if (i != mp_bus_entries[i].bus_id) 
421                         panic("Oh noes! We need to sort entries. The MP Spec lied! Ok lied is too strong a word, it implied.");
422                         
423                 mptables_dump("Bus entry %u\n", i);
424                 mptables_dump("-->type: %x\n", mp_bus_entries[i].type);
425                 mptables_dump("-->Bus ID: %x\n", mp_bus_entries[i].bus_id);
426                 mptables_dump("-->Bus: %c%c%c\n", mp_bus_entries[i].bus_type[0], mp_bus_entries[i].bus_type[1], mp_bus_entries[i].bus_type[2]);
427         
428         }
429         
430         mptables_dump("\n");
431 }
432
433 /** @brief Parse all ioapic mptable entires
434  *
435  * This function will loop over the raw ioapic entry structure and parse it into a usable form.
436  * ioapic_entires[] contains all found ioapics after this function.
437  */
438 void ioapic_parse() {
439
440         // Note: We don't check if the apicFlags is 0. If zero, unusable
441         // This should be done elsewhere.
442         
443         // mp_entries_count[IOAPIC] contains the number of ioapics on this system
444         
445         for (int i = 0; i < mp_entries_count[IOAPIC]; i++){
446                 
447                 memcpy((void*)(ioapic_entries + mp_ioapic_entries[i].apic_id), (void*)(mp_ioapic_entries + i), sizeof(ioapic_entry_t));
448                 
449                 mptables_dump("IOAPIC entry %u\n", i);
450                 mptables_dump("-->type: %x\n", mp_ioapic_entries[i].type);
451                 mptables_dump("-->apic_id: %x\n", mp_ioapic_entries[i].apic_id);
452                 mptables_dump("-->apic_version: %x\n", mp_ioapic_entries[i].apic_version);
453                 mptables_dump("-->apic_flags: %x\n", mp_ioapic_entries[i].apic_flags);
454                 mptables_dump("-->apic_address: %p\n", mp_ioapic_entries[i].apic_address);
455                 
456         }
457         mptables_dump("\n");
458 }
459
460 /** @brief Parse all interrupt mptable entires
461  *
462  * This function will loop over the raw interrupt entry structure and parse it into a usable form.
463  * pci_int_devices[] and isa_int_entries[] will be populated after this function is called.
464  */
465 void int_parse() {
466         // create a massive array, tied together with bus/dev, for indexing
467         
468         for (int i = 0; i < mp_entries_count[INT]; i++){
469                 mptables_dump("Interrupt entry %u\n", i);
470                 mptables_dump("-->type: %x\n", mp_int_entries[i].type);
471                 mptables_dump("-->int Type: %x\n", mp_int_entries[i].int_type);
472                 mptables_dump("-->int Flags: %x\n", mp_int_entries[i].int_flags);
473                 mptables_dump("-->src Bus ID: %u\n", mp_int_entries[i].src_bus_id);
474                 mptables_dump("-->src Device: %u (PCI ONLY)\n", (mp_int_entries[i].src_bus_irq >> 2) & 0x1F);
475                 mptables_dump("-->src Bus IRQ: %x\n", mp_int_entries[i].src_bus_irq);
476                 mptables_dump("-->dst Apic ID: %u\n", mp_int_entries[i].dst_apic_id);
477                 mptables_dump("-->dst Apic INT: %u\n", mp_int_entries[i].dst_apic_int);
478                                         
479         }
480         mptables_dump("\n");
481
482         // Populate the PCI/ISA structure with the interrupt entries.
483         for (int i = 0; i < mp_entries_count[INT]; i++) {
484                 if (strncmp(mp_bus_entries[mp_int_entries[i].src_bus_id].bus_type, "PCI", 3) == 0) {
485                         int bus_idx, dev_idx, line_idx;
486                         bus_idx = mp_int_entries[i].src_bus_id;
487                         dev_idx = (mp_int_entries[i].src_bus_irq >> 2) & 0x1F;
488                         line_idx = mp_int_entries[i].src_bus_irq & 0x3;
489                         pci_int_devices[bus_idx][dev_idx].line[line_idx].dst_apic_id = mp_int_entries[i].dst_apic_id;
490                         pci_int_devices[bus_idx][dev_idx].line[line_idx].dst_apic_int = mp_int_entries[i].dst_apic_int;
491                 }
492                 
493                 if (strncmp(mp_bus_entries[mp_int_entries[i].src_bus_id].bus_type, "ISA", 3) == 0) {
494                         int irq = mp_int_entries[i].src_bus_irq;
495                         int int_type = mp_int_entries[i].int_type;
496                         
497                         if (int_type == 3) {
498                                 /* THIS IS WHERE THE PIC CONNECTS TO THE IOAPIC
499                                  * WE DON'T CURRENTLY DO ANYTHING WITH THIS, BUT SHOULD WE NEED TO
500                                  * HERES WHERE TO LOOK!
501                                  * WE MUST NOT PLACE THIS INTO OUR TABLE AS IRQ HAS NO REAL MEANING AFAPK
502                                  */
503                                 continue;
504                                 
505                                 /* Note. On the dev boxes the pit and pic both claim to be on irq 0
506                                  * However the pit and the pic are on different ioapic entries.
507                                  * Seems odd. Not sure whats up with this. Paul assumes the IRQ has no meaning
508                                  * in regards to the pic... which makes sense.
509                                  */
510                         }
511                                                 
512                         if ((isa_int_entries[irq].dst_apic_id != 0xFFFF) && 
513                                  ((isa_int_entries[irq].dst_apic_id != mp_int_entries[i].dst_apic_id) 
514                                    || (isa_int_entries[irq].dst_apic_int != mp_int_entries[i].dst_apic_int)))
515                                 panic("SAME IRQ MAPS TO DIFFERENT IOAPIC/INTN'S. THIS DEFIES LOGIC.");
516                         
517                         isa_int_entries[irq].dst_apic_id = mp_int_entries[i].dst_apic_id;
518                         isa_int_entries[irq].dst_apic_int = mp_int_entries[i].dst_apic_int;
519                 }                       
520         }
521 }
522
523 /** @brief Parse all local interrupt mptable entires
524  *
525  * This function will loop over the raw local interrupt entry structure and parse it into a usable form.
526  * This currently just prints stuff if dumping is enabled.
527  */
528
529 void lint_parse() {
530         // For now, we don't do anything with the local interrupt entries
531         
532         for (int i = 0; i < mp_entries_count[LINT]; i++){
533                 mptables_dump("Local Interrupt entry %u\n", i);
534                 mptables_dump("-->type: %x\n", mp_lint_entries[i].type);
535                 mptables_dump("-->int Type: %x\n", mp_lint_entries[i].int_type);
536                 mptables_dump("-->src Bus ID: %x\n", mp_lint_entries[i].src_bus_id);
537                 mptables_dump("-->src Bus IRQ: %x\n", mp_lint_entries[i].src_bus_irq);
538                 mptables_dump("-->dst Apic ID: %p\n", mp_lint_entries[i].dst_apic_id);
539                 mptables_dump("-->dst Apic INT: %p\n", mp_lint_entries[i].dst_apic_int);
540                 
541         }
542 }