;----------------------------------------------------------------------------- ; ; TESTDSEG.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 ; ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- Test_DSEG_Attr proc near ;----------------------------------------------------------------------------- ; Using LOADALL it is possible to combine segment access attributes ; in a manner that is impossible to duplicate under any other means. ; Two questions arise from these (and even legal situations): ; * Does the access attribute stay in affect after segment loads? ; * What are the definitions of these new attributes ; ; Here is what I've found: ; ; G EXE ED W ; 0 0 0 0 = Small R/O Expand UP (Legal combination) ; 0 0 0 1 = Small R/W Expand UP (Legal combination) ; 0 0 1 0 = Small R/O Expand Down (Legal combination) ; 0 0 1 1 = Small R/W Expand Down (Legal combination) ; 0 1 0 0 = Small No access allowed (Illegal combination) ; 0 1 0 1 = Small R/O Expand UP (Illegal combination) ; 0 1 1 1 = Small No access allowed (Illegal combination) ; 0 1 1 1 = Small R/O Expand UP (Illegal combination) ; 1 0 1 0 = Large R/O Expand Down (Legal combination) ; 1 0 1 1 = Large R/W Expand Down (Legal combination) ; 1 1 0 0 = Large No access allowed (Illegal combination) ; 1 1 0 1 = Large R/O Expand UP (Illegal combination) ; 1 1 1 1 = Large No access allowed (Illegal combination) ; 1 1 1 1 = Large R/O Expand UP (Illegal combination) ; ;----------------------------------------------------------------------------- ; 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 ; Output: AX = Test status. Each bit represents a single test. ; 1=Pass, 0=Fail. ; Registers Modified: Ha, are you kidding, this uses LOADALL! ;----------------------------------------------------------------------------- mov test_status,0 ; clear result status mov test_counter,4 ; initialize counter mov Access_Attr,al mov Big_Attr,ah mov Expect_Results,bl mov Upper_Limit,ecx mov Test_Within,esi mov Test_Beyond,edi mov Loadall_tbl.DS_Cache._Type,al mov Loadall_tbl.FS_Cache._Type,al mov Loadall_tbl.DS_Cache._CS32,ah mov Loadall_tbl.FS_Cache._CS32,ah mov Loadall_tbl.DS_Cache._Limit,ecx mov Loadall_tbl.FS_Cache._Limit,ecx mov Loadall_tbl._ESP,esp mov Loadall_tbl._EIP,offset Test3a Go_Test3: mov edi,offset Loadall_tbl LOADALL Assume ds:nothing, es:_data, fs:nothing, gs:_data ;----------------------------------------------------------------------------- ; 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 ;----------------------------------------------------------------------------- Test3a: mov ebx,Test_Within ; address to read from mov si,offset @F ; return address for ISR mov cx,ds:[ebx] ; try to generate GP from DS @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov cx,fs:[ebx] ; try to generate GP from FS @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov ds:[ebx],cx ; try to generate GP from DS @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov fs:[ebx],cx ; try to generate GP from FS @@: rcl ax,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 ;----------------------------------------------------------------------------- mov ebx,Test_Beyond ; address to read from mov si,offset @F ; return address for ISR mov cx,ds:[ebx] ; try to generate GP from DS @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov cx,fs:[ebx] ; try to generate GP from FS @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov ds:[ebx],cx ; try to generate GP from DS @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov fs:[ebx],cx ; try to generate GP from FS @@: rcl ax,1 ; accumulate error status ;----------------------------------------------------------------------------- ; Check for intermediary status. If the results are correct, then set ; a bit in the test_status variable. ;----------------------------------------------------------------------------- cmp al,Expect_Results ; correct results? stc ; set result flag je short @F ; yes clc ; set result=fail flag @@: rcl test_status,1 ; set result status dec test_counter ; check for current iteration jz Test3d_Done cmp test_counter,3 ; use MOV SEG,MEM16? je @Test3c_mem16 ; yes cmp test_counter,2 ; use MOV SEG,REG16? je @Test3d_reg16 ; yes ;----------------------------------------------------------------------------- ; Use L{SEGREG} REG to load segment. If the test_status didn't pass the last ; test, then our access attributes are hosed. If this is the case, we need to ; reload those attributes. The only way sure-fire way to do that is to ; use LOADALL. ;----------------------------------------------------------------------------- test test_status,1 ; did last test pass? jnz short Test3b mov Loadall_tbl._EIP,offset Test3b jmp Go_Test3 Test3b: lds di,dword ptr DSEG_Ptr ; use LSEG form of segment load lfs di,dword ptr DSEG_Ptr xor ax,ax ; clear error flag jmp Test3a ; go redo test ;----------------------------------------------------------------------------- ; Use MOV SEG,MEM16. However, if the test_status didn't pass the last test, ; then our access attributes are hosed. If this is the case, we need to ; reload those attributes. The only way sure-fire way to do that is to ; use LOADALL. ;----------------------------------------------------------------------------- @Test3c_mem16: test test_status,1 ; did last test pass? jnz short Test3c mov Loadall_tbl._EIP,offset Test3c jmp Go_Test3 Test3c: mov ds,DSEG mov fs,DSEG xor ax,ax ; clear error flag jmp Test3a ; go redo test ;----------------------------------------------------------------------------- ; Use MOV SEG,REG16. However, if the test_status didn't pass the last test, ; then our access attributes are hosed. If this is the case, we need to ; reload those attributes. The only way sure-fire way to do that is to ; use LOADALL. ;----------------------------------------------------------------------------- @Test3d_reg16: test test_status,1 ; did last test pass? jnz short Test3d mov Loadall_tbl._EIP,offset Test3d jmp Go_Test3 Test3d: mov dx,_Data mov ds,dx mov fs,dx xor ax,ax ; clear error flag jmp Test3a ; go redo test ;----------------------------------------------------------------------------- ; We have just completed testing DS & FS. Testing these two registers, ; allowed us to still have access to two data segments (ES & GS). This data ; segment access is essential if any errors occured within the test -- as ; we need to reload the LOADALL data image with a new EIP pointer. And ; obviously to do that, we need a data segment register available. ; ; So here, we reload DS & FS with real-mode compatible attributes and then ; load ES & GS with those values used on DS & FS. Then we attempt the same ; test on ES & GS. ;----------------------------------------------------------------------------- Test3d_Done: mov test_counter,4 ; initialize counter mov al,Access_Attr mov ah,Big_Attr mov ecx,Upper_Limit mov Loadall_tbl.DS_Cache._Type,93h mov Loadall_tbl.FS_Cache._Type,93h mov Loadall_tbl.DS_Cache._CS32,0 mov Loadall_tbl.FS_Cache._CS32,0 mov Loadall_tbl.DS_Cache._Limit,0ffffh mov Loadall_tbl.FS_Cache._Limit,0ffffh mov Loadall_tbl.ES_Cache._Type,al mov Loadall_tbl.GS_Cache._Type,al mov Loadall_tbl.ES_Cache._CS32,ah mov Loadall_tbl.GS_Cache._CS32,ah mov Loadall_tbl.ES_Cache._Limit,ecx mov Loadall_tbl.GS_Cache._Limit,ecx mov Loadall_tbl._EIP,offset Test3e mov edi,offset Loadall_tbl LOADALL Assume ds:_data, es:nothing, fs:_data, gs:nothing ;----------------------------------------------------------------------------- ; 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 ;----------------------------------------------------------------------------- Test3e: mov ebx,Test_Within ; address to read from mov si,offset @F ; return address for ISR mov cx,es:[ebx] ; try to generate GP from ES @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov cx,gs:[ebx] ; try to generate GP from GS @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov es:[ebx],cx ; try to generate GP from ES @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov gs:[ebx],cx ; try to generate GP from GS @@: rcl ax,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 ;----------------------------------------------------------------------------- mov ebx,Test_Beyond ; address to read from mov si,offset @F ; return address for ISR mov cx,es:[ebx] ; try to generate GP from ES @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov cx,gs:[ebx] ; try to generate GP from GS @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov es:[ebx],cx ; try to generate GP from ES @@: rcl ax,1 ; accumulate error status mov si,offset @F ; return address for ISR mov gs:[ebx],cx ; try to generate GP from GS @@: rcl ax,1 ; accumulate error status ;----------------------------------------------------------------------------- ; Check for intermediary status. If the results are correct, then set ; a bit in the test_status variable. ;----------------------------------------------------------------------------- cmp al,Expect_Results ; correct results? stc ; set result flag je short @F ; yes clc ; set result=fail flag @@: rcl test_status,1 ; set result status dec test_counter ; check for current iteration jz Test3h_Done cmp test_counter,3 ; use MOV SEG,MEM16? je @Test3g_mem16 ; yes cmp test_counter,2 ; use MOV SEG,REG16? je @Test3h_reg16 ; yes ;----------------------------------------------------------------------------- ; Use L{SEGREG} REG to load segment. If the test_status didn't pass the last ; test, then our access attributes are hosed. If this is the case, we need to ; reload those attributes. The only way sure-fire way to do that is to ; use LOADALL. ;----------------------------------------------------------------------------- test test_status,1 ; did last test pass? jnz short Test3f mov Loadall_tbl._EIP,offset Test3f jmp Go_Test3 Test3f: les di,dword ptr DSEG_Ptr lgs di,dword ptr DSEG_Ptr xor ax,ax ; clear error flag jmp Test3e ; go redo test ;----------------------------------------------------------------------------- ; Use MOV SEG,MEM16. However, if the test_status didn't pass the last test, ; then our access attributes are hosed. If this is the case, we need to ; reload those attributes. The only way sure-fire way to do that is to ; use LOADALL. ;----------------------------------------------------------------------------- @Test3g_mem16: test test_status,1 ; did last test pass? jnz short Test3g mov Loadall_tbl._EIP,offset Test3g jmp Go_Test3 Test3g: mov es,DSEG mov gs,DSEG xor ax,ax ; clear error flag jmp Test3e ; go redo test ;----------------------------------------------------------------------------- ; Use MOV SEG,REG16. However, if the test_status didn't pass the last test, ; then our access attributes are hosed. If this is the case, we need to ; reload those attributes. The only way sure-fire way to do that is to ; use LOADALL. ;----------------------------------------------------------------------------- @Test3h_reg16: test test_status,1 ; did last test pass? jnz short Test3h mov Loadall_tbl._EIP,offset Test3h jmp Go_Test3 Test3h: mov dx,_Data mov es,dx mov gs,dx xor ax,ax ; clear error flag jmp Test3e ; go redo test ;----------------------------------------------------------------------------- ; Test 3 done. Reset segment registers with real mode compatible values. ;----------------------------------------------------------------------------- Test3h_Done: Enter_PM ; Enter protected mode mov dx,DS_64k-Gdt_386 ; Set segment limit=64k mov es,dx mov gs,dx Exit_PM ; back to real mode mov dx,seg _Data mov es,dx mov gs,dx Assume ds:_data, es:_data, fs:_data, gs:_data ;----------------------------------------------------------------------------- ; Restore ;----------------------------------------------------------------------------- mov ax,test_status mov test_status,0 ; clear status variable mov Loadall_tbl.ES_Cache._Type,93h mov Loadall_tbl.GS_Cache._Type,93h mov Loadall_tbl.ES_Cache._CS32,0 mov Loadall_tbl.GS_Cache._CS32,0 mov Loadall_tbl.ES_Cache._Limit,0ffffh mov Loadall_tbl.GS_Cache._Limit,0ffffh ret Test_DSEG_Attr endp