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.

556 lines
17 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. ntsetup.c
  5. Abstract:
  6. This module is the tail-end of the OS loader program. It performs all
  7. IA64 specific allocations and initialize. The OS loader invokes this
  8. this routine immediately before calling the loaded kernel image.
  9. Author:
  10. Allen Kay (akay) 19-May-1999
  11. based on MIPS version by John Vert (jvert) 20-Jun-1991
  12. Environment:
  13. Kernel mode
  14. Revision History:
  15. --*/
  16. #include "bldr.h"
  17. #include "stdio.h"
  18. #include "bootia64.h"
  19. #include "sal.h"
  20. #include "efi.h"
  21. #include "fpswa.h"
  22. #include "extern.h"
  23. //
  24. // Define macro to round structure size to next 16-byte boundary
  25. //
  26. #undef ROUND_UP
  27. #define ROUND_UP(x) ((sizeof(x) + 15) & (~15))
  28. #define MIN(_a,_b) (((_a) <= (_b)) ? (_a) : (_b))
  29. #define MAX(_a,_b) (((_a) <= (_b)) ? (_b) : (_a))
  30. //
  31. // Configuration Data Header
  32. // The following structure is copied from fw\mips\oli2msft.h
  33. // NOTE shielint - Somehow, this structure got incorporated into
  34. // firmware EISA configuration data. We need to know the size of the
  35. // header and remove it before writing eisa configuration data to
  36. // registry.
  37. //
  38. typedef struct _CONFIGURATION_DATA_HEADER {
  39. USHORT Version;
  40. USHORT Revision;
  41. PCHAR Type;
  42. PCHAR Vendor;
  43. PCHAR ProductName;
  44. PCHAR SerialNumber;
  45. } CONFIGURATION_DATA_HEADER;
  46. #define CONFIGURATION_DATA_HEADER_SIZE sizeof(CONFIGURATION_DATA_HEADER)
  47. //
  48. // Global Definition: This structure value is setup in sumain.c
  49. //
  50. TR_INFO ItrInfo[8], DtrInfo[8];
  51. extern ULONGLONG MemoryMapKey;
  52. //
  53. // Internal function references
  54. //
  55. VOID
  56. BlQueryImplementationAndRevision (
  57. OUT PULONG ProcessorId,
  58. OUT PULONG FloatingId
  59. );
  60. VOID
  61. BlTrCleanUp (
  62. );
  63. ARC_STATUS
  64. BlSetupForNt(
  65. IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
  66. )
  67. /*++
  68. Routine Description:
  69. This function initializes the IA64 specific kernel data structures
  70. required by the NT system.
  71. Arguments:
  72. BlLoaderBlock - Supplies the address of the loader parameter block.
  73. Return Value:
  74. ESUCCESS is returned if the setup is successfully complete. Otherwise,
  75. an unsuccessful status is returned.
  76. --*/
  77. {
  78. PCONFIGURATION_COMPONENT_DATA ConfigEntry;
  79. ULONG FloatingId;
  80. CHAR Identifier[256];
  81. ULONG KernelPage;
  82. ULONG LinesPerBlock;
  83. ULONG LineSize;
  84. PCHAR NewIdentifier;
  85. ULONGLONG PrcbPage;
  86. ULONG ProcessorId;
  87. ARC_STATUS Status;
  88. ULONG i;
  89. PULONG KernelStructureBase;
  90. PHARDWARE_PTE SelfMapPde;
  91. PHARDWARE_PTE Pde;
  92. PHARDWARE_PTE HalPT;
  93. PLIST_ENTRY NextMd;
  94. PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
  95. EFI_MEMORY_DESCRIPTOR * MemoryMap = NULL;
  96. ULONGLONG MemoryMapSize = 0;
  97. ULONGLONG MapKey;
  98. ULONGLONG DescriptorSize;
  99. ULONG DescriptorVersion;
  100. EFI_STATUS EfiStatus;
  101. EFI_GUID FpswaId = EFI_INTEL_FPSWA;
  102. EFI_HANDLE FpswaImage;
  103. FPSWA_INTERFACE *FpswaInterface;
  104. ULONGLONG BufferSize;
  105. BOOLEAN FpswaFound = FALSE;
  106. //
  107. // Allocate DPC stack pages for the boot processor.
  108. //
  109. Status = BlAllocateDescriptor(LoaderStartupDpcStack,
  110. 0,
  111. (KERNEL_BSTORE_SIZE + KERNEL_STACK_SIZE) >> PAGE_SHIFT,
  112. &KernelPage);
  113. if (Status != ESUCCESS) {
  114. return(Status);
  115. }
  116. BlLoaderBlock->u.Ia64.InterruptStack =
  117. (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
  118. //
  119. // Allocate kernel stack pages for the boot processor idle thread.
  120. //
  121. Status = BlAllocateDescriptor(LoaderStartupKernelStack,
  122. 0,
  123. (KERNEL_BSTORE_SIZE + KERNEL_STACK_SIZE) >> PAGE_SHIFT,
  124. &KernelPage);
  125. if (Status != ESUCCESS) {
  126. return(Status);
  127. }
  128. BlLoaderBlock->KernelStack =
  129. (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
  130. //
  131. // Allocate panic stack pages for the boot processor.
  132. //
  133. Status = BlAllocateDescriptor(LoaderStartupPanicStack,
  134. 0,
  135. (KERNEL_BSTORE_SIZE + KERNEL_STACK_SIZE) >> PAGE_SHIFT,
  136. &KernelPage);
  137. if (Status != ESUCCESS) {
  138. return(Status);
  139. }
  140. BlLoaderBlock->u.Ia64.PanicStack =
  141. (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
  142. //
  143. // Allocate and zero two pages for the PCR.
  144. //
  145. Status = BlAllocateDescriptor(LoaderStartupPcrPage,
  146. 0,
  147. 2,
  148. (PULONG) &BlLoaderBlock->u.Ia64.PcrPage);
  149. if (Status != ESUCCESS) {
  150. return(Status);
  151. }
  152. BlLoaderBlock->u.Ia64.PcrPage2 = BlLoaderBlock->u.Ia64.PcrPage + 1;
  153. RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Ia64.PcrPage << PAGE_SHIFT)),
  154. PAGE_SIZE * 2);
  155. //
  156. // Allocate and zero four pages for the PDR and one page of memory for
  157. // the initial processor block, idle process, and idle thread structures.
  158. //
  159. Status = BlAllocateDescriptor(LoaderStartupPdrPage,
  160. 0,
  161. 3,
  162. (PULONG) &BlLoaderBlock->u.Ia64.PdrPage);
  163. if (Status != ESUCCESS) {
  164. return(Status);
  165. }
  166. RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Ia64.PdrPage << PAGE_SHIFT)),
  167. PAGE_SIZE * 3);
  168. //
  169. // The storage for processor control block, the idle thread object, and
  170. // the idle thread process object are allocated from the third page of the
  171. // PDR allocation. The addresses of these data structures are computed
  172. // and stored in the loader parameter block and the memory is zeroed.
  173. //
  174. PrcbPage = BlLoaderBlock->u.Ia64.PdrPage + 1;
  175. if ((PAGE_SIZE * 2) >= (ROUND_UP(KPRCB) + ROUND_UP(EPROCESS) + ROUND_UP(ETHREAD))) {
  176. BlLoaderBlock->Prcb = KSEG0_BASE | (PrcbPage << PAGE_SHIFT);
  177. BlLoaderBlock->Process = BlLoaderBlock->Prcb + ROUND_UP(KPRCB);
  178. BlLoaderBlock->Thread = BlLoaderBlock->Process + ROUND_UP(EPROCESS);
  179. } else {
  180. return(ENOMEM);
  181. }
  182. Status = BlAllocateDescriptor(LoaderStartupPdrPage,
  183. 0,
  184. 1,
  185. &KernelPage);
  186. if (Status != ESUCCESS) {
  187. return(Status);
  188. }
  189. RtlZeroMemory((PVOID)(KSEG0_BASE | ((ULONGLONG) KernelPage << PAGE_SHIFT)),
  190. PAGE_SIZE * 1);
  191. //
  192. // Setup last two entries in the page directory table for HAL and
  193. // allocate page tables for them.
  194. //
  195. Pde = (PHARDWARE_PTE) (ULONG_PTR)( (BlLoaderBlock->u.Ia64.PdrPage) << PAGE_SHIFT);
  196. Pde[(KIPCR & 0xffffffff) >> PDI_SHIFT].PageFrameNumber = (ULONG) KernelPage;
  197. Pde[(KIPCR & 0xffffffff) >> PDI_SHIFT].Valid = 1;
  198. Pde[(KIPCR & 0xffffffff) >> PDI_SHIFT].Cache = 0;
  199. Pde[(KIPCR & 0xffffffff) >> PDI_SHIFT].Accessed = 1;
  200. Pde[(KIPCR & 0xffffffff) >> PDI_SHIFT].Dirty = 1;
  201. Pde[(KIPCR & 0xffffffff) >> PDI_SHIFT].Execute = 1;
  202. Pde[(KIPCR & 0xffffffff) >> PDI_SHIFT].Write = 1;
  203. Pde[(KIPCR & 0xffffffff) >> PDI_SHIFT].CopyOnWrite = 1;
  204. //
  205. // 0xFFC00000 is the starting virtual address of Pde[2046].
  206. //
  207. HalPT = (PHARDWARE_PTE)((ULONG_PTR) KernelPage << PAGE_SHIFT);
  208. HalPT[GetPteOffset(KI_USER_SHARED_DATA)].PageFrameNumber = BlLoaderBlock->u.Ia64.PcrPage2;
  209. HalPT[GetPteOffset(KI_USER_SHARED_DATA)].Valid = 1;
  210. HalPT[GetPteOffset(KI_USER_SHARED_DATA)].Cache = 0;
  211. HalPT[GetPteOffset(KI_USER_SHARED_DATA)].Accessed = 1;
  212. HalPT[GetPteOffset(KI_USER_SHARED_DATA)].Dirty = 1;
  213. HalPT[GetPteOffset(KI_USER_SHARED_DATA)].Execute = 1;
  214. HalPT[GetPteOffset(KI_USER_SHARED_DATA)].Write = 1;
  215. HalPT[GetPteOffset(KI_USER_SHARED_DATA)].CopyOnWrite = 1;
  216. //
  217. // Fill in the rest of the loader block fields.
  218. //
  219. BlLoaderBlock->u.Ia64.AcpiRsdt = (ULONG_PTR) AcpiTable;
  220. //
  221. // Fill the ItrInfo and DtrInfo fields
  222. //
  223. BlLoaderBlock->u.Ia64.EfiSystemTable = (ULONG_PTR) EfiST;
  224. BlLoaderBlock->u.Ia64.PalProcVirtual = (ULONG_PTR) PalProcVirtual;
  225. //
  226. // Fill in ItrInfo and DtrInfo for DRIVER0
  227. //
  228. BlLoaderBlock->u.Ia64.ItrInfo[ITR_DRIVER0_INDEX].Index = ITR_DRIVER0_INDEX;
  229. BlLoaderBlock->u.Ia64.ItrInfo[ITR_DRIVER0_INDEX].PageSize = PS_16M;
  230. BlLoaderBlock->u.Ia64.ItrInfo[ITR_DRIVER0_INDEX].VirtualAddress = KSEG0_BASE + BL_16M;
  231. BlLoaderBlock->u.Ia64.ItrInfo[ITR_DRIVER0_INDEX].PhysicalAddress = BL_16M;
  232. BlLoaderBlock->u.Ia64.DtrInfo[DTR_DRIVER0_INDEX].Index = DTR_DRIVER0_INDEX;
  233. BlLoaderBlock->u.Ia64.DtrInfo[DTR_DRIVER0_INDEX].PageSize = PS_16M;
  234. BlLoaderBlock->u.Ia64.DtrInfo[DTR_DRIVER0_INDEX].VirtualAddress = KSEG0_BASE + BL_16M;
  235. BlLoaderBlock->u.Ia64.DtrInfo[DTR_DRIVER0_INDEX].PhysicalAddress = BL_16M;
  236. //
  237. // Fill in ItrInfo and DtrInfo for DRIVER1
  238. //
  239. BlLoaderBlock->u.Ia64.ItrInfo[ITR_DRIVER1_INDEX].Index = ITR_DRIVER1_INDEX;
  240. BlLoaderBlock->u.Ia64.ItrInfo[ITR_DRIVER1_INDEX].PageSize = PS_16M;
  241. BlLoaderBlock->u.Ia64.ItrInfo[ITR_DRIVER1_INDEX].VirtualAddress = KSEG0_BASE + BL_32M;
  242. BlLoaderBlock->u.Ia64.ItrInfo[ITR_DRIVER1_INDEX].PhysicalAddress = BL_32M;
  243. BlLoaderBlock->u.Ia64.DtrInfo[DTR_DRIVER1_INDEX].Index = DTR_DRIVER1_INDEX;
  244. BlLoaderBlock->u.Ia64.DtrInfo[DTR_DRIVER1_INDEX].PageSize = PS_16M;
  245. BlLoaderBlock->u.Ia64.DtrInfo[DTR_DRIVER1_INDEX].VirtualAddress = KSEG0_BASE + BL_32M;
  246. BlLoaderBlock->u.Ia64.DtrInfo[DTR_DRIVER1_INDEX].PhysicalAddress = BL_32M;
  247. //
  248. // Fill in ItrInfo and DtrInfo for KERNEL
  249. //
  250. BlLoaderBlock->u.Ia64.ItrInfo[ITR_KERNEL_INDEX].Index = ITR_KERNEL_INDEX;
  251. BlLoaderBlock->u.Ia64.ItrInfo[ITR_KERNEL_INDEX].PageSize = PS_16M;
  252. BlLoaderBlock->u.Ia64.ItrInfo[ITR_KERNEL_INDEX].VirtualAddress = KSEG0_BASE + BL_48M;
  253. BlLoaderBlock->u.Ia64.ItrInfo[ITR_KERNEL_INDEX].PhysicalAddress = BL_48M;
  254. BlLoaderBlock->u.Ia64.DtrInfo[DTR_KERNEL_INDEX].Index = DTR_KERNEL_INDEX;
  255. BlLoaderBlock->u.Ia64.DtrInfo[DTR_KERNEL_INDEX].PageSize = PS_16M;
  256. BlLoaderBlock->u.Ia64.DtrInfo[DTR_KERNEL_INDEX].VirtualAddress = KSEG0_BASE + BL_48M;
  257. BlLoaderBlock->u.Ia64.DtrInfo[DTR_KERNEL_INDEX].PhysicalAddress = BL_48M;
  258. //
  259. // Fill in ItrInfo and DtrInfo for PAL
  260. //
  261. BlLoaderBlock->u.Ia64.ItrInfo[ITR_PAL_INDEX].Index = ITR_PAL_INDEX;
  262. BlLoaderBlock->u.Ia64.ItrInfo[ITR_PAL_INDEX].PageSize = (ULONG) PalTrPs;
  263. BlLoaderBlock->u.Ia64.ItrInfo[ITR_PAL_INDEX].VirtualAddress = VIRTUAL_PAL_BASE;
  264. BlLoaderBlock->u.Ia64.ItrInfo[ITR_PAL_INDEX].PhysicalAddress = PalPhysicalBase;
  265. BlLoaderBlock->u.Ia64.DtrInfo[DTR_PAL_INDEX].Index = DTR_PAL_INDEX;
  266. BlLoaderBlock->u.Ia64.DtrInfo[DTR_PAL_INDEX].PageSize = (ULONG) PalTrPs;
  267. BlLoaderBlock->u.Ia64.DtrInfo[DTR_PAL_INDEX].VirtualAddress = VIRTUAL_PAL_BASE;
  268. BlLoaderBlock->u.Ia64.DtrInfo[DTR_PAL_INDEX].PhysicalAddress = PalPhysicalBase;
  269. //
  270. // Fill in ItrInfo and DtrInfo for IO port
  271. //
  272. BlLoaderBlock->u.Ia64.DtrInfo[DTR_IO_PORT_INDEX].Index = DTR_IO_PORT_INDEX;
  273. BlLoaderBlock->u.Ia64.DtrInfo[DTR_IO_PORT_INDEX].PageSize = (ULONG) IoPortTrPs;
  274. BlLoaderBlock->u.Ia64.DtrInfo[DTR_IO_PORT_INDEX].VirtualAddress = VIRTUAL_IO_BASE;
  275. BlLoaderBlock->u.Ia64.DtrInfo[DTR_IO_PORT_INDEX].PhysicalAddress = IoPortPhysicalBase;
  276. //
  277. // Flush all caches.
  278. //
  279. if (SYSTEM_BLOCK->FirmwareVectorLength > (sizeof(PVOID) * FlushAllCachesRoutine)) {
  280. ArcFlushAllCaches();
  281. }
  282. //
  283. // make memory map by TR's unavailable for kernel use.
  284. //
  285. NextMd = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  286. while (NextMd != &BlLoaderBlock->MemoryDescriptorListHead) {
  287. MemoryDescriptor = CONTAINING_RECORD(NextMd,
  288. MEMORY_ALLOCATION_DESCRIPTOR,
  289. ListEntry);
  290. //
  291. // lock down pages we don't want the kernel to use.
  292. // NB. The only reason we need to lock down LoaderLoadedProgram because
  293. // there is static data in the loader image that the kernel uses.
  294. //
  295. if ((MemoryDescriptor->MemoryType == LoaderLoadedProgram) ||
  296. (MemoryDescriptor->MemoryType == LoaderOsloaderStack)) {
  297. MemoryDescriptor->MemoryType = LoaderFirmwarePermanent;
  298. }
  299. //
  300. // we've marked lots of memory as off limits to trick our allocator
  301. // into allocating memory at a specific location (which is necessary to
  302. // get hte kernel loaded at the right location, etc.). We do this by
  303. // marking the page type as LoaderSystemBlock. Now that we're done
  304. // allocating memory, we can restore all of the LoaderSystemBlock pages
  305. // to LoaderFree, so that the kernel can use this memory.
  306. //
  307. if (MemoryDescriptor->MemoryType == LoaderSystemBlock) {
  308. MemoryDescriptor->MemoryType = LoaderFree;
  309. }
  310. NextMd = MemoryDescriptor->ListEntry.Flink;
  311. }
  312. //
  313. // Go to physical mode before making EFI calls.
  314. //
  315. FlipToPhysical();
  316. //
  317. // Get processor configuration information
  318. //
  319. ReadProcessorConfigInfo( &BlLoaderBlock->u.Ia64.ProcessorConfigInfo );
  320. //
  321. // Get FP assist handle
  322. //
  323. BufferSize = sizeof(FpswaImage);
  324. EfiStatus = EfiBS->LocateHandle(ByProtocol,
  325. &FpswaId,
  326. NULL,
  327. &BufferSize,
  328. &FpswaImage
  329. );
  330. if (!EFI_ERROR(EfiStatus)) {
  331. //
  332. // Get FP assist protocol interface.
  333. //
  334. EfiStatus = EfiBS->HandleProtocol(FpswaImage, &FpswaId, &FpswaInterface);
  335. if (EFI_ERROR(EfiStatus)) {
  336. EfiST->ConOut->OutputString(
  337. EfiST->ConOut,
  338. L"BlSetupForNt: Could not get FP assist entry point\n"
  339. );
  340. EfiBS->Exit(EfiImageHandle, EfiStatus, 0, 0);
  341. }
  342. FpswaFound = TRUE;
  343. }
  344. #if 1
  345. //
  346. // The following code must be fixed to handle ExitBootServices() failing
  347. // because the memory map has changed in between calls to GetMemoryMap and
  348. // the call to ExitBootServices(). We should also walk the EFI memory map
  349. // and correlate it against the MemoryDescriptorList to ensure that all of
  350. // the memory is properly accounted for.
  351. //
  352. //
  353. // Get memory map info from EFI firmware
  354. //
  355. EfiStatus = EfiBS->GetMemoryMap (
  356. &MemoryMapSize,
  357. MemoryMap,
  358. &MapKey,
  359. &DescriptorSize,
  360. &DescriptorVersion
  361. );
  362. if (EfiStatus != EFI_BUFFER_TOO_SMALL) {
  363. EfiST->ConOut->OutputString(EfiST->ConOut,
  364. L"BlSetupForNt: GetMemoryMap failed\r\n");
  365. EfiBS->Exit(EfiImageHandle, EfiStatus, 0, 0);
  366. }
  367. FlipToVirtual();
  368. #if DBG
  369. DbgPrint( "About to call BlAllocateAlignedDescriptor for %x\r\n",
  370. MAX((MemoryMapSize >> 16), 1));
  371. #endif
  372. Status = BlAllocateAlignedDescriptor(
  373. LoaderOsloaderHeap,
  374. 0,
  375. (ULONG)(MAX((MemoryMapSize >> 16), 1)),
  376. 0,
  377. &KernelPage);
  378. if (Status != ESUCCESS) {
  379. return(Status);
  380. }
  381. FlipToPhysical();
  382. //
  383. // We need a physical address for EFI, and the hal expects a physical
  384. // address as well.
  385. //
  386. MemoryMap = (PVOID)(ULONGLONG)((ULONGLONG)KernelPage << PAGE_SHIFT);
  387. EfiStatus = EfiBS->GetMemoryMap (
  388. &MemoryMapSize,
  389. MemoryMap,
  390. &MapKey,
  391. &DescriptorSize,
  392. &DescriptorVersion
  393. );
  394. if (EFI_ERROR(EfiStatus)) {
  395. EfiST->ConOut->OutputString(EfiST->ConOut,
  396. L"BlSetupForNt: GetMemoryMap failed\r\n");
  397. EfiBS->Exit(EfiImageHandle, EfiStatus, 0, 0);
  398. }
  399. //
  400. // Call EFI exit boot services. No more Efi calls to boot services
  401. // API's will be called beyond this point.
  402. //
  403. EfiStatus = EfiBS->ExitBootServices (
  404. EfiImageHandle,
  405. MapKey
  406. );
  407. if (EFI_ERROR(EfiStatus)) {
  408. EfiST->ConOut->OutputString(EfiST->ConOut,
  409. L"BlSetupForNt: ExitBootServices failed\r\n");
  410. EfiBS->Exit(EfiImageHandle, EfiStatus, 0, 0);
  411. }
  412. #endif
  413. //
  414. // Go back to virtual mode.
  415. //
  416. FlipToVirtual();
  417. //
  418. // Pass EFI memory descriptor Parameters to kernel through OS
  419. // loader block.
  420. //
  421. BlLoaderBlock->u.Ia64.EfiMemMapParam.MemoryMapSize = MemoryMapSize;
  422. BlLoaderBlock->u.Ia64.EfiMemMapParam.MemoryMap = (PUCHAR) MemoryMap;
  423. BlLoaderBlock->u.Ia64.EfiMemMapParam.MapKey = MapKey;
  424. BlLoaderBlock->u.Ia64.EfiMemMapParam.DescriptorSize = DescriptorSize;
  425. BlLoaderBlock->u.Ia64.EfiMemMapParam.DescriptorVersion = DescriptorVersion;
  426. if (FpswaFound) {
  427. BlLoaderBlock->u.Ia64.FpswaInterface = (ULONG_PTR) FpswaInterface;
  428. } else {
  429. BlLoaderBlock->u.Ia64.FpswaInterface = (ULONG_PTR) NULL;
  430. }
  431. //
  432. // Clean up TR's used by boot loader but not needed by ntoskrnl.
  433. //
  434. BlTrCleanUp();
  435. //
  436. // Flush the memory range where kernel, hal, and the drivers are
  437. // loaded into.
  438. //
  439. PioICacheFlush(KSEG0_BASE+BL_16M, BL_48M);
  440. return(ESUCCESS);
  441. }