From 926d9e7c4ebf6bb4546883cdea6fa109e9f08721 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Tue, 16 Feb 2016 13:09:00 -0800 Subject: [PATCH] Saved LOADALL-related files --- docs/x86/ops/AAD/AAD.ASM | 5 +- docs/x86/ops/AAD/README.md | 4 +- docs/x86/ops/AAM/AAM.ASM | 3 - docs/x86/ops/AAM/README.md | 4 +- docs/x86/ops/LOADALL/286load.asm | 625 ++++++++++++ docs/x86/ops/LOADALL/386load.asm | 1000 +++++++++++++++++++ docs/x86/ops/LOADALL/README.md | 12 + docs/x86/ops/LOADALL/cpu_type.asm | 203 ++++ docs/x86/ops/LOADALL/emuload.asm | 648 ++++++++++++ docs/x86/ops/LOADALL/loadfns.286.asm | 382 +++++++ docs/x86/ops/LOADALL/loadfns.386.asm | 205 ++++ docs/x86/ops/LOADALL/macros.286.asm | 51 + docs/x86/ops/LOADALL/macros.386.asm | 78 ++ docs/x86/ops/LOADALL/tspec_a3_doc.html | 1276 ++++++++++++++++++++++++ 14 files changed, 4487 insertions(+), 9 deletions(-) create mode 100644 docs/x86/ops/LOADALL/286load.asm create mode 100644 docs/x86/ops/LOADALL/386load.asm create mode 100644 docs/x86/ops/LOADALL/cpu_type.asm create mode 100644 docs/x86/ops/LOADALL/emuload.asm create mode 100644 docs/x86/ops/LOADALL/loadfns.286.asm create mode 100644 docs/x86/ops/LOADALL/loadfns.386.asm create mode 100644 docs/x86/ops/LOADALL/macros.286.asm create mode 100644 docs/x86/ops/LOADALL/macros.386.asm create mode 100644 docs/x86/ops/LOADALL/tspec_a3_doc.html diff --git a/docs/x86/ops/AAD/AAD.ASM b/docs/x86/ops/AAD/AAD.ASM index 827f87c4a..30fd78dd9 100644 --- a/docs/x86/ops/AAD/AAD.ASM +++ b/docs/x86/ops/AAD/AAD.ASM @@ -1,6 +1,3 @@ -; -; Saved on February 16, 2015 from http://www.rcollins.org/ftp/source/aad/aad.asm -; .386p ;----------------------------------------------------------------------------- ; @@ -201,4 +198,4 @@ Test_AAD endp end - + diff --git a/docs/x86/ops/AAD/README.md b/docs/x86/ops/AAD/README.md index 6be10eba7..9d9f9e75e 100644 --- a/docs/x86/ops/AAD/README.md +++ b/docs/x86/ops/AAD/README.md @@ -43,4 +43,6 @@ From [http://www.rcollins.org/secrets/opcodes/AAD.html](http://www.rcollins.org/ This instruction exists in this form on all Intel x86 processors. -See the file [AAD.ASM](AAD.ASM) for diagnostic source code for this instruction. +The following related files were saved on February 16, 2015 from [http://www.rcollins.org](http://www.rcollins.org/): + +* [AAD.ASM](AAD.ASM) diff --git a/docs/x86/ops/AAM/AAM.ASM b/docs/x86/ops/AAM/AAM.ASM index c2ddcc419..86b2c4f2d 100644 --- a/docs/x86/ops/AAM/AAM.ASM +++ b/docs/x86/ops/AAM/AAM.ASM @@ -1,6 +1,3 @@ -; -; Saved on February 16, 2015 from http://www.rcollins.org/ftp/source/aam/aam.asm -; .386p ;----------------------------------------------------------------------------- ; diff --git a/docs/x86/ops/AAM/README.md b/docs/x86/ops/AAM/README.md index 79257fd09..c7cfff0b4 100644 --- a/docs/x86/ops/AAM/README.md +++ b/docs/x86/ops/AAM/README.md @@ -59,4 +59,6 @@ From [http://www.rcollins.org/secrets/opcodes/AAM.html](http://www.rcollins.org/ This instruction exists in this form on all Intel x86 processors. -See the file [AAM.ASM](AAM.ASM) for diagnostic source code for this instruction. +The following related files were saved on February 16, 2015 from [http://www.rcollins.org](http://www.rcollins.org/): + +* [AAM.ASM](AAM.ASM) diff --git a/docs/x86/ops/LOADALL/286load.asm b/docs/x86/ops/LOADALL/286load.asm new file mode 100644 index 000000000..d91994fda --- /dev/null +++ b/docs/x86/ops/LOADALL/286load.asm @@ -0,0 +1,625 @@ + Page 60,132 +;----------------------------------------------------------------------------- +; BEGIN LISTING 1 +;----------------------------------------------------------------------------- +; +; 286LOAD.ASM +; +; 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 +; +;----------------------------------------------------------------------------- +; +; This program demonstrates various aspects of CPU +; behavior that become apparent when using LOADALL. +; +; Test 1: Checks that LOADALL loads all the general- +; purpose registers; loads the segment registers +; with values that are inconsistant to their +; respective descriptor cache registers. +; +; Test 2: Access extended memory in real mode. +; +; Test 3: Tests that the Present bit in a descriptor +; table can be loaded using LOADALL without +; generating exception 11. But when the segment +; is accessed, exception 13 is generated. +; NOTE: This test should be done in protected +; mode, but can be done in real mode. 1) In real +; mode, no error code is pushed on the stack +; (possibly due to a bug in the CPU). 2) Also +; in real mode, when this program is emulated on +; a '386, the '386 fails to set the Present bit +; when any subsequent segment in loaded. This +; latter condition is clearly a bug in the '386. +; +; This program was written for Microsoft MASM 5.1, and +; MS DOS 3.3. This program contains compiler directives +; and branching techniques that might not be available +; on previous versions of the Macro Assembler, nor in +; competitive products. If this program is executed on +; any version of DOS prior to 3.3, it will most certainaly +; cause the system to crash. No attempt is made in this +; program to be compatible with previous versions of DOS, +; but compatibility can be done, and is left as an +; exercise to the reader. +; +;--------------------------------------------------------------- + +;--------------------------------------------------------------- +; Compiler directives +;--------------------------------------------------------------- + Title LOADALL_286 + .radix 16 + .8086 + + +;--------------------------------------------------------------- +; Interrupt vector segment +;--------------------------------------------------------------- +ABS0 segment at 0 + org 06h*4 ; INT 06h vector + INT_6 dd ? + + org 0467h ; PM Return address + PM_Ret_off dw ? ; Offset + PM_Ret_seg dw ? ; Segment + + org 800h ; LOADALL table loc'n. + Loadall_Locn label word + +ABS0 ends + + +;--------------------------------------------------------------- +; Structure definitions +;--------------------------------------------------------------- +Desc_cache STRUC ;; Hidden descriptor cache + A15_A00 dw ? ;; format. + A23_A16 db ? + _Type db ? + _Limit dw ? +Desc_cache ENDS + + +Loadall_struc STRUC ;; LOADALL memory image format + dw 3 dup (0) + _Msw dw 0 + dw 7 dup (0) + _Tr dw 0 + _Flags dw 2 + _Ip dw 0 + _Ldt dw 0 + _Ds dw 2222h + _Ss dw 4444h + _Cs dw 1111h + _Es dw 3333h + _Di dw 6666h + _Si dw 7777h + _Bp dw 5555h + _Sp dw 8888h + _Bx dw 2222h + _Dx dw 4444h + _Cx dw 3333h + _Ax dw 1111h + ES_Desc db 00,00,03,93h,0ffh,0ffh + CS_Desc db 00,00,00,9bh,0ffh,0ffh + SS_Desc db 00,00,04,93h,0ffh,0ffh + DS_Desc db 00,00,02,93h,0ffh,0ffh + Gdt_Desc db 00,00,00,00h,000h,000h + Ldt_Desc db 00,00,06,82h,088h,000h + Idt_Desc db 00,00,00,00h,0ffh,003h + TSS_Desc db 00,00,05,89h,000h,008h +Loadall_Struc ENDS + + +Descriptor STRUC + Seg_limit dw ? ; Segment limit + Base_A15_A00 dw ? ; A00..A15 of base address + Base_A23_A16 db ? ; A16..A23 of base address + Access_rights db ? ; Segment access rights + Limit_A19_A16 db ? ; Granularity, Op-size, + ; Limit A16..A19 + Base_A31_A24 db ? ; A24..A31 of base address +Descriptor ENDS + + +INT_Desc STRUC + IGate_Offset dw ? ; Offset of handler + CSEG_Sel dw ? ; Code segment selector + db 0 + db 86h ; 286 interrupt gate=16bit + ; CS:IP, FLAGS + Resvd dw 0 ; Reserved=0 +INT_Desc ENDS + + +;--------------------------------------------------------------- +; Macro definitions in MACROS.286: +; MFARJMP: Far JUMP since MASM doesn't assemble it. +; IO_DELAY: Put your favorite I/O delay macro here. +; LOADALL: Copy the LOADALL memory image down to +; 0:800 and execute a '286 LOADALL. +; PRINT_STRING: Given a variable name, use the DOS +; print string command to send it to the +; screen. +;--------------------------------------------------------------- + Include MACROS.286 + + + _DATA SEGMENT PARA PUBLIC 'DATA' +;--------------------------------------------------------------- +; Equates & local variables +;--------------------------------------------------------------- +; Protected mode access rights +;--------------------------------------------------------------- + CS_access equ 10011011b + DS_access equ 10010011b + +;--------------------------------------------------------------- +; Text equates +;--------------------------------------------------------------- + CRLF equ <0dh,0ah> + CRLF$ equ + INT6 equ [bp-4] + +;--------------------------------------------------------------- +; Conditional compilation. Set USE_386=1 if you plan to execute +; this program on a '386 using EMULOAD. +;--------------------------------------------------------------- + USE_386 equ 0 + + +;--------------------------------------------------------------- +; Loadall table(s) +;--------------------------------------------------------------- + Loadall_tbl Loadall_struc <> + Machine_State Loadall_struc <> + +;--------------------------------------------------------------- +; Global Descriptor Table +;--------------------------------------------------------------- + GDT_286 Descriptor + CSEG2 Descriptor <0ffffh,,,CS_access> ; CS + DSEG2 Descriptor <0ffffh,,,DS_access> ; DS + Gdt2_len equ $-Gdt_286 + +;--------------------------------------------------------------- +; Interrupt Descriptor Table +;--------------------------------------------------------------- +IDT_286 INT_Desc ; INT00 + INT_Desc ; INT01 + INT_Desc ; INT02 + INT_Desc ; INT03 + INT_Desc ; INT04 + INT_Desc ; INT05 + INT_Desc ; INT06 + INT_Desc ; INT07 + INT_Desc ; INT08 + INT_Desc ; INT09 + INT_Desc ; INT0a + INT_Desc ; INT0b + INT_Desc ; INT0c + INT_Desc ; INT0d +IDT2_Len equ $-IDT_286 + +;--------------------------------------------------------------- +; Misc. local variables +;--------------------------------------------------------------- +Mem_buffer db 400h dup (0) +Results dw 0 +i8259_1 db ? ; Status for master device +i8259_2 db ? ; Status of slave device + + +;--------------------------------------------------------------- +; String Messages +;--------------------------------------------------------------- +Passed db " PASSED.",CRLF$ +Failed db "--> FAILED <--",CRLF$ +Not_286 db "Not 80286 class computer.",CRLF$ +Rmvd db "LOADALL removed from 80286 mask.",CRLF$ +RFail db "Registers weren't loaded correctly." +LF db CRLF$ + +;--------------------------------------------------------------- +; I'm doing this wierd string definition technique to limit the +; page width to 64 characters. +;--------------------------------------------------------------- +Test_1 label word +db "Test 1: Testing 286 LOADALL instruction: ",24 + +Test_2 label word +db "Test 2: Testing extended memory in real mode: ",24 + +Test_3 label word +db "Test 3: Testing Present BIT in descriptor: ",24 + +_DATA ends + + + _TEXT SEGMENT PARA PUBLIC 'CODE' + ASSUME CS:_TEXT, DS:_DATA, ES:_DATA, SS:STACK + .286p +;--------------------------------------------------------------- +; A little CS-relative data for the stack pointer. This is +; to avoid using other kludge techniques, caused by using +; LOADALL, that make using the data segment undesirable. +;--------------------------------------------------------------- + Stack_ptr dw 0 + dw 0 + +;--------------------------------------------------------------- + LOADALL_286 proc far +;--------------------------------------------------------------- + PUSH DS ; Setup the stack to + XOR AX,AX ; return to DOS + PUSH AX + + MOV AX,_Data + MOV DS,AX + MOV ES,AX + +;--------------------------------------------------------------- +; Check CPU type, and set up a minimal invalid opcode handler +; in case LOADALL has been removed from the CPU mask. +;--------------------------------------------------------------- + IFE USE_386 + Call CPU_Type ; 286, 386? + cmp ax,2 ; 286? + je short @F ; yep + Print_String LF + Print_String Not_286 + retf ; go split + +@@: enter 4,0 ; create stack frame + mov word ptr INT6,offset INT6_handler + mov INT6[2],cs + call set_INT6_vector ; set our INT6 handler + ENDIF + + cli + Call Save_State ; Save the current CPU + Print_String LF ; state + Print_String Test_1 + + +;--------------------------------------------------------------- +; +; TEST1: Real mode +; Test general purpose registers +; Test Segment registers +; Test Descriptor cache base address +; +; (1) Setup LOADALL structures, and pointers +; (2) Execute LOADALL +; (3) Verify results of the test +; +;--------------------------------------------------------------- + mov ax,cs ; Prepare 24-bit + mov es,ax ; physical address that + mov si,0 ; is put in the LOADALL + call Calc_pm_address ; descriptor cache + mov Loadall_tbl.CS_Desc.A15_A00,ax ; entry. + mov Loadall_tbl.CS_Desc.A23_A16,dl + smsw ax + mov Loadall_tbl._Msw,ax + mov Loadall_tbl._Ip,offset Verify_State + mov word ptr cs:stack_ptr,sp ; save SS:SP + mov word ptr cs:stack_ptr[2],ss + LOADALL ; If LOADALL is removed + nop ; from the CPU mask, + Print_String failed ; then fall through + Print_String Rmvd ; to here. + +Loadall_RET: + call Restore_state + + IFE USE_386 + call set_INT6_vector ; set our INT6 handler + leave + ENDIF + + retf + +;--------------------------------------------------------------- + Verify_State: ; Verify that LOADALL worked +;--------------------------------------------------------------- +; This is where we land for the first test of '286 LOADALL. +; The purpose of this test is to verify that all the general +; purpose registers get loaded correctly. Specifically, we are +; testing to verify that all segment registers contain values +; that don't correspond to the memory addresses they appear to +; be pointing to. In other words, we are checking that the +; that the segment registers have one value, while their +; associated hidden descriptor cache registers have different +; values. +;--------------------------------------------------------------- + cmp ax,1111h ; Test AX + jne @F + cmp bx,2222h ; Test BX + jne @F + cmp cx,3333h ; Test CX + jne @F + cmp dx,4444h ; Test DX + jne @F + cmp bp,5555h ; Test BP + jne @F + cmp di,6666h ; Test DI + jne @F + cmp si,7777h ; Test SI + jne @F + cmp sp,8888h ; Test SP + jne short @F + mov ax,cs ; Test CS + cmp ax,1111h + jne short @F + mov ax,ds ; Test DS + cmp ax,2222h + jne short @F + mov ax,es ; Test ES + cmp ax,3333h + jne short @F + mov ax,ss ; Test SS + cmp ax,4444h + jne short @F + cmp word ptr ds:[0],0202h ; Test DS Desc Cache + jne short @F + cmp word ptr es:[0],0303h ; Test ES Desc Cache + jne short @F + cmp word ptr ss:[0],0404h ; Test SS Desc Cache + jne short @F + mov ax,_Data + mov ds,ax + mov es,ax + + mov ax,cs:stack_ptr[2] + mov ss,ax + mov sp,cs:stack_ptr + FARJMP <@Test1_Pass>, + +;--------------------------------------------------------------- +; Loadall failed the REGISTERs test. +;--------------------------------------------------------------- +@@: mov ax,_Data + mov ds,ax + mov es,ax + mov ax,cs:stack_ptr[2] + mov ss,ax + mov sp,cs:stack_ptr + FARJMP <@F>, + +@@: Print_String failed + Print_String RFail + jmp loadall_ret + +;--------------------------------------------------------------- +; LOADALL passed +;--------------------------------------------------------------- +@Test1_Pass: + Print_String passed + +;--------------------------------------------------------------- +; +; TEST2: Access extended memory while in real mode. +; +; (1) Enable A20 +; (2) Save contents of extended memory +; (3) Write data pattern in extended memory +; (4) Set IP & ES descriptor cache pointing to extended memory +; (5) LOADALL +; (6) Verify results +; (7) Restore original data in extended memory +; +;---------------------------------------------------------------- + Print_String Test_2 + Call Enable_Gate20 ; Enable extended memory + mov bx,0ffffh ; Point to extended mem. + mov ds,bx ; as FFFF:0010 + mov si,10h + mov di,offset Mem_buffer + mov cx,400h / 2 ; 1k data block to test + rep movsw ; save extended memory + mov ax,5aa5h ; test pattern + mov es,bx ; point to extended mem. + mov cx,400h / 2 + mov di,10h + rep stosw ; store pattern in mem. + mov ax,_data + mov ds,ax + mov Loadall_tbl._AX,5aa5h + mov Loadall_tbl._CX,400h / 2 + mov Loadall_tbl._DI,0h + mov Loadall_tbl._SP,sp ; save SP + mov Loadall_tbl._IP,offset @F + mov Loadall_tbl.ES_Desc.A15_A00,00 + mov Loadall_tbl.ES_Desc.A23_A16,10 + LOADALL + +@@: repz scasw ; data match? + lahf ; get flags + mov bx,_Data + mov ds,bx + mov cx,0ffffh + mov es,cx + mov cx,400h / 2 + mov si,offset Mem_buffer + mov di,10h + rep movsw ; restore data + mov es,bx + mov cx,cs:stack_ptr[2] + mov ss,cx + FARJMP <@F>, +@@: sahf ; restore flags + jz @Test2_Pass + PRINT_STRING failed + jmp Loadall_RET + +@Test2_Pass: + PRINT_STRING passed + +;--------------------------------------------------------------- +; +; TEST3: Test that the Present bit gets loaded w/out exception, +; but when a segment is accessed INT13 get generated. +; +; If LOADALL works even remotely like we think it does, +; then this test will work in REAL MODE! And as this +; test was originally programmed, it did! However, I +; was doing my testing by emulating '286 LOADALL with +; '386 LOADALL, where I could use an ICE for debug +; purposes. The code worked on a '286, but failed on a +; '386! I found that the '386 fails to clear the +; Present bit in the descriptor cache register when a +; segment register is loaded in real mode. This is +; obviously a bug in the '386. Since the CPU is in a +; state that can never be duplicated under any program +; control, except by using LOADALL (Present=0), the bug +; will never be manifested in any production code. As a +; result, I reprogramed this example to use protected +; mode so it would work on both the '286 and '386. +; +; (1) Prepare GDT & IDT descriptor cache registers and +; descriptor tables, & segment selectors +; (2) Set protected mode bit, clear Present bit, set IP +; (3) Save the 8259 masks, set the PM return address, and set +; CMOS shutdown=5 +; (4) LOADALL +; (5) Generate the exception +; (6) Reset ES to a valid segment selector & save results of +; test. +; (7) Reset the CPU, restore 8259 masks, inhibit A20 from the +; CPU bus, restore segment registers to real mode values. +; (8) Verify the results +; +;--------------------------------------------------------------- +; Test Present bit: verify that P=0 in a descriptor cache +; register will, even in REAL MODE, will generate an exception +; 13 when trying to access memory +;--------------------------------------------------------------- +Test3: Print_String Test_3 + mov ax,_Data + mov es,ax + mov si,0 + call Calc_pm_address + mov DSEG2.Base_A15_A00,ax + mov DSEG2.Base_A23_A16,dl + add ax,offset GDT_286 + adc dl,0 + mov Loadall_tbl.GDT_Desc.A15_A00,ax + mov Loadall_tbl.GDT_Desc.A23_A16,dl + mov Loadall_tbl.GDT_Desc._Limit,GDT2_Len-1 + mov si,offset IDT_286 + call Calc_pm_address + mov Loadall_tbl.IDT_Desc.A15_A00,ax + mov Loadall_tbl.IDT_Desc.A23_A16,dl + mov Loadall_tbl.IDT_Desc._Limit,IDT2_Len-1 + mov ax,_TEXT + mov es,ax + mov si,0 + call Calc_pm_address + mov CSEG2.Base_A15_A00,ax + mov CSEG2.Base_A23_A16,dl + mov Loadall_tbl._CS,CSEG2-GDT_286 + + or Loadall_tbl._MSW,1 + and Loadall_tbl.ES_Desc._Type,7fh ; Clear P bit + mov Loadall_tbl._IP,offset @PM_286 ; Set IP + + Call Get_INT_Status ; save PIC masks + mov ax,offset @RM_286 ; save real mode return + Call SetPM_RET_addr ; address + Call Set_shutdown_type ; set shutdown in CMOS + + LOADALL + +@PM_286:mov al,es:[di][2] + + mov ax,DSEG2-GDT_286 + mov es,ax + mov ES:Results,di + jmp RESET_CPU + +@RM_286:mov ax,cs:stack_ptr[2] + mov ss,ax + mov sp,cs:stack_ptr + mov ax,_Data + mov ds,ax + mov es,ax + call Set_INT_Status + call Shut_A20 + + mov di,Results ; If an exception 13 was + test di,1 ; generated, then the + jnz @F ; low bit of DI is set + + + Print_String failed ; Test failed + jmp Loadall_RET + +@@: Print_String passed ; Test passed + jmp Loadall_RET +LOADALL_286 endp + + +;--------------------------------------------------------------- +; Minimal exception 13 handler that points past a 4-byte opcode, +; and sets the lowest bit in DI before returning. +;--------------------------------------------------------------- + INT13 label word + push bp + mov bp,sp + add word ptr [bp][4],4 + or di,1 + pop bp + add sp,2 + iret + + +;--------------------------------------------------------------- +; Include all the protected mode functions: +; RESET_CPU: Reset the CPU back to real mode +; SETPM_RET_ADDR: Put the PM return address @ 40:67 +; GET_INT_STATUS: Save the 8259 (PIC) masks. +; SET_INT_STATUS: Restore the 8259 (PIC) masks. +; SET_SHUTDOWN_TYPE: Set CMOS shutdown type 5 +; ENABLE_GATE20: Enable A20 to CPU bus +; SHUT_A20: Disable A20 from the CPU bus +; CALC_PM_ADDRESS: Calculate a 24-bit physical address +; SAVE_STATE: Save machine state before LOADALL +; RESTORE_STATE: Restore machine state after LOADALL +;--------------------------------------------------------------- + Include LOADFNS.286 + + + IFE USE_386 +;--------------------------------------------------------------- +; Include the CPU_TYPE procedure & LOADALL test +;--------------------------------------------------------------- + Include CPU_TYPE.ASM + ENDIF + +_text ends + + + stack segment para stack 'stack' + db 400h dup (0) + stack ends + + end LOADALL_286 + +;--------------------------------------------------------------- +; END LISTING 1 +;--------------------------------------------------------------- diff --git a/docs/x86/ops/LOADALL/386load.asm b/docs/x86/ops/LOADALL/386load.asm new file mode 100644 index 000000000..9fb379813 --- /dev/null +++ b/docs/x86/ops/LOADALL/386load.asm @@ -0,0 +1,1000 @@ + Page 60,132 +;--------------------------------------------------------------- +; BEGIN LISTING 2 +;--------------------------------------------------------------- +; +; 386LOAD.ASM +; +; 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 +; +;----------------------------------------------------------------------------- +; +; This program demonstrates various aspects of CPU +; behavior that become apparent when using LOADALL. +; +; Test 1: Checks that LOADALL loads all the general- +; purpose registers; loads the segment registers +; with values that are inconsistant to their +; respective descriptor cache registers. +; +; Test 2: Access extended memory in real mode. +; +; Test 3: Tests that the Present bit in a descriptor +; table can be loaded using LOADALL without +; generating exception 11. But when the segment +; is accessed, exception 13 is generated. +; NOTE: This test should be done in protected +; mode, but can be done in real mode. 1) In real +; mode, no error code is pushed on the stack +; (possibly due to a bug in the CPU). 2) Also, +; when this test is executed in real-mode, the +; '386 fails to set the Present bit when the +; segment is subsequently loaded. This latter +; condition is clearly a bug in the '386. +; +; Test 4: Test 32-bit protected mode. +; +; Test 5: Test 32-bit real mode -- a mode that is an +; illegal mode for the CPU. +; +; Test 6: Test that the Granularity bit in the descriptor +; cache register has no affect on the segment +; limit field. +; +; Test 7: Test execution breakpoints. +; +; Test 8: Test data breakpoints. +; +; This program was written for Microsoft MASM 5.1. +; This program contains compiler directives and branching +; techniques that might not be available on previous +; versions of the Macro Assembler, nor in competitive +; products. +; +;--------------------------------------------------------------- + +;--------------------------------------------------------------- +; Compiler directives +;--------------------------------------------------------------- + Title LOADALL_386 + .radix 16 + .8086 + + +;--------------------------------------------------------------- +; Interrupt vector segment +;--------------------------------------------------------------- +ABS0 segment at 0 + org 6*4 + INT_6 dd ? +ABS0 ends + + +;--------------------------------------------------------------- +; Structure definitions +;--------------------------------------------------------------- +Desc_cache STRUC + db 0 + _Type db ? + _CS32 db 0 + db 0 + _Addr dd ? + _Limit dd ? +Desc_cache ENDS + + +Loadall_struc STRUC + _Cr0 dd 0 + _Eflags dd 2 + _Eip dd 0 + _Edi dd 66666666h + _Esi dd 77777777h + _Ebp dd 55555555h + _Esp dd 88888888h + _Ebx dd 22222222h + _Edx dd 44444444h + _Ecx dd 33333333h + _Eax dd 11111111h + _Dr6 dd 0 + _Dr7 dd 0 + _Tr dd 0 + _Ldt dd 0 + _Gs dd 5555h + _Fs dd 4444h + _Ds dd 2222h + _Ss dd 6666h + _Cs dd 1111h + _Es dd 3333h + TSS_Desc dd 00008900h,00070000h,00000800h + IDT_Desc dd 00000000h,00000000h,000003ffh + Gdt_Desc dd 00000000h,00000000h,00000000h + Ldt_Desc dd 00008200h,00090000h,00000088h + GS_Desc dd 00009300h,00050000h,0000ffffh + FS_Desc dd 00009300h,00040000h,0000ffffh + DS_Desc dd 00009300h,00020000h,0000ffffh + SS_Desc dd 00009300h,00060000h,0000ffffh + CS_Desc dd 00009b00h,00000000h,0000ffffh + ES_Desc dd 00009300h,00030000h,00fffffch +Loadall_Struc ENDS + + +Descriptor STRUC + Seg_limit dw ? ; Segment limit + Base_A15_A00 dw ? ; A00..A15 of base address + Base_A23_A16 db ? ; A16..A23 of base address + Access_rights db ? ; Segment access rights + Limit_A19_A16 db ? ; Granularity, Op-size, + ; Limit A16..A19 + Base_A31_A24 db ? ; A24..A31 of base address +Descriptor ENDS + + +INT_Desc STRUC + IGate_Offset dw ? ; Offset of handler + CSEG_Sel dw ? ; Code segment selector + db 0 + db 86h ; 286 interrupt gate=16bit + ; CS:IP, FLAGS + Resvd dw 0 ; Reserved=0 +INT_Desc ENDS + + +;--------------------------------------------------------------- +; Macro definitions in MACROS.386: +; INIT_DESCRIPTOR: Given a segment, offset, and descriptor +; name, calculate the 24-bit physical +; address, and store it in the descriptor. +; FARJMP: Far JUMP since MASM doesn't assemble it. +; LONGJMP: 32-bit FAR JUMP similar to above. +; IO_DELAY: Put your favorite I/O delay macro here. +; LOADALL: Copy the LOADALL memory image down to +; 0:800 and execute a '286 LOADALL. +; PRINT_STRING: Given a variable name, use the DOS +; print string command to send it to the +; screen. +;--------------------------------------------------------------- + Include MACROS.386 + + + _DATA SEGMENT PARA PUBLIC 'DATA' +;--------------------------------------------------------------- +; Equates & local variables +;--------------------------------------------------------------- +; Protected mode access rights +;--------------------------------------------------------------- + CS_access equ 10011011b + DS_access equ 10010011b + +;--------------------------------------------------------------- +; Text equates +;--------------------------------------------------------------- + CRLF equ <0dh,0ah> + CRLF$ equ + INT6 equ [bp-4] + +;--------------------------------------------------------------- +; Loadall table(s) +;--------------------------------------------------------------- + Loadall_tbl Loadall_struc <> + Machine_State Loadall_struc <> + +;--------------------------------------------------------------- +; Global Descriptor Table +;--------------------------------------------------------------- + GDT_386 Descriptor + CSEG3 Descriptor <0ffffh,0,0,CS_access> + DSEG3 Descriptor <0ffffh,0,20h,DS_access> + Gdt3_len equ $-Gdt_386 + +;--------------------------------------------------------------- +; Interrupt Descriptor Table +;--------------------------------------------------------------- +IDT_386 INT_Desc ; INT00 + INT_Desc ; INT01 + INT_Desc ; INT02 + INT_Desc ; INT03 + INT_Desc ; INT04 + INT_Desc ; INT05 + INT_Desc ; INT06 + INT_Desc ; INT07 + INT_Desc ; INT08 + INT_Desc ; INT09 + INT_Desc ; INT0a + INT_Desc ; INT0b + INT_Desc ; INT0c + INT_Desc ; INT0d +IDT3_Len equ $-IDT_386 + +;--------------------------------------------------------------- +; Misc. local variables +;--------------------------------------------------------------- + Mem_buffer db 400h dup (0) ; Store 2M mem. + Buffer db 40h dup (0) + Buffer2 dw 10h dup (0) + + RM_IDT3_Ptr dw (256d*4)-1 ; Real-mode IDT + dd 0 ; pointer + dw 0 + + +;--------------------------------------------------------------- +; String Messages +;--------------------------------------------------------------- +Passed db " PASSED.",CRLF$ +Failed db "--> FAILED <--",CRLF$ +Not_386 db "Not 80386 class computer.",CRLF$ +Rmvd db "LOADALL removed from 80386 mask.",CRLF$ +RFail db "Registers weren't loaded correctly." +LF db CRLF$ + +;--------------------------------------------------------------- +; I'm doing this wierd string definition technique to limit the +; page width to 64 characters. +;--------------------------------------------------------------- +Test_1 label word +db "Test 1: Testing 386 LOADALL instruction: ",24 + +Test_2 label word +db "Test 2: Testing extended memory in real mode: ",24 + +Test_3 label word +db "Test 3: Testing Present BIT in descriptor: ",24 + +Test_4 label word +db "Test 4: Testing 32-bit protected mode: ",24 + +Test_5 label word +db "Test 5: Testing 32-bit real mode: ",24 + +Test_6 label word +db "Test 6: Testing Granularity BIT: ",24 + +Test_7 label word +db "Test 7: Testing Execution breakpoints: ",24 + +Test_8 label word +db "Test 8: Testing byte, write, data breakpoints: ",24 + +_DATA ENDS + + + _TEXT SEGMENT PARA PUBLIC 'CODE' + ASSUME CS:_TEXT, ds:_DATA, ES:_DATA, SS:STACK + .386P +;--------------------------------------------------------------- +; A little CS-relative data for the stack pointer. This is +; to avoid using other kludge techniques, caused by using +; LOADALL, that make using the data segment undesirable. +;--------------------------------------------------------------- + Stack_ptr dd 0 + dw 0 + +;--------------------------------------------------------------- + LOADALL_386 proc far +;--------------------------------------------------------------- + PUSH DS ; Setup the stack to + XOR AX,AX ; return to DOS + PUSH AX + + MOV AX,_Data + MOV DS,AX + MOV ES,AX + +;--------------------------------------------------------------- +; Check CPU type +;--------------------------------------------------------------- + Call CPU_Type ; 386, 486? + cmp ax,3 ; 386? + je short @F ; yep + Print_String LF + Print_String Not_386 + retf ; go split + +@@: enter 4,0 ; create stack frame + mov word ptr INT6,offset INT6_handler + mov INT6+2,cs + call set_INT6_vector ; set our INT6 handler + cli + Call Save_State + Print_String LF + Print_String Test_1 + Init_descriptor ,,Gdt_386 + Init_descriptor cs, 0,CSEG3 + +;--------------------------------------------------------------- +; +; TEST1: 16-bit Real mode +; Test general purpose registers +; Test Segment registers +; Test Descriptor cache base address +; +; (1) Setup LOADALL structures, and pointers +; (2) Execute LOADALL +; (3) Verify results of the test +; +;--------------------------------------------------------------- + mov eax,cs ; Prepare a 32-bit + shl eax,4 ; physical address that + ; is put in the LOADALL + ; CS descriptor cache. + mov Loadall_tbl.CS_Desc._Addr,eax + + mov eax,cr0 ; Initialize CR0 in the + and eax,0fffffff0h ; LOADALL data table + mov Loadall_tbl._CR0,eax ; DR6, DR7, EIP + mov eax,dr6 + mov ebx,dr7 + mov Loadall_tbl._DR6,eax + mov Loadall_tbl._DR7,ebx + mov Loadall_tbl._EIP,offset Verify_State + mov dword ptr cs:stack_ptr,esp ; save SS:ESP + mov word ptr cs:stack_ptr[4],ss + mov edi,offset loadall_tbl + LOADALL + nop ; If LOADALL is removed + Print_String failed ; from the CPU mask, + Print_String Rmvd ; then fall through + ; to here. +Loadall_RET: + call Restore_state + call set_int6_vector + leave + retf + +;--------------------------------------------------------------- + Verify_State: ; Verify that LOADALL worked +;--------------------------------------------------------------- +; This is where we land for the first test of '386 LOADALL. +; The purpose of this test is to verify that all the general +; purpose registers get loaded correctly. Specifically, we are +; testing to verify that all segment registers contain values +; that don't correspond to the memory addresses they appear to +; be pointing to. In other words, we are checking that the +; that the segment registers have one value, while their +; associated hidden descriptor cache registers have different +; values. +;--------------------------------------------------------------- + cmp eax,11111111h ; Test EAX + jne @F + cmp ebx,22222222h ; Test EBX + jne @F + cmp ecx,33333333h ; Test ECX + jne @F + cmp edx,44444444h ; Test EDX + jne @F + cmp ebp,55555555h ; Test EBP + jne @F + cmp edi,66666666h ; Test EDI + jne @F + cmp esi,77777777h ; Test ESI + jne @F + cmp esp,88888888h ; Test ESP + jne short @F + mov ax,cs ; Test CS + cmp ax,1111h + jne short @F + mov ax,ds ; Test DS + cmp ax,2222h + jne short @F + mov ax,es ; Test ES + cmp ax,3333h + jne short @F + mov ax,fs ; Test FS + cmp ax,4444h + jne short @F + mov ax,gs ; Test GS + cmp ax,5555h + jne short @F + mov ax,ss ; Test SS + cmp ax,6666h + jne short @F + cmp dword ptr ds:[0],02020202h ; Test DS Desc Cache + jne short @F + cmp dword ptr es:[0],03030303h ; Test ES Desc Cache + jne short @F + cmp dword ptr fs:[0],04040404h ; Test FS Desc Cache + jne short @F + cmp dword ptr gs:[0],05050505h ; Test GS Desc Cache + jne short @F + cmp dword ptr ss:[0],06060606h ; Test SS Desc Cache + jne short @F + mov ax,_Data ; Reset segment regs. + mov ds,ax + mov es,ax + lss esp,fword ptr cs:stack_ptr ; Reset SS:ESP + FARJMP , ; Continue + +;--------------------------------------------------------------- +; Loadall failed the REGISTERs test. +;--------------------------------------------------------------- +@@: mov ax,_Data + mov ds,ax + mov es,ax + lss esp,fword ptr cs:stack_ptr + FARJMP <@F>, +@@: Print_String failed + Print_String RFail + jmp loadall_ret + +;--------------------------------------------------------------- +; LOADALL passed +;--------------------------------------------------------------- +Loadall_test: + Print_String passed + +;--------------------------------------------------------------- +; +; TEST2: Access extended memory while in real mode (@ 2M). +; +; (1) Fill in LOADALL structure with "reasonable" values +; (2) Save contents of extended memory +; (3) Write data pattern in extended memory +; (4) Set LOADALL registers used by this test +; (5) LOADALL +; (6) Verify results +; (7) Restore original data in extended memory +; +;--------------------------------------------------------------- +; In this test, I'll access extended memory while in real mode. +; I'll assume the computer has at least 2M of memory. By +; assuming 2M, I don't need to enable A20 on the CPU bus, since +; memory @ 2M doesn't assert A20. +;--------------------------------------------------------------- +; Fill LOADALL structure with more reasonable values. +;--------------------------------------------------------------- + mov Loadall_tbl._EAX,0 + mov Loadall_tbl._EBX,0 + mov Loadall_tbl._ECX,0 + mov Loadall_tbl._EDX,0 + mov Loadall_tbl._EBP,0 + mov Loadall_tbl._ESP,esp + mov Loadall_tbl._CS,cs + mov Loadall_tbl._DS,ds + mov Loadall_tbl._ES,es + mov Loadall_tbl._FS,8000h + mov Loadall_tbl._GS,8000h + mov Loadall_tbl._SS,ss + +;--------------------------------------------------------------- +; Load segment descriptor cache registers: +; DS=ES = _DATA segment +; FS=GS = 80000h (8000:0) +; SS = STACK segment +;--------------------------------------------------------------- + mov ax,ds + movzx eax,ax + shl eax,4 + mov bx,ss + movzx ebx,bx + shl ebx,4 + mov Loadall_tbl.DS_Desc._addr,eax + mov Loadall_tbl.ES_Desc._addr,eax + mov Loadall_tbl.FS_Desc._addr,80000h; + mov Loadall_tbl.GS_Desc._addr,80000h + mov Loadall_tbl.SS_Desc._addr,ebx + +;--------------------------------------------------------------- +; Slip into protected mode to save the contents of memory @ 2M, +; and write a test pattern into that memory. +;--------------------------------------------------------------- + Print_String Test_2 + lgdt fword ptr Gdt_386 ; Load the GDT + mov ebx,cr0 ; enter protected mode + or bl,1 + mov cr0,ebx + FARJMP <@F>, + +@@: mov dx,DSEG3-Gdt_386 ; Get segment selector + mov ds,dx ; for DS @ 2M + mov cx,400h / 4 + mov si,0 + mov di,offset Mem_buffer + rep movsd ; Save memory + mov eax,5aa5aa5ah ; Test pattern + mov cx,400h / 4 + mov di,0 + mov es,dx ; ES = 2M + rep stosd ; Store test pattern + and bl,not 1 ; exit protected mdoe + mov cr0,ebx + FARJMP <@F>,<_TEXT> + +;--------------------------------------------------------------- +; Set LOADALL-image registers used by this test +;--------------------------------------------------------------- +@@: mov ax,_data + mov ds,ax + mov es,ax + mov Loadall_tbl._EAX,5aa5aa5ah ; Test pattern + mov Loadall_tbl._ECX,400h / 4 ; # of DWORDS + mov Loadall_tbl._ESI,offset Mem_buffer + mov Loadall_tbl._EDI,0h ; ES:0 + mov Loadall_tbl._EIP,offset @F ; EIP + mov Loadall_tbl.ES_Desc._Addr,200000h ; 2M + mov edi,offset loadall_tbl + LOADALL + +;--------------------------------------------------------------- +; Check memory for a match of the pattern +;--------------------------------------------------------------- +@@: repz scasd ; data match? + mov bx,_Data ; ES still points to 2M, + mov ds,bx ; so I can reset DS and + mov cx,400h / 4 ; restore the original + mov di,0 ; contents @ 2M without + rep movsd ; changing ES. + mov es,bx ; Set ES to real mode + lss esp,fword ptr cs:stack_ptr ; Restore SS:ESP + FARJMP <@F>,<_TEXT> ; Must jump to R/W CS +@@: jz short @Test2_Pass + + PRINT_STRING failed + jmp short @Test3 + +@Test2_Pass: + PRINT_STRING passed + +;--------------------------------------------------------------- +; +; TEST3: Test that the Present bit gets loaded w/out exception, +; but when a segment is accessed INT13 get generated. +; +; (1) Load GDT & IDT pointers into LOADALL table +; (2) Set PM bit, CS selector, EIP offset, clear P bit +; (3) LOADALL +; (4) Verify Results +; +;----------------------------------------------------------------------------- +@Test3: Print_String Test_3 + +;--------------------------------------------------------------- +; Initialize the GDT & IDT descriptor cache +;--------------------------------------------------------------- + mov eax,Loadall_tbl.DS_Desc._Addr + mov ebx,eax + mov Loadall_tbl.ES_Desc._Addr,eax + add eax,offset Gdt_386 + add ebx,offset Idt_386 + mov Loadall_tbl.GDT_Desc._Addr,eax + mov Loadall_tbl.GDT_Desc._Limit,Gdt3_len-1 + mov Loadall_tbl.Idt_Desc._Addr,ebx + mov Loadall_tbl.Idt_Desc._Limit,Idt3_len-1 + + or Loadall_tbl._CR0,1 ; set PM bit + mov Loadall_tbl._ESI,0 + mov Loadall_tbl._CS,CSEG3-Gdt_386 ; CS selector + mov Loadall_tbl._EIP,offset @Test_Present + and Loadall_tbl.GS_Desc._Type,7fh ; clear Present + mov edi,offset loadall_tbl ; bit in GS + LOADALL + +@Test_Present: + mov si,gs:[si][2] ; choose this because + ; it's a 4-byte instr. + Lidt fword ptr RM_IDT3_Ptr ; Restore real-mode IDT + mov eax,cr0 ; Exit protected mode. + and al,not 1 + mov cr0,eax + FARJMP <@F>,<_TEXT> ; Return to R/W, real- + ; mode code segment + +@@: test si,1 ; pass test? + jnz short @F ; yep + Print_String failed + jmp short @Test4 + +@@: Print_String passed + +;--------------------------------------------------------------- +; +; TEST4: Test 32-bit Protected Mode operation +; +; (1) Set LOADALL operand size, PM bits, and EIP offset +; (2) LOADALL +; (3) Verify Results +; +;--------------------------------------------------------------- +@Test4: Print_String Test_4 + +;--------------------------------------------------------------- +; Perform 32-bit protected mode test +;--------------------------------------------------------------- + or Loadall_tbl.CS_Desc._CS32,40h ; CS32 bit + mov Loadall_tbl._EDI,offset Loadall_tbl + mov Loadall_tbl._EIP,offset PM32 + LOADALL + +;--------------------------------------------------------------- +; This test uses a simple technique to determine if we are in +; 32-bit mode or 16-bit mode: +; +; In 16-bit mode, this code will be executed as: +; mov si,1234h +; nop +; nop +; +; In 32-bit mode, this code will be executed as: +; mov esi,90901234h ; The two NOP's are absorbed +; ; into the 32-bit operand. +; +;--------------------------------------------------------------- +;--------------------------------------------------------------- +; In 16-bit mode, this code will be executed as: +; mov di,1234h +; nop +; nop +; +; In 32-bit mode, this code will be executed as: +; mov edi,90901234h +;--------------------------------------------------------------- +PM32: mov si,1234h + nop + nop + +;--------------------------------------------------------------- +; Now, we need to exit 32-bit mode gracefully. In order to do +; that, we need code that will generate predictable results in +; both 32-bit, and 16-bit mode. If we are in 32-bit mode, then +; the following compiled code will behave as documented under +; the '32-bit mode' column. If we failed to enter 32-bit mode, +; then the following compiled code will behave as documented +; under the '16-bit mode' column. In order to exit gracefully, +; we need to know which mode we are in! Hence the following +; code to detect it!: +; +; 16-bit mode 32-bit mode +; push ax push eax +; mov ax,si mov eax,esi +; shr ax,10h shr eax,10h ; AX=9090 if in 32-bit +; ; AX=0 if in 16-bit +; +; cmp al,90h cmp al,90h ; PASS=32-bit, FAIL=16-bit +; pushf pushf ; save results for later +; shl ax,10h shl eax,10h ; EAX=90900000 if in 32-bit +; mov si,ax mov esi,eax ; ESI=90900000 if in 32-bit +; ; ESI=66660000 if in 16-bit +; popf popf ; restore ZF +; pop ax pop eax +; +; So, the result of this code is to exit 32-bit mode if we got +; there, and to keep going in 16-bit mode if we didn't. +;--------------------------------------------------------------- + push ax ; See the above + mov ax,si ; explanation on how + shr ax,10h ; this code works + cmp al,90h + pushf + shl ax,10h + mov si,ax + popf + pop ax + jne short @No_PM32bitCS + or si,1 ; set SI if 32-bit mode + +;--------------------------------------------------------------- +; 32-bit JUMP instruction, to transfer control back to a 16-bit +; segment +;--------------------------------------------------------------- + LONGJMP <@F>, ; Construct 32-bit far + ; JMP + +@No_PM32bitCS: ; FAR JUMP if stuck in + FARJMP <@F>, ; 16-bit mode. + +@@: Lidt fword ptr RM_IDT3_Ptr ; Restore real-mode IDT + mov eax,cr0 ; Exit protected mode. + and al,not 1 + mov cr0,eax + FARJMP <@F>,<_TEXT> ; Jump to real-mode + ; code segment +@@: mov ax,_Data ; Restore real-mode + mov ds,ax ; segment registers + mov es,ax + test si,1 ; 32-bit mode passed? + jnz short @F ; yep + Print_String failed + jmp short @Test5 + +@@: Print_String passed + +;--------------------------------------------------------------- +; +; TEST5: Test 32-bit real-mode operation +; +; (1) Clear operand size, PM bits, and set EIP offset +; (2) LOADALL +; (3) Verify Results +; (4) Get the h&*@! out of 32-bit real-mode +; +;--------------------------------------------------------------- +; Test 32-bit real-mode operation. Make sure we can put the +; processor in an illegal state: 32-bit real-mode. +;--------------------------------------------------------------- +@Test5: Print_String Test_5 + and Loadall_tbl._CR0,not 1 ; disable PM bit + and Loadall_tbl.CS_Desc._Type,not 8 ; make CS R/W + ; Data segment + mov Loadall_tbl._EIP,offset RM32 ; Load EIP + LOADALL + +;--------------------------------------------------------------- +; This test uses the exact same technique documented in TEST4. +; See TEST4 for an explanation of these next two code sections. +;--------------------------------------------------------------- +RM32: mov si,1234h + nop + nop + +;--------------------------------------------------------------- +; See TEST4 for an explanation of this code section. +;--------------------------------------------------------------- + push ax ; See the above + mov ax,si ; explanation on how + shr ax,10h ; this code works + cmp al,90h + pushf + shl ax,10h + mov si,ax + popf + pop ax + +;--------------------------------------------------------------- +; Now getting out of 32-bit real mode is a bit more complicated +; than you may think. According to Intel, the internal +; descriptor cache registers get re-loaded with default values +; each time the segment is loaded. But the operand size bit in +; the CS descriptor cache doesn't get cleared in a long jump. +; So, to program around this, I need to either execute LOADALL +; again, or go to protected mode, jump to a 16-bit code segment, +; then go back to real mode. I think I will do the latter. +;--------------------------------------------------------------- + jne short @RM32_Fail ; Do something else + mov eax,cr0 ; Enter protected mode + or al,1 + mov cr0,eax + LONGJMP <@F>, ; To 16-bit CS + +@@: Lidt fword ptr RM_IDT3_Ptr ; Reload real-mode IDT + and al,not 1 ; Exit protected mode + mov cr0,eax + FARJMP <@RM32_Pass>,; Back to real-mode CS + +@RM32_Fail: + Print_String failed + jmp short @Test6 + +@RM32_Pass: + mov ax,_Data ; Reload real-mode + mov ds,ax ; segment registers + mov es,ax + Print_String passed + +;--------------------------------------------------------------- +; +; TEST6: Test Granularity bit. Test that the granularity bit +; in the descriptor cache has no effect on the limit +; field of the descriptor cache. This is a three-part +; test. First, by setting G=1 in a segment descriptor +; cache whose limit=64k should cause an exception. +; Second, ES_LIMIT=16M-4. This LIMIT can't ever be +; generated under program control. So we simply need +; to access memory @ 16M-8 to verify this test. If +; an exception gets generated, then the test failed. +; Third, try to access memory @ 16M-4. If an exception +; ISN'T generated, then the test failed. +; +; (1) Set Present, Granularity bits, and EIP offset +; (2) LOADALL +; (3) Verify results +; +;--------------------------------------------------------------- +; Test Granularity bit: Test that G=1 has no effect in the +; descriptor cache register. In the GS descriptor cache, I set +; the limit=64k. If G=1 has any effect on this field, then the +; following memory access will pass. We want it to fail, and +; generate an exception-13. +;--------------------------------------------------------------- +@Test6: Print_String Test_6 + or Loadall_tbl._CR0,1 ; set PM bit + or Loadall_tbl.GS_Desc._Type,80h ; set P=1 + or Loadall_tbl.GS_Desc._CS32,80h ; set G=1 + and Loadall_tbl.CS_Desc._CS32,0bfh ; clear CS32 bit + mov Loadall_tbl._EIP,offset @Test_Gran + LOADALL + +@Test_Gran: + mov esi,10000h ; should generate exc. + mov si,gs:[esi] + shl si,1 ; save results + mov esi,0fffff8h ; 16M-8 + mov si,es:[esi] ; shouldn't generate exc + shl si,1 + mov esi,0fffffch ; 16M-4 + mov si,es:[esi] ; should generate exc. + add esi,4 + Lidt fword ptr RM_IDT3_Ptr ; Restore real-mode IDT + mov eax,cr0 + and al,not 1 + mov cr0,eax + FARJMP <@F>,<_TEXT> + +@@: and si,7 + cmp si,5 ; pass test? + jnz short @F ; yep + Print_String failed + jmp short @Test7 + +@@: Print_String passed + +;--------------------------------------------------------------- +; The following two expamples show how to use the debug +; registers to generate execution and data break points. They +; are included in this program because they use LOADALL to set +; DR7. Forgive the fact that they are poorly documented. +;--------------------------------------------------------------- +; +; TEST7: Test execution breakpoints through debug registers. +; +; (1) Clear granularity bit, set ES_LIMIT=64k, set EIP offset +; (2) Set breakpoint qualifiers +; (3) LOADALL +; (4) Generate execution breakpoints +; (5) Verify results +; +;--------------------------------------------------------------- +@Test7: Print_String Test_7 + and Loadall_tbl.GS_Desc._CS32,7fh ; set G=0 + mov Loadall_tbl.ES_Desc._Limit,0ffffh; limit=64k + mov Loadall_tbl._EIP,offset Test_DR0 + +;--------------------------------------------------------------- +; Set a series of execution break points in the debug registers. +;--------------------------------------------------------------- + mov bx,cs + movzx ebx,bx + shl ebx,4 + lea eax,[ebx][dword ptr Test_Dr0] + mov dr0,eax + lea eax,[ebx][dword ptr Test_DR1] + mov dr1,eax + lea eax,[ebx][dword ptr Test_DR2] + mov dr2,eax + lea eax,[ebx][dword ptr Test_DR3] + mov dr3,eax + mov Loadall_tbl._DR7,0aah ; enable all code + ; breakpoints + LOADALL + +Test_DR0: + nop +Test_DR1: + nop +Test_DR2: + nop +Test_DR3: + nop + + Lidt fword ptr RM_IDT3_Ptr ; Restore real-mode IDT + mov eax,cr0 ; exit protected mode + and al,not 1 + mov cr0,eax + FARJMP <@F>, + +@@: and si,0fh + cmp si,0fh ; pass all breakpoints? + je short @F ; yep + Print_String failed + jmp @Test8 + +@@: Print_String passed + +;--------------------------------------------------------------- +; +; TEST8: Test byte-size data write breakpoints +; +; (1) Set EIP offset +; (2) Set breakpoint qualifiers +; (3) LOADALL +; (4) Generate data breakpoints +; (5) Verify results +; +;--------------------------------------------------------------- +@Test8: Print_String Test_8 + mov Loadall_tbl._EAX,55h + mov Loadall_tbl._ECX,40h + mov Loadall_tbl._EDI,offset Buffer + mov Loadall_tbl._EIP,offset @Test_DRBW + + mov bx,ds + movzx ebx,bx + shl ebx,4 + lea eax,[ebx][Dword ptr Buffer][3] + mov dr0,eax + add eax,10h + mov dr1,eax + add eax,10h + mov dr2,eax + add eax,10h + mov dr3,eax + mov Loadall_Tbl._DR7,111102aah + LOADALL + +@Test_DRBW: + rep stosb + Lidt fword ptr RM_IDT3_Ptr + mov ebx,cr0 + and bl,not 1 + mov cr0,ebx + FARJMP <@F>, + +@@: and si,0fh + cmp si,0fh ; pass all breakpoints? + je short @T7P ; yep + Print_String failed + jmp @Test9 + +@T7P: cmp dx,4 ; INT01 4 times? + jne @B + Print_String passed + +@Test9: + jmp Loadall_ret + + +LOADALL_386 endp + + +;--------------------------------------------------------------- +; Minimal exception 13 handler that points past a 4-byte opcode, +; and sets the lowest bit in DI before returning. +;--------------------------------------------------------------- + INT13 label word + push bp + mov bp,sp + add word ptr [bp][4],4 + or si,1 + pop bp + add sp,2 + iret + + +;--------------------------------------------------------------- +; Include all the protected mode functions: +; INT01: Breakpoint interrupt for debug register +; breakpoints. +; SAVE_STATE: Save machine state before LOADALL +; RESTORE_STATE: Restore machine state after LOADALL +;--------------------------------------------------------------- + Include LOADFNS.386 + + +;--------------------------------------------------------------- +; Include the CPU_TYPE procedure & LOADALL test +;--------------------------------------------------------------- + Include CPU_TYPE.ASM + +_text ends + + + stack segment para stack 'stack' + db 400h dup (0) + stack ends + + end LOADALL_386 + +;--------------------------------------------------------------- +; END LISTING 2 +;--------------------------------------------------------------- diff --git a/docs/x86/ops/LOADALL/README.md b/docs/x86/ops/LOADALL/README.md index 1b00670fe..ca17a2aa7 100644 --- a/docs/x86/ops/LOADALL/README.md +++ b/docs/x86/ops/LOADALL/README.md @@ -226,3 +226,15 @@ From [http://www.rcollins.org/secrets/opcodes/LOADALL.html](http://www.rcollins. ; the access rights as a Read/Write/Data segment. This will ; even work in protected mode. ;--------------------------------------------------------------------- + +The following related files were saved on February 16, 2015 from [http://www.rcollins.org](http://www.rcollins.org/): + +* [The LOADALL Instruction](tspec_a3_doc.html) +* [286LOAD.ASM](286load.asm) +* [386LOAD.ASM](386load.asm) +* [CPU_TYPE.ASM](cpu_type.asm) +* [EMULOAD.ASM](emuload.asm) +* [LOADFNS.286](loadfns.286.asm) +* [LOADFNS.386](loadfns.386.asm) +* [MACROS.286](macros.286.asm) +* [MACROS.386](macros.386.asm) diff --git a/docs/x86/ops/LOADALL/cpu_type.asm b/docs/x86/ops/LOADALL/cpu_type.asm new file mode 100644 index 000000000..5b9ff7992 --- /dev/null +++ b/docs/x86/ops/LOADALL/cpu_type.asm @@ -0,0 +1,203 @@ + .386p +;----------------------------------------------------------------------------- +; +; CPU_TYPE.ASM +; +; 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 +; +;----------------------------------------------------------------------------- + + +;---------------------------------------------------------------; +; CPU_Type determines the CPU type in the system. ; +;---------------------------------------------------------------; +; Written by: ; +; Robert Collins ; +;---------------------------------------------------------------; +; Input: None ; +; Output: AX = CPU type ; +; 0 = 8086/8088 ; +; 1 = 80186/80188 ; +; 2 = 80286 ; +; 3 = 80386 ; +; 4 = 80486 ; +; FFFF = Unknown CPU type ; +; Register(s) modified: AX, BX, CX, EDX ; +;---------------------------------------------------------------; +; Macro definitions ; +;---------------------------------------------------------------; +; 80486 instruction macro -- because MASM 5.1 doesn't support ; +; the 80486! ; +;---------------------------------------------------------------; +XADD macro ; + db 0fh,0C0h,0D2h ; 80486 instruction macro ; +ENDM ; + ; + ; +;---------------------------------------------------------------; + CPU_Type proc near ; +;---------------------------------------------------------------; +; Determine the CPU type by testing for differences in the CPU ; +; in the system. ; +;---------------------------------------------------------------; +; To determine if we are a 8086/8088, or 80186/80188, test the +; value of SP after it is placed on the stack. The algorithm +; for "PUSH SP" differs from 8086/80186 to 80286+. The +; algorithm difference is as follows: +; +; 8086/80186 80286+ +; { { +; SP = SP - 2 TEMP = SP +; SS:SP = SP SP = SP - 2 +; } SS:SP = TEMP +; } +; +; Thus for the 8086/80186, the value of SP that gets pushed on +; the stack is the value after SP is decremented. Hence, the +; value on the stack does not reflect the value of SP before the +; "PUSH" instruction. Therefore, all we have to do to +; categorize the CPU as 8086/8088 or 80186/80188 is to "PUSH SP" +; and compare the value on the stack image to the value in SP. +;--------------------------------------------------------------- + xor ax,ax ; clear CPU type return register + push sp ; save SP on stack to look at + pop bx ; get SP saved on stack + cmp bx,sp ; if 8086/8088 these values will + ; differ + jz short @Not_8086 ; nope, must be other CPU type + +;--------------------------------------------------------------- +; If this test passes, then we need some other means to differ- +; entiate between 8088/8088 and 80186/80188. This method I will +; use comes from "80186/188, 80C186/C188 Hardware Reference +; Manual" from Intel, PN# 270788, page A-2: "When a word write +; is performed at offset FFFFh in a segment, the 8086 will write +; one byte at offset FFFFh, and the other at offset 0, while an +; 80186 family processor will write one byte at offset FFFFh, +; and the other at offset 10000h (one byte beyond the end of the +; segment). +;--------------------------------------------------------------- +; Before we can blast a value out to FFFFh, we must save +; anything there, so we don't crash anybody else's data. +;--------------------------------------------------------------- + push es + mov bx,ds ; get original DS + inc bx + mov es,bx + mov bl,ds:[0] ; get byte @ 0 + mov bh,es:[0fff0h] ; get byte @ 10000h + mov ds:[0ffffh],0aaaah ; write signature at + ; test location + cmp byte ptr ds:[0],0aah ; 8086? + mov ds:[0],bl ; restore original value + mov es:[0fff0h],bh + pop es + je short CPU_8086_Exit + inc ax + jmp short CPU_8086_Exit + +;--------------------------------------------------------------- +; When we get here, we know that we aren't a 8086/80186. And +; since all subsequent processors will trap invalid opcodes via +; INT6, we will determine which CPU we are by trapping an +; invalid opcode. +; We are an 80486 if: XADD DX,DX executes correctly +; 80386 if: MOV EDX,CR0 executes correctly +; 80286 if: SMSW DX executes correctly +;--------------------------------------------------------------- +; Setup INT6 handler +;--------------------------------------------------------------- +@Not_8086: + enter 4,0 ; create stack frame + mov word ptr INT6,offset INT6_handler + mov INT6+2,cs + call set_INT6_vector ; set pointer for INT6 handler + mov ax,4 ; initialize CPU flag=4 (80486) + xor cx,cx ; initialize semaphore + +;--------------------------------------------------------------- +; Now, try and determine which CPU we are by executing invalid +; opcodes. The instructions I chose to invoke invalid opcodes, +; are themselves rather benign. In each case, the chosen +; instruction modifies the DX register, and nothing else. No +; system parameters are changed, e.g. protected mode, or other +; CPU dependant features. +;--------------------------------------------------------------- +; The 80486 instruction 'XADD' xchanges the registers, then adds +; them. The exact syntax for a '486 compiler would be: +; XADD DX,DX. +;--------------------------------------------------------------- + XADD ;DX,DX ; 80486 + jcxz CPU_exit + dec ax ; set 80386 semaphore + inc cx ; CX=0 + +;--------------------------------------------------------------- +; For a description on the effects of the following instructions, +; look in the Intel Programmers Reference Manual's for the 80186, +; 80286, or 80386. +;--------------------------------------------------------------- + mov edx,cr0 ; 80386 + jcxz CPU_exit + dec ax ; set 80286 semaphore + inc cx ; CX=0 + + smsw dx ; 80286 + jcxz CPU_exit + sub ax,3 ; set UNKNOWN_CPU semaphore + +CPU_exit: + call set_INT6_vector + leave + +CPU_8086_exit: + ret + + +;--------------------------------------------------------------- +; Set the INT6 vector by exchanging it with the one currently on +; the stack. +;--------------------------------------------------------------- +set_INT6_vector: + push ds + push ABS0 ; save interrupt vector segment + pop ds ; make DS=INT vector segment + +ASSUME DS:ABS0 + mov dx,word ptr ds:INT_6 ; get offset of INT6 + xchg INT6,dx ; set new INT6 offset + mov word ptr ds:INT_6,dx + mov dx,word ptr ds:INT_6[2] ; get segment of INT6 + xchg INT6+2,dx ; set new INT6 segment + mov word ptr ds:INT_6[2],dx + pop ds ; restore register + ret ; split +ASSUME DS:_TEXT + + +;--------------------------------------------------------------- +; INT6 handler sets a semaphore (CX=FFFF) and adjusts the return +; address to point past the invalid opcode. +; [BP] +;--------------------------------------------------------------- +INT6_handler: + enter 0,0 ; create new stack frame + dec cx ; make CX=FFFF + add word ptr ss:[bp][2],3 ; point past invalid + ; opcode + leave + iret +CPU_Type endp diff --git a/docs/x86/ops/LOADALL/emuload.asm b/docs/x86/ops/LOADALL/emuload.asm new file mode 100644 index 000000000..35695e314 --- /dev/null +++ b/docs/x86/ops/LOADALL/emuload.asm @@ -0,0 +1,648 @@ + Page 60,132 +;----------------------------------------------------------------------------- +; BEGIN LISTING 3 +;----------------------------------------------------------------------------- +; +; EMULOAD.ASM +; +; 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 +; +;----------------------------------------------------------------------------- +; +; This utility uses '386 LOADALL to emulate '286 LOADALL. +; All 16-bit registers are zero-extended to 32-bit +; registers. All 24-bit physical addresses are zero- +; extended to 32-bit registers. '386-specific registers +; not used in '286 LOADALL are either set to the current +; values (Debug registers), or zeroed (segment registers). +; +;--------------------------------------------------------------- +; +; This program assumes that you have run the '386 LOADALL +; test prior to installing this TSR. Obviously if LOADALL +; has been removed from the '386 mask, then this program +; will never work. Likewise, it is easier for me to +; document the need to run the LOADALL test program, than +; to incorporate it into this code. +; +;--------------------------------------------------------------- +; +; EMULOAD returns ERROR codes to DOS that can be +; intecepted by the batch file command 'IF ERRORLEVEL'. +; The following ERRORLEVEL codes are generated by this +; program: +; 0 = EMULOAD driver now installed in memory +; 1 = Attempted removal of the EMULOAD driver from +; memory failed because EMULOAD was not in already +; in memory. +; 2 = The EMULOAD driver was already in memory when an +; attempt was made to install it again. +; 3 = Bogus command line argument(s). +; 4 = Help requested. +; 5 = The EMULOAD driver was sucessfully removed from +; memory. +; 6 = Can't install the EMULOAD driver because this +; computer isn't an 80386. +; +;--------------------------------------------------------------- +; +; Compilation instructions: +; MASM EMULOAD; (MASM 5.1) +; LINK EMULOAD; +; EXE2BIN EMULOAD EMULOAD.COM +; DEL EMULOAD.EXE +; +; The resultant EMULOAD.COM file is 1473 bytes, while the +; TSR portion is 1072 bytes. +; +;--------------------------------------------------------------- +; Compiler directives +;--------------------------------------------------------------- + Title EMULOAD + .radix 16 + .8086 + +;--------------------------------------------------------------- +; Interrupt vector segment +;--------------------------------------------------------------- +ABS0 segment at 0 + org 6*4 + INT_6 dd ? + + org 800h + Loadall_286 dd ? +ABS0 ends + + +;--------------------------------------------------------------- +; Structure definitions +;--------------------------------------------------------------- +Desc_cache2 STRUC ; 80286 Descriptor cache + A15_A00 dw ? ; register layout. + A23_A16 db ? + _Type2 db ? + _Limit2 dw ? +Desc_cache2 ENDS + + +Desc_cache3 STRUC ; 80386 Descriptor cache + _Access db 0 ; register layout + _Type db ? + _CS32 db 0 + db 0 + _Addr dd ? + _Limit dd ? +Desc_cache3 ENDS + + + +Loadall_struc2 STRUC ; 80286 LOADALL table + dw 3 dup (?) ; RESERVED + _286Msw dw ? ; MSW + dw 7 dup (?) ; RESERVED + _286Tr dw ? ; TR + _Flags dw ? ; FLAGS + _286Ip dw ? ; IP + _286Ldt dw ? ; LDT + _286Ds dw ? ; DS + _286Ss dw ? ; SS + _286Cs dw ? ; CS + _286Es dw ? ; ES + _286Di dw ? ; DI + _286Si dw ? ; SI + _286Bp dw ? ; BP + _286Sp dw ? ; SP + _286Bx dw ? ; BX + _286Dx dw ? ; DX + _286Cx dw ? ; CX + _286Ax dw ? ; AX + ES_Desc286 dw 3 dup (?) ; ES Desc. Cache + CS_Desc286 dw 3 dup (?) ; CS Desc. Cache + SS_Desc286 dw 3 dup (?) ; SS Desc. Cache + DS_Desc286 dw 3 dup (?) ; DS Desc. Cache + Gdt_Desc286 dw 3 dup (?) ; GDTR + Ldt_Desc286 dw 3 dup (?) ; LDTR + Idt_Desc286 dw 3 dup (?) ; IDTR + TSS_Desc286 dw 3 dup (?) ; TSSR +Loadall_Struc2 ENDS + +Loadall_struc3 STRUC + _Cr0 dd ? ; EAX + _Eflags dd ? ; EFLAGS + _Eip dd ? ; EIP + _Edi dd ? ; EDI + _Esi dd ? ; ESI + _Ebp dd ? ; EBP + _Esp dd ? ; ESP + _Ebx dd ? ; EBX + _Edx dd ? ; EDX + _Ecx dd ? ; ECX + _Eax dd ? ; EAX + _Dr6 dd ? ; DR6 + _Dr7 dd ? ; DR7 + _Tr dd ? ; TR + _Ldt dd ? ; LDT + _Gs dd ? ; GS + _Fs dd ? ; FS + _Ds dd ? ; DS + _Ss dd ? ; SS + _Cs dd ? ; CS + _Es dd ? ; ES + TSS_Desc dd 3 dup (?) ; TSSR + IDT_Desc dd 3 dup (?) ; IDTR + Gdt_Desc dd 3 dup (?) ; GDTR + Ldt_Desc dd 3 dup (?) ; LDTR + GS_Desc dd 3 dup (?) ; GS Desc. Cache + FS_Desc dd 3 dup (?) ; FS Desc. Cache + DS_Desc dd 3 dup (?) ; DS Desc. Cache + SS_Desc dd 3 dup (?) ; SS Desc. Cache + CS_Desc dd 3 dup (?) ; CS Desc. Cache + ES_Desc dd 3 dup (?) ; ES Desc. Cache + dd 0ah dup (?) ; RESERVED +Loadall_Struc3 ENDS + +INT_VEC STRUC + int_offset dw ? + int_segment dw ? +INT_VEC ENDS + + +;--------------------------------------------------------------- +; Equate definitions +;--------------------------------------------------------------- + LOADALL286 equ 050fh + CRLF equ <0dh,0ah> + CRLF$ equ <0dh,0ah,'$'> + INT6 equ [bp-4] + + +;--------------------------------------------------------------- +; Macro definitions +;--------------------------------------------------------------- + LOADALL_386 MACRO + db 0fh,07h + ENDM + + + PRINT_STRING MACRO MSG_NAME + mov ah,9 + mov dx,offset MSG_NAME + int 21h + ENDM + + + +_TEXT SEGMENT PARA PUBLIC 'CODE' + Assume CS:_TEXT, DS:_TEXT, ES:_TEXT, SS:_TEXT + Org 100h + .386p +;--------------------------------------------------------------- + Emulate_286_Loadall Proc Far +;--------------------------------------------------------------- + jmp EMULOAD ; goto beginning instruction + +Align 4 +;--------------------------------------------------------------- +; Local Data +;--------------------------------------------------------------- +Loadall_tbl Loadall_Struc3 <> + +emuload_msg db "80286 LOADALL EMULATOR utility.",CRLF + db "Version 1.0 Only for 80386 computers." + db CRLF + db "Copyright (c) 1991 Robert Collins." + db CRLF$ +emu_msg_len equ $-emuload_msg + +align 4 +;--------------------------------------------------------------- +; TSR Code begins here as an INT06 replacement. +;--------------------------------------------------------------- +Int06: push bp + mov bp,sp + push si + push ds + lds si,[bp][2] ; get CS:IP of bogus + ; opcode + cmp word ptr [si],LOADALL286; was it LOADALL? + jne @Not_LOADALL ; nope + mov di,0 + mov ds,di + mov di,cs + mov es,di + mov edi,offset Loadall_tbl + +Assume DS:ABS0, ES:_TEXT, SS:NOTHING +;--------------------------------------------------------------- +; Convert 80286 registers to 80386 counterparts. The sequencing +; order follows the 80386 LOADALL table. +;--------------------------------------------------------------- +; While mapping MSW to CR0, bit5 in CR0 is documented as +; RESERVED on the '386 DX, and '1' on the '386 SX. Bit6 is +; defined as 'NE' (Numeric Exception) on the '486. If we wanted +; this code to work on the '486, then we should mask the lower +; nibble of MSW with CR0. But the '486 doesn't have LOADALL, +; so this isn't necesary. Next consider the Reserved bit5 on +; the '386 DX. Since LOADALL completely redefines the CPU +; state, it is safe to clear this reserved bit instead of +; masking it with MSW. +;--------------------------------------------------------------- + mov eax,cr0 ; MSW --> CR0 + mov ax,Loadall_286._286Msw + mov Loadall_tbl._CR0,eax + movzx eax,Loadall_286._Flags ; FLAGS --> EFLAGS + mov Loadall_tbl._EFLAGS,eax + +;--------------------------------------------------------------- +; Hereafter MOVZX isn't needed because the upper 16-bits are +; guaranteed to be 0. +;--------------------------------------------------------------- + mov ax,Loadall_286._286IP ; IP --> EIP + mov Loadall_tbl._EIP,eax + mov ax,Loadall_286._286DI ; DI --> EDI + mov Loadall_tbl._EDI,eax + mov ax,Loadall_286._286SI ; SI --> ESI + mov Loadall_tbl._ESI,eax + mov ax,Loadall_286._286BP ; BP --> EBP + mov Loadall_tbl._EBP,eax + mov ax,Loadall_286._286SP ; SP --> ESP + mov Loadall_tbl._ESP,eax + mov ax,Loadall_286._286BX ; BX --> EBX + mov Loadall_tbl._EBX,eax + mov ax,Loadall_286._286DX ; DX --> EDX + mov Loadall_tbl._EDX,eax + mov ax,Loadall_286._286CX ; CX --> ECX + mov Loadall_tbl._ECX,eax + mov ax,Loadall_286._286AX ; AX --> EAX + mov Loadall_tbl._EAX,eax + +;--------------------------------------------------------------- +; DR6 & DR7 aren't in the '286, so let's use the current values. +; By keeping the current values, guarantees that any ICE +; breakpoints, or debug register breakpoints are preserved. +; (ICE breakpoints use (at least) the upper two of the +; 'RESERVED' bits in DR7. +;--------------------------------------------------------------- + mov eax,dr6 ; Keep DR6 + mov Loadall_tbl._DR6,eax + mov eax,dr7 ; Keep DR7 + mov Loadall_tbl._DR7,eax + + movzx eax,Loadall_286._286TR ; TR --> TR + mov Loadall_tbl._TR,eax + mov ax,Loadall_286._286LDT ; LDT --> LDT + mov Loadall_tbl._LDT,eax + +;--------------------------------------------------------------- +; FS & GS aren't in the '286, so let's zero them out. +;--------------------------------------------------------------- + xor ax,ax + mov Loadall_tbl._GS,eax ; Clear GS + mov Loadall_tbl._FS,eax ; Clear FS + + mov ax,Loadall_286._286DS ; DS --> DS + mov Loadall_tbl._DS,eax + mov ax,Loadall_286._286SS ; SS --> SS + mov Loadall_tbl._SS,eax + mov ax,Loadall_286._286CS ; CS --> CS + mov Loadall_tbl._CS,eax + mov ax,Loadall_286._286ES ; ES --> ES + mov Loadall_tbl._ES,eax + +;----------------------------------------------------------- +; Convert '286 descriptor cache register entries to '386 +; format. +;----------------------------------------------------------- + mov esi,offset Loadall_286.TSS_Desc286 + mov edi,offset Loadall_tbl.TSS_Desc + call CVT_Desc + mov esi,offset Loadall_286.IDT_Desc286 + mov edi,offset Loadall_tbl.IDT_Desc + call CVT_Desc + mov esi,offset Loadall_286.GDT_Desc286 + mov edi,offset Loadall_tbl.GDT_Desc + call CVT_Desc + mov esi,offset Loadall_286.LDT_Desc286 + mov edi,offset Loadall_tbl.LDT_Desc + call CVT_Desc + +;----------------------------------------------------------- +; Fill in FS & GS descriptor cache entires with 0. +;----------------------------------------------------------- + mov Loadall_tbl.GS_Desc._Type,93h + mov Loadall_tbl.GS_Desc._Addr,0 + mov Loadall_tbl.GS_Desc._Limit,0ffffh + mov Loadall_tbl.FS_Desc._Type,93h + mov Loadall_tbl.FS_Desc._Addr,0 + mov Loadall_tbl.FS_Desc._Limit,0ffffh + +;----------------------------------------------------------- +; Convert '286 descriptor cache register entries to '386 +; format. +;----------------------------------------------------------- + mov esi,offset Loadall_286.DS_Desc286 + mov edi,offset Loadall_tbl.DS_Desc + call CVT_Desc + mov esi,offset Loadall_286.SS_Desc286 + mov edi,offset Loadall_tbl.SS_Desc + call CVT_Desc + mov esi,offset Loadall_286.CS_Desc286 + mov edi,offset Loadall_tbl.CS_Desc + call CVT_Desc + mov esi,offset Loadall_286.ES_Desc286 + mov edi,offset Loadall_tbl.ES_Desc + call CVT_Desc + mov edi,offset Loadall_tbl + LOADALL_386 + HLT ; This instruction never + ; gets executed + +@Not_LOADALL: + pop ds + pop si + pop bp + +Orig_int06: + jmp far ptr INT_6 +Emulate_286_Loadall endp + + +;--------------------------------------------------------------- + CVT_Desc proc near ; Convert '286 descriptor table +; ; cache register format to '386 +; ; format. +;--------------------------------------------------------------- +; Input: DS:ESI = Pointer to '286 descriptor cache entry +; DS:EDI = Pointer to '386 descriptor cache entry +; Output: None +; Register(s) modified: EAX, EBX, ECX +;--------------------------------------------------------------- + mov eax,[esi] ; get 24-bit base & + ; access rights + mov ebx,eax ; make a copy + movzx ecx,[esi]._Limit2 ; get 16-bit limit + rol eax,8 ; put access in AL + and ebx,00ffffffh ; make 24-bit address + mov ES:[edi]._Type,al ; store Access + mov ES:[edi]._Addr,ebx ; store Address + mov ES:[edi]._Limit,ecx ; store Limit + ret +CVT_Desc endp + +TSR_End label word +;--------------------------------------------------------------- +; End of TSR program +;--------------------------------------------------------------- + + +;--------------------------------------------------------------- +; Local DATA used for initialization code only. +;--------------------------------------------------------------- +bogus_msg1 db "Unrecognized command line argument." + db CRLF$ +bogus_msg2 db "Not 80386 computer.",7,CRLF$ + +driver_msg1 db "Resident driver installed." + db CRLF$ +driver_msg2 db "Resident driver already installed." + db 7,CRLF$ +driver_msg3 db "Resident driver removed from memory." + db CRLF$ +driver_msg4 db "Resident driver was not already " + db "installed",7,CRLF$ +help_msg db CRLF + db "Syntax: EMULOAD",CRLF + db " EMULOAD -R (to remove from " + db "memory)",CRLF$ + + +ASSUME DS:_TEXT +;--------------------------------------------------------------- + EMULOAD proc near ; Beginning of initialization +; ; code as the NON-TSR part of +; ; the program. +;--------------------------------------------------------------- + cld ; clear direction flag + Print_String emuload_msg ; Print initialization + ; message. + +;--------------------------------------------------------------- +; Check CPU type +;--------------------------------------------------------------- + call CPU_TYPE ; Get CPU type + and al,0fh ; mask out CPU sub-type + cmp al,3 ; 80386? + jz short @F ; yes + Print_String Bogus_msg2 ; Not 80386 computer + mov ax,4c06h ; set function to DOS + int 21h ; exit to DOS + +;--------------------------------------------------------------- +; Check command line argument +;--------------------------------------------------------------- +@@: xor ax,ax ; clear AX + mov si,80h ; get start of PSP + lodsb ; get command line len. + or ax,ax ; Any command line args? + jz short Installed? ; nope + mov cx,ax ; put into counter + mov di,si ; + mov al,' ' ; skip past superfluous + repz scasb ; blank characters + cmp byte ptr [di],0dh ; are we at the end? + jz short Installed? ; yep + cmp byte ptr [di-1],'-' ; check if it's a switch + jnz short @F ; if not, then error + mov si,di ; get pointer + lodsb ; get cmd line switch + cmp al,'r' ; remove driver? + jz short remove_driver ; yep + cmp al,'R' ; remove driver? + jz short remove_driver ; go remove driver + cmp al,'?' ; help? + jnz short @F ; nope + Print_String help_msg ; Print help message + mov ax,4c04h ; set return code + int 21h ; exit to DOS + +;--------------------------------------------------------------- +; Bogus command line argument +;--------------------------------------------------------------- +@@: Print_String bogus_msg1 ; Invalid command line + mov ax,4c03h ; set function code + int 21h ; exit to DOS + +;--------------------------------------------------------------- +; Remove driver from memory +;--------------------------------------------------------------- +remove_driver: + call check_installed ; Driver installed? + jnz short @F ; driver not installed + mov bp,sp ; create stack frame + push ds ; save (DS) + mov dx,ABS0 ; get bottom of memory + mov ds,dx ; make segment register + +ASSUME DS:ABS0, ES:_TEXT +;--------------------------------------------------------------- +; Restore original INT6 vector +;--------------------------------------------------------------- +; We can restore the original INT6 by getting the vector from +; our current memory resident driver -- not the DS from the +; code now executing. The original DS is the same as the code +; segment for our EMULOAD driver. Hence we only need to get +; the original segment value from the memory resident image. +; And we get this by looking at the segment for INT6! +;--------------------------------------------------------------- + mov es,int_6.int_segment ; Original DS + mov ax,es:orig_int06[1].int_offset ; Original INT6 + mov bx,es:orig_int06[1].int_segment ; " " + mov int_6.int_offset,ax ; Restore orig. + mov int_6.int_segment,bx ; INT6 + +;--------------------------------------------------------------- +; Free memory pointed to by ES +;--------------------------------------------------------------- + mov ah,49h ; DOS FREE_MEM function + int 21h ; free allocated memory + mov ds,[bp-2] ; get original (DS) + +ASSUME DS:_TEXT +;--------------------------------------------------------------- +; Now split with TSR removed from memory. +;--------------------------------------------------------------- + Print_String driver_msg3 ; Driver removed + mov ax,4c05h ; set function to DOS + int 21h ; exit to DOS + +;--------------------------------------------------------------- +; If EMULOAD was not in memory, then come here and split with +; the error code. +;--------------------------------------------------------------- +@@: Print_String driver_msg4 ; Driver not installed + mov ax,4c01h ; set function to DOS + int 21h ; exit to DOS + +;--------------------------------------------------------------- +; Check for driver already installed +;--------------------------------------------------------------- +Installed?: + call check_installed ; check if driver is + jnz short @F ; already installed? + +;--------------------------------------------------------------- +; Driver already installed +;--------------------------------------------------------------- + Print_String driver_msg2 ; Driver already inst. + mov ax,4c02h ; set function to DOS + int 21h ; exit to DOS + +;--------------------------------------------------------------- +; Driver not yet installed +;--------------------------------------------------------------- +@@: Print_String driver_msg1 ; Driver now installed + +;--------------------------------------------------------------- +; Install driver into memory +;--------------------------------------------------------------- + xor dx,dx ; Point to INT. vectors + mov ds,dx ; complete the move +ASSUME ds:ABS0 + +;--------------------------------------------------------------- +; Chain to INT6 by replacing and saving the original INT6 +; vector. +;--------------------------------------------------------------- + mov ax,int_6.int_offset ; Orig. offset + mov bx,int_6.int_segment ; Orig. segment + mov orig_int06[1].int_offset,ax ; save old INT6 + mov orig_int06[1].int_segment,bx ; vector. + +;--------------------------------------------------------------- +; Now replace the original INT6 vector. +;--------------------------------------------------------------- + mov dx,offset cs:int06 ; Get new INT6 vector + mov int_6.int_offset,dx ; as CS:INT6 + mov int_6.int_segment,cs ; + +ASSUME DS:_TEXT +;--------------------------------------------------------------- +; Terminate and Stay Resident +;--------------------------------------------------------------- + mov dx,cs ; make DS=CS + mov ds,dx + mov es,ds:[2ch] ; get DOS env. segment + mov ah,49h ; release memory func. + int 21h ; release memory + mov dx,offset tsr_end ; get ending address + shr dx,4 ; divide by 16 + adc dx,1 ; check for remainder; + ; add 1 + mov ax,3100h ; set return code to DOS + int 21h +EMULOAD endp + + +ASSUME ES:ABS0 +;--------------------------------------------------------------- +; Check to see if the EMULOAD driver is installed in memory. +; It is possible to check if a TSR program is already installed +; in memory by looking for a semaphore in the memory image. +; Luckily we can locate the memory image of our TSR by looking +; at the current INT6 vector. The INT6 code segment is the +; segment of the TSR! So this routine looks in this segment +; for the inital banner message: +; +; 80286 LOADALL EMULATOR utility. +; Version 1.0 Only for 80386 computers. +; Copyright (c) 1991 Robert Collins. +; +; If this message is found, then the TSR is in memory. If +; another TSR has chained to the same INT6 vector, this +; technique will fail to find EMULOAD, as it very well should! +;--------------------------------------------------------------- + Check_installed proc near +;--------------------------------------------------------------- +; Input: None +; Output: NZ if NOT installed +; ZF if ALREADY installed +; Register(s) modified: CX, SI, DI +;--------------------------------------------------------------- + push es ; save (ES) + mov cx,ABS0 ; get bios data segment + mov es,cx ; put in (ES) + mov cx,emu_msg_len ; # of bytes to compare + mov si,offset emuload_msg ; get address of message + les di,ES:INT_6 ; get INT6 vector + sub di,int06-emuload_msg ; point to theoretical + ; start of message + repz cmpsb ; check data + pop es ; restore (ES) + ret ; split +Check_installed endp + + +;--------------------------------------------------------------- +; Include the CPU_TYPE procedure & LOADALL test +;--------------------------------------------------------------- + Include CPU_TYPE.ASM + +_TEXT ends + end Emulate_286_LOADALL + +;--------------------------------------------------------------- +; END LISTING 3 +;--------------------------------------------------------------- diff --git a/docs/x86/ops/LOADALL/loadfns.286.asm b/docs/x86/ops/LOADALL/loadfns.286.asm new file mode 100644 index 000000000..5c3287b38 --- /dev/null +++ b/docs/x86/ops/LOADALL/loadfns.286.asm @@ -0,0 +1,382 @@ +;----------------------------------------------------------------------------- +; +; LOADFNS.286 +; +; 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 +; +;----------------------------------------------------------------------------- + +;--------------------------------------------------------------- +; Equates & local variables +;--------------------------------------------------------------- +; I/O Ports +;--------------------------------------------------------------- + Mstrmsk equ 021h ; 8259 master mask addr + KBC_CTL equ 060h ; 8042 control port + KBC_STAT equ 064h ; 8042 status port + Cmos_index equ 070h ; CMOS address port + Cmos_data equ 071h ; CMOS data port + Slv_msk equ 0a1h ; 8259 slave mask addr + +;--------------------------------------------------------------- +; CMOS RAM +;--------------------------------------------------------------- + Shut_down equ 00fh ; CMOS index for shutdwn + Type5 equ 5 ; Shutdown type-5 + +;--------------------------------------------------------------- +; Keyboard Controller +;--------------------------------------------------------------- + inpt_buf_full equ 2 ; Input buffer full + Shutdown_CMD equ 0feh ; Shutdown CMD for KBC + enable_bit20 equ 0dfh ; enable A20 command + disable_bit20 equ 0ddh ; disable A20 command + + +;---------------------------------------------------------------; + RESET_CPU:; Resets the CPU by sending a shutdown command to +; the keyboard controller. +;--------------------------------------------------------------- +; Input: None +; Output: None +; Register(s) modified: Doesn't matter, the CPU is reset +;--------------------------------------------------------------- + mov al,Shutdown_CMD ; get shutdown command + out KBC_STAT,al ; send command to shutdown CPU + cli ; disable interrupts so that + ; an INT can't come through + ; before the CPU resets + hlt ; + + +;---------------------------------------------------------------; +; SETPM_RET_ADDR: Save the real-mode return address @ 40:67 +; from protected mode. +;--------------------------------------------------------------- +; Input: CS:AX = Return address from PM. +; DS = Better darn well have a PM segment selector! +; (Or else Kablooie!) +; Output: None +; Register(s) modified: None +;--------------------------------------------------------------- + Setpm_ret_addr proc near +;--------------------------------------------------------------- + push dx ; save it + push ds + mov dx,ABS0 ; + mov ds,dx +ASSUME DS:ABS0 + mov DS:PM_Ret_off,ax + mov DS:PM_Ret_seg,cs +ASSUME DS:_DATA + pop ds + pop dx + ret +Setpm_ret_addr endp + + +;--------------------------------------------------------------- +; Get_INT_status: Saves the master and slave mask register +; contents from the 8259 interrupt controller. +;--------------------------------------------------------------- +; Input: DS = _DATA SEGMENT +; Output: i8259_1 = Status of master device +; i8259_2 = Status of slave device +; Register(s) modified: None +;--------------------------------------------------------------- + Get_int_status proc near +;--------------------------------------------------------------- + push ax + in al,mstrmsk ; get master PIC mask + mov i8259_1,al + IO_Delay ; I/O delay + in al,slv_msk ; get slave PIC mask + mov i8259_2,al + pop ax + ret ; exit +Get_int_status endp + + +;---------------------------------------------------------------; +; Set_INT_status: Restores the interrupt status of the 8259A +; programmable interrupt controller (PIC). +;--------------------------------------------------------------- +; Input: i8259_1 = Status of master device +; i8259_2 = Status of slave device +; DS = _DATA SEGMENT +; Output: None +; Register(s) modified: None +;--------------------------------------------------------------- + Set_int_status proc near +;--------------------------------------------------------------- + pushf ; save interrupt flag + cli ; we REALLY don't want an int + ; to come through while we are + push ax ; reprogramming the PIC masks + mov al,i8259_1 + out mstrmsk,al ; restore master PIC mask + IO_Delay ; I/O delay + mov al,i8259_2 + out slv_msk,al ; restore slave PIC mask + pop ax + popf ; restore interrupt flag + ret ; exit +Set_int_status endp + + +;--------------------------------------------------------------- +; SET_SHUTDOWN_TYPE: Set the processor shutdown type-5 in CMOS. +;--------------------------------------------------------------- +; Input: None +; Output: None +; Register(s) modified: None +;--------------------------------------------------------------- + Set_shutdown_type proc near +;--------------------------------------------------------------- + pushf ; save interrupt status + cli ; disable ints so somebody else + ; doesn't do this right now + push ax + mov al,shut_down ; Set shutdown byte + out cmos_index,al ; to shut down x05. + IO_Delay ; I/O delay + mov al,Type5 ; + out cmos_data,al ; CMOS data port + pop ax + popf + ret +set_shutdown_type endp + + +;--------------------------------------------------------------- +; Enable_gate20: Turn on A20, and check for errors. +;--------------------------------------------------------------- +; Input: None +; Output: CY=ERROR +; Register(s) modified: None +;--------------------------------------------------------------- + Enable_gate20 proc near +;--------------------------------------------------------------- + push ax + mov ah,enable_bit20 ; gate address bit 20 on + Call Gate_A20 + or al,al ; command accepted? + jz A20_OK ; go if yes + stc ; set error flag +A20_OK: pop ax + ret ; exit +Enable_gate20 endp + + +;--------------------------------------------------------------- +; SHUT_A20: Disable A20 from CPU address BUS. +;--------------------------------------------------------------- +; Input: None +; Output: CY=ERROR +; Register(s) modified: None +;--------------------------------------------------------------- + Shut_a20 proc near +;--------------------------------------------------------------- + push ax + mov ah,disable_bit20 ; gate address bit 20 on + Call Gate_A20 + or al,al ; was command accepted? + jz A20_Shut ; go if yes + stc ; set error flag + +A20_Shut: + pop ax + ret ; exit +Shut_a20 endp + + +;--------------------------------------------------------------- +; GATE_A20: This routine controls a signal which gates address +; line 20 (A20). The gate A20 signal is an output of +; of the 8042 slave processor (keyboard controller). +; A20 should be gated on before entering protected +; mode, to allow addressing of the entire 16M address +; space of the 80286, or 4G address space of the +; 80386 & 80486. It should be gated off after +; entering real mode -- from protected mode. +;--------------------------------------------------------------- +; Input: AH = DD ==> A20 gated off (A20 always 0) +; AH = DF ==> A20 gated on (CPU controls A20) +; Output: AL = 0 ==> Operation successful +; AL = 2 ==> Operation failed, 8042 can't accept cmd +; Register(s) modified: AX +;--------------------------------------------------------------- + Gate_a20 proc near +;--------------------------------------------------------------- + pushf ; save interrupt status + cli ; disable ints while using 8042 + Call Empty_8042 ; insure 8042 input buffer empty + jnz A20_Fail ; ret: 8042 unable to accept cmd + IO_Delay ; I/O Delay + mov al,0D1h ; 8042 cmd to write output port + out KBC_STAT,al ; output cmd to 8042 + Call Empty_8042 ; wait for 8042 to accept cmd + jnz A20_Fail ; ret: 8042 unable to accept cmd + mov al,ah ; 8042 port data + out KBC_CTL,al ; output port data to 8042 + Call Empty_8042 ; wait for 8042 to port data + push cx ; save it + mov cx,14h ; +@DLY: IO_Delay ; Wait for KBC to execute the + loop @DLY ; command. (about 25uS) + pop cx ; restore it + +A20_Fail: + popf ; restore flags + ret +Gate_a20 endp + + +;--------------------------------------------------------------- +; EMPTY_8042: This routine waits for the 8042 buffer to empty. +;--------------------------------------------------------------- +; Input: None +; Output: AL = 0, 8042 input buffer empty: ZF +; AL = 2, Time out; 8042 buffer full: NZ +; Register(s) modified: AX +;--------------------------------------------------------------- + Empty_8042 proc near +;--------------------------------------------------------------- + push cx ; save CX + xor cx,cx ; CX=0: timeout value + +Try_KBC: + IO_Delay ; + in al,KBC_STAT ; read 8042 status port + and al,inpt_buf_full; input buffer full flag (D1) + loopnz Try_KBC ; loop until input buffer empty + ; or timeout + pop cx ; restore CX + ret +Empty_8042 endp + + +;--------------------------------------------------------------- +; CALC_PM_ADDRESS: Calculate 32-bit protected mode address. +; Used for building descriptor tables. +;--------------------------------------------------------------- +; Input: ES:SI = Real mode address +; Output: DX:AX = 32-bit linear address +; Register(s) modified: AX, DX +;--------------------------------------------------------------- + Calc_pm_address proc near +;--------------------------------------------------------------- + mov ax,es ; point to control block + xor dh,dh ; clear upper register + mov dl,ah ; build high byte of 32-bit addr + shr dl,4 ; use only high nibble from (AX) + shl ax,4 ; strip high nibble from segment + add ax,si ; add GDT offset for low word + adc dx,0 ; adj high byte if CY from low + ret ; back to calling program +calc_pm_address endp + + +;--------------------------------------------------------------- + Save_state proc near ; Save the machine state before +; ; LOADALL +;--------------------------------------------------------------- + push ax + push ds + mov si,0 + mov di,offset Machine_State.ES_Desc + mov ax,3000h ; ES descriptor + mov ds,ax + mov bx,0303h + movsw + mov word ptr [si-2],bx + + add ax,1000h ; SS descriptor + add bx,0101h + mov si,0 + add di,0ah + mov ds,ax + movsw + mov word ptr [si-2],bx + sub ax,2000h ; DS descriptor + sub bx,0202h + mov si,0 + add di,4 + mov ds,ax + movsw + mov word ptr [si-2],bx + pop ds + + smsw ax + mov Machine_State._Msw,ax + pushf + pop ax + mov Machine_State._Flags,ax + pop ax + mov Machine_State._DI,di + mov Machine_State._SI,si + mov Machine_State._BP,bp + mov Machine_State._BX,bx + mov Machine_State._DX,dx + mov Machine_State._CX,cx + mov Machine_State._AX,ax + mov ax,ds + mov Machine_State._DS,ax + mov ax,es + mov Machine_State._ES,ax + ret +Save_state endp + + +;--------------------------------------------------------------- + Restore_state proc near ; Restore the machine state +; ; after LOADALL +;--------------------------------------------------------------- + mov ax,_data + mov ds,ax + mov ax,3000h ; ES + mov es,ax + mov si,offset Machine_State.DS_Desc + mov di,0 + movsw + add ax,1000h ; SS + add si,0ah + mov di,0 + mov es,ax + movsw + sub ax,2000h ; DS + add si,4 + mov di,0 + mov es,ax + movsw + mov ax,Machine_State._ES + mov es,ax + mov ax,Machine_State._DS + mov ds,ax + mov ax,Machine_State._Flags + push ax + popf + mov ax,Machine_State._Msw + lmsw ax + mov ax,Machine_State._AX + mov cx,Machine_State._CX + mov dx,Machine_State._DX + mov bx,Machine_State._BX + mov bp,Machine_State._BP + mov si,Machine_State._SI + mov di,Machine_State._DI + ret +Restore_State endp diff --git a/docs/x86/ops/LOADALL/loadfns.386.asm b/docs/x86/ops/LOADALL/loadfns.386.asm new file mode 100644 index 000000000..f26d009e5 --- /dev/null +++ b/docs/x86/ops/LOADALL/loadfns.386.asm @@ -0,0 +1,205 @@ +;----------------------------------------------------------------------------- +; +; LOADFNS.386 +; +; 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 +; +;----------------------------------------------------------------------------- + + +;----------------------------------------------------------------------------- + INT01: ; Int1 trap routine +;----------------------------------------------------------------------------- +; Interprets breakpoint type, and sets a flag +;----------------------------------------------------------------------------- + inc dx + push bp + mov bp,sp + mov buffer2[bx],cx + add bx,2 + push eax + push ebx + push ecx + mov eax,dr6 + mov ecx,eax + mov ebx,dr7 + shr ebx,10h ; get length encodings + test ah,20h ; debug register access attempt? + jnz @DR_Attempt ; yep + shr al,1 ; DR0? + jc @DR0 + shr al,1 ; DR1? + jc @DR1 + shr al,1 ; DR2? + jc @DR2 +@DR3: or si,8 + and cl,not 8 + test bh,30h ; code, or data? + jz @Fault + jmp short @Trap +@DR2: or si,4 + and cl,not 4 + test bh,03h ; code, or data? + jz @Fault + jmp short @Trap +@DR1: or si,2 + and cl,not 2 + test bl,30h ; code, or data? + jz @Fault + jmp short @Trap +@DR0: or si,1 + and cl,not 1 + test bl,03h ; code, or data? + jz @Fault + jmp short @Trap +@Fault: add word ptr [bp][2],1 + mov dr6,ecx +@Trap: pop ecx + pop ebx + pop eax + pop bp + iret + +@Dr_Attempt: + push bp + add word ptr [bp][2],3 + pop bp + iret + + + + +;----------------------------------------------------------------------------- + Save_state proc near ; Save the machine state before LOADALL +;----------------------------------------------------------------------------- + push eax + push ds + mov si,0 + mov di,offset Machine_State.GS_Desc + mov ax,5000h ; GS descriptor + mov ds,ax + mov ebx,05050505h + movsd + mov dword ptr [si-4],ebx + + sub ax,1000h ; FS descriptor + sub ebx,01010101h + mov si,0 + add di,8 + mov ds,ax + movsd + mov dword ptr [si-4],ebx + sub ax,2000h ; DS descriptor + sub ebx,02020202h + mov si,0 + add di,8 + mov ds,ax + movsd + mov dword ptr [si-4],ebx + add ax,4000h ; SS descriptor + add ebx,04040404h + mov si,0 + add di,8 + mov ds,ax + movsd + mov dword ptr [si-4],ebx + sub ax,3000h ; ES descriptor + sub ebx,03030303h + mov si,0 + add di,14h + mov ds,ax + movsd + mov dword ptr [si-4],ebx + pop ds + + mov eax,cr0 + mov Machine_State._CR0,eax + pushfd + pop eax + mov Machine_State._Eflags,eax + pop eax + mov Machine_State._EDI,edi + mov Machine_State._ESI,esi + mov Machine_State._EBP,ebp + mov Machine_State._EBX,ebx + mov Machine_State._EDX,edx + mov Machine_State._ECX,ecx + mov Machine_State._EAX,eax + mov ax,gs + movzx eax,ax + mov Machine_State._GS,eax + mov ax,fs + mov Machine_State._FS,eax + mov ax,ds + mov Machine_State._DS,eax + mov ax,es + mov Machine_State._ES,eax + ret +Save_state endp + + +;----------------------------------------------------------------------------- + Restore_state proc near ; Restore the machine state after LOADALL +;----------------------------------------------------------------------------- + mov ax,_data + mov ds,ax + mov ax,5000h ; GS + mov es,ax + mov si,offset Machine_State.GS_Desc + mov di,0 + movsd + sub ax,1000h ; FS + add si,8 + mov di,0 + mov es,ax + movsd + sub ax,2000h ; DS + add si,8 + mov di,0 + mov es,ax + movsd + add ax,4000h ; SS + add si,8 + mov di,0 + mov es,ax + movsd + sub ax,3000h ; ES + add si,14h + mov di,0 + mov es,ax + movsd + mov eax,Machine_State._ES + mov es,ax + mov eax,Machine_State._DS + mov ds,ax + mov eax,Machine_State._FS + mov fs,ax + mov eax,Machine_State._GS + mov gs,ax + mov eax,Machine_State._Eflags + push eax + popfd + mov eax,Machine_State._CR0 + mov cr0,eax + mov eax,Machine_State._EAX + mov ecx,Machine_State._ECX + mov edx,Machine_State._EDX + mov ebx,Machine_State._EBX + mov ebp,Machine_State._EBP + mov esi,Machine_State._ESI + mov edi,Machine_State._EDI + ret +Restore_State endp diff --git a/docs/x86/ops/LOADALL/macros.286.asm b/docs/x86/ops/LOADALL/macros.286.asm new file mode 100644 index 000000000..f3a006bd0 --- /dev/null +++ b/docs/x86/ops/LOADALL/macros.286.asm @@ -0,0 +1,51 @@ +;----------------------------------------------------------------------------- +; +; MACROS.286 +; +; 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 +; +;----------------------------------------------------------------------------- + + +;--------------------------------------------------------------- +; Macro definitions +;--------------------------------------------------------------- +FARJMP MACRO destination,selector ; dynamic JMP FAR SEG:OFF + db 0eah ;; jmp instruction + dw offset destination ;; offset word + dw selector ;; segment selector word + endm + + +IO_DELAY MACRO + out 0edh,ax + endm + +LOADALL MACRO + mov cx,ABS0 + mov es,cx + mov cx,(size Loadall_struc) / 2 + mov si,offset Loadall_tbl + mov di,800h + rep movsw + db 0fh,05 + ENDM + +PRINT_STRING MACRO MSG_NAME + mov ah,9 + mov dx,offset MSG_NAME + int 21h + ENDM diff --git a/docs/x86/ops/LOADALL/macros.386.asm b/docs/x86/ops/LOADALL/macros.386.asm new file mode 100644 index 000000000..b5b3a21f4 --- /dev/null +++ b/docs/x86/ops/LOADALL/macros.386.asm @@ -0,0 +1,78 @@ +;----------------------------------------------------------------------------- +; +; MACROS.386 +; +; 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 +; +;----------------------------------------------------------------------------- + + +;----------------------------------------------------------------------------- +; Macro definitions +;----------------------------------------------------------------------------- + Init_descriptor macro segment,offset,desc_name + push ax + push dx + push si + push es + mov ax,&segment ;; get segment name + mov es,ax ;; to form 24 bit address + mov si,&offset ;; + mov ax,es ; point to control block + xor dh,dh ; clear upper register + mov dl,ah ; build high byte of 32-bit address + shr dl,4 ; use only high nibble from (AX) + shl ax,4 ; strip high nibble from segment + add ax,si ; add the GDT offset to develop low word + adc dx,0 ; adjust high byte if carry from low + mov &desc_name.Base_A15_A00,ax ;; low word of address + mov &desc_name.Base_A23_A16,dl ;; high byte of address + mov &desc_name.Base_A31_A24,dh ;; high byte of linear address + pop es + pop si + pop dx + pop ax + endm + + +FARJMP MACRO destination,selector ; dynamic JMP FAR SEG:OFF + db 0eah ;; jmp instruction + dw offset destination ;; offset word + dw selector ;; segment selector word + endm + + +LONGJMP MACRO destination,selector ; dynamic JMP FAR SEG:OFF + db 0eah ;; jmp instruction + dd offset destination ;; offset word + dw selector ;; segment selector word + endm + + +IO_DELAY MACRO + out 0edh,ax + endm + +LOADALL MACRO + db 0fh,07h + ENDM + + +PRINT_STRING MACRO MSG_NAME + mov ah,9 + mov dx,offset MSG_NAME + int 21h + ENDM diff --git a/docs/x86/ops/LOADALL/tspec_a3_doc.html b/docs/x86/ops/LOADALL/tspec_a3_doc.html new file mode 100644 index 000000000..94ca8ad9b --- /dev/null +++ b/docs/x86/ops/LOADALL/tspec_a3_doc.html @@ -0,0 +1,1276 @@ + + + + + + +The LOADALL Instruction + + + + + +
+

