Leaked source code of windows server 2003
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.

549 lines
14 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 = 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;
  243. PUCHAR LocalApic;
  244. PHYSICAL_ADDRESS physicalAddress;
  245. #ifndef SETUP
  246. UCHAR i;
  247. PPCMPIOAPIC IoEntryPtr;
  248. #endif
  249. //
  250. // Initialize MpInfo table
  251. //
  252. RtlZeroMemory (&HalpMpInfoTable, sizeof HalpMpInfoTable);
  253. //
  254. // Set the return Values to the default
  255. //
  256. *IsConfiguredMp = FALSE;
  257. //
  258. // See if there is a MP Table
  259. //
  260. #if 1
  261. if ((PcMpTablePtr = GetPcMpTable()) == NULL) {
  262. FAILMSG (rgzNoMpsTable);
  263. return(FALSE);
  264. }
  265. #else
  266. //********
  267. //******** HACK! To make down level 1.0 machine work
  268. //********
  269. if ((PcMpTablePtr = MPS10_GetPcMpTable()) == NULL) {
  270. FAILMSG (rgzNoMpsTable);
  271. return(FALSE);
  272. }
  273. #endif
  274. #ifdef SETUP
  275. // During setup, if we detected a default MPS configuration, we have
  276. // no more checking to do.
  277. if (PcMpTablePtr == (struct PcMpTable *) DEFAULT_MPS_INDICATOR) {
  278. *IsConfiguredMp = TRUE;
  279. return(TRUE);
  280. }
  281. #endif // SETUP
  282. #if DEBUGGING
  283. HalpDisplayConfigTable();
  284. #endif
  285. // We have a MPS table. Initialize a HAL specific MP information
  286. // structure that gets information from the MPS table.
  287. HalpInitMpInfo(PcMpTablePtr);
  288. // Verify the information in the MPS table as best as we can.
  289. if (HalpMpInfoTable.IOApicCount == 0) {
  290. //
  291. // Someone Has a MP Table and no IO Units -- Weird
  292. // We have to assume the BIOS knew what it was doing
  293. // when it built the table. so ..
  294. //
  295. FAILMSG (rgzNoApic);
  296. return (FALSE);
  297. }
  298. //
  299. // It's a MPS System. It could be a UP System though.
  300. //
  301. #ifdef SETUP
  302. //
  303. // If this is a MPS (MPS) compliant system, but has only 1 processor,
  304. // for now we want to install a standard UP kernel and HAL.
  305. //
  306. if (HalpMpInfoTable.ProcessorCount <= 1) {
  307. return FALSE;
  308. }
  309. #endif
  310. if (HalpMpInfoTable.ProcessorCount > 1) {
  311. *IsConfiguredMp = TRUE;
  312. }
  313. HalpMpInfoTable.LocalApicBase = (ULONG) PcMpTablePtr->LocalApicAddress;
  314. physicalAddress.QuadPart = HalpMpInfoTable.LocalApicBase;
  315. LocalApic = (PUCHAR) HalpMapPhysicalMemoryWriteThrough64(
  316. physicalAddress,1);
  317. if (!LocalApic) {
  318. FAILMSG (rgzNoMem);
  319. return (FALSE);
  320. }
  321. #ifndef SETUP
  322. HalpRemapVirtualAddress64 (
  323. (PVOID) LOCALAPIC,
  324. physicalAddress,
  325. TRUE
  326. );
  327. #endif
  328. ApicVersion = (UCHAR) *(LocalApic + LU_VERS_REGISTER);
  329. if (ApicVersion > 0x1f) {
  330. //
  331. // Only known Apics are 82489dx with version 0.x and
  332. // Embedded Apics with version 1.x (where x is don't care)
  333. //
  334. // Return of 0xFF? Can't have an MPS system without a Local Unit.
  335. //
  336. #ifdef DEBUGGING
  337. sprintf(Cbuf, "HALMPS: apic version %x, read from %x\n",
  338. ApicVersion, LocalApic + LU_VERS_REGISTER);
  339. HalDisplayString(Cbuf);
  340. #endif
  341. FAILMSG (rgzBadApicVersion);
  342. return (FALSE);
  343. }
  344. #ifdef SETUP
  345. //
  346. // MP MPS table, and the local APIC ID looked OK.
  347. //
  348. return TRUE;
  349. #endif //SETUP
  350. #ifdef DEBUGGING
  351. if ((ApicVersion & 0xf0) == 0) {
  352. if (HalpMpInfoTable.ApicVersion != APIC_82489DX)
  353. HalDisplayString("HAL:Invalid Local Apic version in MP table\n");
  354. else {
  355. sprintf(Cbuf, "HAL: DetectMPS: Found 82489DX Local APIC (Ver 0x%x) at 0x%lx\n",
  356. ApicVersion, LocalApic);
  357. HalDisplayString(Cbuf);
  358. }
  359. } else {
  360. sprintf(Cbuf, "HAL: DetectMPS: Found Embedded Local APIC (Ver 0x%x) at 0x%lx\n",
  361. ApicVersion, LocalApic);
  362. HalDisplayString(Cbuf);
  363. }
  364. #endif // DEBUGGING
  365. #ifndef SETUP
  366. HalpUnmapVirtualAddress(LocalApic,1);
  367. IoEntryPtr = HalpMpInfoTable.IoApicEntryPtr;
  368. for(i=0; i < HalpMpInfoTable.IOApicCount; i++, IoEntryPtr++)
  369. {
  370. if (IoEntryPtr->IoApicFlag & IO_APIC_ENABLED) {
  371. //
  372. // Verify the existance of the IO Units
  373. //
  374. physicalAddress.QuadPart = (ULONG)IoEntryPtr->IoApicAddress;
  375. HalpMpInfoTable.IoApicPhys[i] = (ULONG)IoEntryPtr->IoApicAddress;
  376. HalpMpInfoTable.IoApicBase[i] = (PULONG)
  377. HalpMapPhysicalMemoryWriteThrough64(physicalAddress, 1);
  378. //
  379. // Verify the existance of the IO Unit
  380. //
  381. if (!(HalpVerifyIOUnit((PUCHAR)HalpMpInfoTable.IoApicBase[i]))) {
  382. FAILMSG (rgzApicNotVerified);
  383. return (FALSE);
  384. }
  385. }
  386. }
  387. DBGMSG("HAL: DetectMPS: MPS system found - Returning TRUE\n");
  388. return(TRUE);
  389. #endif
  390. }
  391. ULONG
  392. DetectUPMPS(
  393. OUT PBOOLEAN IsConfiguredMp
  394. )
  395. /*++
  396. Routine Description:
  397. This function is called by setup after DetectMPS has returned
  398. false. During setup time DetectMPS will return false, if the
  399. machine is an MPS system, but only has one processor. This
  400. function is used to detect such a machine at setup time.
  401. Arguments:
  402. IsConfiguredMp - FALSE
  403. Return Value:
  404. 0 - if not a UP MPS
  405. 1 - if UP MPS
  406. --*/
  407. {
  408. *IsConfiguredMp = FALSE;
  409. // we assume the caller has already called DetectMPS, and the
  410. // MPS table has already been parsed.
  411. return (HalpMpInfoTable.ProcessorCount == 1 ? TRUE : FALSE);
  412. }