mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2025-01-19 02:36:04 +00:00
370 lines
10 KiB
HolyC
Executable file
370 lines
10 KiB
HolyC
Executable file
asm {/* See $LK,"::/Doc/Boot.DD"$.
|
|
ZealOS starts in real, calls some BIOS routines, switches to 32 bit, and 64 bit mode and continues in $LK,"ZealC",A="FI:::/Doc/ZealC.DD"$ at $LK,"KMain",A="MN:KMain"$().
|
|
|
|
The boot loader jumps here in real-mode (16-bit).
|
|
It actually jumps to the $LK,"CZXE",A="MN:CZXE"$ header which is placed just before this by $LK,"the compiler",A="FF:::/Compiler/CMain.ZC,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 variables 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,"AHCIBootDVDProbeAll",A="MN:AHCIBootDVDProbeAll"$
|
|
};
|
|
|
|
#assert SYS_COMPILE_TIME + sizeof(CDate) + sizeof(CZXE) < 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.ZC"$, 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_FRAMEBUFFER_ADDR:: DU64 0;
|
|
SYS_FRAMEBUFFER_WIDTH:: DU64 0;
|
|
SYS_FRAMEBUFFER_HEIGHT:: DU64 0;
|
|
SYS_FRAMEBUFFER_PITCH:: DU64 0;
|
|
SYS_FRAMEBUFFER_BPP:: DU8 0;
|
|
|
|
SYS_SMBIOS_ENTRY:: DU64 0;
|
|
|
|
SYS_DISK_UUID:: DU64 0, 0;
|
|
|
|
SYS_BOOT_STACK:: DU32 BOOT_RAM_LIMIT;
|
|
|
|
SYS_IS_UEFI_BOOTED:: DU8 0;
|
|
|
|
//SYS_FRAMEBUFFER_LIST:: DU8 sizeof(CVideoInfo) * VBE_MODES_NUM DUP(0);
|
|
|
|
#assert $$ - SYS_KERNEL == sizeof(CKernel) - sizeof(CZXE)
|
|
|
|
REQUESTED_SCREEN_WIDTH: DU16 1024;
|
|
REQUESTED_SCREEN_HEIGHT: DU16 768;
|
|
|
|
VBE_TEMP_MODE: DU8 sizeof(CVBEMode) DUP(0);
|
|
VBE_INFO: DU8 sizeof(CVBEInfo) DUP(0);
|
|
VBE_FINAL_MODE_NUM: DU16 0; // gets set to final result mode number
|
|
VBE_STD_MODE_NUM: DU16 0; // gets set to mode number for standard 1024x768
|
|
|
|
SYS_FRAMEBUFFER_LIST:: DU8 sizeof(CVideoInfo) * VBE_MODES_NUM DUP(0);
|
|
|
|
//************************************
|
|
CORE0_16BIT_INIT::
|
|
//EAX is $LK,"SYS_BOOT_SRC",A="FF:::/Kernel/KStart16.ZC,[SYS_BOOT_SRC]"$. (Value passed from boot block, $LK,"BootHD",A="FF:::/System/Boot/BootHD.ZC,BOOT_SRC_HARDDRIVE"$, $LK,"BootDVD",A="FF:::/System/Boot/BootDVD.ZC,BOOT_SRC_DVD"$, & $LK,"BootRAM",A="FF:::/System/Boot/BootRAM.ZC,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.ZC,[SYS_BOOT_SRC]"$. See $LK,"BootHD",A="FF:::/System/Boot/BootHD.ZC,BOOT_SRC_HARDDRIVE"$, $LK,"BootDVD",A="FF:::/System/Boot/BootDVD.ZC,BOOT_SRC_DVD"$ & $LK,"BootRAM",A="FF:::/System/Boot/BootRAM.ZC,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 @@05
|
|
RETF
|
|
|
|
@@05: 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, VBE_INFO
|
|
MOV CVBEInfo.signature[DI], 'VBE2' //set to 'VBE2' to use VBE 2.0 functionality
|
|
INT 0x10
|
|
POP ES
|
|
CMP AX, 0x004F
|
|
JE @@10
|
|
JMP $$ //Freeze system if VBE not supported
|
|
|
|
@@10:
|
|
|
|
/*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, VBE_INFO
|
|
MOV SI, CVBEInfo.video_modes[AX]
|
|
MOV GS, CVBEInfo.video_modes+2[AX]
|
|
MOV DX, SYS_FRAMEBUFFER_LIST
|
|
MOV DI, VBE_TEMP_MODE
|
|
|
|
@@15: //Loop through all the mode numbers
|
|
MOV AX, GS:[SI]
|
|
CMP AX, 0xFFFF //FFFF signifies the end of the list
|
|
JE @@25
|
|
|
|
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 @@15 //if call to get mode information failed
|
|
|
|
//Filter everything but 32-bit color
|
|
MOV AL, CVBEMode.bpp[DI]
|
|
CMP AL, 32
|
|
JNE @@15
|
|
|
|
//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 @@15
|
|
|
|
//Only want memory model of packed pixel or direct color (RGB)
|
|
MOV AX, CVBEMode.memory_model[DI]
|
|
CMP AX, 4
|
|
JE @@18
|
|
CMP AX, 6
|
|
JNE @@15
|
|
|
|
//Copy information about this mode into AX and BX
|
|
@@18: MOV BX, CVBEMode.height[DI]
|
|
@@20: MOV AX, CVBEMode.width[DI]
|
|
|
|
// Copy info into DX SYS_FRAMEBUFFER_LIST
|
|
|
|
MOV CVideoInfo.height[DX], BX
|
|
MOV CVideoInfo.width[DX], AX
|
|
ADD DX, sizeof(CVideoInfo) // next array element
|
|
|
|
//Check if width and height match standard 1024x768
|
|
//If they match, set VBE_STD_MODE_NUM to this mode num
|
|
CMP AX, 1024
|
|
JNE @@23
|
|
CMP BX, 768
|
|
JNE @@23
|
|
MOV [VBE_STD_MODE_NUM], CX
|
|
|
|
//Check if width and height match requested resolution
|
|
@@23: CMP AX, [REQUESTED_SCREEN_WIDTH]
|
|
JNE @@15
|
|
CMP BX, [REQUESTED_SCREEN_HEIGHT]
|
|
JNE @@15
|
|
|
|
//If we've made it here we have our mode
|
|
MOV [VBE_FINAL_MODE_NUM], CX
|
|
JMP @@15
|
|
|
|
@@25: //End of loop
|
|
|
|
//If requested resolution wasn't found in VBE mode list,
|
|
//use the standard 1024x768 mode as fallback
|
|
MOV AX, [VBE_FINAL_MODE_NUM]
|
|
CMP AX, 0
|
|
JNE @@30
|
|
|
|
MOV CX, [VBE_STD_MODE_NUM]
|
|
MOV [VBE_FINAL_MODE_NUM], CX
|
|
|
|
@@30: PUSH ES
|
|
PUSH DS
|
|
POP ES
|
|
//Get mode information for the mode we want
|
|
MOV DI, VBE_TEMP_MODE
|
|
MOV CX, [VBE_FINAL_MODE_NUM]
|
|
MOV AX, 0x4F01
|
|
INT 0x10
|
|
POP ES
|
|
CMP AX, 0x004F
|
|
JNE @@35 //if called failed
|
|
|
|
//Set the mode; call takes mode number in BX
|
|
MOV AX, 0x4F02
|
|
MOV BX, CX
|
|
INT 0x10
|
|
CMP AX, 0x004F
|
|
JNE @@35
|
|
|
|
//Give mode information to kernel
|
|
MOV EAX, CVBEMode.framebuffer[DI]
|
|
MOV U32 [SYS_FRAMEBUFFER_ADDR], EAX
|
|
MOV AX, CVBEMode.height[DI]
|
|
MOV U16 [SYS_FRAMEBUFFER_HEIGHT], AX
|
|
MOV AX, CVBEMode.width[DI]
|
|
MOV U16 [SYS_FRAMEBUFFER_WIDTH], AX
|
|
MOV AX, CVBEMode.pitch[DI]
|
|
MOV U16 [SYS_FRAMEBUFFER_PITCH], AX
|
|
MOV AL, CVBEMode.bpp[DI]
|
|
MOV U8 [SYS_FRAMEBUFFER_BPP], AL
|
|
|
|
BTS U32 [SYS_RUN_LEVEL], RLf_VESA
|
|
@@35:
|
|
|
|
//Get E801 memory map.
|
|
//Output: AX = Memory between 1MiB and 16MiB in KiB (max 0x3C00 == 15 MiB)
|
|
// BX = Memory after 16MiB until first memory hole in 64KiB blocks.
|
|
XOR CX, CX
|
|
XOR DX, DX
|
|
MOV AX, 0xE801
|
|
INT 0x15
|
|
JCXZ @@40 //if CX and DX are zero, use AX and BX instead.
|
|
MOV AX, CX
|
|
MOV BX, DX
|
|
@@40: MOV U16 [MEM_E801], AX
|
|
MOV U16 [MEM_E801+2], BX
|
|
|
|
//Get E820 memory map.
|
|
MOV CX, MEM_E820_ENTRIES_NUM - 1 //Leave one to terminate
|
|
XOR EBX, EBX
|
|
PUSH DS
|
|
POP ES
|
|
MOV DI, MEM_E820
|
|
@@45: PUSH CX
|
|
MOV EAX, 0xE820
|
|
MOV ECX, sizeof(CMemE820)
|
|
MOV EDX, 'PAMS'
|
|
INT 0x15
|
|
JC @@50
|
|
CMP EAX, 'PAMS'
|
|
JNE @@50
|
|
TEST EBX, EBX
|
|
JZ @@50
|
|
ADD DI, sizeof(CMemE820)
|
|
POP CX
|
|
LOOP @@45
|
|
SUB SP, 2
|
|
@@50: ADD SP, 2 //if called failed we want to nullify the PUSHed CX value.
|
|
|
|
//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
|
|
@@55: MOV CL, CMemE820.type[SI]
|
|
TEST CL, CL
|
|
JZ @@65
|
|
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 @@60
|
|
MOV EAX, CMemE820.base [SI]
|
|
MOV EDX, CMemE820.base+4[SI]
|
|
ADD EAX, CMemE820.len [SI]
|
|
ADC EDX, CMemE820.len+4 [SI]
|
|
@@60: ADD SI, sizeof(CMemE820)
|
|
JMP @@55
|
|
|
|
@@65: 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 @@70
|
|
MOV CH, 0
|
|
INC CX
|
|
MOV U16 [SYS_PCI_BUSES], CX
|
|
@@70:
|
|
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:::/System/Boot/BootHD.ZC,BOOT_SRC_HARDDRIVE"$, $LK,"BootDVD",A="FF:::/System/Boot/BootDVD.ZC,BOOT_SRC_DVD"$, & $LK,"BootRAM",A="FF:::/System/Boot/BootRAM.ZC,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(CZXE) / 16
|
|
#assert !(sizeof(CZXE) & 0xF)
|
|
MOV GS, DX
|
|
|
|
MOV EDX, EAX
|
|
ADD EDX, U32 GS:[CZXE.patch_table_offset]
|
|
SUB EDX, sizeof(CZXE)
|
|
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
|
|
}
|