The LOADALL +Instruction

+ +

by

+ +

Robert Collins

+ +
+ +

Of the few undocumented instructions in the 80286 and 80386 +microprocessors, the LOADALL instruction is the most +widely known. Nevertheless, very few people understand how to use +it. Using LOADALL is not as simp)e as merely knowing the LOADALL +opcode and its format, because knowing how to use LOADALL requires +a knowledge of many aspects of the CPUs' behavior that are not +documented in their respective data sheets.

+ +

The 286 LOADALL is widely known because a 15-page lntel +confidential document describing its use was given to many +developers. 286 LOADALL is so commonly used in production +code that DOS 3.3 (and above) and OS/2 have provisions for using LOADALL +built in them. Every 386 and 486 BIOS emulates 286 LOADALL +and even Microsoft CODEVIEW recognizes the 286 LOADALL opcode +and disassembles it.

+ +

On the other hand, the 386 LOADALL is not widely known, +and very few developers even know it exists. In this article, I +will explain how to use both the 286 and 386 LOADALL instructions +and present source code to demonstrate the various aspects of CPU +behavior that become apparent, or can be proven, when using LOADALL.

+
+ + + + + + +
Intel originally included LOADALL + in the CPU mask for testing purposes and In Circuit + Emulator (ICE) support. As its name implies, LOADALL loads + all of the CPU registers, including the + "hidden" software-invisible registers. At the + completion of a LOADALL instruction, the entire + CPU state is defined according to the LOADALL data + table. LOADALL loads all of the software-visible + registers such as AX, and all of the + software-invisible registers such as the segment descriptor caches.

