; BA-Headr.asm
; Header & Initialization code for the MOOSE BIOS-based API
; see ~/info/BIOS-API.nfo

Ideal
Include "API.ash"
Include "M_Magic.h"
Include "BIOS-API.inc"
DEBUG=1
__DEBUG__=1

;;;;;;;;;;;;;;;;;;;;;;;;;;;; EXTRN statements ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Extrn	RM_IRQ: NEAR
Extrn	GoProtect: NEAR
Extrn	GoReal: NEAR, GoRealSEG: ABS
Extrn	RMPartLen:  NEAR	; size in bytes to reserve for RM Part
Extrn	RMPartELen: NEAR	; size in bytes to move for RM Part
Extrn	PMPartLen:  NEAR	; size in bytes to reserve for PM Part
Extrn	PMPartELen: NEAR	; size in bytes to move for PM Part
Extrn	__RMPART__: NEAR	; relative offset in para of RMPART in file
Extrn	__PMPART__: NEAR	; relative offset in para of PMPART in file
Extrn	__KERNEL__: NEAR	; relative offset in para of KERNEL in file
Extrn	Putc: NEAR, Getc: NEAR
Extrn	cPutc: NEAR, cGetc: NEAR
Extrn	Puts: NEAR
IF DEBUG
Extrn	DumpRegs: NEAR
Extrn	Beep: NEAR
Extrn	PutHexWord: NEAR
Extrn	PrCRLF: NEAR
ENDIF

;;;;;;;;;;;;;;;;;;;;;;;;;;; Global Declarations ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_Data_is	InitData
_UData_is	InitUData
_Code_is	RM_InitCode

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
__INIT__ = __RIC__		; Real-Mode Code segment must come first...
Init_PM_Target_seg = PMPARTCS
Init_PM_Target_ofs = PM_Entry_Point
Init_RM_Target_seg = API_Seg
Init_RM_Target_ofs = RM_Return_Point

;;;;;;;;;;;;;;;;;;;;;;;;;; Initialization Data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Segment InitData
__ID__:			; (!) must be first thing in InitData

align 4
Init_GDT:
	DefDescriptor	0,0,0,0,0		; Invalid NULL descriptor
	DefDescriptor	0,0FFFFFh,9Ah,5		; TEMPSEG: PM_InitCode
	DefDescriptor	0,0FFFFFh,9Ah,0Dh	; ALLMEMCS
	DefDescriptor	0,0FFFFFh,92h,0Dh	; ALLMEMDS
	DefDescriptor	0,0FFFFFh,9Ah,01h	; RMPARTCS
	DefDescriptor	0,0FFFFFh,92h,01h	; RMPARTDS
	DefDescriptor	0,0FFFFFh,9Ah,0Dh	; PMPARTCS
	DefDescriptor	0,0FFFFFh,92h,0Dh	; PMPARTDS
;Init_GDT_Len = $-Init_GDT
Init_GDT_Len = 65535
EndS	InitData
;;;;;;;;;;;;;;;;;;;;;;;;;;;; Uninitialized Data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Segment	InitUData
if1
__IU__:			; (!) must be first thing in InitUData
  LOADER_seg	dw	?
  RMPart_seg	dw	?	; where the RM Part is to be put.
endif
EndS	InitUData
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; I/O routines ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Segment RM_InitCode
__RIC__:		; (!) must be first thing in RM_InitCode
EndS	RM_InitCode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;; API Entry/Exit Points ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Segment	RM_InitCode
Proc	API_Entry_Point	near
; Called by the boot loader.
; must be far away from the top of conventional memory.
; * Entry:
;  AX is the segment of the LOADER and its parameters
;  CS,DS,ES point to the API group of segments
;  SS still points to the LOADER. Beware, before loading !
; * Never exits, but launches MOOSE.
	__ <"Initializing the BIOS-based API.",CRLF>
; Get parameters from the LOADER
	;.....
; Print Init Message
	PUTS <"Welcome to MOOSE.",CRLF>
; Set the keyboard repeat rate to the max
	mov ax,0305h
	clr bx
	int 16h
; Prepare landing
  ;....
; Jump into the Protected Mode
   STEP 4
   __ <"Let's jump into protected mode !",CRLF>
   jmp	GoProtect	; original (unmoved) version
