A CRASH COURSE IN PROTECTED MODE

                               By Adam Seychell


    After my release of DOS32 V1.2 a lot of people were asking for basic help
in protected mode programming. If you already know what a selector is then
there is probably no need for you to read this file.
 
   Ok you know all about the 8086 ( or a 386 in real mode ) architecture and
what to know about this fantastic protected mode stuff. I'll start off saying
that I think real mode on the 386 is like driving a car that is stuck in
first gear. There is the potential of a lot of power but it is not being
used. It really degrades the 386 processor and was not designed to normally
operate in this mode. Even the Intel data book states  "Real mode is required
primarily to set up the processor for Protected Mode operation".



                      SEGMENTATION OF THE INTEL 80x86 

    A segment is a block of memory that starts at a fixed base address and
has a set length.  As you should already know that *every* memory reference
by the CPU requires both a SEGMENT value and a OFFSET value to be specified.
The OFFSET value is the location relative to the base address of the segment.
The SEGMENT value contains the information for the segment. I am going to
explain very basically how this SEGMENT value is interpreted by the 80386 to
give the parameters of segments. 


   In protected mode this SEGMENT value is interpreted completely different
than in real mode and Virtual 86 mode. The SEGMENT values are now called
"selectors". You'll see why when finished reading this file. So whenever you
load a segment register you are loading it with a selector.



The Selector is word length and contains three different fields.

Bits  0..1       Request Privilege level        ( just set this to zero )

Bit   2          Table Indicator        0 = Global Descriptor Table
                                        1 = Local Descriptor Table

Bits 3..15      The INDEX field value of the desired descriptor in the GDT   
                This index value points to a descriptor in the table. 









                     The  GLOBAL DESCRIPTOR TABLE  (GDT)

    The Global Descriptor Table ( GDT ) is a table of DESCRIPTORS and it's
stored in memory. The address of this table is given in a special register of
the CPU and is called the global descriptor table register. There always must
be a GDT when in protected mode because it is in this table where all of
the segments are defined.
    Each DESCRIPTOR ( stored in the GDT ) contains the complete information
about a segment. It is a description of the segment.  Each Descriptor is 64
bits long and contains many different fields. I'll explain the fields later. 
The INDEX field  ( stored in bits 3..15 of any segment register ) selects a
descriptor to use for the type of segment wanted. So the only segments the
programmer can use are the available descriptors in the GDT.


Example code:
    Suppose you what to access location 012345h in your data segment and
you were told that the descriptor for your data segment is descriptor
number 6 in the Global Descriptor Table.  Assume that the Global Descriptor
Table has already been set up and built for you  ( example, as in DOS32).

Solution:
    We need to load a segment register (SS,DS,FS,GS,ES)  with a value so
that it will select (or index ) descriptor number 6 of the GDT. Then
reference the address with a instruction that will use this loaded
segment register.

The segment register (FS,DS,GS,SS,CS or ES) must be loaded with the following
three fields,

        Request Privilege level ( Bits 0..1 ) = 0  (always)
        Table Indicator ( bit 2 )  = 0  
        Index  ( bits 3..15 ) = 6

             
     mov  ax,0000000110000b      ;load DS with the selector value      
     mov  ds,ax          
     mov  byte ptr DS:[ 012345h ],0     ; Using the DS segment register



    The 386 has hardware for a complete multitasking system. There are 
several different types of descriptors available in the GDT for managing
multitasking. You don't need to know about all the different descriptors just
to program in protected mode. Just the info above is enough.  All you need to
know to program in protected mode is what descriptors are available to you
and what are the selector values of these descriptors.  Also the base address
of the segment may be need to be known. See the file DOS32.DOC for obtaining
the selector values.

    There are two groups of descriptors
1) CODE/DATA descriptors which are used for any code and data segments.

2) SYSTEM descriptors are used for the multitasking system of the 386. These
type of descriptors will never need to be used for programming applications.



          Format of a code and data descriptor

BITS                 description if the field
----------------------------------------------------------------
0..15                SEGMENT LIMIT 0...15
16..39               SEGMENT BASE 0..23
40                  (A)   accessed bit                           
41..43              (TYPE) 0 = SEE BELOW
44                  (0)  0 = code/data descriptor 1 = system descriptor
45..46              (DPL) Descriptor Privilege level
47                  (P)  Segment Present bit
48..50              SEGMENT LIMIT 16..19
51..52              (AVL)   2 bits available for the OS
53                  zero for future processors
54                  Default Operation size used by code descriptors only
55                  Granularly:  1 = segment limit = limit field *1000h
                                0 = segment limit = limit field
56..63              SEGMENT BASE 24..31      

format of TYPE field
          bit  2    Executable (E)     0 = Descriptor is data type    
               1    Expansion Direction (ED) 0 = Expand up
                                             1 = Expand up
               0    Writeable (W)       W = 0 data segment is read only
                                        W = 1 data segment is R/W     


          bit  2    Executable (E)  1 = Descriptor is code type  
               1    Conforming (C)   ( I don't understand )
               0    Readable (R)        R = 0 Code segment execute only
                                        R = 1 Code segment is Readable


   I'd better stop here, I am confusing myself. As you can see there is
more to a segment that just it's base address and limit.
    The three descriptors that are avalible in DOS32  all have limits of
0ffffffffh (4GB). This means that the offsets can be any value. 
For example, the instruction    XOR EAX,ES:[0FFFFFFFFh]  in allowed.
   If you happen to load an invalid selector value into one of the segment
registers then the 386 will report an General Protection exception
( interrupt 13 ).  In protected mode this exception is also used for many
other invalid settings.
     


   This was only meant to be a rough introduction to the protected mode
segmentation mechanism of the 80386+. I hope I did not make this sound
too complicated so that you've been put off with the whole idea of protected
mode programming. If you want to know more then I suggest you buy a book on
the 80386. The "Intel Programmers Reference guide" is the most detailed book
around.
   Please note that DOS32 does *ALL* of the setting up needed for protected
mode. This includes the descriptors in the GDT. So you don't have to know
about any stupid things like the descriptor format, selector index fields,
privilege levels ,ect , ect.  What you do need to know are the selector
values for all the descriptors that are available to your program. Then the
segment registers can simply be loaded with these known selector values.
DOS32 uses only 3 descriptors ( or segments ) as described in DOS32.DOC.

1