mptable.c revision 29850
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
31static 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
89enum 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
100typedef struct BUSTYPENAME {
101    u_char	type;
102    char	name[ 7 ];
103} busTypeName;
104
105static 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
128char* 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
138typedef struct TABLE_ENTRY {
139    u_char	type;
140    u_char	length;
141    char	name[ 32 ];
142} tableEntry;
143
144tableEntry 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
153tableEntry 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 */
161typedef 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 */
175typedef 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
192typedef 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
203typedef struct BUSENTRY {
204    u_char	type;
205    u_char	busID;
206    char	busType[ 6 ];
207} BusEntry;
208
209typedef struct IOAPICENTRY {
210    u_char	type;
211    u_char	apicID;
212    u_char	apicVersion;
213    u_char	apicFlags;
214    void*	apicAddress;
215} IOApicEntry;
216
217typedef 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
232typedef 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
242typedef 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
252typedef 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
262static void apic_probe( vm_offset_t* paddr, int* where );
263
264static void MPConfigDefault( int featureByte );
265
266static void MPFloatingPointer( vm_offset_t paddr, int where, mpfps_t* mpfps );
267static void MPConfigTableHeader( void* pap );
268
269static int readType( void );
270static void seekEntry( vm_offset_t addr );
271static void readEntry( void* entry, int size );
272
273static void processorEntry( void );
274static void busEntry( void );
275static void ioApicEntry( void );
276static void intEntry( void );
277
278static void sasEntry( void );
279static void bhdEntry( void );
280static void cbasmEntry( void );
281
282static void doOptionList( void );
283static void doDmesg( void );
284static void pnstr( char* s, int c );
285
286/* global data */
287int	pfd;		/* physical /dev/mem fd */
288
289int	busses[ 16 ];
290int	apics[ 16 ];
291
292int	ncpu;
293int	nbus;
294int	napic;
295int	nintr;
296
297int	dmesg;
298int	grope;
299int	verbose;
300
301static void
302usage( void )
303{
304    fprintf( stderr, "usage: mptable [-dmesg] [-verbose] [-grope] [-help]\n" );
305    exit( 0 );
306}
307
308/*
309 *
310 */
311int
312main( 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)
402static void
403apic_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 */
546static void
547MPFloatingPointer( 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 */
615static void
616MPConfigDefault( 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 */
672static void
673MPConfigTableHeader( 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 */
854static int
855readType( 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 */
872static void
873seekEntry( 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 */
883static void
884readEntry( void* entry, int size )
885{
886    if ( read( pfd, entry, size ) != size )
887        err( 1, "readEntry" );
888}
889
890
891static void
892processorEntry( 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 */
921static int
922lookupBusType( 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
934static void
935busEntry( 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
961static void
962ioApicEntry( 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
982char* intTypes[] = {
983    "INT", "NMI", "SMI", "ExtINT"
984};
985
986char* polarityMode[] = {
987    "conforms", "active-hi", "reserved", "active-lo"
988};
989char* triggerMode[] = {
990    "conforms", "edge", "reserved", "level"
991};
992
993static void
994intEntry( 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
1022static void
1023sasEntry( 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
1053static void
1054bhdEntry( 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
1068static void
1069cbasmEntry( 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 */
1087static void
1088doDmesg( 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 */
1101static void
1102doOptionList( 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 */
1123static void
1124pnstr( 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