asm {
// ::/Doc/MemOverview.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_lst[ESI]
        MOV     U32 CMemBlk.next[EDI],EBX
        MOV     U32 CMemBlk.next+4[EDI],0
        MOV     U32 CBlkPool.mem_free_lst[ESI],EDI
        MOV     U32 CBlkPool.mem_free_lst+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;
}