;//--------------------------------------------------------------- ;// ex1.s (Instructor's solution to in-class exercise #1) ;// ;// This program is a modification of the 'tryring1.s' demo. ;// (The three lines that got changed are marked by arrows.) ;// ;// assemble with: $ as86 ex1.s -b ex1.b ;// install using: $ dd if=ex1.b of=/dev/fd0 seek=1 ;// ;// NOTE: This code begins executing with CS:IP = 1000:0002. ;// ;// programmer: ALLAN CRUSE ;// written on: 14 FEB 2004 -- originally called 'tryring1' ;// revised on: 19 FEB 2004 -- to use 32-bit TSS and CALLGATE ;//--------------------------------------------------------------- .SECT .TEXT ;----------------------------------------------------------------- .WORD 0xABCD ; programming signature ;----------------------------------------------------------------- main: mov ax, cs ; address this segment mov ds, ax ; with DS register pop dword return_address ; store return-address mov ss, ax ; adjust SS register lea sp, tos0 ; setup ring0 stacktop call enter_protected_mode call exec_ring1_procedure finis: call leave_protected_mode push dword return_address ; recover our exit-address retf ; exit to program launcher ;----------------------------------------------------------------- return_address: .LONG 0 ; storage for far return ;----------------------------------------------------------------- ; EQUATES for our segment-descriptor and call-gate selectors sel_tss EQU 0x08 ; selector for task-state sel_cs0 EQU 0x10 ; selector for ring0 code sel_ss0 EQU 0x18 ; selector for ring0 data sel_cs1 EQU 0x21 ; selector for ring1 code sel_ss1 EQU 0x29 ; selector for ring1 data sel_es1 EQU 0x31 ; selector for ring1 vram sel_ret EQU 0x38 ; selector for call-gate ;----------------------------------------------------------------- .ALIGN 8 ; table-alignment theGDT: .WORD 0x0000, 0x0000, 0x0000, 0x0000 ; null-descriptor .WORD 0x000B, theTSS, 0x8901, 0x0000 ; task-descriptor <-- 2 changes .WORD 0xFFFF, 0x0000, 0x9A01, 0x0000 ; code-descriptor .WORD 0xFFFF, 0x0000, 0x9201, 0x0000 ; data-descriptor .WORD 0xFFFF, 0x0000, 0xBA01, 0x0000 ; code-descriptor .WORD 0xFFFF, 0x0000, 0xB201, 0x0000 ; data-descriptor .WORD 0x7FFF, 0x8000, 0xB20B, 0x0000 ; vram-descriptor .WORD finis, sel_cs0, 0xAC00, 0x0000 ; call-descriptor <-- 1 change ;----------------------------------------------------------------- theTSS: .LONG 0, tos0, sel_ss0 ; essential pieces of TSS <-- 1 change ;----------------------------------------------------------------- ;----------------------------------------------------------------- regGDT: .WORD 0x003F, theGDT, 0x0001 ; image for register GDTR ;----------------------------------------------------------------- enter_protected_mode: ; NOTE: not prepared for interrupts in protected-mode! cli ; no device interrupts ; turn on PE-bit in system register CR0 mov eax, cr0 ; get machine status bts eax, #0 ; set PE-bit to 1 mov cr0, eax ; turn on protection ; reinitialize CS and SS segment-register caches lgdt regGDT ; initialize GDTR jmpf #pm, #sel_cs0 ; reload CS register pm: mov ax, #sel_ss0 mov ss, ax ; reload SS register ; nullify 'stale' values in other segment-registers xor ax, ax ; purge invalid values mov ds, ax ; from DS register mov es, ax ; also ES register ret ;----------------------------------------------------------------- leave_protected_mode: ; insure segment-registers have real-mode attributes mov ax, ss ; put limit and rights mov ds, ax ; into the DS cache mov es, ax ; alse the ES cache ; turn off protection mov eax, cr0 ; read machine status btr eax, #0 ; reset PE-bit to 0 mov cr0, eax ; turn off protection ; reinitialize CS, DS, SS for 'real-mode' addressing jmpf #rm, #0x1000 ; reload CS register rm: mov ax, cs mov ss, ax ; reload SS register mov ds, ax ; reload DS register ; NOTE: now the system can handle interrupts again! sti ; device interrupts ok ret ;----------------------------------------------------------------- ;----------------------------------------------------------------- exec_ring1_procedure: ; initialize the TR register mov ax, #sel_tss ; address task-state ltr ax ; with TR register ; setup ring0 stack for "return" to ring1 procedure push word #sel_ss1 ; push SS-image push word #tos1 ; push SP-image push word #sel_cs1 ; push CS-image push word #showmsg ; push IP-image retf ; transfer to ring1 ;----------------------------------------------------------------- ;================================================================= ;=============== RING-1 TEXT AND DATA FOLLOWS ================== ;================================================================= ;----------------------------------------------------------------- msg1: .ASCII " Now executing in ring1 " ; text of message len1: .WORD * - msg1 ; size of message ;----------------------------------------------------------------- showmsg: ; display our ring1 confirmation-message mov ax, #sel_cs1 ; address our message text mov ds, ax ; with DS segment-register mov ax, #sel_es1 ; address the display vram mov es, ax ; with ES segment-register cld ; use forward processing lea si, msg1 ; point DS:SI to string mov di, #320 ; point ES:DI to screen mov ah, #0x2E ; yellow against green mov cx, len1 ; number of characters nxchr: lodsb ; fetch next character stosw ; store char and color loop nxchr ; print entire message ; transfer control through call-gate back to ring 0 callf #0, #sel_ret ; invoke far direct call ;----------------------------------------------------------------- ;================================================================= ;============== STORAGE ALLOCATED FOR STACK USE ================ ;================================================================= ;----------------------------------------------------------------- .ALIGN 16 ; insure proper alignment .SPACE 1024 ; storage for ring1 stack tos1: ; labels the top-of-stack ;----------------------------------------------------------------- .SPACE 1024 ; storage for ring0 stack tos0: ; labels the top-of-stack ;----------------------------------------------------------------- END