User:Johnburger/Demo/x86/Desc

From OSDev Wiki
Jump to navigation Jump to search

This is both the most involved x86 definition file and the most useful. Since I decided to define as many system tables as possible at assembly time rather than run time, defining Descriptors became a frequent occurrence. And it didn't take long for NASM's structure instantiation mechanism (ISTRUC - *shudder*) to muddy the code enough to warrant a %macro to help.

I'm actually quite proud of the result - take a look at the Interrupt Descriptor Table definition for an example of how clean the resultant definition really is.

Demo/x86/Desc.inc

;
; x86/Desc.inc
;

; Descriptor Tables hold Descriptor Table Entries, or Descriptors for short.
; To select a Descriptor, you load a Segment register with a Selector (see Seg.inc).

; The following is the generic structure of a Descriptor (not very useful!)
                STRUC           x86.Desc
                RESD            1
                RESB            1
.Type           RESB            1       ; All Descriptors have a Type field here
                RESW            1
                ENDSTRUC                ; All Descriptors have the same Desc_size

; The following is the structure of a System Descriptor
                STRUC           x86.Desc.Sys
.OffsetLo       RESW            1
.Selector       RESW            1
.Args           RESB            1
.Type           RESB            1
.OffsetHi       RESW            1
                ENDSTRUC

; The following is the structure of a Memory (Code/Data) Descriptor
                STRUC           x86.Desc.Mem
.LimitLo        RESW            1
.BaseLo         RESW            1
.BaseMid        RESB            1
.Type           RESB            1
.Gran           RESB            1
.BaseHi         RESB            1
                ENDSTRUC

; The .Type field in both .Sys and .Mem structures above have the same format.
; These are the bitfields of the .Type field
x86.Desc.Type.Present EQU       1000_0000b

; These are the different Descriptor Privilege Levels
x86.Desc.Type.DPL3    EQU       0110_0000b
x86.Desc.Type.DPL2    EQU       0100_0000b
x86.Desc.Type.DPL1    EQU       0010_0000b
x86.Desc.Type.DPL0    EQU       0000_0000b

x86.Desc.Type.Sys     EQU       0000_0000b
x86.Desc.Type.Mem     EQU       0001_0000b

x86.Desc.Type.Type    EQU       0000_1111b

;-------------------------------------------------------------------------------

; These are the .Type.Type field values and modifiers for System Descriptors
x86.Desc.Sys.Type.TSS   EQU     0000_0001b      ; Task State Segment
x86.Desc.Sys.Type.LDT   EQU     0000_0010b      ; Local Descriptor Table
x86.Desc.Sys.Type.Busy  EQU     0000_0011b      ; Busy TSS
x86.Desc.Sys.Type.Gate  EQU     0000_0111b      ; One of a number of Gates
x86.Desc.Sys.Type.Call  EQU     0000_0100b      ; Call Gate (switches Priv)
x86.Desc.Sys.Type.Task  EQU     0000_0101b      ; Task Gate (switches TSS)
x86.Desc.Sys.Type.Int   EQU     0000_0110b      ; Int Gate (disables interrupts)
x86.Desc.Sys.Type.Trap  EQU     0000_0111b      ; Trap Gate
x86.Desc.Sys.Type.386   EQU     0000_1000b      ; '386 variant of above
x86.Desc.Sys.Type.286   EQU     0000_0000b      ; '286 is the original ones
; The .386 modifier is used for 32-bit variants of the original '286 16-bit ones.
; Note it cannot be used for either .LDT or .Task

;-------------------------------------------------------------------------------

