rulimine/stage2/protos/linux.c

161 lines
4.4 KiB
C
Raw Normal View History

2020-04-19 11:14:49 +03:00
#include <stdint.h>
#include <stddef.h>
#include <protos/linux.h>
#include <fs/file.h>
#include <lib/blib.h>
#include <lib/real.h>
2020-09-02 10:55:56 +03:00
#include <lib/term.h>
#include <lib/config.h>
2020-05-10 01:38:27 +03:00
#include <lib/print.h>
2020-11-02 11:20:34 +03:00
#include <lib/uri.h>
2020-09-20 13:03:44 +03:00
#include <mm/pmm.h>
#include <mm/mtrr.h>
2020-04-19 11:14:49 +03:00
2020-05-03 00:38:57 +03:00
#define KERNEL_LOAD_ADDR ((size_t)0x100000)
#define INITRD_LOAD_ADDR ((size_t)0x1000000)
__attribute__((section(".realmode"), used))
static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg) {
asm volatile (
"cld\n\t"
"jmp 0x08:1f\n\t"
"1: .code16\n\t"
"mov ax, 0x10\n\t"
"mov ds, ax\n\t"
"mov es, ax\n\t"
"mov fs, ax\n\t"
"mov gs, ax\n\t"
"mov ss, ax\n\t"
"mov eax, cr0\n\t"
"and al, 0xfe\n\t"
"mov cr0, eax\n\t"
"jmp 0x0000:1f\n\t"
"1:\n\t"
"mov ds, bx\n\t"
"mov es, bx\n\t"
"mov fs, bx\n\t"
"mov gs, bx\n\t"
"mov ss, bx\n\t"
"mov esp, 0xfdf0\n\t"
"sti\n\t"
"push cx\n\t"
"push 0\n\t"
"retf\n\t"
".code32\n\t"
:
: "b" (real_mode_code_seg), "c" (kernel_entry_seg)
: "memory"
);
}
void linux_load(char *config, char *cmdline) {
char buf[128];
struct file_handle *kernel = conv_mem_alloc(sizeof(struct file_handle));
if (!config_get_value(config, buf, 0, 128, "KERNEL_PATH"))
panic("KERNEL_PATH not specified");
if (!uri_open(kernel, buf))
panic("Could not open kernel resource");
2020-05-06 17:38:45 +03:00
2020-04-19 11:14:49 +03:00
uint32_t signature;
fread(kernel, &signature, 0x202, sizeof(uint32_t));
2020-04-19 11:14:49 +03:00
// validate signature
if (signature != 0x53726448) {
panic("Invalid Linux kernel signature");
}
size_t setup_code_size = 0;
fread(kernel, &setup_code_size, 0x1f1, 1);
2020-04-19 11:14:49 +03:00
if (setup_code_size == 0)
setup_code_size = 4;
setup_code_size *= 512;
print("linux: Setup code size: %x\n", setup_code_size);
size_t real_mode_code_size = 512 + setup_code_size;
print("linux: Real Mode code size: %x\n", real_mode_code_size);
2020-09-20 13:03:44 +03:00
void *real_mode_code = conv_mem_alloc_aligned(real_mode_code_size, 0x1000);
2020-04-19 11:14:49 +03:00
fread(kernel, real_mode_code, 0, real_mode_code_size);
2020-04-19 11:14:49 +03:00
size_t heap_end_ptr = ((real_mode_code_size & 0x0f) + 0x10) - 0x200;
*((uint16_t *)(real_mode_code + 0x224)) = (uint16_t)heap_end_ptr;
// vid_mode. 0xffff means "normal"
*((uint16_t *)(real_mode_code + 0x1fa)) = 0xffff;
uint16_t boot_protocol_ver;
boot_protocol_ver = *((uint16_t *)(real_mode_code + 0x206));
print("linux: Boot protocol: %u.%u\n",
boot_protocol_ver >> 8, boot_protocol_ver & 0xff);
char *kernel_version;
kernel_version = real_mode_code + *((uint16_t *)(real_mode_code + 0x20e)) + 0x200;
if (kernel_version) {
print("linux: Kernel version: %s\n", kernel_version);
}
// set type of loader
*((uint8_t *)(real_mode_code + 0x210)) = 0xff;
uint8_t loadflags;
loadflags = *((uint8_t *)(real_mode_code + 0x211));
loadflags |= (1 << 0); // kernel is loaded at 0x100000
loadflags &= ~(1 << 5); // print early messages
loadflags |= (1 << 7); // can use heap
*((uint8_t *)(real_mode_code + 0x211)) = loadflags;
// cmdline
*((uint32_t *)(real_mode_code + 0x228)) = (uint32_t)cmdline;
// load kernel
print("Loading kernel...\n");
memmap_alloc_range(KERNEL_LOAD_ADDR, kernel->size - real_mode_code_size, 0);
fread(kernel, (void *)KERNEL_LOAD_ADDR, real_mode_code_size, kernel->size - real_mode_code_size);
2020-04-19 11:14:49 +03:00
size_t modules_mem_base = INITRD_LOAD_ADDR;
for (size_t i = 0; ; i++) {
if (!config_get_value(config, buf, i, 128, "MODULE_PATH"))
break;
2020-04-19 11:14:49 +03:00
struct file_handle module;
if (!uri_open(&module, buf))
panic("Could not open `%s`", buf);
2020-04-19 11:14:49 +03:00
print("Loading module `%s`...\n", buf);
2020-04-19 11:14:49 +03:00
memmap_alloc_range(modules_mem_base, module.size, 0);
fread(&module, (void *)modules_mem_base, 0, module.size);
modules_mem_base += module.size;
}
if (modules_mem_base != INITRD_LOAD_ADDR) {
*((uint32_t *)(real_mode_code + 0x218)) = (uint32_t)INITRD_LOAD_ADDR;
*((uint32_t *)(real_mode_code + 0x21c)) = (uint32_t)(modules_mem_base - INITRD_LOAD_ADDR);
}
2020-04-19 11:14:49 +03:00
uint16_t real_mode_code_seg = rm_seg(real_mode_code);
uint16_t kernel_entry_seg = real_mode_code_seg + 0x20;
2020-09-02 10:55:56 +03:00
term_deinit();
mtrr_restore();
spinup(real_mode_code_seg, kernel_entry_seg);
2020-04-19 11:14:49 +03:00
}