bootboot: Remove bootboot support from Limine

I added bootboot support to Limine because it was sent as a pull request by a
friend. The following does not in any way place any blame on said friend.

After having had to fix numerous bugs related to misunderstandings about the
pretentious BOOTBOOT specification I've come to the conclusion that BOOTBOOT
absolutely doesn't belong in Limine.

If you want to boot a BOOTBOOT kernel with Limine just chainload the OG BOOTBOOT
and don't pollute the source tree of Limine with having to support such a brain
dead protocol.

Legit, I didn't really read the BOOTBOOT spec prior to today and just winged
the fixes to the BOOTBOOT proto code based on common sense, but it turns out that
BOOTBOOT adheres to no common sense.

Use stivale(2).
This commit is contained in:
mintsuki 2021-11-10 14:15:14 +01:00
parent 636164a8ae
commit 202eac3d3a
14 changed files with 1 additions and 797 deletions

View File

@ -99,9 +99,6 @@ Some keys take *URIs* as values; these are described in the next section.
Note that one can define this last variable multiple times to specify multiple
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.
* Bootboot protocol:
* `INITRD_PATH` - The URI path to the ramdisk/initrd or kernel.
* `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.
* stivale and stivale2 protocols:
* `KERNEL_PATH` - The URI path of the kernel.
* `MODULE_PATH` - The URI path to a module.

View File

@ -18,7 +18,6 @@ Like Limine and want to support it? Donate Bitcoin to
### Supported boot protocols
* stivale and stivale2 (Limine's native boot protocols, see [their specifications](https://github.com/stivale/stivale) for details)
* Bootboot (Another hobby OS boot protocol designed for microkernels, see the [specification](https://gitlab.com/bztsrc/bootboot) for details)
* Linux
* Multiboot 1
* Multiboot 2

View File

@ -14,7 +14,6 @@
#include <mm/pmm.h>
#include <protos/stivale.h>
#include <protos/stivale2.h>
#include <protos/bootboot.h>
#include <protos/linux.h>
#include <protos/chainload.h>
#include <protos/multiboot1.h>
@ -175,8 +174,6 @@ void stage3_common(void) {
multiboot1_load(config, cmdline);
} else if (!strcmp(proto, "multiboot2")) {
multiboot2_load(config, cmdline);
} else if (!strcmp(proto, "bootboot")) {
bootboot_load(config);
}
panic("Invalid protocol specified");

View File

@ -46,28 +46,6 @@ uint64_t time(void) {
uint8_t hour = bcd_to_int((r.ecx & 0xff00) >> 8);
return get_unix_epoch(second, minute, hour, day, month, year);
}
void bootboot_time(
uint32_t* day, uint32_t* month, uint32_t* year,
uint32_t* second, uint32_t* minute, uint32_t* hour) {
struct rm_regs r = {0};
r.eax = 0x0400;
rm_int(0x1a, &r, &r);
*day = bcd_to_int( r.edx & 0x00ff);
*month = bcd_to_int((r.edx & 0xff00) >> 8);
*year = bcd_to_int( r.ecx & 0x00ff) +
/* century */ bcd_to_int((r.ecx & 0xff00) >> 8) * 100;
r.eax = 0x0200;
rm_int(0x1a, &r, &r);
*second = bcd_to_int((r.edx & 0xff00) >> 8);
*minute = bcd_to_int( r.ecx & 0x00ff);
*hour = bcd_to_int((r.ecx & 0xff00) >> 8);
}
#endif
@ -79,13 +57,4 @@ uint64_t time(void) {
return get_unix_epoch(time.Second, time.Minute, time.Hour,
time.Day, time.Month, time.Year);
}
void bootboot_time(
uint32_t* day, uint32_t* month, uint32_t* year,
uint32_t* second, uint32_t* minute, uint32_t* hour) {
EFI_TIME time;
gRT->GetTime(&time, NULL);
*day = time.Day; *month = time.Month; *year = time.Year;
*second = time.Second; *minute = time.Minute; *hour = time.Hour;
}
#endif

View File

@ -4,7 +4,5 @@
#include <stdint.h>
uint64_t time(void);
void bootboot_time(
uint32_t* day, uint32_t* month, uint32_t* year,
uint32_t* second, uint32_t* minute, uint32_t* hour);
#endif

View File

@ -75,7 +75,6 @@ static size_t get_prev_line(size_t index, const char *buffer) {
}
static const char *VALID_KEYS[] = {
"BOOTBOOT_ENV",
"TIMEOUT",
"DEFAULT_ENTRY",
"GRAPHICS",

View File

@ -1,89 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <mm/vmm.h>
__attribute__((noreturn)) void bootboot_spinup_32(
uint32_t pagemap_top_lv,
uint32_t entry_point_lo, uint32_t entry_point_hi,
uint32_t stack_lo, uint32_t stack_hi) {
uint64_t casted_to_64[] = {
(uint64_t)entry_point_lo | ((uint64_t)entry_point_hi << 32),
(uint64_t)stack_lo | ((uint64_t)stack_hi << 32)
};
asm volatile (
"cld\n\t"
"movl %%eax, %%cr3\n\t"
"movl %%cr4, %%eax\n\t"
"btsl $5, %%eax\n\t"
"movl %%eax, %%cr4\n\t"
"movl $0xc0000080, %%ecx\n\t"
"rdmsr\n\t"
"btsl $8, %%eax\n\t"
"wrmsr\n\t"
"movl %%cr0, %%eax\n\t"
"btsl $31, %%eax\n\t"
"movl %%eax, %%cr0\n\t"
"call 1f\n\t"
"1: popl %%eax\n\t"
"addl $8, %%eax\n\t"
"pushl $0x28\n\t"
"pushl %%eax\n\t"
"lret\n\t"
".code64\n\t"
"movl $0x30, %%eax\n\t"
"movl %%eax, %%ds\n\t"
"movl %%eax, %%es\n\t"
"movl %%eax, %%fs\n\t"
"movl %%eax, %%gs\n\t"
"movl %%eax, %%ss\n\t"
// Since we don't really know what is now present in the upper
// 32 bits of the 64 bit registers, clear up the upper bits
// of the register that points to the 64-bit casted value array.
"movl %%esi, %%esi\n\t"
// Move in 64-bit values
"movq 0x00(%%rsi), %%rbx\n\t"
"movq 0x08(%%rsi), %%rsi\n\t"
// Let's pretend we push a return address
"testq %%rsi, %%rsi\n\t"
"jz 1f\n\t"
"subq $8, %%rsi\n\t"
"movq $0, (%%rsi)\n\t"
"1:\n\t"
"pushq $0x30\n\t"
"pushq %%rsi\n\t"
"pushfq\n\t"
"pushq $0x28\n\t"
"pushq %%rbx\n\t"
"xorl %%eax, %%eax\n\t"
"xorl %%ebx, %%ebx\n\t"
"xorl %%ecx, %%ecx\n\t"
"xorl %%edx, %%edx\n\t"
"xorl %%edi, %%edi\n\t"
"xorl %%esi, %%esi\n\t"
"xorl %%ebp, %%ebp\n\t"
"xorq %%r8, %%r8\n\t"
"xorq %%r9, %%r9\n\t"
"xorq %%r10, %%r10\n\t"
"xorq %%r11, %%r11\n\t"
"xorq %%r12, %%r12\n\t"
"xorq %%r13, %%r13\n\t"
"xorq %%r14, %%r14\n\t"
"xorq %%r15, %%r15\n\t"
"iretq\n\t"
".code32\n\t"
:
: "a" (pagemap_top_lv), "S" (casted_to_64)
: "memory"
);
__builtin_unreachable();
}

View File

@ -1,339 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <protos/bootboot.h>
#include <protos/bootboot/initrd.h>
#include <lib/libc.h>
#include <lib/elf.h>
#include <lib/blib.h>
#include <lib/acpi.h>
#include <lib/config.h>
#include <lib/time.h>
#include <lib/print.h>
#include <lib/real.h>
#include <lib/uri.h>
#include <lib/fb.h>
#include <lib/term.h>
#include <sys/pic.h>
#include <sys/cpu.h>
#include <sys/gdt.h>
#include <sys/idt.h>
#include <sys/lapic.h>
#include <sys/smp.h>
#include <fs/file.h>
#include <mm/vmm.h>
#include <mm/pmm.h>
#include <drivers/vga_textmode.h>
#define _emitenv(e) do { \
if (envoff >= 4095) { \
panic("bootboot: too much env data!"); \
} \
env[envoff++] = e; \
} while (false);
#define KOFFSET(type, off) (type)&kernel[(off)]
#define ESECTION(idx) KOFFSET(struct elf64_shdr*, elf_header->shoff + elf_header->shdr_size * (idx))
__attribute__((noreturn)) void bootboot_spinup_32(
uint32_t pagemap_top_lv,
uint32_t entry_point_lo, uint32_t entry_point_hi,
uint32_t stack_lo, uint32_t stack_hi);
void bootboot_load(char *config) {
uint64_t fb_vaddr = BOOTBOOT_FB;
uint64_t struct_vaddr = BOOTBOOT_INFO;
uint64_t env_vaddr = BOOTBOOT_ENV;
uint64_t init_stack_size = (uint64_t)-1;
char *initrd = config_get_value(config, 0, "INITRD_PATH");
if (initrd == NULL) {
panic("bootboot: no INITRD_PATH specified!");
}
/// Initrd loading ///
struct initrd_file bootboot_initrd_file;
uint64_t initrd_start = 0, initrd_size = 0;
struct file_handle *initrd_file;
if ((initrd_file = uri_open(initrd)) == NULL) {
panic("bootboot: Failed to open initrd with path `%s`. Is the path correct?", initrd);
}
uint8_t *initrd_data = freadall(initrd_file, MEMMAP_KERNEL_AND_MODULES);
initrd_size = initrd_file->size;
initrd_start = (uint64_t)(size_t)initrd_data;
fclose(initrd_file);
bootboot_initrd_file.size = initrd_size;
bootboot_initrd_file.data = initrd_data;
/// Load bootboot config ///
uint8_t *env = ext_mem_alloc_type_aligned(4096, MEMMAP_BOOTLOADER_RECLAIMABLE, 4096);
uint64_t envoff = 0;
do {
struct initrd_file conf = initrd_open_auto(bootboot_initrd_file, "sys/config");
if (!conf.data) {
break;
}
uint8_t state = 0;
uint8_t ipeq = 0;
// state 0: kv
// state 1: precomment
// state 2: comment
for (uint64_t inoff = 0; inoff < conf.size; inoff++) {
if (conf.data[inoff] == ' ' && !(state == 0 && ipeq == 2)) continue;
if (conf.data[inoff] != ' ' && state == 0 && ipeq == 1) { ipeq = 2; }
if (conf.data[inoff] == '/' && state == 1) { state = 2; continue; }
if (conf.data[inoff] == '\n' && state == 2) { state = 0; continue; }
if (conf.data[inoff] == '\n') { ipeq = 0; }
if (conf.data[inoff] == '/' && state == 0) { state = 1; continue; }
if (state == 1) { state = 0; _emitenv('/'); _emitenv(conf.data[inoff]); continue; }
if (state == 2) continue;
if (state == 0 && conf.data[inoff] == '=') ipeq = 1;
_emitenv(conf.data[inoff]);
}
} while (false);
_emitenv(0);
printv("env: ---------\n%s\n--------\n", env);
/// Kernel loading code ///
uint8_t *kernel;
if (initrd_format(bootboot_initrd_file) != INITRD_FORMAT_UNKNOWN) {
const char *corefile = config_get_value((char *)env, 0, "kernel");
if (corefile == NULL) {
corefile = "sys/core";
}
struct initrd_file file = initrd_open_auto(bootboot_initrd_file, corefile);
if (!file.size) {
panic("bootboot: cannot find the kernel!");
}
kernel = file.data;
} else {
struct initrd_file file = bruteforce_kernel(bootboot_initrd_file);
if (!file.size) {
panic("bootboot: cannot find the kernel!");
}
kernel = file.data;
}
/// Memory mappings ///
pagemap_t pmap = new_pagemap(4);
/// Load kernel ///
uint64_t entry, top, physbase, virtbase;
{
if (elf64_load(
kernel, &entry, &top, NULL, MEMMAP_KERNEL_AND_MODULES,
false, false, NULL, NULL, true, &physbase, &virtbase)) {
panic("bootboot: elf64 load failed");
}
for (uint64_t mapvirt = virtbase, mapphys = physbase; mapphys < top; mapvirt += 0x1000, mapphys += 0x1000) {
map_page(pmap, mapvirt, mapphys, VMM_FLAG_PRESENT | VMM_FLAG_WRITE, false);
}
}
/// Bootboot symbols ///
struct elf64_hdr *elf_header = (struct elf64_hdr *)kernel;
struct elf64_shdr *section_header_strings_section = ESECTION(elf_header->shstrndx);
char *section_header_strings = KOFFSET(char *, section_header_strings_section->sh_offset);
struct elf64_shdr *symbol_table = NULL;
struct elf64_shdr *string_table = NULL;
for (uint32_t i = 0; i < elf_header->sh_num; i++){
struct elf64_shdr *section_header = ESECTION(i);
char *secname = &section_header_strings[section_header->sh_name];
if (!strcmp(secname, ".symtab")) {
symbol_table = section_header;
}
if (!strcmp(secname, ".strtab")) {
string_table = section_header;
}
}
if (!symbol_table || !string_table) {
print("bootboot: WARNING: no symbol/string tables in the ELF!\n");
} else {
struct elf64_sym *symbols = KOFFSET(struct elf64_sym *, symbol_table->sh_offset);
char *symbol_strings = KOFFSET(char *, string_table->sh_offset);
for (uint32_t i = 0, symcount = symbol_table->sh_size / sizeof(struct elf64_sym); i < symcount; i++) {
char *elf_sym = &symbol_strings[symbols[i].st_name];
uint64_t symaddr = symbols[i].st_value;
if (!strcmp(elf_sym, "bootboot")) {
struct_vaddr = symaddr;
}
if (!strcmp(elf_sym, "environment")) {
env_vaddr = symaddr;
}
if (!strcmp(elf_sym, "fb")) {
fb_vaddr = symaddr;
}
if (!strcmp(elf_sym, "initstack")) {
init_stack_size = symaddr;
}
}
}
if (init_stack_size == (uint64_t)-1) {
print("bootboot: WARNING: no init stack size entered, assuming 1024\n");
print("1024 is really small, specify more using initstack=size ini initrd;\n");
init_stack_size = 1024;
}
printv("bootboot: mapping struct to %X\n", struct_vaddr);
printv("bootboot: mapping environemnt to %X\n", env_vaddr);
printv("bootboot: mapping framebuffer to %X\n", fb_vaddr);
printv("bootboot: the init stack is %X bytes\n", init_stack_size);;
/// Bootboot structure ///
BOOTBOOT *bootboot = ext_mem_alloc_type_aligned(4096, MEMMAP_BOOTLOADER_RECLAIMABLE, 4096);
map_page(pmap, struct_vaddr, (uintptr_t)bootboot, VMM_FLAG_PRESENT | VMM_FLAG_WRITE, false);
/// Environment ///
map_page(pmap, env_vaddr, (uintptr_t)env, VMM_FLAG_PRESENT | VMM_FLAG_WRITE, false);
/// Identity mapping ///
for (uint64_t i = 0; i < 0x400000000; i += 0x200000) {
map_page(pmap, i, i, 0x03, true);
}
/// Framebuffer init ///
size_t fbwidth = 0, fbheight = 0, fbbpp = 32;
struct fb_info fbi;
char *resolution = config_get_value(config, 0, "RESOLUTION");
if (resolution != NULL) {
parse_resolution(&fbwidth, &fbheight, &fbbpp, resolution);
}
term_deinit();
fb_init(&fbi, fbwidth, fbheight, fbbpp);
uint64_t fb_size = fbi.framebuffer_height * fbi.framebuffer_pitch;
for (uint64_t current = 0; current < fb_size; current += 0x1000) {
map_page(pmap, fb_vaddr + current, fbi.framebuffer_addr + current, VMM_FLAG_PRESENT | VMM_FLAG_WRITE, false);
}
/// Header info ///
memcpy(bootboot->magic, "BOOT", 4);
#if bios
bootboot->protocol = 2 | (0 << 2);
#elif uefi
bootboot->protocol = 2 | (1 << 2);
#endif
/// Time stubs ///
uint32_t year, month, day, hour, minute, second;
bootboot_time(&day, &month, &year, &second, &minute, &hour);
bootboot->timezone = 0;
bootboot->datetime[0] = int_to_bcd(year / 100);
bootboot->datetime[1] = int_to_bcd(year % 100);
bootboot->datetime[2] = int_to_bcd(month);
bootboot->datetime[3] = int_to_bcd(day);
bootboot->datetime[4] = int_to_bcd(hour);
bootboot->datetime[5] = int_to_bcd(minute);
bootboot->datetime[6] = int_to_bcd(second);
bootboot->datetime[7] = 0;
/// Ramdisk ///
bootboot->initrd_ptr = initrd_start;
bootboot->initrd_size = initrd_size;
/// Framebuffer ///
bootboot->fb_ptr = fbi.framebuffer_addr;
bootboot->fb_size = fb_size;
bootboot->fb_width = fbi.framebuffer_width;
bootboot->fb_height = fbi.framebuffer_height;
bootboot->fb_scanline = fbi.framebuffer_pitch;
bootboot->fb_type = 1;
/// SMBIOS and ACPI ///
uint64_t smbios_entry_32 = 0, smbios_entry_64 = 0;
acpi_get_smbios((void **)&smbios_entry_32, (void **)&smbios_entry_64);
bootboot->arch.x86_64.acpi_ptr = (uintptr_t)acpi_get_rsdp();
if (smbios_entry_64) {
bootboot->arch.x86_64.smbi_ptr = smbios_entry_64;
} else if (smbios_entry_32) {
bootboot->arch.x86_64.smbi_ptr = smbios_entry_32;
} else {
bootboot->arch.x86_64.smbi_ptr = 0;
}
#if uefi == 1
bootboot->arch.x86_64.efi_ptr = (uintptr_t)gST;
#elif bios == 1
bootboot->arch.x86_64.efi_ptr = 0;
#endif
bootboot->arch.x86_64.mp_ptr = 0;
#if uefi == 1
efi_exit_boot_services();
#endif
/// SMP info ///
size_t numcores;
uint32_t bsplapic;
volatile struct smp_information *cores;
init_smp(0, (void **)&cores, &numcores, &bsplapic, true, false, pmap, false, false);
bootboot->numcores = numcores;
bootboot->bspid = bsplapic;
for (size_t i = 0; i < numcores; i++) {
cores[i].stack_addr = ((uint64_t)(size_t)ext_mem_alloc(init_stack_size)) + init_stack_size;
}
/// Memory map ///
{
size_t mmapent;
struct e820_entry_t* e820e = get_memmap(&mmapent);
if (mmapent > 248) {
panic("Too many memory map entries");
}
for (size_t i = 0; i < mmapent; i++) {
uint32_t btype;
switch (e820e[i].type) {
case 1: btype = 1; break;
case 3: case 4: btype = 2; break;
default: btype = 0; break;
}
bootboot->mmap[i].size = (e820e[i].length & ~0xF) | btype;
bootboot->mmap[i].ptr = e820e[i].base;
}
bootboot->size = 128 + mmapent * 16;
}
/// Spinup ///
#if bios == 1
// If we're going 64, we might as well call this BIOS interrupt
// to tell the BIOS that we are entering Long Mode, since it is in
// the specification.
struct rm_regs r = {0};
r.eax = 0xec00;
r.ebx = 0x02; // Long mode only
rm_int(0x15, &r, &r);
#endif
pic_mask_all();
io_apic_mask_all();
irq_flush_type = IRQ_PIC_APIC_FLUSH;
for (size_t i = 0; i < numcores; i++) {
cores[i].extra_argument = 0;
cores[i].goto_address = entry;
}
common_spinup(bootboot_spinup_32, 5,
(uint32_t)(uintptr_t)pmap.top_level,
(uint32_t)entry, (uint32_t)(entry >> 32),
(uint32_t)cores[0].stack_addr, (uint32_t)(cores[0].stack_addr >> 32));
}

View File

@ -1,89 +0,0 @@
#ifndef __PROTOS__BOOTBOOT_H__
#define __PROTOS__BOOTBOOT_H__
#include <stdint.h>
#include <stdbool.h>
void bootboot_load(char *config);
/*
* what follows is (modified) bootboot.h
* https://gitlab.com/bztsrc/bootboot
*
* Copyright (C) 2021 pitust (piotr@stelmaszek.com)
* Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* This file is part of the BOOTBOOT Protocol package.
* @brief The BOOTBOOT structure
*
*/
#define BOOTBOOT_MAGIC "BOOT"
/* default virtual addresses for level 0 and 1 static loaders */
#define BOOTBOOT_MMIO 0xfffffffff8000000 /* memory mapped IO virtual address */
#define BOOTBOOT_FB 0xfffffffffc000000 /* frame buffer virtual address */
#define BOOTBOOT_INFO 0xffffffffffe00000 /* bootboot struct virtual address */
#define BOOTBOOT_ENV 0xffffffffffe01000 /* environment string virtual address */
#define BOOTBOOT_CORE 0xffffffffffe02000 /* core loadable segment start */
typedef struct {
uint64_t ptr;
uint64_t size;
} MMapEnt;
typedef struct {
uint8_t magic[4];
uint32_t size;
uint8_t protocol;
uint8_t fb_type;
uint16_t numcores;
uint16_t bspid;
int16_t timezone;
uint8_t datetime[8];
uint64_t initrd_ptr;
uint64_t initrd_size;
uint64_t fb_ptr;
uint32_t fb_size;
uint32_t fb_width;
uint32_t fb_height;
uint32_t fb_scanline;
union {
struct {
uint64_t acpi_ptr;
uint64_t smbi_ptr;
uint64_t efi_ptr;
uint64_t mp_ptr;
uint64_t unused0;
uint64_t unused1;
uint64_t unused2;
uint64_t unused3;
} x86_64;
} arch;
MMapEnt mmap[];
} BOOTBOOT;
#endif

View File

@ -1,83 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <protos/bootboot/initrd.h>
#include <lib/libc.h>
#include <lib/blib.h>
#include <lib/print.h>
#define HPODC_MAGIC "070707"
#define _offset(cnt) do { offset += (cnt); if (offset > file.size) return (struct initrd_file){0}; } while (false);
#define _atoffset() (&file.data[offset])
#define _must(n) do { if ((offset + (n)) > file.size) return (struct initrd_file){0}; } while (false);
/**
* cpio archive
*/
INITRD_HANDLER(cpio) {
uint64_t offset = 0;
if (file.size < 6) {
return (struct initrd_file){0};
}
/// Check magic ///
// this may be a bit unclear, but this checks if the file even **has** a cpio header
if (memcmp(file.data, "070701", 6) && memcmp(file.data, "070702", 6) && memcmp(file.data, "070707", 6)) {
return (struct initrd_file){0};
}
/// Some variables ///
size_t path_name_size = strlen(path);
/// hpodc archive ///
while (!memcmp(_atoffset(), HPODC_MAGIC, 6)) {
_must(22);
uint32_t name_size = oct2bin(_atoffset() + 8 * 6 + 11, 6);
uint32_t file_size = oct2bin(_atoffset() + 8 * 6 + 11 + 6, 11);
_must(9 * 6 + 2 * 11 + name_size);
uint8_t *target_path = _atoffset() + 9 * 6 + 2 * 11;
if (name_size > 2 && target_path[0] == '.' && target_path[1] == '/') {
target_path += 2;
}
if (!memcmp(target_path, path, path_name_size + 1)) {
return (struct initrd_file){
file_size,
_atoffset() + 9 * 6 + 2 * 11 + name_size,
};
}
_offset(76 + name_size + file_size);
}
offset = 0;
// newc and crc archive
while (!memcmp(_atoffset(), "07070", 5)) {
uint32_t file_size = hex2bin(_atoffset() + 8 * 6 + 6, 8);
uint32_t name_size = hex2bin(_atoffset() + 8 * 11 + 6, 8);
uint8_t *target_path = _atoffset() + 110;
if (name_size > 2 && target_path[0] == '.' && target_path[1] == '/') {
target_path += 2;
}
if (!memcmp(target_path, path, path_name_size + 1)) {
uint8_t buf[9];
memcpy(buf, _atoffset() + 8 * 11 + 6, 8);
buf[8] = 0;
return (struct initrd_file){
file_size,
(_atoffset() + ((110 + name_size + 3) / 4) * 4),
};
}
_offset(((110 + name_size + 3) / 4) * 4 + ((file_size + 3) / 4) * 4);
}
return (struct initrd_file){0};
}

View File

@ -1,54 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <protos/bootboot/initrd.h>
#include <lib/print.h>
#include <lib/libc.h>
#include <lib/blib.h>
struct initrd_file bruteforce_kernel(struct initrd_file file) {
for (size_t i = 0; i < file.size - 19; i++) {
if (memcmp(file.data + i, "\177ELF", 4) == 0
&& file.data[i + 18] == 62 && file.data[i + 19] == 0 /* ehdr->e_machine == EM_X86_64 */) {
printv("bootboot: using bruteforced kernel at initrd offset %X\n", file.data + i);
return (struct initrd_file){
.size = file.size - i,
.data = file.data + i
};
}
}
return (struct initrd_file){0};
}
enum initrd_format initrd_format(struct initrd_file file) {
if (file.size >= 5 && file.data[4] == 0xbf) {
return INITRD_FORMAT_JAMESM;
}
if (file.size >= 5 && memcmp("07070", file.data, 5) == 0) {
return INITRD_FORMAT_CPIO;
}
if (file.size >= 262 && memcmp("ustar", file.data + 257, 5) == 0) {
return INITRD_FORMAT_USTAR;
}
return INITRD_FORMAT_UNKNOWN;
}
INITRD_HANDLER(jamesm);
INITRD_HANDLER(ustar);
INITRD_HANDLER(cpio);
INITRD_HANDLER(auto) {
switch (initrd_format(file)) {
case INITRD_FORMAT_JAMESM:
return initrd_open_jamesm(file, path);
case INITRD_FORMAT_CPIO:
return initrd_open_cpio(file, path);
case INITRD_FORMAT_USTAR:
return initrd_open_ustar(file, path);
default:
return (struct initrd_file){0};
}
}

View File

@ -1,26 +0,0 @@
#ifndef __PROTOS__BOOTBOOT__INITRD_H__
#define __PROTOS__BOOTBOOT__INITRD_H__
#include <stdint.h>
#include <stdbool.h>
struct initrd_file {
uint64_t size;
uint8_t *data;
};
enum initrd_format {
INITRD_FORMAT_UNKNOWN,
INITRD_FORMAT_JAMESM,
INITRD_FORMAT_CPIO,
INITRD_FORMAT_USTAR
};
struct initrd_file bruteforce_kernel(struct initrd_file file);
enum initrd_format initrd_format(struct initrd_file file);
#define INITRD_HANDLER(name) struct initrd_file initrd_open_##name(struct initrd_file file, const char *path)
INITRD_HANDLER(auto);
#endif

View File

@ -1,41 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include <protos/bootboot/initrd.h>
#include <lib/libc.h>
// This looks really sketchy, but that's what the official """spec""" says...
struct initrd_entry {
uint8_t magic; // The magic number is there to check for consistency.
char name[64];
uint32_t offset; // Offset in the initrd the file starts.
uint32_t length; // Length of the file.
};
INITRD_HANDLER(jamesm) {
if (file.size < 5) {
return (struct initrd_file){0};
}
uint32_t file_count = *((uint32_t *)(file.data));
size_t path_len = strlen(path);
struct initrd_entry *data = (void *)(file.data + 4);
if (data->magic != 0xbf) {
return (struct initrd_file){0};
}
for (uint32_t i = 0; i < file_count; i++) {
if (data[i].magic != 0xbf) {
return (struct initrd_file){0};
}
if (!memcmp(data[i].name, path, path_len + 1)) {
return (struct initrd_file){
data[i].length,
file.data + data[i].offset
};
}
}
return (struct initrd_file){0};
}

View File

@ -1,34 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include <protos/bootboot/initrd.h>
#include <lib/libc.h>
#include <lib/blib.h>
#define PTR (file.data + offset)
INITRD_HANDLER(ustar) {
if (file.size < 262) {
return (struct initrd_file){0};
}
if (memcmp(file.data + 257, "ustar", 5)) {
return (struct initrd_file){0};
}
size_t path_size = strlen(path);
uint32_t offset = 0;
while (!memcmp(PTR + 257, "ustar", 5)) {
uint32_t file_size = oct2bin(PTR + 0x7c, 11);
if (!memcmp(PTR, path, path_size + 1)
|| (PTR[0] == '.' && PTR[1] == '/' && !memcmp(PTR + 2, path, path_size + 1))) {
return (struct initrd_file){
file_size,
PTR + 512,
};
}
offset += (((file_size + 511) / 512) + 1) * 512;
}
return (struct initrd_file){0};
}