mptable.c revision 115972
1139804Simp/*
21541Srgrimes * Copyright (c) 1996, by Steve Passe
31541Srgrimes * All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. The name of the developer may NOT be used to endorse or promote products
111541Srgrimes *    derived from this software without specific prior written permission.
121541Srgrimes *
131541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
141541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
151541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
161541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
171541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
181541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
191541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
201541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
211541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
221541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
231541Srgrimes * SUCH DAMAGE.
241541Srgrimes */
251541Srgrimes
261541Srgrimes/*
271541Srgrimes * mptable.c
281541Srgrimes */
291541Srgrimes
301541Srgrimes#ifndef lint
311541Srgrimesstatic const char rcsid[] =
321541Srgrimes  "$FreeBSD: head/usr.sbin/mptable/mptable.c 115972 2003-06-07 18:33:18Z imp $";
331541Srgrimes#endif /* not lint */
341541Srgrimes
351541Srgrimes#define VMAJOR			2
361541Srgrimes#define VMINOR			0
37116182Sobrien#define VDELTA			15
38116182Sobrien
391541Srgrimes/*
401541Srgrimes * this will cause the raw mp table to be dumped to /tmp/mpdump
412112Swollman *
422946Swollman#define RAW_DUMP
43138350Sphk */
441541Srgrimes
45138350Sphk#define MP_SIG			0x5f504d5f	/* _MP_ */
46159590Sjhb#define EXTENDED_PROCESSING_READY
4738869Sbde#define OEM_PROCESSING_READY_NOT
481541Srgrimes
491541Srgrimes#include <sys/types.h>
501541Srgrimes#include <err.h>
51141634Sphk#include <fcntl.h>
52141634Sphk#include <paths.h>
5312577Sbde#include <stdio.h>
5430354Sphk#include <stdlib.h>
5530354Sphk#include <string.h>
5610358Sjulian#include <unistd.h>
5769664Speter
5829653Sdyson#define SEP_LINE \
5969664Speter"\n-------------------------------------------------------------------------------\n"
6091690Seivind
6191690Seivind#define SEP_LINE2 \
6291690Seivind"\n===============================================================================\n"
6391690Seivind
6491690Seivind/* EBDA is @ 40:0e in real-mode terms */
65132710Sphk#define EBDA_POINTER		0x040e		/* location of EBDA pointer */
6652780Smsmith
6752780Smsmith/* CMOS 'top of mem' is @ 40:13 in real-mode terms */
68135279Sphk#define TOPOFMEM_POINTER	0x0413		/* BIOS: base memory size */
69135279Sphk
70135279Sphk#define DEFAULT_TOPOFMEM	0xa0000
71135279Sphk
72135279Sphk#define BIOS_BASE		0xf0000
73135279Sphk#define BIOS_BASE2		0xe0000
74135279Sphk#define BIOS_SIZE		0x10000
751541Srgrimes#define ONE_KBYTE		1024
761541Srgrimes
771541Srgrimes#define GROPE_AREA1		0x80000
781541Srgrimes#define GROPE_AREA2		0x90000
791541Srgrimes#define GROPE_SIZE		0x10000
801541Srgrimes
811541Srgrimes#define PROCENTRY_FLAG_EN	0x01
821541Srgrimes#define PROCENTRY_FLAG_BP	0x02
831541Srgrimes#define IOAPICENTRY_FLAG_EN	0x01
841541Srgrimes
851541Srgrimes#define MAXPNSTR		132
861541Srgrimes
871541Srgrimesenum busTypes {
881541Srgrimes    CBUS = 1,
891541Srgrimes    CBUSII = 2,
9041056Speter    EISA = 3,
91138290Sphk    ISA = 6,
92138290Sphk    PCI = 13,
93138290Sphk    XPRESS = 18,
9441056Speter    MAX_BUSTYPE = 18,
95132710Sphk    UNKNOWN_BUSTYPE = 0xff
96132710Sphk};
97132710Sphk
98132710Sphktypedef struct BUSTYPENAME {
99132710Sphk    u_char	type;
100138497Sphk    char	name[ 7 ];
101138497Sphk} busTypeName;
102132710Sphk
103132710Sphkstatic busTypeName busTypeTable[] =
104132710Sphk{
105132710Sphk    { CBUS,		"CBUS"   },
106132710Sphk    { CBUSII,		"CBUSII" },
107132710Sphk    { EISA,		"EISA"   },
108138350Sphk    { UNKNOWN_BUSTYPE,	"---"    },
109138350Sphk    { UNKNOWN_BUSTYPE,	"---"    },
110138350Sphk    { ISA,		"ISA"    },
111138350Sphk    { UNKNOWN_BUSTYPE,	"---"    },
112159590Sjhb    { UNKNOWN_BUSTYPE,	"---"    },
113138350Sphk    { UNKNOWN_BUSTYPE,	"---"    },
114138350Sphk    { UNKNOWN_BUSTYPE,	"---"    },
115138350Sphk    { UNKNOWN_BUSTYPE,	"---"    },
116138350Sphk    { UNKNOWN_BUSTYPE,	"---"    },
117138350Sphk    { PCI,		"PCI"    },
118159956Sjhb    { UNKNOWN_BUSTYPE,	"---"    },
119159590Sjhb    { UNKNOWN_BUSTYPE,	"---"    },
120138350Sphk    { UNKNOWN_BUSTYPE,	"---"    },
121138350Sphk    { UNKNOWN_BUSTYPE,	"---"    },
122159590Sjhb    { UNKNOWN_BUSTYPE,	"---"    },
123138350Sphk    { UNKNOWN_BUSTYPE,	"---"    }
124138350Sphk};
125138350Sphk
126159590Sjhbchar* whereStrings[] = {
127138350Sphk    "Extended BIOS Data Area",
128138350Sphk    "BIOS top of memory",
129138350Sphk    "Default top of memory",
130138350Sphk    "BIOS",
131138350Sphk    "Extended BIOS",
132138350Sphk    "GROPE AREA #1",
133138350Sphk    "GROPE AREA #2"
13496755Strhodes};
135141634Sphk
13641056Spetertypedef struct TABLE_ENTRY {
13740435Speter    u_char	type;
13844549Sdfr    u_char	length;
139116271Sphk    char	name[ 32 ];
140135279Sphk} tableEntry;
141135279Sphk
142135279SphktableEntry basetableEntryTypes[] =
143135279Sphk{
144135279Sphk    { 0, 20, "Processor" },
145135279Sphk    { 1,  8, "Bus" },
146116271Sphk    { 2,  8, "I/O APIC" },
147132902Sphk    { 3,  8, "I/O INT" },
148132902Sphk    { 4,  8, "Local INT" }
149132902Sphk};
150132902Sphk
151132902SphktableEntry extendedtableEntryTypes[] =
152132710Sphk{
153132710Sphk    { 128, 20, "System Address Space" },
15440435Speter    { 129,  8, "Bus Heirarchy" },
15540435Speter    { 130,  8, "Compatibility Bus Address" }
156132710Sphk};
15740435Speter
15840435Speter/* MP Floating Pointer Structure */
15944549Sdfrtypedef struct MPFPS {
16044549Sdfr    char	signature[ 4 ];
16144549Sdfr    void*	pap;
16244549Sdfr    u_char	length;
16344549Sdfr    u_char	spec_rev;
16444549Sdfr    u_char	checksum;
16544549Sdfr    u_char	mpfb1;
16644549Sdfr    u_char	mpfb2;
16744549Sdfr    u_char	mpfb3;
16872012Sphk    u_char	mpfb4;
16944549Sdfr    u_char	mpfb5;
17044549Sdfr} mpfps_t;
17144549Sdfr
17244549Sdfr/* MP Configuration Table Header */
17344549Sdfrtypedef struct MPCTH {
17444549Sdfr    char	signature[ 4 ];
17544549Sdfr    u_short	base_table_length;
176116271Sphk    u_char	spec_rev;
177116271Sphk    u_char	checksum;
178116271Sphk    u_char	oem_id[ 8 ];
179116271Sphk    u_char	product_id[ 12 ];
180116271Sphk    void*	oem_table_pointer;
181116271Sphk    u_short	oem_table_size;
182116271Sphk    u_short	entry_count;
183116271Sphk    void*	apic_address;
184116271Sphk    u_short	extended_table_length;
185116271Sphk    u_char	extended_table_checksum;
186116271Sphk    u_char	reserved;
187138509Sphk} mpcth_t;
188138509Sphk
189116271Sphk
190116271Sphktypedef struct PROCENTRY {
191116271Sphk    u_char	type;
192116271Sphk    u_char	apicID;
193116271Sphk    u_char	apicVersion;
194116271Sphk    u_char	cpuFlags;
195116271Sphk    u_long	cpuSignature;
196116271Sphk    u_long	featureFlags;
197116271Sphk    u_long	reserved1;
198116271Sphk    u_long	reserved2;
199116271Sphk} ProcEntry;
200116271Sphk
201116271Sphktypedef struct BUSENTRY {
202116271Sphk    u_char	type;
203116271Sphk    u_char	busID;
204116271Sphk    char	busType[ 6 ];
205116271Sphk} BusEntry;
206116271Sphk
207116271Sphktypedef struct IOAPICENTRY {
208116271Sphk    u_char	type;
209116271Sphk    u_char	apicID;
210116271Sphk    u_char	apicVersion;
211116271Sphk    u_char	apicFlags;
212116271Sphk    void*	apicAddress;
213116271Sphk} IOApicEntry;
214116271Sphk
215116271Sphktypedef struct INTENTRY {
216116271Sphk    u_char	type;
217116271Sphk    u_char	intType;
218116271Sphk    u_short	intFlags;
219116271Sphk    u_char	srcBusID;
220116271Sphk    u_char	srcBusIRQ;
221116271Sphk    u_char	dstApicID;
222116271Sphk    u_char	dstApicINT;
223116271Sphk} IntEntry;
224116271Sphk
225116271Sphk
226116271Sphk/*
227116271Sphk * extended entry type structures
228116271Sphk */
229116271Sphk
230131733Salfredtypedef struct SASENTRY {
231131733Salfred    u_char	type;
232116271Sphk    u_char	length;
233116271Sphk    u_char	busID;
23440435Speter    u_char	addressType;
23540435Speter    u_int64_t	addressBase;
23640435Speter    u_int64_t	addressLength;
23740435Speter} SasEntry;
23840435Speter
2391541Srgrimes
2402946Swollmantypedef struct BHDENTRY {
24140435Speter    u_char	type;
24296755Strhodes    u_char	length;
243141634Sphk    u_char	busID;
24441056Speter    u_char	busInfo;
24540435Speter    u_char	busParent;
246132710Sphk    u_char	reserved[ 3 ];
24740435Speter} BhdEntry;
24840435Speter
24940435Speter
25040435Spetertypedef struct CBASMENTRY {
251132710Sphk    u_char	type;
25240435Speter    u_char	length;
25340435Speter    u_char	busID;
25440435Speter    u_char	addressMod;
25540435Speter    u_int	predefinedRange;
25640435Speter} CbasmEntry;
25740435Speter
25840435Speter
25940435Speter
26040435Speterstatic void apic_probe( vm_offset_t* paddr, int* where );
261132710Sphk
26240435Speterstatic void MPConfigDefault( int featureByte );
263132710Sphk
26440435Speterstatic void MPFloatingPointer( vm_offset_t paddr, int where, mpfps_t* mpfps );
26540435Speterstatic void MPConfigTableHeader( void* pap );
26640435Speter
26740435Speterstatic int readType( void );
26840435Speterstatic void seekEntry( vm_offset_t addr );
26941056Speterstatic void readEntry( void* entry, int size );
27091690Seivind
27196755Strhodesstatic void processorEntry( void );
27291690Seivindstatic void busEntry( void );
27391690Seivindstatic void ioApicEntry( void );
27441056Speterstatic void intEntry( void );
27541170Sbde
27641056Speterstatic void sasEntry( void );
27741056Speterstatic void bhdEntry( void );
27841056Speterstatic void cbasmEntry( void );
27941056Speter
28041056Speterstatic void doDmesg( void );
28141056Speterstatic void pnstr( char* s, int c );
28241056Speter
28341056Speter/* global data */
28441056Speterint	pfd;		/* physical /dev/mem fd */
28541056Speter
28641056Speterint	busses[ 16 ];
28741056Speterint	apics[ 16 ];
28841056Speter
28941056Speterint	ncpu;
29041056Speterint	nbus;
29141056Speterint	napic;
292132199Sphkint	nintr;
293132199Sphk
29441056Speterint	dmesg;
29541056Speterint	grope;
29641056Speterint	verbose;
29741056Speter
298static void
299usage( void )
300{
301    fprintf( stderr, "usage: mptable [-dmesg] [-verbose] [-grope] [-help]\n" );
302    exit( 0 );
303}
304
305/*
306 *
307 */
308int
309main( int argc, char *argv[] )
310{
311    vm_offset_t	paddr;
312    int		where;
313    mpfps_t	mpfps;
314    int		defaultConfig;
315
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( _PATH_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;
672    int		count, c;
673    int		type;
674    int		oldtype, entrytype;
675
676    if ( pap == 0 ) {
677	printf( "MP Configuration Table Header MISSING!\n" );
678        exit( 1 );
679    }
680
681    /* convert physical address to virtual address */
682    paddr = (vm_offset_t)pap;
683
684    /* read in cth structure */
685    seekEntry( paddr );
686    readEntry( &cth, sizeof( cth ) );
687
688    printf( "MP Config Table Header:\n\n" );
689
690    printf( "  physical address:\t\t0x%08x\n", pap );
691
692    printf( "  signature:\t\t\t'" );
693    pnstr( cth.signature, 4 );
694    printf( "'\n" );
695
696    printf( "  base table length:\t\t%d\n", cth.base_table_length );
697
698    printf( "  version:\t\t\t1.%1d\n", cth.spec_rev );
699    printf( "  checksum:\t\t\t0x%02x\n", cth.checksum );
700
701    printf( "  OEM ID:\t\t\t'" );
702    pnstr( cth.oem_id, 8 );
703    printf( "'\n" );
704
705    printf( "  Product ID:\t\t\t'" );
706    pnstr( cth.product_id, 12 );
707    printf( "'\n" );
708
709    printf( "  OEM table pointer:\t\t0x%08x\n", cth.oem_table_pointer );
710    printf( "  OEM table size:\t\t%d\n", cth.oem_table_size );
711
712    printf( "  entry count:\t\t\t%d\n", cth.entry_count );
713
714    printf( "  local APIC address:\t\t0x%08x\n", cth.apic_address );
715
716    printf( "  extended table length:\t%d\n", cth.extended_table_length );
717    printf( "  extended table checksum:\t%d\n", cth.extended_table_checksum );
718
719    totalSize = cth.base_table_length - sizeof( struct MPCTH );
720    count = cth.entry_count;
721
722    puts( SEP_LINE );
723
724    printf( "MP Config Base Table Entries:\n\n" );
725
726    /* initialze tables */
727    for ( x = 0; x < 16; ++x ) {
728	busses[ x ] = apics[ x ] = 0xff;
729    }
730
731    ncpu = 0;
732    nbus = 0;
733    napic = 0;
734    nintr = 0;
735
736    oldtype = -1;
737    for (c = count; c; c--) {
738	entrytype = readType();
739	if (entrytype != oldtype)
740	    printf("--\n");
741	if (entrytype < oldtype)
742	    printf("MPTABLE OUT OF ORDER!\n");
743	switch (entrytype) {
744	case 0:
745	    if (oldtype != 0)
746		printf( "Processors:\tAPIC ID\tVersion\tState"
747			"\t\tFamily\tModel\tStep\tFlags\n" );
748	    oldtype = 0;
749	    processorEntry();
750	    break;
751
752	case 1:
753	    if (oldtype != 1)
754		printf( "Bus:\t\tBus ID\tType\n" );
755	    oldtype = 1;
756	    busEntry();
757	    break;
758
759	case 2:
760	    if (oldtype != 2)
761		printf( "I/O APICs:\tAPIC ID\tVersion\tState\t\tAddress\n" );
762	    oldtype = 2;
763	    ioApicEntry();
764	    break;
765
766	case 3:
767	    if (oldtype != 3)
768		printf( "I/O Ints:\tType\tPolarity    Trigger\tBus ID\t IRQ\tAPIC ID\tPIN#\n" );
769	    oldtype = 3;
770	    intEntry();
771	    break;
772
773	case 4:
774	    if (oldtype != 4)
775		printf( "Local Ints:\tType\tPolarity    Trigger\tBus ID\t IRQ\tAPIC ID\tPIN#\n" );
776	    oldtype = 4;
777	    intEntry();
778	    break;
779
780	default:
781	    printf("MPTABLE HOSED! record type = %d\n", entrytype);
782	    exit(1);
783	}
784    }
785
786
787#if defined( EXTENDED_PROCESSING_READY )
788    /* process any extended data */
789    if ( (totalSize = cth.extended_table_length) ) {
790	puts( SEP_LINE );
791
792        printf( "MP Config Extended Table Entries:\n\n" );
793
794        while ( totalSize > 0 ) {
795            switch ( type = readType() ) {
796            case 128:
797		sasEntry();
798		break;
799            case 129:
800		bhdEntry();
801		break;
802            case 130:
803		cbasmEntry();
804		break;
805            default:
806                printf( "Extended Table HOSED!\n" );
807                exit( 1 );
808            }
809
810            totalSize -= extendedtableEntryTypes[ type-128 ].length;
811        }
812    }
813#endif  /* EXTENDED_PROCESSING_READY */
814
815    /* process any OEM data */
816    if ( cth.oem_table_pointer && (cth.oem_table_size > 0) ) {
817#if defined( OEM_PROCESSING_READY )
818# error your on your own here!
819        /* convert OEM table pointer to virtual address */
820        poemtp = (vm_offset_t)cth.oem_table_pointer;
821
822        /* read in oem table structure */
823        if ( (oemdata = (void*)malloc( cth.oem_table_size )) == NULL )
824            err( 1, "oem malloc" );
825
826        seekEntry( poemtp );
827        readEntry( oemdata, cth.oem_table_size );
828
829        /** process it */
830
831        free( oemdata );
832#else
833        printf( "\nyou need to modify the source to handle OEM data!\n\n" );
834#endif  /* OEM_PROCESSING_READY */
835    }
836
837    fflush( stdout );
838
839#if defined( RAW_DUMP )
840{
841    int		ofd;
842    u_char	dumpbuf[ 4096 ];
843
844    ofd = open( "/tmp/mpdump", O_CREAT | O_RDWR );
845    seekEntry( paddr );
846    readEntry( dumpbuf, 1024 );
847    write( ofd, dumpbuf, 1024 );
848    close( ofd );
849}
850#endif /* RAW_DUMP */
851}
852
853
854/*
855 *
856 */
857static int
858readType( void )
859{
860    u_char	type;
861
862    if ( read( pfd, &type, sizeof( u_char ) ) != sizeof( u_char ) )
863        err( 1, "type read; pfd: %d", pfd );
864
865    if ( lseek( pfd, -1, SEEK_CUR ) < 0 )
866        err( 1, "type seek" );
867
868    return (int)type;
869}
870
871
872/*
873 *
874 */
875static void
876seekEntry( vm_offset_t addr )
877{
878    if ( lseek( pfd, (off_t)addr, SEEK_SET ) < 0 )
879        err( 1, "%s seek", _PATH_MEM );
880}
881
882
883/*
884 *
885 */
886static void
887readEntry( void* entry, int size )
888{
889    if ( read( pfd, entry, size ) != size )
890        err( 1, "readEntry" );
891}
892
893
894static void
895processorEntry( void )
896{
897    ProcEntry	entry;
898
899    /* read it into local memory */
900    readEntry( &entry, sizeof( entry ) );
901
902    /* count it */
903    ++ncpu;
904
905    printf( "\t\t%2d", entry.apicID );
906    printf( "\t 0x%2x", entry.apicVersion );
907
908    printf( "\t %s, %s",
909            (entry.cpuFlags & PROCENTRY_FLAG_BP) ? "BSP" : "AP",
910            (entry.cpuFlags & PROCENTRY_FLAG_EN) ? "usable" : "unusable" );
911
912    printf( "\t %d\t %d\t %d",
913            (entry.cpuSignature >> 8) & 0x0f,
914            (entry.cpuSignature >> 4) & 0x0f,
915            entry.cpuSignature & 0x0f );
916
917    printf( "\t 0x%04x\n", entry.featureFlags );
918}
919
920
921/*
922 *
923 */
924static int
925lookupBusType( char* name )
926{
927    int x;
928
929    for ( x = 0; x < MAX_BUSTYPE; ++x )
930	if ( strcmp( busTypeTable[ x ].name, name ) == 0 )
931	    return busTypeTable[ x ].type;
932
933    return UNKNOWN_BUSTYPE;
934}
935
936
937static void
938busEntry( void )
939{
940    int		x;
941    char	name[ 8 ];
942    char	c;
943    BusEntry	entry;
944
945    /* read it into local memory */
946    readEntry( &entry, sizeof( entry ) );
947
948    /* count it */
949    ++nbus;
950
951    printf( "\t\t%2d", entry.busID );
952    printf( "\t " ); pnstr( entry.busType, 6 ); printf( "\n" );
953
954    for ( x = 0; x < 6; ++x ) {
955	if ( (c = entry.busType[ x ]) == ' ' )
956	    break;
957	name[ x ] = c;
958    }
959    name[ x ] = '\0';
960    busses[ entry.busID ] = lookupBusType( name );
961}
962
963
964static void
965ioApicEntry( void )
966{
967    IOApicEntry	entry;
968
969    /* read it into local memory */
970    readEntry( &entry, sizeof( entry ) );
971
972    /* count it */
973    ++napic;
974
975    printf( "\t\t%2d", entry.apicID );
976    printf( "\t 0x%02x", entry.apicVersion );
977    printf( "\t %s",
978            (entry.apicFlags & IOAPICENTRY_FLAG_EN) ? "usable" : "unusable" );
979    printf( "\t\t 0x%x\n", entry.apicAddress );
980
981    apics[ entry.apicID ] = entry.apicID;
982}
983
984
985char* intTypes[] = {
986    "INT", "NMI", "SMI", "ExtINT"
987};
988
989char* polarityMode[] = {
990    "conforms", "active-hi", "reserved", "active-lo"
991};
992char* triggerMode[] = {
993    "conforms", "edge", "reserved", "level"
994};
995
996static void
997intEntry( void )
998{
999    IntEntry	entry;
1000
1001    /* read it into local memory */
1002    readEntry( &entry, sizeof( entry ) );
1003
1004    /* count it */
1005    if ( (int)entry.type == 3 )
1006	++nintr;
1007
1008    printf( "\t\t%s", intTypes[ (int)entry.intType ] );
1009
1010    printf( "\t%9s", polarityMode[ (int)entry.intFlags & 0x03 ] );
1011    printf( "%12s", triggerMode[ ((int)entry.intFlags >> 2) & 0x03 ] );
1012
1013    printf( "\t %5d", (int)entry.srcBusID );
1014    if ( busses[ (int)entry.srcBusID ] == PCI )
1015	printf( "\t%2d:%c",
1016	        ((int)entry.srcBusIRQ >> 2) & 0x1f,
1017	        ((int)entry.srcBusIRQ & 0x03) + 'A' );
1018    else
1019	printf( "\t %3d", (int)entry.srcBusIRQ );
1020    printf( "\t %6d", (int)entry.dstApicID );
1021    printf( "\t %3d\n", (int)entry.dstApicINT );
1022}
1023
1024
1025static void
1026sasEntry( void )
1027{
1028    SasEntry	entry;
1029
1030    /* read it into local memory */
1031    readEntry( &entry, sizeof( entry ) );
1032
1033    printf( "--\n%s\n", extendedtableEntryTypes[entry.type - 128].name );
1034    printf( " bus ID: %d", entry.busID );
1035    printf( " address type: " );
1036    switch ( entry.addressType ) {
1037    case 0:
1038	printf( "I/O address\n" );
1039	break;
1040    case 1:
1041	printf( "memory address\n" );
1042	break;
1043    case 2:
1044	printf( "prefetch address\n" );
1045	break;
1046    default:
1047	printf( "UNKNOWN type\n" );
1048	break;
1049    }
1050
1051    printf( " address base: 0x%qx\n", entry.addressBase );
1052    printf( " address range: 0x%qx\n", entry.addressLength );
1053}
1054
1055
1056static void
1057bhdEntry( void )
1058{
1059    BhdEntry	entry;
1060
1061    /* read it into local memory */
1062    readEntry( &entry, sizeof( entry ) );
1063
1064    printf( "--\n%s\n", extendedtableEntryTypes[entry.type - 128].name );
1065    printf( " bus ID: %d", entry.busID );
1066    printf( " bus info: 0x%02x", entry.busInfo );
1067    printf( " parent bus ID: %d\n", entry.busParent );
1068}
1069
1070
1071static void
1072cbasmEntry( void )
1073{
1074    CbasmEntry	entry;
1075
1076    /* read it into local memory */
1077    readEntry( &entry, sizeof( entry ) );
1078
1079    printf( "--\n%s\n", extendedtableEntryTypes[entry.type - 128].name );
1080    printf( " bus ID: %d", entry.busID );
1081    printf( " address modifier: %s\n", (entry.addressMod & 0x01) ?
1082                                        "subtract" : "add" );
1083    printf( " predefined range: 0x%08x\n", entry.predefinedRange );
1084}
1085
1086
1087/*
1088 * do a dmesg output
1089 */
1090static void
1091doDmesg( void )
1092{
1093    puts( SEP_LINE );
1094
1095    printf( "dmesg output:\n\n" );
1096    fflush( stdout );
1097    system( "dmesg" );
1098}
1099
1100
1101/*
1102 *
1103 */
1104static void
1105pnstr( char* s, int c )
1106{
1107    char string[ MAXPNSTR + 1 ];
1108
1109    if ( c > MAXPNSTR )
1110        c = MAXPNSTR;
1111    strncpy( string, s, c );
1112    string[ c ] = '\0';
1113    printf( "%s", string );
1114}
1115