boot: Implement multiboot2 loader

It's based on uefi loader and paves the road to loading on platforms
that are not directly supported like coreboot.

Right now it supports only 64-bit kernel but 32-bit can be added later.
This commit is contained in:
Vladimir Serbinenko 2023-08-14 23:52:18 +02:00
parent 0a70170952
commit 015fb75973
5 changed files with 1027 additions and 0 deletions

343
boot/x86/mb2.c Normal file
View File

@ -0,0 +1,343 @@
// This file is part of the Essence operating system.
// It is released under the terms of the MIT license -- see LICENSE.md.
// Written by: phcoder.
#include "multiboot2.h"
#define ENTRIES_PER_PAGE_TABLE (512)
#define ENTRIES_PER_PAGE_TABLE_BITS (9)
#define K_PAGE_SIZE (4096)
#define K_PAGE_BITS (12)
typedef __UINT8_TYPE__ uint8_t;
typedef __UINT16_TYPE__ uint16_t;
typedef __UINT32_TYPE__ uint32_t;
typedef __UINTPTR_TYPE__ uintptr_t;
typedef __UINT64_TYPE__ uint64_t;
typedef struct VideoModeInformation {
uint8_t valid : 1, edidValid : 1;
uint8_t bitsPerPixel;
uint16_t widthPixels, heightPixels;
uint16_t bytesPerScanlineLinear;
uint64_t bufferPhysical;
uint8_t edid[128];
} VideoModeInformation;
typedef struct ElfHeader {
uint32_t magicNumber; // 0x7F followed by 'ELF'
uint8_t bits; // 1 = 32 bit, 2 = 64 bit
uint8_t endianness; // 1 = LE, 2 = BE
uint8_t version1;
uint8_t abi; // 0 = System V
uint8_t _unused0[8];
uint16_t type; // 1 = relocatable, 2 = executable, 3 = shared
uint16_t instructionSet; // 0x03 = x86, 0x28 = ARM, 0x3E = x86-64, 0xB7 = AArch64
uint32_t version2;
uint64_t entry;
uint64_t programHeaderTable;
uint64_t sectionHeaderTable;
uint32_t flags;
uint16_t headerSize;
uint16_t programHeaderEntrySize;
uint16_t programHeaderEntries;
uint16_t sectionHeaderEntrySize;
uint16_t sectionHeaderEntries;
uint16_t sectionNameIndex;
} ElfHeader;
typedef struct ElfSectionHeader {
uint32_t name; // Offset into section header->sectionNameIndex.
uint32_t type; // 4 = rela
uint64_t flags;
uint64_t address;
uint64_t offset;
uint64_t size;
uint32_t link;
uint32_t info;
uint64_t align;
uint64_t entrySize;
} ElfSectionHeader;
typedef struct ElfProgramHeader {
uint32_t type; // 0 = unused, 1 = load, 2 = dynamic, 3 = interp, 4 = note
uint32_t flags; // 1 = executable, 2 = writable, 4 = readable
uint64_t fileOffset;
uint64_t virtualAddress;
uint64_t _unused0;
uint64_t dataInFile;
uint64_t segmentSize;
uint64_t alignment;
} ElfProgramHeader;
typedef struct __attribute__((packed)) GDTData {
uint16_t length;
uint64_t address;
} GDTData;
typedef struct MemoryRegion {
uint64_t base, pages;
} MemoryRegion;
#define MAX_MEMORY_REGIONS (1024)
struct {
// 0x106000
char rsdp_copy[4096];
// 0x107000 Graphics info
VideoModeInformation graphics_info;
char filler[0xFE8 - sizeof(VideoModeInformation)];
// 0x107FE8 RSDP address
uint64_t rsdp_address;
// 0x107FF0 Installation ID
char iid[16];
} kernel_params __attribute__((section(".kernel_params")));
// 0x140000-0x150000 Identity paging tables
uint64_t paging_table[0x2000] __attribute__((section(".paging_table"), aligned(4096)));
// 0x160000-0x170000 Memory regions
MemoryRegion memoryRegions[MAX_MEMORY_REGIONS] __attribute__((section(".memory_map")));
int memoryRegionCount = 0;
// 0x1c0000-0x1e0000 Identity paging tables
uint64_t kernel_paging_table[0x2000] __attribute__((section(".kernel_paging_table"), aligned(4096)));
// 0x180000-0x1C0000 Loader (this)
// 0x1F0000-0x200000 Stack
uint8_t stack[0x10000] __attribute__((section(".stack"), aligned(4096)));
uint64_t kernel_start;
static void ZeroMemory(void *pointer, uint64_t size) {
char *d = (char *) pointer;
for (uintptr_t i = 0; i < size; i++) {
d[i] = 0;
}
}
static void CopyMemory(void *dest, void *src, uint64_t size) {
char *d = (char *) dest;
char *s = (char *) src;
for (uintptr_t i = 0; i < size; i++) {
d[i] = s[i];
}
}
static uint8_t hex2val (char c) {
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
return 0;
}
#ifdef __cplusplus
extern "C"
#endif
void mb2_main(void *mb2_info) {
ElfHeader *header;
struct multiboot_tag_old_acpi *old_acpi = 0;
struct multiboot_tag_new_acpi *new_acpi = 0;
struct multiboot_tag_module *kernel_module = 0, *iid_module = 0;
const char *iid_string = 0;
ZeroMemory(&kernel_params, sizeof(kernel_params));
for (struct multiboot_tag *tag = (struct multiboot_tag *) ((uint8_t *)mb2_info + 8);
tag->type != MULTIBOOT_TAG_TYPE_END;
tag = (struct multiboot_tag *) ((uint8_t *) tag + ((tag->size + MULTIBOOT_TAG_ALIGN - 1) & ~(MULTIBOOT_TAG_ALIGN - 1))))
switch(tag->type) {
case MULTIBOOT_TAG_TYPE_ACPI_OLD:
old_acpi = (struct multiboot_tag_old_acpi *) tag;
break;
case MULTIBOOT_TAG_TYPE_ACPI_NEW:
new_acpi = (struct multiboot_tag_new_acpi *) tag;
break;
case MULTIBOOT_TAG_TYPE_MODULE: {
struct multiboot_tag_module *module = (struct multiboot_tag_module *) tag;
if (module->mod_end - module->mod_start == 16)
iid_module = module;
else
kernel_module = module;
break;
}
case MULTIBOOT_TAG_TYPE_MMAP: {
struct multiboot_tag_mmap *mmap = (struct multiboot_tag_mmap *) tag;
struct multiboot_mmap_entry *mmap_entry = mmap->entries;
for (; (uint8_t *)mmap_entry < (uint8_t *)tag + tag->size && memoryRegionCount != MAX_MEMORY_REGIONS - 1;
mmap_entry = (struct multiboot_mmap_entry *) ((uint8_t *) mmap_entry + mmap->entry_size)) {
if (mmap_entry->type != MULTIBOOT_MEMORY_AVAILABLE)
continue;
uint64_t st = (mmap_entry->addr + 0xfff) & ~0xfffULL;
uint64_t end = (mmap_entry->addr + mmap_entry->len) & ~0xfffULL;
if (st < 0x300000)
st = 0x300000;
if (st >= end)
continue;
memoryRegions[memoryRegionCount].base = st;
memoryRegions[memoryRegionCount].pages = (end - st) >> 12;
memoryRegionCount++;
}
memoryRegions[memoryRegionCount].base = 0;
break;
}
case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: {
struct multiboot_tag_framebuffer *fb = (struct multiboot_tag_framebuffer *) tag;
kernel_params.graphics_info.heightPixels = fb->common.framebuffer_height;
kernel_params.graphics_info.widthPixels = fb->common.framebuffer_width;
kernel_params.graphics_info.bytesPerScanlineLinear = fb->common.framebuffer_pitch;
kernel_params.graphics_info.bufferPhysical = fb->common.framebuffer_addr;
kernel_params.graphics_info.bitsPerPixel = fb->common.framebuffer_bpp;
kernel_params.graphics_info.valid = 1;
kernel_params.graphics_info.edidValid = 0;
break;
}
case MULTIBOOT_TAG_TYPE_CMDLINE: {
struct multiboot_tag_string *cmdline = (struct multiboot_tag_string *) tag;
for (const char *ptr = cmdline->string; *ptr;) {
if (ptr[0] == 'i' && ptr[1] == 'i' && ptr[2] == 'd' && ptr[3] == '=')
iid_string = ptr + 4;
while (*ptr && *ptr != ' ' && *ptr != '\t')
ptr++;
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
ptr++;
}
break;
}
}
if (new_acpi) {
CopyMemory (&kernel_params.rsdp_copy, new_acpi->rsdp, new_acpi->size - sizeof(struct multiboot_tag));
kernel_params.rsdp_address = (uintptr_t) &kernel_params.rsdp_copy;
} else if (old_acpi) {
CopyMemory (&kernel_params.rsdp_copy, old_acpi->rsdp, old_acpi->size - sizeof(struct multiboot_tag));
kernel_params.rsdp_address = (uintptr_t) &kernel_params.rsdp_copy;
}
if (iid_string) {
int j = 0;
for (const char *ptr = iid_string; *ptr && *ptr != ' ' && *ptr != '\t' && j < 16; ) {
while (*ptr == '-')
ptr++;
if (ptr[0] == '\0' || ptr[0] == ' ' || ptr[0] == '\t' ||
ptr[1] == '\0' || ptr[1] == ' ' || ptr[1] == '\t')
break;
kernel_params.iid[j++] = (hex2val(ptr[0]) << 4) | hex2val(ptr[1]);
ptr += 2;
}
} else if (iid_module) {
CopyMemory (kernel_params.iid, (void *) iid_module->mod_start, sizeof(kernel_params.iid));
}
// Identity map the first 3MB for the loader.
{
uint64_t *paging = paging_table;
uint64_t base = (uintptr_t)paging;
ZeroMemory(paging, 0x5000);
paging[0x1FE] = base | 3; // Recursive
paging[0x000] = (base + 0x1000) | 3; // L4
paging[0x200] = (base + 0x2000) | 3; // L3
paging[0x400] = (base + 0x3000) | 3; // L2
paging[0x401] = (base + 0x4000) | 3;
for (uintptr_t i = 0; i < 0x400; i++) {
paging[0x600 + i] = (i * 0x1000) | 3; // L1
}
}
// Allocate and map memory for the kernel.
{
uint64_t nextPageTable = (uintptr_t) &kernel_paging_table;
uint32_t kernelBuffer = kernel_module->mod_start;
uint32_t kernelBufferEnd = kernel_module->mod_end;
header = (ElfHeader *) kernelBuffer;
kernel_start = header->entry;
ElfProgramHeader *programHeaders = (ElfProgramHeader *) (kernelBuffer + header->programHeaderTable);
uintptr_t programHeaderEntrySize = header->programHeaderEntrySize;
for (uintptr_t i = 0; i < header->programHeaderEntries; i++) {
ElfProgramHeader *header = (ElfProgramHeader *) ((uint8_t *) programHeaders + programHeaderEntrySize * i);
if (header->type != 1) continue;
uintptr_t pagesToAllocate = (header->segmentSize + 0xfff) >> 12;
uintptr_t physicalAddress = 0;
for (uintptr_t j = 0; j < MAX_MEMORY_REGIONS; j++) {
MemoryRegion *region = memoryRegions + j;
if (!region->base) break;
if (region->pages < pagesToAllocate) continue;
// Prevent intersections with kernel buffer
if (region->base <= kernelBufferEnd && region->base + (pagesToAllocate << 12) > kernelBuffer) {
uint64_t new_base = (kernelBufferEnd + 0xfff) & ~0xfffULL;
uint64_t new_pages = region->pages - (new_base - region->base);
if (new_pages < pagesToAllocate) continue;
// Sacrifice at most size of kernel buffer
region->base = new_base;
region->pages = new_pages;
}
physicalAddress = region->base;
region->pages -= pagesToAllocate;
region->base += pagesToAllocate << 12;
break;
}
if (!physicalAddress) {
// TODO Error handling.
*((uint32_t *) kernel_params.graphics_info.bufferPhysical + 3) = 0xFFFF00FF;
while (1);
}
ZeroMemory((void *) physicalAddress, header->segmentSize);
CopyMemory((void *) physicalAddress, (void *) (kernelBuffer + header->fileOffset), header->dataInFile);
for (uintptr_t j = 0; j < pagesToAllocate; j++, physicalAddress += 0x1000) {
uint64_t virtualAddress = header->virtualAddress + j * K_PAGE_SIZE;
physicalAddress &= 0xFFFFFFFFFFFFF000;
virtualAddress &= 0x0000FFFFFFFFF000;
uintptr_t indexL4 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 3)) & (ENTRIES_PER_PAGE_TABLE - 1);
uintptr_t indexL3 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 2)) & (ENTRIES_PER_PAGE_TABLE - 1);
uintptr_t indexL2 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 1)) & (ENTRIES_PER_PAGE_TABLE - 1);
uintptr_t indexL1 = (virtualAddress >> (K_PAGE_BITS + ENTRIES_PER_PAGE_TABLE_BITS * 0)) & (ENTRIES_PER_PAGE_TABLE - 1);
uint64_t *tableL4 = paging_table;
if (!(tableL4[indexL4] & 1)) {
tableL4[indexL4] = nextPageTable | 7;
ZeroMemory((void *) nextPageTable, K_PAGE_SIZE);
nextPageTable += K_PAGE_SIZE;
}
uint64_t *tableL3 = (uint64_t *) (tableL4[indexL4] & ~(K_PAGE_SIZE - 1));
if (!(tableL3[indexL3] & 1)) {
tableL3[indexL3] = nextPageTable | 7;
ZeroMemory((void *) nextPageTable, K_PAGE_SIZE);
nextPageTable += K_PAGE_SIZE;
}
uint64_t *tableL2 = (uint64_t *) (tableL3[indexL3] & ~(K_PAGE_SIZE - 1));
if (!(tableL2[indexL2] & 1)) {
tableL2[indexL2] = nextPageTable | 7;
ZeroMemory((void *) nextPageTable, K_PAGE_SIZE);
nextPageTable += K_PAGE_SIZE;
}
uint64_t *tableL1 = (uint64_t *) (tableL2[indexL2] & ~(K_PAGE_SIZE - 1));
uintptr_t value = physicalAddress | 3;
tableL1[indexL1] = value;
}
}
}
// Back to asm.
}

