Chapter 10 Initialization


Chapter 10  Initialization

----------------------------------------------------------------------------

After a signal on the RESET pin, certain registers of the 80386 are set to
predefined values. These values are adequate to enable execution of a
bootstrap program, but additional initialization must be performed by
software before all the features of the processor can be utilized.


10.1 Processor State after Reset



10.1  Processor State After Reset

The contents of EAX depend upon the results of the power-up self test. The
self-test may be requested externally by assertion of BUSY# at the end of
RESET. The EAX register holds zero if the 80386 passed the test. A nonzero
value in EAX after self-test indicates that the particular 80386 unit is
faulty. If the self-test is not requested, the contents of EAX after RESET
is undefined.

DX holds a component identifier and revision number after RESET as Figure
10-1 illustrates. DH contains 3, which indicates an 80386 component. DL
contains a unique identifier of the revision level.

Control register zero (CR0) contains the values shown in Figure 10-2. The
ET bit of CR0 is set if an 80387 is present in the configuration (according
to the state of the ERROR# pin after RESET). If ET is reset, the
configuration either contains an 80287 or does not contain a coprocessor. A
software test is required to distinguish between these latter two
possibilities.

The remaining registers and flags are set as follows:

   EFLAGS             =00000002H
   IP                 =0000FFF0H
   CS selector        =000H
   DS selector        =0000H
   ES selector        =0000H
   SS selector        =0000H
   FS selector        =0000H
   GS selector        =0000H
   IDTR:
              base    =0
              limit   =03FFH

All registers not mentioned above are undefined.

These settings imply that the processor begins in real-address mode with
interrupts disabled.

See Also: Fig.10-2 


10.2 Software Initialization for Real-Address Mode



10.2  Software Initialization for Real-Address Mode

In real-address mode a few structures must be initialized before a program
can take advantage of all the features available in this mode.


10.2.1 Stack



10.2.1  Stack

No instructions that use the stack can be used until the stack-segment
register (SS) has been loaded. SS must point to an area in RAM.


10.2.2 Interrupt Table



10.2.2  Interrupt Table

The initial state of the 80386 leaves interrupts disabled; however, the
processor will still attempt to access the interrupt table if an exception
or nonmaskable interrupt (NMI) occurs. Initialization software should take
one of the following actions:

  *  Change the limit value in the IDTR to zero. This will cause a shutdown
     if an exception or nonmaskable interrupt occurs. (Refer to the 80386
     Hardware Reference Manual to see how shutdown is signalled externally.)

  *  Put pointers to valid interrupt handlers in all positions of the
     interrupt table that might be used by exceptions or interrupts.

  *  Change the IDTR to point to a valid interrupt table.


10.2.3 First Instructions



10.2.3  First Instructions

After RESET, address lines A{31-20} are automatically asserted for
instruction fetches. This fact, together with the initial values of CS:IP,
causes instruction execution to begin at physical address FFFFFFF0H. Near
(intrasegment) forms of control transfer instructions may be used to pass
control to other addresses in the upper 64K bytes of the address space. The
first far (intersegment) JMP or CALL instruction causes A{31-20} to drop
low, and the 80386 continues executing instructions in the lower one
megabyte of physical memory. This automatic assertion of address lines
A{31-20} allows systems designers to use a ROM at the high end of
the address space to initialize the system.


10.3 Switching to Protected Mode



10.3  Switching to Protected Mode

Setting the PE bit of the MSW in CR0 causes the 80386 to begin executing in
protected mode. The current privilege level (CPL) starts at zero. The
segment registers continue to point to the same linear addresses as in real
address mode (in real address mode, linear addresses are the same physical
addresses).

Immediately after setting the PE flag, the initialization code must flush
the processor's instruction prefetch queue by executing a JMP instruction.
The 80386 fetches and decodes instructions and addresses before they are
used; however, after a change into protected mode, the prefetched
instruction information (which pertains to real-address mode) is no longer
valid. A JMP forces the processor to discard the invalid information.


10.4 Software Initialization for Protected Mode



10.4  Software Initialization for Protected Mode

Most of the initialization needed for protected mode can be done either
before or after switching to protected mode. If done in protected mode,
however, the initialization procedures must not use protected-mode features
that are not yet initialized.


10.4.1 Interrupt Descriptor Table



10.4.1  Interrupt Descriptor Table

The IDTR may be loaded in either real-address or protected mode. However,
the format of the interrupt table for protected mode is different than that
for real-address mode. It is not possible to change to protected mode and
change interrupt table formats at the same time; therefore, it is inevitable
that, if IDTR selects an interrupt table, it will have the wrong format at
some time. An interrupt or exception that occurs at this time will have
unpredictable results. To avoid this unpredictability, interrupts should
remain disabled until interrupt handlers are in place and a valid IDT has
been created in protected mode.


10.4.2 Stack



10.4.2  Stack

The SS register may be loaded in either real-address mode or protected
mode. If loaded in real-address mode, SS continues to point to the same
linear base-address after the switch to protected mode.


10.4.3 Global Descriptor Table



10.4.3  Global Descriptor Table

Before any segment register is changed in protected mode, the GDT register
must point to a valid GDT. Initialization of the GDT and GDTR may be done in
real-address mode. The GDT (as well as LDTs) should reside in RAM, because
the processor modifies the accessed bit of descriptors.


10.4.4 Page Tables



10.4.4  Page Tables

Page tables and the PDBR in CR3 can be initialized in either real-address
mode or in protected mode; however, the paging enabled (PG) bit of CR0
cannot be set until the processor is in protected mode. PG may be set
simultaneously with PE, or later. When PG is set, the PDBR in CR3 should
already be initialized with a physical address that points to a valid page
directory. The initialization procedure should adopt one of the following
strategies to ensure consistent addressing before and after paging is
enabled:

  *  The page that is currently being executed should map to the same
     physical addresses both before and after PG is set.

  *  A JMP instruction should immediately follow the setting of PG.


10.4.5 First Task



10.4.5  First Task

The initialization procedure can run awhile in protected mode without
initializing the task register; however, before the first task switch, the
following conditions must prevail:

  *  There must be a valid task state segment (TSS) for the new task. The
     stack pointers in the TSS for privilege levels numerically less than or
     equal to the initial CPL must point to valid stack segments.

  *  The task register must point to an area in which to save the current
     task state. After the first task switch, the information dumped in this
     area is not needed, and the area can be used for other purposes.


10.5 Initialization Example



10.5  Initialization Example

$TITLE ('Initial Task')

    NAME    INIT

init_stack  SEGMENT RW
            DW  20  DUP(?)
tos         LABEL   WORD
init_stack  ENDS

init_data   SEGMENT RW PUBLIC
            DW  20  DUP(?)
init_data   ENDS

init_code   SEGMENT ER PUBLIC

ASSUME      DS:init_data

    nop
    nop
    nop
init_start:
                                    ; set up stack
    mov ax, init_stack
    mov ss, ax
    mov esp, offset tos

    mov a1,1
blink:
    xor a1,1
    out 0e4h,a1
    mov cx,3FFFh
here:
    dec cx
    jnz here

    jmp SHORT blink

    hlt
init_code   ends

    END init_start, SS:init_stack, DS:init_data

$TITLE('Protected Mode Transition -- 386 initialization')
NAME  RESET

;*****************************************************************
; Upon reset the 386 starts executing at address 0FFFFFFF0H.  The
; upper 12 address bits remain high until a FAR call or jump is
; executed.
;
; Assume the following:
;
;
; -  a short jump at address 0FFFFFFF0H (placed there by the
;    system builder) causes execution to begin at START in segment
;    RESET_CODE.
;
;
; -  segment RESET_CODE is based at physical address 0FFFF0000H,
;    i.e.   at the start of the last  64K in the 4G address space.
;    Note that  this is the base of the CS register at reset.  If
;    you locate ROMcode above  this  address,  you  will  need  to
;    figure out an adjustment factor to address things within this
;    segment.
;
;*****************************************************************
$EJECT ;

; Define addresses to locate GDT and IDT in RAM.
; These addresses are also used in the BLD386 file that defines
; the GDT and IDT. If you change these addresses, make sure you
; change the base addresses specified in the build file.

GDTbase         EQU    00001000H   ; physical address for GDT base
IDTbase         EQU    00000400H   ; physical address for IDT base

PUBLIC     GDT_EPROM
PUBLIC     IDT_EPROM
PUBLIC     START

DUMMY      segment rw      ; ONLY for ASM386 main module stack init
           DW 0
DUMMY   ends

;*****************************************************************
;
; Note: RESET CODE must be USEl6 because the 386 initally executes
;       in real mode.
;

RESET_CODE segment er PUBLIC    USE16

ASSUME DS:nothing, ES:nothing

;
; 386 Descriptor template

DESC       STRUC
    lim_0_15    DW  0              ; limit bits (0..15)
    bas_0_15    DW  0              ; base bits (0..15)
    bas_16_23   DB  0              ; base bits (16..23)
    access      DB  0              ; access byte
    gran        DB  0              ; granularity byte
    bas_24_31   DB  0              ; base bits (24..31)
DESC       ENDS

; The following is the layout of the real GDT created by BLD386.
; It is located in EPROM and will be copied to RAM.
;
; GDT[O]      ...  NULL
; GDT[1]      ...  Alias for RAM GDT
; GDT[2]      ...  Alias for RAM IDT
; GDT[2]      ...  initial task TSS
; GDT[3]      ...  initial task TSS alias
; GDT[4]      ...  initial task LDT
; GDT[5]      ...  initial task LDT alias

;
; define entries in GDT and IDT.

GDT_ENTRIES    EQU    8
IDT_ENTRIES    EQU    32

; define some constants to index into the real GDT

GDT_ALIAS      EQU    1*SIZE DESC
IDT_ALIAS      EQU    2*SIZE DESC
INIT_TSS       EQU    3*SIZE DESC
INIT_TSS_A     EQU    4*SIZE DESC
INIT_LDT       EQU    5*SIZE DESC
INIT_LDT_A     EQU    6*SIZE DESC

;
; location of alias in INIT_LDT

INIT_LDT_ALIAS    EQU    1*SIZE DESC

;
; access rights byte for DATA and TSS descriptors

DS_ACCESS   EQU   010010010B
TSS_ACCESS  EQU   010001001B


;
; This temporary GDT will be used to set up the real GDT in RAM.

Temp_GDT    LABEL   BYTE        ; tag for begin of scratch GDT

NULL_DES    DESC <>             ; NULL descriptor

                                ; 32-Gigabyte data segment based at 0
FLAT_DES    DESC <0FFFFH,0,0,92h,0CFh,0>

GDT_eprom     DP    ?           ; Builder places GDT address and limit
                                ; in this 6 byte area.

IDT_eprom     DP    ?           ; Builder places IDT address and limit
                                ; in this 6 byte area.

;
; Prepare operand for loadings GDTR and LDTR.


TGDT_pword     LABEL  PWORD                 ; for temp GDT
        DW     end_Temp_GDT_Temp_GDT -1
        DD     0

GDT_pword      LABEL  PWORD                 ; for GDT in RAM
        DW     GDT_ENTRIES * SIZE DESC -1
        DD     GDTbase

IDT_pword      LABEL   PWORD                ; for IDT in RAM
        DW     IDT_ENTRIES * SIZE DESC -1
        DD     IDTbase


end_Temp_GDT   LABEL   BYTE

;
; Define equates for addressing convenience.

GDT_DES_FLAT        EQU DS:GDT_ALIAS +GDTbase
IDT_DES_FLAT        EQU DS:IDT_ALIAS +GDTbase

INIT_TSS_A_OFFSET   EQU DS:INIT_TSS_A
INIT_TSS_OFFSET     EQU DS:INIT_TSS

INIT_LDT_A_OFFSET   EQU DS:INIT_LDT_A
INIT_LDT_OFFSET     EQU DS:INIT_LDT


; define pointer for first task switch

ENTRY POINTER LABEL DWORD
             DW 0, INIT_TSS

;******************************************************************
;
;   Jump from reset vector to here.

START:

    CLI                ;disable interrupts
    CLD                ;clear direction flag

    LIDT    NULL_des   ;force shutdown on errors

;
;   move scratch GDT to RAM at physical 0

    XOR DI,DI
    MOV ES,DI           ;point ES:DI to physical location 0


    MOV SI,OFFSET Temp_GDT
    MOV CX,end_Temp_GDT-Temp_GDT        ;set byte count
    INC CX
;
;   move table

    REP MOVS BYTE PTR ES:[DI],BYTE PTR CS:[SI]

    LGDT    tGDT_pword                ;load GDTR for Temp. GDT
                                      ;(located at 0)

;   switch to protected mode

    MOV EAX,CR0                       ;get current CRO
    MOV EAX,1                         ;set PE bit
    MOV CRO,EAX                       ;begin protected mode
;
;   clear prefetch queue

    JMP SHORT flush
flush:

; set DS,ES,SS to address flat linear space (0 ... 4GB)

    MOV BX,FLAT_DES-Temp_GDT
    MOV US,BX
    MOV ES,BX
    MOV SS,BX
;
; initialize stack pointer to some (arbitrary) RAM location

    MOV ESP, OFFSET end_Temp_GDT

;
; copy eprom GDT to RAM

    MOV ESI,DWORD PTR GDT_eprom +2 ; get base of eprom GDT
                                   ; (put here by builder).

    MOV EDI,GDTbase                ; point ES:EDI to GDT base in RAM.

    MOV CX,WORD PTR gdt_eprom +0   ; limit of eprom GDT
    INC CX
    SHR CX,1                       ; easier to move words
    CLD
    REP MOVS   WORD PTR ES:[EDI],WORD PTR DS:[ESI]

;
; copy eprom IDT to RAM
;
    MOV ESI,DWORD PTR IDT_eprom +2 ; get base of eprom IDT
                                   ; (put here by builder)

    MOV EDI,IDTbase                ; point ES:EDI to IDT base in RAM.

    MOV CX,WORD PTR idt_eprom +0   ; limit of eprom IDT
    INC CX
    SHR CX,1
    CLD
    REP MOVS   WORD PTR ES:[EDI],WORD PTR DS:[ESI]

; switch to RAM GDT and IDT
;
    LIDT IDT_pword
    LGDT GDT_pword

;
    MOV BX,GDT_ALIAS               ; point DS to GDT alias
    MOV DS,BX
;
; copy eprom TSS to RAM
;
    MOV BX,INIT_TSS_A              ; INIT TSS A descriptor base
                                   ; has RAM location of INIT TSS.

    MOV ES,BX                      ; ES points to TSS in RAM

    MOV BX,INIT_TSS                ; get inital task selector
    LAR DX,BX                      ; save access byte
    MOV [BX].access,DS_ACCESS      ; set access as data segment
    MOV FS,BX                      ; FS points to eprom TSS

    XOR si,si                      ; FS:si points to eprom TSS
    XOR di,di                      ; ES:di points to RAM TSS

    MOV CX,[BX].lim_0_15           ; get count to move
    INC CX

;
; move INIT_TSS to RAM.

    REP MOVS BYTE PTR ES:[di],BYTE PTR FS:[si]

    MOV [BX].access,DH             ; restore access byte

;
; change base of INIT TSS descriptor to point to RAM.

    MOV AX,INIT_TSS_A_OFFSET.bas_0_15
    MOV INIT_TSS_OFFSET.bas_0_15,AX
    MOV AL,INIT_TSS_A_OFFSET.bas_16_23
    MOV INIT_TSS_OFFSET.bas_16_23,AL
    MOV AL,INIT_TSS_A_OFFSET.bas_24_31
    MOV INIT_TSS_OFFSET.bas_24_31,AL

;
; change INIT TSS A to form a save area for TSS on first task
; switch. Use RAM at location 0.

    MOV BX,INIT_TSS_A
    MOV WORD PTR [BX].bas_0_15,0
    MOV [BX].bas_16_23,0
    MOV [BX].bas_24_31,0
    MOV [BX].access,TSS_ACCESS
    MOV [BX].gran,O
    LTR BX                         ; defines save area for TSS

;
; copy eprom LDT to RAM

    MOV BX,INIT_LDT_A              ; INIT_LDT_A descriptor has
                                   ; base address in RAM for INIT_LDT.

    MOV ES,BX                      ; ES points LDT location in RAM.

    MOV AH,[BX].bas_24_31
    MOV AL,[BX].bas_16_23
    SHL EAX,16
    MOV AX,[BX].bas_0_15           ; save INIT_LDT base (ram) in EAX

    MOV BX,INIT_LDT                ; get inital LDT selector
    LAR DX,BX                      ; save access rights
    MOV [BX].access,DS_ACCESS      ; set access as data segment
    MOV FS,BX                      ; FS points to eprom LDT

    XOR si,si                      ; FS:SI points to eprom LDT
    XOR di,di                      ; ES:DI points to RAM LDT

    MOV CX,[BX].lim_0_15           ; get count to move
    INC CX
;
; move initial LDT to RAM

    REP MOVS BYTE PTR ES:[di],BYTE PTR FS:[si]

    MOV [BX].access,DH             ; restore access rights in
                                   ; INIT_LDT descriptor

;
; change base of alias (of INIT_LDT) to point to location in RAM.

    MOV ES:[INIT_LDT_ALIAS].bas_0_15,AX
    SHR EAX,16
    MOV ES:[INIT_LDT_ALIAS].bas_16_23,AL
    MOV ES:[INIT_LDT_ALIAS].bas_24_31,AH

;
; now set the base value in INIT_LDT descriptor

    MOV AX,INIT_LDT_A_OFFSET.bas_0_15
    MOV INIT_LDT_OFFSET.bas_0_15,AX
    MOV AL,INIT_LDT_A_OFFSET.bas_16_23
    MOV INIT_LDT_OFFSET.bas_16_23,AL
    MOV AL,INIT_LDT_A_OFFSET.bas_24_31
    MOV INIT_LDT_OFFSET.bas_24_31,AL

;
; Now GDT, IDT, initial TSS and initial LDT are all set up.
;
; Start the first task!
'
   JMP ENTRY_POINTER

RESET_CODE ends
   END START, SS:DUMMY,DS:DUMMY


10.6 TLB Testing



10.6  TLB Testing

The 80386 provides a mechanism for testing the Translation Lookaside Buffer
(TLB), the cache used for translating linear addresses to physical
addresses. Although failure of the TLB hardware is extremely unlikely, users
may wish to include TLB confidence tests among other power-up confidence
tests for the 80386.

---------------------------------------------------------------------------
NOTE
  This TLB testing mechanism is unique to the 80386 and may not be
  continued in the same way in future processors. Sortware that uses
  this mechanism may be incompatible with future processors.
---------------------------------------------------------------------------

When testing the TLB it is recommended that paging be turned off (PG=0 in
CR0) to avoid interference with the test data being written to the TLB.


10.6.1 Structure of the TLB



10.6.1  Structure of the TLB

The TLB is a four-way set-associative memory. Figure 10-3 illustrates the
structure of the TLB. There are four sets of eight entries each. Each entry
consists of a tag and data. Tags are 24-bits wide. They contain the
high-order 20 bits of the linear address, the valid bit, and three attribute
bits. The data portion of each entry contains the high-order 20 bits of the
physical address.


See Also: Fig.10-3 


10.6.2 Test Registers



10.6.2  Test Registers

Two test registers, shown in Figure 10-4, are provided for the purpose of
testing. TR6 is the test command register, and TR7 is the test data
register. These registers are accessed by variants of the MOV
instruction. A test register may be either the source operand or destination
operand. The MOV instructions are defined in both real-address mode and
protected mode. The test registers are privileged resources; in protected
mode, the MOV instructions that access them can only be executed at
privilege level 0. An attempt to read or write the test registers when
executing at any other privilege level causes a general
protection exception.

The test command register (TR6) contains a command and an address tag to
use in performing the command:

C         This is the command bit. There are two TLB testing commands:
          write entries into the TLB, and perform TLB lookups. To cause an
          immediate write into the TLB entry, move a doubleword into TR6
          that contains a 0 in this bit. To cause an immediate TLB lookup,
          move a doubleword into TR6 that contains a 1 in this bit.

Linear    On a TLB write, a TLB entry is allocated to this linear address;
Address   the rest of that TLB entry is set per the value of TR7 and the
          value just written into TR6. On a TLB lookup, the TLB is
          interrogated per this value; if one and only one TLB entry
          matches, the rest of the fields of TR6 and TR7 are set from the
          matching TLB entry.

V         The valid bit for this TLB entry. The TLB uses the valid bit to
          identify entries that contain valid data. Entries of the TLB
          that have not been assigned values have zero in the valid bit.
          All valid bits can be cleared by writing to CR3.

D, D#     The dirty bit (and its complement) for/from the TLB entry.

U, U#     The U/S bit (and its complement) for/from the TLB entry.

W, W#     The R/W bit (and its complement) for/from the TLB entry.

          The meaning of these pairs of bits is given by Table 10-1,
          where X represents D, U, or W.

The test data register (TR7) holds data read from or data to be written to
the TLB.

Physical  This is the data field of the TLB. On a write to the TLB, the
Address   TLB entry allocated to the linear address in TR6 is set to this
          value. On a TLB lookup, if HT is set, the data field (physical
          address) from the TLB is read out to this field. If HT is not
          set, this field is undefined.

HT        For a TLB lookup, the HT bit indicates whether the lookup was a
          hit (HT = 1) or a miss (HT = 0). For a TLB write, HT must be set
          to 1.

REP       For a TLB write, selects which of four associative blocks of the
          TLB is to be written. For a TLB read, if HT is set, REP reports
          in which of the four associative blocks the tag was found; if HT
          is not set, REP is undefined.

See Also: Fig.10-4 


10.6.3 Test Operations




10.6.3  Test Operations

To write a TLB entry:

  1.  Move a doubleword to TR7 that contains the desired physical address,
      HT, and REP values. HT must contain 1. REP must point to the
      associative block in which to place the entry.

  2.  Move a doubleword to TR6 that contains the appropriate linear
      address, and values for V, D, U, and W. Be sure C=0 for "write"
      command.

Be careful not to write duplicate tags; the results of doing so are
undefined.

To look up (read) a TLB entry:

  1.  Move a doubleword to TR6 that contains the appropriate linear address
      and attributes. Be sure C=1 for "lookup" command.

  2.  Store TR7. If the HT bit in TR7 indicates a hit, then the other
      values reveal the TLB contents. If HT indicates a miss, then the other
      values in TR7 are indeterminate.

For the purposes of testing, the V bit functions as another bit of
addresss.  The V bit for a lookup request should usually be set, so that
uninitialized tags do not match. Lookups with V=0 are unpredictable if any
tags are uninitialized.