; Flat Real Mode Initializer -
;    A tiny ASM app to initialize the undocumented x86 addressing

; Copyright (C) 1999  by Louis P. Santill n
;    Parts taken from bootsector code of Jeff Weeks, John Fine, and
;    Flat Real Mode demonstration code of ASM Gems

; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation; either version 2
; of the License, or (at your option) any later version.

; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.

; You should have received a copy of the GNU General Public License
; along with this program; if not, write to

; the Free Software Foundation, Inc.
; 59 Temple Place
; Suite 330
; Boston, MA  02111-1307
; USA

[BITS 16]
[
ORG 0x100]

JMP main

detectEMM
:
  
MOV SI, detectingEMMString
  
CALL puts

  
PUSH ES
   MOV AX
, 0
  
MOV ES, AX
   MOV BX
, 0x91
  
MOV CX, [ ES : BX ]
  
MOV AX, [ ES : BX + 2 ]
  
MOV ES, AX
   MOV BX
, CX
   ADD BX
, 0x000A

  
MOV AX, [ ES : BX ]
  
CMP AX, [ EMMDeviceNameCMPString ]
  
JNE detectEMM@@

  
MOV AX, [ ES : BX + 2 ]
  
CMP AX, [ EMMDeviceNameCMPString + 2 ]
  
JNE detectEMM@@
   
  
MOV AX, [ ES : BX + 4 ]
  
CMP AX, [ EMMDeviceNameCMPString + 4 ]
  
JNE detectEMM@@
   
  
MOV AX, [ ES : BX + 6 ]
  
CMP AX, [ EMMDeviceNameCMPString + 6 ]
  
JNE detectEMM@@

  
POP ES
   
   MOV AH
, getEMMVersion
  
INT EMMint

  
JMP detectEMM00

   detectEMM@@
:
     
POP ES

      MOV SI
, checked
     
CALL puts

     
MOV SI, NWLN
     
CALL puts

     
MOV BYTE [ EMMflag ], EMMnotInstalled

     
JMP detectEMM01

   detectEMM00
:
     
; EMM is install...we should not continue
     
PUSH AX

      MOV SI
, unChecked
     
CALL puts

     
MOV SI, EMMVersionString
     
CALL puts

     
POP AX

      AND AL
, 0xF0
     
MOV CL, 4
     
SHR AX, CL
      CALL
puti

     
MOV SI, EMMVersionXString
     
CALL puts

     
MOV BYTE [ EMMflag ], 0

  
detectEMM01:
     
RET
;///////////////////////////////////////////////////////////////////////
detectXMM:
  
MOV SI, detectXMMString
  
CALL puts

  
MOV AX, 0x4300
  
INT 0x2F

  
CMP AL, 0x80
  
JE detectXMM00
   
     
MOV BYTE [ XMMflag ], XMMnotInstalled
      
     
MOV SI, unChecked
     
CALL puts
   
     
MOV SI, XMMnotInstalledString
     
CALL puts

     
JMP detectXMM@@

   detectXMM00
:
     
PUSH DX
      PUSH BX
      PUSH AX

      MOV SI
, checked
     
CALL puts

     
MOV SI, XMMVersionString
     
CALL puts

     
POP AX
      PUSH AX

      AND AH
, 0x0F
     
MOV AL, AH
      CALL
puti

     
MOV SI, dotString
     
CALL puts

     
POP AX
      PUSH AX
      
      AND AL
, 0xF0
     
MOV CL, 4
     
SHR AL, CL
      CALL
puti

     
POP AX
      AND AX
, 0x000F
     
CALL puti

     
MOV SI, NWLN
     
CALL puts

     
MOV SI, useXMMString
     
CALL puts

     
; Still need to add HMA detection (DX) and internal revision (BX) check
     
POP BX
      POP DX

  
detectXMM@@:
     
RET
;///////////////////////////////////////////////////////////////////////
detectCPU:
  
MOV SI, check286Plus
  
CALL puts

  
PUSHF

   XOR AH
, AH
   PUSH AX
   POPF

   PUSHF
   POP AX
   AND AH
, 0xF0
  
CMP AH, 0xF0
  
; < 286 check
  
JE detectCPU01

     
MOV SI, unChecked
     
CALL puts

     
MOV SI, check386Plus
     
CALL puts

     
MOV AH, 0xF0
     
PUSH AX
      POPF

      PUSHF
      POP AX
      AND AH
, 0xF0
     
; 386 check
     
JZ detectCPU00

     
MOV BYTE [ CPUflag ], found386Flag

     
MOV SI, checked
     
CALL puts

     
MOV SI, found386Plus
     
CALL puts

     
JMP detectCPU02

   detectCPU00
     
MOV BYTE [ CPUflag ], 2

     
MOV SI, unChecked
     
CALL puts

     
MOV SI, found286Plus
     
CALL puts

   detectCPU01
:
     
MOV SI, unChecked
     
CALL puts
   
     
MOV SI, foundSub286
     
CALL puts

   detectCPU02
:
     
POPF
      
      RET
;///////////////////////////////////////////////////////////////////////
puts:
  
LODSB
   OR AL
, AL
   JZ
puts00
  
MOV AH, 0x0E
  
MOV BX, 0x0007
  
INT 0x10
  
JMP puts
   puts00
:
     
RET
;///////////////////////////////////////////////////////////////////////
initFlatRealMode:
  
CLI
   PUSH DS
   PUSH ES
   PUSH FS
   PUSH GS
   
   XOR EAX
, EAX
   MOV AX
, DS
   SHL EAX
, 4
  
ADD [ GDT + 2 ], EAX
   LGDT
[ GDT ]

  
MOV EAX, CR0
  
INC AX
   MOV
CR0, EAX
   MOV BX
