[comp.sys.intel] Returning the 80286 to real mode

sanders@idec.stc.co.uk (Tom Sanders) (10/27/88)

   Rumour has it that it is possible to switch the 80286 back to real mode
   once having gone protected.  Can anyone advise me how this is done?

Regards,
-- 
Tom Sanders  <sanders@idec.stc.co.uk> or <...mcvax!ukc!idec!sanders>

JANET: sanders%idec@uk.ac.ukc

root@conexch.UUCP (Larry Dighera) (10/31/88)

In article <1081@xenon.idec.stc.co.uk> sanders@idec.stc.co.uk (Tom Sanders) writes:
>
>   Rumour has it that it is possible to switch the 80286 back to real mode
>   once having gone protected.  Can anyone advise me how this is done?
>


Here is a copy of an article that recently appeared in a periodical magizine.
The informatin it contains and the opinions expressed in it are not mine.
I'm sure you will find it useful and informitive.



------------------------  LOADALL DOCUMENTATION  -------------------------

Secret 286 LOADALL instruction allows access to extended memory in real mode.

In last month's article on the P9, we described the method used to access
extended memory (memory beyond the lower 1 megabyte) from real-mode
programs running on a 286.  This method requires switching to protected
mode to perform access, and then resetting the processor to return to
real mode.  We have since learned that there is another way.  An undocumented
286 instruction, LOADALL, allows all of the processor's registers (including
protected mode registers and hidden internal registers) to be loaded, even
when operating in real mode.  By changing the value of the descriptor
cache base register, a program can select a segment beyond the lower 1Mbyte.
LOADALL also has other uses, as described later in this article.

----------------------------------------------------------------------
Physical Memory Address    CPU register
       (hex)
======================================================================
800-805 		   none
806-807 		   MSW (Machine Status Word)
808-815 		   None
816-817 		   TR (Task Register)
818-819 		   Flag Word
81A-81B 		   IP (Instruction Pointer)
81C-81D 		   LDT (Local Descriptor Table)
81E-81F 		   DS (Data Segment Selector)
820-821 		   SS (Stack Segment Selector)
822-823 		   CS (Code Segment Selector)
824-825 		   ES (Extra Segment Selector)
826-827 		   DI (Destination Index)
818-829 		   SI (Source Index)
82A-82B 		   BP (Base Pointer)
82C-82D 		   SP (Stack Pointer)
82E-82F 		   BX (Data Register B)
830-831 		   DX (Data Register D)
832-833 		   CX (Data Register C)
834-835 		   AX (Accumulator)
836-83B 		   ES Descriptor Cache
83C-841 		   CS Descriptor Cache
842-847 		   SS Descriptor Cache
848-84D 		   DS Descriptor Cache
84E-853 		   GDTR (Global Descriptor Table Register)
854-859 		   LDT Descriptor Cache
85A-85F 		   IDTR (Interrupt Descriptor Table Register)
860-865 		   TSS (Task State Segment) Descriptor Cache
=======================================================================
Table 1.  LOADALL data area format
-----------------------------------------------------------------------

Originally included by Intel for chip testing, Microsoft is now using this
instruction in their RAM Drive program and in OS/2's compatibility box.
While this instruction is probably appropriate only for use in operating
systems and system-level utilities, it is important because it provides a
set of capabilities that are not otherwise available in a 286-based system.

We have received a copy of a document that describes LOADALL.  No company
name is shown, but is almost surely written by Intel.  The 15-page
document describes in detail how to use the instruction, so calling it
"undocumented" is not quite correct -- it is documented, but not in the
data sheet.  By restricting access to this documentation, Intel gives unfair
advantage to Microsoft and other large customers.

----------------------------------------------------------------------
Descriptor Cache Format
 Bytes 0-2	24-bit segment base address
 Byte 3 	Access rights byte.  Format is the same as the access
		rights byte in a descriptor, except that the "present"
		bit becomes a "valid" bit.  If a "valid" bit is not
		set, any memory reference using the descriptor will
		cause exception 13 with error code of 0.
Bytes 4-5	16-bit segment size

GDTR and IDTR Format
 Bytes 0-2	24-bit base address
 Byte 3 	0
 Bytes 4-5	16-bit segment limit
----------------------------------------------------------------------
Table 2.  Descriptor Cache Formats

Intel's position is that this instruction is not useful to most users,
and can easily lead to machine crashes if not used properly.  Intel says
that they will provide documentation for the instruction on a "need-to-know"
basis, presumably only after a non-disclosure agreement has been signed.
Most developers, of course, would not know to ask.  The information we are
presenting here should be enough for you to evaluate the usefulness of the
instruction; if you intend to use it in a product, you should contact
Intel for the full documentation.

