//----------------------------------------------------------------- // vm86demo.s // // This example shows the steps needed to enter the x86 CPU's // 'Virtual-8086' mode, take some kind of perceptible action, // and then return to real-mode for a restart of the machine. // // to assemble: $ as vm86demo.s -o vm86demo.o // and to link: $ ld vm86demo.o -T ldscript -o vm86demo.b // and install: $ dd if=vm86demo.b of=/dev/sda4 seek=1 // // NOTE: This code begins executing with CS:IP = 1000:0002. // // programmer: ALLAN CRUSE // written on: 03 DEC 2008 //----------------------------------------------------------------- .section .text #------------------------------------------------------------------ .word 0xABCD #------------------------------------------------------------------ main: .code16 mov %sp, %cs:ipltos+0 mov %ss, %cs:ipltos+2 mov %cs, %ax mov %ax, %ss lea tos0, %sp call enter_protected_mode call execute_program_demo call leave_protected_mode lss %cs:ipltos, %sp lret #------------------------------------------------------------------ ipltos: .word 0, 0 #------------------------------------------------------------------ theTSS: .space 0x68 .equ limTSS, (.-theTSS)-1 #------------------------------------------------------------------ theIDT: .space 13 * 8 .word isrGPF, privCS, 0x8E00, 0x0000 .equ limIDT, (.-theIDT)-1 #------------------------------------------------------------------ theGDT: .quad 0x0000000000000000 .equ privCS, (.-theGDT)+0 .quad 0x00409A010000FFFF .equ privSS, (.-theGDT)+0 .quad 0x004092010000FFFF .equ sel_cs, (.-theGDT)+0 .quad 0x00009A010000FFFF .equ sel_ds, (.-theGDT)+0 .quad 0x000092010000FFFF .equ sel_es, (.-theGDT)+0 .quad 0x0000920B8000FFFF .equ sel_fs, (.-theGDT)+0 .quad 0x008F92000000FFFF .equ selTSS, (.-theGDT) .word limTSS, theTSS, 0x8901, 0x0000 .equ limGDT, (.-theGDT)-1 #------------------------------------------------------------------ regGDT: .word limGDT, theGDT, 0x0001 regIDT: .word limIDT, theIDT, 0x0001 regIVT: .word 0x03FF, 0x0000, 0x0000 #------------------------------------------------------------------ enter_protected_mode: cli mov %cr0, %eax bts $0, %eax mov %eax, %cr0 lgdt %cs:regGDT lidt %cs:regIDT ljmp $sel_cs, $pm pm: mov $sel_ds, %ax mov %ax, %ss xor %ax, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs ret #------------------------------------------------------------------ execute_program_demo: # preserve our current stacktop address mov %esp, %ss:tossav+0 mov %ss, %ss:tossav+4 # switch to a 32-bit stack mov $privSS, %ax mov %ax, %ss and $~0x3, %esp # establish the Task-State Segment mov $selTSS, %ax ltr %ax # initialize the SS0:ESP0 fields in our TSS mov %esp, %ss:theTSS+4 mov %ss, %ss:theTSS+8 # prepare the stack for a transfer to Virtual-8086 mode pushl $0 # image for GS pushl $0 # image for FS pushl $0 # image for DS pushl $0 # image for ES pushl $0x1000 # image for SS pushl $tos3 # image for SP pushl $0x00020000 # image for EFLAGS pushl $0x1000 # image for CS pushl $vm86 # image for IP # transfer to Virtual-8086 mode (in ring3) iretl #------------------------------------------------------------------ tossav: .long 0, 0 # area for holding SS:ESP #------------------------------------------------------------------ back_to_main_routine: lss %cs:tossav, %esp # recover former stacktop ret # and go back to 'main' #------------------------------------------------------------------ vm86: .code16 # set all text-mode video attributes to a blue-background mov $0xB800, %ax # address video memory mov %ax, %ds # with DS register mov %ax, %es # also ES register xor %si, %si # point DS:SI to start xor %di, %di # point ES:DI to start cld # do forward processing mov $0x4000, %cx # number of video words nxpel: lodsw # fetch picture-element mov $0x17, %ah # set attribute-byte stosw # store picture-element loop nxpel # again for entire vram hlt # generate a GP-exception #------------------------------------------------------------------ isrGPF: .code32 # this is our exception-handler for GP-exceptions ljmp $sel_cs, $back_to_main_routine #------------------------------------------------------------------ leave_protected_mode: .code16 mov $sel_ds, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs mov %cr0, %eax btr $0, %eax mov %eax, %cr0 ljmp $0x1000, $rm rm: mov %cs, %ax mov %ax, %ss lidt %cs:regIVT sti ret #------------------------------------------------------------------ .align 16 .space 256 tos3: .space 256 tos0: #------------------------------------------------------------------ .end