//main.ctp Copyright (C) 1989-2008 I.Pedley (CTPP) Tue 17-May-2005 at 20:09:17

//28.12.2009 ChaOS type system revision

#include {os.htm}
#include {i86.htm}
#include {time.htm}
#include {conio.htm}
#include {80x86.htm}
#include {box.htm}
#include {stdlib.htm}
#include {string.htm}
#include {chaoskey.htm}
#include {accdis.htm}

#include {pci.htm}
#include {dev.htm}

SL  catdisp(UL row,UL col,CH* format,...);

SL  stacksize(VD);
VD  stackfill(VD);
SL  stackused(VD);

VD  emergency(VD);

    UL      pagebase;
    UL      OSflags;
    UL      OSbase;
    UL      OSsize;
    UL      memtop;
    UL      stacktop;
    UL      stackbase;
    UL      DOSpsp;

VD  clrallbps(VD);

//extern in mem.ctp
EX  UL  validatefree;
//extern in cmos.ctp
UL  getCMOShimem(VD);
#include {heap.htm}

//extern in sym.ctp
VD  initSYM(VD);
VD  symutils(UL key);

//extern in pic.ctp
VD  maskIRQ(UL irq);
VD  unmaskIRQ(UL irq);
VD  _enable(VD);
VD  _disable(VD);

//externs in gen.ctp
EX  CH* banner;
EX  UL  vispage;
VD  outmsg(CH* msg);
VD  outmem (UC* mem,UL buflen,UL row,UL col);
VD  outmemd(UL* mem,UL buflen,UL row,UL col);
VD  outstr (CH* str,UL row,UL col);
VD  outchar(CH  c,  UL row,UL col);
VD  outhexdword(UL dword,UL row,UL col);
VD  setvisiblepage(SL page);
SL  getvisiblepage(VD);
EX  UC* videobase;
VD  clrscreen(VD);

//extern in string.ctp
VD  memcpy(VD* dst,VD* src,UL bytes);

//externs in keybd.ctp
VD  kbdcmd(UL cmdbyte);
SL  getkey(VD);
EX  CH* kbddisp;
EX  CH* hdcdisp;
EX  CH* netdisp;
EX  CH* vbuf;

//for LDRIVE structure
#include {drive.htm}

//externs in ipx.ctp
VD  termNET(VD);
VD  netutils(UL key);

UL  getCMOStime(VD);
UL  getCMOSdate(VD);

//in gen.ctp
VD  set8x8charset(VD);
VD  displaycharset(UL row,UL col);
VD  displaybanners(VD);

//in SCSI.ctp
VD  initSCSI(VD);

VD  initIRQ(VD);    //in irq.ctp

VD  shutdown(UC shutdownbyte);

VD  setvbuf(CH* buf);

VD  mhidecursor(VD);
VD  mshowcursor(VD);

EX  UL  inrmdebugger;

VD  storevscreen(VD)
{
    if(inrmdebugger){return;}
//    mhidecursor();
    if(vbuf)
    memcpy(vbuf,videobase+24000,80*50*2);
//    mshowcursor();
}
VD  getvscreen(VD)
{
    if(inrmdebugger){return;}
//    mhidecursor();
    if(vbuf)
         memcpy(videobase+24000,vbuf,80*50*2);
//    mshowcursor();
}

EX  UL  inmalloc;
EX  UL  inaccdis;
EX  UL  indebugger;
EX  UL  inemergency;
EX  UL  inpoll;
EX  UL  ldrives;
EX  UL  devpaths;
EX  SL  goingdownflag;
VD  initDEV(VD);
SL  termDEV(VD);

VD  oscleanup(VD)
{//perform any necessary re-initialisation of globals before hot reboot
    setthread((CBJHEADER*)OSbase);
    vbuf=NULL;
    goingdownflag=0;
    ldrives=0;
    inaccdis=0;
    indebugger=0;
    inemergency=0;
    inpoll=0;
    inmalloc=0;
    clicur=8;
    devpaths=0;
    initIRQ();
}

