• Please review our updated Terms and Rules here

I found the SAVEALL opcode

dreNorteR

Experienced Member
Joined
Dec 19, 2016
Messages
119
Everyone who is interested in this sort of thing already knows about the LOADALL instruction. But what Intel didn't include in this no-longer-secret document is that there is an instruction that does the reverse, and it can be used on a regular 286 chip without extra pins.

There is one hint in Intel's attempts at misdirection:

The opcode 0D6H is a proprietary single byte instruction. No restrictions apply to its execution. It can be emulated as a NOP.

The 0F1H opcode is a prefix which performs no function. It counts like any other prefix towards the maximum instruction length. No restrictions apply to its execution.

D6 does do something of course, and I suspected F1 might as well. Note it says that it is a prefix!

Executing 0F 04 will lock up the CPU without doing anything. With the F1 prefix, it appears at first to do the same, but the internal state is actually written to memory at 000800H! All we need is a short timeout before resetting the CPU, and the keyboard controller is slow enough to work for that.

This might be helpful to investigate some internal details, the 10 extra words ignored by LOADALL are written too. Maybe also for a debugger (if only there was a way to interrupt without changing any descriptor caches!)
 

Attachments

  • saveall.zip
    2.1 KB · Views: 4
Is this 80286 only or does it also apply to later CPUs? Is it uniformly implemented in the second source 80286 and 80C286 CPUs?

I assume it works on every 286, but not on any later generation, since they don't have the 286 version of LOADALL. Maybe there is something similar on 386s, I don't have any to test this with.
 
N80C286-12
ET 037E6KX
(M) AMD
(C) INTEL 1982

Results:
Code:
(clean boot, no HIMEM.SYS)
???? ???? ????  MSW stk? ???? ???? ???? ???? ???? ????
0018 9310 00AD FFF0 03AE 0000 00E6 0000 0000 03B0 0002

(with HIMEM.SYS)
0000 9315 00AD ...

My other 286:
Harris
CS80C286-16
F3360 (delta) 8929
(C) INTEL '82

Hangs, which shouldn't happen - likely a problem with the mainboard, BIOS or my reset code. I'll try the chip in the first machine later.
 
Tested the Harris chip and another AMD in the same machine, they all work. There are some differences in both unitialized descriptors and the unknown registers, as seen after a clean boot:

Code:
N80C286-12
ET 037E6KX
(M) AMD
(C) INTEL 1982

???? ???? ????  MSW stk? ???? ???? ???? ???? ???? ????
0018 9310 0164 FFF0 03BE 0000 00E6 0000 0000 03C0 0060 

TASK FLAG   IP  LDT   DS   SS   CS   ES
0000 0046 016B 0000 0F9A 0F9A 0F7E 0F9A 

  DI   SI   BP   SP   BX   DX   CX   AX
04C0 0900 091C 03C0 0000 0171 0F7E 00FE 

ESbase ar  lim CSbase ar  lim SSbase ar  lim DSbase ar  lim
00F9A0 82 FFFF 00F7E0 82 FFFF 00F9A0 82 FFFF 00F9A0 82 FFFF 

GDTbas ar  lim LDTbas ar  lim IDTbas ar  lim TSSbas ar  lim
08F866 FF FFFF 000000 7F 0000 000000 FF FFFF 000000 FF 0000 
------

HARRIS
CS80C286-16
F3360 Δ 8929
(C) INTEL '82

???? ???? ????  MSW stk? ???? ???? ???? ???? ???? ????
0018 9310 0164 FFF0 03BE 5EEC 00E6 CD8D 8BFC 03C0 0060

TASK FLAG   IP  LDT   DS   SS   CS   ES
0000 0046 016B 0000 0F9A 0F9A 0F7E 0F9A

  DI   SI   BP   SP   BX   DX   CX   AX
04C0 0900 091C 03C0 0000 0171 0F7E 00FE

ESbase ar  lim CSbase ar  lim SSbase ar  lim DSbase ar  lim
00F9A0 82 FFFF 00F7E0 82 FFFF 00F9A0 82 FFFF 00F9A0 82 FFFF

GDTbas ar  lim LDTbas ar  lim IDTbas ar  lim TSSbas ar  lim
08F866 FF FFFF FFFFFF FF FFFF 000000 FF FFFF FFFFFF FF FFFF

------

