;//--------------------------------------------------------------- ;// tryvm86.s ;// ;// This program, after entering protected-mode, executes ;// a real-mode procedure in Virtual-8086 emulation mode. ;// The program exits VM86-mode when a General Protection ;// Exception is triggered, e.g., by a 'hlt' instruction. ;// ;// assemble with: $ as86 tryvm86.s -b tryvm86.b ;// install using: $ dd if=tryvm86.b of=/dev/fd0 seek=1 ;// ;// NOTE: This code begins executing with CS:IP = 1000:0002. ;// ;// programmer: ALLAN CRUSE ;// written on: 23 MAR 2004 ;//--------------------------------------------------------------- .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 esp, tos0 ; and set new stacktop call initialize_os_tables call enter_protected_mode call execute_program_demo call leave_protected_mode push dword return_address ; recover our exit-address retf ; exit to program launcher ;----------------------------------------------------------------- return_address: .LONG 0, tos0, sel_ss ; to store exit-address ;----------------------------------------------------------------- ; EQUATES realCS EQU 0x1000 ; segment-address of code limGDT EQU 0x0027 ; allocates 5 descriptors sel_es EQU 0x0008 ; vram-segment selector sel_cs EQU 0x0010 ; code-segment selector sel_ss EQU 0x0018 ; data-segment selector sel_ts EQU 0x0020 ; TSS-segment selector ;----------------------------------------------------------------- .ALIGN 8 theGDT: .WORD 0x0000, 0x0000, 0x0000, 0x0000 ; null descriptor .WORD 0x7FFF, 0x8000, 0x920B, 0x0000 ; vram descriptor .WORD 0xFFFF, 0x0000, 0x9A01, 0x0000 ; code descriptor .WORD 0xFFFF, 0x0000, 0x9201, 0x0000 ; data descriptor .WORD 0x000B, theTSS, 0x8901, 0x0000 ; TSS descriptor ;----------------------------------------------------------------- theIDT: .SPACE 2048 ; enough for 256 gate-descriptors ;----------------------------------------------------------------- theTSS: .LONG 0, 0, 0 ; 32bit Task-State Segment ;----------------------------------------------------------------- ;----------------------------------------------------------------- enter_protected_mode: cli ; no device interrupts mov eax, cr0 ; get machine status bts eax, #0 ; set PE-bit to 1 mov cr0, eax ; enable protection push #0x0001 ; push base-address hiword push #theGDT ; push base-address loword push #limGDT ; push GDT's segment-limit lgdt [esp] ; load GDTR register-image add sp, #6 ; discard three stackwords push #0x0001 ; push base-address hiword push #theIDT ; push base-address loword push #0x07FF ; push IDT's segment-limit lidt [esp] ; load IDTR register-image add sp, #6 ; discard three stackwords jmpf #pm, #sel_cs ; reload register CS pm: mov ax, #sel_ss mov ss, ax ; reload register SS mov ds, ax ; reload register DS xor ax, ax ; use 'null' selector mov es, ax ; to purge invalid ES mov fs, ax ; to purge invalid FS mov gs, ax ; to purge invalid GS ret ; back to main routine ;----------------------------------------------------------------- leave_protected_mode: mov ax, ss ; address 64KB r/w segment mov ds, ax ; using DS register mov es, ax ; and ES register mov eax, cr0 ; get machine status btr eax, #0 ; reset PE-bit to 0 mov cr0, eax ; disable protection push #0x0000 ; push base-address hiword push #0x0000 ; push base-address loword push #0x03FF ; push IDT's segment-limit lidt [esp] ; load IDTR register-image add sp, #6 ; discard three stackwords jmpf #rm, #realCS ; reload register CS rm: mov ax, cs mov ss, ax ; reload register SS mov ds, ax ; reload register DS sti ; interrupts allowed ret ; back to main routine ;----------------------------------------------------------------- ;----------------------------------------------------------------- initialize_os_tables: ; initialize IDT descriptor for gate 0x0D mov edi, #0x0D ; ID-number for GP-fault lea di, theIDT[edi*8] ; address gate-descriptor mov 0[di], #isrGPF ; entry-point loword mov 2[di], #sel_cs ; selector for code mov 4[di], #0x8E00 ; 386 interrupt-gate mov 6[di], #0x0000 ; entry-point hiword ret ;----------------------------------------------------------------- execute_program_demo: mov theTSS+4, esp ; current stack-address mov theTSS+8, ss ; preserved in 'theTSS' mov ax, #sel_ts ; establish 'theTSS' as ltr ax ; Task-State Segment pushfd ; insure NT-bit is clear btr [esp], #14 ; in the EFLAGS register popfd ; before executing iretd push dword #0 ; register-image for GS push dword #0 ; register-image for FS push dword #0 ; register-image for DS push dword #0 ; register-image for ES push dword #realCS ; register-image for SS push dword #tos3 ; register-image for SP push dword #0x00023000 ; EFLAGS register-image push dword #realCS ; register-image for CS push dword #turn_blue ; register-image for IP iretd ; enter Virtual-8086 mode ;----------------------------------------------------------------- finish_up_main_thread: CSEG ; address theTSS with CS lss esp, theTSS+4 ; restore saved stackptr ret ; return to main routine ;----------------------------------------------------------------- turn_blue: mov ax, #0xB800 ; address video memory mov ds, ax ; with DS register mov es, ax ; also ES register xor si, si ; point DS:SI to start xor di, di ; point ES:DI to start cld ; use forward processing mov cx, #2000 ; number of screen cells .L0: lodsw ; fetch next char/attrib mov ah, #0x1F ; set new attribute byte stosw ; store that char/attrib loop .L0 ; process the next cell hlt ; privileged instruction ;----------------------------------------------------------------- ;----------------------------------------------------------------- isrGPF: ; quits when the first privileged opcode is encountered jmpf #finish_up_main_thread, #sel_cs ;----------------------------------------------------------------- .ALIGN 16 ; alignment at paragraph .SPACE 512 ; reserved for stack use tos3: ; label fop top-of-stack ;----------------------------------------------------------------- .ALIGN 16 ; alignment at paragraph .SPACE 512 ; reserved for stack use tos0: ; label fop top-of-stack ;----------------------------------------------------------------- END