//in ipx.ctp
EX  UL  network;

SL  initPAG(VD);
UL* getpagetableentry(UL lin);

VD  cli(VD);
SL  invoke(CH* commandline,UL len);
VD  initENV(VD);
VD  setdevpaths(LDRIVE* l);
SL  v_invoke(CH* format,...);

SL  clidisplay(CH* format,...);
UL  initPCI(UL init,UL disp);
VD  initDIG(VD);
VD  flushfilesystems(UL all);

VD  relocateOS(UL newbase);

//in brd.ctp
VD  initBRD(VD);

//    UC* savedataarea;

//VD  savedata(VD)
//{
//    CBJHEADER* c=(CBJHEADER*)OSbase;
//    savedataarea=malloc(c->dlen);
//    UC* ptr=(UC*)OSbase+c->hdrlen+c->dbase;
//    memcpy(savedataarea,ptr,c->dlen);
//}

VD  initVGA(VD);
VD  pagingon(VD);
VD  versionstring(CH* str,UL vno,UL zeroterminate);

SL  memstats(UL argc,CH* argv[]);
SL  downloadfile(CH* fname,UL fsiz,VD* buf);

UL  storemachineinfo(VD);
SL  getprocessor(VD);
VD  maketlookup(CBJHEADER* c);
VD  initSYS(VD);
VD  initVT0(VD);
VD  initSCR(VD);
VD  initMSG(VD);

#include {bootmap.htm}
MODESWITCHES* getmodeswitches(VD);
VD  setrmPICmasks(VD);
SL  findfile  (CH* fname);

VD  initPRC(VD);            //process.ctp

VD  initDEV(VD);            //dev.ctp
VD  initLEGACY(VD);         //dev.ctp
SL  vesatest(VD);

SL  initPnP(UL disp);       //pnp.ctp


VD  rmtest(VD);

SL  initKBD(DEV* d);
VD  emptyKBD(VD);

VD  loadSRVs(UL max,UL min);
VD  rmint(UL intno,DPMIREGS* d);
UL  setkbdLEDs(UL locks);
SL  initAPIC(VD);
#include {gl.htm}
#include {vesa.htm}
EX  VESA* vesa;
VD  set8x8font(MEMBUF* mb);
SL  setfont(MEMBUF* mb,CH* rootname);
VD  bindpointerstovesa(VD);
VD  initvesaenvironment(VD);
SL  initWND1(VD);

VD  osmemory(VD);
SL  countmsds(VD);
SL  createbdds(UL flg);

