refactor(build): split makefiles and normalize internal API names

- align makefile layout with Linux-style directories
This commit is contained in:
Microindole 2026-05-08 20:39:13 +08:00
parent 62c8836886
commit e3782144b8
No known key found for this signature in database
GPG Key ID: 22FB34CD2133ACA1
26 changed files with 864 additions and 696 deletions

17
.clang-format Normal file
View 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
View 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

View File

@ -24,3 +24,12 @@
- 当前代码以“先做最小,但不把架构完全写死”为原则推进。 - 当前代码以“先做最小,但不把架构完全写死”为原则推进。
- `arch/` 放架构相关实现。 - `arch/` 放架构相关实现。
- `include/tianole/` 放尽量与具体架构无关的共享接口。 - `include/tianole/` 放尽量与具体架构无关的共享接口。
- 入口文件只负责串联启动流程不承载文件加载、ELF 解析、内存映射统计等功能细节。
- 检查式日志应该放在对应功能模块中,避免把 `kernel_main()` 变成临时测试脚本。
- 内部 C API 不加 `tianole_` 前缀;这是单一内核代码库,不把项目名重复进函数名和类型名。
- 避免 `temp` / `tmp` 这类临时语义进入函数名、类型名和长期变量名;一次性局部变量可以用具体含义命名。
- C 代码风格参考 Linuxtabs 缩进,函数左花括号另起一行,`if/for/while` 左花括号留在行尾。
- 文本文件使用 LF 行尾。
- `.clang-format` 是当前格式化约定;如果环境有 `clang-format`,新增或大改 C/H 文件后应按它格式化。
- 根 `Makefile` 只做总控和通用规则;架构配置放在 `arch/<arch>/Makefile`,目录自己的源文件列表放在对应目录的 `Makefile` 中。
- 本地维护入口是 `scripts/check.sh`GitHub Actions 应调用同一个脚本,避免 CI 逻辑和本地逻辑分叉。

View File

@ -1,91 +1,43 @@
SHELL := /bin/bash SHELL := /bin/bash
ARCH ?= x86_64
CC := clang CC := clang
ELF_LD := ld.lld ELF_LD := ld.lld
LD := lld-link 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) ifeq ($(ARCH),x86_64)
ARCH_DIR := arch/x86 ARCH_MAKEFILE := arch/x86/Makefile
EFI_ARCH_TARGET := x86_64-unknown-windows
KERNEL_ARCH_TARGET := x86_64-unknown-none-elf
BOOT_EFI_NAME := BOOTX64.EFI
else else
$(error Unsupported ARCH '$(ARCH)') $(error Unsupported ARCH '$(ARCH)')
endif endif
BUILD_DIR := build include $(ARCH_MAKEFILE)
EFI_DIR := $(BUILD_DIR)/image/EFI/BOOT include $(ARCH_DIR)/boot/Makefile
BOOT_EFI := $(EFI_DIR)/$(BOOT_EFI_NAME) include $(ARCH_DIR)/kernel/Makefile
BOOT_OBJ := $(BUILD_DIR)/arch/boot/main.obj include kernel/Makefile
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
CFLAGS := \ .PHONY: all clean dirs run run-headless
-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
all: $(BOOT_EFI) $(KERNEL_ELF) all: $(BOOT_EFI) $(KERNEL_ELF)
dirs: dirs:
mkdir -p $(BUILD_DIR)/arch/boot $(BUILD_DIR)/arch/kernel $(BUILD_DIR)/kernel $(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 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 $@ $(CC) $(CFLAGS) -c $< -o $@
$(BOOT_EFI): $(BOOT_OBJ) | dirs $(BOOT_EFI): $(BOOT_OBJS) | dirs
$(LD) $(LDFLAGS) $< $(LD) $(LDFLAGS) $(BOOT_OBJS)
$(BUILD_DIR)/arch/kernel/entry.o: $(ARCH_DIR)/kernel/entry.S | dirs $(BUILD_DIR)/arch/kernel/entry.o: $(ARCH_DIR)/kernel/entry.S | dirs
$(CC) $(KERNEL_ASFLAGS) -c $< -o $@ $(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 $@ $(CC) $(KERNEL_CFLAGS) -c $< -o $@
$(KERNEL_ELF): $(KERNEL_OBJS) $(ARCH_DIR)/kernel/linker.ld | dirs $(KERNEL_ELF): $(KERNEL_OBJS) $(ARCH_DIR)/kernel/linker.ld | dirs

View File

@ -65,6 +65,14 @@ make run-headless
cat build/debug.log 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) - 路线图:[docs/roadmap.md](//wsl.localhost/Ubuntu/home/indole/tianole/docs/roadmap.md)

54
arch/x86/Makefile Normal file
View 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
View 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
View 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;
}

View 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
View 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
View 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

View File

@ -1,358 +1,60 @@
#include "efi.h" #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/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[] = { efi_status EFIAPI efi_main(
'T', 'i', 'a', 'n', 'o', 'l', 'e', ' ', efi_handle image_handle, efi_system_table_t *system_table)
'x', '8', '6', ' ', 'b', 'o', 'o', 't', {
'l', 'o', 'a', 'd', 'e', 'r', '.', '\r', '\n', 0 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[] = { system_table->con_out->output_string(
'\\', 'k', 'e', 'r', 'n', 'e', 'l', '.', system_table->con_out, boot_banner_text);
'e', 'l', 'f', 0 early_log_puts("Tianole x86 bootloader loaded.\n");
};
static inline void debug_putc(char ch) { status = boot_read_file(image_handle,
__asm__ volatile("outb %0, $0xe9" : : "a"(ch)); system_table,
} kernel_path_text,
&kernel_image,
static void debug_puts(const char *text) { &kernel_size);
while (*text != '\0') { if (status != EFI_SUCCESS) {
if (*text == '\n') { early_log_puts("failed: read kernel.elf\n");
debug_putc('\r'); return status;
} }
debug_putc(*text++);
} status = boot_load_kernel_elf(
} system_table, kernel_image, kernel_size, &kernel_entry);
if (status != EFI_SUCCESS) {
static void *mem_copy(void *dst, const void *src, uint64_t size) { early_log_puts("failed: load kernel image\n");
uint8_t *out = (uint8_t *)dst; return status;
const uint8_t *in = (const uint8_t *)src; }
uint64_t i;
status = boot_exit_services_with_latest_memory_map(
for (i = 0; i < size; ++i) { image_handle, system_table, &boot_info);
out[i] = in[i]; if (status != EFI_SUCCESS) {
} early_log_puts("failed: exit boot services\n");
return status;
return dst; }
}
early_log_puts("jumping to kernel entry\n");
static void mem_zero(void *dst, uint64_t size) { kernel_entry(&boot_info);
uint8_t *out = (uint8_t *)dst;
uint64_t i; early_log_puts("kernel returned unexpectedly\n");
for (;;) {
for (i = 0; i < size; ++i) { __asm__ volatile("hlt");
out[i] = 0; }
}
} return EFI_SUCCESS;
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;
} }