By + manipulating the descriptor cache base registers, you can + access the entire address space without switching to + protected mode. In other words, by using LOADALL, you + can access memory above 1Mb from real mode. Since the + alternative method for the 286 (switching to protected + mode, accessing the desired memory, then resetting the + CPU - the only way to get the 286 back to real mode) has + a significant performance penalty, LOADALL is most + significant to 286 programmers. LOADALL provides + them with a new capability that is not available by any + other means.

+

LOADALL Details

+

LOADALL is closely coupled with the CPU + hardware. Both the 286 and 386 have different internal + hardware and Intel implemented LOADALL using + different opcodes on the 286 and 386. 80286 LOADALL (opcode + 0F05) produces an invalid opcode exception when executed + on the 386, and 80386 LOADALL (opcode 0F07) + produces an invalid opcode exception when executed on the + 286.

+

LOADALL loads all CPU registers (including MSW, + GDTR, CSBASE, ESACCESS) from a memory image. You can + execute LOADALL in real or protected mode, but + only at privilege level 0 (CPL=0). If you execute LOADALL + at any other privilege level, the CPU generates an + exception.

+

By directly loading the descriptor cache registers + with LOADALL, a program has explicit control over + the base address, segment limit, and access rights + associated with each memory segment. Normally, the CPU + loads these values each time it loads a segment register, + but LOADALL allows you to load these hidden + registers independently of their segment register + counterparts.