VD  osvmode(VD)
{
    BSINFO* bsi=(BSINFO*)bmLOAD;    //pointer bootstrap info
    if(!bsi->vflags)
        {
         DPMIREGS d;memset(&d,0,sizeof(DPMIREGS));
         d.eax=3;
         realmodeinterrupt(0x10,&d);    //set CGA mode 3
         bsi->vmode=3;
        }
    else
        {
         vesa=(VESA*)bsi->bsendptr;
         UC* ptr=(UC*)vesa;
         vesa->vbc=(VBCINFO*) vesa->info;
         vesa->vbm=(VBMINFO*)(vesa->info+0x200);
         vesa->pal=           vesa->info+0x300;
         vesa->framelen=vesa->mb.buflen=vesa->vbm->pitch*vesa->vbm->h;
         UL  align=0x10000;
         UL  msize=vesa->framelen*VESAFRAMES;
         msize+=align-1;msize/=align;msize*=align;
         memtop-=msize;
         vesa->mb.buf=(UC*)memtop;
         vesa->mb.pages=VESAFRAMES;
         initvesaenvironment();
         bsi->vflags=3;         //vesa mode is set+membuf can be used
        }
}
VD  osmain(VD)
{
    BSINFO* bsi=(BSINFO*)bmLOAD;    //pointer bootstrap info

    oscleanup();
    initPRC();

    dcat(2,0,"ChaOS Full Debug version, initialising debug info....");
    initSYM();          //link up symbol tables etc if they are there


    initDEV();          //resets DEV table, IRQ table

    initMSG();
    initLEGACY();       //sets up 9 legacy devices
                        //CGA CPU RAM PIC DMA TMR RTC KBD BBD
    initMSG();

    VESA* v=vesa;
    VBCINFO* vbc=v->vbc;
    VBMINFO* vbm=v->vbm;
    UC*      pal=v->pal;


    if(bsi->vflags)
        {
         bindpointerstovesa();  //bind pointers after device scan
         initWND1();            //GUI test
        }

    displaybanners();   //construct banners once time and date are known
                        //TMR device now running

//display some info
    CBJHEADER* os=(CBJHEADER*)OSbase;
    CH  verstr[12]; versionstring(verstr,os->ver,1);
    DB  q=(DB)OSsize/0x100000;
    dcat(2,0,"os %s (flags=0x%04X,base=0x%08X,size=%6.3dMb (0x%08X))",verstr,&OSflags,&OSbase,&q,&OSsize);

    initENV();          //start environment string list

    if(*(UC*)0x417&0x10)    //BIOS keyboard scroll lock on
        {
         clidisplay("|c1400Legacy mode: no DRVs loaded |c700(BIOS keyboard scroll lock on)");
         *(UC*)0x417=0x20;
         setkbdLEDs(kbdstate=NUMLOCK);
        }
    else{
         initAPIC();
         loadSRVs(5,4);     //protocol servers level 5 and 4 IP and ARP
         initPCI (1,0);     //device scan
//         initPnP (0);
        }

//    initSCSI();

    initMSG();
    loadSRVs(3,1);          //protocol servers level 3 SLPSRV
                            //message servers level 2 TELSRV FTPSRV HTPSRV
                            //application servers level 1 PRNSRV
    if(LDcur)
        {
         //don't invoke setup if running over DOS
         if(!(OSflags&DOSLOAD))
            {
             if(!strcmp(LDcur->tag,"bootcd"))
               {
                 setdevpaths(LDcur);    //just in case partially installed
                 v_invoke("setup");     //ChaOS drive has set paths to hda1:\\
                }
            }
        }

    if(!countmsds())
        {//if no mass storage devices found
         //create bda mass storage containers for boot devices
         createbdds(0);
        }
    else
        {
         createbdds(1);
        }

    initSYS();

    if(!(kbdstate&LSHIFT))
    {
    if(!findfile("\\go.job"))
        {
         clidisplay("Found autorun file |c1500go.job");
         v_invoke("go");
        }
    }

    cli();      //first call to cli() calls initSCR() and initMSG()

    SL  key;
    UI  cw;
    UL* pt;

//on exit from shell, fall through to old utilities
    while(1)
        {
         key=dgetkey();

         switch(vispage)
            {
             case 3: //send keystrokes to virtual screen in view
                if(vbuf==netdisp)
                    {
                     netutils(key&0xffff);
                    }
                break;
             case 2:
                symutils(key&0xffff);
                break;
             case 0:
                switch(key&0xffff)
                    {
                     case (ALT|F12):
                        cli();
                        break;
                     case (ALT|F11):
                        emergency();
                        break;
                     case (ALT|F10):
                        goto B000;
                        break;
                    }
             default:
                break;
            }

        }//end while(1)

B000:
    setvisiblepage(0);
    UL n=stackused();
    clidisplay("stackused() is 0x%08X",&n);
    n=_memavl();
    clidisplay("_memavl() 0x%08X  bytes heapsize is 0x%08X bytes validatefree= %1l",&n,&heapsize,&validatefree);

B001:
    clidisplay("System halted: restart= DOS Netboot Reboot=");
    key=dgetkey();
    switch(key&0xffff)
        {
         case F1:
//            oscleanup();
            break;
         case F5:           //test divide by zero trap int_00
#asm
            mov     ecx,0
            div     ecx
#endasm
            break;
         case F6:           //test breakpoint trap int_03
#asm
            op      0xcc
            op      0xf1
#endasm
            goto B001;
         case F7:           //test GP fault trap int_13
#asm
            mov     eax,0xaaaa
            push    eax
            pop     ds
#endasm
         case F8:           //switch paging on
#asm
            mov     eax,pagebase
            mov     cr3,eax
            mov     eax,cr0
            or      eax,FLGPG
            mov     cr0,eax
#endasm
            goto B001;
//         case F9:           //test page fault trap int_14
//#asm
//            mov     edi,memtop
//            dec     edi
//            stosb
//            stosb
//            stosb
//#endasm
//            goto B001;
         case F2:
            if(OSflags&NETWORKLOAD)
                {
                 *(UC*)NETROMRESTARTFLAG=0;
                }
            clrscreen();
            shutdown(10);
            break;
         case F9:
            if(OSflags&NETWORKLOAD)
                {
                 *(UC*)NETROMRESTARTFLAG=7;
                }
            shutdown(10);
            break;
         case F10:
            if(OSflags&NETWORKLOAD)
                {
                 *(UC*)NETROMRESTARTFLAG=3;
                }
            shutdown(10);
            break;
         case F11:
            if(OSflags&NETWORKLOAD)
                {
                 *(UC*)NETROMRESTARTFLAG=1;
                }
            shutdown(10);
            break;
         case F12:
            shutdown(0);
            break;
         case (CTRL|F12):
            asm
                {
//                 fstcw  cw
//                 mov    cw,0x37e
//                 or     wp cw,1
//                 fldcw  cw
                 fldpi
                 fldpi
                 fldpi
                 fldpi
                 fldpi
                 fldpi
                 fldpi
                 fldpi
                 fldpi
                 fldpi
                 fldpi
                 fldpi
                }
            break;
         case (ALT|F12):
            clidisplay("OPTION:");
            if(!acceptat(clicur,0,"Enter address to move to 0x%08X",&n))
                {
                 relocateOS(n);
                }
            goto B001;  //in case relocateOS() returned after address error
            break;
         default:
            goto B001;
        }
    PICSoff();              //mask both PICS off to halt hardware
                            //before fall through to RESTART
}
VD  devhalt(VD);
SL  termSRV(VD);
VD  clrscreen(UL page);
codelabel RESTART;         //for emergency() jmp back into startup code
VD  emergency(VD)
{
    termSRV();
    termNET();
    flushfilesystems(1);
//    termDEV();
//    unmaskIRQ(1);
    devhalt();
    termDEV();
    PICSoff();
    clrallbps();
    clrscreen(0);
asm{
    mov     ebx,OSbase          //just in case
    jmp     RESTART
   }
}

