Defining protected-mode segment-descriptors
An example of a protected-mode bootsector application that draws a message to the video display
What will we do once there?
• Let’s explore writing a bootsector program that will do something perceptible while in protected-mode, namely: show a message
• We won’t be able to call BIOS functions
(they’re designed to work in real-mode)
• We must write directly to video memory
Recall PC Memory Layout
0xF0000
0xC0000
0xA0000
ROM-BIOS
VIDEO-BIOS
VRAM
RAM 1-MB
0x00000
0xB8000
0xB0000
0xA0000
Three VRAM zones
COLOR TEXT
MONOCHROME TEXT
GRAPHICS
32-KB
32-KB
64-KB
Array of picture-elements
• Text-mode VRAM is organized as an array
• Each array-element occupies one word
• Word’s LSB holds ascii character-code
• Word’s MSB holds a color-number pair
15 bgcolor
12 11 fgcolor
8 7
ASCII character-code
0 nybble nybble byte
Color-Attribute Byte
Blink
R G B
Intense
R background color attribute
G B foreground color attribute
Screen-element locations
80 columns characters 0..79
characters 80..159
25 rows characters 1920..1999
Video screen
x86 “Little-Endian” storage
• Intel’s x86 CPUs use little-endian storage
• The “little end” of any multibyte value is stored at the smaller operand-address
• Example: EAX = 0x12345678 mov [0x9000], EAX
Memory-addresses occupied by operand
0x78
0x9000
0x56
0x9001
0x34
0x9002
0x12
0x9003
Drawing a character-string
• Setup DS:SI with string’s starting address
• Setup ES:DI with initial address on screen
• Clear DF-bit (Direction Flag) in FLAGS register
• Setup desired color attribute-byte in AH register again: lodsb ; next character to AL or al, al ; is final null-byte?
jz finis stosw jmp again
; yes, exit from loop
; write char & colors
; go back for another finis:
Planning our memory usage
• To draw a screen-message in protectedmode, our program will need to address these memory-segments:
– its code (executable, at 0x07C00)
– its data (readable and writable, at 0x07C00)
– its stack (readable, writable, expand-down)
– the video ram (32KB, writable, at 0xB8000)
• For its return to real-mode, our program will need 64KB code and data segments
31
VRAM segment-descriptor
Base[31..24] G D
R
S
V
A
V
L
Limit
[19..16]
P
D
P
L
C R
S X / /
D W
A Base[23..16]
16
Base[15..0] Limit[15..0]
15 0
VRAM Base-Address = 0x000B8000
VRAM Segment-Limit = 0x07FFF (32-KB)
Segment-attributes: P=1, A=0, S=1, X=0, D=0, W=1
DPL=0, G=0, D=0 (RSV=0, AVL=0)
.WORD
0x7FFF, 0x8000, 0x920B, 0x0000
31
CODE segment-descriptor
Base[31..24] G D
R
S
V
A
V
L
Limit
[19..16]
P
D
P
L
C R
S X / /
D W
A Base[23..16]
16
Base[15..0] Limit[15..0]
15 0
CODE Base-Address = 0x00007C00
CODE Segment-Limit = 0x0FFFF (64-KB)
Segment-attributes: P=1, A=0, S=1, X=1, C=0, R=1
DPL=0, G=0, D=0 (RSV=0, AVL=0)
.WORD
0xFFFF, 0x7C00, 0x9A00, 0x0000
31
DATA segment-descriptor
Base[31..24] G D
R
S
V
A
V
L
Limit
[19..16]
P
D
P
L
C R
S X / /
D W
A Base[23..16]
16
Base[15..0] Limit[15..0]
15 0
DATA Base-Address = 0x00007C00
DATA Segment-Limit = 0x0FFFF (64-KB)
Segment-attributes: P=1, A=0, S=1, X=0, D=0, W=1
DPL=0, G=0, D=0 (RSV=0, AVL=0)
.WORD
0xFFFF, 0x7C00, 0x9200, 0x0000
31
STACK segment-descriptor
16
Base[31..24] G D
R
S
V
A
V
L
Limit
[19..16]
P
D
P
L
C R
S X / /
D W
A Base[23..16]
Base[15..0] Limit[15..0]
15 0
STACK Base-Address = 0x00007C00
STACK Segment-Limit = 0x001FF (512-Bytes)
Segment-attributes: P=1, A=0, S=1, X=0, D=1, W=1
DPL=0, G=0, D=0 (RSV=0, AVL=0)
.WORD
0x01FF, 0x7C00, 0x9600, 0x0000
Setting up the GDT
• Base-Address must be quadword-aligned
.ALIGN
8
• NULL-Descriptor occupies first quadward theGDT: .WORD
0, 0, 0, 0
• GDT base-address and segment-limit: base: #0x00007C00 + #theGDT limit: 8 * (number of descriptors) - 1
Loading register LDTR
GDTR BASE_ADDRESS LIMIT
48-bits
• We can load LDTR from our stack: mov add eax, #0x00007C00 ; boot location eax, #theGDT ; add GDT offset mov push push lgdt add dx, #0x27 eax dx
[esp] esp, #6
; five descriptors
; push bits 47..16
; push bits 15..0
; load 48-bit LDTR
; discard 3 words
Entering protected-mode
• No interrupts from any peripheral devices
(since BIOS’s real-mode ISRs won’t work)
• Set the PE-bit to 1 (in register CR0)
• Do a far-jump (to load the CS attributes)
• Load SS:SP with stacktop and attributes
• Setup DS and ES for data and vram
• Write character-string to video memory
Leaving protected-mode
• Be sure segment-registers are loaded with selectors for descriptors that have suitable segment-limits and segment-attributes for correct execution when back in real-mode
• Reset PE-bit to 0 (in register CR0)
• Do a far-jump (to load CS with paragraph)
• Load SS:SP with real-mode stack-address
• Wait for user’s keypress before rebooting
Demo-program
• We have a bootsector program on website
(‘pmhello.s’) which illustrates the principles just discussed
• Try assembling and installing it:
– $ as86 pmhello.s –b pmhello.b
– $ dd if=pmhello.b of=/dev/fd0
• Restart machine, use the GRUB memu to select this bootsector as execution-option
In-class exercises
• What happens if you changed the ‘code’ descriptor’s access-rights byte from 0x9A to 0x9C (i.e., conforming code-segment)?
• Where exactly in does the ‘expand-down’ stack-segment reside?
– BASE_ADDRESS = 0x00007C00
– SEGMENT_LIMIT = 0x001FF