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.

1615 lines
54 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. PPC 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. #define KB 1024
  18. #define MB (KB * KB)
  19. #define MBpages (MB / PAGE_SIZE)
  20. #define MIN(_a,_b) (((_a) <= (_b)) ? (_a) : (_b))
  21. #define MAX(_a,_b) (((_a) >= (_b)) ? (_a) : (_b))
  22. #define PAGES(_bytes) ((_bytes) >> PAGE_SHIFT)
  23. #define BYTES(_pages) ((_pages) << PAGE_SHIFT)
  24. #define PageFromAddress(_addr) PAGES((_addr) & ~KSEG0_BASE)
  25. #define AddressFromPage(_page) (KSEG0_BASE | BYTES(_page))
  26. #define RealAddressFromPage(_page) BYTES(_page)
  27. //
  28. // If a system has less than PAGED_KERNEL_MEMORY_LIMIT pages of memory,
  29. // we will page the kernel, thus making more memory available for apps.
  30. // If a system has more than PAGED_KERNEL_MEMORY_LIMIT pages of memory,
  31. // we will map the kernel using the KSEG0 BAT, thus avoiding translation
  32. // overhead.
  33. //
  34. #define PAGED_KERNEL_MEMORY_LIMIT (48*MBpages)
  35. //
  36. // Boolean indicating whether the kernel is to be paged or mapped by a BAT register.
  37. //
  38. BOOLEAN PageKernel;
  39. //
  40. // Define macro to round structure size to next 16-byte boundary
  41. //
  42. #define ROUND_UP(x) ((sizeof(x) + 15) & (~15))
  43. //
  44. // Configuration Data Header
  45. // The following structure is copied from fw\ppc\oli2msft.h
  46. // NOTE shielint - Somehow, this structure got incorporated into
  47. // firmware EISA configuration data. We need to know the size of the
  48. // header and remove it before writing eisa configuration data to
  49. // registry.
  50. //
  51. typedef struct _CONFIGURATION_DATA_HEADER {
  52. USHORT Version;
  53. USHORT Revision;
  54. PCHAR Type;
  55. PCHAR Vendor;
  56. PCHAR ProductName;
  57. PCHAR SerialNumber;
  58. } CONFIGURATION_DATA_HEADER;
  59. #define CONFIGURATION_DATA_HEADER_SIZE sizeof(CONFIGURATION_DATA_HEADER)
  60. //
  61. // Internal function references
  62. //
  63. ARC_STATUS
  64. ReorganizeEisaConfigurationTree(
  65. IN PCONFIGURATION_COMPONENT_DATA RootEntry
  66. );
  67. ARC_STATUS
  68. CreateEisaConfigurationData (
  69. IN PCONFIGURATION_COMPONENT_DATA RootEntry
  70. );
  71. VOID
  72. BlQueryImplementationAndRevision (
  73. OUT PULONG ProcessorId,
  74. OUT PULONG ProcessorRev
  75. );
  76. ARC_STATUS
  77. NextFreePage (
  78. IN OUT PULONG FreePage,
  79. IN OUT PULONG NumberFree,
  80. IN OUT PMEMORY_ALLOCATION_DESCRIPTOR *FreeDescriptor
  81. )
  82. {
  83. PLIST_ENTRY NextEntry;
  84. PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
  85. (*FreePage)++;
  86. (*NumberFree)--;
  87. if (*NumberFree != 0) {
  88. return ESUCCESS;
  89. }
  90. BlLog((LOG_ALL,"Generating FirmwarePermanent descriptor for %x pages at %x taken for PTE pages",(*FreeDescriptor)->PageCount,(*FreeDescriptor)->BasePage));
  91. (*FreeDescriptor)->MemoryType = LoaderFirmwarePermanent;
  92. NextEntry = (*FreeDescriptor)->ListEntry.Flink;
  93. while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  94. NextDescriptor = CONTAINING_RECORD(NextEntry,
  95. MEMORY_ALLOCATION_DESCRIPTOR,
  96. ListEntry);
  97. if (NextDescriptor->MemoryType == LoaderFree) {
  98. *FreeDescriptor = NextDescriptor;
  99. *FreePage = NextDescriptor->BasePage;
  100. *NumberFree = NextDescriptor->PageCount;
  101. BlLog((LOG_ALL,"%x PTE pages available at %x",*NumberFree,*FreePage));
  102. return ESUCCESS;
  103. }
  104. NextEntry = NextEntry->Flink;
  105. }
  106. return ENOMEM;
  107. }
  108. ARC_STATUS
  109. AllocateKseg0Blocks (
  110. OUT PULONG HighestKseg0PageParameter
  111. )
  112. {
  113. ARC_STATUS Status;
  114. ULONG HighestKseg0Page;
  115. ULONG HptPages;
  116. ULONG BasePage;
  117. ULONG NumberOfPcrs;
  118. //
  119. // We need to allocate a number of items in what will become KSEG0,
  120. // mapped by a BAT register. We want these items to be allocated as
  121. // low in memory as possible.
  122. //
  123. // N.B. We do a number of individual allocations, rather than one
  124. // large allocation, in order to ensure that the allocations
  125. // succeed, even if low memory is fragmented.
  126. //
  127. BlSetAllocationPolicy(BlAllocateLowestFit, BlAllocateHighestFit);
  128. HighestKseg0Page = 5; // exception vector pages
  129. BlLogMemoryDescriptors(LOG_ALL_W);
  130. //
  131. // Allocate the hashed page table first, because the HPT must be
  132. // aligned based on its size.
  133. //
  134. // N.B. Not all machines require an HPT (e.g., 603).
  135. //
  136. HptPages = BlLoaderBlock->u.Ppc.HashedPageTableSize;
  137. BlLoaderBlock->u.Ppc.HashedPageTable = 0;
  138. if (HptPages != 0) {
  139. Status = BlAllocateAlignedDescriptor(LoaderFirmwarePermanent,
  140. 0,
  141. HptPages,
  142. HptPages,
  143. &BasePage);
  144. if (Status != ESUCCESS) {
  145. return Status;
  146. }
  147. BlLoaderBlock->u.Ppc.HashedPageTable = RealAddressFromPage(BasePage);
  148. RtlZeroMemory((PVOID)AddressFromPage(BasePage), BYTES(HptPages));
  149. if ((BasePage + HptPages) > HighestKseg0Page) {
  150. HighestKseg0Page = BasePage + HptPages;
  151. }
  152. BlLog((LOG_ALL,"Allocated %x pages for HPT at %x",HptPages,BasePage));
  153. }
  154. //
  155. // Allocate PCRs for additional processors. (We don't know how many
  156. // processors there might be, so we assume the most.)
  157. //
  158. // N.B. If we can't get the maximum number of PCR pages, we try for
  159. // less. This just means the system won't be able to start 32
  160. // processors. If not even one page can be allocated,
  161. // however, we give up on the boot, because our next
  162. // allocation is sure to fail.
  163. //
  164. BlLoaderBlock->u.Ppc.PcrPagesDescriptor = NULL;
  165. NumberOfPcrs = MAXIMUM_PROCESSORS - 1;
  166. do {
  167. Status = BlAllocateAlignedDescriptor(LoaderStartupPcrPage,
  168. 0,
  169. NumberOfPcrs,
  170. 0,
  171. &BasePage);
  172. if (Status == ESUCCESS) {
  173. break;
  174. }
  175. NumberOfPcrs--;
  176. } while (NumberOfPcrs != 0);
  177. if (Status != ESUCCESS) {
  178. return Status;
  179. }
  180. BlLoaderBlock->u.Ppc.PcrPagesDescriptor = BlFindMemoryDescriptor(BasePage);
  181. RtlZeroMemory((PVOID)AddressFromPage(BasePage), NumberOfPcrs * PAGE_SIZE);
  182. if ((BasePage + NumberOfPcrs) > HighestKseg0Page) {
  183. HighestKseg0Page = BasePage + NumberOfPcrs;
  184. }
  185. BlLog((LOG_ALL,"Allocated %x pages for PCRs at %x",NumberOfPcrs,BasePage));
  186. //
  187. // Allocate a few extra pages in KSEG0 for the kernel to use.
  188. //
  189. Status = BlAllocateDescriptor(LoaderFirmwarePermanent,
  190. 0,
  191. 5,
  192. &BasePage);
  193. if (Status != ESUCCESS) {
  194. return(Status);
  195. }
  196. BlLoaderBlock->u.Ppc.KernelKseg0PagesDescriptor = BlFindMemoryDescriptor(BasePage);
  197. RtlZeroMemory((PVOID)AddressFromPage(BasePage), 5 * PAGE_SIZE);
  198. if ((BasePage + 5) > HighestKseg0Page) {
  199. HighestKseg0Page = BasePage + 5;
  200. }
  201. BlLog((LOG_ALL,"Allocated %x pages for kernel at %x",5,BasePage));
  202. //
  203. // Allocate and zero three pages, one for the page directory page,
  204. // one for the hyperspace PTE page, and one for the HAL's PTE page.
  205. //
  206. Status = BlAllocateDescriptor(LoaderStartupPdrPage,
  207. 0,
  208. 3,
  209. &BasePage);
  210. if (Status != ESUCCESS) {
  211. return(Status);
  212. }
  213. BlLoaderBlock->u.Ppc.PdrPage = BasePage;
  214. RtlZeroMemory((PVOID)AddressFromPage(BasePage), 3 * PAGE_SIZE);
  215. if ((BasePage + 3) > HighestKseg0Page) {
  216. HighestKseg0Page = BasePage + 3;
  217. }
  218. BlLog((LOG_ALL,"Allocated %x pages for PDR at %x",3,BasePage));
  219. //
  220. // Allocate and zero two pages, one for the PCR for processor 0 and
  221. // one for the common PCR2 page.
  222. //
  223. Status = BlAllocateDescriptor(LoaderStartupPcrPage,
  224. 0,
  225. 2,
  226. &BasePage);
  227. if (Status != ESUCCESS) {
  228. return(Status);
  229. }
  230. BlLoaderBlock->u.Ppc.PcrPage = BasePage;
  231. BlLoaderBlock->u.Ppc.PcrPage2 = BlLoaderBlock->u.Ppc.PcrPage + 1;
  232. RtlZeroMemory((PVOID)AddressFromPage(BasePage), 2 * PAGE_SIZE);
  233. if ((BasePage + 2) > HighestKseg0Page) {
  234. HighestKseg0Page = BasePage + 2;
  235. }
  236. BlLog((LOG_ALL,"Allocated %x pages for PCR at %x",2,BasePage));
  237. //
  238. // Now that we've allocated everything that needs to be in KSEG0, we
  239. // can tell the memory allocator to start allocating using a
  240. // best-fit algorithm.
  241. //
  242. BlSetAllocationPolicy(BlAllocateBestFit, BlAllocateBestFit);
  243. *HighestKseg0PageParameter = HighestKseg0Page;
  244. BlLogWaitForKeystroke();
  245. return ESUCCESS;
  246. }
  247. ARC_STATUS
  248. BlSetupForNt(
  249. IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
  250. )
  251. /*++
  252. Routine Description:
  253. This function initializes the PPC specific kernel data structures
  254. required by the NT system.
  255. Arguments:
  256. BlLoaderBlock - Supplies the address of the loader parameter block.
  257. Return Value:
  258. ESUCCESS is returned if the setup is successfully complete. Otherwise,
  259. an unsuccessful status is returned.
  260. --*/
  261. {
  262. PCONFIGURATION_COMPONENT_DATA ConfigEntry;
  263. CHAR Identifier[256];
  264. ULONG KernelPage;
  265. ULONG LinesPerBlock;
  266. ULONG LineSize;
  267. PCHAR NewIdentifier;
  268. ARC_STATUS Status;
  269. PCHAR IcacheModeString;
  270. PCHAR DcacheModeString;
  271. ULONG HighestKseg0Page;
  272. ULONG Kseg0Pages;
  273. ULONG Page;
  274. ULONG HighPage;
  275. ULONG Entry;
  276. PHARDWARE_PTE PdePage;
  277. PHARDWARE_PTE PtePage;
  278. PLIST_ENTRY NextEntry;
  279. PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
  280. PMEMORY_ALLOCATION_DESCRIPTOR FreeDescriptor;
  281. ULONG FreePage;
  282. ULONG NumberFree;
  283. ULONG ProcessorId;
  284. ULONG ProcessorRev;
  285. UCHAR Processor[32];
  286. UCHAR Revision[32];
  287. //
  288. // If the host configuration is not a multiprocessor machine, then add
  289. // the processor identification to the processor identification string.
  290. //
  291. if (SYSTEM_BLOCK->RestartBlock == NULL) {
  292. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  293. ProcessorClass,
  294. CentralProcessor,
  295. NULL);
  296. if (ConfigEntry != NULL) {
  297. BlQueryImplementationAndRevision(&ProcessorId, &ProcessorRev);
  298. //
  299. // Unfortunately, PowerPC numbering doesn't directly give us
  300. // the name of the part.
  301. //
  302. switch (ProcessorId) {
  303. case 6:
  304. sprintf(Processor, "603+");
  305. break;
  306. case 7:
  307. sprintf(Processor, "603++");
  308. break;
  309. case 9:
  310. sprintf(Processor, "604+");
  311. break;
  312. default:
  313. sprintf(Processor, "%d", ProcessorId + 600);
  314. }
  315. //
  316. // 601 revision is just a number, others are a xx.yy eg
  317. // 3.1
  318. //
  319. if ( ProcessorId == 1 ) {
  320. sprintf(Revision, "%d", ProcessorRev);
  321. } else {
  322. sprintf(Revision, "%d.%d", ProcessorRev >> 8,
  323. ProcessorRev & 0xff);
  324. }
  325. sprintf(&Identifier[0],
  326. "%s - Pr %s, Rev %s",
  327. ConfigEntry->ComponentEntry.Identifier,
  328. Processor,
  329. Revision);
  330. NewIdentifier = (PCHAR)BlAllocateHeap(strlen(&Identifier[0]) + 1);
  331. if (NewIdentifier != NULL) {
  332. strcpy(NewIdentifier, &Identifier[0]);
  333. ConfigEntry->ComponentEntry.IdentifierLength = strlen(NewIdentifier);
  334. ConfigEntry->ComponentEntry.Identifier = NewIdentifier;
  335. }
  336. }
  337. }
  338. //
  339. // Find System entry and check each of its direct child to
  340. // look for EisaAdapter.
  341. //
  342. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  343. SystemClass,
  344. ArcSystem,
  345. NULL);
  346. if (ConfigEntry) {
  347. ConfigEntry = ConfigEntry->Child;
  348. }
  349. while (ConfigEntry) {
  350. if ((ConfigEntry->ComponentEntry.Class == AdapterClass) &&
  351. (ConfigEntry->ComponentEntry.Type == EisaAdapter)) {
  352. //
  353. // Convert EISA format configuration data to our CM_ format.
  354. //
  355. Status = ReorganizeEisaConfigurationTree(ConfigEntry);
  356. if (Status != ESUCCESS) {
  357. return(Status);
  358. }
  359. }
  360. ConfigEntry = ConfigEntry->Sibling;
  361. }
  362. //
  363. // Find the primary data and instruction cache configuration entries, and
  364. // compute the fill size and cache size for each cache. These entries MUST
  365. // be present on all ARC compliant systems.
  366. //
  367. // BUT of course they aren't. So we'll handle their not being there by
  368. // ignoring their absence and not writing cache sizes to the loader block.
  369. //
  370. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  371. CacheClass,
  372. PrimaryDcache,
  373. NULL);
  374. if (ConfigEntry != NULL) {
  375. LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
  376. LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
  377. BlLoaderBlock->u.Ppc.FirstLevelDcacheFillSize = LinesPerBlock * LineSize;
  378. BlLoaderBlock->u.Ppc.FirstLevelDcacheSize =
  379. 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
  380. }
  381. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  382. CacheClass,
  383. PrimaryIcache,
  384. NULL);
  385. if (ConfigEntry != NULL) {
  386. LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
  387. LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
  388. BlLoaderBlock->u.Ppc.FirstLevelIcacheFillSize = LinesPerBlock * LineSize;
  389. BlLoaderBlock->u.Ppc.FirstLevelIcacheSize =
  390. 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
  391. }
  392. //
  393. // Find the secondary data and instruction cache configuration entries,
  394. // and if present, compute the fill size and cache size for each cache.
  395. // These entries are optional, and may or may not, be present.
  396. //
  397. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  398. CacheClass,
  399. SecondaryCache,
  400. NULL);
  401. if (ConfigEntry != NULL) {
  402. LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
  403. LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
  404. BlLoaderBlock->u.Ppc.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
  405. BlLoaderBlock->u.Ppc.SecondLevelDcacheSize =
  406. 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
  407. BlLoaderBlock->u.Ppc.SecondLevelIcacheSize = 0;
  408. BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = 0;
  409. } else {
  410. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  411. CacheClass,
  412. SecondaryDcache,
  413. NULL);
  414. if (ConfigEntry != NULL) {
  415. LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
  416. LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
  417. BlLoaderBlock->u.Ppc.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
  418. BlLoaderBlock->u.Ppc.SecondLevelDcacheSize =
  419. 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
  420. ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
  421. CacheClass,
  422. SecondaryIcache,
  423. NULL);
  424. if (ConfigEntry != NULL) {
  425. LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
  426. LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
  427. BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = LinesPerBlock * LineSize;
  428. BlLoaderBlock->u.Ppc.SecondLevelIcacheSize =
  429. 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
  430. } else {
  431. BlLoaderBlock->u.Ppc.SecondLevelIcacheSize = 0;
  432. BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = 0;
  433. }
  434. } else {
  435. BlLoaderBlock->u.Ppc.SecondLevelDcacheSize = 0;
  436. BlLoaderBlock->u.Ppc.SecondLevelDcacheFillSize = 0;
  437. BlLoaderBlock->u.Ppc.SecondLevelIcacheSize = 0;
  438. BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = 0;
  439. }
  440. }
  441. //
  442. // Allocate DPC stack pages for the boot processor.
  443. //
  444. Status = BlAllocateDescriptor(LoaderStartupDpcStack,
  445. 0,
  446. PAGES(KERNEL_STACK_SIZE),
  447. &KernelPage);
  448. if (Status != ESUCCESS) {
  449. return(Status);
  450. }
  451. BlLoaderBlock->u.Ppc.InterruptStack = AddressFromPage(KernelPage) + KERNEL_STACK_SIZE;
  452. //
  453. // Allocate kernel stack pages for the boot processor idle thread.
  454. //
  455. Status = BlAllocateDescriptor(LoaderStartupKernelStack,
  456. 0,
  457. PAGES(KERNEL_STACK_SIZE),
  458. &KernelPage);
  459. if (Status != ESUCCESS) {
  460. return(Status);
  461. }
  462. BlLoaderBlock->KernelStack = AddressFromPage(KernelPage) + KERNEL_STACK_SIZE;
  463. //
  464. // Allocate panic stack pages for the boot processor.
  465. //
  466. Status = BlAllocateDescriptor(LoaderStartupPanicStack,
  467. 0,
  468. PAGES(KERNEL_STACK_SIZE),
  469. &KernelPage);
  470. if (Status != ESUCCESS) {
  471. return(Status);
  472. }
  473. BlLoaderBlock->u.Ppc.PanicStack = AddressFromPage(KernelPage) + KERNEL_STACK_SIZE;
  474. //
  475. // Disable the caches, if requested.
  476. //
  477. BlLoaderBlock->u.Ppc.IcacheMode = 0;
  478. if (IcacheModeString = ArcGetEnvironmentVariable("ICACHEMODE")) {
  479. if (_stricmp(IcacheModeString, "OFF") == 0) {
  480. BlLoaderBlock->u.Ppc.IcacheMode = 1;
  481. }
  482. }
  483. BlLoaderBlock->u.Ppc.DcacheMode = 0;
  484. if (DcacheModeString = ArcGetEnvironmentVariable("DCACHEMODE")) {
  485. if (_stricmp(DcacheModeString, "OFF") == 0) {
  486. BlLoaderBlock->u.Ppc.DcacheMode = 1;
  487. }
  488. }
  489. //
  490. // Allocate the PRCB, process, and thread.
  491. //
  492. #define OS_DATA_SIZE PAGES(ROUND_UP(KPRCB)+ROUND_UP(EPROCESS)+ROUND_UP(ETHREAD)+(PAGE_SIZE-1))
  493. Status = BlAllocateDescriptor(LoaderStartupPdrPage,
  494. 0,
  495. OS_DATA_SIZE,
  496. &KernelPage);
  497. if (Status != ESUCCESS) {
  498. return(Status);
  499. }
  500. BlLoaderBlock->Prcb = AddressFromPage(KernelPage);
  501. RtlZeroMemory((PVOID)BlLoaderBlock->Prcb, BYTES(OS_DATA_SIZE));
  502. BlLoaderBlock->Process = BlLoaderBlock->Prcb + ROUND_UP(KPRCB);
  503. BlLoaderBlock->Thread = BlLoaderBlock->Process + ROUND_UP(EPROCESS);
  504. //
  505. // Initialize the page directory page. Set up the mappings for the
  506. // PDR page and the hyperspace page.
  507. //
  508. PdePage = (PHARDWARE_PTE)AddressFromPage(BlLoaderBlock->u.Ppc.PdrPage);
  509. BlLog((LOG_ALL,"PDE page at %x",PdePage));
  510. PdePage[PDE_BASE>>PDI_SHIFT].PageFrameNumber = BlLoaderBlock->u.Ppc.PdrPage;
  511. PdePage[PDE_BASE>>PDI_SHIFT].Valid = 1;
  512. PdePage[PDE_BASE>>PDI_SHIFT].Write = 1;
  513. BlLog((LOG_ALL,"PDE mapped at PdePage[%x] = %x",PDE_BASE>>PDI_SHIFT,*(PULONG)&PdePage[PDE_BASE>>PDI_SHIFT]));
  514. PdePage[(PDE_BASE>>PDI_SHIFT)+1].PageFrameNumber = BlLoaderBlock->u.Ppc.PdrPage + 1;
  515. PdePage[(PDE_BASE>>PDI_SHIFT)+1].Valid = 1;
  516. PdePage[(PDE_BASE>>PDI_SHIFT)+1].Write = 1;
  517. BlLog((LOG_ALL,"Hyperspace mapped at PdePage[%x] = %x",(PDE_BASE>>PDI_SHIFT)+1,*(PULONG)&PdePage[(PDE_BASE>>PDI_SHIFT)+1]));
  518. //
  519. // Allocate one page for the HAL to use to map memory. This goes in
  520. // the very last PDE slot (VA 0xFFC00000 - 0xFFFFFFFF). Our HAL
  521. // is currently not using this but it is required since this is
  522. // where the magic PTE for the kernel debugger to map physical pages
  523. // is located.
  524. //
  525. PdePage[1023].PageFrameNumber = BlLoaderBlock->u.Ppc.PdrPage + 2;
  526. PdePage[1023].Valid = 1;
  527. PdePage[1023].Write = 1;
  528. BlLog((LOG_ALL,"HAL PTE page mapped at PdePage[%x] = %x",1023,*(PULONG)&PdePage[1023]));
  529. //
  530. // Within the above Page Table Page, allocate a PTE for
  531. // USER_SHARED_DATA (PcrPage2) at virtual address 0xffffe000. This
  532. // is the second to last page in the address space.
  533. //
  534. PtePage = (PHARDWARE_PTE)AddressFromPage(BlLoaderBlock->u.Ppc.PdrPage + 2);
  535. BlLog((LOG_ALL,"PCR2 PTE page at %x",PtePage));
  536. PtePage[1022].PageFrameNumber = BlLoaderBlock->u.Ppc.PcrPage2;
  537. PtePage[1022].Valid = 1;
  538. PtePage[1022].Dirty = 1; // allow user read, kernel read/write
  539. PtePage[1022].Change = 1;
  540. PtePage[1022].Reference = 1;
  541. BlLog((LOG_ALL,"PCR2 PTE mapped at PtePage[%x] = %x",1022,*(PULONG)&PtePage[1022]));
  542. //
  543. // If we're paging the kernel, find free memory to use for page
  544. // table pages.
  545. //
  546. if (PageKernel) {
  547. FreePage = 0;
  548. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  549. while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  550. NextDescriptor = CONTAINING_RECORD(NextEntry,
  551. MEMORY_ALLOCATION_DESCRIPTOR,
  552. ListEntry);
  553. if (NextDescriptor->MemoryType == LoaderFree) {
  554. FreeDescriptor = NextDescriptor;
  555. FreePage = FreeDescriptor->BasePage;
  556. NumberFree = FreeDescriptor->PageCount;
  557. break;
  558. }
  559. NextEntry = NextEntry->Flink;
  560. }
  561. if (FreePage == 0) {
  562. BlLog((LOG_ALL,"Unable to find free memory for PTE pages"));
  563. return ENOMEM;
  564. }
  565. BlLog((LOG_ALL,"%x PTE pages available at %x",NumberFree,FreePage));
  566. }
  567. //
  568. // If we're paging the kernel, then for each page used to load boot
  569. // code/data, set up a PTE. Do not do this for pages that reside in
  570. // KSEG0. If we're not paging the kernel, find the highest page
  571. // used to load boot code/data, so that we know how to set up the
  572. // KSEG0 BAT.
  573. //
  574. Kseg0Pages = PageFromAddress(BlLoaderBlock->u.Ppc.Kseg0Top);
  575. HighestKseg0Page = 0;
  576. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  577. while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  578. NextDescriptor = CONTAINING_RECORD(NextEntry,
  579. MEMORY_ALLOCATION_DESCRIPTOR,
  580. ListEntry);
  581. if ((NextDescriptor->MemoryType != LoaderExceptionBlock) &&
  582. (NextDescriptor->MemoryType != LoaderSystemBlock) &&
  583. (NextDescriptor->MemoryType != LoaderFree) &&
  584. (NextDescriptor->MemoryType != LoaderBad) &&
  585. (NextDescriptor->MemoryType != LoaderLoadedProgram) &&
  586. (NextDescriptor->MemoryType != LoaderFirmwareTemporary) &&
  587. (NextDescriptor->MemoryType != LoaderFirmwarePermanent) &&
  588. (NextDescriptor->MemoryType != LoaderOsloaderStack) &&
  589. (NextDescriptor->MemoryType != LoaderSpecialMemory)) {
  590. HighPage = NextDescriptor->BasePage + NextDescriptor->PageCount;
  591. if (PageKernel) {
  592. if (NextDescriptor->BasePage >= Kseg0Pages) {
  593. BlLog((LOG_ALL,
  594. "Setting up mapping for pages[%x:%x]",
  595. NextDescriptor->BasePage,
  596. HighPage-1));
  597. for (Page = NextDescriptor->BasePage; Page < HighPage; Page++) {
  598. Entry = AddressFromPage(Page) >> PDI_SHIFT;
  599. if (PdePage[Entry].Valid == 0) {
  600. PtePage = (PHARDWARE_PTE)AddressFromPage(FreePage);
  601. RtlZeroMemory(PtePage, PAGE_SIZE);
  602. PdePage[Entry].PageFrameNumber = FreePage;
  603. PdePage[Entry].Valid = 1;
  604. PdePage[Entry].Write = 1;
  605. BlLog((LOG_ALL,
  606. "PTE page mapped at PdePage[%x] = %x",
  607. Entry,
  608. *(PULONG)&PdePage[Entry]));
  609. if (NextFreePage(&FreePage, &NumberFree, &FreeDescriptor) != ESUCCESS) {
  610. BlLog((LOG_ALL,"Unable to find free memory for PTE pages"));
  611. return ENOMEM;
  612. }
  613. } else {
  614. PtePage = (PHARDWARE_PTE)AddressFromPage(PdePage[Entry].PageFrameNumber);
  615. }
  616. Entry = Page & ((1 << (PDI_SHIFT-PTI_SHIFT)) - 1);
  617. PtePage[Entry].PageFrameNumber = Page;
  618. PtePage[Entry].Valid = 1;
  619. PtePage[Entry].Write = 1;
  620. //BlLog((LOG_ALL,
  621. // "Page %x mapped at PtePage[%x] (%x) = %x",
  622. // Page,
  623. // Entry,
  624. // &PtePage[Entry],
  625. // *(PULONG)&PtePage[Entry]));
  626. }
  627. //BlLogWaitForKeystroke();
  628. }
  629. } else { // not paging the kernel
  630. HighestKseg0Page = HighPage;
  631. }
  632. }
  633. NextEntry = NextEntry->Flink;
  634. }
  635. if (PageKernel) {
  636. //
  637. // Account for pages taken from FreeDescriptor for page table pages.
  638. //
  639. if (NumberFree != FreeDescriptor->PageCount) {
  640. BlLog((LOG_ALL,"Generating FirmwarePermanent descriptor for %x pages at %x taken for PTE pages",FreeDescriptor->PageCount-NumberFree,FreeDescriptor->BasePage));
  641. BlGenerateDescriptor(FreeDescriptor,
  642. LoaderFirmwarePermanent,
  643. FreeDescriptor->BasePage,
  644. FreeDescriptor->PageCount - NumberFree);
  645. }
  646. } else {
  647. //
  648. // We're not paging the kernel. Tell the kernel how big the
  649. // KSEG0 BAT needs to be -- it must cover all boot code/data.
  650. // (If we're paging the kernel, BlPpcMemoryInitialize already
  651. // set the KSEG0 BAT size.)
  652. //
  653. Kseg0Pages = PAGES(BlLoaderBlock->u.Ppc.MinimumBlockLength);
  654. while (Kseg0Pages < HighestKseg0Page) {
  655. Kseg0Pages <<= 1;
  656. }
  657. BlLoaderBlock->u.Ppc.Kseg0Top = AddressFromPage(Kseg0Pages);
  658. BlLog((LOG_ALL,"Highest KSEG0 page: %x, KSEG0 pages: %x",HighestKseg0Page,Kseg0Pages));
  659. }
  660. BlLogWaitForKeystroke();
  661. return(ESUCCESS);
  662. }
  663. ARC_STATUS
  664. ReorganizeEisaConfigurationTree(
  665. IN PCONFIGURATION_COMPONENT_DATA RootEntry
  666. )
  667. /*++
  668. Routine Description:
  669. This routine sorts the eisa adapter configuration tree based on
  670. the slot the component resided in. It also creates a new configuration
  671. data for EisaAdapter component to contain ALL the eisa slot and function
  672. information. Finally the Eisa tree will be wiped out.
  673. Arguments:
  674. RootEntry - Supplies a pointer to a EisaAdapter component. This is
  675. the root of Eisa adapter tree.
  676. Returns:
  677. ESUCCESS is returned if the reorganization is successfully complete.
  678. Otherwise, an unsuccessful status is returned.
  679. --*/
  680. {
  681. PCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry;
  682. PCONFIGURATION_COMPONENT_DATA EntryFound, EntryFoundPrevious;
  683. PCONFIGURATION_COMPONENT_DATA AttachedEntry, DetachedList;
  684. ARC_STATUS Status;
  685. //
  686. // We sort the direct children of EISA adapter tree based on the slot
  687. // they reside in. Only the direct children of EISA root need to be
  688. // sorted.
  689. // Note the "Key" field of CONFIGURATION_COMPONENT contains
  690. // EISA slot number.
  691. //
  692. //
  693. // First, detach all the children from EISA root.
  694. //
  695. AttachedEntry = NULL; // Child list of Eisa root
  696. DetachedList = RootEntry->Child; // Detached child list
  697. PreviousEntry = NULL;
  698. while (DetachedList) {
  699. //
  700. // Find the component with the smallest slot number from detached
  701. // list.
  702. //
  703. EntryFound = DetachedList;
  704. EntryFoundPrevious = NULL;
  705. CurrentEntry = DetachedList->Sibling;
  706. PreviousEntry = DetachedList;
  707. while (CurrentEntry) {
  708. if (CurrentEntry->ComponentEntry.Key <
  709. EntryFound->ComponentEntry.Key) {
  710. EntryFound = CurrentEntry;
  711. EntryFoundPrevious = PreviousEntry;
  712. }
  713. PreviousEntry = CurrentEntry;
  714. CurrentEntry = CurrentEntry->Sibling;
  715. }
  716. //
  717. // Remove the component from the detached child list.
  718. // If the component is not the head of the detached list, we remove it
  719. // by setting its previous entry's sibling to the component's sibling.
  720. // Otherwise, we simply update Detach list head to point to the
  721. // component's sibling.
  722. //
  723. if (EntryFoundPrevious) {
  724. EntryFoundPrevious->Sibling = EntryFound->Sibling;
  725. } else {
  726. DetachedList = EntryFound->Sibling;
  727. }
  728. //
  729. // Attach the component to the child list of Eisa root.
  730. //
  731. if (AttachedEntry) {
  732. AttachedEntry->Sibling = EntryFound;
  733. } else {
  734. RootEntry->Child = EntryFound;
  735. }
  736. AttachedEntry = EntryFound;
  737. AttachedEntry->Sibling = NULL;
  738. }
  739. //
  740. // Finally, we traverse the Eisa tree to collect all the Eisa slot
  741. // and function information and put it to the configuration data of
  742. // Eisa root entry.
  743. //
  744. Status = CreateEisaConfigurationData(RootEntry);
  745. //
  746. // Wipe out all the children of EISA tree.
  747. // NOTE shielint - For each child component, we should convert its
  748. // configuration data from EISA format to our CM_ format.
  749. //
  750. RootEntry->Child = NULL;
  751. return(Status);
  752. }
  753. ARC_STATUS
  754. CreateEisaConfigurationData (
  755. IN PCONFIGURATION_COMPONENT_DATA RootEntry
  756. )
  757. /*++
  758. Routine Description:
  759. This routine traverses Eisa configuration tree to collect all the
  760. slot and function information and attaches it to the configuration data
  761. of Eisa RootEntry.
  762. Note that this routine assumes that the EISA tree has been sorted based
  763. on the slot number.
  764. Arguments:
  765. RootEntry - Supplies a pointer to the Eisa configuration
  766. component entry.
  767. Returns:
  768. ESUCCESS is returned if the new EisaAdapter configuration data is
  769. successfully created. Otherwise, an unsuccessful status is returned.
  770. --*/
  771. {
  772. ULONG DataSize, NextSlot = 0, i;
  773. PCM_PARTIAL_RESOURCE_LIST Descriptor;
  774. PCONFIGURATION_COMPONENT Component;
  775. PCONFIGURATION_COMPONENT_DATA CurrentEntry;
  776. PUCHAR DataPointer;
  777. CM_EISA_SLOT_INFORMATION EmptySlot =
  778. {EISA_EMPTY_SLOT, 0, 0, 0, 0, 0, 0, 0};
  779. //
  780. // Remove the configuration data of Eisa Adapter
  781. //
  782. RootEntry->ConfigurationData = NULL;
  783. RootEntry->ComponentEntry.ConfigurationDataLength = 0;
  784. //
  785. // If the EISA stree contains valid slot information, i.e.
  786. // root has children attaching to it.
  787. //
  788. if (RootEntry->Child) {
  789. //
  790. // First find out how much memory is needed to store EISA config
  791. // data.
  792. //
  793. DataSize = sizeof(CM_PARTIAL_RESOURCE_LIST);
  794. CurrentEntry = RootEntry->Child;
  795. while (CurrentEntry) {
  796. Component = &CurrentEntry->ComponentEntry;
  797. if (CurrentEntry->ConfigurationData) {
  798. if (Component->Key > NextSlot) {
  799. //
  800. // If there is any empty slot between current slot
  801. // and previous checked slot, we need to count the
  802. // space for the empty slots.
  803. //
  804. DataSize += (Component->Key - NextSlot) *
  805. sizeof(CM_EISA_SLOT_INFORMATION);
  806. }
  807. DataSize += Component->ConfigurationDataLength + 1 -
  808. CONFIGURATION_DATA_HEADER_SIZE;
  809. NextSlot = Component->Key + 1;
  810. }
  811. CurrentEntry = CurrentEntry->Sibling;
  812. }
  813. //
  814. // Allocate memory from heap to hold the EISA configuration data.
  815. //
  816. DataPointer = BlAllocateHeap(DataSize);
  817. if (DataPointer == NULL) {
  818. return ENOMEM;
  819. } else {
  820. RootEntry->ConfigurationData = DataPointer;
  821. RootEntry->ComponentEntry.ConfigurationDataLength = DataSize;
  822. }
  823. //
  824. // Create a CM_PARTIAL_RESOURCE_LIST for the new configuration data.
  825. //
  826. Descriptor = (PCM_PARTIAL_RESOURCE_LIST)DataPointer;
  827. Descriptor->Version = 0;
  828. Descriptor->Revision = 0;
  829. Descriptor->Count = 1;
  830. Descriptor->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific;
  831. Descriptor->PartialDescriptors[0].ShareDisposition = 0;
  832. Descriptor->PartialDescriptors[0].Flags = 0;
  833. Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved1 = 0;
  834. Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved2 = 0;
  835. Descriptor->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
  836. DataSize - sizeof(CM_PARTIAL_RESOURCE_LIST);
  837. //
  838. // Visit each child of the RootEntry and copy its ConfigurationData
  839. // to the new configuration data area.
  840. // N.B. The configuration data includes a slot information and zero
  841. // or more function information. The slot information provided
  842. // by ARC eisa data does not have "ReturnedCode" as defined in
  843. // our CM_EISA_SLOT_INFORMATION. This code will convert the
  844. // standard EISA slot information to our CM format.
  845. //
  846. CurrentEntry = RootEntry->Child;
  847. DataPointer += sizeof(CM_PARTIAL_RESOURCE_LIST);
  848. NextSlot = 0;
  849. while (CurrentEntry) {
  850. Component = &CurrentEntry->ComponentEntry;
  851. if (CurrentEntry->ConfigurationData) {
  852. //
  853. // Check if there is any empty slot. If yes, create empty
  854. // slot information. Also make sure the config data area is
  855. // big enough.
  856. //
  857. if (Component->Key > NextSlot) {
  858. for (i = NextSlot; i < CurrentEntry->ComponentEntry.Key; i++ ) {
  859. *(PCM_EISA_SLOT_INFORMATION)DataPointer = EmptySlot;
  860. DataPointer += sizeof(CM_EISA_SLOT_INFORMATION);
  861. }
  862. }
  863. *DataPointer++ = 0; // See comment above
  864. RtlMoveMemory( // Skip config data header
  865. DataPointer,
  866. (PUCHAR)CurrentEntry->ConfigurationData +
  867. CONFIGURATION_DATA_HEADER_SIZE,
  868. Component->ConfigurationDataLength -
  869. CONFIGURATION_DATA_HEADER_SIZE
  870. );
  871. DataPointer += Component->ConfigurationDataLength -
  872. CONFIGURATION_DATA_HEADER_SIZE;
  873. NextSlot = Component->Key + 1;
  874. }
  875. CurrentEntry = CurrentEntry->Sibling;
  876. }
  877. }
  878. return(ESUCCESS);
  879. }
  880. ARC_STATUS
  881. BlPpcMemoryInitialize(
  882. VOID
  883. )
  884. /*++
  885. Routine Description:
  886. Called by BlPpcInitialize to do platform-specific memory initialization.
  887. This routine allocates all blocks that need to be in KSEG0 (mapped by a
  888. BAT register from virtual 0x80000000 to physical 0). It also changes
  889. MemoryLoadedProgram blocks above 8 MB to MemoryFree. This routine also
  890. makes the decision about whether the kernel and other boot code is going
  891. to be paged.
  892. Arguments:
  893. None.
  894. Return Value:
  895. None.
  896. --*/
  897. {
  898. ARC_STATUS Status;
  899. ULONG HighestKseg0Page;
  900. ULONG TotalPages;
  901. ULONG ContiguousLowMemoryPages;
  902. ULONG HighPage;
  903. PLIST_ENTRY NextEntry;
  904. PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
  905. PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor;
  906. PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor;
  907. ULONG Kseg0Length;
  908. ULONG Kseg0Pages;
  909. ULONG Kseg0PagesAdded;
  910. PCHAR EnvironmentVariable;
  911. //
  912. // Determine the amount of memory in the system, as well as the
  913. // amount of contiguous low memory at physical address 0.
  914. //
  915. // N.B. The ContiguousLowMemoryPages calculation depends on
  916. // the memory descriptor list being sorted.
  917. //
  918. TotalPages = 0;
  919. ContiguousLowMemoryPages = 0;
  920. for (NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  921. NextEntry != &BlLoaderBlock->MemoryDescriptorListHead;
  922. NextEntry = NextEntry->Flink) {
  923. NextDescriptor = CONTAINING_RECORD(NextEntry,
  924. MEMORY_ALLOCATION_DESCRIPTOR,
  925. ListEntry);
  926. TotalPages += NextDescriptor->PageCount;
  927. if (NextDescriptor->BasePage == ContiguousLowMemoryPages) {
  928. ContiguousLowMemoryPages += NextDescriptor->PageCount;
  929. }
  930. }
  931. //
  932. // If there is enough memory in the system, don't page the kernel
  933. // and the boot drivers -- use the KSEG0 BAT to cover all of it.
  934. //
  935. // The PAGEKERNEL environment variable can be used to override
  936. // this calculation. If the variable doesn't exist, the
  937. // calculation is used. If the variable exists and is equal to
  938. // "FALSE", the kernel is not paged. If the variable exists and
  939. // is not equal to "FALSE", the kernel is paged.
  940. //
  941. EnvironmentVariable = ArcGetEnvironmentVariable("PAGEKERNEL");
  942. if (EnvironmentVariable != NULL) {
  943. PageKernel = (BOOLEAN)(_stricmp(EnvironmentVariable, "FALSE") != 0);
  944. } else {
  945. PageKernel = (BOOLEAN)(TotalPages < PAGED_KERNEL_MEMORY_LIMIT);
  946. }
  947. //PageKernel = FALSE;
  948. //
  949. // Look for memory blocks marked LoadedProgram that are above 8 MB
  950. // and below 256 MB. If there are any, that means that we are
  951. // running with new firmware that maps free memory above 8 MB and
  952. // marks it as LoadedProgram, and we can treat all such memory as
  953. // free. Old firmware marks all memory above 8 MB, free or not, as
  954. // FirmwareTemporary.
  955. //
  956. // N.B. Because of the way the original firmware/system interface
  957. // was designed, new firmware cannot mark free memory above 8
  958. // MB as free, because the old loader might use such memory,
  959. // and when the old kernel mapped BAT0 to cover just the low 8
  960. // MB, that memory would become inaccessible.
  961. //
  962. // N.B. We ignore memory above 256 MB because we only want to use
  963. // one segment register to map boot code.
  964. //
  965. // N.B. If we're going to use the KSEG0 BAT to map the kernel, then
  966. // we must limit our search for LoadedProgram blocks to the
  967. // lower of the processor's BAT size limit and the amount of
  968. // contiguous low memory.
  969. //
  970. if (PageKernel) {
  971. Kseg0Pages = 256*MBpages;
  972. } else {
  973. Kseg0Pages = MIN(ContiguousLowMemoryPages,
  974. PAGES(BlLoaderBlock->u.Ppc.MaximumBlockLength));
  975. }
  976. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  977. while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  978. NextDescriptor = CONTAINING_RECORD(NextEntry,
  979. MEMORY_ALLOCATION_DESCRIPTOR,
  980. ListEntry);
  981. if (NextDescriptor->BasePage >= Kseg0Pages) {
  982. break;
  983. }
  984. if ((NextDescriptor->MemoryType == LoaderLoadedProgram) &&
  985. (NextDescriptor->BasePage >= 8*MBpages)) {
  986. //
  987. // We have found a LoadedProgram block above 8 MB. If
  988. // the block ends below 256 MB, simply mark the block as
  989. // free, and remove the descriptor from the memory list and
  990. // reinsert it, to allow the block to be merged with the
  991. // preceeding block, if possible. If the block crosses 256
  992. // MB, split the lower part of the block into a separate
  993. // free block, leaving the upper part marked as
  994. // LoadedProgram.
  995. //
  996. if ((NextDescriptor->BasePage + NextDescriptor->PageCount) <= Kseg0Pages) {
  997. NextDescriptor->MemoryType = LoaderFree;
  998. BlRemoveDescriptor(NextDescriptor);
  999. BlInsertDescriptor(NextDescriptor);
  1000. } else {
  1001. //
  1002. // The descriptor crosses 256 MB. If the previous
  1003. // descriptor describes free memory (a likely scenario),
  1004. // then we can move the low part of the block into that
  1005. // descriptor.
  1006. //
  1007. Kseg0PagesAdded = Kseg0Pages - NextDescriptor->BasePage;
  1008. PreviousDescriptor = CONTAINING_RECORD(NextDescriptor->ListEntry.Blink,
  1009. MEMORY_ALLOCATION_DESCRIPTOR,
  1010. ListEntry);
  1011. if ((&PreviousDescriptor->ListEntry != &BlLoaderBlock->MemoryDescriptorListHead) &&
  1012. (PreviousDescriptor->MemoryType == LoaderFree) &&
  1013. ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==
  1014. NextDescriptor->BasePage)) {
  1015. PreviousDescriptor->PageCount += Kseg0PagesAdded;
  1016. NextDescriptor->BasePage += Kseg0PagesAdded;
  1017. NextDescriptor->PageCount -= Kseg0PagesAdded;
  1018. } else {
  1019. //
  1020. // The previous descriptor does not describe free
  1021. // memory, so we need a new descriptor. If
  1022. // allocating a descriptor fails, we just don't
  1023. // change this block.
  1024. //
  1025. NewDescriptor = BlAllocateHeap(sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
  1026. if (NewDescriptor != NULL) {
  1027. NewDescriptor->MemoryType = LoaderFree;
  1028. NewDescriptor->BasePage = NextDescriptor->BasePage;
  1029. NewDescriptor->PageCount = Kseg0PagesAdded;
  1030. NextDescriptor->BasePage += Kseg0PagesAdded;
  1031. NextDescriptor->PageCount -= Kseg0PagesAdded;
  1032. BlInsertDescriptor(NewDescriptor);
  1033. }
  1034. }
  1035. }
  1036. }
  1037. NextEntry = NextEntry->Flink;
  1038. }
  1039. #define IBAT_BASE 528
  1040. #define DBAT_BASE 536
  1041. BlLog((LOG_ALL,"IBAT0U: %08lx IBAT0L: %08lx IBAT1U: %08lx IBAT1L: %08lx",
  1042. __sregister_get(IBAT_BASE+0),
  1043. __sregister_get(IBAT_BASE+1),
  1044. __sregister_get(IBAT_BASE+2),
  1045. __sregister_get(IBAT_BASE+3)));
  1046. BlLog((LOG_ALL,"IBAT2U: %08lx IBAT2L: %08lx IBAT3U: %08lx IBAT3L: %08lx",
  1047. __sregister_get(IBAT_BASE+4),
  1048. __sregister_get(IBAT_BASE+5),
  1049. __sregister_get(IBAT_BASE+6),
  1050. __sregister_get(IBAT_BASE+7)));
  1051. BlLog((LOG_ALL,"DBAT0U: %08lx DBAT0L: %08lx DBAT1U: %08lx DBAT1L: %08lx",
  1052. __sregister_get(DBAT_BASE+0),
  1053. __sregister_get(DBAT_BASE+1),
  1054. __sregister_get(DBAT_BASE+2),
  1055. __sregister_get(DBAT_BASE+3)));
  1056. BlLog((LOG_ALL,"DBAT2U: %08lx DBAT2L: %08lx DBAT3U: %08lx DBAT3L: %08lx",
  1057. __sregister_get(DBAT_BASE+4),
  1058. __sregister_get(DBAT_BASE+5),
  1059. __sregister_get(DBAT_BASE+6),
  1060. __sregister_get(DBAT_BASE+7)));
  1061. #if DBG
  1062. {
  1063. ULONG sr[16];
  1064. VOID GetSegmentRegisters(ULONG sr[16]);
  1065. GetSegmentRegisters(sr);
  1066. BlLog((LOG_ALL,"SR0 : %08lx SR1 : %08lx SR2 : %08lx SR3 : %08lx",
  1067. sr[0], sr[1], sr[2], sr[3]));
  1068. BlLog((LOG_ALL,"SR4 : %08lx SR5 : %08lx SR6 : %08lx SR7 : %08lx",
  1069. sr[4], sr[5], sr[6], sr[7]));
  1070. BlLog((LOG_ALL,"SR8 : %08lx SR9 : %08lx SR10: %08lx SR11: %08lx",
  1071. sr[8], sr[9], sr[10], sr[11]));
  1072. BlLog((LOG_ALL,"SR12: %08lx SR13: %08lx SR14: %08lx SR15: %08lx",
  1073. sr[12], sr[13], sr[14], sr[15]));
  1074. }
  1075. #endif
  1076. BlLog((LOG_ALL,"SPRG0: %08lx SPRG1: %08lx SPRG2: %08lx SPRG3: %08lx",
  1077. __sregister_get(272),
  1078. __sregister_get(273),
  1079. __sregister_get(274),
  1080. __sregister_get(275)));
  1081. BlLog((LOG_ALL_W,"SDR1: %08lx",
  1082. __sregister_get(25)));
  1083. //
  1084. // Allow the HPTSIZE environment variable to override the default HPT size.
  1085. //
  1086. // The format of the translation is decimal-number[k|K|m|M]. If the format
  1087. // is incorrect, or if the number is not a valid HPT size, the override is
  1088. // silently ignored.
  1089. //
  1090. if (BlLoaderBlock->u.Ppc.HashedPageTableSize != 0) {
  1091. EnvironmentVariable = ArcGetEnvironmentVariable("HPTSIZE");
  1092. if (EnvironmentVariable != NULL) {
  1093. ULONG NewHptSize = 0;
  1094. PUCHAR p = EnvironmentVariable;
  1095. //
  1096. // Parse the decimal number portion of the string.
  1097. //
  1098. while ((*p >= '0') && (*p <= '9')) {
  1099. NewHptSize = (NewHptSize * 10) + (*p - '0');
  1100. p++;
  1101. }
  1102. //
  1103. // Check for a k or m suffix.
  1104. //
  1105. if ((*p == 'k') || (*p == 'K')) {
  1106. NewHptSize = NewHptSize * KB;
  1107. p++;
  1108. }
  1109. if ((*p == 'm') || (*p == 'M')) {
  1110. NewHptSize = NewHptSize * MB;
  1111. p++;
  1112. }
  1113. //
  1114. // We must be at the end of the string. The number must be a
  1115. // power of 2, and it must be a valid HPT size.
  1116. //
  1117. if ((*p == 0) &&
  1118. ((NewHptSize & (NewHptSize - 1)) == 0) &&
  1119. ((NewHptSize >= 64*KB) && (NewHptSize <= 32*MB))) {
  1120. //
  1121. // Override the default HPT size.
  1122. //
  1123. BlLoaderBlock->u.Ppc.HashedPageTableSize = PAGES(NewHptSize);
  1124. }
  1125. }
  1126. }
  1127. //
  1128. // Allocate blocks that must be in KSEG0.
  1129. //
  1130. Status = AllocateKseg0Blocks( &HighestKseg0Page );
  1131. if (Status != ESUCCESS) {
  1132. return Status;
  1133. }
  1134. #if DBG
  1135. EnvironmentVariable = ArcGetEnvironmentVariable("HIGHESTFIT");
  1136. if (EnvironmentVariable != NULL) {
  1137. if (_stricmp(EnvironmentVariable, "TRUE") == 0) {
  1138. BlSetAllocationPolicy(BlAllocateHighestFit, BlAllocateHighestFit);
  1139. }
  1140. }
  1141. #endif
  1142. //
  1143. // If we're going to page the kernel, calculate the amount of low
  1144. // memory we need to reserve for KSEG0. HighestKseg0Page-1 tells us
  1145. // the highest page actually used by blocks that must be in KSEG0.
  1146. // We round this up to the next legal BAT size.
  1147. //
  1148. // KSEG0 must be at least as big as the level 1 D-cache, because
  1149. // the HAL D-cache sweep routines fill the cache from KSEG0.
  1150. //
  1151. if (PageKernel) {
  1152. Kseg0Pages = PAGES(BlLoaderBlock->u.Ppc.MinimumBlockLength);
  1153. while (Kseg0Pages < PAGES(BlLoaderBlock->u.Ppc.FirstLevelDcacheSize)) {
  1154. Kseg0Pages <<= 1;
  1155. }
  1156. while (Kseg0Pages < HighestKseg0Page) {
  1157. Kseg0Pages <<= 1;
  1158. }
  1159. Kseg0Length = BYTES(Kseg0Pages);
  1160. BlLoaderBlock->u.Ppc.Kseg0Top = AddressFromPage(Kseg0Pages);
  1161. BlLog((LOG_ALL,"Highest KSEG0 page: %x, KSEG0 pages: %x",HighestKseg0Page,Kseg0Pages));
  1162. //
  1163. // KSEG0 must be at least as big as the level 1 D-cache, because
  1164. // the HAL D-cache sweep routines fille the cache from KSEG0.
  1165. //
  1166. //
  1167. // Ensure that we don't require a BAT bigger than the processor can
  1168. // handle.
  1169. //
  1170. if (Kseg0Length > BlLoaderBlock->u.Ppc.MaximumBlockLength) {
  1171. BlLog((LOG_ALL,"ACK! KSEG0 too big! %x vs. %x",
  1172. Kseg0Length,BlLoaderBlock->u.Ppc.MaximumBlockLength));
  1173. return ENOMEM;
  1174. }
  1175. //
  1176. // We should have allocated everything from very low memory. At the
  1177. // very least, there must not be any holes in the memory that we're
  1178. // going to map the KSEG0 BAT to, otherwise we'll have problems with
  1179. // speculative execution on 603.
  1180. //
  1181. if (ContiguousLowMemoryPages < Kseg0Pages) {
  1182. BlLog((LOG_ALL,"ACK! Not enough contiguous memory at 0! (%x, need %x)",
  1183. ContiguousLowMemoryPages,Kseg0Pages));
  1184. return ENOMEM;
  1185. }
  1186. //
  1187. // All remaining free memory in the range of KSEG0 must be marked as
  1188. // FirmwareTemporary so that we don't use it during boot. The OS
  1189. // will reclaim this memory (and map it outside of KSEG0) after
  1190. // booting.
  1191. //
  1192. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  1193. while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  1194. NextDescriptor = CONTAINING_RECORD(NextEntry,
  1195. MEMORY_ALLOCATION_DESCRIPTOR,
  1196. ListEntry);
  1197. if (NextDescriptor->BasePage >= Kseg0Pages) {
  1198. break;
  1199. }
  1200. if (NextDescriptor->MemoryType == LoaderFree) {
  1201. HighPage = NextDescriptor->BasePage + NextDescriptor->PageCount;
  1202. HighPage = MIN(HighPage, Kseg0Pages);
  1203. BlLog((LOG_ALL,"Changing %x pages at %x to FirmwareTemporary",HighPage-NextDescriptor->BasePage,NextDescriptor->BasePage));
  1204. BlGenerateDescriptor(NextDescriptor,
  1205. LoaderFirmwareTemporary,
  1206. NextDescriptor->BasePage,
  1207. HighPage - NextDescriptor->BasePage);
  1208. }
  1209. NextEntry = NextEntry->Flink;
  1210. }
  1211. BlLogWaitForKeystroke();
  1212. }
  1213. BlLogMemoryDescriptors(LOG_ALL_W);
  1214. return ESUCCESS;
  1215. }
  1216. ARC_STATUS
  1217. BlPpcInitialize (
  1218. VOID
  1219. )
  1220. {
  1221. union {
  1222. PVR Pvr;
  1223. ULONG Ulong;
  1224. } Pvr;
  1225. BOOLEAN Is601;
  1226. BOOLEAN Is603;
  1227. BOOLEAN Is604;
  1228. BOOLEAN Is620;
  1229. ULONG MinBat;
  1230. ULONG MaxBat;
  1231. ULONG HptSize;
  1232. ULONG DcacheSize;
  1233. ULONG DcacheFill;
  1234. ULONG IcacheSize;
  1235. ULONG IcacheFill;
  1236. ULONG TlbSets;
  1237. Pvr.Ulong = KeGetPvr();
  1238. if (Pvr.Pvr.Version == 1) { // 601
  1239. MinBat = 128*KB;
  1240. MaxBat = 8*MB;
  1241. HptSize = 64*KB;
  1242. DcacheSize = 32*KB;
  1243. DcacheFill = 64;
  1244. IcacheSize = 32*KB;
  1245. IcacheFill = 64;
  1246. TlbSets = 128;
  1247. } else if (Pvr.Pvr.Version == 3) { // 603
  1248. MinBat = 128*KB;
  1249. MaxBat = 256*MB;
  1250. HptSize = 0;
  1251. DcacheSize = 8*KB;
  1252. DcacheFill = 32;
  1253. IcacheSize = 8*KB;
  1254. IcacheFill = 32;
  1255. TlbSets = 32;
  1256. } else if (Pvr.Pvr.Version == 4) { // 604
  1257. MinBat = 128*KB;
  1258. MaxBat = 256*MB;
  1259. HptSize = 64*KB;
  1260. DcacheSize = 16*KB;
  1261. DcacheFill = 32;
  1262. IcacheSize = 16*KB;
  1263. IcacheFill = 32;
  1264. TlbSets = 64;
  1265. } else if (Pvr.Pvr.Version == 6) { // 603+
  1266. MinBat = 128*KB;
  1267. MaxBat = 256*MB;
  1268. HptSize = 0;
  1269. DcacheSize = 16*KB;
  1270. DcacheFill = 32;
  1271. IcacheSize = 16*KB;
  1272. IcacheFill = 32;
  1273. TlbSets = 32;
  1274. } else if (Pvr.Pvr.Version == 7) { // 603++
  1275. MinBat = 128*KB;
  1276. MaxBat = 256*MB;
  1277. HptSize = 0;
  1278. DcacheSize = 16*KB;
  1279. DcacheFill = 32;
  1280. IcacheSize = 16*KB;
  1281. IcacheFill = 32;
  1282. TlbSets = 32;
  1283. } else if (Pvr.Pvr.Version == 8) { // Arthur or 613
  1284. MinBat = 128*KB;
  1285. MaxBat = 256*MB;
  1286. HptSize = 64*KB;
  1287. DcacheSize = 32*KB;
  1288. DcacheFill = 32;
  1289. IcacheSize = 32*KB;
  1290. IcacheFill = 32;
  1291. TlbSets = 64;
  1292. } else if (Pvr.Pvr.Version == 9) { // 604+
  1293. MinBat = 128*KB;
  1294. MaxBat = 256*MB;
  1295. HptSize = 64*KB;
  1296. DcacheSize = 32*KB;
  1297. DcacheFill = 32;
  1298. IcacheSize = 32*KB;
  1299. IcacheFill = 32;
  1300. TlbSets = 64;
  1301. } else if (Pvr.Pvr.Version == 20) { // 620+
  1302. MinBat = 128*KB;
  1303. MaxBat = 256*MB;
  1304. HptSize = 256*KB;
  1305. DcacheSize = 32*KB;
  1306. DcacheFill = 64;
  1307. IcacheSize = 32*KB;
  1308. IcacheFill = 64;
  1309. TlbSets = 64;
  1310. } else {
  1311. return EINVAL;
  1312. }
  1313. BlLoaderBlock->u.Ppc.MinimumBlockLength = MinBat;
  1314. BlLoaderBlock->u.Ppc.MaximumBlockLength = MaxBat;
  1315. BlLoaderBlock->u.Ppc.HashedPageTableSize = PAGES(HptSize);
  1316. BlLoaderBlock->u.Ppc.FirstLevelDcacheSize = DcacheSize;
  1317. BlLoaderBlock->u.Ppc.FirstLevelDcacheFillSize = DcacheFill;
  1318. BlLoaderBlock->u.Ppc.FirstLevelIcacheSize = IcacheSize;
  1319. BlLoaderBlock->u.Ppc.FirstLevelIcacheFillSize = IcacheFill;
  1320. BlLoaderBlock->u.Ppc.NumberCongruenceClasses = TlbSets;
  1321. BlLoaderBlock->u.Ppc.MajorVersion = 2;
  1322. BlLoaderBlock->u.Ppc.MinorVersion = 0;
  1323. return BlPpcMemoryInitialize();
  1324. }