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