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.

355 lines
7.9 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. mpclock.c
  5. Abstract:
  6. This module implements processor starup code.
  7. Author:
  8. Forrest Foltz (forrestf) 27-Oct-2000
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "halcmn.h"
  14. #include <acpitabl.h>
  15. #include <xxacpi.h>
  16. #include <ixsleep.h>
  17. #if !defined(NT_UP)
  18. //
  19. // Pull in the real- and 32-bit protected-mode object code
  20. //
  21. #include "pmstub.h"
  22. #include "rmstub.h"
  23. extern UCHAR HalpLMStub[];
  24. extern UCHAR HalpLMStubEnd[];
  25. extern UCHAR HalpLMStubTarget[];
  26. #endif
  27. extern BOOLEAN HalpHiberInProgress;
  28. extern PUCHAR Halp1stPhysicalPageVaddr;
  29. #define WARM_RESET_VECTOR 0x467 // warm reset vector in ROM data segment
  30. #define CMOS_SHUTDOWN_REG 0x0f
  31. #define CMOS_SHUTDOWN_JMP 0x0a
  32. #define _20BITS (1 << 20)
  33. ULONG
  34. HalpStartProcessor (
  35. IN PVOID InitCodePhysAddr,
  36. IN ULONG ProcessorNumber
  37. );
  38. VOID
  39. HalpBuildKGDTEntry32 (
  40. IN PKGDTENTRY64 Gdt,
  41. IN ULONG Selector,
  42. IN ULONG Base,
  43. IN ULONG Limit,
  44. IN ULONG Type,
  45. IN BOOLEAN LongMode
  46. );
  47. BOOLEAN
  48. HalStartNextProcessor (
  49. IN PLOADER_PARAMETER_BLOCK LoaderBlock,
  50. IN PKPROCESSOR_STATE ProcessorState
  51. )
  52. /*++
  53. Routine Description:
  54. This routine is called by the kernel during kernel initialization to
  55. obtain more processors. It is called until no more processors are
  56. available.
  57. If another processor exists this function is to initialize it to the
  58. passed in processor state structure, and return TRUE.
  59. If another processor does not exist or if the processor fails to start,
  60. then FALSE is returned.
  61. Also note that the loader block has been set up for the next processor.
  62. The new processor logical thread number can be obtained from it if
  63. required.
  64. In order to use the Startup IPI the real mode startup code must be page
  65. aligned. The HalpLowStubPhysicalAddress has always been page aligned
  66. but because the PxParamBlock was placed first in this segment the real
  67. mode code has been something other than page aligned. THis has been
  68. changed by making the first entry in the PxParamBlock a jump instruction
  69. to the real mode startup code.
  70. Arguments:
  71. LoaderBlock - A pointer to the loader block which has been initialized
  72. for the next processor.
  73. ProcessorState - A pointer to a structure which containts the initial
  74. state of the processor.
  75. Return Value:
  76. TRUE - ProcessorNumber was dispatched.
  77. FALSE - A processor was not dispatched, or no other processor exists.
  78. --*/
  79. {
  80. #if defined(NT_UP)
  81. return FALSE;
  82. #else
  83. C_ASSERT(PSB_GDT32_CODE64 == KGDT64_R0_CODE);
  84. ULONG cr3;
  85. PPROCESSOR_START_BLOCK startupBlock;
  86. ULONG __unaligned *resetVectorLocation;
  87. ULONG oldResetVector;
  88. ULONG newResetVector;
  89. UCHAR cmosValue;
  90. PKPRCB prcb;
  91. ULONG apicId;
  92. ULONG count;
  93. PVOID pmStubStart;
  94. ULONG startupBlockPhysical;
  95. PVOID pmStub;
  96. PCHAR dst;
  97. return FALSE;
  98. //
  99. // Initialize the startup block
  100. //
  101. startupBlock = (PPROCESSOR_START_BLOCK)HalpLowStub;
  102. startupBlockPhysical = PtrToUlong(HalpLowStubPhysicalAddress);
  103. startupBlock->SelfMap = startupBlock;
  104. //
  105. // Copy the x86 16-bit real-mode startup code.
  106. //
  107. dst = (PCHAR)startupBlock;
  108. RtlCopyMemory(dst, HalpRMStub, HalpRMStubSize);
  109. //
  110. // Copy the x86 32-bit protected-mode startup code and set PmTarget.
  111. //
  112. dst += HalpRMStubSize;
  113. RtlCopyMemory(dst, HalpPMStub, HalpPMStubSize);
  114. startupBlock->PmTarget.Selector = PSB_GDT32_CODE32;
  115. startupBlock->PmTarget.Offset =
  116. (ULONG)(dst - (PUCHAR)startupBlock) + startupBlockPhysical;
  117. //
  118. // Copy the AMD64 longmode startup code and set LmTarget.
  119. //
  120. startupBlock->LmTarget.Selector = PSB_GDT32_CODE64;
  121. startupBlock->LmTarget.Offset = (ULONG64)&HalpLMStub;
  122. //
  123. // Build the temporary GDT entries to be used while in 32-bit
  124. // protected mode
  125. //
  126. HalpBuildKGDTEntry32(startupBlock->Gdt,
  127. PSB_GDT32_CODE32,
  128. 0,
  129. (ULONG)(-1),
  130. TYPE_CODE,
  131. FALSE);
  132. HalpBuildKGDTEntry32(startupBlock->Gdt,
  133. PSB_GDT32_DATA32,
  134. 0,
  135. (ULONG)(-1),
  136. TYPE_DATA,
  137. FALSE);
  138. //
  139. // Build the temporary code selector GDT entry to be used while in long
  140. // mode.
  141. //
  142. HalpBuildKGDTEntry32(startupBlock->Gdt,
  143. PSB_GDT32_CODE64,
  144. 0, // base and limit are ignored in
  145. 0, // a long-mode CS selector
  146. TYPE_CODE,
  147. TRUE);
  148. //
  149. // Build the pseudo-descriptor for the GDT
  150. //
  151. startupBlock->Gdt32.Limit = sizeof(startupBlock->Gdt) - 1;
  152. startupBlock->Gdt32.Base =
  153. startupBlockPhysical + FIELD_OFFSET(PROCESSOR_START_BLOCK,Gdt);
  154. //
  155. // Build a CR3 for the starting processor. If returning from
  156. // hibernation, then use setup tiled CR3 else create a new map.
  157. //
  158. if (HalpHiberInProgress == FALSE) {
  159. startupBlock->TiledCr3 = HalpBuildTiledCR3(ProcessorState);
  160. } else {
  161. startupBlock->TiledCr3 = CurTiledCr3LowPart;
  162. }
  163. //
  164. // Copy in the processor state and the linear address of the startup
  165. // block, and zero the completionflag.
  166. //
  167. startupBlock->ProcessorState = *ProcessorState;
  168. startupBlock->CompletionFlag = 0;
  169. //
  170. // The reset vector lives in the BIOS data area. Build a pointer to it
  171. // and store the existing value locally.
  172. //
  173. resetVectorLocation = (PULONG)((PUCHAR)Halp1stPhysicalPageVaddr +
  174. WARM_RESET_VECTOR);
  175. oldResetVector = *resetVectorLocation;
  176. //
  177. // Build the new real-mode vector in SEG:OFFS format and store it in the
  178. // BIOS data area.
  179. //
  180. newResetVector = PtrToUlong(HalpLowStubPhysicalAddress);
  181. newResetVector <<= 12;
  182. *resetVectorLocation = newResetVector;
  183. //
  184. // Tell the BIOS to jump via the vector we gave it by setting the
  185. // reset code in the cmos
  186. //
  187. HalpAcquireCmosSpinLock();
  188. cmosValue = CMOS_READ(CMOS_SHUTDOWN_REG);
  189. CMOS_WRITE(CMOS_SHUTDOWN_REG,CMOS_SHUTDOWN_JMP);
  190. HalpReleaseCmosSpinLock();
  191. prcb = (PKPRCB)LoaderBlock->Prcb;
  192. apicId = HalpStartProcessor(HalpLowStubPhysicalAddress, prcb->Number);
  193. #if 0 // later
  194. if (apicId != 0) {
  195. apicId -= 1;
  196. prcb->HalReserved.PCMPApicId = apicId;
  197. }
  198. for (count = 0; count < 200; count += 1) {
  199. if (startupBock->
  200. }
  201. #endif
  202. return FALSE;
  203. #endif // NT_UP
  204. }
  205. VOID
  206. HalpBuildKGDTEntry32 (
  207. IN PKGDTENTRY64 Gdt,
  208. IN ULONG Selector,
  209. IN ULONG Base,
  210. IN ULONG Limit,
  211. IN ULONG Type,
  212. IN BOOLEAN LongMode
  213. )
  214. {
  215. KGDT_BASE base;
  216. KGDT_LIMIT limit;
  217. PKGDTENTRY64 gdtEntry;
  218. gdtEntry = &Gdt[Selector >> 4];
  219. //
  220. // Note that although gdtEntry points to a 16-byte structure,
  221. // we're actually building an 8-byte GDT so we are careful to not
  222. // touch the high 8 bytes.
  223. //
  224. RtlZeroMemory(gdtEntry, 8);
  225. //
  226. // Set limit information
  227. //
  228. if (Limit > (_20BITS - 1)) {
  229. gdtEntry->Bits.Granularity = GRANULARITY_PAGE;
  230. limit.Limit = Limit / PAGE_SIZE;
  231. } else {
  232. limit.Limit = Limit;
  233. }
  234. gdtEntry->LimitLow = limit.LimitLow;
  235. gdtEntry->Bits.LimitHigh = limit.LimitHigh;
  236. //
  237. // Set base information
  238. //
  239. base.Base = Base;
  240. gdtEntry->BaseLow = base.BaseLow;
  241. gdtEntry->Bits.BaseMiddle = base.BaseMiddle;
  242. gdtEntry->Bits.BaseHigh = base.BaseHigh;
  243. //
  244. // Set other bits
  245. //
  246. gdtEntry->Bits.Present = 1;
  247. gdtEntry->Bits.Dpl = DPL_SYSTEM;
  248. gdtEntry->Bits.DefaultBig = 1;
  249. gdtEntry->Bits.Type = Type;
  250. if (LongMode != FALSE) {
  251. gdtEntry->Bits.LongMode = 1;
  252. }
  253. }