VD  relocateOS(UL newbase)
{
    if(newbaseOSbase)
            {
             clidisplay("Address 0x%08X is within current ChaOS session!",&newbase);
             return;
            }
        }
    flushfilesystems(1);
    memcpy((CH*)newbase,(CH*)OSbase,OSsize);
    asm
        {
         mov     edi,ebx            //edi is OSbase for this image
         mov     ebx,newbase        //ebx becomes base of new image
         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 operating system with none at all
    NEXTRELOC:
         lodsw
         sub     dp [eax+ebx],edi   //reverse fastrelocs for this image
         loop    NEXTRELOC
    RELOCSDONE:
         mov     eax,newbase
         add     eax,0x200
         mov     edi,eax
         mov     eax,OSflags
         mov     edx,OSsize
//         call    edi
        }
}

//SHUTDOWN section, including DOS restart preparation

VD  restorelowmem(VD);
VD  shutdown(UC shutdownbyte)
{
    termSRV();
    termNET();
    flushfilesystems(1);

    usecdelay(10000);

    sndalldevs(DM_SHUTDOWN,0,0,0);

//reset processor, old-style, via kbd controller!
asm
    {
        cli
        mov     al,0x8f
        out     0x70,al
        mov     al,shutdownbyte
        out     0x71,al

        mov     al,0xfe     //pulse bit 0 on kbd controlller
        out     0x64,al
SHUTDOWN:
        hlt
        jmp     SHUTDOWN
    }

}

    CH* goingdownmsg[]={
                        "  ...Hot reboot",
                        "  ...Return to bootstrap...(or DOS if it's there)...",
                        "  ...Hot boot rom restart...(send BOOTINIT to server)",
                        " ...Warm boot rom restart...(re-detect network card)",
                        " ...Cold boot rom restart...",
                        " ...Reboot processor...",
                        " ...Don't shutdown"
                       };
    UL  goingdownvalid[]={1,0,0,0,0,1,1};

