diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..09ed4e4 --- /dev/null +++ b/.clang-format @@ -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 diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..1f0fdb8 --- /dev/null +++ b/.github/workflows/check.yml @@ -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 diff --git a/AGENTS.md b/AGENTS.md index 899df7b..0a65a3a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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//Makefile`,目录自己的源文件列表放在对应目录的 `Makefile` 中。 +- 本地维护入口是 `scripts/check.sh`;GitHub Actions 应调用同一个脚本,避免 CI 逻辑和本地逻辑分叉。 diff --git a/Makefile b/Makefile index e47b9d5..3738e20 100644 --- a/Makefile +++ b/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 diff --git a/README.md b/README.md index 065d6ca..aa74909 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/arch/x86/Makefile b/arch/x86/Makefile new file mode 100644 index 0000000..54c80cf --- /dev/null +++ b/arch/x86/Makefile @@ -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) diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile new file mode 100644 index 0000000..2432692 --- /dev/null +++ b/arch/x86/boot/Makefile @@ -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)) diff --git a/arch/x86/boot/elf_loader.c b/arch/x86/boot/elf_loader.c new file mode 100644 index 0000000..ef59419 --- /dev/null +++ b/arch/x86/boot/elf_loader.c @@ -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; +} diff --git a/arch/x86/boot/elf_loader.h b/arch/x86/boot/elf_loader.h new file mode 100644 index 0000000..f0a7054 --- /dev/null +++ b/arch/x86/boot/elf_loader.h @@ -0,0 +1,17 @@ +#ifndef X86_BOOT_ELF_LOADER_H +#define X86_BOOT_ELF_LOADER_H + +#include + +#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 diff --git a/arch/x86/boot/file.c b/arch/x86/boot/file.c new file mode 100644 index 0000000..34f5473 --- /dev/null +++ b/arch/x86/boot/file.c @@ -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; +} diff --git a/arch/x86/boot/file.h b/arch/x86/boot/file.h new file mode 100644 index 0000000..590c9c7 --- /dev/null +++ b/arch/x86/boot/file.h @@ -0,0 +1,14 @@ +#ifndef X86_BOOT_FILE_H +#define X86_BOOT_FILE_H + +#include + +#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 diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c index 82f229b..18b95f4 100644 --- a/arch/x86/boot/main.c +++ b/arch/x86/boot/main.c @@ -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; } diff --git a/arch/x86/boot/memory_map.c b/arch/x86/boot/memory_map.c new file mode 100644 index 0000000..ff15614 --- /dev/null +++ b/arch/x86/boot/memory_map.c @@ -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; +} diff --git a/arch/x86/boot/memory_map.h b/arch/x86/boot/memory_map.h new file mode 100644 index 0000000..f6d79dd --- /dev/null +++ b/arch/x86/boot/memory_map.h @@ -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 diff --git a/arch/x86/boot/support.c b/arch/x86/boot/support.c new file mode 100644 index 0000000..91a71cd --- /dev/null +++ b/arch/x86/boot/support.c @@ -0,0 +1,13 @@ +#include + +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; +} diff --git a/arch/x86/include/efi.h b/arch/x86/include/efi.h index 39ba455..0a3d83a 100644 --- a/arch/x86/include/efi.h +++ b/arch/x86/include/efi.h @@ -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 @@ -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 diff --git a/arch/x86/include/tianole/early_log.h b/arch/x86/include/tianole/early_log.h new file mode 100644 index 0000000..8038823 --- /dev/null +++ b/arch/x86/include/tianole/early_log.h @@ -0,0 +1,41 @@ +#ifndef X86_EARLY_LOG_H +#define X86_EARLY_LOG_H + +#include + +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 diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile new file mode 100644 index 0000000..40f5feb --- /dev/null +++ b/arch/x86/kernel/Makefile @@ -0,0 +1,2 @@ +ARCH_KERNEL_OBJS := \ + $(BUILD_DIR)/arch/kernel/entry.o diff --git a/docs/roadmap.md b/docs/roadmap.md index fb7bd6b..a114f49 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -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 - 真正的内存管理和异常子系统 diff --git a/include/tianole/boot_info.h b/include/tianole/boot_info.h index 32aaa23..1a808f9 100644 --- a/include/tianole/boot_info.h +++ b/include/tianole/boot_info.h @@ -1,18 +1,18 @@ -#ifndef TIANOLE_BOOT_INFO_H -#define TIANOLE_BOOT_INFO_H +#ifndef BOOT_INFO_H +#define BOOT_INFO_H #include -#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 diff --git a/include/tianole/elf.h b/include/tianole/elf.h index 8d95557..f105986 100644 --- a/include/tianole/elf.h +++ b/include/tianole/elf.h @@ -1,5 +1,5 @@ -#ifndef TIANOLE_ELF_H -#define TIANOLE_ELF_H +#ifndef ELF_H +#define ELF_H #include @@ -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 diff --git a/include/tianole/kernel_init.h b/include/tianole/kernel_init.h new file mode 100644 index 0000000..9e137dd --- /dev/null +++ b/include/tianole/kernel_init.h @@ -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 diff --git a/kernel/Makefile b/kernel/Makefile new file mode 100644 index 0000000..32e6638 --- /dev/null +++ b/kernel/Makefile @@ -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)) diff --git a/kernel/boot_report.c b/kernel/boot_report.c new file mode 100644 index 0000000..9ea68ff --- /dev/null +++ b/kernel/boot_report.c @@ -0,0 +1,57 @@ +#include + +#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); +} diff --git a/kernel/main.c b/kernel/main.c index b29468a..e47dbe7 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -1,83 +1,12 @@ -#include +#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"); + } } diff --git a/scripts/check.sh b/scripts/check.sh new file mode 100755 index 0000000..d56cbb8 --- /dev/null +++ b/scripts/check.sh @@ -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