197 lines
5.1 KiB
C
197 lines
5.1 KiB
C
#include "lnxboot.h"
|
|
#include "efi/types.h"
|
|
#include "efi/memmap.h"
|
|
|
|
extern void _start();
|
|
|
|
[[gnu::section(".lnxhead")]]
|
|
[[gnu::used]]
|
|
[[gnu::aligned(1)]]
|
|
[[gnu::unavailable("not present at runtime. use setup_info instead")]]
|
|
struct setup_info bzhead = {
|
|
.setup_sects = 2, // 1 512-byte sector
|
|
.boot_flag = 0xAA55,
|
|
.syssize = 16,
|
|
.jump_instruction = 0xEB,
|
|
.jump_offset = sizeof(struct setup_info) - __builtin_offsetof(struct setup_info, signature),
|
|
.signature = 0x53726448,
|
|
.version = 0x020F,
|
|
.loadflags = 0x01, // LOADED_HIGH,
|
|
.kernel_alignment = 1,
|
|
.relocatable_kernel = 0,
|
|
.xloadflags = 0x13, // XLF_KERNEL_64 | XLF_CAN_BE_LOADED_ABOVE_4G | XLF_5LEVEL
|
|
.cmdline_size = 255, // max command line size
|
|
.init_size = 0x10000 // we dont need THAT much memory
|
|
};
|
|
|
|
struct setup_info* setup_info;
|
|
struct boot_params* boot_params;
|
|
|
|
unsigned short serial_port;
|
|
|
|
void outb(unsigned short port, unsigned char value) {
|
|
asm volatile (
|
|
"outb %b0, %1"
|
|
::"a" (value)
|
|
,"d" (port)
|
|
);
|
|
}
|
|
|
|
void serial_putc(char c) {
|
|
outb(serial_port, c);
|
|
}
|
|
|
|
void serial_puts(const char* s) {
|
|
while (*s) serial_putc(*(s++));
|
|
}
|
|
|
|
void serial_put_formatted_u64(u64 v) {
|
|
if (v == 0) {
|
|
serial_putc('0');
|
|
} else {
|
|
u64 max = 1;
|
|
|
|
while (v > max) max *= 10;
|
|
|
|
while (v) {
|
|
serial_putc('0' + (u8)(v / max));
|
|
|
|
v %= max;
|
|
max /= 10;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* We can't do anything, just hang.
|
|
*/
|
|
[[noreturn, gnu::naked]]
|
|
void Hang() {
|
|
// This should make us hang
|
|
asm volatile (
|
|
" cli\n"
|
|
"1: hlt\n"
|
|
" jmp 1b"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Congratulations, you panicked twice!
|
|
*/
|
|
[[noreturn]]
|
|
void Panic(const char* message) {
|
|
// We don't even do anything with the message, but it's nice to have just in case.
|
|
Hang();
|
|
}
|
|
|
|
[[gnu::section(".text._start"), gnu::naked, gnu::no_reorder]]
|
|
extern void _start() {
|
|
asm ("jmp _start");
|
|
asm ( // grab the setup_info and boot_params locations
|
|
"mov %%rsi, %1\n"
|
|
"mov %%rsi, %0\n"
|
|
"addq $0x1f1, %0"
|
|
: "=m" (setup_info),
|
|
"=m" (boot_params)
|
|
);
|
|
asm ("jmp entry");
|
|
}
|
|
|
|
c16* FirmwareVendor = 0;
|
|
|
|
/**
|
|
* we're in some kind of purgatory between booted and not booted, a lot of devices are currently initialized from the previous
|
|
* kernel, but we have no idea where they are, what they are, or how to use them. all we have is the stuff in setup_info and
|
|
* boot_params, and whatever we can salvage from the crashed kernel.
|
|
*/
|
|
[[gnu::section(".text._start"), gnu::no_reorder]]
|
|
void entry() {
|
|
// get command line from kernel. we likely won't use it, but its nice to have.
|
|
u8* cmdline_ptr = (u8*)((u64)setup_info->cmd_line_ptr | ((u64)boot_params->ext_cmd_line_ptr << 32));
|
|
|
|
// do we have efi?
|
|
struct EfiSystemTable* systab_ptr = 0;
|
|
if (boot_params) {
|
|
systab_ptr = (struct EfiSystemTable*)(
|
|
(u64)boot_params->efi_info.EfiSystemTable |
|
|
((u64)boot_params->efi_info.EfiSystemTableHigh << 32)
|
|
);
|
|
|
|
EfiLoadStoredMemoryMap(
|
|
(struct EfiMemoryDescription*)(
|
|
(u64)boot_params->efi_info.EfiMemoryMap |
|
|
((u64)boot_params->efi_info.EfiMemoryMapHigh << 32)
|
|
), // this might be 0, we should probably check ---------------V
|
|
boot_params->efi_info.EfiMemoryMapSize / boot_params->efi_info.EfiMemoryDescriptionSize,
|
|
boot_params->efi_info.EfiMemoryDescriptionSize
|
|
);
|
|
|
|
FirmwareVendor = EfiTranslatePointer(systab_ptr->FirmwareVendor);
|
|
while (1) {
|
|
volatile char* a = FirmwareVendor;
|
|
}
|
|
}
|
|
|
|
// -- find acpi --
|
|
struct AcpiRSDP* AcpiRSDP = 0;
|
|
|
|
// check bootparams
|
|
if (boot_params->acpi_rsdp_addr) AcpiRSDP = boot_params->acpi_rsdp_addr;
|
|
|
|
// check efi
|
|
if (!AcpiRSDP && systab_ptr && systab_ptr->NumberOfTableEntries) {
|
|
volatile void* ConfigurationTable = EfiTranslatePointer(systab_ptr->ConfigurationTable);
|
|
}
|
|
|
|
// we're playing where's waldo with this stupid fucking tableS
|
|
if (!AcpiRSDP) {
|
|
for (struct AcpiRSDP* addr = 0x00000000; addr < 0x000FFFFF; addr = (void*)addr + 16) {
|
|
if (addr->Signature[0] == 'R' && addr->Signature[1] == 'S'
|
|
&& addr->Signature[2] == 'D' && addr->Signature[3] == ' '
|
|
&& addr->Signature[4] == 'P' && addr->Signature[5] == 'T'
|
|
&& addr->Signature[6] == 'R' && addr->Signature[7] == ' ') {
|
|
AcpiRSDP = addr;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!AcpiRSDP) Panic("Failed to find ACPI RSDP");
|
|
|
|
// do we have acpi?
|
|
asm volatile ("ljmp 0");
|
|
|
|
// we dont have the privilege of getting a rodata segment. any reads off our stack cause a triple fault
|
|
// for some fucking reason. allocate our strings and shit on the stack.
|
|
//char s_you_fucked_up[] = "!!! YOU FUCKED UP !!!\n";
|
|
//char s_vga_you_fucked_up[] = "YOU FUCKED UP.\n";
|
|
//char s_description[] = "A SERIOUS ERROR HAS OCCURED AND LINDOWS HAS STOPPED TO PREVENT FURTHER DAMAGE.";
|
|
//char s_registers[] = "REGISTERS:";
|
|
//char s_call_trace[] = "CALL TRACE:";
|
|
//char s_dumpcore[] = "[(D)UMP CORE]";
|
|
//char s_poweroff[] = "[(P)OWER OFF]";
|
|
//char s_reboot[] = "[(R)EBOOT ]";
|
|
|
|
// You fucked up.
|
|
//serial_puts(s_you_fucked_up);
|
|
//serial_puts(s_description);
|
|
//serial_putc('\n');
|
|
|
|
// register dump
|
|
//serial_puts(s_registers);
|
|
//serial_putc('\n');
|
|
//serial_putc('\n');
|
|
|
|
// call trace
|
|
//serial_puts(s_call_trace);
|
|
//serial_putc('\n');
|
|
//serial_putc('\n');
|
|
|
|
// thing
|
|
// serial_puts("test\n");
|
|
// serial_puts(bzhead.cmd_line_ptr);
|
|
|
|
// Die.
|
|
Panic("Nothing left to do.");
|
|
}
|