;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Demo of "unreal" mode ; Chris Giese ; http://SisAndHappy.com/ChrisGiese ; ; I, the copyright holder of this work, hereby release it into the ; public domain. This applies worldwide. If this is not legally possible: ; I grant any entity the right to use this work for any purpose, ; without any conditions, unless such conditions are required by law. ; ; 27 Feb 2014: ; - Now a full-fledged DOS program; not just a snippet ; - 32-bit addresses in real mode (i.e. "unreal mode") are demonstrated ; by copying some text directly to video memory using a 32-bit ; address in EDI and a value of zero in ES. ; ; 31 Oct 2003: ; - Initial release ; ; Unreal mode is identical with real mode with one exception: 32-bit ; addresses greater than 0xFFFF are allowed (they do not cause INT 0x0D, ; as they do in true real mode). ; ; Unreal mode does not work with the CS or SS registers; nor with V86 mode. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BITS 16 ORG 0x100 ; DOS .COM file ; set text video mode 80x25 and clear screen mov ax,0x0003 int 0x10 ; check for 32-bit CPU mov dx,_cpu16_msg pushf pushf pop bx ; old FLAGS -> BX mov ax,bx xor ah,0x70 ; try changing b14 (NT) or b13:b12 (IOPL) push ax popf pushf pop ax ; new FLAGS -> AX popf xor bh,ah xor ax,ax and bh,0x70 ; 32-bit CPU if we changed NT or IOPL je msg_and_exit ; check if (32-bit) CPU is in V86 mode mov dx,_v86_msg smsw bx ; 'SMSW' is a '286+ instruction and bl,1 jne msg_and_exit ; point _gdt_ptr to _gdt xor eax,eax mov ax,ds shl eax,4 %if 1 add eax,_gdt mov [_gdt_ptr + 2],eax %else add [_gdt_ptr + 2],eax ; this will fail if called more than once %endif cli ; interrupts off push ds push es push fs push gs lgdt [_gdt_ptr] mov eax,cr0 ; CR0.PE=1: enable protected mode or al,1 mov cr0,eax mov bx,DATA_SEL ; selector to segment with 4GB-1 limit mov ds,bx ; set segment limits in descriptor caches mov es,bx mov fs,bx mov gs,bx dec al ; CR0.PE=0: back to (un)real mode mov cr0,eax ; loading segment registers in (un)real mode changes their base address ; but not the segment limit; which remains 4GB-1 pop gs pop fs pop es pop ds ; demo use of 32-bit address by copying stuff to bottom line of 80x25 screen push es xor di,di mov es,di mov edi,(0xB8000 + 80*2*24) mov esi,_unreal_msg mov ecx,_unreal_msg_len ; Action of "rep movsb" in (un)real mode: ; With a32 prefix byte (0x67): byte [ES:EDI++] <- [DS:ESI++], ECX times ; Without prefix byte: byte [ES:DI++] <- [DS:SI++], CX times a32 rep movsb pop es mov dx,_success_msg msg_and_exit: ; DOS syscall: write '$'-terminated string from DS:DX to stdout mov ah,0x09 int 0x21 ; DOS syscall: exit with ERRORLEVEL=0 mov ax,0x4C00 int 0x21 ; Global Descriptor Table ; NULL descriptor (required): _gdt: dw 0 ; limit 15:0 dw 0 ; base 15:0 db 0 ; base 23:16 db 0 ; access byte (descriptor type) db 0 ; b7-4=flags, b3-0=limit 19:16 db 0 ; base 31:24 ; data segment descriptor: DATA_SEL equ ($ - _gdt) dw 0xFFFF dw 0 db 0 db 0x92 ; present, ring 0, data, expand-up, writable ; can put zero byte here (instead of 0xCF) to DISABLE unreal mode: db 0xCF ; 32-bit segment, page-granular 20-bit limit=4GB-1 db 0 _gdt_end: _gdt_ptr: dw _gdt_end - _gdt - 1 ; GDT limit dd _gdt ; linear address of GDT (set by code above) _cpu16_msg: db "Sorry, 32-bit CPU required", 13, 10, '$' _v86_msg: db "Sorry, CPU in Virtual-8086 mode (Windows DOS box" db " or EMM386 loaded)", 13, 10, '$' _success_msg: db "Welcome to unreal mode!", 13, 10, db "There should be some black-on-green text" db " at the bottom of the screen", 13, 10, '$' ; This string is written directly to text-mode video memory. ; The alternating spaces are treated as character attribute bytes. ; 0x20 = black text (color 0) on green background (color 2) _unreal_msg: db "U n r e a l m o d e " _unreal_msg_len equ ($ - _unreal_msg)