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