linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* The well-factored 386
@ 2003-07-28 16:02 Jack Dennon
  2003-07-28 16:32 ` David S. Miller
  0 siblings, 1 reply; 32+ messages in thread
From: Jack Dennon @ 2003-07-28 16:02 UTC (permalink / raw)
  To: linux-kernel


hmm...didn't seem off-topic to me.
Anything about 386 hardware would seem
to be rather closely related to Linux
assembly language programming.
jdennon@seasurf.com

^ permalink raw reply	[flat|nested] 32+ messages in thread
* Re: The well-factored 386
@ 2003-07-29 12:59 John Bradford
  2003-07-29 13:32 ` Ville Herva
  0 siblings, 1 reply; 32+ messages in thread
From: John Bradford @ 2003-07-29 12:59 UTC (permalink / raw)
  To: helgehaf, jamie; +Cc: linux-kernel

> > I didn't realise he was talking about an x86 emulator.  I thought he
> > was analyzing real hardware.
> > 
> > The one thing that made it on-topic for me was his quiet suggestion
> > that "forreal" mode interrupts are faster, and that it might, perhaps,
> > be possible to modify a Linux kernel to run in that mode - to take
> > advantage of the faster interrupts.
>
> That would have to be a kernel for very special use.  The "forreal"
> mode has protection turned off.  As far as I know, that
> means any user process can take over the cpu as if
> it was running in kernel mode.
>
> Perhaps useful for some embedded use with only a couple well-tested
> processes running.  Still, a programming error could overwrite
> kernel memory instead of segfaulting.

Anything that's single user and non-networked isn't beyond the realms
of feasability - it would be useful for a games console, or high
performance graphics work.

It would be an interesting project, but what concerns me is how well
implemented these non-standard modes actually are.  It's possible that
there are processors out there that don't work reliably with them, or
don't implement them at all.

John.

