;----------------------------------------------------------------------------- ; ; TESTCSEG.INC ; ; Copyright (c) 1991, 1995-Present Robert Collins ; ; You have my permission to copy and distribute this software for ; non-commercial purposes. Any commercial use of this software or ; source code is allowed, so long as the appropriate copyright ; attributions (to me) are intact, *AND* my email address is properly ; displayed. ; ; Basically, give me credit, where credit is due, and show my email ; address. ; ;----------------------------------------------------------------------------- ; ; Robert R. Collins email: rcollins@x86.org ; ;----------------------------------------------------------------------------- Public Test32_Done Extrn @FC32: Near Extrn Test32a1: Near Extrn Trap13_32: Near ;----------------------------------------------------------------------------- Test_CSEG16_Attr proc near ;----------------------------------------------------------------------------- ; Input: AL = Access Attributes ; AH = Big Bit (bit6) 0=Small segment; 40=Big segment ; BL = Expectant bit pattern of result ; ECX = Upper segment limit ; ESI = Address to test within segment bounds ; EDI = Address to test beyond end of segment ; EXPANSION_BIAS = An initial offset to EIP used when testing the ; expansion direction bits. ; Output: AX = Test status. Each bit represents a single test. ; 1=Pass, 0=Fail. ; Registers Modified: Ha, are you kidding, this uses LOADALL! ;----------------------------------------------------------------------------- ; This test must be flexible enough to handle an expand-down code segment ; (if such a thing can be proven to exist), and to test whether the "PRESENT" ; bit has any effect in the CS segment. ; ; Testing expand-down code segments present an interesting problem, as a ; CALL, RET, or JMP instruction may ultimately clear this bit. Therefore, ; this test must be able to detect whether the bit has been changed by ; the instruction. ;----------------------------------------------------------------------------- ; The LOADALL data image is used in the following manner for this test: ; (Register names are used for reference only. All register names refer to ; the register which will get the value stored in the LOADALL image once ; LOADALL is executed.) ; EAX[b15..b08] (AH) = Expected results from each test iteration ; [b07..b00] (AL) = Cumulative test results from each test sub-section ; (Read/write within and outside segment bounds) ; EBX = Address to test within segment bounds ; EDX = Address to test beyond segment bounds ; ESI[b31..b16] = BIASed return address in case of processor ; shutdown. This address is used to continue the ; test as if an exception had occured. ; [b07..b00] = Cumulative test results from each test section ; (test a, b, c, etc.). ; EDI = Counter used for test iteration (test a, b, c, etc.). ;----------------------------------------------------------------------------- mov dword ptr SSEG_Ptr,esp ; save ESP mov Loadall_tbl.CS_Cache._Type,al mov Loadall_tbl.CS_Cache._CS32,ah mov Loadall_tbl.CS_Cache._Limit,ecx xor eax,eax ; clear accumulator for results mov ah,bl ; save expected results in AH mov Loadall_tbl._EAX,eax ; save expected results in loadall img. mov Loadall_tbl._EBX,esi ; address to read within segment bounds mov Loadall_tbl._EDX,edi ; address to read outside segment bounds mov Loadall_tbl._EDI,5 ; test iteration counter mov Loadall_tbl._ESP,esp mov eax,Expansion_BIAS ; get CS code base BIAS test Loadall_tbl.CS_Cache._CS32,40h ; USE32? jz @Use16 add eax,offset Test32a1 ; use32 destination address jmp short @F @Use16: add eax,offset Test2a1 ; convert to destination address @@: mov Loadall_tbl._EIP,eax ; call Enable_Gate20 ; enable A20 to CPU bus ;----------------------------------------------------------------------------- ; Set Exception-13 vector ;----------------------------------------------------------------------------- mov ax,offset Trap13 test Loadall_tbl.CS_Cache._CS32,40h ; USE32? jz short @F mov ax,offset Trap13_32 @@: add eax,Expansion_BIAS mov INT_SAVE,ax ; save IP of Exc-13 mov INT_SAVE[2],cs ; save CS of Exc-13 mov bx,offset RMInt0D call Swap_INT ;----------------------------------------------------------------------------- ; Test for various special access rights cases. ; ACCESS RIGHTS = 13 -- Testing PRESENT bit: ; Set user shutdown in CMOS RAM ; Set RESET address in BIOS data area ; = 94 -- Testing Read-Only expand down code segment: ; Move the entire code segment to the CS BIAS addr. ; = 96 -- Testing Read-Write expand down code segment: ; Move the entire code segment to the CS BIAS addr. ;----------------------------------------------------------------------------- ; Access rights=13h -- Present bit ;----------------------------------------------------------------------------- cmp Loadall_tbl.CS_Cache._Type,13h ; testing present bit? jne short @F CMOS_Write2 CMOS_Shutdown,User_Shutdown mov Loadall_tbl._EDI,1 ; test iteration counter mov word ptr Loadall_tbl._ESI[2],offset Test2a2_Done mov ax,BIOSDATA ; make DS=BIOSDATA segment @ 40h mov ds,ax assume ds:biosdata mov word ptr Shut_Restart,offset Test2_Shut1 mov word ptr Shut_Restart[2],cs ;----------------------------------------------------------------------------- ; Access rights=94h -- R/O expand down ;----------------------------------------------------------------------------- @@: cmp Loadall_tbl.CS_Cache._Type,94h ; expansion direction=down? jne short @RW_ED? ; nope test Loadall_tbl.CS_Cache._CS32,40h ; USE32? jz short @Move_Code ; nope mov eax,offset Test32a1 add ax,-(CS_Size + 1000h) mov cs:@FC32[1],eax @Move_Code: push es mov cx,cs mov es,cx mov si,0 ; source index address mov edi,Expansion_BIAS ; destination index address mov ecx,edi ; COUNT = 10000-Destination address neg cx rep movs byte ptr es:[di],byte ptr cs:[si] pop es jmp Go_Test2 ;----------------------------------------------------------------------------- ; Access rights=96h -- R/W expand down ;----------------------------------------------------------------------------- @RW_ED?:cmp Loadall_tbl.CS_Cache._Type,96h ; R/W expand down? je short @Move_Code ; yes Go_Test2: mov edi,offset Loadall_tbl LOADALL ;----------------------------------------------------------------------------- ; Determine whether the expansion direction bit has been cleared. If it has, ; then we can detect this by comparing the current EIP to the CS BIAS used ; to offset EIP for expansion direction tests. If EIP is EVER less than the ; expansion direction BIAS, then the expansion direction bit has been cleared. ; If this happens, we need to guarantee that we mark the test as having ; failed. ;----------------------------------------------------------------------------- Test2a1:mov ecx,Expansion_BIAS ; check to see of ED got reset call @F @@: pop bx movzx ebx,bx cmp ebx,ecx ; ED get reset? ja short @F mov al,byte ptr Loadall_tbl._EAX[1] ; get expected results not al ; change them mov byte ptr Loadall_tbl._EAX,al ; force ERROR conditions jmp short Test2_Results ;----------------------------------------------------------------------------- ; For expand UP segments, these next two tests don't produce any errors for ; a normal data segment. But with LOADALL it is possible to individually ; set access attributes in a manner inconsistent with segment register ; loads, and contrary to Intel documentation. The next two tests read within ; segment bounds and produce the following results (as per access attributes): ; ; EXE ED W Read Write ; 0 0 0 = YES NO ; 0 1 0 = NO NO ; 0 1 1 = NO NO ; 1 0 0 = NO NO ; 1 0 1 = YES NO ; 1 1 0 = NO NO ; 1 1 1 = YES NO ;----------------------------------------------------------------------------- @@: mov ebx,Loadall_tbl._EBX ; address to read from mov esi,offset @F ; return address for ISR add esi,word ptr Expansion_BIAS ; add offset for expansion dir. mov word ptr Loadall_tbl._ESI[2],si mov cx,cs:[ebx] ; @@: rcl byte ptr Loadall_tbl._EAX,1 ; accumulate error status mov esi,offset @F ; return address for ISR add esi,word ptr Expansion_BIAS ; add offset for expansion dir. mov word ptr Loadall_tbl._ESI[2],si mov cs:[ebx],cx ; try to generate GP from DS @@: rcl byte ptr Loadall_tbl._EAX,1 ; accumulate error status ;----------------------------------------------------------------------------- ; For expand UP segments, these next two tests should both produce errors for ; a normal data segment. The next two tests read outside the segment bounds ; and produce the following results (as per access attributes): ; ; EXE ED W Read Write ; 0 0 0 = NO NO ; 0 1 0 = YES NO ; 0 1 1 = YES YES ; 1 0 0 = NO NO ; 1 0 1 = NO NO ; 1 1 0 = NO NO ; 1 1 1 = NO NO ;----------------------------------------------------------------------------- Test2a2: mov Loadall_tbl._EIP,offset Test2a1 mov ebx,Loadall_tbl._EDX ; address to read from mov esi,offset @F ; return address for ISR add esi,word ptr Expansion_BIAS ; add offset for expansion dir. mov word ptr Loadall_tbl._ESI[2],si mov cx,cs:[ebx] ; try to generate GP from DS @@: rcl byte ptr Loadall_tbl._EAX,1 ; accumulate error status mov esi,offset @F ; return address for ISR add esi,word ptr Expansion_BIAS ; add offset for expansion dir. mov word ptr Loadall_tbl._ESI[2],si mov cs:[ebx],cx ; try to generate GP from FS Test2a2_Done: @@: rcl byte ptr Loadall_tbl._EAX,1 ; accumulate error status ;----------------------------------------------------------------------------- ; Check for intermediary status. If the results are correct, then set ; a bit in the LOADALL (ESI) data image. ;----------------------------------------------------------------------------- Test2_Results: mov al,byte ptr Loadall_tbl._EAX ; get current ERROR status cmp al,byte ptr Loadall_tbl._EAX[1] ; expected results? stc ; set results flag je short @F clc ; set result=fail flag @@: rcl byte ptr Loadall_tbl._ESI,1 dec Loadall_tbl._EDI ; check for current iteration jz Test2e_Done cmp Loadall_tbl._EDI,4 ; use CALL LABEL ? je @Test2c_CALLF_LBL ; yes cmp Loadall_tbl._EDI,3 ; use CALL MEM32 ? je @Test2d_CALLF_M32 cmp Loadall_tbl._EDI,2 ; use RET FAR ? je @Test2e_RETF ; yes ;----------------------------------------------------------------------------- ; For each of these tests, we need to determine if the last test passed. If ; it did NOT, then we need to reload the segment access attributes with ; LOADALL. ;----------------------------------------------------------------------------- ; USE JMP FAR LABEL32 to reload CS access attributes. ;----------------------------------------------------------------------------- test byte ptr Loadall_tbl._ESI,1 ; did last test pass? jnz short Test2b mov Loadall_tbl._EIP,offset Test2b mov eax,Expansion_BIAS ; get BIAS for expans. dir. add Loadall_tbl._EIP,eax ; add to expected EIP jmp Go_Test2 Test2b: mov byte ptr Loadall_tbl._EAX,0 ; clear error flag farjmp Test2a1, ;----------------------------------------------------------------------------- ; Use CALL FAR LABEL32 to reload CS access attributes. ;----------------------------------------------------------------------------- @Test2c_CALLF_LBL: test byte ptr Loadall_tbl._ESI,1 ; did last test pass? jnz short Test2c mov Loadall_tbl._EIP,offset Test2c mov eax,Expansion_BIAS ; get BIAS for expans. dir. add Loadall_tbl._EIP,eax ; add to expected EIP jmp Go_Test2 Test2c: mov byte ptr Loadall_tbl._EAX,0 ; clear error flag cmp Loadall_tbl.CS_Cache._Type,94h ; expansion direction? je short @F ; yes cmp Loadall_tbl.CS_Cache._Type,96h ; expansion direction? je short @F ; yes call far ptr Test2a1 @@: call far ptr Test2a1[-CS_SIZE] ;----------------------------------------------------------------------------- ; Use CALL FAR MEM32 to reload CS access attributes. ;----------------------------------------------------------------------------- @Test2d_CALLF_M32: test byte ptr Loadall_tbl._ESI,1 ; did last test pass? jnz short Test2d mov Loadall_tbl._EIP,offset Test2c mov eax,Expansion_BIAS ; get BIAS for expans. dir. add Loadall_tbl._EIP,eax ; add to expected EIP jmp Go_Test2 Test2d: mov byte ptr Loadall_tbl._EAX,0 ; clear error flag mov word ptr CSEG_Ptr,offset Test2a1 mov eax,Expansion_BIAS add word ptr CSEG_Ptr,ax mov word ptr CSEG_Ptr[2],cs call CSEG_Ptr ;----------------------------------------------------------------------------- ; Use RET FAR to reload CS access attributes. ;----------------------------------------------------------------------------- @Test2e_RETF: test byte ptr Loadall_tbl._ESI,1 ; did last test pass? jnz short Test2e mov Loadall_tbl._EIP,offset Test2e mov eax,Expansion_BIAS ; get BIAS for expans. dir. add Loadall_tbl._EIP,eax ; add to expected EIP jmp Go_Test2 Test2e: mov byte ptr Loadall_tbl._EAX,0 ; clear error flag push seg _text mov eax,offset Test2a1 ; destination EIP add eax,word ptr Expansion_BIAS ; add BIAS for exp. dir. tests push ax ; save destination EIP on stk retf ;----------------------------------------------------------------------------- ; If the processor is shutdown either by accident or intentionally (as when ; testing the PRESENT bit), execution resumes here, and will then re-continue ; at the destination address contained in the LOADALL (ESI) data image. ;----------------------------------------------------------------------------- Test2_Shut1: lss esp,fword ptr cs:SSEG_PTr mov dx,seg _Data ; Reload ALL segment registers after mov ds,dx ; RESET. mov es,dx mov fs,dx mov gs,dx mov ebp,Loadall_tbl._EBP ; get original EBP or Loadall_tbl._Eflags,1 ; set carry flag movzx eax,word ptr Loadall_tbl._ESI[2] ; get return address mov Loadall_tbl._EIP,eax ; set new destination address cmp Loadall_tbl.CS_Cache._Type,13h ; testing present bit? jne Go_Test2 ; nope @@: mov Loadall_tbl.CS_Cache._Type,93h test Loadall_tbl.CS_Cache._CS32,40h ; USE32? jz Go_Test2 xor Loadall_tbl.CS_Cache._CS32,40h ; clear USE32 bit jmp Go_Test2 ;----------------------------------------------------------------------------- ; Done with CS test. Reload segment registers with real-mode compatible ; values. ;----------------------------------------------------------------------------- Test2e_Done: Enter_PM farjmp @F,CS_64k-Gdt_386 Test32_done: @@: Exit_PM lss esp,fword ptr SSEG_Ptr ; restore stack segment ;----------------------------------------------------------------------------- ; Restore ;----------------------------------------------------------------------------- call Shut_A20 ; disable A20 from CPU bus CMOS_Write2 CMOS_Shutdown,0 ; Enable NMI mov bx,offset RMInt0D ; Restore original Exc-13 vector call Swap_INT mov al,byte ptr Loadall_tbl._ESI ; get test results mov Loadall_tbl._EAX,0 ; clear registers used in this test mov Loadall_tbl._EBX,0 ; clear registers used in this test mov Loadall_tbl._EDX,0 ; clear registers used in this test mov Loadall_tbl._ESI,0 ; clear registers used in this test mov Loadall_tbl._EDI,0 ; clear registers used in this test mov Loadall_tbl._EFlags,2 ; clear flags used in this test mov Loadall_tbl.CS_Cache._Type,93h mov Loadall_tbl.CS_Cache._CS32,0 mov Loadall_tbl.CS_Cache._Limit,0ffffh ret Test_CSEG16_Attr endp