The opcode for LOADALL is 0F05 hex.  No operands follow the instruction;
LOADALL gets its data from a 102-byte block of memory starting at the
fixed address 800 hex, as shown in Table 1.  Table 2 shows the format of
the descriptor cache entries.  These are hidden registers that cannot
otherwise be modified by the programmer; they are set automatically when
a descriptor is read from the descriptor table.

ACCESSING EXTENDED MEMORY FROM REAL MODE

The following sequence is required to access high memory from real mode
using LOADALL:
  1. Disable interrupts
  2. Save the 102 (decimal) bytes starting at 800 hex.  (MS-DOS uses this
     area for system code.  OS/2 presumably leaves it free for LOADALL,
     but depends on application programs not to change it.)
  3. Set up the 102-byte register image at 800.  The base address in the
     data segment descriptor cache is set to select the desired high-memory
     area.
  4. Execute the LOADALL instruction.  The data segment now points to the
     new, high-memory segment.
  5. Move data to or from high memory.
  6. Restore the base address in the data segment descriptor cache in the
     image at 800, and execute another LOADALL.
  7. Enable interrupts.
  <<< The next step is not in the article, but conspicuously absent. >>>
  8. Restore the original 102 bytes to 800.

Thus while it is appealing not to have to go to protected mode and back to
access high memory from real mode, this isn't much better.  LOADALL requires
195 clock cycles on a machine with no wait states, or 19.5 us at 10Mhz.

LOADALL can also be used to allow programs to be executed in high memory,
even though the processor is in real mode.  A special paragraph ID (such as
FFFF) is used to indicate when a program is running in extended memory.
Interrupt service routines must check the segment register to see if any
contain the special ID, and if so, they must reload the registers using
LOADALL to restore the segment base addresses before returning from the
interrupt.

OTHER APPLICATIONS

LOADALL has other uses as well.  It can be used to switch back to a
protected mode task from real mode, serving as a fast intermode context
switch.  OS/2 presumably uses it to return to protected mode from a
real-mode task running in the compatibility box.

LOADALL can also be used to emulate real mode from protected mode.  By
setting the privilege level of all local and global descriptor table
entries lower than that of the current program, a protection violation
occurs whenever the program attempts to load a segment register.  (Actually,
loading the segment register with a value of 0000 to 0003 does not cause
an exception, and this case must be handled specially.)  The exception
handler then uses LOADALL to set the base address for the segment.

There are many other complexities to this emulation, as described in the
LOADALL document.  The emulation is imperfect, and Microsoft apparently
decided to use the "reset to real mode" technique (as described in our
article last month on the P9), rather than trying to emulate real mode
from within protected mode.

RESTRICTIONS

LOADALL performs no checking on the values loaded into the registers, so
no exception will occur even if an illegal value is loaded.  Thus, the
processor can potential be put into a strange state.  If an illegal
descriptor value is set, no exception occurs from the execution of LOADALL.
An exception will occur, however, when an access  using that descriptor
is attempted.

LOADALL can be executed in protected mode, but only at the most privileged
level (level 0).  Thus it does not violate the protection.  Unfortunately,
LOADALL cannot be used to switch back to real mode from protected mode.

Early versions of 286 (A1 and B1 steppings) have bugs which affect the use
of LOADALL.  Thus, the techniques described in this article may not work
properly on older systems.

LOADALL is not implemented on the 80386, so Microsoft has included code in
OS/2 and in the current version of RAM Drive that tests for the processor
type.  If it's a 286, LOADALL is used, and if it's a 386, the native 386
mechanisms are used.  If you use LOADALL, you should also perform this
check, or your software will not run on 386-based machines.

Using LOADALL is certainly fraught with peril, and requires careful
program design and knowledge of all the implications.  We have spoken with
a number of software vendors that were aware of the instruction, and all
had decided not to use it due to the risks and complexity involved.  We
don't recommend its use to most people, but we do feel that everyone should
have access to the information so they can make their own choice about
whether or not to use the instruction.

-- 
USPS: The Consultants' Exchange, PO Box 12100, Santa Ana, CA  92712
TELE: (714) 842-6348: BBS (N81); (714) 842-5851: Xenix guest account (E71)
UUCP: conexch Any ACU 2400 17148425851 ogin:-""-ogin:-""-ogin: nuucp
UUCP: ...!uunet!turnkey!conexch!root || ...!trwrb!ucla-an!conexch!root

rob@conexch.UUCP (Robert Collins) (11/04/88)