+

In real mode, LOADALL makes it possible to + access a memory segment that is not associated with any + segment register. Likewise in protected mode, you can + access memory that has no descriptor table entry.

+

LOADALL performs no protection checks against + any of the loaded register values. When you execute it at + CPL 0, LOADALL can generate no exceptions. The + segment access rights and limit portions may be values + that would otherwise be illegal in the context of real + mode or protected mode, but LOADALL willingly + loads these values with no checks. Once loaded, however, + the CPU performs full access checks when accessing a + segment. For example, you can load a segment whose access + is marked "not present." Normally, this + condition would generate exception 11, "segment not + present", but LOADALL does not generate + exception 11. Instead, any attempt to access this segment + will generate exception 13.

+

LOADALL does not check coherency between the + software-visible segment registers and the + software-invisible segment descriptor cache registers. + Any segment descriptor base register may point to any + area in the CPU address space, while the software-visible + segment register may contain any other arbitrary value. + The CPU makes all memory references according to the + descriptor cache registers, not the software-visible + segment registers. All subsequent segment register loads + will reload the descriptor cache register. Beware of + using values in CS that do not perfectly match a code + segment descriptor table entry, or a real mode code + segment - an interrupt return (IRET) may either + cause an exception or execution to resume at an + unexpected location. Likewise, pushing and subsequently + popping any segment register will force the descriptor + cache register to reload according to the CPU's + conventional protocol, thereby inhibiting any further + real mode extended memory references.

