%include "asm.inc"
%define STUB_STAT   _stub_stat

	BITS 32

	GLOBAL entry_point
        GLOBAL __exit

        GLOBAL __fpu_family
        GLOBAL __cpu_family
        GLOBAL __cpu_model
        GLOBAL __cpu_steppingID
        GLOBAL __cpu_feature
        GLOBAL __cpu_vendor
        GLOBAL __cr4


        EXTERN _start
        EXTERN STUB_STAT
        EXTERN end_datas
        EXTERN end_bsss

	SECTION .data

	temp dw 0

        __fpu_family   db 0
	__cpu_family db 3
        __cpu_model  db 0
        __cpu_steppingID db 0
        __cpu_feature dd 0
        __cpu_vendor_  db 'unknown',0,0,0,0,0,0
        __cpu_vendor  dd __cpu_vendor_
        __cr4	     dd 0

        saved_ss_esp dd 0
	             dw 0
        saved_gdt    dw 0
                     dd 0


        SECTION .text

;
; questo e` l'indirizzo che viene chiamato dal loader.
; la paginazione e` gia` attiva, occhio pero` che per risparmiare
; memoria ho messo il pde e i pte nella memoria video :)
;
; secondo il draft del 10/09/197 il kernel dovrebbe essere caricato
; a 512Mb, e la memoria kernel e` riservata fino a 1Gb.
; quindi ci sono 512Mb di spazio per il kernel, dovrebbero essere
; sufficiente per tutti ... [come disse l'amico Bill per i 640K del dos]
;
; la versione 0.6 dello stub comunque mappa solo i primi 4Mb a partire
; dall'indirizzo virtuale base del kernel, e poi mappa il primo Mb 1:1.
;
;
; i selettori sono :
;   30h punta allo stub (256 bytes)
;   38h dati (limite 4G)
;   40h codice (4G)
;   48h TSS _TEMPORANEO_ (non deve essere + richiamato!)
;
;   DS = ES = SS = dati [30h]
;   FS = stub selector GS = ?
;
;   TR=48h, ldt=0, idt=0
;
;   esp = stack dello stub, poco meno di 1K disponibile ... magari usero`
;         un po' di memoria video anche per questo :)
;
;   tutti i flags sono stati azzerati (DF,IF,..)
;
;-----
; la versione 0.61 dello stub mappa i primi 12Mb di memoria fisica, e 4 kernel
; inoltre l'indirizzo del kernel e` cambiato, ora e` 3Gb, la memoria da
; 1Gb fino a 3Gb e` disponibile. la memoria < 1Gb e` riservata per altri scopi

entry_point:
        ;
        ; salva lo stack
        ;
        mov	dword [saved_ss_esp],esp
        mov     word [saved_ss_esp+4],ss

        ;
        ; salva gdt
        ;
        sgdt    [saved_gdt]

        ;
        ; azzera bss
        ;
        mov	edi,end_datas
        mov	ecx,end_bsss
        xor	eax,eax
        sub	ecx,edi
        rep	stosb


        ;
        ; copia stub_stat
        ;
        xor	esi,esi
        cmp	word [fs:esi],'V0'		; confronta magic (versione)
        mov	al,0xff
        jne	__exit
        mov	cx,[fs:esi+2]	; legge dimensione da trasferire
        add	esi,4
        mov	edi,STUB_STAT

.copy
        mov	al,[fs:esi]
        inc	esi
        mov	[edi],al
        inc	edi
        loop	.copy,cx

        mov	fs,cx		; azzera fs e gs
        mov	gs,cx


        call	cpu_info
        call	fpu_info
        cmp	byte [__fpu_family],0
        setne	al
        or	byte [__cpu_feature],al
        call	set_cr


        mov	bx,0xF8F0
        mov	cl,3
        call	pic_setup

	call	_start


