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