^ permalink raw reply	[flat|nested] 32+ messages in thread
* The Well-Factored 386
@ 2003-07-28  8:44 Rick A. Hohensee
  2003-07-28 14:06 ` David S. Miller
  0 siblings, 1 reply; 32+ messages in thread
From: Rick A. Hohensee @ 2003-07-28  8:44 UTC (permalink / raw)
  To: linux-kernel, linux-assembly

The four actual main modes of the 386

Operation of the INTeL 80386 is clearly much more flexible than currently
used, as far as the basic states the machine can run in. "Real Mode" and
"Protected Mode" are two possibilities out of several that are concievably
useful. It can be seen from things that are possible in "Real Mode", such
as "Unreal Mode", use of 386-era instructions and so on, that the
canonical modes are not monolithic entities, but are cases of various
combinations of discrete state switches. There is no 8086 in a 386.
Canonical Wake-up Real Mode, which I will refer to as CWR Mode, seems to
be how these several state switches are set at machine reset, but are
semantically just settings of independant things, and clearly CWR Mode can
be set up from individual settings available to the user. This is also
much more evident from a careful traversal of the detailed instruction
specs in the INTeL Programmer's Reference (386INTEL.TXT) for the 80386.

I'd say the two most global switches in the machine are the PE bit,
Protection Enabled, quite sensibly placed at bit 0 in control register 0,
and the D bit of the active code segment descriptor affiliated with CS,
the Default Bit. Two bits gives four possible states. All four are capable
of being the default mode of a system. Two are used as such; CWR Mode and
Protected Mode. Here's a breakdown and some neologizing...


        PE=0    Dbit=0          (un)Real Mode
        PE=0    Dbit=1          Forreal Mode
        PE=1    Dbit=0          Veal Mode  (BKA "286 task")
        PE=1    Dbit=1          Protected Mode


The documented modes are the outside cases in a binary-count listing,
where PE=Dbit. There's a very good reason for that. IRET is sensitive to
Dbit, whereas interrupts push a stack frame of operands sized in
accordance with PE. This is some of INTeL's* description of the action of
INT, which represents all interrupts in this regard, when PE=0...

IF PE = 0
THEN GOTO REAL-ADDRESS-MODE;

REAL-ADDRESS-MODE:
   Push (FLAGS);
   IF <! 0; (* Clear interrupt flag *)
   TF <! 0; (* Clear trap flag *)
   Push(CS);
   Push(IP);
   (* No error codes are pushed *)
   CS <! IDT[Interrupt number * 4].selector;
   IP <! IDT[Interrupt number * 4].offset;


That is, IP is pushed if PE=0, not EIP. FLAGS is also a dual (a "word" in
INTeLese, 16 bits). Thus if, for example, you are in Forreal Mode, you get
a 6-byte stack push of FLAGS, CS and then IP on an interrupt, and the
corresponding IRET will later pop 12 bytes for basically the same 3
registers, and the system streaks off to the big bitbucket in the sky.

HOW ever, IRET is only PARTIALLY sensitive to Dbit. What I didn't say a
moment ago is that IRET is really sensitive to the current effective code
size, of which the D bit is just one component. If we prefix the IRET in a
Forreal Mode interrupt handler with 0x66, the other-operand-size prefix,
it will pop duals in a use32 CS. The interrupt occuring with PE=0 pushed
duals. It works. The inside cases of Veal Mode and Forreal Mode simply
need thier IRETs un-default-sized. In Veal Mode you coerce IRET into using
quads in a use16 code segment, and in Forreal Mode the same prefix in a
use32 code segment will coerce the IRET pops to duals. In Veal Mode, where
PE=1 when an interrupt occurs, you also have the option of handling the
interrupt with a Dbit=1 segment for the pertinent interrupt handler, in
which case it can IRET back to Veal Mode with a naked IRET. I suppose you
can also segregate Veal Mode segments with thier descriptor bases and
limits. In all the quirkiness of the 386, the broad orthogonality of the
other-sizing prefixes is quite refreshing, and even works on stuff like
POPA.

This is from the blow-by-blow description of IRET...

   IF OperandSize = 32 (* Instruction = IRETD *)
   THEN EIP <! Pop();
   ELSE (* Instruction = IRET *)
      IP <! Pop();

Again, OperandSize is Dbit as effected by a possible prefix.

This is why INTeL only mentions Veal Mode as "286 tasks". Tasks don't
IRET. Most of what a 386 provides big facilities for, like tasks, can also
be done piecemeal, as would be the case running a system in straight
Forreal Mode.

Canonical Wake-up Real Mode and Unreal Mode are two flavors of the same
basic setting of PE and Dbit. The difference is in segment limits. This
points up a basic concept here. 8086-style segments are a lightweight
layer that may or may not be active, but 386 segments are always active.
PE=0 does not turn them off. PE=0 means you can't change them until you
turn PE back to 1. PE should be called "PCE, Protections Changes Enabled".

This means the four basic modes have a state diagram about like so...


                         _______________
                        |    WAKE-UP    |
                        |canonical rmode|
                        |  PE=0 use16   |
                        |_______________|
                            A        |set PE to 1
                            |        |
                 set PE to 0|        |
                         ___|________V__
                        |     Veal      |
                        |     Mode      |
                        |   PE=1 use16  |
                        |_______________|
                            A       |far xfer
                            |       | to use32 CS
                far xfer to |       |
                    use16 CS|       |
                         ___|_______V___
                        |   Protected   |
                        |      Mode     |
                        |   PE=1 use32  |
                        |_______________|
                            A        |set PE to 1
                            |        |
                 set PE to 0|        |
                         ___|________V__
                        |  Forreal Mode |
                        |      Mode     |
                        |   PE=0 use32  |
                        |_______________|


Interesting. Forreal Mode is the furthest from Wake-up, and you can only
get to Forreal Mode from pmode. Forreal Mode is like a back room off of
pmode. You can interrupt between pmode and Veal Mode. Conversely, events
in rmode or Forreal Mode (PE=0) have to be handled in the mode they occur
in.

The above diagram does not account for different segment limits and bases
than those in effect in WakeUp Rmode, so e.g. unreal mode is not shown.
This chart also does not account for V86 Mode, which basically requires
386 task-switch constructs. The above modes and transitions do NOT need a
TSS, or paging. I suspect V86 could run off Veal Mode OR pmode.

Veal Mode is a protected mode. That means it's a quick switch to good old
use32 Protected Mode. It may afford some better code density, and thus
speed. Forreal Mode is unprotected, which means interrupts are handled
somewhat faster, which benefits realtime services. Either can be
incorporated into a multi-mode system. Forreal Mode also doesn't seem to
have any analogy at all in current use, other than the INTeL "flat model",
which is a simplified pmode, but that similarity is rather superficial.

For the 386 to do what it does, and particularly to have pulled it off in
the mid-eighties, things have to be fairly simple. You can figure that
whatever the 386 does, it's implemented as simply as possible. The modes
of the machine are composites of simple switches, and various effects,
such as loaded descriptors, tend to persist until changed. This has always
been the case with e.g. 8086 segment registers. In the 386, however,
8086-style "segments" are not alternates of 386 segments, they are a
superficiality on top of them. With that in mind, the states one goes
through simply getting from real mode to pmode start to make more sense.

The following (osimplay) code demonstrates the superficiality of 8086
"schmegments" vis-a-vis 386 segments, even when PE=0...

<from flat pmode>
. global/flipPE         # Welcome to Forreal Mode
                        # cell still 4

= 4 to A                # 32-bit schmegmented addressing demo
= A to ES               # proving we got PE = to 0.
= 9348539 to A
= A to @ $((0xb8a00))
ES
= A to @ $((0xb8a00))

That code causes two identical attribute-glyph pairs to appear on the VGA
text screen 32 charcells displaced from each other. That is the 4 in ES,
times 16 as per 8086, divided by two since each charcell is 2 bytes. Plus
a flat 32-bit address to put it on the screen. Forreal Mode thus does
32-bit 8086 schmegmented address computation. What is this type of
addressing useful for? Precious little. In Forreal mode you've got 32 bits
to start with. The point is you have the big flat segments left over from
pmode. The 8086 address-math does prove we're not in pmode any more,
however. Otherwise the ES prefix of 4 would have GPFed.


Rick Hohensee
Precision Mojo Engineer

*
 I've converted my 386INTEL.TXT to 7-bit ASCII-art, not to mention
op-source-dest and other unINTeLifications, and "<!" is the right-to-left
assignment operator in the instruction description code, helpfully
pronounced "becomes".


The appended hex/octal/listing appears to be handling INT 35 in Forreal
Mode, ala
                otheroperandsize
                dismiss

It also demos the 32-bit schmegmented addressing mentioned earlier, and it
keeps it's IDT in the VGA text buffer. The hex/octal input editor in
osimplay needed to type it in is Left As An Excercize To The Reader.


00000000  00...                         ALLOT 0x7C00
00007c00  270 28 02                     = 552 to A
00007c03  271 01 00                     = 1 to C
00007c06  31 322                        XOR D with D
00007c08  8e 302                        = D to ES
00007c0a  273 00 7c                     = 0x7c00 to B
00007c0d  cd 13                         submit 0x13
00007c0f  fa                    nosurprises
00007c10  270 00 b8                     = 0xb800 to A
00007c13  8e 330                        = A to DS
00007c15  270 93 0d                     = 3475 to A
00007c18  89 006 2c 01                  = A to @ 300
00007c1c  31 300                        XOR A with A
00007c1e  8e 330                        = A to DS
00007c20  0f 01 16 37 7d                        setGDT IGDTRpointer
00007c25  270 00 b8                     = 0xb800 to A
00007c28  8e 330                        = A to DS
00007c2a  270 94 0d                     = 3476 to A
00007c2d  89 006 30 01                  = A to @ 304
00007c31  66                    otheroperandsize
00007c32  31 300                        XOR A with A
00007c34  100                   1+ A
00007c35  0f 22 300                     = A to CR0
00007c38  e9 00 00                      jump hvfnvkfv
00007c3b                (O) hvfnvkfv
00007c3b  89 006 34 01                  = A to @ 308
00007c3f  89 006 35 01                  = A to @ 309
00007c43  0f 20 300                     = CR0 to A
00007c46  89 006 36 01                  = A to @ 310
00007c4a  89 006 37 01                  = A to @ 311
00007c4e  ea 53 7c 10 00
00007c53                (O) u32
00007c53  270 18 00 00 00                       = 0x18 to A
00007c58  8e 330                        = A to DS
00007c5a  270 57 65 67 13                       = 325543255 to A
00007c5f  89 005 d4 00 00 00                    = A to @ 212
00007c65  89 005 d8 80 0b 00                    = A to @ 753880
00007c6b  89 005 78 81 0b 00                    = A to @ 754040
00007c71  89 005 18 82 0b 00                    = A to @ 754200
00007c77  270 18 00 00 00                       = 0x18 to A
00007c7c  8e 330                        = A to DS
00007c7e  8e 300                        = A to ES
00007c80  8e 320                        = A to SS
00007c82  31 300                        XOR A with A
00007c84  8e 340                        = A to FS
00007c86  8e 350                        = A to GS
00007c88  270 d1 00 00 00                       = 0xd1 to A
00007c8d  272 64 00 00 00                       = 0x64 to D
00007c92  ee                    send byte
00007c93  90                    nop
00007c94  90                    nop
00007c95  90                    nop
00007c96  90                    nop
00007c97  90                    nop
00007c98  90                    nop
00007c99  90                    nop
00007c9a  90                    nop
00007c9b  90                    nop
00007c9c  90                    nop
00007c9d  270 df 00 00 00                       = 0xdf to A
00007ca2  272 60 00 00 00                       = 0x60 to D
00007ca7  ee                    send byte
00007ca8  272 92 00 00 00                       = 0x92 to D
00007cad  ec                    recieve byte
00007cae  0d 02 00 00 00                        OR 2 to A
00007cb3  ee                    send byte
00007cb4                (O) a20loop
00007cb4  270 55 55 aa aa                       = 0xaaaa5555 to A
00007cb9  89 005 d8 ff 1f 00                    = A to @ 2097112
00007cbf  8b 035 d8 ff 1f 00                    = @ 2097112 to B
00007cc5  39 303                        -test A to B
00007cc7  0f 85 e7 ff ff ff   when not zero a20loop
00007ccd  274 f0 ef 00 00                       = 61424 to SP
00007cd2  31 377                        XOR DI with DI
00007cd4                (O) perFMIDTvector
00007cd4  60                    pushcore
00007cd5  270 aa 7d 00 00                       = twitch32unP to A
00007cda  e8 ae 00 00 00                        call install32unP
00007cdf  61                    pullcore
00007ce0  107                   1+ DI
00007ce1  81 377 ff 00 00 00                    -test 255 with DI
00007ce7  75 eb   when not zero short perFMIDTvector
00007ce9  0f 01 1d bb 7d 00 00                  setIDT IDT32unPpointer
00007cf0  31 333                        XOR B with B
00007cf2  103                   1+ B
00007cf3  0f 20 300                     = CR0 to A
00007cf6  31 330                        XOR B to A
00007cf8  0f 22 300                     = A to CR0
00007cfb  270 04 00 00 00                       = 4 to A
00007d00  8e 300                        = A to ES
00007d02  270 bb a5 8e 00                       = 9348539 to A
00007d07  89 005 00 8a 0b 00                    = A to @ 756224
00007d0d  26                    ES
00007d0e  89 005 00 8a 0b 00                    = A to @ 756224
00007d14  66                    otheroperandsize
00007d15  9c                    pushflags
00007d16  66                    otheroperandsize
00007d17  68 00 00                      push 0
00007d1a  66                    otheroperandsize
00007d1b  e8 8c 00                      call twitch32unP
00007d1e                (O) theloop
00007d1e  8b 005 88 88 0b 00                    = @ 755848 to A
00007d24  100                   1+ A
00007d25  89 005 88 88 0b 00                    = A to @ 755848
00007d2b  cd 23                         submit 35
00007d2d  90                    nop
00007d2e  90                    nop
00007d2f  90                    nop
00007d30  90                    nop
00007d31  e9 e8 ff ff ff                        jump theloop
00007d36  f4                    halt
00007d37                (O) IGDTRpointer
00007d37  00 04 3d 7d 00 00
00007d3d                (O) GDT
00007d3d  00 00 00 00 00 00 00 00                       0 the required NULL
00007d45  ff ff 00 00 00 89 cf 00                       1 0x8 TSS
stackstack
00007d4d  ff ff 00 00 00 9a cf 00                       2 0x10 ring0 USE32
CS
00007d55  ff ff 00 00 00 92 cf 00                       3 0x18  ring0 data
00007d5d  ff ff 00 00 00 9a 00 00                       4 0x20 USE16 CS
00007d65  ff ff 00 00 00 92 00 00                       5 0x28 USE16 data
?S
00007d6d  00 00 00 00 00 00 00 00                       6 0x30
00007d75  00 00 00 00 00 00 00 00                       7 0x38
00007d7d  00 00 00 00 00 00 00 00                       8 0x40
00007d85  00 00 00 00 00 00 00 00                       9 0x48
00007d8d
00007d8d                (O) install32unP
00007d8d  c1 347 02                     upshift 2 to DI
00007d90  81 307 00 80 0b 00                    + IDT32unP to DI
00007d96  89 007                        = A to @ DI
00007d98  c3                    return
00007d99                (O) install16
00007d99  c1 347 02                     upshift 2 to DI
00007d9c  81 307 00 84 0b 00                    + IDT16 to DI
00007da2  e8 1a 00 00 00                        call schmegment
00007da7  89 007                        = A to @ DI
00007da9  c3                    return
00007daa                (O) twitch32unP
00007daa  120                   push A
00007dab  8b 005 50 8a 0b 00                    = @ 756304 to A
00007db1  100                   1+ A
00007db2  89 005 50 8a 0b 00                    = A to @ 756304
00007db8  130                   pull A
00007db9  66                    otheroperandsize
00007dba  cf                    dismiss
00007dbb                (O) IDT32unPpointer
00007dbb  00 04 00 80 0b 00
00007dc1                (O) schmegment
00007dc1  123                   push B
00007dc2  89 303                        = A to B
00007dc4  c1 353 10                     downshift 16 to B
00007dc7  81 340 ff ff 00 00                    AND 65535 to A
00007dcd  c1 343 1c                     upshift 28 to B
00007dd0  09 330                        OR B to A
00007dd2  133                   pull B
00007dd3  c3                    return



^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2003-07-30 14:05 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-07-28 16:02 The well-factored 386 Jack Dennon
2003-07-28 16:32 ` David S. Miller
2003-07-28 16:46   ` Andries Brouwer
2003-07-28 16:55     ` David S. Miller
2003-07-28 19:31       ` Herbert Pötzl
2003-07-28 19:41   ` Jamie Lokier
2003-07-29 11:14     ` Helge Hafting
2003-07-29 16:19       ` Jamie Lokier
2003-07-30  7:11         ` Helge Hafting
2003-07-30 14:05           ` Jamie Lokier
  -- strict thread matches above, loose matches on Subject: below --
2003-07-29 12:59 John Bradford
2003-07-29 13:32 ` Ville Herva
2003-07-28  8:44 The Well-Factored 386 Rick A. Hohensee
2003-07-28 14:06 ` David S. Miller
2003-07-28 16:36   ` hp
2003-07-28 20:33   ` Rick A. Hohensee
2003-07-28 20:33     ` David S. Miller
2003-07-28 22:27       ` Stephan von Krawczynski
2003-07-28 22:30         ` David S. Miller
2003-07-28 22:58           ` David D. Hagood
2003-07-29 14:32             ` Timothy Miller
2003-07-29 17:21               ` hp
2003-07-29  0:34           ` jw schultz
2003-07-29  1:27             ` Alan Cox
2003-07-29  3:49               ` Larry McVoy
2003-07-29  4:25                 ` Gene Heskett
2003-07-29  4:42                 ` jw schultz
2003-07-29 12:04                 ` Alan Cox
2003-07-29 14:55                 ` Timothy Miller
2003-07-29  8:45           ` hp
2003-07-28 23:11         ` viro
2003-07-29  0:17       ` Brian Raiter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).