Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

80386 Protected Mode Initialization


OCT88: 80386 PROTECTED MODE INITIALIZATION

Neal Margulis is an applications engineer for Intel Corp. and can be reached at 2625 Walsh Ave., SC4-40, Santa Clara, CA 95051.


The 32-bit mode of the Intel 80386 and the 80386SX provides significant architectural advantages over the 80286. ln addition, software that takes advantage of these advanced features has significant performance improvements. An application program running in the 80386's native 32-bit mode typically executes from two to six times faster than the equivalent application written for the 80286. Furthermore, programs that manipulate large data structures are easier to write when you use the 32-bit mode of the 80386. Among the features that the 80386 provides over the 80286 are support for large segment sizes, 32-bit data operations, and paged memory management.

The program presented here shows how to initialize the 80386 into protected mode, how to define segments greater than 64K in size, and how to return to real mode. You can use this program as a template for coding applications that use the 80386 features. Although the 80386SX has a reduced physical addressing space of 16 Mbytes (the maximum address space of AT architecture), its programming model is the same as that of the 80386. Thus the template can be used with it as well.

This article explains how the code works and briefly describes how to adapt the template to suit your individual needs. You may also find it helpful to refer to one of many 80386 programming articles, such as "Programming on the 80386" (DDJ, October 1986). Additional information can be found in the Intel 80386 Programmers Reference Guide and the 80386 Data Sheet, as well as the book Programming the 80386 by Crawford and Gelsinger (Sybex Books).

32-Bit Data Operations

The ability to operate on 32 bits of data adds power to arithmetic and logical instructions. While the 80286 generates only 16-bit data, the 80386 contains eight general-purpose 32-bit registers. Segments for 80386 protected mode are set to either use16 or use32, which indicates the default sizes for data and addressing. in real mode, the 80386 is limited to only use16 segments. An override prefix must be designated in order to perform 32-bit operations within a protected mode use16 segment. This results in greater program length and a possible decrease in performance. The 80386 in protected mode allows for both use16 and use32 segments. No override prefixes are necessary for 32-bit data operations or 32-bit addressing in a use32 segment. In the program shown in Listing One, page 84, CSEG and C3 are use16 code segments because they must be executable from real mode, and PMODE segment is a use32 code segment.

Large Segments

The 64K limit on the segment size of the 80286 and the real mode 80386 hinder the addressing of large data arrays and of long sequences of code. Reloading segments is time consuming, disrupts the task at hand, and causes an unnatural breakup of procedures and data. The 80386 protected mode allows for segments up to 4 gigabytes in size. The base, limit, and granularity fields of segment descriptors specify the segment size and location in memory. The base represents a linear address and the segment size is determined by the limit and the granularity (G) bit. When the G bit is a zero, the actual limit is the 20-bit limit field of the descriptor (Maximum size 220 = 1 Mbyte). If the G bit is a one, then the limit field page granularity is multiplied by 4K. This gives a maximum limit of 4 gigabytes (220 * 212). The base's linear address is 32-bits long, thus allowing it to be specified anywhere within the 4-gigabyte address space.

Segmentation is the basis for protection. Data and code segments can reside in separate, nonoverlapping areas of memory. In addition, privilege levels assigned to different segments provide a mechanism for limiting access to certain data or privileged instruction sequences (for both). The 80386 provides four privilege levels. In the program presented in Listing One, all segments are of the highest privilege level (0). You can change this by modifying the segment descriptors and the selectors.

4-Gigabyte Addressing

To use the increased segment sizes, the 80386 has expanded the instruction pointer to 32-bits and added new addressing modes. As a result, segment loads and stores within a procedure can be eliminated and the entire physical address space can be accessed as one segment. The template program sets up a data segment that starts at the base of video memory 0B8000H. The entire address space is accessible through a segment that begins at zero.

The effective address of a memory operand can be obtained through an absolute address or through one of the register-base methods of the following form:

[base register] + [(index register *           scale) + displacement]

The 80386 also has page translation by which linear addresses can be resolved to physical addresses. Page translation occurs when the PG bit in CR0 is set. Two levels of tables are used to address each page of memory. The higher-level table is the page directory, which addresses up to 1K second-level page tables. These second-level page tables address up to 1K pages, each being 4K.

