mirror of
https://github.com/limine-bootloader/limine
synced 2024-12-23 22:36:48 +03:00
protos: Implement autodetection
This commit is contained in:
parent
ad3e17569c
commit
6bcbfe9b48
@ -88,7 +88,7 @@ Some keys take *URIs* as values; these are described in the next section.
|
||||
|
||||
*Locally assignable (non protocol specific)* keys are:
|
||||
* `COMMENT` - An optional comment string that will be displayed by the bootloader on the menu when an entry is selected.
|
||||
* `PROTOCOL` - The boot protocol that will be used to boot the kernel. Valid protocols are: `linux`, `stivale`, `stivale2`, `chainload`, `multiboot` or `multiboot1` and `multiboot2`.
|
||||
* `PROTOCOL` - The boot protocol that will be used to boot the kernel. Valid protocols are: `linux`, `stivale`, `stivale2`, `chainload`, `multiboot` or `multiboot1` and `multiboot2`. If the protocol is omitted, Limine will try to autodetect it, following this list of protocols, in this order: `stivale2 -> stivale1 -> multiboot2 -> multiboot1 -> linux -> failure`.
|
||||
* `CMDLINE` - The command line string to be passed to the kernel. Can be omitted.
|
||||
* `KERNEL_CMDLINE` - Alias of `CMDLINE`.
|
||||
|
||||
|
@ -164,22 +164,38 @@ void stage3_common(void) {
|
||||
|
||||
char *proto = config_get_value(config, 0, "PROTOCOL");
|
||||
if (proto == NULL) {
|
||||
panic("PROTOCOL not specified");
|
||||
printv("PROTOCOL not specified, using autodetection...\n");
|
||||
autodetect:
|
||||
stivale2_load(config, cmdline);
|
||||
stivale_load(config, cmdline);
|
||||
multiboot2_load(config, cmdline);
|
||||
multiboot1_load(config, cmdline);
|
||||
linux_load(config, cmdline);
|
||||
panic("Kernel protocol autodetection failed");
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
|
||||
if (!strcmp(proto, "stivale1") || !strcmp(proto, "stivale")) {
|
||||
stivale_load(config, cmdline);
|
||||
ret = stivale_load(config, cmdline);
|
||||
} else if (!strcmp(proto, "stivale2")) {
|
||||
stivale2_load(config, cmdline);
|
||||
ret = stivale2_load(config, cmdline);
|
||||
} else if (!strcmp(proto, "linux")) {
|
||||
linux_load(config, cmdline);
|
||||
ret = linux_load(config, cmdline);
|
||||
} else if (!strcmp(proto, "multiboot1") || !strcmp(proto, "multiboot")) {
|
||||
ret = multiboot1_load(config, cmdline);
|
||||
} else if (!strcmp(proto, "multiboot2")) {
|
||||
ret = multiboot2_load(config, cmdline);
|
||||
} else if (!strcmp(proto, "chainload")) {
|
||||
chainload(config);
|
||||
} else if (!strcmp(proto, "multiboot1") || !strcmp(proto, "multiboot")) {
|
||||
multiboot1_load(config, cmdline);
|
||||
} else if (!strcmp(proto, "multiboot2")) {
|
||||
multiboot2_load(config, cmdline);
|
||||
}
|
||||
|
||||
panic("Invalid protocol specified");
|
||||
if (ret) {
|
||||
print("WARNING: Unsupported protocol specified: %s.\n", proto);
|
||||
} else {
|
||||
print("WARNING: Incorrect protocol specified for kernel.\n");
|
||||
}
|
||||
|
||||
print(" Attempting autodetection.\n");
|
||||
goto autodetect;
|
||||
}
|
||||
|
@ -345,7 +345,7 @@ struct boot_params {
|
||||
|
||||
// End of Linux code
|
||||
|
||||
void linux_load(char *config, char *cmdline) {
|
||||
bool linux_load(char *config, char *cmdline) {
|
||||
struct file_handle *kernel_file;
|
||||
|
||||
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
||||
@ -360,7 +360,8 @@ void linux_load(char *config, char *cmdline) {
|
||||
|
||||
// validate signature
|
||||
if (signature != 0x53726448) {
|
||||
panic("linux: Invalid Linux kernel signature");
|
||||
fclose(kernel_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t setup_code_size = 0;
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef __PROTOS__LINUX_H__
|
||||
#define __PROTOS__LINUX_H__
|
||||
|
||||
void linux_load(char *config, char *cmdline);
|
||||
#include <stdbool.h>
|
||||
|
||||
bool linux_load(char *config, char *cmdline);
|
||||
|
||||
#endif
|
||||
|
@ -23,7 +23,7 @@ __attribute__((noreturn)) void multiboot1_spinup_32(
|
||||
|
||||
struct multiboot1_info multiboot1_info = {0};
|
||||
|
||||
void multiboot1_load(char *config, char *cmdline) {
|
||||
bool multiboot1_load(char *config, char *cmdline) {
|
||||
struct file_handle *kernel_file;
|
||||
|
||||
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
||||
@ -54,8 +54,10 @@ void multiboot1_load(char *config, char *cmdline) {
|
||||
}
|
||||
}
|
||||
|
||||
if (header.magic != MULTIBOOT1_HEADER_MAGIC)
|
||||
panic("multiboot1: Could not find header");
|
||||
if (header.magic != MULTIBOOT1_HEADER_MAGIC) {
|
||||
pmm_free(kernel_file, kernel_file_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.magic + header.flags + header.checksum)
|
||||
panic("multiboot1: Header checksum is invalid");
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MULTIBOOT1_HEADER_MAGIC 0x1BADB002
|
||||
|
||||
@ -93,9 +94,6 @@ struct multiboot1_mmap_entry {
|
||||
uint32_t type;
|
||||
} __attribute__((packed));
|
||||
|
||||
void multiboot1_load(char *config, char *cmdline);
|
||||
|
||||
__attribute__((noreturn)) void multiboot1_spinup(
|
||||
uint32_t entry_point, uint32_t multiboot1_info);
|
||||
bool multiboot1_load(char *config, char *cmdline);
|
||||
|
||||
#endif
|
||||
|
@ -19,32 +19,6 @@
|
||||
#include <lib/blib.h>
|
||||
#include <drivers/vga_textmode.h>
|
||||
|
||||
static struct multiboot_header *load_multiboot2_header(uint8_t *kernel) {
|
||||
struct multiboot_header *ptr = NULL;
|
||||
|
||||
size_t header_offset;
|
||||
|
||||
for (header_offset = 0; header_offset < MULTIBOOT_SEARCH; header_offset += MULTIBOOT_HEADER_ALIGN) {
|
||||
uint32_t v;
|
||||
memcpy(&v, kernel + header_offset, 4);
|
||||
|
||||
if (v == MULTIBOOT2_HEADER_MAGIC) {
|
||||
ptr = (void *)(kernel + header_offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr->magic != MULTIBOOT2_HEADER_MAGIC) {
|
||||
panic("multiboot2: Could not find header");
|
||||
}
|
||||
|
||||
if (ptr->magic + ptr->architecture + ptr->checksum + ptr->header_length) {
|
||||
panic("mutliboot2: Header checksum is invalid");
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// Returns the size required to store the multiboot2 info.
|
||||
static size_t get_multiboot2_info_size(
|
||||
char *cmdline,
|
||||
@ -78,7 +52,7 @@ static size_t get_multiboot2_info_size(
|
||||
|
||||
#define append_tag(P, TAG) ({ (P) += ALIGN_UP((TAG)->size, MULTIBOOT_TAG_ALIGN); })
|
||||
|
||||
void multiboot2_load(char *config, char* cmdline) {
|
||||
bool multiboot2_load(char *config, char* cmdline) {
|
||||
struct file_handle *kernel_file;
|
||||
|
||||
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
||||
@ -96,7 +70,24 @@ void multiboot2_load(char *config, char* cmdline) {
|
||||
|
||||
fclose(kernel_file);
|
||||
|
||||
struct multiboot_header *header = load_multiboot2_header(kernel);
|
||||
struct multiboot_header *header;
|
||||
|
||||
for (size_t header_offset = 0; header_offset < MULTIBOOT_SEARCH; header_offset += MULTIBOOT_HEADER_ALIGN) {
|
||||
header = (void *)(kernel + header_offset);
|
||||
|
||||
if (header->magic == MULTIBOOT2_HEADER_MAGIC) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (header->magic != MULTIBOOT2_HEADER_MAGIC) {
|
||||
pmm_free(kernel_file, kernel_file_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header->magic + header->architecture + header->checksum + header->header_length) {
|
||||
panic("multiboot2: Header checksum is invalid");
|
||||
}
|
||||
|
||||
struct multiboot_header_tag_address *addresstag = NULL;
|
||||
struct multiboot_header_tag_framebuffer *fbtag = NULL;
|
||||
|
@ -23,8 +23,9 @@
|
||||
#define __PROTOS__MULTIBOOT2_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void multiboot2_load(char *config, char* cmdline);
|
||||
bool multiboot2_load(char *config, char* cmdline);
|
||||
|
||||
/* How many bytes from the start of the file we search for the header. */
|
||||
#define MULTIBOOT_SEARCH 32768
|
||||
|
@ -57,7 +57,7 @@ bool stivale_load_by_anchor(void **_anchor, const char *magic,
|
||||
|
||||
struct stivale_struct stivale_struct = {0};
|
||||
|
||||
void stivale_load(char *config, char *cmdline) {
|
||||
bool stivale_load(char *config, char *cmdline) {
|
||||
// BIOS or UEFI?
|
||||
#if bios == 1
|
||||
stivale_struct.flags |= (1 << 0);
|
||||
@ -72,8 +72,6 @@ void stivale_load(char *config, char *cmdline) {
|
||||
if (kernel_path == NULL)
|
||||
panic("stivale: KERNEL_PATH not specified");
|
||||
|
||||
print("stivale: Loading kernel `%s`...\n", kernel_path);
|
||||
|
||||
if ((kernel_file = uri_open(kernel_path)) == NULL)
|
||||
panic("stivale: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
|
||||
|
||||
@ -99,7 +97,7 @@ void stivale_load(char *config, char *cmdline) {
|
||||
if (bits == -1) {
|
||||
struct stivale_anchor *anchor;
|
||||
if (!stivale_load_by_anchor((void **)&anchor, "STIVALE1 ANCHOR", kernel, kernel_file_size)) {
|
||||
panic("stivale: Not a valid ELF or anchored file.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bits = anchor->bits;
|
||||
@ -108,8 +106,25 @@ void stivale_load(char *config, char *cmdline) {
|
||||
sizeof(struct stivale_header));
|
||||
|
||||
loaded_by_anchor = true;
|
||||
} else {
|
||||
switch (bits) {
|
||||
case 64:
|
||||
if (elf64_load_section(kernel, &stivale_hdr, ".stivalehdr",
|
||||
sizeof(struct stivale_header), slide)) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
if (elf32_load_section(kernel, &stivale_hdr, ".stivalehdr",
|
||||
sizeof(struct stivale_header))) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
print("stivale: Loading kernel `%s`...\n", kernel_path);
|
||||
|
||||
int ret = 0;
|
||||
switch (bits) {
|
||||
case 64: {
|
||||
@ -340,6 +355,10 @@ void stivale_load(char *config, char *cmdline) {
|
||||
stivale_spinup(bits, want_5lv, &pagemap,
|
||||
entry_point, REPORTED_ADDR((uint64_t)(uintptr_t)&stivale_struct),
|
||||
stivale_hdr.stack, false);
|
||||
|
||||
fail:
|
||||
pmm_free(kernel, kernel_file_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
pagemap_t stivale_build_pagemap(bool level5pg, bool unmap_null, struct elf_range *ranges, size_t ranges_count,
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <mm/vmm.h>
|
||||
#include <lib/elf.h>
|
||||
|
||||
void stivale_load(char *config, char *cmdline);
|
||||
bool stivale_load(char *config, char *cmdline);
|
||||
|
||||
bool stivale_load_by_anchor(void **_anchor, const char *magic,
|
||||
uint8_t *file, uint64_t filesize);
|
||||
|
@ -75,15 +75,13 @@ uint64_t stivale2_term_callback_ptr = 0;
|
||||
void stivale2_term_callback(uint64_t, uint64_t, uint64_t, uint64_t);
|
||||
#endif
|
||||
|
||||
void stivale2_load(char *config, char *cmdline) {
|
||||
bool stivale2_load(char *config, char *cmdline) {
|
||||
struct file_handle *kernel_file;
|
||||
|
||||
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
||||
if (kernel_path == NULL)
|
||||
panic("stivale2: KERNEL_PATH not specified");
|
||||
|
||||
print("stivale2: Loading kernel `%s`...\n", kernel_path);
|
||||
|
||||
if ((kernel_file = uri_open(kernel_path)) == NULL)
|
||||
panic("stivale2: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
|
||||
|
||||
@ -114,7 +112,7 @@ void stivale2_load(char *config, char *cmdline) {
|
||||
if (bits == -1) {
|
||||
struct stivale2_anchor *anchor;
|
||||
if (!stivale_load_by_anchor((void **)&anchor, "STIVALE2 ANCHOR", kernel, kernel_file_size)) {
|
||||
panic("stivale2: Not a valid ELF or anchored file.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bits = anchor->bits;
|
||||
@ -123,8 +121,25 @@ void stivale2_load(char *config, char *cmdline) {
|
||||
sizeof(struct stivale2_header));
|
||||
|
||||
loaded_by_anchor = true;
|
||||
} else {
|
||||
switch (bits) {
|
||||
case 64:
|
||||
if (elf64_load_section(kernel, &stivale2_hdr, ".stivale2hdr",
|
||||
sizeof(struct stivale2_header), slide)) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
if (elf32_load_section(kernel, &stivale2_hdr, ".stivale2hdr",
|
||||
sizeof(struct stivale2_header))) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
print("stivale2: Loading kernel `%s`...\n", kernel_path);
|
||||
|
||||
bool want_pmrs = false;
|
||||
bool want_fully_virtual = false;
|
||||
|
||||
@ -766,4 +781,8 @@ have_tm_tag:;
|
||||
stivale_spinup(bits, want_5lv, &pagemap, entry_point,
|
||||
REPORTED_ADDR((uint64_t)(uintptr_t)&stivale2_struct),
|
||||
stivale2_hdr.stack, want_pmrs);
|
||||
|
||||
fail:
|
||||
pmm_free(kernel, kernel_file_size);
|
||||
return false;
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef __PROTOS__STIVALE2_H__
|
||||
#define __PROTOS__STIVALE2_H__
|
||||
|
||||
void stivale2_load(char *config, char *cmdline);
|
||||
#include <stdbool.h>
|
||||
|
||||
bool stivale2_load(char *config, char *cmdline);
|
||||
|
||||
#endif
|
||||
|
@ -13,7 +13,8 @@ BACKDROP_COLOUR=008080
|
||||
|
||||
COMMENT=Test of the stivale2 boot protocol.
|
||||
|
||||
PROTOCOL=stivale2
|
||||
# Let's use autodetection
|
||||
#PROTOCOL=stivale2
|
||||
RESOLUTION=800x600
|
||||
KERNEL_PATH=boot:///boot/test.elf
|
||||
KERNEL_CMDLINE=Woah! Another example!
|
||||
|
Loading…
Reference in New Issue
Block a user