+

80286 LOADALL

+

You encode the 80286 LOADALL as a two-byte + opcode, 0F05h. LOADALL reads its table from a + fixed memory location at 800h (80:0 in real-mode + addressing). LOADALL performs 51 bus cycles (WORD + cycles), and takes 195 clocks with no wait states. Table 1 shows the format you must + prepare at location 800h before executing the 286 LOADALL + instruction. All CPU register entries in the LOADALL + table conform to the standard Intel format, where the + least significant byte is at the lowest memory address. Table 2 shows the 286 format of the + descriptor cache entries.

+


+

+

+
+ + + + + + + + + + + + + + + + +
+ Table 1 -- 80286 LOADALL + Table
Physical AddressDescriptionData SizeData Value

[800]
+ [802]
+ [804]
+ [806]
+ [808]
+ [80A]
+ [80C]
+ [80E]
+ [810]
+ [812]
+ [814]
+ [816]
+ [818]
+ [81A]
+ [81C]
+ [81E]
+ [820]
+ [822]
+ [824]
+ [826]
+ [828]
+ [82A]
+ [82C]
+ [82E]
+ [830]
+ [832]
+ [834]
+ [836]
+ [83C]
+ [842]
+ [848]
+ [84E]
+ [854]
+ [85A]
+ [860]
+ [866]

