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