EndP	API_Entry_Point
EndS	RM_InitCode
Segment	PM_InitCode
__PIC__:		; (!) must be first thing in PM_InitCode
;;;;; And Now, the dreaded entry point ! ;;;;;
Proc	PM_Entry_Point
	mov eax,RMPARTDS ; ALLMEMDS
	mov fs,ax
	mov ebx,0B8000h+2*(38+5*80)
	mov [dword fs:ebx+0],0F4F0F4Dh
	call sleep_1s
	mov [dword fs:ebx+4],0F530F4Fh
	call sleep_1s
	mov [dword fs:ebx+8],0F200F45h
	movzx esp,sp
	STOP fs:,0,0,'P',78h
	mov ecx,16
	call sleep
	db 0eah
	dd ofs GoReal
	dw GoRealSEG
EndP	PM_Entry_Point
EndS	PM_InitCode
Segment	RM_InitCode
Proc	RM_Return_Point
; Restore segment registers
	clr ax
	mov ds,ax
   @_@ <"Back in real mode:",CRLF>
	@wo@ <"cs=">,cs,<CRLF>
; Show that we got there
	mov bx,0B800h
	mov es,bx
	STOP es:,13,3,'R',04h	; 'R' for RealMode
; Try accessing ALLMEMDS through fs.
	mov ebx,0B8000h
	STOP fs:ebx+,13,10,'A',0Ch	; 'A' for Allmem
; Reenable Interruptions
	STOP es:,13,4,'e',04h	; 'R' for RealMode
	Enable_NMI
	sti
; That's all, folks
	GETC <CRLF,"Hit any key to reboot.">
	jmp far 0FFFFh:0
EndP	RM_Return_Point
IF 0
Proc	Test_Mode
; This routine has been used instead of RM_Return_Point,
; to prove that returning in real mode from a 32 bit protected mode segment
; made the CPU land in such thing as a 32 bit real mode !!!
; To have it work, copy the GoReal procedure in a 32 bit segment,
; and have it jump into this routine.
; (beware: jump address should be word ofs,word 0,word seg)
; print 'M' indifferently in 32 bit and 16 bit modes
; In both modes, it will print a M white on black on the first character of
; the second line.
; In 32 bit mode, it will also print next to it a blinking {acute E}
; (which corresponds to the nop's 9090h value which is pushed then poped !!!)
	push 0B800h
	nop
	nop
	pop ds
	push 074Dh
	nop
	nop
	xor bx,bx
	push 160
	nop
	nop
	pop dx
	mov bl,dl
	mov di,bx
	pop [word bx]
	hlt		; halt, or the computer may reboot before you see the result.
EndP	Test_Mode
ENDIF
EndS	RM_InitCode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Subroutines ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Segment PM_InitCode
Proc sleep_1s
	push ecx
	mov ecx,10000h	; 1 M
 s1s:
	loop s1s
	pop ecx
	ret
EndP sleep_1s
Proc sleep
 sns:
	call sleep_1s
	loop sns
	ret
EndP sleep
EndS	PM_InitCode
;;;;;;;;;;;;;;;;;;;;;;;;;; Initialization routines ;;;;;;;;;;;;;;;;;;;;;;;;;;;
Segment	PM_InitCode
Proc	Setup_GDT near		; see the GDT in BA-PM.asm
EndP	Setup_GDT
Proc	Setup_LDT near
EndP	Setup_LDT
Proc	Setup_RM_IDT near
	mov cx,16
	push ds
	push 0
	pop ds
	ldea ax,RM_IRQ
	mov bx,IRQ_INT_BASE
	shl bx,2
  SRMI_0:
	mov [bx],ax
	mov [bx+2],cs
	add bx,4
	add ax,3
	loop SRMI_0
	pop ds
	ret
EndP	Setup_RM_IDT
Proc	Setup_PM_IDT near
EndP	Setup_PM_IDT
Proc	Setup_Paging near
EndP	Setup_Paging


EndS	PM_InitCode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;; Public declarations ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Public API_Entry_Point
Public Init_GDT, Init_GDT_Len
Public Init_RM_Target_seg,Init_RM_Target_ofs
Public Init_PM_Target_seg,Init_PM_Target_ofs
Public __ID__,__RIC__,__PIC__,__IU__,__INIT__
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
End
