protos: Add chainload_next protocol. Closes #191

This commit is contained in:
mintsuki 2022-07-11 00:15:56 +02:00
parent 1ac1343059
commit 95272c5f1d
6 changed files with 115 additions and 4 deletions

View File

@ -97,7 +97,7 @@ Editor control options.
*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`, `limine`, `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: `multiboot2 -> multiboot1 -> limine -> linux -> failure`.
* `PROTOCOL` - The boot protocol that will be used to boot the kernel. Valid protocols are: `linux`, `limine`, `chainload`, `chainload_next`, `multiboot` or `multiboot1` and `multiboot2`. If the protocol is omitted, Limine will try to autodetect it, following this list of protocols, in this order: `multiboot2 -> multiboot1 -> limine -> linux -> failure`.
* `CMDLINE` - The command line string to be passed to the kernel. Can be omitted.
* `KERNEL_CMDLINE` - Alias of `CMDLINE`.
@ -110,6 +110,7 @@ Editor control options.
modules.
* `RESOLUTION` - The resolution to be used. This setting takes the form of `<width>x<height>x<bpp>`. If the resolution is not available, Limine will pick another one automatically. Omitting `<bpp>` will default to 32.
* `TEXTMODE` - If set to `yes`, prefer text mode. (BIOS only)
* Limine protocol:
* `KERNEL_PATH` - The URI path of the kernel.
* `MODULE_PATH` - The URI path to a module.
@ -122,22 +123,28 @@ Editor control options.
* `RESOLUTION` - The resolution to be used. This setting takes the form of `<width>x<height>x<bpp>`. If the resolution is not available, Limine will pick another one automatically. Omitting `<bpp>` will default to 32.
* `KASLR` - For relocatable kernels, if set to `no`, disable kernel address space layout randomisation. KASLR is enabled by default.
* Chainload protocol on BIOS:
* `DRIVE` - The 1-based BIOS drive to chainload, if omitted, assume boot drive.
* `PARTITION` - The 1-based BIOS partition to chainload, if omitted, chainload drive (MBR).
* Chainload protocol on UEFI:
* `IMAGE_PATH` - URI of the EFI application to chainload.
* `RESOLUTION` - The resolution to be used. This setting takes the form of `<width>x<height>x<bpp>`. If the resolution is not available, Limine will pick another one automatically. Omitting `<bpp>` will default to 32.
* chainload_next protocol:
This protocol does not specify any locally assignable key. Will boot the next bootable drive found in the system, if there is one.
* multiboot1 and multiboot2 protocols:
* `KERNEL_PATH` - The URI path of the kernel.
* `MODULE_PATH` - The URI path to a module.
* `MODULE_STRING` - A string to be passed to a module.
Note that one can define these 2 last variable multiple times to specify multiple
**Note:** One can define these 2 last variable multiple times to specify multiple
modules.
The entries will be matched in order. E.g.: the 1st module path entry will be matched
to the 1st module string entry that appear, and so on.
* `RESOLUTION` - The resolution to be used should the kernel request a graphical framebuffer. This setting takes the form of `<width>x<height>x<bpp>` and *overrides* any resolution requested by the kernel. If the resolution is not available, Limine will pick another one automatically. Omitting `<bpp>` will default to 32.
## URIs

View File

@ -17,6 +17,7 @@
#include <console.h>
#include <protos/linux.h>
#include <protos/chainload.h>
#include <protos/chainload_next.h>
#include <protos/multiboot1.h>
#include <protos/multiboot2.h>
#include <protos/limine.h>
@ -929,6 +930,8 @@ noreturn void boot(char *config) {
multiboot1_load(config, cmdline);
} else if (!strcmp(proto, "multiboot2")) {
multiboot2_load(config, cmdline);
} else if (!strcmp(proto, "chainload_next")) {
chainload_next(config);
} else if (!strcmp(proto, "chainload")) {
chainload(config);
}

View File

@ -99,19 +99,29 @@ void chainload(char *config) {
struct volume *p = volume_get_by_coord(false, drive, part);
bios_chainload_volume(p);
panic(true, "chainload: Volume is not bootable");
}
void bios_chainload_volume(struct volume *p) {
size_t rows, cols;
init_vga_textmode(&rows, &cols, false);
volume_read(p, (void *)0x7c00, 0, 512);
volatile uint16_t *boot_sig = (volatile uint16_t *)0x7dfe;
if (*boot_sig != 0xaa55) {
return;
}
spinup(p->drive);
}
#elif uefi == 1
void chainload(char *config) {
EFI_STATUS status;
char *image_path = config_get_value(config, 0, "IMAGE_PATH");
if (image_path == NULL)
panic(true, "chainload: IMAGE_PATH not specified");
@ -120,6 +130,12 @@ void chainload(char *config) {
if ((image = uri_open(image_path)) == NULL)
panic(true, "chainload: Failed to open image with path `%s`. Is the path correct?", image_path);
efi_chainload_file(image);
}
void efi_chainload_file(struct file_handle *image) {
EFI_STATUS status;
EFI_HANDLE efi_part_handle = image->efi_part_handle;
void *_ptr = freadall(image, MEMMAP_RESERVED);

View File

@ -3,4 +3,14 @@
void chainload(char *config);
#if uefi == 1
#include <fs/file.h>
void efi_chainload_file(struct file_handle *image);
#endif
#if bios == 1
#include <lib/part.h>
void bios_chainload_volume(struct volume *v);
#endif
#endif

View File

@ -0,0 +1,69 @@
#include <stddef.h>
#include <stdint.h>
#include <protos/chainload_next.h>
#include <protos/chainload.h>
#include <lib/blib.h>
#include <lib/print.h>
#include <lib/part.h>
#if bios == 1
static void try(struct volume *v) {
bios_chainload_volume(v);
}
#endif
#if uefi == 1
static void try(struct volume *v) {
for (int i = 0; i < v->max_partition + 1; i++) {
struct file_handle *image;
if ((image = fopen(v, "/EFI/BOOT/BOOTX64.EFI")) == NULL
&& (image = fopen(v, "/efi/boot/bootx64.efi")) == NULL
&& (image = fopen(v, "/EFI/BOOT/BOOTx64.efi")) == NULL) {
continue;
}
uefi_chainload_file(image);
}
}
#endif
void chainload_next(char *config) {
(void)config;
bool wrap = false;
for (int i = boot_volume->is_optical ? 0 : (wrap = true, boot_volume->index + 1);
boot_volume->is_optical ? true : i != boot_volume->index; i++) {
struct volume *v = volume_get_by_coord(false, i, 0);
if (v == NULL) {
if (wrap) {
i = 0;
continue;
} else {
break;
}
}
try(v);
}
wrap = false;
for (int i = boot_volume->is_optical ? (wrap = true, boot_volume->index + 1) : 0;
boot_volume->is_optical ? i != boot_volume->index : true; i++) {
struct volume *v = volume_get_by_coord(true, i, 0);
if (v == NULL) {
if (wrap) {
i = 0;
continue;
} else {
break;
}
}
try(v);
}
panic(true, "chainload_next: No other bootable device");
__builtin_unreachable();
}

View File

@ -0,0 +1,6 @@
#ifndef __PROTOS__CHAINLOAD_NEXT_H__
#define __PROTOS__CHAINLOAD_NEXT_H__
void chainload_next(char *config);
#endif