, flatdata
   
  
MOV DS, BX
   MOV ES
, BX
   MOV FS
, BX
   MOV GS
, BX
   
   DEC AX
   MOV
CR0, EAX

   POP GS
   POP FS
   POP ES
   POP DS
   
   STI

   RET
;//////////////////////////////////////////////////////////////////////
puti:
  
ADD AL, '0'
  
MOV AH, 0x0E
  
MOV BX, 0x0007
  
INT 0x10
  
RET
;//////////////////////////////////////////////////////////////////////
enableA20:
  
MOV AL, 0xD1
  
OUT 0x64, AL
   CALL
A20Wait
  
MOV AL, 0xDF
  
OUT 0x60, AL
   CALL
A20Wait
  
MOV AL, 0xFF
  
OUT 0x64, AL
   CALL
A20Wait
  
RET

A20Wait:
  
IN AL, 0x64
  
JMP A20Wait00
   A20Wait00
:
     
AND AL, 2
     
JNZ A20Wait
  
RET
;//////////////////////////////////////////////////////////////////////
  
%define ENDL 13, 10

  
%define EOS 0

  
NWLN DB ENDL, EOS

  
%define version 'v0.0pre2'
;///////////////////////////////////////////////////////////////////////
  
introMessage DB 'FreeDOS Flat Real Mode Initializer ', version, ENDL
                DB
'GPL Copyright (C) 1999, Louis P. Santillan', ENDL
                DB ENDL
                DB EOS
;//////////////////////////////////////////////////////////////////////
  
checked DB 0xFB, ']...', EOS

   unChecked DB
' ]', ENDL, EOS

   dotString DB
'.', EOS
;//////////////////////////////////////////////////////////////////////
  
GDT DW 0xF, GDT, 0, 0, 0xFFFF, 0, 0x9200, 0x8F

  
flatdata EQU 8
;//////////////////////////////////////////////////////////////////////
  
initializingFRMString DB 'Entering Flat Real Mode [', EOS

   FRMInitializedString DB
'Flat Real Mode has been entered', ENDL, EOS

   FRMInitOK DB
'EMM Check Passed...', ENDL
             DB
'   Flat Real Mode can only be entered when an EMM is '
            
DB 'not installed', ENDL
             DB ENDL
, EOS
;//////////////////////////////////////////////////////////////////////
  
getEMMVersion EQU 0x46

  
EMMnotInstalled EQU -1

  
EMMint EQU 0x67

  
detectingEMMString DB 'EMM Installed [', EOS

   EMMVersionString DB
'EMM version/generation: ', EOS

   EMMVersionXString DB
'.x', ENDL, EOS

   EMMflag DB
0

  
; Device name read as 4 words
  
EMMDeviceNameCMPString DB 'EMMXXXX0'

  
yesEMMError DB '   Exiting with EMM running...', ENDL
               DB
'      Flat Real Mode cannot be entered when an EMM is running'
              
DB ENDL, EOS
;//////////////////////////////////////////////////////////////////////
  
detectXMMString DB 'XMM Installed [', EOS

   getXMMVersion EQU
0x4300

  
XMMint EQU 0x2F

  
XMMnotInstalled EQU 0

  
XMMnotInstalledString DB '   An XMM is not installed...you must use '
                        
DB 'your own allocation/de-allocation', ENDL
                         DB
'   methods', ENDL
                         DB ENDL
, EOS

   XMMVersionString DB
'XMM Version ', EOS

   XMMflag DB XMMnotInstalled

   useXMMString DB
'   You should use XMM for allocation & de-allocation'
               
DB ENDL
                DB ENDL
                DB EOS
;//////////////////////////////////////////////////////////////////////
  
enableA20String DB 'Enabling A20 Line of MMU [', EOS

   A20EnabledString DB
'A20 Line of MMU has been ENABLED', ENDL
                    DB ENDL
, EOS
;//////////////////////////////////////////////////////////////////////
  
check286Plus DB 'Checking for 286+ CPU [', EOS

   found286Plus DB
'A 286+ CPU has been found', ENDL
                DB ENDL
, EOS

   found286Flag EQU
2

  
foundSub286 DB 'A sub-286 CPU has been found', ENDL
               DB ENDL
, EOS

   check386Plus DB
'Checking for 386+ CPU [', EOS

   found386Plus DB
'A 386+ CPU has been found', ENDL
                DB ENDL
, EOS

   found386Flag EQU
3

  
CPUflag DB 0
;//////////////////////////////////////////////////////////////////////
getKey:
  
PUSH AX
   XOR AH
, AH
   INT
0x16
  
POP AX
   RET
;//////////////////////////////////////////////////////////////////////
main:
  
MOV SI, introMessage
  
CALL puts

  
CALL detectEMM

  
CMP BYTE [ EMMflag ], EMMnotInstalled
  
JE main00
   
     
MOV SI, FRMInitOK
     
CALL puts

     
CALL detectXMM

     
CMP BYTE [ XMMflag ], 0
     
JE main00z

        
CALL detectCPU

        
CMP BYTE [ CPUflag ], found386Flag
        
JE main00z

           
MOV AL, 0

           
JMP main01

      main00z
:
   
     
MOV SI, enableA20String
     
CALL puts

     
CALL enableA20

     
MOV SI, checked
     
CALL puts

     
MOV SI, A20EnabledString
     
CALL puts

     
MOV SI, initializingFRMString
     
CALL puts

     
CALL initFlatRealMode

     
MOV SI, checked
     
CALL puts

     
MOV SI, FRMInitializedString
     
CALL puts

     
MOV AL, 0

     
JMP main01

   main00
:
     
MOV SI, yesEMMError
     
CALL puts
   
     
MOV AL, -1

  
main01:

  
MOV AH, 0x4C
  
INT 0x21