refactor(build): split makefiles and normalize internal API names
- align makefile layout with Linux-style directories
This commit is contained in:
parent
62c8836886
commit
e3782144b8
17
.clang-format
Normal file
17
.clang-format
Normal file
@ -0,0 +1,17 @@
|
||||
BasedOnStyle: LLVM
|
||||
UseTab: Always
|
||||
IndentWidth: 8
|
||||
TabWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
BreakBeforeBraces: Linux
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignOperands: DontAlign
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
ColumnLimit: 80
|
||||
PointerAlignment: Right
|
||||
23
.github/workflows/check.yml
vendored
Normal file
23
.github/workflows/check.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: check
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build-and-boot:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
clang \
|
||||
lld \
|
||||
qemu-system-x86 \
|
||||
ovmf
|
||||
|
||||
- name: Run project checks
|
||||
run: ./scripts/check.sh
|
||||
@ -24,3 +24,12 @@
|
||||
- 当前代码以“先做最小,但不把架构完全写死”为原则推进。
|
||||
- `arch/` 放架构相关实现。
|
||||
- `include/tianole/` 放尽量与具体架构无关的共享接口。
|
||||
- 入口文件只负责串联启动流程,不承载文件加载、ELF 解析、内存映射统计等功能细节。
|
||||
- 检查式日志应该放在对应功能模块中,避免把 `kernel_main()` 变成临时测试脚本。
|
||||
- 内部 C API 不加 `tianole_` 前缀;这是单一内核代码库,不把项目名重复进函数名和类型名。
|
||||
- 避免 `temp` / `tmp` 这类临时语义进入函数名、类型名和长期变量名;一次性局部变量可以用具体含义命名。
|
||||
- C 代码风格参考 Linux:tabs 缩进,函数左花括号另起一行,`if/for/while` 左花括号留在行尾。
|
||||
- 文本文件使用 LF 行尾。
|
||||
- `.clang-format` 是当前格式化约定;如果环境有 `clang-format`,新增或大改 C/H 文件后应按它格式化。
|
||||
- 根 `Makefile` 只做总控和通用规则;架构配置放在 `arch/<arch>/Makefile`,目录自己的源文件列表放在对应目录的 `Makefile` 中。
|
||||
- 本地维护入口是 `scripts/check.sh`;GitHub Actions 应调用同一个脚本,避免 CI 逻辑和本地逻辑分叉。
|
||||
|
||||
80
Makefile
80
Makefile
@ -1,91 +1,43 @@
|
||||
SHELL := /bin/bash
|
||||
|
||||
ARCH ?= x86_64
|
||||
|
||||
CC := clang
|
||||
ELF_LD := ld.lld
|
||||
LD := lld-link
|
||||
ARCH ?= x86_64
|
||||
|
||||
BUILD_DIR := build
|
||||
KERNEL_ELF := $(BUILD_DIR)/image/kernel.elf
|
||||
DEBUG_LOG := $(BUILD_DIR)/debug.log
|
||||
|
||||
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
|
||||
ARCH_MAKEFILE := arch/x86/Makefile
|
||||
else
|
||||
$(error Unsupported ARCH '$(ARCH)')
|
||||
endif
|
||||
|
||||
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
|
||||
OVMF_VARS := $(BUILD_DIR)/OVMF_VARS.fd
|
||||
include $(ARCH_MAKEFILE)
|
||||
include $(ARCH_DIR)/boot/Makefile
|
||||
include $(ARCH_DIR)/kernel/Makefile
|
||||
include kernel/Makefile
|
||||
|
||||
CFLAGS := \
|
||||
-target $(EFI_ARCH_TARGET) \
|
||||
-ffreestanding \
|
||||
-fshort-wchar \
|
||||
-mno-red-zone \
|
||||
-fno-stack-protector \
|
||||
-fno-builtin \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Werror \
|
||||
-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 \
|
||||
/nodefaultlib \
|
||||
/dll \
|
||||
/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
|
||||
.PHONY: all clean dirs run run-headless
|
||||
|
||||
all: $(BOOT_EFI) $(KERNEL_ELF)
|
||||
|
||||
dirs:
|
||||
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 include/tianole/elf.h | dirs
|
||||
$(BUILD_DIR)/arch/boot/%.obj: $(ARCH_DIR)/boot/%.c $(ARCH_DIR)/include/efi.h $(ARCH_DIR)/include/tianole/early_log.h include/tianole/boot_info.h include/tianole/elf.h | dirs
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BOOT_EFI): $(BOOT_OBJ) | dirs
|
||||
$(LD) $(LDFLAGS) $<
|
||||
$(BOOT_EFI): $(BOOT_OBJS) | dirs
|
||||
$(LD) $(LDFLAGS) $(BOOT_OBJS)
|
||||
|
||||
$(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
|
||||
$(BUILD_DIR)/kernel/%.o: kernel/%.c include/tianole/boot_info.h include/tianole/kernel_init.h $(ARCH_DIR)/include/tianole/early_log.h | dirs
|
||||
$(CC) $(KERNEL_CFLAGS) -c $< -o $@
|
||||
|
||||
$(KERNEL_ELF): $(KERNEL_OBJS) $(ARCH_DIR)/kernel/linker.ld | dirs
|
||||
|
||||
@ -65,6 +65,14 @@ make run-headless
|
||||
cat build/debug.log
|
||||
```
|
||||
|
||||
本地完整检查:
|
||||
|
||||
```bash
|
||||
scripts/check.sh
|
||||
```
|
||||
|
||||
GitHub Actions 会在 push 和 pull request 时运行同一个检查脚本。
|
||||
|
||||
## 文档
|
||||
|
||||
- 路线图:[docs/roadmap.md](//wsl.localhost/Ubuntu/home/indole/tianole/docs/roadmap.md)
|
||||
|
||||
54
arch/x86/Makefile
Normal file
54
arch/x86/Makefile
Normal file
@ -0,0 +1,54 @@
|
||||
ARCH_DIR := arch/x86
|
||||
EFI_ARCH_TARGET := x86_64-unknown-windows
|
||||
KERNEL_ARCH_TARGET := x86_64-unknown-none-elf
|
||||
BOOT_EFI_NAME := BOOTX64.EFI
|
||||
|
||||
EFI_DIR := $(BUILD_DIR)/image/EFI/BOOT
|
||||
BOOT_EFI := $(EFI_DIR)/$(BOOT_EFI_NAME)
|
||||
OVMF_CODE ?= /usr/share/OVMF/OVMF_CODE_4M.fd
|
||||
OVMF_VARS_TEMPLATE ?= /usr/share/OVMF/OVMF_VARS_4M.fd
|
||||
OVMF_VARS := $(BUILD_DIR)/OVMF_VARS.fd
|
||||
|
||||
CFLAGS := \
|
||||
-target $(EFI_ARCH_TARGET) \
|
||||
-ffreestanding \
|
||||
-fshort-wchar \
|
||||
-mno-red-zone \
|
||||
-fno-stack-protector \
|
||||
-fno-builtin \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Werror \
|
||||
-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 \
|
||||
/nodefaultlib \
|
||||
/dll \
|
||||
/machine:x64 \
|
||||
/out:$(BOOT_EFI)
|
||||
|
||||
KERNEL_LDFLAGS := \
|
||||
-m elf_x86_64 \
|
||||
-nostdlib \
|
||||
-T $(ARCH_DIR)/kernel/linker.ld \
|
||||
-o $(KERNEL_ELF)
|
||||
8
arch/x86/boot/Makefile
Normal file
8
arch/x86/boot/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
BOOT_SRCS := \
|
||||
$(ARCH_DIR)/boot/main.c \
|
||||
$(ARCH_DIR)/boot/file.c \
|
||||
$(ARCH_DIR)/boot/elf_loader.c \
|
||||
$(ARCH_DIR)/boot/memory_map.c \
|
||||
$(ARCH_DIR)/boot/support.c
|
||||
|
||||
BOOT_OBJS := $(patsubst $(ARCH_DIR)/boot/%.c,$(BUILD_DIR)/arch/boot/%.obj,$(BOOT_SRCS))
|
||||
106
arch/x86/boot/elf_loader.c
Normal file
106
arch/x86/boot/elf_loader.c
Normal file
@ -0,0 +1,106 @@
|
||||
#include "elf_loader.h"
|
||||
|
||||
#include "tianole/elf.h"
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
efi_status boot_load_kernel_elf(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;
|
||||
}
|
||||
17
arch/x86/boot/elf_loader.h
Normal file
17
arch/x86/boot/elf_loader.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef X86_BOOT_ELF_LOADER_H
|
||||
#define X86_BOOT_ELF_LOADER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "efi.h"
|
||||
#include "tianole/boot_info.h"
|
||||
|
||||
typedef void
|
||||
__attribute__((sysv_abi)) (*kernel_entry_fn_t)(const boot_info_t *);
|
||||
|
||||
efi_status boot_load_kernel_elf(efi_system_table_t *system_table,
|
||||
const void *kernel_image,
|
||||
uint64_t kernel_size,
|
||||
kernel_entry_fn_t *entry_out);
|
||||
|
||||
#endif
|
||||
93
arch/x86/boot/file.c
Normal file
93
arch/x86/boot/file.c
Normal file
@ -0,0 +1,93 @@
|
||||
#include "file.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
efi_status boot_read_file(efi_handle image_handle,
|
||||
efi_system_table_t *system_table,
|
||||
efi_char16_t *path,
|
||||
void **buffer,
|
||||
uint64_t *size)
|
||||
{
|
||||
efi_guid_t file_info_guid = efi_file_info_guid();
|
||||
efi_file_protocol_t *root;
|
||||
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 = open_root(image_handle, system_table, &root);
|
||||
if (status != EFI_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = root->open(root, &file, path, EFI_OPEN_MODE_READ, 0);
|
||||
root->close(root);
|
||||
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;
|
||||
}
|
||||
14
arch/x86/boot/file.h
Normal file
14
arch/x86/boot/file.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef X86_BOOT_FILE_H
|
||||
#define X86_BOOT_FILE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "efi.h"
|
||||
|
||||
efi_status boot_read_file(efi_handle image_handle,
|
||||
efi_system_table_t *system_table,
|
||||
efi_char16_t *path,
|
||||
void **buffer,
|
||||
uint64_t *size);
|
||||
|
||||
#endif
|
||||
@ -1,358 +1,60 @@
|
||||
#include "efi.h"
|
||||
#include "tianole/elf.h"
|
||||
#include "elf_loader.h"
|
||||
#include "file.h"
|
||||
#include "memory_map.h"
|
||||
#include "tianole/boot_info.h"
|
||||
#include "tianole/early_log.h"
|
||||
|
||||
typedef void __attribute__((sysv_abi)) (*kernel_entry_fn_t)(const tianole_boot_info_t *);
|
||||
static efi_char16_t boot_banner_text[] = u"Tianole x86 bootloader.\r\n";
|
||||
static efi_char16_t kernel_path_text[] = u"\\kernel.elf";
|
||||
|
||||
static efi_char16_t boot_banner_text[] = {
|
||||
'T', 'i', 'a', 'n', 'o', 'l', 'e', ' ',
|
||||
'x', '8', '6', ' ', 'b', 'o', 'o', 't',
|
||||
'l', 'o', 'a', 'd', 'e', 'r', '.', '\r', '\n', 0
|
||||
};
|
||||
efi_status EFIAPI efi_main(
|
||||
efi_handle image_handle, efi_system_table_t *system_table)
|
||||
{
|
||||
void *kernel_image;
|
||||
uint64_t kernel_size;
|
||||
kernel_entry_fn_t kernel_entry;
|
||||
boot_info_t boot_info = {
|
||||
.version = BOOT_INFO_VERSION,
|
||||
.boot_flags = BOOT_FLAG_SERVICES_ACTIVE,
|
||||
};
|
||||
efi_status status;
|
||||
|
||||
static efi_char16_t kernel_path_text[] = {
|
||||
'\\', 'k', 'e', 'r', 'n', 'e', 'l', '.',
|
||||
'e', 'l', 'f', 0
|
||||
};
|
||||
system_table->con_out->output_string(
|
||||
system_table->con_out, boot_banner_text);
|
||||
early_log_puts("Tianole x86 bootloader loaded.\n");
|
||||
|
||||
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++);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void *memset(void *dst, int value, __SIZE_TYPE__ size) {
|
||||
uint8_t *out = (uint8_t *)dst;
|
||||
__SIZE_TYPE__ i;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
out[i] = (uint8_t)value;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void debug_put_hex64(uint64_t value) {
|
||||
static const char digits[] = "0123456789abcdef";
|
||||
int shift;
|
||||
|
||||
debug_puts("0x");
|
||||
for (shift = 60; shift >= 0; shift -= 4) {
|
||||
debug_putc(digits[(value >> shift) & 0xf]);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static efi_status fetch_memory_map(
|
||||
efi_system_table_t *system_table,
|
||||
tianole_boot_info_t *boot_info
|
||||
) {
|
||||
tianole_efi_memory_descriptor_t *memory_map;
|
||||
efi_uintn_t memory_map_size;
|
||||
efi_uintn_t map_key;
|
||||
efi_uintn_t descriptor_size;
|
||||
uint32_t descriptor_version;
|
||||
efi_status status;
|
||||
|
||||
memory_map_size = 0;
|
||||
map_key = 0;
|
||||
descriptor_size = 0;
|
||||
descriptor_version = 0;
|
||||
status = system_table->boot_services->get_memory_map(
|
||||
&memory_map_size,
|
||||
0,
|
||||
&map_key,
|
||||
&descriptor_size,
|
||||
&descriptor_version
|
||||
);
|
||||
if (status != EFI_BUFFER_TOO_SMALL) {
|
||||
return status;
|
||||
}
|
||||
|
||||
memory_map_size += descriptor_size * 8;
|
||||
status = system_table->boot_services->allocate_pool(
|
||||
EFI_LOADER_DATA,
|
||||
memory_map_size,
|
||||
(void **)&memory_map
|
||||
);
|
||||
if (status != EFI_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = system_table->boot_services->get_memory_map(
|
||||
&memory_map_size,
|
||||
memory_map,
|
||||
&map_key,
|
||||
&descriptor_size,
|
||||
&descriptor_version
|
||||
);
|
||||
if (status != EFI_SUCCESS) {
|
||||
system_table->boot_services->free_pool(memory_map);
|
||||
return status;
|
||||
}
|
||||
|
||||
boot_info->memory_map = (uint64_t)(uintptr_t)memory_map;
|
||||
boot_info->memory_map_size = memory_map_size;
|
||||
boot_info->memory_map_key = map_key;
|
||||
boot_info->memory_descriptor_size = descriptor_size;
|
||||
boot_info->memory_descriptor_version = descriptor_version;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
efi_status EFIAPI efi_main(efi_handle image_handle, efi_system_table_t *system_table) {
|
||||
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, 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;
|
||||
}
|
||||
|
||||
status = fetch_memory_map(system_table, &boot_info);
|
||||
if (status != EFI_SUCCESS) {
|
||||
debug_puts("failed: fetch memory map\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
debug_puts("memory_map descriptors_size=");
|
||||
debug_put_hex64(boot_info.memory_descriptor_size);
|
||||
debug_puts("\n");
|
||||
debug_puts("memory_map size=");
|
||||
debug_put_hex64(boot_info.memory_map_size);
|
||||
debug_puts("\n");
|
||||
|
||||
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;
|
||||
status = boot_read_file(image_handle,
|
||||
system_table,
|
||||
kernel_path_text,
|
||||
&kernel_image,
|
||||
&kernel_size);
|
||||
if (status != EFI_SUCCESS) {
|
||||
early_log_puts("failed: read kernel.elf\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = boot_load_kernel_elf(
|
||||
system_table, kernel_image, kernel_size, &kernel_entry);
|
||||
if (status != EFI_SUCCESS) {
|
||||
early_log_puts("failed: load kernel image\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = boot_exit_services_with_latest_memory_map(
|
||||
image_handle, system_table, &boot_info);
|
||||
if (status != EFI_SUCCESS) {
|
||||
early_log_puts("failed: exit boot services\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
early_log_puts("jumping to kernel entry\n");
|
||||
kernel_entry(&boot_info);
|
||||
|
||||
early_log_puts("kernel returned unexpectedly\n");
|
||||
for (;;) {
|
||||
__asm__ volatile("hlt");
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
74
arch/x86/boot/memory_map.c
Normal file
74
arch/x86/boot/memory_map.c
Normal file
@ -0,0 +1,74 @@
|
||||
#include "memory_map.h"
|
||||
|
||||
static efi_status fetch_memory_map(
|
||||
efi_system_table_t *system_table, boot_info_t *boot_info)
|
||||
{
|
||||
boot_memory_descriptor_t *memory_map;
|
||||
efi_uintn_t memory_map_size;
|
||||
efi_uintn_t map_key;
|
||||
efi_uintn_t descriptor_size;
|
||||
uint32_t descriptor_version;
|
||||
efi_status status;
|
||||
|
||||
memory_map_size = 0;
|
||||
map_key = 0;
|
||||
descriptor_size = 0;
|
||||
descriptor_version = 0;
|
||||
status = system_table->boot_services->get_memory_map(&memory_map_size,
|
||||
0,
|
||||
&map_key,
|
||||
&descriptor_size,
|
||||
&descriptor_version);
|
||||
if (status != EFI_BUFFER_TOO_SMALL) {
|
||||
return status;
|
||||
}
|
||||
|
||||
memory_map_size += descriptor_size * 8;
|
||||
status = system_table->boot_services->allocate_pool(
|
||||
EFI_LOADER_DATA, memory_map_size, (void **)&memory_map);
|
||||
if (status != EFI_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = system_table->boot_services->get_memory_map(&memory_map_size,
|
||||
memory_map,
|
||||
&map_key,
|
||||
&descriptor_size,
|
||||
&descriptor_version);
|
||||
if (status != EFI_SUCCESS) {
|
||||
system_table->boot_services->free_pool(memory_map);
|
||||
return status;
|
||||
}
|
||||
|
||||
boot_info->memory_map = (uint64_t)(uintptr_t)memory_map;
|
||||
boot_info->memory_map_size = memory_map_size;
|
||||
boot_info->memory_map_key = map_key;
|
||||
boot_info->memory_descriptor_size = descriptor_size;
|
||||
boot_info->memory_descriptor_version = descriptor_version;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
efi_status boot_exit_services_with_latest_memory_map(efi_handle image_handle,
|
||||
efi_system_table_t *system_table,
|
||||
boot_info_t *boot_info)
|
||||
{
|
||||
efi_status status;
|
||||
uint32_t exit_try;
|
||||
|
||||
for (exit_try = 0; exit_try < 2; ++exit_try) {
|
||||
status = fetch_memory_map(system_table, boot_info);
|
||||
if (status != EFI_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = system_table->boot_services->exit_boot_services(
|
||||
image_handle, boot_info->memory_map_key);
|
||||
if (status == EFI_SUCCESS) {
|
||||
boot_info->boot_flags &= ~BOOT_FLAG_SERVICES_ACTIVE;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
11
arch/x86/boot/memory_map.h
Normal file
11
arch/x86/boot/memory_map.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef X86_BOOT_MEMORY_MAP_H
|
||||
#define X86_BOOT_MEMORY_MAP_H
|
||||
|
||||
#include "efi.h"
|
||||
#include "tianole/boot_info.h"
|
||||
|
||||
efi_status boot_exit_services_with_latest_memory_map(efi_handle image_handle,
|
||||
efi_system_table_t *system_table,
|
||||
boot_info_t *boot_info);
|
||||
|
||||
#endif
|
||||
13
arch/x86/boot/support.c
Normal file
13
arch/x86/boot/support.c
Normal file
@ -0,0 +1,13 @@
|
||||
#include <stdint.h>
|
||||
|
||||
void *memset(void *dst, int value, __SIZE_TYPE__ size)
|
||||
{
|
||||
uint8_t *out = (uint8_t *)dst;
|
||||
__SIZE_TYPE__ i;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
out[i] = (uint8_t)value;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef TIANOLE_ARCH_X86_EFI_H
|
||||
#define TIANOLE_ARCH_X86_EFI_H
|
||||
#ifndef X86_EFI_H
|
||||
#define X86_EFI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -11,10 +11,10 @@ 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_INVALID_PARAMETER 0x8000000000000002ULL
|
||||
|
||||
#define EFI_ALLOCATE_ADDRESS 2
|
||||
#define EFI_LOADER_DATA 4
|
||||
@ -37,193 +37,179 @@ typedef uint64_t efi_physical_address_t;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t data1;
|
||||
uint16_t data2;
|
||||
uint16_t data3;
|
||||
uint8_t data4[8];
|
||||
uint32_t data1;
|
||||
uint16_t data2;
|
||||
uint16_t data3;
|
||||
uint8_t data4[8];
|
||||
} efi_guid_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t signature;
|
||||
uint32_t revision;
|
||||
uint32_t header_size;
|
||||
uint32_t crc32;
|
||||
uint32_t reserved;
|
||||
uint64_t signature;
|
||||
uint32_t revision;
|
||||
uint32_t header_size;
|
||||
uint32_t crc32;
|
||||
uint32_t reserved;
|
||||
} efi_table_header_t;
|
||||
|
||||
typedef struct efi_simple_text_output_protocol efi_simple_text_output_protocol_t;
|
||||
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_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;
|
||||
efi_status(EFIAPI *output_string)(
|
||||
efi_simple_text_output_protocol_t *self,
|
||||
efi_char16_t *string
|
||||
);
|
||||
void *reset;
|
||||
efi_status(EFIAPI *output_string)(
|
||||
efi_simple_text_output_protocol_t *self, efi_char16_t *string);
|
||||
};
|
||||
|
||||
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];
|
||||
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;
|
||||
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
|
||||
);
|
||||
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;
|
||||
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;
|
||||
efi_status(EFIAPI *allocate_pages)(
|
||||
int type,
|
||||
int memory_type,
|
||||
efi_uintn_t pages,
|
||||
efi_physical_address_t *memory
|
||||
);
|
||||
void *free_pages;
|
||||
efi_status(EFIAPI *get_memory_map)(
|
||||
efi_uintn_t *memory_map_size,
|
||||
void *memory_map,
|
||||
efi_uintn_t *map_key,
|
||||
efi_uintn_t *descriptor_size,
|
||||
uint32_t *descriptor_version
|
||||
);
|
||||
efi_status(EFIAPI *allocate_pool)(
|
||||
int pool_type,
|
||||
efi_uintn_t size,
|
||||
void **buffer
|
||||
);
|
||||
efi_status(EFIAPI *free_pool)(void *buffer);
|
||||
void *create_event;
|
||||
void *set_timer;
|
||||
void *wait_for_event;
|
||||
void *signal_event;
|
||||
void *close_event;
|
||||
void *check_event;
|
||||
void *install_protocol_interface;
|
||||
void *reinstall_protocol_interface;
|
||||
void *uninstall_protocol_interface;
|
||||
efi_status(EFIAPI *handle_protocol)(
|
||||
efi_handle handle,
|
||||
efi_guid_t *protocol,
|
||||
void **interface
|
||||
);
|
||||
void *reserved;
|
||||
void *register_protocol_notify;
|
||||
void *locate_handle;
|
||||
void *locate_device_path;
|
||||
void *install_configuration_table;
|
||||
void *load_image;
|
||||
void *start_image;
|
||||
void *exit;
|
||||
void *unload_image;
|
||||
void *exit_boot_services;
|
||||
void *get_next_monotonic_count;
|
||||
void(EFIAPI *stall)(efi_uintn_t microseconds);
|
||||
void *set_watchdog_timer;
|
||||
efi_table_header_t hdr;
|
||||
void *raise_tpl;
|
||||
void *restore_tpl;
|
||||
efi_status(EFIAPI *allocate_pages)(int type,
|
||||
int memory_type,
|
||||
efi_uintn_t pages,
|
||||
efi_physical_address_t *memory);
|
||||
void *free_pages;
|
||||
efi_status(EFIAPI *get_memory_map)(efi_uintn_t *memory_map_size,
|
||||
void *memory_map,
|
||||
efi_uintn_t *map_key,
|
||||
efi_uintn_t *descriptor_size,
|
||||
uint32_t *descriptor_version);
|
||||
efi_status(EFIAPI *allocate_pool)(
|
||||
int pool_type, efi_uintn_t size, void **buffer);
|
||||
efi_status(EFIAPI *free_pool)(void *buffer);
|
||||
void *create_event;
|
||||
void *set_timer;
|
||||
void *wait_for_event;
|
||||
void *signal_event;
|
||||
void *close_event;
|
||||
void *check_event;
|
||||
void *install_protocol_interface;
|
||||
void *reinstall_protocol_interface;
|
||||
void *uninstall_protocol_interface;
|
||||
efi_status(EFIAPI *handle_protocol)(
|
||||
efi_handle handle, efi_guid_t *protocol, void **interface);
|
||||
void *reserved;
|
||||
void *register_protocol_notify;
|
||||
void *locate_handle;
|
||||
void *locate_device_path;
|
||||
void *install_configuration_table;
|
||||
void *load_image;
|
||||
void *start_image;
|
||||
void *exit;
|
||||
void *unload_image;
|
||||
efi_status(EFIAPI *exit_boot_services)(
|
||||
efi_handle image_handle, efi_uintn_t map_key);
|
||||
void *get_next_monotonic_count;
|
||||
void(EFIAPI *stall)(efi_uintn_t microseconds);
|
||||
void *set_watchdog_timer;
|
||||
};
|
||||
|
||||
struct efi_system_table {
|
||||
efi_table_header_t hdr;
|
||||
efi_char16_t *firmware_vendor;
|
||||
uint32_t firmware_revision;
|
||||
efi_handle console_in_handle;
|
||||
void *con_in;
|
||||
efi_handle console_out_handle;
|
||||
efi_simple_text_output_protocol_t *con_out;
|
||||
efi_handle standard_error_handle;
|
||||
efi_simple_text_output_protocol_t *std_err;
|
||||
void *runtime_services;
|
||||
efi_boot_services_t *boot_services;
|
||||
uint64_t number_of_table_entries;
|
||||
void *configuration_table;
|
||||
efi_table_header_t hdr;
|
||||
efi_char16_t *firmware_vendor;
|
||||
uint32_t firmware_revision;
|
||||
efi_handle console_in_handle;
|
||||
void *con_in;
|
||||
efi_handle console_out_handle;
|
||||
efi_simple_text_output_protocol_t *con_out;
|
||||
efi_handle standard_error_handle;
|
||||
efi_simple_text_output_protocol_t *std_err;
|
||||
void *runtime_services;
|
||||
efi_boot_services_t *boot_services;
|
||||
uint64_t number_of_table_entries;
|
||||
void *configuration_table;
|
||||
};
|
||||
|
||||
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_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_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},
|
||||
};
|
||||
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
|
||||
|
||||
41
arch/x86/include/tianole/early_log.h
Normal file
41
arch/x86/include/tianole/early_log.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef X86_EARLY_LOG_H
|
||||
#define X86_EARLY_LOG_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static inline void early_log_putc(char ch)
|
||||
{
|
||||
__asm__ volatile("outb %0, $0xe9" : : "a"(ch));
|
||||
}
|
||||
|
||||
static inline void early_log_puts(const char *text)
|
||||
{
|
||||
while (*text != '\0') {
|
||||
if (*text == '\n') {
|
||||
early_log_putc('\r');
|
||||
}
|
||||
early_log_putc(*text++);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void early_log_u64_decimal(uint64_t value)
|
||||
{
|
||||
char digits[20];
|
||||
uint32_t index = 0;
|
||||
|
||||
if (value == 0) {
|
||||
early_log_putc('0');
|
||||
return;
|
||||
}
|
||||
|
||||
while (value != 0) {
|
||||
digits[index++] = (char)('0' + (value % 10));
|
||||
value /= 10;
|
||||
}
|
||||
|
||||
while (index != 0) {
|
||||
early_log_putc(digits[--index]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
2
arch/x86/kernel/Makefile
Normal file
2
arch/x86/kernel/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
ARCH_KERNEL_OBJS := \
|
||||
$(BUILD_DIR)/arch/kernel/entry.o
|
||||
@ -130,10 +130,13 @@
|
||||
- 独立 `kernel.elf` 加载
|
||||
- `kernel_main()` 实际执行
|
||||
- `memory map` 已通过 `boot_info` 传递,并能在 kernel 中统计描述符与可用页数
|
||||
- `ExitBootServices` 已在进入 kernel 前执行
|
||||
- x86 早期日志接口已集中到 `arch/x86/include/tianole/early_log.h`
|
||||
- 构建布局已改为接近 Linux 的目录 Makefile 组织方式
|
||||
- 本地检查脚本和 GitHub Actions 已接入
|
||||
|
||||
当前还没有完成:
|
||||
|
||||
- `ExitBootServices`
|
||||
- early serial log
|
||||
- framebuffer console
|
||||
- 真正的内存管理和异常子系统
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
#ifndef TIANOLE_BOOT_INFO_H
|
||||
#define TIANOLE_BOOT_INFO_H
|
||||
#ifndef BOOT_INFO_H
|
||||
#define BOOT_INFO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define TIANOLE_EFI_MEMORY_TYPE_CONVENTIONAL 7u
|
||||
#define BOOT_MEMORY_TYPE_CONVENTIONAL 7u
|
||||
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
uint32_t pad;
|
||||
uint64_t physical_start;
|
||||
uint64_t virtual_start;
|
||||
uint64_t number_of_pages;
|
||||
uint64_t attribute;
|
||||
} tianole_efi_memory_descriptor_t;
|
||||
uint32_t type;
|
||||
uint32_t pad;
|
||||
uint64_t physical_start;
|
||||
uint64_t virtual_start;
|
||||
uint64_t number_of_pages;
|
||||
uint64_t attribute;
|
||||
} boot_memory_descriptor_t;
|
||||
|
||||
/*
|
||||
* Boot-time handoff data owned by Tianole rather than by a specific
|
||||
@ -20,17 +20,17 @@ typedef struct {
|
||||
* kernel entry stays stable.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint32_t boot_flags;
|
||||
uint64_t memory_map;
|
||||
uint64_t memory_map_size;
|
||||
uint64_t memory_map_key;
|
||||
uint64_t memory_descriptor_size;
|
||||
uint32_t memory_descriptor_version;
|
||||
uint32_t reserved0;
|
||||
} tianole_boot_info_t;
|
||||
uint32_t version;
|
||||
uint32_t boot_flags;
|
||||
uint64_t memory_map;
|
||||
uint64_t memory_map_size;
|
||||
uint64_t memory_map_key;
|
||||
uint64_t memory_descriptor_size;
|
||||
uint32_t memory_descriptor_version;
|
||||
uint32_t reserved0;
|
||||
} boot_info_t;
|
||||
|
||||
#define TIANOLE_BOOT_INFO_VERSION 1u
|
||||
#define TIANOLE_BOOT_FLAG_BOOT_SERVICES_ACTIVE (1u << 0)
|
||||
#define BOOT_INFO_VERSION 1u
|
||||
#define BOOT_FLAG_SERVICES_ACTIVE (1u << 0)
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef TIANOLE_ELF_H
|
||||
#define TIANOLE_ELF_H
|
||||
#ifndef ELF_H
|
||||
#define ELF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -14,31 +14,31 @@
|
||||
#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;
|
||||
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;
|
||||
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
|
||||
|
||||
8
include/tianole/kernel_init.h
Normal file
8
include/tianole/kernel_init.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef KERNEL_INIT_H
|
||||
#define KERNEL_INIT_H
|
||||
|
||||
#include "tianole/boot_info.h"
|
||||
|
||||
void kernel_report_boot_state(const boot_info_t *boot_info);
|
||||
|
||||
#endif
|
||||
7
kernel/Makefile
Normal file
7
kernel/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
KERNEL_SRCS := \
|
||||
kernel/main.c \
|
||||
kernel/boot_report.c
|
||||
|
||||
KERNEL_OBJS := \
|
||||
$(ARCH_KERNEL_OBJS) \
|
||||
$(patsubst kernel/%.c,$(BUILD_DIR)/kernel/%.o,$(KERNEL_SRCS))
|
||||
57
kernel/boot_report.c
Normal file
57
kernel/boot_report.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tianole/boot_info.h"
|
||||
#include "tianole/early_log.h"
|
||||
#include "tianole/kernel_init.h"
|
||||
|
||||
static void log_memory_map_summary(const boot_info_t *boot_info)
|
||||
{
|
||||
uint64_t offset;
|
||||
uint64_t descriptors = 0;
|
||||
uint64_t conventional_pages = 0;
|
||||
|
||||
if (boot_info == 0 || boot_info->memory_map == 0 ||
|
||||
boot_info->memory_descriptor_size == 0) {
|
||||
early_log_puts("memory map metadata missing\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (offset = 0; offset + sizeof(boot_memory_descriptor_t) <=
|
||||
boot_info->memory_map_size;
|
||||
offset += boot_info->memory_descriptor_size) {
|
||||
const boot_memory_descriptor_t *descriptor =
|
||||
(const boot_memory_descriptor_t
|
||||
*)(uintptr_t)(boot_info->memory_map +
|
||||
offset);
|
||||
|
||||
descriptors++;
|
||||
if (descriptor->type == BOOT_MEMORY_TYPE_CONVENTIONAL) {
|
||||
conventional_pages += descriptor->number_of_pages;
|
||||
}
|
||||
}
|
||||
|
||||
early_log_puts("memory map descriptors=");
|
||||
early_log_u64_decimal(descriptors);
|
||||
early_log_puts("\n");
|
||||
early_log_puts("conventional memory pages=");
|
||||
early_log_u64_decimal(conventional_pages);
|
||||
early_log_puts("\n");
|
||||
}
|
||||
|
||||
void kernel_report_boot_state(const boot_info_t *boot_info)
|
||||
{
|
||||
if (boot_info != 0 && boot_info->version == BOOT_INFO_VERSION) {
|
||||
early_log_puts("boot_info.version ok\n");
|
||||
} else {
|
||||
early_log_puts("boot_info.version invalid\n");
|
||||
}
|
||||
|
||||
if (boot_info != 0 &&
|
||||
(boot_info->boot_flags & BOOT_FLAG_SERVICES_ACTIVE) == 0) {
|
||||
early_log_puts("boot services exited\n");
|
||||
} else {
|
||||
early_log_puts("boot services still active\n");
|
||||
}
|
||||
|
||||
log_memory_map_summary(boot_info);
|
||||
}
|
||||
@ -1,83 +1,12 @@
|
||||
#include <stdint.h>
|
||||
#include "tianole/early_log.h"
|
||||
#include "tianole/kernel_init.h"
|
||||
|
||||
#include "tianole/boot_info.h"
|
||||
void kernel_main(const boot_info_t *boot_info)
|
||||
{
|
||||
early_log_puts("kernel_main entered\n");
|
||||
kernel_report_boot_state(boot_info);
|
||||
|
||||
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++);
|
||||
}
|
||||
}
|
||||
|
||||
static void debug_put_u64_decimal(uint64_t value) {
|
||||
char digits[20];
|
||||
uint32_t index = 0;
|
||||
|
||||
if (value == 0) {
|
||||
debug_putc('0');
|
||||
return;
|
||||
}
|
||||
|
||||
while (value != 0) {
|
||||
digits[index++] = (char)('0' + (value % 10));
|
||||
value /= 10;
|
||||
}
|
||||
|
||||
while (index != 0) {
|
||||
debug_putc(digits[--index]);
|
||||
}
|
||||
}
|
||||
|
||||
static void log_memory_map_summary(const tianole_boot_info_t *boot_info) {
|
||||
uint64_t offset;
|
||||
uint64_t descriptors = 0;
|
||||
uint64_t conventional_pages = 0;
|
||||
|
||||
if (boot_info == 0 || boot_info->memory_map == 0 || boot_info->memory_descriptor_size == 0) {
|
||||
debug_puts("memory map metadata missing\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (offset = 0; offset + sizeof(tianole_efi_memory_descriptor_t) <= boot_info->memory_map_size;
|
||||
offset += boot_info->memory_descriptor_size) {
|
||||
const tianole_efi_memory_descriptor_t *descriptor =
|
||||
(const tianole_efi_memory_descriptor_t *)(uintptr_t)(boot_info->memory_map + offset);
|
||||
|
||||
descriptors++;
|
||||
if (descriptor->type == TIANOLE_EFI_MEMORY_TYPE_CONVENTIONAL) {
|
||||
conventional_pages += descriptor->number_of_pages;
|
||||
}
|
||||
}
|
||||
|
||||
debug_puts("memory map descriptors=");
|
||||
debug_put_u64_decimal(descriptors);
|
||||
debug_puts("\n");
|
||||
debug_puts("conventional memory pages=");
|
||||
debug_put_u64_decimal(conventional_pages);
|
||||
debug_puts("\n");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
log_memory_map_summary(boot_info);
|
||||
|
||||
for (;;) {
|
||||
__asm__ volatile("hlt");
|
||||
}
|
||||
for (;;) {
|
||||
__asm__ volatile("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
34
scripts/check.sh
Executable file
34
scripts/check.sh
Executable file
@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
sources=$(find arch include kernel -name '*.c' -o -name '*.h')
|
||||
|
||||
clang-format --dry-run --Werror $sources
|
||||
|
||||
make clean
|
||||
make
|
||||
|
||||
timeout 30s make run-headless || true
|
||||
|
||||
required_lines=(
|
||||
"Tianole x86 bootloader loaded."
|
||||
"jumping to kernel entry"
|
||||
"kernel_main entered"
|
||||
"boot_info.version ok"
|
||||
"boot services exited"
|
||||
"memory map descriptors="
|
||||
"conventional memory pages="
|
||||
)
|
||||
|
||||
for line in "${required_lines[@]}"; do
|
||||
if ! grep -F "$line" build/debug.log >/dev/null; then
|
||||
echo "missing expected boot log line: $line" >&2
|
||||
echo "--- build/debug.log ---" >&2
|
||||
cat build/debug.log >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
cat build/debug.log
|
||||
Loading…
Reference in New Issue
Block a user