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