ZealOS/src/Kernel/KStart16.CC

347 lines
8.6 KiB
HolyC
Raw Normal View History

2020-02-15 20:01:48 +00:00
asm {/* See $LK,"::/Doc/Boot.DD"$.
2020-02-15 21:11:16 +00:00
ZenithOS starts in real, calls some BIOS
2020-02-15 20:01:48 +00:00
routines, switches to 32 bit, and 64 bit mode
2020-02-16 05:24:10 +00:00
and continues in $LK,"CosmiC",A="FI:::/Doc/CosmiC.DD"$ at $LK,"KMain",A="MN:KMain"$().
2020-02-15 20:01:48 +00:00
The boot loader jumps here in real-mode (16-bit).
It actually jumps to the $LK,"CBinFile",A="MN:CBinFile"$ header which is
2020-02-16 04:57:03 +00:00
placed just before this by $LK,"the compiler",A="FF:::/Compiler/CMain.CC,16 ALIGN"$.
2020-02-15 20:01:48 +00:00
The header begins with a short jmp to
the start of this file's code which begins
with the following small jump past some data.
This file is first in the Kernel image
because it is #included first.$LK,"Kernel.PRJ",A="FF:::/Kernel/Kernel.PRJ,KStart16:1"$
*/
USE16
SYS_KERNEL:: //This must match $LK,"CKernel",A="MN:CKernel"$.
JMP I16 CORE0_16BIT_INIT
//************************************
// ASM Global vars required for 16-bit start-up
ALIGN 4,OC_NOP
SYS_BOOT_SRC:: DU32 BOOT_SRC_NULL;
SYS_BOOT_BLK:: DU32 0;
SYS_BOOT_PATCH_TABLE_BASE:: DU32 0;
SYS_RUN_LEVEL:: DU32 0;
#exe {StreamPrint("SYS_COMPILE_TIME:: DU64 0x%X;",Now);} //See $LK,"BootDVDProbe",A="MN:BootDVDProbe"$
#assert SYS_COMPILE_TIME+sizeof(CDate)+sizeof(CBinFile)<DVD_BLK_SIZE
MEM_BOOT_BASE:: DU32 0; //Offset from start used by reboot
MEM_E801:: DU16 0,0;
MEM_E820:: DU8 MEM_E820_ENTRIES_NUM*sizeof(CMemE820) DUP (0);
MEM_PHYSICAL_SPACE:: DU64 0;
SYS_GDT_PTR:: DU16 sizeof(CGDT)-1;
DU64 0;
SYS_PCI_BUSES:: DU16 0;
ALIGN 16,OC_NOP
SYS_GDT:: //See $LK,"CGDT",A="MN:CGDT"$
GDT_NULL: DU64 0,0;
GDT_BOOT_DS: DU64 0x00CF92000000FFFF,0; //Gets patched.
GDT_BOOT_CS: DU64 0x00CF9A000000FFFF,0; //Gets patched.
GDT_CS32: DU64 0x00CF9A000000FFFF,0;
GDT_CS64: DU64 0x00209A0000000000,0; //The $LK,"Charter",A="FI:::/Doc/Charter.DD"$ says just ring0.
2020-02-16 04:57:03 +00:00
GDT_CS64_RING3: DU64 0x0020FA0000000000,0; //$LK,"Ring3",A="FI:::/Demo/Lectures/Ring3.CC"$, so you can play with.
2020-02-15 20:01:48 +00:00
GDT_DS: DU64 0x00CF92000000FFFF,0;
GDT_DS_RING3: DU64 0x00CFF2000000FFFF,0;
GDT_TR: DU8 MP_PROCESSORS_NUM*16 DUP(0);
GDT_TR_RING3: DU8 MP_PROCESSORS_NUM*16 DUP(0);
#assert $$-SYS_GDT==sizeof(CGDT)
2020-02-19 20:57:13 +00:00
SYS_FONT_PTR:: DU32 0;
2020-02-19 06:17:33 +00:00
SYS_VBE_INFO:: DU8 sizeof(CVBEInfo) DUP(0);
SYS_VBE_MODES:: DU8 sizeof(CVBEModeShort) * VBE_MODES_NUM DUP(0);
SYS_VBE_FINAL_MODE:: DU8 sizeof(CVBEMode) DUP(0);
SYS_VBE_FINAL:: DU16 0; //mode number of final mode set
2020-02-19 20:57:13 +00:00
#assert $$-SYS_KERNEL==sizeof(CKernel)-sizeof(CBinFile)
2020-02-19 06:17:33 +00:00
TEMP_VBE_MODE: DU8 sizeof(CVBEMode) DUP(0);
2020-02-19 06:17:33 +00:00
MAX_VBE_MODE: DU8 sizeof(CVBEModeShort) DUP(0);
MAX_SCREEN_HEIGHT: DU16 0;
#exe
{StreamPrint(
"SCREEN_WIDTH: DU16 %d;"
"SCREEN_HEIGHT: DU16 %d;",
kernel_config->screen_width, kernel_config->screen_height);
};
2020-02-15 20:01:48 +00:00
//************************************
2020-02-19 07:11:54 +00:00
CORE0_16BIT_INIT::
2020-02-16 04:57:03 +00:00
//EAX is $LK,"SYS_BOOT_SRC",A="FF:::/Kernel/KStart16.CC,[SYS_BOOT_SRC]"$. (Val passed from boot blk, $LK,"BootHD",A="FF:::/Zenith/Boot/BootHD.CC,BOOT_SRC_HARDDRIVE"$, $LK,"BootDVD",A="FF:::/Zenith/Boot/BootDVD.CC,BOOT_SRC_DVD"$, & $LK,"BootRAM",A="FF:::/Zenith/Boot/BootRAM.CC,BOOT_SRC_RAM"$.)
2020-02-15 20:01:48 +00:00
MOV ECX,EAX
2020-02-19 06:17:33 +00:00
MOV AX, (BOOT_RAM_LIMIT-BOOT_STACK_SIZE) / 16
MOV SS, AX
MOV SP, BOOT_STACK_SIZE
2020-02-16 04:57:03 +00:00
PUSH ECX //Will be $LK,"SYS_BOOT_SRC",A="FF:::/Kernel/KStart16.CC,[SYS_BOOT_SRC]"$. See $LK,"BootHD",A="FF:::/Zenith/Boot/BootHD.CC,BOOT_SRC_HARDDRIVE"$, $LK,"BootDVD",A="FF:::/Zenith/Boot/BootDVD.CC,BOOT_SRC_DVD"$ & $LK,"BootRAM",A="FF:::/Zenith/Boot/BootRAM.CC,BOOT_SRC_RAM"$.
2020-02-15 20:01:48 +00:00
PUSH EBX
2020-02-19 06:17:33 +00:00
CALL U16 GET_IP
GET_IP: POP BX
SUB BX,GET_IP
2020-02-15 20:01:48 +00:00
SHR BX,4
MOV AX,CS
ADD AX,BX
PUSH AX
2020-02-19 06:17:33 +00:00
PUSH U16 @@04
2020-02-15 20:01:48 +00:00
RETF
2020-02-19 06:17:33 +00:00
@@04: STI
2020-02-15 20:01:48 +00:00
MOV AX,CS
MOV DS,AX
MOV U32 [SYS_RUN_LEVEL],RLF_16BIT
2020-02-19 06:17:33 +00:00
//Our variables are on the data segment, but VBE functions require ES.
//moving DS into ES, while preserving ES
PUSH ES
PUSH DS
POP ES
//Get VBE implementation information
MOV AX, 0x4F00
MOV DI, SYS_VBE_INFO
MOV CVBEInfo.signature[DI], 'VBE2' //set to 'VBE2' to use VBE 2.0 functionality
INT 0x10
2020-02-19 06:17:33 +00:00
POP ES
CMP AX, 0x004F
JE @@05
JMP $$ //Freeze system if VBE not supported
@@05:
/*Loop variables:
DI <- Temporary storage for mode information
CX <- Mode number
DX <- mode array
GS <- Segment for video modes list
SI <- Offset for video modes list
*/
//Obtain segment:offset of list of potential video modes
MOV AX, SYS_VBE_INFO
MOV SI, CVBEInfo.video_modes[AX]
MOV GS, CVBEInfo.video_modes+2[AX]
MOV DI, TEMP_VBE_MODE
MOV DX, SYS_VBE_MODES
@@06: //Loop through all the mode numbers
MOV AX, GS:[SI]
CMP AX, 0xFFFF //FFFF signifies the end of the list
JE @@08
ADD SI, 2 //Increment pointer to read next U16 mode
MOV CX, AX
BTS CX, 14 //Set linear framebuffer bit in the mode number we are about to pass to the BIOS below
PUSH ES
PUSH DS
POP ES
//Get mode information for mode number
MOV AX, 0x4F01
INT 0x10
POP ES
CMP AX, 0x004F
JNE @@06 //if call to get mode information failed
//filter everything but 32-bit color
MOV AL, CVBEMode.bpp[DI]
CMP AL, 32
JNE @@06
//Check if the mode is actually supported
MOV AX, CVBEMode.attributes[DI]
AND AX, 0x91 //bit 0 = supported, bit 4 = graphics mode, bit 7 = linear framebuffer
CMP AX, 0x91
JNE @@06
// MOV AX, CVBEMode.memory_model[DI]
// CMP AX, 4
// JNE @@06
// CMP AX, 6
// JNE @@06
//Copy information about this mode into an element of the mode array
MOV BX, CVBEMode.height[DI]
MOV CVBEModeShort.height[DX], BX
CMP BX, [MAX_SCREEN_HEIGHT]
JL @@07
MOV [MAX_SCREEN_HEIGHT], BX
MOV [MAX_VBE_MODE], CX
@@07: MOV AX, CVBEMode.width[DI]
MOV CVBEModeShort.width[DX], AX
// MOV EAX, CVBEMode.max_pixel_clock[DI]
// MOV CVBEModeShort.max_pixel_clock[DX], EAX
MOV CVBEModeShort.mode_num[DX], CX
ADD DX, sizeof(CVBEModeShort) //next array element
//Check if width and height match
CMP AX, [SCREEN_WIDTH]
JNE @@06
CMP BX, [SCREEN_HEIGHT]
JNE @@06
//If we've made it here we have our mode
MOV [SYS_VBE_FINAL], CX
JMP @@06
@@08: //End of loop
//If there isn't a valid mode set by user through kernel config, set the mode with the biggest height.
MOV AX, [SYS_VBE_FINAL]
CMP AX, 0
JNE @@09
MOV CX, [MAX_VBE_MODE]
MOV [SYS_VBE_FINAL], CX
@@09: PUSH ES
PUSH DS
POP ES
//Get mode infomration for the mode we want
MOV DI, SYS_VBE_FINAL_MODE
MOV CX, [SYS_VBE_FINAL]
MOV AX, 0x4F01
INT 0x10
POP ES
CMP AX, 0x004F
JNE @@10 //if called failed
//Set the mode; call takes mode number in BX
MOV AX, 0x4F02
MOV BX, CX
INT 0x10
CMP AX, 0x004F
JNE @@10
2020-02-19 07:11:54 +00:00
BTS U32 [SYS_RUN_LEVEL],RLf_VESA
2020-02-15 20:01:48 +00:00
@@10:
2020-02-19 06:17:33 +00:00
//Get pointer to 8x8 VGA ROM font.
MOV AX, 0x1130
MOV BH, 3
INT 0x10
MOV AX, ES
SHL EAX, 16
MOV AX, BP
MOV U32 [SYS_FONT_PTR], EAX
2020-02-15 20:01:48 +00:00
//Get mem maps.
MOV AX,0xE801
INT 0x15
MOV U16 [MEM_E801],CX
MOV U16 [MEM_E801+2],DX
MOV CX,MEM_E820_ENTRIES_NUM-1 //Leave one to terminate
XOR EBX,EBX
MOV AX,DS
MOV ES,AX
MOV DI,MEM_E820
@@15: PUSH CX
MOV EAX,0xE820
MOV ECX,sizeof(CMemE820)
MOV EDX,'PAMS'
INT 0x15
JC @@20
CMP EAX,'PAMS'
JNE @@20
TEST EBX,EBX
JZ @@20
ADD DI,sizeof(CMemE820)
POP CX
LOOP @@15
SUB SP,2
@@20: ADD SP,2
//Find how much space to map, start with E801 limit.
XOR EAX,EAX
MOV AX,[MEM_E801+2]
SHL EAX,16
ADD EAX,SYS_16MEG_AREA_LIMIT
XOR EDX,EDX
//Find max of E820 to set mapped space.
MOV SI,MEM_E820
@@25: MOV CL,CMemE820.type[SI]
TEST CL,CL
JZ @@35
MOV EBX,CMemE820.base[SI]
MOV ECX,CMemE820.base+4[SI]
ADD EBX,CMemE820.len[SI]
ADC ECX,CMemE820.len+4[SI]
SUB EBX,EAX
SBB ECX,EDX
JC @@30
MOV EAX,CMemE820.base[SI]
MOV EDX,CMemE820.base+4[SI]
ADD EAX,CMemE820.len[SI]
ADC EDX,CMemE820.len+4[SI]
@@30: ADD SI,sizeof(CMemE820)
JMP @@25
@@35: MOV [MEM_PHYSICAL_SPACE],EAX
MOV [MEM_PHYSICAL_SPACE+4],EDX
//Get PCI Bus Info
MOV U16 [SYS_PCI_BUSES],256
XOR DX,DX
MOV AX,0xB101
INT 0x1A
CMP DX,'PC'
JNE @@40
MOV CH,0
INC CX
MOV U16 [SYS_PCI_BUSES],CX
@@40:
CLI
//Enable A20
IN AL,0x92
OR AL,2
OUT 0x92,AL
POP U32 [SYS_BOOT_BLK]
2020-02-16 04:57:03 +00:00
POP U32 [SYS_BOOT_SRC] //See $LK,"BootHD",A="FF:::/Zenith/Boot/BootHD.CC,BOOT_SRC_HARDDRIVE"$, $LK,"BootDVD",A="FF:::/Zenith/Boot/BootDVD.CC,BOOT_SRC_DVD"$, & $LK,"BootRAM",A="FF:::/Zenith/Boot/BootRAM.CC,BOOT_SRC_RAM"$.
2020-02-15 20:01:48 +00:00
CLD
XOR EAX,EAX
MOV AX,CS
MOV DS,AX
MOV ES,AX
SHL EAX,4
MOV U32 [MEM_BOOT_BASE],EAX
MOV DX,CS
SUB DX,sizeof(CBinFile)/16
#assert !(sizeof(CBinFile)&15)
MOV GS,DX
MOV EDX,EAX
ADD EDX,U32 GS:[CBinFile.patch_table_offset]
SUB EDX,sizeof(CBinFile)
MOV U32 [SYS_BOOT_PATCH_TABLE_BASE],EDX
ADD U32 [GDT_BOOT_DS+2],EAX
ADD U32 [GDT_BOOT_CS+2],EAX
ADD EAX,I32 SYS_GDT
MOV U32 [SYS_GDT_PTR+CSysLimitBase.base],EAX
LGDT U32 [SYS_GDT_PTR]
MOV EAX,SYS_START_CR0
MOV_CR0_EAX
/* The assembler doesn't support far jumps so
we hand code it. 16-bit code is not important
enough to fully implement in the assembler.
To complete the switch to 32-bit mode, we have to load
the code segment with a far jump.
*/
DU8 0x66,0xEA; //JMP CGDT.boot_cs:CORE0_32BIT_INIT
DU32 CORE0_32BIT_INIT;
DU16 CGDT.boot_cs;
#assert $$+16<=0xFFFF
}