mirror of
https://github.com/limine-bootloader/limine
synced 2024-12-24 14:56:49 +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:
|
*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.
|
* `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.
|
* `CMDLINE` - The command line string to be passed to the kernel. Can be omitted.
|
||||||
* `KERNEL_CMDLINE` - Alias of `CMDLINE`.
|
* `KERNEL_CMDLINE` - Alias of `CMDLINE`.
|
||||||
|
|
||||||
|
@ -164,22 +164,38 @@ void stage3_common(void) {
|
|||||||
|
|
||||||
char *proto = config_get_value(config, 0, "PROTOCOL");
|
char *proto = config_get_value(config, 0, "PROTOCOL");
|
||||||
if (proto == NULL) {
|
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")) {
|
if (!strcmp(proto, "stivale1") || !strcmp(proto, "stivale")) {
|
||||||
stivale_load(config, cmdline);
|
ret = stivale_load(config, cmdline);
|
||||||
} else if (!strcmp(proto, "stivale2")) {
|
} else if (!strcmp(proto, "stivale2")) {
|
||||||
stivale2_load(config, cmdline);
|
ret = stivale2_load(config, cmdline);
|
||||||
} else if (!strcmp(proto, "linux")) {
|
} 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")) {
|
} else if (!strcmp(proto, "chainload")) {
|
||||||
chainload(config);
|
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
|
// End of Linux code
|
||||||
|
|
||||||
void linux_load(char *config, char *cmdline) {
|
bool linux_load(char *config, char *cmdline) {
|
||||||
struct file_handle *kernel_file;
|
struct file_handle *kernel_file;
|
||||||
|
|
||||||
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
||||||
@ -360,7 +360,8 @@ void linux_load(char *config, char *cmdline) {
|
|||||||
|
|
||||||
// validate signature
|
// validate signature
|
||||||
if (signature != 0x53726448) {
|
if (signature != 0x53726448) {
|
||||||
panic("linux: Invalid Linux kernel signature");
|
fclose(kernel_file);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t setup_code_size = 0;
|
size_t setup_code_size = 0;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef __PROTOS__LINUX_H__
|
#ifndef __PROTOS__LINUX_H__
|
||||||
#define __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
|
#endif
|
||||||
|
@ -23,7 +23,7 @@ __attribute__((noreturn)) void multiboot1_spinup_32(
|
|||||||
|
|
||||||
struct multiboot1_info multiboot1_info = {0};
|
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;
|
struct file_handle *kernel_file;
|
||||||
|
|
||||||
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
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)
|
if (header.magic != MULTIBOOT1_HEADER_MAGIC) {
|
||||||
panic("multiboot1: Could not find header");
|
pmm_free(kernel_file, kernel_file_size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (header.magic + header.flags + header.checksum)
|
if (header.magic + header.flags + header.checksum)
|
||||||
panic("multiboot1: Header checksum is invalid");
|
panic("multiboot1: Header checksum is invalid");
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define MULTIBOOT1_HEADER_MAGIC 0x1BADB002
|
#define MULTIBOOT1_HEADER_MAGIC 0x1BADB002
|
||||||
|
|
||||||
@ -93,9 +94,6 @@ struct multiboot1_mmap_entry {
|
|||||||
uint32_t type;
|
uint32_t type;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
void multiboot1_load(char *config, char *cmdline);
|
bool multiboot1_load(char *config, char *cmdline);
|
||||||
|
|
||||||
__attribute__((noreturn)) void multiboot1_spinup(
|
|
||||||
uint32_t entry_point, uint32_t multiboot1_info);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,32 +19,6 @@
|
|||||||
#include <lib/blib.h>
|
#include <lib/blib.h>
|
||||||
#include <drivers/vga_textmode.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.
|
/// Returns the size required to store the multiboot2 info.
|
||||||
static size_t get_multiboot2_info_size(
|
static size_t get_multiboot2_info_size(
|
||||||
char *cmdline,
|
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); })
|
#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;
|
struct file_handle *kernel_file;
|
||||||
|
|
||||||
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
||||||
@ -96,7 +70,24 @@ void multiboot2_load(char *config, char* cmdline) {
|
|||||||
|
|
||||||
fclose(kernel_file);
|
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_address *addresstag = NULL;
|
||||||
struct multiboot_header_tag_framebuffer *fbtag = NULL;
|
struct multiboot_header_tag_framebuffer *fbtag = NULL;
|
||||||
|
@ -23,8 +23,9 @@
|
|||||||
#define __PROTOS__MULTIBOOT2_H__
|
#define __PROTOS__MULTIBOOT2_H__
|
||||||
|
|
||||||
#include <stdint.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. */
|
/* How many bytes from the start of the file we search for the header. */
|
||||||
#define MULTIBOOT_SEARCH 32768
|
#define MULTIBOOT_SEARCH 32768
|
||||||
|
@ -57,7 +57,7 @@ bool stivale_load_by_anchor(void **_anchor, const char *magic,
|
|||||||
|
|
||||||
struct stivale_struct stivale_struct = {0};
|
struct stivale_struct stivale_struct = {0};
|
||||||
|
|
||||||
void stivale_load(char *config, char *cmdline) {
|
bool stivale_load(char *config, char *cmdline) {
|
||||||
// BIOS or UEFI?
|
// BIOS or UEFI?
|
||||||
#if bios == 1
|
#if bios == 1
|
||||||
stivale_struct.flags |= (1 << 0);
|
stivale_struct.flags |= (1 << 0);
|
||||||
@ -72,8 +72,6 @@ void stivale_load(char *config, char *cmdline) {
|
|||||||
if (kernel_path == NULL)
|
if (kernel_path == NULL)
|
||||||
panic("stivale: KERNEL_PATH not specified");
|
panic("stivale: KERNEL_PATH not specified");
|
||||||
|
|
||||||
print("stivale: Loading kernel `%s`...\n", kernel_path);
|
|
||||||
|
|
||||||
if ((kernel_file = uri_open(kernel_path)) == NULL)
|
if ((kernel_file = uri_open(kernel_path)) == NULL)
|
||||||
panic("stivale: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
|
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) {
|
if (bits == -1) {
|
||||||
struct stivale_anchor *anchor;
|
struct stivale_anchor *anchor;
|
||||||
if (!stivale_load_by_anchor((void **)&anchor, "STIVALE1 ANCHOR", kernel, kernel_file_size)) {
|
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;
|
bits = anchor->bits;
|
||||||
@ -108,8 +106,25 @@ void stivale_load(char *config, char *cmdline) {
|
|||||||
sizeof(struct stivale_header));
|
sizeof(struct stivale_header));
|
||||||
|
|
||||||
loaded_by_anchor = true;
|
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;
|
int ret = 0;
|
||||||
switch (bits) {
|
switch (bits) {
|
||||||
case 64: {
|
case 64: {
|
||||||
@ -340,6 +355,10 @@ void stivale_load(char *config, char *cmdline) {
|
|||||||
stivale_spinup(bits, want_5lv, &pagemap,
|
stivale_spinup(bits, want_5lv, &pagemap,
|
||||||
entry_point, REPORTED_ADDR((uint64_t)(uintptr_t)&stivale_struct),
|
entry_point, REPORTED_ADDR((uint64_t)(uintptr_t)&stivale_struct),
|
||||||
stivale_hdr.stack, false);
|
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,
|
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 <mm/vmm.h>
|
||||||
#include <lib/elf.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,
|
bool stivale_load_by_anchor(void **_anchor, const char *magic,
|
||||||
uint8_t *file, uint64_t filesize);
|
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);
|
void stivale2_term_callback(uint64_t, uint64_t, uint64_t, uint64_t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void stivale2_load(char *config, char *cmdline) {
|
bool stivale2_load(char *config, char *cmdline) {
|
||||||
struct file_handle *kernel_file;
|
struct file_handle *kernel_file;
|
||||||
|
|
||||||
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
||||||
if (kernel_path == NULL)
|
if (kernel_path == NULL)
|
||||||
panic("stivale2: KERNEL_PATH not specified");
|
panic("stivale2: KERNEL_PATH not specified");
|
||||||
|
|
||||||
print("stivale2: Loading kernel `%s`...\n", kernel_path);
|
|
||||||
|
|
||||||
if ((kernel_file = uri_open(kernel_path)) == NULL)
|
if ((kernel_file = uri_open(kernel_path)) == NULL)
|
||||||
panic("stivale2: Failed to open kernel with path `%s`. Is the path correct?", kernel_path);
|
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) {
|
if (bits == -1) {
|
||||||
struct stivale2_anchor *anchor;
|
struct stivale2_anchor *anchor;
|
||||||
if (!stivale_load_by_anchor((void **)&anchor, "STIVALE2 ANCHOR", kernel, kernel_file_size)) {
|
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;
|
bits = anchor->bits;
|
||||||
@ -123,8 +121,25 @@ void stivale2_load(char *config, char *cmdline) {
|
|||||||
sizeof(struct stivale2_header));
|
sizeof(struct stivale2_header));
|
||||||
|
|
||||||
loaded_by_anchor = true;
|
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_pmrs = false;
|
||||||
bool want_fully_virtual = false;
|
bool want_fully_virtual = false;
|
||||||
|
|
||||||
@ -766,4 +781,8 @@ have_tm_tag:;
|
|||||||
stivale_spinup(bits, want_5lv, &pagemap, entry_point,
|
stivale_spinup(bits, want_5lv, &pagemap, entry_point,
|
||||||
REPORTED_ADDR((uint64_t)(uintptr_t)&stivale2_struct),
|
REPORTED_ADDR((uint64_t)(uintptr_t)&stivale2_struct),
|
||||||
stivale2_hdr.stack, want_pmrs);
|
stivale2_hdr.stack, want_pmrs);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
pmm_free(kernel, kernel_file_size);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef __PROTOS__STIVALE2_H__
|
#ifndef __PROTOS__STIVALE2_H__
|
||||||
#define __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
|
#endif
|
||||||
|
@ -13,7 +13,8 @@ BACKDROP_COLOUR=008080
|
|||||||
|
|
||||||
COMMENT=Test of the stivale2 boot protocol.
|
COMMENT=Test of the stivale2 boot protocol.
|
||||||
|
|
||||||
PROTOCOL=stivale2
|
# Let's use autodetection
|
||||||
|
#PROTOCOL=stivale2
|
||||||
RESOLUTION=800x600
|
RESOLUTION=800x600
|
||||||
KERNEL_PATH=boot:///boot/test.elf
|
KERNEL_PATH=boot:///boot/test.elf
|
||||||
KERNEL_CMDLINE=Woah! Another example!
|
KERNEL_CMDLINE=Woah! Another example!
|
||||||
|
Loading…
Reference in New Issue
Block a user