ZealOS/src/Kernel/KStart16.ZC

357 lines
9.6 KiB
HolyC
Raw Normal View History

2020-02-15 20:01:48 +00:00
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"$().
2020-02-15 20:01:48 +00:00
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.
2020-03-01 01:59:50 +00:00
This file is first in the Kernel image because it is #included first. $LK,"Kernel.PRJ",A="FF:::/Kernel/Kernel.PRJ,KStart16:1"$
2020-02-15 20:01:48 +00:00
*/
USE16
SYS_KERNEL:: //This must match $LK,"CKernel",A="MN:CKernel"$.
JMP I16 CORE0_16BIT_INIT
2020-02-15 20:01:48 +00:00
//************************************
// 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
2020-02-15 20:01:48 +00:00
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;
#assert $$ - SYS_KERNEL == sizeof(CKernel) - sizeof(CZXE)
REQUESTED_SCREEN_WIDTH: DU16 1024;
REQUESTED_SCREEN_HEIGHT: DU16 768;
2020-02-19 06:17:33 +00:00
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
2020-02-15 20:01:48 +00:00
//************************************
2020-02-19 07:11:54 +00:00
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
2022-08-25 12:15:24 +01:00
PUSH U16 @@05
RETF
2022-08-25 12:15:24 +01:00
@@05: STI
MOV AX, CS
MOV DS, AX
MOV U32 [SYS_RUN_LEVEL], RLF_16BIT
2020-02-15 20:01:48 +00:00
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
2020-02-19 06:17:33 +00:00
//Get VBE implementation information
MOV AX, 0x4F00
2022-08-25 12:15:24 +01:00
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
2022-08-25 12:15:24 +01:00
JE @@10
JMP $$ //Freeze system if VBE not supported
2020-02-19 06:17:33 +00:00
2022-08-25 12:15:24 +01:00
@@10:
2020-02-19 06:17:33 +00:00
/*Loop variables:
DI <- Temporary storage for mode information
CX <- Mode number
GS <- Segment for video modes list
SI <- Offset for video modes list
*/
//Obtain segment:offset of list of potential video modes
2022-08-25 12:15:24 +01:00
MOV AX, VBE_INFO
MOV SI, CVBEInfo.video_modes[AX]
MOV GS, CVBEInfo.video_modes+2[AX]
MOV DI, VBE_TEMP_MODE
2020-02-19 06:17:33 +00:00
2022-08-25 12:15:24 +01:00
@@15: //Loop through all the mode numbers
MOV AX, GS:[SI]
CMP AX, 0xFFFF //FFFF signifies the end of the list
2022-08-25 12:15:24 +01:00
JE @@25
2020-02-19 06:17:33 +00:00
ADD SI, 2 //Increment pointer to read next U16 mode
2020-02-19 06:17:33 +00:00
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
2020-02-19 06:17:33 +00:00
//Get mode information for mode number
MOV AX, 0x4F01
INT 0x10
POP ES
CMP AX, 0x004F
2022-08-25 12:15:24 +01:00
JNE @@15 //if call to get mode information failed
2020-02-19 06:17:33 +00:00
//Filter everything but 32-bit color
MOV AL, CVBEMode.bpp[DI]
CMP AL, 32
2022-08-25 12:15:24 +01:00
JNE @@15
2020-02-19 06:17:33 +00:00
//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
2022-08-25 12:15:24 +01:00
JNE @@15
//Only want memory model of packed pixel or direct color (RGB)
2022-08-25 12:15:24 +01:00
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]
//Check if width and height match standard 1024x768
//If they match, set VBE_STD_MODE_NUM to this mode num
2022-08-25 12:15:24 +01:00
CMP AX, 1024
JNE @@23
2022-08-25 12:15:24 +01:00
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]
2022-08-25 12:15:24 +01:00
JNE @@15
2020-02-19 06:17:33 +00:00
//If we've made it here we have our mode
2022-08-25 12:15:24 +01:00
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
2022-08-25 12:15:24 +01:00
@@30: PUSH ES
PUSH DS
POP ES
//Get mode information for the mode we want
MOV DI, VBE_TEMP_MODE
2022-08-25 12:15:24 +01:00
MOV CX, [VBE_FINAL_MODE_NUM]
MOV AX, 0x4F01
INT 0x10
POP ES
CMP AX, 0x004F
2022-08-25 12:15:24 +01:00
JNE @@35 //if called failed
2020-02-19 06:17:33 +00:00
//Set the mode; call takes mode number in BX
MOV AX, 0x4F02
MOV BX, CX
INT 0x10
CMP AX, 0x004F
2022-08-25 12:15:24 +01:00
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
2022-08-25 12:15:24 +01:00
@@35:
2020-02-15 20:01:48 +00:00
//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
2022-08-25 12:15:24 +01:00
JCXZ @@40 //if CX and DX are zero, use AX and BX instead.
MOV AX, CX
MOV BX, DX
2022-08-25 12:15:24 +01:00
@@40: MOV U16 [MEM_E801], AX
MOV U16 [MEM_E801+2], BX
2020-02-21 08:57:37 +00:00
//Get E820 memory map.
MOV CX, MEM_E820_ENTRIES_NUM - 1 //Leave one to terminate
2020-02-21 08:57:37 +00:00
XOR EBX, EBX
PUSH DS
POP ES
MOV DI, MEM_E820
2022-08-25 12:15:24 +01:00
@@45: PUSH CX
MOV EAX, 0xE820
MOV ECX, sizeof(CMemE820)
MOV EDX, 'PAMS'
INT 0x15
2022-08-25 12:15:24 +01:00
JC @@50
CMP EAX, 'PAMS'
2022-08-25 12:15:24 +01:00
JNE @@50
2020-02-21 08:57:37 +00:00
TEST EBX, EBX
2022-08-25 12:15:24 +01:00
JZ @@50
ADD DI, sizeof(CMemE820)
POP CX
2022-08-25 12:15:24 +01:00
LOOP @@45
SUB SP, 2
2022-08-25 12:15:24 +01:00
@@50: ADD SP, 2 //if called failed we want to nullify the PUSHed CX value.
2020-02-15 20:01:48 +00:00
//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
2020-02-15 20:01:48 +00:00
//Find max of E820 to set mapped space.
MOV SI, MEM_E820
2022-08-25 12:15:24 +01:00
@@55: MOV CL, CMemE820.type[SI]
TEST CL, CL
2022-08-25 12:15:24 +01:00
JZ @@65
2020-02-21 08:57:37 +00:00
MOV EBX, CMemE820.base [SI]
MOV ECX, CMemE820.base+4[SI]
2020-02-21 10:46:20 +00:00
ADD EBX, CMemE820.len [SI]
2020-02-21 08:57:37 +00:00
ADC ECX, CMemE820.len+4 [SI]
SUB EBX, EAX
SBB ECX, EDX
2022-08-25 12:15:24 +01:00
JC @@60
MOV EAX, CMemE820.base [SI]
2020-02-21 08:57:37 +00:00
MOV EDX, CMemE820.base+4[SI]
ADD EAX, CMemE820.len [SI]
ADC EDX, CMemE820.len+4 [SI]
2022-08-25 12:15:24 +01:00
@@60: ADD SI, sizeof(CMemE820)
JMP @@55
2022-08-25 12:15:24 +01:00
@@65: MOV [MEM_PHYSICAL_SPACE], EAX
MOV [MEM_PHYSICAL_SPACE+4], EDX
2020-02-15 20:01:48 +00:00
//Get PCI Bus Info
MOV U16 [SYS_PCI_BUSES], 256
XOR DX, DX
MOV AX, 0xB101
INT 0x1A
CMP DX, 'PC'
2022-08-25 12:15:24 +01:00
JNE @@70
MOV CH, 0
INC CX
MOV U16 [SYS_PCI_BUSES], CX
2022-08-25 12:15:24 +01:00
@@70:
CLI
2020-02-15 20:01:48 +00:00
//Enable A20
IN AL, 0x92
OR AL, 2
OUT 0x92, AL
2020-02-15 20:01:48 +00:00
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"$.
2020-02-15 20:01:48 +00:00
CLD
XOR EAX, EAX
MOV AX, CS
MOV DS, AX
MOV ES, AX
SHL EAX, 4
2020-02-15 20:01:48 +00:00
MOV U32 [MEM_BOOT_BASE], EAX
2020-02-15 20:01:48 +00:00
MOV DX, CS
SUB DX, sizeof(CZXE) / 16
#assert !(sizeof(CZXE) & 0xF)
MOV GS, DX
2020-02-15 20:01:48 +00:00
MOV EDX, EAX
ADD EDX, U32 GS:[CZXE.patch_table_offset]
SUB EDX, sizeof(CZXE)
MOV U32 [SYS_BOOT_PATCH_TABLE_BASE], EDX
2020-02-15 20:01:48 +00:00
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]
2020-02-15 20:01:48 +00:00
MOV EAX, SYS_START_CR0
MOV_CR0_EAX
2020-02-15 20:01:48 +00:00
/* The assembler doesn't support far jumps so
we hand code it. 16-bit code is not important
2020-02-15 20:01:48 +00:00
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
2020-02-15 20:01:48 +00:00
}