feat(boot): load separate x86 kernel image from UEFI bootloader
This commit is contained in:
parent
80a2ec024d
commit
f60b6af52f
42
Makefile
42
Makefile
@ -1,12 +1,14 @@
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := clang
|
||||
ELF_LD := ld.lld
|
||||
LD := lld-link
|
||||
ARCH ?= x86_64
|
||||
|
||||
ifeq ($(ARCH),x86_64)
|
||||
ARCH_DIR := arch/x86
|
||||
EFI_ARCH_TARGET := x86_64-unknown-windows
|
||||
KERNEL_ARCH_TARGET := x86_64-unknown-none-elf
|
||||
BOOT_EFI_NAME := BOOTX64.EFI
|
||||
else
|
||||
$(error Unsupported ARCH '$(ARCH)')
|
||||
@ -16,6 +18,8 @@ BUILD_DIR := build
|
||||
EFI_DIR := $(BUILD_DIR)/image/EFI/BOOT
|
||||
BOOT_EFI := $(EFI_DIR)/$(BOOT_EFI_NAME)
|
||||
BOOT_OBJ := $(BUILD_DIR)/arch/boot/main.obj
|
||||
KERNEL_ELF := $(BUILD_DIR)/image/kernel.elf
|
||||
KERNEL_OBJS := $(BUILD_DIR)/arch/kernel/entry.o $(BUILD_DIR)/kernel/main.o
|
||||
DEBUG_LOG := $(BUILD_DIR)/debug.log
|
||||
OVMF_CODE ?= /usr/share/OVMF/OVMF_CODE_4M.fd
|
||||
OVMF_VARS_TEMPLATE ?= /usr/share/OVMF/OVMF_VARS_4M.fd
|
||||
@ -34,6 +38,23 @@ CFLAGS := \
|
||||
-Iinclude \
|
||||
-I$(ARCH_DIR)/include
|
||||
|
||||
KERNEL_CFLAGS := \
|
||||
-target $(KERNEL_ARCH_TARGET) \
|
||||
-ffreestanding \
|
||||
-fno-stack-protector \
|
||||
-fno-builtin \
|
||||
-fno-pic \
|
||||
-mno-red-zone \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Werror \
|
||||
-Iinclude \
|
||||
-I$(ARCH_DIR)/include
|
||||
|
||||
KERNEL_ASFLAGS := \
|
||||
-target $(KERNEL_ARCH_TARGET) \
|
||||
-ffreestanding
|
||||
|
||||
LDFLAGS := \
|
||||
/subsystem:efi_application \
|
||||
/entry:efi_main \
|
||||
@ -42,19 +63,34 @@ LDFLAGS := \
|
||||
/machine:x64 \
|
||||
/out:$(BOOT_EFI)
|
||||
|
||||
KERNEL_LDFLAGS := \
|
||||
-m elf_x86_64 \
|
||||
-nostdlib \
|
||||
-T $(ARCH_DIR)/kernel/linker.ld \
|
||||
-o $(KERNEL_ELF)
|
||||
|
||||
.PHONY: all clean run run-headless dirs
|
||||
|
||||
all: $(BOOT_EFI)
|
||||
all: $(BOOT_EFI) $(KERNEL_ELF)
|
||||
|
||||
dirs:
|
||||
mkdir -p $(BUILD_DIR)/arch/boot $(EFI_DIR)
|
||||
mkdir -p $(BUILD_DIR)/arch/boot $(BUILD_DIR)/arch/kernel $(BUILD_DIR)/kernel $(EFI_DIR)
|
||||
|
||||
$(BOOT_OBJ): $(ARCH_DIR)/boot/main.c $(ARCH_DIR)/include/efi.h include/tianole/boot_info.h | dirs
|
||||
$(BOOT_OBJ): $(ARCH_DIR)/boot/main.c $(ARCH_DIR)/include/efi.h include/tianole/boot_info.h include/tianole/elf.h | dirs
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BOOT_EFI): $(BOOT_OBJ) | dirs
|
||||
$(LD) $(LDFLAGS) $<
|
||||
|
||||
$(BUILD_DIR)/arch/kernel/entry.o: $(ARCH_DIR)/kernel/entry.S | dirs
|
||||
$(CC) $(KERNEL_ASFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/kernel/main.o: kernel/main.c include/tianole/boot_info.h | dirs
|
||||
$(CC) $(KERNEL_CFLAGS) -c $< -o $@
|
||||
|
||||
$(KERNEL_ELF): $(KERNEL_OBJS) $(ARCH_DIR)/kernel/linker.ld | dirs
|
||||
$(ELF_LD) $(KERNEL_LDFLAGS) $(KERNEL_OBJS)
|
||||
|
||||
$(OVMF_VARS): | dirs
|
||||
cp $(OVMF_VARS_TEMPLATE) $@
|
||||
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
#include "efi.h"
|
||||
#include "tianole/elf.h"
|
||||
#include "tianole/boot_info.h"
|
||||
|
||||
static efi_char16_t banner_text[] = {
|
||||
typedef void __attribute__((sysv_abi)) (*kernel_entry_fn_t)(const tianole_boot_info_t *);
|
||||
|
||||
static efi_char16_t boot_banner_text[] = {
|
||||
'T', 'i', 'a', 'n', 'o', 'l', 'e', ' ',
|
||||
'x', '8', '6', ' ', 'b', 'o', 'o', 't',
|
||||
' ', 's', 't', 'u', 'b', ' ', 'l', 'o',
|
||||
'a', 'd', 'e', 'd', '.', '\r', '\n', 0
|
||||
'l', 'o', 'a', 'd', 'e', 'r', '.', '\r', '\n', 0
|
||||
};
|
||||
|
||||
static const tianole_boot_info_t boot_info = {
|
||||
.version = TIANOLE_BOOT_INFO_VERSION,
|
||||
.boot_flags = 0,
|
||||
static efi_char16_t kernel_path_text[] = {
|
||||
'\\', 'k', 'e', 'r', 'n', 'e', 'l', '.',
|
||||
'e', 'l', 'f', 0
|
||||
};
|
||||
|
||||
static inline void debug_putc(char ch) {
|
||||
@ -26,19 +28,240 @@ static void debug_puts(const char *text) {
|
||||
}
|
||||
}
|
||||
|
||||
static void debug_boot_info(const tianole_boot_info_t *info) {
|
||||
(void)info;
|
||||
debug_puts("boot_info.version=1\n");
|
||||
static void *mem_copy(void *dst, const void *src, uint64_t size) {
|
||||
uint8_t *out = (uint8_t *)dst;
|
||||
const uint8_t *in = (const uint8_t *)src;
|
||||
uint64_t i;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
out[i] = in[i];
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void mem_zero(void *dst, uint64_t size) {
|
||||
uint8_t *out = (uint8_t *)dst;
|
||||
uint64_t i;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
out[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static efi_status open_root(
|
||||
efi_handle image_handle,
|
||||
efi_system_table_t *system_table,
|
||||
efi_file_protocol_t **root
|
||||
) {
|
||||
efi_guid_t loaded_image_guid = efi_loaded_image_protocol_guid();
|
||||
efi_guid_t simple_fs_guid = efi_simple_file_system_protocol_guid();
|
||||
efi_loaded_image_protocol_t *loaded_image;
|
||||
efi_simple_file_system_protocol_t *fs;
|
||||
efi_status status;
|
||||
|
||||
status = system_table->boot_services->handle_protocol(
|
||||
image_handle,
|
||||
&loaded_image_guid,
|
||||
(void **)&loaded_image
|
||||
);
|
||||
if (status != EFI_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = system_table->boot_services->handle_protocol(
|
||||
loaded_image->device_handle,
|
||||
&simple_fs_guid,
|
||||
(void **)&fs
|
||||
);
|
||||
if (status != EFI_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return fs->open_volume(fs, root);
|
||||
}
|
||||
|
||||
static efi_status read_entire_file(
|
||||
efi_system_table_t *system_table,
|
||||
efi_file_protocol_t *root,
|
||||
efi_char16_t *path,
|
||||
void **buffer,
|
||||
uint64_t *size
|
||||
) {
|
||||
efi_guid_t file_info_guid = efi_file_info_guid();
|
||||
efi_file_protocol_t *file;
|
||||
efi_file_info_t *file_info;
|
||||
efi_uintn_t info_size;
|
||||
efi_uintn_t read_size;
|
||||
efi_status status;
|
||||
|
||||
status = root->open(root, &file, path, EFI_OPEN_MODE_READ, 0);
|
||||
if (status != EFI_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
info_size = 0;
|
||||
status = file->get_info(file, &file_info_guid, &info_size, 0);
|
||||
if (status != EFI_BUFFER_TOO_SMALL) {
|
||||
file->close(file);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = system_table->boot_services->allocate_pool(EFI_LOADER_DATA, info_size, (void **)&file_info);
|
||||
if (status != EFI_SUCCESS) {
|
||||
file->close(file);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = file->get_info(file, &file_info_guid, &info_size, file_info);
|
||||
if (status != EFI_SUCCESS) {
|
||||
file->close(file);
|
||||
return status;
|
||||
}
|
||||
|
||||
*size = file_info->file_size;
|
||||
status = system_table->boot_services->allocate_pool(EFI_LOADER_DATA, *size, buffer);
|
||||
if (status != EFI_SUCCESS) {
|
||||
file->close(file);
|
||||
return status;
|
||||
}
|
||||
|
||||
read_size = *size;
|
||||
status = file->read(file, &read_size, *buffer);
|
||||
file->close(file);
|
||||
if (status != EFI_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (read_size != *size) {
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static efi_status validate_kernel_elf(const elf64_ehdr_t *ehdr) {
|
||||
if (*(const uint32_t *)ehdr->ident != ELF_MAGIC) {
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
if (ehdr->ident[4] != ELFCLASS64 || ehdr->ident[5] != ELFDATA2LSB) {
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
if (ehdr->ident[6] != EV_CURRENT || ehdr->version != EV_CURRENT) {
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
if (ehdr->type != ET_EXEC || ehdr->machine != EM_X86_64) {
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
if (ehdr->phentsize != sizeof(elf64_phdr_t)) {
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static efi_status load_kernel_image(
|
||||
efi_system_table_t *system_table,
|
||||
const void *kernel_image,
|
||||
uint64_t kernel_size,
|
||||
kernel_entry_fn_t *entry_out
|
||||
) {
|
||||
const elf64_ehdr_t *ehdr = (const elf64_ehdr_t *)kernel_image;
|
||||
const elf64_phdr_t *phdrs;
|
||||
uint16_t index;
|
||||
efi_status status;
|
||||
|
||||
if (kernel_size < sizeof(*ehdr)) {
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
status = validate_kernel_elf(ehdr);
|
||||
if (status != EFI_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
phdrs = (const elf64_phdr_t *)((const uint8_t *)kernel_image + ehdr->phoff);
|
||||
|
||||
for (index = 0; index < ehdr->phnum; ++index) {
|
||||
const elf64_phdr_t *phdr = &phdrs[index];
|
||||
efi_physical_address_t segment_base;
|
||||
uint64_t page_count;
|
||||
|
||||
if (phdr->type != PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (phdr->memsz < phdr->filesz) {
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
if (phdr->offset + phdr->filesz > kernel_size) {
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
segment_base = phdr->paddr;
|
||||
page_count = (phdr->memsz + 0xfffULL) >> 12;
|
||||
status = system_table->boot_services->allocate_pages(
|
||||
EFI_ALLOCATE_ADDRESS,
|
||||
EFI_LOADER_DATA,
|
||||
page_count,
|
||||
&segment_base
|
||||
);
|
||||
if (status != EFI_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
mem_zero((void *)(uintptr_t)phdr->paddr, phdr->memsz);
|
||||
mem_copy(
|
||||
(void *)(uintptr_t)phdr->paddr,
|
||||
(const uint8_t *)kernel_image + phdr->offset,
|
||||
phdr->filesz
|
||||
);
|
||||
}
|
||||
|
||||
*entry_out = (kernel_entry_fn_t)(uintptr_t)ehdr->entry;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
efi_status EFIAPI efi_main(efi_handle image_handle, efi_system_table_t *system_table) {
|
||||
(void)image_handle;
|
||||
efi_file_protocol_t *root;
|
||||
void *kernel_image;
|
||||
uint64_t kernel_size;
|
||||
kernel_entry_fn_t kernel_entry;
|
||||
tianole_boot_info_t boot_info = {
|
||||
.version = TIANOLE_BOOT_INFO_VERSION,
|
||||
.boot_flags = TIANOLE_BOOT_FLAG_BOOT_SERVICES_ACTIVE,
|
||||
};
|
||||
efi_status status;
|
||||
|
||||
system_table->con_out->output_string(system_table->con_out, banner_text);
|
||||
debug_puts("Tianole x86 boot stub loaded.\n");
|
||||
debug_boot_info(&boot_info);
|
||||
system_table->con_out->output_string(system_table->con_out, boot_banner_text);
|
||||
debug_puts("Tianole x86 bootloader loaded.\n");
|
||||
|
||||
status = open_root(image_handle, system_table, &root);
|
||||
if (status != EFI_SUCCESS) {
|
||||
debug_puts("failed: open_root\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = read_entire_file(system_table, root, kernel_path_text, &kernel_image, &kernel_size);
|
||||
root->close(root);
|
||||
if (status != EFI_SUCCESS) {
|
||||
debug_puts("failed: read kernel.elf\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = load_kernel_image(system_table, kernel_image, kernel_size, &kernel_entry);
|
||||
if (status != EFI_SUCCESS) {
|
||||
debug_puts("failed: load kernel image\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
debug_puts("jumping to kernel entry\n");
|
||||
kernel_entry(&boot_info);
|
||||
|
||||
debug_puts("kernel returned unexpectedly\n");
|
||||
for (;;) {
|
||||
system_table->boot_services->stall(1000 * 1000);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
@ -7,8 +7,28 @@ typedef uint64_t efi_status;
|
||||
typedef void *efi_handle;
|
||||
typedef uint16_t efi_char16_t;
|
||||
typedef uint64_t efi_uintn_t;
|
||||
typedef uint64_t efi_physical_address_t;
|
||||
|
||||
#define EFI_SUCCESS 0
|
||||
#define EFI_LOAD_ERROR 0x8000000000000001ULL
|
||||
#define EFI_INVALID_PARAMETER 0x8000000000000002ULL
|
||||
#define EFI_BUFFER_TOO_SMALL 0x8000000000000005ULL
|
||||
#define EFI_OUT_OF_RESOURCES 0x8000000000000009ULL
|
||||
#define EFI_NOT_FOUND 0x800000000000000eULL
|
||||
|
||||
#define EFI_ALLOCATE_ADDRESS 2
|
||||
#define EFI_LOADER_DATA 4
|
||||
#define EFI_OPEN_MODE_READ 0x0000000000000001ULL
|
||||
|
||||
#define EFI_FILE_INFO_ID 0x09576e92
|
||||
#define EFI_FILE_INFO_ID_A 0x6d3f
|
||||
#define EFI_FILE_INFO_ID_B 0x11d2
|
||||
#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID_A 0x964e5b22
|
||||
#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID_B 0x6459
|
||||
#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID_C 0x11d2
|
||||
#define EFI_LOADED_IMAGE_PROTOCOL_GUID_A 0x5b1b31a1
|
||||
#define EFI_LOADED_IMAGE_PROTOCOL_GUID_B 0x9562
|
||||
#define EFI_LOADED_IMAGE_PROTOCOL_GUID_C 0x11d2
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#define EFIAPI __attribute__((ms_abi))
|
||||
@ -16,6 +36,13 @@ typedef uint64_t efi_uintn_t;
|
||||
#define EFIAPI
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t data1;
|
||||
uint16_t data2;
|
||||
uint16_t data3;
|
||||
uint8_t data4[8];
|
||||
} efi_guid_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t signature;
|
||||
uint32_t revision;
|
||||
@ -26,6 +53,10 @@ typedef struct {
|
||||
|
||||
typedef struct efi_simple_text_output_protocol efi_simple_text_output_protocol_t;
|
||||
typedef struct efi_boot_services efi_boot_services_t;
|
||||
typedef struct efi_simple_file_system_protocol efi_simple_file_system_protocol_t;
|
||||
typedef struct efi_file_protocol efi_file_protocol_t;
|
||||
typedef struct efi_loaded_image_protocol efi_loaded_image_protocol_t;
|
||||
typedef struct efi_system_table efi_system_table_t;
|
||||
|
||||
struct efi_simple_text_output_protocol {
|
||||
void *reset;
|
||||
@ -35,14 +66,87 @@ struct efi_simple_text_output_protocol {
|
||||
);
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint64_t size;
|
||||
uint64_t file_size;
|
||||
uint64_t physical_size;
|
||||
uint64_t create_time[2];
|
||||
uint64_t last_access_time[2];
|
||||
uint64_t modification_time[2];
|
||||
uint64_t attribute;
|
||||
efi_char16_t file_name[1];
|
||||
} efi_file_info_t;
|
||||
|
||||
struct efi_file_protocol {
|
||||
uint64_t revision;
|
||||
efi_status(EFIAPI *open)(
|
||||
efi_file_protocol_t *self,
|
||||
efi_file_protocol_t **new_handle,
|
||||
efi_char16_t *file_name,
|
||||
uint64_t open_mode,
|
||||
uint64_t attributes
|
||||
);
|
||||
efi_status(EFIAPI *close)(efi_file_protocol_t *self);
|
||||
void *delete_;
|
||||
efi_status(EFIAPI *read)(
|
||||
efi_file_protocol_t *self,
|
||||
efi_uintn_t *buffer_size,
|
||||
void *buffer
|
||||
);
|
||||
void *write;
|
||||
void *get_position;
|
||||
void *set_position;
|
||||
efi_status(EFIAPI *get_info)(
|
||||
efi_file_protocol_t *self,
|
||||
efi_guid_t *information_type,
|
||||
efi_uintn_t *buffer_size,
|
||||
void *buffer
|
||||
);
|
||||
void *set_info;
|
||||
void *flush;
|
||||
};
|
||||
|
||||
struct efi_simple_file_system_protocol {
|
||||
uint64_t revision;
|
||||
efi_status(EFIAPI *open_volume)(
|
||||
efi_simple_file_system_protocol_t *self,
|
||||
efi_file_protocol_t **root
|
||||
);
|
||||
};
|
||||
|
||||
struct efi_loaded_image_protocol {
|
||||
uint32_t revision;
|
||||
efi_handle parent_handle;
|
||||
efi_system_table_t *system_table;
|
||||
efi_handle device_handle;
|
||||
void *file_path;
|
||||
void *reserved;
|
||||
uint32_t load_options_size;
|
||||
void *load_options;
|
||||
void *image_base;
|
||||
uint64_t image_size;
|
||||
uint32_t image_code_type;
|
||||
uint32_t image_data_type;
|
||||
void *unload;
|
||||
};
|
||||
|
||||
struct efi_boot_services {
|
||||
efi_table_header_t hdr;
|
||||
void *raise_tpl;
|
||||
void *restore_tpl;
|
||||
void *allocate_pages;
|
||||
efi_status(EFIAPI *allocate_pages)(
|
||||
int type,
|
||||
int memory_type,
|
||||
efi_uintn_t pages,
|
||||
efi_physical_address_t *memory
|
||||
);
|
||||
void *free_pages;
|
||||
void *get_memory_map;
|
||||
void *allocate_pool;
|
||||
efi_status(EFIAPI *allocate_pool)(
|
||||
int pool_type,
|
||||
efi_uintn_t size,
|
||||
void **buffer
|
||||
);
|
||||
void *free_pool;
|
||||
void *create_event;
|
||||
void *set_timer;
|
||||
@ -53,7 +157,11 @@ struct efi_boot_services {
|
||||
void *install_protocol_interface;
|
||||
void *reinstall_protocol_interface;
|
||||
void *uninstall_protocol_interface;
|
||||
void *handle_protocol;
|
||||
efi_status(EFIAPI *handle_protocol)(
|
||||
efi_handle handle,
|
||||
efi_guid_t *protocol,
|
||||
void **interface
|
||||
);
|
||||
void *reserved;
|
||||
void *register_protocol_notify;
|
||||
void *locate_handle;
|
||||
@ -69,7 +177,7 @@ struct efi_boot_services {
|
||||
void *set_watchdog_timer;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct efi_system_table {
|
||||
efi_table_header_t hdr;
|
||||
efi_char16_t *firmware_vendor;
|
||||
uint32_t firmware_revision;
|
||||
@ -83,6 +191,33 @@ typedef struct {
|
||||
efi_boot_services_t *boot_services;
|
||||
uint64_t number_of_table_entries;
|
||||
void *configuration_table;
|
||||
} efi_system_table_t;
|
||||
};
|
||||
|
||||
static inline efi_guid_t efi_file_info_guid(void) {
|
||||
return (efi_guid_t){
|
||||
.data1 = EFI_FILE_INFO_ID,
|
||||
.data2 = EFI_FILE_INFO_ID_A,
|
||||
.data3 = EFI_FILE_INFO_ID_B,
|
||||
.data4 = {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b},
|
||||
};
|
||||
}
|
||||
|
||||
static inline efi_guid_t efi_simple_file_system_protocol_guid(void) {
|
||||
return (efi_guid_t){
|
||||
.data1 = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID_A,
|
||||
.data2 = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID_B,
|
||||
.data3 = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID_C,
|
||||
.data4 = {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b},
|
||||
};
|
||||
}
|
||||
|
||||
static inline efi_guid_t efi_loaded_image_protocol_guid(void) {
|
||||
return (efi_guid_t){
|
||||
.data1 = EFI_LOADED_IMAGE_PROTOCOL_GUID_A,
|
||||
.data2 = EFI_LOADED_IMAGE_PROTOCOL_GUID_B,
|
||||
.data3 = EFI_LOADED_IMAGE_PROTOCOL_GUID_C,
|
||||
.data4 = {0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b},
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
17
arch/x86/kernel/entry.S
Normal file
17
arch/x86/kernel/entry.S
Normal file
@ -0,0 +1,17 @@
|
||||
.global _start
|
||||
.type _start, @function
|
||||
|
||||
.section .text
|
||||
_start:
|
||||
lea kernel_stack_top(%rip), %rsp
|
||||
call kernel_main
|
||||
|
||||
1:
|
||||
hlt
|
||||
jmp 1b
|
||||
|
||||
.section .bss
|
||||
.balign 16
|
||||
kernel_stack:
|
||||
.skip 16384
|
||||
kernel_stack_top:
|
||||
23
arch/x86/kernel/linker.ld
Normal file
23
arch/x86/kernel/linker.ld
Normal file
@ -0,0 +1,23 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x200000;
|
||||
|
||||
.text : ALIGN(4K) {
|
||||
*(.text .text.*)
|
||||
}
|
||||
|
||||
.rodata : ALIGN(4K) {
|
||||
*(.rodata .rodata.*)
|
||||
}
|
||||
|
||||
.data : ALIGN(4K) {
|
||||
*(.data .data.*)
|
||||
}
|
||||
|
||||
.bss : ALIGN(4K) {
|
||||
*(COMMON)
|
||||
*(.bss .bss.*)
|
||||
}
|
||||
}
|
||||
@ -149,6 +149,12 @@
|
||||
- 屏幕和 `debug.log` 有可见输出
|
||||
- 程序可常驻,便于调试
|
||||
|
||||
当前已经开始进入第 1 阶段:
|
||||
|
||||
- 代码结构已经为 `bootloader -> kernel` 交接预留边界
|
||||
- `boot_info` 已经作为项目自有交接结构存在
|
||||
- `arch/x86/` 已经承载当前架构专用启动代码
|
||||
|
||||
当前还没有完成:
|
||||
|
||||
- 独立 `kernel` 接管
|
||||
|
||||
@ -14,5 +14,6 @@ typedef struct {
|
||||
} tianole_boot_info_t;
|
||||
|
||||
#define TIANOLE_BOOT_INFO_VERSION 1u
|
||||
#define TIANOLE_BOOT_FLAG_BOOT_SERVICES_ACTIVE (1u << 0)
|
||||
|
||||
#endif
|
||||
|
||||
44
include/tianole/elf.h
Normal file
44
include/tianole/elf.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef TIANOLE_ELF_H
|
||||
#define TIANOLE_ELF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define ELF_MAGIC 0x464c457fu
|
||||
#define ELFCLASS64 2
|
||||
#define ELFDATA2LSB 1
|
||||
#define EV_CURRENT 1
|
||||
|
||||
#define ET_EXEC 2
|
||||
#define EM_X86_64 62
|
||||
|
||||
#define PT_LOAD 1
|
||||
|
||||
typedef struct {
|
||||
unsigned char 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 ehsize;
|
||||
uint16_t phentsize;
|
||||
uint16_t phnum;
|
||||
uint16_t shentsize;
|
||||
uint16_t shnum;
|
||||
uint16_t shstrndx;
|
||||
} elf64_ehdr_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
uint32_t flags;
|
||||
uint64_t offset;
|
||||
uint64_t vaddr;
|
||||
uint64_t paddr;
|
||||
uint64_t filesz;
|
||||
uint64_t memsz;
|
||||
uint64_t align;
|
||||
} elf64_phdr_t;
|
||||
|
||||
#endif
|
||||
@ -1,4 +1,33 @@
|
||||
/*
|
||||
* Kernel code starts in the next stage.
|
||||
* The initial milestone is a verified UEFI boot path.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tianole/boot_info.h"
|
||||
|
||||
static inline void debug_putc(char ch) {
|
||||
__asm__ volatile("outb %0, $0xe9" : : "a"(ch));
|
||||
}
|
||||
|
||||
static void debug_puts(const char *text) {
|
||||
while (*text != '\0') {
|
||||
if (*text == '\n') {
|
||||
debug_putc('\r');
|
||||
}
|
||||
debug_putc(*text++);
|
||||
}
|
||||
}
|
||||
|
||||
void kernel_main(const tianole_boot_info_t *boot_info) {
|
||||
debug_puts("kernel_main entered\n");
|
||||
if (boot_info != 0 && boot_info->version == TIANOLE_BOOT_INFO_VERSION) {
|
||||
debug_puts("boot_info.version ok\n");
|
||||
} else {
|
||||
debug_puts("boot_info.version invalid\n");
|
||||
}
|
||||
|
||||
if (boot_info != 0 && (boot_info->boot_flags & TIANOLE_BOOT_FLAG_BOOT_SERVICES_ACTIVE) != 0) {
|
||||
debug_puts("boot services still active\n");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
__asm__ volatile("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user