asm {
// ::/Doc/MemoryOverview.DD

USE32
SYS_INIT_PAGE_TABLES::
//Check 1Gig page capability and set page size.
                MOV         EAX, 0x80000001
                CPUID
                MOV         EAX, 1 << 21
                BT          EDX, 26
                JNC         @@05
                MOV         EAX, 1 << 30
@@05:           MOV         U32 [MEM_PAGE_SIZE], EAX

//Set mapped space limit
                MOV         EAX, [MEM_PHYSICAL_SPACE]
                MOV         EDX, [MEM_PHYSICAL_SPACE + 4]
                BT          U32 [MEM_PAGE_SIZE], 30 //Round-up to 1Gig boundary?
                JNC         @@10
                ADD         EAX, 0x3FFFFFFF
                ADC         EDX, 0
                AND         EAX, ~0x3FFFFFFF
@@10:           INC         EDX         //Need 4Gig extra for uncached alias up at top of space.
                MOV         [MEM_MAPPED_SPACE],     EAX
                MOV         [MEM_MAPPED_SPACE + 4], EDX

//How many 2Meg pages?
                MOV         CL,  21
                ADD         EAX, 0x1FFFFF
                ADC         EDX, 0
                SHRD        EAX, EDX
                SHR         EDX, CL
                MOV         [MEM_2MEG_NUM],     EAX
                MOV         [MEM_2MEG_NUM + 4], EDX

//How many 1Gig pages?
                MOV         CL,  9
                ADD         EAX, 0x1FF
                ADC         EDX, 0
                SHRD        EAX, EDX
                SHR         EDX, CL
                MOV         [MEM_1GIG_NUM],     EAX
                MOV         [MEM_1GIG_NUM + 4], EDX

//How many 512Gig pages?
                MOV         CL,  9
                ADD         EAX, 0x1FF
                ADC         EDX, 0
                SHRD        EAX, EDX
                SHR         EDX, CL
                MOV         [MEM_512GIG_NUM],     EAX
                MOV         [MEM_512GIG_NUM + 4], EDX

//Set CSysFixedArea to zero
                MOV         EDI, SYS_FIXED_AREA
                XOR         EAX, EAX
                MOV         ECX, sizeof(CSysFixedArea) / 4
                REP_STOSD

                MOV         U32 [MEM_PML2], EDI
//Check for 1Gig page capability.
                BT          U32 [MEM_PAGE_SIZE], 30
                JC          @@15
//Find PML2 Size
                MOV         EAX, U32 [MEM_2MEG_NUM]
                ADD         EAX, 0x1FF
                AND         EAX, ~0x1FF
                SHL         EAX, 3
                ADD         EDI, EAX

//Find PML3 Size
@@15:           MOV         U32 [MEM_PML3], EDI
                MOV         EAX, U32 [MEM_1GIG_NUM]
                ADD         EAX, 0x1FF
                AND         EAX, ~0x1FF
                SHL         EAX, 3
                ADD         EDI, EAX

//Find PML4 Size
                MOV         U32 [MEM_PML4], EDI
                MOV         EAX, U32 [MEM_512GIG_NUM]
                ADD         EAX, 0x1FF
                AND         EAX, ~0x1FF
                SHL         EAX, 3
                ADD         EAX, EDI

                MOV         U32 [MEM_HEAP_BASE], EAX

//Set page tables to zero
                MOV         EDI, U32 [MEM_PML2]
                SUB         EAX, EDI
                MOV         ECX, EAX
                SHR         ECX, 2
                XOR         EAX, EAX
                REP_STOSD

//Check for 1Gig page capability.
                BT          U32 [MEM_PAGE_SIZE], 30
                JC          @@30

//PML2: Use 2Meg Pages
                MOV         EAX, 0x87 //bit 7 is page size (2Meg)
                XOR         EDX, EDX
                MOV         EDI, [MEM_PML2]
                MOV         ECX, [MEM_2MEG_NUM]
@@20:           MOV         U32 [EDI], EAX
                ADD         EDI, 4
                MOV         U32 [EDI], EDX
                ADD         EDI, 4
                ADD         EAX, 0x200000
                ADC         EDX, 0
                LOOP        @@20
//PML3: Use 2Meg Pages
                MOV         EAX, [MEM_PML2]
                OR          EAX, 7
                XOR         EDX, EDX
                MOV         EDI, [MEM_PML3]
                MOV         ECX, [MEM_1GIG_NUM]
@@25:           MOV         U32 [EDI], EAX
                ADD         EDI, 4
                MOV         U32 [EDI], EDX
                ADD         EDI, 4
                ADD         EAX, 0x1000
                ADC         EDX, 0
                LOOP        @@25
                JMP         @@40

//PML3: Use 1Gig Pages
@@30:           MOV         EAX, 0x87 //bit 7 is page size (1Gig)
                XOR         EDX, EDX
                MOV         EDI, [MEM_PML3]
                MOV         ECX, [MEM_1GIG_NUM]
@@35:           MOV         U32 [EDI], EAX
                ADD         EDI, 4
                MOV         U32 [EDI], EDX
                ADD         EDI, 4
                ADD         EAX, 0x40000000
                ADC         EDX, 0
                LOOP        @@35

//PML4
@@40:           MOV         EAX, [MEM_PML3]
                OR          EAX, 7
                XOR         EDX, EDX
                MOV         EDI, [MEM_PML4]
                MOV         ECX, [MEM_512GIG_NUM]
@@45:           MOV         U32 [EDI], EAX
                ADD         EDI, 4
                MOV         U32 [EDI], EDX
                ADD         EDI, 4
                ADD         EAX, 0x1000
                ADC         EDX, 0
                LOOP        @@45
                RET

SYS_INIT_16MEG_SYS_CODE_BP::
// Init sys_code_bp to BIOS E801 lowest 16Meg val.
// BlkPoolsInit() adds the rest.
                MOV         U32 [SYS_CODE_BP],     SYS_FIXED_AREA + CSysFixedArea.sys_code_bp
                MOV         U32 [SYS_CODE_BP + 4], 0

                MOV         U32 [SYS_DATA_BP],     0
                MOV         U32 [SYS_DATA_BP + 4], 0

                XOR         EAX, EAX
                MOV         AX,  U16 [MEM_E801] //1 Kb blks between 1M and 16M
                SHL         EAX, 10
                ADD         EAX, 0x100000
                MOV         EDI, U32 [MEM_HEAP_BASE]
                SUB         EAX, EDI

//EDI=BASE EAX=SIZE
                TEST        U8 [SYS_MEM_INIT_FLAG], 1
                JZ          @@05
                PUSH        EAX
                PUSH        EDI
                MOV         ECX, EAX
                MOV         AL,  U8 [SYS_MEM_INIT_VAL]
                REP_STOSB
                POP         EDI
                POP         EAX

@@05:           SHR         EAX, MEM_PAG_BITS
                MOV         ESI, SYS_FIXED_AREA + CSysFixedArea.sys_code_bp
                MOV         EBX, U32 CBlkPool.mem_free_list[ESI]
                MOV         U32 CMemBlk.next     [EDI], EBX
                MOV         U32 CMemBlk.next + 4 [EDI], 0
                MOV         U32 CBlkPool.mem_free_list     [ESI], EDI
                MOV         U32 CBlkPool.mem_free_list + 4 [ESI], 0
                MOV         U32 CMemBlk.mb_signature[EDI], MBS_UNUSED_SIGNATURE_VAL
                MOV         U32 CMemBlk.pags[EDI], EAX
                SHL         EAX, MEM_PAG_BITS
                ADD         U32 CBlkPool.alloced_u8s[ESI], EAX

                BTS         U32 [SYS_RUN_LEVEL], RLf_16MEG_SYS_CODE_BP
                RET
}

I64 *MemPageTable(U8 *a)
{//Point to page table entry for addr.
    if (Bt(&mem_page_size, 30))
        return *MEM_PML3(U64 *) + a >> 30 * 8;
    else
        return *MEM_PML2(U64 *) + a >> 21 * 8;
}