AMD
N80L286-10/S
003D42S
(M) (C) INTEL 1982

???? ???? ????  MSW stk? ???? ???? ???? ???? ???? ????
0018 9310 0164 FFF0 03BE FFFF 00E6 FFFF FFFF 03C0 0060

TASK FLAG   IP  LDT   DS   SS   CS   ES
0000 0046 016B 0000 0F9A 0F9A 0F7E 0F9A

  DI   SI   BP   SP   BX   DX   CX   AX
04C0 0900 091C 03C0 0000 0171 0F7E 00FE

ESbase ar  lim CSbase ar  lim SSbase ar  lim DSbase ar  lim
00F9A0 82 FFFF 00F7E0 82 FFFF 00F9A0 82 FFFF 00F9A0 82 FFFF

GDTbas ar  lim LDTbas ar  lim IDTbas ar  lim TSSbas ar  lim
08F866 FF FFFF FFFFFF FF FFFF 000000 FF FFFF FFFFFF FF FFFF

I also did a quick check of which registers can be changed using LOADALL (on the 80C286-12):

0800 writable
0802 only some bits, CPL/access rights?
0804 no change
0808 no change, copy of SP before last push/pop?
080A writable
080C writable
080E writable
0810 writable
0812 no change
0814 no change
 
dreNorteR,

This is very interesting. A couple of questions:
What happens if you run the following in DEBUG under DOS 3.3 or 4.0/4.01 (those versions of DOS reserve 102 bytes at 0:800h for LOADALL use by HIMEM.SYS):

e 100 f1 0f 04 cc 90
g
d 0:800

Theoretically since DOS 3.3 and 4.0/4.01 reserve 102 bytes in the IBMBIO/IO.SYS data area this should not hang DOS since no system data will be overwritten.

Also what happens if you use F0 instead of F1 as the first byte ? If F0 works the same as F1 then this would show that F1 is an alias for F0 (LOCK) on the 286.
 
I made a program that lets you interactively change the registers. A "Load+Save" function sets everything up to immediately start the reset and save operation:

Code:
;come here by LOADALL, DX=0064, AL=FE
out dx,al
db 0f1h,0fh,04h
;can resume here with another LOADALL
jmp hello_world

All registers except for X1 and maybe X8 are writable, some just don't keep their value for much more than these minimal instructions. Changing them doesn't have any observable effect so far. Would be kind of disappointing if there isn't some secret debug mode to be enabled...

800 'X0' ???
802 'X1' ??? (read-only? high byte always 93 or 83)
804 'X2' IP after last CALL or near RET
808 'X3' Value of SP before last stack access
80A 'X4' ???
80C 'X5' ???
80E 'X6' ???
810 'X7' ???
812 'X8' (loses written value) SP after last RET
814 'X9' IP after last RETF or IRET

X4 (but not X5), X6 and X7 persist after Ctrl-Alt-Del on my machine.
X5 (but not X4), X6 and X7 after CPU reset.
X8 seems to have another temporary use that makes it change immediately. Maybe I/O instructions?

Can anyone try if this works at all on their machine?

edit: very quick & dirty user interface, doesn't support mono video card
 

Attachments

  • undoc286.zip
    1.5 KB · Views: 3
Made a few improvements, like monochrome support and more reliable reset code. I didn't enable A20 before, since it worked for me without that, but many machines apparently require this. Also disabling the keyboard so it can't interfere during reset, which seems to have fixed some random hangs for me.

Still only works on one of my two machines, so I really want someone else to try it!
(Reset and LOADALL work on both, only SAVEALL hangs)

F1: Set up defaults for LOADALL (also done at start)
F2: Test CPU reset
F3: Test SAVEALL on its own
F4: Test LOADALL on its own
F5: LOADALL -> reset+SAVEALL immediately afterwards
F6: Same, but starts reset even before LOADALL

Starting the reset command before LOADALL seems to be just as reliable. And X8 is used by the LOADALL microcode itself, which is why it is set to 0864 - the address of the last word loaded.

-----

So what is the F1 prefix really? I don't think Intel added this just to be extra sneaky, there must be a technical reason. Some research / speculation:

The original purpose of LOADALL was to return from ICE mode (similar to SMM on newer CPUs), loading all the internal registers is just a necessary part of that. When LOADALL is executed in ICE mode, the state would be loaded from its own special address space that uses extra pins, which are likely not connected on a normal 80286 chip.