60
boot/x86/mb2_link.sc Normal file
View File

@ -0,0 +1,60 @@
/* Linker script to create multiboo2 loader. */
SECTIONS
{
. = 0x106000;
.kernel_params (NOLOAD) : { *(.kernel_params) }
. = 0x140000;
.paging_table (NOLOAD) : { *(.paging_table) }
. = 0x160000;
.memory_map (NOLOAD) : { *(.memory_map) }
. = 0x180000;
.text :
{
*(.text)
}
.data :
{
*(.data)
*(.rdata)
*(.pdata)
}
.bss :
{
*(.bss)
*(COMMON)
}
.edata :
{
*(.edata)
}
.stab :
{
*(.stab)
}
.stabstr :
{
*(.stabstr)
}
. = 0x1c0000;
.kernel_paging_table (NOLOAD) : { *(.kernel_paging_table) }
. = 0x1f0000;
.stack (NOLOAD) : { *(.stack) }
/DISCARD/ : {
*(.dynamic)
*(.comment)
*(.note.gnu.build-id)
}
}

179
boot/x86/mb2_loader.S Normal file
View File

@ -0,0 +1,179 @@
// This file is part of the Essence operating system.
// It is released under the terms of the MIT license -- see LICENSE.md.
// Written by: phcoder.
#define ASM_FILE
#include "multiboot2.h"
.text
.code32
#define REL32(x) ((x) - _start + 0x180000)
.globl _start
.globl stack
_start:
// Change GDT
lgdt REL32(.gdt)
ljmpl $0x8, $REL32(.start_32_bit_mode)
.start_32_bit_mode:
mov $0x10, %eax
mov %eax, %ds
mov %eax, %es
mov %eax, %ss
mov $REL32(stack + 0x10000 - 8), %esp
push %ebx
call mb2_main
mov %cr4, %eax
or $0x30, %eax
mov %eax, %cr4
mov $0x140000, %eax
mov %eax, %cr3
// Enable long mode
mov $0xC0000080, %ecx
rdmsr
or $0x100, %eax
wrmsr
mov %cr0, %eax
or $0x80000000, %eax
mov %eax, %cr0
lgdt REL32(.gdt)
// Go to 64-bit mode
ljmpl $0x48, $REL32(.start_64_bit_mode)
.code64
.align 16
.start_64_bit_mode:
mov $0x50, %rax
mov %rax, %ds
mov %rax, %es
mov %rax, %ss
// Get the start address of the kernel
mov kernel_start(%rip), %rcx
// Map the first MB at 0xFFFFFE0000000000 --> 0xFFFFFE0000100000
mov $0xFFFFFF7FBFDFE000, %rdi
mov (%rdi), %rax
mov $0xFFFFFF7FBFDFEFE0, %rdi
mov %rax, (%rdi)
mov %cr3, %rax
mov %rax, %cr3
// Use the new linear address of the GDT
mov $0xFFFFFE0000000000, %rax
add %rax, .gdt2(%rip)
lgdt .gdt(%rip)
call .set_cs
// Execute the kernel's _start function
mov $0x100000, %rdi
mov $2, %rsi
jmp *%rcx
.set_cs:
pop %rax
push $0x48
push %rax
.byte 0x48, 0xCB
.align MULTIBOOT_HEADER_ALIGN
.multiboot2_header:
.long MULTIBOOT2_HEADER_MAGIC
.long MULTIBOOT2_ARCHITECTURE_I386
.long .multiboot2_header_end - .multiboot2_header
.long -(.multiboot2_header_end - .multiboot2_header + MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_ARCHITECTURE_I386)
.word MULTIBOOT_HEADER_TAG_FRAMEBUFFER
.word 0
.long 20
.long 0 // width: any
.long 0 // height: any
.long 0 // depth: any
.long 0 // padding
.word MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST
.word 0
.long 20
.long MULTIBOOT_TAG_TYPE_ACPI_NEW
.long MULTIBOOT_TAG_TYPE_FRAMEBUFFER
.long MULTIBOOT_TAG_TYPE_MODULE
.long 0 // padding
.word MULTIBOOT_HEADER_TAG_MODULE_ALIGN
.word 0
.long 8
.word MULTIBOOT_HEADER_TAG_END
.word 0
.long 8
.multiboot2_header_end:
.align 16
.gdt_data:
.null_entry: .quad 0
.code_entry: .long 0xFFFF // 0x08
.byte 0
.word 0xCF9A
.byte 0
.data_entry: .long 0xFFFF // 0x10
.byte 0
.word 0xCF92
.byte 0
.code_entry_16: .long 0xFFFF // 0x18
.byte 0
.word 0x0F9A
.byte 0
.data_entry_16: .long 0xFFFF // 0x20
.byte 0
.word 0x0F92
.byte 0
.user_code: .long 0xFFFF // 0x28
.byte 0
.word 0xCFFA
.byte 0
.user_data: .long 0xFFFF // 0x30
.byte 0
.word 0xCFF2
.byte 0
.tss: .long 0x68 // 0x38
.byte 0
.word 0xE9
.byte 0
.quad 0
.code_entry64: .long 0xFFFF // 0x48
.byte 0
.word 0xAF9A
.byte 0
.data_entry64: .long 0xFFFF // 0x50
.byte 0
.word 0xAF92
.byte 0
.user_code64: .long 0xFFFF // 0x58
.byte 0
.word 0xAFFA
.byte 0
.user_data64: .long 0xFFFF // 0x60
.byte 0
.word 0xAFF2
.byte 0
.user_code64c: .long 0xFFFF // 0x68
.byte 0
.word 0xAFFA
.byte 0
.gdt: .word (.gdt - .gdt_data - 1)
.gdt2: .quad REL32(.gdt_data)

