mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2025-01-19 02:36:04 +00:00
8723b39969
FPS changed from 60 to 30 (temporarily) slight font change SYS_VBE_FINAL -> SYS_VBE_FINAL_MODE_NUM
330 lines
9 KiB
HolyC
Executable file
330 lines
9 KiB
HolyC
Executable file
asm {/* See $LK,"::/Doc/Boot.DD"$.
|
||
ZenithOS starts in real, calls some BIOS routines, switches to 32 bit, and 64 bit mode and continues in $LK,"CosmiC",A="FI:::/Doc/CosmiC.DD"$ at $LK,"KMain",A="MN:KMain"$().
|
||
|
||
The boot loader jumps here in real-mode (16-bit).
|
||
It actually jumps to the $LK,"CBinFile",A="MN:CBinFile"$ header which is placed just before this by $LK,"the compiler",A="FF:::/Compiler/CMain.CC,16 ALIGN"$.
|
||
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.
|
||
GDT_CS64_RING3: DU64 0x0020FA0000000000,0; //$LK,"Ring3",A="FI:::/Demo/Lectures/Ring3.CC"$, so you can play with.
|
||
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)
|
||
|
||
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_MODE_NUM::DU16 0; //mode number of final mode set
|
||
#assert $$ - SYS_KERNEL == sizeof(CKernel) - sizeof(CBinFile)
|
||
|
||
TEMP_VBE_MODE: DU8 sizeof(CVBEMode) DUP(0);
|
||
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);
|
||
};
|
||
//************************************
|
||
CORE0_16BIT_INIT::
|
||
//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"$.)
|
||
MOV ECX, EAX
|
||
MOV AX, (BOOT_RAM_LIMIT-BOOT_STACK_SIZE) / 16
|
||
MOV SS, AX
|
||
MOV SP, BOOT_STACK_SIZE
|
||
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"$.
|
||
PUSH EBX
|
||
CALL U16 GET_IP
|
||
GET_IP: POP BX
|
||
SUB BX, GET_IP
|
||
SHR BX, 4
|
||
MOV AX, CS
|
||
ADD AX, BX
|
||
PUSH AX
|
||
PUSH U16 @@04
|
||
RETF
|
||
|
||
@@04: STI
|
||
MOV AX, CS
|
||
MOV DS, AX
|
||
MOV U32 [SYS_RUN_LEVEL],RLF_16BIT
|
||
|
||
//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
|
||
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
|
||
|
||
//Only want memory model of packed pixel or direct color (RGB)
|
||
// 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_MODE_NUM], 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_MODE_NUM]
|
||
CMP AX, 0
|
||
JNE @@09
|
||
MOV CX, [MAX_VBE_MODE]
|
||
MOV [SYS_VBE_FINAL_MODE_NUM], 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_MODE_NUM]
|
||
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
|
||
|
||
BTS U32 [SYS_RUN_LEVEL], RLf_VESA
|
||
@@10:
|
||
|
||
//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]
|
||
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"$.
|
||
|
||
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) & 0xF)
|
||
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
|
||
}
|