;*****************************************************
; $Id: loader.s,v 1.1 2002/11/25 02:07:53 rminnich Exp $
;*****************************************************
USE32
; code it is loaded into memory at 0x7C00
;*****************************************************
nop
nop
;*****************************************************
; A) setup GDT, so that we do not depend on program 
; that loaded us for GDT. 
; Ex: LinuxBIOS and EtherBOOT use different GDT's.

;-----------------------------------------------------
; 0)

cli

;-----------------------------------------------------
; I)

lgdt [0x7C00+protected_gdt]

;-----------------------------------------------------
; II) setup CS

jmp 0x08:0x7C00+newpgdt

newpgdt: nop

;-----------------------------------------------------
; III) setup all other segments

mov ax,  #0x10
mov ss,  ax
mov ds,  ax
mov es,  ax
mov fs,  ax
mov gs,  ax

;-----------------------------------------------------
; IV) 

; not now
;sti

;*****************************************************
nop
nop

; Outputs a value to PCI config space
; put the bus,dev,function,offset in eax
; and the byte value in dl then call this macro

MACRO PCI_CONFIG_WRITE_BYTE
   shl edx, #8
   mov dl,  al
   and dl,  #3
   shl edx, #16
   or  eax, #0x80000000
   and eax, #0xfffffffc
   mov dx,  #0x0cf8
   out dx,  eax
   shr edx, #16
   mov al,  dh
   mov dh,  #0
   add edx, #0x0cfc
   out dx,  al
MEND

;*****************************************************
; B) shadow - ON (enable/read/write)

; This is orginal shadowing setup code
; Works on the Matsonic 7308e mainboard
;mov eax, #0x80000070
;mov dx,  #0x0cf8
;out dx,  eax

;mov eax, #0xFFFFFFFF
;mov dx,  #0x0cfc
;out dx,  eax

; This enables shadowing for the 0x0f0000 -
; 0x0fffff range and the 0x0C0000 - 0x0cffff range
; for the 440bx chipset.  

mov eax, #0x59
mov edx, #0x20
PCI_CONFIG_WRITE_BYTE
mov eax, #0x5A
mov edx, #0x22
PCI_CONFIG_WRITE_BYTE
mov eax, #0x5b
mov edx, #0x22
PCI_CONFIG_WRITE_BYTE

;*****************************************************
nop
nop
;*****************************************************
; C) copy -- boch bios

; counter - 64kb.     
mov ecx, #0x10000

; source - 0x8000  ( 0x7C00+0x400 = 0x8000 ) 
mov ax,  #0x10        ; src-segment - 2nd entry in GDT
mov ds,  ax
mov eax, #0x8000      ; src-offset  - 0x8000
mov esi, eax

; destination - 0xF0000
mov ax,  #0x10        ; dst-segment - 2nd entry in GDT
mov es,  ax     
mov eax, #0xF0000     ; dst-offset  - 0xF0000
mov edi, eax

; clear direction flag
cld

; the copy
rep
  movsb

;*****************************************************
nop
nop
;*****************************************************
; D) copy -- video bios

; on my system video bios is just 48KB (0x0C000)
; but just for paranoida we copy  64kb (0X10000)

; counter - 64kb
mov ecx, #0x10000

; source - 0x18000  ( 0x8000+0x10000 = 0x18000 ) 
mov ax,  #0x10         ; src-segment - 2nd entry in GDT
mov ds,  ax
mov eax, #0x18000      ; src-offset  - 0x18000
mov esi, eax

; destination - 0xC0000
mov ax,  #0x10         ; dst-segment - 2nd entry in GDT
mov es,  ax
mov eax, #0xC0000      ; dst-offset  - 0xC0000
mov edi, eax

; clear direction flag
cld

; the copy
rep
  movsb



;*****************************************************
nop
nop
;*****************************************************
; E) copy -- pirq table

; on my system video bios is just 48KB (0x0C000)
; but just for paranoida we copy  64kb (0X10000)

; counter - 256kb -- 0x100
mov ecx, #0x100

; source - 0x7F00  ( 0x7C00+0x300 = 0x7F00 ) 
mov ax,  #0x10        ; src-segment - 2nd entry in GDT
mov ds,  ax
mov eax, #0x7F00      ; src-offset  - 0x7F00
mov esi, eax

