;------------------------------------------------------------------------------\r
CpuFlushTlb PROC\r
mov eax, cr3\r
- mov cr3, eax\r
+ mov cr3, eax ; moving to CR3 flushes TLB\r
ret\r
CpuFlushTlb ENDP\r
\r
; );\r
;------------------------------------------------------------------------------\r
InternalMathDivRemU64x32 PROC\r
- mov ecx, [esp + 12]\r
- mov eax, [esp + 8]\r
+ mov ecx, [esp + 12] ; ecx <- divisor\r
+ mov eax, [esp + 8] ; eax <- dividend[32..63]\r
xor edx, edx\r
- div ecx\r
+ div ecx ; eax <- quotient[32..63], edx <- remainder\r
push eax\r
- mov eax, [esp + 8]\r
- div ecx\r
- mov ecx, [esp + 20]\r
+ mov eax, [esp + 8] ; eax <- dividend[0..31]\r
+ div ecx ; eax <- quotient[0..31]\r
+ mov ecx, [esp + 20] ; ecx <- Remainder\r
jecxz @F ; abandon remainder if Remainder == NULL\r
mov [ecx], edx\r
@@:\r
- pop edx\r
+ pop edx ; edx <- quotient[32..63]\r
ret\r
InternalMathDivRemU64x32 ENDP\r
\r
; );\r
;------------------------------------------------------------------------------\r
InternalMathDivRemU64x64 PROC\r
- mov ecx, [esp + 16]\r
+ mov ecx, [esp + 16] ; ecx <- divisor[32..63]\r
test ecx, ecx\r
jnz _@DivRemU64x64 ; call _@DivRemU64x64 if Divisor > 2^32\r
mov ecx, [esp + 20]\r
jecxz @F\r
- and dword ptr [ecx + 4], 0\r
- mov [esp + 16], ecx\r
+ and dword ptr [ecx + 4], 0 ; zero high dword of remainder\r
+ mov [esp + 16], ecx ; set up stack frame to match DivRemU64x32\r
@@:\r
jmp InternalMathDivRemU64x32\r
InternalMathDivRemU64x64 ENDP\r
jnz @B\r
div ebx\r
mov ebx, eax ; ebx <- quotient\r
- mov ecx, [esp + 28]\r
- mul dword ptr [esp + 24]\r
- imul ecx, ebx\r
- add edx, ecx\r
- mov ecx, dword ptr [esp + 32]\r
+ mov ecx, [esp + 28] ; ecx <- high dword of divisor\r
+ mul dword ptr [esp + 24] ; edx:eax <- quotient * divisor[0..31]\r
+ imul ecx, ebx ; ecx <- quotient * divisor[32..63]\r
+ add edx, ecx ; edx <- (quotient * divisor)[32..63]\r
+ mov ecx, dword ptr [esp + 32] ; ecx <- addr for Remainder\r
jc @TooLarge ; product > 2^64\r
cmp edi, edx ; compare high 32 bits\r
ja @Correct\r
dec ebx ; adjust quotient by -1\r
jecxz @Return ; return if Remainder == NULL\r
sub eax, dword ptr [esp + 24]\r
- sbb edx, dword ptr [esp + 28]\r
+ sbb edx, dword ptr [esp + 28] ; edx:eax <- (quotient - 1) * divisor\r
@Correct:\r
jecxz @Return\r
sub esi, eax\r
mov [ecx + 4], edi\r
@Return:\r
mov eax, ebx ; eax <- quotient\r
- xor edx, edx\r
+ xor edx, edx ; quotient is 32 bits long\r
ret\r
_@DivRemU64x64 ENDP\r
\r
mov ecx, [esp + 8]\r
mov edx, [esp + 12]\r
pushfd\r
- pop edi\r
+ pop edi ; save flags in edi\r
cli\r
mov eax, cr0\r
bts eax, 31\r
mov esp, [esp + 16]\r
mov cr0, eax\r
push edi\r
- popfd\r
+ popfd ; restore flags\r
push edx\r
push ecx\r
call ebx\r
or ah, 1 ; set LME\r
wrmsr\r
mov eax, cr0\r
- bts eax, 31\r
+ bts eax, 31 ; set PG\r
mov cr0, eax ; enable paging\r
- retf\r
+ retf ; topmost 2 dwords hold the address\r
@@: ; long mode starts here\r
- DB 67h, 48h\r
+ DB 67h, 48h ; 32-bit address size, 64-bit operand size\r
mov ebx, [esp] ; mov rbx, [esp]\r
DB 67h, 48h\r
mov ecx, [esp + 8] ; mov rcx, [esp + 8]\r
DB 48h\r
add esp, -20h ; add rsp, -20h\r
call ebx ; call rbx\r
- jmp $\r
+ hlt ; no one should get here\r
InternalX86EnablePaging64 ENDP\r
\r
END\r
; );\r
;------------------------------------------------------------------------------\r
InternalX86FxRestore PROC\r
- mov eax, [esp + 4]\r
+ mov eax, [esp + 4] ; Buffer must be 16-byte aligned\r
fxrstor [eax]\r
ret\r
InternalX86FxRestore ENDP\r
; );\r
;------------------------------------------------------------------------------\r
InternalX86FxSave PROC\r
- mov eax, [esp + 4]\r
+ mov eax, [esp + 4] ; Buffer must be 16-byte aligned\r
fxsave [eax]\r
ret\r
InternalX86FxSave ENDP\r
mov edi, [edx + 8]\r
mov ebp, [edx + 12]\r
mov esp, [edx + 16]\r
- jmp dword ptr [edx + 20]\r
+ jmp dword ptr [edx + 20] ; restore "eip"\r
InternalLongJump ENDP\r
\r
END\r
; );\r
;------------------------------------------------------------------------------\r
InternalMathMultU64x64 PROC USES ebx\r
- mov ebx, [esp + 8]\r
- mov edx, [esp + 16]\r
+ mov ebx, [esp + 8] ; ebx <- M1[0..31]\r
+ mov edx, [esp + 16] ; edx <- M2[0..31]\r
mov ecx, ebx\r
mov eax, edx\r
- imul ebx, [esp + 20]\r
- imul edx, [esp + 12]\r
- add ebx, edx\r
- mul ecx\r
- add edx, ebx\r
+ imul ebx, [esp + 20] ; ebx <- M1[0..31] * M2[32..63]\r
+ imul edx, [esp + 12] ; edx <- M1[32..63] * M2[0..31]\r
+ add ebx, edx ; carries are abandoned\r
+ mul ecx ; edx:eax <- M1[0..31] * M2[0..31]\r
+ add edx, ebx ; carries are abandoned\r
ret\r
InternalMathMultU64x64 ENDP\r
\r
rol ebx, cl\r
shrd edx, ebx, cl\r
test cl, 32 ; Count >= 32?\r
- cmovnz ecx, eax\r
+ cmovnz ecx, eax ; switch eax & edx if Count >= 32\r
cmovnz eax, edx\r
cmovnz edx, ecx\r
ret\r
; );\r
;------------------------------------------------------------------------------\r
InternalMathRShiftU64 PROC\r
- mov cl, [esp + 12]\r
+ mov cl, [esp + 12] ; cl <- Count\r
xor edx, edx\r
mov eax, [esp + 8]\r
- test cl, 32\r
+ test cl, 32 ; Count >= 32?\r
cmovz edx, eax\r
cmovz eax, [esp + 4]\r
shrd eax, edx, cl\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadDr4 PROC\r
+ ;\r
+ ; DR4 is alias to DR6 only if DE (in CR4) is cleared. Otherwise, reading\r
+ ; this register will cause a #UD exception.\r
+ ;\r
+ ; MS assembler doesn't support this instruction since no one would use it\r
+ ; under normal circustances. Here opcode is used.\r
+ ;\r
DB 0fh, 21h, 0e0h\r
ret\r
AsmReadDr4 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadDr5 PROC\r
+ ;\r
+ ; DR5 is alias to DR7 only if DE (in CR4) is cleared. Otherwise, reading\r
+ ; this register will cause a #UD exception.\r
+ ;\r
+ ; MS assembler doesn't support this instruction since no one would use it\r
+ ; under normal circustances. Here opcode is used.\r
+ ;\r
DB 0fh, 21h, 0e8h\r
ret\r
AsmReadDr5 ENDP\r
;------------------------------------------------------------------------------\r
SetJump PROC\r
push [esp + 4]\r
- call InternalAssertJumpBuffer\r
- pop ecx\r
+ call InternalAssertJumpBuffer ; To validate JumpBuffer\r
pop ecx\r
+ pop ecx ; ecx <- return address\r
mov edx, [esp]\r
mov [edx], ebx\r
mov [edx + 4], esi\r
mov [edx + 8], edi\r
mov [edx + 12], ebp\r
mov [edx + 16], esp\r
- mov [edx + 20], ecx\r
+ mov [edx + 20], ecx ; eip value to restore in LongJump\r
xor eax, eax\r
jmp ecx\r
SetJump ENDP\r
; );\r
;------------------------------------------------------------------------------\r
InternalMathSwapBytes64 PROC\r
- mov eax, [esp + 8]\r
- mov edx, [esp + 4]\r
+ mov eax, [esp + 8] ; eax <- upper 32 bits\r
+ mov edx, [esp + 4] ; edx <- lower 32 bits\r
bswap eax\r
bswap edx\r
ret\r
; by user code. It will be shadowed to somewhere in memory below 1MB.\r
;------------------------------------------------------------------------------\r
_BackFromUserCode PROC\r
+ ;\r
+ ; The order of saved registers on the stack matches the order they appears\r
+ ; in IA32_REGS structure. This facilitates wrapper function to extract them\r
+ ; into that structure.\r
+ ;\r
push ss\r
push cs\r
DB 66h\r
mov eax, ss\r
DB 67h\r
lea bp, [esp + sizeof (IA32_REGS)]\r
+ ;\r
+ ; esi's in the following 2 instructions are indeed bp in 16-bit code. Fact\r
+ ; is "esi" in 32-bit addressing mode has the same encoding of "bp" in 16-\r
+ ; bit addressing mode.\r
+ ;\r
mov word ptr (IA32_REGS ptr [esi - sizeof (IA32_REGS)])._ESP, bp\r
mov ebx, (IA32_REGS ptr [esi - sizeof (IA32_REGS)])._EIP\r
shl ax, 4 ; shl eax, 4\r
pop fs\r
pop gs\r
popf ; popfd\r
- DB 66h\r
+ DB 66h ; Use 32-bit addressing for "retf" below\r
retf ; transfer control to user code\r
_ToUserCode ENDP\r
\r
; );\r
;------------------------------------------------------------------------------\r
InternalAsmThunk16 PROC USES ebp ebx esi edi ds es fs gs\r
- mov esi, [esp + 36] ; esi <- RegSet\r
+ mov esi, [esp + 36] ; esi <- RegSet, the 1st parameter\r
movzx edx, (IA32_REGS ptr [esi])._SS\r
mov edi, (IA32_REGS ptr [esi])._ESP\r
add edi, - (sizeof (IA32_REGS) + 4) ; reserve stack space\r
push 10h\r
pop ecx ; ecx <- selector for data segments\r
lgdt fword ptr [edx + (_16Gdtr - SavedCr0)]\r
- pushfd\r
+ pushfd ; Save df/if indeed\r
call fword ptr [edx + (_EntryPoint - SavedCr0)]\r
popfd\r
lidt fword ptr [esp + 36] ; restore protected mode IDTR\r
- lea eax, [ebp - sizeof (IA32_REGS)]\r
+ lea eax, [ebp - sizeof (IA32_REGS)] ; eax <- the address of IA32_REGS\r
ret\r
InternalAsmThunk16 ENDP\r
\r
;------------------------------------------------------------------------------\r
AsmWriteDr4 PROC\r
mov eax, [esp + 4]\r
+ ;\r
+ ; DR4 is alias to DR6 only if DE (in CR4) is cleared. Otherwise, writing to\r
+ ; this register will cause a #UD exception.\r
+ ;\r
+ ; MS assembler doesn't support this instruction since no one would use it\r
+ ; under normal circustances. Here opcode is used.\r
+ ;\r
DB 0fh, 23h, 0e0h\r
ret\r
AsmWriteDr4 ENDP\r
;------------------------------------------------------------------------------\r
AsmWriteDr5 PROC\r
mov eax, [esp + 4]\r
+ ;\r
+ ; DR5 is alias to DR7 only if DE (in CR4) is cleared. Otherwise, writing to\r
+ ; this register will cause a #UD exception.\r
+ ;\r
+ ; MS assembler doesn't support this instruction since no one would use it\r
+ ; under normal circustances. Here opcode is used.\r
+ ;\r
DB 0fh, 23h, 0e8h\r
ret\r
AsmWriteDr5 ENDP\r
;------------------------------------------------------------------------------\r
InternalX86DisablePaging64 PROC\r
cli\r
- shl rcx, 32\r
+ shl rcx, 32 ; rcx[32..47] <- Cs\r
lea eax, @F\r
- mov ecx, eax\r
- push rcx\r
- mov ebx, edx\r
mov esi, r8d\r
+ or rcx, rax ; rcx[0..47] <- Cs:@F\r
mov edi, r9d\r
- mov eax, [rsp + 28h]\r
- retf\r
+ mov eax, [rsp + 28h] ; eax <- New Stack\r
+ push rcx\r
+ retf ; switch to compatibility mode\r
@@:\r
mov esp, eax ; set up new stack\r
mov rax, cr0\r
mov rax, cr4\r
and al, NOT (1 SHL 5) ; clear PAE\r
mov cr4, rax\r
- push rdi\r
- push rsi\r
- call rbx\r
- jmp $\r
+ push rdi ; push Context2\r
+ push rsi ; push Context1\r
+ call rdx ; transfer control to EntryPoint\r
+ hlt ; no one should get here\r
InternalX86DisablePaging64 ENDP\r
\r
END\r
;------------------------------------------------------------------------------\r
InternalX86EnablePaging64 PROC\r
cli\r
- pop rax\r
+ pop rax ; skip the return address\r
call @Base\r
@Base:\r
add dword ptr [rsp], @F - @Base ; offset for far retf, seg is the 1st arg\r
mov rsp, [esp + 18h]\r
add rsp, -20h\r
call rbx\r
- jmp $ ; halt processor if EntryPoint() returned\r
+ hlt ; halt processor if EntryPoint() returned\r
InternalX86EnablePaging64 ENDP\r
\r
END\r
mov r13, [rcx + 30h]\r
mov r14, [rcx + 38h]\r
mov r15, [rcx + 40h]\r
- mov rax, rdx\r
+ mov rax, rdx ; set return value\r
jmp qword ptr [rcx + 48h]\r
InternalLongJump ENDP\r
\r
mov eax, ecx\r
mov ecx, edx\r
mov edx, r8d\r
- DB 0fh, 1, 0c8h\r
+ DB 0fh, 1, 0c8h ; monitor\r
ret\r
AsmMonitor ENDP\r
\r
AsmMwait PROC\r
mov eax, ecx\r
mov ecx, edx\r
- DB 0fh, 1, 0c9h\r
+ DB 0fh, 1, 0c9h ; mwait\r
ret\r
AsmMwait ENDP\r
\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadDr4 PROC\r
+ ;\r
+ ; There's no obvious reason to access this register, since it's aliased to\r
+ ; DR7 when DE=0 or an exception generated when DE=1\r
+ ;\r
DB 0fh, 21h, 0e0h\r
ret\r
AsmReadDr4 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadDr5 PROC\r
+ ;\r
+ ; There's no obvious reason to access this register, since it's aliased to\r
+ ; DR7 when DE=0 or an exception generated when DE=1\r
+ ;\r
DB 0fh, 21h, 0e8h\r
ret\r
AsmReadDr5 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadMm0 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 7eh, 0c0h\r
ret\r
AsmReadMm0 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadMm1 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 7eh, 0c8h\r
ret\r
AsmReadMm1 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadMm2 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 7eh, 0d0h\r
ret\r
AsmReadMm2 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadMm3 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 7eh, 0d8h\r
ret\r
AsmReadMm3 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadMm4 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 7eh, 0e0h\r
ret\r
AsmReadMm4 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadMm5 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 7eh, 0e8h\r
ret\r
AsmReadMm5 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadMm6 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 7eh, 0f0h\r
ret\r
AsmReadMm6 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmReadMm7 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 7eh, 0f8h\r
ret\r
AsmReadMm7 ENDP\r
; by user code. It will be shadowed to somewhere in memory below 1MB.\r
;------------------------------------------------------------------------------\r
_BackFromUserCode PROC\r
+ ;\r
+ ; The order of saved registers on the stack matches the order they appears\r
+ ; in IA32_REGS structure. This facilitates wrapper function to extract them\r
+ ; into that structure.\r
+ ;\r
+ ; Some instructions for manipulation of segment registers have to be written\r
+ ; in opcode since 64-bit MASM prevents accesses to those registers.\r
+ ;\r
DB 16h ; push ss\r
DB 0eh ; push cs\r
DB 66h\r
;\r
; rdi in the instruction below is indeed bx in 16-bit code\r
;\r
- DB 66h, 2eh\r
+ DB 66h, 2eh ; 2eh is "cs:" segment override\r
lgdt fword ptr [rdi + (SavedGdt - @Base)]\r
DB 66h\r
mov ecx, 0c0000080h\r
@64Eip DD ?\r
SavedCs DW ?\r
@64BitCode:\r
- DB 48h, 0b8h ; mov rax, imm64\r
-SavedRip DQ ?\r
- jmp rax ; return to caller\r
+ mov rsp, r8 ; restore stack\r
+ ret\r
_BackFromUserCode ENDP\r
\r
_EntryPoint DD _ToUserCode - m16Start\r
mov cr4, rbp\r
mov ss, esi ; set up 16-bit stack segment\r
mov sp, bx ; set up 16-bit stack pointer\r
- DB 66h\r
+ DB 66h ; make the following call 32-bit\r
call @Base ; push eip\r
@Base:\r
pop bp ; ebp <- address of @Base\r
push [esp + sizeof (IA32_REGS) + 2]\r
- lea eax, [rsi + (@RealMode - @Base)]\r
+ lea eax, [rsi + (@RealMode - @Base)] ; rsi is "bp" in 16-bit code\r
push rax\r
- retf\r
+ retf ; execution begins at next instruction\r
@RealMode:\r
DB 66h, 2eh ; CS and operand size override\r
lidt fword ptr [rsi + (_16Idtr - @Base)]\r
pop gs\r
popf ; popfd\r
lea sp, [esp + 4] ; skip high order 32 bits of EFlags\r
- DB 66h\r
+ DB 66h ; make the following retf 32-bit\r
retf ; transfer control to user code\r
_ToUserCode ENDP\r
\r
; );\r
;------------------------------------------------------------------------------\r
InternalAsmThunk16 PROC USES rbp rbx rsi rdi\r
- mov r10d, ds\r
- mov r11d, es\r
+ mov r10d, ds ; r9 ~ r11 are not accessible in 16-bit\r
+ mov r11d, es ; so use them for saving seg registers\r
mov r9d, ss\r
push fs\r
push gs\r
lea ecx, [rdx + (SavedCr4 - m16Start)]\r
mov eax, edx ; eax <- transition code address\r
and edx, 0fh\r
- shl eax, 12\r
- lea ax, [rdx + (_BackFromUserCode - m16Start)]\r
+ shl eax, 12 ; segment address in high order 16 bits\r
+ lea ax, [rdx + (_BackFromUserCode - m16Start)] ; offset address\r
stosd ; [edi] <- return address of user code\r
sgdt fword ptr [rcx + (SavedGdt - SavedCr4)]\r
sidt fword ptr [rsp + 38h] ; save IDT stack in argument space\r
pushfq\r
lea edx, [rdx + DATA16 - DATA32]\r
lea r8, @RetFromRealMode\r
- mov [rcx + (SavedRip - SavedCr4)], r8\r
+ push r8\r
mov r8d, cs\r
mov [rcx + (SavedCs - SavedCr4)], r8w\r
mov r8, rsp\r
jmp fword ptr [rcx + (_EntryPoint - SavedCr4)]\r
@RetFromRealMode:\r
- mov rsp, r8\r
popfq\r
lidt fword ptr [rsp + 38h] ; restore protected mode IDTR\r
lea eax, [rbp - sizeof (IA32_REGS)]\r
; );\r
;------------------------------------------------------------------------------\r
AsmWriteDr4 PROC\r
+ ;\r
+ ; There's no obvious reason to access this register, since it's aliased to\r
+ ; DR6 when DE=0 or an exception generated when DE=1\r
+ ;\r
DB 0fh, 23h, 0e1h\r
mov rax, rcx\r
ret\r
; );\r
;------------------------------------------------------------------------------\r
AsmWriteDr5 PROC\r
+ ;\r
+ ; There's no obvious reason to access this register, since it's aliased to\r
+ ; DR7 when DE=0 or an exception generated when DE=1\r
+ ;\r
DB 0fh, 23h, 0e9h\r
mov rax, rcx\r
ret\r
; );\r
;------------------------------------------------------------------------------\r
AsmWriteMm0 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 6eh, 0c1h\r
ret\r
AsmWriteMm0 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmWriteMm1 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 6eh, 0c9h\r
ret\r
AsmWriteMm1 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmWriteMm2 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 6eh, 0d1h\r
ret\r
AsmWriteMm2 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmWriteMm3 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 6eh, 0d9h\r
ret\r
AsmWriteMm3 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmWriteMm4 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 6eh, 0e1h\r
ret\r
AsmWriteMm4 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmWriteMm5 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 6eh, 0e9h\r
ret\r
AsmWriteMm5 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmWriteMm6 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 6eh, 0f1h\r
ret\r
AsmWriteMm6 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmWriteMm7 PROC\r
+ ;\r
+ ; 64-bit MASM doesn't support MMX instructions, so use opcode here\r
+ ;\r
DB 48h, 0fh, 6eh, 0f9h\r
ret\r
AsmWriteMm7 ENDP\r
; );\r
;------------------------------------------------------------------------------\r
AsmWriteMsr64 PROC\r
- mov rax, rdx\r
- shr rdx, 20h\r
+ mov rax, rdx ; meanwhile, rax <- return value\r
+ shr rdx, 20h ; edx:eax contains the value to write\r
wrmsr\r
ret\r
AsmWriteMsr64 ENDP\r