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.

653 lines
17 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. pcmpdtct.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. #include "apic.inc"
  25. #include "pcmp_nt.inc"
  26. #include "stdio.h"
  27. #if DEBUGGING
  28. CHAR Cbuf[120];
  29. VOID HalpDisplayConfigTable(VOID);
  30. VOID HalpDisplayExtConfigTable(VOID);
  31. VOID HalpDisplayBIOSSysCfg(struct SystemConfigTable *);
  32. #define DBGMSG(a) HalDisplayString(a)
  33. #else
  34. #define DBGMSG(a)
  35. #endif
  36. #define DEBUG_MSG(a)
  37. //
  38. // The floating pointer structure defined by the MPS spec can reside
  39. // anywhere in BIOS extended data area. These defines are used to search for
  40. // the floating structure starting from physical address 639K(9f000+c00)
  41. //
  42. #define PCMP_TABLE_PTR_BASE 0x09f000
  43. #define PCMP_TABLE_PTR_OFFSET 0x00000c00
  44. extern struct HalpMpInfo HalpMpInfoTable;
  45. UCHAR
  46. ComputeCheckSum(
  47. IN PUCHAR SourcePtr,
  48. IN USHORT NumOfBytes
  49. );
  50. VOID
  51. HalpUnmapVirtualAddress(
  52. IN PVOID VirtualAddress,
  53. IN ULONG NumberPages
  54. );
  55. struct FloatPtrStruct *
  56. SearchFloatPtr (
  57. ULONG PhysicalAddress,
  58. ULONG ByteSize
  59. );
  60. struct FloatPtrStruct *
  61. PcMpGetFloatingPtr (
  62. VOID
  63. );
  64. struct PcMpTable *
  65. GetPcMpTable (
  66. VOID
  67. );
  68. struct PcMpTable *
  69. MPS10_GetPcMpTablePtr (
  70. VOID
  71. );
  72. struct PcMpTable *
  73. MPS10_GetPcMpTable (
  74. VOID
  75. );
  76. struct PcMpTable *
  77. GetDefaultConfig (
  78. IN ULONG Config
  79. );
  80. #ifdef SETUP
  81. //
  82. // A dummy pointer to a default MPS table. For setup, we can conserve
  83. // space by not building default tables in our data area.
  84. #define DEFAULT_MPS_INDICATOR 0xfefefefe
  85. #define HalpUnmapVirtualAddress(a, b)
  86. #endif //SETUP
  87. #ifndef SETUP
  88. #ifdef ALLOC_PRAGMA
  89. #pragma alloc_text(PAGELK,SearchFloatPtr)
  90. #pragma alloc_text(PAGELK,PcMpGetFloatingPtr)
  91. #pragma alloc_text(PAGELK,ComputeCheckSum)
  92. #pragma alloc_text(PAGELK,GetPcMpTable)
  93. #pragma alloc_text(PAGELK,MPS10_GetPcMpTablePtr)
  94. #pragma alloc_text(PAGELK,MPS10_GetPcMpTable)
  95. #pragma alloc_text(PAGELK,GetDefaultConfig)
  96. #endif // ALLOC_PRAGMA
  97. extern struct PcMpTable *PcMpDefaultTablePtrs[];
  98. extern BOOLEAN HalpUse8254;
  99. #endif // ndef SETUP
  100. struct FloatPtrStruct *
  101. SearchFloatPtr(
  102. ULONG PhysicalAddress,
  103. ULONG ByteSize
  104. )
  105. {
  106. // Search for the MPS floating pointer structure starting from the
  107. // physical address given.
  108. USHORT Index, ParagraphLength;
  109. UCHAR CheckSum;
  110. struct FloatPtrStruct *VirtualAddress;
  111. BOOLEAN CheckSumError;
  112. PHYSICAL_ADDRESS physAddr = {0};
  113. #ifdef DEBUGGING
  114. sprintf(Cbuf, "SearchFloatPtr: Will search at physical address 0x%lx\n",
  115. PhysicalAddress);
  116. HalDisplayString(Cbuf);
  117. #endif // DEBUGGING
  118. // The MPS spec says that the floating pointer structure MUST be
  119. // aligned at 16 byte boundaries. We can use this fact to search for
  120. // the structure only at those boundaries. Assume that the input physical
  121. // address to start search from is 16 byte aligned.
  122. CheckSumError = FALSE;
  123. for(Index = 0; Index < (ByteSize/sizeof(struct FloatPtrStruct)); Index++) {
  124. physAddr.LowPart = PhysicalAddress + (Index * sizeof(struct FloatPtrStruct));
  125. VirtualAddress = (struct FloatPtrStruct *)HalpMapPhysicalMemory64(
  126. physAddr,
  127. 1
  128. );
  129. if (VirtualAddress == NULL) {
  130. DEBUG_MSG ("SearchFloatPtr: Cannot map Physical address\n");
  131. return (NULL);
  132. }
  133. if ( (*((PULONG)VirtualAddress) ) == MP_PTR_SIGNATURE) {
  134. ParagraphLength =
  135. ((struct FloatPtrStruct *)VirtualAddress)->MpTableLength;
  136. //
  137. // Detected the floating structure signature. Check if the
  138. // floating pointer structure checksum is valid.
  139. //
  140. CheckSum = ComputeCheckSum((PUCHAR)VirtualAddress,
  141. (USHORT) (ParagraphLength*16) );
  142. if (CheckSum == 0 ) {
  143. // We have a valid floating pointer structure.
  144. // Return a pointer to it.
  145. DEBUG_MSG ("SearchFloatPtr: Found structure\n");
  146. return((struct FloatPtrStruct *) VirtualAddress);
  147. }
  148. // Invalid structure. Continue searching.
  149. CheckSumError = TRUE;
  150. DEBUG_MSG ("SearchFloatPtr: Valid MP_PTR signature, invalid checksum\n");
  151. }
  152. //
  153. // Give back the PTE.
  154. //
  155. HalpUnmapVirtualAddress(VirtualAddress, 1);
  156. }
  157. if (CheckSumError) {
  158. FAILMSG (rgzMPPTRCheck);
  159. }
  160. return(NULL);
  161. }
  162. struct FloatPtrStruct *
  163. PcMpGetFloatingPtr(
  164. VOID)
  165. {
  166. ULONG EbdaSegmentPtr, BaseMemPtr;
  167. ULONG EbdaPhysicalAdd = 0, ByteLength, BaseMemKb = 0;
  168. struct FloatPtrStruct *FloatPtr = NULL;
  169. PUCHAR zeroVirtual;
  170. PHYSICAL_ADDRESS zeroPhysical;
  171. // Search for the floating pointer structure in the order specified in
  172. // MPS spec version 1.1.
  173. // First, search for it in the first kilobyte in the Extended BIOS Data
  174. // Area. The EBDA segment address is available at physical address 40:0E
  175. zeroPhysical = HalpPtrToPhysicalAddress( (PVOID)0 );
  176. zeroVirtual = HalpMapPhysicalMemory64( zeroPhysical, 1);
  177. EbdaSegmentPtr = (ULONG)(zeroVirtual + EBDA_SEGMENT_PTR);
  178. EbdaPhysicalAdd = *((PUSHORT)EbdaSegmentPtr);
  179. EbdaPhysicalAdd = EbdaPhysicalAdd << 4;
  180. if (EbdaPhysicalAdd != 0)
  181. FloatPtr = SearchFloatPtr(EbdaPhysicalAdd, 1024);
  182. HalpUnmapVirtualAddress(zeroVirtual, 1);
  183. if (FloatPtr == NULL) {
  184. // Did not find it in EBDA.
  185. // Look for it in the last KB of system memory.
  186. zeroVirtual = HalpMapPhysicalMemory64( zeroPhysical, 1);
  187. BaseMemPtr = (ULONG)(zeroVirtual + BASE_MEM_PTR);
  188. BaseMemKb = *((PUSHORT)BaseMemPtr);
  189. FloatPtr = SearchFloatPtr(BaseMemKb*1024, 1024);
  190. HalpUnmapVirtualAddress(zeroVirtual, 1);
  191. if (FloatPtr == NULL) {
  192. // Finally, look for the floating Pointer Structure at physical
  193. // address F0000H to FFFFFH
  194. ByteLength = 0xfffff - 0xf0000;
  195. FloatPtr = SearchFloatPtr(0xf0000, ByteLength);
  196. }
  197. }
  198. // At this point, we have a pointer to the MPS floating structure.
  199. return(FloatPtr);
  200. }
  201. struct PcMpTable *
  202. MPS10_GetPcMpTablePtr(
  203. VOID
  204. )
  205. /*++
  206. Routine Description:
  207. Gets the Address of the MPS configuration table built by BIOS.
  208. This routine looks for the floating pointer structure defined
  209. in the MPS spec. This structure points to the MPS configuration
  210. table built by an MP BIOS. The floating pointer structure can be
  211. located anywhere in the extended BIOS data area(physical address range
  212. 639K to 640K), and must be aligned on a 16 byte boundary.
  213. Arguments:
  214. None
  215. Return Value:
  216. struct PcMpTable * - Virtual address pointer to the PcMpTable, if
  217. it exists, NULL otherwise
  218. --*/
  219. {
  220. PUCHAR TempPtr;
  221. ULONG LinearPtr;
  222. UCHAR CheckSum;
  223. struct PcMpTableLocator *PcMpPtrPtr;
  224. PULONG TraversePtr;
  225. PVOID BasePtr;
  226. USHORT ParagraphLength;
  227. int i;
  228. PHYSICAL_ADDRESS physicalAddress;
  229. // Map the physical address of the BIOS extended data area to a virtual
  230. // address we can use.
  231. physicalAddress = HalpPtrToPhysicalAddress( (PVOID)PCMP_TABLE_PTR_BASE );
  232. BasePtr = (PUCHAR) HalpMapPhysicalMemory64(physicalAddress, 1);
  233. TempPtr = BasePtr;
  234. TraversePtr = (PULONG)((PUCHAR) TempPtr + PCMP_TABLE_PTR_OFFSET);
  235. // Look at 16 byte boundaries for the floating pointer structure
  236. // The structure is identified by its signature, and verified by its
  237. // checksum.
  238. for (i=0; i < (1024/16); ++i)
  239. {
  240. if (*(TraversePtr) == MP_PTR_SIGNATURE)
  241. {
  242. // Got a valid signature.
  243. PcMpPtrPtr = (struct PcMpTableLocator *)TraversePtr;
  244. // Length in 16 byte paragraphs of the floating structure.
  245. // Normally, this should be set to 1 by the BIOS.
  246. ParagraphLength = PcMpPtrPtr->MpTableLength;
  247. // Check if the floating pointer structure is valid.
  248. CheckSum = ComputeCheckSum((PUCHAR)PcMpPtrPtr,
  249. (USHORT) (ParagraphLength*16));
  250. if (CheckSum != 0 ) {
  251. FAILMSG (rgzMPPTRCheck);
  252. // Invalid structure. Continue searching.
  253. TraversePtr += 4;
  254. continue;
  255. }
  256. // We have a valid floating pointer structure.
  257. // The value stored in the structure is a physical address of the
  258. // MPS table built by BIOS. Get the corresponding virtual
  259. // address.
  260. physicalAddress = HalpPtrToPhysicalAddress( PcMpPtrPtr->TablePtr );
  261. TempPtr = HalpMapPhysicalMemory64(physicalAddress,2);
  262. //
  263. // Done with base pointer.
  264. //
  265. HalpUnmapVirtualAddress(BasePtr, 1);
  266. if (TempPtr == NULL) {
  267. DEBUG_MSG ("HAL: Cannot map BIOS created MPS table\n");
  268. return (NULL);
  269. }
  270. // Return the virtual address pointer to the MPS table.
  271. return((struct PcMpTable *) TempPtr);
  272. }
  273. TraversePtr += 4;
  274. }
  275. return(NULL);
  276. }
  277. UCHAR
  278. ComputeCheckSum (
  279. IN PUCHAR SourcePtr,
  280. IN USHORT NumOfBytes
  281. )
  282. /*++
  283. Routine Description:
  284. This routine computes a checksum for NumOfBytes bytes, starting
  285. from SourcePtr. It is used to validate the tables built by BIOS.
  286. Arguments:
  287. SourcePtr : Starting virtual address to compute checksum.
  288. NumOfBytes: Number of bytes to compute the checksum of.
  289. Return Value:
  290. The checksum value.
  291. */
  292. {
  293. UCHAR Result = 0;
  294. USHORT Count;
  295. for(Count=0; Count < NumOfBytes; ++Count)
  296. Result += *SourcePtr++;
  297. return(Result);
  298. }
  299. struct PcMpTable *
  300. MPS10_GetPcMpTable (
  301. VOID
  302. )
  303. /*++
  304. Routine Description:
  305. Detects an MPS 1.0 system only.
  306. Arguments:
  307. None.
  308. Return Value:
  309. Pointer to an MPS table.
  310. --*/
  311. {
  312. struct SystemConfigTable *SystemConfigPtr;
  313. UCHAR DefaultConfig, CheckSum;
  314. struct PcMpTable *MpTablePtr;
  315. UCHAR MpFeatureInfoByte1 = 0, MpFeatureInfoByte2 = 0;
  316. PHYSICAL_ADDRESS physicalAddress;
  317. // Get the virtual address of the system configuration table.
  318. physicalAddress = HalpPtrToPhysicalAddress( (PVOID)BIOS_BASE );
  319. SystemConfigPtr = (struct SystemConfigTable *)
  320. HalpMapPhysicalMemory64( physicalAddress, 16);
  321. if (SystemConfigPtr == NULL) {
  322. DEBUG_MSG ("GetPcMpTable: Cannot map system configuration table\n");
  323. return(NULL);
  324. }
  325. // HalpDisplayBIOSSysCfg(SystemConfigPtr);
  326. // The system configuration table built by BIOS has 2 MP feature
  327. // information bytes.
  328. MpFeatureInfoByte1 = SystemConfigPtr->MpFeatureInfoByte1;
  329. MpFeatureInfoByte2 = SystemConfigPtr->MpFeatureInfoByte2;
  330. // The second MP feature information byte tells us whether the system
  331. // has an IMCR(Interrupt Mode Control Register). We use this information
  332. // in the HAL, so we store this information in the OS specific private
  333. // area.
  334. if ((MpFeatureInfoByte2 & IMCR_MASK) == 0) {
  335. HalpMpInfoTable.IMCRPresent = 0;
  336. } else {
  337. HalpMpInfoTable.IMCRPresent = 1;
  338. }
  339. #ifndef SETUP
  340. // The second MP feature information byte tells us whether Time
  341. // Stamp Counter should be used as a high-resolution timer on
  342. // multiprocessor systems.
  343. if ((MpFeatureInfoByte2 & MULT_CLOCKS_MASK) != 0) {
  344. HalpUse8254 = 1;
  345. }
  346. #endif
  347. // MP feature byte 1 indicates if the system is MPS compliant
  348. if (! (MpFeatureInfoByte1 & PCMP_IMPLEMENTED)) {
  349. // The MP feature information byte indicates that this
  350. // system is not MPS compliant.
  351. FAILMSG (rgzNoMpsTable);
  352. return(NULL);
  353. }
  354. // The system is MPS compliant. MP feature byte 2 indicates if the
  355. // system is a default configuration or not.
  356. DefaultConfig = (MpFeatureInfoByte1 & PCMP_CONFIG_MASK) >> 1;
  357. if (DefaultConfig) {
  358. return GetDefaultConfig(DefaultConfig);
  359. }
  360. // DefaultConfig == 0. This means that the BIOS has built a MP
  361. // config table for us. The BIOS will also build a floating pointer
  362. // structure that points to the MP config table. This floating pointer
  363. // structure resides in the BIOS extended data area.
  364. MpTablePtr = MPS10_GetPcMpTablePtr();
  365. if (MpTablePtr == NULL) {
  366. FAILMSG (rgzNoMPTable); // Could not find BIOS created MPS table
  367. return(NULL);
  368. }
  369. // We have a pointer to the MP config table. Check if the table is valid.
  370. if ((MpTablePtr->Signature != PCMP_SIGNATURE) ||
  371. (MpTablePtr->TableLength < sizeof(struct PcMpTable)) ) {
  372. FAILMSG(rgzMPSBadSig);
  373. return(NULL);
  374. }
  375. CheckSum = ComputeCheckSum((PUCHAR)MpTablePtr, MpTablePtr->TableLength);
  376. if (CheckSum != 0) {
  377. FAILMSG(rgzMPSBadCheck);
  378. return(NULL);
  379. }
  380. return MpTablePtr;
  381. }
  382. struct PcMpTable *
  383. GetPcMpTable(
  384. VOID
  385. )
  386. /*++
  387. Routine Description:
  388. This routine gets the MP table for a MPS compliant system.
  389. For a MPS compliant system, either the BIOS builds an MP table, or
  390. it indicates that the system is one of the default configurations
  391. defined in the MPS spec. The MP feature information bytes in the BIOS
  392. system configuration table indicate whether the system is one of the
  393. default systems, or has a BIOS created MP table. For a default system
  394. configuration, this routine uses a statically built default table.
  395. This routine copies the MPS table into private system memory, and
  396. returns a pointer to this table.
  397. Arguments:
  398. None.
  399. Return Value:
  400. Pointer to the private copy of the MP table that has been copied in
  401. system memory.
  402. */
  403. {
  404. struct FloatPtrStruct *FloatingPtr;
  405. UCHAR CheckSum;
  406. struct PcMpTable *MpTablePtr;
  407. UCHAR MpFeatureInfoByte1 = 0, MpFeatureInfoByte2 = 0;
  408. PUCHAR TempPtr;
  409. PHYSICAL_ADDRESS physicalAddress;
  410. ULONG tableLength;
  411. DEBUG_MSG("GetMpTable\n");
  412. FloatingPtr = PcMpGetFloatingPtr();
  413. if (FloatingPtr == NULL) {
  414. FAILMSG (rgzNoMPTable);
  415. return(NULL);
  416. }
  417. // The floating structure has 2 MP feature information bytes.
  418. MpFeatureInfoByte1 = FloatingPtr->MpFeatureInfoByte1;
  419. MpFeatureInfoByte2 = FloatingPtr->MpFeatureInfoByte2;
  420. // The second MP feature information byte tells us whether the system
  421. // has an IMCR(Interrupt Mode Control Register). We use this information
  422. // in the HAL, so we store this information in the OS specific private
  423. // area.
  424. if ((MpFeatureInfoByte2 & IMCR_MASK) == 0)
  425. HalpMpInfoTable.IMCRPresent = 0;
  426. else
  427. HalpMpInfoTable.IMCRPresent = 1;
  428. if (MpFeatureInfoByte1 != 0) {
  429. // The system configuration is one of the default
  430. // configurations defined in the MPS spec. Find out which
  431. // default configuration it is and get a pointer to the
  432. // corresponding default table.
  433. return GetDefaultConfig(MpFeatureInfoByte1);
  434. }
  435. // MpFeatureInfoByte1 == 0. This means that the BIOS has built a MP
  436. // config table for us. The address of the OEM created table is in
  437. // the MPS floating structure.
  438. physicalAddress = HalpPtrToPhysicalAddress( FloatingPtr->TablePtr );
  439. TempPtr = HalpMapPhysicalMemory64(physicalAddress,2);
  440. HalpUnmapVirtualAddress(FloatingPtr, 1);
  441. if (TempPtr == NULL) {
  442. DEBUG_MSG ("HAL: Cannot map OEM MPS table [1]\n");
  443. return (NULL);
  444. }
  445. MpTablePtr = (struct PcMpTable *)TempPtr;
  446. // We have a pointer to the MP config table. Check if the table is valid.
  447. if ((MpTablePtr->Signature != PCMP_SIGNATURE) ||
  448. (MpTablePtr->TableLength < sizeof(struct PcMpTable)) ) {
  449. FAILMSG (rgzMPSBadSig);
  450. return(NULL);
  451. }
  452. //
  453. // Now re-map it, making sure that we have mapped enough pages.
  454. //
  455. tableLength = MpTablePtr->TableLength + MpTablePtr->ExtTableLength;
  456. HalpUnmapVirtualAddress(TempPtr, 2);
  457. MpTablePtr = (struct PcMpTable *)HalpMapPhysicalMemory64(
  458. physicalAddress,
  459. (ULONG)(((physicalAddress.QuadPart + tableLength) / PAGE_SIZE) -
  460. (physicalAddress.QuadPart / PAGE_SIZE) + 1)
  461. );
  462. if (MpTablePtr == NULL) {
  463. DEBUG_MSG ("HAL: Cannot map OEM MPS table [2]\n");
  464. return (NULL);
  465. }
  466. CheckSum = ComputeCheckSum((PUCHAR)MpTablePtr, MpTablePtr->TableLength);
  467. if (CheckSum != 0) {
  468. FAILMSG (rgzMPSBadCheck);
  469. return(NULL);
  470. }
  471. return MpTablePtr;
  472. }
  473. struct PcMpTable *
  474. GetDefaultConfig (
  475. IN ULONG Config
  476. )
  477. {
  478. Config -= 1;
  479. if (Config >= NUM_DEFAULT_CONFIGS) {
  480. FAILMSG (rgzBadDefault);
  481. return NULL;
  482. }
  483. #ifdef DEBUGGING
  484. HalDisplayString ("HALMPS: Using default table\n");
  485. #endif
  486. #ifdef SETUP
  487. return((struct PcMpTable *) DEFAULT_MPS_INDICATOR);
  488. #else
  489. return PcMpDefaultTablePtrs[Config];
  490. #endif // SETUP
  491. }