; destination - 0xFFD00
mov ax,  #0x10         ; dst-segment - 2nd entry in GDT
mov es,  ax
mov eax, #0xFFD00      ; dst-offset  - 0xFD00
mov edi, eax

; clear direction flag
cld

; the copy
rep
  movsb

;*****************************************************
nop
nop
;*****************************************************
; X) copy -- LinuxBIOS table into safe place.

	;; TODO.
	;; Q1 :	 what is the size of table.
	;; Q2 :	 where to copy?
		
;*****************************************************
nop
nop	
;*****************************************************
; E) shadow - OFF (write)

mov eax, #0x59
mov edx, #0x30
PCI_CONFIG_WRITE_BYTE
mov eax, #0x5A
mov edx, #0x33
PCI_CONFIG_WRITE_BYTE
mov eax, #0x5b
mov edx, #0x33
PCI_CONFIG_WRITE_BYTE

;mov eax, #0x80000070
;mov dx,  #0x0cf8
;out dx,  eax

;mov eax, #0xFFFFFFFF
;mov eax, #0x0000FFFF
;mov dx,  #0x0cfc
;out dx,  eax

;*****************************************************
nop
nop
;*****************************************************
; F) do a little prep work.

;-----------------------------------------------------
; I) disable cache

; if you disable cache, GRUB's GFX mode will be VERY slow.
; so DO NOT DISABLE

;mov eax, cr0
;or  eax, #0x60000000
;wbinvd
;mov cr0, eax
;wbinvd

;-----------------------------------------------------
; II) disable MTRR
; clear the "E" (0x800) and "FE" (0x400) flags in 
; IA32_MTRRdefType register (0x2FF)

;-----------------------

;mov ECX,#0x2FF

; select either of the two below 
; depending on if your compiler suports 
; {RD,WR}MSR or not
;rdmsr
; .byte 0x0F, 0x32

;xor edx, edx
; xor eax, eax
;and eax, #0xFFFFF3FF

; select either of the two below 
; depending on if your compiler suports 
; {RD,WR}MSR or not
;wrmsr
; .byte 0x0F, 0x30

;-----------------------
;; This is what PC BIOS is setting. -- P6STMT.
; add VIDEO BIOS cacheable!!!!
;-----------------------
; Fixed Range C0--C8
;mov ECX,#0x268
;mov EDX,#0x05050505 
;mov EAX,#0x05050505 
;wrmsr
;-----------------------
; Fixed Range C8--CF
;mov ECX,#0x269
;mov EDX,#0x0 
;mov EAX,#0x05050505 
;wrmsr
;-----------------------

;-----------------------------------------------------
; III) tell BOCHS' BIOS we want to boot from hdd.
; 0x00 - floppy
; 0x02 - hdd
; In future there will be 'fd failover'option in bochs.

mov  al, #0x3d ;; cmos_reg
out  0x70, al
mov  al, #0x02 ;; val (hdd)
out  0x71, al

;-----------------------------------------------------
; IV) tell BOCHS' BIOS length of our mem block @ 1mb.
;     This is for Int 15 / EAX=E820
;     119mb = 0x77 00 00 00 
;     (this is for 128mb of ram)
;     (FIXME: this value is currently hard coded)
;     (it should be being passed from LinuxBIOS )

; for WinFast  6300
; 07 70 = 0770
; 06 80 = 0770 - 00F0		<< ALT (for unpatched bochs)

; for P6STMT - 10kb less ram
; 077F - 10     = 07 6F 
; 07 6F - 00 F0 = 06 7F

mov  al, #0x35 ;; cmos_reg
out  0x70, al
mov  al, #0x06 ;; val 
out  0x71, al

mov  al, #0x34 ;; cmos_reg
out  0x70, al
mov  al, #0x7F ;; val 
out  0x71, al

mov  al, #0x31 ;; cmos_reg
out  0x70, al
mov  al, #0x00 ;; val 
out  0x71, al

mov  al, #0x30 ;; cmos_reg
out  0x70, al
mov  al, #0x00 ;; val 
out  0x71, al

;-----------------------------------------------------
; V) tell BOCHS' BIOS we want to have LBA translation.
; 0x00 - NONE
; 0x01 - LBA    <<<<
; 0x02 - LARGE
; 0x03 - R-CHS
; In future there will be 'fd failover'option in bochs.

mov  al, #0x39 ;; cmos_reg
out  0x70, al
mov  al, #0x01 ;; val (LBA)
out  0x71, al

;*****************************************************
nop
nop
;*****************************************************
; G) the switch -- protected to real mode

; IASDM, Vol 3
; (8-14) 8.8.2 Switching Back to Real-Address Mode

;=====================================================
; 1) disable interrupts

cli

;=====================================================
nop
;=====================================================
; 2) paging

;not enabled, so not applicable.

;=====================================================
; 3) setup CS segment limit (64kb)
; I)

lgdt [0x7C00+new_gdt]

;-----------------------------------------------------
; II)

jmp 0x08:0x7C00+new64lim

new64lim: nop

;=====================================================
nop
;=====================================================
; 4) setup all other segments

mov ax,  #0x10
mov ss,  ax
mov ds,  ax
mov es,  ax
mov fs,  ax
mov gs,  ax

;=====================================================
nop
;=====================================================
; 5) LIDT
; I)

; set up Real Mode IDT table (0...3FF)

; for BOCH's BIOS the address 0xF000:0xFF53 
; cantains value 0xCF which is IRET opcode.

; counter 
mov cx,  #0xFF ;1024 bytes(255 interrupts)(4*255=0x3FF)

; destination - 0x00000 = ES:EDI
mov ax,  #0x10        ; dst-segment - 2nd entry in GDT
mov es,  ax
mov eax, #0x00000     ; dst-offset  - 0x00000
mov edi, eax

; data to store -- 0xF000:FF53
mov eax, #0xF000FF53

; clear direction flag
cld

; the store 
rep
  stosd

;-----------------------------------------------------
; II)
; load interrupt descriptor table

lidt [0x7C00+new_idt]

;=====================================================
nop
nop
;=====================================================
; 6) clear the PE flag in CR0 register.
; I)

; switch to 16 bit segments
mov ax,  #0x20
mov ss,  ax
mov ds,  ax
mov es,  ax
mov fs,  ax
mov gs,  ax

;-----------------------------------------------------
; II)

; switch to 16 bit CS

jmp 0x018:0x7C00+new16bit

USE16

new16bit: nop

;-----------------------------------------------------
; III)
; the switch

;xor eax, eax

mov eax, cr0            
and eax, #0xFFFFFFFE
mov cr0, eax            ;switch to RM

;=====================================================
nop
nop
;=====================================================
; 7) far jump -- (to real mode address)

jmp 0x0:0x7C00+realcs

realcs: nop

;=====================================================
; 8) set all segment registers to 0's

mov ax,  #0x0
mov ss,  ax
mov ds,  ax
mov es,  ax
mov fs,  ax
mov gs,  ax

;=====================================================
; 9) re-enable interrupts

sti

;*****************************************************
nop
nop
;*****************************************************
; G) jump to BIOS.

jmp 0xFFFF:0x0000
;jmp 0xF000:0xFFF0

;*****************************************************
;*****************************************************
nop
nop
nop
nop
;*****************************************************
;*****************************************************

USE32

new_idt:
dw 0x03ff ;; limit 15:00
dw 0x0000 ;; base  15:00
dw 0x0000 ;; base  23:16

new_gdt:
dw 0x0028                     ;; limit 15:00
dw 0x7C00+new_gdt_table       ;; base  15:00
dw 0x0000                     ;; base  23:16

protected_gdt:
dw 0x0018                     ;; limit 15:00
dw 0x7C00+pmode_gdt_table     ;; base  15:00
dw 0x0000                     ;; base  23:16

;-----------------------------------------------------

new_gdt_table:
;//  1 2 3 4 
;//0
dd 0x00000000
dd 0x00000000

;//8
dd 0x0000ffff
dd 0x00409E00

;//10
dd 0x0000ffff
dd 0x00409200

;//18
dd 0x0000ffff
dd 0x00009a00

;//20
dd 0x0000ffff
dd 0x00009200

;-------------------------

pmode_gdt_table:
;//  1 2 3 4 
;//0
dd 0x00000000
dd 0x00000000

;//8
dd 0x0000ffff
dd 0x00CF9E00

;//10
dd 0x0000ffff
dd 0x00CF9200

;*****************************************************
;*****************************************************
; the file size must be 1024 bytes.

; -0x100 b/c we put $PIR table here.

.org 0x400-1-0x100
; dd 0xdeadbeef			
db 0x0

;*****************************************************
