1330449Seadler/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
425265Sfsmp * Copyright (c) 1996, by Steve Passe
525265Sfsmp * All rights reserved.
625265Sfsmp *
725265Sfsmp * Redistribution and use in source and binary forms, with or without
825265Sfsmp * modification, are permitted provided that the following conditions
925265Sfsmp * are met:
1025265Sfsmp * 1. Redistributions of source code must retain the above copyright
1125265Sfsmp *    notice, this list of conditions and the following disclaimer.
1225265Sfsmp * 2. The name of the developer may NOT be used to endorse or promote products
1325265Sfsmp *    derived from this software without specific prior written permission.
1425265Sfsmp *
1525265Sfsmp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1625265Sfsmp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1725265Sfsmp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1825265Sfsmp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1925265Sfsmp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2025265Sfsmp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2125265Sfsmp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2225265Sfsmp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2325265Sfsmp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2425265Sfsmp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2525265Sfsmp * SUCH DAMAGE.
2625265Sfsmp */
2725265Sfsmp
2825265Sfsmp/*
2925265Sfsmp * mptable.c
3025265Sfsmp */
3125265Sfsmp
3229850Scharnier#ifndef lint
3329850Scharnierstatic const char rcsid[] =
3450479Speter  "$FreeBSD: stable/11/usr.sbin/mptable/mptable.c 330449 2018-03-05 07:26:05Z eadler $";
3529850Scharnier#endif /* not lint */
3629850Scharnier
3725265Sfsmp/*
3825265Sfsmp * this will cause the raw mp table to be dumped to /tmp/mpdump
3925265Sfsmp *
4025265Sfsmp#define RAW_DUMP
4125265Sfsmp */
4225265Sfsmp
4325265Sfsmp#define MP_SIG			0x5f504d5f	/* _MP_ */
4425265Sfsmp#define EXTENDED_PROCESSING_READY
4525265Sfsmp#define OEM_PROCESSING_READY_NOT
4625265Sfsmp
47244530Sneel#include <sys/param.h>
48259229Sjhb#include <sys/mman.h>
49259229Sjhb#include <x86/mptable.h>
5029850Scharnier#include <err.h>
5129850Scharnier#include <fcntl.h>
5269793Sobrien#include <paths.h>
53259229Sjhb#include <stdint.h>
5425265Sfsmp#include <stdio.h>
5529850Scharnier#include <stdlib.h>
5629850Scharnier#include <string.h>
5725265Sfsmp#include <unistd.h>
5825265Sfsmp
5925265Sfsmp#define SEP_LINE \
6025265Sfsmp"\n-------------------------------------------------------------------------------\n"
6125265Sfsmp
6225265Sfsmp#define SEP_LINE2 \
6325265Sfsmp"\n===============================================================================\n"
6425265Sfsmp
6525265Sfsmp/* EBDA is @ 40:0e in real-mode terms */
6625265Sfsmp#define EBDA_POINTER		0x040e		/* location of EBDA pointer */
6725265Sfsmp
6825265Sfsmp/* CMOS 'top of mem' is @ 40:13 in real-mode terms */
6925265Sfsmp#define TOPOFMEM_POINTER	0x0413		/* BIOS: base memory size */
7025265Sfsmp
7125265Sfsmp#define DEFAULT_TOPOFMEM	0xa0000
7225265Sfsmp
7325265Sfsmp#define BIOS_BASE		0xf0000
7425265Sfsmp#define BIOS_BASE2		0xe0000
7525265Sfsmp#define BIOS_SIZE		0x10000
7625265Sfsmp#define ONE_KBYTE		1024
7725265Sfsmp
7825265Sfsmp#define GROPE_AREA1		0x80000
7925265Sfsmp#define GROPE_AREA2		0x90000
8025265Sfsmp#define GROPE_SIZE		0x10000
8125265Sfsmp
8225265Sfsmp#define MAXPNSTR		132
8325265Sfsmp
8425265Sfsmptypedef struct BUSTYPENAME {
8525265Sfsmp    u_char	type;
8625265Sfsmp    char	name[ 7 ];
8725265Sfsmp} busTypeName;
8825265Sfsmp
89227224Sedstatic const busTypeName busTypeTable[] =
9025265Sfsmp{
9125265Sfsmp    { CBUS,		"CBUS"   },
9225265Sfsmp    { CBUSII,		"CBUSII" },
9325265Sfsmp    { EISA,		"EISA"   },
9425265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
9525265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
9625265Sfsmp    { ISA,		"ISA"    },
9725265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
9825265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
9925265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
10025265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
10125265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
10225265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
10325265Sfsmp    { PCI,		"PCI"    },
10425265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
10525265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
10625265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
10725265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
10825265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    },
10925265Sfsmp    { UNKNOWN_BUSTYPE,	"---"    }
11025265Sfsmp};
11125265Sfsmp
112227224Sedstatic const char *whereStrings[] = {
11325265Sfsmp    "Extended BIOS Data Area",
11425265Sfsmp    "BIOS top of memory",
11525265Sfsmp    "Default top of memory",
11625265Sfsmp    "BIOS",
11725265Sfsmp    "Extended BIOS",
11825265Sfsmp    "GROPE AREA #1",
11925265Sfsmp    "GROPE AREA #2"
12025265Sfsmp};
12125265Sfsmp
122120590Speterstatic void apic_probe( u_int32_t* paddr, int* where );
12325265Sfsmp
12425265Sfsmpstatic void MPConfigDefault( int featureByte );
12525265Sfsmp
126259229Sjhbstatic void MPFloatingPointer( u_int32_t paddr, int where, mpfps_t* mpfpsp );
127120590Speterstatic void MPConfigTableHeader( u_int32_t pap );
12825265Sfsmp
129120590Speterstatic void seekEntry( u_int32_t addr );
13025265Sfsmpstatic void readEntry( void* entry, int size );
131259229Sjhbstatic void *mapEntry( u_int32_t addr, int size );
13225265Sfsmp
133259229Sjhbstatic void processorEntry( proc_entry_ptr entry );
134259229Sjhbstatic void busEntry( bus_entry_ptr entry );
135259229Sjhbstatic void ioApicEntry( io_apic_entry_ptr entry );
136259229Sjhbstatic void intEntry( int_entry_ptr entry );
13725265Sfsmp
138259229Sjhbstatic void sasEntry( sas_entry_ptr entry );
139259229Sjhbstatic void bhdEntry( bhd_entry_ptr entry );
140259229Sjhbstatic void cbasmEntry( cbasm_entry_ptr entry );
14125265Sfsmp
14225265Sfsmpstatic void doDmesg( void );
14325265Sfsmpstatic void pnstr( char* s, int c );
14425265Sfsmp
14525265Sfsmp/* global data */
146227224Sedstatic int	pfd;		/* physical /dev/mem fd */
14725265Sfsmp
148244526Sneelstatic int	busses[256];
149244526Sneelstatic int	apics[256];
15025265Sfsmp
151227224Sedstatic int	ncpu;
152227224Sedstatic int	nbus;
153227224Sedstatic int	napic;
154227224Sedstatic int	nintr;
15525265Sfsmp
156227224Sedstatic int	dmesg;
157227224Sedstatic int	grope;
158227224Sedstatic int	verbose;
15925265Sfsmp
16025265Sfsmpstatic void
16125265Sfsmpusage( void )
16225265Sfsmp{
16329850Scharnier    fprintf( stderr, "usage: mptable [-dmesg] [-verbose] [-grope] [-help]\n" );
16425265Sfsmp    exit( 0 );
16525265Sfsmp}
16625265Sfsmp
16725265Sfsmp/*
16825265Sfsmp *
16925265Sfsmp */
17025265Sfsmpint
17125265Sfsmpmain( int argc, char *argv[] )
17225265Sfsmp{
173120590Speter    u_int32_t	paddr;
17425265Sfsmp    int		where;
17525265Sfsmp    mpfps_t	mpfps;
17625265Sfsmp    int		defaultConfig;
17725265Sfsmp
17825265Sfsmp    int		ch;
17925265Sfsmp
18025265Sfsmp    /* announce ourselves */
18125265Sfsmp    puts( SEP_LINE2 );
18225265Sfsmp
183141385Sobrien    printf( "MPTable\n" );
18425265Sfsmp
18547442Simp    while ((ch = getopt(argc, argv, "d:g:h:v:")) != -1) {
18625265Sfsmp	switch(ch) {
18725265Sfsmp	case 'd':
18825265Sfsmp	    if ( strcmp( optarg, "mesg") == 0 )
18925265Sfsmp	        dmesg = 1;
19025265Sfsmp	    else
19125265Sfsmp	        dmesg = 0;
19225265Sfsmp	    break;
19325265Sfsmp	case 'h':
19425265Sfsmp	    if ( strcmp( optarg, "elp") == 0 )
19525265Sfsmp	        usage();
19625265Sfsmp	    break;
19725265Sfsmp	case 'g':
19825326Sfsmp	    if ( strcmp( optarg, "rope") == 0 )
19925265Sfsmp	        grope = 1;
20025265Sfsmp	    break;
20125265Sfsmp	case 'v':
20225265Sfsmp	    if ( strcmp( optarg, "erbose") == 0 )
20325265Sfsmp	        verbose = 1;
20425265Sfsmp	    break;
20525265Sfsmp	default:
20625265Sfsmp	    usage();
20725265Sfsmp	}
20825265Sfsmp	argc -= optind;
20925265Sfsmp	argv += optind;
21025265Sfsmp	optreset = 1;
21125265Sfsmp	optind = 0;
21225265Sfsmp    }
21325265Sfsmp
21425265Sfsmp    /* open physical memory for access to MP structures */
21569793Sobrien    if ( (pfd = open( _PATH_MEM, O_RDONLY )) < 0 )
21629850Scharnier        err( 1, "mem open" );
21725265Sfsmp
21825265Sfsmp    /* probe for MP structures */
21925265Sfsmp    apic_probe( &paddr, &where );
22025265Sfsmp    if ( where <= 0 ) {
22125265Sfsmp        fprintf( stderr, "\n MP FPS NOT found,\n" );
222289767Sbapt        if (!grope)
223289767Sbapt            fprintf( stderr, " suggest trying -grope option!!!\n\n" );
22425265Sfsmp        return 1;
22525265Sfsmp    }
22625265Sfsmp
22725265Sfsmp    if ( verbose )
22825265Sfsmp        printf( "\n MP FPS found in %s @ physical addr: 0x%08x\n",
22925265Sfsmp	      whereStrings[ where - 1 ], paddr );
23025265Sfsmp
23125265Sfsmp    puts( SEP_LINE );
23225265Sfsmp
23325265Sfsmp    /* analyze the MP Floating Pointer Structure */
23425265Sfsmp    MPFloatingPointer( paddr, where, &mpfps );
23525265Sfsmp
23625265Sfsmp    puts( SEP_LINE );
23725265Sfsmp
23825265Sfsmp    /* check whether an MP config table exists */
239259229Sjhb    if ( (defaultConfig = mpfps->config_type) )
24025265Sfsmp        MPConfigDefault( defaultConfig );
24125265Sfsmp    else
242259229Sjhb	MPConfigTableHeader( mpfps->pap );
24325265Sfsmp
24425265Sfsmp    /* do a dmesg output */
24525265Sfsmp    if ( dmesg )
24625265Sfsmp        doDmesg();
24725265Sfsmp
24825265Sfsmp    puts( SEP_LINE2 );
24925265Sfsmp
25025265Sfsmp    return 0;
25125265Sfsmp}
25225265Sfsmp
25325265Sfsmp
25425265Sfsmp/*
25525265Sfsmp * set PHYSICAL address of MP floating pointer structure
25625265Sfsmp */
25725265Sfsmp#define NEXT(X)		((X) += 4)
25825265Sfsmpstatic void
259120590Speterapic_probe( u_int32_t* paddr, int* where )
26025265Sfsmp{
26125265Sfsmp    /*
26225265Sfsmp     * c rewrite of apic_probe() by Jack F. Vogel
26325265Sfsmp     */
26425265Sfsmp
26525265Sfsmp    int		x;
26625265Sfsmp    u_short	segment;
267120590Speter    u_int32_t	target;
26825265Sfsmp    u_int	buffer[ BIOS_SIZE / sizeof( int ) ];
26925265Sfsmp
27025265Sfsmp    if ( verbose )
27125265Sfsmp        printf( "\n" );
27225265Sfsmp
27325265Sfsmp    /* search Extended Bios Data Area, if present */
27425265Sfsmp    if ( verbose )
27525265Sfsmp        printf( " looking for EBDA pointer @ 0x%04x, ", EBDA_POINTER );
276120590Speter    seekEntry( (u_int32_t)EBDA_POINTER );
27725265Sfsmp    readEntry( &segment, 2 );
27825265Sfsmp    if ( segment ) {		    /* search EBDA */
279120590Speter        target = (u_int32_t)segment << 4;
28025265Sfsmp	if ( verbose )
28125265Sfsmp	    printf( "found, searching EBDA @ 0x%08x\n", target );
28225265Sfsmp        seekEntry( target );
28325265Sfsmp        readEntry( buffer, ONE_KBYTE );
28425265Sfsmp
285120590Speter        for ( x = 0; x < ONE_KBYTE / (int)sizeof ( unsigned int ); NEXT(x) ) {
28625265Sfsmp            if ( buffer[ x ] == MP_SIG ) {
28725265Sfsmp                *where = 1;
28825265Sfsmp                *paddr = (x * sizeof( unsigned int )) + target;
28925265Sfsmp                return;
29025265Sfsmp            }
29125265Sfsmp        }
29225265Sfsmp    }
29325265Sfsmp    else {
29425265Sfsmp	if ( verbose )
29525265Sfsmp	    printf( "NOT found\n" );
29625265Sfsmp    }
29725265Sfsmp
29825265Sfsmp    /* read CMOS for real top of mem */
299120590Speter    seekEntry( (u_int32_t)TOPOFMEM_POINTER );
30025265Sfsmp    readEntry( &segment, 2 );
30125265Sfsmp    --segment;						/* less ONE_KBYTE */
30225265Sfsmp    target = segment * 1024;
30325265Sfsmp    if ( verbose )
30425265Sfsmp        printf( " searching CMOS 'top of mem' @ 0x%08x (%dK)\n",
30525265Sfsmp	        target, segment );
30625265Sfsmp    seekEntry( target );
30725265Sfsmp    readEntry( buffer, ONE_KBYTE );
30825265Sfsmp
309120590Speter    for ( x = 0; x < ONE_KBYTE / (int)sizeof ( unsigned int ); NEXT(x) ) {
31025265Sfsmp        if ( buffer[ x ] == MP_SIG ) {
31125265Sfsmp            *where = 2;
31225265Sfsmp            *paddr = (x * sizeof( unsigned int )) + target;
31325265Sfsmp            return;
31425265Sfsmp        }
31525265Sfsmp    }
31625265Sfsmp
31725265Sfsmp    /* we don't necessarily believe CMOS, check base of the last 1K of 640K */
31825265Sfsmp    if ( target != (DEFAULT_TOPOFMEM - 1024)) {
31925265Sfsmp	target = (DEFAULT_TOPOFMEM - 1024);
32025265Sfsmp	if ( verbose )
32125265Sfsmp	    printf( " searching default 'top of mem' @ 0x%08x (%dK)\n",
32225265Sfsmp		    target, (target / 1024) );
32325265Sfsmp	seekEntry( target );
32425265Sfsmp	readEntry( buffer, ONE_KBYTE );
32525265Sfsmp
326120590Speter	for ( x = 0; x < ONE_KBYTE / (int)sizeof ( unsigned int ); NEXT(x) ) {
32725265Sfsmp	    if ( buffer[ x ] == MP_SIG ) {
32825265Sfsmp		*where = 3;
32925265Sfsmp		*paddr = (x * sizeof( unsigned int )) + target;
33025265Sfsmp		return;
33125265Sfsmp	    }
33225265Sfsmp	}
33325265Sfsmp    }
33425265Sfsmp
33525265Sfsmp    /* search the BIOS */
33625265Sfsmp    if ( verbose )
33725265Sfsmp        printf( " searching BIOS @ 0x%08x\n", BIOS_BASE );
33825265Sfsmp    seekEntry( BIOS_BASE );
33925265Sfsmp    readEntry( buffer, BIOS_SIZE );
34025265Sfsmp
341120590Speter    for ( x = 0; x < BIOS_SIZE / (int)sizeof( unsigned int ); NEXT(x) ) {
34225265Sfsmp        if ( buffer[ x ] == MP_SIG ) {
34325265Sfsmp            *where = 4;
34425265Sfsmp            *paddr = (x * sizeof( unsigned int )) + BIOS_BASE;
34525265Sfsmp            return;
34625265Sfsmp        }
34725265Sfsmp    }
34825265Sfsmp
34925265Sfsmp    /* search the extended BIOS */
35025265Sfsmp    if ( verbose )
35125265Sfsmp        printf( " searching extended BIOS @ 0x%08x\n", BIOS_BASE2 );
35225265Sfsmp    seekEntry( BIOS_BASE2 );
35325265Sfsmp    readEntry( buffer, BIOS_SIZE );
35425265Sfsmp
355120590Speter    for ( x = 0; x < BIOS_SIZE / (int)sizeof( unsigned int ); NEXT(x) ) {
35625265Sfsmp        if ( buffer[ x ] == MP_SIG ) {
35725265Sfsmp            *where = 5;
35825265Sfsmp            *paddr = (x * sizeof( unsigned int )) + BIOS_BASE2;
35925265Sfsmp            return;
36025265Sfsmp        }
36125265Sfsmp    }
36225265Sfsmp
36325265Sfsmp    if ( grope ) {
36425265Sfsmp	/* search additional memory */
36525265Sfsmp	target = GROPE_AREA1;
36625265Sfsmp	if ( verbose )
36725265Sfsmp	    printf( " groping memory @ 0x%08x\n", target );
36825265Sfsmp	seekEntry( target );
36925265Sfsmp	readEntry( buffer, GROPE_SIZE );
37025265Sfsmp
371120590Speter	for ( x = 0; x < GROPE_SIZE / (int)sizeof( unsigned int ); NEXT(x) ) {
37225265Sfsmp	    if ( buffer[ x ] == MP_SIG ) {
37325265Sfsmp		*where = 6;
37425265Sfsmp		*paddr = (x * sizeof( unsigned int )) + GROPE_AREA1;
37525265Sfsmp		return;
37625265Sfsmp	    }
37725265Sfsmp	}
37825265Sfsmp
37925265Sfsmp	target = GROPE_AREA2;
38025265Sfsmp	if ( verbose )
38125265Sfsmp	    printf( " groping memory @ 0x%08x\n", target );
38225265Sfsmp	seekEntry( target );
38325265Sfsmp	readEntry( buffer, GROPE_SIZE );
38425265Sfsmp
385120590Speter	for ( x = 0; x < GROPE_SIZE / (int)sizeof( unsigned int ); NEXT(x) ) {
38625265Sfsmp	    if ( buffer[ x ] == MP_SIG ) {
38725265Sfsmp		*where = 7;
38825265Sfsmp		*paddr = (x * sizeof( unsigned int )) + GROPE_AREA2;
38925265Sfsmp		return;
39025265Sfsmp	    }
39125265Sfsmp	}
39225265Sfsmp    }
39325265Sfsmp
39425265Sfsmp    *where = 0;
395120590Speter    *paddr = (u_int32_t)0;
39625265Sfsmp}
39725265Sfsmp
39825265Sfsmp
39925265Sfsmp/*
40025265Sfsmp *
40125265Sfsmp */
40229850Scharnierstatic void
403259229SjhbMPFloatingPointer( u_int32_t paddr, int where, mpfps_t* mpfpsp )
40425265Sfsmp{
405259229Sjhb    mpfps_t mpfps;
406259229Sjhb
407259229Sjhb    /* map in mpfps structure*/
408262978Sjhb    *mpfpsp = mpfps = mapEntry( paddr, sizeof( *mpfps ) );
40925265Sfsmp
41025265Sfsmp    /* show its contents */
41125265Sfsmp    printf( "MP Floating Pointer Structure:\n\n" );
41225265Sfsmp
41329850Scharnier    printf( "  location:\t\t\t" );
41425265Sfsmp    switch ( where )
41525265Sfsmp    {
41625265Sfsmp    case 1:
41725265Sfsmp	printf( "EBDA\n" );
41825265Sfsmp	break;
41925265Sfsmp    case 2:
42025265Sfsmp	printf( "BIOS base memory\n" );
42125265Sfsmp	break;
42225265Sfsmp    case 3:
42325265Sfsmp	printf( "DEFAULT base memory (639K)\n" );
42425265Sfsmp	break;
42525265Sfsmp    case 4:
42625265Sfsmp	printf( "BIOS\n" );
42725265Sfsmp	break;
42825265Sfsmp    case 5:
42925265Sfsmp	printf( "Extended BIOS\n" );
43025265Sfsmp	break;
43125265Sfsmp
43225265Sfsmp    case 0:
43325265Sfsmp	printf( "NOT found!\n" );
43425265Sfsmp	exit( 1 );
43525265Sfsmp    default:
43625265Sfsmp	printf( "BOGUS!\n" );
43725265Sfsmp	exit( 1 );
43825265Sfsmp    }
43925265Sfsmp    printf( "  physical address:\t\t0x%08x\n", paddr );
44025265Sfsmp
44125265Sfsmp    printf( "  signature:\t\t\t'" );
44225265Sfsmp    pnstr( mpfps->signature, 4 );
44325265Sfsmp    printf( "'\n" );
44425265Sfsmp
44525265Sfsmp    printf( "  length:\t\t\t%d bytes\n", mpfps->length * 16 );
44625265Sfsmp    printf( "  version:\t\t\t1.%1d\n", mpfps->spec_rev );
44725265Sfsmp    printf( "  checksum:\t\t\t0x%02x\n", mpfps->checksum );
44825265Sfsmp
44925265Sfsmp    /* bits 0:6 are RESERVED */
45025265Sfsmp    if ( mpfps->mpfb2 & 0x7f ) {
45129850Scharnier        printf( " warning, MP feature byte 2: 0x%02x\n", mpfps->mpfb2 );
45225265Sfsmp    }
45325265Sfsmp
45425265Sfsmp    /* bit 7 is IMCRP */
455259229Sjhb    printf( "  mode:\t\t\t\t%s\n", (mpfps->mpfb2 & MPFB2_IMCR_PRESENT) ?
45625265Sfsmp            "PIC" : "Virtual Wire" );
45725265Sfsmp
45825265Sfsmp    /* MP feature bytes 3-5 are expected to be ZERO */
45925265Sfsmp    if ( mpfps->mpfb3 )
46025265Sfsmp        printf( " warning, MP feature byte 3 NONZERO!\n" );
46125265Sfsmp    if ( mpfps->mpfb4 )
46225265Sfsmp        printf( " warning, MP feature byte 4 NONZERO!\n" );
46325265Sfsmp    if ( mpfps->mpfb5 )
46425265Sfsmp        printf( " warning, MP feature byte 5 NONZERO!\n" );
46525265Sfsmp}
46625265Sfsmp
46725265Sfsmp
46825265Sfsmp/*
46925265Sfsmp *
47025265Sfsmp */
47125265Sfsmpstatic void
47225265SfsmpMPConfigDefault( int featureByte )
47325265Sfsmp{
47425265Sfsmp    printf( "  MP default config type: %d\n\n", featureByte );
47525265Sfsmp    switch ( featureByte ) {
47625265Sfsmp    case 1:
47725265Sfsmp	printf( "   bus: ISA, APIC: 82489DX\n" );
47825265Sfsmp	break;
47925265Sfsmp    case 2:
48025265Sfsmp	printf( "   bus: EISA, APIC: 82489DX\n" );
48125265Sfsmp	break;
48225265Sfsmp    case 3:
48325265Sfsmp	printf( "   bus: EISA, APIC: 82489DX\n" );
48425265Sfsmp	break;
48525265Sfsmp    case 4:
48625265Sfsmp	printf( "   bus: MCA, APIC: 82489DX\n" );
48725265Sfsmp	break;
48825265Sfsmp    case 5:
48925265Sfsmp	printf( "   bus: ISA+PCI, APIC: Integrated\n" );
49025265Sfsmp	break;
49125265Sfsmp    case 6:
49225265Sfsmp	printf( "   bus: EISA+PCI, APIC: Integrated\n" );
49325265Sfsmp	break;
49425265Sfsmp    case 7:
49525265Sfsmp	printf( "   bus: MCA+PCI, APIC: Integrated\n" );
49625265Sfsmp	break;
49725265Sfsmp    default:
49825265Sfsmp	printf( "   future type\n" );
49925265Sfsmp	break;
50025265Sfsmp    }
50125265Sfsmp
50225265Sfsmp    switch ( featureByte ) {
50325265Sfsmp    case 1:
50425265Sfsmp    case 2:
50525265Sfsmp    case 3:
50625265Sfsmp    case 4:
50725265Sfsmp	nbus = 1;
50825265Sfsmp	break;
50925265Sfsmp    case 5:
51025265Sfsmp    case 6:
51125265Sfsmp    case 7:
51225265Sfsmp	nbus = 2;
51325265Sfsmp	break;
51425265Sfsmp    default:
51525265Sfsmp	printf( "   future type\n" );
51625265Sfsmp	break;
51725265Sfsmp    }
51825265Sfsmp
51925265Sfsmp    ncpu = 2;
52025265Sfsmp    napic = 1;
52125265Sfsmp    nintr = 16;
52225265Sfsmp}
52325265Sfsmp
52425265Sfsmp
52525265Sfsmp/*
52625265Sfsmp *
52725265Sfsmp */
52825265Sfsmpstatic void
529120590SpeterMPConfigTableHeader( u_int32_t pap )
53025265Sfsmp{
53125265Sfsmp    mpcth_t	cth;
53229850Scharnier    int		x;
53371209Speter    int		totalSize;
534259229Sjhb    int		c;
53571209Speter    int		oldtype, entrytype;
536259229Sjhb    u_int8_t	*entry;
53725265Sfsmp
53825265Sfsmp    if ( pap == 0 ) {
53925265Sfsmp	printf( "MP Configuration Table Header MISSING!\n" );
54025265Sfsmp        exit( 1 );
54125265Sfsmp    }
54225265Sfsmp
543259229Sjhb    /* map in cth structure */
544259229Sjhb    cth = mapEntry( pap, sizeof( *cth ) );
54525265Sfsmp
54625265Sfsmp    printf( "MP Config Table Header:\n\n" );
54725265Sfsmp
54825265Sfsmp    printf( "  physical address:\t\t0x%08x\n", pap );
54925265Sfsmp
55025265Sfsmp    printf( "  signature:\t\t\t'" );
551259229Sjhb    pnstr( cth->signature, 4 );
55225265Sfsmp    printf( "'\n" );
55325265Sfsmp
554259229Sjhb    printf( "  base table length:\t\t%d\n", cth->base_table_length );
55525265Sfsmp
556259229Sjhb    printf( "  version:\t\t\t1.%1d\n", cth->spec_rev );
557259229Sjhb    printf( "  checksum:\t\t\t0x%02x\n", cth->checksum );
55825265Sfsmp
55925265Sfsmp    printf( "  OEM ID:\t\t\t'" );
560259229Sjhb    pnstr( cth->oem_id, 8 );
56125265Sfsmp    printf( "'\n" );
56225265Sfsmp
56325265Sfsmp    printf( "  Product ID:\t\t\t'" );
564259229Sjhb    pnstr( cth->product_id, 12 );
56525265Sfsmp    printf( "'\n" );
56625265Sfsmp
567259229Sjhb    printf( "  OEM table pointer:\t\t0x%08x\n", cth->oem_table_pointer );
568259229Sjhb    printf( "  OEM table size:\t\t%d\n", cth->oem_table_size );
56925265Sfsmp
570259229Sjhb    printf( "  entry count:\t\t\t%d\n", cth->entry_count );
57125265Sfsmp
572259229Sjhb    printf( "  local APIC address:\t\t0x%08x\n", cth->apic_address );
57325265Sfsmp
574259229Sjhb    printf( "  extended table length:\t%d\n", cth->extended_table_length );
575259229Sjhb    printf( "  extended table checksum:\t%d\n", cth->extended_table_checksum );
57625265Sfsmp
577259229Sjhb    totalSize = cth->base_table_length - sizeof( struct MPCTH );
57825265Sfsmp
57925265Sfsmp    puts( SEP_LINE );
58025265Sfsmp
58125265Sfsmp    printf( "MP Config Base Table Entries:\n\n" );
58225265Sfsmp
583244530Sneel    /* initialize tables */
584244530Sneel    for (x = 0; x < (int)nitems(busses); x++)
585244530Sneel	busses[x] = 0xff;
58625265Sfsmp
587244530Sneel    for (x = 0; x < (int)nitems(apics); x++)
588244530Sneel	apics[x] = 0xff;
589244530Sneel
59025265Sfsmp    ncpu = 0;
59125265Sfsmp    nbus = 0;
59225265Sfsmp    napic = 0;
59325265Sfsmp    nintr = 0;
59425265Sfsmp
59571209Speter    oldtype = -1;
596259229Sjhb    entry = mapEntry(pap + sizeof(*cth), cth->base_table_length);
597259229Sjhb    for (c = cth->entry_count; c; c--) {
598259229Sjhb	entrytype = *entry;
59971209Speter	if (entrytype != oldtype)
60071209Speter	    printf("--\n");
60171209Speter	if (entrytype < oldtype)
60271209Speter	    printf("MPTABLE OUT OF ORDER!\n");
60371209Speter	switch (entrytype) {
604259229Sjhb	case MPCT_ENTRY_PROCESSOR:
605259229Sjhb	    if (oldtype != MPCT_ENTRY_PROCESSOR)
60671209Speter		printf( "Processors:\tAPIC ID\tVersion\tState"
60771209Speter			"\t\tFamily\tModel\tStep\tFlags\n" );
608259229Sjhb	    processorEntry((proc_entry_ptr)entry);
609259229Sjhb	    entry += sizeof(struct PROCENTRY);
61071209Speter	    break;
61125265Sfsmp
612259229Sjhb	case MPCT_ENTRY_BUS:
613259229Sjhb	    if (oldtype != MPCT_ENTRY_BUS)
61471209Speter		printf( "Bus:\t\tBus ID\tType\n" );
615259229Sjhb	    busEntry((bus_entry_ptr)entry);
616259229Sjhb	    entry += sizeof(struct BUSENTRY);
61771209Speter	    break;
61825265Sfsmp
619259229Sjhb	case MPCT_ENTRY_IOAPIC:
620259229Sjhb	    if (oldtype != MPCT_ENTRY_IOAPIC)
62171209Speter		printf( "I/O APICs:\tAPIC ID\tVersion\tState\t\tAddress\n" );
622259229Sjhb	    ioApicEntry((io_apic_entry_ptr)entry);
623259229Sjhb	    entry += sizeof(struct IOAPICENTRY);
62471209Speter	    break;
62525265Sfsmp
626259229Sjhb	case MPCT_ENTRY_INT:
627259229Sjhb	    if (oldtype != MPCT_ENTRY_INT)
62871209Speter		printf( "I/O Ints:\tType\tPolarity    Trigger\tBus ID\t IRQ\tAPIC ID\tPIN#\n" );
629259229Sjhb	    intEntry((int_entry_ptr)entry);
630259229Sjhb	    entry += sizeof(struct INTENTRY);
63171209Speter	    break;
63225265Sfsmp
633259229Sjhb	case MPCT_ENTRY_LOCAL_INT:
634259229Sjhb	    if (oldtype != MPCT_ENTRY_LOCAL_INT)
63571209Speter		printf( "Local Ints:\tType\tPolarity    Trigger\tBus ID\t IRQ\tAPIC ID\tPIN#\n" );
636259229Sjhb	    intEntry((int_entry_ptr)entry);
637259229Sjhb	    entry += sizeof(struct INTENTRY);
63871209Speter	    break;
63971209Speter
64071209Speter	default:
64171209Speter	    printf("MPTABLE HOSED! record type = %d\n", entrytype);
64271209Speter	    exit(1);
64371209Speter	}
644259229Sjhb	oldtype = entrytype;
64525265Sfsmp    }
64625265Sfsmp
64725265Sfsmp
64825265Sfsmp#if defined( EXTENDED_PROCESSING_READY )
64925265Sfsmp    /* process any extended data */
650259229Sjhb    if ( cth->extended_table_length ) {
651259229Sjhb	ext_entry_ptr ext_entry, end;
652259229Sjhb
65325265Sfsmp	puts( SEP_LINE );
65425265Sfsmp
65525265Sfsmp        printf( "MP Config Extended Table Entries:\n\n" );
65625265Sfsmp
657259229Sjhb	ext_entry = mapEntry(pap + cth->base_table_length,
658259229Sjhb	    cth->extended_table_length);
659259229Sjhb	end = (ext_entry_ptr)((char *)ext_entry + cth->extended_table_length);
660259229Sjhb	while (ext_entry < end) {
661259229Sjhb	    switch (ext_entry->type) {
662259229Sjhb            case MPCT_EXTENTRY_SAS:
663259229Sjhb		sasEntry((sas_entry_ptr)ext_entry);
66425265Sfsmp		break;
665259229Sjhb            case MPCT_EXTENTRY_BHD:
666259229Sjhb		bhdEntry((bhd_entry_ptr)ext_entry);
66725265Sfsmp		break;
668259229Sjhb            case MPCT_EXTENTRY_CBASM:
669259229Sjhb		cbasmEntry((cbasm_entry_ptr)ext_entry);
67025265Sfsmp		break;
67125265Sfsmp            default:
67225265Sfsmp                printf( "Extended Table HOSED!\n" );
67325265Sfsmp                exit( 1 );
67425265Sfsmp            }
67525265Sfsmp
676259229Sjhb	    ext_entry = (ext_entry_ptr)((char *)ext_entry + ext_entry->length);
67725265Sfsmp        }
67825265Sfsmp    }
67925265Sfsmp#endif  /* EXTENDED_PROCESSING_READY */
68025265Sfsmp
68125265Sfsmp    /* process any OEM data */
682259229Sjhb    if ( cth->oem_table_pointer && (cth->oem_table_size > 0) ) {
68325265Sfsmp#if defined( OEM_PROCESSING_READY )
68425265Sfsmp# error your on your own here!
685259229Sjhb        /* map in oem table structure */
686259229Sjhb	oemdata = mapEntry( cth->oem_table_pointer, cth->oem_table_size);
68725265Sfsmp
68825265Sfsmp        /** process it */
68925265Sfsmp#else
69025265Sfsmp        printf( "\nyou need to modify the source to handle OEM data!\n\n" );
69125265Sfsmp#endif  /* OEM_PROCESSING_READY */
69225265Sfsmp    }
69325265Sfsmp
69425265Sfsmp    fflush( stdout );
69525265Sfsmp
69625265Sfsmp#if defined( RAW_DUMP )
69725265Sfsmp{
69825265Sfsmp    int		ofd;
699259229Sjhb    void	*dumpbuf;
70025265Sfsmp
701229466Spjd    ofd = open( "/tmp/mpdump", O_CREAT | O_RDWR, 0666 );
702259229Sjhb
703259229Sjhb    dumpbuf = mapEntry( paddr, 1024 );
70425265Sfsmp    write( ofd, dumpbuf, 1024 );
70525265Sfsmp    close( ofd );
70625265Sfsmp}
70725265Sfsmp#endif /* RAW_DUMP */
70825265Sfsmp}
70925265Sfsmp
71025265Sfsmp
71125265Sfsmp/*
71225265Sfsmp *
71325265Sfsmp */
71425265Sfsmpstatic void
715120590SpeterseekEntry( u_int32_t addr )
71625265Sfsmp{
71729850Scharnier    if ( lseek( pfd, (off_t)addr, SEEK_SET ) < 0 )
71869793Sobrien        err( 1, "%s seek", _PATH_MEM );
71925265Sfsmp}
72025265Sfsmp
72125265Sfsmp
72225265Sfsmp/*
72325265Sfsmp *
72425265Sfsmp */
72525265Sfsmpstatic void
72625265SfsmpreadEntry( void* entry, int size )
72725265Sfsmp{
72829850Scharnier    if ( read( pfd, entry, size ) != size )
72929850Scharnier        err( 1, "readEntry" );
73025265Sfsmp}
73125265Sfsmp
732259229Sjhbstatic void *
733259229SjhbmapEntry( u_int32_t addr, int size )
734259229Sjhb{
735259229Sjhb    void	*p;
73625265Sfsmp
737259229Sjhb    p = mmap( NULL, size, PROT_READ, MAP_SHARED, pfd, addr );
738259229Sjhb    if (p == MAP_FAILED)
739259229Sjhb	err( 1, "mapEntry" );
740259229Sjhb    return (p);
741259229Sjhb}
742259229Sjhb
74325265Sfsmpstatic void
744259229SjhbprocessorEntry( proc_entry_ptr entry )
74525265Sfsmp{
74625265Sfsmp
74725265Sfsmp    /* count it */
74825265Sfsmp    ++ncpu;
74925265Sfsmp
750259229Sjhb    printf( "\t\t%2d", entry->apic_id );
751259229Sjhb    printf( "\t 0x%2x", entry->apic_version );
75225265Sfsmp
75325265Sfsmp    printf( "\t %s, %s",
754259229Sjhb            (entry->cpu_flags & PROCENTRY_FLAG_BP) ? "BSP" : "AP",
755259229Sjhb            (entry->cpu_flags & PROCENTRY_FLAG_EN) ? "usable" : "unusable" );
75625265Sfsmp
75725265Sfsmp    printf( "\t %d\t %d\t %d",
758259229Sjhb            (entry->cpu_signature >> 8) & 0x0f,
759259229Sjhb            (entry->cpu_signature >> 4) & 0x0f,
760259229Sjhb            entry->cpu_signature & 0x0f );
76125265Sfsmp
762259229Sjhb    printf( "\t 0x%04x\n", entry->feature_flags );
76325265Sfsmp}
76425265Sfsmp
76525265Sfsmp
76625265Sfsmp/*
76725265Sfsmp *
76825265Sfsmp */
76925265Sfsmpstatic int
77025265SfsmplookupBusType( char* name )
77125265Sfsmp{
77225265Sfsmp    int x;
77325265Sfsmp
77425265Sfsmp    for ( x = 0; x < MAX_BUSTYPE; ++x )
77525265Sfsmp	if ( strcmp( busTypeTable[ x ].name, name ) == 0 )
77625265Sfsmp	    return busTypeTable[ x ].type;
77725265Sfsmp
77825265Sfsmp    return UNKNOWN_BUSTYPE;
77925265Sfsmp}
78025265Sfsmp
78125265Sfsmp
78225265Sfsmpstatic void
783259229SjhbbusEntry( bus_entry_ptr entry )
78425265Sfsmp{
78525265Sfsmp    int		x;
78625265Sfsmp    char	name[ 8 ];
78725265Sfsmp    char	c;
78825265Sfsmp
78925265Sfsmp    /* count it */
79025265Sfsmp    ++nbus;
79125265Sfsmp
792259229Sjhb    printf( "\t\t%2d", entry->bus_id );
793259229Sjhb    printf( "\t " ); pnstr( entry->bus_type, 6 ); printf( "\n" );
79425265Sfsmp
79525265Sfsmp    for ( x = 0; x < 6; ++x ) {
796259229Sjhb	if ( (c = entry->bus_type[ x ]) == ' ' )
79725265Sfsmp	    break;
79825265Sfsmp	name[ x ] = c;
79925265Sfsmp    }
80025265Sfsmp    name[ x ] = '\0';
801259229Sjhb    busses[ entry->bus_id ] = lookupBusType( name );
80225265Sfsmp}
80325265Sfsmp
80425265Sfsmp
80525265Sfsmpstatic void
806259229SjhbioApicEntry( io_apic_entry_ptr entry )
80725265Sfsmp{
80825265Sfsmp
80925265Sfsmp    /* count it */
81025265Sfsmp    ++napic;
81125265Sfsmp
812259229Sjhb    printf( "\t\t%2d", entry->apic_id );
813259229Sjhb    printf( "\t 0x%02x", entry->apic_version );
81425265Sfsmp    printf( "\t %s",
815259229Sjhb            (entry->apic_flags & IOAPICENTRY_FLAG_EN) ? "usable" : "unusable" );
816259229Sjhb    printf( "\t\t 0x%x\n", entry->apic_address );
81725265Sfsmp
818259229Sjhb    apics[ entry->apic_id ] = entry->apic_id;
81925265Sfsmp}
82025265Sfsmp
82125265Sfsmp
822227224Sedstatic const char *intTypes[] = {
82325265Sfsmp    "INT", "NMI", "SMI", "ExtINT"
82425265Sfsmp};
82525265Sfsmp
826227224Sedstatic const char *polarityMode[] = {
82725265Sfsmp    "conforms", "active-hi", "reserved", "active-lo"
82825265Sfsmp};
829227224Sedstatic const char *triggerMode[] = {
83025265Sfsmp    "conforms", "edge", "reserved", "level"
83125265Sfsmp};
83225265Sfsmp
83325265Sfsmpstatic void
834259229SjhbintEntry( int_entry_ptr entry )
83525265Sfsmp{
83625265Sfsmp
83725265Sfsmp    /* count it */
838259229Sjhb    if ( entry->type == MPCT_ENTRY_INT )
83925265Sfsmp	++nintr;
84025265Sfsmp
841259229Sjhb    printf( "\t\t%s", intTypes[ entry->int_type ] );
84225265Sfsmp
843259229Sjhb    printf( "\t%9s", polarityMode[ entry->int_flags & INTENTRY_FLAGS_POLARITY ] );
844259229Sjhb    printf( "%12s", triggerMode[ (entry->int_flags & INTENTRY_FLAGS_TRIGGER) >> 2 ] );
84525265Sfsmp
846259229Sjhb    printf( "\t %5d", entry->src_bus_id );
847259229Sjhb    if ( busses[ entry->src_bus_id ] == PCI )
84825265Sfsmp	printf( "\t%2d:%c",
849259229Sjhb	        (entry->src_bus_irq >> 2) & 0x1f,
850259229Sjhb	        (entry->src_bus_irq & 0x03) + 'A' );
85125265Sfsmp    else
852259229Sjhb	printf( "\t %3d", entry->src_bus_irq );
853259229Sjhb    printf( "\t %6d", entry->dst_apic_id );
854259229Sjhb    printf( "\t %3d\n", entry->dst_apic_int );
85525265Sfsmp}
85625265Sfsmp
85725265Sfsmp
85825265Sfsmpstatic void
859259229SjhbsasEntry( sas_entry_ptr entry )
86025265Sfsmp{
86125265Sfsmp
862259229Sjhb    printf( "--\nSystem Address Space\n");
863259229Sjhb    printf( " bus ID: %d", entry->bus_id );
86425265Sfsmp    printf( " address type: " );
865259229Sjhb    switch ( entry->address_type ) {
866259229Sjhb    case SASENTRY_TYPE_IO:
86725265Sfsmp	printf( "I/O address\n" );
86825265Sfsmp	break;
869259229Sjhb    case SASENTRY_TYPE_MEMORY:
87025265Sfsmp	printf( "memory address\n" );
87125265Sfsmp	break;
872259229Sjhb    case SASENTRY_TYPE_PREFETCH:
87325265Sfsmp	printf( "prefetch address\n" );
87425265Sfsmp	break;
87525265Sfsmp    default:
87625265Sfsmp	printf( "UNKNOWN type\n" );
87725265Sfsmp	break;
87825265Sfsmp    }
87925265Sfsmp
880259229Sjhb    printf( " address base: 0x%jx\n", (uintmax_t)entry->address_base );
881259229Sjhb    printf( " address range: 0x%jx\n", (uintmax_t)entry->address_length );
88225265Sfsmp}
88325265Sfsmp
88425265Sfsmp
88525265Sfsmpstatic void
886259229SjhbbhdEntry( bhd_entry_ptr entry )
88725265Sfsmp{
88825265Sfsmp
889259229Sjhb    printf( "--\nBus Hierarchy\n" );
890259229Sjhb    printf( " bus ID: %d", entry->bus_id );
891259229Sjhb    printf( " bus info: 0x%02x", entry->bus_info );
892259229Sjhb    printf( " parent bus ID: %d\n", entry->parent_bus );
89325265Sfsmp}
89425265Sfsmp
89525265Sfsmp
89625265Sfsmpstatic void
897259229SjhbcbasmEntry( cbasm_entry_ptr entry )
89825265Sfsmp{
89925265Sfsmp
900259229Sjhb    printf( "--\nCompatibility Bus Address\n" );
901259229Sjhb    printf( " bus ID: %d", entry->bus_id );
902259229Sjhb    printf( " address modifier: %s\n",
903259229Sjhb	(entry->address_mod & CBASMENTRY_ADDRESS_MOD_SUBTRACT) ?
904259229Sjhb	"subtract" : "add" );
905259229Sjhb    printf( " predefined range: 0x%08x\n", entry->predefined_range );
90625265Sfsmp}
90725265Sfsmp
90825265Sfsmp
90925265Sfsmp/*
91025265Sfsmp * do a dmesg output
91125265Sfsmp */
91225265Sfsmpstatic void
91325265SfsmpdoDmesg( void )
91425265Sfsmp{
91525265Sfsmp    puts( SEP_LINE );
91625265Sfsmp
91725265Sfsmp    printf( "dmesg output:\n\n" );
91825265Sfsmp    fflush( stdout );
91925265Sfsmp    system( "dmesg" );
92025265Sfsmp}
92125265Sfsmp
92225265Sfsmp
92325265Sfsmp/*
92425265Sfsmp *
92525265Sfsmp */
92625265Sfsmpstatic void
92725265Sfsmppnstr( char* s, int c )
92825265Sfsmp{
92925265Sfsmp    char string[ MAXPNSTR + 1 ];
93025265Sfsmp
93125265Sfsmp    if ( c > MAXPNSTR )
93225265Sfsmp        c = MAXPNSTR;
93325265Sfsmp    strncpy( string, s, c );
93425265Sfsmp    string[ c ] = '\0';
93525265Sfsmp    printf( "%s", string );
93625265Sfsmp}
937