; These are the .Type.Type field values and modifiers for Memory Descriptors
x86.Desc.Mem.Type.Code     EQU  0000_1000b
x86.Desc.Mem.Type.Data     EQU  0000_0000b
x86.Desc.Mem.Type.Conform  EQU  0000_0100b ; Code can be executed at different PLs
x86.Desc.Mem.Type.Expand   EQU  0000_0100b ; Base is TOP, Limit is size BELOW that
x86.Desc.Mem.Type.Stack    EQU  0000_0100b ; (Best used for Stacks)
x86.Desc.Mem.Type.RW       EQU  0000_0010b ; Readable for Code, Writable for Data
x86.Desc.Mem.Type.NoRW     EQU  0000_0000b ; No Read for Code, no Write for Data
x86.Desc.Mem.Type.Accessed EQU  0000_0001b ; Set when Descriptor loaded

; These are the bitfields of the .Gran field in Memory Descriptors
x86.Desc.Mem.Gran.LimitHi EQU   0000_1111b

x86.Desc.Mem.Gran.Gran  EQU     1000_0000b ; Use Page-granular Limit
x86.Desc.Mem.Gran.Byte  EQU     0000_0000b ; Use byte-granular Limit

x86.Desc.Mem.Gran.Big   EQU     0100_0000b ; Use EIP and ESP for Code and Stacks
x86.Desc.Mem.Gran.Small EQU     0000_0000b ; Use IP and SP for Code and Stacks

x86.Desc.Mem.Gran.Def32 EQU     0100_0000b ; Default to 32-bit instructions
x86.Desc.Mem.Gran.Def16 EQU     0000_0000b ; Default to 16-bit instructions

x86.Desc.Mem.Gran.Avail EQU     0001_0000b ; Available for system use

;-------------------------------------------------------------------------------

; Helper macros for each of the .Types defined above. There are a number of
; fields that need to be set, making for long source lines, and it's easy to
; forget one! Each of these assume only one thing: they're .Present

; Parameters are: TSS or LDT or Call or Task or Int or Trap, DPL 0-3, 286 or 386
%define         Type.Sys(Type, DPL, x86) (\
                x86.Desc.Type.Present | x86.Desc.Type.Sys | \
                x86.Desc.Type.%+ DPL | x86.Desc.Sys.Type.%+ Type | x86.Desc.Sys.Type.%+ x86 \
                )

; Parameters are: Code or Data or Stack, DPL 0-3, and RW or NoRW
%define         Type.Mem(Type, DPL, RW) (\
                x86.Desc.Type.Present | x86.Desc.Type.Mem | \
                x86.Desc.Type.%+ DPL | x86.Desc.Mem.Type.%+ Type | x86.Desc.Mem.Type.%+ RW \
                )

; Parameters are: Gran or Byte, and Big or Small
%define         Gran.Mem(Gran, Size) (\
                x86.Desc.Mem.Gran.%+ Gran | x86.Desc.Mem.Gran.%+ Size \
                )

; A helper macro, making it easy to allocate a System Descriptor in a Table.
; Unfortunately this macro requires that the Offset is less than 64K.
; Tne parameters are: Selector, Offset, Type
%macro          Desc.Sys                   3
%00             ISTRUC x86.Desc.Sys
AT x86.Desc.Sys.OffsetLo,  DW              %2
AT x86.Desc.Sys.Selector,  DW              %1
AT x86.Desc.Sys.Args,      DB              0
AT x86.Desc.Sys.Type,      DB              %3
AT x86.Desc.Sys.OffsetHi,  DW              0
                IEND
%endmacro

; A helper macro, making it easy to allocate a Memory Descriptor in a Table.
; The parameters are: Base, Limit, Type, and Gran
%macro          Desc.Mem                   4
%00             ISTRUC x86.Desc.Mem
AT x86.Desc.Mem.LimitLo,   DW              %2
AT x86.Desc.Mem.BaseLo,    DW              (%1 >> 0) & 0FFFFh
AT x86.Desc.Mem.BaseMid,   DB              (%1 >> 16) & 0FFh
AT x86.Desc.Mem.Type,      DB              %3
AT x86.Desc.Mem.Gran,      DB              %4
AT x86.Desc.Mem.BaseHi,    DB              (%1 >> 24) & 0FFh
                IEND
%endmacro