416
boot/x86/multiboot2.h Normal file
View File

@ -0,0 +1,416 @@
/* multiboot2.h - Multiboot 2 header file. */
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* 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 ANY
* DEVELOPER OR DISTRIBUTOR 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.
*/
#ifndef MULTIBOOT_HEADER
#define MULTIBOOT_HEADER 1
/* How many bytes from the start of the file we search for the header. */
#define MULTIBOOT_SEARCH 32768
#define MULTIBOOT_HEADER_ALIGN 8
/* The magic field should contain this. */
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
/* This should be in %eax. */
#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
/* Alignment of multiboot modules. */
#define MULTIBOOT_MOD_ALIGN 0x00001000
/* Alignment of the multiboot info structure. */
#define MULTIBOOT_INFO_ALIGN 0x00000008
/* Flags set in the 'flags' member of the multiboot header. */
#define MULTIBOOT_TAG_ALIGN 8
#define MULTIBOOT_TAG_TYPE_END 0
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
#define MULTIBOOT_TAG_TYPE_MODULE 3
#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
#define MULTIBOOT_TAG_TYPE_MMAP 6
#define MULTIBOOT_TAG_TYPE_VBE 7
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
#define MULTIBOOT_TAG_TYPE_APM 10
#define MULTIBOOT_TAG_TYPE_EFI32 11
#define MULTIBOOT_TAG_TYPE_EFI64 12
#define MULTIBOOT_TAG_TYPE_SMBIOS 13
#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
#define MULTIBOOT_TAG_TYPE_NETWORK 16
#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
#define MULTIBOOT_TAG_TYPE_EFI_BS 18
#define MULTIBOOT_TAG_TYPE_EFI32_IH 19
#define MULTIBOOT_TAG_TYPE_EFI64_IH 20
#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
#define MULTIBOOT_HEADER_TAG_END 0
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
#define MULTIBOOT_HEADER_TAG_ADDRESS 2
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
#define MULTIBOOT_HEADER_TAG_EFI_BS 7
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
#define MULTIBOOT2_ARCHITECTURE_I386 0
#define MULTIBOOT2_ARCHITECTURE_MIPS32 4
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
#ifndef ASM_FILE
typedef unsigned char multiboot_uint8_t;
typedef unsigned short multiboot_uint16_t;
typedef unsigned int multiboot_uint32_t;
typedef unsigned long long multiboot_uint64_t;
struct multiboot_header
{
/* Must be MULTIBOOT_MAGIC - see above. */
multiboot_uint32_t magic;
/* ISA */
multiboot_uint32_t architecture;
/* Total header length. */
multiboot_uint32_t header_length;
/* The above fields plus this one must equal 0 mod 2^32. */
multiboot_uint32_t checksum;
};
struct multiboot_header_tag
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
};
struct multiboot_header_tag_information_request
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t requests[0];
};
struct multiboot_header_tag_address
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t header_addr;
multiboot_uint32_t load_addr;
multiboot_uint32_t load_end_addr;
multiboot_uint32_t bss_end_addr;
};
struct multiboot_header_tag_entry_address
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t entry_addr;
};
struct multiboot_header_tag_console_flags
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t console_flags;
};
struct multiboot_header_tag_framebuffer
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t width;
multiboot_uint32_t height;
multiboot_uint32_t depth;
};
struct multiboot_header_tag_module_align
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
};
struct multiboot_header_tag_relocatable
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t min_addr;
multiboot_uint32_t max_addr;
multiboot_uint32_t align;
multiboot_uint32_t preference;
};
struct multiboot_color
{
multiboot_uint8_t red;
multiboot_uint8_t green;
multiboot_uint8_t blue;
};
struct multiboot_mmap_entry
{
multiboot_uint64_t addr;
multiboot_uint64_t len;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
multiboot_uint32_t type;
multiboot_uint32_t zero;
};
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_tag
{
multiboot_uint32_t type;
multiboot_uint32_t size;
};
struct multiboot_tag_string
{
multiboot_uint32_t type;
multiboot_uint32_t size;
char string[0];
};
struct multiboot_tag_module
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t mod_start;
multiboot_uint32_t mod_end;
char cmdline[0];
};
struct multiboot_tag_basic_meminfo
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t mem_lower;
multiboot_uint32_t mem_upper;
};
struct multiboot_tag_bootdev
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t biosdev;
multiboot_uint32_t slice;
multiboot_uint32_t part;
};
struct multiboot_tag_mmap
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t entry_size;
multiboot_uint32_t entry_version;
struct multiboot_mmap_entry entries[0];
};
struct multiboot_vbe_info_block
{
multiboot_uint8_t external_specification[512];
};
struct multiboot_vbe_mode_info_block
{
multiboot_uint8_t external_specification[256];
};
struct multiboot_tag_vbe
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint16_t vbe_mode;
multiboot_uint16_t vbe_interface_seg;
multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len;
struct multiboot_vbe_info_block vbe_control_info;
struct multiboot_vbe_mode_info_block vbe_mode_info;
};
struct multiboot_tag_framebuffer_common
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t framebuffer_addr;
multiboot_uint32_t framebuffer_pitch;
multiboot_uint32_t framebuffer_width;
multiboot_uint32_t framebuffer_height;
multiboot_uint8_t framebuffer_bpp;
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
multiboot_uint8_t framebuffer_type;
multiboot_uint16_t reserved;
};
struct multiboot_tag_framebuffer
{
struct multiboot_tag_framebuffer_common common;
union
{
struct
{
multiboot_uint16_t framebuffer_palette_num_colors;
struct multiboot_color framebuffer_palette[0];
};
struct
{
multiboot_uint8_t framebuffer_red_field_position;
multiboot_uint8_t framebuffer_red_mask_size;
multiboot_uint8_t framebuffer_green_field_position;
multiboot_uint8_t framebuffer_green_mask_size;
multiboot_uint8_t framebuffer_blue_field_position;
multiboot_uint8_t framebuffer_blue_mask_size;
};
};
};
struct multiboot_tag_elf_sections
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t num;
multiboot_uint32_t entsize;
multiboot_uint32_t shndx;
char sections[0];
};
struct multiboot_tag_apm
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint16_t version;
multiboot_uint16_t cseg;
multiboot_uint32_t offset;
multiboot_uint16_t cseg_16;
multiboot_uint16_t dseg;
multiboot_uint16_t flags;
multiboot_uint16_t cseg_len;
multiboot_uint16_t cseg_16_len;
multiboot_uint16_t dseg_len;
};
struct multiboot_tag_efi32
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t pointer;
};
struct multiboot_tag_efi64
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t pointer;
};
struct multiboot_tag_smbios
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t major;
multiboot_uint8_t minor;
multiboot_uint8_t reserved[6];
multiboot_uint8_t tables[0];
};
struct multiboot_tag_old_acpi
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t rsdp[0];
};
struct multiboot_tag_new_acpi
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t rsdp[0];
};
struct multiboot_tag_network
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t dhcpack[0];
};
struct multiboot_tag_efi_mmap
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t descr_size;
multiboot_uint32_t descr_vers;
multiboot_uint8_t efi_mmap[0];
};
struct multiboot_tag_efi32_ih
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t pointer;
};
struct multiboot_tag_efi64_ih
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t pointer;
};
struct multiboot_tag_load_base_addr
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t load_base_addr;
};
#endif /* ! ASM_FILE */
#endif /* ! MULTIBOOT_HEADER */

