mptable(8): Remove an unused variable.
[dragonfly.git] / usr.sbin / mptable / mptable.c
1 /*
2  * Copyright (c) 1996, by Steve Passe
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. The name of the developer may NOT be used to endorse or promote products
11  *    derived from this software without specific prior written permission.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD: src/usr.sbin/mptable/mptable.c,v 1.12.2.3 2000/12/11 01:03:34 obrien Exp $
26  * $DragonFly: src/usr.sbin/mptable/mptable.c,v 1.4 2008/04/20 13:44:26 swildner Exp $
27  */
28
29 /*
30  * mptable.c
31  */
32
33 #define VMAJOR                  2
34 #define VMINOR                  0
35 #define VDELTA                  15
36
37 #define MP_SIG                  0x5f504d5f      /* _MP_ */
38 #define EXTENDED_PROCESSING_READY
39 #define OEM_PROCESSING_READY_NOT
40
41 #include <sys/types.h>
42 #include <err.h>
43 #include <fcntl.h>
44 #include <inttypes.h>
45 #include <paths.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50
51 #define SEP_LINE \
52 "\n-------------------------------------------------------------------------------\n"
53
54 #define SEP_LINE2 \
55 "\n===============================================================================\n"
56
57 /* EBDA is @ 40:0e in real-mode terms */
58 #define EBDA_POINTER            0x040e          /* location of EBDA pointer */
59
60 /* CMOS 'top of mem' is @ 40:13 in real-mode terms */
61 #define TOPOFMEM_POINTER        0x0413          /* BIOS: base memory size */
62
63 #define DEFAULT_TOPOFMEM        0xa0000
64
65 #define BIOS_BASE               0xf0000
66 #define BIOS_BASE2              0xe0000
67 #define BIOS_SIZE               0x10000
68 #define ONE_KBYTE               1024
69
70 #define GROPE_AREA1             0x80000
71 #define GROPE_AREA2             0x90000
72 #define GROPE_SIZE              0x10000
73
74 #define PROCENTRY_FLAG_EN       0x01
75 #define PROCENTRY_FLAG_BP       0x02
76 #define IOAPICENTRY_FLAG_EN     0x01
77
78 #define MAXPNSTR                132
79
80 enum busTypes {
81     CBUS = 1,
82     CBUSII = 2,
83     EISA = 3,
84     ISA = 6,
85     PCI = 13,
86     XPRESS = 18,
87     MAX_BUSTYPE = 18,
88     UNKNOWN_BUSTYPE = 0xff
89 };
90
91 typedef struct BUSTYPENAME {
92     u_char      type;
93     char        name[ 7 ];
94 } busTypeName;
95
96 static busTypeName busTypeTable[] =
97 {
98     { CBUS,             "CBUS"   },
99     { CBUSII,           "CBUSII" },
100     { EISA,             "EISA"   },
101     { UNKNOWN_BUSTYPE,  "---"    },
102     { UNKNOWN_BUSTYPE,  "---"    },
103     { ISA,              "ISA"    },
104     { UNKNOWN_BUSTYPE,  "---"    },
105     { UNKNOWN_BUSTYPE,  "---"    },
106     { UNKNOWN_BUSTYPE,  "---"    },
107     { UNKNOWN_BUSTYPE,  "---"    },
108     { UNKNOWN_BUSTYPE,  "---"    },
109     { UNKNOWN_BUSTYPE,  "---"    },
110     { PCI,              "PCI"    },
111     { UNKNOWN_BUSTYPE,  "---"    },
112     { UNKNOWN_BUSTYPE,  "---"    },
113     { UNKNOWN_BUSTYPE,  "---"    },
114     { UNKNOWN_BUSTYPE,  "---"    },
115     { UNKNOWN_BUSTYPE,  "---"    },
116     { UNKNOWN_BUSTYPE,  "---"    }
117 };
118
119 const char* whereStrings[] = {
120     "Extended BIOS Data Area",
121     "BIOS top of memory",
122     "Default top of memory",
123     "BIOS",
124     "Extended BIOS",
125     "GROPE AREA #1",
126     "GROPE AREA #2"
127 };
128
129 typedef struct TABLE_ENTRY {
130     u_char      type;
131     u_char      length;
132     char        name[ 32 ];
133 } tableEntry;
134
135 tableEntry basetableEntryTypes[] =
136 {
137     { 0, 20, "Processor" },
138     { 1,  8, "Bus" },
139     { 2,  8, "I/O APIC" },
140     { 3,  8, "I/O INT" },
141     { 4,  8, "Local INT" }
142 };
143
144 tableEntry extendedtableEntryTypes[] =
145 {
146     { 128, 20, "System Address Space" },
147     { 129,  8, "Bus Hierarchy" },
148     { 130,  8, "Compatibility Bus Address" }
149 };
150
151 /* MP Floating Pointer Structure */
152 typedef struct MPFPS {
153     char        signature[ 4 ];
154     uint32_t    pap;
155     u_char      length;
156     u_char      spec_rev;
157     u_char      checksum;
158     u_char      mpfb1;
159     u_char      mpfb2;
160     u_char      mpfb3;
161     u_char      mpfb4;
162     u_char      mpfb5;
163 } mpfps_t;
164
165 /* MP Configuration Table Header */
166 typedef struct MPCTH {
167     char        signature[ 4 ];
168     uint16_t    base_table_length;
169     u_char      spec_rev;
170     u_char      checksum;
171     u_char      oem_id[ 8 ];
172     u_char      product_id[ 12 ];
173     uint32_t    oem_table_pointer;
174     uint16_t    oem_table_size;
175     uint16_t    entry_count;
176     uint32_t    apic_address;
177     uint16_t    extended_table_length;
178     u_char      extended_table_checksum;
179     u_char      reserved;
180 } mpcth_t;
181
182
183 typedef struct PROCENTRY {
184     u_char      type;
185     u_char      apicID;
186     u_char      apicVersion;
187     u_char      cpuFlags;
188     uint32_t    cpuSignature;
189     uint32_t    featureFlags;
190     uint32_t    reserved1;
191     uint32_t    reserved2;
192 } ProcEntry;
193
194 typedef struct BUSENTRY {
195     u_char      type;
196     u_char      busID;
197     char        busType[ 6 ];
198 } BusEntry;
199
200 typedef struct IOAPICENTRY {
201     u_char      type;
202     u_char      apicID;
203     u_char      apicVersion;
204     u_char      apicFlags;
205     uint32_t    apicAddress;
206 } IOApicEntry;
207
208 typedef struct INTENTRY {
209     u_char      type;
210     u_char      intType;
211     uint16_t    intFlags;
212     u_char      srcBusID;
213     u_char      srcBusIRQ;
214     u_char      dstApicID;
215     u_char      dstApicINT;
216 } IntEntry;
217
218
219 /*
220  * extended entry type structures
221  */
222
223 typedef struct SASENTRY {
224     u_char      type;
225     u_char      length;
226     u_char      busID;
227     u_char      addressType;
228     u_int64_t   addressBase;
229     u_int64_t   addressLength;
230 } SasEntry;
231
232
233 typedef struct BHDENTRY {
234     u_char      type;
235     u_char      length;
236     u_char      busID;
237     u_char      busInfo;
238     u_char      busParent;
239     u_char      reserved[ 3 ];
240 } BhdEntry;
241
242
243 typedef struct CBASMENTRY {
244     u_char      type;
245     u_char      length;
246     u_char      busID;
247     u_char      addressMod;
248     uint32_t    predefinedRange;
249 } CbasmEntry;
250
251
252
253 static void apic_probe( vm_offset_t* paddr, int* where );
254
255 static void MPConfigDefault( int featureByte );
256
257 static void MPFloatingPointer( vm_offset_t paddr, int where, mpfps_t* mpfps );
258 static void MPConfigTableHeader( uint32_t pap );
259
260 static int readType( void );
261 static void seekEntry( vm_offset_t addr );
262 static void readEntry( void* entry, int size );
263
264 static void processorEntry( void );
265 static void busEntry( void );
266 static void ioApicEntry( void );
267 static void intEntry( void );
268
269 static void sasEntry( void );
270 static void bhdEntry( void );
271 static void cbasmEntry( void );
272
273 static void doDmesg( void );
274 static void pnstr( char* s, int c );
275
276 /* global data */
277 int     pfd;            /* physical /dev/mem fd */
278
279 int     busses[ 16 ];
280 int     apics[ 16 ];
281
282 int     ncpu;
283 int     nbus;
284 int     napic;
285 int     nintr;
286
287 int     dmesg;
288 int     grope;
289 int     raw;
290 int     verbose;
291
292 static void
293 usage( void )
294 {
295     fprintf( stderr, "usage: mptable [-dmesg] [-verbose] [-grope] [-raw] [-help]\n" );
296     exit( 0 );
297 }
298
299 /*
300  * 
301  */
302 int
303 main( int argc, char *argv[] )
304 {
305     vm_offset_t paddr;
306     int         where;
307     mpfps_t     mpfps;
308     int         defaultConfig;
309
310     int         ch;
311
312     /* announce ourselves */
313     puts( SEP_LINE2 );
314
315     printf( "MPTable, version %d.%d.%d\n", VMAJOR, VMINOR, VDELTA );
316
317     while ((ch = getopt(argc, argv, "d:g:h:r:v:")) != -1) {
318         switch(ch) {
319         case 'd':
320             if ( strcmp( optarg, "mesg") == 0 )
321                 dmesg = 1;
322             else
323                 dmesg = 0;
324             break;
325         case 'h':
326             if ( strcmp( optarg, "elp") == 0 )
327                 usage();
328             break;
329         case 'g':
330             if ( strcmp( optarg, "rope") == 0 )
331                 grope = 1;
332             break;
333         case 'r':
334             if ( strcmp (optarg, "aw") == 0 )
335                 raw = 1;
336             break;
337         case 'v':
338             if ( strcmp( optarg, "erbose") == 0 )
339                 verbose = 1;
340             break;
341         default:
342             usage();
343         }
344     }
345
346     argc -= optind;
347     argv += optind;
348
349     /* open physical memory for access to MP structures */
350     if ( (pfd = open( _PATH_MEM, O_RDONLY )) < 0 )
351         err( 1, "mem open" );
352
353     /* probe for MP structures */
354     apic_probe( &paddr, &where );
355     if ( where <= 0 ) {
356         fprintf( stderr, "\n MP FPS NOT found%s\n\n",
357               grope ? "" : ",\n suggest trying -grope option!!!" );
358         return 1;
359     }
360
361     if ( verbose )
362         printf( "\n MP FPS found in %s @ physical addr: 0x%08lx\n",
363               whereStrings[ where - 1 ], paddr );
364
365     puts( SEP_LINE );
366
367     /* analyze the MP Floating Pointer Structure */
368     MPFloatingPointer( paddr, where, &mpfps );
369
370     puts( SEP_LINE );
371
372     /* check whether an MP config table exists */
373     if ( (defaultConfig = mpfps.mpfb1) )
374         MPConfigDefault( defaultConfig );
375     else
376         MPConfigTableHeader( mpfps.pap );
377
378     /* do a dmesg output */
379     if ( dmesg )
380         doDmesg();
381
382     puts( SEP_LINE2 );
383
384     return 0;
385 }
386
387
388 static int
389 findMpSig(uint32_t target, size_t bufsize)
390 {
391     uint32_t    buffer[BIOS_SIZE / sizeof(uint32_t)];
392     uint32_t *x;
393
394     seekEntry(target);
395     readEntry(buffer, (bufsize + sizeof(*x) - 1) & ~sizeof(*x));
396     for (x = buffer; x < buffer + bufsize / sizeof(*x); ++x) {
397         if (*x == MP_SIG)
398             return (x - buffer) * sizeof(*x) + target;
399     }
400     return -1;
401 }
402
403 /*
404  * set PHYSICAL address of MP floating pointer structure
405  */
406 static void
407 apic_probe( vm_offset_t* paddr, int* where )
408 {
409     /*
410      * c rewrite of apic_probe() by Jack F. Vogel
411      */
412
413     int         x;
414     uint16_t    segment;
415     vm_offset_t target;
416
417     if ( verbose )
418         printf( "\n" );
419
420     /* search Extended Bios Data Area, if present */
421     if ( verbose )
422         printf( " looking for EBDA pointer @ 0x%04x, ", EBDA_POINTER );
423     seekEntry( (vm_offset_t)EBDA_POINTER );
424     readEntry( &segment, sizeof(segment) );
425     if ( segment ) {                /* search EBDA */
426         target = (vm_offset_t)segment << 4;
427         if ( verbose )
428             printf( "found, searching EBDA @ 0x%08lx\n", target );
429
430         if ((x = findMpSig(target, ONE_KBYTE)) != -1) {
431             *where = 1;
432             *paddr = x;
433             return;
434         }
435     }
436     else {
437         if ( verbose )
438             printf( "NOT found\n" );
439     }
440
441     /* read CMOS for real top of mem */
442     seekEntry( (vm_offset_t)TOPOFMEM_POINTER );
443     readEntry( &segment, sizeof(segment) );
444     --segment;                                          /* less ONE_KBYTE */
445     target = segment * 1024;
446     if ( verbose )
447         printf( " searching CMOS 'top of mem' @ 0x%08lx (%dK)\n",
448                 target, segment );
449
450     if ((x = findMpSig(target, ONE_KBYTE)) != -1) {
451         *where = 2;
452         *paddr = x;
453         return;
454     }
455
456     /* we don't necessarily believe CMOS, check base of the last 1K of 640K */
457     if ( target != (DEFAULT_TOPOFMEM - 1024)) {
458         target = (DEFAULT_TOPOFMEM - 1024);
459         if ( verbose )
460             printf( " searching default 'top of mem' @ 0x%08lx (%ldK)\n",
461                     target, (target / 1024) );
462
463         if ((x = findMpSig(target, ONE_KBYTE)) != -1) {
464             *where = 3;
465             *paddr = x;
466             return;
467         }
468     }
469
470     /* search the BIOS */
471     if ( verbose )
472         printf( " searching BIOS @ 0x%08x\n", BIOS_BASE );
473
474     if ((x = findMpSig(BIOS_BASE, BIOS_SIZE)) != -1) {
475         *where = 4;
476         *paddr = x;
477         return;
478     }
479
480     /* search the extended BIOS */
481     if ( verbose )
482         printf( " searching extended BIOS @ 0x%08x\n", BIOS_BASE2 );
483
484     if ((x = findMpSig(BIOS_BASE2, BIOS_SIZE)) != -1) {
485         *where = 5;
486         *paddr = x;
487         return;
488     }
489
490     if ( grope ) {
491         /* search additional memory */
492         target = GROPE_AREA1;
493         if ( verbose )
494             printf( " groping memory @ 0x%08lx\n", target );
495
496         if ((x = findMpSig(target, GROPE_SIZE)) != -1) {
497             *where = 6;
498             *paddr = x;
499             return;
500         }
501
502         target = GROPE_AREA2;
503         if ( verbose )
504             printf( " groping memory @ 0x%08lx\n", target );
505
506         if ((x = findMpSig(target, GROPE_SIZE)) != -1) {
507             *where = 7;
508             *paddr = x;
509             return;
510         }
511     }
512
513     *where = 0;
514     *paddr = (vm_offset_t)0;
515 }
516
517
518 /*
519  * 
520  */
521 static void
522 MPFloatingPointer( vm_offset_t paddr, int where, mpfps_t* mpfps )
523 {
524
525     /* read in mpfps structure*/
526     seekEntry( paddr );
527     readEntry( mpfps, sizeof( mpfps_t ) );
528
529     /* show its contents */
530     printf( "MP Floating Pointer Structure:\n\n" );
531
532     printf( "  location:\t\t\t" );
533     switch ( where )
534     {
535     case 1:
536         printf( "EBDA\n" );
537         break;
538     case 2:
539         printf( "BIOS base memory\n" );
540         break;
541     case 3:
542         printf( "DEFAULT base memory (639K)\n" );
543         break;
544     case 4:
545         printf( "BIOS\n" );
546         break;
547     case 5:
548         printf( "Extended BIOS\n" );
549         break;
550
551     case 0:
552         printf( "NOT found!\n" );
553         exit( 1 );
554     default:
555         printf( "BOGUS!\n" );
556         exit( 1 );
557     }
558     printf( "  physical address:\t\t0x%08lx\n", paddr );
559
560     printf( "  signature:\t\t\t'" );
561     pnstr( mpfps->signature, 4 );
562     printf( "'\n" );
563
564     printf( "  length:\t\t\t%d bytes\n", mpfps->length * 16 );
565     printf( "  version:\t\t\t1.%1d\n", mpfps->spec_rev );
566     printf( "  checksum:\t\t\t0x%02x\n", mpfps->checksum );
567
568     /* bits 0:6 are RESERVED */
569     if ( mpfps->mpfb2 & 0x7f ) {
570         printf( " warning, MP feature byte 2: 0x%02x\n", mpfps->mpfb2 );
571     }
572
573     /* bit 7 is IMCRP */
574     printf( "  mode:\t\t\t\t%s\n", (mpfps->mpfb2 & 0x80) ?
575             "PIC" : "Virtual Wire" );
576
577     /* MP feature bytes 3-5 are expected to be ZERO */
578     if ( mpfps->mpfb3 )
579         printf( " warning, MP feature byte 3 NONZERO!\n" );
580     if ( mpfps->mpfb4 )
581         printf( " warning, MP feature byte 4 NONZERO!\n" );
582     if ( mpfps->mpfb5 )
583         printf( " warning, MP feature byte 5 NONZERO!\n" );
584 }
585
586
587 /*
588  * 
589  */
590 static void
591 MPConfigDefault( int featureByte )
592 {
593     printf( "  MP default config type: %d\n\n", featureByte );
594     switch ( featureByte ) {
595     case 1:
596         printf( "   bus: ISA, APIC: 82489DX\n" );
597         break;
598     case 2:
599         printf( "   bus: EISA, APIC: 82489DX\n" );
600         break;
601     case 3:
602         printf( "   bus: EISA, APIC: 82489DX\n" );
603         break;
604     case 4:
605         printf( "   bus: MCA, APIC: 82489DX\n" );
606         break;
607     case 5:
608         printf( "   bus: ISA+PCI, APIC: Integrated\n" );
609         break;
610     case 6:
611         printf( "   bus: EISA+PCI, APIC: Integrated\n" );
612         break;
613     case 7:
614         printf( "   bus: MCA+PCI, APIC: Integrated\n" );
615         break;
616     default:
617         printf( "   future type\n" );
618         break;
619     }
620
621     switch ( featureByte ) {
622     case 1:
623     case 2:
624     case 3:
625     case 4:
626         nbus = 1;
627         break;
628     case 5:
629     case 6:
630     case 7:
631         nbus = 2;
632         break;
633     default:
634         printf( "   future type\n" );
635         break;
636     }
637
638     ncpu = 2;
639     napic = 1;
640     nintr = 16;
641 }
642
643
644 /*
645  * 
646  */
647 static void
648 MPConfigTableHeader( uint32_t pap )
649 {
650     vm_offset_t paddr;
651     mpcth_t     cth;
652     int         x;
653     int         totalSize;
654     int         count, c;
655     int         type;
656
657     if ( pap == 0 ) {
658         printf( "MP Configuration Table Header MISSING!\n" );
659         exit( 1 );
660     }
661
662     /* convert physical address to virtual address */
663     paddr = (vm_offset_t)pap;
664
665     /* read in cth structure */
666     seekEntry( paddr );
667     readEntry( &cth, sizeof( cth ) );
668
669     printf( "MP Config Table Header:\n\n" );
670
671     printf( "  physical address:\t\t0x%08x\n", pap );
672
673     printf( "  signature:\t\t\t'" );
674     pnstr( cth.signature, 4 );
675     printf( "'\n" );
676
677     printf( "  base table length:\t\t%d\n", cth.base_table_length );
678
679     printf( "  version:\t\t\t1.%1d\n", cth.spec_rev );
680     printf( "  checksum:\t\t\t0x%02x\n", cth.checksum );
681
682     printf( "  OEM ID:\t\t\t'" );
683     pnstr( cth.oem_id, 8 );
684     printf( "'\n" );
685
686     printf( "  Product ID:\t\t\t'" );
687     pnstr( cth.product_id, 12 );
688     printf( "'\n" );
689
690     printf( "  OEM table pointer:\t\t0x%08x\n", cth.oem_table_pointer );
691     printf( "  OEM table size:\t\t%d\n", cth.oem_table_size );
692
693     printf( "  entry count:\t\t\t%d\n", cth.entry_count );
694
695     printf( "  local APIC address:\t\t0x%08x\n", cth.apic_address );
696
697     printf( "  extended table length:\t%d\n", cth.extended_table_length );
698     printf( "  extended table checksum:\t%d\n", cth.extended_table_checksum );
699
700     totalSize = cth.base_table_length - sizeof( struct MPCTH );
701     count = cth.entry_count;
702
703     puts( SEP_LINE );
704
705     printf( "MP Config Base Table Entries:\n\n" );
706
707     /* initialze tables */
708     for ( x = 0; x < 16; ++x ) {
709         busses[ x ] = apics[ x ] = 0xff;
710     }
711
712     ncpu = 0;
713     nbus = 0;
714     napic = 0;
715     nintr = 0;
716
717     /* process all the CPUs */
718     printf( "--\nProcessors:\tAPIC ID\tVersion\tState"
719             "\t\tFamily\tModel\tStep\tFlags\n" );
720     for ( c = count; c; c-- ) {
721         if ( readType() == 0 )
722             processorEntry();
723         totalSize -= basetableEntryTypes[ 0 ].length;
724     }
725
726     /* process all the busses */
727     printf( "--\nBus:\t\tBus ID\tType\n" );
728     for ( c = count; c; c-- ) {
729         if ( readType() == 1 )
730             busEntry();
731         totalSize -= basetableEntryTypes[ 1 ].length;
732     }
733
734     /* process all the apics */
735     printf( "--\nI/O APICs:\tAPIC ID\tVersion\tState\t\tAddress\n" );
736     for ( c = count; c; c-- ) {
737         if ( readType() == 2 )
738             ioApicEntry();
739         totalSize -= basetableEntryTypes[ 2 ].length;
740     }
741
742     /* process all the I/O Ints */
743     printf( "--\nI/O Ints:\tType\tPolarity    Trigger\tBus ID\t IRQ\tAPIC ID\tPIN#\n" );
744     for ( c = count; c; c-- ) {
745         if ( readType() == 3 )
746             intEntry();
747         totalSize -= basetableEntryTypes[ 3 ].length;
748     }
749
750     /* process all the Local Ints */
751     printf( "--\nLocal Ints:\tType\tPolarity    Trigger\tBus ID\t IRQ\tAPIC ID\tPIN#\n" );
752     for ( c = count; c; c-- ) {
753         if ( readType() == 4 )
754             intEntry();
755         totalSize -= basetableEntryTypes[ 4 ].length;
756     }
757
758
759 #if defined( EXTENDED_PROCESSING_READY )
760     /* process any extended data */
761     if ( (totalSize = cth.extended_table_length) ) {
762         puts( SEP_LINE );
763
764         printf( "MP Config Extended Table Entries:\n\n" );
765
766         while ( totalSize > 0 ) {
767             switch ( type = readType() ) {
768             case 128:
769                 sasEntry();
770                 break;
771             case 129:
772                 bhdEntry();
773                 break;
774             case 130:
775                 cbasmEntry();
776                 break;
777             default:
778                 printf( "Extended Table HOSED!\n" );
779                 exit( 1 );
780             }
781
782             totalSize -= extendedtableEntryTypes[ type-128 ].length;
783         }
784     }
785 #endif  /* EXTENDED_PROCESSING_READY */
786
787     /* process any OEM data */
788     if ( cth.oem_table_pointer && (cth.oem_table_size > 0) ) {
789 #if defined( OEM_PROCESSING_READY )
790 # error your on your own here!
791         /* convert OEM table pointer to virtual address */
792         poemtp = (vm_offset_t)cth.oem_table_pointer;
793
794         /* read in oem table structure */
795         if ( (oemdata = (void*)malloc( cth.oem_table_size )) == NULL )
796             err( 1, "oem malloc" );
797
798         seekEntry( poemtp );
799         readEntry( oemdata, cth.oem_table_size );
800
801         /** process it */
802
803         free( oemdata );
804 #else
805         printf( "\nyou need to modify the source to handle OEM data!\n\n" );
806 #endif  /* OEM_PROCESSING_READY */
807     }
808
809     fflush( stdout );
810
811     if ( raw ) {
812         int             ofd;
813         u_char  dumpbuf[ 4096 ];
814
815         ofd = open( "/tmp/mpdump", O_CREAT | O_RDWR );
816         seekEntry( paddr );
817         readEntry( dumpbuf, 1024 );
818         write( ofd, dumpbuf, 1024 );
819         close( ofd );
820     }
821 }
822
823
824 /*
825  * 
826  */
827 static int
828 readType( void )
829 {
830     u_char      type;
831
832     if ( read( pfd, &type, sizeof( u_char ) ) != sizeof( u_char ) )
833         err( 1, "type read; pfd: %d", pfd );
834
835     if ( lseek( pfd, -1, SEEK_CUR ) < 0 )
836         err( 1, "type seek" );
837
838     return (int)type;
839 }
840
841
842 /*
843  * 
844  */
845 static void
846 seekEntry( vm_offset_t addr )
847 {
848     if ( lseek( pfd, (off_t)addr, SEEK_SET ) < 0 )
849         err( 1, "%s seek", _PATH_MEM );
850 }
851
852
853 /*
854  * 
855  */
856 static void
857 readEntry( void* entry, int size )
858 {
859     if ( read( pfd, entry, size ) != size )
860         err( 1, "readEntry" );
861 }
862
863
864 static void
865 processorEntry( void )
866 {
867     ProcEntry   entry;
868
869     /* read it into local memory */
870     readEntry( &entry, sizeof( entry ) );
871
872     /* count it */
873     ++ncpu;
874
875     printf( "\t\t%2d", entry.apicID );
876     printf( "\t 0x%2x", entry.apicVersion );
877
878     printf( "\t %s, %s",
879             (entry.cpuFlags & PROCENTRY_FLAG_BP) ? "BSP" : "AP",
880             (entry.cpuFlags & PROCENTRY_FLAG_EN) ? "usable" : "unusable" );
881
882     printf( "\t %d\t %d\t %d",
883             (entry.cpuSignature >> 8) & 0x0f,
884             (entry.cpuSignature >> 4) & 0x0f,
885             entry.cpuSignature & 0x0f );
886
887     printf( "\t 0x%04x\n", entry.featureFlags );
888 }
889
890
891 /*
892  * 
893  */
894 static int
895 lookupBusType( char* name )
896 {
897     int x;
898
899     for ( x = 0; x < MAX_BUSTYPE; ++x )
900         if ( strcmp( busTypeTable[ x ].name, name ) == 0 )
901             return busTypeTable[ x ].type;
902
903     return UNKNOWN_BUSTYPE;
904 }
905
906
907 static void
908 busEntry( void )
909 {
910     int         x;
911     char        name[ 8 ];
912     char        c;
913     BusEntry    entry;
914
915     /* read it into local memory */
916     readEntry( &entry, sizeof( entry ) );
917
918     /* count it */
919     ++nbus;
920
921     printf( "\t\t%2d", entry.busID );
922     printf( "\t " ); pnstr( entry.busType, 6 ); printf( "\n" );
923
924     for ( x = 0; x < 6; ++x ) {
925         if ( (c = entry.busType[ x ]) == ' ' )
926             break;
927         name[ x ] = c;
928     }
929     name[ x ] = '\0';
930     busses[ entry.busID ] = lookupBusType( name );
931 }
932
933
934 static void
935 ioApicEntry( void )
936 {
937     IOApicEntry entry;
938
939     /* read it into local memory */
940     readEntry( &entry, sizeof( entry ) );
941
942     /* count it */
943     ++napic;
944
945     printf( "\t\t%2d", entry.apicID );
946     printf( "\t 0x%02x", entry.apicVersion );
947     printf( "\t %s",
948             (entry.apicFlags & IOAPICENTRY_FLAG_EN) ? "usable" : "unusable" );
949     printf( "\t\t 0x%x\n", entry.apicAddress );
950
951     apics[ entry.apicID ] = entry.apicID;
952 }
953
954
955 const char* intTypes[] = {
956     "INT", "NMI", "SMI", "ExtINT"
957 };
958
959 const char* polarityMode[] = {
960     "conforms", "active-hi", "reserved", "active-lo"
961 };
962 const char* triggerMode[] = {
963     "conforms", "edge", "reserved", "level"
964 };
965
966 static void
967 intEntry( void )
968 {
969     IntEntry    entry;
970
971     /* read it into local memory */
972     readEntry( &entry, sizeof( entry ) );
973
974     /* count it */
975     if ( (int)entry.type == 3 )
976         ++nintr;
977
978     printf( "\t\t%s", intTypes[ (int)entry.intType ] );
979
980     printf( "\t%9s", polarityMode[ (int)entry.intFlags & 0x03 ] );
981     printf( "%12s", triggerMode[ ((int)entry.intFlags >> 2) & 0x03 ] );
982
983     printf( "\t %5d", (int)entry.srcBusID );
984     if ( busses[ (int)entry.srcBusID ] == PCI )
985         printf( "\t%2d:%c", 
986                 ((int)entry.srcBusIRQ >> 2) & 0x1f,
987                 ((int)entry.srcBusIRQ & 0x03) + 'A' );
988     else
989         printf( "\t %3d", (int)entry.srcBusIRQ );
990     printf( "\t %6d", (int)entry.dstApicID );
991     printf( "\t %3d\n", (int)entry.dstApicINT );
992 }
993
994
995 static void
996 sasEntry( void )
997 {
998     SasEntry    entry;
999
1000     /* read it into local memory */
1001     readEntry( &entry, sizeof( entry ) );
1002
1003     printf( "--\n%s\n", extendedtableEntryTypes[entry.type - 128].name );
1004     printf( " bus ID: %d", entry.busID );
1005     printf( " address type: " );
1006     switch ( entry.addressType ) {
1007     case 0:
1008         printf( "I/O address\n" );
1009         break;
1010     case 1:
1011         printf( "memory address\n" );
1012         break;
1013     case 2:
1014         printf( "prefetch address\n" );
1015         break;
1016     default:
1017         printf( "UNKNOWN type\n" );
1018         break;
1019     }
1020
1021     printf( " address base: 0x%" PRIx64 "\n", entry.addressBase );
1022     printf( " address range: 0x%" PRIx64 "\n", entry.addressLength );
1023 }
1024
1025
1026 static void
1027 bhdEntry( void )
1028 {
1029     BhdEntry    entry;
1030
1031     /* read it into local memory */
1032     readEntry( &entry, sizeof( entry ) );
1033
1034     printf( "--\n%s\n", extendedtableEntryTypes[entry.type - 128].name );
1035     printf( " bus ID: %d", entry.busID );
1036     printf( " bus info: 0x%02x", entry.busInfo );
1037     printf( " parent bus ID: %d\n", entry.busParent );
1038 }
1039
1040
1041 static void
1042 cbasmEntry( void )
1043 {
1044     CbasmEntry  entry;
1045
1046     /* read it into local memory */
1047     readEntry( &entry, sizeof( entry ) );
1048
1049     printf( "--\n%s\n", extendedtableEntryTypes[entry.type - 128].name );
1050     printf( " bus ID: %d", entry.busID );
1051     printf( " address modifier: %s\n", (entry.addressMod & 0x01) ?
1052                                         "subtract" : "add" );
1053     printf( " predefined range: 0x%08x\n", entry.predefinedRange );
1054 }
1055
1056
1057 /*
1058  * do a dmesg output
1059  */
1060 static void
1061 doDmesg( void )
1062 {
1063     puts( SEP_LINE );
1064
1065     printf( "dmesg output:\n\n" );
1066     fflush( stdout );
1067     system( "dmesg" );
1068 }
1069
1070
1071 /*
1072  * 
1073  */
1074 static void
1075 pnstr( char* s, int c )
1076 {
1077     char string[ MAXPNSTR + 1 ];
1078
1079     if ( c > MAXPNSTR )
1080         c = MAXPNSTR;
1081     strncpy( string, s, c );
1082     string[ c ] = '\0';
1083     printf( "%s", string );
1084 }