Windows NT 4.0 source code leak
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.

652 lines
21 KiB

4 years ago
  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. MIPS specific allocations and initialize. The OS loader invokes this
  8. this routine immediately before calling the loaded kernel image.
  9. Author:
  10. John Vert (jvert) 20-Jun-1991
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. --*/
  15. #include "bldr.h"
  16. #include "stdio.h"
  17. //
  18. // Define macro to round structure size to next 16-byte boundary
  19. //
  20. #define ROUND_UP(x) ((sizeof(x) + 15) & (~15))
  21. //
  22. // Configuration Data Header
  23. // The following structure is copied from fw\mips\oli2msft.h
  24. // NOTE shielint - Somehow, this structure got incorporated into
  25. // firmware EISA configuration data. We need to know the size of the
  26. // header and remove it before writing eisa configuration data to
  27. // registry.
  28. //
  29. typedef struct _CONFIGURATION_DATA_HEADER {
  30. USHORT Version;
  31. USHORT Revision;
  32. PCHAR Type;
  33. PCHAR Vendor;
  34. PCHAR ProductName;
  35. PCHAR SerialNumber;
  36. } CONFIGURATION_DATA_HEADER;
  37. #define CONFIGURATION_DATA_HEADER_SIZE sizeof(CONFIGURATION_DATA_HEADER)
  38. //
  39. // Internal function references
  40. //
  41. ARC_STATUS
  42. ReorganizeEisaConfigurationTree(
  43. IN PCONFIGURATION_COMPONENT_DATA RootEntry
  44. );
  45. ARC_STATUS
  46. CreateEisaConfigurationData (
  47. IN PCONFIGURATION_COMPONENT_DATA RootEntry
  48. );
  49. VOID
  50. BlQueryImplementationAndRevision (
  51. OUT PULONG ProcessorId,
  52. OUT PULONG FloatingId
  53. );
  54. ARC_STATUS
  55. BlSetupForNt(
  56. IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
  57. )
  58. /*++
  59. Routine Description:
  60. This function initializes the MIPS specific kernel data structures
  61. required by the NT system.
  62. Arguments:
  63. BlLoaderBlock - Supplies the address of the loader parameter block.
  64. Return Value:
  65. ESUCCESS is returned if the setup is successfully complete. Otherwise,
  66. an unsuccessful status is returned.
  67. --*/
  68. {
  69. PCONFIGURATION_COMPONENT_DATA ConfigEntry;
  70. ULONG FloatingId;
  71. CHAR Identifier[256];
  72. ULONG KernelPage;
  73. ULONG LinesPerBlock;
  74. ULONG LineSize;
  75. PCHAR NewIdentifier;
  76. ULONG PrcbPage;
  77. ULONG ProcessorId;
  78. ARC_STATUS Status;
  79. //
  80. // If the host configuration is not a multiprocessor machine, then add
  81. // the processor and floating point coprocessor identification to the
  82. // processor identification string.
  83. //
  84. if (SYSTEM_BLOCK->RestartBlock == NULL) {
  85. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  86. ProcessorClass,
  87. CentralProcessor,
  88. NULL);
  89. if (ConfigEntry != NULL) {
  90. BlQueryImplementationAndRevision(&ProcessorId, &FloatingId);
  91. sprintf(&Identifier[0],
  92. "%s - Pr %d/%d, Fp %d/%d",
  93. ConfigEntry->ComponentEntry.Identifier,
  94. (ProcessorId >> 8) & 0xff,
  95. ProcessorId & 0xff,
  96. (FloatingId >> 8) & 0xff,
  97. FloatingId & 0xff);
  98. NewIdentifier = (PCHAR)BlAllocateHeap(strlen(&Identifier[0]) + 1);
  99. if (NewIdentifier != NULL) {
  100. strcpy(NewIdentifier, &Identifier[0]);
  101. ConfigEntry->ComponentEntry.IdentifierLength = strlen(NewIdentifier);
  102. ConfigEntry->ComponentEntry.Identifier = NewIdentifier;
  103. }
  104. }
  105. }
  106. //
  107. // Find System entry and check each of its direct child to
  108. // look for EisaAdapter.
  109. //
  110. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  111. SystemClass,
  112. ArcSystem,
  113. NULL);
  114. if (ConfigEntry) {
  115. ConfigEntry = ConfigEntry->Child;
  116. }
  117. while (ConfigEntry) {
  118. if ((ConfigEntry->ComponentEntry.Class == AdapterClass) &&
  119. (ConfigEntry->ComponentEntry.Type == EisaAdapter)) {
  120. //
  121. // Convert EISA format configuration data to our CM_ format.
  122. //
  123. Status = ReorganizeEisaConfigurationTree(ConfigEntry);
  124. if (Status != ESUCCESS) {
  125. return(Status);
  126. }
  127. }
  128. ConfigEntry = ConfigEntry->Sibling;
  129. }
  130. //
  131. // Find the primary data and instruction cache configuration entries, and
  132. // compute the fill size and cache size for each cache. These entries MUST
  133. // be present on all ARC compliant systems.
  134. //
  135. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  136. CacheClass,
  137. PrimaryDcache,
  138. NULL);
  139. if (ConfigEntry != NULL) {
  140. LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
  141. LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
  142. BlLoaderBlock->u.Mips.FirstLevelDcacheFillSize = LinesPerBlock * LineSize;
  143. BlLoaderBlock->u.Mips.FirstLevelDcacheSize =
  144. 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
  145. } else {
  146. return EINVAL;
  147. }
  148. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  149. CacheClass,
  150. PrimaryIcache,
  151. NULL);
  152. if (ConfigEntry != NULL) {
  153. LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
  154. LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
  155. BlLoaderBlock->u.Mips.FirstLevelIcacheFillSize = LinesPerBlock * LineSize;
  156. BlLoaderBlock->u.Mips.FirstLevelIcacheSize =
  157. 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
  158. } else {
  159. return EINVAL;
  160. }
  161. //
  162. // Find the secondary data and instruction cache configuration entries,
  163. // and if present, compute the fill size and cache size for each cache.
  164. // These entries are optional, and may or may not, be present.
  165. //
  166. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  167. CacheClass,
  168. SecondaryCache,
  169. NULL);
  170. if (ConfigEntry != NULL) {
  171. LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
  172. LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
  173. BlLoaderBlock->u.Mips.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
  174. BlLoaderBlock->u.Mips.SecondLevelDcacheSize =
  175. 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
  176. BlLoaderBlock->u.Mips.SecondLevelIcacheSize = 0;
  177. BlLoaderBlock->u.Mips.SecondLevelIcacheFillSize = 0;
  178. } else {
  179. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  180. CacheClass,
  181. SecondaryDcache,
  182. NULL);
  183. if (ConfigEntry != NULL) {
  184. LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
  185. LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
  186. BlLoaderBlock->u.Mips.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
  187. BlLoaderBlock->u.Mips.SecondLevelDcacheSize =
  188. 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
  189. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  190. CacheClass,
  191. SecondaryIcache,
  192. NULL);
  193. if (ConfigEntry != NULL) {
  194. LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
  195. LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
  196. BlLoaderBlock->u.Mips.SecondLevelIcacheFillSize = LinesPerBlock * LineSize;
  197. BlLoaderBlock->u.Mips.SecondLevelIcacheSize =
  198. 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
  199. } else {
  200. BlLoaderBlock->u.Mips.SecondLevelIcacheSize = 0;
  201. BlLoaderBlock->u.Mips.SecondLevelIcacheFillSize = 0;
  202. }
  203. } else {
  204. BlLoaderBlock->u.Mips.SecondLevelDcacheSize = 0;
  205. BlLoaderBlock->u.Mips.SecondLevelDcacheFillSize = 0;
  206. BlLoaderBlock->u.Mips.SecondLevelIcacheSize = 0;
  207. BlLoaderBlock->u.Mips.SecondLevelIcacheFillSize = 0;
  208. }
  209. }
  210. //
  211. // Allocate DPC stack pages for the boot processor.
  212. //
  213. Status = BlAllocateDescriptor(LoaderStartupDpcStack,
  214. 0,
  215. KERNEL_STACK_SIZE >> PAGE_SHIFT,
  216. &KernelPage);
  217. if (Status != ESUCCESS) {
  218. return(Status);
  219. }
  220. BlLoaderBlock->u.Mips.InterruptStack =
  221. (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
  222. //
  223. // Allocate kernel stack pages for the boot processor idle thread.
  224. //
  225. Status = BlAllocateDescriptor(LoaderStartupKernelStack,
  226. 0,
  227. KERNEL_STACK_SIZE >> PAGE_SHIFT,
  228. &KernelPage);
  229. if (Status != ESUCCESS) {
  230. return(Status);
  231. }
  232. BlLoaderBlock->KernelStack =
  233. (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
  234. //
  235. // Allocate panic stack pages for the boot processor.
  236. //
  237. Status = BlAllocateDescriptor(LoaderStartupPanicStack,
  238. 0,
  239. KERNEL_STACK_SIZE >> PAGE_SHIFT,
  240. &KernelPage);
  241. if (Status != ESUCCESS) {
  242. return(Status);
  243. }
  244. BlLoaderBlock->u.Mips.PanicStack =
  245. (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
  246. //
  247. // Allocate and zero two pages for the PCR.
  248. //
  249. Status = BlAllocateDescriptor(LoaderStartupPcrPage,
  250. 0,
  251. 2,
  252. &BlLoaderBlock->u.Mips.PcrPage);
  253. if (Status != ESUCCESS) {
  254. return(Status);
  255. }
  256. BlLoaderBlock->u.Mips.PcrPage2 = BlLoaderBlock->u.Mips.PcrPage + 1;
  257. RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Mips.PcrPage << PAGE_SHIFT)),
  258. PAGE_SIZE * 2);
  259. //
  260. // Allocate and zero two pages for the PDR and one page of memory for
  261. // the initial processor block, idle process, and idle thread structures.
  262. //
  263. Status = BlAllocateDescriptor(LoaderStartupPdrPage,
  264. 0,
  265. 3,
  266. &BlLoaderBlock->u.Mips.PdrPage);
  267. if (Status != ESUCCESS) {
  268. return(Status);
  269. }
  270. RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Mips.PdrPage << PAGE_SHIFT)),
  271. PAGE_SIZE * 3);
  272. //
  273. // The storage for processor control block, the idle thread object, and
  274. // the idle thread process object are allocated from the third page of the
  275. // PDR allocation. The addresses of these data structures are computed
  276. // and stored in the loader parameter block and the memory is zeroed.
  277. //
  278. PrcbPage = BlLoaderBlock->u.Mips.PdrPage + 2;
  279. if (PAGE_SIZE >= (ROUND_UP(KPRCB) + ROUND_UP(EPROCESS) + ROUND_UP(ETHREAD))) {
  280. BlLoaderBlock->Prcb = KSEG0_BASE | (PrcbPage << PAGE_SHIFT);
  281. BlLoaderBlock->Process = BlLoaderBlock->Prcb + ROUND_UP(KPRCB);
  282. BlLoaderBlock->Thread = BlLoaderBlock->Process + ROUND_UP(EPROCESS);
  283. } else {
  284. return(ENOMEM);
  285. }
  286. //
  287. // Flush all caches.
  288. //
  289. if (SYSTEM_BLOCK->FirmwareVectorLength > (sizeof(PVOID) * FlushAllCachesRoutine)) {
  290. ArcFlushAllCaches();
  291. }
  292. return(ESUCCESS);
  293. }
  294. ARC_STATUS
  295. ReorganizeEisaConfigurationTree(
  296. IN PCONFIGURATION_COMPONENT_DATA RootEntry
  297. )
  298. /*++
  299. Routine Description:
  300. This routine sorts the eisa adapter configuration tree based on
  301. the slot the component resided in. It also creates a new configuration
  302. data for EisaAdapter component to contain ALL the eisa slot and function
  303. information. Finally the Eisa tree will be wiped out.
  304. Arguments:
  305. RootEntry - Supplies a pointer to a EisaAdapter component. This is
  306. the root of Eisa adapter tree.
  307. Returns:
  308. ESUCCESS is returned if the reorganization is successfully complete.
  309. Otherwise, an unsuccessful status is returned.
  310. --*/
  311. {
  312. PCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry;
  313. PCONFIGURATION_COMPONENT_DATA EntryFound, EntryFoundPrevious;
  314. PCONFIGURATION_COMPONENT_DATA AttachedEntry, DetachedList;
  315. ARC_STATUS Status;
  316. //
  317. // We sort the direct children of EISA adapter tree based on the slot
  318. // they reside in. Only the direct children of EISA root need to be
  319. // sorted.
  320. // Note the "Key" field of CONFIGURATION_COMPONENT contains
  321. // EISA slot number.
  322. //
  323. //
  324. // First, detach all the children from EISA root.
  325. //
  326. AttachedEntry = NULL; // Child list of Eisa root
  327. DetachedList = RootEntry->Child; // Detached child list
  328. PreviousEntry = NULL;
  329. while (DetachedList) {
  330. //
  331. // Find the component with the smallest slot number from detached
  332. // list.
  333. //
  334. EntryFound = DetachedList;
  335. EntryFoundPrevious = NULL;
  336. CurrentEntry = DetachedList->Sibling;
  337. PreviousEntry = DetachedList;
  338. while (CurrentEntry) {
  339. if (CurrentEntry->ComponentEntry.Key <
  340. EntryFound->ComponentEntry.Key) {
  341. EntryFound = CurrentEntry;
  342. EntryFoundPrevious = PreviousEntry;
  343. }
  344. PreviousEntry = CurrentEntry;
  345. CurrentEntry = CurrentEntry->Sibling;
  346. }
  347. //
  348. // Remove the component from the detached child list.
  349. // If the component is not the head of the detached list, we remove it
  350. // by setting its previous entry's sibling to the component's sibling.
  351. // Otherwise, we simply update Detach list head to point to the
  352. // component's sibling.
  353. //
  354. if (EntryFoundPrevious) {
  355. EntryFoundPrevious->Sibling = EntryFound->Sibling;
  356. } else {
  357. DetachedList = EntryFound->Sibling;
  358. }
  359. //
  360. // Attach the component to the child list of Eisa root.
  361. //
  362. if (AttachedEntry) {
  363. AttachedEntry->Sibling = EntryFound;
  364. } else {
  365. RootEntry->Child = EntryFound;
  366. }
  367. AttachedEntry = EntryFound;
  368. AttachedEntry->Sibling = NULL;
  369. }
  370. //
  371. // Finally, we traverse the Eisa tree to collect all the Eisa slot
  372. // and function information and put it to the configuration data of
  373. // Eisa root entry.
  374. //
  375. Status = CreateEisaConfigurationData(RootEntry);
  376. //
  377. // Wipe out all the children of EISA tree.
  378. // NOTE shielint - For each child component, we should convert its
  379. // configuration data from EISA format to our CM_ format.
  380. //
  381. RootEntry->Child = NULL;
  382. return(Status);
  383. }
  384. ARC_STATUS
  385. CreateEisaConfigurationData (
  386. IN PCONFIGURATION_COMPONENT_DATA RootEntry
  387. )
  388. /*++
  389. Routine Description:
  390. This routine traverses Eisa configuration tree to collect all the
  391. slot and function information and attaches it to the configuration data
  392. of Eisa RootEntry.
  393. Note that this routine assumes that the EISA tree has been sorted based
  394. on the slot number.
  395. Arguments:
  396. RootEntry - Supplies a pointer to the Eisa configuration
  397. component entry.
  398. Returns:
  399. ESUCCESS is returned if the new EisaAdapter configuration data is
  400. successfully created. Otherwise, an unsuccessful status is returned.
  401. --*/
  402. {
  403. ULONG DataSize, NextSlot = 0, i;
  404. PCM_PARTIAL_RESOURCE_LIST Descriptor;
  405. PCONFIGURATION_COMPONENT Component;
  406. PCONFIGURATION_COMPONENT_DATA CurrentEntry;
  407. PUCHAR DataPointer;
  408. CM_EISA_SLOT_INFORMATION EmptySlot =
  409. {EISA_EMPTY_SLOT, 0, 0, 0, 0, 0, 0, 0};
  410. //
  411. // Remove the configuration data of Eisa Adapter
  412. //
  413. RootEntry->ConfigurationData = NULL;
  414. RootEntry->ComponentEntry.ConfigurationDataLength = 0;
  415. //
  416. // If the EISA stree contains valid slot information, i.e.
  417. // root has children attaching to it.
  418. //
  419. if (RootEntry->Child) {
  420. //
  421. // First find out how much memory is needed to store EISA config
  422. // data.
  423. //
  424. DataSize = sizeof(CM_PARTIAL_RESOURCE_LIST);
  425. CurrentEntry = RootEntry->Child;
  426. while (CurrentEntry) {
  427. Component = &CurrentEntry->ComponentEntry;
  428. if (CurrentEntry->ConfigurationData) {
  429. if (Component->Key > NextSlot) {
  430. //
  431. // If there is any empty slot between current slot
  432. // and previous checked slot, we need to count the
  433. // space for the empty slots.
  434. //
  435. DataSize += (Component->Key - NextSlot) *
  436. sizeof(CM_EISA_SLOT_INFORMATION);
  437. }
  438. DataSize += Component->ConfigurationDataLength + 1 -
  439. CONFIGURATION_DATA_HEADER_SIZE;
  440. NextSlot = Component->Key + 1;
  441. }
  442. CurrentEntry = CurrentEntry->Sibling;
  443. }
  444. //
  445. // Allocate memory from heap to hold the EISA configuration data.
  446. //
  447. DataPointer = BlAllocateHeap(DataSize);
  448. if (DataPointer == NULL) {
  449. return ENOMEM;
  450. } else {
  451. RootEntry->ConfigurationData = DataPointer;
  452. RootEntry->ComponentEntry.ConfigurationDataLength = DataSize;
  453. }
  454. //
  455. // Create a CM_PARTIAL_RESOURCE_LIST for the new configuration data.
  456. //
  457. Descriptor = (PCM_PARTIAL_RESOURCE_LIST)DataPointer;
  458. Descriptor->Version = 0;
  459. Descriptor->Revision = 0;
  460. Descriptor->Count = 1;
  461. Descriptor->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific;
  462. Descriptor->PartialDescriptors[0].ShareDisposition = 0;
  463. Descriptor->PartialDescriptors[0].Flags = 0;
  464. Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved1 = 0;
  465. Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved2 = 0;
  466. Descriptor->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
  467. DataSize - sizeof(CM_PARTIAL_RESOURCE_LIST);
  468. //
  469. // Visit each child of the RootEntry and copy its ConfigurationData
  470. // to the new configuration data area.
  471. // N.B. The configuration data includes a slot information and zero
  472. // or more function information. The slot information provided
  473. // by ARC eisa data does not have "ReturnedCode" as defined in
  474. // our CM_EISA_SLOT_INFORMATION. This code will convert the
  475. // standard EISA slot information to our CM format.
  476. //
  477. CurrentEntry = RootEntry->Child;
  478. DataPointer += sizeof(CM_PARTIAL_RESOURCE_LIST);
  479. NextSlot = 0;
  480. while (CurrentEntry) {
  481. Component = &CurrentEntry->ComponentEntry;
  482. if (CurrentEntry->ConfigurationData) {
  483. //
  484. // Check if there is any empty slot. If yes, create empty
  485. // slot information. Also make sure the config data area is
  486. // big enough.
  487. //
  488. if (Component->Key > NextSlot) {
  489. for (i = NextSlot; i < CurrentEntry->ComponentEntry.Key; i++ ) {
  490. *(PCM_EISA_SLOT_INFORMATION)DataPointer = EmptySlot;
  491. DataPointer += sizeof(CM_EISA_SLOT_INFORMATION);
  492. }
  493. }
  494. *DataPointer++ = 0; // See comment above
  495. RtlMoveMemory( // Skip config data header
  496. DataPointer,
  497. (PUCHAR)CurrentEntry->ConfigurationData +
  498. CONFIGURATION_DATA_HEADER_SIZE,
  499. Component->ConfigurationDataLength -
  500. CONFIGURATION_DATA_HEADER_SIZE
  501. );
  502. DataPointer += Component->ConfigurationDataLength -
  503. CONFIGURATION_DATA_HEADER_SIZE;
  504. NextSlot = Component->Key + 1;
  505. }
  506. CurrentEntry = CurrentEntry->Sibling;
  507. }
  508. }
  509. return(ESUCCESS);
  510. }