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