EX  UL  shutarg;
VD  drestorebox(BOX* b,CH* ptr);
CH*  dsavebox(BOX* b);
VD  dbox1(BOX* b,UL no,CH* str,UI col);
SL  dcat(UL row,UL col,CH* format,...);
VD  dclear(BOX* b,UL col);

VD  goingdown(VD)
{
    if(goingdownflag){return;}  //stop keyboard polling loop from re-entering!
    goingdownflag=1;
    UL  vis=getvisiblepage();
    setvisiblepage(0);

    BOX bp      ={10,10,24,70};
    BOX bp1     ={25,40,44,78};
    CH* ptr=dsavebox(&bp);
    dclear(&bp,0);
    dbox1(&bp,-1,"System shutdown options",0x20);
    CH* ptr1=dsavebox(&bp1);
    dclear(&bp1,0);
    dbox1(&bp1,-1,"Some system stats",0x60);

    UL n=stackused();
    UL m=stacksize();
    UL o;
    o=muldiv(n,100,m);
    dcat(bp1.t+1,bp1.l+1,"stack used %8l of   %8l %2l%%",&n,&m,&o);
    n=_memused();
    o=muldiv(n,100,heapsize);
    dcat(bp1.t+2,bp1.l+1," heap used %8l of %10l %2l%%",&n,&heapsize,&o);
    o=n&0xfffff;
    n/=0x100000;
    o=muldiv(o,100,0x100000);
    m=heapsize/0x100000;
    dcat(bp1.t+3,bp1.l+1,"     only %4l.%02lMb of %4lMb ",&n,&o,&m);

//    n=_memavl();
//    dcat(bp.t+2,bp.l+1,"_memavl() 0x%08X  bytes heapsize is 0x%08X bytes validatefree= %1l",&n,&heapsize,&validatefree);


B001:
    dcat(bp.t+3 ,bp.l+1,"Even ChaOS has to end sometime...");

    if(OSflags&NETWORKLOAD){goingdownvalid[2]=goingdownvalid[3]=goingdownvalid[4]=1;}
    if(OSflags&DOSLOAD)    {goingdownvalid[1]=1;}

    for(n=0;n<7;n++)
        {
         if(goingdownvalid[n])
            {
             dcat(bp.t+5+n ,bp.l+1,goingdownmsg[n]);
            }
         else
            {
             dcat(bp.t+5+n ,bp.l+1,"%sc800",goingdownmsg[n]);
            }
        }

    UL key=dgetkey();
    switch(key&0xffff)
        {
         case F1:
            emergency();
            break;
         case F2:
            if(OSflags&NETWORKLOAD)
                {
                 *(UC*)NETROMRESTARTFLAG=0;
                }
            clrscreen();
            shutdown(10);
            break;
         case F9:
            if(OSflags&NETWORKLOAD)
                {
                 *(UC*)NETROMRESTARTFLAG=7;
                }
            shutdown(10);
            break;
         case F10:
            if(OSflags&NETWORKLOAD)
                {
                 *(UC*)NETROMRESTARTFLAG=3;
                }
            shutdown(10);
            break;
         case F11:
            if(OSflags&NETWORKLOAD)
                {
                 *(UC*)NETROMRESTARTFLAG=1;
                }
            shutdown(10);
            break;
         case F12:
            *(UI*)0x472=0x1234;
            shutdown(shutarg);
            break;
         default:
            goto B001;
         case ESC:
            break;
        }

    drestorebox(&bp,    ptr);
    drestorebox(&bp1,   ptr1);
    setvisiblepage(vis);
    goingdownflag=0;
}