//startup.htm

#include {string.htm}
#include {80x86.htm}
#include {i86.htm}
#include {os.htm}
#include {bootmap.htm}

#define IDTENTRIES  0x0100
#define GDTENTRIES  0x0080

VD  osmemory(VD);
VD  osvmode(VD);
VD  osmain (VD);

    SYSDESC32  IDT[IDTENTRIES];

//20.10.2009 32-bit GDT now doubles as 64-bit GDT
    DESC32  GDT[128]=
           {
            {     0,0,0,   0,     0},
            {     0,0,0,   0,     0},
            {0xffff,0,0,   0xcf9a,0}, //0x10 32-bit code,base 0x00000 4Gb
            {     0,0,0,   0,     0},
            {0xffff,0,0,   0xcf92,0}, //0x20 32-bit data,base 0x00000 4Gb
            {     0,0,0,   0,     0},
            {0xffff,0,0x00,0x009b,0}, //0x30 16-bit code,base 0x00000 64k
            {     0,0,0,   0,     0},
            {0xffff,0,0x00,0x0093,0}, //0x40 16-bit data,base 0x00000 64k
            {     0,0,0,   0,     0},
            {0xffff,0,0x60,0x0089,0}, //0x50 386 TSS at 0x60000
            {     0,0,0,   0,     0}, //present and non-busy
    {0xffff,0x8000,0x10,0x8089,0x00}, //0x60 64-bit TSS at 0x00108000
            {     0,0,0,   0,     0}, //present and non-busy
            {0xffff,0,0,   0x209a,0}, //0x70 64-bit code,base 0x00000 256Tb
            {     0,0,0,   0,     0}
           };

    pdesc   GDTcopy={0x3ff, (UL)&GDT};
    pdesc   IDTcopy={0x7ff, (UL)&IDT};

//ChaOS starts here!
//
//Well actually, ChaOS now starts in the loader, which transfers control to this
//point via a jmp 0x0010:0xnnnnnnnn
//
//loader get the entry point by looking the header for c->boot
//then adding the base address (which is passed in in EBX)
//
//on entry we expect:
//      CS=0x10, mapped in GDT to 4Gb code selector, base 0
//      DS=0x20, mapped in GDT to 4Gb data selector, base 0
//      ES=0x20,    ditto
//      FS=0x20,    ditto
//      GS=0x20,    ditto
//      SS=0x20,    ditto

//     EAX=OSflags   1=SYSTEMSYMBOLS,2=DOSLOAD,4=BIOSBOOT
//     EBX=OSbase    load address of boot image OS.XEC header
//     EDX=OSsize    to calculate base of free memory
//     EDI=DOS psp of loader (if launched by KLDR, else 0)

//10 lines of assembly language which complete relocation patches
//ChaOS disk image to any memory address; obviously no relocations
//must refer to this bit of code, so no data symbols are used!!
//(the code symbols are relative jumps, and so generate no relocs)
#asm
OSSTART::
        cli
//self-relocating code thunk
        mov     ebp,eax             //save OSflags in ebp for now
        mov     esi,dp [ebx+0x80]   //get file offset of fastreloc table
        add     esi,ebx             //adjust for loader offset
        mov     ecx,dp [ebx+0x84]   //get fastreloc count
        cmp     ecx,0               //test for no relocs, just in case you can
        jz      RELOCSDONE          //write an OS with none at all!
NEXTRELOC:
        lodsd
        add     dp [eax+ebx],ebx
        loop    NEXTRELOC
RELOCSDONE:
//it's that easy eat your heart out Bill Gates

        or      dp [ebx+0xb8],0x100 //c->patched|=FASTRELOCSPATCHED;

                                    //relocs are done, now we can access data
        mov     OSflags,ebp         //recover OSflags from eax on entry
        mov     OSbase, ebx
        mov     OSsize, edx
        mov     DOSpsp, edi

        lgdt    fword GDTcopy       //remap now to our GDT
        lidt    fword IDTcopy       //             and IDT

RESTART::
        cli
//set up processor flags
        mov     eax,cr0
        and     eax,not FLGPG       //knock paged mode off
        or      eax,FLGNE           //co-processor NE bit on
        mov     cr0,eax
//set up EFLAGS
        push    0                   //IOPL=0, NT=0, VM=0
        popfd

//eventually, check RUNTIME flags here
        mov     eax,dp [ebx]CBJHEADER.rtflags

        cmp     stacktop,0
        jz      @F
        mov     esp,stacktop        //clean stack on hot reboot
