Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmpconfig.c
Go to the documentation of this file.
00001 /* $Id$ 00002 * 00003 * COPYRIGHT: See COPYING in the top level directory 00004 * PROJECT: ReactOS kernel 00005 * FILE: hal/halx86/mp/mpconfig.c 00006 * PURPOSE: 00007 * PROGRAMMER: 00008 */ 00009 00010 /* INCLUDES *****************************************************************/ 00011 00012 #include <hal.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* GLOBALS ******************************************************************/ 00017 00018 MP_FLOATING_POINTER* Mpf = NULL; 00019 00020 /* FUNCTIONS ****************************************************************/ 00021 00022 static UCHAR 00023 MPChecksum(PUCHAR Base, 00024 ULONG Size) 00025 /* 00026 * Checksum an MP configuration block 00027 */ 00028 { 00029 UCHAR Sum = 0; 00030 00031 while (Size--) 00032 Sum += *Base++; 00033 00034 return Sum; 00035 } 00036 00037 static VOID 00038 HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m) 00039 { 00040 DPRINT("Int: type %d, pol %d, trig %d, bus %d," 00041 " IRQ %02x, APIC ID %x, APIC INT %02x\n", 00042 m->IrqType, m->IrqFlag & 3, 00043 (m->IrqFlag >> 2) & 3, m->SrcBusId, 00044 m->SrcBusIrq, m->DstApicId, m->DstApicInt); 00045 if (IRQCount > MAX_IRQ_SOURCE) 00046 { 00047 DPRINT1("Max # of irq sources exceeded!!\n"); 00048 ASSERT(FALSE); 00049 } 00050 00051 IRQMap[IRQCount] = *m; 00052 IRQCount++; 00053 } 00054 00055 PCHAR 00056 HaliMPFamily(ULONG Family, 00057 ULONG Model) 00058 { 00059 static CHAR str[64]; 00060 static PCHAR CPUs[] = 00061 { 00062 "80486DX", "80486DX", 00063 "80486SX", "80486DX/2 or 80487", 00064 "80486SL", "Intel5X2(tm)", 00065 "Unknown", "Unknown", 00066 "80486DX/4" 00067 }; 00068 if (Family == 0x6) 00069 return ("Pentium(tm) Pro"); 00070 if (Family == 0x5) 00071 return ("Pentium(tm)"); 00072 if (Family == 0x0F && Model == 0x0F) 00073 return("Special controller"); 00074 if (Family == 0x0F && Model == 0x00) 00075 return("Pentium 4(tm)"); 00076 if (Family == 0x04 && Model < 9) 00077 return CPUs[Model]; 00078 sprintf(str, "Unknown CPU with family ID %ld and model ID %ld", Family, Model); 00079 return str; 00080 } 00081 00082 00083 static VOID 00084 HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m) 00085 { 00086 UCHAR ver; 00087 00088 if (!(m->CpuFlags & CPU_FLAG_ENABLED)) 00089 return; 00090 00091 DPRINT("Processor #%d %s APIC version %d\n", 00092 m->ApicId, 00093 HaliMPFamily((m->FeatureFlags & CPU_FAMILY_MASK) >> 8, 00094 (m->FeatureFlags & CPU_MODEL_MASK) >> 4), 00095 m->ApicVersion); 00096 00097 if (m->FeatureFlags & (1 << 0)) 00098 DPRINT(" Floating point unit present.\n"); 00099 if (m->FeatureFlags & (1 << 7)) 00100 DPRINT(" Machine Exception supported.\n"); 00101 if (m->FeatureFlags & (1 << 8)) 00102 DPRINT(" 64 bit compare & exchange supported.\n"); 00103 if (m->FeatureFlags & (1 << 9)) 00104 DPRINT(" Internal APIC present.\n"); 00105 if (m->FeatureFlags & (1 << 11)) 00106 DPRINT(" SEP present.\n"); 00107 if (m->FeatureFlags & (1 << 12)) 00108 DPRINT(" MTRR present.\n"); 00109 if (m->FeatureFlags & (1 << 13)) 00110 DPRINT(" PGE present.\n"); 00111 if (m->FeatureFlags & (1 << 14)) 00112 DPRINT(" MCA present.\n"); 00113 if (m->FeatureFlags & (1 << 15)) 00114 DPRINT(" CMOV present.\n"); 00115 if (m->FeatureFlags & (1 << 16)) 00116 DPRINT(" PAT present.\n"); 00117 if (m->FeatureFlags & (1 << 17)) 00118 DPRINT(" PSE present.\n"); 00119 if (m->FeatureFlags & (1 << 18)) 00120 DPRINT(" PSN present.\n"); 00121 if (m->FeatureFlags & (1 << 19)) 00122 DPRINT(" Cache Line Flush Instruction present.\n"); 00123 /* 20 Reserved */ 00124 if (m->FeatureFlags & (1 << 21)) 00125 DPRINT(" Debug Trace and EMON Store present.\n"); 00126 if (m->FeatureFlags & (1 << 22)) 00127 DPRINT(" ACPI Thermal Throttle Registers present.\n"); 00128 if (m->FeatureFlags & (1 << 23)) 00129 DPRINT(" MMX present.\n"); 00130 if (m->FeatureFlags & (1 << 24)) 00131 DPRINT(" FXSR present.\n"); 00132 if (m->FeatureFlags & (1 << 25)) 00133 DPRINT(" XMM present.\n"); 00134 if (m->FeatureFlags & (1 << 26)) 00135 DPRINT(" Willamette New Instructions present.\n"); 00136 if (m->FeatureFlags & (1 << 27)) 00137 DPRINT(" Self Snoop present.\n"); 00138 /* 28 Reserved */ 00139 if (m->FeatureFlags & (1 << 29)) 00140 DPRINT(" Thermal Monitor present.\n"); 00141 /* 30, 31 Reserved */ 00142 00143 CPUMap[CPUCount].APICId = m->ApicId; 00144 00145 CPUMap[CPUCount].Flags = CPU_USABLE; 00146 00147 if (m->CpuFlags & CPU_FLAG_BSP) 00148 { 00149 DPRINT(" Bootup CPU\n"); 00150 CPUMap[CPUCount].Flags |= CPU_BSP; 00151 BootCPU = m->ApicId; 00152 } 00153 00154 if (m->ApicId > MAX_CPU) 00155 { 00156 DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m->ApicId, MAX_CPU); 00157 return; 00158 } 00159 ver = m->ApicVersion; 00160 00161 /* 00162 * Validate version 00163 */ 00164 if (ver == 0x0) 00165 { 00166 DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->ApicId); 00167 ver = 0x10; 00168 } 00169 // ApicVersion[m->ApicId] = Ver; 00170 // BiosCpuApicId[CPUCount] = m->ApicId; 00171 CPUMap[CPUCount].APICVersion = ver; 00172 00173 CPUCount++; 00174 } 00175 00176 static VOID 00177 HaliMPBusInfo(PMP_CONFIGURATION_BUS m) 00178 { 00179 static UCHAR CurrentPCIBusId = 0; 00180 00181 DPRINT("Bus #%d is %.*s\n", m->BusId, 6, m->BusType); 00182 00183 if (strncmp(m->BusType, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) 00184 { 00185 BUSMap[m->BusId] = MP_BUS_ISA; 00186 } 00187 else if (strncmp(m->BusType, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) 00188 { 00189 BUSMap[m->BusId] = MP_BUS_EISA; 00190 } 00191 else if (strncmp(m->BusType, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) 00192 { 00193 BUSMap[m->BusId] = MP_BUS_PCI; 00194 PCIBUSMap[m->BusId] = CurrentPCIBusId; 00195 CurrentPCIBusId++; 00196 } 00197 else if (strncmp(m->BusType, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) 00198 { 00199 BUSMap[m->BusId] = MP_BUS_MCA; 00200 } 00201 else 00202 { 00203 DPRINT("Unknown bustype %.*s - ignoring\n", 6, m->BusType); 00204 } 00205 } 00206 00207 static VOID 00208 HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m) 00209 { 00210 if (!(m->ApicFlags & CPU_FLAG_ENABLED)) 00211 return; 00212 00213 DPRINT("I/O APIC #%d Version %d at 0x%lX.\n", 00214 m->ApicId, m->ApicVersion, m->ApicAddress); 00215 if (IOAPICCount > MAX_IOAPIC) 00216 { 00217 DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n", 00218 MAX_IOAPIC, IOAPICCount); 00219 DPRINT1("Recompile with bigger MAX_IOAPIC!.\n"); 00220 ASSERT(FALSE); 00221 } 00222 00223 IOAPICMap[IOAPICCount].ApicId = m->ApicId; 00224 IOAPICMap[IOAPICCount].ApicVersion = m->ApicVersion; 00225 IOAPICMap[IOAPICCount].ApicAddress = m->ApicAddress; 00226 IOAPICCount++; 00227 } 00228 00229 00230 static VOID 00231 HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m) 00232 { 00233 DPRINT("Lint: type %d, pol %d, trig %d, bus %d," 00234 " IRQ %02x, APIC ID %x, APIC LINT %02x\n", 00235 m->IrqType, m->SrcBusIrq & 3, 00236 (m->SrcBusIrq >> 2) & 3, m->SrcBusId, 00237 m->SrcBusIrq, m->DstApicId, m->DstApicLInt); 00238 /* 00239 * Well it seems all SMP boards in existence 00240 * use ExtINT/LVT1 == LINT0 and 00241 * NMI/LVT2 == LINT1 - the following check 00242 * will show us if this assumptions is false. 00243 * Until then we do not have to add baggage. 00244 */ 00245 if ((m->IrqType == INT_EXTINT) && (m->DstApicLInt != 0)) 00246 { 00247 DPRINT1("Invalid MP table!\n"); 00248 ASSERT(FALSE); 00249 } 00250 if ((m->IrqType == INT_NMI) && (m->DstApicLInt != 1)) 00251 { 00252 DPRINT1("Invalid MP table!\n"); 00253 ASSERT(FALSE); 00254 } 00255 } 00256 00257 00258 static BOOLEAN 00259 HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table) 00260 /* 00261 PARAMETERS: 00262 Table = Pointer to MP configuration table 00263 */ 00264 { 00265 PUCHAR Entry; 00266 ULONG Count; 00267 00268 if (Table->Signature != MPC_SIGNATURE) 00269 { 00270 PUCHAR pc = (PUCHAR)&Table->Signature; 00271 00272 DPRINT1("Bad MP configuration block signature: %c%c%c%c\n", 00273 pc[0], pc[1], pc[2], pc[3]); 00274 KeBugCheckEx(HAL_INITIALIZATION_FAILED, pc[0], pc[1], pc[2], pc[3]); 00275 return FALSE; 00276 } 00277 00278 if (MPChecksum((PUCHAR)Table, Table->Length)) 00279 { 00280 DPRINT1("Bad MP configuration block checksum\n"); 00281 ASSERT(FALSE); 00282 return FALSE; 00283 } 00284 00285 if (Table->Specification != 0x01 && Table->Specification != 0x04) 00286 { 00287 DPRINT1("Bad MP configuration table version (%d)\n", 00288 Table->Specification); 00289 ASSERT(FALSE); 00290 return FALSE; 00291 } 00292 00293 if (Table->LocalAPICAddress != APIC_DEFAULT_BASE) 00294 { 00295 DPRINT1("APIC base address is at 0x%X. I cannot handle non-standard adresses\n", 00296 Table->LocalAPICAddress); 00297 ASSERT(FALSE); 00298 return FALSE; 00299 } 00300 00301 DPRINT("Oem: %.*s, ProductId: %.*s\n", 8, Table->Oem, 12, Table->ProductId); 00302 DPRINT("APIC at: %08x\n", Table->LocalAPICAddress); 00303 00304 00305 Entry = (PUCHAR)((ULONG_PTR)Table + sizeof(MP_CONFIGURATION_TABLE)); 00306 Count = 0; 00307 while (Count < (Table->Length - sizeof(MP_CONFIGURATION_TABLE))) 00308 { 00309 /* Switch on type */ 00310 switch (*Entry) 00311 { 00312 case MPCTE_PROCESSOR: 00313 { 00314 HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR)Entry); 00315 Entry += sizeof(MP_CONFIGURATION_PROCESSOR); 00316 Count += sizeof(MP_CONFIGURATION_PROCESSOR); 00317 break; 00318 } 00319 case MPCTE_BUS: 00320 { 00321 HaliMPBusInfo((PMP_CONFIGURATION_BUS)Entry); 00322 Entry += sizeof(MP_CONFIGURATION_BUS); 00323 Count += sizeof(MP_CONFIGURATION_BUS); 00324 break; 00325 } 00326 case MPCTE_IOAPIC: 00327 { 00328 HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC)Entry); 00329 Entry += sizeof(MP_CONFIGURATION_IOAPIC); 00330 Count += sizeof(MP_CONFIGURATION_IOAPIC); 00331 break; 00332 } 00333 case MPCTE_INTSRC: 00334 { 00335 HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC)Entry); 00336 Entry += sizeof(MP_CONFIGURATION_INTSRC); 00337 Count += sizeof(MP_CONFIGURATION_INTSRC); 00338 break; 00339 } 00340 case MPCTE_LINTSRC: 00341 { 00342 HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL)Entry); 00343 Entry += sizeof(MP_CONFIGURATION_INTLOCAL); 00344 Count += sizeof(MP_CONFIGURATION_INTLOCAL); 00345 break; 00346 } 00347 default: 00348 DPRINT1("Unknown entry in MPC table\n"); 00349 ASSERT(FALSE); 00350 return FALSE; 00351 } 00352 } 00353 return TRUE; 00354 } 00355 00356 static VOID 00357 HaliConstructDefaultIOIrqMPTable(ULONG Type) 00358 { 00359 MP_CONFIGURATION_INTSRC intsrc; 00360 UCHAR i; 00361 00362 intsrc.Type = MPCTE_INTSRC; 00363 intsrc.IrqFlag = 0; /* conforming */ 00364 intsrc.SrcBusId = 0; 00365 intsrc.DstApicId = IOAPICMap[0].ApicId; 00366 00367 intsrc.IrqType = INT_VECTORED; 00368 for (i = 0; i < 16; i++) { 00369 switch (Type) { 00370 case 2: 00371 if (i == 0 || i == 13) 00372 continue; /* IRQ0 & IRQ13 not connected */ 00373 /* Fall through */ 00374 default: 00375 if (i == 2) 00376 continue; /* IRQ2 is never connected */ 00377 } 00378 00379 intsrc.SrcBusIrq = i; 00380 intsrc.DstApicInt = i ? i : 2; /* IRQ0 to INTIN2 */ 00381 HaliMPIntSrcInfo(&intsrc); 00382 } 00383 00384 intsrc.IrqType = INT_EXTINT; 00385 intsrc.SrcBusIrq = 0; 00386 intsrc.DstApicInt = 0; /* 8259A to INTIN0 */ 00387 HaliMPIntSrcInfo(&intsrc); 00388 } 00389 00390 static VOID 00391 HaliConstructDefaultISAMPTable(ULONG Type) 00392 { 00393 MP_CONFIGURATION_PROCESSOR processor; 00394 MP_CONFIGURATION_BUS bus; 00395 MP_CONFIGURATION_IOAPIC ioapic; 00396 MP_CONFIGURATION_INTLOCAL lintsrc; 00397 UCHAR linttypes[2] = { INT_EXTINT, INT_NMI }; 00398 UCHAR i; 00399 00400 /* 00401 * 2 CPUs, numbered 0 & 1. 00402 */ 00403 processor.Type = MPCTE_PROCESSOR; 00404 /* Either an integrated APIC or a discrete 82489DX. */ 00405 processor.ApicVersion = Type > 4 ? 0x10 : 0x01; 00406 processor.CpuFlags = CPU_FLAG_ENABLED | CPU_FLAG_BSP; 00407 /* FIXME: Get this from the bootstrap processor */ 00408 processor.CpuSignature = 0; 00409 processor.FeatureFlags = 0; 00410 processor.Reserved[0] = 0; 00411 processor.Reserved[1] = 0; 00412 for (i = 0; i < 2; i++) 00413 { 00414 processor.ApicId = i; 00415 HaliMPProcessorInfo(&processor); 00416 processor.CpuFlags &= ~CPU_FLAG_BSP; 00417 } 00418 00419 bus.Type = MPCTE_BUS; 00420 bus.BusId = 0; 00421 switch (Type) 00422 { 00423 default: 00424 DPRINT("Unknown standard configuration %d\n", Type); 00425 /* Fall through */ 00426 case 1: 00427 case 5: 00428 memcpy(bus.BusType, "ISA ", 6); 00429 break; 00430 case 2: 00431 case 6: 00432 case 3: 00433 memcpy(bus.BusType, "EISA ", 6); 00434 break; 00435 case 4: 00436 case 7: 00437 memcpy(bus.BusType, "MCA ", 6); 00438 } 00439 HaliMPBusInfo(&bus); 00440 if (Type > 4) 00441 { 00442 bus.Type = MPCTE_BUS; 00443 bus.BusId = 1; 00444 memcpy(bus.BusType, "PCI ", 6); 00445 HaliMPBusInfo(&bus); 00446 } 00447 00448 ioapic.Type = MPCTE_IOAPIC; 00449 ioapic.ApicId = 2; 00450 ioapic.ApicVersion = Type > 4 ? 0x10 : 0x01; 00451 ioapic.ApicFlags = MP_IOAPIC_USABLE; 00452 ioapic.ApicAddress = IOAPIC_DEFAULT_BASE; 00453 HaliMPIOApicInfo(&ioapic); 00454 00455 /* 00456 * We set up most of the low 16 IO-APIC pins according to MPS rules. 00457 */ 00458 HaliConstructDefaultIOIrqMPTable(Type); 00459 00460 lintsrc.Type = MPCTE_LINTSRC; 00461 lintsrc.IrqType = 0; 00462 lintsrc.IrqFlag = 0; /* conforming */ 00463 lintsrc.SrcBusId = 0; 00464 lintsrc.SrcBusIrq = 0; 00465 lintsrc.DstApicId = MP_APIC_ALL; 00466 for (i = 0; i < 2; i++) 00467 { 00468 lintsrc.IrqType = linttypes[i]; 00469 lintsrc.DstApicLInt = i; 00470 HaliMPIntLocalInfo(&lintsrc); 00471 } 00472 } 00473 00474 00475 static BOOLEAN 00476 HaliScanForMPConfigTable(ULONG Base, 00477 ULONG Size) 00478 { 00479 /* 00480 PARAMETERS: 00481 Base = Base address of region 00482 Size = Length of region to check 00483 RETURNS: 00484 TRUE if a valid MP configuration table was found 00485 */ 00486 00487 PULONG bp = (PULONG)Base; 00488 MP_FLOATING_POINTER* mpf; 00489 UCHAR Checksum; 00490 00491 while (Size > 0) 00492 { 00493 mpf = (MP_FLOATING_POINTER*)bp; 00494 if (mpf->Signature == MPF_SIGNATURE) 00495 { 00496 Checksum = MPChecksum((PUCHAR)bp, 16); 00497 DPRINT("Found MPF signature at %x, checksum %x\n", bp, Checksum); 00498 if (Checksum == 0 && 00499 mpf->Length == 1) 00500 { 00501 DPRINT("Intel MultiProcessor Specification v1.%d compliant system.\n", 00502 mpf->Specification); 00503 00504 if (mpf->Feature2 & FEATURE2_IMCRP) 00505 { 00506 DPRINT("Running in IMCR and PIC compatibility mode.\n"); 00507 } 00508 else 00509 { 00510 DPRINT("Running in Virtual Wire compatibility mode.\n"); 00511 } 00512 00513 00514 switch (mpf->Feature1) 00515 { 00516 case 0: 00517 /* Non standard configuration */ 00518 break; 00519 case 1: 00520 DPRINT("ISA\n"); 00521 break; 00522 case 2: 00523 DPRINT("EISA with no IRQ8 chaining\n"); 00524 break; 00525 case 3: 00526 DPRINT("EISA\n"); 00527 break; 00528 case 4: 00529 DPRINT("MCA\n"); 00530 break; 00531 case 5: 00532 DPRINT("ISA and PCI\n"); 00533 break; 00534 case 6: 00535 DPRINT("EISA and PCI\n"); 00536 break; 00537 case 7: 00538 DPRINT("MCA and PCI\n"); 00539 break; 00540 default: 00541 DPRINT("Unknown standard configuration %d\n", mpf->Feature1); 00542 return FALSE; 00543 } 00544 Mpf = mpf; 00545 return TRUE; 00546 } 00547 } 00548 bp += 4; 00549 Size -= 16; 00550 } 00551 return FALSE; 00552 } 00553 00554 static BOOLEAN 00555 HaliGetSmpConfig(VOID) 00556 { 00557 if (Mpf == NULL) 00558 { 00559 return FALSE; 00560 } 00561 00562 if (Mpf->Feature2 & FEATURE2_IMCRP) 00563 { 00564 DPRINT("Running in IMCR and PIC compatibility mode.\n"); 00565 APICMode = amPIC; 00566 } 00567 else 00568 { 00569 DPRINT("Running in Virtual Wire compatibility mode.\n"); 00570 APICMode = amVWIRE; 00571 } 00572 00573 if (Mpf->Feature1 == 0 && Mpf->Address) 00574 { 00575 if(!HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE)Mpf->Address)) 00576 { 00577 DPRINT("BIOS bug, MP table errors detected!...\n"); 00578 DPRINT("... disabling SMP support. (tell your hw vendor)\n"); 00579 return FALSE; 00580 } 00581 if (IRQCount == 0) 00582 { 00583 MP_CONFIGURATION_BUS bus; 00584 00585 DPRINT("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); 00586 00587 bus.BusId = 1; 00588 memcpy(bus.BusType, "ISA ", 6); 00589 HaliMPBusInfo(&bus); 00590 HaliConstructDefaultIOIrqMPTable(bus.BusId); 00591 } 00592 00593 } 00594 else if(Mpf->Feature1 != 0) 00595 { 00596 HaliConstructDefaultISAMPTable(Mpf->Feature1); 00597 } 00598 else 00599 { 00600 ASSERT(FALSE); 00601 } 00602 return TRUE; 00603 } 00604 00605 BOOLEAN 00606 HaliFindSmpConfig(VOID) 00607 { 00608 /* 00609 Scan the system memory for an MP configuration table 00610 1) Scan the first KB of system base memory 00611 2) Scan the last KB of system base memory 00612 3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh 00613 4) Scan the first KB from the Extended BIOS Data Area 00614 */ 00615 00616 if (!HaliScanForMPConfigTable(0x0, 0x400)) 00617 { 00618 if (!HaliScanForMPConfigTable(0x9FC00, 0x400)) 00619 { 00620 if (!HaliScanForMPConfigTable(0xF0000, 0x10000)) 00621 { 00622 if (!HaliScanForMPConfigTable(*((PUSHORT)0x040E) << 4, 0x400)) 00623 { 00624 DPRINT("No multiprocessor compliant system found.\n"); 00625 return FALSE; 00626 } 00627 } 00628 } 00629 } 00630 00631 if (HaliGetSmpConfig()) 00632 { 00633 return TRUE; 00634 } 00635 else 00636 { 00637 DPRINT("No MP config table found\n"); 00638 return FALSE; 00639 } 00640 00641 } 00642 00643 /* EOF */ Generated on Sun May 27 2012 04:28:44 for ReactOS by
1.7.6.1
|