+
None
+ None
+ MSW
+ None
+ None
+ None
+ None
+ None
+ None
+ None
+ None
+ TR_REG
+ FLAGS
+ IP
+ LDT_REG
+ DS_REG
+ SS_REG
+ CS_REG
+ ES_REG
+ DI
+ SI
+ BP
+ SP
+ BX
+ DX
+ CX
+ AX
+ ES_DESC
+ CS_DESC
+ SS_DESC
+ DS_DESC
+ GDT_DESC
+ LDT_DESC
+ IDT_DESC
+ TSS_DESC
+ ENT OF TABLE
DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DW
+ DESC_CACHE286
+ DESC_CACHE286
+ DESC_CACHE286
+ DESC_CACHE286
+ DESC_CACHE286
+ DESC_CACHE286
+ DESC_CACHE286
+ DESC_CACHE286
+
0
+ 0
+ 0
+ ?
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+
DESC_CACHE286 STRUC
+    Addr_A15_A00 DW ?
+    Addr_A23_A16 DB ?
+    Access DB ?
+    Limit DW ?
+ENDS
+
+

Intel recommends some guidelines for + proper execution following LOADALL. The stack + segment should be a read/write data segment; the code + segment can be execute on1y (access=95h), read/execute + (access=9bh), or read/write/execute (access=93h). Proper + protected mode operation also requires that the DPL of CS + and DPL of SS be equal. These attributes + determine the CPL of the processor. Also, the DPL fields + of ES and DS should be equal to 3 to + prevent RETF or IRET instructions from + zeroing these registers.

