;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
;³           PMode Tutorial (c) 1996 MATTsoft, All rights reserved.          ³
;ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
;³            THiS iS EXAMPLE (6th) Stack and pmode call to 'main'           ³
;³                    úúúúúúúúúúúúú G00D LuCK! úúúúúúúúúúúúú                 ³
;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

; þþþþþþþþþþþþþ IMPORTANT þþþþþþþþþþþþþþ
; ÛÛÛÛÛÛ Select your graphics card ÛÛÛÛÛÛ
 VIDEO_SEG equ 0B0000h	; for HERCULES
;VIDEO_SEG equ 0B8000h	; for VGA
; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

LOCALS @@
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
CODE16  SEGMENT BYTE PUBLIC 'CODE'
        ASSUME CS:CODE16,DS:DATA16
        .386
	.386P
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
Start:  mov ax,DATA16
	mov ds,ax
	mov es,ax
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        call CheckProcessor                     ; Check if 386+
	call CheckV86				; Check V86 mode
        call EnableA20
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
	ASSUME DS:DATA32
        ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        xor eax,eax
        mov ax,DATA32
        mov ds,ax
        ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        shl eax,4
        add dword ptr ds:[GDT+2],eax
        ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        xor eax,eax
        mov ax,CODE16
        shl eax,4
        add dword ptr ds:[GDT_Code16+2],eax
        ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        xor eax,eax
        mov ax,CODE32
        shl eax,4
        add dword ptr ds:[GDT_Code32+2],eax
        ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        xor eax,eax
        mov ax,DATA32
        shl eax,4
        add dword ptr ds:[GDT_Data32+2],eax
        ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        xor eax,eax
        mov ax,STACK32
        shl eax,4
        add dword ptr ds:[GDT_Stack32+2],eax
        ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        xor eax,eax
        mov ax,DATA16
        shl eax,4
        add dword ptr ds:[GDT_Data16+2],eax
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
	cli
        lgdt fword ptr ds:[GDT]                 ; Load GDTR
        mov eax,cr0
        or al,1
        mov cr0,eax                             ; Set Pmode
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        db 0EAh
        dw 0
        dw CODE32_idx
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
Exit16:
	cli
	pop cx
	pop edx
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        mov eax,cr0
        xor al,1
        mov cr0,eax                             ; Return back to real :-(
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
	mov ss,cx				; Restore DOS stack
	mov esp,edx
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        mov ax,4c00h
        int 21h                                 ; ... and terminate
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                               $0ME R0UTiNES...

;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
; Checks if the processor is 386+
CheckProcessor:
	pushf			; save flags for later
        xor ah,ah               ; clear high byte
        push ax                 ; push AX on the stack
	popf			; pop this value into the flag register
	pushf			; push flags on the stack
        pop ax                  ; ...and get flags into AX
        and ah,0f0h             ; try to set the high nibble
        cmp ah,0f0h             ; on a 80386, the high nibble can never be 0f0h
        je @@1                  ; ...
        mov ah,70h              ; now try to set NT and IOPL
        push ax                 ;
        popf                    ;
        pushf                   ;
        pop ax                  ;
        and ah,70h              ; if they couldn't be modified, no 386 is installed
        jz @@1                  ; ...
	popf			; restore flags
        retn                    ; and return
@@1:    mov dx,offset no386err  ; if there is no 386, exit with error msg
        mov ah,9
        int 21h
        mov ax,4c01h
        int 21h

;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
; Checks if in V86 mode
CheckV86:
        smsw ax                 ; mov eax,cr0 is not allowed in V86
        test al,1               ; Test for V86
        jnz @@1
        ret
@@1:    mov dx,offset InV86err  ; if in V86, exit with error msg
        mov ah,9
        int 21h
        mov ax,4c02h
        int 21h
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
; Enable A20 gate
EnableA20:
        mov ah,11011111b
        call GateA20
        or al,al
        jnz @@1
        ret
@@1:    mov dx,offset A20err
        mov ah,9
        int 21h
        mov ax,4C03h
        int 21h
GateA20:cli
        call @@2
        jnz @@1
        mov al,0d1h
        out 64h,al
        call @@2
        jnz @@1
        mov al,ah
        out 60h,al
        call @@2
@@1:    ret
@@2:    push cx
        sub cx,cx
@@3:    in al,64h
        and al,00000010b
        loopnz @@3
        pop cx
        ret

;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
CODE16  ENDS
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
DATA16  SEGMENT PARA PUBLIC 'DATA' USE16

;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
; Error messages
no386err db '386 is needed!',13,10,'$'
InV86err db 'Processor is in V86 mode!',13,10,'$'
A20err   db 'A20 error!!!',13,10,'$'

DATA16  ENDS
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
DATA32  SEGMENT PARA PUBLIC 'DATA32' USE32
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
; Global Descriptor Table
GDT     	dw GDT_Size			; Limit[0..15]
		dd offset GDT_0			; Base[0..32]
                ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
GDT_0           dw 0                            ; Limit[0..15]
                db 0,0,0                        ; Base[0..23]
                db 0                            ; AR[]
                db 0                            ; Info[]
                db 0                            ; Base[24..31]
                ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
GDT_Core32      dw 0ffffh                       ; Limit[0..15]
                db 0,0,0                        ; Base[0..23]
                db 10010010b                    ; AR[P=1,DPL=0,ED=0,W=1,A=0]
                db 11001111b                    ; Info[G=1,s=1], Limit[16..19]
                db 0                            ; Base[24..31]
                ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
GDT_Code32      dw 0ffffh                       ; Limit[0..15]
                db 0,0,0                        ; Base[0..23]
                db 10011010b                    ; AR[P=1,DPL=0,C=0,R=1,A=0]
                db 11001111b                    ; Info[G=1,s=0], Limit[16..19]
                db 0                            ; Base[24..31]
                ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
GDT_Data32      dw 0ffffh                       ; Limit[0..15]
                db 0,0,0                        ; Base[0..23]
                db 10010010b                    ; AR[P=1,DPL=0,ED=0,W=1,A=0]
                db 11001111b                    ; Info[G=1,s=1], Limit[16..19]
                db 0                            ; Base[24..31]
                ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
GDT_Stack32     dw 0ffffh                       ; Limit[0..15]
                db 0,0,0                        ; Base[0..23]
                db 10010010b                    ; AR[P=1,DPL=0,ED=0,W=1,A=0]
                db 11001111b                    ; Info[G=1,s=1], Limit[16..19]
                db 0                            ; Base[24..31]
                ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
GDT_Code16      dw 0ffffh                       ; Limit[0..15]
                db 0,0,0                        ; Base[0..23]
                db 10011010b                    ; AR[P=1,DPL=0,C=0,R=1,A=0]
                db 00000000b                    ; Info[G=0,s=0], Limit[16..19]
                db 0                            ; Base[24..31]
                ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
GDT_Data16      dw 0ffffh                       ; Limit[0..15]
                db 0,0,0                        ; Base[0..23]
                db 10010010b                    ; AR[P=1,DPL=0,ED=0,W=1,A=0]
                db 00000000b                    ; Info[G=1,s=1], Limit[16..19]
                db 0                            ; Base[24..31]
                ;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
GDT_Size = ($-GDT_0)
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú

CORE32_idx  = 08h
CODE32_idx  = 10h
DATA32_idx  = 18h
STACK32_idx = 20h
CODE16_idx  = 28h
DATA16_idx  = 30h


My_Msg	db 'Now in protected mode!'

DATA32  ENDS
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
STACK32 SEGMENT BYTE PUBLIC 'STACK32' USE32
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
STACK32_stk  db 100h dup (0)
STACK32_end label byte
STACK32_size = (STACK32_end-STACK32_stk)
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
STACK32 ENDS
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
CODE32  SEGMENT PARA PUBLIC 'CODE32' USE32
	ASSUME CS:CODE32,DS:DATA32

; ÛÛÛÛ Start32 Must be AT OFFSET 0000h !!!! ÛÛÛÛ
Start32:
	mov ax,CORE32_idx
	mov es,ax
	mov fs,ax
	mov gs,ax
	mov ax,DATA32_idx
	mov ds,ax
	mov cx,ss
	mov edx,esp
	mov ax,STACK32_idx
	mov ss,ax
	mov esp,offset STACK32_end
	push edx
	push cx
	sti

        call main

        db 0eah
	dw offset Exit16
	dw 0
	dw CODE16_idx

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

main:   mov esi,offset My_Msg
	mov edi,VIDEO_SEG+640
	mov ah,0eh
	mov ecx,22

@@1:	lodsb
	stosw
	loop @@1
        ret

CODE32    ENDS
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
        END
