windows-nt/Source/XPSP1/NT/base/boot/lib/i386/decode.inc
2020-09-26 16:20:57 +08:00

516 lines
16 KiB
PHP

;** Decoding macros
;
; These walk a state machine based on where a command (i.e., char or string)
; begins.
;** BitsAt - Extract from bit position n some bits
;
; Macro parameter:
; n bit position to begin extract
; cbits number of bits to extract
; Entry: eax working data
; esi input stream
; edi output stream
; Exit: eax updated so that next data begins in al
; esi/edi updated
; ecx contains data
; Uses: none
BitsAt macro n,cbits
.errnz n eq 0
if (n+cbits) lt 8 ; entire operation occurs in low byte
CopyBits cx,ax,n,cbits ; (cx) = desired bits rightmost
elseif (n+cbits) lt 16 ; operation consumes byte
CopyBits cx,ax,n,cbits ; (cx) = desired bits rightmost
lodsb ; (ah/al) = next input
xchg al,ah ; (al/ah) = next input
elseif (n+cbits) eq 16 ; operation consumes remainder of buffered data
CopyBits cx,ax,n,cbits ; (cx) = desired bits rightmost
lodsw ; (al/ah) = next input
else ; operation consumes into unbuffered data
mov ecx,eax
lodsw
shrd cx,ax,n
and ecx,(1 shl cbits)-1
endif
endm
;** CmdAt - macro that processes a command at a bit position
;
; Macro parameter:
; n bit position where command is expected
; Entry: eax working data, command begins in al
; esi points to input stream
; edi points to output stream
; Exit: eax updated so that next command begins in al
; esi/edi updated
; EXPECTS FALL-THROUGH TO NEXT CmdAT
; Uses: ecx, edx (not directly, but by virtue of OffsetAt, which
; in turn calls LengthAt....)
CmdAt macro n
local ca1
align4
public CmdAt&n
CmdAt&n:
if n eq 7
ror eax,1
test al,11b shl 6
rol eax,1
else
test al,11b shl n
endif
jpo ca1
OffsetAt %(n+1)
align4 ; note that OffsetAt jumps away
ca1: ; so there is no fall-through penalty
CharAt %(n+1)
endm
;** CharAt - macro that processes a character at a bit position
;
; Macro parameter:
; n bit position where char is expected
; Entry: eax working data, char may be in ah
; esi input stream
; edi output stream
; Exit: eax updated so that next command begins in al
; esi/edi updated
; Uses: ch
CharAt macro n
if n eq 8
mov al,ah ; (al) = char for output
XlatChr
CheckOffset
stosb ; store it
lodsw ; (al/ah) = next input
else
if n eq 1
shr eax,1 ; (al) = byte for output
XlatChr
CheckOffset
stosb ; store it
add eax,eax ; (ah) = next byte
lodsb ; (ah/al) = next input
else
mov ch,ah ; (ch) = saved next input
shr eax,n ; (al) = byte for output
XlatChr
CheckOffset
stosb ; store it
lodsb ; (al) = byte-after-next
mov ah,ch ; (ah/al) = next input
endif
xchg al,ah ; (al/ah) = next input
endif
endm
;** OffsetAt - Parse an offset at a bit position
;
; Macro parameter:
; n bit position where offset is expected
; Entry: cbits number of bits in offset
; eax working data, offset may begin in ah
; esi input stream
; edi output stream
; Exit: eax updated so that length begins in al
; ecx offset
; esi/edi updated
; Uses: ecx
OffsetAt macro n
local try8,try12
public OffsetAt&n
OffsetAt&n:
CheckBit a,n ; does a 6-bit offset follow?
jnz try8 ; no, try an 8-bit offset
BitsAt %(n+1),6 ; yes, load it into (ecx) and go
Jump LengthAt,%((n+7) mod 8)
align4
try8:
CheckBit a,%(n+1) ; does an 8-bit offset follow?
jnz try12 ; no, must be a 12-bit offset
BitsAt %(n+2),8 ; yes, load it into (ecx)
add ecx,MAX_6BIT_OFFSET+1 ;
Jump LengthAt,%((n+10) mod 8); go process the following length
align4
try12:
BitsAt %(n+2),12 ; load 12-bit offset into (ecx)
add ecx,MAX_8BIT_OFFSET+1 ;
Jump LengthAt,%((n+14) mod 8); go process the following length
endm
;** LengthAt - parse off a length at a position and move the bytes
;
; LengthAt parses off a length (gamma-prime encoded), moves the
; relevant string, and dispatches to the next command.
;
; Macro parameter:
; n bit position to begin extract
; Entry: eax working data
; ecx offset for string
; esi input stream
; edi output stream
; Exit: eax updated so that next data begins in al
; esi/edi updated
; Uses: ecx, edx
LengthAt macro n
local try3,try5,try7,try9,tryGeneral,done,error
% ifidni <LastErrBJump>,<DecodeError>
LastErrBJump equ <error>
endif
align4
public LengthAt&n
LengthAt&n:
jecxz error ; check for 0 offset (illegal)
cmp ecx,SPECIAL_EOS ; check end-of-segment offset
je done ; that's our EOS, so get out
CheckBit a,n ; is this a degenerate encoding?
jz try3 ; no, go for a wider encoding
DoMovs short,2
if n eq 7 ; are we finished with this byte?
lodsb ; (ah/al) is next input
xchg al,ah ; (al/ah) is next input
endif
Jump CmdAt,%((n + 1) mod 8) ; go process next command
done:
mov dl,n ; DL == current state
jmp DecodeDone ; exit
error:
;; Debug_Out "MRCI32 Decompress32: bad offset in LengthAt&n"
jmp DecodeError
align4
try3:
mov edx,ecx ; save delta
CheckBit a,%(n + 1) ; is this a 3-bit encoding?
jz try5 ; no, go for wider still
BitsAt %(n+2),1
DoMovs short,ecx,3
Jump CmdAt,%((n + 3) mod 8) ; go process next command
align4
try5:
CheckBit a,%(n + 2) ; is this a 5-bit encoding?
jz try7 ; no, go test for wider STILL
BitsAt %(n+3),2
DoMovs short,ecx,5
Jump CmdAt,%((n + 5) mod 8) ; go process next command
align4
try7:
CheckBit a,%(n + 3) ; is this a 7 bit encoding?
jz try9 ; no, go test for wider STILL
BitsAt %(n+4),3
DoMovs long,ecx,9
Jump CmdAt,%((n + 7) mod 8) ; go process next command
align4
try9:
CheckBit a,%(n + 4) ; is this a 9 bit encoding?
jz tryGeneral ; no, go handle generically
BitsAt %(n+5),4
DoMovs long,ecx,17
Jump CmdAt,%((n + 9) mod 8) ; go process next command
;
; Length exception handling code goes here
;
align4
tryGeneral:
mov cl,n+5 ; CL == # of bits to eat to yield
if n NE 7
jmp LengthAbove32 ; gamma length with 5 leading zeros stripped
else
;; .errnz $-GeneralLength ; assert that we'll fall through
endif
endm
DoGeneralLength macro
local try11,try13,try15,try17
public LengthAbove32,CopyString
GeneralLength:
align4
LengthAbove32:
shl eax,16 ;
mov ax,[esi] ; get 16 more bits
add cl,16 ;
ror eax,cl ; (eax) is filled, time to party
;
; Figure out the length and do a string op
;
try11:
shr eax,1 ; is it an 11-bit encoding?
jnc try13 ; no
and eax,1Fh ; mask off the numeric value
add eax,33 ;
xchg ecx,eax ; (ecx) now has string length
sub al,10 ; record # extra bits in this length
;
; At this point, (ecx) is the # of bytes to copy and (al) is the number of
; additional bits to eat for the particular gamma length.
;
; Good coding practices suggest that CopyString be at the end so that the
; other gamma decoders need not jump backwards to it, but if we assume
; that the longer strings are marginally less common, then it is marginally
; better to fall through on this, the smallest of the general cases.
;
align4
CopyString:
DoMovs long,ecx
mov dl,al ; (dl) == bit position in old ax
cmp dl,24 ; is it the max?
jb @F ; no
inc esi ; yes, need to skip 1 more whole byte
lodsw ; get new (ax) to restart state machine
sub dl,24 ; (dl) == new state
DecodeRestart
align4
@@:
cmp dl,16 ; did we exhaust the old ax?
jae @F ; yes
dec esi ; no,
add dl,8 ; but we know we exhausted the low byte
@@:
lodsw ; get new (ax) to restart state machine
sub dl,16 ; (dl) == new state
DecodeRestart
align4
try13:
shr eax,1 ; is it an 13-bit encoding?
jnc try15 ; no
and eax,3Fh ; mask off the numeric value
add eax,65 ;
xchg ecx,eax ; (cx) now has string length
sub al,8 ; record # extra bits in this length
jmp CopyString ;
align4
try15:
shr eax,1 ; is it an 15-bit encoding?
jnc try17 ; no
and eax,7Fh ; mask off the numeric value
add eax,129 ;
xchg ecx,eax ; (ecx) now has string length
sub al,6 ; record # extra bits in this length
jmp CopyString ;
align4
try17:
shr eax,1 ; is it an 17-bit encoding?
;; Debug_OutNC "MRCI32 Decompress32: invalid length"
jnc DecodeError ; no, ERROR
and eax,0FFh ; mask off the numeric value
add eax,257 ;
xchg ecx,eax ; (ecx) now has string length
sub al,4 ; record # extra bits in this length
jmp CopyString ;
endm
;** DoMovs - worker macro for LengthAt and DoGeneralLength
;
; <size> is either "short" or "long"; if short, then we don't
; bother trying to do a movsw/movsb combo (overhead swamps benefit);
; if long, we do.
;
; If <len> == 2, the offset to use is in (ecx). (edx) is trashed.
;
; Otherwise, the offset has been saved in (edx), and <len>
; is the size of the string to move (normally ecx). (ecx) and (edx)
; are trashed.
;
; <errjmp> is where to go if the expansion is going to overflow the
; destination buffer. DoMovs just passes this parameter along to the
; CheckOffset macro.
;
DoMovs macro size,len,extra,errjmp
local slower
ifidni <len>,<2>
mov edx,esi ; save (esi) in (edx)
mov esi,edi
sub esi,ecx
CheckOffset 2,errjmp ; check target offset
movsb ; don't do movsw,
movsb ; that doesn't handle overlap!
mov esi,edx ; restore (esi) from (edx)
else
ifnb <len>
ifdifi <len>,<ecx>
ifb <extra>
mov ecx,len
else
lea ecx,[len+extra]
endif
else
ifnb <extra>
add ecx,extra
endif
endif
endif
mov ebx,esi ; save (esi) in (ebx)
mov esi,edi ;
sub esi,edx ; (esi) points to string to move
CheckOffset ecx,errjmp ; check target offset
ifidni <size>,<short>
rep movsb
elseifidni <size>,<long>
cmp edx,1 ; if the offset is 1,
je short slower ; then overlap forces us to do movsb
shr ecx,1
rep movsw
adc ecx,ecx
slower: rep movsb
else
.err <Bad DoMovs parameter: size>
endif
mov esi,ebx ; restore (esi) from (ebx)
endif
endm
;** CheckOffset - Verify offsets in ESI and EDI are ok for len bytes
;
; If "len" is blank, then CheckOffset simply does a 1-byte check.
; In the event of an error in any case, it branches to DecodeError.
;
LastErrSJump equ <DecodeError>
LastErrBJump equ <DecodeError>
CheckOffset macro len,errjmp
local tmp,jsjmp,jbjmp
IFDEF MAXDEBUG
cmp edi,[maxOffset]
jb short tmp
int 3
tmp:
ENDIF
ifnb <errjmp>
ErrSJump equ <errjmp>
else
ErrSJump catstr LastErrSJump
LastErrSJump equ <jsjmp>
endif
ifb <len>
dec ebp ; space remaining in destination buffer?
else
sub ebp,len ; space remaining in destination buffer?
endif
;; Debug_OutS "MRCI32 Decompress32: target buffer overflow"
jsjmp: js ErrSJump
IFDEF INLINE_LOWER_BOUND_CHECKING
;
; In-line bounds checking is disabled in favor of an invalid page fault
; handler. To use this code, be aware that EBX cannot be used by the
; decoding macros above (and it currently is!)
;
ifnb <len>
ifnb <errjmp>
ErrBJump equ <errjmp>
else
ErrBJump catstr LastErrBJump
LastErrBJump equ <jbjmp>
endif
cmp esi,ebx ; have we ventured before start of dest. buffer?
;; Debug_OutB "MRCI32 Decompress32: target buffer underflow"
jbjmp: jb ErrBJump
endif
ENDIF ;INLINE_LOWER_BOUND_CHECKING
endm
;* Misc. macros
Jump macro lab,tag
jmp lab&tag
endm
XlatChr macro ch
ror al,1
xor al,80h
endm
align4 macro
;
; This actually slowed down the real-mode decompressor, so some
; time will need to be spent verifying this is a real win... -JP
;
align 4
endm
CheckBit macro reg,bit
if bit lt 8
test reg&l,(1 shl bit)
else
test reg&h,(1 shl (bit-8))
endif
endm
CopyBits macro dst,src,n,cbits
shld dst,src,16-n
and e&dst,(1 shl cbits)-1
endm
;
; AX has the remaining bits, DL has the next state
;
DecodeRestart macro
IFDEF DEBUG
cmp dl,8
;; Debug_OutAE "MRCI32 Decompress32: bad decode state in DL"
ENDIF
movzx edx,dl
jmp aCmdAt[edx*4] ; go to correct state handler
endm
IFDEF MAXDEBUG
public maxOffset
maxOffset dd -1 ; handy for getting control at a specific point
ENDIF