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