1 /* $Id$ 2 * 3 * COPYRIGHT: See COPYING in the top level directory 4 * PROJECT: ReactOS kernel 5 * FILE: hal/halx86/mp/mpconfig.c 6 * PURPOSE: 7 * PROGRAMMER: 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <hal.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS ******************************************************************/ 17 18 MP_FLOATING_POINTER* Mpf = NULL; 19 20 /* FUNCTIONS ****************************************************************/ 21 22 static UCHAR 23 MPChecksum(PUCHAR Base, 24 ULONG Size) 25 /* 26 * Checksum an MP configuration block 27 */ 28 { 29 UCHAR Sum = 0; 30 31 while (Size--) 32 Sum += *Base++; 33 34 return Sum; 35 } 36 37 static VOID 38 HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m) 39 { 40 DPRINT("Int: type %d, pol %d, trig %d, bus %d," 41 " IRQ %02x, APIC ID %x, APIC INT %02x\n", 42 m->IrqType, m->IrqFlag & 3, 43 (m->IrqFlag >> 2) & 3, m->SrcBusId, 44 m->SrcBusIrq, m->DstApicId, m->DstApicInt); 45 if (IRQCount > MAX_IRQ_SOURCE) 46 { 47 DPRINT1("Max # of irq sources exceeded!!\n"); 48 ASSERT(FALSE); 49 } 50 51 IRQMap[IRQCount] = *m; 52 IRQCount++; 53 } 54 55 PCHAR 56 HaliMPFamily(ULONG Family, 57 ULONG Model) 58 { 59 static CHAR str[64]; 60 static PCHAR CPUs[] = 61 { 62 "80486DX", "80486DX", 63 "80486SX", "80486DX/2 or 80487", 64 "80486SL", "Intel5X2(tm)", 65 "Unknown", "Unknown", 66 "80486DX/4" 67 }; 68 if (Family == 0x6) 69 return ("Pentium(tm) Pro"); 70 if (Family == 0x5) 71 return ("Pentium(tm)"); 72 if (Family == 0x0F && Model == 0x0F) 73 return("Special controller"); 74 if (Family == 0x0F && Model == 0x00) 75 return("Pentium 4(tm)"); 76 if (Family == 0x04 && Model < 9) 77 return CPUs[Model]; 78 sprintf(str, "Unknown CPU with family ID %ld and model ID %ld", Family, Model); 79 return str; 80 } 81 82 83 static VOID 84 HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m) 85 { 86 UCHAR ver; 87 88 if (!(m->CpuFlags & CPU_FLAG_ENABLED)) 89 return; 90 91 DPRINT("Processor #%d %s APIC version %d\n", 92 m->ApicId, 93 HaliMPFamily((m->FeatureFlags & CPU_FAMILY_MASK) >> 8, 94 (m->FeatureFlags & CPU_MODEL_MASK) >> 4), 95 m->ApicVersion); 96 97 if (m->FeatureFlags & (1 << 0)) 98 DPRINT(" Floating point unit present.\n"); 99 if (m->FeatureFlags & (1 << 7)) 100 DPRINT(" Machine Exception supported.\n"); 101 if (m->FeatureFlags & (1 << 8)) 102 DPRINT(" 64 bit compare & exchange supported.\n"); 103 if (m->FeatureFlags & (1 << 9)) 104 DPRINT(" Internal APIC present.\n"); 105 if (m->FeatureFlags & (1 << 11)) 106 DPRINT(" SEP present.\n"); 107 if (m->FeatureFlags & (1 << 12)) 108 DPRINT(" MTRR present.\n"); 109 if (m->FeatureFlags & (1 << 13)) 110 DPRINT(" PGE present.\n"); 111 if (m->FeatureFlags & (1 << 14)) 112 DPRINT(" MCA present.\n"); 113 if (m->FeatureFlags & (1 << 15)) 114 DPRINT(" CMOV present.\n"); 115 if (m->FeatureFlags & (1 << 16)) 116 DPRINT(" PAT present.\n"); 117 if (m->FeatureFlags & (1 << 17)) 118 DPRINT(" PSE present.\n"); 119 if (m->FeatureFlags & (1 << 18)) 120 DPRINT(" PSN present.\n"); 121 if (m->FeatureFlags & (1 << 19)) 122 DPRINT(" Cache Line Flush Instruction present.\n"); 123 /* 20 Reserved */ 124 if (m->FeatureFlags & (1 << 21)) 125 DPRINT(" Debug Trace and EMON Store present.\n"); 126 if (m->FeatureFlags & (1 << 22)) 127 DPRINT(" ACPI Thermal Throttle Registers present.\n"); 128 if (m->FeatureFlags & (1 << 23)) 129 DPRINT(" MMX present.\n"); 130 if (m->FeatureFlags & (1 << 24)) 131 DPRINT(" FXSR present.\n"); 132 if (m->FeatureFlags & (1 << 25)) 133 DPRINT(" XMM present.\n"); 134 if (m->FeatureFlags & (1 << 26)) 135 DPRINT(" Willamette New Instructions present.\n"); 136 if (m->FeatureFlags & (1 << 27)) 137 DPRINT(" Self Snoop present.\n"); 138 /* 28 Reserved */ 139 if (m->FeatureFlags & (1 << 29)) 140 DPRINT(" Thermal Monitor present.\n"); 141 /* 30, 31 Reserved */ 142 143 CPUMap[CPUCount].APICId = m->ApicId; 144 145 CPUMap[CPUCount].Flags = CPU_USABLE; 146 147 if (m->CpuFlags & CPU_FLAG_BSP) 148 { 149 DPRINT(" Bootup CPU\n"); 150 CPUMap[CPUCount].Flags |= CPU_BSP; 151 BootCPU = m->ApicId; 152 } 153 154 if (m->ApicId > MAX_CPU) 155 { 156 DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m->ApicId, MAX_CPU); 157 return; 158 } 159 ver = m->ApicVersion; 160 161 /* 162 * Validate version 163 */ 164 if (ver == 0x0) 165 { 166 DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->ApicId); 167 ver = 0x10; 168 } 169 // ApicVersion[m->ApicId] = Ver; 170 // BiosCpuApicId[CPUCount] = m->ApicId; 171 CPUMap[CPUCount].APICVersion = ver; 172 173 CPUCount++; 174 } 175 176 static VOID 177 HaliMPBusInfo(PMP_CONFIGURATION_BUS m) 178 { 179 static UCHAR CurrentPCIBusId = 0; 180 181 DPRINT("Bus #%d is %.*s\n", m->BusId, 6, m->BusType); 182 183 if (strncmp(m->BusType, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) 184 { 185 BUSMap[m->BusId] = MP_BUS_ISA; 186 } 187 else if (strncmp(m->BusType, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) 188 { 189 BUSMap[m->BusId] = MP_BUS_EISA; 190 } 191 else if (strncmp(m->BusType, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) 192 { 193 BUSMap[m->BusId] = MP_BUS_PCI; 194 PCIBUSMap[m->BusId] = CurrentPCIBusId; 195 CurrentPCIBusId++; 196 } 197 else if (strncmp(m->BusType, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) 198 { 199 BUSMap[m->BusId] = MP_BUS_MCA; 200 } 201 else 202 { 203 DPRINT("Unknown bustype %.*s - ignoring\n", 6, m->BusType); 204 } 205 } 206 207 static VOID 208 HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m) 209 { 210 if (!(m->ApicFlags & CPU_FLAG_ENABLED)) 211 return; 212 213 DPRINT("I/O APIC #%d Version %d at 0x%lX.\n", 214 m->ApicId, m->ApicVersion, m->ApicAddress); 215 if (IOAPICCount > MAX_IOAPIC) 216 { 217 DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n", 218 MAX_IOAPIC, IOAPICCount); 219 DPRINT1("Recompile with bigger MAX_IOAPIC!.\n"); 220 ASSERT(FALSE); 221 } 222 223 IOAPICMap[IOAPICCount].ApicId = m->ApicId; 224 IOAPICMap[IOAPICCount].ApicVersion = m->ApicVersion; 225 IOAPICMap[IOAPICCount].ApicAddress = m->ApicAddress; 226 IOAPICCount++; 227 } 228 229 230 static VOID 231 HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m) 232 { 233 DPRINT("Lint: type %d, pol %d, trig %d, bus %d," 234 " IRQ %02x, APIC ID %x, APIC LINT %02x\n", 235 m->IrqType, m->SrcBusIrq & 3, 236 (m->SrcBusIrq >> 2) & 3, m->SrcBusId, 237 m->SrcBusIrq, m->DstApicId, m->DstApicLInt); 238 /* 239 * Well it seems all SMP boards in existence 240 * use ExtINT/LVT1 == LINT0 and 241 * NMI/LVT2 == LINT1 - the following check 242 * will show us if this assumptions is false. 243 * Until then we do not have to add baggage. 244 */ 245 if ((m->IrqType == INT_EXTINT) && (m->DstApicLInt != 0)) 246 { 247 DPRINT1("Invalid MP table!\n"); 248 ASSERT(FALSE); 249 } 250 if ((m->IrqType == INT_NMI) && (m->DstApicLInt != 1)) 251 { 252 DPRINT1("Invalid MP table!\n"); 253 ASSERT(FALSE); 254 } 255 } 256 257 258 static BOOLEAN 259 HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table) 260 /* 261 PARAMETERS: 262 Table = Pointer to MP configuration table 263 */ 264 { 265 PUCHAR Entry; 266 ULONG Count; 267 268 if (Table->Signature != MPC_SIGNATURE) 269 { 270 PUCHAR pc = (PUCHAR)&Table->Signature; 271 272 DPRINT1("Bad MP configuration block signature: %c%c%c%c\n", 273 pc[0], pc[1], pc[2], pc[3]); 274 KeBugCheckEx(HAL_INITIALIZATION_FAILED, pc[0], pc[1], pc[2], pc[3]); 275 return FALSE; 276 } 277 278 if (MPChecksum((PUCHAR)Table, Table->Length)) 279 { 280 DPRINT1("Bad MP configuration block checksum\n"); 281 ASSERT(FALSE); 282 return FALSE; 283 } 284 285 if (Table->Specification != 0x01 && Table->Specification != 0x04) 286 { 287 DPRINT1("Bad MP configuration table version (%d)\n", 288 Table->Specification); 289 ASSERT(FALSE); 290 return FALSE; 291 } 292 293 if (Table->LocalAPICAddress != APIC_DEFAULT_BASE) 294 { 295 DPRINT1("APIC base address is at 0x%X. I cannot handle non-standard adresses\n", 296 Table->LocalAPICAddress); 297 ASSERT(FALSE); 298 return FALSE; 299 } 300 301 DPRINT("Oem: %.*s, ProductId: %.*s\n", 8, Table->Oem, 12, Table->ProductId); 302 DPRINT("APIC at: %08x\n", Table->LocalAPICAddress); 303 304 305 Entry = (PUCHAR)((ULONG_PTR)Table + sizeof(MP_CONFIGURATION_TABLE)); 306 Count = 0; 307 while (Count < (Table->Length - sizeof(MP_CONFIGURATION_TABLE))) 308 { 309 /* Switch on type */ 310 switch (*Entry) 311 { 312 case MPCTE_PROCESSOR: 313 { 314 HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR)Entry); 315 Entry += sizeof(MP_CONFIGURATION_PROCESSOR); 316 Count += sizeof(MP_CONFIGURATION_PROCESSOR); 317 break; 318 } 319 case MPCTE_BUS: 320 { 321 HaliMPBusInfo((PMP_CONFIGURATION_BUS)Entry); 322 Entry += sizeof(MP_CONFIGURATION_BUS); 323 Count += sizeof(MP_CONFIGURATION_BUS); 324 break; 325 } 326 case MPCTE_IOAPIC: 327 { 328 HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC)Entry); 329 Entry += sizeof(MP_CONFIGURATION_IOAPIC); 330 Count += sizeof(MP_CONFIGURATION_IOAPIC); 331 break; 332 } 333 case MPCTE_INTSRC: 334 { 335 HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC)Entry); 336 Entry += sizeof(MP_CONFIGURATION_INTSRC); 337 Count += sizeof(MP_CONFIGURATION_INTSRC); 338 break; 339 } 340 case MPCTE_LINTSRC: 341 { 342 HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL)Entry); 343 Entry += sizeof(MP_CONFIGURATION_INTLOCAL); 344 Count += sizeof(MP_CONFIGURATION_INTLOCAL); 345 break; 346 } 347 default: 348 DPRINT1("Unknown entry in MPC table\n"); 349 ASSERT(FALSE); 350 return FALSE; 351 } 352 } 353 return TRUE; 354 } 355 356 static VOID 357 HaliConstructDefaultIOIrqMPTable(ULONG Type) 358 { 359 MP_CONFIGURATION_INTSRC intsrc; 360 UCHAR i; 361 362 intsrc.Type = MPCTE_INTSRC; 363 intsrc.IrqFlag = 0; /* conforming */ 364 intsrc.SrcBusId = 0; 365 intsrc.DstApicId = IOAPICMap[0].ApicId; 366 367 intsrc.IrqType = INT_VECTORED; 368 for (i = 0; i < 16; i++) { 369 switch (Type) { 370 case 2: 371 if (i == 0 || i == 13) 372 continue; /* IRQ0 & IRQ13 not connected */ 373 /* Fall through */ 374 default: 375 if (i == 2) 376 continue; /* IRQ2 is never connected */ 377 } 378 379 intsrc.SrcBusIrq = i; 380 intsrc.DstApicInt = i ? i : 2; /* IRQ0 to INTIN2 */ 381 HaliMPIntSrcInfo(&intsrc); 382 } 383 384 intsrc.IrqType = INT_EXTINT; 385 intsrc.SrcBusIrq = 0; 386 intsrc.DstApicInt = 0; /* 8259A to INTIN0 */ 387 HaliMPIntSrcInfo(&intsrc); 388 } 389 390 static VOID 391 HaliConstructDefaultISAMPTable(ULONG Type) 392 { 393 MP_CONFIGURATION_PROCESSOR processor; 394 MP_CONFIGURATION_BUS bus; 395 MP_CONFIGURATION_IOAPIC ioapic; 396 MP_CONFIGURATION_INTLOCAL lintsrc; 397 UCHAR linttypes[2] = { INT_EXTINT, INT_NMI }; 398 UCHAR i; 399 400 /* 401 * 2 CPUs, numbered 0 & 1. 402 */ 403 processor.Type = MPCTE_PROCESSOR; 404 /* Either an integrated APIC or a discrete 82489DX. */ 405 processor.ApicVersion = Type > 4 ? 0x10 : 0x01; 406 processor.CpuFlags = CPU_FLAG_ENABLED | CPU_FLAG_BSP; 407 /* FIXME: Get this from the bootstrap processor */ 408 processor.CpuSignature = 0; 409 processor.FeatureFlags = 0; 410 processor.Reserved[0] = 0; 411 processor.Reserved[1] = 0; 412 for (i = 0; i < 2; i++) 413 { 414 processor.ApicId = i; 415 HaliMPProcessorInfo(&processor); 416 processor.CpuFlags &= ~CPU_FLAG_BSP; 417 } 418 419 bus.Type = MPCTE_BUS; 420 bus.BusId = 0; 421 switch (Type) 422 { 423 default: 424 DPRINT("Unknown standard configuration %d\n", Type); 425 /* Fall through */ 426 case 1: 427 case 5: 428 memcpy(bus.BusType, "ISA ", 6); 429 break; 430 case 2: 431 case 6: 432 case 3: 433 memcpy(bus.BusType, "EISA ", 6); 434 break; 435 case 4: 436 case 7: 437 memcpy(bus.BusType, "MCA ", 6); 438 } 439 HaliMPBusInfo(&bus); 440 if (Type > 4) 441 { 442 bus.Type = MPCTE_BUS; 443 bus.BusId = 1; 444 memcpy(bus.BusType, "PCI ", 6); 445 HaliMPBusInfo(&bus); 446 } 447 448 ioapic.Type = MPCTE_IOAPIC; 449 ioapic.ApicId = 2; 450 ioapic.ApicVersion = Type > 4 ? 0x10 : 0x01; 451 ioapic.ApicFlags = MP_IOAPIC_USABLE; 452 ioapic.ApicAddress = IOAPIC_DEFAULT_BASE; 453 HaliMPIOApicInfo(&ioapic); 454 455 /* 456 * We set up most of the low 16 IO-APIC pins according to MPS rules. 457 */ 458 HaliConstructDefaultIOIrqMPTable(Type); 459 460 lintsrc.Type = MPCTE_LINTSRC; 461 lintsrc.IrqType = 0; 462 lintsrc.IrqFlag = 0; /* conforming */ 463 lintsrc.SrcBusId = 0; 464 lintsrc.SrcBusIrq = 0; 465 lintsrc.DstApicId = MP_APIC_ALL; 466 for (i = 0; i < 2; i++) 467 { 468 lintsrc.IrqType = linttypes[i]; 469 lintsrc.DstApicLInt = i; 470 HaliMPIntLocalInfo(&lintsrc); 471 } 472 } 473 474 475 static BOOLEAN 476 HaliScanForMPConfigTable(ULONG Base, 477 ULONG Size) 478 { 479 /* 480 PARAMETERS: 481 Base = Base address of region 482 Size = Length of region to check 483 RETURNS: 484 TRUE if a valid MP configuration table was found 485 */ 486 487 PULONG bp = (PULONG)Base; 488 MP_FLOATING_POINTER* mpf; 489 UCHAR Checksum; 490 491 while (Size > 0) 492 { 493 mpf = (MP_FLOATING_POINTER*)bp; 494 if (mpf->Signature == MPF_SIGNATURE) 495 { 496 Checksum = MPChecksum((PUCHAR)bp, 16); 497 DPRINT("Found MPF signature at %x, checksum %x\n", bp, Checksum); 498 if (Checksum == 0 && 499 mpf->Length == 1) 500 { 501 DPRINT("Intel MultiProcessor Specification v1.%d compliant system.\n", 502 mpf->Specification); 503 504 if (mpf->Feature2 & FEATURE2_IMCRP) 505 { 506 DPRINT("Running in IMCR and PIC compatibility mode.\n"); 507 } 508 else 509 { 510 DPRINT("Running in Virtual Wire compatibility mode.\n"); 511 } 512 513 514 switch (mpf->Feature1) 515 { 516 case 0: 517 /* Non standard configuration */ 518 break; 519 case 1: 520 DPRINT("ISA\n"); 521 break; 522 case 2: 523 DPRINT("EISA with no IRQ8 chaining\n"); 524 break; 525 case 3: 526 DPRINT("EISA\n"); 527 break; 528 case 4: 529 DPRINT("MCA\n"); 530 break; 531 case 5: 532 DPRINT("ISA and PCI\n"); 533 break; 534 case 6: 535 DPRINT("EISA and PCI\n"); 536 break; 537 case 7: 538 DPRINT("MCA and PCI\n"); 539 break; 540 default: 541 DPRINT("Unknown standard configuration %d\n", mpf->Feature1); 542 return FALSE; 543 } 544 Mpf = mpf; 545 return TRUE; 546 } 547 } 548 bp += 4; 549 Size -= 16; 550 } 551 return FALSE; 552 } 553 554 static BOOLEAN 555 HaliGetSmpConfig(VOID) 556 { 557 if (Mpf == NULL) 558 { 559 return FALSE; 560 } 561 562 if (Mpf->Feature2 & FEATURE2_IMCRP) 563 { 564 DPRINT("Running in IMCR and PIC compatibility mode.\n"); 565 APICMode = amPIC; 566 } 567 else 568 { 569 DPRINT("Running in Virtual Wire compatibility mode.\n"); 570 APICMode = amVWIRE; 571 } 572 573 if (Mpf->Feature1 == 0 && Mpf->Address) 574 { 575 if(!HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE)Mpf->Address)) 576 { 577 DPRINT("BIOS bug, MP table errors detected!...\n"); 578 DPRINT("... disabling SMP support. (tell your hw vendor)\n"); 579 return FALSE; 580 } 581 if (IRQCount == 0) 582 { 583 MP_CONFIGURATION_BUS bus; 584 585 DPRINT("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); 586 587 bus.BusId = 1; 588 memcpy(bus.BusType, "ISA ", 6); 589 HaliMPBusInfo(&bus); 590 HaliConstructDefaultIOIrqMPTable(bus.BusId); 591 } 592 593 } 594 else if(Mpf->Feature1 != 0) 595 { 596 HaliConstructDefaultISAMPTable(Mpf->Feature1); 597 } 598 else 599 { 600 ASSERT(FALSE); 601 } 602 return TRUE; 603 } 604 605 BOOLEAN 606 HaliFindSmpConfig(VOID) 607 { 608 /* 609 Scan the system memory for an MP configuration table 610 1) Scan the first KB of system base memory 611 2) Scan the last KB of system base memory 612 3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh 613 4) Scan the first KB from the Extended BIOS Data Area 614 */ 615 616 if (!HaliScanForMPConfigTable(0x0, 0x400)) 617 { 618 if (!HaliScanForMPConfigTable(0x9FC00, 0x400)) 619 { 620 if (!HaliScanForMPConfigTable(0xF0000, 0x10000)) 621 { 622 if (!HaliScanForMPConfigTable(*((PUSHORT)0x040E) << 4, 0x400)) 623 { 624 DPRINT("No multiprocessor compliant system found.\n"); 625 return FALSE; 626 } 627 } 628 } 629 } 630 631 if (HaliGetSmpConfig()) 632 { 633 return TRUE; 634 } 635 else 636 { 637 DPRINT("No MP config table found\n"); 638 return FALSE; 639 } 640 641 } 642 643 /* EOF */ 644