View 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;
}

View 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
View 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;
}

View File

@ -1,5 +1,5 @@
#ifndef TIANOLE_ARCH_X86_EFI_H #ifndef X86_EFI_H
#define TIANOLE_ARCH_X86_EFI_H #define X86_EFI_H
#include <stdint.h> #include <stdint.h>
@ -11,10 +11,10 @@ typedef uint64_t efi_physical_address_t;
#define EFI_SUCCESS 0 #define EFI_SUCCESS 0
#define EFI_LOAD_ERROR 0x8000000000000001ULL #define EFI_LOAD_ERROR 0x8000000000000001ULL
#define EFI_INVALID_PARAMETER 0x8000000000000002ULL
#define EFI_BUFFER_TOO_SMALL 0x8000000000000005ULL #define EFI_BUFFER_TOO_SMALL 0x8000000000000005ULL
#define EFI_OUT_OF_RESOURCES 0x8000000000000009ULL #define EFI_OUT_OF_RESOURCES 0x8000000000000009ULL
#define EFI_NOT_FOUND 0x800000000000000eULL #define EFI_NOT_FOUND 0x800000000000000eULL
#define EFI_INVALID_PARAMETER 0x8000000000000002ULL
#define EFI_ALLOCATE_ADDRESS 2 #define EFI_ALLOCATE_ADDRESS 2
#define EFI_LOADER_DATA 4 #define EFI_LOADER_DATA 4
@ -37,193 +37,179 @@ typedef uint64_t efi_physical_address_t;
#endif #endif
typedef struct { typedef struct {
uint32_t data1; uint32_t data1;
uint16_t data2; uint16_t data2;
uint16_t data3; uint16_t data3;
uint8_t data4[8]; uint8_t data4[8];
} efi_guid_t; } efi_guid_t;
typedef struct { typedef struct {
uint64_t signature; uint64_t signature;
uint32_t revision; uint32_t revision;
uint32_t header_size; uint32_t header_size;
uint32_t crc32; uint32_t crc32;
uint32_t reserved; uint32_t reserved;
} efi_table_header_t; } 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_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_file_protocol efi_file_protocol_t;
typedef struct efi_loaded_image_protocol efi_loaded_image_protocol_t; typedef struct efi_loaded_image_protocol efi_loaded_image_protocol_t;
typedef struct efi_system_table efi_system_table_t; typedef struct efi_system_table efi_system_table_t;
struct efi_simple_text_output_protocol { struct efi_simple_text_output_protocol {
void *reset; void *reset;
efi_status(EFIAPI *output_string)( efi_status(EFIAPI *output_string)(
efi_simple_text_output_protocol_t *self, efi_simple_text_output_protocol_t *self, efi_char16_t *string);
efi_char16_t *string
);
}; };
typedef struct { typedef struct {
uint64_t size; uint64_t size;
uint64_t file_size; uint64_t file_size;
uint64_t physical_size; uint64_t physical_size;
uint64_t create_time[2]; uint64_t create_time[2];
uint64_t last_access_time[2]; uint64_t last_access_time[2];
uint64_t modification_time[2]; uint64_t modification_time[2];
uint64_t attribute; uint64_t attribute;
efi_char16_t file_name[1]; efi_char16_t file_name[1];
} efi_file_info_t; } efi_file_info_t;
struct efi_file_protocol { struct efi_file_protocol {
uint64_t revision; uint64_t revision;
efi_status(EFIAPI *open)( efi_status(EFIAPI *open)(efi_file_protocol_t *self,
efi_file_protocol_t *self, efi_file_protocol_t **new_handle,
efi_file_protocol_t **new_handle, efi_char16_t *file_name,
efi_char16_t *file_name, uint64_t open_mode,
uint64_t open_mode, uint64_t attributes);
uint64_t attributes efi_status(EFIAPI *close)(efi_file_protocol_t *self);
); void *delete_;
efi_status(EFIAPI *close)(efi_file_protocol_t *self); efi_status(EFIAPI *read)(efi_file_protocol_t *self,
void *delete_; efi_uintn_t *buffer_size,
efi_status(EFIAPI *read)( void *buffer);
efi_file_protocol_t *self, void *write;
efi_uintn_t *buffer_size, void *get_position;
void *buffer void *set_position;
); efi_status(EFIAPI *get_info)(efi_file_protocol_t *self,
void *write; efi_guid_t *information_type,
void *get_position; efi_uintn_t *buffer_size,
void *set_position; void *buffer);
efi_status(EFIAPI *get_info)( void *set_info;
efi_file_protocol_t *self, void *flush;
efi_guid_t *information_type,
efi_uintn_t *buffer_size,
void *buffer
);
void *set_info;
void *flush;
}; };
struct efi_simple_file_system_protocol { struct efi_simple_file_system_protocol {
uint64_t revision; uint64_t revision;
efi_status(EFIAPI *open_volume)( efi_status(EFIAPI *open_volume)(efi_simple_file_system_protocol_t *self,
efi_simple_file_system_protocol_t *self, efi_file_protocol_t **root);
efi_file_protocol_t **root
);
}; };
struct efi_loaded_image_protocol { struct efi_loaded_image_protocol {
uint32_t revision; uint32_t revision;
efi_handle parent_handle; efi_handle parent_handle;
efi_system_table_t *system_table; efi_system_table_t *system_table;
efi_handle device_handle; efi_handle device_handle;
void *file_path; void *file_path;
void *reserved; void *reserved;
uint32_t load_options_size; uint32_t load_options_size;
void *load_options; void *load_options;
void *image_base; void *image_base;
uint64_t image_size; uint64_t image_size;
uint32_t image_code_type; uint32_t image_code_type;
uint32_t image_data_type; uint32_t image_data_type;
void *unload; void *unload;
}; };
struct efi_boot_services { struct efi_boot_services {
efi_table_header_t hdr; efi_table_header_t hdr;
void *raise_tpl; void *raise_tpl;
void *restore_tpl; void *restore_tpl;
efi_status(EFIAPI *allocate_pages)( efi_status(EFIAPI *allocate_pages)(int type,
int type, int memory_type,
int memory_type, efi_uintn_t pages,
efi_uintn_t pages, efi_physical_address_t *memory);
efi_physical_address_t *memory void *free_pages;
); efi_status(EFIAPI *get_memory_map)(efi_uintn_t *memory_map_size,
void *free_pages; void *memory_map,
efi_status(EFIAPI *get_memory_map)( efi_uintn_t *map_key,
efi_uintn_t *memory_map_size, efi_uintn_t *descriptor_size,
void *memory_map, uint32_t *descriptor_version);
efi_uintn_t *map_key, efi_status(EFIAPI *allocate_pool)(
efi_uintn_t *descriptor_size, int pool_type, efi_uintn_t size, void **buffer);
uint32_t *descriptor_version efi_status(EFIAPI *free_pool)(void *buffer);
); void *create_event;
efi_status(EFIAPI *allocate_pool)( void *set_timer;
int pool_type, void *wait_for_event;
efi_uintn_t size, void *signal_event;
void **buffer void *close_event;
); void *check_event;
efi_status(EFIAPI *free_pool)(void *buffer); void *install_protocol_interface;
void *create_event; void *reinstall_protocol_interface;
void *set_timer; void *uninstall_protocol_interface;
void *wait_for_event; efi_status(EFIAPI *handle_protocol)(
void *signal_event; efi_handle handle, efi_guid_t *protocol, void **interface);
void *close_event; void *reserved;
void *check_event; void *register_protocol_notify;
void *install_protocol_interface; void *locate_handle;
void *reinstall_protocol_interface; void *locate_device_path;
void *uninstall_protocol_interface; void *install_configuration_table;
efi_status(EFIAPI *handle_protocol)( void *load_image;
efi_handle handle, void *start_image;
efi_guid_t *protocol, void *exit;
void **interface void *unload_image;
); efi_status(EFIAPI *exit_boot_services)(
void *reserved; efi_handle image_handle, efi_uintn_t map_key);
void *register_protocol_notify; void *get_next_monotonic_count;
void *locate_handle; void(EFIAPI *stall)(efi_uintn_t microseconds);
void *locate_device_path; void *set_watchdog_timer;
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;
}; };
struct efi_system_table { struct efi_system_table {
efi_table_header_t hdr; efi_table_header_t hdr;
efi_char16_t *firmware_vendor; efi_char16_t *firmware_vendor;
uint32_t firmware_revision; uint32_t firmware_revision;
efi_handle console_in_handle; efi_handle console_in_handle;
void *con_in; void *con_in;
efi_handle console_out_handle; efi_handle console_out_handle;
efi_simple_text_output_protocol_t *con_out; efi_simple_text_output_protocol_t *con_out;
efi_handle standard_error_handle; efi_handle standard_error_handle;
efi_simple_text_output_protocol_t *std_err; efi_simple_text_output_protocol_t *std_err;
void *runtime_services; void *runtime_services;
efi_boot_services_t *boot_services; efi_boot_services_t *boot_services;
uint64_t number_of_table_entries; uint64_t number_of_table_entries;
void *configuration_table; void *configuration_table;
}; };
static inline efi_guid_t efi_file_info_guid(void) { static inline efi_guid_t efi_file_info_guid(void)
return (efi_guid_t){ {
.data1 = EFI_FILE_INFO_ID, return (efi_guid_t){
.data2 = EFI_FILE_INFO_ID_A, .data1 = EFI_FILE_INFO_ID,
.data3 = EFI_FILE_INFO_ID_B, .data2 = EFI_FILE_INFO_ID_A,
.data4 = {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}, .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) { static inline efi_guid_t efi_simple_file_system_protocol_guid(void)
return (efi_guid_t){ {
.data1 = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID_A, return (efi_guid_t){
.data2 = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID_B, .data1 = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID_A,
.data3 = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID_C, .data2 = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID_B,
.data4 = {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}, .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) { static inline efi_guid_t efi_loaded_image_protocol_guid(void)
return (efi_guid_t){ {
.data1 = EFI_LOADED_IMAGE_PROTOCOL_GUID_A, return (efi_guid_t){
.data2 = EFI_LOADED_IMAGE_PROTOCOL_GUID_B, .data1 = EFI_LOADED_IMAGE_PROTOCOL_GUID_A,
.data3 = EFI_LOADED_IMAGE_PROTOCOL_GUID_C, .data2 = EFI_LOADED_IMAGE_PROTOCOL_GUID_B,
.data4 = {0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}, .data3 = EFI_LOADED_IMAGE_PROTOCOL_GUID_C,
}; .data4 = {0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b},
};
} }
#endif #endif

View 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
View File

@ -0,0 +1,2 @@
ARCH_KERNEL_OBJS := \
$(BUILD_DIR)/arch/kernel/entry.o

View File

@ -130,10 +130,13 @@
- 独立 `kernel.elf` 加载 - 独立 `kernel.elf` 加载
- `kernel_main()` 实际执行 - `kernel_main()` 实际执行
- `memory map` 已通过 `boot_info` 传递,并能在 kernel 中统计描述符与可用页数 - `memory map` 已通过 `boot_info` 传递,并能在 kernel 中统计描述符与可用页数
- `ExitBootServices` 已在进入 kernel 前执行
- x86 早期日志接口已集中到 `arch/x86/include/tianole/early_log.h`
- 构建布局已改为接近 Linux 的目录 Makefile 组织方式
- 本地检查脚本和 GitHub Actions 已接入
当前还没有完成: 当前还没有完成:
- `ExitBootServices`
- early serial log - early serial log
- framebuffer console - framebuffer console
- 真正的内存管理和异常子系统 - 真正的内存管理和异常子系统

View File

@ -1,18 +1,18 @@
#ifndef TIANOLE_BOOT_INFO_H #ifndef BOOT_INFO_H
#define TIANOLE_BOOT_INFO_H #define BOOT_INFO_H
#include <stdint.h> #include <stdint.h>
#define TIANOLE_EFI_MEMORY_TYPE_CONVENTIONAL 7u #define BOOT_MEMORY_TYPE_CONVENTIONAL 7u
typedef struct { typedef struct {
uint32_t type; uint32_t type;
uint32_t pad; uint32_t pad;
uint64_t physical_start; uint64_t physical_start;
uint64_t virtual_start; uint64_t virtual_start;
uint64_t number_of_pages; uint64_t number_of_pages;
uint64_t attribute; uint64_t attribute;
} tianole_efi_memory_descriptor_t; } boot_memory_descriptor_t;
/* /*
* Boot-time handoff data owned by Tianole rather than by a specific * Boot-time handoff data owned by Tianole rather than by a specific
@ -20,17 +20,17 @@ typedef struct {
* kernel entry stays stable. * kernel entry stays stable.
*/ */
typedef struct { typedef struct {
uint32_t version; uint32_t version;
uint32_t boot_flags; uint32_t boot_flags;
uint64_t memory_map; uint64_t memory_map;
uint64_t memory_map_size; uint64_t memory_map_size;
uint64_t memory_map_key; uint64_t memory_map_key;
uint64_t memory_descriptor_size; uint64_t memory_descriptor_size;
uint32_t memory_descriptor_version; uint32_t memory_descriptor_version;
uint32_t reserved0; uint32_t reserved0;
} tianole_boot_info_t; } boot_info_t;
#define TIANOLE_BOOT_INFO_VERSION 1u #define BOOT_INFO_VERSION 1u
#define TIANOLE_BOOT_FLAG_BOOT_SERVICES_ACTIVE (1u << 0) #define BOOT_FLAG_SERVICES_ACTIVE (1u << 0)
#endif #endif

View File

@ -1,5 +1,5 @@
#ifndef TIANOLE_ELF_H #ifndef ELF_H
#define TIANOLE_ELF_H #define ELF_H
#include <stdint.h> #include <stdint.h>
@ -14,31 +14,31 @@
#define PT_LOAD 1 #define PT_LOAD 1
typedef struct { typedef struct {
unsigned char ident[16]; unsigned char ident[16];
uint16_t type; uint16_t type;
uint16_t machine; uint16_t machine;
uint32_t version; uint32_t version;
uint64_t entry; uint64_t entry;
uint64_t phoff; uint64_t phoff;
uint64_t shoff; uint64_t shoff;
uint32_t flags; uint32_t flags;
uint16_t ehsize; uint16_t ehsize;
uint16_t phentsize; uint16_t phentsize;
uint16_t phnum; uint16_t phnum;
uint16_t shentsize; uint16_t shentsize;
uint16_t shnum; uint16_t shnum;
uint16_t shstrndx; uint16_t shstrndx;
} elf64_ehdr_t; } elf64_ehdr_t;
typedef struct { typedef struct {
uint32_t type; uint32_t type;
uint32_t flags; uint32_t flags;
uint64_t offset; uint64_t offset;
uint64_t vaddr; uint64_t vaddr;
uint64_t paddr; uint64_t paddr;
uint64_t filesz; uint64_t filesz;
uint64_t memsz; uint64_t memsz;
uint64_t align; uint64_t align;
} elf64_phdr_t; } elf64_phdr_t;
#endif #endif

View 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
View 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
View 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);
}

View File

@ -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) { for (;;) {
__asm__ volatile("outb %0, $0xe9" : : "a"(ch)); __asm__ volatile("hlt");
} }
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");
}
} }

34
scripts/check.sh Executable file
View 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