; Assemble with ; nasm -f bin unreal.asm -o unreal.obj ; ; Link with Watcom Linker to unreal.exe ; wlink format dos file unreal.obj ; ; Or link with MS 16-bit segmented linker ; link16 unreal.obj; ; ; Or link with TLink (Turbo link) ; tlink unreal.obj ; Macro to build a GDT descriptor entry %define MAKE_GDT_DESC(base, limit, access, flags) \ (((base & 0x00FFFFFF) << 16) | \ ((base & 0xFF000000) << 32) | \ (limit & 0x0000FFFF) | \ ((limit & 0x000F0000) << 32) | \ ((access & 0xFF) << 40) | \ ((flags & 0x0F) << 52)) bits 16 segment data align 4 gdt: FLAT_SEL equ .flat - .start .start: .null: dq MAKE_GDT_DESC(0, 0, 0, 0) ; null descriptor .flat: dq MAKE_GDT_DESC(0, 0x000fffff, 10010010b, 1100b) ; 32-bit data, 4kb gran, limit 0xffffffff bytes, base=0 .end: .gdtr: dw .end - .start - 1 ; limit (Size of GDT - 1) dd .start ; base of GDT. Needs to be fixed up at runtime in_pmode_str: db "Processor already in protected mode - exiting", 0x0a, 0x0d, "$" section code ; ..start is a special label for the DOS entry point ..start: ; Save initial EFLAGS state pushfd cli ; Initialize DS to our DOS DATA segment (needed for EXEs) ; SS:SP will be set by the DOS EXE loader to our stack segment mov ax, data mov ds, ax check_pmode: smsw ax test ax, 0x1 ; Check if we are already in protected mode ; This may be the case if we are in a VM8086 task. ; EMM386 and other expanded memory manager often ; run DOS in a VM8086 task. DOS extenders will have ; the same effect jz not_prot_mode ; If not in protected mode proceed to switch mov dx, in_pmode_str ; otherwise print an error and exit back to DOS mov ah, 0x9 int 0x21 ; Print Error jmp exit ; Exit program not_prot_mode: ; Apply a fixup to the GDTR base to convert to a linear address mov eax, ds shl eax, 4 add [gdt.gdtr+2], eax lgdt [gdt.gdtr] ; Load our GDT mov cx, ds ; Save DS so it can be restored mov eax, cr0 or al, 1 mov cr0, eax ; Set protected mode flag jmp .next1 ; Flush the instruction pefetch queue .next1: ; In 16-bit protected mode ; Since we aren't changing CS ; we don't need to enter 32-bit protected mode mov bx, FLAT_SEL mov ss, bx mov ds, bx mov es, bx mov fs, bx mov gs, bx and al, ~1 mov cr0, eax ; Unset protected mode flag jmp .next2 ; Flush the instruction pefetch queue .next2: ; Unreal mode here ; Restore SS=DS=ES mov ss, cx mov ds, cx mov es, cx ; Print UNR to the screen using a flat 4GiB selector ; This code won't work in regular real mode xor ax, ax mov fs, ax mov word fs:[dword 0xb8000+80*2*3+0], 0x57<<8 | 'U' mov word fs:[dword 0xb8000+80*2*3+2], 0x57<<8 | 'N' mov word fs:[dword 0xb8000+80*2*3+4], 0x57<<8 | 'R' exit: ; Restore initial EFLAGS state popfd ; DOS exit mov ax, 0x4c00 int 0x21 segment stack stack resb 1024