Because all pages are of equal size, page translation can reduce the memory fragmentation that occurs when using segmentation for on-demand memory allocation. The template program does not use paging, so all linear addresses are treated as the physical address.

Setting Up the Descriptor Tables

Before entering protected mode, you must set up descriptor tables and load the 80386 with pointers to these tables. While in real mode, the program in Listing One sets up a global descriptor table (GDT) and does not require a local descriptor table.

Starting at the memory location designated by the label GDT__table, successive 8-byte descriptor entries make up the GDT. MASM's STRUC feature makes coding of the entries much easier. Because DOS determines the memory location of the program at run time, the absolute addresses must also be calculated at run time.

The template program determines the bases for each of the segments and the pointer to the descriptor table. This table pointer consists of a 32-bit linear address and a 16-bit limit.

Such 48-bit (6-byte) objects are sometimes referred to as a PWORD or FWORD data type. Using a QWORD (8 bytes), as in this program, helps to maintain portability between assemblers.

The Type field of the descriptor determines whether segments that use this descriptor contain code or data. Descriptors to specify gates, task state segments, and local descriptor tables are also available, but are not used in this example.

Entering Protected Mode

Having set up the descriptor table, it is simple to enter protected mode. The PE bit of Control Register Zero (CR0) is set to one, and then a jump is executed. The jump flushes the prefetch queue, which contains instructions that were decoded for execution in real mode. Either a near or a far jump will flush the prefetch queue. By using a far jump, the 80386 reloads the code segment register (CS) and the internal segment descriptor cache. The far jump instruction uses selector 08H, which is GDT entry 1. This is the PMODE segment entry. Execution in this segment allows native 32-bit operations. (Bits 15 through 3 of the selector determine the GDT table entry. Bit 2 is Table indicator, and bits 1 and 0 are the privilege level.)

The Jump instructions are handcoded by using the define byte (DB) assembler directive. Opcode 0EAH specifies an intersegment jump, with the next two fields of the instruction being the offset and the segment selector operands. In this example, all of the offsets are zero because the jump targets are at the start of their respective segments. The offset size is either a 16-bit or 32-bit field. This is determined by the code segment type size in which the jump instruction occurs. The segment selector field of the jump instruction determines which descriptor table entry is the target segment for the jump.

Returning to Real Mode

Returning to real mode on the 80286 requires that you reset the processor. On an PC AT, this means saving the required processor contents, placing a reset code in the CMOS RAM, storing a return address in memory, and using the keyboard controller to reset the processor. Although 386 based ATs support this reset scheme, a much simpler and far faster way to return the 386 to real mode is available. In the C3 segment of the example program, the 80386 is returned to real mode by clearing the PE bit then executing a jump instruction to flush the instruction queue. To assure proper operation after returning to real mode, the segment registers must be loaded with real mode type selectors while still in protected mode. Entry 4 in the GDT represents what should be in the segment descriptor caches during real mode. They have a 64K limit with the base at zero and the top 2 bytes set to zero.

Other Considerations

In the early days of PCs, some programs took advantage of addresses wrapping around to zero after the limit of the 8088 was exceeded. When the 80286-based AT was introduced, it was necessary to emulate this address wrapping. An enable gate was added to address line 20. To prevent unwanted wrapping, you must enable this gate. The code for doing this is located in the IBM Technical References for the AT and PS/2. The procedures are different because the AT uses the keyboard controller to enable the address line. The programming example indicates where to insert the procedures for enabling and disabling of the address line.

[LISTING ONE]

<a name="01ca_000c">
_80386 PROTECTED MODE INITIALIZATION_
by
Neal Margulis

comment #*****************************
Program by  Neal Margulis -- Use MASM 5.0
#*************************************

descriptor STRUC
    limit_0_15  dw  0      ;  lowest 16 bits of segment limit
    base_0_15   dw  0      ;  lowest 16 bits of base
    base_16_23  db  0      ;  base bits 16-23
    access      db  0      ;  Present bit, priv. level, type
    gran        db  0      ;  G bit, D/B bit , limit bits 16-19
    base_24_31  db  0      ;  base bits 24-31