+

The code in listing 1 + demonstrates how to exp1ore the various operating modes + with 286 LOADALL and how to access extended memory + while in real mode. The LOADALL test performs + various functions that would be impossible to duplicate + without using LOADALL.

+

80386 LOADALL

+

The 386 LOADALL is encoded as a two-byte opcode + (0F07). Unlike the 286 LOADALL, this LOADALL instruction + reads its data from a table pointed to by ES:EDI. Segment + overrides are allowed, but apparently ignored. The 386 + LOADALL performs 51 bus cycles (DWORD cycles) and takes + 122 clocks with no wait states. Table 3 shows the 386 + LOADALL format. However, Table 3 does + not show that prior to reading the LOADALL table, LOADALL + reads 10 DWORDs exactly 100h bytes beyond the beginning + of the table (ES:EDI+100h). This data is not used to load + any of the registers LOADALL does not load (CR2, CR3, + DRO-DR3, TR6, TR7), or the Numeric Processor eXtension + (NPX). At this time, the purpose of reading this data and + its destination is a mystery. Figure 1 shows an ICE trace + showing all the bus cycles associated with LOADALL's + execution.

+

As with the 286 LOADALL, all CPU register entries in + the LOADALL table are in the standard Intel format where + the least significant byte is at the lowest memory + address. The 386 descriptor cache entries have the format + shown in Table 4.