In article <1081@xenon.idec.stc.co.uk> sanders@idec.stc.co.uk (Tom Sanders) writes:
>
>   Rumour has it that it is possible to switch the 80286 back to real mode
>   once having gone protected.  Can anyone advise me how this is done?
>
It is quite possible to return to real mode.  Remember, IBM and everybody
else MUST perform memory testing in protected mode.  When YOU get control
of your computer, you are in REAL mode.

One of the many reasons software engineers HATE the 80286 is because of
the lack of a built-in mechanism for switching to REAL mode from protected
mode.  The 386 has this feature built in.  But, in the 286, the proccess
in quite involved.  The process involves actually shutting down the
processor.  This is typically done by sending a command to the keyboard
controller (yeah, the keyboard controller).  But here is a synopsis of
exiting to real mode from protected mode.
* While in real mode, write a byte to CMOS to indicate the 'type' of
  shutdown that will occur (Kludge #1)
* While in real mode, write the return address (real mode address)
  down in 40:XXX.  (Kludge #2)
* Enter protected mode
* Write the appropriate command to the keyboard controller to shutdown
  the processor.  (KLUDGE #3)

If memory serves me correctly, IBM states that the processor shutdown
will typically take 60ms to take place.  One the processor shuts down,
you go executing the ROM BIOS @ F000:FFF0.  Before POST (Power On Self
Test), the BIOS checks for a 'magic' byte down in CMOS.  IF such a magic
byte appears, then POST says "Oh, I get it, I'm really returning from
protected mode."  (What is completely hidden from you, at this point,
is the fact that when the processor is reset, it automatically is in
REAL mode.)  After POST determines there is a 'magic' byte in CMOS,
he goes and does a FAR JUMP to the location you put in memory @ 40:XXX.
(Kludge #4)

So, the bottom line is this:  Kludge #3 takes ~60ms.  Kludge #4 takes
another few ms.  In other words, it's SLOW!  There is another MUCH
more elegant way to cause a processor shutdown without using the
keyboard controller.  In fact, it takes ~1ms (or less).  This method
involves telling the processor you will service NO interrupts, (lidt to
a idt w/ 0 entries), then generate an interrupt.  Since the processor
can't service the interrupt, it generates an exception.  The exception
also can't be service (since you hosed IDT), which will in turn will
reset the processor.  The former method is rather well documented in
magazines, and the IBM tech-ref manual.  The latter method was
developed by a friend of mine, so I don't feel comfortable telling any
more than I already have.  But I will give you a hint:
executing a 386 instruction on the 286 will cause the desired exception.
I'll let you figure out the most elegant 386 instruction to use for
this purpose!

-- 
"Worship the Lord your God, and serve him only."  Mat. 4:10
Robert Collins                 UUCP:  ucbvax!ucivax!icnvax!conexch!rob
HOMENET:  (714) 995-7344       UUCP:  uunet!ccicpg!turnkey!conexch!rob
WORKNET:  (714) 229-0284

ralf@b.gp.cs.cmu.edu (Ralf Brown) (11/06/88)

(someone from Intel will no doubt correct any errors in the following)

In article <11367@conexch.UUCP> rob@conexch.UUCP (PUT YOUR NAME HERE) writes:
}If memory serves me correctly, IBM states that the processor shutdown
}will typically take 60ms to take place.  One the processor shuts down,

More like 600 microseconds.  If it were 60ms, VDISK could only service 16 
requests per second, for a maximum possible throughput of 64K/s (8 512-byte 
sectors).

}So, the bottom line is this:  Kludge #3 takes ~60ms.  Kludge #4 takes
}another few ms.  In other words, it's SLOW!  There is another MUCH
}more elegant way to cause a processor shutdown without using the
}keyboard controller.  In fact, it takes ~1ms (or less).  This method
}involves telling the processor you will service NO interrupts, (lidt to
}a idt w/ 0 entries), then generate an interrupt.  Since the processor
}can't service the interrupt, it generates an exception.  The exception
}also can't be service (since you hosed IDT), which will in turn will
}reset the processor.  The former method is rather well documented in

The processor is only reset by an external signal.  What happens is that
the triple exception generated by the above puts the processor in SHUTDOWN
mode.  The PC/AT contains external circuitry to assert the reset line when
the processor goes into SHUTDOWN.  Since the processor is reset, you still
need kludges #1, 2, and 4 (magic CMOS byte, return address, FAR jump in BIOS).

}executing a 386 instruction on the 286 will cause the desired exception.
It generates an "undefined opcode" exception.


-- 
{harvard,uunet,ucbvax}!b.gp.cs.cmu.edu!ralf -=-=- AT&T: (412)268-3053 (school) 
ARPA: RALF@B.GP.CS.CMU.EDU |"Tolerance means excusing the mistakes others make.
FIDO: Ralf Brown at 129/31 | Tact means not noticing them." --Arthur Schnitzler
BITnet: RALF%B.GP.CS.CMU.EDU@CMUCCVMA -=-=- DISCLAIMER? I claimed something?

