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