Leaked source code of windows server 2003
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.

2490 lines
65 KiB

  1. /*++
  2. Copyright (c) 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. memory.c
  5. Abstract:
  6. This module sets up paging so that the first 1Mb of virtual memory is
  7. directly mapped to the first 1Mb of physical memory. This allows the
  8. BIOS callbacks to work, and the osloader to continue running below
  9. 1Mb. It also maps up to the first 16MB of physical memory to KSEG0_BASE
  10. and ALTERNATE_BASE, so the osloader can load kernel code into kernel
  11. space, and allocate kernel parameters in kernel space. This allows the
  12. dynamic configuration of the system for either a 2gb or 3gb user space
  13. address range.
  14. Note!!
  15. 3/16/00 (mikeg):
  16. All I/O (BlRead etc.) use a buffer below 1MB to do transfers so we
  17. don't need to worry about ISA cards DMA buffers. This change allows
  18. setupldr to run with all files compressed.
  19. If you need to change this, also change BASE_LOADER_IMAGE in bootx86.h
  20. or the PDE will not be completely unmapped. This must ALSO match
  21. ntos\mm\i386\mi386.h (BOOT_IMAGE_SIZE) so we know where
  22. to start loading images.
  23. Memory Map used by NTLDR:
  24. 000000 - 000fff RM IDT & Bios Data Area
  25. 007C00 - 007fff BPB loaded by Bootstrap
  26. 010000 - 01ffff Loadable miniport drivers, free memory
  27. 020000 - 02ffff SU + real-mode stack
  28. 030000 - 039000 BIOS disk cache
  29. 039000 - 039000 Permanent heap (GDT, IDT, TSS, Page Dir, Page Tables)
  30. (grows up)
  31. |
  32. v
  33. ^
  34. |
  35. (grows down)
  36. 039000 - 05ffff Temporary heap
  37. 060000 - 062000 osloader stack (grows down)
  38. 062000 - 09ffff osloader heap (grows down)
  39. 0b8000 - 0bbfff Video Buffer
  40. 0d0000 - 0fffff Bios and Adaptor ROM area
  41. Author:
  42. John Vert (jvert) 18-Jun-1991
  43. Environment:
  44. Kernel Mode
  45. Revision History:
  46. --*/
  47. #include "arccodes.h"
  48. #include "bootx86.h"
  49. //
  50. // 4-gigabyte boundary line (in pages)
  51. //
  52. #define _4G (1 << (32 - PAGE_SHIFT))
  53. //
  54. // Bogus memory line. (We don't ever want to use the memory that is in
  55. // the 0x40 pages just under the 16Mb line.)
  56. //
  57. #define _16MB_BOGUS (((ULONG)0x1000000-0x40*PAGE_SIZE) >> PAGE_SHIFT)
  58. #define ROM_START_PAGE (0x0A0000 >> PAGE_SHIFT)
  59. #define ROM_END_PAGE (0x100000 >> PAGE_SHIFT)
  60. //
  61. // Buffer for temporary storage of data read from the disk that needs
  62. // to end up in a location above the 1MB boundary.
  63. //
  64. // NOTE: it is very important that this buffer not cross a 64k boundary.
  65. //
  66. PUCHAR FwDiskCache = (PUCHAR)(BIOS_DISK_CACHE_START * PAGE_SIZE);
  67. //
  68. // Current heap start pointers (physical addresses)
  69. // Note that 0x50000 to 0x5ffff is reserved for detection configuration memory
  70. //
  71. ULONG FwPermanentHeap = PERMANENT_HEAP_START * PAGE_SIZE;
  72. ULONG FwTemporaryHeap = (TEMPORARY_HEAP_START - 0x10) * PAGE_SIZE;
  73. //
  74. // Current pool pointers. This is different than the temporary/permanent
  75. // heaps, because it is not required to be under 1MB. It is used by the
  76. // SCSI miniports for allocating their extensions and for the dbcs font image.
  77. //
  78. #define FW_POOL_SIZE 96
  79. ULONG FwPoolStart;
  80. ULONG FwPoolEnd;
  81. //
  82. // This gets set to FALSE right before we call into the osloader, so we
  83. // know that the fw memory descriptors can no longer be changed at will.
  84. //
  85. BOOLEAN FwDescriptorsValid = TRUE;
  86. ULONG HighestPde=((_16MB << PAGE_SHIFT) >> PDI_SHIFT);
  87. //
  88. // Private function prototypes
  89. //
  90. ARC_STATUS
  91. MempCopyGdt(
  92. VOID
  93. );
  94. ARC_STATUS
  95. MempSetupPaging(
  96. IN ULONG StartPage,
  97. IN ULONG NumberOfPages
  98. );
  99. VOID
  100. MempDisablePages(
  101. VOID
  102. );
  103. ARC_STATUS
  104. MempTurnOnPaging(
  105. VOID
  106. );
  107. ARC_STATUS
  108. MempSetDescriptorRegion (
  109. IN ULONG StartPage,
  110. IN ULONG EndPage,
  111. IN TYPE_OF_MEMORY MemoryType
  112. );
  113. ARC_STATUS
  114. MempSetPageMappingOverride(
  115. IN ULONG StartPage,
  116. IN ULONG NumberOfPages,
  117. IN BOOLEAN Enable
  118. );
  119. extern
  120. void
  121. BlpTrackUsage (
  122. MEMORY_TYPE MemoryType,
  123. ULONG ActualBase,
  124. ULONG NumberPages
  125. );
  126. //
  127. // Global - memory management variables.
  128. //
  129. PHARDWARE_PTE PDE;
  130. PHARDWARE_PTE HalPT;
  131. #define MAX_DESCRIPTORS 60
  132. MEMORY_DESCRIPTOR MDArray[MAX_DESCRIPTORS]; // Memory Descriptor List
  133. ULONG NumberDescriptors=0;
  134. ARC_STATUS
  135. InitializeMemorySubsystem(
  136. PBOOT_CONTEXT BootContext
  137. )
  138. /*++
  139. Routine Description:
  140. The initial heap is mapped and allocated. Pointers to the
  141. Page directory and page tables are initialized.
  142. Arguments:
  143. BootContext - Supplies basic information provided by SU module.
  144. Returns:
  145. ESUCCESS - Memory succesfully initialized.
  146. --*/
  147. {
  148. ARC_STATUS Status = ESUCCESS;
  149. PSU_MEMORY_DESCRIPTOR SuMemory;
  150. ULONG PageStart;
  151. ULONG PageEnd;
  152. ULONG RomStart = ROM_START_PAGE;
  153. ULONG LoaderStart;
  154. ULONG LoaderEnd;
  155. ULONG BAddr, EAddr, BRound, ERound;
  156. //
  157. // Start by creating memory descriptors to describe all of the memory
  158. // we know about. Then setup the page tables. Finally, allocate
  159. // descriptors that describe our memory layout.
  160. //
  161. //
  162. // We know that one of the SU descriptors is for < 1Mb,
  163. // and we don't care about that, since we know everything we'll run
  164. // on will have at least 1Mb of memory. The rest are for extended
  165. // memory, and those are the ones we are interested in.
  166. //
  167. SuMemory = BootContext->MemoryDescriptorList;
  168. while (SuMemory->BlockSize != 0) {
  169. BAddr = SuMemory->BlockBase;
  170. EAddr = BAddr + SuMemory->BlockSize - 1;
  171. //
  172. // Round the starting address to a page boundry.
  173. //
  174. BRound = BAddr & (ULONG) (PAGE_SIZE - 1);
  175. if (BRound) {
  176. BAddr = BAddr + PAGE_SIZE - BRound;
  177. }
  178. //
  179. // Round the ending address to a page boundry minus 1
  180. //
  181. ERound = (EAddr + 1) & (ULONG) (PAGE_SIZE - 1);
  182. if (ERound) {
  183. EAddr -= ERound;
  184. }
  185. //
  186. // Covert begining & ending address to page
  187. //
  188. PageStart = BAddr >> PAGE_SHIFT;
  189. PageEnd = (EAddr + 1) >> PAGE_SHIFT;
  190. //
  191. // If this memory descriptor describes conventional ( <640k )
  192. // memory, then assume the ROM starts immediately after it
  193. // ends.
  194. //
  195. if (PageStart == 0) {
  196. RomStart = PageEnd;
  197. }
  198. //
  199. // If PageStart was rounded up to a page boundry, then add
  200. // the fractional page as SpecialMemory
  201. //
  202. if (BRound) {
  203. Status = MempSetDescriptorRegion (
  204. PageStart - 1,
  205. PageStart,
  206. MemorySpecialMemory
  207. );
  208. if (Status != ESUCCESS) {
  209. break;
  210. }
  211. }
  212. //
  213. // If PageEnd was rounded down to a page boundry, then add
  214. // the fractional page as SpecialMemory
  215. //
  216. if (ERound) {
  217. Status = MempSetDescriptorRegion (
  218. PageEnd,
  219. PageEnd + 1,
  220. MemorySpecialMemory
  221. );
  222. if (Status != ESUCCESS) {
  223. break;
  224. }
  225. //
  226. // RomStart starts after the reserved page
  227. //
  228. if (RomStart == PageEnd) {
  229. RomStart += 1;
  230. }
  231. }
  232. //
  233. // Add memory range PageStart though PageEnd
  234. //
  235. if (PageEnd <= _16MB_BOGUS) {
  236. //
  237. // This memory descriptor is all below the 16MB_BOGUS mark
  238. //
  239. Status = MempSetDescriptorRegion( PageStart, PageEnd, MemoryFree );
  240. } else if (PageStart >= _16MB) {
  241. //
  242. // Memory above 16MB is only used when absolutely necessary so it
  243. // is flagged as LoaderReserve
  244. //
  245. // --- 3/14/00 Allow it to be used. The diamond code
  246. // and the bios disk code manage read buffers to
  247. // keep reads below the 1Mb or 16MB lines
  248. //
  249. Status = MempSetDescriptorRegion( PageStart, PageEnd, LoaderReserve);
  250. } else {
  251. //
  252. // This memory descriptor describes memory within the
  253. // last 40h pages of the 16MB mark - otherwise known as
  254. // 16MB_BOGUS.
  255. //
  256. //
  257. if (PageStart < _16MB_BOGUS) {
  258. //
  259. // Clip starting address to 16MB_BOGUS mark, and add
  260. // memory below 16MB_BOGUS as useable memory.
  261. //
  262. Status = MempSetDescriptorRegion( PageStart, _16MB_BOGUS,
  263. MemoryFree );
  264. if (Status != ESUCCESS) {
  265. break;
  266. }
  267. PageStart = _16MB_BOGUS;
  268. }
  269. //
  270. // Add remaining memory as LoaderReserve.
  271. //
  272. Status = MempSetDescriptorRegion( PageStart, PageEnd, LoaderReserve);
  273. }
  274. if (Status != ESUCCESS) {
  275. break;
  276. }
  277. //
  278. // Move to the next memory descriptor
  279. //
  280. ++SuMemory;
  281. }
  282. if (Status != ESUCCESS) {
  283. BlPrint("MempSetDescriptorRegion failed %lx\n",Status);
  284. return(Status);
  285. }
  286. //
  287. // Set the range 16MB_BOGUS - 16MB as unusable
  288. //
  289. Status = MempSetDescriptorRegion(_16MB_BOGUS, _16MB, MemorySpecialMemory);
  290. if (Status != ESUCCESS) {
  291. return(Status);
  292. }
  293. //
  294. // Hack for EISA machines that insist there is usable memory in the
  295. // ROM area, where we know darn well there isn't.
  296. //
  297. // Remove anything in this range..
  298. MempSetDescriptorRegion(ROM_START_PAGE, ROM_END_PAGE, LoaderMaximum);
  299. //
  300. // Describe the BIOS area
  301. //
  302. MempSetDescriptorRegion(RomStart, ROM_END_PAGE, MemoryFirmwarePermanent);
  303. //
  304. // If this is a remote boot, then everything between the "size of free
  305. // base memory" mark and the start of the ROM area needs to be marked
  306. // as firmware temporary. This is the boot ROM's data/stack area.
  307. //
  308. if ( BootContext->FSContextPointer->BootDrive == 0x40 ) {
  309. ULONG SizeOfFreeBaseMemory = (ULONG)*(USHORT *)0x413 * 1024;
  310. ULONG FirstRomDataPage = SizeOfFreeBaseMemory >> PAGE_SHIFT;
  311. if ( FirstRomDataPage < RomStart ) {
  312. MempSetDescriptorRegion(FirstRomDataPage, RomStart, MemoryFirmwareTemporary);
  313. }
  314. }
  315. //
  316. // Now we have descriptors that map all of physical memory. Carve
  317. // out descriptors from these that describe the parts that we are
  318. // currently using.
  319. //
  320. //
  321. // Create the descriptors which describe the low 1Mb of memory.
  322. //
  323. //
  324. // 00000 - 00fff real-mode interrupt vectors
  325. //
  326. Status = MempAllocDescriptor(0, 1, MemoryFirmwarePermanent);
  327. if (Status != ESUCCESS) {
  328. return(Status);
  329. }
  330. //
  331. // 01000 - 1ffff loadable miniport drivers, free memory.
  332. //
  333. Status = MempAllocDescriptor(1, 0x20, MemoryFree);
  334. if (Status != ESUCCESS) {
  335. return(Status);
  336. }
  337. //
  338. // 20000 - 2ffff SU module, SU stack
  339. //
  340. Status = MempAllocDescriptor(0x20, PERMANENT_HEAP_START, MemoryFirmwareTemporary);
  341. if (Status != ESUCCESS) {
  342. return(Status);
  343. }
  344. //
  345. // 30000 - 30000 Firmware Permanent
  346. // This starts out as zero-length. It grows into the firmware temporary
  347. // heap descriptor as we allocate permanent pages for the Page Directory
  348. // and Page Tables
  349. //
  350. Status = MempAllocDescriptor(PERMANENT_HEAP_START,
  351. PERMANENT_HEAP_START,
  352. LoaderMemoryData);
  353. if (Status != ESUCCESS) {
  354. return(Status);
  355. }
  356. //
  357. // 30000 - 5ffff Firmware temporary heap
  358. //
  359. Status = MempAllocDescriptor(PERMANENT_HEAP_START,
  360. TEMPORARY_HEAP_START,
  361. MemoryFirmwareTemporary);
  362. if (Status != ESUCCESS) {
  363. return(Status);
  364. }
  365. //
  366. // Stack we are currently running on.
  367. //
  368. Status = MempAllocDescriptor(TEMPORARY_HEAP_START,
  369. TEMPORARY_HEAP_START+2,
  370. MemoryFirmwareTemporary);
  371. if (Status != ESUCCESS) {
  372. return(Status);
  373. }
  374. //
  375. // Describe the osloader memory image
  376. //
  377. LoaderStart = BootContext->OsLoaderStart >> PAGE_SHIFT;
  378. LoaderEnd = (BootContext->OsLoaderEnd + PAGE_SIZE - 1) >> PAGE_SHIFT;
  379. Status = MempAllocDescriptor(LoaderStart,
  380. LoaderEnd,
  381. MemoryLoadedProgram);
  382. if (Status != ESUCCESS) {
  383. return(Status);
  384. }
  385. //
  386. // Describe the memory pool used to allocate memory for the SCSI
  387. // miniports.
  388. //
  389. Status = MempAllocDescriptor(LoaderEnd,
  390. LoaderEnd + FW_POOL_SIZE,
  391. MemoryFirmwareTemporary);
  392. if (Status != ESUCCESS) {
  393. return(Status);
  394. }
  395. FwPoolStart = LoaderEnd << PAGE_SHIFT;
  396. FwPoolEnd = FwPoolStart + (FW_POOL_SIZE << PAGE_SHIFT);
  397. //
  398. // HACKHACK - try to mark a page just below the osloader as firmwaretemp,
  399. // so it will not get used for heap/stack. This is to force
  400. // our heap/stack to be < 1Mb.
  401. //
  402. MempAllocDescriptor((BootContext->OsLoaderStart >> PAGE_SHIFT)-1,
  403. BootContext->OsLoaderStart >> PAGE_SHIFT,
  404. MemoryFirmwareTemporary);
  405. Status = MempTurnOnPaging();
  406. if (Status != ESUCCESS) {
  407. return(Status);
  408. }
  409. Status = MempCopyGdt();
  410. //
  411. // Find any reserved ranges described by the firmware and
  412. // record these
  413. //
  414. return(Status);
  415. }
  416. VOID
  417. InitializeMemoryDescriptors (
  418. VOID
  419. )
  420. /*++
  421. Routine Description:
  422. Pass 2 of InitializeMemorySubsystem. This function reads the
  423. firmware address space map and reserves ranges the firmware declares
  424. as "address space reserved".
  425. Note: free memory range descriptors has already been reported by su.
  426. Arguments:
  427. none
  428. Returns:
  429. none
  430. --*/
  431. {
  432. ULONGLONG BAddr, EAddr, Length;
  433. ULONG BPage, EPage;
  434. E820FRAME Frame;
  435. #ifdef LOADER_DEBUG
  436. BlPrint("Begin InitializeMemoryDescriptors\n") ;
  437. #endif
  438. Frame.Key = 0;
  439. do {
  440. Frame.Size = sizeof (Frame.Descriptor);
  441. GET_MEMORY_DESCRIPTOR (&Frame);
  442. if (Frame.ErrorFlag || Frame.Size < sizeof (Frame.Descriptor)) {
  443. break;
  444. }
  445. #ifdef LOADER_DEBUG
  446. BlPrint("*E820: %lx %lx:%lx %lx:%lx %lx %lx\n",
  447. Frame.Size,
  448. Frame.Descriptor.BaseAddrHigh, Frame.Descriptor.BaseAddrLow,
  449. Frame.Descriptor.SizeHigh, Frame.Descriptor.SizeLow,
  450. Frame.Descriptor.MemoryType,
  451. Frame.Key
  452. );
  453. #endif
  454. BAddr = Frame.Descriptor.BaseAddrHigh;
  455. BAddr = (BAddr << 32) + Frame.Descriptor.BaseAddrLow;
  456. Length = Frame.Descriptor.SizeHigh;
  457. Length = (Length << 32) + Frame.Descriptor.SizeLow;
  458. EAddr = BAddr + Length - 1;
  459. //
  460. // The memory range is described as the region from BAddr to EAddr
  461. // inclusive.
  462. //
  463. //
  464. // Some processors support physical addressing above 32 bits.
  465. //
  466. //
  467. // Based upon the address range descriptor type, find the
  468. // available memory and add it to the descriptor list
  469. //
  470. switch (Frame.Descriptor.MemoryType) {
  471. case 1:
  472. //
  473. // This is a memory descriptor - it's already been handled
  474. // by su (eisac.c)
  475. //
  476. // However, any memory within 16MB_BOGUS - 16MB was
  477. // considered unuseable. Reclaim memory within this
  478. // region which is described via this interface.
  479. //
  480. // Also, any memory above 4G was considered unusable.
  481. // Reclaim memory within this range as well.
  482. //
  483. BPage = (ULONG)((BAddr + PAGE_SIZE - 1) >> PAGE_SHIFT);
  484. EPage = (ULONG)((EAddr >> PAGE_SHIFT) + 1);
  485. //
  486. // Clip to bogus range
  487. //
  488. if (BPage < _16MB_BOGUS && EPage >= _16MB_BOGUS) {
  489. BPage = _16MB_BOGUS;
  490. }
  491. //
  492. // SGP - The code in InitializeMemorySubsystem reserves
  493. // from 16MB_BOGUS to 16MB as MemorySpecialMemory. This
  494. // piece set the endpage to 16MB - 1, which isn't consistent
  495. //
  496. //
  497. if (EPage > _16MB && BPage <= _16MB) {
  498. EPage = _16MB;
  499. }
  500. if (BPage >= _16MB_BOGUS && EPage <= _16MB) {
  501. //
  502. // Reclaim memory within the bogus range
  503. // by setting it to FirmwareTemporary
  504. //
  505. MempSetDescriptorRegion (
  506. BPage,
  507. EPage,
  508. MemoryFirmwareTemporary
  509. );
  510. }
  511. //
  512. // Now reclaim any portion of this range that lies above
  513. // the 4G line.
  514. //
  515. BPage = (ULONG)((BAddr + PAGE_SIZE - 1) >> PAGE_SHIFT);
  516. EPage = (ULONG)((EAddr >> PAGE_SHIFT) + 1);
  517. if (EPage >= _4G) {
  518. //
  519. // At least part of this region is above 4G. Truncate
  520. // any portion that falls below 4G, and reclaim
  521. // the memory.
  522. //
  523. if (BPage < _4G) {
  524. BPage = _4G;
  525. }
  526. MempSetDescriptorRegion (
  527. BPage,
  528. EPage,
  529. MemoryFirmwareTemporary
  530. );
  531. }
  532. break;
  533. default: // unkown types are treated as Reserved
  534. case 2:
  535. //
  536. // This memory descriptor is a reserved address range
  537. //
  538. BPage = (ULONG)(BAddr >> PAGE_SHIFT);
  539. EPage = (ULONG)((EAddr + 1 + PAGE_SIZE - 1) >> PAGE_SHIFT);
  540. MempSetDescriptorRegion (
  541. BPage,
  542. EPage,
  543. MemorySpecialMemory
  544. );
  545. break;
  546. }
  547. } while (Frame.Key) ;
  548. //
  549. // Disable pages from KSEG0 which are disabled
  550. //
  551. MempDisablePages();
  552. #ifdef LOADER_DEBUG
  553. BlPrint("Complete InitializeMemoryDescriptors\n") ;
  554. #endif
  555. return;
  556. }
  557. ARC_STATUS
  558. MempCopyGdt(
  559. VOID
  560. )
  561. /*++
  562. Routine Description:
  563. Copies the GDT & IDT into pages allocated out of our permanent heap.
  564. Arguments:
  565. None
  566. Return Value:
  567. ESUCCESS - GDT & IDT copy successful
  568. --*/
  569. {
  570. #pragma pack(2)
  571. static struct {
  572. USHORT Limit;
  573. ULONG Base;
  574. } GdtDef, IdtDef;
  575. #pragma pack(4)
  576. ULONG BlockSize;
  577. PKGDTENTRY NewGdt;
  578. PKIDTENTRY NewIdt;
  579. ULONG NumPages;
  580. //
  581. // Get the current location of the GDT & IDT
  582. //
  583. _asm {
  584. sgdt GdtDef;
  585. sidt IdtDef;
  586. }
  587. if (GdtDef.Base + GdtDef.Limit + 1 != IdtDef.Base) {
  588. //
  589. // Just a sanity check to make sure that the IDT immediately
  590. // follows the GDT. (As set up in SUDATA.ASM)
  591. //
  592. BlPrint("ERROR - GDT and IDT are not contiguous!\n");
  593. BlPrint("GDT - %lx (%x) IDT - %lx (%x)\n",
  594. GdtDef.Base, GdtDef.Limit,
  595. IdtDef.Base, IdtDef.Limit);
  596. while (1);
  597. }
  598. BlockSize = GdtDef.Limit+1 + IdtDef.Limit+1;
  599. NumPages = (BlockSize + PAGE_SIZE-1) >> PAGE_SHIFT;
  600. NewGdt = (PKGDTENTRY)FwAllocateHeapPermanent(NumPages);
  601. if (NewGdt == NULL) {
  602. return(ENOMEM);
  603. }
  604. RtlMoveMemory((PVOID)NewGdt, (PVOID)GdtDef.Base, NumPages << PAGE_SHIFT);
  605. GdtDef.Base = (ULONG)NewGdt;
  606. IdtDef.Base = (ULONG)((PUCHAR)NewGdt + GdtDef.Limit + 1);
  607. //
  608. // Initialize the boot debugger IDT entries.
  609. //
  610. NewIdt = (PKIDTENTRY)IdtDef.Base;
  611. NewIdt[1].Offset = (USHORT)((ULONG)BdTrap01 & 0xffff);
  612. NewIdt[1].Selector = 8;
  613. NewIdt[1].Access = 0x8e00;
  614. NewIdt[1].ExtendedOffset = (USHORT)((ULONG)BdTrap01 >> 16);
  615. NewIdt[3].Offset = (USHORT)((ULONG)BdTrap03 & 0xffff);
  616. NewIdt[3].Selector = 8;
  617. NewIdt[3].Access = 0x8e00;
  618. NewIdt[3].ExtendedOffset = (USHORT)((ULONG)BdTrap03 >> 16);
  619. NewIdt[0xd].Offset = (USHORT)((ULONG)BdTrap0d & 0xffff);
  620. NewIdt[0xd].Selector = 8;
  621. NewIdt[0xd].Access = 0x8e00;
  622. NewIdt[0xd].ExtendedOffset = (USHORT)((ULONG)BdTrap0d >> 16);
  623. NewIdt[0xe].Offset = (USHORT)((ULONG)BdTrap0e & 0xffff);
  624. NewIdt[0xe].Selector = 8;
  625. NewIdt[0xe].Access = 0x8e00;
  626. NewIdt[0xe].ExtendedOffset = (USHORT)((ULONG)BdTrap0e >> 16);
  627. NewIdt[0x2d].Offset = (USHORT)((ULONG)BdTrap2d & 0xffff);
  628. NewIdt[0x2d].Selector = 8;
  629. NewIdt[0x2d].Access = 0x8e00;
  630. NewIdt[0x2d].ExtendedOffset = (USHORT)((ULONG)BdTrap2d >> 16);
  631. //
  632. // Load GDT and IDT registers.
  633. //
  634. _asm {
  635. lgdt GdtDef;
  636. lidt IdtDef;
  637. }
  638. //
  639. // Initialize the boot debugger.
  640. //
  641. #if defined(ENABLE_LOADER_DEBUG)
  642. BdInitDebugger((PCHAR)OsLoaderName, (PVOID)OsLoaderBase, ENABLE_LOADER_DEBUG);
  643. #else
  644. BdInitDebugger((PCHAR)OsLoaderName, (PVOID)OsLoaderBase, NULL);
  645. #endif
  646. return ESUCCESS;
  647. }
  648. ARC_STATUS
  649. MempSetDescriptorRegion (
  650. IN ULONG StartPage,
  651. IN ULONG EndPage,
  652. IN TYPE_OF_MEMORY MemoryType
  653. )
  654. /*++
  655. Routine Description:
  656. This function sets a range to the corrisponding memory type.
  657. Descriptors will be removed, modified, inserted as needed to
  658. set the specified range.
  659. Arguments:
  660. StartPage - Supplies the beginning page of the new memory descriptor
  661. EndPage - Supplies the ending page of the new memory descriptor
  662. MemoryType - Supplies the type of memory of the new memory descriptor
  663. Return Value:
  664. ESUCCESS - Memory descriptor succesfully added to MDL array
  665. ENOMEM - MDArray is full.
  666. --*/
  667. {
  668. ULONG i;
  669. ULONG sp, ep;
  670. TYPE_OF_MEMORY mt;
  671. BOOLEAN RegionAdded;
  672. if (EndPage <= StartPage) {
  673. //
  674. // This is a completely bogus memory descriptor. Ignore it.
  675. //
  676. #ifdef LOADER_DEBUG
  677. BlPrint("Attempt to create invalid memory descriptor %lx - %lx\n",
  678. StartPage,EndPage);
  679. #endif
  680. return(ESUCCESS);
  681. }
  682. RegionAdded = FALSE;
  683. //
  684. // Clip, remove, any descriptors in target area
  685. //
  686. for (i=0; i < NumberDescriptors; i++) {
  687. sp = MDArray[i].BasePage;
  688. ep = MDArray[i].BasePage + MDArray[i].PageCount;
  689. mt = MDArray[i].MemoryType;
  690. if (sp < StartPage) {
  691. if (ep > StartPage && ep <= EndPage) {
  692. // truncate this descriptor
  693. ep = StartPage;
  694. }
  695. if (ep > EndPage) {
  696. //
  697. // Target area is contained totally within this
  698. // descriptor. Split the descriptor into two ranges
  699. //
  700. if (NumberDescriptors == MAX_DESCRIPTORS) {
  701. return(ENOMEM);
  702. }
  703. //
  704. // Add descriptor for EndPage - ep
  705. //
  706. MDArray[NumberDescriptors].MemoryType = mt;
  707. MDArray[NumberDescriptors].BasePage = EndPage;
  708. MDArray[NumberDescriptors].PageCount = ep - EndPage;
  709. NumberDescriptors += 1;
  710. //
  711. // Adjust current descriptor for sp - StartPage
  712. //
  713. ep = StartPage;
  714. }
  715. } else {
  716. // sp >= StartPage
  717. if (sp < EndPage) {
  718. if (ep < EndPage) {
  719. //
  720. // This descriptor is totally within the target area -
  721. // remove it
  722. //
  723. ep = sp;
  724. } else {
  725. // bump begining page of this descriptor
  726. sp = EndPage;
  727. }
  728. }
  729. }
  730. //
  731. // Check if the new range can be appended or prepended to
  732. // this descriptor
  733. //
  734. if (mt == MemoryType && !RegionAdded) {
  735. if (sp == EndPage) {
  736. // prepend region being set
  737. sp = StartPage;
  738. RegionAdded = TRUE;
  739. } else if (ep == StartPage) {
  740. // append region being set
  741. ep = EndPage;
  742. RegionAdded = TRUE;
  743. }
  744. }
  745. if (MDArray[i].BasePage == sp && MDArray[i].PageCount == ep-sp) {
  746. //
  747. // Descriptor was not editted
  748. //
  749. continue;
  750. }
  751. //
  752. // Reset this descriptor
  753. //
  754. MDArray[i].BasePage = sp;
  755. MDArray[i].PageCount = ep - sp;
  756. if (ep == sp) {
  757. //
  758. // Descriptor vanished - remove it
  759. //
  760. NumberDescriptors -= 1;
  761. if (i < NumberDescriptors) {
  762. MDArray[i] = MDArray[NumberDescriptors];
  763. }
  764. i--; // backup & recheck current position
  765. }
  766. }
  767. //
  768. // If region wasn't already added to a neighboring region, then
  769. // create a new descriptor now
  770. //
  771. if (!RegionAdded && MemoryType < LoaderMaximum) {
  772. if (NumberDescriptors == MAX_DESCRIPTORS) {
  773. return(ENOMEM);
  774. }
  775. #ifdef LOADER_DEBUG
  776. BlPrint("Adding '%lx - %lx, type %x' to descriptor list\n",
  777. StartPage << PAGE_SHIFT,
  778. EndPage << PAGE_SHIFT,
  779. (USHORT) MemoryType
  780. );
  781. #endif
  782. MDArray[NumberDescriptors].MemoryType = MemoryType;
  783. MDArray[NumberDescriptors].BasePage = StartPage;
  784. MDArray[NumberDescriptors].PageCount = EndPage - StartPage;
  785. NumberDescriptors += 1;
  786. }
  787. return (ESUCCESS);
  788. }
  789. ARC_STATUS
  790. MempAllocDescriptor(
  791. IN ULONG StartPage,
  792. IN ULONG EndPage,
  793. IN TYPE_OF_MEMORY MemoryType
  794. )
  795. /*++
  796. Routine Description:
  797. This routine carves out a specific memory descriptor from the
  798. memory descriptors that have already been created. The MD array
  799. is updated to reflect the new state of memory.
  800. The new memory descriptor must be completely contained within an
  801. already existing memory descriptor. (i.e. memory that does not
  802. exist should never be marked as a certain type)
  803. Arguments:
  804. StartPage - Supplies the beginning page of the new memory descriptor
  805. EndPage - Supplies the ending page of the new memory descriptor
  806. MemoryType - Supplies the type of memory of the new memory descriptor
  807. Return Value:
  808. ESUCCESS - Memory descriptor succesfully added to MDL array
  809. ENOMEM - MDArray is full.
  810. --*/
  811. {
  812. ULONG i;
  813. //
  814. // Walk through the memory descriptors until we find one that
  815. // contains the start of the descriptor.
  816. //
  817. for (i=0; i<NumberDescriptors; i++) {
  818. if ((MDArray[i].MemoryType == MemoryFree) &&
  819. (MDArray[i].BasePage <= StartPage ) &&
  820. (MDArray[i].BasePage+MDArray[i].PageCount > StartPage) &&
  821. (MDArray[i].BasePage+MDArray[i].PageCount >= EndPage)) {
  822. break;
  823. }
  824. }
  825. if (i==NumberDescriptors) {
  826. return(ENOMEM);
  827. }
  828. if (MDArray[i].BasePage == StartPage) {
  829. if (MDArray[i].BasePage+MDArray[i].PageCount == EndPage) {
  830. //
  831. // The new descriptor is identical to the existing descriptor.
  832. // Simply change the memory type of the existing descriptor in
  833. // place.
  834. //
  835. MDArray[i].MemoryType = MemoryType;
  836. } else {
  837. //
  838. // The new descriptor starts on the same page, but is smaller
  839. // than the existing descriptor. Shrink the existing descriptor
  840. // by moving its start page up, and create a new descriptor.
  841. //
  842. if (NumberDescriptors == MAX_DESCRIPTORS) {
  843. return(ENOMEM);
  844. }
  845. MDArray[i].BasePage = EndPage;
  846. MDArray[i].PageCount -= (EndPage-StartPage);
  847. MDArray[NumberDescriptors].BasePage = StartPage;
  848. MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
  849. MDArray[NumberDescriptors].MemoryType = MemoryType;
  850. ++NumberDescriptors;
  851. }
  852. } else if (MDArray[i].BasePage+MDArray[i].PageCount == EndPage) {
  853. //
  854. // The new descriptor ends on the same page. Shrink the existing
  855. // by decreasing its page count, and create a new descriptor.
  856. //
  857. if (NumberDescriptors == MAX_DESCRIPTORS) {
  858. return(ENOMEM);
  859. }
  860. MDArray[i].PageCount = StartPage - MDArray[i].BasePage;
  861. MDArray[NumberDescriptors].BasePage = StartPage;
  862. MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
  863. MDArray[NumberDescriptors].MemoryType = MemoryType;
  864. ++NumberDescriptors;
  865. } else {
  866. //
  867. // The new descriptor is in the middle of the existing descriptor.
  868. // Shrink the existing descriptor by decreasing its page count, and
  869. // create two new descriptors.
  870. //
  871. if (NumberDescriptors+1 >= MAX_DESCRIPTORS) {
  872. return(ENOMEM);
  873. }
  874. MDArray[NumberDescriptors].BasePage = EndPage;
  875. MDArray[NumberDescriptors].PageCount = MDArray[i].PageCount -
  876. (EndPage-MDArray[i].BasePage);
  877. MDArray[NumberDescriptors].MemoryType = MemoryFree;
  878. ++NumberDescriptors;
  879. MDArray[i].PageCount = StartPage - MDArray[i].BasePage;
  880. MDArray[NumberDescriptors].BasePage = StartPage;
  881. MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
  882. MDArray[NumberDescriptors].MemoryType = MemoryType;
  883. ++NumberDescriptors;
  884. }
  885. BlpTrackUsage (MemoryType,StartPage,EndPage-StartPage);
  886. return(ESUCCESS);
  887. }
  888. ARC_STATUS
  889. MempTurnOnPaging(
  890. VOID
  891. )
  892. /*++
  893. Routine Description:
  894. Sets up the page tables necessary to map the first 16mb of memory and
  895. enables paging.
  896. Arguments:
  897. None.
  898. Return Value:
  899. ESUCCESS - Paging successfully turned on
  900. --*/
  901. {
  902. ULONG i;
  903. ARC_STATUS Status;
  904. //
  905. // Allocate, initialize, and map the PDE page onto itself (i.e., virtual
  906. // address PDE_BASE).
  907. //
  908. PDE = FwAllocateHeapPermanent(1);
  909. if (PDE == NULL) {
  910. return ENOMEM;
  911. }
  912. RtlZeroMemory(PDE, PAGE_SIZE);
  913. PDE[PDE_BASE >> 22].Valid = 1;
  914. PDE[PDE_BASE >> 22].Write = 1;
  915. PDE[PDE_BASE >> 22].PageFrameNumber = (ULONG)PDE >> PAGE_SHIFT;
  916. //
  917. // Allocate, initialize, and map the HAL page into the last PDE (i.e.,
  918. // virtual address range 0xffc00000 - 0xffffffff).
  919. //
  920. HalPT = FwAllocateHeapPermanent(1);
  921. if (HalPT == NULL) {
  922. return ENOMEM;
  923. }
  924. RtlZeroMemory(HalPT, PAGE_SIZE);
  925. PDE[1023].Valid = 1;
  926. PDE[1023].Write = 1;
  927. PDE[1023].PageFrameNumber = (ULONG)HalPT >> PAGE_SHIFT;
  928. //
  929. // Scan the memory descriptor list and setup paging for each descriptor.
  930. //
  931. for (i = 0; i < NumberDescriptors; i++) {
  932. if (MDArray[i].BasePage < _16MB) {
  933. Status = MempSetupPaging(MDArray[i].BasePage,
  934. MDArray[i].PageCount);
  935. if (Status != ESUCCESS) {
  936. BlPrint("ERROR - MempSetupPaging(%lx, %lx) failed\n",
  937. MDArray[i].BasePage,
  938. MDArray[i].PageCount);
  939. return Status;
  940. }
  941. }
  942. }
  943. //
  944. // Turn on paging.
  945. //
  946. _asm {
  947. //
  948. // Load physical address of page directory
  949. //
  950. mov eax,PDE
  951. mov cr3,eax
  952. //
  953. // Enable paging mode
  954. //
  955. mov eax,cr0
  956. or eax,CR0_PG
  957. mov cr0,eax
  958. }
  959. return ESUCCESS;
  960. }
  961. ARC_STATUS
  962. MempSetupPaging(
  963. IN ULONG StartPage,
  964. IN ULONG NumberPages
  965. )
  966. /*++
  967. Routine Description:
  968. Allocates and initializes the page table pages required to identity map
  969. the specified region of memory at its physical address, at KSEG0_BASE, OLD_ALTERNATE
  970. and at ALTERNATE_BASE.
  971. Arguments:
  972. StartPage - Supplies the first page to start mapping.
  973. NumberPage - Supplies the number of pages to map.
  974. Return Value:
  975. ESUCCESS - Paging successfully set up
  976. --*/
  977. {
  978. ULONG EndPage;
  979. ULONG Entry;
  980. ULONG FrameNumber;
  981. ULONG Page;
  982. PHARDWARE_PTE PageTableP;
  983. PHARDWARE_PTE PageTableV;
  984. ULONG Offset;
  985. //
  986. // The page table pages that are used to map memory at physical equal
  987. // real addresses are allocated from firmware temporary memory which
  988. // gets released when memory management initializes.
  989. //
  990. // N.B. Physical memory is mapped at its physical address, KSEG0_BASE,
  991. // and at ALTERNATE_BASE. This allows the system to be configured
  992. // by the OS Loader to be either a 2gb or 3gb user space system
  993. // based on an OS Loader option.
  994. //
  995. EndPage = StartPage + NumberPages;
  996. for (Page = StartPage; Page < EndPage; Page += 1) {
  997. Entry = Page >> 10;
  998. //
  999. // If the PDE entry for this page address range is not allocated,
  1000. // then allocate and initialize the PDE entry to map the page table
  1001. // pages for the the memory range. Otherwise, compute the address
  1002. // of the page table pages.
  1003. //
  1004. if (PDE[Entry].Valid == 0) {
  1005. //
  1006. // Allocate and initialize a page table page to map the specified
  1007. // page into physical memory.
  1008. //
  1009. PageTableP = (PHARDWARE_PTE)FwAllocateHeapAligned(PAGE_SIZE);
  1010. if (PageTableP == NULL) {
  1011. return ENOMEM;
  1012. }
  1013. RtlZeroMemory(PageTableP, PAGE_SIZE);
  1014. FrameNumber = (ULONG)PageTableP >> PAGE_SHIFT;
  1015. PDE[Entry].Valid = 1;
  1016. PDE[Entry].Write = 1;
  1017. PDE[Entry].PageFrameNumber = FrameNumber;
  1018. //
  1019. // Allocate and initialize a page table page to map the specified
  1020. // page into KSEG0_BASE and ALTERNATE_BASE.
  1021. //
  1022. // N.B. Only one page table page is allocated since the contents
  1023. // for both mappings are the same.
  1024. //
  1025. PageTableV = (PHARDWARE_PTE)FwAllocateHeapPermanent(1);
  1026. if (PageTableV == NULL) {
  1027. return ENOMEM;
  1028. }
  1029. RtlZeroMemory(PageTableV, PAGE_SIZE);
  1030. FrameNumber = (ULONG)PageTableV >> PAGE_SHIFT;
  1031. Offset = Entry + (KSEG0_BASE >> 22);
  1032. PDE[Offset].Valid = 1;
  1033. PDE[Offset].Write = 1;
  1034. PDE[Offset].PageFrameNumber = FrameNumber;
  1035. Offset = Entry + (ALTERNATE_BASE >> 22);
  1036. PDE[Offset].Valid = 1;
  1037. PDE[Offset].Write = 1;
  1038. PDE[Offset].PageFrameNumber = FrameNumber;
  1039. if (Entry > HighestPde) {
  1040. HighestPde = Entry;
  1041. }
  1042. } else {
  1043. Offset = Entry + (KSEG0_BASE >> 22);
  1044. PageTableP = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << PAGE_SHIFT);
  1045. PageTableV = (PHARDWARE_PTE)(PDE[Offset].PageFrameNumber << PAGE_SHIFT);
  1046. }
  1047. //
  1048. // If this is not the first page in memory, then mark it valid.
  1049. //
  1050. if (Page != 0) {
  1051. Offset = Page & 0x3ff;
  1052. PageTableP[Offset].Valid = 1;
  1053. PageTableP[Offset].Write = 1;
  1054. PageTableP[Offset].PageFrameNumber = Page;
  1055. PageTableV[Offset].Valid = 1;
  1056. PageTableV[Offset].Write = 1;
  1057. PageTableV[Offset].PageFrameNumber = Page;
  1058. }
  1059. }
  1060. return ESUCCESS;
  1061. }
  1062. VOID
  1063. MempDisablePages(
  1064. VOID
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. Frees as many Page Tables as are required from the KSEG0_BASE, OLD_ALTERNATE
  1069. and ALTERNATE_BASE regions.
  1070. Arguments:
  1071. None.
  1072. Return Value:
  1073. none
  1074. --*/
  1075. {
  1076. ULONG EndPage;
  1077. ULONG Entry;
  1078. ULONG i;
  1079. ULONG Offset;
  1080. ULONG Page;
  1081. PHARDWARE_PTE PageTable;
  1082. //
  1083. // Cleanup the KSEG0_BASE and ALTERNATE_BASE regions. The MM PFN database
  1084. // is an array of entries which track each page of main memory. Large
  1085. // enough memory holes will cause this array to be sparse. MM requires
  1086. // enabled PTEs to have entries in the PFN database. So locate any memory
  1087. // hole and remove their PTEs.
  1088. //
  1089. for (i = 0; i < NumberDescriptors; i += 1) {
  1090. if (MDArray[i].MemoryType == MemorySpecialMemory ||
  1091. MDArray[i].MemoryType == MemoryFirmwarePermanent) {
  1092. //
  1093. // The KSEG0_BASE and ALTERNATE_BASE regions only map up to 16MB,
  1094. // so clip the high end at that address.
  1095. //
  1096. Page = MDArray[i].BasePage;
  1097. EndPage = Page + MDArray[i].PageCount;
  1098. if (EndPage > _16MB) {
  1099. EndPage = _16MB;
  1100. }
  1101. //
  1102. // Some PTEs below 1M may need to stay mapped since they may have
  1103. // been put into ABIOS selectors. Instead of determining which PTEs
  1104. // they may be, we will leave PTEs below 1M alone. This doesn't
  1105. // cause the PFN any problems since we know there is some memory
  1106. // below then 680K mark and some more memory at the 1M mark. Thus
  1107. // there is not a large enough "memory hole" to cause the PFN database
  1108. // to be sparse below 1M.
  1109. //
  1110. // Clip starting address to 1MB
  1111. //
  1112. if (Page < _1MB) {
  1113. Page = _1MB;
  1114. }
  1115. //
  1116. // For each page in this range make sure it is invalid in the
  1117. // KSEG0_BASE and ALTERNATE_BASE regions.
  1118. //
  1119. // N.B. Since there is only one page table page for both the
  1120. // KSEG0_BASE and ALTERNATE_BASE regions the page only
  1121. // needs to marked invalid once.
  1122. //
  1123. while (Page < EndPage) {
  1124. Entry = (Page >> 10) + (KSEG0_BASE >> 22);
  1125. if (PDE[Entry].Valid == 1) {
  1126. PageTable = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << PAGE_SHIFT);
  1127. Offset = Page & 0x3ff;
  1128. PageTable[Offset].Valid = 0;
  1129. PageTable[Offset].Write = 0;
  1130. PageTable[Offset].PageFrameNumber = 0;
  1131. }
  1132. Page += 1;
  1133. }
  1134. }
  1135. }
  1136. }
  1137. PVOID
  1138. FwAllocateHeapPermanent(
  1139. IN ULONG NumberPages
  1140. )
  1141. /*++
  1142. Routine Description:
  1143. This allocates pages from the private heap. The memory descriptor for
  1144. the LoaderMemoryData area is grown to include the returned pages, while
  1145. the memory descriptor for the temporary heap is shrunk by the same amount.
  1146. N.B. DO NOT call this routine after we have passed control to
  1147. BlOsLoader! Once BlOsLoader calls BlMemoryInitialize, the
  1148. firmware memory descriptors are sucked into the OS Loader heap
  1149. and those are the descriptors passed to the kernel. So any
  1150. changes in the firmware private heap will be irrelevant.
  1151. If you need to allocate permanent memory after the OS Loader
  1152. has initialized, use BlAllocateDescriptor.
  1153. Arguments:
  1154. NumberPages - size of memory to allocate (in pages)
  1155. Return Value:
  1156. Pointer to block of memory, if successful.
  1157. NULL, if unsuccessful.
  1158. --*/
  1159. {
  1160. PVOID MemoryPointer;
  1161. PMEMORY_DESCRIPTOR Descriptor;
  1162. if (FwPermanentHeap + (NumberPages << PAGE_SHIFT) > FwTemporaryHeap) {
  1163. //
  1164. // Our heaps collide, so we are out of memory
  1165. //
  1166. BlPrint("Out of permanent heap!\n");
  1167. while (1) {
  1168. }
  1169. return(NULL);
  1170. }
  1171. //
  1172. // Find the memory descriptor which describes the LoaderMemoryData area,
  1173. // so we can grow it to include the just-allocated pages.
  1174. //
  1175. Descriptor = MDArray;
  1176. while (Descriptor->MemoryType != LoaderMemoryData) {
  1177. ++Descriptor;
  1178. if (Descriptor > MDArray+MAX_DESCRIPTORS) {
  1179. BlPrint("ERROR - FwAllocateHeapPermanent couldn't find the\n");
  1180. BlPrint(" LoaderMemoryData descriptor!\n");
  1181. while (1) {
  1182. }
  1183. return(NULL);
  1184. }
  1185. }
  1186. Descriptor->PageCount += NumberPages;
  1187. //
  1188. // We know that the memory descriptor after this one is the firmware
  1189. // temporary heap descriptor. Since it is physically contiguous with our
  1190. // LoaderMemoryData block, we remove the pages from its descriptor.
  1191. //
  1192. ++Descriptor;
  1193. Descriptor->PageCount -= NumberPages;
  1194. Descriptor->BasePage += NumberPages;
  1195. MemoryPointer = (PVOID)FwPermanentHeap;
  1196. FwPermanentHeap += NumberPages << PAGE_SHIFT;
  1197. return(MemoryPointer);
  1198. }
  1199. PVOID
  1200. FwAllocateHeap(
  1201. IN ULONG Size
  1202. )
  1203. /*++
  1204. Routine Description:
  1205. Allocates memory from the "firmware" temporary heap.
  1206. Arguments:
  1207. Size - Supplies size of block to allocate
  1208. Return Value:
  1209. PVOID - Pointer to the beginning of the block
  1210. NULL - Out of memory
  1211. --*/
  1212. {
  1213. ULONG i;
  1214. ULONG SizeInPages;
  1215. ULONG StartPage;
  1216. ARC_STATUS Status;
  1217. if (((FwTemporaryHeap - FwPermanentHeap) < Size) && (FwDescriptorsValid)) {
  1218. //
  1219. // Large allocations get their own descriptor so miniports that
  1220. // have huge device extensions don't suck up all of the heap.
  1221. //
  1222. // Note that we can only do this while running in "firmware" mode.
  1223. // Once we call into the osloader, it sucks all the memory descriptors
  1224. // out of the "firmware" and changes to this list will not show
  1225. // up there.
  1226. //
  1227. // We are looking for a descriptor that is MemoryFree and <16Mb.
  1228. //
  1229. // [ChuckL 13-Dec-2001]
  1230. // This routine has always been called after the loader's memory list
  1231. // was initialized, which meant that it was stomping on memory that
  1232. // might have been allocated by the loader. This was not a problem
  1233. // because the loader initialized its memory list twice(!), so it
  1234. // looked at the MDArray again to get an updated picture of the
  1235. // memory allocation situation. This didn't really work, and there
  1236. // used to be extra code here to handle the situation by calling
  1237. // BlFindDescriptor/BlGeneratorDescriptor to tell the loader about
  1238. // the low-level allocation. But even that didn't really work. And
  1239. // now, because of the elimination of the second call to
  1240. // BlMemoryInitialize(), the brokenness of the old code has been
  1241. // exposed. What happened is that this routine would use the MDArray
  1242. // to decide where to allocate memory, then it would tell the loader
  1243. // about it. But using MDArray to find free memory was bogus,
  1244. // because the loader had already used its own copy of the list to
  1245. // make its own allocations. So the same memory was allocated twice.
  1246. // The fix implemented here is to use BlAllocateAlignedDescriptor if
  1247. // the loader has been initialized, skipping the MDArray entirely.
  1248. //
  1249. SizeInPages = (Size+PAGE_SIZE-1) >> PAGE_SHIFT;
  1250. if (BlLoaderBlock != NULL) {
  1251. Status = BlAllocateAlignedDescriptor(
  1252. LoaderFirmwareTemporary,
  1253. 0,
  1254. SizeInPages,
  1255. 1,
  1256. &StartPage
  1257. );
  1258. if (Status == ESUCCESS) {
  1259. return((PVOID)(StartPage << PAGE_SHIFT));
  1260. }
  1261. } else {
  1262. for (i=0; i<NumberDescriptors; i++) {
  1263. if ((MDArray[i].MemoryType == MemoryFree) &&
  1264. (MDArray[i].BasePage <= _16MB_BOGUS) &&
  1265. (MDArray[i].PageCount >= SizeInPages)) {
  1266. break;
  1267. }
  1268. }
  1269. if (i < NumberDescriptors) {
  1270. StartPage = MDArray[i].BasePage+MDArray[i].PageCount-SizeInPages;
  1271. Status = MempAllocDescriptor(StartPage,
  1272. StartPage+SizeInPages,
  1273. MemoryFirmwareTemporary);
  1274. if (Status==ESUCCESS) {
  1275. return((PVOID)(StartPage << PAGE_SHIFT));
  1276. }
  1277. }
  1278. }
  1279. }
  1280. FwTemporaryHeap -= Size;
  1281. //
  1282. // Round down to 16-byte boundary
  1283. //
  1284. FwTemporaryHeap &= ~((ULONG)0xf);
  1285. if (FwTemporaryHeap < FwPermanentHeap) {
  1286. #if DBG
  1287. BlPrint("Out of temporary heap!\n");
  1288. #endif
  1289. return(NULL);
  1290. }
  1291. return((PVOID)FwTemporaryHeap);
  1292. }
  1293. PVOID
  1294. FwAllocatePool(
  1295. IN ULONG Size
  1296. )
  1297. /*++
  1298. Routine Description:
  1299. This routine allocates memory from the firmware pool. Note that
  1300. this memory is NOT under the 1MB line, so it cannot be used for
  1301. anything that must be accessed from real mode. It is currently used
  1302. only by the SCSI miniport drivers and dbcs font loader.
  1303. Arguments:
  1304. Size - Supplies size of block to allocate.
  1305. Return Value:
  1306. PVOID - pointer to the beginning of the block
  1307. NULL - out of memory
  1308. --*/
  1309. {
  1310. PVOID Buffer;
  1311. ULONG NewSize;
  1312. //
  1313. // round size up to 16 byte boundary
  1314. //
  1315. NewSize = (Size + 15) & ~0xf;
  1316. if ((FwPoolStart + NewSize) <= FwPoolEnd) {
  1317. Buffer = (PVOID)FwPoolStart;
  1318. FwPoolStart += NewSize;
  1319. return(Buffer);
  1320. } else {
  1321. //
  1322. // we've used up all our pool, try to allocate from the heap.
  1323. //
  1324. return(FwAllocateHeap(Size));
  1325. }
  1326. }
  1327. PVOID
  1328. FwAllocateHeapAligned(
  1329. IN ULONG Size
  1330. )
  1331. /*++
  1332. Routine Description:
  1333. Allocates memory from the "firmware" temporary heap. This memory is
  1334. always allocated on a page boundary, so it can readily be used for
  1335. temporary page tables
  1336. Arguments:
  1337. Size - Supplies size of block to allocate
  1338. Return Value:
  1339. PVOID - Pointer to the beginning of the block
  1340. NULL - Out of memory
  1341. --*/
  1342. {
  1343. FwTemporaryHeap -= Size;
  1344. //
  1345. // Round down to a page boundary
  1346. //
  1347. FwTemporaryHeap &= ~(PAGE_SIZE-1);
  1348. if (FwTemporaryHeap < FwPermanentHeap) {
  1349. BlPrint("Out of temporary heap!\n");
  1350. return(NULL);
  1351. }
  1352. RtlZeroMemory((PVOID)FwTemporaryHeap,Size);
  1353. return((PVOID)FwTemporaryHeap);
  1354. }
  1355. PVOID
  1356. MmMapIoSpace (
  1357. IN PHYSICAL_ADDRESS PhysicalAddress,
  1358. IN ULONG NumberOfBytes,
  1359. IN MEMORY_CACHING_TYPE CacheType
  1360. )
  1361. /*++
  1362. Routine Description:
  1363. This function returns the corresponding virtual address for a
  1364. known physical address.
  1365. Arguments:
  1366. PhysicalAddress - Supplies the physical address.
  1367. NumberOfBytes - Unused.
  1368. CacheType - Unused.
  1369. Return Value:
  1370. Returns the corresponding virtual address.
  1371. Environment:
  1372. Kernel mode. Any IRQL level.
  1373. --*/
  1374. {
  1375. ULONG i;
  1376. ULONG j;
  1377. ULONG NumberPages;
  1378. NumberPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(PhysicalAddress.LowPart, NumberOfBytes);
  1379. //
  1380. // We use the HAL's PDE for mapping memory buffers.
  1381. // Find enough free PTEs.
  1382. //
  1383. //
  1384. // Check the value of NumberPages
  1385. //
  1386. #define X86_MAX_NUMBER_OF_PAGES 1024
  1387. //
  1388. // since NumberPages is ULONG any arithmetic with NumberPages will
  1389. // result in a ULONG (unless casted)
  1390. // therefore if NumberPages is greated than X86_MAX_NUMBER_OF_PAGES
  1391. // the results of X86_MAX_NUMBER_OF_PAGES-NUmberPages
  1392. // will not be negative (its a ULONG!) therfore the following loop would
  1393. // have returned some bogus pointer...
  1394. //
  1395. // The following 3 line check was added to avoid this problem
  1396. //
  1397. if (NumberPages > X86_MAX_NUMBER_OF_PAGES) {
  1398. return (NULL);
  1399. }
  1400. for (i=0; i <= X86_MAX_NUMBER_OF_PAGES - NumberPages; i++) {
  1401. for (j=0; j < NumberPages; j++) {
  1402. if ((((PULONG)HalPT))[i+j]) {
  1403. break;
  1404. }
  1405. }
  1406. if (j == NumberPages) {
  1407. for (j=0; j<NumberPages; j++) {
  1408. HalPT[i+j].PageFrameNumber =
  1409. (PhysicalAddress.LowPart >> PAGE_SHIFT)+j;
  1410. HalPT[i+j].Valid = 1;
  1411. HalPT[i+j].Write = 1;
  1412. HalPT[i+j].WriteThrough = 1;
  1413. if (CacheType == MmNonCached) {
  1414. HalPT[i+j].CacheDisable = 1;
  1415. }
  1416. }
  1417. return((PVOID)(0xffc00000 | (i<<12) | (PhysicalAddress.LowPart & 0xfff)));
  1418. }
  1419. //
  1420. // page 'i + j' is used. walk past it
  1421. //
  1422. i += j;
  1423. }
  1424. return(NULL);
  1425. }
  1426. VOID
  1427. MmUnmapIoSpace (
  1428. IN PVOID BaseAddress,
  1429. IN ULONG NumberOfBytes
  1430. )
  1431. /*++
  1432. Routine Description:
  1433. This function unmaps a range of physical address which were previously
  1434. mapped via an MmMapIoSpace function call.
  1435. Arguments:
  1436. BaseAddress - Supplies the base virtual address where the physical
  1437. address was previously mapped.
  1438. NumberOfBytes - Supplies the number of bytes which were mapped.
  1439. Return Value:
  1440. None.
  1441. Environment:
  1442. Kernel mode, IRQL of DISPATCH_LEVEL or below.
  1443. --*/
  1444. {
  1445. ULONG StartPage, PageCount;
  1446. PageCount = COMPUTE_PAGES_SPANNED(BaseAddress, NumberOfBytes);
  1447. StartPage = (((ULONG_PTR)BaseAddress & ~0xffc00000) >> PAGE_SHIFT);
  1448. if (BaseAddress > (PVOID)0xffc00000) {
  1449. RtlZeroMemory(&HalPT[StartPage], PageCount * sizeof(HARDWARE_PTE_X86));
  1450. }
  1451. _asm {
  1452. mov eax, cr3
  1453. mov cr3, eax
  1454. }
  1455. return;
  1456. }
  1457. VOID
  1458. BlpTruncateMemory (
  1459. IN ULONG MaxMemory
  1460. )
  1461. /*++
  1462. Routine Description:
  1463. Eliminates all the memory descriptors above a given boundary
  1464. Arguments:
  1465. MaxMemory - Supplies the maximum memory boundary in megabytes
  1466. Return Value:
  1467. None.
  1468. --*/
  1469. {
  1470. extern MEMORY_DESCRIPTOR MDArray[];
  1471. extern ULONG NumberDescriptors;
  1472. ULONG Current = 0;
  1473. ULONG MaxPage = MaxMemory * 256; // Convert Mb to pages
  1474. if (MaxMemory == 0) {
  1475. return;
  1476. }
  1477. while (Current < NumberDescriptors) {
  1478. if (MDArray[Current].BasePage >= MaxPage) {
  1479. //
  1480. // This memory descriptor lies entirely above the boundary,
  1481. // eliminate it.
  1482. //
  1483. RtlMoveMemory(MDArray+Current,
  1484. MDArray+Current+1,
  1485. sizeof(MEMORY_DESCRIPTOR)*
  1486. (NumberDescriptors-Current-1));
  1487. --NumberDescriptors;
  1488. } else if (MDArray[Current].BasePage + MDArray[Current].PageCount > MaxPage) {
  1489. //
  1490. // This memory descriptor crosses the boundary, truncate it.
  1491. //
  1492. MDArray[Current].PageCount = MaxPage - MDArray[Current].BasePage;
  1493. ++Current;
  1494. } else {
  1495. //
  1496. // This one's ok, keep it.
  1497. //
  1498. ++Current;
  1499. }
  1500. }
  1501. }
  1502. ARC_STATUS
  1503. MempCheckMapping(
  1504. ULONG StartPage,
  1505. ULONG NumberPages
  1506. )
  1507. /*++
  1508. Routine Description:
  1509. This routine makes sure all pages in the range are mapped and
  1510. tracks the highest page used.
  1511. X86 Only.
  1512. Arguments:
  1513. Page - Supplies the physical page number we are starting at.
  1514. Return Value:
  1515. None.
  1516. --*/
  1517. {
  1518. PUCHAR p;
  1519. ULONG EndPage;
  1520. ULONG Entry;
  1521. ULONG FrameNumber;
  1522. ULONG Page;
  1523. PHARDWARE_PTE PageTableP;
  1524. PHARDWARE_PTE PageTableV;
  1525. ULONG Offset;
  1526. //
  1527. // memory under 16MB is always mapped.
  1528. //
  1529. if (StartPage < _16MB) {
  1530. return(ESUCCESS);
  1531. }
  1532. //
  1533. // A PDE is 4MB (22 bits, so if we're in the same 4MB region, nothing to do)
  1534. //
  1535. EndPage = StartPage + NumberPages;
  1536. for (Page = StartPage; Page < EndPage; Page += 1) {
  1537. Entry = Page >> 10;
  1538. //
  1539. // If the PDE entry for this page address range is not allocated,
  1540. // then allocate and initialize the PDE entry to map the page table
  1541. // pages for the the memory range. Otherwise, compute the address
  1542. // of the page table pages.
  1543. //
  1544. if (PDE[Entry].Valid == 0) {
  1545. //
  1546. // Allocate and initialize two page table pages to map the specified
  1547. // page into physical memory.
  1548. //
  1549. p = BlAllocateHeapAligned(PAGE_SIZE*3);
  1550. if (p==NULL) {
  1551. return(ENOMEM);
  1552. }
  1553. PageTableP = (PHARDWARE_PTE)PAGE_ALIGN((ULONG)p+PAGE_SIZE-1);
  1554. RtlZeroMemory(PageTableP, PAGE_SIZE);
  1555. FrameNumber = ((ULONG)PageTableP & ~KSEG0_BASE) >> PAGE_SHIFT;
  1556. PDE[Entry].Valid = 1;
  1557. PDE[Entry].Write = 1;
  1558. PDE[Entry].PageFrameNumber = FrameNumber;
  1559. //
  1560. // initialize a page table page to map the specified
  1561. // page into KSEG0_BASE and ALTERNATE_BASE.
  1562. //
  1563. // N.B. Only one page table page is allocated since the contents
  1564. // for both mappings are the same.
  1565. //
  1566. PageTableV = (PHARDWARE_PTE)((PUCHAR)PageTableP + PAGE_SIZE);
  1567. RtlZeroMemory(PageTableV, PAGE_SIZE);
  1568. FrameNumber = ((ULONG)PageTableV & ~KSEG0_BASE) >> PAGE_SHIFT;
  1569. Offset = Entry + (KSEG0_BASE >> 22);
  1570. PDE[Offset].Valid = 1;
  1571. PDE[Offset].Write = 1;
  1572. PDE[Offset].PageFrameNumber = FrameNumber;
  1573. if (BlVirtualBias) {
  1574. Offset += (BlVirtualBias >> 22);
  1575. PDE[Offset].Valid = 1;
  1576. PDE[Offset].Write = 1;
  1577. PDE[Offset].PageFrameNumber = FrameNumber;
  1578. }
  1579. if (Entry > HighestPde) {
  1580. HighestPde = Entry;
  1581. }
  1582. } else {
  1583. Offset = Entry + (KSEG0_BASE >> 22);
  1584. PageTableP = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << PAGE_SHIFT);
  1585. PageTableV = (PHARDWARE_PTE)(PDE[Offset].PageFrameNumber << PAGE_SHIFT);
  1586. }
  1587. //
  1588. // If this is not the first page in memory, then mark it valid.
  1589. //
  1590. if (Page != 0) {
  1591. Offset = Page & 0x3ff;
  1592. PageTableP[Offset].Valid = 1;
  1593. PageTableP[Offset].Write = 1;
  1594. PageTableP[Offset].PageFrameNumber = Page;
  1595. PageTableV[Offset].Valid = 1;
  1596. PageTableV[Offset].Write = 1;
  1597. PageTableV[Offset].PageFrameNumber = Page;
  1598. }
  1599. }
  1600. _asm {
  1601. //
  1602. // Reload cr3 to force a flush
  1603. //
  1604. mov eax,cr3
  1605. mov cr3,eax
  1606. }
  1607. return ESUCCESS;
  1608. }
  1609. ARC_STATUS
  1610. MempFixMapping(
  1611. ULONG StartPage,
  1612. ULONG NumberPages
  1613. )
  1614. /*++
  1615. Routine Description:
  1616. This routine makes sure that the range for kernel/hal, which
  1617. are currently not relocatable, are mapped by "permanent" PTEs.
  1618. Normally they are allocated via OsLoaderHeap, and they could
  1619. become unmapped during system bootup.
  1620. X86 Only.
  1621. Arguments:
  1622. StartPage - Supplies the physical page number we are starting at.
  1623. NumberPages - total # of pages
  1624. Return Value:
  1625. None.
  1626. --*/
  1627. {
  1628. ULONG EndPage;
  1629. ULONG PTPage;
  1630. ULONG Entry;
  1631. ULONG FrameNumber;
  1632. ULONG Page;
  1633. PHARDWARE_PTE PhysPageTable;
  1634. PHARDWARE_PTE VirtPageTable;
  1635. PHARDWARE_PTE PageTableOri;
  1636. ULONG Offset;
  1637. ARC_STATUS Status;
  1638. //
  1639. // memory under 16MB is always mapped.
  1640. //
  1641. if (StartPage < _16MB) {
  1642. return(ESUCCESS);
  1643. }
  1644. //
  1645. // A PDE is 4MB (22 bits, so if we're in the same 4MB region, nothing to do)
  1646. //
  1647. EndPage = StartPage + NumberPages;
  1648. for (Page = StartPage; Page < EndPage; Page += 1024) {
  1649. Entry = Page >> 10;
  1650. if (PDE[Entry].Valid == 0) {
  1651. //
  1652. // this must have been previously mapped or MempCheckMapping has a
  1653. // bug in it.
  1654. //
  1655. return(EINVAL);
  1656. }
  1657. //
  1658. // allocate space for the new PTEs
  1659. //
  1660. Status = BlAllocateAlignedDescriptor(
  1661. LoaderMemoryData,
  1662. 0,
  1663. 2,
  1664. 1,
  1665. &PTPage );
  1666. if (Status != ESUCCESS) {
  1667. return(ENOMEM);
  1668. }
  1669. //
  1670. // copy the contents of the original PTE into the new PTE.
  1671. // then point the PDE at the new entry.
  1672. //
  1673. FrameNumber = PTPage;
  1674. PhysPageTable = (PHARDWARE_PTE) (KSEG0_BASE | (FrameNumber << PAGE_SHIFT));
  1675. PageTableOri = (PHARDWARE_PTE) ((PDE[Entry].PageFrameNumber << PAGE_SHIFT) | KSEG0_BASE);
  1676. RtlCopyMemory(PhysPageTable, PageTableOri, PAGE_SIZE);
  1677. PDE[Entry].Valid = 1;
  1678. PDE[Entry].Write = 1;
  1679. PDE[Entry].PageFrameNumber = FrameNumber;
  1680. //
  1681. // now repeat this exercise of copying original PTE into the new PTE
  1682. // for the virtual mappings of the PTE.
  1683. //
  1684. // N.B. Only one page table page is allocated since the contents
  1685. // for both mappings are the same.
  1686. //
  1687. FrameNumber = PTPage+1;
  1688. VirtPageTable = (PHARDWARE_PTE) (KSEG0_BASE | ((FrameNumber) << PAGE_SHIFT));
  1689. Offset = Entry + (KSEG0_BASE >> 22);
  1690. PageTableOri = (PHARDWARE_PTE)((PDE[Offset].PageFrameNumber << PAGE_SHIFT) | KSEG0_BASE);
  1691. RtlCopyMemory(VirtPageTable, PageTableOri, PAGE_SIZE);
  1692. PDE[Offset].Valid = 1;
  1693. PDE[Offset].Write = 1;
  1694. PDE[Offset].PageFrameNumber = FrameNumber;
  1695. if (BlVirtualBias) {
  1696. Offset += (BlVirtualBias >> 22);
  1697. PDE[Offset].Valid = 1;
  1698. PDE[Offset].Write = 1;
  1699. PDE[Offset].PageFrameNumber = FrameNumber;
  1700. }
  1701. }
  1702. _asm {
  1703. //
  1704. // Reload cr3 to force a flush
  1705. //
  1706. mov eax,cr3
  1707. mov cr3,eax
  1708. }
  1709. return ESUCCESS;
  1710. }
  1711. ARC_STATUS
  1712. MempSetPageZeroOverride(
  1713. BOOLEAN Enable
  1714. )
  1715. /*++
  1716. Routine Description:
  1717. This routine maps or unmaps page 0.
  1718. X86 Only.
  1719. Arguments:
  1720. Enable - specifies whether to enable or disable the mapping for this page.
  1721. Return Value:
  1722. None.
  1723. --*/
  1724. {
  1725. ULONG Entry;
  1726. PHARDWARE_PTE PageTableP;
  1727. PHARDWARE_PTE PageTableV;
  1728. ULONG Offset;
  1729. const ULONG StartPage = 0;
  1730. Entry = StartPage >> 10;
  1731. //
  1732. // compute the address of the page table pages.
  1733. //
  1734. if (PDE[Entry].Valid == 0) {
  1735. //
  1736. // the pde for the pte should already be setup.
  1737. // if it's not then we're dead.
  1738. //
  1739. return(ENOMEM);
  1740. } else {
  1741. Offset = Entry + (KSEG0_BASE >> 22);
  1742. PageTableP = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << PAGE_SHIFT);
  1743. PageTableV = (PHARDWARE_PTE)(PDE[Offset].PageFrameNumber << PAGE_SHIFT);
  1744. }
  1745. Offset = StartPage & 0x3ff;
  1746. if (PageTableP[Offset].PageFrameNumber != StartPage &&
  1747. PageTableV[Offset].PageFrameNumber != StartPage) {
  1748. //
  1749. // the PTE isn't setup correctly. Bail out.
  1750. //
  1751. return(ENOMEM);
  1752. }
  1753. PageTableP[Offset].Valid = Enable ? 1 : 0;
  1754. PageTableV[Offset].Valid = Enable ? 1 : 0;
  1755. _asm {
  1756. //
  1757. // Reload cr3 to force a flush
  1758. //
  1759. mov eax,cr3
  1760. mov cr3,eax
  1761. }
  1762. return ESUCCESS;
  1763. }
  1764. //
  1765. // Convert remaing LoaderReserve (>16MB mem) to
  1766. // MemoryFirmwareTemporary for the mmgr
  1767. //
  1768. //
  1769. void
  1770. BlpRemapReserve (void)
  1771. {
  1772. PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
  1773. PLIST_ENTRY NextEntry;
  1774. NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  1775. while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
  1776. NextDescriptor = CONTAINING_RECORD(NextEntry,
  1777. MEMORY_ALLOCATION_DESCRIPTOR,
  1778. ListEntry);
  1779. if ((NextDescriptor->MemoryType == LoaderReserve)) {
  1780. NextDescriptor->MemoryType = MemoryFirmwareTemporary;
  1781. }
  1782. NextEntry = NextEntry->Flink;
  1783. }
  1784. }
  1785. ARC_STATUS
  1786. BlpMarkExtendedVideoRegionOffLimits(
  1787. VOID
  1788. )
  1789. /*++
  1790. Routine Description:
  1791. This routine marks the extended video memory region as permanant, so that
  1792. the OS doesn't try to map this memory.
  1793. The ntdetect.com module actually finds out the location of this region as
  1794. well as the region size. We read this from the memory location that
  1795. ntdetect put the data in.
  1796. Arguments:
  1797. None.
  1798. Return Value:
  1799. ARC_STATUS indicating outcome.
  1800. --*/
  1801. {
  1802. ULONG BaseOfExtendedVideoRegionInBytes;
  1803. ULONG SizeOfExtendedVideoRegionInBytes;
  1804. ARC_STATUS Status;
  1805. //
  1806. // ntdetect has placed the base page and size of video rom at physical
  1807. // address 0x740
  1808. //
  1809. //
  1810. // Before we go read this address, we have to explicitly map in page zero.
  1811. //
  1812. Status = MempSetPageZeroOverride(TRUE);
  1813. if (Status != ESUCCESS) {
  1814. return(Status);
  1815. }
  1816. //
  1817. // read the memory.
  1818. //
  1819. BaseOfExtendedVideoRegionInBytes = *(PULONG)0x740;
  1820. SizeOfExtendedVideoRegionInBytes = *(PULONG)0x744;
  1821. //
  1822. // Ok, we're done with this page. unmap it so no one can dereference null.
  1823. //
  1824. Status = MempSetPageZeroOverride(FALSE);
  1825. if (Status != ESUCCESS) {
  1826. return(Status);
  1827. }
  1828. if (BaseOfExtendedVideoRegionInBytes == 0 || SizeOfExtendedVideoRegionInBytes == 0) {
  1829. return(ESUCCESS);
  1830. }
  1831. if (BlLoaderBlock != NULL) {
  1832. PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
  1833. PKLDR_DATA_TABLE_ENTRY BiosDataTableEntry;
  1834. ULONG BasePage;
  1835. ULONG LastPage;
  1836. ULONG PageCount;
  1837. BasePage = BaseOfExtendedVideoRegionInBytes >> PAGE_SHIFT;
  1838. LastPage = (BaseOfExtendedVideoRegionInBytes + SizeOfExtendedVideoRegionInBytes - 1) >> PAGE_SHIFT;
  1839. PageCount = LastPage - BasePage + 1;
  1840. while ( PageCount != 0 ) {
  1841. ULONG thisCount;
  1842. MemoryDescriptor = BlFindMemoryDescriptor(BasePage);
  1843. if (MemoryDescriptor == NULL) {
  1844. break;
  1845. }
  1846. thisCount = PageCount;
  1847. //
  1848. // if we run off of this descriptor, truncate our region
  1849. // at the end of the descriptor.
  1850. //
  1851. if (BasePage + PageCount > MemoryDescriptor->BasePage + MemoryDescriptor->PageCount) {
  1852. thisCount = (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount) - BasePage;
  1853. }
  1854. BlGenerateDescriptor(MemoryDescriptor,
  1855. MemoryFirmwarePermanent,
  1856. BasePage,
  1857. thisCount);
  1858. BasePage += thisCount;
  1859. PageCount -= thisCount;
  1860. }
  1861. //
  1862. // Allocate the memory in the firmware module list as well
  1863. //
  1864. Status = BlAllocateFirmwareTableEntry(
  1865. "VidBios",
  1866. "\\System\\Firmware\\VidBios",
  1867. (PVOID) BaseOfExtendedVideoRegionInBytes,
  1868. SizeOfExtendedVideoRegionInBytes,
  1869. &BiosDataTableEntry
  1870. );
  1871. if (Status != ESUCCESS) {
  1872. BlPrint("BlpMarkExtendedVideoRegionOffLimits: Failed Adding Firmware\n");
  1873. }
  1874. }
  1875. return(Status);
  1876. }