descriptor ENDS

code_seg_access equ 09AH   ; Present, DPL=0, non-conforming,read/exec
data_seg_access equ 092H   ; Present, DPL=0, Expand-Up,writeable

; have screenbase equal B8000H for EGA or B0000H for monochrome
screenbase   EQU  0B8000H
screenseg    EQU  0B800H

CSEG segment word  use16 'code'
assume  cs:CSEG,ds:CSEG

       mov ax,CSEG
       mov ds, ax

; Make entries in GDT for PMODE segment as code or data
       mov ax, seg PMODE
       and eax, 0FFFFh
       shl eax, 4H
       mov ebx, eax
       shr eax, 16
       mov gdt_PM_1.base_0_15, bx
       mov gdt_PM_2.base_0_15, bx
       mov gdt_PM_1.base_16_23,al
       mov gdt_PM_2.base_16_23,al

; Make entry in GDT for C3 segment as code
       mov ax,seg C3
       and eax, 0FFFFH
       shl eax, 4H
       mov ebx, eax
       shr eax, 16
       mov gdt_c3_5.base_0_15, bx
       mov gdt_c3_5.base_16_23,al

; Set up gdtr for lgdt instruction
       mov ax, cs
       and eax, 0FFFFH
       shl eax, 4H
       add eax, offset gdttbl
       mov dword ptr gdtaddr+2,eax
       lgdt  gdtaddr               ; set GDT address
A20_ON:

       cld                         ; Clear direction flag
       cli                         ; Disable interrupts

; Enter Protected Mode
        mov     eax,cr0
        or      eax,1
        mov     cr0,eax            ; Enable protected mode

              ;flush prefetch queue
        DB 0EAH,0H,0H,08H,0H       ; jmp to PMODE and execute

gdtaddr label   qword
        dw      48
        dd      ?
        dw      0

; global descriptor table

gdttbl   label   dword
gdt_null  descriptor <,,,,,>  ;   GDT entry 0 (null descriptor)
gdt_PM_1  descriptor <0FFFFH,,,code_seg_access,0C0H,0>  ;  D bit
ON
gdt_PM_2  descriptor <0FFFFH,,,data_seg_access,08FH,>  ;
gdt_3     descriptor <0FFFFH,0,0,data_seg_access,08FH,0>
gdt_rm_4  descriptor <0FFFFH,0,0,data_seg_access,08fH,0>
gdt_c3_5  descriptor <0FFFFH,,,code_seg_access,080H,0>  ;  D bit
OFF

CSEG ends

PMODE segment para public use32 'code'
    assume cs:PMODE
        mov ax, 18h         ;selector 18H is 4 Gigabyte data
segment with
                                                          ;
base at 0
        mov es, ax
        mov fs, ax
        mov ax, 10h         ;  Data segment with base at 'c2seg'
        mov ds, ax
        mov cx, 025h
        mov     edi,screenbase  ;  Addressing screen memory from
protected mode
display:mov byte ptr es:[edi],'P'
        add     edi,2
        mov     byte ptr es:[edi],'M'
        add     edi,2
        mov     byte ptr es:[edi],' '
        add     edi,2
        loopne display

        db      0eah, 0h, 0h, 0h, 0h,28h, 0h ; jmp to c3 and
execute

align 16

                pdat  db 0ach
lastpm  label dword
PMODE ends

c3 segment para public use16 'code'
    assume cs:c3

        mov ax, 20h         ; Change segments back to have valid
        mov es, ax          ;  real mode attributes.
        mov ds, ax
        mov fs, ax
        mov eax,cr0
        and eax, 07ffffffeh
        mov cr0,eax               ; enter real mode
        jmp far ptr flushrl       ; flush queue
 flushrl:
         mov ax, screenseg        ; Address screen memory from real mode
         mov ds, ax
         sub edi, 0b8000h
         mov si,di
        mov byte ptr ds:[si],'C'    ;  Write to screen
        add si,2
        mov byte ptr ds:[si],'3'

A20_off:

        mov ah, 04ch                    ;  DOS termination
        mov al, 01h
        int 21h
c3 ends

end









Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.