;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
;³           PMode Tutorial (c) 1996 MATTsoft, All rights reserved.          ³
;ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
;³ THiS iS EXAMPLE (4th) Switch to Pmode, setup GDTR and write to screen '?' ³
;³                    úúúúúúúúúúúúú G00D LuCK! úúúúúúúúúúúúú                 ³
;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

; þþþþþþþþþþþþþ IMPORTANT þþþþþþþþþþþþþþ
; ÛÛÛÛÛÛÛÛ Select your gr. card ÛÛÛÛÛÛÛÛ
 VIDEO_SEG equ 0B0000h	; for HERCULES
;VIDEO_SEG equ 0B8000h	; for VGA
; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

LOCALS @@
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
CODE    SEGMENT BYTE PUBLIC 'CODE'
        ASSUME CS:CODE,DS:DATA
        .386
	.386P
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
Start:  mov ax,DATA
	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
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        lgdt fword ptr ds:[GDT]                 ; Load GDTR
        mov eax,cr0
        or al,1
        mov cr0,eax                             ; Set Pmode
        mov ax,CORE32_idx
	mov ds,ax
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
	mov ebx,VIDEO_SEG
	add ebx,320
	mov word ptr ds:[ebx],'??'
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        mov eax,cr0
        xor al,1
        mov cr0,eax                             ; Return back to real :-(
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
        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

;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú
CODE    ENDS
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
DATA    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,'$'

DATA    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_Size = ($-GDT_0)
;ùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùúùú

CORE32_idx = 08h

DATA32  ENDS
;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
        END
