From: Mark Dixon Subj: LOADALL ________________________________________________________________________ > I know from past threads that LOADALL is an intruction available > on 80x86 CPU's with a protected mode that is undocumented by INTEL > but was used by Microsoft in their VDISK program, amoung other > places. I have rather fragmentary information suggesting that > there is "another" LOADALL instruction on 80386+ chips, perhaps > only a BIOS emulation (?) of the 286's LAOADALL. Apparently, so my doc's tell me, the actual instruction is only present on 286 processors, but that 386+ processors have similar functions that allow it to achive the same thing. So it's just a matter of detecting 286/386 and using the appropriate routine.... Anyway, here's a few extracts from my doc's on loadall ; Some uses for the Loadall instruction (just to get your mind going) : - getting at all the memory in your machine at will, even if it is addressed above 1 megabyte, from real mode. - executing real-mode programs in ram above one megabyte. - installing a second operating-system-like program, or command proces- sor, or shell, in memory above 1 megabyte, and alternating between that and DOS. - installing most of the guts of custom TSR's, shells, and device-driv- ers in ram above 1 megabyte (freeing up precious base memory), leaving in low memory only the stubs to call the code upstairs. - writing very large programs, which are "split", and have half the program residing in the low-down 640K, and the other half up in extended memory, and running in either real or protected mode. - installing large protected-mode programs in extended memory, where they will not conflict with, or crowd out DOS, and ping-ponging between them and DOS. - switching to protected mode. - emulating real mode from protected mode (tough, and full of gotchas, but still worth mentioning). - this is really off-the-wall, but possible: building automata that use Loadall to warp from state to state, sort of like a computer game of Life, played in the twilight zone. LOADALL Okay, so what IS the Loadall instruction? Simple: *** 0F 05 hex *** So how does it work? Well, I've already told you the gist of it: all CPU registers are loaded from a 51-word table of data that starts at 80:0h (absolute 24-bit address 800h). This address is one thing that cannot be changed or re-programmed. It's hard-wired into the chip, and that's that. And that's unfortunate, because all versions of anybody's DOS earlier than version 3.3 use that area for critical system code. Loadall takes no operands, and is just a two-byte instruction. All the "operands" for the instruction are obtained from the table at 80:0h. Just put "db 0Fh, 05" in your code stream, and watch the fun. But you had better get that table right before you do, or else... (crash). ** THE LOAD TABLE ** ----------------------------------------------------------- Address Size CPU register (words) ----------------------------------------------------------- 800 3 unused (?? I don't believe it.) 806 1 MSW (Machine Status Word) 808 7 unused (?? I don't believe it.) 816 1 TR (Task Register) 818 1 Flag Word 81A 1 IP (Instruction Pointer) 81C 1 LDT (Local Descriptor Table) 81E 1 DS (Data Segment, or DS Selector) 820 1 SS (Stack Segment, or SS Selector) 822 1 CS (Code Segment, or CS Selector) 824 1 ES (Extra Segment, or CS Selector) 826 1 DI (Destination Index) 828 1 SI (Source Index) 82A 1 BP (Base Pointer) 82C 1 SP (Stack Pointer) 82E 1 BX (Data Register BX) 830 1 DX (Data Register BX) 832 1 CX (Data Register BX) 834 1 AX (Data Register BX) 836 3 ES Descriptor Cache 83C 3 CS Descriptor Cache 842 3 SS Descriptor Cache 848 3 DS Descriptor Cache 84E 3 GDTR (Global-Descriptor-Table Register) 854 3 LDTDC (Local-Descriptor-Table Descriptor Cache) 85A 3 IDTR (Interrupt-Descriptor-Table Register) 860 3 TSSDC (Task-State-Segment Descriptor Cache) total = 33h words == 102. bytes AND A PRETTY-TOGETHER DEFAULT TABLE So here's what a default Loadall table looks like. Note that "new_Reg_Buf" doesn't label any data item that we really use; it's the name of the whole table. ; LOADALL Register Load Table for new values to be loaded ; into registers by a Loadall. new_Reg_Buf dw 3 dup (0) ; unused space newMSW dw 0 newDead dw 7 dup (0) ; unused space newTR dw 0 newFlagWord dw 0 newIP dw offset after_ldall ; * may chng newLDT dw 0 newDS dw 0 ; *chng newSS dw 0 ; *chng newCS dw 0 ; *chng newES dw 0 ; *chng newDI dw 0 newSI dw 0 newBP dw 0 newSP dw 0 ; *chng newBX dw 0 newDX dw 0 newCX dw 0 newAX dw 0 newESDC dw 0, 9300h, 0FFFFh ; *chng newCSDC dw 0, 9300h, 0FFFFh ; *chng newSSDC dw 0, 9300h, 0FFFFh ; *chng newDSDC dw 0, 9300h, 0FFFFh ; *chng newGDTR dw D8A0h, 0FF00h, 88h ; @ 0D8A:0 *n newLDTDC dw 0, 0FF0Eh, 88h ; @ E000:0 newIDTR dw 0, 0FF00h, 0FFFFh ; @ 0000:0 *n newTSSDC dw 4000h, 0FF0Eh, 800h ; @ E400:0 Those "*chng" comments mean that those items MUST be changed by the running program before actually doing the Loadall. We cannot correctly default them in the sources because the correct values can only be determined at runtime. The "*n" means that those values are not really in the default tables in the sources: the running program uses the sgdt and sidt instructions to get those values and then plugs them into those two entries. Just letting you see what they will look like. You could have anything in the original table there, because the running program will over-write those items with correct values anyway. The "@ 0D8A:0" comments are just noting the addresses in those items, in a more readable form. THE PROCEDURE FOR USING LOADALL (the ultra-safe, long procedure) 1. Save the original machine state, so you have a state to return to. This information can be saved in a Loadall table, which is the most convenient form for later use. 2. Disable interrupts. Just in case. We want a clean copy of area 80. 3. Save the 102-byte (33h words) block of data located at 80:0h. Ver- sions of DOS (both PC- and MS-) earlier than 3.3 use this area for critical system code, and as of DOS 3.3, RamDrive.Sys, and Himem.Sys use this area for their own Loadall tables. 4. Re-enable interrupts. Let the clock ticks, or whatever, through, while we do the following step. 5. Set up the new Loadall table (new_reg_buf), which defines the new state we want to warp to. 6. Disable Interrupts. 7. Copy the new Loadall table to 80:0h. 8. Execute a Loadall. 9. Do something or other with your new machine state. Read or write extended memory, run code upstairs, or whatever. 10. Copy the "old" Loadall table, containing the saved machine state, down to 80:0. 11. Do another Loadall (Un-Loadall.) This restores the original machine state. 12. Copy the block of saved data back to 80:0h. 13. Re-enable interrupts. Well, I hope that helps a bit. This is just a small bit out of some 45k doc file I have on the subject. If you were really interested (though, this is most of the important stuff here) I could netmail it bit by bit... Mark.