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/` 放架构相关实现。
|
- `arch/` 放架构相关实现。
|
||||||
- `include/tianole/` 放尽量与具体架构无关的共享接口。
|
- `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
|
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
|
||||||
|
|||||||
@ -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
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 "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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
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
|
#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
|
||||||
|
|||||||
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.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
|
||||||
- 真正的内存管理和异常子系统
|
- 真正的内存管理和异常子系统
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
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) {
|
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
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