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