View File

@ -171,11 +171,13 @@ char commonCompileFlagsWithCStdLib[4096];
char cCompileFlags[4096] = "";
char cppCompileFlags[4096] = " -std=c++14 -Wno-pmf-conversions -Wno-invalid-offsetof -fno-rtti ";
char kernelCompileFlags[4096] = " -fno-omit-frame-pointer ";
char multiboot2LoaderCompileFlags[4096] = " -m32 -fno-common -g -mno-mmx -mno-sse -mno-sse2 -mno-ssse3 -mno-sse4 ";
char applicationLinkFlags[4096] = " -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 ";
char apiLinkFlags1[4096] = " -T util/linker/api64.ld -ffreestanding -nostdlib -g -z max-page-size=0x1000 -Wl,--start-group "; // TODO Don't hardcode the target.
char apiLinkFlags2[4096] = " -lgcc ";
char apiLinkFlags3[4096] = " -Wl,--end-group -Lroot/Applications/POSIX/lib ";
char kernelLinkFlags[4096] = " -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 ";
char multiboot2LoaderLinkFlags[4096] = " -nostdlib -melf_i386 --no-dynamic-linker -Tboot/x86/mb2_link.sc -g ";
char commonAssemblyFlags[4096] = " -Fdwarf ";
const char *desktopProfilingFlags = "";
@ -1096,6 +1098,15 @@ void ParseKernelConfiguration() {
DeleteFile("bin/dependency_files/system_config.d");
}
void LinkMultiboot2Loader() {
if (Execute(toolchainLD, "bin/Object Files/mb2_loader.o", "bin/Object Files/mb2.o", ArgString(multiboot2LoaderLinkFlags), "-o" "bin/Multiboot2Loader")) {
return;
}
Execute(toolchainStrip, "-o", "bin/Stripped Executables/Multiboot2Loader", "--strip-all", "bin/Multiboot2Loader");
CopyFile("bin/Stripped Executables/Multiboot2Loader", "root/" SYSTEM_FOLDER_NAME "/Multiboot2Loader.elf", false);
}
void LinkKernel() {
if (encounteredErrorsInKernelModules) {
return;
@ -1157,6 +1168,13 @@ void BuildKernel(Application *application) {
if (application->error) __sync_fetch_and_or(&encounteredErrorsInKernelModules, 1);
}
void BuildMultiboot2Loader(Application *application) {
ExecuteForApp(application, toolchainCXX, "-MD", "-MF", "bin/dependency_files/mb2.d", "-c", "boot/x86/mb2.c", "-o", "bin/Object Files/mb2.o",
ArgString(multiboot2LoaderCompileFlags), ArgString(cppCompileFlags), ArgString(commonCompileFlags), buffer);
ExecuteForApp(application, toolchainCXX, "-MD", "-MF", "bin/dependency_files/mb2.d", "-c", "boot/x86/mb2_loader.S", "-o", "bin/Object Files/mb2_loader.o",
ArgString(multiboot2LoaderCompileFlags), ArgString(cppCompileFlags), ArgString(commonCompileFlags), buffer);
}
void BuildBootloader(Application *application) {
ExecuteForApp(application, toolchainNasm, "-MD", "bin/dependency_files/boot1.d", "-fbin",
forEmulator ? "boot/x86/mbr.s" : "boot/x86/mbr-emu.s" , "-obin/mbr");
@ -1620,6 +1638,15 @@ int main(int argc, char **argv) {
arrput(applications, application);
}
if (systemBuild) {
Application application = {};
application.name = "Multiboot2Loader";
application.buildCallback = BuildMultiboot2Loader;
ADD_DEPENDENCY_FILE(application, "bin/dependency_files/mb2.d", "Multiboot2Loader1");
ADD_DEPENDENCY_FILE(application, "bin/dependency_files/mb2_loader.d", "Multiboot2Loader2");
arrput(applications, application);
}
for (uintptr_t i = 0; i < arrlenu(applicationManifests); i++) {
ParseApplicationManifest(applicationManifests[i]);
}
@ -1746,6 +1773,8 @@ int main(int argc, char **argv) {
LinkKernel();
}
LinkMultiboot2Loader();
OutputSystemConfiguration();
}
}