__exit:
	; eax = exit
        cli

        mov	ebp,eax

        mov	bx,0x7008
        mov	cl,1
        call	pic_setup




        mov	bx,KERNEL_DS
        mov	ds,bx
;        cmp	dword [__cr4],0
;        je	.nocr4
;        xor	ebx,ebx
;        mov	cr4,ebx
.nocr4

        lgdt	[saved_gdt]		; DS deve sempre essere 30h !!
        lss	esp, [saved_ss_esp]
        mov	eax,ebp
        retf

;
; in: copia il bit %1 di edx alla posizione %2 in ebx
;
;

%macro testbt 2
        xor	ecx,ecx
	bt	edx,%1
        rcl	ecx,%2+1
        or	ebx,ecx
%endm


set_cr:

        ;
        ; setup per cr4 (registro ebx)
        ;
        mov	edx,[__cpu_feature]
        xor	ebx,ebx
        testbt	1,0		; VM86 Mode Ex
        testbt  1,1             ; PVI
        testbt  2,3		; Debug Extension
        testbt  3,4             ; Page Size extension
        testbt  13,7		; Page Global

        test	ebx,ebx
        jz	.nocr4
        mov	cr4,ebx
        mov	[__cr4],ebx
.nocr4

	;
        ; setup per cr0
        ;
	mov	ebx,0x80000001
        testbt	0,1

        cmp	byte [__cpu_family],4
        jb	.end
        je	.486
	or	ebx,50020h	; AM WP NE

.486
	or	ebx,50000h      ; AM WP

.end
	mov	cr0,ebx
        ret



cpu_info:
        pushfd
        pop	eax
        mov	eax,ecx
        xor	eax,0x40000
        push	eax
        popfd
        pushfd
        pop	eax
        xor	eax,ecx
        and	eax,0x40000
        jz	.end
        mov	byte [__cpu_family],4	; 486
        mov	eax,ecx
        xor	eax,0x200000
        push	eax
        popfd
        pushfd
        pop	eax
        xor	eax,ecx
        jz	.end
        push	ecx           		; 486DX4/Pentium+
        popfd
        xor	eax,eax
        cpuid
        mov	[__cpu_vendor_],ebx
        mov	[__cpu_vendor_+4],edx
        mov	[__cpu_vendor_+8],ecx
        test	eax,eax
        jz	.end


        mov	eax,1
        cpuid
        mov	cl,al
        and	cl,0x0f
        mov	[__cpu_steppingID],al
        shr	al,4
        mov	[__cpu_model],al
        mov	cl,ah
        and	cl,0x0f
        mov	[__cpu_family],cl
        mov	[__cpu_feature],edx

.end
	ret

fpu_info:
	clts
        fninit
        mov     word [temp],0x5a5a
        fstsw   [temp]
        mov	ax,[temp]
        cmp	al,0
        jnz	.end
        mov	byte [__fpu_family],2
        mov	eax,cr0
        shr	eax,5
        jnc	.end
        inc	byte [__fpu_family]
.end
	ret

;
; BL = PIC #1 vect
; BH = PIC #2 vect
; CL = 1 -> standard, 3 -> auto EOI

%macro delay 0
	dw 00ebh
        dw 00ebh
%endm

pic_setup:
	mov	al,0x11		;init command
	out	0x20,al
        delay
        out     0xa0,al

        mov	ax,bx  		; set vector
        out	0x21,al
        xchg	al,ah
        delay
        out	0xa1,al

        mov	al,4
        out	0x21,al		; irq 2 = cascade
        mov	al,2
        delay
        out	0xa1,al		; irq 9 ->irq2

        mov	al,cl		; mode control, 1 = standard, 3 auto EOI
        out	0x21,al
        delay
        out	0xa1,al

        ;
        ; keyboard reset
        ;

        delay
        in	al,60h
        delay
        or	al,80h
        out	60h,al
        delay
        and	al,7fh
        out	60h,al
        ret