commit
f3aee7feb5
|
@ -99,6 +99,14 @@ 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
|
Note that one can define this last variable multiple times to specify multiple
|
||||||
modules.
|
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.
|
* `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:
|
||||||
|
* `KERNEL_PATH` - The URI path of the kernel.
|
||||||
|
* `INITRD_PATH` - The URI path to the ramdisk/initrd.
|
||||||
|
* `BOOTBOOT_ENV` - A configuration key to be passed into the kernel.
|
||||||
|
|
||||||
|
Note that one can define this last variable multiple times to specify multiple
|
||||||
|
environemnt keys.
|
||||||
|
* `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:
|
* stivale and stivale2 protocols:
|
||||||
* `KERNEL_PATH` - The URI path of the kernel.
|
* `KERNEL_PATH` - The URI path of the kernel.
|
||||||
* `MODULE_PATH` - The URI path to a module.
|
* `MODULE_PATH` - The URI path to a module.
|
||||||
|
|
|
@ -18,6 +18,7 @@ Like Limine and want to support it? Donate Bitcoin to
|
||||||
|
|
||||||
### Supported boot protocols
|
### Supported boot protocols
|
||||||
* stivale and stivale2 (Limine's native boot protocols, see [their specifications](https://github.com/stivale/stivale) for details)
|
* 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
|
* Linux
|
||||||
* Multiboot 1
|
* Multiboot 1
|
||||||
* Multiboot 2
|
* Multiboot 2
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <mm/pmm.h>
|
#include <mm/pmm.h>
|
||||||
#include <protos/stivale.h>
|
#include <protos/stivale.h>
|
||||||
#include <protos/stivale2.h>
|
#include <protos/stivale2.h>
|
||||||
|
#include <protos/bootboot.h>
|
||||||
#include <protos/linux.h>
|
#include <protos/linux.h>
|
||||||
#include <protos/chainload.h>
|
#include <protos/chainload.h>
|
||||||
#include <protos/multiboot1.h>
|
#include <protos/multiboot1.h>
|
||||||
|
@ -177,6 +178,8 @@ void stage3_common(void) {
|
||||||
multiboot1_load(config, cmdline);
|
multiboot1_load(config, cmdline);
|
||||||
} else if (!strcmp(proto, "multiboot2")) {
|
} else if (!strcmp(proto, "multiboot2")) {
|
||||||
multiboot2_load(config, cmdline);
|
multiboot2_load(config, cmdline);
|
||||||
|
} else if (!strcmp(proto, "bootboot")) {
|
||||||
|
bootboot_load(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("Invalid protocol specified");
|
panic("Invalid protocol specified");
|
||||||
|
|
|
@ -43,6 +43,7 @@ size_t get_trailing_zeros(uint64_t val);
|
||||||
|
|
||||||
int digit_to_int(char c);
|
int digit_to_int(char c);
|
||||||
uint8_t bcd_to_int(uint8_t val);
|
uint8_t bcd_to_int(uint8_t val);
|
||||||
|
uint8_t int_to_bcd(uint8_t val);
|
||||||
|
|
||||||
__attribute__((noreturn)) void panic(const char *fmt, ...);
|
__attribute__((noreturn)) void panic(const char *fmt, ...);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,9 @@ bool verbose = true;
|
||||||
uint8_t bcd_to_int(uint8_t val) {
|
uint8_t bcd_to_int(uint8_t val) {
|
||||||
return (val & 0x0f) + ((val & 0xf0) >> 4) * 10;
|
return (val & 0x0f) + ((val & 0xf0) >> 4) * 10;
|
||||||
}
|
}
|
||||||
|
uint8_t int_to_bcd(uint8_t val) {
|
||||||
|
return (val % 10) | (val / 10) << 4;
|
||||||
|
}
|
||||||
|
|
||||||
int digit_to_int(char c) {
|
int digit_to_int(char c) {
|
||||||
if (c >= 'a' && c <= 'f') {
|
if (c >= 'a' && c <= 'f') {
|
||||||
|
|
|
@ -26,22 +26,6 @@
|
||||||
#define EI_VERSION 6
|
#define EI_VERSION 6
|
||||||
#define EI_OSABI 7
|
#define EI_OSABI 7
|
||||||
|
|
||||||
struct elf64_hdr {
|
|
||||||
uint8_t ident[16];
|
|
||||||
uint16_t type;
|
|
||||||
uint16_t machine;
|
|
||||||
uint32_t version;
|
|
||||||
uint64_t entry;
|
|
||||||
uint64_t phoff;
|
|
||||||
uint64_t shoff;
|
|
||||||
uint32_t flags;
|
|
||||||
uint16_t hdr_size;
|
|
||||||
uint16_t phdr_size;
|
|
||||||
uint16_t ph_num;
|
|
||||||
uint16_t shdr_size;
|
|
||||||
uint16_t sh_num;
|
|
||||||
uint16_t shstrndx;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct elf32_hdr {
|
struct elf32_hdr {
|
||||||
uint8_t ident[16];
|
uint8_t ident[16];
|
||||||
|
@ -82,19 +66,6 @@ struct elf32_phdr {
|
||||||
uint32_t p_align;
|
uint32_t p_align;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct elf64_shdr {
|
|
||||||
uint32_t sh_name;
|
|
||||||
uint32_t sh_type;
|
|
||||||
uint64_t sh_flags;
|
|
||||||
uint64_t sh_addr;
|
|
||||||
uint64_t sh_offset;
|
|
||||||
uint64_t sh_size;
|
|
||||||
uint32_t sh_link;
|
|
||||||
uint32_t sh_info;
|
|
||||||
uint64_t sh_addralign;
|
|
||||||
uint64_t sh_entsize;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct elf32_shdr {
|
struct elf32_shdr {
|
||||||
uint32_t sh_name;
|
uint32_t sh_name;
|
||||||
uint32_t sh_type;
|
uint32_t sh_type;
|
||||||
|
|
|
@ -35,4 +35,41 @@ int elf32_load(uint8_t *elf, uint32_t *entry_point, uint32_t *top, uint32_t allo
|
||||||
int elf32_load_section(uint8_t *elf, void *buffer, const char *name, size_t limit);
|
int elf32_load_section(uint8_t *elf, void *buffer, const char *name, size_t limit);
|
||||||
struct elf_section_hdr_info* elf32_section_hdr_info(uint8_t *elf);
|
struct elf_section_hdr_info* elf32_section_hdr_info(uint8_t *elf);
|
||||||
|
|
||||||
|
struct elf64_hdr {
|
||||||
|
uint8_t ident[16];
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t machine;
|
||||||
|
uint32_t version;
|
||||||
|
uint64_t entry;
|
||||||
|
uint64_t phoff;
|
||||||
|
uint64_t shoff;
|
||||||
|
uint32_t flags;
|
||||||
|
uint16_t hdr_size;
|
||||||
|
uint16_t phdr_size;
|
||||||
|
uint16_t ph_num;
|
||||||
|
uint16_t shdr_size;
|
||||||
|
uint16_t sh_num;
|
||||||
|
uint16_t shstrndx;
|
||||||
|
};
|
||||||
|
struct elf64_shdr {
|
||||||
|
uint32_t sh_name;
|
||||||
|
uint32_t sh_type;
|
||||||
|
uint64_t sh_flags;
|
||||||
|
uint64_t sh_addr;
|
||||||
|
uint64_t sh_offset;
|
||||||
|
uint64_t sh_size;
|
||||||
|
uint32_t sh_link;
|
||||||
|
uint32_t sh_info;
|
||||||
|
uint64_t sh_addralign;
|
||||||
|
uint64_t sh_entsize;
|
||||||
|
};
|
||||||
|
struct elf64_sym {
|
||||||
|
uint32_t st_name;
|
||||||
|
uint8_t st_info;
|
||||||
|
uint8_t st_other;
|
||||||
|
uint16_t st_shndx;
|
||||||
|
uint64_t st_value;
|
||||||
|
uint64_t st_size;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -46,6 +46,28 @@ uint64_t time(void) {
|
||||||
uint8_t hour = bcd_to_int((r.ecx & 0xff00) >> 8);
|
uint8_t hour = bcd_to_int((r.ecx & 0xff00) >> 8);
|
||||||
|
|
||||||
return get_unix_epoch(second, minute, hour, day, month, year);
|
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
|
#endif
|
||||||
|
|
||||||
|
@ -57,4 +79,13 @@ uint64_t time(void) {
|
||||||
return get_unix_epoch(time.Second, time.Minute, time.Hour,
|
return get_unix_epoch(time.Second, time.Minute, time.Hour,
|
||||||
time.Day, time.Month, time.Year);
|
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
|
#endif
|
||||||
|
|
|
@ -4,5 +4,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
uint64_t time(void);
|
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
|
#endif
|
||||||
|
|
|
@ -75,6 +75,7 @@ static size_t get_prev_line(size_t index, const char *buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *VALID_KEYS[] = {
|
static const char *VALID_KEYS[] = {
|
||||||
|
"BOOTBOOT_ENV",
|
||||||
"TIMEOUT",
|
"TIMEOUT",
|
||||||
"DEFAULT_ENTRY",
|
"DEFAULT_ENTRY",
|
||||||
"GRAPHICS",
|
"GRAPHICS",
|
||||||
|
@ -113,6 +114,7 @@ static const char *VALID_KEYS[] = {
|
||||||
"CMDLINE",
|
"CMDLINE",
|
||||||
"KERNEL_CMDLINE",
|
"KERNEL_CMDLINE",
|
||||||
"KERNEL_PATH",
|
"KERNEL_PATH",
|
||||||
|
"INITRD_PATH",
|
||||||
"MODULE_PATH",
|
"MODULE_PATH",
|
||||||
"MODULE_STRING",
|
"MODULE_STRING",
|
||||||
"RESOLUTION",
|
"RESOLUTION",
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
#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();
|
||||||
|
}
|
|
@ -0,0 +1,281 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <protos/bootboot.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>
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void bootboot_spinup(
|
||||||
|
pagemap_t *pagemap,
|
||||||
|
uint64_t entry_point, uint64_t stack,
|
||||||
|
size_t numcores, struct smp_information* cores);
|
||||||
|
|
||||||
|
#define BOOTBOOT_FB 0xfffffffffc000000
|
||||||
|
#define BOOTBOOT_INFO 0xffffffffffe00000
|
||||||
|
#define BOOTBOOT_ENV 0xffffffffffe01000
|
||||||
|
#define BOOTBOOT_CORE 0xffffffffffe02000
|
||||||
|
|
||||||
|
|
||||||
|
__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) {
|
||||||
|
#if bios
|
||||||
|
void *efi_system_table = NULL;
|
||||||
|
#elif uefi
|
||||||
|
void *efi_system_table = gST;
|
||||||
|
#endif
|
||||||
|
uint64_t fb_vaddr = BOOTBOOT_FB;
|
||||||
|
uint64_t struct_vaddr = BOOTBOOT_INFO;
|
||||||
|
uint64_t env_vaddr = BOOTBOOT_ENV;
|
||||||
|
uint64_t init_stack_size = 1024;
|
||||||
|
|
||||||
|
/// Config ///
|
||||||
|
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
||||||
|
if (kernel_path == NULL)
|
||||||
|
panic("bootboot: KERNEL_PATH not specified");
|
||||||
|
|
||||||
|
char *initrd = config_get_value(config, 0, "INITRD");
|
||||||
|
if (initrd == NULL) {
|
||||||
|
print("bootboot: warning: no initrd!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Kernel loading code ///
|
||||||
|
print("bootboot: Loading kernel `%s`...\n", kernel_path);
|
||||||
|
struct file_handle* kernel_file;
|
||||||
|
if ((kernel_file = uri_open(kernel_path)) == NULL)
|
||||||
|
panic("bootboot: Failed to open kernel with path `%s`. Is the path correct?\n", kernel_path);
|
||||||
|
|
||||||
|
uint8_t* kernel = freadall(kernel_file, MEMMAP_KERNEL_AND_MODULES);
|
||||||
|
|
||||||
|
/// Funky macros ///
|
||||||
|
#define KOFFSET(type, off) (type)&kernel[(off)]
|
||||||
|
#define ESECTION(idx) KOFFSET(struct elf64_shdr*, elf_header->shoff + elf_header->shdr_size * (idx))
|
||||||
|
|
||||||
|
/// 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 = §ion_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!");
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printv("bootboot: mapping struct to %X", struct_vaddr);
|
||||||
|
printv("bootboot: mapping environemnt to %X", env_vaddr);
|
||||||
|
printv("bootboot: mapping framebuffer to %X", fb_vaddr);
|
||||||
|
printv("bootboot: the init stack is %X bytes", init_stack_size);
|
||||||
|
|
||||||
|
uint64_t entry, top, slide, rangecount, physbase, virtbase = 0;
|
||||||
|
struct elf_range* ranges;
|
||||||
|
|
||||||
|
/// Memory mappings ///
|
||||||
|
pagemap_t pmap = new_pagemap(4);
|
||||||
|
|
||||||
|
/// Load kernel ///
|
||||||
|
{
|
||||||
|
if (elf64_load(
|
||||||
|
kernel, &entry, &top, &slide, MEMMAP_KERNEL_AND_MODULES,
|
||||||
|
false, false, &ranges, &rangecount, 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* bootboot = (BOOTBOOT*)ext_mem_alloc_type_aligned(4096, MEMMAP_BOOTLOADER_RECLAIMABLE, 4096);
|
||||||
|
map_page(pmap, struct_vaddr, (uint64_t)(size_t)bootboot, VMM_FLAG_PRESENT | VMM_FLAG_WRITE, false);
|
||||||
|
|
||||||
|
/// Environment ///
|
||||||
|
{
|
||||||
|
char* env = (char*)ext_mem_alloc_type_aligned(4096, MEMMAP_BOOTLOADER_RECLAIMABLE, 4096);
|
||||||
|
map_page(pmap, env_vaddr, (uint64_t)(size_t)env, VMM_FLAG_PRESENT | VMM_FLAG_WRITE, false);
|
||||||
|
uint32_t index = 0, offset = 0;
|
||||||
|
char* cfgent = NULL;
|
||||||
|
do {
|
||||||
|
cfgent = config_get_value(config, index++, "BOOTBOOT_ENV");
|
||||||
|
if (cfgent) {
|
||||||
|
uint32_t off = strlen(cfgent);
|
||||||
|
if (offset + off + 1 > 4095) {
|
||||||
|
panic("Too much config options! we only have 4k of env vars!");
|
||||||
|
}
|
||||||
|
memcpy(&env[offset], cfgent, off);
|
||||||
|
offset += off;
|
||||||
|
env[offset++] = '\n';
|
||||||
|
}
|
||||||
|
} while (cfgent);
|
||||||
|
cfgent[offset] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initrd loading ///
|
||||||
|
uint64_t initrd_start = 0, initrd_size = 0;
|
||||||
|
if (initrd) {
|
||||||
|
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?\n", 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Header info ///
|
||||||
|
memcpy(bootboot->magic, "BOOT", 4);
|
||||||
|
#if bios
|
||||||
|
bootboot->protocol = 2 | (0 << 2);
|
||||||
|
#elif uefi
|
||||||
|
bootboot->protocol = 2 | (1 << 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// SMP info ///
|
||||||
|
size_t numcores;
|
||||||
|
uint32_t bsplapic;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 = (uint64_t)(size_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;
|
||||||
|
bootboot->arch.x86_64.efi_ptr = (uint64_t)(size_t)efi_system_table;
|
||||||
|
bootboot->arch.x86_64.mp_ptr = 0;
|
||||||
|
|
||||||
|
/// Memory map ///
|
||||||
|
{
|
||||||
|
size_t mmapent;
|
||||||
|
struct e820_entry_t* e820e = get_memmap(&mmapent);
|
||||||
|
if (mmapent > 248) {
|
||||||
|
panic("Too much memory entries! our god bzt decided that %d entries is too much, max is 248", mmapent);
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0;i < mmapent;i++) {
|
||||||
|
uint32_t btype = 0;
|
||||||
|
if (e820e[i].type == 1) btype = 1;
|
||||||
|
if (e820e[i].type == 3) btype = 2;
|
||||||
|
if (e820e[i].type == 4) btype = 2;
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
irq_flush_type = IRQ_PIC_ONLY_FLUSH;
|
||||||
|
|
||||||
|
for (size_t i = 0;i < numcores;i++) {
|
||||||
|
cores[i].extra_argument = 0;
|
||||||
|
cores[i].goto_address = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
common_spinup(bootboot_spinup_32, 10,
|
||||||
|
(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));
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
#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
|
Loading…
Reference in New Issue