#include "clib.h"
#include "globals.h"
#include "i386.h"
#include "phmem.h"
#include "paging.h"
#include "systab.h"
#include "sched.h"
#include "excpt.h"
#include "irq.h"
#include "kmalloc.h"
#include "vm86.h"
#include "debugg.h"

#ifndef NDEBUG
bool debug_verbose = false;
bool debug_trace   = false;
bool debug_flag	   = false;
#endif


stub_stat_t stub_stat;



#define SHOW_CR4(b) DEBUG_VERBOSE(#b" %d ", _cr4.##b);
void start_kernel();



/*
 * questa e` la prima procedura chiamata da crt0.asm situazione :
 *
 * ds,ss,es = KERNEL_DS  fs,gs=0   cs=KERNEL_CS
 * esp = stack dello stub, poco meno di 1K
 *
 * la paginazione e` gia` attivata [e con lo stub 0.6 le tabelle sono
 * nella memoria video!]
 *
 * cr0 :  per 386 -> PG/PE
 *        per 486 -> PG/AM/WP/PE
 *        per 586 -> PG/AM/WP/NE/PE
 *
 *        se c'e` la FPU MP = 1, comunque EM e` sempre a 0
 *
 * cr4 :  per 386/486dx2 -> nada
 *        per 486dx4+ -> vengono abilitati VME/PVI/DE/PSE/PGE se disponibili
 *
 *
 *
 * gli interrupt sono disabilitati, il PIC e` stato riprogrammato,
 * l'IRQ0 e` l'int 0xf0, IRQ 8 = int 0xf8, uso l'auto EOI
 *
 * TR = task temporaneo
 * ldt = 0
 * GDT = gdt dello stub loader, per la V0.6 i descrittori sono 10
 * IDT = nulla
 */

int start(void)
{
	int i;

	#ifndef NDEBUG
	if (stub_stat.flags & 1) {
        	debug_verbose = 1;
                debug_trace = 1;
                memset((void*)0xB8000, 0, 50*80*2);  /* clrscr */
        }
        #endif
        DEBUG_VERBOSE("CPU %d vendor %s feature %xh FPU %d CR4 %xh\n",
        	_cpu_family, _cpu_vendor, _cpu_feature, _fpu_family, _cr4);
        SHOW_CR4(vme);
        SHOW_CR4(pvi);
        SHOW_CR4(tsd);
        SHOW_CR4(de);
        SHOW_CR4(pse);
        SHOW_CR4(pae);
        SHOW_CR4(mce);
        SHOW_CR4(pge);
        SHOW_CR4(pce);
	DEBUG_VERBOSE("\nkernel phisical addr %xh, virtual addr %xh\n",
        	stub_stat.kernel_base, (u32)&end_texts & 0xFFFF0000);
        i = (int)&end_bsss & 0x3FFFFF;
        DEBUG_VERBOSE("kernel pages %xh\n", i shr 12);

        /*
         * inizializza il gestore delle pagine di memoria
         *
         */

	ph_memory_setup(stub_stat.kernel_base + i,
		stub_stat.kernel_pages - (i shr 12));

        /*
         * alloca spazio per una nuova GDT e IDT, entrambe da 256 descrittori.
         * la GDT viene riempita coi valori della vecchia GDT
         */
	systab_setup();


        /*
         * inizializza per scheduler
         */
        sched_setup();


        /*
         * ok, ora ho sufficienti procedure per creare il vero task del kernel
         */

        /*
         * crea i task ausiliari per le eccezioni, e quello
         * del kernel.
         */
        base_tasks_setup();
        tss_kernel.esp = (u32)valloc(2) + 8192;
        tss_kernel.eip = &start_kernel;


        jmp_task(tss_kernel.tss_sel);

        DEBUG_FATAL("unexpected return");
	return 1;
}

v86_tss *v86;
tss_t *t;

extern void v86_startup;


void start_kernel()
{
	int i;
        tss_t *dbg;

        /*
         * ora posso inizializzare anche kmalloc
         */

        kmalloc_startup(16);	// 16 pagine = 64K

        /*
         * imposta i descrittori degli irq.
         * NB: Irq0 = int 0xf0, irq 8=int0xf8
         */
	irq_setup();
        asm_sti;


        dbg = alloc_tss(NULL, "KDebugger");
        dbg->cs = KERNEL_CS;
        dbg->ds = dbg->ss = dbg->es = KERNEL_DS;
        dbg->esp = (u32)valloc(4) + 4*4096;
        dbg->eip = debug_start;
        dbg->handler = debug_handler;
        dbg->eflags = 0;
        dbg->cr3 = tss_kernel.cr3;
        jmp_task(dbg->tss_sel);
        DEBUG_TRACE;
        exit(0);
#if 0

        v86 = alloc_v86_task("DOSV86");

        v86->tss.cs = stub_stat.dos_mem_ptr shr 16;
        v86->tss.eip = 0;


        v86->tss.ss = v86->tss.ds = v86->tss.es = v86->tss.cs;
        v86->tss.gs = stub_stat.prefixseg;
        v86->tss.esp = 0xfffc;
        v86->tss.ss0 = KERNEL_DS;
        v86->tss.esp0 = alloc_free_page() + 4096;

        map_memory(&v86->tss, v86->tss.esp0-4096, v86->tss.esp0-4096, 1, pfWritable);
//        v86->tss.eflags |= (1 shl 12)+(1 shl 13);
        memset(v86->iobitmap, 0, 128);
//        v86->iobitmap[4] |= 1;
        memset(v86->intbitmap, 0, 32);
        v86->intbitmap[2] |= (1 shl 5);
//        v86->tss.cr3 = tss_kernel.cr3;
	map_memory(&v86->tss, (addr_t)0xB8000, (addr_t)0xB8000, 8, pfWritable + pfUser);

//	memcpy((char*)&v86_startup+4, stub_stat.cmd_line, 40);
        write_to_task(&v86->tss, (addr_t)(v86->tss.cs*16L), &v86_startup, 500);
//        memset((addr_t)0xB8000, 0x20, 0x2000);
       kprintf("DOS MEM: %x, CS:IP %x:%x\n\n", stub_stat.dos_mem_ptr,
        v86->tss.cs,v86->tss.eip);

        DEBUG_TRACE
        jmp_task(v86->tss.tss_sel);
        DEBUG_TRACE


  	exit(0);
#endif
}