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