@@:
        sub     ebp,ebp
        test    eax,rtSTACKALREADY
        jnz      @F

//        mov     esp,ebx             //if no passed-in stack,
//        mov     stacktop,ebx        //stack is just below OS header

        mov     eax,0x7f000         //if no passed-in stack,
        mov     esp,eax             //stack is in low memory
        mov     stacktop,eax        //just below 0x80000
        sub     eax,0x10000
        mov     stackbase,eax       //just below 0x70000
        jmp     GOMAIN
@@:
        mov     stacktop,esp
        mov     ecx,esp
        sub     ecx,STACKSIZE
        mov     stackbase,ecx
//        call    stackfill
GOMAIN:
        call    osmemory
        call    osvmode
        call    osmain

        jmp     RESTART         //HOT reboot, try doing that in DOS!!
OSHALT:
        jmp     OSHALT          //whoa! Neddy

DUMMYIRET::
        iret
#endasm

UL  getGDT(VD)
{
    return (UL)&GDT;
}
UL  getIDT(VD)
{
    return (UL)&IDT;
}
VD  restoreIDT(VD)
{
asm
    {
     lidt    fword IDTcopy
    }
}
VD  restoreGDT(VD)
{
asm
    {
     lgdt    fword GDTcopy
    }
}
VD  makeTrapGate(SYSDESC32* d,UL sel,UL off)
{
//    d->attribute=0x8f00;        //Programming the 80386 Crawford/Gelsinger P460
    d->attribute=0x8e00;        //Programming the 80386 Crawford/Gelsinger P460
    d->offsetloword=off;
    d->offsethiword=off>>16;
    d->selector=sel;
}
VD  clearvector(UL intno)
{
    SYSDESC32* i=IDT+intno;
    makeTrapGate(i,CS32,(UL)&DUMMYIRET);
}
VD  setvector(UL intno,UL off)
{
    SYSDESC32* i=IDT+intno;
    makeTrapGate(i,CS32,off);
}
UL  getvector(UL intno)
{
    SYSDESC32* i=IDT+intno;
    UL n=i->offsethiword;
    n<<=16;
    n+=i->offsetloword;
    return n;
}

    UL  pic1IRQctr;
    UL  pic2IRQctr;

VD  interrupt   pic1IRQ(VD)
{
    pic1IRQctr++;
    eoiIRQ(0);
}
VD  interrupt   pic2IRQ(VD)
{
    *(UC*)(0xb8000+50*160-4)='!';
    pic2IRQctr++;
//    eoiIRQ(8);
    *(UL*)0xfec00040=0x22;   //eoi to IO APIC
    *(UL*)0xfee000b0=0x22;   //eoi to Local APIC (CPU)
    *(UC*)(0xb8000+50*160-4)='0';
}
    UL  rmintctr;
VD  setupDPMIREGS(DPMIREGS* d,UL irq)
{
    memset(d,0,sizeof(DPMIREGS));
    d->ds=d->es=d->fs=d->gs=0x40;
    clidisplay("RM interrupt handler IRQ%02l",&irq);
    rmintctr++;
}
VD  realmodeinterrupt(UL intno,DPMIREGS* d);
VD  initIDT(VD)
{
    SYSDESC32* i=IDT;
    UL n;
    for(n=0;n<=IDTENTRIES-1;n++)
        {
         makeTrapGate(i,CS32,(UL)DUMMYIRET);
         i++;
        }
//set up eoiIRQ handlers for BIOS PIC mapping to field
//unexpected interrupts during PIC remap phase
    for(n=0x8;n<0x10;n++)
        {
         makeTrapGate(IDT+n,CS32,(UL)&pic1IRQ);
         i++;
        }
    for(n=0x70;n<0x78;n++)
        {
         makeTrapGate(IDT+n,CS32,(UL)&pic2IRQ);
         i++;
        }

//set up eoiIRQ handlers for ChaOS PIC mapping to field
//unexpected interrupts after PICs have been remapped
    for(n=0x20;n<0x28;n++)
        {
         makeTrapGate(IDT+n,CS32,(UL)&pic1IRQ);
         i++;
        }
    for(n=0x28;n<0x30;n++)
        {
         makeTrapGate(IDT+n,CS32,(UL)&pic2IRQ);
         i++;
        }
}
#include {heap.htm}

EX  HEAPITEM* heap;
VD  osmemory(VD)
{
//first call by startup code, to set memtop
    CBJHEADER* c=(CBJHEADER*)OSbase;
    memtop=c->heap;
    heap=NULL;
}