Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

546 lines
13 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1992 Intel Corporation
  4. All rights reserved
  5. INTEL CORPORATION PROPRIETARY INFORMATION
  6. This software is supplied to Microsoft under the terms
  7. of a license agreement with Intel Corporation and may not be
  8. copied nor disclosed except in accordance with the terms
  9. of that agreement.
  10. Module Name:
  11. mpdetect.c
  12. Abstract:
  13. This module detects an MPS system.
  14. Author:
  15. Ron Mosgrove (Intel) - Aug 1993.
  16. Environment:
  17. Kernel mode or from textmode setup.
  18. Revision History:
  19. Rajesh Shah (Intel) - Oct 1993. Added support for MPS table.
  20. --*/
  21. #ifndef _NTOS_
  22. #include "halp.h"
  23. #endif
  24. #ifdef SETUP
  25. #define FAILMSG(a)
  26. #else
  27. #define FAILMSG(a) HalDisplayString(a)
  28. extern UCHAR rgzNoMpsTable[];
  29. extern UCHAR rgzNoApic[];
  30. extern UCHAR rgzBadApicVersion[];
  31. extern UCHAR rgzApicNotVerified[];
  32. extern UCHAR rgzMPPTRCheck[];
  33. extern UCHAR rgzNoMPTable[];
  34. extern UCHAR rgzMPSBadSig[];
  35. extern UCHAR rgzMPSBadCheck[];
  36. extern UCHAR rgzBadDefault[];
  37. extern UCHAR rgzNoMem[];
  38. #endif
  39. // Include the code that actually detect a MPS system
  40. #include "pcmpdtct.c"
  41. BOOLEAN
  42. HalpVerifyIOUnit (
  43. IN PUCHAR BaseAddress
  44. );
  45. VOID
  46. HalpInitMpInfo (
  47. IN struct PcMpTable *MpTablePtr
  48. );
  49. ULONG
  50. DetectMPS (
  51. OUT PBOOLEAN IsConfiguredMp
  52. );
  53. ULONG
  54. DetectUPMPS (
  55. OUT PBOOLEAN IsConfiguredMp
  56. );
  57. extern struct PcMpTable *GetPcMpTable( VOID );
  58. ULONG UserSpecifiedNoIoApic = 0;
  59. struct HalpMpInfo HalpMpInfoTable;
  60. struct PcMpTable HalpPcMpTable;
  61. struct PcMpTable *PcMpTablePtr;
  62. #ifndef SETUP
  63. #ifdef ALLOC_PRAGMA
  64. #pragma alloc_text(PAGELK,HalpVerifyIOUnit)
  65. #pragma alloc_text(PAGELK,HalpInitMpInfo)
  66. #pragma alloc_text(PAGELK,DetectMPS)
  67. #pragma alloc_text(PAGELK,DetectUPMPS)
  68. #endif // ALLOC_PRAGMA
  69. extern struct PcMpTable *PcMpDefaultTablePtrs[];
  70. #endif // SETUP
  71. BOOLEAN
  72. HalpVerifyIOUnit(
  73. IN PUCHAR BaseAddress
  74. )
  75. /*++
  76. Routine Description:
  77. Verify that an IO Unit exists at the specified address
  78. Arguments:
  79. BaseAddress - Virtual address of the IO Unit to test.
  80. Return Value:
  81. BOOLEAN - TRUE if a IO Unit was found at the passed address
  82. - FALSE otherwise
  83. --*/
  84. {
  85. union ApicUnion {
  86. ULONG Raw;
  87. struct ApicVersion Ver;
  88. } Temp1, Temp2;
  89. struct ApicIoUnit *IoUnitPtr = (struct ApicIoUnit *) BaseAddress;
  90. //
  91. // The documented detection mechanism is to write all zeros to
  92. // the Version register. Then read it back. The IO Unit exists if the
  93. // same result is read both times and the Version is valid.
  94. //
  95. IoUnitPtr->RegisterSelect = IO_VERS_REGISTER;
  96. IoUnitPtr->RegisterWindow = 0;
  97. IoUnitPtr->RegisterSelect = IO_VERS_REGISTER;
  98. Temp1.Raw = IoUnitPtr->RegisterWindow;
  99. IoUnitPtr->RegisterSelect = IO_VERS_REGISTER;
  100. IoUnitPtr->RegisterWindow = 0;
  101. IoUnitPtr->RegisterSelect = IO_VERS_REGISTER;
  102. Temp2.Raw = IoUnitPtr->RegisterWindow;
  103. if ((Temp1.Ver.Version != Temp2.Ver.Version) ||
  104. (Temp1.Ver.MaxRedirEntries != Temp2.Ver.MaxRedirEntries)) {
  105. //
  106. // No IO Unit There
  107. //
  108. return (FALSE);
  109. }
  110. return (TRUE);
  111. }
  112. VOID
  113. HalpInitMpInfo (
  114. IN struct PcMpTable *MpTablePtr
  115. )
  116. /*++
  117. Routine Description:
  118. This routine initializes a HAL specific data structure that is
  119. used by the HAL to simplify access to MP information.
  120. Arguments:
  121. MpTablePtr: Pointer to the MPS table.
  122. Return Value:
  123. Pointer to the HAL MP information table.
  124. */
  125. {
  126. PUCHAR TraversePtr, EndOfBaseTable;
  127. UCHAR CheckSum;
  128. // Walk the MPS table. The HAL MP information structure has
  129. // pointers to the first entry for each entry type in the MPS
  130. // table. Set these pointers.
  131. TraversePtr = (PUCHAR) MpTablePtr + HEADER_SIZE;
  132. EndOfBaseTable = (PUCHAR) MpTablePtr + MpTablePtr->TableLength;
  133. HalpMpInfoTable.ApicVersion =
  134. (ULONG) (((PPCMPPROCESSOR)(TraversePtr))->LocalApicVersion & 0xf0);
  135. while (TraversePtr < EndOfBaseTable) {
  136. switch (*TraversePtr) {
  137. case ENTRY_PROCESSOR:
  138. if(((PPCMPPROCESSOR)(TraversePtr))->CpuFlags & CPU_ENABLED) {
  139. if (HalpMpInfoTable.ProcessorCount == 0) {
  140. HalpMpInfoTable.ProcessorEntryPtr =
  141. (PPCMPPROCESSOR) TraversePtr;
  142. }
  143. HalpMpInfoTable.ProcessorCount++;
  144. }
  145. TraversePtr += sizeof(PCMPPROCESSOR);
  146. break;
  147. case ENTRY_BUS:
  148. if (HalpMpInfoTable.BusCount == 0) {
  149. HalpMpInfoTable.BusEntryPtr = (PPCMPBUS) TraversePtr;
  150. }
  151. HalpMpInfoTable.BusCount += 1;
  152. TraversePtr += sizeof(PCMPBUS);
  153. break;
  154. case ENTRY_IOAPIC:
  155. if ((((PPCMPIOAPIC)(TraversePtr))->IoApicFlag &
  156. IO_APIC_ENABLED) && (UserSpecifiedNoIoApic == 0)) {
  157. if (HalpMpInfoTable.IOApicCount == 0) {
  158. HalpMpInfoTable.IoApicEntryPtr =
  159. (PPCMPIOAPIC) TraversePtr;
  160. }
  161. HalpMpInfoTable.IOApicCount += 1;
  162. }
  163. TraversePtr += sizeof(PCMPIOAPIC);
  164. break;
  165. case ENTRY_INTI:
  166. if (HalpMpInfoTable.IntiCount == 0) {
  167. HalpMpInfoTable.IntiEntryPtr = (PPCMPINTI) TraversePtr;
  168. }
  169. HalpMpInfoTable.IntiCount += 1;
  170. TraversePtr += sizeof(PCMPINTI);
  171. break;
  172. case ENTRY_LINTI:
  173. if (HalpMpInfoTable.LintiCount == 0) {
  174. HalpMpInfoTable.LintiEntryPtr = (PPCMPLINTI) TraversePtr;
  175. }
  176. HalpMpInfoTable.LintiCount += 1;
  177. TraversePtr += sizeof(PCMPLINTI);
  178. break;
  179. default:
  180. //
  181. // Unknown MPS entry. Since we don't know it's size, we will
  182. // terminate parsing here.
  183. //
  184. DBGMSG("HAL: Invalid MPS table entry type detected\n");
  185. TraversePtr = EndOfBaseTable;
  186. break;
  187. } // switch
  188. } // while
  189. //
  190. // Check for Extension table defined
  191. //
  192. if (MpTablePtr->ExtTableLength &&
  193. MpTablePtr->TableLength + MpTablePtr->ExtTableLength < 8192) {
  194. CheckSum = ComputeCheckSum(
  195. (PUCHAR) MpTablePtr + MpTablePtr->TableLength,
  196. MpTablePtr->ExtTableLength
  197. );
  198. CheckSum += MpTablePtr->ExtTableChecksum;
  199. if (CheckSum != 0) {
  200. DBGMSG("HALMPS: InitMpInfo: Extension table checksum error\n");
  201. } else {
  202. HalpMpInfoTable.ExtensionTable = (PMPS_EXTENTRY)
  203. (((PUCHAR) MpTablePtr) + MpTablePtr->TableLength);
  204. HalpMpInfoTable.EndOfExtensionTable = (PMPS_EXTENTRY)
  205. (((PUCHAR) MpTablePtr) + MpTablePtr->TableLength +
  206. MpTablePtr->ExtTableLength);
  207. }
  208. }
  209. return;
  210. }
  211. ULONG
  212. DetectMPS(
  213. OUT PBOOLEAN IsConfiguredMp
  214. )
  215. /*++
  216. Routine Description:
  217. This function is called from HalInitializeProcessors to determine
  218. if this is an appropriate system to run the MPS hal on.
  219. The recommended detection mechanism is:
  220. if ( MPS information does not exist )
  221. then
  222. System is not MPS compliant. Return false.
  223. In MP table:
  224. if ( number IO APICs < 1 )
  225. then
  226. Not a MPS System - return false
  227. if ( # CPUs = 1 )
  228. then
  229. Found a Single Processor MPS System
  230. else
  231. Found a MP MPS System
  232. A side effect of this routine is the mapping of the IO UNits and
  233. Local unit virtual addresses.
  234. Return TRUE
  235. Arguments:
  236. IsConfiguredMp - TRUE if this machine is a MP instance of the MPS spec, else FALSE.
  237. Return Value:
  238. 0 - if not a MPS
  239. 1 - if MPS
  240. */
  241. {
  242. UCHAR ApicVersion, i;
  243. PUCHAR LocalApic;
  244. PPCMPIOAPIC IoEntryPtr;
  245. PHYSICAL_ADDRESS physicalAddress;
  246. //
  247. // Initialize MpInfo table
  248. //
  249. RtlZeroMemory (&HalpMpInfoTable, sizeof HalpMpInfoTable);
  250. //
  251. // Set the return Values to the default
  252. //
  253. *IsConfiguredMp = FALSE;
  254. //
  255. // See if there is a MP Table
  256. //
  257. #if 1
  258. if ((PcMpTablePtr = GetPcMpTable()) == NULL) {
  259. FAILMSG (rgzNoMpsTable);
  260. return(FALSE);
  261. }
  262. #else
  263. //********
  264. //******** HACK! To make down level 1.0 machine work
  265. //********
  266. if ((PcMpTablePtr = MPS10_GetPcMpTable()) == NULL) {
  267. FAILMSG (rgzNoMpsTable);
  268. return(FALSE);
  269. }
  270. #endif
  271. #ifdef SETUP
  272. // During setup, if we detected a default MPS configuration, we have
  273. // no more checking to do.
  274. if (PcMpTablePtr == (struct PcMpTable *) DEFAULT_MPS_INDICATOR) {
  275. *IsConfiguredMp = TRUE;
  276. return(TRUE);
  277. }
  278. #endif // SETUP
  279. #if DEBUGGING
  280. HalpDisplayConfigTable();
  281. #endif
  282. // We have a MPS table. Initialize a HAL specific MP information
  283. // structure that gets information from the MPS table.
  284. HalpInitMpInfo(PcMpTablePtr);
  285. // Verify the information in the MPS table as best as we can.
  286. if (HalpMpInfoTable.IOApicCount == 0) {
  287. //
  288. // Someone Has a MP Table and no IO Units -- Weird
  289. // We have to assume the BIOS knew what it was doing
  290. // when it built the table. so ..
  291. //
  292. FAILMSG (rgzNoApic);
  293. return (FALSE);
  294. }
  295. //
  296. // It's a MPS System. It could be a UP System though.
  297. //
  298. #ifdef SETUP
  299. //
  300. // If this is a MPS (MPS) compliant system, but has only 1 processor,
  301. // for now we want to install a standard UP kernel and HAL.
  302. //
  303. if (HalpMpInfoTable.ProcessorCount <= 1) {
  304. return FALSE;
  305. }
  306. #endif
  307. if (HalpMpInfoTable.ProcessorCount > 1) {
  308. *IsConfiguredMp = TRUE;
  309. }
  310. HalpMpInfoTable.LocalApicBase = (ULONG) PcMpTablePtr->LocalApicAddress;
  311. physicalAddress.QuadPart = HalpMpInfoTable.LocalApicBase;
  312. LocalApic = (PUCHAR) HalpMapPhysicalMemoryWriteThrough64(
  313. physicalAddress,1);
  314. if (!LocalApic) {
  315. FAILMSG (rgzNoMem);
  316. return (FALSE);
  317. }
  318. #ifndef SETUP
  319. HalpRemapVirtualAddress64 (
  320. (PVOID) LOCALAPIC,
  321. physicalAddress,
  322. TRUE
  323. );
  324. #endif
  325. ApicVersion = (UCHAR) *(LocalApic + LU_VERS_REGISTER);
  326. if (ApicVersion > 0x1f) {
  327. //
  328. // Only known Apics are 82489dx with version 0.x and
  329. // Embedded Apics with version 1.x (where x is don't care)
  330. //
  331. // Return of 0xFF? Can't have an MPS system without a Local Unit.
  332. //
  333. #ifdef DEBUGGING
  334. sprintf(Cbuf, "HALMPS: apic version %x, read from %x\n",
  335. ApicVersion, LocalApic + LU_VERS_REGISTER);
  336. HalDisplayString(Cbuf);
  337. #endif
  338. FAILMSG (rgzBadApicVersion);
  339. return (FALSE);
  340. }
  341. #ifdef SETUP
  342. //
  343. // MP MPS table, and the local APIC ID looked OK.
  344. //
  345. return TRUE;
  346. #endif //SETUP
  347. #ifdef DEBUGGING
  348. if ((ApicVersion & 0xf0) == 0) {
  349. if (HalpMpInfoTable.ApicVersion != APIC_82489DX)
  350. HalDisplayString("HAL:Invalid Local Apic version in MP table\n");
  351. else {
  352. sprintf(Cbuf, "HAL: DetectMPS: Found 82489DX Local APIC (Ver 0x%x) at 0x%lx\n",
  353. ApicVersion, LocalApic);
  354. HalDisplayString(Cbuf);
  355. }
  356. } else {
  357. sprintf(Cbuf, "HAL: DetectMPS: Found Embedded Local APIC (Ver 0x%x) at 0x%lx\n",
  358. ApicVersion, LocalApic);
  359. HalDisplayString(Cbuf);
  360. }
  361. #endif // DEBUGGING
  362. #ifndef SETUP
  363. HalpUnmapVirtualAddress(LocalApic,1);
  364. #endif
  365. IoEntryPtr = HalpMpInfoTable.IoApicEntryPtr;
  366. for(i=0; i < HalpMpInfoTable.IOApicCount; i++, IoEntryPtr++)
  367. {
  368. if (IoEntryPtr->IoApicFlag & IO_APIC_ENABLED) {
  369. //
  370. // Verify the existance of the IO Units
  371. //
  372. physicalAddress.QuadPart = (ULONG)IoEntryPtr->IoApicAddress;
  373. HalpMpInfoTable.IoApicPhys[i] = (ULONG)IoEntryPtr->IoApicAddress;
  374. HalpMpInfoTable.IoApicBase[i] = (PULONG)
  375. HalpMapPhysicalMemoryWriteThrough64(physicalAddress, 1);
  376. //
  377. // Verify the existance of the IO Unit
  378. //
  379. if (!(HalpVerifyIOUnit((PUCHAR)HalpMpInfoTable.IoApicBase[i]))) {
  380. FAILMSG (rgzApicNotVerified);
  381. return (FALSE);
  382. }
  383. }
  384. }
  385. DBGMSG("HAL: DetectMPS: MPS system found - Returning TRUE\n");
  386. return(TRUE);
  387. }
  388. ULONG
  389. DetectUPMPS(
  390. OUT PBOOLEAN IsConfiguredMp
  391. )
  392. /*++
  393. Routine Description:
  394. This function is called by setup after DetectMPS has returned
  395. false. During setup time DetectMPS will return false, if the
  396. machine is an MPS system, but only has one processor. This
  397. function is used to detect such a machine at setup time.
  398. Arguments:
  399. IsConfiguredMp - FALSE
  400. Return Value:
  401. 0 - if not a UP MPS
  402. 1 - if UP MPS
  403. --*/
  404. {
  405. *IsConfiguredMp = FALSE;
  406. // we assume the caller has already called DetectMPS, and the
  407. // MPS table has already been parsed.
  408. return (HalpMpInfoTable.ProcessorCount == 1 ? TRUE : FALSE);
  409. }