0F 04 must then be the opcode to enter ICE mode, and the CPU switches immediately to this separate address space, waiting forever for a ready signal on the non-connected pins. But there must be a way for ICE mode to access the memory of the program being debugged. The 80386 has the UMOV instruction for this.

So it is likely that this is the function performed by the F1 prefix on the 286 (which is different from the 386's ICEBP opcode): it modifies an instruction to access memory using the normal bus pins. Outside of ICE mode, it has no effect, as Intel documented. The one exception is 0F 04, because when executing the state save it has already switched modes.

Unfortunately, the mode switch seems to clear the prefetch queue, so we can't get it to execute an instruction in ICE mode (like F1 0F 05 to resume normal execution, although there is another reason this couldn't work - can you see why?).

I also couldn't get a triple fault by setting the IDT limit to zero and enabling the trap flag just before switching. Either these registers are reset, or the CPU gets stuck before a trap can occur.
 

Attachments

  • undoc286.zip
    1.6 KB · Views: 2
Last edited:
Well, you can see why the F1 instruction went undocumented--on the 80386 and higher, it serves a different function--so called "ICEBP" INT 01 instruction. I wonder if other F1 xx opcodes on the 80286 tie in with the bond-out 80286 used in ICE.

The instruction clutter got so bad with later CPUs that Intel eventually had to have two "official" undocumented opcodes for the software emulators (UD1 and UD2).
 
Well, you can see why the F1 instruction went undocumented--on the 80386 and higher, it serves a different function--so called "ICEBP" INT 01 instruction. I wonder if other F1 xx opcodes on the 80286 tie in with the bond-out 80286 used in ICE.

Yes, F1h on the 286 is a prefix, and different from ICEBP which is a single byte opcode for 386+

Its likely function is to access user memory from ICE mode, which explains how it interacts with 0F 04. But of course we can't know for sure, unless someone who actually worked at Intel on the 286 design confirms this.
 
Yes, F1h on the 286 is a prefix, and different from ICEBP which is a single byte opcode for 386+

Its likely function is to access user memory from ICE mode, which explains how it interacts with 0F 04. But of course we can't know for sure, unless someone who actually worked at Intel on the 286 design confirms this.

Try replacing F1h with F0h and executing F0h 0Fh 04h and see what happens (see my earlier post in this thread).
 
Try replacing F1h with F0h and executing F0h 0Fh 04h and see what happens (see my earlier post in this thread).

Sorry, didn't see your post!

F1 is not an alias for F0, nothing will get written to memory if you use the F0 prefix. Also, whether you use the correct prefix or not, the CPU will hang and has to be reset to regain control. Using the keyboard controller (output FEh to port 64h) works because there is a delay long enough that the instruction can execute first.

My test program saves the data at 0800, so it will run under DOS 6.22.
 
Having tested some more, it seems that all the extra registers are simply temporary values used by certain instructions. X1 must be involved in privilege checking and FPU emulation; for some reason, LOADALL will leave a copy of the word containing access rights of the ES (not CS or SS) descriptor there. Floating point opcodes load it with MSW.

X0 and X4-X7 are all used in protected mode, as can be seen after starting and exiting Windows 3.0.

So, no hidden features to unlock, and apart from the descriptor caches it seems rather useless for debugging too. I wonder if Intel actually had a need to save this particular information, or if it is just a side effect of how the state saving works?

I think there is not much more to discover about this, except for the actual code used by Intel in their I²ICE system. From reading the documentation archived on bitsavers, the code for the probe module is not in ROM but loaded by the host software, from a file called I2ICE.286. A disassembly of that could confirm the actual intended use of the F1 prefix.

edit:
Apparently Intel referred to this instruction as STOREALL - https://www.pcjs.org/pubs/pc/reference/intel/80386/loadall/
Thanks for the link (now I can see your post for some reason, must be the "new user" filter), wouldn't have expected this page to have information on the 286. This seems to confirm what I found out with my experiments:

The 286 also loads a number of temp registers, but the values in these registers are “dead” when the next instruction (other than STOREALL) begins execution. Consequently, the values loaded into the temp registers can have no effecton 286 program execution, so these can be ignored. As long as the 386 temps are also “dead” when the next instruction begins (except for STOREALL), there will be no problems with 386-specific temp registers.
 
Last edited:
Back
Top