Compare commits

..

22 Commits

48 changed files with 3601 additions and 306 deletions
-1
View File
@@ -4,7 +4,6 @@
"name": "Linux", "name": "Linux",
"includePath": [ "includePath": [
"${workspaceFolder}/**", "${workspaceFolder}/**",
"gnu-efi/inc/",
"include/" "include/"
], ],
"defines": [], "defines": [],
+60 -19
View File
@@ -7,28 +7,69 @@ x86_64 UEFI hobby OS. C17 boot → C++17 kernel, ELF64 → PE32+ via objcopy.
| Command | What | | Command | What |
|---------|------| |---------|------|
| `make` | Build `build/BOOTX64.EFI` + `build/Kernel.elf` | | `make` | Build `build/BOOTX64.EFI` + `build/Kernel.elf` |
| `make run` | QEMU + OVMF, serial 1 → `serial.log`, serial 2 → stdio, paused for GDB (`:1234`) | | `make disk` | Build FAT32 disk image (128 MiB) only — no QEMU |
| `make vdir` | Stage both binaries into `vdir/EFI/BOOT/` for manual boot | | `make run` | `make disk` + QEMU/OVMF. Serial 1 → `serial.log` (gitignored), paused for GDB (`:1234`) |
| `make clean` | **Always before commit** — untracked build artifacts leak outside `build/` | | `make vdir` | Stage `BOOTX64.EFI` + `Kernel.elf` + `resources/` into `vdir/EFI/BOOT/` for manual boot |
| `make clean` | wipes `build/`, `vdir/`, and `serial.log` |
**Prereqs for `make run`:** `qemu-system-x86_64`, OVMF at `/usr/share/ovmf/OVMF.fd`, `mtools` (`mformat`/`mmd`/`mcopy`). QEMU starts paused — connect GDB to `:1234` to proceed. Kernel debug output goes to `serial.log`.
## Architecture ## Architecture
- Two-stage boot: `boot.c` (UEFI app) loads `Kernel.elf` from FAT volume, parses ELF PHDRs, jumps to entry `boot.c` is legacy UEFI glue — loads `Kernel.elf` from the FAT volume, parses ELF PHDRs, jumps to entry. Don't refactor unless touching the boot stage. Bundled gnu-efi sources live in `efi/`.
- `kernel/entry.cpp``_start` saves `SystemTable`, calls `kernel_main()`
- `kernel/main.cpp``extern "C" kernel_main()`: init GOP → serial → PMM → heap → idle (`hlt`) **Kernel** lives in `kernel/`. Boot calls `_start` (`kernel/entry.cpp:8`), which saves `EFI_SYSTEM_TABLE*` in global `ST`, then `extern "C" kernel_main()` (`kernel/main.cpp:73`) runs:
- `kernel/serial.cpp` — UEFI serial protocol wrapper (write/read/hex)
- `kernel/memory/pmm.cpp` — bitmap + free-list physical page allocator 1. `init_gop()``gfx_init(GOP)` framebuffer (`graphics/context.cpp`)
- `kernel/memory/heap.cpp` — kmalloc/kfree/kcalloc/krealloc (first-fit w/ coalescing) 2. `init_serial()` → locate SERIAL_IO protocol
- `graphics/` — GOP framebuffer, `fonts/` — Hankaku 8×16 font via `pf_print()` 3. `pmm_init()` — bitmap + free-list page allocator (`kernel/memory/pmm.cpp`)
- `efi/` — bundled gnu-efi sources: `gnuefi/` (crt0, lds, reloc), `lib/`, `inc/` 4. `init_heap()` — kmalloc/kfree/kcalloc/krealloc, first-fit w/ coalescing (`kernel/memory/heap.cpp`)
- Kernel linked at `0x100000` (`kernel/kernel.ld`) 5. `fs_init()` / `fs_list()` — reads FAT volume via UEFI (`kernel/fs.cpp`)
6. `gdt_init()``idt_init()``pic_init()``pit_init()` (`kernel/interrupt/`)
7. `ASM("sti")` — interrupts on
8. `layer_init()` + `layer_create(...)` for desktop + windows (`kernel/graphics/layer.cpp`)
9. `task_create("compositor", layer_compositor_task)`
10. `scheduler_run()` — never returns. Preemptive, 100 Hz PIT, 5-tick time slice (`kernel/scheduler/`)
PIT IRQ 0 dispatches to `pit_irq_handler``scheduler_tick` via the IRQ handler in `kernel/main.cpp:56`.
## `include/common.h` — use these, not raw equivalents
Always `#include <common.h>` (it pulls in `<types.h>` + `<string_utils.h>` and defines the `ASM` macro):
| Provided | Use instead of |
|----------|----------------|
| `SSINT8/16/32/64`, `SUINT8/16/32/64` | raw `int*_t` / `uint*_t` |
| `String` (`const char*`), `WString` (`const uint16_t*`) | raw `char*` / `CHAR16*` |
| `str_len`, `str_cmp`, `str_eq`, `str_copy` | hand-rolled loops on `char*` |
| `wstr_len`, `wstr_cmp`, `wstr_eq`, `wstr_copy`, `wstr_to_ascii` | hand-rolled loops on `CHAR16*` |
| `mem_set`, `mem_copy` | hand-rolled byte loops |
| `ASM(...)` | raw `asm volatile(...)` — e.g. `ASM("cli")`, `ASM("hlt")`, `ASM("sti")` |
All `string_utils.h` helpers are `static inline` — header-only, no link issues. New kernel code should reach for these before adding anything new to `string_utils.h`.
## Conventions ## Conventions
- Commits: `[type] message` with types `feat`, `fix`, `chore`, `docs` (git log) - **Commits:** `[type] message` types: `feat`, `fix`, `chore`, `docs`, `refactor`, `optm` (see `git log`).
- `#define ASM asm volatile` in `include/common.h` - **Languages:** C17 (`boot.c`), C++17 (`kernel/`) — `-ffreestanding -fno-stack-protector -fshort-wchar -mno-red-zone -fcf-protection=none`. Kernel adds `-DGNU_EFI_USE_MS_ABI -fno-pic`.
- C17 (`boot.c`), C++17 (`kernel/`) — `-ffreestanding -fno-stack-protector -fshort-wchar -mno-red-zone` - **`kernel_main` must be `extern "C"`** — `boot.c` (C) calls into C++ (`kernel/entry.cpp:6`).
- `uefi_call_wrapper` required for all UEFI protocol calls (omission → page-fault) - **All UEFI protocol calls must use `uefi_call_wrapper`** — calling the member fn directly page-faults in long mode. See `kernel/main.cpp:23-24` and throughout.
- `kernel_main` must be `extern "C"` (C→C++ linkage) - **Kernel linked at `0x100000`** (`kernel/kernel.ld`); `.bss` start/end symbols exposed as `__bss_start` / `__bss_end`.
- QEMU starts paused: connect GDB to `:1234` to proceed - **No tests, no CI, no lint config** — `make` is the only verification step. Boot by hand in QEMU to confirm kernel output in `serial.log`.
- No tests, no CI, no lint config
## Global state
| Symbol | File | Type |
|--------|------|------|
| `ST` | `kernel/entry.cpp` | `EFI_SYSTEM_TABLE*` — saved from UEFI boot |
| `g_gfx` | `include/graphics/context.h` | `gfx_context` — GOP framebuffer info |
| `g_draw_target` | `include/graphics/context.h` | `draw_target` — current draw surface |
| `g_pmm` | `include/memory/pmm.h` | `pmm_t` — physical page allocator state |
| `g_serial` | `kernel/serial.cpp` | `serial_context` — serial protocol handle |
## Gotchas
- **No paging** — kernel runs in physical memory, identity-mapped.
- **No libc** — all string/memory ops go through `string_utils.h` (header-only, `static inline`).
- **Window switching** uses Shift+F10 (hardcoded PS/2 scan codes in `kernel/graphics/layer.cpp`).
- **`third_party/`** is empty — no external deps beyond bundled gnu-efi in `efi/`.
+28 -36
View File
@@ -1,5 +1,5 @@
CFLAGS = -Iinclude -Iefi/inc -ffreestanding -fno-stack-protector -fno-stack-check -fshort-wchar -mno-red-zone -std=c17 -Wwrite-strings -fcf-protection=none CFLAGS = -Iinclude -Iefi/inc -ffreestanding -fno-stack-protector -fno-stack-check -fshort-wchar -mno-red-zone -std=c17 -Wwrite-strings -fcf-protection=none -g
CXXFLAGS = -Iinclude -Iefi/inc -ffreestanding -fno-stack-protector -fno-stack-check -fshort-wchar -mno-red-zone -maccumulate-outgoing-args -std=c++17 -Wwrite-strings -fcf-protection=none CXXFLAGS = -Iinclude -Iefi/inc -ffreestanding -fno-stack-protector -fno-stack-check -fshort-wchar -mno-red-zone -maccumulate-outgoing-args -std=c++17 -Wwrite-strings -fcf-protection=none -g
LDFLAGS = -shared -Bsymbolic -Tefi/gnuefi/elf_x86_64_efi.lds LDFLAGS = -shared -Bsymbolic -Tefi/gnuefi/elf_x86_64_efi.lds
LDLIBS = --no-undefined LDLIBS = --no-undefined
@@ -15,13 +15,14 @@ EFI_CFLAGS = -Iefi/inc -Iefi/inc/x86_64 -Iefi/inc/protocol \
BOOT_OBJ = build/boot.o BOOT_OBJ = build/boot.o
KERNEL_CPP = kernel/entry.cpp kernel/main.cpp kernel/serial.cpp kernel/fs.cpp \ KERNEL_ASMFLAGS = -Iinclude -Iefi/inc -ffreestanding -fno-stack-protector -fno-stack-check \
kernel/memory/heap.cpp kernel/memory/pmm.cpp \ -fshort-wchar -mno-red-zone -fcf-protection=none -g
kernel/scheduler/scheduler.cpp \
graphics/context.cpp graphics/draw.cpp \ KERNEL_CPP := $(shell find kernel graphics fonts devices -name '*.cpp' -type f)
fonts/pixel_font.cpp KERNEL_ASM := $(shell find kernel -name '*.S' -type f)
KERNEL_ASM = kernel/scheduler/context_switch.S
KERNEL_OBJ = $(KERNEL_CPP:%.cpp=build/%.o) $(KERNEL_ASM:%.S=build/%.o) KERNEL_OBJ := $(KERNEL_CPP:%.cpp=build/%.o) $(KERNEL_ASM:%.S=build/%.o)
KERNEL_DIRS := $(sort $(dir $(KERNEL_OBJ)))
EFI_TOP_C = $(wildcard efi/lib/*.c) EFI_TOP_C = $(wildcard efi/lib/*.c)
EFI_TOP_S = $(wildcard efi/lib/*.S) EFI_TOP_S = $(wildcard efi/lib/*.S)
@@ -45,9 +46,7 @@ all: _bd $(EFI_OBJ) $(BOOT_OBJ) $(KERNEL_OBJ)
@echo "Done." @echo "Done."
_bd: _bd:
@mkdir -p build/graphics build/kernel build/fonts build/kernel/memory \ @mkdir -p $(KERNEL_DIRS) build/efi/gnuefi build/efi/lib build/efi/lib/x86_64 build/efi/lib/runtime
build/kernel/scheduler \
build/efi/lib build/efi/lib/x86_64 build/efi/lib/runtime build/efi/gnuefi
$(EFI_CRT0_OBJ): efi/gnuefi/crt0-efi-x86_64.S | _bd $(EFI_CRT0_OBJ): efi/gnuefi/crt0-efi-x86_64.S | _bd
@echo "Compile AS $<" @echo "Compile AS $<"
@@ -81,42 +80,35 @@ build/%.o: %.c
@echo "Compile C $<" @echo "Compile C $<"
@gcc $(CFLAGS) -c $< -o $@ @gcc $(CFLAGS) -c $< -o $@
build/kernel/%.o: kernel/%.cpp | _bd build/%.o: %.cpp | _bd
@echo "Compile CPP $<" @echo "Compile CPP $<"
@g++ $(KERNEL_CXXFLAGS) -c $< -o $@ @g++ $(KERNEL_CXXFLAGS) -c $< -o $@
build/kernel/memory/%.o: kernel/memory/%.cpp | _bd build/%.o: %.S | _bd
@echo "Compile CPP $<"
@g++ $(KERNEL_CXXFLAGS) -c $< -o $@
build/kernel/scheduler/%.o: kernel/scheduler/%.cpp | _bd
@echo "Compile CPP $<"
@g++ $(KERNEL_CXXFLAGS) -c $< -o $@
build/kernel/scheduler/%.o: kernel/scheduler/%.S | _bd
@echo "Compile AS $<" @echo "Compile AS $<"
@gcc -Iinclude -Iefi/inc -ffreestanding -fno-stack-protector -fno-stack-check \ @gcc $(KERNEL_ASMFLAGS) -c $< -o $@
-fshort-wchar -mno-red-zone -fcf-protection=none -c $< -o $@
build/graphics/%.o: graphics/%.cpp | _bd
@echo "Compile CPP $<"
@g++ $(KERNEL_CXXFLAGS) -c $< -o $@
build/fonts/%.o: fonts/%.cpp | _bd
@echo "Compile CPP $<"
@g++ $(KERNEL_CXXFLAGS) -c $< -o $@
vdir: all vdir: all
@mkdir -p vdir/EFI/BOOT @mkdir -p vdir/EFI/BOOT vdir/sys
@cp build/BOOTX64.EFI vdir/EFI/BOOT @cp build/BOOTX64.EFI vdir/EFI/BOOT
@cp build/Kernel.elf vdir/ @cp build/Kernel.elf vdir/
@cp -r resources vdir/sys/
run: vdir disk: vdir
@echo "* Building FAT32 disk image (128 MiB)..."
@dd if=/dev/zero of=build/disk.img bs=1M count=128 status=none
@mformat -i build/disk.img -F -T 262144 -h 16 -s 32 ::
@mmd -i build/disk.img ::/EFI ::/EFI/BOOT ::/sys
@mcopy -i build/disk.img -s vdir/EFI/BOOT/BOOTX64.EFI ::/EFI/BOOT/
@mcopy -i build/disk.img -s vdir/Kernel.elf ::/
@mcopy -i build/disk.img -s vdir/sys/resources ::/sys/
run: disk
@echo "Launching QEMU" @echo "Launching QEMU"
@qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -net none -drive file=fat:rw:vdir,index=0,format=vvfat -serial file:serial.log -serial stdio -s -S @qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -net none -drive file=build/disk.img,index=0,format=raw -serial stdio -serial file:serial.log -s -S
clean: clean:
@echo "Cleaning old files" @echo "Cleaning old files"
@rm -rf build vdir @rm -rf build vdir
.PHONY: all vdir run clean _bd .PHONY: all vdir disk run clean _bd
+75
View File
@@ -0,0 +1,75 @@
#include <devices/cursor.h>
#include <devices/mouse.h>
#include <graphics/draw.h>
#include <graphics/context.h>
#include <memory/heap.h>
#include <common.h>
// 经典箭头光标位图 (12x16)
// 0=透明, 1=白色填充, 2=黑色轮廓
static const SUINT8 g_cursor_bitmap[CURSOR_H][CURSOR_W] = {
{2,0,0,0,0,0,0,0,0,0,0,0},
{2,2,0,0,0,0,0,0,0,0,0,0},
{2,1,2,0,0,0,0,0,0,0,0,0},
{2,1,1,2,0,0,0,0,0,0,0,0},
{2,1,1,1,2,0,0,0,0,0,0,0},
{2,1,1,1,1,2,0,0,0,0,0,0},
{2,1,1,1,1,1,2,0,0,0,0,0},
{2,1,1,1,1,1,1,2,0,0,0,0},
{2,1,1,1,1,1,1,1,2,0,0,0},
{2,1,1,1,1,1,1,1,1,2,0,0},
{2,1,1,1,1,1,2,2,2,2,2,0},
{2,1,1,2,1,2,0,0,0,0,0,0},
{2,1,2,0,0,2,0,0,0,0,0,0},
{2,2,0,0,0,0,2,0,0,0,0,0},
{2,0,0,0,0,0,2,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0},
};
static layer_t* g_cursor_layer = NULL;
void cursor_init(void) {
g_cursor_layer = layer_create("cursor", LAYER_TYPE_MOUSE, CURSOR_W, CURSOR_H);
if (!g_cursor_layer) return;
layer_set_z(g_cursor_layer, 9999);
// 将位图写入图层缓冲区,Reserved 用作 alpha0=透明, 255=不透明)
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* buf = g_cursor_layer->buffer;
for (UINT32 y = 0; y < CURSOR_H; y++) {
for (UINT32 x = 0; x < CURSOR_W; x++) {
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* dst = &buf[y * CURSOR_W + x];
SUINT8 px = g_cursor_bitmap[y][x];
if (px == 1) {
dst->Blue = 255; dst->Green = 255; dst->Red = 255; dst->Reserved = 255;
} else if (px == 2) {
dst->Blue = 0; dst->Green = 0; dst->Red = 0; dst->Reserved = 255;
} else {
dst->Blue = 0; dst->Green = 0; dst->Red = 0; dst->Reserved = 0;
}
}
}
// 初始位置:屏幕中心
layer_set_pos(g_cursor_layer,
(SSINT32)(g_gfx.hr / 2),
(SSINT32)(g_gfx.vr / 2));
}
void cursor_update(void) {
if (!g_cursor_layer) return;
SSINT32 cx = (SSINT32)(g_gfx.hr / 2) + mouse_get_x();
SSINT32 cy = (SSINT32)(g_gfx.vr / 2) + mouse_get_y();
if (cx < 0) cx = 0;
if (cy < 0) cy = 0;
if (cx + (SSINT32)CURSOR_W > (SSINT32)g_gfx.hr) cx = (SSINT32)g_gfx.hr - CURSOR_W;
if (cy + (SSINT32)CURSOR_H > (SSINT32)g_gfx.vr) cy = (SSINT32)g_gfx.vr - CURSOR_H;
layer_set_pos(g_cursor_layer, cx, cy);
}
layer_t* cursor_get_layer(void) {
return g_cursor_layer;
}
+170
View File
@@ -0,0 +1,170 @@
#include <devices/mouse.h>
#include <interrupt/idt.h>
#include <interrupt/pic.h>
#include <serial.h>
static inline void outb(UINT16 port, UINT8 val) {
ASM("outb %0, %1" : : "a"(val), "Nd"(port));
}
static inline UINT8 inb(UINT16 port) {
UINT8 ret;
ASM("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
// 等待 PS/2 控制器输入缓冲区清空
static void ps2_wait_input(void) {
for (int i = 0; i < 100000; i++) {
if (!(inb(PS2_STATUS_PORT) & PS2_STAT_IBF)) return;
}
}
// 等待 PS/2 控制器输出缓冲区有数据
static void ps2_wait_output(void) {
for (int i = 0; i < 100000; i++) {
if (inb(PS2_STATUS_PORT) & PS2_STAT_OBF) return;
}
}
// 向 PS/2 控制器发送命令
static void ps2_write_cmd(UINT8 cmd) {
ps2_wait_input();
outb(PS2_CMD_PORT, cmd);
}
// 读取 PS/2 控制器返回的数据
static UINT8 ps2_read_data(void) {
ps2_wait_output();
return inb(PS2_DATA_PORT);
}
// 向辅助端口(鼠标)发送数据
static void ps2_write_mouse(UINT8 data) {
ps2_write_cmd(0xD4); // Write to Auxiliary Device
ps2_wait_input();
outb(PS2_DATA_PORT, data);
}
// 鼠标 3 字节数据包状态
static int g_pkt_phase = 0; // 0=byte0, 1=byte1, 2=byte2
static UINT8 g_pkt_byte0 = 0;
static UINT8 g_pkt_byte1 = 0;
// 鼠标光标位置(相对于屏幕中心)
static volatile SSINT32 g_mouse_x = 0;
static volatile SSINT32 g_mouse_y = 0;
static volatile bool g_mouse_btn_l = false;
static volatile bool g_mouse_btn_r = false;
static volatile bool g_mouse_btn_m = false;
// IRQ12 处理函数
static void mouse_irq_handler(trap_frame* frame) {
(void)frame;
pic_send_eoi(PS2_MOUSE_IRQ);
// 读取状态寄存器,检查输出缓冲区是否有数据
UINT8 status = inb(PS2_STATUS_PORT);
if (!(status & PS2_STAT_OBF)) return;
UINT8 data = inb(PS2_DATA_PORT);
// 解析 3 字节数据包
switch (g_pkt_phase) {
case 0: // byte 0: 按钮 + 标志
if (!(data & PS2_MOUSE_ALWAYS1)) return; // 无效字节,重新同步
g_pkt_byte0 = data;
g_pkt_phase = 1;
break;
case 1: // byte 1: X delta
g_pkt_byte1 = data;
g_pkt_phase = 2;
break;
case 2: // byte 2: Y delta
g_pkt_byte0 = g_pkt_byte0; // 确保编译器不优化
g_pkt_byte1 = g_pkt_byte1;
// 解析按钮状态
g_mouse_btn_l = (g_pkt_byte0 & PS2_MOUSE_LEFT) != 0;
g_mouse_btn_r = (g_pkt_byte0 & PS2_MOUSE_RIGHT) != 0;
g_mouse_btn_m = (g_pkt_byte0 & PS2_MOUSE_MIDDLE) != 0;
// 解析 X delta
SSINT32 dx = (SSINT32)(SSINT8)g_pkt_byte1;
if (g_pkt_byte0 & PS2_MOUSE_X_SIGN) dx |= 0xFFFFFF00;
// 解析 Y delta
SSINT32 dy = (SSINT32)(SSINT8)data;
if (g_pkt_byte0 & PS2_MOUSE_Y_SIGN) dy |= 0xFFFFFF00;
// 更新光标位置(Y 轴在屏幕上向下为正)
g_mouse_x += dx;
g_mouse_y -= dy;
g_pkt_phase = 0;
break;
}
}
// 丢弃输出缓冲区中的残留数据
static void ps2_flush_output(void) {
for (int i = 0; i < 100; i++) {
inb(PS2_DATA_PORT);
}
}
void mouse_init(void) {
// 1. 控制器自检(必须在命令字节写入之前,因为自检会重置命令字节)
ps2_write_cmd(PS2_CMD_SELF_TEST);
UINT8 self_test = ps2_read_data();
if (self_test != 0x55) {
serial_write("MOUSE: self-test FAILED\n");
}
// 2. 丢弃自检可能产生的残留数据
ps2_flush_output();
// 3. 启用辅助端口(鼠标)
ps2_write_cmd(PS2_CMD_ENABLE_A2);
// 4. 读取当前命令字节
ps2_write_cmd(PS2_CMD_READ_MB);
UINT8 cmd = ps2_read_data();
// 5. 启用 IRQ12 + IRQ1
cmd |= PS2_CMD_IRQ12 | PS2_CMD_IRQ1;
// 6. 写入修改后的命令字节(在自检之后,不会被重置)
ps2_write_cmd(PS2_CMD_WRITE_MB);
ps2_wait_input();
outb(PS2_DATA_PORT, cmd);
// 7. 验证命令字节已写入
ps2_write_cmd(PS2_CMD_READ_MB);
UINT8 verify = ps2_read_data();
if (verify != cmd) {
serial_write("MOUSE: cmd verify mismatch\n");
}
// 重置鼠标
ps2_write_mouse(PS2_MOUSE_RESET);
UINT8 ack = ps2_read_data();
if (ack == 0xFA) {
ps2_read_data(); // 丢弃第二字节
}
// 启用鼠标数据上报
ps2_write_mouse(PS2_MOUSE_ENABLE);
ps2_read_data();
// 注册 IRQ12 处理函数并取消屏蔽
idt_set_handler(PS2_MOUSE_VECTOR, mouse_irq_handler);
pic_unmask_irq(2); // 取消主片级联屏蔽
pic_unmask_irq(PS2_MOUSE_IRQ);
}
SSINT32 mouse_get_x(void) { return g_mouse_x; }
SSINT32 mouse_get_y(void) { return g_mouse_y; }
bool mouse_get_btn_left(void) { return g_mouse_btn_l; }
bool mouse_get_btn_right(void) { return g_mouse_btn_r; }
bool mouse_get_btn_middle(void) { return g_mouse_btn_m; }
+1
View File
@@ -3,5 +3,6 @@
本系统引用了下列字体: 本系统引用了下列字体:
- Hankaku - Hankaku
- 霞鹜文楷 Light
并在相关协议下使用。 并在相关协议下使用。
+10 -42
View File
@@ -2,28 +2,14 @@
#include <fonts/pixel_font.h> #include <fonts/pixel_font.h>
#include <graphics/draw.h> #include <graphics/draw.h>
#include <common.h> #include <common.h>
#include <string_utils.h>
static unsigned int pf_x = 0; void pf_print_char(char c, SUINT32 basex, SUINT32 basey, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) {
static unsigned int pf_y = 1; for (SUINT32 y = 0; y < 16; y++) {
SUINT8 data = hankaku_pixels[c][y];
void pf_reset_position(void) { for (SSINT32 x = 7; x >= 0; x--) {
// 其实应该还要清一下屏,后面思考一个安全的做法 // Hankaku 字体解码:每个字节代表一行,低位在右
pf_x = 0; SUINT32 current = data & 1;
pf_y = 1;
}
void pf_print_char(char c, unsigned int basex, unsigned int basey, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) {
for (unsigned int y = 0; y < 16; y++) {
unsigned char data = hankaku_pixels[c][y];
for (int x = 7; x >= 0; x--) {
// 解码Hankaku字体
/*
既然都在这了,就讲一下Hankaku字体是如何解码的
比如一个
{0x00, 0x82, 0x82, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00}
每一个Hex代表一行,比如0x82就是一行,转换成Bin得到10000010,1代表有像素,0代表没像素
*/
unsigned int current = data & 1;
data >>= 1; data >>= 1;
if (current) if (current)
draw_pixel(basex + x, basey + y, color); draw_pixel(basex + x, basey + y, color);
@@ -31,27 +17,9 @@ void pf_print_char(char c, unsigned int basex, unsigned int basey, EFI_GRAPHICS_
} }
} }
void pf_print(const char* text, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) { void pf_print(const char* text, SUINT32 basex, SUINT32 basey, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) {
for (unsigned int i = 0; i < strlen(text); i++) { for (SUINT32 i = 0; i < str_len(text); i++) {
char c = text[i]; char c = text[i];
if (c == '\n') { pf_print_char(c, basex + i * 8, basey, color);
pf_x = 0;
pf_y++;
if ((pf_y - 1) * 16 >= g_gfx.vr) {
gfx_clear();
pf_y = 1;
}
continue;
}
if (pf_x * 9 + 9 > g_gfx.hr) {
pf_x = 0;
pf_y++;
if ((pf_y - 1) * 16 >= g_gfx.vr) {
gfx_clear();
pf_y = 1;
}
}
pf_print_char(c, pf_x * 9, (pf_y - 1) * 16, color);
pf_x++;
} }
} }
+120
View File
@@ -0,0 +1,120 @@
#include <fonts/ttf.h>
#include "ttf_internal.h"
#include <graphics/draw.h>
#include <memory/heap.h>
#include <serial.h>
// 逐字形临时缓冲区 — 静态分配以避免大中文字形的栈压力
static ttf_outline_t s_outline;
static ttf_seg_t s_segs[4096];
static SUINT8 s_coverage[256 * 256];
// 在屏幕 (px, py) 处渲染单个字形位图,py 为字形顶部(已从基线转换)
static void blit_glyph(SSINT32 px, SSINT32 py, SUINT32 w, SUINT32 h,
const SUINT8* coverage, SUINT32 N,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color)
{
SUINT32 scale = 255 / N;
for (SUINT32 y = 0; y < h; y++) {
SSINT32 sy = py + (SSINT32)y;
if (sy < 0) continue;
for (SUINT32 x = 0; x < w; x++) {
SSINT32 sx = px + (SSINT32)x;
if (sx < 0) continue;
SUINT8 c = coverage[y * w + x];
if (c == 0) continue;
SUINT8 a = (SUINT8)(c * scale);
draw_pixel_alpha(sx, sy, color, a);
}
}
}
// 在基线 (x, y) 处渲染单个码点,返回进宽(26.6 定点数)
static f26_6 render_codepoint(ttf_face_t* face, SSINT32 cp,
SSINT32 x, SSINT32 y, SUINT32 pixel_size,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color)
{
SUINT16 gid = ttf_cmap_lookup(face, cp);
if (!ttf_load_glyph(face, gid, pixel_size, &s_outline)) {
return 0; // composite / parse error
}
// Bitmap dims in pixels
SSINT32 bbox_w = s_outline.xmax - s_outline.xmin;
SSINT32 bbox_h = s_outline.ymax - s_outline.ymin;
if (bbox_w <= 0 || bbox_h <= 0) {
return s_outline.advance; // whitespace or zero-size
}
SUINT32 pw = (SUINT32)((bbox_w + 63) >> 6);
SUINT32 ph = (SUINT32)((bbox_h + 63) >> 6);
if (pw > 256 || ph > 256) {
return s_outline.advance; // too big for scratch
}
// Translate outline to bitmap-local: bx = fx - xmin, by = ymax - fy
ttf_outline_t local;
local.num_points = s_outline.num_points;
local.num_contours = s_outline.num_contours;
for (SUINT16 i = 0; i < s_outline.num_contours; i++) {
local.first[i] = s_outline.first[i];
local.last[i] = s_outline.last[i];
}
for (SUINT16 i = 0; i < s_outline.num_points; i++) {
local.x[i] = s_outline.x[i] - s_outline.xmin;
local.y[i] = s_outline.ymax - s_outline.y[i];
local.on_curve[i] = s_outline.on_curve[i];
}
local.xmin = 0;
local.ymin = 0;
local.xmax = bbox_w;
local.ymax = bbox_h;
SUINT32 n_segs = 0;
ttf_outline_to_segments(&local, s_segs, &n_segs);
// Clear coverage
for (SUINT32 i = 0; i < pw * ph; i++) s_coverage[i] = 0;
const SUINT32 N = 5; // subsamples per pixel row
ttf_rasterize(s_segs, n_segs, 0, 0, pw, ph, s_coverage, N);
// Screen origin of bitmap
SSINT32 px_screen = x + (s_outline.xmin >> 6);
SSINT32 py_screen = y - (s_outline.ymax >> 6);
blit_glyph(px_screen, py_screen, pw, ph, s_coverage, N, color);
return s_outline.advance;
}
SSINT32 ttf_draw_text(ttf_face_t* face, const char* utf8,
SSINT32 x, SSINT32 y, SUINT32 pixel_size,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color)
{
if (!face || !utf8) return 0;
const char* p = utf8;
f26_6 pen = 0;
while (*p) {
SSINT32 cp = ttf_utf8_decode(&p);
if (cp < 0) continue;
f26_6 adv = render_codepoint(face, cp,
x + (pen >> 6), y, pixel_size, color);
pen += adv;
}
return pen;
}
SSINT32 ttf_text_width(ttf_face_t* face, const char* utf8, SUINT32 pixel_size) {
if (!face || !utf8) return 0;
const char* p = utf8;
f26_6 pen = 0;
while (*p) {
SSINT32 cp = ttf_utf8_decode(&p);
if (cp < 0) continue;
SUINT16 gid = ttf_cmap_lookup(face, cp);
if (!ttf_load_glyph(face, gid, pixel_size, &s_outline)) continue;
pen += s_outline.advance;
}
return pen;
}
+93
View File
@@ -0,0 +1,93 @@
#pragma once
#include <efi.h>
#include <common.h>
#include "ttf_math.h"
typedef struct ttf_face ttf_face_t;
typedef struct ttf_face {
const SUINT8* data;
UINTN size;
// head
SUINT32 units_per_em;
SSINT16 index_to_loc_format; // 0 = short, 1 = long
// hhea
SSINT16 hhea_ascender;
SSINT16 hhea_descender;
SSINT16 hhea_line_gap;
SUINT16 num_long_hor_metrics;
// maxp
SUINT16 num_glyphs;
SUINT16 max_points;
SUINT16 max_contours;
// os/2
SSINT16 os2_ascender;
SSINT16 os2_descender;
SSINT16 os2_line_gap;
// Table directory (sorted by tag at open time)
struct {
char tag[4];
SUINT32 offset;
SUINT32 length;
} tables[32];
SUINT16 num_tables;
// Cached pointers into data[]
const SUINT8* loca; // size depends on num_glyphs and format
const SUINT8* glyf;
SUINT32 glyf_len;
const SUINT8* hmtx;
SUINT32 hmtx_len;
const SUINT8* cmap;
} ttf_face_t;
// Decomposed glyph: contours in pixel space (26.6 fp) ready to scan.
typedef struct ttf_outline {
f26_6 x[1024];
f26_6 y[1024];
SUINT8 on_curve[1024];
SUINT16 first[64];
SUINT16 last[64];
SUINT16 num_contours;
SUINT16 num_points;
// Bounding box in pixel space (26.6 fp).
SSINT32 xmin, ymin, xmax, ymax;
// Pen advance in pixel space (26.6 fp).
f26_6 advance;
} ttf_outline_t;
typedef struct ttf_seg {
f26_6 x0, y0, x1, y1; // line / quad end points
f26_6 cx, cy; // quadratic control (set to x0/y0 if is_line)
SUINT8 is_line; // 1 = line, 0 = quad
} ttf_seg_t;
// Parse the glyf entry for glyph_id. Fills outline already
// scaled to pixel_size_px. Returns false on composite / parse error.
bool ttf_load_glyph(ttf_face_t* face, SUINT16 glyph_id,
SUINT32 pixel_size_px, ttf_outline_t* out);
// UTF-8 decoder. *p advances past the codepoint. Returns -1 on error.
SSINT32 ttf_utf8_decode(const char** p);
// cmap lookup — returns glyph_id (0 = notdef).
SUINT16 ttf_cmap_lookup(ttf_face_t* face, SSINT32 cp);
// Decompose outline into a flat array of line/quadratic segments.
// out must have room for 2*num_points + num_contours entries.
void ttf_outline_to_segments(const ttf_outline_t* outline,
ttf_seg_t* segs, SUINT32* num_segs);
// Scanline rasterize segments into per-pixel coverage.
// coverage[w*h] gets values in [0, N] where N = supersample count.
void ttf_rasterize(const ttf_seg_t* segs, SUINT32 num_segs,
SSINT32 x0, SSINT32 y0, SUINT32 w, SUINT32 h,
SUINT8* coverage, SUINT32 N);
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <common.h>
// 26.6 fixed point. 1.0 = 64, -32.0 .. 31.999 range in SSINT32.
typedef SSINT32 f26_6;
#define F26_ONE ((f26_6)64)
#define F26_HALF ((f26_6)32)
#define F26_FROM_INT(x) ((f26_6)((x) * 64))
#define F26_FLOOR(x) ((x) >> 6)
#define F26_ROUND(x) (((x) + 32) >> 6)
#define F26_FRAC(x) ((x) & 63)
static inline f26_6 f26_mul(f26_6 a, f26_6 b) {
return (f26_6)(((SSINT64)a * b) >> 6);
}
static inline f26_6 f26_div(f26_6 a, f26_6 b) {
if (b == 0) return 0;
return (f26_6)(((SSINT64)a << 6) / b);
}
// Linear interpolation. t in [0, 64].
static inline f26_6 f26_lerp(f26_6 a, f26_6 b, f26_6 t) {
return a + f26_mul(b - a, t);
}
// Floor-of-division helper for bezier root solving.
static inline SSINT32 isign(SSINT32 x) { return (x > 0) - (x < 0); }
+461
View File
@@ -0,0 +1,461 @@
#include "ttf_internal.h"
#include <string_utils.h>
#include <memory/heap.h>
#include <serial.h>
// 大端读取器(TTF 为大端格式)
static inline SUINT16 rd16(const SUINT8* p) {
return ((SUINT16)p[0] << 8) | p[1];
}
static inline SSINT16 rd16s(const SUINT8* p) {
return (SSINT16)(((SUINT16)p[0] << 8) | p[1]);
}
static inline SUINT32 rd32(const SUINT8* p) {
return ((SUINT32)p[0] << 24) | ((SUINT32)p[1] << 16) |
((SUINT32)p[2] << 8) | (SUINT32)p[3];
}
static const SUINT8* find_table(ttf_face_t* face, const char tag[4]) {
for (SUINT16 i = 0; i < face->num_tables; i++) {
if (face->tables[i].tag[0] == tag[0] &&
face->tables[i].tag[1] == tag[1] &&
face->tables[i].tag[2] == tag[2] &&
face->tables[i].tag[3] == tag[3]) {
return face->data + face->tables[i].offset;
}
}
return NULL;
}
// UTF-8 解码
SSINT32 ttf_utf8_decode(const char** p) {
const SUINT8* s = (const SUINT8*)*p;
SUINT8 b0 = s[0];
if (b0 < 0x80) { (*p)++; return b0; }
if ((b0 & 0xE0) == 0xC0) { (*p) += 2; return ((b0 & 0x1F) << 6) | (s[1] & 0x3F); }
if ((b0 & 0xF0) == 0xE0) { (*p) += 3; return ((b0 & 0x0F) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F); }
if ((b0 & 0xF8) == 0xF0) { (*p) += 4; return ((b0 & 0x07) << 18) | ((s[1] & 0x3F) << 12) | ((s[2] & 0x3F) << 6) | (s[3] & 0x3F); }
(*p)++;
return -1;
}
// cmap 子表查找
static const SUINT8* find_cmap_subtable(ttf_face_t* face) {
const SUINT8* cmap = face->cmap;
SUINT16 num = rd16(cmap + 2);
const SUINT8* best = NULL;
SSINT32 best_score = -1;
for (SUINT16 i = 0; i < num; i++) {
const SUINT8* rec = cmap + 4 + i * 8;
SUINT16 platform = rd16(rec + 0);
SUINT16 encoding = rd16(rec + 2);
SUINT32 offset = rd32(rec + 4);
SSINT32 score = -1;
if (platform == 3 && encoding == 10) score = 30;
else if (platform == 3 && encoding == 1) score = 20;
else if (platform == 0 && encoding == 4) score = 10;
else if (platform == 0 && encoding == 3) score = 5;
if (score > best_score) { best_score = score; best = cmap + offset; }
}
return best;
}
static SUINT16 cmap4_lookup(const SUINT8* sub, SSINT32 cp) {
SUINT16 segCountX2 = rd16(sub + 6);
SUINT16 segCount = segCountX2 / 2;
const SUINT8* endCode = sub + 14;
const SUINT8* startCode = endCode + segCountX2 + 2;
const SUINT8* idDelta = startCode + segCountX2;
const SUINT8* idRangeOff = idDelta + segCountX2;
for (SUINT16 i = 0; i < segCount; i++) {
SUINT16 ec = rd16(endCode + i * 2);
SUINT16 sc = rd16(startCode + i * 2);
if (cp < sc) break;
if (cp <= ec) {
SUINT16 dro = rd16(idRangeOff + i * 2);
if (dro == 0) {
return (SUINT16)((SSINT16)cp + (SSINT16)rd16(idDelta + i * 2));
}
SUINT16 gidx = rd16(idRangeOff + i * 2 + dro + (cp - sc) * 2);
if (gidx == 0) return 0;
return (SUINT16)((SSINT16)gidx + (SSINT16)rd16(idDelta + i * 2));
}
}
return 0;
}
static SUINT16 cmap12_lookup(const SUINT8* sub, SSINT32 cp) {
// Format 12 头:format(2) reserved(2) length(4) language(4) nGroups(4)
SUINT32 nGroups = rd32(sub + 12);
const SUINT8* g = sub + 16;
for (SUINT32 i = 0; i < nGroups; i++) {
SUINT32 sc = rd32(g + 0);
SUINT32 ec = rd32(g + 4);
SUINT32 sG = rd32(g + 8);
if (cp < (SSINT32)sc) break;
if (cp <= (SSINT32)ec) return (SUINT16)(sG + (cp - sc));
g += 12;
}
return 0;
}
SUINT16 ttf_cmap_lookup(ttf_face_t* face, SSINT32 cp) {
const SUINT8* sub = find_cmap_subtable(face);
if (!sub) return 0;
SUINT16 fmt = rd16(sub);
if (fmt == 4) return cmap4_lookup(sub, cp);
if (fmt == 12) return cmap12_lookup(sub, cp);
return 0;
}
// glyf 解码
bool ttf_load_glyph(ttf_face_t* face, SUINT16 glyph_id,
SUINT32 pixel_size_px, ttf_outline_t* out)
{
mem_set(out, 0, sizeof(*out));
if (glyph_id >= face->num_glyphs) return false;
// Loca 索引
SUINT32 off0, off1;
if (face->index_to_loc_format == 0) {
off0 = ((SUINT32)rd16(face->loca + glyph_id * 2)) * 2;
off1 = ((SUINT32)rd16(face->loca + (glyph_id + 1) * 2)) * 2;
} else {
off0 = rd32(face->loca + glyph_id * 4);
off1 = rd32(face->loca + (glyph_id + 1) * 4);
}
if (off0 >= face->glyf_len) return false;
// 进宽(始终从 hmtx 读取,无论 glyf 是否存在)
{
SUINT16 aw;
if (glyph_id < face->num_long_hor_metrics) {
aw = rd16(face->hmtx + glyph_id * 4);
} else {
aw = rd16(face->hmtx + (face->num_long_hor_metrics - 1) * 4);
}
out->advance = (f26_6)(((SUINT64)aw * (SUINT64)pixel_size_px * 64) / face->units_per_em);
}
if (off0 == off1) {
// 空白字形(如空格)
return true;
}
const SUINT8* g = face->glyf + off0;
SSINT16 numContours = rd16s(g + 0);
if (numContours < 0) {
// 复合字形 — 解析组件记录并合并轮廓
const SUINT8* cp = g + 10;
SSINT32 all_xmin = 0x7FFFFFFF, all_ymin = 0x7FFFFFFF;
SSINT32 all_xmax = -0x7FFFFFFF, all_ymax = -0x7FFFFFFF;
// 复合字形标志(OpenType 规范):
// 0x0001 = ARG_1_AND_2_ARE_WORDS16 位参数;否则 8 位)
// 0x0002 = ARGS_ARE_XY_VALUES(偏移量;否则点索引)
// 0x0008 = WE_HAVE_A_SCALE
// 0x0040 = WE_HAVE_A_2x2
// 0x0080 = WE_HAVE_AN_X_AND_Y_SCALE
// 0x0020 = MORE_COMPONENTS
for (;;) {
SUINT16 comp_flags = rd16(cp); cp += 2;
SUINT16 comp_glyph = rd16(cp); cp += 2;
// 读取参数(大小取决于 ARG_1_AND_2_ARE_WORDS
SSINT32 arg1, arg2;
if (comp_flags & 0x0001) {
// 16 位有符号字
arg1 = rd16s(cp); cp += 2;
arg2 = rd16s(cp); cp += 2;
} else {
// 8 位有符号字节
arg1 = (SSINT8)cp[0];
arg2 = (SSINT8)cp[1];
cp += 2;
}
// 如果存在则读取缩放比例
f26_6 scale = F26_ONE;
if (comp_flags & 0x0008) {
// WE_HAVE_A_SCALE16.16 定点数
SSINT16 s16 = rd16s(cp); cp += 2;
scale = (f26_6)s16; // already in f26.6 from 16.16
}
// 如果存在则读取 x/y 缩放
f26_6 scaleX = F26_ONE, scaleY = F26_ONE;
if (comp_flags & 0x0080) {
// WE_HAVE_AN_X_AND_Y_SCALE:两个 16.16 值
SSINT16 sx16 = rd16s(cp); cp += 2;
SSINT16 sy16 = rd16s(cp); cp += 2;
scaleX = (f26_6)sx16;
scaleY = (f26_6)sy16;
}
// 如果存在则读取 2x2 矩阵
f26_6 m00 = F26_ONE, m01 = 0, m10 = 0, m11 = F26_ONE;
if (comp_flags & 0x0040) {
// WE_HAVE_A_2x2:四个 2.14 值
SSINT16 a = rd16s(cp); cp += 2;
SSINT16 b = rd16s(cp); cp += 2;
SSINT16 c = rd16s(cp); cp += 2;
SSINT16 d = rd16s(cp); cp += 2;
m00 = (f26_6)(a >> 8); // 2.14 -> 26.6: shift right 8
m01 = (f26_6)(b >> 8);
m10 = (f26_6)(c >> 8);
m11 = (f26_6)(d >> 8);
}
// 加载组件字形
ttf_outline_t comp;
if (!ttf_load_glyph(face, comp_glyph, pixel_size_px, &comp))
return false;
// 判断参数是偏移量(XY 值)还是点索引
SSINT32 offset_x = 0, offset_y = 0;
if (comp_flags & 0x0002) {
// ARGS_ARE_XY_VALUES:参数是像素偏移量(已缩放)
// 从字体单位缩放到像素空间
offset_x = (SSINT32)(((SSINT64)arg1 * (SSINT64)pixel_size_px * 64 / face->units_per_em));
offset_y = (SSINT32)(((SSINT64)arg2 * (SSINT64)pixel_size_px * 64 / face->units_per_em));
}
// 变换并合并组件点
for (SUINT16 i = 0; i < comp.num_points; i++) {
f26_6 fx = comp.x[i];
f26_6 fy = comp.y[i];
f26_6 tx, ty;
if (comp_flags & 0x0040) {
// 2x2 矩阵变换
tx = f26_mul(m00, fx) + f26_mul(m01, fy);
ty = f26_mul(m10, fx) + f26_mul(m11, fy);
} else if (comp_flags & 0x0008) {
// 均匀缩放
tx = f26_mul(scale, fx);
ty = f26_mul(scale, fy);
} else if (comp_flags & 0x0080) {
// x/y 独立缩放
tx = f26_mul(scaleX, fx);
ty = f26_mul(scaleY, fy);
} else {
tx = fx;
ty = fy;
}
f26_6 final_x = tx + offset_x;
f26_6 final_y = ty + offset_y;
out->x[out->num_points] = final_x;
out->y[out->num_points] = final_y;
out->on_curve[out->num_points] = comp.on_curve[i];
out->num_points++;
if (out->num_points > 1024) return false;
SSINT32 xi = F26_FLOOR(final_x);
SSINT32 yi = F26_FLOOR(final_y);
if (xi < all_xmin) all_xmin = xi;
if (xi > all_xmax) all_xmax = xi;
if (yi < all_ymin) all_ymin = yi;
if (yi > all_ymax) all_ymax = yi;
}
for (SUINT16 i = 0; i < comp.num_contours; i++) {
if (out->num_contours >= 64) return false;
out->first[out->num_contours] = (SUINT16)(out->num_points - comp.num_points + comp.first[i]);
out->last[out->num_contours] = (SUINT16)(out->num_points - comp.num_points + comp.last[i]);
out->num_contours++;
}
if (!(comp_flags & 0x0020)) break; // no more components
}
if (out->num_points == 0) return true;
out->xmin = all_xmin;
out->ymin = all_ymin;
out->xmax = all_xmax;
out->ymax = all_ymax;
return true;
}
if (numContours == 0) return true;
if (numContours > 64) return false;
SSINT16 gxMin = rd16s(g + 2);
SSINT16 gyMin = rd16s(g + 4);
SSINT16 gxMax = rd16s(g + 6);
SSINT16 gyMax = rd16s(g + 8);
const SUINT8* p = g + 10;
SUINT16 endPts[64];
for (SSINT16 i = 0; i < numContours; i++) { endPts[i] = rd16(p); p += 2; }
SUINT16 numPoints = (SUINT16)(endPts[numContours - 1] + 1);
if (numPoints > 1024) return false;
SUINT16 instrLen = rd16(p); p += 2;
p += instrLen;
// 解码标志(含 REPEAT
SUINT8 flags[1024];
SUINT16 pi = 0;
while (pi < numPoints) {
SUINT8 f = *p++;
flags[pi++] = f;
if (f & 0x08) {
SUINT8 rep = *p++;
for (SUINT16 k = 1; k <= rep && pi < numPoints; k++)
flags[pi++] = f;
}
}
// 解码 x 坐标到 x_raw[]
SSINT32 x_raw[1024];
{
SSINT32 x = 0;
for (SUINT16 i = 0; i < numPoints; i++) {
SUINT8 f = flags[i];
if (f & 0x02) {
SUINT8 b = *p++;
x += (f & 0x10) ? b : -(SSINT32)b;
} else if (!(f & 0x10)) {
x += (SSINT16)((SUINT16)p[0] << 8 | p[1]);
p += 2;
}
x_raw[i] = x;
}
}
// 解码 y 坐标到 y_raw[]
SSINT32 y_raw[1024];
{
SSINT32 y = 0;
for (SUINT16 i = 0; i < numPoints; i++) {
SUINT8 f = flags[i];
if (f & 0x04) {
SUINT8 b = *p++;
y += (f & 0x20) ? b : -(SSINT32)b;
} else if (!(f & 0x20)) {
y += (SSINT16)((SUINT16)p[0] << 8 | p[1]);
p += 2;
}
y_raw[i] = y;
}
}
// 缩放到像素空间(f26_6
SUINT64 scale_num = (SUINT64)pixel_size_px * 64;
for (SUINT16 i = 0; i < numPoints; i++) {
out->x[i] = (f26_6)(((SSINT64)x_raw[i] * (SSINT64)scale_num) / face->units_per_em);
out->y[i] = (f26_6)(((SSINT64)y_raw[i] * (SSINT64)scale_num) / face->units_per_em);
out->on_curve[i] = (flags[i] & 0x01) ? 1 : 0;
}
out->num_contours = (SUINT16)numContours;
out->num_points = numPoints;
SUINT16 start = 0;
for (SSINT16 i = 0; i < numContours; i++) {
out->first[i] = start;
out->last[i] = endPts[i];
start = endPts[i] + 1;
}
out->xmin = (SSINT32)(((SSINT64)gxMin * (SSINT64)scale_num) / face->units_per_em);
out->ymin = (SSINT32)(((SSINT64)gyMin * (SSINT64)scale_num) / face->units_per_em);
out->xmax = (SSINT32)(((SSINT64)gxMax * (SSINT64)scale_num) / face->units_per_em);
out->ymax = (SSINT32)(((SSINT64)gyMax * (SSINT64)scale_num) / face->units_per_em);
return true;
}
// 打开 / 关闭
ttf_face_t* ttf_open(const void* data, UINTN size) {
if (!data || size < 12) return NULL;
const SUINT8* d = (const SUINT8*)data;
SUINT32 sfVersion = rd32(d);
if (sfVersion != 0x00010000 && sfVersion != 0x74727565) {
serial_write("ttf: bad sfVersion\n");
return NULL;
}
SUINT16 numTables = rd16(d + 4);
if (numTables == 0 || numTables > 32) return NULL;
ttf_face_t* face = (ttf_face_t*)kcalloc(1, sizeof(ttf_face_t));
if (!face) return NULL;
face->data = d;
face->size = size;
face->num_tables = numTables;
for (SUINT16 i = 0; i < numTables; i++) {
const SUINT8* r = d + 12 + i * 16;
face->tables[i].tag[0] = r[0];
face->tables[i].tag[1] = r[1];
face->tables[i].tag[2] = r[2];
face->tables[i].tag[3] = r[3];
face->tables[i].offset = rd32(r + 8);
face->tables[i].length = rd32(r + 12);
}
const SUINT8* head = find_table(face, "head");
if (!head) { kfree(face); return NULL; }
face->units_per_em = rd16(head + 18);
face->index_to_loc_format = rd16s(head + 50);
const SUINT8* hhea = find_table(face, "hhea");
if (!hhea) { kfree(face); return NULL; }
face->hhea_ascender = rd16s(hhea + 4);
face->hhea_descender = rd16s(hhea + 6);
face->hhea_line_gap = rd16s(hhea + 8);
face->num_long_hor_metrics = rd16(hhea + 34);
const SUINT8* maxp = find_table(face, "maxp");
if (!maxp) { kfree(face); return NULL; }
face->num_glyphs = rd16(maxp + 4);
face->max_points = rd16(maxp + 6);
face->max_contours = rd16(maxp + 8);
const SUINT8* os2 = find_table(face, "OS/2");
if (os2) {
face->os2_ascender = rd16s(os2 + 68);
face->os2_descender = rd16s(os2 + 70);
face->os2_line_gap = rd16s(os2 + 72);
} else {
face->os2_ascender = face->hhea_ascender;
face->os2_descender = face->hhea_descender;
face->os2_line_gap = face->hhea_line_gap;
}
const SUINT8* loca = find_table(face, "loca");
const SUINT8* glyf = find_table(face, "glyf");
const SUINT8* hmtx = find_table(face, "hmtx");
if (!loca || !glyf || !hmtx) { kfree(face); return NULL; }
face->loca = loca;
face->glyf = glyf;
face->hmtx = hmtx;
for (SUINT16 i = 0; i < numTables; i++) {
if (face->tables[i].tag[0]=='g'&&face->tables[i].tag[1]=='l'&&
face->tables[i].tag[2]=='y'&&face->tables[i].tag[3]=='f')
face->glyf_len = face->tables[i].length;
if (face->tables[i].tag[0]=='h'&&face->tables[i].tag[1]=='m'&&
face->tables[i].tag[2]=='t'&&face->tables[i].tag[3]=='x')
face->hmtx_len = face->tables[i].length;
}
face->cmap = find_table(face, "cmap");
if (!face->cmap) { kfree(face); return NULL; }
return face;
}
void ttf_close(ttf_face_t* face) {
if (face) kfree(face);
}
// 度量值(缩放到 pixel_size,返回 26.6 定点数)
SSINT32 ttf_ascender (ttf_face_t* face, SUINT32 px) {
return (SSINT32)(((SSINT64)face->os2_ascender * (SSINT64)px * 64) / face->units_per_em);
}
SSINT32 ttf_descender(ttf_face_t* face, SUINT32 px) {
return (SSINT32)(((SSINT64)face->os2_descender * (SSINT64)px * 64) / face->units_per_em);
}
SSINT32 ttf_line_gap (ttf_face_t* face, SUINT32 px) {
return (SSINT32)(((SSINT64)face->os2_line_gap * (SSINT64)px * 64) / face->units_per_em);
}
+226
View File
@@ -0,0 +1,226 @@
#include "ttf_internal.h"
#include <string_utils.h>
// 轮廓 → 线段转换
//
// TrueType 轮廓遍历:对每对连续点,发射直线或二次贝塞尔曲线。
// 两个连续的非曲线点会触发合成一个曲线中点。
//
// 所有坐标全程使用 26.6 定点数。
void ttf_outline_to_segments(const ttf_outline_t* outline,
ttf_seg_t* segs, SUINT32* num_segs)
{
*num_segs = 0;
f26_6 syn_x[256];
f26_6 syn_y[256];
int n_syn = 0;
for (SUINT16 ci = 0; ci < outline->num_contours; ci++) {
SUINT16 first = outline->first[ci];
SUINT16 last = outline->last[ci];
int n_pts = last - first + 1;
if (n_pts < 2) continue;
f26_6 lx[1024];
f26_6 ly[1024];
SUINT8 on_c[1024];
for (int i = 0; i < n_pts; i++) {
lx[i] = outline->x[first + i];
ly[i] = outline->y[first + i];
on_c[i] = outline->on_curve[first + i];
}
// First on-curve point
int start = 0;
while (start < n_pts && !on_c[start]) start++;
if (start == n_pts) start = 0; // all off-curve (rare) — keep going
int anchor = start;
int pending = -1;
#define GET_X(i) ((i) < n_pts ? lx[(i)] : syn_x[(i) - n_pts])
#define GET_Y(i) ((i) < n_pts ? ly[(i)] : syn_y[(i) - n_pts])
#define PUSH_LINE(a, b) do { \
ttf_seg_t* __s = &segs[(*num_segs)++]; \
__s->x0 = GET_X(a); __s->y0 = GET_Y(a); \
__s->x1 = GET_X(b); __s->y1 = GET_Y(b); \
__s->cx = __s->x0; __s->cy = __s->y0; __s->is_line = 1; \
} while (0)
#define PUSH_QUAD(a, c, b) do { \
ttf_seg_t* __s = &segs[(*num_segs)++]; \
__s->x0 = GET_X(a); __s->y0 = GET_Y(a); \
__s->x1 = GET_X(b); __s->y1 = GET_Y(b); \
__s->cx = GET_X(c); __s->cy = GET_Y(c); __s->is_line = 0; \
} while (0)
for (int step = 0; step < n_pts; step++) {
int cur = (start + step) % n_pts;
if (step == 0) { anchor = cur; continue; }
if (on_c[cur]) {
if (pending < 0) {
PUSH_LINE(anchor, cur);
} else {
PUSH_QUAD(anchor, pending, cur);
pending = -1;
}
anchor = cur;
} else {
if (pending < 0) {
pending = cur;
} else {
int syn_idx = n_pts + n_syn;
syn_x[n_syn] = (GET_X(pending) + GET_X(cur)) >> 1;
syn_y[n_syn] = (GET_Y(pending) + GET_Y(cur)) >> 1;
n_syn++;
PUSH_QUAD(anchor, pending, syn_idx);
anchor = syn_idx;
pending = cur;
}
}
}
if (pending >= 0) {
PUSH_QUAD(anchor, pending, start);
} else if (anchor != start) {
PUSH_LINE(anchor, start);
}
#undef GET_X
#undef GET_Y
#undef PUSH_LINE
#undef PUSH_QUAD
}
}
// 整数平方根(牛顿法)
static SUINT32 isqrt_u64(SUINT64 n) {
if (n == 0) return 0;
SUINT32 x = (n > 0xFFFFFFFFu) ? 0xFFFFu : (SUINT32)n;
SUINT32 y = (x + 1) >> 1;
while (y < x) { x = y; y = (x + (SUINT32)(n / x)) >> 1; }
return x;
}
// 扫描线填充 + 子像素超采样
//
// 对每个输出行,运行 N 条子扫描线,偏移为 (k+0.5)/N。
// 对每条子扫描线 y,收集所有 x 交点,排序后交替填充 x 对。
// 对 N 个子采样求和得到每个像素的覆盖率 [0, N]。
void ttf_rasterize(const ttf_seg_t* segs, SUINT32 num_segs,
SSINT32 x0, SSINT32 y0, SUINT32 w, SUINT32 h,
SUINT8* coverage, SUINT32 N)
{
// 清空覆盖率缓冲区
for (SUINT32 i = 0; i < w * h; i++) coverage[i] = 0;
// 交点 x 缓冲区(每扫描线,最大可能数 = num_segs)
f26_6 xs[2048];
if (num_segs > 2048) num_segs = 2048;
for (SUINT32 row = 0; row < h; row++) {
for (SUINT32 k = 0; k < N; k++) {
// Sub-scanline y, in 26.6, with y = 0 at glyph top
f26_6 sy = (f26_6)((row * 64) + ((k * 2 + 1) * 64) / (SSINT32)(N * 2));
// ^ y center of subpixel k: (k + 0.5) * 64 / N
// = ((2k+1) * 64) / (2N)
// For N=5: k=0 -> 6.4, k=1 -> 19.2, etc.
SUINT32 nxs = 0;
for (SUINT32 s = 0; s < num_segs; s++) {
const ttf_seg_t* g = &segs[s];
if (g->is_line) {
f26_6 y0s = g->y0;
f26_6 y1s = g->y1;
if (y0s == y1s) continue; // horizontal — skip
// t = (sy - y0s) / (y1s - y0s) in (0, 1)
if (((y0s < sy) && (y1s < sy)) ||
((y0s > sy) && (y1s > sy))) continue;
f26_6 t = f26_div(sy - y0s, y1s - y0s);
if (t <= 0 || t >= F26_ONE) continue;
f26_6 x = g->x0 + f26_mul(t, g->x1 - g->x0);
xs[nxs++] = x;
} else {
// Quadratic: y(t) = (1-t)^2 y0 + 2(1-t)t cy + t^2 y1
// a t^2 + b t + c = 0
// a = y1 - 2 cy + y0
// b = 2 (cy - y0)
// c = y0 - sy
SSINT64 a = (SSINT64)g->y1 - 2 * (SSINT64)g->cy + (SSINT64)g->y0;
SSINT64 b = 2 * ((SSINT64)g->cy - (SSINT64)g->y0);
SSINT64 c = (SSINT64)g->y0 - (SSINT64)sy;
SSINT32 t0_valid = 0, t1_valid = 0;
f26_6 t0 = 0, t1 = 0;
if (a == 0) {
// Linear
if (b == 0) continue;
f26_6 t = f26_div((f26_6)(-c), (f26_6)b);
if (t > 0 && t < F26_ONE) { t0 = t; t0_valid = 1; }
} else {
SSINT64 disc = b * b - 4 * a * c;
if (disc < 0) continue;
SUINT32 sq = isqrt_u64((SUINT64)disc);
// 26.6 roots: t = (-b ± sqrt(disc)) / (2a)
// All in 26.6 fp.
// t = (-b ± sq) / (2a); both numerator and denom in 26.6 units
// Use f26_div: t_26_6 = ((-b ± sq) << 6) / (2a)
SSINT64 denom = 2 * a;
if (denom == 0) continue;
SSINT64 num0 = -b + (SSINT64)sq;
SSINT64 num1 = -b - (SSINT64)sq;
t0 = (f26_6)(num0 == 0 ? 0 : (num0 << 6) / denom);
t1 = (f26_6)(num1 == 0 ? 0 : (num1 << 6) / denom);
if (t0 > 0 && t0 < F26_ONE) t0_valid = 1;
if (t1 > 0 && t1 < F26_ONE) t1_valid = 1;
}
if (t0_valid) {
// x(t) = (1-t)^2 x0 + 2(1-t)t cx + t^2 x1
f26_6 omt = F26_ONE - t0;
f26_6 x = f26_mul(f26_mul(omt, omt), g->x0)
+ f26_mul(2 * f26_mul(omt, t0), g->cx)
+ f26_mul(f26_mul(t0, t0), g->x1);
xs[nxs++] = x;
}
if (t1_valid) {
f26_6 omt = F26_ONE - t1;
f26_6 x = f26_mul(f26_mul(omt, omt), g->x0)
+ f26_mul(2 * f26_mul(omt, t1), g->cx)
+ f26_mul(f26_mul(t1, t1), g->x1);
xs[nxs++] = x;
}
}
}
if (nxs < 2) continue;
// Insertion sort
for (SUINT32 i = 1; i < nxs; i++) {
f26_6 v = xs[i]; SUINT32 j = i;
while (j > 0 && xs[j-1] > v) { xs[j] = xs[j-1]; j--; }
xs[j] = v;
}
// Deduplicate: merge intersections within 1/16 pixel (4 in 26.6)
SUINT32 nxd = 0;
for (SUINT32 i = 0; i < nxs; i++) {
if (nxd > 0 && (xs[i] - xs[nxd - 1]) < 4) {
continue;
}
xs[nxd++] = xs[i];
}
nxs = nxd;
// Fill alternating pairs
for (SUINT32 i = 0; i + 1 < nxs; i += 2) {
f26_6 xa = xs[i];
f26_6 xb = xs[i+1];
if (xa == xb) continue;
SSINT32 c0 = F26_FLOOR(xa);
SSINT32 c1 = F26_FLOOR(xb);
if (c0 == c1) continue;
if (c0 < 0) c0 = 0;
if (c1 > (SSINT32)w) c1 = (SSINT32)w;
for (SSINT32 x = c0; x < c1; x++) {
if (x >= 0 && x < (SSINT32)w) coverage[row * w + x]++;
}
}
}
}
// 覆盖率转换在调用端通过 N 完成
(void)x0; (void)y0;
}
+23 -1
View File
@@ -1,15 +1,37 @@
// GFX 全局图形上下文,避免每次绘制都传递 GOP 参数
#include <graphics/context.h> #include <graphics/context.h>
gfx_context g_gfx; gfx_context g_gfx;
draw_target g_draw_target;
void gfx_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *GOP) { void gfx_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *GOP) {
g_gfx.GOP = GOP; g_gfx.GOP = GOP;
g_gfx.hr = GOP->Mode->Info->HorizontalResolution; g_gfx.hr = GOP->Mode->Info->HorizontalResolution;
g_gfx.vr = GOP->Mode->Info->VerticalResolution; g_gfx.vr = GOP->Mode->Info->VerticalResolution;
g_gfx.base = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) GOP->Mode->FrameBufferBase; g_gfx.base = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) GOP->Mode->FrameBufferBase;
g_draw_target.buf = g_gfx.base;
g_draw_target.w = g_gfx.hr;
g_draw_target.h = g_gfx.vr;
} }
void gfx_clear(void) { void gfx_clear(void) {
EFI_GRAPHICS_OUTPUT_BLT_PIXEL black = {0, 0, 0, 0}; EFI_GRAPHICS_OUTPUT_BLT_PIXEL black = {0, 0, 0, 0};
g_gfx.GOP->Blt(g_gfx.GOP, &black, EfiBltVideoFill, 0, 0, 0, 0, g_gfx.hr, g_gfx.vr, 0); uefi_call_wrapper(g_gfx.GOP->Blt, 10,
g_gfx.GOP, &black, EfiBltVideoFill,
(UINTN)0, (UINTN)0, (UINTN)0, (UINTN)0,
(UINTN)g_gfx.hr, (UINTN)g_gfx.vr, (UINTN)0);
}
void draw_set_target(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf, SUINT32 w, SUINT32 h) {
g_draw_target.buf = buf;
g_draw_target.w = w;
g_draw_target.h = h;
}
void draw_set_default_target(void) {
g_draw_target.buf = g_gfx.base;
g_draw_target.w = g_gfx.hr;
g_draw_target.h = g_gfx.vr;
} }
+46 -2
View File
@@ -1,10 +1,54 @@
#include <graphics/draw.h> #include <graphics/draw.h>
void draw_pixel(unsigned int x, unsigned int y, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) { // --- Global (framebuffer) ---
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p = g_gfx.base + (g_gfx.hr * y) + x;
void global_draw_pixel(SUINT32 x, SUINT32 y, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) {
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p = g_gfx.base + (g_gfx.hr * y) + x;
p->Blue = color.Blue; p->Blue = color.Blue;
p->Green = color.Green; p->Green = color.Green;
p->Red = color.Red; p->Red = color.Red;
p->Reserved = color.Reserved; p->Reserved = color.Reserved;
} }
void global_draw_rect(SUINT32 bx, SUINT32 by, SUINT32 ex, SUINT32 ey,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) {
for (SUINT32 x = bx; x <= ex; x++)
for (SUINT32 y = by; y <= ey; y++)
global_draw_pixel(x, y, color);
}
// --- Current target buffer ---
void draw_pixel(SUINT32 x, SUINT32 y, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) {
if (x >= g_draw_target.w || y >= g_draw_target.h) return;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p = g_draw_target.buf + (g_draw_target.w * y) + x;
p->Blue = color.Blue;
p->Green = color.Green;
p->Red = color.Red;
p->Reserved = color.Reserved;
}
void draw_rect(SUINT32 bx, SUINT32 by, SUINT32 ex, SUINT32 ey,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color) {
for (SUINT32 x = bx; x <= ex; x++)
for (SUINT32 y = by; y <= ey; y++)
draw_pixel(x, y, color);
}
void draw_pixel_alpha(SUINT32 x, SUINT32 y, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color, SUINT8 alpha) {
if (x >= g_draw_target.w || y >= g_draw_target.h) return;
if (alpha == 0) return;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p = g_draw_target.buf + (g_draw_target.w * y) + x;
if (alpha == 255) {
p->Blue = color.Blue;
p->Green = color.Green;
p->Red = color.Red;
p->Reserved = color.Reserved;
return;
}
SUINT32 inv = 255 - alpha;
p->Blue = (SUINT8)((color.Blue * alpha + p->Blue * inv) / 255);
p->Green = (SUINT8)((color.Green * alpha + p->Green * inv) / 255);
p->Red = (SUINT8)((color.Red * alpha + p->Red * inv) / 255);
p->Reserved = color.Reserved;
}
+2 -6
View File
@@ -1,9 +1,5 @@
#pragma once #pragma once
#include <types.h>
#include <string_utils.h>
#define ASM asm volatile #define ASM asm volatile
static unsigned int strlen(const char* arr) { // 获取string长度
int i = 0;
while (arr[i++] != '\0');
return i - 1;
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include <common.h>
#include <graphics/layer.h>
#define CURSOR_W 12
#define CURSOR_H 16
void cursor_init(void);
void cursor_update(void);
layer_t* cursor_get_layer(void);
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include <common.h>
#define PS2_MOUSE_IRQ 12
#define PS2_MOUSE_VECTOR (PIC_IRQ_BASE + PS2_MOUSE_IRQ)
// PS/2 controller ports
#define PS2_DATA_PORT 0x60
#define PS2_STATUS_PORT 0x64
#define PS2_CMD_PORT 0x64
// PS/2 controller commands
#define PS2_CMD_READ_MB 0x20 // Read command byte
#define PS2_CMD_WRITE_MB 0x60 // Write command byte
#define PS2_CMD_ENABLE_A2 0xA8 // Enable auxiliary (second) port
#define PS2_CMD_SELF_TEST 0xAA // Controller self-test
// PS/2 command byte bits
#define PS2_CMD_IRQ12 0x02 // Enable IRQ12 (auxiliary device)
#define PS2_CMD_IRQ1 0x01 // Enable IRQ1 (keyboard)
// PS/2 controller status bits
#define PS2_STAT_OBF 0x01 // Output buffer full (data ready)
#define PS2_STAT_IBF 0x02 // Input buffer full (controller busy)
// PS/2 mouse commands
#define PS2_MOUSE_ENABLE 0xF4 // Enable data reporting
#define PS2_MOUSE_DISABLE 0xF5 // Disable data reporting
#define PS2_MOUSE_RESET 0xFF // Reset mouse
// Mouse packet byte 0 flags
#define PS2_MOUSE_LEFT 0x01
#define PS2_MOUSE_RIGHT 0x02
#define PS2_MOUSE_MIDDLE 0x04
#define PS2_MOUSE_ALWAYS1 0x08
#define PS2_MOUSE_X_SIGN 0x10
#define PS2_MOUSE_Y_SIGN 0x20
#define PS2_MOUSE_X_OVER 0x40
#define PS2_MOUSE_Y_OVER 0x80
void mouse_init(void);
SSINT32 mouse_get_x(void);
SSINT32 mouse_get_y(void);
bool mouse_get_btn_left(void);
bool mouse_get_btn_right(void);
bool mouse_get_btn_middle(void);
+3 -2
View File
@@ -1,7 +1,8 @@
#pragma once #pragma once
#include <common.h>
// Hankaku 字体,不动 // Hankaku 8x16 点阵字体数据
static unsigned char hankaku_pixels[256][16] = { static SUINT8 hankaku_pixels[256][16] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10, 0x00, 0x00}, {0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10, 0x00, 0x00},
{0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x00, 0x00}, {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x00, 0x00},
+6 -4
View File
@@ -1,8 +1,10 @@
#pragma once #pragma once
#include <graphics/context.h> #include <graphics/context.h>
#include <string_utils.h>
void pf_print_char(char c, unsigned int basex, unsigned int basey, // 打印单个字符
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color = {255, 255, 255, 255}); // Pixel Font 打印字符 void pf_print_char(char c, SUINT32 basex, SUINT32 basey,
void pf_print(const char* text, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color = {255, 255, 255, 255}); // Pixel Font 打印string EFI_GRAPHICS_OUTPUT_BLT_PIXEL color = {255, 255, 255, 255});
void pf_reset_position(void); // 重设Pixel Font Cursor位置 // 打印字符串
void pf_print(String text, SUINT32 basex, SUINT32 basey, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color = {255, 255, 255, 255});
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <efi.h>
#include <common.h>
#include <graphics/context.h>
// Opaque font face. Created by ttf_open() over a memory-mapped TTF blob.
typedef struct ttf_face ttf_face_t;
// Open a TrueType font from a memory buffer. Buffer must remain valid
// for the lifetime of the face. Returns NULL on parse failure.
ttf_face_t* ttf_open(const void* data, UINTN size);
// Free face. Does NOT free the source buffer.
void ttf_close(ttf_face_t* face);
// Vertical metrics in 26.6 fixed point, scaled to pixel_size.
SSINT32 ttf_ascender (ttf_face_t* face, SUINT32 pixel_size);
SSINT32 ttf_descender(ttf_face_t* face, SUINT32 pixel_size);
SSINT32 ttf_line_gap (ttf_face_t* face, SUINT32 pixel_size);
// Measure total advance width of a UTF-8 string at pixel_size (26.6 fp).
SSINT32 ttf_text_width(ttf_face_t* face, const char* utf8, SUINT32 pixel_size);
// Render a UTF-8 string onto the current draw target.
// (x, y) = baseline origin in TARGET coordinates
// pixel_size = nominal glyph height in pixels (e.g. 16, 24, 48)
// color = foreground; alpha-blended over the current buffer
// Returns the total pen advance (26.6 fp) consumed.
SSINT32 ttf_draw_text(ttf_face_t* face, const char* utf8,
SSINT32 x, SSINT32 y, SUINT32 pixel_size, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color);
+3 -1
View File
@@ -1,6 +1,8 @@
#pragma once #pragma once
#include <efi.h> #include <efi.h>
#include <string_utils.h>
EFI_STATUS fs_init(); EFI_STATUS fs_init();
void fs_list(); void fs_list();
EFI_STATUS fs_read(const CHAR16 *Path, void **Buffer, UINTN *Size); EFI_STATUS fs_read(WString Path, void **Buffer, UINTN *Size);
EFI_STATUS fs_write(WString Path, const void *Data, UINTN Size, UINTN Offset);
+15 -6
View File
@@ -1,17 +1,26 @@
#pragma once #pragma once
// 这个文件存在的目的是让graphics的draw功能不用每次传 GOP hr vr base
#include <efi.h> #include <efi.h>
#include <common.h>
struct gfx_context { struct gfx_context {
EFI_GRAPHICS_OUTPUT_PROTOCOL *GOP; EFI_GRAPHICS_OUTPUT_PROTOCOL *GOP;
unsigned int hr; SUINT32 hr;
unsigned int vr; SUINT32 vr;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *base; EFI_GRAPHICS_OUTPUT_BLT_PIXEL *base;
}; };
extern gfx_context g_gfx; extern gfx_context g_gfx;
void gfx_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *GOP); // 初始化 GFX struct draw_target {
void gfx_clear(void); // 清空 GFX(相当于重置) EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf;
SUINT32 w;
SUINT32 h;
};
extern draw_target g_draw_target;
void gfx_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *GOP);
void gfx_clear(void);
void draw_set_target(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf, SUINT32 w, SUINT32 h);
void draw_set_default_target(void);
+10 -1
View File
@@ -3,4 +3,13 @@
#include <efi.h> #include <efi.h>
#include <graphics/context.h> #include <graphics/context.h>
void draw_pixel(unsigned int x, unsigned int y, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color); // 画像素 void global_draw_pixel(SUINT32 x, SUINT32 y, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color);
void global_draw_rect(SUINT32 bx, SUINT32 by, SUINT32 ex, SUINT32 ey,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color);
void draw_pixel(SUINT32 x, SUINT32 y, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color);
void draw_rect(SUINT32 bx, SUINT32 by, SUINT32 ex, SUINT32 ey,
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color);
// Alpha blend (alpha 0..255). dest = src*alpha/255 + dest*(255-alpha)/255.
void draw_pixel_alpha(SUINT32 x, SUINT32 y, EFI_GRAPHICS_OUTPUT_BLT_PIXEL color, SUINT8 alpha);
+42
View File
@@ -0,0 +1,42 @@
#pragma once
#include <efi.h>
#include <common.h>
#include <string_utils.h>
#define LAYER_MAX 32
#define LAYER_NAME_LEN 32
typedef enum {
LAYER_TYPE_DESKTOP,
LAYER_TYPE_WINDOW,
LAYER_TYPE_MOUSE,
LAYER_TYPE_OVERLAY,
} layer_type_t;
typedef struct layer {
UINT32 id;
char name[LAYER_NAME_LEN];
layer_type_t type;
SSINT32 x, y;
UINT32 w, h;
SSINT32 z;
bool visible;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* buffer;
struct layer* next;
} layer_t;
// Initialization — allocates back buffer, registers keyboard handler
void layer_init(void);
// Layer management
layer_t* layer_create(String name, layer_type_t type, UINT32 w, UINT32 h);
void layer_destroy(layer_t* layer);
void layer_set_z(layer_t* layer, SSINT32 z);
void layer_set_pos(layer_t* layer, SSINT32 x, SSINT32 y);
void layer_set_visible(layer_t* layer, bool visible);
layer_t* layer_get_by_id(UINT32 id);
layer_t* layer_get_focused(void);
// Compositor task entry
void layer_compositor_task(void);
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#include <efi.h>
// GDT selectors
#define GDT_NULL 0x00
#define GDT_KERNEL_CODE 0x08
#define GDT_KERNEL_DATA 0x10
#define GDT_USER_CODE 0x18
#define GDT_USER_DATA 0x20
#define GDT_TSS 0x28
// GDT entry
struct gdt_entry {
UINT16 limit_low;
UINT16 base_low;
UINT8 base_mid;
UINT8 access;
UINT8 granularity;
UINT8 base_high;
} __attribute__((packed));
// GDT pointer
struct gdt_ptr {
UINT16 limit;
UINT64 base;
} __attribute__((packed));
// TSS (Task State Segment) — 64-bit mode uses only RSP0 and IST1-7
struct tss {
UINT32 reserved0;
UINT64 rsp0;
UINT64 rsp1;
UINT64 rsp2;
UINT64 reserved1;
UINT64 ist1;
UINT64 ist2;
UINT64 ist3;
UINT64 ist4;
UINT64 ist5;
UINT64 ist6;
UINT64 ist7;
UINT64 reserved2;
UINT16 reserved3;
UINT16 iopb_offset;
} __attribute__((packed));
// TSS descriptor in GDT (system segment, 16 bytes)
struct tss_descriptor {
UINT16 limit_low;
UINT16 base_low;
UINT8 base_mid;
UINT8 access;
UINT8 granularity;
UINT8 base_high;
UINT32 base_upper;
UINT32 reserved;
} __attribute__((packed));
void gdt_init(void);
void gdt_set_kernel_stack(UINT64 stack); // sets TSS.RSP0
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include <efi.h>
// IDT entry (64-bit gate descriptor)
struct idt_entry {
UINT16 offset_low;
UINT16 selector;
UINT8 ist; // IST index (bits 0-2), reserved (bits 3-6), type (bit 7)
UINT8 type_attr; // P (bit 7), DPL (bits 5-6), 0 (bit 4), type (bits 0-3)
UINT16 offset_mid;
UINT32 offset_high;
UINT32 reserved;
} __attribute__((packed));
struct idt_ptr {
UINT16 limit;
UINT64 base;
} __attribute__((packed));
// Interrupt frame saved by ISR stubs
struct trap_frame {
// Pushed by ISR stub (general-purpose registers)
UINT64 r11;
UINT64 r10;
UINT64 r9;
UINT64 r8;
UINT64 rdi;
UINT64 rsi;
UINT64 rdx;
UINT64 rcx;
UINT64 rax;
// Pushed by ISR stub (metadata)
UINT64 vector;
UINT64 error_code;
// Pushed by CPU (interrupt frame)
UINT64 rip;
UINT64 cs;
UINT64 rflags;
UINT64 rsp;
UINT64 ss;
} __attribute__((packed));
// Handler function type
typedef void (*isr_handler_t)(trap_frame*);
void idt_init(void);
void idt_set_handler(UINT8 vector, isr_handler_t handler);
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <efi.h>
// 8259 PIC ports
#define PIC1_CMD 0x20
#define PIC1_DATA 0x21
#define PIC2_CMD 0xA0
#define PIC2_DATA 0xA1
// PIC vectors
#define PIC_IRQ_BASE 0x20 // IRQ 0 mapped to vector 0x20 (32)
// EOI signal
#define PIC_EOI 0x20
void pic_init(void);
void pic_send_eoi(UINT8 irq);
void pic_mask_irq(UINT8 irq);
void pic_unmask_irq(UINT8 irq);
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#include <efi.h>
// PIT I/O ports
#define PIT_CHANNEL0_DATA 0x40
#define PIT_COMMAND_PORT 0x43
// PIT frequency
#define PIT_BASE_FREQ 1193182 // 1.193182 MHz
#define PIT_TICK_HZ 100 // 100 Hz tick (10ms per tick)
// Timer tick callback type
typedef void (*timer_callback_t)(void);
void pit_init(void);
void pit_set_tick_handler(timer_callback_t handler);
UINT64 pit_get_ticks(void);
+7 -1
View File
@@ -3,10 +3,12 @@
#include <efi.h> #include <efi.h>
#include <memory/pmm.h> #include <memory/pmm.h>
#include <common.h> #include <common.h>
#include <string_utils.h>
#define TASK_STACK_SIZE (PAGE_SIZE * 4) // 16 KB kernel stack per task #define TASK_STACK_SIZE (PAGE_SIZE * 4) // 16 KB kernel stack per task
#define TASK_MAX 32 #define TASK_MAX 32
#define TASK_NAME_LEN 32 #define TASK_NAME_LEN 32
#define TIME_SLICE_DEFAULT 5 // 5 ticks = 50ms at 100 Hz
typedef enum { typedef enum {
TASK_STATE_READY, TASK_STATE_READY,
@@ -21,10 +23,11 @@ typedef struct task {
char name[TASK_NAME_LEN]; char name[TASK_NAME_LEN];
void* stack_base; // base address of kernel stack void* stack_base; // base address of kernel stack
struct task* next; // circular linked list struct task* next; // circular linked list
UINT32 time_slice; // remaining ticks before preemption
} task_t; } task_t;
// Create a new task. Returns task pointer or NULL on failure. // Create a new task. Returns task pointer or NULL on failure.
task_t* task_create(const char* name, void (*entry)(void)); task_t* task_create(String name, void (*entry)(void));
// Yield CPU to next ready task (cooperative) // Yield CPU to next ready task (cooperative)
void yield(void); void yield(void);
@@ -37,3 +40,6 @@ void task_exit(void);
// Get current running task // Get current running task
task_t* scheduler_current(void); task_t* scheduler_current(void);
// Timer tick handler — called by PIT IRQ 0, drives preemption
void scheduler_tick(void);
+13 -6
View File
@@ -2,15 +2,22 @@
#include <efi.h> #include <efi.h>
#include <efiser.h> #include <efiser.h>
#include <string_utils.h>
struct serial_context { // 串行内容结构体 // 串行通信上下文
struct serial_context {
EFI_SERIAL_IO_PROTOCOL *SerialIo; EFI_SERIAL_IO_PROTOCOL *SerialIo;
}; };
extern serial_context g_serial; extern serial_context g_serial;
void serial_init(EFI_SERIAL_IO_PROTOCOL *SerialIo); // 初始化串行驱动 // 初始化串行驱动
void serial_write(const char *str); // 往串行写string void serial_init(EFI_SERIAL_IO_PROTOCOL *SerialIo);
void serial_write_char(char c); // 往串行写char(不推荐使用) // 写字符串到串行
void serial_write_hex(UINTN val); // 往串行写十六进制数字 void serial_write(String str);
char serial_read_char(); // 读串行 // 写单个字符到串行(不推荐直接使用)
void serial_write_char(char c);
// 写十六进制数字到串行
void serial_write_hex(UINTN val);
// 从串行读取一个字符
char serial_read_char();
+91
View File
@@ -0,0 +1,91 @@
#pragma once
#include <types.h>
// === Unified string types ===
// Use these throughout the kernel instead of raw char*/const char*.
typedef const char* String; // 8-bit narrow string
typedef const uint16_t* WString; // 16-bit wide string (CHAR16)
// === Narrow string utilities (String) ===
static inline SUINT32 str_len(String s) {
SUINT32 i = 0;
while (s[i]) i++;
return i;
}
static inline SSINT32 str_cmp(String a, String b) {
while (*a && *a == *b) { a++; b++; }
return (SUINT8)*a - (SUINT8)*b;
}
static inline bool str_eq(String a, String b) {
return str_cmp(a, b) == 0;
}
// Copy up to max-1 chars, always null-terminates.
static inline void str_copy(char* dst, String src, SUINT32 max) {
if (max == 0) return;
SUINT32 i = 0;
while (src[i] && i < max - 1) {
dst[i] = src[i];
i++;
}
dst[i] = '\0';
}
// === Wide string utilities (WString) ===
static inline SUINT32 wstr_len(WString s) {
SUINT32 i = 0;
while (s[i]) i++;
return i;
}
static inline SSINT32 wstr_cmp(WString a, WString b) {
while (*a && *a == *b) { a++; b++; }
return (SUINT16)*a - (SUINT16)*b;
}
static inline bool wstr_eq(WString a, WString b) {
return wstr_cmp(a, b) == 0;
}
static inline void wstr_copy(uint16_t* dst, WString src, SUINT32 max) {
if (max == 0) return;
SUINT32 i = 0;
while (src[i] && i < max - 1) {
dst[i] = src[i];
i++;
}
dst[i] = 0;
}
// Convert wide string to ASCII (non-printable -> '?')
static inline void wstr_to_ascii(char* dst, WString src, SUINT32 max) {
if (max == 0) return;
SUINT32 i = 0;
while (src[i] && i < max - 1) {
if (src[i] >= 0x20 && src[i] <= 0x7E)
dst[i] = (char)src[i];
else
dst[i] = '?';
i++;
}
dst[i] = '\0';
}
// === Memory utilities ===
static inline void mem_set(void* dst, SUINT8 val, SUINT32 size) {
SUINT8* d = (SUINT8*)dst;
for (SUINT32 i = 0; i < size; i++) d[i] = val;
}
static inline void mem_copy(void* dst, const void* src, SUINT32 size) {
SUINT8* d = (SUINT8*)dst;
const SUINT8* s = (const SUINT8*)src;
for (SUINT32 i = 0; i < size; i++) d[i] = s[i];
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
// Signed integers
#define SSINT8 int8_t
#define SSINT16 int16_t
#define SSINT32 int32_t
#define SSINT64 int64_t
// Unsigned integers
#define SUINT8 uint8_t
#define SUINT16 uint16_t
#define SUINT32 uint32_t
#define SUINT64 uint64_t
+2
View File
@@ -8,6 +8,8 @@ extern "C" void kernel_main();
extern "C" void _start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { extern "C" void _start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
(void)ImageHandle; (void)ImageHandle;
ST = SystemTable; ST = SystemTable;
// 在 IDT 就绪前禁用中断
ASM("cli");
kernel_main(); kernel_main();
while (1) ASM ("hlt"); while (1) ASM ("hlt");
} }
+321 -53
View File
@@ -1,7 +1,7 @@
#include <fs.h> #include <fs.h>
#include <serial.h> #include <serial.h>
#include <memory/heap.h> #include <memory/heap.h>
#include <common.h> #include <string_utils.h>
extern EFI_SYSTEM_TABLE *ST; extern EFI_SYSTEM_TABLE *ST;
@@ -144,6 +144,13 @@ static EFI_STATUS blk_read(struct block_dev *dev, UINT64 LBA,
Sectors * dev->BlockSize, Buf); Sectors * dev->BlockSize, Buf);
} }
static EFI_STATUS blk_write(struct block_dev *dev, UINT64 LBA,
UINTN Sectors, const void *Buf) {
return uefi_call_wrapper(dev->Bio->WriteBlocks, 5,
dev->Bio, dev->Bio->Media->MediaId, LBA,
Sectors * dev->BlockSize, (void*)Buf);
}
// ---- Partition detection ---- // ---- Partition detection ----
static EFI_STATUS find_gpt_partition(struct block_dev *dev, UINT64 *StartLBA) { static EFI_STATUS find_gpt_partition(struct block_dev *dev, UINT64 *StartLBA) {
@@ -216,7 +223,7 @@ static EFI_STATUS find_mbr_partition(struct block_dev *dev, UINT64 *StartLBA) {
struct MBRPart *Parts = (struct MBRPart*)(Buf + 446); struct MBRPart *Parts = (struct MBRPart*)(Buf + 446);
// Verify at least one non-zero partition entry exists // Verify at least one non-zero partition entry exists
BOOLEAN has_part = FALSE; BOOLEAN has_part = FALSE;
for (int i = 0; i < 4; i++) { for (SSINT32 i = 0; i < 4; i++) {
if (Parts[i].Type != 0x00 && Parts[i].Type != 0xEE) { if (Parts[i].Type != 0x00 && Parts[i].Type != 0xEE) {
has_part = TRUE; has_part = TRUE;
break; break;
@@ -224,7 +231,7 @@ static EFI_STATUS find_mbr_partition(struct block_dev *dev, UINT64 *StartLBA) {
} }
if (!has_part) { kfree(Buf); return EFI_NOT_FOUND; } if (!has_part) { kfree(Buf); return EFI_NOT_FOUND; }
for (int i = 0; i < 4; i++) { for (SSINT32 i = 0; i < 4; i++) {
UINT8 t = Parts[i].Type; UINT8 t = Parts[i].Type;
if (t == 0x00 || t == 0xEE) continue; if (t == 0x00 || t == 0xEE) continue;
if (t == MBR_TYPE_FAT12 || t == MBR_TYPE_FAT16 || if (t == MBR_TYPE_FAT12 || t == MBR_TYPE_FAT16 ||
@@ -238,7 +245,7 @@ static EFI_STATUS find_mbr_partition(struct block_dev *dev, UINT64 *StartLBA) {
} }
// Fallback: first non-empty partition // Fallback: first non-empty partition
for (int i = 0; i < 4; i++) { for (SSINT32 i = 0; i < 4; i++) {
if (Parts[i].Type != 0x00) { if (Parts[i].Type != 0x00) {
*StartLBA = Parts[i].LBABegin; *StartLBA = Parts[i].LBABegin;
kfree(Buf); kfree(Buf);
@@ -361,7 +368,7 @@ static EFI_STATUS fat_init(struct fat_fs *fs, struct block_dev *dev, UINT64 Part
static UINT8 lfn_checksum(const UINT8 *SFN) { static UINT8 lfn_checksum(const UINT8 *SFN) {
UINT8 sum = 0; UINT8 sum = 0;
for (int i = 0; i < 11; i++) for (SSINT32 i = 0; i < 11; i++)
sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + SFN[i]; sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + SFN[i];
return sum; return sum;
} }
@@ -372,28 +379,32 @@ static UINT8 lfn_checksum(const UINT8 *SFN) {
struct lfn_state { struct lfn_state {
CHAR16 frags[LFN_MAX_FRAGS][LFN_FRAG_SIZE + 1]; CHAR16 frags[LFN_MAX_FRAGS][LFN_FRAG_SIZE + 1];
UINTN count; UINTN count;
UINT8 checksum;
}; };
static void lfn_reset(struct lfn_state *lfn) { static void lfn_reset(struct lfn_state *lfn) {
lfn->count = 0; lfn->count = 0;
lfn->checksum = 0;
} }
static void lfn_add(struct lfn_state *lfn, const UINT8 *E) { static void lfn_add(struct lfn_state *lfn, const UINT8 *E) {
if (lfn->count >= LFN_MAX_FRAGS) return; if (lfn->count >= LFN_MAX_FRAGS) return;
lfn->checksum = E[13];
UINTN pos = 0; UINTN pos = 0;
for (int i = 0; i < 5 && pos < LFN_FRAG_SIZE; i++) { BOOLEAN done = FALSE;
for (SSINT32 i = 0; i < 5 && pos < LFN_FRAG_SIZE && !done; i++) {
CHAR16 c = *(const UINT16*)(E + 1 + i * 2); CHAR16 c = *(const UINT16*)(E + 1 + i * 2);
if (c == 0x0000 || c == 0xFFFF) { lfn->frags[lfn->count][pos] = 0; return; } if (c == 0x0000 || c == 0xFFFF) { done = TRUE; break; }
lfn->frags[lfn->count][pos++] = c; lfn->frags[lfn->count][pos++] = c;
} }
for (int i = 0; i < 6 && pos < LFN_FRAG_SIZE; i++) { for (SSINT32 i = 0; i < 6 && pos < LFN_FRAG_SIZE && !done; i++) {
CHAR16 c = *(const UINT16*)(E + 14 + i * 2); CHAR16 c = *(const UINT16*)(E + 14 + i * 2);
if (c == 0x0000 || c == 0xFFFF) { lfn->frags[lfn->count][pos] = 0; return; } if (c == 0x0000 || c == 0xFFFF) { done = TRUE; break; }
lfn->frags[lfn->count][pos++] = c; lfn->frags[lfn->count][pos++] = c;
} }
for (int i = 0; i < 2 && pos < LFN_FRAG_SIZE; i++) { for (SSINT32 i = 0; i < 2 && pos < LFN_FRAG_SIZE && !done; i++) {
CHAR16 c = *(const UINT16*)(E + 28 + i * 2); CHAR16 c = *(const UINT16*)(E + 28 + i * 2);
if (c == 0x0000 || c == 0xFFFF) { lfn->frags[lfn->count][pos] = 0; return; } if (c == 0x0000 || c == 0xFFFF) { done = TRUE; break; }
lfn->frags[lfn->count][pos++] = c; lfn->frags[lfn->count][pos++] = c;
} }
lfn->frags[lfn->count][pos] = 0; lfn->frags[lfn->count][pos] = 0;
@@ -413,11 +424,11 @@ static void lfn_build(struct lfn_state *lfn, CHAR16 *out, UINTN out_size) {
static void sfn_to_name(const UINT8 *E, CHAR16 *out, UINTN out_size) { static void sfn_to_name(const UINT8 *E, CHAR16 *out, UINTN out_size) {
UINTN pos = 0; UINTN pos = 0;
for (int i = 0; i < 8 && pos < out_size - 1; i++) for (SSINT32 i = 0; i < 8 && pos < out_size - 1; i++)
if (E[i] != ' ') out[pos++] = E[i]; if (E[i] != ' ') out[pos++] = E[i];
UINTN ext_start = pos; UINTN ext_start = pos;
BOOLEAN has_ext = FALSE; BOOLEAN has_ext = FALSE;
for (int i = 8; i < 11 && pos < out_size - 1; i++) { for (SSINT32 i = 8; i < 11 && pos < out_size - 1; i++) {
if (E[i] != ' ') { if (E[i] != ' ') {
if (!has_ext) { out[pos++] = '.'; has_ext = TRUE; ext_start = pos; } if (!has_ext) { out[pos++] = '.'; has_ext = TRUE; ext_start = pos; }
out[pos++] = E[i]; out[pos++] = E[i];
@@ -431,10 +442,10 @@ static void sfn_to_name(const UINT8 *E, CHAR16 *out, UINTN out_size) {
// ---- Directory reading ---- // ---- Directory reading ----
typedef void (*dir_cb)(void *Ctx, const CHAR16 *Name, UINT8 Attr, typedef void (*dir_cb)(void *Ctx, const CHAR16 *Name, UINT8 Attr,
UINT32 Size, UINT32 FirstClus); UINT32 Size, UINT32 FirstClus, UINTN EntryOff);
// Returns TRUE when end-of-directory reached // Returns TRUE when end-of-directory reached
static BOOLEAN process_sector(struct fat_fs *fs, UINT8 *Buf, static BOOLEAN process_sector(struct fat_fs *fs, UINT8 *Buf, UINTN SectBase,
struct lfn_state *lfn, struct lfn_state *lfn,
dir_cb Callback, void *Ctx) { dir_cb Callback, void *Ctx) {
for (UINTN off = 0; off < fs->BytsPerSec; off += 32) { for (UINTN off = 0; off < fs->BytsPerSec; off += 32) {
@@ -445,7 +456,7 @@ static BOOLEAN process_sector(struct fat_fs *fs, UINT8 *Buf,
UINT8 Attr = E[11]; UINT8 Attr = E[11];
if (Attr == 0x0F) { if ((Attr & 0x3F) == 0x0F) {
if (E[0] & 0x40) lfn_reset(lfn); if (E[0] & 0x40) lfn_reset(lfn);
lfn_add(lfn, E); lfn_add(lfn, E);
continue; continue;
@@ -454,7 +465,7 @@ static BOOLEAN process_sector(struct fat_fs *fs, UINT8 *Buf,
// SFN entry // SFN entry
CHAR16 Name[256]; CHAR16 Name[256];
BOOLEAN use_lfn = FALSE; BOOLEAN use_lfn = FALSE;
if (lfn->count > 0 && lfn_checksum(E) == E[13]) { if (lfn->count > 0 && lfn_checksum(E) == lfn->checksum) {
lfn_build(lfn, Name, 256); lfn_build(lfn, Name, 256);
use_lfn = TRUE; use_lfn = TRUE;
} }
@@ -471,7 +482,7 @@ static BOOLEAN process_sector(struct fat_fs *fs, UINT8 *Buf,
else else
FirstClus = *(const UINT16*)(E + 26); FirstClus = *(const UINT16*)(E + 26);
Callback(Ctx, Name, Attr, Size, FirstClus); Callback(Ctx, Name, Attr, Size, FirstClus, SectBase + off);
lfn_reset(lfn); lfn_reset(lfn);
} }
return FALSE; return FALSE;
@@ -479,7 +490,8 @@ static BOOLEAN process_sector(struct fat_fs *fs, UINT8 *Buf,
static void read_directory(struct fat_fs *fs, UINT32 Cluster, static void read_directory(struct fat_fs *fs, UINT32 Cluster,
dir_cb Callback, void *Ctx) { dir_cb Callback, void *Ctx) {
UINT8 *Buf = (UINT8*)kmalloc(fs->BytsPerSec); UINTN ClusBytes = fs->ClusSize;
UINT8 *Buf = (UINT8*)kmalloc(ClusBytes);
if (!Buf) return; if (!Buf) return;
struct lfn_state lfn; struct lfn_state lfn;
@@ -489,10 +501,12 @@ static void read_directory(struct fat_fs *fs, UINT32 Cluster,
UINT32 Clus = Cluster; UINT32 Clus = Cluster;
while (Clus >= 2 && Clus < 0x0FFFFFF8) { while (Clus >= 2 && Clus < 0x0FFFFFF8) {
UINT64 BaseLBA = clus_to_lba(fs, Clus); UINT64 BaseLBA = clus_to_lba(fs, Clus);
if (EFI_ERROR(blk_read(fs->Dev, BaseLBA, fs->SecPerClus, Buf)))
goto done;
for (UINTN s = 0; s < fs->SecPerClus; s++) { for (UINTN s = 0; s < fs->SecPerClus; s++) {
if (EFI_ERROR(blk_read(fs->Dev, BaseLBA + s, 1, Buf))) if (process_sector(fs, Buf + s * fs->BytsPerSec,
goto done; s * fs->BytsPerSec,
if (process_sector(fs, Buf, &lfn, Callback, Ctx)) &lfn, Callback, Ctx))
goto done; goto done;
} }
Clus = fat_next(fs, Clus); Clus = fat_next(fs, Clus);
@@ -501,19 +515,25 @@ static void read_directory(struct fat_fs *fs, UINT32 Cluster,
UINT32 RootSecs = ((fs->RootEntCnt * 32) + fs->BytsPerSec - 1) / fs->BytsPerSec; UINT32 RootSecs = ((fs->RootEntCnt * 32) + fs->BytsPerSec - 1) / fs->BytsPerSec;
UINT64 RootLBA = fs->PartLBA + fs->RsvdSecCnt + fs->NumFATs * fs->FATSz; UINT64 RootLBA = fs->PartLBA + fs->RsvdSecCnt + fs->NumFATs * fs->FATSz;
for (UINTN s = 0; s < RootSecs; s++) { for (UINTN s = 0; s < RootSecs; s++) {
if (EFI_ERROR(blk_read(fs->Dev, RootLBA + s, 1, Buf))) if (EFI_ERROR(blk_read(fs->Dev, RootLBA + s, 1, Buf + s * fs->BytsPerSec)))
goto done; goto done;
if (process_sector(fs, Buf, &lfn, Callback, Ctx)) }
for (UINTN s = 0; s < RootSecs; s++) {
if (process_sector(fs, Buf + s * fs->BytsPerSec,
s * fs->BytsPerSec,
&lfn, Callback, Ctx))
goto done; goto done;
} }
} else { } else {
UINT32 Clus = Cluster; UINT32 Clus = Cluster;
while (Clus >= 2 && Clus < 0x0FFFFFF8) { while (Clus >= 2 && Clus < 0x0FFFFFF8) {
UINT64 BaseLBA = clus_to_lba(fs, Clus); UINT64 BaseLBA = clus_to_lba(fs, Clus);
if (EFI_ERROR(blk_read(fs->Dev, BaseLBA, fs->SecPerClus, Buf)))
goto done;
for (UINTN s = 0; s < fs->SecPerClus; s++) { for (UINTN s = 0; s < fs->SecPerClus; s++) {
if (EFI_ERROR(blk_read(fs->Dev, BaseLBA + s, 1, Buf))) if (process_sector(fs, Buf + s * fs->BytsPerSec,
goto done; s * fs->BytsPerSec,
if (process_sector(fs, Buf, &lfn, Callback, Ctx)) &lfn, Callback, Ctx))
goto done; goto done;
} }
Clus = fat_next(fs, Clus); Clus = fat_next(fs, Clus);
@@ -533,24 +553,17 @@ static BOOLEAN g_fs_inited = FALSE;
struct list_ctx { struct list_ctx {
struct fat_fs *fs; struct fat_fs *fs;
int depth; SSINT32 depth;
}; };
static void name_to_ascii(const CHAR16 *Name, char *Ascii, UINTN ascii_sz) { static void name_to_ascii(const CHAR16 *Name, char *Ascii, UINTN ascii_sz) {
UINTN i = 0; wstr_to_ascii(Ascii, (WString)Name, ascii_sz);
for (; Name[i] && i < ascii_sz - 1; i++) {
if (Name[i] >= 0x20 && Name[i] <= 0x7E)
Ascii[i] = (char)Name[i];
else
Ascii[i] = '?';
}
Ascii[i] = 0;
} }
static void list_callback(void *ctx, const CHAR16 *Name, UINT8 Attr, static void list_callback(void *ctx, const CHAR16 *Name, UINT8 Attr,
UINT32 Size, UINT32 FirstClus) { UINT32 Size, UINT32 FirstClus, UINTN EntryOff) {
struct list_ctx *lc = (struct list_ctx*)ctx; struct list_ctx *lc = (struct list_ctx*)ctx;
for (int i = 0; i < lc->depth; i++) serial_write(" "); for (SSINT32 i = 0; i < lc->depth; i++) serial_write(" ");
serial_write(Attr & 0x10 ? "[DIR] " : "[FILE] "); serial_write(Attr & 0x10 ? "[DIR] " : "[FILE] ");
@@ -633,14 +646,18 @@ struct find_ctx {
}; };
static BOOLEAN name_match(const CHAR16 *a, const CHAR16 *b) { static BOOLEAN name_match(const CHAR16 *a, const CHAR16 *b) {
UINTN i = 0; while (*a && *b) {
for (; a[i] && b[i]; i++) CHAR16 ca = *a, cb = *b;
if (a[i] != b[i]) return FALSE; if (ca >= L'A' && ca <= L'Z') ca += 32;
return a[i] == 0 && b[i] == 0; if (cb >= L'A' && cb <= L'Z') cb += 32;
if (ca != cb) return FALSE;
a++; b++;
}
return *a == 0 && *b == 0;
} }
static void find_callback(void *ctx, const CHAR16 *Name, UINT8 Attr, static void find_callback(void *ctx, const CHAR16 *Name, UINT8 Attr,
UINT32 Size, UINT32 FirstClus) { UINT32 Size, UINT32 FirstClus, UINTN EntryOff) {
struct find_ctx *fc = (struct find_ctx*)ctx; struct find_ctx *fc = (struct find_ctx*)ctx;
if (fc->Found) return; if (fc->Found) return;
if (name_match(fc->Target, Name)) { if (name_match(fc->Target, Name)) {
@@ -651,7 +668,7 @@ static void find_callback(void *ctx, const CHAR16 *Name, UINT8 Attr,
} }
} }
EFI_STATUS fs_read(const CHAR16 *Path, void **Buffer, UINTN *Size) { EFI_STATUS fs_read(WString Path, void **Buffer, UINTN *Size) {
if (!g_fs_inited) return EFI_NOT_READY; if (!g_fs_inited) return EFI_NOT_READY;
const CHAR16 *p = Path; const CHAR16 *p = Path;
@@ -683,16 +700,24 @@ EFI_STATUS fs_read(const CHAR16 *Path, void **Buffer, UINTN *Size) {
UINTN ClusBytes = g_fs.ClusSize; UINTN ClusBytes = g_fs.ClusSize;
while (Clus >= 2 && Clus < 0x0FFFFFF8 && Offset < FileSz) { while (Clus >= 2 && Clus < 0x0FFFFFF8 && Offset < FileSz) {
UINT64 LBA = clus_to_lba(&g_fs, Clus); // Find longest contiguous run starting at Clus
for (UINTN s = 0; s < g_fs.SecPerClus && Offset < FileSz; s++) { UINT32 RunStart = Clus;
UINTN Part = g_fs.BytsPerSec; UINT32 RunEnd = Clus;
if (Part > FileSz - Offset) Part = FileSz - Offset; UINT32 Next = fat_next(&g_fs, Clus);
EFI_STATUS st = blk_read(g_fs.Dev, LBA + s, 1, while (Next == RunEnd + 1 && Next >= 2 && Next < 0x0FFFFFF8) {
(UINT8*)Buf + Offset); RunEnd = Next;
if (EFI_ERROR(st)) { kfree(Buf); return st; } Next = fat_next(&g_fs, RunEnd);
Offset += Part;
} }
Clus = fat_next(&g_fs, Clus); UINTN RunClus = (UINTN)(RunEnd - RunStart + 1);
UINT64 LBA = clus_to_lba(&g_fs, RunStart);
UINTN Want = RunClus * ClusBytes;
if (Want > FileSz - Offset) Want = FileSz - Offset;
UINTN NSecs = (Want + g_fs.BytsPerSec - 1) / g_fs.BytsPerSec;
EFI_STATUS st = blk_read(g_fs.Dev, LBA, NSecs,
(UINT8*)Buf + Offset);
if (EFI_ERROR(st)) { kfree(Buf); return st; }
Offset += Want;
Clus = Next;
} }
} }
@@ -707,3 +732,246 @@ EFI_STATUS fs_read(const CHAR16 *Path, void **Buffer, UINTN *Size) {
return EFI_NOT_FOUND; return EFI_NOT_FOUND;
} }
// ---- FAT allocation ----
static BOOLEAN fat_entry_free(struct fat_fs *fs, UINT32 Clus) {
if (Clus >= fs->FATEntries) return FALSE;
if (fs->IsFAT32) return (fs->FAT32[Clus] & 0x0FFFFFFF) == 0;
return fs->FAT16[Clus] == 0;
}
static void fat_entry_set(struct fat_fs *fs, UINT32 Clus, UINT32 Val) {
if (Clus >= fs->FATEntries) return;
if (fs->IsFAT32) fs->FAT32[Clus] = Val;
else fs->FAT16[Clus] = (UINT16)Val;
}
// Allocate `Count` free clusters and link them into a chain.
// Returns the first cluster of the new chain; the last entry is marked EOF.
static EFI_STATUS fat_alloc_chain(struct fat_fs *fs, UINT32 Count, UINT32 *OutFirst) {
UINT32 Found = 0;
UINT32 First = 0, Prev = 0;
UINT32 EOC = fs->IsFAT32 ? 0x0FFFFFFF : 0xFFFF;
for (UINT32 i = 2; i < fs->FATEntries && Found < Count; i++) {
if (!fat_entry_free(fs, i)) continue;
if (Found == 0) First = i;
else fat_entry_set(fs, Prev, i);
Found++;
Prev = i;
}
if (Found < Count) return EFI_OUT_OF_RESOURCES;
fat_entry_set(fs, Prev, EOC);
*OutFirst = First;
return EFI_SUCCESS;
}
// Write the in-memory FAT cache back to all FAT copies on disk.
static EFI_STATUS fat_flush(struct fat_fs *fs) {
for (UINTN f = 0; f < fs->NumFATs; f++) {
EFI_STATUS st = blk_write(fs->Dev,
fs->PartLBA + fs->RsvdSecCnt + f * fs->FATSz,
fs->FATSz, fs->FatBuf);
if (EFI_ERROR(st)) return st;
}
return EFI_SUCCESS;
}
// ---- File writing ----
struct find_write_ctx {
const CHAR16 *Target;
BOOLEAN Found;
UINT32 Cluster;
UINT32 Size;
UINT8 Attr;
UINTN DirOffset;
};
static void find_write_callback(void *ctx, const CHAR16 *Name, UINT8 Attr,
UINT32 Size, UINT32 FirstClus, UINTN EntryOff) {
struct find_write_ctx *fc = (struct find_write_ctx*)ctx;
if (fc->Found) return;
if (name_match(fc->Target, Name)) {
fc->Found = TRUE;
fc->Cluster = FirstClus;
fc->Size = Size;
fc->Attr = Attr;
fc->DirOffset = EntryOff;
}
}
// Update a dirent's size + first-cluster fields in-place inside `DirBuf`
// at the given byte offset. For FAT32 we also patch the high cluster word.
static void dirent_update_size(void *DirBuf, UINTN EntryOff,
UINT32 NewSize, UINT32 FirstClus,
BOOLEAN PatchFirstClus, BOOLEAN IsFAT32) {
UINT8 *E = (UINT8*)DirBuf + EntryOff;
*(UINT32*)(E + 28) = NewSize;
if (PatchFirstClus) {
if (IsFAT32) {
*(UINT16*)(E + 20) = (UINT16)(FirstClus >> 16);
*(UINT16*)(E + 26) = (UINT16)(FirstClus & 0xFFFF);
} else {
*(UINT16*)(E + 26) = (UINT16)(FirstClus & 0xFFFF);
}
}
}
// Write [Data, Data+Size) into the file at Path, starting at byte Offset.
// Semantics: existing file only (no create); Offset must be <= current size.
// New file size = Offset + Size. Trailing clusters beyond the new size are
// left allocated (lost) — no truncate support.
EFI_STATUS fs_write(WString Path, const void *Data, UINTN Size, UINTN Offset) {
if (!g_fs_inited) return EFI_NOT_READY;
if (Data == NULL && Size > 0) return EFI_INVALID_PARAMETER;
const CHAR16 *p = Path;
while (*p == L'\\') p++;
UINT32 CurClus = g_fs.IsFAT32 ? g_fs.RootClus : 0;
CHAR16 Comp[256];
BOOLEAN Resolved = FALSE;
UINT32 FileFirst = 0, FileSize = 0, FileAttr = 0;
UINTN FileDirOff = 0;
while (*p) {
UINTN ci = 0;
while (*p && *p != L'\\' && ci < 255) Comp[ci++] = *p++;
Comp[ci] = 0;
while (*p == L'\\') p++;
struct find_write_ctx fc;
fc.Target = Comp;
fc.Found = FALSE;
read_directory(&g_fs, CurClus, find_write_callback, &fc);
if (!fc.Found) return EFI_NOT_FOUND;
if (*p == 0) {
if (fc.Attr & 0x10) return EFI_INVALID_PARAMETER;
Resolved = TRUE;
FileFirst = fc.Cluster;
FileSize = fc.Size;
FileAttr = fc.Attr;
FileDirOff = fc.DirOffset;
} else {
if (!(fc.Attr & 0x10)) return EFI_NOT_FOUND;
CurClus = fc.Cluster;
}
}
if (!Resolved) return EFI_NOT_FOUND;
if (Offset > FileSize) return EFI_INVALID_PARAMETER;
UINT32 NewSize = (UINT32)(Offset + Size);
UINT32 OldClusCount = (FileSize + g_fs.ClusSize - 1) / g_fs.ClusSize;
UINT32 NewClusCount = (NewSize + g_fs.ClusSize - 1) / g_fs.ClusSize;
UINT32 AddClusCount = NewClusCount - OldClusCount;
BOOLEAN FileWasEmpty = (FileSize == 0);
// --- Extend cluster chain if we need more clusters ---
if (AddClusCount > 0) {
UINT32 NewFirst;
EFI_STATUS st = fat_alloc_chain(&g_fs, AddClusCount, &NewFirst);
if (EFI_ERROR(st)) return st;
if (FileWasEmpty) {
FileFirst = NewFirst;
} else {
// Walk to the last cluster of the existing chain
UINT32 Cur = FileFirst;
UINT32 Next;
while (TRUE) {
Next = fat_next(&g_fs, Cur);
if (Next >= 0x0FFFFFF8) break;
Cur = Next;
}
// Cur is the last cluster; link to new chain
fat_entry_set(&g_fs, Cur, NewFirst);
}
}
// --- Write data clusters ---
if (Size > 0) {
// Walk to the cluster containing byte Offset
UINT32 Clus = FileFirst;
UINTN SkipBytes = Offset;
while (SkipBytes >= g_fs.ClusSize) {
Clus = fat_next(&g_fs, Clus);
SkipBytes -= g_fs.ClusSize;
}
void *ClusBuf = kmalloc(g_fs.ClusSize);
if (!ClusBuf) return EFI_OUT_OF_RESOURCES;
const UINT8 *Src = (const UINT8*)Data;
UINTN Remaining = Size;
UINTN InClusOff = SkipBytes;
while (Remaining > 0) {
UINT64 LBA = clus_to_lba(&g_fs, Clus);
UINTN SpaceInClus = g_fs.ClusSize - InClusOff;
UINTN Chunk = Remaining < SpaceInClus ? Remaining : SpaceInClus;
if (InClusOff > 0 || Chunk < g_fs.ClusSize) {
EFI_STATUS rst = blk_read(g_fs.Dev, LBA, g_fs.SecPerClus, ClusBuf);
if (EFI_ERROR(rst)) { kfree(ClusBuf); return rst; }
mem_copy((UINT8*)ClusBuf + InClusOff, Src, Chunk);
EFI_STATUS wst = blk_write(g_fs.Dev, LBA, g_fs.SecPerClus, ClusBuf);
if (EFI_ERROR(wst)) { kfree(ClusBuf); return wst; }
} else {
EFI_STATUS wst = blk_write(g_fs.Dev, LBA, g_fs.SecPerClus, Src);
if (EFI_ERROR(wst)) { kfree(ClusBuf); return wst; }
}
Src += Chunk;
Remaining -= Chunk;
InClusOff = 0;
if (Remaining > 0) {
Clus = fat_next(&g_fs, Clus);
}
}
kfree(ClusBuf);
}
// --- Update dirent (size, and first cluster if file was empty) ---
{
void *DirBuf;
UINT64 DirLBA;
UINTN DirNSecs;
UINTN DirBufBytes;
if (g_fs.IsFAT32) {
DirLBA = clus_to_lba(&g_fs, CurClus);
DirNSecs = g_fs.SecPerClus;
DirBufBytes = g_fs.ClusSize;
} else if (CurClus == 0) {
UINT32 RootSecs = ((g_fs.RootEntCnt * 32) + g_fs.BytsPerSec - 1) / g_fs.BytsPerSec;
DirLBA = g_fs.PartLBA + g_fs.RsvdSecCnt + g_fs.NumFATs * g_fs.FATSz;
DirNSecs = RootSecs;
DirBufBytes = RootSecs * g_fs.BytsPerSec;
} else {
DirLBA = clus_to_lba(&g_fs, CurClus);
DirNSecs = g_fs.SecPerClus;
DirBufBytes = g_fs.ClusSize;
}
DirBuf = kmalloc(DirBufBytes);
if (!DirBuf) return EFI_OUT_OF_RESOURCES;
EFI_STATUS rst = blk_read(g_fs.Dev, DirLBA, DirNSecs, DirBuf);
if (EFI_ERROR(rst)) { kfree(DirBuf); return rst; }
dirent_update_size(DirBuf, FileDirOff, NewSize, FileFirst,
FileWasEmpty, g_fs.IsFAT32);
EFI_STATUS wst = blk_write(g_fs.Dev, DirLBA, DirNSecs, DirBuf);
kfree(DirBuf);
if (EFI_ERROR(wst)) return wst;
}
// --- Flush FAT ---
return fat_flush(&g_fs);
}
+299
View File
@@ -0,0 +1,299 @@
#include <graphics/layer.h>
#include <graphics/draw.h>
#include <graphics/context.h>
#include <memory/heap.h>
#include <memory/pmm.h>
#include <scheduler.h>
#include <serial.h>
#include <devices/cursor.h>
#include <interrupt/idt.h>
#include <interrupt/pic.h>
#include <string_utils.h>
// 图层列表(按 z 排序,最低在前)
static layer_t g_layers[LAYER_MAX];
static UINT32 g_layer_count = 0;
static layer_t* g_layer_list = NULL;
// 合成器后台缓冲区
static EFI_GRAPHICS_OUTPUT_BLT_PIXEL* g_back_buffer = NULL;
// 焦点追踪
static layer_t* g_focused = NULL;
// Shift+F10 状态(由 IRQ 处理函数设置,合成器消费)
static volatile bool g_shift_held = false;
static volatile bool g_switch_pending = false;
static volatile layer_t* g_switch_target = NULL;
// PS/2 扫描码集 1
#define PS2_F10 0x44
#define PS2_LSHIFT 0x2A
#define PS2_RSHIFT 0x36
#define PS2_BREAK_BIT 0x80
// 前向声明
static void layer_insert_sorted(layer_t* layer);
static void layer_remove(layer_t* layer);
static layer_t* find_next_window(layer_t* from);
// PS/2 键盘 IRQ 处理
static void ps2_irq_handler(trap_frame* frame) {
(void)frame;
pic_send_eoi(1);
UINT8 sc;
ASM("inb %1, %0" : "=a"(sc) : "Nd"((UINT16)0x60));
bool is_break = (sc & PS2_BREAK_BIT) != 0;
UINT8 code = sc & 0x7F;
if (code == PS2_LSHIFT || code == PS2_RSHIFT) {
g_shift_held = !is_break;
return;
}
if (!is_break && g_shift_held && code == PS2_F10) {
layer_t* next = find_next_window((layer_t*)g_focused);
if (next) {
g_switch_target = next;
g_switch_pending = true;
}
}
}
// 图层管理
layer_t* layer_create(const char* name, layer_type_t type, UINT32 w, UINT32 h) {
if (g_layer_count >= LAYER_MAX) {
serial_write("LAYER: limit reached\n");
return NULL;
}
UINT32 id = g_layer_count++;
layer_t* layer = &g_layers[id];
layer->id = id;
layer->type = type;
layer->x = 0;
layer->y = 0;
layer->w = w;
layer->h = h;
layer->z = 0;
layer->visible = true;
layer->next = NULL;
str_copy(layer->name, name, LAYER_NAME_LEN);
UINTN buf_size = (UINTN)w * h * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
layer->buffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)kmalloc(buf_size);
if (!layer->buffer) {
serial_write("LAYER: buffer alloc failed for ");
serial_write(name);
serial_write("\n");
g_layer_count--;
return NULL;
}
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* p = layer->buffer;
for (UINTN i = 0; i < (UINTN)w * h; i++) {
p->Blue = 0; p->Green = 0; p->Red = 0; p->Reserved = 0;
p++;
}
layer_insert_sorted(layer);
return layer;
}
void layer_destroy(layer_t* layer) {
if (!layer) return;
layer_remove(layer);
if (layer->buffer) {
kfree(layer->buffer);
layer->buffer = NULL;
}
if (g_focused == layer) g_focused = NULL;
if (g_switch_target == layer) {
g_switch_target = NULL;
g_switch_pending = false;
}
}
layer_t* layer_get_by_id(UINT32 id) {
if (id >= LAYER_MAX) return NULL;
layer_t* l = &g_layers[id];
return l->buffer ? l : NULL;
}
layer_t* layer_get_focused(void) {
return g_focused;
}
void layer_set_z(layer_t* layer, SSINT32 z) {
if (!layer) return;
layer_remove(layer);
layer->z = z;
layer_insert_sorted(layer);
}
void layer_set_pos(layer_t* layer, SSINT32 x, SSINT32 y) {
if (!layer) return;
layer->x = x;
layer->y = y;
}
void layer_set_visible(layer_t* layer, bool visible) {
if (!layer) return;
layer->visible = visible;
}
// 有序插入/移除
static void layer_insert_sorted(layer_t* layer) {
layer->next = NULL;
if (!g_layer_list || layer->z < g_layer_list->z) {
layer->next = g_layer_list;
g_layer_list = layer;
return;
}
layer_t* cur = g_layer_list;
while (cur->next && cur->next->z <= layer->z) {
cur = cur->next;
}
layer->next = cur->next;
cur->next = layer;
}
static void layer_remove(layer_t* layer) {
if (!g_layer_list) return;
if (g_layer_list == layer) {
g_layer_list = layer->next;
layer->next = NULL;
return;
}
layer_t* cur = g_layer_list;
while (cur->next && cur->next != layer) {
cur = cur->next;
}
if (cur->next == layer) {
cur->next = layer->next;
layer->next = NULL;
}
}
static layer_t* find_next_window(layer_t* from) {
layer_t* start = from ? from->next : g_layer_list;
if (!start) start = g_layer_list;
layer_t* cur = start;
do {
if (cur->type == LAYER_TYPE_WINDOW && cur->visible) {
return cur;
}
cur = cur->next;
if (!cur) cur = g_layer_list;
} while (cur != start);
return NULL;
}
// 初始化
void layer_init(void) {
UINT32 hr = g_gfx.hr;
UINT32 vr = g_gfx.vr;
UINTN buf_size = (UINTN)hr * vr * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
g_back_buffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)kmalloc(buf_size);
if (!g_back_buffer) {
serial_write("LAYER: back buffer alloc FAILED\n");
return;
}
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* p = g_back_buffer;
for (UINTN i = 0; i < (UINTN)hr * vr; i++) {
p->Blue = 0; p->Green = 0; p->Red = 0; p->Reserved = 0;
p++;
}
// 注册键盘 IRQ 并取消屏蔽
idt_set_handler(PIC_IRQ_BASE + 1, ps2_irq_handler);
pic_unmask_irq(1);
}
// 合成器任务
void layer_compositor_task(void) {
UINT32 hr = g_gfx.hr;
UINT32 vr = g_gfx.vr;
while (1) {
// 处理延迟的 Shift+F10 窗口切换
if (g_switch_pending) {
g_switch_pending = false;
layer_t* target = (layer_t*)g_switch_target;
if (target && target->visible && target->type == LAYER_TYPE_WINDOW) {
g_focused = target;
layer_set_z(target, 99);
}
}
// 更新光标位置
cursor_update();
// 清除后台缓冲区
EFI_GRAPHICS_OUTPUT_BLT_PIXEL black = {0, 0, 0, 0};
draw_set_target(g_back_buffer, hr, vr);
draw_rect(0, 0, hr, vr, black);
draw_set_default_target();
// 按 z 从低到高合成图层
layer_t* cur = g_layer_list;
while (cur) {
if (cur->visible && cur->buffer) {
SSINT32 sx = 0, sy = 0;
SSINT32 dx = cur->x, dy = cur->y;
UINT32 sw = cur->w, sh = cur->h;
if (dx < 0) { sx = -dx; sw -= sx; dx = 0; }
if (dy < 0) { sy = -dy; sh -= sy; dy = 0; }
if (dx + (SSINT32)sw > (SSINT32)hr) sw = hr - dx;
if (dy + (SSINT32)sh > (SSINT32)vr) sh = vr - dy;
if (sw == 0 || sh == 0) { cur = cur->next; continue; }
bool use_alpha = (cur->type == LAYER_TYPE_MOUSE);
for (UINT32 row = 0; row < sh; row++) {
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* src = cur->buffer + ((UINTN)cur->w * (sy + row)) + sx;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* dst = g_back_buffer + ((UINTN)hr * (dy + row)) + dx;
for (UINT32 col = 0; col < sw; col++) {
if (!use_alpha || src->Reserved != 0) {
dst->Blue = src->Blue;
dst->Green = src->Green;
dst->Red = src->Red;
dst->Reserved = src->Reserved;
}
src++;
dst++;
}
}
}
cur = cur->next;
}
// Blit 到屏幕
uefi_call_wrapper(g_gfx.GOP->Blt, 10,
g_gfx.GOP,
g_back_buffer,
EfiBltBufferToVideo,
(UINTN)0, (UINTN)0, (UINTN)0, (UINTN)0,
(UINTN)hr, (UINTN)vr, (UINTN)0
);
yield();
}
}
+72
View File
@@ -0,0 +1,72 @@
#include <interrupt/gdt.h>
#include <common.h>
#include <string_utils.h>
#include <serial.h>
static gdt_entry g_gdt[7]; // 5 segments + TSS (2 entries)
static gdt_ptr g_gdt_ptr;
static tss g_tss;
extern "C" void lgdt_and_reload(void* gdt_ptr);
extern "C" void tss_load(UINT16 selector);
static void gdt_set_entry(UINT32 index, UINT32 base, UINT32 limit,
UINT8 access, UINT8 granularity) {
g_gdt[index].limit_low = limit & 0xFFFF;
g_gdt[index].base_low = base & 0xFFFF;
g_gdt[index].base_mid = (base >> 16) & 0xFF;
g_gdt[index].access = access;
g_gdt[index].granularity = granularity | ((limit >> 16) & 0x0F);
g_gdt[index].base_high = (base >> 24) & 0xFF;
}
static void tss_set_descriptor(UINT32 index) {
UINT64 base = (UINT64)&g_tss;
UINT32 limit = sizeof(tss) - 1;
g_gdt[index].limit_low = limit & 0xFFFF;
g_gdt[index].base_low = base & 0xFFFF;
g_gdt[index].base_mid = (base >> 16) & 0xFF;
g_gdt[index].access = 0x89;
g_gdt[index].granularity = 0x00;
g_gdt[index].base_high = (base >> 24) & 0xFF;
g_gdt[index + 1].limit_low = (limit >> 16) & 0xFFFF;
g_gdt[index + 1].base_low = (base >> 32) & 0xFFFF;
g_gdt[index + 1].base_mid = (base >> 48) & 0xFF;
g_gdt[index + 1].access = 0;
g_gdt[index + 1].granularity = 0;
g_gdt[index + 1].base_high = 0;
}
void gdt_init(void) {
serial_write("GDT: initializing\n");
for (SSINT32 i = 0; i < 7; i++) {
g_gdt[i] = {0};
}
gdt_set_entry(0, 0, 0, 0, 0);
gdt_set_entry(1, 0, 0xFFFFF, 0x9A, 0xA0);
gdt_set_entry(2, 0, 0xFFFFF, 0x92, 0xC0);
gdt_set_entry(3, 0, 0xFFFFF, 0xFA, 0xA0);
gdt_set_entry(4, 0, 0xFFFFF, 0xF2, 0xC0);
tss_set_descriptor(5);
g_tss = {};
g_tss.iopb_offset = sizeof(tss);
g_gdt_ptr.limit = sizeof(g_gdt) - 1;
g_gdt_ptr.base = (UINT64)&g_gdt[0];
serial_write("GDT: loading GDT + reloading segments\n");
lgdt_and_reload(&g_gdt_ptr);
serial_write("GDT: loading TSS\n");
tss_load(GDT_TSS);
serial_write("GDT: done\n");
}
void gdt_set_kernel_stack(UINT64 stack) {
g_tss.rsp0 = stack;
}
+67
View File
@@ -0,0 +1,67 @@
#include <interrupt/idt.h>
#include <common.h>
#include <string_utils.h>
#include <interrupt/pic.h>
#include <serial.h>
// isr.S 中定义的 256 个 ISR 桩函数
extern "C" void* isr_stub_table[256];
static idt_entry g_idt[256];
static idt_ptr g_idt_ptr;
static isr_handler_t g_handlers[256] = {0};
void idt_set_handler(UINT8 vector, isr_handler_t handler) {
g_handlers[vector] = handler;
}
// 由 isr.S 通用处理函数调用
extern "C" void isr_dispatch(trap_frame* frame) {
UINT8 vector = (UINT8)frame->vector;
if (g_handlers[vector]) {
g_handlers[vector](frame);
} else if (vector < 32) {
serial_write("IDT: unhandled exception #");
serial_write_hex(vector);
serial_write(" error=");
serial_write_hex(frame->error_code);
serial_write("\n");
while (1) ASM("hlt");
}
}
// IDT 辅助函数(定义在 idt_helpers.S
extern "C" void idt_load(UINT64 base, UINT16 limit);
static void idt_set_entry(UINT8 vector, UINT64 handler_addr) {
g_idt[vector].offset_low = handler_addr & 0xFFFF;
g_idt[vector].selector = 0x08; // 内核代码段
g_idt[vector].ist = 0;
g_idt[vector].type_attr = 0x8E; // 存在,DPL=064 位中断门
g_idt[vector].offset_mid = (handler_addr >> 16) & 0xFFFF;
g_idt[vector].offset_high = (handler_addr >> 32) & 0xFFFFFFFF;
g_idt[vector].reserved = 0;
}
void idt_init(void) {
serial_write("IDT: initializing 256 entries\n");
// 清空 IDT
for (SSINT32 i = 0; i < 256; i++) {
g_idt[i] = {0};
g_handlers[i] = NULL;
}
// 安装所有 256 个 ISR 桩函数
for (SSINT32 i = 0; i < 256; i++) {
idt_set_entry(i, (UINT64)isr_stub_table[i]);
}
// 加载 IDT
g_idt_ptr.limit = sizeof(g_idt) - 1;
g_idt_ptr.base = (UINT64)&g_idt[0];
idt_load(g_idt_ptr.base, g_idt_ptr.limit);
serial_write("IDT: loaded\n");
}
+33
View File
@@ -0,0 +1,33 @@
.intel_syntax noprefix
.global idt_load
idt_load:
sub rsp, 10
mov [rsp], si
mov [rsp + 2], rdi
lidt [rsp]
add rsp, 10
ret
.global lgdt_and_reload
lgdt_and_reload:
lgdt [rdi]
push 0x08
mov rax, offset .reload_cs
push rax
retfq
.reload_cs:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
ret
.global tss_load
tss_load:
ltr di
ret
.section .note.GNU-stack,"",@progbits
+589
View File
@@ -0,0 +1,589 @@
.intel_syntax noprefix
// ISR stub table 256 entries
// For exceptions without error code, we push a dummy 0
// For exceptions with error code, the CPU already pushed it
// Macros for generating ISR stubs
.macro ISR_NOERR num
.global isr_stub_\num
isr_stub_\num:
push 0 // dummy error code
push \num // vector number
jmp isr_common
.endm
.macro ISR_ERR num
.global isr_stub_\num
isr_stub_\num:
// error code already on stack from CPU
push \num // vector number
jmp isr_common
.endm
// === Exceptions 0-31 ===
ISR_NOERR 0 // #DE Divide Error
ISR_NOERR 1 // #DB Debug
ISR_NOERR 2 // NMI
ISR_NOERR 3 // #BP Breakpoint
ISR_NOERR 4 // #OF Overflow
ISR_NOERR 5 // #BR Bound Range Exceeded
ISR_NOERR 6 // #UD Invalid Opcode
ISR_NOERR 7 // #NM Device Not Available
ISR_ERR 8 // #DF Double Fault
ISR_NOERR 9 // Coprocessor Segment Overrun (reserved)
ISR_ERR 10 // #TS Invalid TSS
ISR_ERR 11 // #NP Segment Not Present
ISR_ERR 12 // #SS Stack-Segment Fault
ISR_ERR 13 // #GP General Protection
ISR_ERR 14 // #PF Page Fault
ISR_NOERR 15 // Reserved
ISR_NOERR 16 // #MF x87 FPU Error
ISR_ERR 17 // #AC Alignment Check
ISR_NOERR 18 // #MC Machine Check
ISR_NOERR 19 // #XM SIMD Exception
ISR_NOERR 20 // Virtualization Exception
ISR_ERR 21 // #CP Control Protection
ISR_NOERR 22
ISR_NOERR 23
ISR_NOERR 24
ISR_NOERR 25
ISR_NOERR 26
ISR_NOERR 27
ISR_NOERR 28
ISR_ERR 29 // Hypervisor Injection
ISR_ERR 30 // #SX Security Exception
ISR_NOERR 31 // Reserved
// === Hardware IRQs 32-255 ===
ISR_NOERR 32 // PIT timer (IRQ 0)
ISR_NOERR 33 // Keyboard (IRQ 1)
ISR_NOERR 34 // Cascade (IRQ 2)
ISR_NOERR 35 // COM2 (IRQ 3)
ISR_NOERR 36 // COM1 (IRQ 4)
ISR_NOERR 37 // LPT2 (IRQ 5)
ISR_NOERR 38 // Floppy (IRQ 6)
ISR_NOERR 39 // LPT1 / Spurious (IRQ 7)
ISR_NOERR 40 // CMOS RTC (IRQ 8)
ISR_NOERR 41 // ACPI (IRQ 9)
ISR_NOERR 42 // Open (IRQ 10)
ISR_NOERR 43 // Open (IRQ 11)
ISR_NOERR 44 // PS/2 Mouse (IRQ 12)
ISR_NOERR 45 // FPU (IRQ 13)
ISR_NOERR 46 // Primary ATA (IRQ 14)
ISR_NOERR 47 // Secondary ATA (IRQ 15)
// Vectors 48-255: software / unused
ISR_NOERR 48
ISR_NOERR 49
ISR_NOERR 50
ISR_NOERR 51
ISR_NOERR 52
ISR_NOERR 53
ISR_NOERR 54
ISR_NOERR 55
ISR_NOERR 56
ISR_NOERR 57
ISR_NOERR 58
ISR_NOERR 59
ISR_NOERR 60
ISR_NOERR 61
ISR_NOERR 62
ISR_NOERR 63
ISR_NOERR 64
ISR_NOERR 65
ISR_NOERR 66
ISR_NOERR 67
ISR_NOERR 68
ISR_NOERR 69
ISR_NOERR 70
ISR_NOERR 71
ISR_NOERR 72
ISR_NOERR 73
ISR_NOERR 74
ISR_NOERR 75
ISR_NOERR 76
ISR_NOERR 77
ISR_NOERR 78
ISR_NOERR 79
ISR_NOERR 80
ISR_NOERR 81
ISR_NOERR 82
ISR_NOERR 83
ISR_NOERR 84
ISR_NOERR 85
ISR_NOERR 86
ISR_NOERR 87
ISR_NOERR 88
ISR_NOERR 89
ISR_NOERR 90
ISR_NOERR 91
ISR_NOERR 92
ISR_NOERR 93
ISR_NOERR 94
ISR_NOERR 95
ISR_NOERR 96
ISR_NOERR 97
ISR_NOERR 98
ISR_NOERR 99
ISR_NOERR 100
ISR_NOERR 101
ISR_NOERR 102
ISR_NOERR 103
ISR_NOERR 104
ISR_NOERR 105
ISR_NOERR 106
ISR_NOERR 107
ISR_NOERR 108
ISR_NOERR 109
ISR_NOERR 110
ISR_NOERR 111
ISR_NOERR 112
ISR_NOERR 113
ISR_NOERR 114
ISR_NOERR 115
ISR_NOERR 116
ISR_NOERR 117
ISR_NOERR 118
ISR_NOERR 119
ISR_NOERR 120
ISR_NOERR 121
ISR_NOERR 122
ISR_NOERR 123
ISR_NOERR 124
ISR_NOERR 125
ISR_NOERR 126
ISR_NOERR 127
ISR_NOERR 128
ISR_NOERR 129
ISR_NOERR 130
ISR_NOERR 131
ISR_NOERR 132
ISR_NOERR 133
ISR_NOERR 134
ISR_NOERR 135
ISR_NOERR 136
ISR_NOERR 137
ISR_NOERR 138
ISR_NOERR 139
ISR_NOERR 140
ISR_NOERR 141
ISR_NOERR 142
ISR_NOERR 143
ISR_NOERR 144
ISR_NOERR 145
ISR_NOERR 146
ISR_NOERR 147
ISR_NOERR 148
ISR_NOERR 149
ISR_NOERR 150
ISR_NOERR 151
ISR_NOERR 152
ISR_NOERR 153
ISR_NOERR 154
ISR_NOERR 155
ISR_NOERR 156
ISR_NOERR 157
ISR_NOERR 158
ISR_NOERR 159
ISR_NOERR 160
ISR_NOERR 161
ISR_NOERR 162
ISR_NOERR 163
ISR_NOERR 164
ISR_NOERR 165
ISR_NOERR 166
ISR_NOERR 167
ISR_NOERR 168
ISR_NOERR 169
ISR_NOERR 170
ISR_NOERR 171
ISR_NOERR 172
ISR_NOERR 173
ISR_NOERR 174
ISR_NOERR 175
ISR_NOERR 176
ISR_NOERR 177
ISR_NOERR 178
ISR_NOERR 179
ISR_NOERR 180
ISR_NOERR 181
ISR_NOERR 182
ISR_NOERR 183
ISR_NOERR 184
ISR_NOERR 185
ISR_NOERR 186
ISR_NOERR 187
ISR_NOERR 188
ISR_NOERR 189
ISR_NOERR 190
ISR_NOERR 191
ISR_NOERR 192
ISR_NOERR 193
ISR_NOERR 194
ISR_NOERR 195
ISR_NOERR 196
ISR_NOERR 197
ISR_NOERR 198
ISR_NOERR 199
ISR_NOERR 200
ISR_NOERR 201
ISR_NOERR 202
ISR_NOERR 203
ISR_NOERR 204
ISR_NOERR 205
ISR_NOERR 206
ISR_NOERR 207
ISR_NOERR 208
ISR_NOERR 209
ISR_NOERR 210
ISR_NOERR 211
ISR_NOERR 212
ISR_NOERR 213
ISR_NOERR 214
ISR_NOERR 215
ISR_NOERR 216
ISR_NOERR 217
ISR_NOERR 218
ISR_NOERR 219
ISR_NOERR 220
ISR_NOERR 221
ISR_NOERR 222
ISR_NOERR 223
ISR_NOERR 224
ISR_NOERR 225
ISR_NOERR 226
ISR_NOERR 227
ISR_NOERR 228
ISR_NOERR 229
ISR_NOERR 230
ISR_NOERR 231
ISR_NOERR 232
ISR_NOERR 233
ISR_NOERR 234
ISR_NOERR 235
ISR_NOERR 236
ISR_NOERR 237
ISR_NOERR 238
ISR_NOERR 239
ISR_NOERR 240
ISR_NOERR 241
ISR_NOERR 242
ISR_NOERR 243
ISR_NOERR 244
ISR_NOERR 245
ISR_NOERR 246
ISR_NOERR 247
ISR_NOERR 248
ISR_NOERR 249
ISR_NOERR 250
ISR_NOERR 251
ISR_NOERR 252
ISR_NOERR 253
ISR_NOERR 254
ISR_NOERR 255
// === Common ISR handler ===
// Stack layout on entry (from ISR stub):
// [rsp+0x00] vector (pushed by stub)
// [rsp+0x08] error_code (pushed by stub or CPU)
// [rsp+0x10] rip (pushed by CPU)
// [rsp+0x18] cs (pushed by CPU)
// [rsp+0x20] rflags (pushed by CPU)
// [rsp+0x28] rsp (pushed by CPU)
// [rsp+0x30] ss (pushed by CPU)
isr_common:
// Save all general-purpose registers to form trap_frame
push r11
push r10
push r9
push r8
push rdi
push rsi
push rdx
push rcx
push rax
// Now RSP points to trap_frame struct, pass as argument
mov rdi, rsp
call isr_dispatch
// Restore registers
pop rax
pop rcx
pop rdx
pop rsi
pop rdi
pop r8
pop r9
pop r10
pop r11
// Skip vector + error_code (16 bytes)
add rsp, 16
iretq
// === ISR stub table (array of pointers) ===
.section .data
.global isr_stub_table
isr_stub_table:
.quad isr_stub_0
.quad isr_stub_1
.quad isr_stub_2
.quad isr_stub_3
.quad isr_stub_4
.quad isr_stub_5
.quad isr_stub_6
.quad isr_stub_7
.quad isr_stub_8
.quad isr_stub_9
.quad isr_stub_10
.quad isr_stub_11
.quad isr_stub_12
.quad isr_stub_13
.quad isr_stub_14
.quad isr_stub_15
.quad isr_stub_16
.quad isr_stub_17
.quad isr_stub_18
.quad isr_stub_19
.quad isr_stub_20
.quad isr_stub_21
.quad isr_stub_22
.quad isr_stub_23
.quad isr_stub_24
.quad isr_stub_25
.quad isr_stub_26
.quad isr_stub_27
.quad isr_stub_28
.quad isr_stub_29
.quad isr_stub_30
.quad isr_stub_31
.quad isr_stub_32
.quad isr_stub_33
.quad isr_stub_34
.quad isr_stub_35
.quad isr_stub_36
.quad isr_stub_37
.quad isr_stub_38
.quad isr_stub_39
.quad isr_stub_40
.quad isr_stub_41
.quad isr_stub_42
.quad isr_stub_43
.quad isr_stub_44
.quad isr_stub_45
.quad isr_stub_46
.quad isr_stub_47
.quad isr_stub_48
.quad isr_stub_49
.quad isr_stub_50
.quad isr_stub_51
.quad isr_stub_52
.quad isr_stub_53
.quad isr_stub_54
.quad isr_stub_55
.quad isr_stub_56
.quad isr_stub_57
.quad isr_stub_58
.quad isr_stub_59
.quad isr_stub_60
.quad isr_stub_61
.quad isr_stub_62
.quad isr_stub_63
.quad isr_stub_64
.quad isr_stub_65
.quad isr_stub_66
.quad isr_stub_67
.quad isr_stub_68
.quad isr_stub_69
.quad isr_stub_70
.quad isr_stub_71
.quad isr_stub_72
.quad isr_stub_73
.quad isr_stub_74
.quad isr_stub_75
.quad isr_stub_76
.quad isr_stub_77
.quad isr_stub_78
.quad isr_stub_79
.quad isr_stub_80
.quad isr_stub_81
.quad isr_stub_82
.quad isr_stub_83
.quad isr_stub_84
.quad isr_stub_85
.quad isr_stub_86
.quad isr_stub_87
.quad isr_stub_88
.quad isr_stub_89
.quad isr_stub_90
.quad isr_stub_91
.quad isr_stub_92
.quad isr_stub_93
.quad isr_stub_94
.quad isr_stub_95
.quad isr_stub_96
.quad isr_stub_97
.quad isr_stub_98
.quad isr_stub_99
.quad isr_stub_100
.quad isr_stub_101
.quad isr_stub_102
.quad isr_stub_103
.quad isr_stub_104
.quad isr_stub_105
.quad isr_stub_106
.quad isr_stub_107
.quad isr_stub_108
.quad isr_stub_109
.quad isr_stub_110
.quad isr_stub_111
.quad isr_stub_112
.quad isr_stub_113
.quad isr_stub_114
.quad isr_stub_115
.quad isr_stub_116
.quad isr_stub_117
.quad isr_stub_118
.quad isr_stub_119
.quad isr_stub_120
.quad isr_stub_121
.quad isr_stub_122
.quad isr_stub_123
.quad isr_stub_124
.quad isr_stub_125
.quad isr_stub_126
.quad isr_stub_127
.quad isr_stub_128
.quad isr_stub_129
.quad isr_stub_130
.quad isr_stub_131
.quad isr_stub_132
.quad isr_stub_133
.quad isr_stub_134
.quad isr_stub_135
.quad isr_stub_136
.quad isr_stub_137
.quad isr_stub_138
.quad isr_stub_139
.quad isr_stub_140
.quad isr_stub_141
.quad isr_stub_142
.quad isr_stub_143
.quad isr_stub_144
.quad isr_stub_145
.quad isr_stub_146
.quad isr_stub_147
.quad isr_stub_148
.quad isr_stub_149
.quad isr_stub_150
.quad isr_stub_151
.quad isr_stub_152
.quad isr_stub_153
.quad isr_stub_154
.quad isr_stub_155
.quad isr_stub_156
.quad isr_stub_157
.quad isr_stub_158
.quad isr_stub_159
.quad isr_stub_160
.quad isr_stub_161
.quad isr_stub_162
.quad isr_stub_163
.quad isr_stub_164
.quad isr_stub_165
.quad isr_stub_166
.quad isr_stub_167
.quad isr_stub_168
.quad isr_stub_169
.quad isr_stub_170
.quad isr_stub_171
.quad isr_stub_172
.quad isr_stub_173
.quad isr_stub_174
.quad isr_stub_175
.quad isr_stub_176
.quad isr_stub_177
.quad isr_stub_178
.quad isr_stub_179
.quad isr_stub_180
.quad isr_stub_181
.quad isr_stub_182
.quad isr_stub_183
.quad isr_stub_184
.quad isr_stub_185
.quad isr_stub_186
.quad isr_stub_187
.quad isr_stub_188
.quad isr_stub_189
.quad isr_stub_190
.quad isr_stub_191
.quad isr_stub_192
.quad isr_stub_193
.quad isr_stub_194
.quad isr_stub_195
.quad isr_stub_196
.quad isr_stub_197
.quad isr_stub_198
.quad isr_stub_199
.quad isr_stub_200
.quad isr_stub_201
.quad isr_stub_202
.quad isr_stub_203
.quad isr_stub_204
.quad isr_stub_205
.quad isr_stub_206
.quad isr_stub_207
.quad isr_stub_208
.quad isr_stub_209
.quad isr_stub_210
.quad isr_stub_211
.quad isr_stub_212
.quad isr_stub_213
.quad isr_stub_214
.quad isr_stub_215
.quad isr_stub_216
.quad isr_stub_217
.quad isr_stub_218
.quad isr_stub_219
.quad isr_stub_220
.quad isr_stub_221
.quad isr_stub_222
.quad isr_stub_223
.quad isr_stub_224
.quad isr_stub_225
.quad isr_stub_226
.quad isr_stub_227
.quad isr_stub_228
.quad isr_stub_229
.quad isr_stub_230
.quad isr_stub_231
.quad isr_stub_232
.quad isr_stub_233
.quad isr_stub_234
.quad isr_stub_235
.quad isr_stub_236
.quad isr_stub_237
.quad isr_stub_238
.quad isr_stub_239
.quad isr_stub_240
.quad isr_stub_241
.quad isr_stub_242
.quad isr_stub_243
.quad isr_stub_244
.quad isr_stub_245
.quad isr_stub_246
.quad isr_stub_247
.quad isr_stub_248
.quad isr_stub_249
.quad isr_stub_250
.quad isr_stub_251
.quad isr_stub_252
.quad isr_stub_253
.quad isr_stub_254
.quad isr_stub_255
.section .note.GNU-stack,"",@progbits
+72
View File
@@ -0,0 +1,72 @@
#include <interrupt/pic.h>
#include <common.h>
#include <string_utils.h>
#include <serial.h>
static inline void outb(UINT16 port, UINT8 val) {
ASM("outb %0, %1" : : "a"(val), "Nd"(port));
}
static inline UINT8 inb(UINT16 port) {
UINT8 ret;
ASM("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
// 慢速 PIC 的小延迟
static void pic_wait(void) {
ASM("jmp 1f\n\t1: jmp 1f\n\t1:");
}
void pic_init(void) {
serial_write("PIC: remapping 8259 PIC\n");
// 保存掩码
UINT8 mask1 = inb(PIC1_DATA);
UINT8 mask2 = inb(PIC2_DATA);
// ICW1:开始初始化,需要 ICW4
outb(PIC1_CMD, 0x11); pic_wait();
outb(PIC2_CMD, 0x11); pic_wait();
// ICW2:向量偏移
outb(PIC1_DATA, PIC_IRQ_BASE); // IRQ 0-7 → 向量 0x20-0x27
pic_wait();
outb(PIC2_DATA, PIC_IRQ_BASE + 8); // IRQ 8-15 → 向量 0x28-0x2F
pic_wait();
// ICW3:级联
outb(PIC1_DATA, 0x04); pic_wait(); // 从片在 IRQ 2
outb(PIC2_DATA, 0x02); pic_wait(); // 级联标识
// ICW48086 模式
outb(PIC1_DATA, 0x01); pic_wait();
outb(PIC2_DATA, 0x01); pic_wait();
// 恢复掩码
outb(PIC1_DATA, mask1);
outb(PIC2_DATA, mask2);
serial_write("PIC: remapped IRQ 0-7 → 0x20-0x27\n");
}
void pic_send_eoi(UINT8 irq) {
if (irq >= 8) {
outb(PIC2_CMD, PIC_EOI);
}
outb(PIC1_CMD, PIC_EOI);
}
void pic_mask_irq(UINT8 irq) {
UINT16 port = (irq < 8) ? PIC1_DATA : PIC2_DATA;
UINT8 shift = irq % 8;
UINT8 mask = inb(port) | (1 << shift);
outb(port, mask);
}
void pic_unmask_irq(UINT8 irq) {
UINT16 port = (irq < 8) ? PIC1_DATA : PIC2_DATA;
UINT8 shift = irq % 8;
UINT8 mask = inb(port) & ~(1 << shift);
outb(port, mask);
}
+49
View File
@@ -0,0 +1,49 @@
#include <interrupt/pit.h>
#include <common.h>
#include <string_utils.h>
#include <interrupt/pic.h>
#include <serial.h>
static inline void outb(UINT16 port, UINT8 val) {
ASM("outb %0, %1" : : "a"(val), "Nd"(port));
}
static volatile UINT64 g_ticks = 0;
static timer_callback_t g_tick_handler = NULL;
extern "C" void pit_irq_handler(void) {
g_ticks++;
if (g_tick_handler) {
g_tick_handler();
}
}
void pit_init(void) {
serial_write("PIT: initializing channel 0 at ");
serial_write_hex(PIT_TICK_HZ);
serial_write(" Hz\n");
UINT32 divisor = PIT_BASE_FREQ / PIT_TICK_HZ;
// 命令字节:通道 0,低/高字节,速率生成器,二进制
outb(PIT_COMMAND_PORT, 0x36);
// 发送除数(先低字节后高字节)
outb(PIT_CHANNEL0_DATA, (UINT8)(divisor & 0xFF));
outb(PIT_CHANNEL0_DATA, (UINT8)((divisor >> 8) & 0xFF));
// 取消屏蔽 IRQ 0(定时器)
pic_unmask_irq(0);
serial_write("PIT: divisor = ");
serial_write_hex(divisor);
serial_write("\n");
}
void pit_set_tick_handler(timer_callback_t handler) {
g_tick_handler = handler;
}
UINT64 pit_get_ticks(void) {
return g_ticks;
}
+164 -34
View File
@@ -1,18 +1,26 @@
#include <efi.h> #include <efi.h>
#include <graphics/context.h> #include <graphics/context.h>
#include <graphics/draw.h> #include <graphics/draw.h>
#include <graphics/layer.h>
#include <fonts/pixel_font.h> #include <fonts/pixel_font.h>
#include <fonts/ttf.h>
#include <serial.h> #include <serial.h>
#include <common.h> #include <common.h>
#include <string_utils.h>
#include <memory/pmm.h> #include <memory/pmm.h>
#include <memory/heap.h> #include <memory/heap.h>
#include <scheduler.h> #include <scheduler.h>
#include <fs.h> #include <fs.h>
#include <interrupt/gdt.h>
#include <interrupt/idt.h>
#include <interrupt/pic.h>
#include <interrupt/pit.h>
#include <devices/mouse.h>
#include <devices/cursor.h>
extern EFI_SYSTEM_TABLE *ST; extern EFI_SYSTEM_TABLE *ST;
inline void init_gop() { inline void init_gop() {
// 初始化 GOP
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GOP; EFI_GRAPHICS_OUTPUT_PROTOCOL *GOP;
uefi_call_wrapper(ST->BootServices->SetWatchdogTimer, 4, 0, 0, 0, NULL); uefi_call_wrapper(ST->BootServices->SetWatchdogTimer, 4, 0, 0, 0, NULL);
@@ -21,7 +29,6 @@ inline void init_gop() {
} }
inline void init_serial() { inline void init_serial() {
// 初始化串行驱动
EFI_SERIAL_IO_PROTOCOL *SerialIo = NULL; EFI_SERIAL_IO_PROTOCOL *SerialIo = NULL;
EFI_GUID gEfiSerialIoProtocolGuid = EFI_SERIAL_IO_PROTOCOL_GUID; EFI_GUID gEfiSerialIoProtocolGuid = EFI_SERIAL_IO_PROTOCOL_GUID;
EFI_HANDLE *SerialHandles = NULL; EFI_HANDLE *SerialHandles = NULL;
@@ -45,6 +52,26 @@ inline void init_serial() {
} }
} }
// 外部 PIT 中断处理函数,定义在 pit.cpp
extern "C" void pit_irq_handler(void);
// PIC 中断处理 — 分发 IRQ 0(定时器)
static void irq_handler(trap_frame* frame) {
UINT8 vector = (UINT8)frame->vector;
UINT8 irq = vector - PIC_IRQ_BASE;
// 先发送 EOI 再处理,这样上下文切换后 PIC 可以立即投递新中断
pic_send_eoi(irq);
switch (irq) {
case 0: // PIT timer
pit_irq_handler();
break;
default:
break;
}
}
extern "C" void kernel_main() { extern "C" void kernel_main() {
init_gop(); init_gop();
init_serial(); init_serial();
@@ -53,9 +80,9 @@ extern "C" void kernel_main() {
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, (CHAR16*)L"Kernel is running!\n"); uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, (CHAR16*)L"Kernel is running!\n");
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
serial_write("\n\n"); // 防止和前面串了serial.log看不清 serial_write("\n\n");
// init memory managers // 初始化内存管理器
serial_write("Sylva: init PMM...\n"); serial_write("Sylva: init PMM...\n");
EFI_STATUS st = pmm_init(); EFI_STATUS st = pmm_init();
if (EFI_ERROR(st)) { if (EFI_ERROR(st)) {
@@ -70,7 +97,7 @@ extern "C" void kernel_main() {
serial_write("Sylva: init heap...\n"); serial_write("Sylva: init heap...\n");
init_heap(); init_heap();
// test kmalloc/kfree // 测试 kmalloc/kfree
serial_write("Sylva: kmalloc test...\n"); serial_write("Sylva: kmalloc test...\n");
void* p1 = kmalloc(64); void* p1 = kmalloc(64);
void* p2 = kmalloc(128); void* p2 = kmalloc(128);
@@ -105,41 +132,144 @@ extern "C" void kernel_main() {
fs_list(); fs_list();
} }
pf_print("Welcome to Sylva OS!\n"); // pf_print("Welcome to Sylva OS!\n");
serial_write(" Kernel prepared well.\n"); serial_write(" Kernel prepared well.\n");
// --- Multitasking demo --- // 初始化中断基础设施
serial_write("Sylva: init GDT...\n");
gdt_init();
serial_write("Sylva: init IDT...\n");
idt_init();
serial_write("Sylva: init PIC...\n");
pic_init();
// 注册 IRQ 处理函数(向量 0x20 = PIC_IRQ_BASE + 0
idt_set_handler(PIC_IRQ_BASE + 0, irq_handler);
// 初始化 PS/2 鼠标驱动
serial_write("Sylva: init mouse...\n");
mouse_init();
serial_write("Sylva: init PIT...\n");
pit_init();
pit_set_tick_handler(scheduler_tick);
// 启用中断
ASM("sti");
serial_write("Sylva: interrupts enabled\n");
// 创建多任务演示
serial_write("Sylva: creating tasks...\n"); serial_write("Sylva: creating tasks...\n");
// Task A: prints a message 3 times, yielding between each // 初始化合成器(分配后台缓冲区,注册键盘处理)
task_create("taskA", []() { layer_init();
for (int i = 0; i < 3; i++) {
serial_write("[taskA] running iteration "); // 初始化鼠标光标
serial_write_hex(i); cursor_init();
serial_write("\n");
yield(); // 创建桌面图层(全屏,z=0
layer_t* desktop = layer_create("desktop", LAYER_TYPE_DESKTOP, g_gfx.hr, g_gfx.vr);
if (desktop) {
layer_set_z(desktop, 0);
EFI_GRAPHICS_OUTPUT_BLT_PIXEL bg = {180, 80, 40, 0};
draw_set_target(desktop->buffer, g_gfx.hr, g_gfx.vr);
draw_rect(0, 0, g_gfx.hr, g_gfx.vr, bg);
draw_set_default_target();
layer_set_pos(desktop, 0, 0);
}
// 创建窗口 1(居中)
layer_t* win1 = layer_create("window_1", LAYER_TYPE_WINDOW, 300, 200);
if (win1) {
layer_set_pos(win1, (SSINT32)(g_gfx.hr / 2) - 150, (SSINT32)(g_gfx.vr / 2) - 100);
layer_set_z(win1, 1);
EFI_GRAPHICS_OUTPUT_BLT_PIXEL win_color = {200, 200, 200, 0};
draw_set_target(win1->buffer, 300, 200);
draw_rect(0, 0, 299, 199, win_color);
draw_set_default_target();
}
// 创建窗口 2(偏离中心)
layer_t* win2 = layer_create("window_2", LAYER_TYPE_WINDOW, 250, 180);
if (win2) {
layer_set_pos(win2, (SSINT32)(g_gfx.hr / 2) - 50, (SSINT32)(g_gfx.vr / 2) - 40);
layer_set_z(win2, 2);
EFI_GRAPHICS_OUTPUT_BLT_PIXEL win2_color = {180, 220, 140, 0};
draw_set_target(win2->buffer, 250, 180);
draw_rect(0, 0, 249, 179, win2_color);
draw_set_default_target();
}
// 合成器任务
task_create("compositor", layer_compositor_task);
serial_write("Sylva: disk read benchmark...\n");
void *ttf_buf = NULL;
UINTN ttf_size = 0;
UINT64 t0 = pit_get_ticks();
EFI_STATUS rd_st = fs_read((WString)L"sys\\resources\\LXGWWenKai-Light.ttf", &ttf_buf, &ttf_size);
UINT64 t1 = pit_get_ticks();
if (EFI_ERROR(rd_st)) {
serial_write("Sylva: fs_read FAILED: ");
serial_write_hex(rd_st);
serial_write("\n");
serial_write("Test done.\n\n");
} else {
UINT64 ticks = t1 - t0;
UINT64 ms = ticks * (1000 / PIT_TICK_HZ);
UINT64 kbps = ms ? (ttf_size * 1000ULL) / (ms * 1024ULL) : 0;
serial_write("Sylva: read ");
serial_write_hex(ttf_size);
serial_write(" bytes in ");
serial_write_hex(ms);
serial_write(" ms (");
serial_write_hex(kbps);
serial_write(" KiB/s)\n");
// TTF 渲染演示
serial_write("Sylva: ttf_open...\n");
ttf_face_t* face = ttf_open(ttf_buf, ttf_size);
if (!face) {
serial_write("Sylva: ttf_open FAILED\n");
} else {
serial_write("Sylva: ttf_open OK\n");
// 创建 TTF 文本覆盖图层
const UINT32 TL_W = 500, TL_H = 200;
layer_t* text_layer = layer_create("ttf_text", LAYER_TYPE_WINDOW, TL_W, TL_H);
if (text_layer) {
layer_set_z(text_layer, 3);
layer_set_pos(text_layer, 100, 300);
EFI_GRAPHICS_OUTPUT_BLT_PIXEL clear = {0, 0, 0, 0};
draw_set_target(text_layer->buffer, TL_W, TL_H);
draw_rect(0, 0, TL_W - 1, TL_H - 1, clear);
// 渲染多种字号和中日韩字符
EFI_GRAPHICS_OUTPUT_BLT_PIXEL white = {255, 255, 255, 0};
EFI_GRAPHICS_OUTPUT_BLT_PIXEL yellow = {255, 240, 80, 0};
EFI_GRAPHICS_OUTPUT_BLT_PIXEL cyan = {80, 220, 255, 0};
EFI_GRAPHICS_OUTPUT_BLT_PIXEL pink = {255, 160, 200, 0};
UINT32 ttf_t0 = pit_get_ticks();
ttf_draw_text(face, "Hello, Sylva OS!",
40, 60, 24, white);
ttf_draw_text(face, "欢迎来到Sylva系统!",
40, 110, 32, yellow);
UINT32 ttf_t1 = pit_get_ticks();
draw_set_default_target();
serial_write("Sylva: ttf render in ");
serial_write_hex((UINT64)((ttf_t1 - ttf_t0) * (1000 / PIT_TICK_HZ)));
serial_write(" ms\n");
}
ttf_close(face);
} }
serial_write("[taskA] done\n"); kfree(ttf_buf);
}); }
serial_write("Test done.\n\n");
// Task B: prints a message 5 times
task_create("taskB", []() {
for (int i = 0; i < 5; i++) {
serial_write("[taskB] hello from taskB #");
serial_write_hex(i);
serial_write("\n");
yield();
}
serial_write("[taskB] done\n");
});
// Task C: short task serial_write("Sylva: starting preemptive scheduler\n");
task_create("taskC", []() {
serial_write("[taskC] quick task\n");
yield();
serial_write("[taskC] finished\n");
});
serial_write("Sylva: starting scheduler\n");
scheduler_run(); // never returns scheduler_run(); // never returns
} }
+17 -23
View File
@@ -1,6 +1,7 @@
#include <memory/heap.h> #include <memory/heap.h>
#include <memory/pmm.h> #include <memory/pmm.h>
#include <serial.h> #include <serial.h>
#include <string_utils.h>
struct heap_block { struct heap_block {
UINTN size; // includes header; bit 0 = 1 used, 0 free UINTN size; // includes header; bit 0 = 1 used, 0 free
@@ -41,7 +42,7 @@ static void heap_expand(UINTN min_size) {
new_block->size = pages * PAGE_SIZE; new_block->size = pages * PAGE_SIZE;
new_block->next = NULL; new_block->next = NULL;
// Add to free list (sorted by address for coalescing) // 添加到空闲链表(按地址排序以便合并)
struct heap_block** prev = &g_heap_free_list; struct heap_block** prev = &g_heap_free_list;
while (*prev && (UINT8*)*prev < (UINT8*)new_block) { while (*prev && (UINT8*)*prev < (UINT8*)new_block) {
prev = &(*prev)->next; prev = &(*prev)->next;
@@ -49,7 +50,7 @@ static void heap_expand(UINTN min_size) {
new_block->next = *prev; new_block->next = *prev;
*prev = new_block; *prev = new_block;
// Try to merge with the previous free block if adjacent // 尝试与前一个空闲块合并(如果相邻)
if (prev != &g_heap_free_list) { if (prev != &g_heap_free_list) {
struct heap_block* prev_block = g_heap_free_list; struct heap_block* prev_block = g_heap_free_list;
while (prev_block->next != new_block) { while (prev_block->next != new_block) {
@@ -103,21 +104,21 @@ void* kmalloc(UINTN size) {
while (*prev) { while (*prev) {
UINTN block_sz = BLOCK_SIZE(*prev); UINTN block_sz = BLOCK_SIZE(*prev);
if (block_sz >= alloc_size) { if (block_sz >= alloc_size) {
// Found a suitable block // 找到合适的块
struct heap_block* block = *prev; struct heap_block* block = *prev;
// Split if remaining space is useful // 如果剩余空间足够则分割
if (block_sz >= alloc_size + MIN_BLOCK_SIZE) { if (block_sz >= alloc_size + MIN_BLOCK_SIZE) {
struct heap_block* split = (struct heap_block*)((UINT8*)block + alloc_size); struct heap_block* split = (struct heap_block*)((UINT8*)block + alloc_size);
split->size = block_sz - alloc_size; split->size = block_sz - alloc_size;
// Insert split into free list // 将分割后的块插入空闲链表
split->next = block->next; split->next = block->next;
block->size = alloc_size | 1; block->size = alloc_size | 1;
*prev = split; *prev = split;
} else { } else {
// Use the whole block // 使用整个块
*prev = block->next; *prev = block->next;
block->size = block_sz | 1; // mark used block->size = block_sz | 1; // 标记为已使用
} }
if (size > 1024) { if (size > 1024) {
@@ -133,11 +134,11 @@ void* kmalloc(UINTN size) {
prev = &(*prev)->next; prev = &(*prev)->next;
} }
// Out of memory in current heap — expand // 当前堆空间不足,扩展堆
UINTN expand_size = alloc_size > PAGE_SIZE ? alloc_size : PAGE_SIZE; UINTN expand_size = alloc_size > PAGE_SIZE ? alloc_size : PAGE_SIZE;
heap_expand(expand_size); heap_expand(expand_size);
// Retry after expansion // 扩展后重试
return kmalloc(size); return kmalloc(size);
} }
@@ -150,14 +151,14 @@ void kfree(void* ptr) {
return; return;
} }
// Mark as free // 标记为空闲
block->size &= ~(UINTN)1; block->size &= ~(UINTN)1;
// Merge with next block if it's free // 与下一个空闲块合并
struct heap_block* next = next_block(block); struct heap_block* next = next_block(block);
if ((UINT8*)next < (UINT8*)g_heap_end) { if ((UINT8*)next < (UINT8*)g_heap_end) {
if (IS_FREE(next)) { if (IS_FREE(next)) {
// Remove next from free list and merge // 从空闲链表中移除 next 并合并
block->size += next->size; block->size += next->size;
struct heap_block** prev = &g_heap_free_list; struct heap_block** prev = &g_heap_free_list;
while (*prev && *prev != next) { while (*prev && *prev != next) {
@@ -167,7 +168,7 @@ void kfree(void* ptr) {
} }
} }
// Insert block into free list // 将块插入空闲链表
struct heap_block** prev = &g_heap_free_list; struct heap_block** prev = &g_heap_free_list;
while (*prev && (UINT8*)*prev < (UINT8*)block) { while (*prev && (UINT8*)*prev < (UINT8*)block) {
prev = &(*prev)->next; prev = &(*prev)->next;
@@ -184,10 +185,7 @@ void* kcalloc(UINTN num, UINTN size) {
UINTN total = num * size; UINTN total = num * size;
void* ptr = kmalloc(total); void* ptr = kmalloc(total);
if (ptr) { if (ptr) {
UINT8* p = (UINT8*)ptr; mem_set(ptr, 0, total);
for (UINTN i = 0; i < total; i++) {
p[i] = 0;
}
} }
return ptr; return ptr;
} }
@@ -203,7 +201,7 @@ void* krealloc(void* ptr, UINTN new_size) {
UINTN old_size = BLOCK_SIZE(block) - HEADER_SIZE; UINTN old_size = BLOCK_SIZE(block) - HEADER_SIZE;
if (old_size >= new_size) { if (old_size >= new_size) {
// Can we split the shrinkage? // 能否分割缩小的部分?
UINTN shrink = old_size - new_size; UINTN shrink = old_size - new_size;
if (shrink >= MIN_BLOCK_SIZE) { if (shrink >= MIN_BLOCK_SIZE) {
block->size = (new_size + HEADER_SIZE) | 1; block->size = (new_size + HEADER_SIZE) | 1;
@@ -216,11 +214,7 @@ void* krealloc(void* ptr, UINTN new_size) {
void* new_ptr = kmalloc(new_size); void* new_ptr = kmalloc(new_size);
if (new_ptr) { if (new_ptr) {
UINT8* src = (UINT8*)ptr; mem_copy(new_ptr, ptr, old_size);
UINT8* dst = (UINT8*)new_ptr;
for (UINTN i = 0; i < old_size; i++) {
dst[i] = src[i];
}
kfree(ptr); kfree(ptr);
} }
return new_ptr; return new_ptr;
+13 -11
View File
@@ -1,5 +1,7 @@
#include <memory/pmm.h> #include <memory/pmm.h>
#include <common.h>
#include <serial.h> #include <serial.h>
#include <string_utils.h>
extern EFI_SYSTEM_TABLE *ST; extern EFI_SYSTEM_TABLE *ST;
@@ -17,7 +19,7 @@ static inline BOOLEAN bitmap_test(UINTN idx) {
return (g_pmm.bitmap[idx / 8] >> (idx % 8)) & 1; return (g_pmm.bitmap[idx / 8] >> (idx % 8)) & 1;
} }
// Clean stale entries from free list head // 清理空闲链表头部的过期条目
static void clean_free_list() { static void clean_free_list() {
while (g_pmm.free_list_head != NULL && while (g_pmm.free_list_head != NULL &&
bitmap_test((UINTN)g_pmm.free_list_head / PAGE_SIZE)) { bitmap_test((UINTN)g_pmm.free_list_head / PAGE_SIZE)) {
@@ -56,7 +58,7 @@ EFI_STATUS pmm_init() {
UINTN entry_count = map_size / desc_size; UINTN entry_count = map_size / desc_size;
// First pass: count total pages and find max physical address // 第一遍:统计总页数并找到最大物理地址
UINT64 max_addr = 0; UINT64 max_addr = 0;
UINT64 total_free = 0; UINT64 total_free = 0;
for (UINTN i = 0; i < entry_count; i++) { for (UINTN i = 0; i < entry_count; i++) {
@@ -71,16 +73,16 @@ EFI_STATUS pmm_init() {
g_pmm.base_addr = 0; g_pmm.base_addr = 0;
g_pmm.max_addr = max_addr; g_pmm.max_addr = max_addr;
// How many pages does the bitmap cover? // 位图覆盖的页数
UINTN total_pages = (UINTN)(max_addr / PAGE_SIZE); UINTN total_pages = (UINTN)(max_addr / PAGE_SIZE);
g_pmm.total_pages = total_pages; g_pmm.total_pages = total_pages;
// Bitmap size in bytes, rounded up to page boundary // 位图大小(字节),向上取整到页边界
g_pmm.bitmap_size = ((total_pages + 7) / 8); g_pmm.bitmap_size = ((total_pages + 7) / 8);
UINTN bitmap_pages = (g_pmm.bitmap_size + PAGE_SIZE - 1) / PAGE_SIZE; UINTN bitmap_pages = (g_pmm.bitmap_size + PAGE_SIZE - 1) / PAGE_SIZE;
g_pmm.bitmap_size = bitmap_pages * PAGE_SIZE; // round to full pages g_pmm.bitmap_size = bitmap_pages * PAGE_SIZE; // round to full pages
// Place bitmap at the end of the highest free conventional memory region // 将位图放在最高空闲常规内存区域的末尾
UINT64 bitmap_addr = 0; UINT64 bitmap_addr = 0;
for (UINTN i = 0; i < entry_count; i++) { for (UINTN i = 0; i < entry_count; i++) {
EFI_MEMORY_DESCRIPTOR* desc = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)mem_map + i * desc_size); EFI_MEMORY_DESCRIPTOR* desc = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)mem_map + i * desc_size);
@@ -103,12 +105,12 @@ EFI_STATUS pmm_init() {
g_pmm.bitmap = (UINT8*)(UINTN)bitmap_addr; g_pmm.bitmap = (UINT8*)(UINTN)bitmap_addr;
// Init bitmap: mark ALL pages as used (0xFF) // 初始化位图:将所有页标记为已使用
for (UINTN i = 0; i < g_pmm.bitmap_size; i++) { for (UINTN i = 0; i < g_pmm.bitmap_size; i++) {
g_pmm.bitmap[i] = 0xFF; g_pmm.bitmap[i] = 0xFF;
} }
// Mark free pages (EfiConventionalMemory) as free in bitmap // 将空闲页(EfiConventionalMemory)在位图中标记为空闲
g_pmm.free_pages = 0; g_pmm.free_pages = 0;
UINT64 bm_start_page = bitmap_addr / PAGE_SIZE; UINT64 bm_start_page = bitmap_addr / PAGE_SIZE;
UINT64 bm_end_page = (bitmap_addr + g_pmm.bitmap_size + PAGE_SIZE - 1) / PAGE_SIZE; UINT64 bm_end_page = (bitmap_addr + g_pmm.bitmap_size + PAGE_SIZE - 1) / PAGE_SIZE;
@@ -121,19 +123,19 @@ EFI_STATUS pmm_init() {
UINT64 end_page = start_page + desc->NumberOfPages; UINT64 end_page = start_page + desc->NumberOfPages;
for (UINT64 p = start_page; p < end_page; p++) { for (UINT64 p = start_page; p < end_page; p++) {
// Skip bitmap pages // 跳过位图占用的页
if (p >= bm_start_page && p < bm_end_page) continue; if (p >= bm_start_page && p < bm_end_page) continue;
bitmap_clear((UINTN)p); bitmap_clear((UINTN)p);
g_pmm.free_pages++; g_pmm.free_pages++;
} }
} }
// Mark bitmap pages as used // 将位图占用的页标记为已使用
for (UINT64 p = bm_start_page; p < bm_end_page; p++) { for (UINT64 p = bm_start_page; p < bm_end_page; p++) {
bitmap_set((UINTN)p); bitmap_set((UINTN)p);
} }
// Reserve low memory (first 4 MB) — UEFI firmware may use it during BS calls // 保留低内存(前 4MB)— 固件可能在 Boot Services 调用期间使用
UINT64 low_reserve_pages = 0x400; UINT64 low_reserve_pages = 0x400;
for (UINT64 p = 0; p < low_reserve_pages && p < g_pmm.total_pages; p++) { for (UINT64 p = 0; p < low_reserve_pages && p < g_pmm.total_pages; p++) {
if (!bitmap_test((UINTN)p)) { if (!bitmap_test((UINTN)p)) {
@@ -142,7 +144,7 @@ EFI_STATUS pmm_init() {
} }
} }
// Build free list by linking free pages // 通过链接空闲页构建空闲链表
g_pmm.free_list_head = NULL; g_pmm.free_list_head = NULL;
void* prev = NULL; void* prev = NULL;
for (UINTN i = 0; i < entry_count; i++) { for (UINTN i = 0; i < entry_count; i++) {
+13 -1
View File
@@ -5,7 +5,19 @@
// rsi = new_rsp (value of new stack pointer) // rsi = new_rsp (value of new stack pointer)
// //
// Saves/restores callee-saved registers only. // Saves/restores callee-saved registers only.
// On first switch into a new task, ret lands on task_entry_trampoline. // The caller-saved registers are already saved on the task's stack
// by the ISR stub (for preemptive switching) or are not in use
// (for the initial switch).
//
// For preemptive switching:
// - Timer IRQ fires, ISR stub pushes rax-r11 + trap_frame
// - C code runs (isr_dispatch timer handler scheduler)
// - context_switch saves/restores callee-saved regs + switches RSP
// - On return, C code unwinds, isr_common pops rax-r11 + iretq
//
// For new tasks:
// - task_create sets up a fake trap_frame on the stack
// - context_switch pops callee-saved regs, returns into task_entry_trampoline
.global context_switch .global context_switch
context_switch: context_switch:
push rbx push rbx
+80 -45
View File
@@ -1,28 +1,29 @@
#include <scheduler.h> #include <scheduler.h>
#include <interrupt/idt.h>
#include <interrupt/pic.h>
#include <memory/heap.h> #include <memory/heap.h>
#include <memory/pmm.h> #include <memory/pmm.h>
#include <common.h> #include <common.h>
#include <serial.h> #include <serial.h>
// Assembly: context_switch(UINT64* old_rsp, UINT64 new_rsp) // 汇编函数:context_switch(UINT64* old_rsp, UINT64 new_rsp)
extern "C" void context_switch(UINT64* old_rsp, UINT64 new_rsp); extern "C" void context_switch(UINT64* old_rsp, UINT64 new_rsp);
static task_t g_tasks[TASK_MAX]; static task_t g_tasks[TASK_MAX];
static UINT32 g_task_count = 0; static UINT32 g_task_count = 0;
static task_t* g_current = NULL; static task_t* g_current = NULL;
static task_t* g_task_list = NULL; // circular linked list head static task_t* g_task_list = NULL; // 循环链表头
// Trampoline: first thing a new task runs after context_switch. // 跳板函数:新任务在 context_switch 后首先执行的函数
// The entry function pointer is stored in the task's name field
// (we repurpose a slot — actually we store it in a simple global array).
static void (*g_task_entries[TASK_MAX])(void); static void (*g_task_entries[TASK_MAX])(void);
extern "C" void task_entry_trampoline() { extern "C" void task_entry_trampoline() {
ASM("sti");
task_t* cur = scheduler_current(); task_t* cur = scheduler_current();
if (cur && g_task_entries[cur->id]) { if (cur && g_task_entries[cur->id]) {
g_task_entries[cur->id](); // call the user function g_task_entries[cur->id]();
} }
task_exit(); // clean up when done task_exit();
} }
task_t* task_create(const char* name, void (*entry)(void)) { task_t* task_create(const char* name, void (*entry)(void)) {
@@ -34,10 +35,9 @@ task_t* task_create(const char* name, void (*entry)(void)) {
UINT32 id = g_task_count++; UINT32 id = g_task_count++;
task_t* task = &g_tasks[id]; task_t* task = &g_tasks[id];
// Store entry function for the trampoline
g_task_entries[id] = entry; g_task_entries[id] = entry;
// Allocate kernel stack // 分配内核栈
UINTN stack_pages = TASK_STACK_SIZE / PAGE_SIZE; UINTN stack_pages = TASK_STACK_SIZE / PAGE_SIZE;
void* stack = pmm_alloc_pages(stack_pages); void* stack = pmm_alloc_pages(stack_pages);
if (!stack) { if (!stack) {
@@ -47,38 +47,31 @@ task_t* task_create(const char* name, void (*entry)(void)) {
return NULL; return NULL;
} }
// Fill task struct
task->id = id; task->id = id;
task->state = TASK_STATE_READY; task->state = TASK_STATE_READY;
task->stack_base = stack; task->stack_base = stack;
task->time_slice = TIME_SLICE_DEFAULT;
// Copy name // 复制任务名称
const char* s = name; str_copy(task->name, name, TASK_NAME_LEN);
char* d = task->name;
for (int i = 0; i < TASK_NAME_LEN - 1 && *s; i++) {
*d++ = *s++;
}
*d = '\0';
// Set up initial stack for first context_switch into this task. // 设置首次 context_switch 时的初始栈
// Stack grows downward. context_switch will pop 6 regs then ret. // 栈向下增长。context_switch 会弹出 6 个寄存器然后 ret
// //
// Layout (high addr -> low addr): // 布局(高地址 → 低地址):
// [stack + TASK_STACK_SIZE] <- top // [stack + TASK_STACK_SIZE] <- 栈顶
// return addr = task_entry_trampoline (ret goes here) // 返回地址 = task_entry_trampolineret 跳转到这里)
// rbx = 0 // rbx = 0
// rbp = 0 // rbp = 0
// r12 = 0 // r12 = 0
// r13 = 0 // r13 = 0
// r14 = 0 // r14 = 0
// r15 = 0 <- RSP points here initially // r15 = 0 <- RSP 初始指向这里
// //
UINT64* sp = (UINT64*)((UINT8*)stack + TASK_STACK_SIZE); UINT64* sp = (UINT64*)((UINT8*)stack + TASK_STACK_SIZE);
// Push return address (task_entry_trampoline)
*--sp = (UINT64)task_entry_trampoline; *--sp = (UINT64)task_entry_trampoline;
// Push callee-saved registers (all zero)
*--sp = 0; // rbx *--sp = 0; // rbx
*--sp = 0; // rbp *--sp = 0; // rbp
*--sp = 0; // r12 *--sp = 0; // r12
@@ -88,15 +81,14 @@ task_t* task_create(const char* name, void (*entry)(void)) {
task->rsp = (UINT64)sp; task->rsp = (UINT64)sp;
// Insert into circular linked list // 插入循环链表
if (g_task_list == NULL) { if (g_task_list == NULL) {
task->next = task; // points to itself (single element circle) task->next = task;
g_task_list = task; g_task_list = task;
} else { } else {
// Insert after current tail (g_task_list is the "last" in circle)
task->next = g_task_list->next; task->next = g_task_list->next;
g_task_list->next = task; g_task_list->next = task;
g_task_list = task; // new tail g_task_list = task;
} }
serial_write("SCHED: created task '"); serial_write("SCHED: created task '");
@@ -108,36 +100,79 @@ task_t* task_create(const char* name, void (*entry)(void)) {
return task; return task;
} }
// 在循环链表中查找下一个就绪任务
static task_t* find_next_ready(void) {
if (g_current == NULL || g_task_list == NULL) return NULL;
task_t* next = g_current->next;
task_t* start = next;
do {
if (next->state == TASK_STATE_READY) {
return next;
}
next = next->next;
} while (next != start);
return NULL; // 没有就绪任务
}
void yield(void) { void yield(void) {
if (g_current == NULL || g_task_list == NULL) return; if (g_current == NULL || g_task_list == NULL) return;
task_t* cur = g_current; task_t* cur = g_current;
task_t* next = cur->next; task_t* next = find_next_ready();
// Skip terminated tasks if (next == NULL || next == cur) return;
while (next->state == TASK_STATE_TERMINATED && next != cur) {
next = next->next;
}
if (next->state == TASK_STATE_TERMINATED) return; // all terminated
if (next == cur) return; // only one task, nothing to do
if (cur->state != TASK_STATE_TERMINATED) if (cur->state != TASK_STATE_TERMINATED)
cur->state = TASK_STATE_READY; cur->state = TASK_STATE_READY;
next->state = TASK_STATE_RUNNING; next->state = TASK_STATE_RUNNING;
next->time_slice = TIME_SLICE_DEFAULT;
g_current = next; g_current = next;
context_switch(&cur->rsp, next->rsp); context_switch(&cur->rsp, next->rsp);
} }
// 定时器 tick 处理 — 由 PIT IRQ 0 调用
void scheduler_tick(void) {
if (g_current == NULL) return;
// 递减时间片
if (g_current->time_slice > 0) {
g_current->time_slice--;
}
// 时间片用完则抢占
if (g_current->time_slice == 0) {
task_t* cur = g_current;
task_t* next = find_next_ready();
if (next == NULL || next == cur) {
// 没有其他就绪任务,或仅此一个 — 重置时间片
cur->time_slice = TIME_SLICE_DEFAULT;
return;
}
// 抢占
cur->state = TASK_STATE_READY;
cur->time_slice = TIME_SLICE_DEFAULT;
next->state = TASK_STATE_RUNNING;
next->time_slice = TIME_SLICE_DEFAULT;
g_current = next;
context_switch(&cur->rsp, next->rsp);
}
}
void scheduler_run(void) { void scheduler_run(void) {
if (g_task_list == NULL) { if (g_task_list == NULL) {
serial_write("SCHED: no tasks to run\n"); serial_write("SCHED: no tasks to run\n");
return; return;
} }
// Find first READY task // 查找第一个就绪任务
task_t* start = g_task_list->next; // head of circle task_t* start = g_task_list->next;
task_t* t = start; task_t* t = start;
do { do {
if (t->state == TASK_STATE_READY) { if (t->state == TASK_STATE_READY) {
@@ -153,18 +188,18 @@ void scheduler_run(void) {
g_current = t; g_current = t;
t->state = TASK_STATE_RUNNING; t->state = TASK_STATE_RUNNING;
t->time_slice = TIME_SLICE_DEFAULT;
serial_write("SCHED: starting task '"); serial_write("SCHED: starting task '");
serial_write(t->name); serial_write(t->name);
serial_write("'\n"); serial_write("'\n");
// First context switch — no old RSP to save (we're still in scheduler_run) // 首次上下文切换 — 切换到任务栈
// Just switch to the task's stack directly. // 此后不会返回(直到所有任务终止)
// We need a dummy old_rsp to satisfy the API, but we never return here.
UINT64 dummy_rsp; UINT64 dummy_rsp;
context_switch(&dummy_rsp, t->rsp); context_switch(&dummy_rsp, t->rsp);
// We only return here when ALL tasks are terminated // 只有所有任务终止后才会返回到这里
serial_write("SCHED: all tasks finished\n"); serial_write("SCHED: all tasks finished\n");
while (1) ASM ("hlt"); while (1) ASM ("hlt");
} }
@@ -178,10 +213,10 @@ void task_exit(void) {
g_current->state = TASK_STATE_TERMINATED; g_current->state = TASK_STATE_TERMINATED;
// Yield to next task — we won't come back // 让出 CPU 给下一个任务 — 不会回来
yield(); yield();
// Should never reach here // 不应到达此处
while (1) ASM ("hlt"); while (1) ASM ("hlt");
} }
+19 -8
View File
@@ -1,4 +1,5 @@
#include <serial.h> #include <serial.h>
#include <string_utils.h>
extern EFI_SYSTEM_TABLE *ST; extern EFI_SYSTEM_TABLE *ST;
@@ -21,7 +22,7 @@ void serial_write_char(char c) {
} }
} }
void serial_write(const char *str) { void serial_write(String str) {
if (!g_serial.SerialIo) { if (!g_serial.SerialIo) {
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, (CHAR16*)L"serial: null io\n"); uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, (CHAR16*)L"serial: null io\n");
return; return;
@@ -33,18 +34,28 @@ void serial_write(const char *str) {
void serial_write_hex(UINTN val) { void serial_write_hex(UINTN val) {
char buf[19]; char buf[19];
buf[0] = '0'; buf[1] = 'x'; buf[0] = '0';
for (int i = 17; i >= 2; i--) { buf[1] = 'x';
UINTN digit = val & 0xF; SSINT32 pos = 2;
buf[i] = digit < 10 ? '0' + digit : 'A' + digit - 10; if (val == 0) {
val >>= 4; buf[pos++] = '0';
} else {
char tmp[17];
SSINT32 len = 0;
while (val) {
UINTN digit = val & 0xF;
tmp[len++] = digit < 10 ? '0' + digit : 'A' + digit - 10;
val >>= 4;
}
for (SSINT32 i = len - 1; i >= 0; i--) {
buf[pos++] = tmp[i];
}
} }
buf[18] = '\0'; buf[pos] = '\0';
serial_write(buf); serial_write(buf);
} }
char serial_read_char() { char serial_read_char() {
// 后面可能用的上,比如远程调试?
if (!g_serial.SerialIo) return 0; if (!g_serial.SerialIo) return 0;
char c = 0; char c = 0;
UINTN size = 1; UINTN size = 1;
Binary file not shown.