|
|
title "Operand Decoding" ;++ ; ;Copyright (c) 1991 Microsoft Corporation ; ;Module Name: ; ; vdmoprnd.asm ; ;Abstract: ; ; This module contains support for decoding 386/486 instruction operands. ; This is used by the opcode 0f emulation. ; ; ;Author: ; ; Dave Hastings (daveh) 20-Feb-1992 ; ;Notes: ; ; The only instruction which uses the operand decodeing (3/10/92) is ; LMSW. This instruction only has 16 bit operands, so only the 16 bit ; operand decode has been tested. The 32 bit decode will be tested ; (or removed?) during clean up, after code freeze. ; ;Revision History: ; ;-- .386p
.xlist include ks386.inc include callconv.inc ; calling convention macros include mi386.inc include vdm.inc include vdmtib.inc
page ,132
_PAGE SEGMENT DWORD PUBLIC 'CODE' ASSUME DS:NOTHING, ES:NOTHING, SS:NOTHING, FS:NOTHING, GS:NOTHING
EXTRNP _Ki386GetSelectorParameters,4 extrn CheckEip:proc
_PAGE ENDS
PAGEDATA SEGMENT DWORD PUBLIC 'DATA' ; ; This table is used to dispatch base on the mod code for 16 bit address size. ; When these locations are dispatched to, ; edi = linear address of next byte of instruction ; esi = pointer to register info ; ecx = R/M value for the instruction modtab16 dd offset FLAT:do20 ; no displacement dd offset FLAT:do40 ; 8 bit displacement dd offset FLAT:do50 ; 16 bit displacement dd offset FLAT:do60 ; Register operand
; ; This table is used to dispatch based on the RM code for 16 bit address size. ; When these locations are dispatched to, ; edi = pointer to trap frame ; esi = pointer to register info ; ebx = partial linear address of operand rmtab16 dd offset FLAT:do70 ; [bx + si] dd offset FLAT:do80 ; [bx + di] dd offset FLAT:do90 ; [bp + si] dd offset FLAT:do100 ; [bp + di] dd offset FLAT:do95 ; [si] dd offset FLAT:do85 ; [di] dd offset FLAT:do105 ; [bp] dd offset FLAT:do75 ; [bx]
; ; This table is used to dispatch base on the mod code for 32 bit address size. ; When these locations are dispatched to, ; edi = linear address of next byte of instruction ; esi = pointer to register info ; ecx = R/M value for the instruction modtab32 dd offset FLAT:do220 ; no displacement dd offset FLAT:do240 ; 8 bit displacement dd offset FLAT:do250 ; 32 bit displacement dd offset FLAT:do260 ; Register operand
; ; This table is used to pick up register offsets in the trap frame. ; N.B. This table cannot be used to find byte registers!! ; public RegTab RegTab dd TsEax dd TsEcx dd TsEdx dd TsEbx dd TsHardwareEsp dd TsEbp dd TsEsi dd TsEdi
PAGEDATA ENDS
_PAGE SEGMENT DWORD PUBLIC 'CODE' ASSUME DS:FLAT, ES:NOTHING, SS:FLAT, FS:NOTHING, GS:NOTHING
page ,132 subttl "Decode Operands" ;++ ; ; Routine Description: ; ; This routine decodes the operands for 386/486 instructions. It returns ; the linear address of the operand. For register operands, this is ; an address in the stack frame. The read/write flag is used for ; operand verification. ; ; Arguments: ; ; esi = address of reg info ; eax = 1 -- Read of operand ; 0 -- Write of operand ; ; Returns: ; ; eax = True -- operand ok, and reg info operand field filled in ; eax = False -- operand not ok. ; reg info eip updated ; ; Notes: ; ; This routine DOES NOT decode the reg field of the mod r/m byte of the ; opcode. This is not a problem because it will only return one operand ; address anyway. It does not decode byte registers correctly!!. ; ; check grow down ss handling
public VdmDecodeOperand VdmDecodeOperand proc
SegBase equ [ebp] - 04h SegLimit equ [ebp] - 08h SegFlags equ [ebp] - 0ch SelLookupResult equ [ebp] - 010h ReadWrite equ [ebp] - 014h ModRm equ [ebp] - 018h SIB equ [ebp] - 01ch
push ebp mov ebp,esp sub esp,01ch push edi push ecx push ebx
mov ReadWrite,eax
; ; Get the info on DS (assumed default selector) ; lea edx,SegLimit push edx lea edx,SegBase push edx lea edx,SegFlags push edx mov edi,[esi].RiTrapFrame push [edi].TsSegDs call VdmSegParams add esp,010h mov SelLookupResult,eax ; check result after override check
mov edi,[esi].RiEip add edi,[esi].RiCsBase call CheckEip test al,0fh jz do200 ; Gp fault, report error
movzx edx,byte ptr [edi] ; get mod r/m byte inc [esi].RiEip inc edi mov ecx,edx mov ModRm,edx and edx,MI_MODMASK shr edx,MI_MODSHIFT ; form jump table index from mod and ecx,MI_RMMASK ; form index for RM jump table test [esi].RiPrefixFlags,PREFIX_ADDR32 ; 32 bit segments. jnz do210 ; 32 bit instructions have diff form
jmp modtab16[edx * 4]
do20: ; ; These forms have no displacement, except for the "bp" form, which ; is just a 16 bit immediate displacement ; mov ebx,0 ; assume no displacement cmp ecx,MI_RMBP jne do30 ; dispatch through jmp table
call CheckEip test al,0fh jz do200 ; Gp fault, report error
movzx ebx,word ptr [edi] ; get displacement inc [esi].RiEip ; update eip inc [esi].RiEip jmp do120 ; go add in seg
do30: mov edi,[esi].RiTrapFrame jmp rmtab16[ecx * 4] ; go get register info.
do40: ; ; These forms have an 8 bit displacement ; call CheckEip test al,0fh jz do200 ; Gp fault, report error
movsx ebx,byte ptr [edi] inc [esi].RiEip mov edi,[esi].RiTrapFrame jmp rmtab16[ecx * 4]
do50: ; ; These forms have an 16 bit displacement ; call CheckEip test al,0fh jz do200 ; Gp fault, report error
movzx ebx,word ptr [edi] inc [esi].RiEip inc [esi].RiEip mov edi,[esi].RiTrapFrame jmp rmtab16[ecx * 4]
do60: ; ; These forms are register operands ; mov ebx,RegTab[ecx * 4] ; get offset into stackframe add ebx,[esi].RiTrapFrame ; form linear address jmp do194 ; return success
do70: ; ; This is the [bx + si] operand ; movzx edx,word ptr [edi].TsEsi add ebx,edx
do75: ; ; This is the [bx] operand, and a fall through to finish forming [bx + si] ; movzx edx,word ptr [edi].TsEbx add ebx,edx jmp do120 ; go add seg info
do80: ; ; This is the [bx + di] operand ; movzx edx,word ptr [edi].TsEbx add ebx,edx
do85: ; ; This is the [di] operand, and the fall through to finish [bx + di] ; movzx edx,word ptr [edi].TsEdi add ebx,edx jmp do120 ; go add seg info
do90: ; ; This is the [bp + si] operand ; movzx edx,word ptr [edi].TsEbp add ebx,edx ; ; Change default segment to be ss ; lea edx,SegLimit push edx lea edx,SegBase push edx lea edx,SegFlags push edx mov edi,[esi].RiTrapFrame push [edi].TsHardwareSegSs call VdmSegParams add esp,010h mov SelLookupResult,eax
do95: ; ; This is the [si] operand, and the fall through for forming [bp + si] ; movzx edx,word ptr [edi].TsEsi add ebx,edx jmp do120 ; go add seg info
do100: ; ; This is the [bp + di] operand ; movzx edx,word ptr [edi].TsEdi add ebx,edx
do105: ; ; This is the [bp] operand, and the fall through for forming [bp + di] ; movzx edx,word ptr [edi].TsEbp add ebx,edx ; ; Change default segment to be SS ; lea edx,SegLimit push edx lea edx,SegBase push edx lea edx,SegFlags push edx mov edi,[esi].RiTrapFrame push [edi].TsHardwareSegSs call VdmSegParams add esp,010h mov SelLookupResult,eax
do120: test [esi].RiPrefixFlags,PREFIX_SEG_ALL ; check for seg prefixes jz do190 ; no prefixes, use default.
; Note: we could use a bsr instruction here, but it has a high ; overhead relative to a test and a jump, and I expect that ; es overrides will be by far the most common mov edi,[esi].RiTrapFrame test [esi].RiPrefixFlags,PREFIX_ES jz do130
movzx edx,word ptr [edi].TsSegEs jmp do180
do130: test [esi].RiPrefixFlags,PREFIX_CS jz do140
movzx edx,word ptr [edi].TsSegCs jmp do180
do140: test [esi].RiPrefixFlags,PREFIX_SS jz do150
movzx edx,word ptr [edi].TsHardwareSegSs jmp do180
do150: test [esi].RiPrefixFlags,PREFIX_DS jz do160
movzx edx,word ptr [edi].TsSegDs jmp do180
do160: test [esi].RiPrefixFlags,PREFIX_FS jz do170
movzx edx,word ptr [edi].TsSegFs jmp do180
do170: ; assert that seg gs bit is set movzx edx,word ptr [edi].TsSegGs
; ; Get information on new default segment ; do180: lea ecx,SegLimit push ecx lea ecx,SegBase push ecx lea ecx,SegFlags push ecx push edx call VdmSegParams add esp,010h mov SelLookupResult,eax
test byte ptr SelLookupResult,0fh jz do200 ; return error
cmp dword ptr ReadWrite,0 jnz do190 ; we can read all sels
test dword ptr SegFlags,SEL_TYPE_WRITE jz do200 ; return error.
cmp ebx,SegLimit jae do200 ; gp fault
do190: add ebx,SegBase do194: mov [esi].RiOperand,ebx ; update op pointer mov eax,1 do195: pop ebx pop ecx pop edi mov esp,ebp pop ebp ret
do200: xor eax,eax jmp do195
; ; Get the SIB if there is one, and save it for later. ; do210: cmp ecx,MI_RMSIB jne do215 ; no Sib, dispatch for displacement
call CheckEip test al,0fh jz do200 ; report GP fault
movzx eax,byte ptr [edi] mov Sib,eax inc edi inc [esi].RiEip do215: jmp modtab32[edx * 4]
do220: ; ; These forms have no displacement, except for the "bp" form, which ; is just a 32 bit immediate displacement ; mov ebx,0 ; assume no displacement cmp ecx,MI_RMBP jne do270
call CheckEip test al,0fh jz do200 ; Gp fault, report error
mov ebx,[edi] ; get displacement add [esi].RiEip,4 ; update eip jmp do120 ; go add in seg
do240: ; ; These forms have an 8 bit displacement ; call CheckEip test al,0fh jz do200 ; Gp fault, report error
movsx ebx,byte ptr [edi] inc [esi].RiEip jmp do270
do250: ; ; These forms have an 32 bit displacement ; call CheckEip test al,0fh jz do200 ; Gp fault, report error
mov ebx, [edi] add [esi].RiEip,4 jmp do270
do260: ; ; These forms are register operands ; mov ebx,RegTab[ecx * 4] ; get offset into stackframe add ebx,[esi].RiTrapFrame ; form linear address jmp do195 ; return success
do270: ; ; Add in the RM portion of the effective address. ; cmp ecx,MI_RMSIB je do290 ; handle SIB specially
mov edi,[esi].RiTrapFrame mov edx,RegTab[ecx * 4] ; get offset of register add ebx,[edx+edi] ; add register to displacement cmp ecx,MI_RMBP ; bp is base? je do280 ; set up ss as default
jmp do120 ; get segment info.
do280: ; ; Change default segment to be SS ; lea edx,SegLimit push edx lea edx,SegBase push edx lea edx,SegFlags push edx mov edi,[esi].RiTrapFrame push [edi].TsHardwareSegSs call VdmSegParams add esp,010h mov SelLookupResult,eax jmp do120 do290: ; ; Decode the Sib ; mov edx,Sib mov edi,[esi].RiTrapFrame and edx,MI_SIB_BASEMASK ; isolate base cmp edx,MI_SIB_BASENONE ; no base je do300
mov eax,RegTab[edx * 4] add ebx,[edi+eax] ; get register contents, and add
do300: mov edx,Sib and ecx,MI_SIB_INDEXMASK shr ecx,MI_SIB_INDEXSHIFT ; make index out of "index" field cmp ecx,MI_SIB_INDEXNONE je do310 ; no index
mov eax,RegTab[ecx * 4] mov eax,[eax+edi] ; get reg contents for multiply. mov ecx,Sib and ecx,MI_SIB_SSMASK shr ecx,MI_SIB_SSSHIFT ; for shift count shl eax,cl add ebx,eax
do310: cmp edx,MI_SIB_BASENONE jne do120
; ; If mod != 0, then we have to add in EBP, and make ss the default seg ; mov edx,ModRm and edx,MI_MODMASK shr edx,MI_MODSHIFT cmp edx,MI_MODNONE jne do120 ; ; Add in Ebp, and change default segment to ss ; add ebx,[edi].TsEbp
lea edx,SegLimit push edx lea edx,SegBase push edx lea edx,SegFlags push edx mov edi,[esi].RiTrapFrame push [edi].TsHardwareSegSs call VdmSegParams add esp,010h mov SelLookupResult,eax jmp do120 ; add in segment info
VdmDecodeOperand endp
public VdmSegParams VdmSegParams proc
push edi mov edi,[esi].RiTrapFrame test dword ptr [edi].TsEFlags,EFLAGS_V86_MASK jz vsp20
Segmt equ word ptr [ebp + 8] SegFlags equ [ebp + 0Ch] SegBase equ [ebp + 010h] SegLimit equ [ebp + 014h]
pop edi push ebp mov ebp,esp push edi
movzx eax,Segmt shl eax,4 mov edi,SegBase mov [edi],eax mov edi,SegLimit mov dword ptr [edi],0FFFFh mov edi,SegFlags mov [edi],dword ptr SEL_TYPE_WRITE mov eax,1
pop edi mov esp,ebp pop ebp ret
vsp20: pop edi jmp _Ki386GetSelectorParameters@16
VdmSegParams endp _PAGE ENDS end
|