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;
}