+

Listing + 2 shows how to test 386 LOADALL. This test is more + comprehensive than the 286 LOADALL test because of the + expanded capabilities of the 386 microprocessor. This + test puts the CPU into various states that are illegal + and are impossible to duplicate through any other + software means.

+

LOADALL Emulation

+

Due to the large number of systems programs that use + 286 LOADALL, all 386 and 486 BIOS's must emu1ate + the 286 LOADALL instruction (opcode 0F05). On + the 386 and 486, the 286 LOADALL instruction + generates an invalid opcode exception. The BIOS traps + this exception and does its best to emulate the + functionality of the LOADALL instruction, but + perfect emulation is impossible without using LOADALL itself. + Using 386 LOADALL to emulate 286 LOADALL can + be done, but has its risks. First of all, the 486 does + not have a LOADALL instruction. Second, Intel has + threatened to remove LOADALL from the 386 mask.

+

Perfect emulation is possible on the 386 by using 386 LOADALL + to emulate 286 LOADALL. Listing 3 + shows a TSR program that uses 386 LOADALL to + emulate 286 LOADALL. The program first tests that + you are a 386 before insta1ling itself. By using this + emu1ation program, you can guarantee perfect 286 LOADALL + emulation.

+

Conclusion

+

LOADALL is a very powerful instruction, but the + features that make it so powerful also make it risky. For + example, LOADALL can put the processor in states + that are otherwise impossible to duplicate through any + other software means. Using LOADALL requires a + thorough understanding of how the CPU processes register + loads, the ramifications of those register loads, and + careful planning. The illegally induced processor states + can easily cause system crashes if not properly planned + for. The best way to avoid system crashes is to avoid + using LOADALL unless you are totally confident in + your understanding of the CPU and in your programming + skills.

+

The 286 LOADALL is described in a 15-page + Intel-confidential document The document describes in + detail how to use the instruction, and also describes + many of its possible uses. LOADALL can be used to + access extended memory while in real mode, and to emulate + real mode while in protected mode. Programs such as + RAMDRIVE, ABOVEDISC, and OS/2 use LOADALL. DOS 3.3 + has provisions for using LOADALL by leaving a + 102-byte 'hole' at 80:0. If you are a systems programmer + and have a need to know this information, Intel will + provide it, along with source code to emulate 286 LOADALL + on the 386 (without using 386 LOADALL).

+

Unlike the 286 LOADALL, the 386 LOADALL is + still an Intel top secret. l do not know of any document + that describes its use, format, or acknowledges its + existence. Very few people at Intel wil1 acknowledge that + LOADALL even exists in the 80386 mask. The + official Intel line is that, due to U.S. Military + pressure, LOADALL was removed from the 80386 mask + over a year ago. However, running the program in + Listing-2 demonstrates that LOADALL is alive, + well, and still available on the latest stepping of the + 80386.

+
+ +

View source code for 286 LOADALL:
+ftp://ftp.x86.org/source/286load/286load.asm
+
ftp://ftp.x86.org/source/286load/loadfns.286
+
ftp://ftp.x86.org/source/286load/macros.286
+
ftp://ftp.x86.org/source/include/cpu_type.asm

+ +

View source code for 386 LOADALL:
+ftp://ftp.x86.org/source/386load/386load.asm
+
ftp://ftp.x86.org/source/386load/loadfns.386
+
ftp://ftp.x86.org/source/386load/macros.386
+
ftp://ftp.x86.org/source/include/cpu_type.asm

+ +

View source code for EMULOAD (286 LOADALL +emulation using 386 LOADALL):
+ftp://ftp.x86.org/source/emuload/emuload.asm
+
ftp://ftp.x86.org/source/include/cpu_type.asm

+ +

Download entire source code archive for 286LOAD, +386LOAD, and EMULOAD:
+ftp://ftp.x86.org/dloads/LOADALL.ZIP

+ +
+ + +
+

+
+ + + + + + + + + + + + + + + + + +
+ Table 2 (a) -- 80286 Descriptor Cache Entry Formats
Offset + Description
0-224-bit physical address of the segment in + memory. These bytes are stored in standard Intel + format with the least significant byte at the + lowest memory address.
3Access rights. The format of this byte is the + same as that in the descriptor table. This access + byte is loaded in the descriptor cache register + regardless of its validity. Therefore the + "present" bit in the access rights + field becomes a "descriptor valid" bit. + When this bit is cleared, the descriptor is + considered invalid, and any memory reference + using this descriptor generates exception 13, + with error code 0. The Descriptor Privilege Level + (DPL) of the SS and CS descriptor caches + determines the Current Privilege Level (CPL). The + CS descriptor cache may be loaded as a read/write + data segment.
4-5Segment limit. The standard 16-bit segment + limit stored in standard Intel format.
+


+
+

+
+ + + + + + + + + + + + + + + + + +
+ Table 2 (b) -- 80286 GDT and IDT Descriptor Cache + Entry Formats
OffsetDescription
0-224-bit physical address of the segment in + memory.
3Should be 0.
4-5Segment limit.
+


+

+
+ + + + + + + + + + + + + + + + + +
+ Table 3 -- 80386 LOADALL + Table
OffsetDescriptionData SizeData Value

[00]
+ [04]
+ [08]
+ [0C]
+ [10]
+ [14]
+ [18]
+ [1C]
+ [20]
+ [24]
+ [28]
+ [2C]
+ [30]
+ [34]
+ [38]
+ [3C]
+ [40]
+ [44]
+ [48]
+ [4C]
+ [50]
+ [54]
+ [60]
+ [6C]
+ [78]
+ [84]
+ [90]
+ [9C]
+ [A8]
+ [B4]
+ [C0]
+ [CC]

+
CR0
+ EFLAGS
+ EIP
+ EDI
+ ESI
+ EBP
+ ESP
+ EBX
+ EDX
+ ECX
+ EAX
+ DR6
+ DR7
+ TR_REG
+ LDT_REG
+ GS_REG
+ FS_REG
+ DS_REG
+ SS_REG
+ CS_REG
+ ES_REG
+ TSS_DESC
+ IDT_DESC
+ GDT_DESC
+ LDT_DESC
+ GS_DESC
+ FS_DESC
+ DS_DESC
+ SS_DESC
+ CS_DESC
+ ES_DESC
+ LENGTH OF TABLE
DD
+ DD
+ DD
+ DD
+ DD
+ DD
+ DD
+ DD
+ DD
+ DD
+ DD
+ DD
+ DD
+ REG_STRUC
+ REG_STRUC
+ REG_STRUC
+ REG_STRUC
+ REG_STRUC
+ REG_STRUC
+ REG_STRUC
+ REG_STRUC
+ DESC_CACHE
+ DESC_CACHE
+ DESC_CACHE
+ DESC_CACHE
+ DESC_CACHE
+ DESC_CACHE
+ DESC_CACHE
+ DESC_CACHE
+ DESC_CACHE
+ DESC_CACHE
+
?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ ?
+ <?>
+ <?>
+ <?>
+ <?>
+ <?>
+ <?>
+ <?>
+ <?>
+ <?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+ <?,?,?>
+
REG_STRUC STRUC
+    REG_VAL    DW     ?
+               DW     0
+ENDS
+
DESC_CACHE STRUC
+              DB     0
+     _Type    DB     ?
+              DB     0
+              DB     0
+     _Addr    DD     ?
+    _Limit    DD     ?
+ENDS
+
+


+

+
+ + + + + + + + + + + + + + + + + +
+ Table 4 (a) -- 80386 Descriptor Cache Entries
Offset + Description
0-3 Access rights. The access rights dword + consumes 11 bits of this 32-bit field. See figure 2 for a + complete description of this field.
4-7 32-bit base address of the segment in + memory..
8-11 32-bit base address of the segment in memory.
+


+
+

+
+ + + + + + + + + + + + + + + + + +
Table 4 (b) -- 80386 GDT + and IDT Descriptor Cache Entry Formats
Offset + Description
0-3 Should be 0.
4-7 32-bit base address of GDTR or IDTR.
8-11 32-bit limit of GDTR or IDTR.
+

+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Figure 1 -- In-Circuit-Emulator + Trace of 80386 LOADALL + Instruction
FrameThe FRAME + number is like a clock count for the CPU. At every CPU + clock, the ICE takes a picture. When a valid cycle + occurs, the ICE records its occurance. Therefore, it is + possible to determine how many CPU clocks a sequence of + instructions takes to execute by reading this + information.
TypeCycle type. + Shown here are F=Fetch, R=Read, and X=eXecute.
AddressThe 32-bit + physical address asserted on the CPU address bus during + each cycle.
DataThe data asserted on the + CPU data bus during each cycle.
BE3#
+ BE2#
+ BE1#
+ BE0#
Byte enable pins on the + CPU. These pins determine which bytes of the 32-bits of + data are valid. These pins are active low, so 8-bits of + data are valid for each '0.'
W/R#Write/Read.Write = 1Read = 0
D/C#Data/Code.Data = 1Code = 0
M/IO#Memory/IOMemory = 1IO = 0
+ + + + + + + + + + + + + + + + + + + +
Frame
+Dec 
+
Type 
+
Address 
+(Hex) 
+
Data
+(Hex) 
+
BBBB
+EEEE
+3210
+#### 
+
WDM
+///
+RCI
+  O
+###
+
Comments
+
5
+8
+011
+013
+015
+017
+019
+021
+023
+025
+027
+029
+031
+033
+035
+037
+039
+041
+043
+045
+047
+049
+051
+053
+055
+057
+059
+061
+063
+065
+067
+069
+071
+073
+075
+077
+079
+081
+083
+085
+087
+089
+091
+093
+095
+097
+099
+101
+103
+105
+107
+109
+111
+113
+115
+117
+119
+121
+123
+125
+127
+129
+131
+
F
+X
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+R
+
0000DE40
+executed
+0000D8F0
+0000D8F4
+0000D8F8
+0000D8FC
+0000D900
+0000D904
+0000D908
+0000D90C
+0000D910
+0000D914
+0000D7F0
+0000D7F4
+0000D7F8
+0000D7FC
+0000D800
+0000D804
+0000D808
+0000D80C
+0000D810
+0000D814
+0000D818
+0000D81C
+0000D820
+0000D824
+0000D828
+0000D82C
+0000D830
+0000D834
+0000D838
+0000D83C
+0000D840
+0000D844
+0000D848
+0000D84C
+0000D850
+0000D854
+0000D858
+0000D85C
+0000D860
+0000D864
+0000D868
+0000D86C
+0000D870
+0000D874
+0000D878
+0000D87C
+0000D880
+0000D884
+0000D888
+0000D88C
+0000D890
+0000D894
+0000D898
+0000D89C
+0000D8A0
+0000D8A4
+0000D8A8
+0000D8AC
+0000D8B0
+0000D8B4
+0000D8B8
+
B490070F
+2bytes
+01010101
+02020202
+03030303
+04040404
+05050505
+06060606
+07070707
+08080808
+09090909
+0A0A0A0A
+7FFFFFE0
+00000002
+00000133
+66666666
+77777777
+55555555
+88888888
+22222222
+44444444
+33333333
+11111111
+FFFF0FF0
+0000D402
+xxxx0000
+xxxx0000
+xxxx5555
+xxxx4444
+xxxx2222
+xxxx6666
+xxxx1111
+xxxx3333
+00008900
+00070000
+00000800
+00000000
+00000000
+000003FF
+00000000
+00000000
+00000000
+00008200
+00090000
+00000088
+00008300
+00050000
+0000FFFF
+00009300
+00040000
+0000FFFF
+00009300
+00020000
+0000FFFF
+00009300
+00060000
+0000FFFF
+00009B00
+0000DD30
+0000FFFF
+00009300
+00030000
+00FFFFFF
+
0000
+at
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+1100
+1100
+1100
+1100
+1100
+1100
+1100
+1100
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+
001
+DE40L
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+011
+
LOADALLfetched
+LOADALLbeginsexecution
+\
+ \
+  \   The10"mystery"
+   \  reads,exactly
+    \ 100hbytesbeyond
+    / thebeginningof
+   /  theLOADALLtable.
+  /
+ /
+/
+CR0
+EFLAGS
+EIP
+EDI
+ESI
+EBP
+ESP
+EBX
+EDX
+ECX
+EAX
+DR6
+DR7
+TRRegister
+LDTRegister
+GSRegister
+FSRegister
+DSRegister
+SSRegister
+CSRegister
+ESRegister
+TSSDescriptorCache
+
+
+IDTDescriptorCache
+
+
+GDTDescriptorCache
+
+
+LDTDescriptorCache
+
+
+GSDescriptorCache
+
+
+FSDescriptorCache
+
+
+DSDescriptorCache
+
+
+SSDescriptorCache
+
+
+CSDescriptorCache
+
+
+ESDescriptorCache
+
+
+
+
+ + +
+
+ + +
+ +

Back to +Books and Articles home page

+ +
+ + + \ No newline at end of file