//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; }