; Simple test for ring-3 debugging of mtrr.inc.
; Contains some inputs taken from real-life MTRRs and expected outputs.
format PE console
;include 'win32a.inc'
macro $Revision [args]
{
}
include '../proc32.inc'
include '../struct.inc'
entry start

; one test has 8, another test has 10
; this is the maximal value for storing/copying, real value is in MTRRCAP
MAX_VARIABLE_MTRR = 10

start:
; Copy test inputs, run init_mtrr, compare with test outputs. Repeat.
        mov     esi, test1_in_data
        mov     edi, mtrrdata
        mov     ecx, mtrrdata_size / 4
        rep movsd
        call    init_mtrr
        mov     esi, test1_out_data
        mov     edi, mtrrdata
        mov     ecx, mtrrdata_size / 4
        repz cmpsd
        jnz     .fail
        mov     esi, test2_in_data
        mov     edi, mtrrdata
        mov     ecx, mtrrdata_size / 4
        rep movsd
        call    init_mtrr
        mov     esi, test2_out_data
        mov     edi, mtrrdata
        mov     ecx, mtrrdata_size / 4
        repz cmpsd
        jnz     .fail
        ret

.fail:
        int3
        jmp     $

; Helper procedure for _rdmsr/_wrmsr, replacements of rdmsr/wrmsr.
; Returns pointer to memory containing the given MSR.
; in: ecx = MSR
; out: esi -> MSR data
proc get_msr_ptr
        mov     esi, mtrrcap
        cmp     ecx, 0xFE
        jz      .ok
        mov     esi, mtrr_def_type
        cmp     ecx, 0x2FF
        jz      .ok
        lea     esi, [ecx-0x200]
        cmp     esi, MAX_VARIABLE_MTRR*2
        jae     .fail
        lea     esi, [mtrr+esi*8]
.ok:
        ret
.fail:
        int3
        ret
endp

; Emulates rdmsr.
proc _rdmsr
        push    esi
        call    get_msr_ptr
        mov     eax, [esi]
        mov     edx, [esi+4]
        pop     esi
        ret
endp

; Emulates wrmsr.
proc _wrmsr
        push    esi
        call    get_msr_ptr
        mov     [esi], eax
        mov     [esi+4], edx
        pop     esi
        ret
endp

; Macro to substitute rdmsr/wrmsr with emulating code.
macro rdmsr
{
        call    _rdmsr
}
macro wrmsr
{
        call    _wrmsr
}
; Our emulation of rdmsr/wrmsr has nothing to do with real cache
; and system-wide settings,
; remove all attempts to wbinvd and disable/enable cache in cr0.
macro wbinvd
{
}
macro mov a,b
{
if ~(a eq cr0) & ~(b eq cr0)
        mov     a, b
end if
}
macro movi r,i
{
        push    i
        pop     r
}

include '../kglobals.inc'
CAPS_MTRR equ 12
MEM_WB     equ 6               ;write-back memory
MEM_WC     equ 1               ;write combined memory
MEM_UC     equ 0               ;uncached memory
include 'mtrr.inc'

BOOT_VARS = 0
BOOT_MTRR       db      1
align 4
cpu_caps        dd      1 shl CAPS_MTRR
LFBAddress      dd      0xE0000000
LFBSize         dd      0x10000000
MEM_AMOUNT      dd      0       ; not used, needed for compilation

align 4
; Test 1: input
test1_in_data:
test1_phys_addr_width   db      36
                        rb      3
test1_in_mtrrcap        dq      0xD08
test1_in_mtrr_def_type dq 0xC00
test1_in_mtrrs:
                dq      0x000000006, 0xF00000800
                dq      0x100000006, 0xFC0000800
                dq      0x0BC000000, 0xFFC000800
                dq      0x0C0000000, 0xFC0000800
                dq      0x138000000, 0xFF8000800
                dq      0, 0
                dq      0, 0
                dq      0, 0
                dq      -1, -1  ; not used
                dq      -1, -1  ; not used
; Test 1: output
test1_out_data:
                dd      36      ; phys_addr_width, readonly
                dq      0xD08   ; MTRRCAP, readonly
                dq      0xC00   ; MTRR_DEF_TYPE, should be the same
                dq      0x000000006, 0xF80000800
                dq      0x080000006, 0xFC0000800
                dq      0x0BC000000, 0xFFC000800
                dq      0x100000006, 0xFC0000800
                dq      0x138000000, 0xFF8000800
                dq      0x0E0000001, 0xFFF000800        ; added for [LFBAddress]
                dq      0, 0
                dq      0, 0
                dq      -1, -1  ; not used
                dq      -1, -1  ; not used

; Test 2: input
test2_in_data:
test2_phys_addr_width   db      39
                        rb      3
test2_in_mtrrcap        dq      0xD0A
test2_in_mtrr_def_type  dq      0xC00
test2_in_mtrrs:
                dq      0x0000000006, 0x7F00000800
                dq      0x0100000006, 0x7FE0000800
                dq      0x00E0000000, 0x7FE0000800
                dq      0x00DC000000, 0x7FFC000800
                dq      0x00DBC00000, 0x7FFFC00800
                dq      0x011F800000, 0x7FFF800800
                dq      0x011F400000, 0x7FFFC00800
                dq      0x011F200000, 0x7FFFE00800
                dq      0, 0
                dq      0, 0

; Test 2: output
test2_out_data:
                dd      39      ; phys_addr_width, readonly
                dq      0xD0A   ; MTRRCAP, readonly
                dq      0xC00   ; MTRR_DEF_TYPE, should be the same
                dq      0x0000000006, 0x7F80000800
                dq      0x0080000006, 0x7FC0000800
                dq      0x00C0000006, 0x7FE0000800
                dq      0x00DC000000, 0x7FFC000800
                dq      0x00DBC00000, 0x7FFFC00800
                dq      0x0100000006, 0x7FE0000800
                dq      0x011F800000, 0x7FFF800800
                dq      0x011F400000, 0x7FFFC00800
                dq      0x011F200000, 0x7FFFE00800
                dq      0x00E0000001, 0x7FFF000800      ; added for [LFBAddress]
IncludeIGlobals
align 4
mtrrdata:
cpu_phys_addr_width     db      ?
                rb      3
mtrrcap         dq      ?
mtrr_def_type   dq      ?
mtrr            rq      MAX_VARIABLE_MTRR*2
mtrrdata_size = $ - mtrrdata
IncludeUGlobals