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