mslater@cup.portal.com (Michael Z Slater) (11/07/88)

> .. a copy of an article that recently appeared in a periodical magazine

> .... long article describing the 286 LOADALL instruction

I wrote that article on the 286 LOADALL instruction, and while I don't at
all mind sharing of information, I have to point out that that article is
from the October 1987 Microprocessor Report, and is copyrighted.  I wouldn't
have objected to it's posting if the poster at least said where it came from.

And besides, LOADALL is not the solution to the problem proposed.  It does
NOT provide a way to switch from protected mode to real mode; rather, it
provides a way to do some things in real mode that most people assume they
have to be in protected mode to do (like access memory beyond 1 Meg).

Michael Slater, Editor and Publisher, Microprocessor Report
mslater@cup.portal.com
550 California Ave., Suite 320, Palo Alto, CA 94306   415/494-2677

rob@conexch.UUCP (Robert Collins) (11/11/88)

In article <3493@pt.cs.cmu.edu> ralf@b.gp.cs.cmu.edu (Ralf Brown) writes:
+(someone from Intel will no doubt correct any errors in the following)
+
+In article <11367@conexch.UUCP> rob@conexch.UUCP (Robert Collins) writes:
+}If memory serves me correctly, IBM states that the processor shutdown
+}will typically take 60ms to take place.  One the processor shuts down,
+
+More like 600 microseconds.  If it were 60ms, VDISK could only service 16
+requests per second, for a maximum possible throughput of 64K/s (8 512-byte
+sectors).
+
Thank you, as I said...if memory serves me correctly.  You are very much
right about the 600 microseconds.  But, I might point out that 600uS
is the time for the keyboard controller to respond to the command.  But,
I suppose the time to actually shut down the processor is negligable.
We found, that the ACTUAL time to perform the shutdown was closer to
1mS (as opposed to 600uS).

+}So, the bottom line is this:  Kludge #3 takes ~60ms.  Kludge #4 takes
+}another few ms.  In other words, it's SLOW!  There is another MUCH
+}more elegant way to cause a processor shutdown without using the
+}keyboard controller.  In fact, it takes ~1ms (or less).  This method
+}involves telling the processor you will service NO interrupts, (lidt to
+}a idt w/ 0 entries), then generate an interrupt.  Since the processor
+}can't service the interrupt, it generates an exception.  The exception
+}also can't be service (since you hosed IDT), which will in turn will
+}reset the processor.  The former method is rather well documented in
+
+The processor is only reset by an external signal.  What happens is that
+the triple exception generated by the above puts the processor in SHUTDOWN
+mode.  The PC/AT contains external circuitry to assert the reset line when
+the processor goes into SHUTDOWN.  Since the processor is reset, you still
+need kludges #1, 2, and 4 (magic CMOS byte, return address, FAR jump in
+BIOS).
+

Sorry if I said "reset" I meant shutdown.  Though, I'll admit, I didn't
know (nor know of the) difference between the two.  And sorry if I implied
the other kludges weren't necesary.  They most certainly are necesary, but
using the keyboard controller isn't!

>}executing a 386 instruction on the 286 will cause the desired exception.
>It generates an "undefined opcode" exception.

And that's the whole key.  Generating the "invalid opcode" exception
will lead to a processor shutdown.  Which switches back to real mode,
and starts execution back at 0f000:0fff0.

When we did the timing tests, we found that this method was about 88%
faster than using the keyboard controller...the time was closer to
400uS from the time the invalid ipcode was executed to the time control
was returned to the original program.


-- 
"Worship the Lord your God, and serve him only."  Mat. 4:10
Robert Collins                 UUCP:  ucbvax!ucivax!icnvax!conexch!rob
HOMENET:  (714) 995-7344       UUCP:  uunet!ccicpg!turnkey!conexch!rob
WORKNET:  (714) 229-0284

sanders@idec.stc.co.uk (Tom Sanders) (12/01/88)

A while ago I sent an article asking if this could be done.  Netters
will have seen the replies.

Most replies assumed a PC/AT hardware environment, which was my own fault
for not making myself clear.  Also, all I really wanted to do was reset
the processor.

In fact, my hardware is an Intel iSBC 286/12 board.
                                 ^^^^
                                   c Intel.

This supports a soft reset by writing byte 01 to port 00E0, as anyone
with the Hardware Reference Manual can look up themselves!  Still,
the replies were interesting.

Regards,
-- 
Tom Sanders  <sanders@idec.stc.co.uk> or <...mcvax!ukc!idec!sanders>

JANET: sanders%idec@uk.ac.ukc