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