;//--------------------------------------------------------------- ;// trypages.s ;// ;// This program builds a page-table and page-directory which ;// define an identity-mapping for the lowest megabyte of the ;// system's memory (i.e., the 8086 real-mode memory region). ;// ;// ;// assemble with: $ as86 trypages.s -b trypages.b ;// install using: $ dd if=trypages.b of=/dev/fd0 seek=1 ;// ;// NOTE: This code begins executing with CS:IP = 1000:0002. ;// ;// programmer: ALLAN CRUSE ;// date begun: 27 MAR 2004 ;// completion: 19 APR 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 create_system_tables call enter_protected_mode call exec_the_paging_demo call leave_protected_mode push dword return_address ; recover our exit-address retf ; exit to program launcher ;----------------------------------------------------------------- return_address: .LONG 0 ; to store exit-address ;----------------------------------------------------------------- ; EQUATES realCS EQU 0x1000 ; segment-address of code limGDT EQU 0x001F ; allocates 4 descriptors sel_es EQU 0x0008 ; vram-segment selector sel_cs EQU 0x0010 ; code-segment selector sel_ss EQU 0x0018 ; data-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 ;----------------------------------------------------------------- pgdir: .LONG 0x00018000 ; page-directory address pgtbl: .LONG 0x00019000 ; and page-table address ;----------------------------------------------------------------- ;----------------------------------------------------------------- create_system_tables: ; clear memory-area from 1000:8000 to 2000:0000 (8 pages) mov eax, pgdir ; address for our tables shr eax, #4 ; is divided by sixteen mov es, ax ; use quotient as segment xor di, di ; point ES:DI to tables cld ; use forward processing xor eax, eax ; use zero as fill-value mov cx, #0x2000 ; fill 8192 double-words rep stosd ; perform fill operation ; now setup an "identity-mapping" for conventional memory mov di, #0x1000 ; point ES:DI to page-table xor eax, eax ; first page-frame address or eax, #3 ; 'present' and 'writable' mov cx, #256 ; one-megabyte = 256 frames .L0: stosd ; write page-table entry add eax, #0x1000 ; next page-frame address loop .L0 ; write the other entries ; now setup the initial page-directory entry mov eax, pgtbl ; address of page-table or eax, #0x3 ; 'present' and 'writable' xor di, di ; point ES:DI to directory stosd ; write a directory-entry ret ;----------------------------------------------------------------- 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 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 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 ;----------------------------------------------------------------- msg: .ASCII " Hello from virtual memory " len: .WORD * - msg ; length of message text ;----------------------------------------------------------------- exec_the_paging_demo: ; store physical address of our page-directory in CR3 mov eax, pgdir ; page-directory address mov cr3, eax ; in control register 3 ; enable paging mov eax, cr0 ; get machine status bts eax, #31 ; turn on the PG-bit mov cr0, eax ; set machine status jmp pg ; flush prefetch queue pg: ; draw a message on the video screen mov ax, #sel_es ; address video memory mov es, ax ; with ES register mov di, #1600 ; point ES:DI to line 10 lea si, msg ; point DS:SI to message cld ; do forward processing mov ah, #0x1F ; white-on-blue colors mov cx, len ; setup character-count .L1: lodsb ; fetch next character stosw ; store char and color loop .L1 ; draw entire message ; disable paging mov eax, cr0 ; get machine status btr eax, #31 ; reset PG-bit image mov cr0, eax ; set machine status ; invalidate the CPU's TLB (Translation Lookaside Buffer) mov eax, cr3 ; read contents of CR3 mov cr3, eax ; write CR3 to flush TLB ret ;----------------------------------------------------------------- .ALIGN 16 ; alignment at paragraph .SPACE 512 ; reserved for stack use tos0: ; label fop top-of-stack ;----------------------------------------------------------------- END