linux: Misc protocol bug fixes
This commit is contained in:
parent
5e344a54b5
commit
81a134b59b
BIN
limine-pxe.bin
BIN
limine-pxe.bin
Binary file not shown.
BIN
limine.bin
BIN
limine.bin
Binary file not shown.
BIN
stage2.map
BIN
stage2.map
Binary file not shown.
|
@ -80,7 +80,7 @@ int fread(struct file_handle *fd, void *buf, uint64_t loc, uint64_t count) {
|
|||
|
||||
void *freadall(struct file_handle *fd, uint32_t type) {
|
||||
if (fd->is_memfile) {
|
||||
memmap_alloc_range((uint64_t)(size_t)fd->fd, fd->size, type, false);
|
||||
memmap_alloc_range((uint64_t)(size_t)fd->fd, fd->size, type, false, true);
|
||||
return fd->fd;
|
||||
} else {
|
||||
void *ret = ext_mem_alloc_aligned_type(fd->size, 4096, type);
|
||||
|
|
|
@ -309,7 +309,7 @@ int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top, uin
|
|||
if (this_top > *top)
|
||||
*top = this_top;
|
||||
|
||||
memmap_alloc_range((size_t)load_vaddr, (size_t)phdr.p_memsz, alloc_type, true);
|
||||
memmap_alloc_range((size_t)load_vaddr, (size_t)phdr.p_memsz, alloc_type, true, true);
|
||||
|
||||
fread(fd, (void *)(uint32_t)load_vaddr, phdr.p_offset, phdr.p_filesz);
|
||||
|
||||
|
@ -362,7 +362,7 @@ int elf32_load(struct file_handle *fd, uint32_t *entry_point, uint32_t *top, uin
|
|||
if (this_top > *top)
|
||||
*top = this_top;
|
||||
|
||||
memmap_alloc_range((size_t)phdr.p_paddr, (size_t)phdr.p_memsz, alloc_type, true);
|
||||
memmap_alloc_range((size_t)phdr.p_paddr, (size_t)phdr.p_memsz, alloc_type, true, true);
|
||||
|
||||
fread(fd, (void *)phdr.p_paddr, phdr.p_offset, phdr.p_filesz);
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type)
|
|||
|
||||
// We now reserve the range we need.
|
||||
int64_t aligned_length = entry_top - alloc_base;
|
||||
memmap_alloc_range((uint64_t)alloc_base, (uint64_t)aligned_length, type, true);
|
||||
memmap_alloc_range((uint64_t)alloc_base, (uint64_t)aligned_length, type, true, true);
|
||||
|
||||
void *ret = (void *)(size_t)alloc_base;
|
||||
|
||||
|
@ -252,13 +252,17 @@ void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type)
|
|||
panic("High memory allocator: Out of memory");
|
||||
}
|
||||
|
||||
void memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only) {
|
||||
bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool do_panic) {
|
||||
uint64_t top = base + length;
|
||||
|
||||
if (base < 0x100000) {
|
||||
// We don't do allocations below 1 MiB
|
||||
panic("Attempt to allocate memory below 1 MiB (%X-%X)",
|
||||
base, base + length);
|
||||
if (do_panic) {
|
||||
// We don't do allocations below 1 MiB
|
||||
panic("Attempt to allocate memory below 1 MiB (%X-%X)",
|
||||
base, base + length);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < memmap_entries; i++) {
|
||||
|
@ -303,11 +307,14 @@ void memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free
|
|||
target->base = base;
|
||||
target->length = length;
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
panic("Out of memory");
|
||||
if (do_panic)
|
||||
panic("Out of memory");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
extern symbol bss_end;
|
||||
|
|
|
@ -20,7 +20,7 @@ extern size_t memmap_entries;
|
|||
void init_memmap(void);
|
||||
struct e820_entry_t *get_memmap(size_t *entries);
|
||||
void print_memmap(struct e820_entry_t *mm, size_t size);
|
||||
void memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only);
|
||||
bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool panic);
|
||||
|
||||
void *ext_mem_alloc(size_t count);
|
||||
void *ext_mem_alloc_type(size_t count, uint32_t type);
|
||||
|
|
|
@ -13,10 +13,11 @@
|
|||
#include <mm/mtrr.h>
|
||||
|
||||
#define KERNEL_LOAD_ADDR ((size_t)0x100000)
|
||||
#define INITRD_LOAD_ADDR ((size_t)0x1000000)
|
||||
#define KERNEL_HEAP_SIZE ((size_t)0x1000)
|
||||
|
||||
__attribute__((section(".realmode"), used))
|
||||
static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg) {
|
||||
static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg,
|
||||
uint16_t stack_pointer) {
|
||||
asm volatile (
|
||||
"cld\n\t"
|
||||
|
||||
|
@ -38,30 +39,22 @@ static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg) {
|
|||
"mov fs, bx\n\t"
|
||||
"mov gs, bx\n\t"
|
||||
"mov ss, bx\n\t"
|
||||
"mov esp, 0xfdf0\n\t"
|
||||
|
||||
"sti\n\t"
|
||||
"mov esp, edx\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)
|
||||
: "b" (real_mode_code_seg), "c" (kernel_entry_seg),
|
||||
"d" (stack_pointer)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
void linux_load(char *config, char *cmdline) {
|
||||
// The command line needs to be before address 0xa0000, we can use
|
||||
// a conv_mem_alloc() allocated buffer for that.
|
||||
// Allocate the relocation buffer for the command line early so it's allocated
|
||||
// before the real mode code.
|
||||
size_t cmdline_len = strlen(cmdline);
|
||||
char *cmdline_reloc = conv_mem_alloc(cmdline_len + 1);
|
||||
strcpy(cmdline_reloc, cmdline);
|
||||
|
||||
struct file_handle *kernel = ext_mem_alloc(sizeof(struct file_handle));
|
||||
|
||||
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
||||
|
@ -93,22 +86,37 @@ void linux_load(char *config, char *cmdline) {
|
|||
|
||||
print("linux: Real Mode code size: %x\n", real_mode_code_size);
|
||||
|
||||
void *real_mode_code = conv_mem_alloc_aligned(real_mode_code_size, 0x1000);
|
||||
size_t real_mode_and_heap_size =
|
||||
((real_mode_code_size & 0x0f) + 0x10) + KERNEL_HEAP_SIZE;
|
||||
|
||||
void *real_mode_code = conv_mem_alloc_aligned(real_mode_and_heap_size, 0x1000);
|
||||
|
||||
fread(kernel, real_mode_code, 0, real_mode_code_size);
|
||||
|
||||
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);
|
||||
|
||||
if (boot_protocol_ver < 0x203) {
|
||||
panic("Linux protocols < 2.03 are not supported");
|
||||
}
|
||||
|
||||
size_t heap_end_ptr = real_mode_and_heap_size - 0x200;
|
||||
*((uint16_t *)(real_mode_code + 0x224)) = (uint16_t)heap_end_ptr;
|
||||
|
||||
// The command line needs to be before address 0xa0000, we can use
|
||||
// a conv_mem_alloc() allocated buffer for that.
|
||||
// Allocate the relocation buffer for the command line early so it's allocated
|
||||
// before the real mode code.
|
||||
size_t cmdline_len = strlen(cmdline);
|
||||
char *cmdline_reloc = conv_mem_alloc(cmdline_len + 1);
|
||||
strcpy(cmdline_reloc, cmdline);
|
||||
|
||||
// vid_mode. 0xffff means "normal"
|
||||
*((uint16_t *)(real_mode_code + 0x1fa)) = 0xffff;
|
||||
|
||||
char *kernel_version;
|
||||
kernel_version = real_mode_code + *((uint16_t *)(real_mode_code + 0x20e)) + 0x200;
|
||||
|
||||
|
@ -122,7 +130,10 @@ void linux_load(char *config, char *cmdline) {
|
|||
uint8_t loadflags;
|
||||
loadflags = *((uint8_t *)(real_mode_code + 0x211));
|
||||
|
||||
loadflags |= (1 << 0); // kernel is loaded at 0x100000
|
||||
if (!(loadflags & (1 << 0))) {
|
||||
panic("Linux kernels that load at 0x10000 are not supported");
|
||||
}
|
||||
|
||||
loadflags &= ~(1 << 5); // print early messages
|
||||
loadflags |= (1 << 7); // can use heap
|
||||
|
||||
|
@ -132,10 +143,34 @@ void linux_load(char *config, char *cmdline) {
|
|||
|
||||
// load kernel
|
||||
print("Loading kernel...\n");
|
||||
memmap_alloc_range(KERNEL_LOAD_ADDR, kernel->size - real_mode_code_size, 0, true);
|
||||
memmap_alloc_range(KERNEL_LOAD_ADDR, kernel->size - real_mode_code_size, 0, true, true);
|
||||
fread(kernel, (void *)KERNEL_LOAD_ADDR, real_mode_code_size, kernel->size - real_mode_code_size);
|
||||
|
||||
size_t modules_mem_base = INITRD_LOAD_ADDR;
|
||||
uint32_t modules_mem_base = *((uint32_t *)(real_mode_code + 0x22c)) + 1;
|
||||
size_t size_of_all_modules = 0;
|
||||
|
||||
for (size_t i = 0; ; i++) {
|
||||
char *module_path = config_get_value(config, i, "MODULE_PATH");
|
||||
if (module_path == NULL)
|
||||
break;
|
||||
|
||||
struct file_handle module;
|
||||
if (!uri_open(&module, module_path))
|
||||
panic("Could not open `%s`", module_path);
|
||||
|
||||
size_of_all_modules += module.size;
|
||||
}
|
||||
|
||||
modules_mem_base -= size_of_all_modules;
|
||||
modules_mem_base = ALIGN_DOWN(modules_mem_base, 4096);
|
||||
|
||||
for (;;) {
|
||||
if (memmap_alloc_range(modules_mem_base, size_of_all_modules, 0, true, false))
|
||||
break;
|
||||
modules_mem_base -= 4096;
|
||||
}
|
||||
|
||||
size_t _modules_mem_base = modules_mem_base;
|
||||
for (size_t i = 0; ; i++) {
|
||||
char *module_path = config_get_value(config, i, "MODULE_PATH");
|
||||
if (module_path == NULL)
|
||||
|
@ -147,15 +182,14 @@ void linux_load(char *config, char *cmdline) {
|
|||
|
||||
print("Loading module `%s`...\n", module_path);
|
||||
|
||||
memmap_alloc_range(modules_mem_base, module.size, 0, true);
|
||||
fread(&module, (void *)modules_mem_base, 0, module.size);
|
||||
fread(&module, (void *)_modules_mem_base, 0, module.size);
|
||||
|
||||
modules_mem_base += 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);
|
||||
if (size_of_all_modules != 0) {
|
||||
*((uint32_t *)(real_mode_code + 0x218)) = (uint32_t)modules_mem_base;
|
||||
*((uint32_t *)(real_mode_code + 0x21c)) = (uint32_t)size_of_all_modules;
|
||||
}
|
||||
|
||||
uint16_t real_mode_code_seg = rm_seg(real_mode_code);
|
||||
|
@ -165,5 +199,5 @@ void linux_load(char *config, char *cmdline) {
|
|||
|
||||
mtrr_restore();
|
||||
|
||||
spinup(real_mode_code_seg, kernel_entry_seg);
|
||||
spinup(real_mode_code_seg, kernel_entry_seg, real_mode_and_heap_size);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue