This commit is contained in:
xyou
2026-07-31 13:53:49 +08:00
parent 5ea84fac97
commit f52157b7af
241 changed files with 26843 additions and 8155 deletions
+10 -2
View File
@@ -12,20 +12,28 @@ LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -T linker.ld
C_SOURCES := $(wildcard arch/x86_64/*.c kernel/*.c runtime/*.c mm/*.c core/*.c crypto/*.c pckc/*.c utrw/*.c drr/*.c dkm/*.c test/*.c vmm/*.c pe/*.c)
S_SOURCES := $(wildcard arch/x86_64/*.S vmm/*.S)
OBJECTS := $(C_SOURCES:.c=.o) $(S_SOURCES:.S=.o)
DEPS := $(C_SOURCES:.c=.d)
.PHONY: all clean
# 显式指定默认目标:防止 -include 的 .d 文件(halt.d 等)抢占默认目标
.DEFAULT_GOAL := all
all: $(OUT)
# 头文件依赖追踪:clang -MMD 生成 .d,避免 config.h 等头修改后对象文件不重建
# 注意:-include 必须放在 all: 之后,否则第一个 .d 中的目标会成为 make 默认目标
-include $(DEPS)
$(OUT): $(OBJECTS) linker.ld
@if not exist "$(ROOT)\SYSTEM\boot" mkdir "$(ROOT)\SYSTEM\boot"
$(LD) $(LDFLAGS) -o $@ $(OBJECTS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
$(CC) $(CFLAGS) -MMD -MP -c $< -o $@
%.o: %.S
$(CC) $(ASFLAGS) -c $< -o $@
clean:
powershell -NoProfile -Command "Get-ChildItem -Path . -Recurse -Filter *.o | Remove-Item -Force; if (Test-Path '$(OUT)') { Remove-Item '$(OUT)' -Force }"
powershell -NoProfile -Command "Get-ChildItem -Path . -Recurse -Include *.o,*.d | Remove-Item -Force; if (Test-Path '$(OUT)') { Remove-Item '$(OUT)' -Force }"
+1
View File
@@ -0,0 +1 @@
arch/x86_64/halt.o: arch\x86_64\halt.c
+335 -28
View File
@@ -1,6 +1,7 @@
#include <utsm/idt.h>
#include <utsm/log.h>
#include <utsm/types.h>
#include <utsm/instr.h>
/* IDT gate descriptor (64-bit) */
typedef struct __attribute__((packed)) {
@@ -29,7 +30,7 @@ static idt_entry g_idt[IDT_ENTRIES] __attribute__((aligned(16)));
#define ICW1_ICW4 0x01
#define ICW1_INIT 0x10
/* assembly stub declarations */
/* assembly stub declarations — vectors 0-255 全覆盖 */
extern void isr_stub_0(void);
extern void isr_stub_1(void);
extern void isr_stub_2(void);
@@ -78,20 +79,280 @@ extern void isr_stub_44(void);
extern void isr_stub_45(void);
extern void isr_stub_46(void);
extern void isr_stub_47(void);
extern void isr_stub_48(void);
extern void isr_stub_49(void);
extern void isr_stub_50(void);
extern void isr_stub_51(void);
extern void isr_stub_52(void);
extern void isr_stub_53(void);
extern void isr_stub_54(void);
extern void isr_stub_55(void);
extern void isr_stub_56(void);
extern void isr_stub_57(void);
extern void isr_stub_58(void);
extern void isr_stub_59(void);
extern void isr_stub_60(void);
extern void isr_stub_61(void);
extern void isr_stub_62(void);
extern void isr_stub_63(void);
extern void isr_stub_64(void);
extern void isr_stub_65(void);
extern void isr_stub_66(void);
extern void isr_stub_67(void);
extern void isr_stub_68(void);
extern void isr_stub_69(void);
extern void isr_stub_70(void);
extern void isr_stub_71(void);
extern void isr_stub_72(void);
extern void isr_stub_73(void);
extern void isr_stub_74(void);
extern void isr_stub_75(void);
extern void isr_stub_76(void);
extern void isr_stub_77(void);
extern void isr_stub_78(void);
extern void isr_stub_79(void);
extern void isr_stub_80(void);
extern void isr_stub_81(void);
extern void isr_stub_82(void);
extern void isr_stub_83(void);
extern void isr_stub_84(void);
extern void isr_stub_85(void);
extern void isr_stub_86(void);
extern void isr_stub_87(void);
extern void isr_stub_88(void);
extern void isr_stub_89(void);
extern void isr_stub_90(void);
extern void isr_stub_91(void);
extern void isr_stub_92(void);
extern void isr_stub_93(void);
extern void isr_stub_94(void);
extern void isr_stub_95(void);
extern void isr_stub_96(void);
extern void isr_stub_97(void);
extern void isr_stub_98(void);
extern void isr_stub_99(void);
extern void isr_stub_100(void);
extern void isr_stub_101(void);
extern void isr_stub_102(void);
extern void isr_stub_103(void);
extern void isr_stub_104(void);
extern void isr_stub_105(void);
extern void isr_stub_106(void);
extern void isr_stub_107(void);
extern void isr_stub_108(void);
extern void isr_stub_109(void);
extern void isr_stub_110(void);
extern void isr_stub_111(void);
extern void isr_stub_112(void);
extern void isr_stub_113(void);
extern void isr_stub_114(void);
extern void isr_stub_115(void);
extern void isr_stub_116(void);
extern void isr_stub_117(void);
extern void isr_stub_118(void);
extern void isr_stub_119(void);
extern void isr_stub_120(void);
extern void isr_stub_121(void);
extern void isr_stub_122(void);
extern void isr_stub_123(void);
extern void isr_stub_124(void);
extern void isr_stub_125(void);
extern void isr_stub_126(void);
extern void isr_stub_127(void);
extern void isr_stub_128(void);
extern void isr_stub_129(void);
extern void isr_stub_130(void);
extern void isr_stub_131(void);
extern void isr_stub_132(void);
extern void isr_stub_133(void);
extern void isr_stub_134(void);
extern void isr_stub_135(void);
extern void isr_stub_136(void);
extern void isr_stub_137(void);
extern void isr_stub_138(void);
extern void isr_stub_139(void);
extern void isr_stub_140(void);
extern void isr_stub_141(void);
extern void isr_stub_142(void);
extern void isr_stub_143(void);
extern void isr_stub_144(void);
extern void isr_stub_145(void);
extern void isr_stub_146(void);
extern void isr_stub_147(void);
extern void isr_stub_148(void);
extern void isr_stub_149(void);
extern void isr_stub_150(void);
extern void isr_stub_151(void);
extern void isr_stub_152(void);
extern void isr_stub_153(void);
extern void isr_stub_154(void);
extern void isr_stub_155(void);
extern void isr_stub_156(void);
extern void isr_stub_157(void);
extern void isr_stub_158(void);
extern void isr_stub_159(void);
extern void isr_stub_160(void);
extern void isr_stub_161(void);
extern void isr_stub_162(void);
extern void isr_stub_163(void);
extern void isr_stub_164(void);
extern void isr_stub_165(void);
extern void isr_stub_166(void);
extern void isr_stub_167(void);
extern void isr_stub_168(void);
extern void isr_stub_169(void);
extern void isr_stub_170(void);
extern void isr_stub_171(void);
extern void isr_stub_172(void);
extern void isr_stub_173(void);
extern void isr_stub_174(void);
extern void isr_stub_175(void);
extern void isr_stub_176(void);
extern void isr_stub_177(void);
extern void isr_stub_178(void);
extern void isr_stub_179(void);
extern void isr_stub_180(void);
extern void isr_stub_181(void);
extern void isr_stub_182(void);
extern void isr_stub_183(void);
extern void isr_stub_184(void);
extern void isr_stub_185(void);
extern void isr_stub_186(void);
extern void isr_stub_187(void);
extern void isr_stub_188(void);
extern void isr_stub_189(void);
extern void isr_stub_190(void);
extern void isr_stub_191(void);
extern void isr_stub_192(void);
extern void isr_stub_193(void);
extern void isr_stub_194(void);
extern void isr_stub_195(void);
extern void isr_stub_196(void);
extern void isr_stub_197(void);
extern void isr_stub_198(void);
extern void isr_stub_199(void);
extern void isr_stub_200(void);
extern void isr_stub_201(void);
extern void isr_stub_202(void);
extern void isr_stub_203(void);
extern void isr_stub_204(void);
extern void isr_stub_205(void);
extern void isr_stub_206(void);
extern void isr_stub_207(void);
extern void isr_stub_208(void);
extern void isr_stub_209(void);
extern void isr_stub_210(void);
extern void isr_stub_211(void);
extern void isr_stub_212(void);
extern void isr_stub_213(void);
extern void isr_stub_214(void);
extern void isr_stub_215(void);
extern void isr_stub_216(void);
extern void isr_stub_217(void);
extern void isr_stub_218(void);
extern void isr_stub_219(void);
extern void isr_stub_220(void);
extern void isr_stub_221(void);
extern void isr_stub_222(void);
extern void isr_stub_223(void);
extern void isr_stub_224(void);
extern void isr_stub_225(void);
extern void isr_stub_226(void);
extern void isr_stub_227(void);
extern void isr_stub_228(void);
extern void isr_stub_229(void);
extern void isr_stub_230(void);
extern void isr_stub_231(void);
extern void isr_stub_232(void);
extern void isr_stub_233(void);
extern void isr_stub_234(void);
extern void isr_stub_235(void);
extern void isr_stub_236(void);
extern void isr_stub_237(void);
extern void isr_stub_238(void);
extern void isr_stub_239(void);
extern void isr_stub_240(void);
extern void isr_stub_241(void);
extern void isr_stub_242(void);
extern void isr_stub_243(void);
extern void isr_stub_244(void);
extern void isr_stub_245(void);
extern void isr_stub_246(void);
extern void isr_stub_247(void);
extern void isr_stub_248(void);
extern void isr_stub_249(void);
extern void isr_stub_250(void);
extern void isr_stub_251(void);
extern void isr_stub_252(void);
extern void isr_stub_253(void);
extern void isr_stub_254(void);
extern void isr_stub_255(void);
static void *g_isr_table[] = {
isr_stub_0, isr_stub_1, isr_stub_2, isr_stub_3,
isr_stub_4, isr_stub_5, isr_stub_6, isr_stub_7,
isr_stub_8, isr_stub_9, isr_stub_10, isr_stub_11,
isr_stub_12, isr_stub_13, isr_stub_14, isr_stub_15,
isr_stub_16, isr_stub_17, isr_stub_18, isr_stub_19,
isr_stub_20, isr_stub_21, isr_stub_22, isr_stub_23,
isr_stub_24, isr_stub_25, isr_stub_26, isr_stub_27,
isr_stub_28, isr_stub_29, isr_stub_30, isr_stub_31,
isr_stub_32, isr_stub_33, isr_stub_34, isr_stub_35,
isr_stub_36, isr_stub_37, isr_stub_38, isr_stub_39,
isr_stub_40, isr_stub_41, isr_stub_42, isr_stub_43,
isr_stub_44, isr_stub_45, isr_stub_46, isr_stub_47,
static void *g_isr_table[256] = {
isr_stub_0, isr_stub_1, isr_stub_2, isr_stub_3,
isr_stub_4, isr_stub_5, isr_stub_6, isr_stub_7,
isr_stub_8, isr_stub_9, isr_stub_10, isr_stub_11,
isr_stub_12, isr_stub_13, isr_stub_14, isr_stub_15,
isr_stub_16, isr_stub_17, isr_stub_18, isr_stub_19,
isr_stub_20, isr_stub_21, isr_stub_22, isr_stub_23,
isr_stub_24, isr_stub_25, isr_stub_26, isr_stub_27,
isr_stub_28, isr_stub_29, isr_stub_30, isr_stub_31,
isr_stub_32, isr_stub_33, isr_stub_34, isr_stub_35,
isr_stub_36, isr_stub_37, isr_stub_38, isr_stub_39,
isr_stub_40, isr_stub_41, isr_stub_42, isr_stub_43,
isr_stub_44, isr_stub_45, isr_stub_46, isr_stub_47,
isr_stub_48, isr_stub_49, isr_stub_50, isr_stub_51,
isr_stub_52, isr_stub_53, isr_stub_54, isr_stub_55,
isr_stub_56, isr_stub_57, isr_stub_58, isr_stub_59,
isr_stub_60, isr_stub_61, isr_stub_62, isr_stub_63,
isr_stub_64, isr_stub_65, isr_stub_66, isr_stub_67,
isr_stub_68, isr_stub_69, isr_stub_70, isr_stub_71,
isr_stub_72, isr_stub_73, isr_stub_74, isr_stub_75,
isr_stub_76, isr_stub_77, isr_stub_78, isr_stub_79,
isr_stub_80, isr_stub_81, isr_stub_82, isr_stub_83,
isr_stub_84, isr_stub_85, isr_stub_86, isr_stub_87,
isr_stub_88, isr_stub_89, isr_stub_90, isr_stub_91,
isr_stub_92, isr_stub_93, isr_stub_94, isr_stub_95,
isr_stub_96, isr_stub_97, isr_stub_98, isr_stub_99,
isr_stub_100, isr_stub_101, isr_stub_102, isr_stub_103,
isr_stub_104, isr_stub_105, isr_stub_106, isr_stub_107,
isr_stub_108, isr_stub_109, isr_stub_110, isr_stub_111,
isr_stub_112, isr_stub_113, isr_stub_114, isr_stub_115,
isr_stub_116, isr_stub_117, isr_stub_118, isr_stub_119,
isr_stub_120, isr_stub_121, isr_stub_122, isr_stub_123,
isr_stub_124, isr_stub_125, isr_stub_126, isr_stub_127,
isr_stub_128, isr_stub_129, isr_stub_130, isr_stub_131,
isr_stub_132, isr_stub_133, isr_stub_134, isr_stub_135,
isr_stub_136, isr_stub_137, isr_stub_138, isr_stub_139,
isr_stub_140, isr_stub_141, isr_stub_142, isr_stub_143,
isr_stub_144, isr_stub_145, isr_stub_146, isr_stub_147,
isr_stub_148, isr_stub_149, isr_stub_150, isr_stub_151,
isr_stub_152, isr_stub_153, isr_stub_154, isr_stub_155,
isr_stub_156, isr_stub_157, isr_stub_158, isr_stub_159,
isr_stub_160, isr_stub_161, isr_stub_162, isr_stub_163,
isr_stub_164, isr_stub_165, isr_stub_166, isr_stub_167,
isr_stub_168, isr_stub_169, isr_stub_170, isr_stub_171,
isr_stub_172, isr_stub_173, isr_stub_174, isr_stub_175,
isr_stub_176, isr_stub_177, isr_stub_178, isr_stub_179,
isr_stub_180, isr_stub_181, isr_stub_182, isr_stub_183,
isr_stub_184, isr_stub_185, isr_stub_186, isr_stub_187,
isr_stub_188, isr_stub_189, isr_stub_190, isr_stub_191,
isr_stub_192, isr_stub_193, isr_stub_194, isr_stub_195,
isr_stub_196, isr_stub_197, isr_stub_198, isr_stub_199,
isr_stub_200, isr_stub_201, isr_stub_202, isr_stub_203,
isr_stub_204, isr_stub_205, isr_stub_206, isr_stub_207,
isr_stub_208, isr_stub_209, isr_stub_210, isr_stub_211,
isr_stub_212, isr_stub_213, isr_stub_214, isr_stub_215,
isr_stub_216, isr_stub_217, isr_stub_218, isr_stub_219,
isr_stub_220, isr_stub_221, isr_stub_222, isr_stub_223,
isr_stub_224, isr_stub_225, isr_stub_226, isr_stub_227,
isr_stub_228, isr_stub_229, isr_stub_230, isr_stub_231,
isr_stub_232, isr_stub_233, isr_stub_234, isr_stub_235,
isr_stub_236, isr_stub_237, isr_stub_238, isr_stub_239,
isr_stub_240, isr_stub_241, isr_stub_242, isr_stub_243,
isr_stub_244, isr_stub_245, isr_stub_246, isr_stub_247,
isr_stub_248, isr_stub_249, isr_stub_250, isr_stub_251,
isr_stub_252, isr_stub_253, isr_stub_254, isr_stub_255,
};
static void outb(u16 port, u8 value) {
@@ -109,9 +370,11 @@ static void io_wait(void) {
}
static void pic_remap(void) {
/* save masks */
/* save masks (kept for reference; fixed masks are applied below) */
u8 m1 = inb(PIC1_DATA);
u8 m2 = inb(PIC2_DATA);
(void)m1;
(void)m2;
/* ICW1: start init + ICW4 */
outb(PIC1_CMD, ICW1_INIT | ICW1_ICW4);
@@ -156,13 +419,9 @@ static void idt_set_entry(u8 vector, void *handler, u8 ist, u8 type) {
void idt_init(void) {
log_info("[IDT] init begin");
for (u16 i = 0; i < 48; i++) {
for (u16 i = 0; i < IDT_ENTRIES; i++) {
idt_set_entry((u8)i, g_isr_table[i], 0, 0x8E); /* present, ring0, 64-bit interrupt gate */
}
/* fill unused entries with null */
for (u16 i = 48; i < IDT_ENTRIES; i++) {
idt_set_entry((u8)i, 0, 0, 0);
}
idt_ptr idtr;
idtr.limit = (u16)(sizeof(g_idt) - 1);
@@ -178,12 +437,39 @@ void idt_init(void) {
log_info("[IDT] init ok");
}
/* IRQ handler table */
static irq_handler_t g_irq_handlers[16];
/* 安全 halt stub: cli; hlt 循环。用于 idt_halt_all()。
* 任何异常/IRQ 触发此 stub 将安全停机,不会三重故障。 */
static void isr_halt_stub(void) {
for (;;) { __asm__ volatile("cli; hlt"); }
}
int irq_register(u8 irq, irq_handler_t handler) {
if (irq >= 16) return -1;
g_irq_handlers[irq] = handler;
void idt_halt_all(void) {
/* 将 IDT 所有 256 个条目替换为安全 halt stub。
* 调用前应已 cli + mask PIC,此函数是额外防御层:
* - 实机 spurious IRQ7/15 即使 PIC 已 mask 也可能触发
* - NMI / SMI 可能导致异常
* - DSK 运行期间 CPU 异常 (PF/GP) 应安全停机而非执行过期 handler */
for (u16 i = 0; i < IDT_ENTRIES; i++) {
idt_set_entry((u8)i, (void *)isr_halt_stub, 0, 0x8E);
}
/* 重新加载 IDTR 以确保更改生效 */
idt_ptr idtr;
idtr.limit = (u16)(sizeof(g_idt) - 1);
idtr.base = (u64)&g_idt;
__asm__ volatile("lidt %0" :: "m"(idtr));
}
/* IRQ handler table — 扩展到 256 个 vector (真机 APIC/IOAPIC/MSI 需要) */
static irq_handler_t g_irq_handlers[256];
/* ---- 插桩: IRQ 统计计数器 ---- */
INSTR_STAT_DECL(pic_irq_total);
INSTR_STAT_DECL(apic_irq_total);
int irq_register(u8 vector, irq_handler_t handler) {
if ((unsigned)vector >= 256) return -1;
g_irq_handlers[vector] = handler;
INSTR_LOG(INSTR_LOG_DEBUG, INSTR_F_UTSM_TRACE, "[IDT] IRQ handler registered");
return 0;
}
@@ -197,6 +483,7 @@ typedef struct {
void idt_handler(isr_frame *frame) {
if (frame->vector < 32) {
INSTR_PROBE(EXCP, frame->vector, frame->error_code, frame->rip, 0);
log_error("[IDT] exception");
log_hex64("[IDT] vector=", frame->vector);
log_hex64("[IDT] err=", frame->error_code);
@@ -204,19 +491,39 @@ void idt_handler(isr_frame *frame) {
for (;;) { __asm__ volatile ("cli; hlt"); }
}
/* PIC IRQ: vectors 0x20-0x2F (32-47) */
if (frame->vector >= 32 && frame->vector <= 47) {
INSTR_STAT_INC(pic_irq_total);
u8 irq = (u8)(frame->vector - 0x20);
/* call registered handler */
if (irq < 16 && g_irq_handlers[irq]) {
int suppress_eoi = g_irq_handlers[irq](irq);
if (g_irq_handlers[frame->vector]) {
int suppress_eoi = g_irq_handlers[frame->vector](irq);
if (suppress_eoi) return;
}
/* send EOI */
/* send PIC EOI */
if (frame->vector >= 0x28) {
outb(PIC2_CMD, 0x20);
}
outb(PIC1_CMD, 0x20);
return;
}
/* APIC/IOAPIC/MSI IRQ: vectors 0x30-0xFF (48-255)
* **QEMU 无法测试但真机必需的代码路径**:
* - APIC EOI 写入 LAPIC EOI 寄存器 (0xFEE000B0)
* - 当前 PIC 仍激活, 不需要 APIC EOI
* - 迁移到 IOAPIC 后需要此处补 APIC EOI */
if (frame->vector >= 48 && frame->vector <= 255) {
INSTR_STAT_INC(apic_irq_total);
if (g_irq_handlers[frame->vector]) {
g_irq_handlers[frame->vector]((u8)frame->vector);
}
/* TODO: LAPIC EOI — 写 0 到 LAPIC EOI 寄存器 (mmio offset 0xB0)
* 当从 PIC 迁移到 APIC 中断路由时, 必须在此处添加:
* *(volatile u32 *)(hhdm_offset + lapic_phys + 0xB0) = 0;
*/
return;
}
}
+6
View File
@@ -0,0 +1,6 @@
arch/x86_64/idt.o: arch\x86_64\idt.c include\utsm\idt.h \
include\utsm\types.h include\utsm\log.h include\utsm\instr.h
include\utsm\idt.h:
include\utsm\types.h:
include\utsm\log.h:
include\utsm\instr.h:
Binary file not shown.
+61 -1
View File
@@ -1,4 +1,8 @@
/* IDT assembly stubs — SAS-R0 interrupt vectors */
/* IDT assembly stubs — SAS-R0 interrupt vectors
* Vectors 0-31: CPU exceptions (some push error code)
* Vectors 32-47: PIC IRQ remap region
* Vectors 48-255: APIC/IOAPIC/MSI dynamic vectors
*/
.section .text
.macro isr_no_err n
@@ -34,6 +38,62 @@ isr_no_err 36; isr_no_err 37; isr_no_err 38; isr_no_err 39
isr_no_err 40; isr_no_err 41; isr_no_err 42; isr_no_err 43
isr_no_err 44; isr_no_err 45; isr_no_err 46; isr_no_err 47
/* Vectors 48-255: APIC/IOAPIC/MSI 真机动态向量
* 真机需要更多 vector: APIC timer (0x30+), IOAPIC GSI, MSI/MSI-X 等。
* 全部生成 stub 确保任何 vector 命中都有 handler, 不会 triple fault。 */
isr_no_err 48; isr_no_err 49; isr_no_err 50; isr_no_err 51
isr_no_err 52; isr_no_err 53; isr_no_err 54; isr_no_err 55
isr_no_err 56; isr_no_err 57; isr_no_err 58; isr_no_err 59
isr_no_err 60; isr_no_err 61; isr_no_err 62; isr_no_err 63
isr_no_err 64; isr_no_err 65; isr_no_err 66; isr_no_err 67
isr_no_err 68; isr_no_err 69; isr_no_err 70; isr_no_err 71
isr_no_err 72; isr_no_err 73; isr_no_err 74; isr_no_err 75
isr_no_err 76; isr_no_err 77; isr_no_err 78; isr_no_err 79
isr_no_err 80; isr_no_err 81; isr_no_err 82; isr_no_err 83
isr_no_err 84; isr_no_err 85; isr_no_err 86; isr_no_err 87
isr_no_err 88; isr_no_err 89; isr_no_err 90; isr_no_err 91
isr_no_err 92; isr_no_err 93; isr_no_err 94; isr_no_err 95
isr_no_err 96; isr_no_err 97; isr_no_err 98; isr_no_err 99
isr_no_err 100; isr_no_err 101; isr_no_err 102; isr_no_err 103
isr_no_err 104; isr_no_err 105; isr_no_err 106; isr_no_err 107
isr_no_err 108; isr_no_err 109; isr_no_err 110; isr_no_err 111
isr_no_err 112; isr_no_err 113; isr_no_err 114; isr_no_err 115
isr_no_err 116; isr_no_err 117; isr_no_err 118; isr_no_err 119
isr_no_err 120; isr_no_err 121; isr_no_err 122; isr_no_err 123
isr_no_err 124; isr_no_err 125; isr_no_err 126; isr_no_err 127
isr_no_err 128; isr_no_err 129; isr_no_err 130; isr_no_err 131
isr_no_err 132; isr_no_err 133; isr_no_err 134; isr_no_err 135
isr_no_err 136; isr_no_err 137; isr_no_err 138; isr_no_err 139
isr_no_err 140; isr_no_err 141; isr_no_err 142; isr_no_err 143
isr_no_err 144; isr_no_err 145; isr_no_err 146; isr_no_err 147
isr_no_err 148; isr_no_err 149; isr_no_err 150; isr_no_err 151
isr_no_err 152; isr_no_err 153; isr_no_err 154; isr_no_err 155
isr_no_err 156; isr_no_err 157; isr_no_err 158; isr_no_err 159
isr_no_err 160; isr_no_err 161; isr_no_err 162; isr_no_err 163
isr_no_err 164; isr_no_err 165; isr_no_err 166; isr_no_err 167
isr_no_err 168; isr_no_err 169; isr_no_err 170; isr_no_err 171
isr_no_err 172; isr_no_err 173; isr_no_err 174; isr_no_err 175
isr_no_err 176; isr_no_err 177; isr_no_err 178; isr_no_err 179
isr_no_err 180; isr_no_err 181; isr_no_err 182; isr_no_err 183
isr_no_err 184; isr_no_err 185; isr_no_err 186; isr_no_err 187
isr_no_err 188; isr_no_err 189; isr_no_err 190; isr_no_err 191
isr_no_err 192; isr_no_err 193; isr_no_err 194; isr_no_err 195
isr_no_err 196; isr_no_err 197; isr_no_err 198; isr_no_err 199
isr_no_err 200; isr_no_err 201; isr_no_err 202; isr_no_err 203
isr_no_err 204; isr_no_err 205; isr_no_err 206; isr_no_err 207
isr_no_err 208; isr_no_err 209; isr_no_err 210; isr_no_err 211
isr_no_err 212; isr_no_err 213; isr_no_err 214; isr_no_err 215
isr_no_err 216; isr_no_err 217; isr_no_err 218; isr_no_err 219
isr_no_err 220; isr_no_err 221; isr_no_err 222; isr_no_err 223
isr_no_err 224; isr_no_err 225; isr_no_err 226; isr_no_err 227
isr_no_err 228; isr_no_err 229; isr_no_err 230; isr_no_err 231
isr_no_err 232; isr_no_err 233; isr_no_err 234; isr_no_err 235
isr_no_err 236; isr_no_err 237; isr_no_err 238; isr_no_err 239
isr_no_err 240; isr_no_err 241; isr_no_err 242; isr_no_err 243
isr_no_err 244; isr_no_err 245; isr_no_err 246; isr_no_err 247
isr_no_err 248; isr_no_err 249; isr_no_err 250; isr_no_err 251
isr_no_err 252; isr_no_err 253; isr_no_err 254; isr_no_err 255
/* Common ISR */
isr_common:
pushq %rdi
Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
arch/x86_64/io.o: arch\x86_64\io.c include\utsm\types.h
include\utsm\types.h:
+2
View File
@@ -0,0 +1,2 @@
arch/x86_64/serial.o: arch\x86_64\serial.c include\utsm\types.h
include\utsm\types.h:
+9
View File
@@ -0,0 +1,9 @@
core/capability.o: core\capability.c include\utsm\capability.h \
include\utsm\types.h include\utsm\status.h include\utsm\segment.h \
include\utsm\uuid.h include\utsm\dirty.h
include\utsm\capability.h:
include\utsm\types.h:
include\utsm\status.h:
include\utsm\segment.h:
include\utsm\uuid.h:
include\utsm\dirty.h:
+11
View File
@@ -0,0 +1,11 @@
core/dirty.o: core\dirty.c include\utsm\dirty.h include\utsm\types.h \
include\utsm\segment.h include\utsm\uuid.h include\utsm\status.h \
include\utsm\capability.h include\utsm\arena.h include\utsm\config.h
include\utsm\dirty.h:
include\utsm\types.h:
include\utsm\segment.h:
include\utsm\uuid.h:
include\utsm\status.h:
include\utsm\capability.h:
include\utsm\arena.h:
include\utsm\config.h:
+10
View File
@@ -0,0 +1,10 @@
core/dmp.o: core\dmp.c include\utsm\dmp.h include\utsm\types.h \
include\utsm\segment.h include\utsm\uuid.h include\utsm\status.h \
include\utsm\capability.h include\utsm\dirty.h
include\utsm\dmp.h:
include\utsm\types.h:
include\utsm\segment.h:
include\utsm\uuid.h:
include\utsm\status.h:
include\utsm\capability.h:
include\utsm\dirty.h:
+13
View File
@@ -0,0 +1,13 @@
core/process.o: core\process.c include\utsm\process.h \
include\utsm\types.h include\utsm\uuid.h include\utsm\capability.h \
include\utsm\status.h include\utsm\config.h include\utsm\drr.h \
include\utsm\arena.h include\utsm\log.h
include\utsm\process.h:
include\utsm\types.h:
include\utsm\uuid.h:
include\utsm\capability.h:
include\utsm\status.h:
include\utsm\config.h:
include\utsm\drr.h:
include\utsm\arena.h:
include\utsm\log.h:
+14
View File
@@ -0,0 +1,14 @@
core/segment.o: core\segment.c include\utsm\segment.h \
include\utsm\types.h include\utsm\uuid.h include\utsm\status.h \
include\utsm\capability.h include\utsm\dirty.h include\utsm\process.h \
include\utsm\config.h include\utsm\arena.h include\utsm\dmp.h
include\utsm\segment.h:
include\utsm\types.h:
include\utsm\uuid.h:
include\utsm\status.h:
include\utsm\capability.h:
include\utsm\dirty.h:
include\utsm\process.h:
include\utsm\config.h:
include\utsm\arena.h:
include\utsm\dmp.h:
+5 -2
View File
@@ -3,13 +3,16 @@
#include <utsm/pckc.h>
#include <utsm/process.h>
#include <utsm/log.h>
#include <utsm/config.h>
static utsm_segment_desc g_segments[UTSM_MAX_SEGMENTS];
static u64 g_generation = 1;
void utsm_init(void) {
log_info("[UTSM] segment table reset begin");
for (u32 i = 0; i < UTSM_MAX_SEGMENTS; i++) {
u32 max_seg = g_utsm_max_segments;
if (max_seg > UTSM_MAX_SEGMENTS) max_seg = UTSM_MAX_SEGMENTS;
for (u32 i = 0; i < max_seg; i++) {
g_segments[i].state = UTSM_SEG_FREE;
g_segments[i].generation = 1;
}
@@ -24,7 +27,7 @@ void utsm_init(void) {
}
utsm_segment_desc *utsm_get_segment(u32 slot) {
if (slot >= UTSM_MAX_SEGMENTS) {
if (slot >= g_utsm_max_segments || slot >= UTSM_MAX_SEGMENTS) {
return NULL;
}
return &g_segments[slot];
+25
View File
@@ -0,0 +1,25 @@
core/utsm_init.o: core\utsm_init.c include\utsm\utsm.h \
include\utsm\types.h include\utsm\status.h include\utsm\config.h \
include\utsm\uuid.h include\utsm\process.h include\utsm\capability.h \
include\utsm\segment.h include\utsm\dirty.h include\utsm\utrw.h \
include\utsm\vmm.h include\utsm\linux_loader.h include\utsm\ipc_shm.h \
..\utsm-ipc\ipc_proto.h include\utsm\hypercall.h include\utsm\pckc.h \
include\utsm\crypto.h include\utsm\log.h
include\utsm\utsm.h:
include\utsm\types.h:
include\utsm\status.h:
include\utsm\config.h:
include\utsm\uuid.h:
include\utsm\process.h:
include\utsm\capability.h:
include\utsm\segment.h:
include\utsm\dirty.h:
include\utsm\utrw.h:
include\utsm\vmm.h:
include\utsm\linux_loader.h:
include\utsm\ipc_shm.h:
..\utsm-ipc\ipc_proto.h:
include\utsm\hypercall.h:
include\utsm\pckc.h:
include\utsm\crypto.h:
include\utsm\log.h:
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
crypto/kdf.o: crypto\kdf.c include\utsm\crypto.h include\utsm\types.h \
include\utsm\uuid.h include\utsm\drr.h include\utsm\config.h
include\utsm\crypto.h:
include\utsm\types.h:
include\utsm\uuid.h:
include\utsm\drr.h:
include\utsm\config.h:
+6
View File
@@ -0,0 +1,6 @@
crypto/stream.o: crypto\stream.c include\utsm\crypto.h \
include\utsm\types.h include\utsm\uuid.h include\utsm\config.h
include\utsm\crypto.h:
include\utsm\types.h:
include\utsm\uuid.h:
include\utsm\config.h:
+5
View File
@@ -0,0 +1,5 @@
crypto/tweak.o: crypto\tweak.c include\utsm\crypto.h include\utsm\types.h \
include\utsm\uuid.h
include\utsm\crypto.h:
include\utsm\types.h:
include\utsm\uuid.h:
+13
View File
@@ -0,0 +1,13 @@
dkm/boot_modules.o: dkm\boot_modules.c include\utsm\dkm.h \
include\utsm\types.h include\utsm\dma.h include\utsm\block.h \
include\utsm\net.h include\utsm\paging.h include\utsm\log.h \
include\utsm\arena.h dkm\..\arch\x86_64\limine.h
include\utsm\dkm.h:
include\utsm\types.h:
include\utsm\dma.h:
include\utsm\block.h:
include\utsm\net.h:
include\utsm\paging.h:
include\utsm\log.h:
include\utsm\arena.h:
dkm\..\arch\x86_64\limine.h:
+9
View File
@@ -0,0 +1,9 @@
dkm/console_early.o: dkm\console_early.c include\utsm\dkm.h \
include\utsm\types.h include\utsm\dma.h include\utsm\block.h \
include\utsm\net.h include\utsm\paging.h
include\utsm\dkm.h:
include\utsm\types.h:
include\utsm\dma.h:
include\utsm\block.h:
include\utsm\net.h:
include\utsm\paging.h:
+10
View File
@@ -0,0 +1,10 @@
dkm/dkm_core.o: dkm\dkm_core.c include\utsm\dkm.h include\utsm\types.h \
include\utsm\dma.h include\utsm\block.h include\utsm\net.h \
include\utsm\paging.h include\utsm\log.h
include\utsm\dkm.h:
include\utsm\types.h:
include\utsm\dma.h:
include\utsm\block.h:
include\utsm\net.h:
include\utsm\paging.h:
include\utsm\log.h:
+8 -1
View File
@@ -2,6 +2,7 @@
#include <utsm/log.h>
#include <utsm/idt.h>
#include <utsm/net.h>
#include <utsm/mm.h>
static void dkm_api_info(const char *msg) {
log_info(msg);
@@ -52,7 +53,10 @@ static dkm_kernel_api g_kernel_api = {
.boot_modules_response = 0,
.irq_register = 0,
.hhdm_offset = 0,
.block = 0
.block = 0,
.mmio = 0,
.mm_map_mmio = 0,
.mm_unmap_mmio = 0
};
const dkm_kernel_api *dkm_get_kernel_api(void) {
@@ -69,6 +73,7 @@ void dkm_fill_platform_info(void) {
g_kernel_api.dma = dma_get_api();
g_kernel_api.net = net_get_api();
g_kernel_api.block = block_get_api();
g_kernel_api.mmio = paging_get_api();
if (g_rsdp_request.response && g_rsdp_request.response->address) {
g_kernel_api.rsdp_address = g_rsdp_request.response->address;
}
@@ -87,4 +92,6 @@ void dkm_fill_platform_info(void) {
if (g_hhdm_request.response) {
g_kernel_api.hhdm_offset = g_hhdm_request.response->offset;
}
g_kernel_api.mm_map_mmio = mm_map_mmio;
g_kernel_api.mm_unmap_mmio = mm_unmap_mmio;
}
+14
View File
@@ -0,0 +1,14 @@
dkm/kernel_api.o: dkm\kernel_api.c include\utsm\dkm.h \
include\utsm\types.h include\utsm\dma.h include\utsm\block.h \
include\utsm\net.h include\utsm\paging.h include\utsm\log.h \
include\utsm\idt.h include\utsm\mm.h dkm\..\arch\x86_64\limine.h
include\utsm\dkm.h:
include\utsm\types.h:
include\utsm\dma.h:
include\utsm\block.h:
include\utsm\net.h:
include\utsm\paging.h:
include\utsm\log.h:
include\utsm\idt.h:
include\utsm\mm.h:
dkm\..\arch\x86_64\limine.h:
Binary file not shown.
+18
View File
@@ -2,6 +2,10 @@
#include <utsm/log.h>
#include <utsm/types.h>
#include "../arch/x86_64/limine.h"
#include "../kernel/ini_parser.h"
/* 前向声明:带 FUCK [drivers] 过滤的加载入口(定义见下文) */
void dsm_load_by_manifest_ex(const ini_config *cfg);
#define DSM_MAX_DRIVERS_PER_STAGE 8
#define DSM_MAX_STAGES 4
@@ -283,6 +287,10 @@ static int dsm_parse_manifest(const char *text, u64 size) {
}
void dsm_load_by_manifest(void) {
dsm_load_by_manifest_ex(NULL);
}
void dsm_load_by_manifest_ex(const ini_config *cfg) {
struct limine_module_response *rsp = g_module_request.response;
if (!rsp) {
log_warn("[DSM] no Limine module response");
@@ -317,6 +325,16 @@ void dsm_load_by_manifest(void) {
for (u32 di = 0; di < stage->driver_count; di++) {
dsm_driver_entry *drv = &stage->drivers[di];
/* === FUCK [drivers] 驱动开关检查 === */
if (cfg) {
int enabled = ini_get_bool(cfg, "drivers", drv->name, 1);
if (!enabled) {
log_info("[DSM] driver disabled by FUCK: ");
log_info(drv->name);
continue; /* 跳过此驱动 */
}
}
drv->boot_module = dsm_find_boot_module(drv->path);
if (!drv->boot_module) {
log_info("[DSM] module not found");
+13
View File
@@ -0,0 +1,13 @@
dkm/manifest.o: dkm\manifest.c include\utsm\dkm.h include\utsm\types.h \
include\utsm\dma.h include\utsm\block.h include\utsm\net.h \
include\utsm\paging.h include\utsm\log.h dkm\..\arch\x86_64\limine.h \
dkm\..\kernel\ini_parser.h
include\utsm\dkm.h:
include\utsm\types.h:
include\utsm\dma.h:
include\utsm\block.h:
include\utsm\net.h:
include\utsm\paging.h:
include\utsm\log.h:
dkm\..\arch\x86_64\limine.h:
dkm\..\kernel\ini_parser.h:
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
drr/drr_stub.o: drr\drr_stub.c include\utsm\drr.h include\utsm\types.h \
include\utsm\config.h include\utsm\log.h
include\utsm\drr.h:
include\utsm\types.h:
include\utsm\config.h:
include\utsm\log.h:
+24 -5
View File
@@ -1,13 +1,32 @@
#ifndef UTSM_CONFIG_H
#define UTSM_CONFIG_H
#include <utsm/types.h>
/* ---- 编译期固定常量(不暴露给 FUCK 配置) ---- */
#define UTSM_CACHE_LINE_SIZE 64ULL
#define UTSM_PAGE_SIZE 4096ULL
#define UTSM_MAX_SEGMENTS 1024U
#define UTSM_MAX_CAPABILITIES 256U
#define UTSM_MAX_PCKC_KEYS 8U
#define UTSM_ARENA_SIZE (16ULL * 1024ULL * 1024ULL)
#define UTSM_DIRTY_SHARD_PAGES 1024ULL
#define UTSM_KERNEL_STACK_SIZE 16384ULL
/* ---- 编译期默认值宏(用于静态数组大小上限) ---- */
#define UTSM_MAX_SEGMENTS_DEFAULT 1024U
#define UTSM_MAX_CAPABILITIES_DEFAULT 256U
#define UTSM_MAX_PCKC_KEYS_DEFAULT 8U
#define UTSM_ARENA_SIZE_DEFAULT (64ULL * 1024ULL * 1024ULL)
#define UTSM_DIRTY_SHARD_PAGES_DEFAULT 1024ULL
/* ---- 运行期配置变量(由 kernel_main 从 FUCK 文件初始化) ---- */
extern u32 g_utsm_max_segments;
extern u32 g_utsm_max_capabilities;
extern u32 g_utsm_max_pckc_keys;
extern u64 g_utsm_arena_size;
extern u64 g_utsm_dirty_shard_pages;
/* ---- 保留旧宏名(兼容性),映射到默认值 ---- */
#define UTSM_MAX_SEGMENTS UTSM_MAX_SEGMENTS_DEFAULT
#define UTSM_MAX_CAPABILITIES UTSM_MAX_CAPABILITIES_DEFAULT
#define UTSM_MAX_PCKC_KEYS UTSM_MAX_PCKC_KEYS_DEFAULT
#define UTSM_ARENA_SIZE UTSM_ARENA_SIZE_DEFAULT
#define UTSM_DIRTY_SHARD_PAGES UTSM_DIRTY_SHARD_PAGES_DEFAULT
#endif
+5
View File
@@ -5,6 +5,7 @@
#include <utsm/dma.h>
#include <utsm/block.h>
#include <utsm/net.h>
#include <utsm/paging.h>
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
@@ -95,6 +96,10 @@ typedef struct dkm_kernel_api {
int (*irq_register)(u8 irq, void *handler); /* kernel irq_register */
u64 hhdm_offset; /* physical → virtual */
const dkm_block_api *block; /* block provider registry */
const dkm_mmio_api *mmio; /* 页表/高位 MMIO 映射服务(尾部追加,ABI 兼容) */
/* —— 新增字段只允许追加在末尾(DSK 以 api+0xA8 硬偏移读取 block) —— */
void *(*mm_map_mmio)(u64 phys, u64 size); /* MMIO 独立窗口映射(PCD|PWT),返回虚拟地址,失败返回 0 */
void (*mm_unmap_mmio)(void *virt, u64 size); /* 解除 MMIO 独立窗口映射 */
} dkm_kernel_api;
typedef enum dkm_driver_state {
+17
View File
@@ -9,6 +9,23 @@
#define DSK_BOOT_FLAG_FROM_UTSM (1ULL << 0)
#define DSK_BOOT_FLAG_DKM_READY (1ULL << 1)
#define DSK_BOOT_FLAG_FAT32_PATH (1ULL << 2)
#define DSK_BOOT_FLAG_PROBE_INFO (1ULL << 3)
/* ---- Probe 信息结构(通过 reserved[6] 传递给 shell/desktop) ---- */
#define PROBE_INFO_MAGIC 0x50524F42u /* "PRFB" — Probe inFo Buffer */
typedef struct probe_info {
u32 magic; /* PROBE_INFO_MAGIC */
u32 version; /* ABI 版本,当前 1 */
u64 probe_buf_addr; /* probe_entry 缓冲基地址(物理/HHDM 地址) */
u32 probe_cap; /* 缓冲容量(条目数) */
u32 probe_head; /* 当前写入位置(递增取模) */
u32 probe_count; /* 已写入总条目数 */
u32 probe_dropped; /* 因缓冲满而覆盖的条目数 */
u32 instr_enabled; /* g_instr_enabled 当前值 */
u32 instr_probe_enable; /* g_instr_probe_enable 当前值 */
u64 reserved[4];
} probe_info;
typedef struct dsk_boot_context {
u64 magic;
+15
View File
@@ -30,4 +30,19 @@ int ept_identity_map(u64 gpa, u64 size, u64 flags);
* Handles 4KB pages and 2MB large pages. */
u64 ept_gpa_to_hpa(u64 gpa);
/* Map a 2MB large page in EPT (PD-level direct mapping).
* GPA and HPA must be 2MB-aligned. memtype = EPT_MEMORY_TYPE_*.
* Required for real hardware MTRR compliance. */
int ept_map_2m_page(u64 gpa, u64 hpa, u64 flags, u64 memtype);
/* Check INVVPID/INVEPT support from IA32_VMX_EPT_VPID_CAP MSR.
* Call once after VMX init. */
void ept_check_vpid_support(void);
/* Flush EPT TLB entries (INVEPT). Required after EPT mapping changes on real hardware. */
void ept_flush_ept(void);
/* Flush VPID TLB entries (INVVPID). Required after VPID changes on real hardware. */
void ept_flush_vpid(u16 vpid);
#endif
+11 -3
View File
@@ -5,8 +5,16 @@
void idt_init(void);
/* IRQ handler: return 1 to suppress default ACK, 0 for normal EOI */
typedef int (*irq_handler_t)(u8 irq);
int irq_register(u8 irq, irq_handler_t handler);
/* 将 IDT 所有 256 个条目替换为安全 halt stub (cli; hlt)。
* 用于 UTSM→DSK 跳转前,防止 DSK 运行期间过期 UTSM handler
* 被 spurious IRQ / 异常触发导致三重故障重启。 */
void idt_halt_all(void);
/* IRQ handler: return 1 to suppress default ACK (PIC), 0 for normal EOI.
* 参数为 IDT vector 号 (0x20-0xFF)。
* PIC IRQ (0x20-0x2F): 返回 1 抑制 PIC EOI; 返回 0 自动发送 PIC EOI。
* APIC/IOAPIC/MSI (0x30-0xFF): 返回值当前忽略, EOI 需手动处理 (TODO)。 */
typedef int (*irq_handler_t)(u8 vector);
int irq_register(u8 vector, irq_handler_t handler);
#endif
+181
View File
@@ -0,0 +1,181 @@
/* instr.h — Deshab 统一插桩宏系统
*
* 提供四级插桩原语:
* INSTR_LOG — 带级别和模块过滤的日志输出
* INSTR_STAT — 轻量级计数器 + 周期性摘要
* INSTR_PROBE — 环形探测缓冲写入(结构化事件记录)
* INSTR_TS — 时间戳标注(阶段耗时测量)
*
* 设计原则:
* - 禁用时零开销: g_instr_enabled=0 时所有宏展开为空操作
* - 热路径安全: STAT_INC 仅一条条件自增,PROBE 仅条件写入
* - 统一配置: 通过 FUCK [debug] 段控制开关与粒度
* - 标签编码: 4 字符 ASCII 编码为 u32,避免字符串比较
*
* 使用方式:
* 1. 在 kernel_main() 中调用 instr_init(&g_boot_cfg) 初始化
* 2. 各模块 #include <utsm/instr.h> 后使用 INSTR_* 宏
* 3. 在 FUCK 中设置 [debug] enabled=1 开启插桩
*/
#ifndef UTSM_INSTR_H
#define UTSM_INSTR_H
#include <utsm/types.h>
/* ---- 日志级别 ---- */
#define INSTR_LOG_TRACE 0
#define INSTR_LOG_DEBUG 1
#define INSTR_LOG_INFO 2
#define INSTR_LOG_WARN 3
#define INSTR_LOG_ERROR 4
#define INSTR_LOG_SILENT 5
/* ---- 全局配置变量 (instr.c 定义) ---- */
extern u32 g_instr_enabled; /* 全局插桩开关,FUCK debug.enabled */
extern u32 g_instr_log_level; /* 日志级别阈值,FUCK debug.log_level */
extern u32 g_instr_probe_enable; /* 探测缓冲开关,FUCK debug.probe_enable */
extern u32 g_instr_stat_interval; /* 统计摘要间隔,FUCK debug.stat_summary_interval */
extern u32 g_instr_module_flags; /* 模块级过滤位掩码 */
/* ---- 模块标志位 ---- */
#define INSTR_F_UTSM_TRACE (1u << 0)
#define INSTR_F_VMM_TRACE (1u << 1)
#define INSTR_F_DKM_TRACE (1u << 2)
#define INSTR_F_DSK_TRACE (1u << 3)
#define INSTR_F_BLOCK_TRACE (1u << 4)
#define INSTR_F_NET_TRACE (1u << 5)
#define INSTR_F_INPUT_TRACE (1u << 6)
/* ---- INSTR_LOG: 带级别和模块过滤的日志 ----
* level: INSTR_LOG_TRACE/DEBUG/INFO/WARN/ERROR
* mod_flag: INSTR_F_xxx 或 0(不过滤)
* msg: 常量字符串
*
* 仅当 g_instr_enabled && level >= g_instr_log_level &&
* (mod_flag==0 || mod_flag & g_instr_module_flags) 时输出。
*/
#define INSTR_LOG(level, mod_flag, msg) do { \
if (g_instr_enabled && (level) >= g_instr_log_level && \
((mod_flag) == 0 || (g_instr_module_flags & (mod_flag)))) { \
if ((level) <= INSTR_LOG_ERROR) log_error(msg); \
else if ((level) <= INSTR_LOG_WARN) log_warn(msg); \
else log_info(msg); \
} \
} while(0)
/* ---- INSTR_STAT: 轻量级计数器 (声明+增量+摘要) ----
* INSTR_STAT_DECL(name) — 在函数/文件作用域声明计数器
* INSTR_STAT_INC(name) — 原子性自增 (仅当 enabled)
* INSTR_STAT_SUMMARY(name) — 达到间隔时输出摘要并重置
*/
#define INSTR_STAT_DECL(name) \
static u64 name##_count = 0; \
static u64 name##_last_ts __attribute__((unused)) = 0
#define INSTR_STAT_INC(name) do { \
if (g_instr_enabled) { name##_count++; } \
} while(0)
#define INSTR_STAT_SUMMARY(name) do { \
if (g_instr_enabled && name##_count >= g_instr_stat_interval) { \
u64 _now = instr_rdtsc(); \
u64 _elapsed_ms = (_now - name##_last_ts) / (instr_tsc_per_ms ? instr_tsc_per_ms : 1); \
log_info("[STAT] " #name " count="); \
log_hex64("", name##_count); \
log_info("[STAT] " #name " interval_ms="); \
log_hex64("", _elapsed_ms); \
name##_count = 0; \
name##_last_ts = _now; \
} \
} while(0)
/* ---- INSTR_PROBE: 写入环形探测缓冲 ----
* 标签编码: 4 字符 ASCII,如 "BOOT", "VME0", "EPTV", "IDTI", "AHCI"
* a0-a3: 4 个 u64 参数,语义由标签定义
*
* 仅当 g_instr_enabled && g_instr_probe_enable 时写入。
*/
#define INSTR_PROBE(tag, a0, a1, a2, a3) do { \
if (g_instr_enabled && g_instr_probe_enable) \
probe_write(INSTR_TAG_##tag, (u64)(a0), (u64)(a1), (u64)(a2), (u64)(a3)); \
} while(0)
/* ---- INSTR_TS: 时间戳标注(阶段耗时测量) ----
* INSTR_TS_DECL(name) — 声明时间戳变量
* INSTR_TS_BEGIN(name) — 记录起始 TSC
* INSTR_TS_END(name, label) — 计算耗时并输出(仅当 enabled)
*/
#define INSTR_TS_DECL(name) static u64 name##_ts = 0
#define INSTR_TS_BEGIN(name) do { name##_ts = instr_rdtsc(); } while(0)
#define INSTR_TS_END(name, label) do { \
if (g_instr_enabled) { \
u64 _d = instr_rdtsc() - name##_ts; \
u64 _ms = _d / (instr_tsc_per_ms ? instr_tsc_per_ms : 1); \
log_info("[TS] " label " elapsed_ms="); \
log_hex64("", _ms); \
} \
} while(0)
/* ---- 标签编码常量 ----
* 4 字符 ASCII 编码为大端序 u32:
* 'B'=0x42, 'O'=0x4F, 'O'=0x4F, 'T'=0x54 → 0x424F4F54
*/
#define INSTR_TAG_BOOT 0x424F4F54u /* "BOOT" — 通用启动事件 */
#define INSTR_TAG_IDT0 0x49445430u /* "IDT0" — IDT/中断初始化 */
#define INSTR_TAG_ARE0 0x41524530u /* "ARE0" — Arena 初始化 */
#define INSTR_TAG_DMA0 0x444D4130u /* "DMA0" — DMA 初始化 */
#define INSTR_TAG_NET0 0x4E455430u /* "NET0" — 网络注册 */
#define INSTR_TAG_DRR0 0x44525230u /* "DRR0" — DRR 初始化 */
#define INSTR_TAG_UTS0 0x55545330u /* "UTS0" — UTSM 核心初始化 */
#define INSTR_TAG_DKM0 0x444B4D30u /* "DKM0" — DKM 加载 */
#define INSTR_TAG_DSM0 0x44534D30u /* "DSM0" — 驱动 manifest 加载 */
#define INSTR_TAG_DSK0 0x44534B30u /* "DSK0" — DSK 加载跳转 */
#define INSTR_TAG_SELF 0x53454C46u /* "SELF" — 自检 */
#define INSTR_TAG_VMM0 0x564D4D30u /* "VMM0" — VMM 初始化 */
#define INSTR_TAG_LIN0 0x4C494E30u /* "LIN0" — Linux loader */
#define INSTR_TAG_VME0 0x564D4530u /* "VME0" — VM-Exit 事件 */
#define INSTR_TAG_EPTV 0x45505456u /* "EPTV" — EPT violation */
#define INSTR_TAG_EPTM 0x4550544Du /* "EPTM" — EPT misconfig */
#define INSTR_TAG_AHCI 0x41484349u /* "AHCI" — AHCI 事件 */
#define INSTR_TAG_E1K0 0x45314B30u /* "E1K0" — e1000 事件 */
#define INSTR_TAG_FAT0 0x46415430u /* "FAT0" — FAT32 事件 */
#define INSTR_TAG_NVM0 0x4E564D30u /* "NVM0" — NVMe 事件 */
#define INSTR_TAG_IRQ0 0x49525130u /* "IRQ0" — IRQ 注册/触发 */
#define INSTR_TAG_PIT0 0x50495430u /* "PIT0" — PIT 模拟 */
#define INSTR_TAG_SRL0 0x53524C30u /* "SRL0" — 串口事件 */
#define INSTR_TAG_MMIO 0x4D4D494Fu /* "MMIO" — MMIO 访问 */
#define INSTR_TAG_HCALL 0x4843414Cu /* "HCAL" — Hypercall */
#define INSTR_TAG_EXCP 0x45584350u /* "EXCP" — CPU 异常 */
/* ---- 探测条目结构(与 probe.c 共享) ---- */
typedef struct probe_entry {
u32 tag; /* 4字符ASCII标签 */
u32 tick; /* 低32位TSC(~2s溢出@2GHz,足够诊断) */
u64 args[4]; /* 4个u64参数 */
} probe_entry;
/* ---- 辅助函数声明 (instr.c / probe.c 定义) ---- */
u64 instr_rdtsc(void);
extern u64 instr_tsc_per_ms;
void instr_init(const void *ini_config);
void probe_init(const void *ini_config);
void probe_write(u32 tag, u64 a0, u64 a1, u64 a2, u64 a3);
int probe_read(u32 n, probe_entry *out);
u32 probe_count(void);
u32 probe_capacity(void);
probe_entry *probe_buf_address(void);
u32 probe_head_value(void);
u32 probe_dropped_count(void);
/* 需要前向声明 log 函数 (避免循环 include) */
#ifndef UTSM_LOG_H
void log_info(const char *msg);
void log_warn(const char *msg);
void log_error(const char *msg);
void log_hex64(const char *prefix, u64 value);
#endif
#endif /* UTSM_INSTR_H */
+14
View File
@@ -43,6 +43,20 @@ u64 ipc_shm_get_gpa(void);
/* Get the size of the shared memory region. */
u64 ipc_shm_get_size(void);
/* ===== Payload pool access (bulk data channel) =====
*
* The payload_pool area of the SHM region carries bulk file-transfer data
* (Phase 3 FILE_LIST/FILE_READ). Linux daemon writes into it (via
* UTSM_IOCTL_WRITE_POOL) before sending UTSM_MSG_FILE_RESPONSE; UTSM reads
* it directly through its own HHDM mapping. */
/* Host virtual pointer into payload_pool at byte offset.
* Returns NULL if not initialized or offset out of range. */
void *ipc_shm_payload_ptr(u32 offset);
/* Total capacity of the payload pool in bytes. */
u32 ipc_shm_payload_capacity(void);
/* ===== Message API (UTSM-side) ===== */
/* Send a message from UTSM to Linux (enqueues into utsm_to_linux ring).
+58
View File
@@ -42,10 +42,68 @@ typedef struct linux_compat_service {
char *stdout_buf, u64 stdout_cap, u64 *stdout_len,
u64 *exit_code);
/* 列出 Linux 目录内容(Phase 3 文件传输)。
* path : Linux 绝对路径(如 "/usr/bin")
* buf/cap : 接收列表文本的缓冲区(每行一项,目录名带 '/' 后缀)
* out_len : 实际写入字节数(可为 NULL)
* 返回 0 成功,负值失败(-1=服务不可用, -2=IPC 发送失败,
* -3=linux_resume 失败, -4=无响应, -5=Linux 侧错误,
* -6=缓冲区不足被截断,此时 out_len 仍给出截断长度)。 */
int (*file_list)(const char *path, char *buf, u64 cap, u64 *out_len);
/* 读取 Linux 文件内容(Phase 3 文件传输,支持大文件分块)。
* path : Linux 绝对路径(如 "/etc/hostname")
* offset : 文件内起始偏移(首次读传 0)
* buf/cap : 接收文件数据的缓冲区
* out_len : 本次实际读取字节数(可为 NULL)
* out_total : 文件总大小(可为 NULL)
* 返回 0 成功(含 EOF:out_len=0 且 offset>=total),负值失败
* (错误码同 file_list)。 */
int (*file_read)(const char *path, u64 offset, char *buf, u64 cap,
u64 *out_len, u64 *out_total);
/* 查询 Linux guest 状态字符串(调试用),写入 buf,返回字符串长度。 */
int (*status)(char *buf, u64 cap);
/* 写入 Linux 文件(Phase 3 文件传输,支持大文件分块)。
* 调用方以递增 offset 循环调用即可上传任意大小文件。
* path : Linux 绝对路径(不存在则以 0644 创建;
* offset==0 时先截断,即 push 语义为整文件替换)
* offset : 文件内写入偏移(首次写传 0)
* buf/len : 待写数据(len 会被钳制到 payload pool 容量,
* 实际写入量以 out_written 为准;len=0 仅创建/截断)
* out_written : 本次实际写入字节数(可为 NULL)
* 返回 0 成功,负值失败(错误码同 file_list)。 */
int (*file_write)(const char *path, u64 offset, const char *buf, u64 len,
u64 *out_written);
/* 跨内核文件拉取:Linux 文件 → UTSM FAT32 系统盘根目录(≤256KB,整文件)。
* linux_path : Linux 绝对路径
* fat32_name : UTSM FAT32 根目录文件名(如 "HOSTNAME.TXT",8.3 可转换)
* out_size : 实际传输字节数(可为 NULL)
* 返回 0 成功,负值失败(-7=文件超过 256KB 暂存上限, -9=无块设备,
* -10=非法 FAT32 名, -12=FAT32 写失败,其余同 file_list)。 */
int (*file_pull)(const char *linux_path, const char *fat32_name,
u64 *out_size);
/* 跨内核文件推送:UTSM FAT32 系统盘根目录 → Linux 文件(≤256KB,整文件替换)。
* fat32_name : UTSM FAT32 根目录文件名(8.3 可转换)
* linux_path : Linux 绝对路径
* out_size : 实际传输字节数(可为 NULL)
* 返回 0 成功,负值失败(-11=文件不存在,其余同 file_pull)。 */
int (*file_push)(const char *fat32_name, const char *linux_path,
u64 *out_size);
} linux_compat_service;
/* ===== UTSM 内部接口(不进服务表,供 hypercall.c 等内核代码使用) =====
*
* UTSM FAT32 系统盘根目录文件访问(经 block_get_api() + fat32_io)。
* name 为普通文件名(内部做 8.3 转换)。
* 返回 0 成功;负值:-9 无块设备, -10 非法文件名, -11 文件不存在,
* -12 磁盘 I/O 错误。 */
int lxc_f32_read_file(const char *name, u8 **out_data, u32 *out_size);
int lxc_f32_write_file(const char *name, const u8 *data, u32 size);
/* 获取全局 Linux 兼容层服务实例指针(UTSM 内部使用,
* 外部通过 boot context reserved[5] 获取)。 */
const linux_compat_service *linux_compat_get_service(void);
+8 -2
View File
@@ -135,9 +135,10 @@ struct linux_setup_header {
#define VIRTIO_MMIO_BLK_GPA (VIRTIO_MMIO_GPA_BASE + 0 * VIRTIO_MMIO_GPA_STRIDE) /* 0xF4000000 */
#define VIRTIO_MMIO_NET_GPA (VIRTIO_MMIO_GPA_BASE + 1 * VIRTIO_MMIO_GPA_STRIDE) /* 0xF4001000 */
#define VIRTIO_MMIO_ROOTFS_GPA (VIRTIO_MMIO_GPA_BASE + 2 * VIRTIO_MMIO_GPA_STRIDE) /* 0xF4002000 */
/* 判断 GPA 是否落在 virtio-mmio 设备区(含两端) */
#define VIRTIO_MMIO_GPA_END (VIRTIO_MMIO_GPA_BASE + 2 * VIRTIO_MMIO_GPA_STRIDE)
#define VIRTIO_MMIO_GPA_END (VIRTIO_MMIO_GPA_BASE + 3 * VIRTIO_MMIO_GPA_STRIDE)
#define IS_VIRTIO_MMIO_GPA(gpa) ((gpa) >= VIRTIO_MMIO_GPA_BASE && (gpa) < VIRTIO_MMIO_GPA_END)
/* ===== Linux loader API ===== */
@@ -162,6 +163,10 @@ struct linux_guest_info {
* Sets *size_out to the module size. */
void *linux_find_bzimage_module(u64 *size_out);
/* Find the Arch rootfs image boot module (path contains "rootfs").
* Exposed to Linux guest via memory-backed virtio-blk as /dev/vdb. */
void *linux_find_rootfs_module(u64 *size_out);
/* Parse bzImage header and extract key parameters.
* Returns 0 on success, negative on error. */
int linux_parse_bzimage(const void *bzimage, u64 size,
@@ -194,6 +199,7 @@ int linux_launch(void);
"no_timer_check loglevel=7 nohlt idle=poll " \
"noapic nolapic nosmp " \
"virtio_mmio.device=4K@0xF4000000:5 " \
"virtio_mmio.device=4K@0xF4001000:6"
"virtio_mmio.device=4K@0xF4001000:6 " \
"virtio_mmio.device=4K@0xF4002000:7"
#endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef UTSM_MM_H
#define UTSM_MM_H
#include <utsm/types.h>
/* MMIO 映射接口:
* mm_map_mmio 在当前页表(Limine 提供的 CR3)的 MMIO 专用窗口中
* 建立 phys → virt 的 4K 页映射,页属性带 PCD|PWT(等效 UC),
* 适用于任意物理地址(含 4G 以上的 PCI BAR)。
* 返回的虚拟地址包含 phys 的页内偏移;失败返回 0。 */
void *mm_map_mmio(u64 phys, u64 size);
/* 解除 mm_map_mmio 建立的映射(按页清除 PTE + invlpg)。
* 窗口虚拟地址与中间页表页不回收,保留复用。 */
void mm_unmap_mmio(void *virt, u64 size);
#endif
+12
View File
@@ -58,6 +58,16 @@ typedef struct dkm_net_device_info {
u32 flags;
} dkm_net_device_info;
/* 网络设备统计(真机诊断用,驱动层累计)。 */
typedef struct dkm_net_stats {
u64 tx_ok; /* TX 成功帧数 */
u64 tx_err; /* TX 失败帧数 */
u64 rx_ok; /* RX 成功帧数 */
u64 rx_err; /* RX 错误帧数 */
u64 rx_overflow; /* RX buffer 溢出丢包 */
u64 link_changes; /* 链路状态变化次数 */
} dkm_net_stats;
typedef struct dkm_net_api {
int (*register_device)(const dkm_net_device_desc *desc);
u32 (*device_count)(void);
@@ -69,6 +79,8 @@ typedef struct dkm_net_api {
int (*scan_count)(u32 index);
int (*scan_result)(u32 index, u32 n, dkm_net_scan_result *out);
int (*is_wireless)(u32 index);
/* 网络统计查询(返回 0 成功,-1 索引越界)。 */
int (*device_stats)(u32 index, dkm_net_stats *out);
} dkm_net_api;
void net_init(void);
+34
View File
@@ -0,0 +1,34 @@
#ifndef UTSM_PAGING_H
#define UTSM_PAGING_H
#include <utsm/types.h>
/*
* UTSM 页表/MMIO 映射服务
*
* 背景:内核使用 Limine 建立的页表 + HHDM 直映射访问全部 RAM,
* 但 HHDM 只保证覆盖内存映射中的 RAM 区域,不保证覆盖 4G 以上的
* PCI MMIO 空洞(QEMU/OVMF 常把 NVMe 等 64-bit BAR 分配到 48GiB
* 附近)。本模块提供:
* 1. is_mapped —— 四级页表只读 walk,运行时核实某虚拟地址是否可访问,
* 用于在触碰高位 BAR 前先确认 HHDM 覆盖情况(零 #PF 风险)。
* 2. map_mmio —— 在 Limine 页表的 HHDM 空洞处原地补充 4KiB UC 映射
* (P|RW|PCD|PWT),页表页取自 DMA 物理页分配器(低 4G、4K 对齐、清零)。
*
* SAS-R0 单地址空间模型:不新建地址空间,直接扩展当前 CR3 指向的页表,
* 所有 CPU/驱动立即可见,无切换成本。
*/
typedef struct dkm_mmio_api {
/* 四级页表 walk。返回 0=未映射;1=4K PTE 命中;2=2M PDE 命中;3=1G PDPTE 命中 */
int (*is_mapped)(u64 vaddr);
/* 把物理区间 [phys, phys+size) 映射到 hhdm_offset + phys,4KiB UC 页。
* 已被 Limine 覆盖(含 1G/2M 大页)的页自动跳过。返回 0 成功,负数失败。 */
int (*map_mmio)(u64 phys, u64 size);
/* 当前 CR3 物理地址(诊断用) */
u64 (*cr3)(void);
} dkm_mmio_api;
const dkm_mmio_api *paging_get_api(void);
#endif
+9
View File
@@ -153,4 +153,13 @@ int virtio_queue_get_ptrs(u32 device_id, u32 queue_idx,
* 由后端在写 used ring 元素后调用,内部做内存屏障。 */
void virtio_queue_bump_used(struct virtq_used *used, u16 new_idx);
/* 异步触发设备中断(设置 INTERRUPT_STATUS bit0 并向 guest 注入虚拟 IRQ)。
* 用于后端在 QUEUE_NOTIFY 上下文之外完成工作(如周期轮询收到 RX 包)。
* device_id: VIRTIO_ID_*;设备未注册或 irq==0 时为空操作。 */
void virtio_mmio_raise_irq(u32 device_id);
/* 周期轮询 virtio-net RX 路径(填充 guest 已投递的 RX buffer,
* 有填充时自动注入 IRQ)。由 vmexit 的 preemption timer 路径调用。 */
void virtio_net_poll(void);
#endif /* UTSM_VIRTIO_MMIO_H */
+5
View File
@@ -0,0 +1,5 @@
kernel/block.o: kernel\block.c include\utsm\block.h include\utsm\types.h \
include\utsm\log.h
include\utsm\block.h:
include\utsm\types.h:
include\utsm\log.h:
+387 -26
View File
@@ -5,6 +5,7 @@
#include <utsm/types.h>
#include <utsm/pe.h>
#include <utsm/linux_compat.h>
#include <utsm/instr.h>
#include "../arch/x86_64/limine.h"
#define DSK_PATH "/system/deshab64/deshab.elf"
@@ -20,6 +21,27 @@
#define ET_EXEC 2
#define EM_X86_64 62
#define PT_LOAD 1
#define PT_DYNAMIC 2
/* ELF Dynamic section tags */
#define DT_NULL 0
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
/* ELF Relocation types */
#define R_X86_64_RELATIVE 8
typedef struct elf64_dyn {
i64 tag;
u64 val;
} elf64_dyn;
typedef struct elf64_rela {
u64 offset;
u64 info;
i64 addend;
} elf64_rela;
void *memset(void *dst, int value, usize len);
void *memcpy(void *dst, const void *src, usize len);
@@ -152,27 +174,86 @@ static struct limine_file *dsk_find_module(void) {
}
/* ---- FAT32 block-provider file reader ---- */
static u8 g_dsk_fat32_disk[65536]; /* 128-sector BPB+FAT+root dir buffer */
static u8 g_dsk_fat32_disk[131072]; /* 256-sector BPB+FAT+root dir buffer (与 DSK 端一致) */
static u8 g_dsk_fat32_cluster[4096]; /* 8-sector cluster buffer */
/* 实机要求: 文件缓冲区足够大容纳 deshab.elf (~1.5MB) */
static u8 g_dsk_fat32_filedata[2097152]; /* 2MB file data buffer */
/* BUG-019 修复: FAT 按需扇区读取缓冲区(仅 512 字节),
* 当 FAT 条目偏移超出 g_dsk_fat32_disk (128KB) 时使用。 */
static u8 g_dsk_fat32_fat_sec[512];
/* BUG-019 修复: 按需读取 FAT 扇区获取下一个簇号。
* 如果目标 FAT 条目在预读缓冲区内,直接读取;
* 否则只读取包含该条目的单个 FAT 扇区(512 字节)。
* fat_start: FAT 在预读缓冲区中的字节偏移(reserved_sectors * 512)。
* clus: 当前簇号。
* bpb: BPB 指针(用于计算 FAT 扇区 LBA)。
* disk: 预读缓冲区基址。
* 返回: 下一个簇号,失败返回 0x0FFFFFFF(链终止)。 */
static u32 fat32_get_next_cluster(u32 fat_start_byte, u32 clus,
const fat32_bpb *bpb, const u8 *disk) {
u32 fat_ent_off = fat_start_byte + clus * 4;
/* 情况 1: FAT 条目在预读缓冲区内(小分区) */
if (fat_ent_off + 4 <= sizeof(g_dsk_fat32_disk)) {
return fat32_read_u32(disk + fat_ent_off) & 0x0FFFFFFF;
}
/* 情况 2: FAT 条目超出预读缓冲区(实机大分区)——按需读取单个 FAT 扇区 */
const dkm_kernel_api *api = dkm_get_kernel_api();
if (!api || !api->block) return 0x0FFFFFFF;
/* FAT 条目在 FAT 表中的字节偏移(相对于 FAT 起始) */
u32 fat_byte_off_in_fat = clus * 4;
/* 该条目所在的 FAT 扇区号(相对于 FAT 起始) */
u32 fat_sec_index = fat_byte_off_in_fat / 512;
/* 条目在扇区内的字节偏移 */
u32 ent_off_in_sec = fat_byte_off_in_fat % 512;
/* FAT 扇区的绝对 LBA */
u32 fat_sec_lba = bpb->reserved_sector_count + fat_sec_index;
int st = api->block->read(0, fat_sec_lba, 1, g_dsk_fat32_fat_sec);
if (st != 0) {
log_error("[UTSM] FAT32: on-demand FAT sector read failed");
log_hex64("[UTSM] FAT32: fat_sec_lba=", fat_sec_lba);
log_hex64("[UTSM] FAT32: clus=", clus);
return 0x0FFFFFFF;
}
return fat32_read_u32(g_dsk_fat32_fat_sec + ent_off_in_sec) & 0x0FFFFFFF;
}
static int dsk_load_from_block_fat32(const void **out_addr, u64 *out_size) {
const dkm_kernel_api *api = dkm_get_kernel_api();
if (!api || !api->block || !api->block->device_count) return -1;
if (!api || !api->block || !api->block->device_count) {
log_error("[UTSM] FAT32: no block api available");
return -1;
}
u32 count = api->block->device_count();
if (count == 0 || api->block->sector_size(0) != 512) return -1;
if (count == 0 || api->block->sector_size(0) != 512) {
log_error("[UTSM] FAT32: no block device or wrong sector size");
log_hex64("[UTSM] FAT32: device_count=", count);
return -1;
}
/* Read first 128 sectors: BPB + FAT + root dir */
/* Read first 256 sectors: BPB + FAT + root dir */
u8 *disk = g_dsk_fat32_disk;
int st = api->block->read(0, 0, 128, disk);
if (st != 0) return -1;
int st = api->block->read(0, 0, 256, disk);
if (st != 0) {
log_error("[UTSM] FAT32: BPB read failed");
log_hex64("[UTSM] FAT32: read status=", (u64)(i64)st);
return -1;
}
const fat32_bpb *bpb = (const fat32_bpb *)disk;
if (bpb->boot_sig != 0xAA55 || bpb->bytes_per_sector != 512) return -1;
if (bpb->boot_sig != 0xAA55 || bpb->bytes_per_sector != 512) {
log_error("[UTSM] FAT32: invalid BPB signature or sector size");
log_hex64("[UTSM] FAT32: boot_sig=", bpb->boot_sig);
log_hex64("[UTSM] FAT32: bps=", bpb->bytes_per_sector);
return -1;
}
u32 fat_start = bpb->reserved_sector_count * 512;
u32 data_start_sec = bpb->reserved_sector_count + (u32)bpb->fat_count * bpb->sectors_per_fat;
log_hex64("[UTSM] FAT32: fat_start_off=", fat_start);
log_hex64("[UTSM] FAT32: data_start_sec=", data_start_sec);
log_hex64("[UTSM] FAT32: spc=", bpb->sectors_per_cluster);
log_hex64("[UTSM] FAT32: root_clus=", bpb->root_cluster);
u32 clus = bpb->root_cluster;
u32 found_clus = 0;
@@ -184,7 +265,12 @@ static int dsk_load_from_block_fat32(const void **out_addr, u64 *out_size) {
u32 cls_sec = bpb->sectors_per_cluster;
u8 *cb = g_dsk_fat32_cluster;
st = api->block->read(0, clus_lba, cls_sec, cb);
if (st != 0) return -1;
if (st != 0) {
log_error("[UTSM] FAT32: dir cluster read failed");
log_hex64("[UTSM] FAT32: clus=", clus);
log_hex64("[UTSM] FAT32: lba=", clus_lba);
return -1;
}
const fat32_dir_entry *dir = (const fat32_dir_entry *)cb;
for (u32 e = 0; e * 32 < cls_sec * 512; e++) {
@@ -194,19 +280,27 @@ static int dsk_load_from_block_fat32(const void **out_addr, u64 *out_size) {
if (dir[e].attr & 0x08) continue;
if (fat32_name11_eq(dir[e].name, target)) {
found_size = dir[e].file_size;
found_clus = fat32_read_u16((const u8 *)&dir[e].cluster_low);
found_clus = fat32_read_u16((const u8 *)&dir[e].cluster_low) |
((u32)fat32_read_u16((const u8 *)&dir[e].cluster_high) << 16);
break;
}
}
if (found_clus) break;
u32 fat_ent = fat_start + clus * 4;
if (fat_ent + 4 > 65536) break;
clus = fat32_read_u32(disk + fat_ent) & 0x0FFFFFFF;
/* BUG-019: 使用按需 FAT 读取,不再受 128KB 缓冲区限制 */
clus = fat32_get_next_cluster(fat_start, clus, bpb, disk);
}
if (!found_clus || found_size == 0) return -1;
if (!found_clus || found_size == 0) {
log_error("[UTSM] FAT32: DESHAB.ELF not found in root dir");
return -1;
}
log_hex64("[UTSM] FAT32: found_clus=", found_clus);
log_hex64("[UTSM] FAT32: found_size=", found_size);
if (found_size > sizeof(g_dsk_fat32_filedata)) return -1;
if (found_size > sizeof(g_dsk_fat32_filedata)) {
log_error("[UTSM] FAT32: file exceeds 2MB buffer");
return -1;
}
u8 *dst = g_dsk_fat32_filedata;
u32 remaining = found_size;
u32 fc = found_clus;
@@ -219,19 +313,27 @@ static int dsk_load_from_block_fat32(const void **out_addr, u64 *out_size) {
u8 *chunk = g_dsk_fat32_cluster;
st = api->block->read(0, fc_lba, fc_sec, chunk);
if (st != 0) return -1;
if (st != 0) {
log_error("[UTSM] FAT32: data cluster read failed");
log_hex64("[UTSM] FAT32: fc=", fc);
log_hex64("[UTSM] FAT32: lba=", fc_lba);
return -1;
}
for (u32 b = 0; b < fc_bytes; b++) dst[b] = chunk[b];
dst += fc_bytes;
remaining -= fc_bytes;
u32 fat_ent = fat_start + fc * 4;
if (fat_ent + 4 > 65536) { fc = 0x0FFFFFFF; break; }
fc = fat32_read_u32(disk + fat_ent) & 0x0FFFFFFF;
/* BUG-019: 使用按需 FAT 读取 */
fc = fat32_get_next_cluster(fat_start, fc, bpb, disk);
}
/* Copy to arena for ELF loader */
u8 *file_buf = (u8 *)kmem_alloc_aligned(found_size, 16);
if (!file_buf) return -1;
if (!file_buf) {
log_error("[UTSM] FAT32: arena alloc failed");
log_hex64("[UTSM] FAT32: size=", found_size);
return -1;
}
for (u32 i = 0; i < found_size; i++) file_buf[i] = g_dsk_fat32_filedata[i];
*out_addr = file_buf;
@@ -240,6 +342,139 @@ static int dsk_load_from_block_fat32(const void **out_addr, u64 *out_size) {
return 0;
}
/* ---- FAT32 subdirectory traversal ---- */
/* 在指定起始 cluster 的目录项中查找 name11。
* is_dir=1 时只匹配子目录(attr & 0x10),is_dir=0 时只匹配文件。
* 返回 0 成功,out_clus/out_size 返回匹配项的起始 cluster 和大小。 */
static int fat32_find_in_dir(u32 start_clus, const char *name11, int is_dir,
u32 *out_clus, u32 *out_size) {
const dkm_kernel_api *api = dkm_get_kernel_api();
if (!api || !api->block || !api->block->device_count) return -1;
u8 *disk = g_dsk_fat32_disk;
const fat32_bpb *bpb = (const fat32_bpb *)disk;
if (bpb->boot_sig != 0xAA55 || bpb->bytes_per_sector != 512) return -2;
u32 fat_start = bpb->reserved_sector_count * 512;
u32 data_start_sec = bpb->reserved_sector_count + (u32)bpb->fat_count * bpb->sectors_per_fat;
u32 spc = bpb->sectors_per_cluster;
u32 clus = start_clus;
while (clus >= 2 && clus < 0x0FFFFFF8) {
u32 clus_lba = data_start_sec + (clus - 2) * spc;
u8 *cb = g_dsk_fat32_cluster;
int st = api->block->read(0, clus_lba, spc, cb);
if (st != 0) return -3;
const fat32_dir_entry *dir = (const fat32_dir_entry *)cb;
for (u32 e = 0; e * 32 < spc * 512; e++) {
if (dir[e].name[0] == 0) break;
if ((u8)dir[e].name[0] == 0xE5) continue;
if (dir[e].attr == 0x0F) continue;
if (dir[e].attr & 0x08) continue;
if (!fat32_name11_eq(dir[e].name, name11)) continue;
/* 名称匹配,检查类型 */
int entry_is_dir = (dir[e].attr & 0x10) ? 1 : 0;
if (entry_is_dir != is_dir) continue;
*out_clus = fat32_read_u16((const u8 *)&dir[e].cluster_low) |
((u32)fat32_read_u16((const u8 *)&dir[e].cluster_high) << 16);
*out_size = dir[e].file_size;
return 0;
}
/* 跟随 FAT 链 — BUG-019: 使用按需 FAT 读取 */
clus = fat32_get_next_cluster(fat_start, clus, bpb, disk);
}
return -4; /* 未找到 */
}
/* 按路径查找文件并读取内容。
* path: '/' 分隔的 8.3 格式路径(如 "SYSTEM /DESHAB64 /FUCK ")。
* out_data: 返回在 g_dsk_fat32_filedata 中的文件数据指针。
* out_size: 返回文件大小。
* 返回 0 成功。 */
int fat32_read_path(const char *path, u8 **out_data, u32 *out_size) {
const dkm_kernel_api *api = dkm_get_kernel_api();
if (!api || !api->block || !api->block->device_count) return -1;
u8 *disk = g_dsk_fat32_disk;
/* 确保 BPB 缓冲区是新鲜的 */
if (api->block->read(0, 0, 256, disk) != 0) return -2;
const fat32_bpb *bpb = (const fat32_bpb *)disk;
if (bpb->boot_sig != 0xAA55 || bpb->bytes_per_sector != 512) return -3;
u32 fat_start = bpb->reserved_sector_count * 512;
u32 data_start_sec = bpb->reserved_sector_count + (u32)bpb->fat_count * bpb->sectors_per_fat;
u32 spc = bpb->sectors_per_cluster;
/* 解析路径组件 */
u32 pos = 0;
u32 path_len = 0;
while (path[path_len]) path_len++;
u32 cur_clus = bpb->root_cluster; /* 从根目录开始 */
while (pos < path_len) {
/* 提取一个路径组件(到下一个 '/' 或结尾) */
char comp[12]; /* 11 字符 8.3 名 + \0 */
u32 ci = 0;
while (pos < path_len && path[pos] != '/' && ci < 11) {
comp[ci++] = path[pos++];
}
/* 不足 11 字符则补空格 */
while (ci < 11) comp[ci++] = ' ';
comp[11] = 0;
/* 跳过 '/' */
if (pos < path_len && path[pos] == '/') pos++;
/* 判断是否为最后一个组件 */
int is_last = (pos >= path_len);
if (is_last) {
/* 最后一级:查找文件 */
u32 found_clus = 0, found_size = 0;
int rc = fat32_find_in_dir(cur_clus, comp, 0, &found_clus, &found_size);
if (rc != 0) return -4;
if (found_size > sizeof(g_dsk_fat32_filedata)) return -5;
/* 读取文件数据 */
u8 *dst = g_dsk_fat32_filedata;
u32 remaining = found_size;
u32 fc = found_clus;
while (fc >= 2 && fc < 0x0FFFFFF8 && remaining > 0) {
u32 fc_lba = data_start_sec + (fc - 2) * spc;
u32 fc_bytes = spc * 512;
if (fc_bytes > remaining) fc_bytes = remaining;
u8 *chunk = g_dsk_fat32_cluster;
if (api->block->read(0, fc_lba, spc, chunk) != 0) return -6;
for (u32 b = 0; b < fc_bytes; b++) dst[b] = chunk[b];
dst += fc_bytes;
remaining -= fc_bytes;
/* BUG-019: 使用按需 FAT 读取 */
fc = fat32_get_next_cluster(fat_start, fc, bpb, disk);
}
*out_data = g_dsk_fat32_filedata;
*out_size = found_size;
return 0;
} else {
/* 中间级:查找子目录 */
u32 sub_clus = 0, sub_size = 0;
int rc = fat32_find_in_dir(cur_clus, comp, 1, &sub_clus, &sub_size);
if (rc != 0) return -7;
cur_clus = sub_clus;
}
}
return -8; /* 路径为空或无效 */
}
/* ---- ELF checks ---- */
static int dsk_check_elf(const void *address, u64 size) {
if (!address || size < sizeof(elf64_ehdr)) return -1;
@@ -263,15 +498,26 @@ static int dsk_load_elf_image(const void *address, u64 size, dsk_entry_fn *entry
u64 max_align = 0x1000;
u32 load_count = 0;
/* PT_DYNAMIC 的位置(PIE 重定位用) */
u64 dyn_off = 0;
u64 dyn_filesz = 0;
int has_dyn = 0;
for (u16 i = 0; i < eh->phnum; i++) {
const elf64_phdr *ph = (const elf64_phdr *)(base + eh->phoff + (u64)i * eh->phentsize);
if (ph->type != PT_LOAD) continue;
if (ph->filesz > ph->memsz) return -1;
if (!range_ok(ph->offset, ph->filesz, size)) return -2;
if (ph->vaddr < min_vaddr) min_vaddr = ph->vaddr;
if (ph->vaddr + ph->memsz > max_vaddr) max_vaddr = ph->vaddr + ph->memsz;
if (ph->align > max_align) max_align = ph->align;
load_count++;
if (ph->type == PT_LOAD) {
if (ph->filesz > ph->memsz) return -1;
if (!range_ok(ph->offset, ph->filesz, size)) return -2;
if (ph->vaddr < min_vaddr) min_vaddr = ph->vaddr;
if (ph->vaddr + ph->memsz > max_vaddr) max_vaddr = ph->vaddr + ph->memsz;
if (ph->align > max_align) max_align = ph->align;
load_count++;
} else if (ph->type == PT_DYNAMIC) {
if (!range_ok(ph->offset, ph->filesz, size)) return -2;
dyn_off = ph->offset;
dyn_filesz = ph->filesz;
has_dyn = 1;
}
}
if (load_count == 0 || min_vaddr == ~0ULL || max_vaddr <= min_vaddr) return -3;
@@ -290,6 +536,44 @@ static int dsk_load_elf_image(const void *address, u64 size, dsk_entry_fn *entry
memcpy(image + dst_off, base + ph->offset, ph->filesz);
}
/* PIE 重定位: 处理 PT_DYNAMIC → DT_RELA → R_X86_64_RELATIVE
* load_bias = image 实际加载地址 - ELF 预期最小 vaddr
* 对每个 R_X86_64_RELATIVE: slot = load_bias + addend */
if (has_dyn && eh->type == ET_DYN) {
u64 load_bias = (u64)image - min_vaddr;
const elf64_dyn *dyn = (const elf64_dyn *)(base + dyn_off);
u64 dyn_count = dyn_filesz / sizeof(elf64_dyn);
u64 rela_off = 0, rela_sz = 0, rela_ent = sizeof(elf64_rela);
for (u64 d = 0; d < dyn_count; d++) {
if (dyn[d].tag == DT_NULL) break;
if (dyn[d].tag == DT_RELA) rela_off = dyn[d].val;
if (dyn[d].tag == DT_RELASZ) rela_sz = dyn[d].val;
if (dyn[d].tag == DT_RELAENT) rela_ent = dyn[d].val;
}
if (rela_off != 0 && rela_sz != 0 && rela_ent != 0) {
/* rela_off 是相对于文件开头的 vaddr,需转换为 image 内偏移 */
if (rela_off >= min_vaddr && rela_off < min_vaddr + image_size) {
u64 rela_count = rela_sz / rela_ent;
for (u64 r = 0; r < rela_count; r++) {
const elf64_rela *rel = (const elf64_rela *)(
image + (rela_off - min_vaddr) + r * rela_ent);
u32 rtype = (u32)rel->info;
if (rtype == R_X86_64_RELATIVE) {
if (rel->offset < min_vaddr || rel->offset >= min_vaddr + image_size) continue;
u64 *slot = (u64 *)(image + (rel->offset - min_vaddr));
*slot = load_bias + (u64)rel->addend;
}
}
}
log_info("[UTSM] PIE reloc applied");
log_hex64("[UTSM] load_bias=", load_bias);
log_hex64("[UTSM] rela_count=", rela_sz / rela_ent);
}
}
*entry_out = (dsk_entry_fn)(image + (eh->entry - min_vaddr));
log_hex64("[UTSM] DSK image base=", (u64)image);
log_hex64("[UTSM] DSK image size=", image_size);
@@ -333,6 +617,24 @@ static void dsk_fill_boot_context(dsk_boot_context *ctx) {
ctx->reserved[5] = (u64)lxc;
}
/* Probe 探测缓冲信息(供 shell $probe 命令读取) */
if (g_instr_enabled) {
probe_info *pi = (probe_info *)kmem_alloc_aligned(sizeof(probe_info), 8);
if (pi) {
pi->magic = PROBE_INFO_MAGIC;
pi->version = 1;
pi->probe_buf_addr = (u64)probe_buf_address();
pi->probe_cap = probe_capacity();
pi->probe_head = probe_head_value();
pi->probe_count = probe_count();
pi->probe_dropped = probe_dropped_count();
pi->instr_enabled = g_instr_enabled;
pi->instr_probe_enable = g_instr_probe_enable;
ctx->reserved[6] = (u64)pi;
ctx->flags |= DSK_BOOT_FLAG_PROBE_INFO;
}
}
u64 rsp;
__asm__ volatile ("movq %%rsp, %0" : "=r"(rsp));
ctx->kernel_stack_top = rsp;
@@ -384,6 +686,65 @@ int dsk_load_and_jump(void) {
}
dsk_fill_boot_context(ctx);
/* 实机安全: 跳转前 cli → mask PIC → 重置 IDT → NMI off。
* DSK 加载的 ELF 映像可能覆盖 UTSM 的驱动代码段,
* 如果 UTSM 注册的 IRQ handler 所在内存被覆盖,
* 中断触发时跳转到无效地址 → 三重故障重启。
*
* P0 修复: 1) 先 cli 禁用中断,消除 PIC mask 两步操作之间的中断竞争窗口
* 2) mask PIC 确保不会有硬件中断到达
* 3) 设置 LAPIC TPR=0xFF 屏蔽所有通过 IOAPIC 路由的中断
* 4) 将 IDT 所有条目替换为安全 halt stub,防止 DSK 运行时
* 过期的 UTSM handler 被异常/spurious IRQ 触发
* 5) 禁用 NMI */
{
extern void outb(u16 port, u8 value);
extern u8 inb(u16 port);
/* 1) 先禁用中断——关键修复!原来缺少此步,
* outb(0xA1,0xFF) 和 outb(0x21,0xFF) 之间有中断窗口 */
__asm__ volatile("cli");
/* 2) mask PIC — 此时 IF=0,安全操作 */
outb(0xA1, 0xFF); /* PIC2: mask IRQ8-15 */
outb(0x21, 0xFF); /* PIC1: mask IRQ0-7 */
/* 3) BUG-020 修复: 设置 LAPIC TPR=0xFF 屏蔽所有 IOAPIC 路由中断。
* 实机多核平台中断通常经 IOAPIC 而非 PIC,PIC mask 不影响
* IOAPIC redirection entry。通过 IA32_APIC_BASE MSR 读取 LAPIC
* 基地址,写入 TPR(偏移 0x80)=0xFF 可在 LAPIC 层面屏蔽所有
* 可屏蔽中断(低于 0xFF 优先级),确保 DSK 运行期间不会有
* IOAPIC 路由的 IRQ 到达。HHDM 映射后 LAPIC MMIO 可访问。 */
{
u32 msr_lo, msr_hi;
__asm__ volatile("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(0x1B));
u64 lapic_phys = ((u64)msr_hi << 32) | (msr_lo & 0xFFFFF000ULL);
if (lapic_phys && (msr_lo & (1 << 11))) {
/* LAPIC 全局启用时(bit 11)才操作 TPR */
extern volatile struct limine_hhdm_request g_hhdm_request;
u64 hhdm_off = g_hhdm_request.response
? g_hhdm_request.response->offset : 0;
if (hhdm_off) {
u64 lapic_vaddr = lapic_phys + hhdm_off;
*(volatile u32 *)(lapic_vaddr + 0x80) = 0xFF;
}
}
}
/* 4) 将 IDT 所有 256 个条目替换为安全 halt stub。
* 实机会产生 spurious IRQ7/15(即使 PIC 已 mask),
* 且 SMI/NMI 可能触发异常。如果 UTSM 的 idt_handler
* 所调用的 log 函数或串口驱动被覆盖,会导致双重异常→三重故障。 */
extern void idt_halt_all(void);
idt_halt_all();
/* 5) NMI off */
outb(0x70, inb(0x70) | 0x80);
}
log_hex64("[UTSM] DSK context magic=", ctx->magic);
log_hex64("[UTSM] DSK context api=", ctx->dkm_kernel_api);
log_hex64("[UTSM] DSK context fb=", ctx->framebuffer_address);
log_info("[UTSM] jumping to DSK");
entry(ctx);
+19
View File
@@ -0,0 +1,19 @@
kernel/dsk_loader.o: kernel\dsk_loader.c include\utsm\dsk.h \
include\utsm\types.h include\utsm\arena.h include\utsm\dkm.h \
include\utsm\dma.h include\utsm\block.h include\utsm\net.h \
include\utsm\paging.h include\utsm\log.h include\utsm\pe.h \
include\utsm\linux_compat.h include\utsm\instr.h \
kernel\..\arch\x86_64\limine.h
include\utsm\dsk.h:
include\utsm\types.h:
include\utsm\arena.h:
include\utsm\dkm.h:
include\utsm\dma.h:
include\utsm\block.h:
include\utsm\net.h:
include\utsm\paging.h:
include\utsm\log.h:
include\utsm\pe.h:
include\utsm\linux_compat.h:
include\utsm\instr.h:
kernel\..\arch\x86_64\limine.h:
Binary file not shown.
+166
View File
@@ -0,0 +1,166 @@
/* INI 分区格式解析器 — freestanding, 无堆分配, 无 libc 依赖 */
#include "ini_parser.h"
/* ---- 内部辅助 ---- */
static int ini_streq(const char *a, const char *b) {
if (!a || !b) return 0;
while (*a && *b) {
if (*a != *b) return 0;
a++; b++;
}
return *a == *b;
}
static int ini_isspace(char c) {
return c == ' ' || c == '\t' || c == '\r';
}
static int ini_isdigit(char c) {
return c >= '0' && c <= '9';
}
static int ini_strncpy(char *dst, const char *src, u32 max) {
u32 i = 0;
while (i + 1 < max && src[i]) {
dst[i] = src[i];
i++;
}
dst[i] = 0;
return (int)i;
}
static int ini_atoi(const char *s) {
int neg = 0, v = 0;
if (!s) return 0;
while (ini_isspace(*s)) s++;
if (*s == '-') { neg = 1; s++; }
while (ini_isdigit(*s)) {
v = v * 10 + (*s - '0');
s++;
}
return neg ? -v : v;
}
static int ini_parse_bool(const char *s) {
if (!s) return -1;
if (s[0] == '1') return 1;
if (s[0] == '0') return 0;
if (ini_streq(s, "true")) return 1;
if (ini_streq(s, "false")) return 0;
if (ini_streq(s, "yes")) return 1;
if (ini_streq(s, "no")) return 0;
return -1;
}
/* ---- 公共接口 ---- */
int ini_parse(const char *text, u32 size, ini_config *cfg) {
if (!text || !cfg) return -1;
cfg->count = 0;
char cur_section[32] = {0}; /* 当前分区名,默认空 */
u32 pos = 0;
while (pos < size) {
/* 跳过行首空白 */
while (pos < size && (text[pos] == ' ' || text[pos] == '\t'))
pos++;
if (pos >= size) break;
char c = text[pos];
/* 空行或换行 */
if (c == '\n') { pos++; continue; }
/* 注释行: # 或 ; 开头 */
if (c == '#' || c == ';') {
while (pos < size && text[pos] != '\n') pos++;
continue;
}
/* 分区头: [section] */
if (c == '[') {
pos++; /* 跳过 '[' */
u32 si = 0;
while (pos < size && text[pos] != ']' && text[pos] != '\n' && si + 1 < 32) {
cur_section[si++] = text[pos++];
}
cur_section[si] = 0;
/* 跳过到行尾 */
while (pos < size && text[pos] != '\n') pos++;
continue;
}
/* key=value 行 */
if (cfg->count >= 64) break; /* 达到上限 */
ini_entry *e = &cfg->entries[cfg->count];
/* 读取 key */
u32 ki = 0;
while (pos < size && text[pos] != '=' && text[pos] != '\n' &&
!ini_isspace(text[pos]) && ki + 1 < 32) {
e->key[ki++] = text[pos++];
}
e->key[ki] = 0;
/* 跳过 key 和 '=' 之间的空白 */
while (pos < size && ini_isspace(text[pos]) && text[pos] != '\n')
pos++;
/* 期望 '=' */
if (pos >= size || text[pos] != '=') {
/* 无效行,跳到行尾 */
while (pos < size && text[pos] != '\n') pos++;
continue;
}
pos++; /* 跳过 '=' */
/* 跳过 '=' 后的空白 */
while (pos < size && ini_isspace(text[pos]) && text[pos] != '\n')
pos++;
/* 读取 value(到行尾,去除尾部空白) */
u32 vi = 0;
while (pos < size && text[pos] != '\n' && vi + 1 < 64) {
e->value[vi++] = text[pos++];
}
/* 去除尾部空白 */
while (vi > 0 && ini_isspace(e->value[vi - 1])) vi--;
e->value[vi] = 0;
/* 复制 section 名 */
ini_strncpy(e->section, cur_section, 32);
cfg->count++;
}
return 0;
}
const char *ini_get(const ini_config *cfg, const char *section, const char *key) {
if (!cfg || !section || !key) return NULL;
for (u32 i = 0; i < cfg->count; i++) {
if (ini_streq(cfg->entries[i].section, section) &&
ini_streq(cfg->entries[i].key, key)) {
return cfg->entries[i].value;
}
}
return NULL;
}
int ini_get_int(const ini_config *cfg, const char *section, const char *key, int defval) {
const char *v = ini_get(cfg, section, key);
if (!v || v[0] == 0) return defval;
return ini_atoi(v);
}
int ini_get_bool(const ini_config *cfg, const char *section, const char *key, int defval) {
const char *v = ini_get(cfg, section, key);
if (!v || v[0] == 0) return defval;
int b = ini_parse_bool(v);
return (b >= 0) ? b : defval;
}
+4
View File
@@ -0,0 +1,4 @@
kernel/ini_parser.o: kernel\ini_parser.c kernel\ini_parser.h \
include\utsm\types.h
kernel\ini_parser.h:
include\utsm\types.h:
+38
View File
@@ -0,0 +1,38 @@
#ifndef UTSM_INI_PARSER_H
#define UTSM_INI_PARSER_H
#include <utsm/types.h>
/* INI 配置条目 */
typedef struct {
char section[32];
char key[32];
char value[64];
} ini_entry;
/* INI 配置集合(栈/静态分配,不依赖堆) */
typedef struct {
ini_entry entries[64]; /* 最多 64 条配置项 */
u32 count;
} ini_config;
/* 解析 INI 文本到 ini_config。
* text: INI 文本起始地址
* size: 文本字节长度
* cfg: 输出配置集合
* 返回 0 成功,负数失败 */
int ini_parse(const char *text, u32 size, ini_config *cfg);
/* 在 section 下查找 key,返回 value 字符串。
* 未找到返回 NULL。 */
const char *ini_get(const ini_config *cfg, const char *section, const char *key);
/* 便捷查询:返回整数值。
* 未找到或格式错误返回 defval。 */
int ini_get_int(const ini_config *cfg, const char *section, const char *key, int defval);
/* 便捷查询:返回布尔值。
* "0"/"false" = 0, "1"/"true" = 1,未找到返回 defval。 */
int ini_get_bool(const ini_config *cfg, const char *section, const char *key, int defval);
#endif /* UTSM_INI_PARSER_H */
+95
View File
@@ -0,0 +1,95 @@
/* instr.c — Deshab 插桩系统初始化与全局配置管理
*
* 从 FUCK [debug] 配置段加载插桩参数,初始化全局配置变量。
* 在 kernel_main() 中调用 instr_init(&g_boot_cfg) 启用。
*/
#include <utsm/instr.h>
#include <utsm/log.h>
#include <utsm/types.h>
#include "ini_parser.h"
/* ---- 全局配置变量(供 instr.h 宏条件判断) ---- */
u32 g_instr_enabled = 0;
u32 g_instr_log_level = INSTR_LOG_INFO;
u32 g_instr_probe_enable = 0;
u32 g_instr_stat_interval = 256;
u32 g_instr_module_flags = 0;
u64 instr_tsc_per_ms = 0;
/* ---- 低级 I/O(TSC 校准用,与 arch/x86_64/io.c 独立避免链接冲突) ---- */
static void instr_outb(u16 port, u8 value) {
__asm__ volatile("outb %0, %1" :: "a"(value), "Nd"(port));
}
static u8 instr_inb(u16 port) {
u8 value;
__asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
/* TSC 读取 */
u64 instr_rdtsc(void) {
u32 lo, hi;
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
return ((u64)hi << 32) | lo;
}
/* TSC 校准:PIT ch0 ~10ms 区间,与 serial.c / dkm_shared.h 相同逻辑 */
static void instr_tsc_calibrate(void) {
instr_outb(0x43, 0x30); /* ch0, lo+hi, mode 0, binary */
instr_outb(0x40, 0x7c); /* 11932 low = ~10ms */
instr_outb(0x40, 0x2e); /* 11932 high */
u64 tsc_start = instr_rdtsc();
u16 prev = 0;
u64 loops = 0;
for (;;) {
instr_outb(0x43, 0x00);
u16 cur = (u16)instr_inb(0x40) | ((u16)instr_inb(0x40) << 8);
if (cur > prev && loops > 10) break;
prev = cur;
loops++;
}
u64 tsc_end = instr_rdtsc();
instr_tsc_per_ms = (tsc_end - tsc_start) / 10;
}
void instr_init(const void *cfg_ptr) {
const ini_config *cfg = (const ini_config *)cfg_ptr;
/* 从 FUCK [debug] 段读取配置 */
g_instr_enabled = (u32)ini_get_bool(cfg, "debug", "enabled", 0);
g_instr_log_level = (u32)ini_get_int(cfg, "debug", "log_level", INSTR_LOG_INFO);
g_instr_probe_enable = (u32)ini_get_bool(cfg, "debug", "probe_enable", 0);
g_instr_stat_interval = (u32)ini_get_int(cfg, "debug", "stat_summary_interval", 256);
/* 模块级过滤标志 */
g_instr_module_flags = 0;
if (ini_get_bool(cfg, "debug", "utsm_trace", 0))
g_instr_module_flags |= INSTR_F_UTSM_TRACE;
if (ini_get_bool(cfg, "debug", "vmm_trace", 0))
g_instr_module_flags |= INSTR_F_VMM_TRACE;
if (ini_get_bool(cfg, "debug", "dkm_trace", 0))
g_instr_module_flags |= INSTR_F_DKM_TRACE;
if (ini_get_bool(cfg, "debug", "dsk_trace", 0))
g_instr_module_flags |= INSTR_F_DSK_TRACE;
if (ini_get_bool(cfg, "debug", "block_trace", 0))
g_instr_module_flags |= INSTR_F_BLOCK_TRACE;
if (ini_get_bool(cfg, "debug", "net_trace", 0))
g_instr_module_flags |= INSTR_F_NET_TRACE;
if (ini_get_bool(cfg, "debug", "input_trace", 0))
g_instr_module_flags |= INSTR_F_INPUT_TRACE;
/* 校准 TSC(独立于 serial.c 的校准,供插桩时间戳使用) */
instr_tsc_calibrate();
/* 初始化探测缓冲 */
probe_init(cfg);
/* 输出初始化状态 */
if (g_instr_enabled) {
log_info("[INSTR] enabled");
log_hex64("[INSTR] log_level=", g_instr_log_level);
log_hex64("[INSTR] probe_enable=", g_instr_probe_enable);
log_hex64("[INSTR] module_flags=", g_instr_module_flags);
log_hex64("[INSTR] tsc_per_ms=", instr_tsc_per_ms);
}
}
+6
View File
@@ -0,0 +1,6 @@
kernel/instr.o: kernel\instr.c include\utsm\instr.h include\utsm\types.h \
include\utsm\log.h kernel\ini_parser.h
include\utsm\instr.h:
include\utsm\types.h:
include\utsm\log.h:
kernel\ini_parser.h:
+3
View File
@@ -0,0 +1,3 @@
kernel/log.o: kernel\log.c include\utsm\log.h include\utsm\types.h
include\utsm\log.h:
include\utsm\types.h:
+267 -51
View File
@@ -9,94 +9,310 @@
#include <utsm/net.h>
#include <utsm/ipc_shm.h>
#include <utsm/linux_compat.h>
#include <utsm/instr.h>
#include "ini_parser.h"
#include "../arch/x86_64/limine.h"
void arch_halt_forever(void);
extern volatile struct limine_module_request g_module_request;
/* dkm/manifest.c: 带 FUCK [drivers] 过滤的 manifest 加载入口 */
void dsm_load_by_manifest_ex(const ini_config *cfg);
/* ---- 运行期配置全局变量(从 FUCK 文件初始化) ---- */
u32 g_utsm_max_segments = UTSM_MAX_SEGMENTS_DEFAULT;
u32 g_utsm_max_capabilities = UTSM_MAX_CAPABILITIES_DEFAULT;
u32 g_utsm_max_pckc_keys = UTSM_MAX_PCKC_KEYS_DEFAULT;
u64 g_utsm_arena_size = UTSM_ARENA_SIZE_DEFAULT;
u64 g_utsm_dirty_shard_pages = UTSM_DIRTY_SHARD_PAGES_DEFAULT;
/* 将 FUCK [utsm] 区的配置应用到运行期全局变量 */
static void utsm_apply_config(const ini_config *cfg) {
if (!cfg) return;
g_utsm_max_segments = (u32)ini_get_int(cfg, "utsm", "max_segments", UTSM_MAX_SEGMENTS_DEFAULT);
g_utsm_max_capabilities = (u32)ini_get_int(cfg, "utsm", "max_capabilities", UTSM_MAX_CAPABILITIES_DEFAULT);
g_utsm_max_pckc_keys = (u32)ini_get_int(cfg, "utsm", "max_pckc_keys", UTSM_MAX_PCKC_KEYS_DEFAULT);
g_utsm_arena_size = (u64)ini_get_int(cfg, "utsm", "arena_size_mb", 16) * 1024 * 1024;
g_utsm_dirty_shard_pages = (u64)ini_get_int(cfg, "utsm", "dirty_shard_pages", UTSM_DIRTY_SHARD_PAGES_DEFAULT);
log_info("[UTSM] FUCK config applied");
log_hex64("[UTSM] max_segments=", g_utsm_max_segments);
log_hex64("[UTSM] max_pckc_keys=", g_utsm_max_pckc_keys);
log_hex64("[UTSM] dirty_shard_pages=", g_utsm_dirty_shard_pages);
}
/* ---- 全局启动配置(从 FUCK 文件读取) ---- */
static ini_config g_boot_cfg;
static int g_boot_cfg_loaded = 0;
/* 从 Limine boot module 读取 FUCK 配置。
* cmdline="fuck:config" 的模块即为 FUCK 配置文件。
* 返回 0 成功,负数失败。 */
static int utsm_load_fuck_config(ini_config *cfg) {
struct limine_module_response *rsp = g_module_request.response;
if (!rsp) return -1;
for (u64 i = 0; i < rsp->module_count; i++) {
struct limine_file *f = rsp->modules[i];
if (f && f->cmdline) {
/* 比较 cmdline 是否为 "fuck:config" */
const char *c = f->cmdline;
const char *tag = "fuck:config";
int match = 1;
for (int j = 0; tag[j]; j++) {
if (c[j] != tag[j]) { match = 0; break; }
}
if (match && c[11] == 0) {
int rc = ini_parse((const char *)f->address, (u32)f->size, cfg);
if (rc == 0) {
log_info("[UTSM] FUCK config loaded from boot module");
return 0;
}
}
}
}
log_warn("[UTSM] FUCK boot module not found");
return -2;
}
void kernel_main(void) {
/* ---- 插桩: 启动总时间戳 ---- */
INSTR_TS_DECL(boot_total);
INSTR_TS_BEGIN(boot_total);
serial_init();
log_info("[UTSM] boot");
/* ==== 真机硬件特征早期检测 (在任何初始化之前) ====
* 检测项目:
* 1. CPU vendor (GenuineIntel / AuthenticAMD / etc.)
* 2. 最大物理地址宽度 (CPUID.80000008H:EAX[7:0])
* 3. LA57 (5-level paging) 是否激活 → 拒绝启动
* 4. CPU 核心数 (CPUID.0BH 或 CPUID.01H)
* 5. PCIe MCFG 可用性 (后续由 ACPI 驱动检测)
*
* **QEMU 无法测试但真机必需的代码路径**:
* - LA57 拒绝: QEMU 默认不启用 5 级分页
* - 物理地址宽度 > 48: 只有大内存真机才有
* - AMD CPU vendor: QEMU 默认 Intel, 实机可能是 AMD
* - 多核: QEMU -smp 可以模拟, 但真机拓扑更复杂
*/
{
/* CPU vendor */
u32 a, b, c, d;
__asm__ volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(0), "c"(0));
char vendor[13];
vendor[0] = (char)(b & 0xff);
vendor[1] = (char)((b >> 8) & 0xff);
vendor[2] = (char)((b >> 16) & 0xff);
vendor[3] = (char)((b >> 24) & 0xff);
vendor[4] = (char)(d & 0xff);
vendor[5] = (char)((d >> 8) & 0xff);
vendor[6] = (char)((d >> 16) & 0xff);
vendor[7] = (char)((d >> 24) & 0xff);
vendor[8] = (char)(c & 0xff);
vendor[9] = (char)((c >> 8) & 0xff);
vendor[10] = (char)((c >> 16) & 0xff);
vendor[11] = (char)((c >> 24) & 0xff);
vendor[12] = 0;
log_info("[UTSM] CPU vendor: ");
log_info(vendor);
/* Max physical address width */
__asm__ volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(0x80000000), "c"(0));
if (a >= 0x80000008) {
__asm__ volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(0x80000008), "c"(0));
u32 phys_bits = a & 0xff;
u32 virt_bits = (a >> 8) & 0xff;
log_hex64("[UTSM] MaxPhysAddr bits=", phys_bits);
log_hex64("[UTSM] MaxVirtAddr bits=", virt_bits);
}
/* LA57 early detection — 在 CR4 读之前先通过 CPUID 检查是否支持 */
__asm__ volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(7), "c"(0));
if (c & (1u << 16)) {
log_warn("[UTSM] CPU supports LA57 (5-level paging)");
/* 检查 CR4 是否实际启用了 LA57 */
u64 cr4;
__asm__ volatile("mov %%cr4, %0" : "=r"(cr4));
if (cr4 & (1ULL << 12)) {
log_error("[UTSM] LA57 is ACTIVE — this kernel requires 4-level paging");
log_error("[UTSM] Refusing to boot. Disable LA57 in firmware settings.");
arch_halt_forever();
}
}
/* CPU core count — CPUID leaf 0BH (Intel Extended Topology) */
__asm__ volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(0), "c"(0));
if (a >= 0x0B) {
/* 尝试 level 0 获取 SMT 核心数 */
u32 level_type = 0, cores = 0;
__asm__ volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(0x0B), "c"(0));
level_type = (c >> 8) & 0xff;
cores = b & 0xffff;
if (level_type == 1 && cores > 0) {
log_hex64("[UTSM] SMT threads=", cores);
}
__asm__ volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(0x0B), "c"(1));
level_type = (c >> 8) & 0xff;
cores = b & 0xffff;
if (level_type == 2 && cores > 0) {
log_hex64("[UTSM] logical processors=", cores);
}
} else {
/* fallback: CPUID.01H EBX[23:16] */
__asm__ volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(1), "c"(0));
u32 lc = (b >> 16) & 0xff;
log_hex64("[UTSM] logical processors (legacy)=", lc);
}
/* ---- 插桩: CPU 检测完成,记录 vendor ---- */
INSTR_PROBE(BOOT, (u64)vendor[0] | ((u64)vendor[1] << 8), 0, 0, 0);
}
/* ---- 插桩: IDT 初始化耗时 ---- */
INSTR_TS_DECL(ts_idt);
INSTR_TS_BEGIN(ts_idt);
idt_init();
INSTR_TS_END(ts_idt, "idt_init");
/* === 读取 FUCK 配置(通过 Limine boot module 预加载) === */
g_boot_cfg_loaded = (utsm_load_fuck_config(&g_boot_cfg) == 0);
ini_config *cfg = g_boot_cfg_loaded ? &g_boot_cfg : NULL;
/* ---- 插桩: FUCK 配置加载完成 ---- */
INSTR_PROBE(BOOT, (u64)g_boot_cfg_loaded, 0, 0, 0);
/* === 初始化插桩系统(在 arena_init 之前,但需要 FUCK 配置) === */
/* 注意: probe_init 需要 arena,所以 instr_init 必须在 arena_init 之后。
* 此处先设置 g_instr_enabled 等全局变量,probe_init 延后到 arena 后。
* 实际上 instr_init 内部会调用 probe_init,而 probe_init 需要 kmem_alloc。
* 所以我们将 instr_init 移到 arena_init 之后。*/
/* === 应用 UTSM 算法参数到运行期全局变量 === */
utsm_apply_config(cfg);
log_info("[UTSM] arena init begin");
INSTR_TS_DECL(ts_arena);
INSTR_TS_BEGIN(ts_arena);
arena_init();
INSTR_TS_END(ts_arena, "arena_init");
log_info("[UTSM] arena init ok");
/* ---- 插桩: arena 就绪后初始化插桩系统(含探测缓冲分配) ---- */
instr_init(cfg);
log_info("[UTSM] dma init begin");
INSTR_TS_DECL(ts_dma);
INSTR_TS_BEGIN(ts_dma);
dma_init();
INSTR_TS_END(ts_dma, "dma_init");
log_info("[UTSM] dma init ok");
log_info("[UTSM] net registry init begin");
INSTR_TS_DECL(ts_net);
INSTR_TS_BEGIN(ts_net);
net_init();
INSTR_TS_END(ts_net, "net_init");
log_info("[UTSM] net registry init ok");
log_info("[UTSM] drr init begin");
INSTR_TS_DECL(ts_drr);
INSTR_TS_BEGIN(ts_drr);
drr_init();
INSTR_TS_END(ts_drr, "drr_init");
log_info("[UTSM] drr init ok");
log_info("[UTSM] core init begin");
INSTR_TS_DECL(ts_utsm);
INSTR_TS_BEGIN(ts_utsm);
utsm_init();
INSTR_TS_END(ts_utsm, "utsm_init");
log_info("[UTSM] init ok");
INSTR_TS_DECL(ts_dkm);
INSTR_TS_BEGIN(ts_dkm);
dkm_init();
dkm_fill_platform_info();
dsm_load_by_manifest();
INSTR_TS_END(ts_dkm, "dkm_init");
int result = utsm_selftest_run();
if (result == 0) {
log_info("[UTSM] SELFTEST PASS");
/* === 驱动加载 — 按 [drivers] 区过滤 === */
INSTR_TS_DECL(ts_dsm);
INSTR_TS_BEGIN(ts_dsm);
dsm_load_by_manifest_ex(cfg);
INSTR_TS_END(ts_dsm, "dsm_load_manifest");
/* Phase 1.1: VMM (VMX/EPT) 初始化 + 自检
* 若 VMX 不可用(如 QEMU 未启用),仅警告,不阻断 DSK 启动 */
if (vmm_init() == 0) {
log_info("[UTSM] VMM init ok");
int vmm_st = vmm_self_test();
if (vmm_st == 0) {
log_info("[UTSM] VMM self-test PASS");
/* Phase 1.2: Linux 加载器 + 启动
* 若 bzImage 模块存在,加载并启动 Linux guest。
* 若无 bzImage,跳过 Linux 启动,继续 DSK 流程。 */
if (linux_loader_init() == 0) {
log_info("[UTSM] Linux loader init ok");
/* Phase 1.3: Initialize IPC shared memory before
* launching Linux. Allocates 1MB, initializes ring
* buffers, and EPT-maps at GPA 0x04000000 so the
* Linux guest can access it via UTSM_HCALL_SHM_INFO. */
if (ipc_shm_init() == 0) {
log_info("[UTSM] IPC shm init ok");
} else {
log_error("[UTSM] IPC shm init failed (non-fatal)");
}
int lin_st = linux_launch();
if (lin_st == 0) {
log_info("[UTSM] Linux guest parked (daemon ready)");
/* Phase 3.2: 初始化 Linux 兼容层服务
* (需在 linux_launch 成功 + guest park 后调用) */
linux_compat_init();
} else {
log_error("[UTSM] Linux launch failed");
log_hex64("[UTSM] Linux st=", (u64)(i64)lin_st);
}
} else {
log_warn("[UTSM] Linux loader unavailable (no bzImage)");
}
} else {
log_error("[UTSM] VMM self-test FAIL");
log_hex64("[UTSM] VMM st=", (u64)(i64)vmm_st);
}
/* === selftest — 可通过 FUCK [boot] selftest=0 跳过 === */
int run_selftest = ini_get_bool(cfg, "boot", "selftest", 1);
if (run_selftest) {
INSTR_TS_DECL(ts_self);
INSTR_TS_BEGIN(ts_self);
int result = utsm_selftest_run();
INSTR_TS_END(ts_self, "selftest");
if (result == 0) {
log_info("[UTSM] SELFTEST PASS");
} else {
log_warn("[UTSM] VMM unavailable (VMX not supported or disabled)");
}
if (dsk_load_and_jump() != 0) {
log_error("[UTSM] DSK jump failed");
log_error("[UTSM] SELFTEST FAIL");
arch_halt_forever();
}
} else {
log_error("[UTSM] SELFTEST FAIL");
log_info("[UTSM] selftest skipped by FUCK config");
}
/* === VMM — 可通过 FUCK [boot] vmm=0 跳过 === */
int run_vmm = ini_get_bool(cfg, "boot", "vmm", 1);
if (run_vmm && vmm_init() == 0) {
INSTR_TS_DECL(ts_vmm);
INSTR_TS_BEGIN(ts_vmm);
log_info("[UTSM] VMM init ok");
int vmm_st = vmm_self_test();
if (vmm_st == 0) {
INSTR_TS_END(ts_vmm, "vmm_init+selftest");
log_info("[UTSM] VMM self-test PASS");
/* === Linux guest — 可通过 FUCK [boot] linux_guest=0 跳过 === */
int run_linux = ini_get_bool(cfg, "boot", "linux_guest", 1);
if (run_linux && linux_loader_init() == 0) {
INSTR_TS_DECL(ts_linux);
INSTR_TS_BEGIN(ts_linux);
log_info("[UTSM] Linux loader init ok");
if (ipc_shm_init() == 0) {
log_info("[UTSM] IPC shm init ok");
} else {
log_error("[UTSM] IPC shm init failed (non-fatal)");
}
int lin_st = linux_launch();
INSTR_TS_END(ts_linux, "linux_launch");
if (lin_st == 0) {
log_info("[UTSM] Linux guest parked (daemon ready)");
linux_compat_init();
} else {
log_error("[UTSM] Linux launch failed");
log_hex64("[UTSM] Linux st=", (u64)(i64)lin_st);
}
} else {
log_warn("[UTSM] Linux loader unavailable (no bzImage or disabled)");
}
} else {
INSTR_TS_END(ts_vmm, "vmm_init+selftest");
log_error("[UTSM] VMM self-test FAIL");
log_hex64("[UTSM] VMM st=", (u64)(i64)vmm_st);
}
} else {
log_warn("[UTSM] VMM unavailable (VMX not supported or disabled by FUCK)");
}
/* ---- 插桩: DSK 加载跳转前记录 ---- */
INSTR_PROBE(DSK0, 0, 0, 0, 0);
if (dsk_load_and_jump() != 0) {
log_error("[UTSM] DSK jump failed");
}
/* ---- 插桩: 启动总耗时(仅在 DSK 跳转失败时可见) ---- */
INSTR_TS_END(boot_total, "boot_total");
arch_halt_forever();
}
+40
View File
@@ -0,0 +1,40 @@
kernel/main.o: kernel\main.c include\utsm\log.h include\utsm\types.h \
include\utsm\arena.h include\utsm\utsm.h include\utsm\status.h \
include\utsm\config.h include\utsm\uuid.h include\utsm\process.h \
include\utsm\capability.h include\utsm\segment.h include\utsm\dirty.h \
include\utsm\utrw.h include\utsm\vmm.h include\utsm\linux_loader.h \
include\utsm\ipc_shm.h ..\utsm-ipc\ipc_proto.h \
include\utsm\hypercall.h include\utsm\drr.h include\utsm\dkm.h \
include\utsm\dma.h include\utsm\block.h include\utsm\net.h \
include\utsm\paging.h include\utsm\idt.h include\utsm\dsk.h \
include\utsm\linux_compat.h include\utsm\instr.h kernel\ini_parser.h \
kernel\..\arch\x86_64\limine.h
include\utsm\log.h:
include\utsm\types.h:
include\utsm\arena.h:
include\utsm\utsm.h:
include\utsm\status.h:
include\utsm\config.h:
include\utsm\uuid.h:
include\utsm\process.h:
include\utsm\capability.h:
include\utsm\segment.h:
include\utsm\dirty.h:
include\utsm\utrw.h:
include\utsm\vmm.h:
include\utsm\linux_loader.h:
include\utsm\ipc_shm.h:
..\utsm-ipc\ipc_proto.h:
include\utsm\hypercall.h:
include\utsm\drr.h:
include\utsm\dkm.h:
include\utsm\dma.h:
include\utsm\block.h:
include\utsm\net.h:
include\utsm\paging.h:
include\utsm\idt.h:
include\utsm\dsk.h:
include\utsm\linux_compat.h:
include\utsm\instr.h:
kernel\ini_parser.h:
kernel\..\arch\x86_64\limine.h:
Binary file not shown.
+16 -2
View File
@@ -52,7 +52,6 @@ static int net_tx_impl(u32 index, const void *packet, u32 length) {
if (index >= g_net_device_count) return -2;
const dkm_net_device_desc *dev = &g_net_devices[index];
if (!dev->tx) return -3;
log_hex64("[NET] tx dispatch fn=", (u64)dev->tx);
return dev->tx(dev->ctx, packet, length);
}
@@ -92,6 +91,20 @@ static int net_is_wireless_impl(u32 index) {
return (dev->flags & DKM_NET_F_WIRELESS) ? 1 : 0;
}
/* 统计查询:返回驱动层累计的收发统计。
* 当前实现为占位:返回全零统计。
* 后续由驱动在 tx/rx 回调内更新共享统计区,此处直接读取。
* 驱动层的本地统计(如 e1000 的 g_stat_tx_ok 等)与 netdev 层统计
* 通过 driver_ctx 统一后即可返回精确值。 */
static int net_device_stats_impl(u32 index, dkm_net_stats *out) {
if (!out) return -1;
if (index >= g_net_device_count) return -2;
/* 占位:全零。后续由驱动填充实际统计。 */
for (u32 i = 0; i < sizeof(dkm_net_stats); i++)
((u8 *)out)[i] = 0;
return 0;
}
static const dkm_net_api g_net_api = {
.register_device = net_register_device_impl,
.device_count = net_device_count_impl,
@@ -101,7 +114,8 @@ static const dkm_net_api g_net_api = {
.scan_start = net_scan_start_impl,
.scan_count = net_scan_count_impl,
.scan_result = net_scan_result_impl,
.is_wireless = net_is_wireless_impl
.is_wireless = net_is_wireless_impl,
.device_stats = net_device_stats_impl
};
const dkm_net_api *net_get_api(void) {
+5
View File
@@ -0,0 +1,5 @@
kernel/net.o: kernel\net.c include\utsm\net.h include\utsm\types.h \
include\utsm\log.h
include\utsm\net.h:
include\utsm\types.h:
include\utsm\log.h:
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
kernel/panic.o: kernel\panic.c include\utsm\log.h include\utsm\types.h
include\utsm\log.h:
include\utsm\types.h:
+111
View File
@@ -0,0 +1,111 @@
/* probe.c — Deshab 环形探测缓冲管理
*
* 结构化事件记录系统:写入环形缓冲,支持事后回溯分析。
* 用于记录关键事件(CPU异常、EPT violation、DMA完成等),
* 通过 shell $probe 命令读取。
*
* 设计要点:
* - 环形缓冲容量由 FUCK debug.probe_capacity 控制(默认 4096 条)
* - 每条记录 40 字节 (tag:4 + tick:4 + args:4*8)
* - 写入时无内存分配,仅 head 指针推进
* - 满时覆盖最旧记录(环形覆盖)
* - 禁用时 probe_write 为空操作
*/
#include <utsm/instr.h>
#include <utsm/log.h>
#include <utsm/types.h>
#include <utsm/arena.h>
#include "ini_parser.h"
/* ---- 探测缓冲状态 ---- */
static probe_entry *g_probe_buf = 0; /* 缓冲基地址(arena 分配) */
static u32 g_probe_cap = 0; /* 缓冲容量(条目数) */
static u32 g_probe_head = 0; /* 下一条写入位置(递增取模) */
static u32 g_probe_count = 0; /* 已写入总条目数 */
static u32 g_probe_dropped = 0; /* 因缓冲满而覆盖的条目数 */
void probe_init(const void *cfg_ptr) {
const ini_config *cfg = (const ini_config *)cfg_ptr;
u32 cap = (u32)ini_get_int(cfg, "debug", "probe_capacity", 4096);
if (cap == 0) {
g_instr_probe_enable = 0;
return;
}
/* 从 arena 分配探测缓冲(对齐到 8 字节) */
u64 size = (u64)cap * sizeof(probe_entry);
g_probe_buf = (probe_entry *)kmem_alloc_aligned(size, 8);
if (!g_probe_buf) {
g_instr_probe_enable = 0;
log_warn("[PROBE] arena alloc failed, probe disabled");
return;
}
g_probe_cap = cap;
g_probe_head = 0;
g_probe_count = 0;
g_probe_dropped = 0;
log_info("[PROBE] init ok, capacity=");
log_hex64("", g_probe_cap);
}
void probe_write(u32 tag, u64 a0, u64 a1, u64 a2, u64 a3) {
if (!g_probe_buf || !g_probe_cap) return;
u32 idx = g_probe_head % g_probe_cap;
/* 环形覆盖:如果 head >= cap,说明有旧记录被覆盖 */
if (g_probe_head >= g_probe_cap && g_probe_dropped == 0) {
/* 仅首次覆盖时计数,避免每条都做减法 */
}
if (g_probe_count >= g_probe_cap) {
g_probe_dropped++;
}
g_probe_buf[idx].tag = tag;
g_probe_buf[idx].tick = (u32)instr_rdtsc();
g_probe_buf[idx].args[0] = a0;
g_probe_buf[idx].args[1] = a1;
g_probe_buf[idx].args[2] = a2;
g_probe_buf[idx].args[3] = a3;
g_probe_head++;
g_probe_count++;
}
int probe_read(u32 n, probe_entry *out) {
if (!g_probe_buf || n == 0) return 0;
u32 avail = (g_probe_count < g_probe_cap) ? g_probe_count : g_probe_cap;
if (n > avail) n = avail;
for (u32 i = 0; i < n; i++) {
u32 src = (g_probe_head - n + i) % g_probe_cap;
out[i] = g_probe_buf[src];
}
return (int)n;
}
u32 probe_count(void) {
return g_probe_count;
}
u32 probe_capacity(void) {
return g_probe_cap;
}
/* ---- 供 dsk_loader 读取内部状态(填充 probe_info) ---- */
probe_entry *probe_buf_address(void) {
return g_probe_buf;
}
u32 probe_head_value(void) {
return g_probe_head;
}
u32 probe_dropped_count(void) {
return g_probe_dropped;
}
+7
View File
@@ -0,0 +1,7 @@
kernel/probe.o: kernel\probe.c include\utsm\instr.h include\utsm\types.h \
include\utsm\log.h include\utsm\arena.h kernel\ini_parser.h
include\utsm\instr.h:
include\utsm\types.h:
include\utsm\log.h:
include\utsm\arena.h:
kernel\ini_parser.h:
+6
View File
@@ -0,0 +1,6 @@
mm/arena.o: mm\arena.c include\utsm\arena.h include\utsm\types.h \
include\utsm\config.h include\utsm\log.h
include\utsm\arena.h:
include\utsm\types.h:
include\utsm\config.h:
include\utsm\log.h:
Binary file not shown.
+4
View File
@@ -96,6 +96,10 @@ void dma_init(void) {
int dma_alloc_pages(u64 page_count, u64 alignment, u64 max_phys, dkm_dma_buffer *out) {
if (!out || page_count == 0 || !g_dma_ready) return -1;
if (page_count > DMA_BITMAP_PAGES) return -3;
/* 真机安全: max_phys 参数上限为低 4G (DMA bitmap 只覆盖低 4G)。
* 调用方若传 0 表示"无限制",按低 4G 上限处理。
* 对 NVMe/AHCI 等需要 32-bit DMA 的设备, max_phys 传 0x100000000。
* 若未来需要 >4G DMA, 需要扩展 bitmap 或使用 IOMMU/SWIOTLB。 */
if (max_phys == 0 || max_phys > DMA_LOW_MAX_PHYS) max_phys = DMA_LOW_MAX_PHYS;
if (alignment < PAGE_SIZE) alignment = PAGE_SIZE;
+6
View File
@@ -0,0 +1,6 @@
mm/dma.o: mm\dma.c include\utsm\dma.h include\utsm\types.h \
include\utsm\log.h mm\..\arch\x86_64\limine.h
include\utsm\dma.h:
include\utsm\types.h:
include\utsm\log.h:
mm\..\arch\x86_64\limine.h:
+241
View File
@@ -0,0 +1,241 @@
#include <utsm/mm.h>
#include <utsm/dma.h>
#include <utsm/log.h>
#include <utsm/types.h>
#include "../arch/x86_64/limine.h"
#define MM_PAGE_SIZE 4096ULL
/* 页表项属性位 */
#define PTE_PRESENT (1ULL << 0)
#define PTE_RW (1ULL << 1)
#define PTE_PWT (1ULL << 3)
#define PTE_PCD (1ULL << 4)
#define PTE_PS (1ULL << 7)
#define PTE_ADDR_MASK 0x000FFFFFFFFFF000ULL
#define PTE_NX (1ULL << 63)
#define CR4_LA57 (1ULL << 12)
#define CR4_PKE (1ULL << 22)
/* MMIO 专用虚拟窗口:运行时在高半部 PML4[256..510] 中扫描空闲槽位,
* 避开 Limine HHDM 区与内核映像(PML4[511],0xFFFFFFFF80000000)。
* 单个 PML4 槽位对应 512GiB 虚拟空间,bump 分配不回收。 */
#define MM_WINDOW_SIZE (1ULL << 39)
extern volatile struct limine_hhdm_request g_hhdm_request;
static u64 g_hhdm;
static u64 g_pml4_phys;
static u64 g_window_base;
static u64 g_window_end;
static u64 g_window_next;
static int g_mm_state; /* 0=未初始化, 1=就绪, -1=不可用 */
static u32 g_max_phys_addr_bits; /* CPUID.80000008H:EAX[7:0], 真机物理地址宽度 */
static inline u64 mm_read_cr3(void) {
u64 v;
__asm__ volatile("mov %%cr3, %0" : "=r"(v));
return v;
}
static inline u64 mm_read_cr4(void) {
u64 v;
__asm__ volatile("mov %%cr4, %0" : "=r"(v));
return v;
}
static inline void mm_cpuid(u32 leaf, u32 *a, u32 *b, u32 *c, u32 *d) {
__asm__ volatile("cpuid" : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d) : "a"(leaf), "c"(0));
}
static inline void mm_invlpg(u64 virt) {
__asm__ volatile("invlpg (%0)" :: "r"(virt) : "memory");
}
/* 在高半部 PML4[256..510] 中找一个空闲槽位作为 MMIO 窗口。
* 返回该槽位覆盖的 canonical 虚拟基址;无空闲槽返回 0。 */
static u64 mm_find_window(void) {
u64 *pml4 = (u64 *)(g_hhdm + g_pml4_phys);
for (u64 idx = 256; idx < 511; idx++) {
if (!(pml4[idx] & PTE_PRESENT)) {
/* bit39..47 为槽位号,bit48 以上符号扩展为全 1 */
return 0xFFFF000000000000ULL | (idx << 39);
}
}
return 0;
}
/* 首次调用时懒初始化:取 HHDM offset 与当前 CR3。
* UTSM 复用 Limine 页表,PML4 经 HHDM 访问。
*
* 真机安全检查:
* 1. LA57 (5-level paging) 拒绝 — 页表 walk 假定 4 级
* 2. CPUID 最大物理地址宽度检测 — 确保映射的物理地址合法
* 3. PML4 槽位扫描 — 确认空闲窗口可用
*/
static void mm_lazy_init(void) {
g_mm_state = -1;
g_max_phys_addr_bits = 0;
if (!g_hhdm_request.response) {
log_warn("[MM] missing HHDM response");
return;
}
g_hhdm = g_hhdm_request.response->offset;
if (!g_hhdm) {
log_warn("[MM] null HHDM offset");
return;
}
/* ---- 真机安全: LA57 早期检测与拒绝 ---- *
* 若固件/BIOS 启用了 5 级分页 (CR4.LA57=1), 本实现的 4 级页表 walk
* 将产生错误的地址转换, 必须拒绝继续运行。
* **QEMU 默认不会启用 LA57, 此路径只在真机触发。** */
if (mm_read_cr4() & CR4_LA57) {
log_error("[MM] LA57 5-level paging ACTIVE — REFUSING to proceed");
log_error("[MM] This kernel requires 4-level paging (48-bit virtual)");
log_error("[MM] Disable LA57 in BIOS/firmware settings");
return;
}
/* ---- 真机安全: 物理地址宽度检测 ---- *
* CPUID leaf 0x80000008 EAX[7:0] 给出 MaxPhysAddr 位宽。
* 典型值: QEMU=40/46, 实机=46/48/52。
* 若物理地址 > 48-bit, 4 级分页的 PTE 地址位可能不够用。
* 当前 PTE_ADDR_MASK 只使用 bit12-51 (40 位物理页号 = 52 位物理地址),
* 支持到 52-bit 物理地址, 足以覆盖所有现有 x86_64 实现。 */
{
u32 a, b, c, d;
mm_cpuid(0x80000000, &a, &b, &c, &d);
if (a >= 0x80000008) {
mm_cpuid(0x80000008, &a, &b, &c, &d);
g_max_phys_addr_bits = a & 0xff;
log_hex64("[MM] CPU MaxPhysAddr bits=", g_max_phys_addr_bits);
if (g_max_phys_addr_bits > 52) {
log_error("[MM] physical address width > 52 bits — PTE cannot represent");
return;
}
} else {
/* 无 80000008H leaf, 假定 36 或 39 位 (旧 CPU) */
g_max_phys_addr_bits = 36;
log_warn("[MM] CPUID 80000008H not available; assuming 36-bit phys");
}
}
g_pml4_phys = mm_read_cr3() & PTE_ADDR_MASK;
g_window_base = mm_find_window();
if (!g_window_base) {
log_error("[MM] no free PML4 slot for mmio window");
return;
}
g_window_end = g_window_base + MM_WINDOW_SIZE;
g_window_next = g_window_base;
g_mm_state = 1;
log_info("[MM] mmio mapper ready");
log_hex64("[MM] PML4 phys=", g_pml4_phys);
log_hex64("[MM] mmio window=", g_window_base);
log_hex64("[MM] MaxPhysAddr bits=", g_max_phys_addr_bits);
}
/* 逐级 walk 到 PT,缺层时从 DMA 页分配器取清零页补层。
* 返回最终 PTE 槽位的 HHDM 虚拟地址;冲突(撞上既有大页)或 OOM 返回 0。 */
static u64 *mm_walk_create(u64 virt) {
u64 *table = (u64 *)(g_hhdm + g_pml4_phys);
/* 中间三级:lvl=3 PML4(shift39) → lvl=2 PDPT(shift30) → lvl=1 PD(shift21) */
for (int lvl = 3; lvl >= 1; lvl--) {
u64 shift = 12 + (u64)lvl * 9;
u64 idx = (virt >> shift) & 0x1FFULL;
u64 entry = table[idx];
if (entry & PTE_PRESENT) {
if (entry & PTE_PS) return 0; /* 既有 1GiB/2MiB 大页占用,冲突 */
table = (u64 *)(g_hhdm + (entry & PTE_ADDR_MASK));
} else {
dkm_dma_buffer buf;
if (dma_alloc_pages(1, MM_PAGE_SIZE, 0, &buf) != 0) {
log_warn("[MM] page table alloc failed");
return 0;
}
table[idx] = buf.phys | PTE_PRESENT | PTE_RW;
table = (u64 *)buf.virt; /* dma 分配已清零 */
}
}
return &table[(virt >> 12) & 0x1FFULL];
}
/* 只查询不创建的 walk;任一级缺失或为大页时返回 0。 */
static u64 *mm_walk_query(u64 virt) {
u64 *table = (u64 *)(g_hhdm + g_pml4_phys);
for (int lvl = 3; lvl >= 1; lvl--) {
u64 shift = 12 + (u64)lvl * 9;
u64 entry = table[(virt >> shift) & 0x1FFULL];
if (!(entry & PTE_PRESENT) || (entry & PTE_PS)) return 0;
table = (u64 *)(g_hhdm + (entry & PTE_ADDR_MASK));
}
return &table[(virt >> 12) & 0x1FFULL];
}
void *mm_map_mmio(u64 phys, u64 size) {
if (g_mm_state == 0) mm_lazy_init();
if (g_mm_state != 1 || !size) return 0;
/* 真机安全: 验证物理地址在 CPU 支持的范围内 */
if (g_max_phys_addr_bits > 0) {
u64 max_phys = (1ULL << g_max_phys_addr_bits) - 1;
if (phys > max_phys) {
log_error("[MM] phys address exceeds CPU MaxPhysAddr");
log_hex64("[MM] phys=", phys);
log_hex64("[MM] max_phys=", max_phys);
return 0;
}
}
u64 off = phys & (MM_PAGE_SIZE - 1ULL);
u64 base_phys = phys - off;
u64 total = (off + size + MM_PAGE_SIZE - 1ULL) & ~(MM_PAGE_SIZE - 1ULL);
u64 pages = total / MM_PAGE_SIZE;
u64 vbase = g_window_next;
if (vbase < g_window_base || vbase + total > g_window_end) {
log_error("[MM] mmio window exhausted");
return 0;
}
u64 mapped = 0;
for (u64 i = 0; i < pages; i++) {
u64 virt = vbase + i * MM_PAGE_SIZE;
u64 *pte = mm_walk_create(virt);
if (!pte || (*pte & PTE_PRESENT)) {
/* 冲突/失败:回滚本次已建立的映射 */
log_error("[MM] map conflict");
for (u64 j = 0; j < mapped; j++) {
u64 v = vbase + j * MM_PAGE_SIZE;
u64 *p = mm_walk_query(v);
if (p) { *p = 0; mm_invlpg(v); }
}
return 0;
}
*pte = (base_phys + i * MM_PAGE_SIZE) | PTE_PRESENT | PTE_RW | PTE_PCD | PTE_PWT;
mm_invlpg(virt);
mapped++;
}
g_window_next = vbase + total;
log_hex64("[MM] map phys=", base_phys);
log_hex64("[MM] map virt=", vbase);
log_hex64("[MM] map pages=", pages);
return (void *)(vbase + off);
}
void mm_unmap_mmio(void *virt, u64 size) {
if (g_mm_state != 1 || !virt || !size) return;
u64 v = (u64)virt & ~(MM_PAGE_SIZE - 1ULL);
u64 end = ((u64)virt + size + MM_PAGE_SIZE - 1ULL) & ~(MM_PAGE_SIZE - 1ULL);
for (; v < end; v += MM_PAGE_SIZE) {
u64 *pte = mm_walk_query(v);
if (pte && (*pte & PTE_PRESENT)) {
*pte = 0;
mm_invlpg(v);
}
}
/* 窗口 bump 指针与中间页表页不回收:映射开销极小,保留复用 */
}
+7
View File
@@ -0,0 +1,7 @@
mm/mmio.o: mm\mmio.c include\utsm\mm.h include\utsm\types.h \
include\utsm\dma.h include\utsm\log.h mm\..\arch\x86_64\limine.h
include\utsm\mm.h:
include\utsm\types.h:
include\utsm\dma.h:
include\utsm\log.h:
mm\..\arch\x86_64\limine.h:
+140
View File
@@ -0,0 +1,140 @@
/*
* UTSM 页表/MMIO 映射服务实现
*
* 算法说明:
* - is_mapped: 标准 x86_64 四级页表 walk,O(1)(固定 4 级),
* 页表页均为 RAM,经 HHDM 直映射访问,全程不触发 #PF。
* - map_mmio: 对 [phys, phys+size) 逐 4K 页在 HHDM 空间 (hhdm+phys)
* 补建 P|RW|PCD|PWT 映射。若中间级已存在则复用;若整页已被
* Limine 大页覆盖则跳过(is_mapped 先行判定)。页表页由
* dma_alloc_pages 提供(低 4G、4K 对齐、返回即清零)。
* - not-present 项不会被 TLB 缓存,新映射无需 invlpg;
* 仍对每页执行 invlpg 作为防御性措施(成本可忽略)。
*/
#include <utsm/paging.h>
#include <utsm/dma.h>
#include <utsm/log.h>
#include "../arch/x86_64/limine.h"
extern volatile struct limine_hhdm_request g_hhdm_request;
#define PTE_PRESENT (1ULL << 0)
#define PTE_RW (1ULL << 1)
#define PTE_PWT (1ULL << 3) /* MMIO: write-through */
#define PTE_PCD (1ULL << 4) /* MMIO: cache disable */
#define PTE_PS (1ULL << 7) /* 1G/2M 大页标志 */
#define PTE_ADDR_MASK 0x000FFFFFFFFFF000ULL
#define PAGE_4K 4096ULL
static u64 paging_hhdm(void) {
return g_hhdm_request.response ? g_hhdm_request.response->offset : 0;
}
static u64 paging_read_cr3(void) {
u64 v;
__asm__ volatile("mov %%cr3, %0" : "=r"(v));
return v & PTE_ADDR_MASK;
}
/* 返回 0=未映射;1=4K PTE;2=2M PDE;3=1G PDPTE */
static int paging_is_mapped_impl(u64 vaddr) {
u64 hhdm = paging_hhdm();
if (!hhdm) return 0;
u64 *pml4 = (u64 *)(paging_read_cr3() + hhdm);
u64 pml4e = pml4[(vaddr >> 39) & 0x1FF];
if (!(pml4e & PTE_PRESENT)) return 0;
u64 *pdpt = (u64 *)((pml4e & PTE_ADDR_MASK) + hhdm);
u64 pdpte = pdpt[(vaddr >> 30) & 0x1FF];
if (!(pdpte & PTE_PRESENT)) return 0;
if (pdpte & PTE_PS) return 3;
u64 *pd = (u64 *)((pdpte & PTE_ADDR_MASK) + hhdm);
u64 pde = pd[(vaddr >> 21) & 0x1FF];
if (!(pde & PTE_PRESENT)) return 0;
if (pde & PTE_PS) return 2;
u64 *pt = (u64 *)((pde & PTE_ADDR_MASK) + hhdm);
u64 pte = pt[(vaddr >> 12) & 0x1FF];
if (!(pte & PTE_PRESENT)) return 0;
return 1;
}
/* 分配一个清零的 4K 页作为页表页,返回物理地址;失败返回 0 */
static u64 paging_alloc_table(void) {
dkm_dma_buffer buf;
if (dma_alloc_pages(1, PAGE_4K, 0, &buf) != 0) return 0;
return buf.phys;
}
static int paging_map_mmio_impl(u64 phys, u64 size) {
u64 hhdm = paging_hhdm();
if (!hhdm || !size) return -1;
u64 begin = phys & ~(PAGE_4K - 1ULL);
u64 end = (phys + size + PAGE_4K - 1ULL) & ~(PAGE_4K - 1ULL);
u64 mapped = 0;
u64 skipped = 0;
for (u64 p = begin; p < end; p += PAGE_4K) {
u64 v = hhdm + p;
if (paging_is_mapped_impl(v)) {
skipped++; /* Limine 已覆盖(含 1G/2M 大页) */
continue;
}
u64 *pml4 = (u64 *)(paging_read_cr3() + hhdm);
u64 idx4 = (v >> 39) & 0x1FF;
if (!(pml4[idx4] & PTE_PRESENT)) {
u64 t = paging_alloc_table();
if (!t) { log_error("[PAGING] alloc PDPT failed"); return -2; }
pml4[idx4] = t | PTE_PRESENT | PTE_RW;
}
u64 *pdpt = (u64 *)((pml4[idx4] & PTE_ADDR_MASK) + hhdm);
u64 idx3 = (v >> 30) & 0x1FF;
if (pdpt[idx3] & PTE_PRESENT) {
if (pdpt[idx3] & PTE_PS) { skipped++; continue; } /* 1G 大页已覆盖 */
} else {
u64 t = paging_alloc_table();
if (!t) { log_error("[PAGING] alloc PD failed"); return -3; }
pdpt[idx3] = t | PTE_PRESENT | PTE_RW;
}
u64 *pd = (u64 *)((pdpt[idx3] & PTE_ADDR_MASK) + hhdm);
u64 idx2 = (v >> 21) & 0x1FF;
if (pd[idx2] & PTE_PRESENT) {
if (pd[idx2] & PTE_PS) { skipped++; continue; } /* 2M 大页已覆盖 */
} else {
u64 t = paging_alloc_table();
if (!t) { log_error("[PAGING] alloc PT failed"); return -4; }
pd[idx2] = t | PTE_PRESENT | PTE_RW;
}
u64 *pt = (u64 *)((pd[idx2] & PTE_ADDR_MASK) + hhdm);
u64 idx1 = (v >> 12) & 0x1FF;
pt[idx1] = p | PTE_PRESENT | PTE_RW | PTE_PCD | PTE_PWT;
__asm__ volatile("invlpg (%0)" :: "r"(v) : "memory");
mapped++;
}
log_info("[PAGING] map_mmio done");
log_hex64("[PAGING] phys=", phys);
log_hex64("[PAGING] size=", size);
log_hex64("[PAGING] 4K pages mapped=", mapped);
log_hex64("[PAGING] pages already covered=", skipped);
return 0;
}
static const dkm_mmio_api g_mmio_api = {
.is_mapped = paging_is_mapped_impl,
.map_mmio = paging_map_mmio_impl,
.cr3 = paging_read_cr3
};
const dkm_mmio_api *paging_get_api(void) {
return &g_mmio_api;
}
+7
View File
@@ -0,0 +1,7 @@
mm/paging.o: mm\paging.c include\utsm\paging.h include\utsm\types.h \
include\utsm\dma.h include\utsm\log.h mm\..\arch\x86_64\limine.h
include\utsm\paging.h:
include\utsm\types.h:
include\utsm\dma.h:
include\utsm\log.h:
mm\..\arch\x86_64\limine.h:
+13
View File
@@ -0,0 +1,13 @@
pckc/pckc.o: pckc\pckc.c include\utsm\pckc.h include\utsm\types.h \
include\utsm\config.h include\utsm\uuid.h include\utsm\crypto.h \
include\utsm\segment.h include\utsm\status.h include\utsm\capability.h \
include\utsm\dirty.h
include\utsm\pckc.h:
include\utsm\types.h:
include\utsm\config.h:
include\utsm\uuid.h:
include\utsm\crypto.h:
include\utsm\segment.h:
include\utsm\status.h:
include\utsm\capability.h:
include\utsm\dirty.h:
+11
View File
@@ -0,0 +1,11 @@
pe/pe_loader.o: pe\pe_loader.c pe\pe_loader.h include\utsm\types.h \
include\utsm\pe.h pe\pe_shim.h pe\x86emu32.h pe\..\include\utsm\pe.h \
include\utsm\arena.h include\utsm\log.h
pe\pe_loader.h:
include\utsm\types.h:
include\utsm\pe.h:
pe\pe_shim.h:
pe\x86emu32.h:
pe\..\include\utsm\pe.h:
include\utsm\arena.h:
include\utsm\log.h:
+79 -21
View File
@@ -1,15 +1,15 @@
/* pe_service.c — PE 兼容层服务装配。
/* pe_service.c — PE 兼容层服务装配.
*
* 将 pe_loader + pe_shim + x86emu32 整合为统一的 pe_service,
* 通过 pe_get_service() 暴露给 DSK/cmd.elf(经 dsk_boot_context.reserved[4])。
* 将 pe_loader + pe_shim + x86emu32 整合为统一的 pe_service,
* 通过 pe_get_service() 暴露给 DSK/cmd.elf(经 dsk_boot_context.reserved[4]).
*
* 执行策略:
* PE32+ (64位):pe_load_image 加载(actual_base 重定位),
* IAT 填 ms_abi shim 函数地址,Ring0 原生执行入口。
* ExitProcess 经 __builtin_longjmp 跳回 pe_service_run。
* PE32 (32位):直接以 preferred_base 加载到一块含栈/堆的大缓冲区,
* 无需重定位。IAT 填合成地址(0x00010000 | shim_idx),
* x86emu32 解释执行,CALL 合成地址时拦截分发到 shim32。
* 执行策略:
* PE32+ (64位):pe_load_image 加载(actual_base 重定位),
* IAT 填 ms_abi shim 函数地址,Ring0 原生执行入口.
* ExitProcess 经 __builtin_longjmp 跳回 pe_service_run.
* PE32 (32位):直接以 preferred_base 加载到一块含栈/堆的大缓冲区,
* 无需重定位.IAT 填合成地址(0x00010000 | shim_idx),
* x86emu32 解释执行,CALL 合成地址时拦截分发到 shim32.
*/
#include "pe_loader.h"
@@ -25,11 +25,11 @@
#define PE32_HEAP_SIZE (256 * 1024) /* 256KB 堆 */
#define PE32_MAX_IAT 256
/* 合成 shim 地址范围(与 pe_loader.c 一致) */
/* 合成 shim 地址范围(与 pe_loader.c 一致) */
#define PE32_SHIM_ADDR_BASE 0x00010000u
#define PE32_SHIM_UNIMPL 0x0001FFFFu
/* 前向声明(服务表引用) */
/* 前向声明(服务表引用) */
int pe_service_load(const void *pe_data, u64 size, pe_image_info *out);
int pe_service_run(const void *pe_data, u64 size, const char *cmdline, u64 *exit_code);
void pe_service_unload(pe_image_info *info);
@@ -46,7 +46,7 @@ const pe_service *pe_get_service(void) {
return &g_pe_service;
}
/* ===== 加载(不执行)===== */
/* ===== 加载(不执行)===== */
int pe_service_load(const void *pe_data, u64 size, pe_image_info *out) {
if (!pe_data || !out) return -1;
return pe_load_image(pe_data, size, out);
@@ -56,7 +56,7 @@ void pe_service_unload(pe_image_info *info) {
pe_unload_image(info);
}
/* ===== PE32 专用加载器(加载到指定缓冲区,base=preferred_base,无重定位)===== */
/* ===== PE32 专用加载器(加载到指定缓冲区,base=preferred_base,无重定位)===== */
typedef struct {
u8 *mem; /* 大缓冲区起始 */
u32 mem_size; /* 缓冲区总大小 */
@@ -93,7 +93,7 @@ static int pe32_load_into(const void *pe_data, u64 size, pe32_interp_image *img)
const image_section_header *sections = (const image_section_header *)
((const u8 *)opt + fh->size_of_optional_header);
/* 分配大缓冲区:[0 .. preferred_base + image_size + stack + heap] */
/* 分配大缓冲区:[0 .. preferred_base + image_size + stack + heap] */
u32 total = preferred_base + image_size + PE32_STACK_SIZE + PE32_HEAP_SIZE;
u8 *mem = (u8 *)kmem_alloc_aligned((u64)total, 0x1000);
if (!mem) return -9;
@@ -118,11 +118,11 @@ static int pe32_load_into(const void *pe_data, u64 size, pe32_interp_image *img)
for (u32 j = 0; j < copy_size; j++) img_start[va + j] = base[raw_off + j];
}
/* 解析 imports,填充 IAT(合成地址) */
/* 解析 imports,填充 IAT(合成地址) */
img->iat_count = 0;
const image_data_directory *import_dir = &oh->data_directory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if (import_dir->virtual_address != 0 && import_dir->size != 0) {
/* RVA→offset 辅助 */
/* RVA->offset 辅助 */
for (int dll_idx = 0; ; dll_idx++) {
u32 imp_rva = import_dir->virtual_address + (u32)dll_idx * sizeof(image_import_descriptor);
/* imp_rva 在 image 内 */
@@ -198,12 +198,61 @@ static int pe32_load_into(const void *pe_data, u64 size, pe32_interp_image *img)
return 0;
}
/* ===== SSE/SSE2 启用 =====
* UTSM 自身用 -mno-sse -msoft-float 编译(启动早期安全),但 PE32+ 原生
* 代码(MSVC/LLVM x86_64 ABI)假定 SSE2 可用——浮点参数走 XMM0-3,
* egui 的 f32/f64 运算也全部编译为 SSE 指令.跳转 PE 入口前必须:
* CR0.EM=0, CR0.TS=0, CR0.MP=1, CR0.NE=1
* CR4.OSFXSR=1, CR4.OSXMMEXCPT=1
* MXCSR=0x1F80(屏蔽全部异常、round-to-nearest,Windows 默认)
* 内核 C 代码不带 SSE 指令,开启后对内核自身无副作用. */
static void pe_enable_sse(void) {
u64 cr0, cr4;
__asm__ volatile("mov %%cr0, %0" : "=r"(cr0));
cr0 &= ~((1ULL << 2) | (1ULL << 3)); /* EM=0, TS=0 */
cr0 |= (1ULL << 1) | (1ULL << 5); /* MP=1, NE=1 */
__asm__ volatile("mov %0, %%cr0" :: "r"(cr0));
__asm__ volatile("mov %%cr4, %0" : "=r"(cr4));
cr4 |= (1ULL << 9) | (1ULL << 10); /* OSFXSR=1, OSXMMEXCPT=1 */
__asm__ volatile("mov %0, %%cr4" :: "r"(cr4));
__asm__ volatile("fninit");
{
u32 mxcsr = 0x1F80;
__asm__ volatile("ldmxcsr %0" :: "m"(mxcsr));
}
log_info("[PE] SSE/SSE2 enabled for native PE32+ execution");
}
/* ===== PE 专用大栈 =====
* 调用链 UTSM->DSK->cmd->pe_service 全部运行在 16KB 内核栈上,
* Rust/egui 渲染(tessellate + 软光栅)栈需求远超 16KB,
* 因此跳转 PE 入口前切换到 arena 分配的 1MB 独立栈.
* 正常 ret 时由 trampoline 恢复旧 RSP;ExitProcess longjmp 路径
* 由 setjmp 时保存的内核 RSP 恢复,两条路径都安全. */
#define PE_STACK_BYTES (1024ULL * 1024ULL)
static u64 g_pe_saved_rsp;
typedef void (*pe_entry_fn)(void);
static void pe_call_on_stack(pe_entry_fn fn, u64 stack_top) {
__asm__ volatile(
"mov %%rsp, %0\n\t"
"mov %1, %%rsp\n\t"
"call *%2\n\t"
"mov %0, %%rsp\n\t"
: "=m"(g_pe_saved_rsp)
: "r"(stack_top), "r"(fn)
: "memory", "cc",
"rax", "rcx", "rdx", "rsi", "rdi",
"r8", "r9", "r10", "r11");
}
/* ===== 运行 =====
* 加载 + 执行 + 卸载。返回 0 成功,*exit_code 为进程退出码。 */
* 加载 + 执行 + 卸载.返回 0 成功,*exit_code 为进程退出码. */
int pe_service_run(const void *pe_data, u64 size, const char *cmdline, u64 *exit_code) {
if (!pe_data || size == 0) return -1;
/* 初始化 shim 状态(cmdline for GetCommandLineA) */
/* 初始化 shim 状态(cmdline for GetCommandLineA) */
pe_shim_init(cmdline ? cmdline : "");
/* 先解析 PE 判断 32/64 位 */
@@ -224,14 +273,23 @@ int pe_service_run(const void *pe_data, u64 size, const char *cmdline, u64 *exit
return -5;
}
log_info("[PE] running PE32+ natively");
pe_enable_sse();
/* 独立 1MB 栈(内核栈仅 16KB,egui 渲染会溢出) */
u8 *pe_stack = (u8 *)kmem_alloc_aligned(PE_STACK_BYTES, 4096);
if (!pe_stack) {
log_error("[PE] stack alloc failed");
return -9;
}
u64 stack_top = (u64)pe_stack + PE_STACK_BYTES; /* 4096 对齐 -> 16 对齐 */
u64 code = 0;
int jumped = pe_shim_setup_exit();
if (jumped == 0) {
typedef void (*pe_entry_fn)(void);
pe_entry_fn entry = (pe_entry_fn)info.entry_point;
log_hex64("[PE] entry=", (u64)entry);
entry();
log_hex64("[PE] stack_top=", stack_top);
pe_call_on_stack(entry, stack_top);
code = 0;
} else {
code = pe_shim_get_exit_code();
+11
View File
@@ -0,0 +1,11 @@
pe/pe_service.o: pe\pe_service.c pe\pe_loader.h include\utsm\types.h \
include\utsm\pe.h pe\pe_shim.h pe\x86emu32.h pe\..\include\utsm\pe.h \
include\utsm\arena.h include\utsm\log.h
pe\pe_loader.h:
include\utsm\types.h:
include\utsm\pe.h:
pe\pe_shim.h:
pe\x86emu32.h:
pe\..\include\utsm\pe.h:
include\utsm\arena.h:
include\utsm\log.h:
+1004 -30
View File
@@ -1,22 +1,45 @@
/* pe_shim.c — Windows API shim 实现。
/* pe_shim.c — Windows API shim 实现.
*
* 所有 64位 shim 用 __attribute__((ms_abi)) 声明,匹配 PE32+ 调用约定。
* 32位 shim 从模拟栈读参数,供 x86emu32 解释器调用。
* 所有 64位 shim 用 __attribute__((ms_abi)) 声明,匹配 PE32+ 调用约定.
* 32位 shim 从模拟栈读参数,供 x86emu32 解释器调用.
*
* 支持 API:kernel32.dll(GetStdHandle/WriteFile/ReadFile/ExitProcess/
* HeapAlloc/HeapFree/VirtualAlloc/VirtualFree/GetCommandLineA/...)
* msvcrt.dll(printf/puts/putchar/malloc/free/exit/memcpy/memset/
* strlen/strcmp/strcpy/_initterm/_initterm_e)
* 支持 API:
* kernel32.dll 控制台、文件、堆、模块、编码转换、QPC、Sleep、同步、卸载桩
* msvcrt.dll printf、puts、malloc、free、mem 系列、str 系列、_initterm
* ntdll.dll NtWriteFile、RtlNtStatusToDosError
* bcryptprimitives.dll ProcessPrng (rdtsc xorshift)
* api-ms-win-core-synch-l1-2-0.dll WaitOnAddress、WakeByAddress (futex 桩)
* user32.dll 窗口类、窗口、消息泵 (PS/2 键盘轮询)、DefWindowProc
* gdi32.dll 内存 DC、DIBSection、BitBlt 到 Limine 帧缓冲
*
* 窗口模型:单顶层窗口 (固定伪句柄),GetDC 返回窗口 DC,
* BitBlt(窗口 DC, ...) 把 DIB 后台缓冲按窗口原点拷入帧缓冲.
* 消息泵:PeekMessageW 轮询 PS/2 键盘 (0x64/0x60),生成
* WM_KEYDOWN、WM_KEYUP、WM_CHAR;Esc 额外合成 WM_CLOSE (无鼠标环境的
* 唯一退出途径).鼠标字节 (状态位 0x20) 直接丢弃.
*/
#include "pe_shim.h"
#include <utsm/arena.h>
#include <utsm/log.h>
#include <utsm/types.h>
#include "../arch/x86_64/limine.h"
/* arch/x86_64/io.c */
extern void outb(u16 port, u8 value);
extern u8 inb(u16 port);
/* dkm/boot_modules.c — Limine framebuffer 请求(GDI BitBlt 目标) */
extern volatile struct limine_framebuffer_request g_fb_request;
/* 前向声明:shim 用户态堆(实现见下文"用户态堆"一节) */
static void *shim_heap_alloc(u64 size);
static void shim_heap_free(void *ptr);
static void *shim_heap_realloc(void *ptr, u64 size);
/* setjmp/longjmp for ExitProcess — 使用 __builtin_setjmp/__builtin_longjmp
* (clang/gcc 内置,freestanding 可用,无需 libc)。
* __builtin_setjmp 接受 void** 缓冲区,至少需要 8 个指针槽。 */
* (clang/gcc 内置,freestanding 可用,无需 libc).
* __builtin_setjmp 接受 void** 缓冲区,至少需要 8 个指针槽. */
static void *g_exit_jmp[24];
static int g_exit_jmp_set;
static u64 g_exit_code;
@@ -28,7 +51,7 @@ void pe_shim_init(const char *cmdline) {
g_exit_code = 0;
}
/* pe_run 调用:保存上下文,返回 0 = 首次(继续执行),1 = ExitProcess 触发 */
/* pe_run 调用:保存上下文,返回 0 = 首次(继续执行),1 = ExitProcess 触发 */
int pe_shim_setup_exit(void) {
g_exit_jmp_set = 1;
return __builtin_setjmp(g_exit_jmp);
@@ -39,7 +62,7 @@ void pe_shim_exit_process(u64 exit_code) {
if (g_exit_jmp_set) {
__builtin_longjmp(g_exit_jmp, 1);
}
/* 无 jmpbuf:直接返回 */
/* 无 jmpbuf:直接返回 */
}
int pe_shim_is_exit_call(u64 target) {
@@ -57,7 +80,7 @@ u64 pe_shim_unimpl_stub(void) {
return pe_shim_unimpl64_addr();
}
/* ===== 串口/帧缓冲输出(shim 内部复用) ===== */
/* ===== 串口/帧缓冲输出(shim 内部复用) ===== */
static void shim_output(const char *s, u64 len) {
for (u64 i = 0; i < len; i++) {
serial_putc(s[i]);
@@ -70,6 +93,9 @@ static void shim_output_str(const char *s) {
/* ===== kernel32.dll shims (64位, ms_abi) ===== */
/* 线程本地 last-error(简化全局) */
static u64 g_last_error = 0;
/* 句柄定义 */
#define STD_INPUT_HANDLE ((u64)0xFFFFFFF6)
#define STD_OUTPUT_HANDLE ((u64)0xFFFFFFF5)
@@ -91,7 +117,8 @@ static u64 __attribute__((ms_abi)) shim_WriteFile(u64 handle, u64 buffer, u64 le
if (handle == SHIM_STDOUT_HANDLE || handle == SHIM_STDERR_HANDLE) {
const char *buf = (const char *)buffer;
shim_output(buf, length);
if (bytes_written_ptr) *(u64 *)bytes_written_ptr = length;
/* lpNumberOfBytesWritten 是 DWORD*(4 字节),不能按 u64 写 */
if (bytes_written_ptr) *(u32 *)bytes_written_ptr = (u32)length;
return 1; /* TRUE */
}
return 0;
@@ -115,23 +142,36 @@ static u64 __attribute__((ms_abi)) shim_GetCommandLineA(void) {
}
static u64 __attribute__((ms_abi)) shim_GetCommandLineW(void) {
return (u64)g_cmdline; /* 简化:返回 ASCII */
return (u64)g_cmdline; /* 简化:返回 ASCII */
}
static u64 __attribute__((ms_abi)) shim_GetLastError(void) { return 0; }
static u64 __attribute__((ms_abi)) shim_SetLastError(u64 code) { (void)code; return 0; }
static u64 __attribute__((ms_abi)) shim_GetLastError(void) { return g_last_error; }
static u64 __attribute__((ms_abi)) shim_SetLastError(u64 code) { g_last_error = code; return 0; }
static u64 __attribute__((ms_abi)) shim_HeapCreate(u64 fl, u64 init, u64 max) {
(void)fl; (void)init; (void)max;
return 0x10000010; /* 假堆句柄 */
}
static u64 __attribute__((ms_abi)) shim_HeapAlloc(u64 heap, u64 flags, u64 size) {
(void)heap; (void)flags;
return (u64)kmem_alloc(size);
(void)heap;
void *p = shim_heap_alloc(size);
if (p && (flags & 8)) { /* HEAP_ZERO_MEMORY */
u8 *z = (u8 *)p;
for (u64 i = 0; i < size; i++) z[i] = 0;
}
return (u64)p;
}
static u64 __attribute__((ms_abi)) shim_HeapFree(u64 heap, u64 flags, u64 ptr) {
(void)heap; (void)flags; (void)ptr;
return 1; /* arena 无 free,返回 TRUE */
(void)heap; (void)flags;
shim_heap_free((void *)ptr);
return 1;
}
static u64 __attribute__((ms_abi)) shim_HeapReAlloc(u64 heap, u64 flags, u64 ptr, u64 size) {
(void)heap; (void)flags;
return (u64)shim_heap_realloc((void *)ptr, size);
}
static u64 __attribute__((ms_abi)) shim_GetProcessHeap(void) {
return 0x10000010;
}
static u64 __attribute__((ms_abi)) shim_VirtualAlloc(u64 addr, u64 size, u64 alloc_type, u64 protect) {
(void)addr; (void)alloc_type; (void)protect;
@@ -172,10 +212,10 @@ static void shim_msvcrt_output(const char *s) {
shim_output_str(s);
}
/* printf — 简化版,只支持 %s %d %c %x %u %% */
/* printf — 简化版,只支持 %s %d %c %x %u %% */
static u64 __attribute__((ms_abi)) shim_printf(u64 fmt, u64 a1, u64 a2, u64 a3) {
/* 可变参数:MS x64 ABI 下 a1-a3 在 RDX/R8/R9,更多参数在栈上。
* 简化处理:只处理前 3 个参数。 */
/* 可变参数:MS x64 ABI 下 a1-a3 在 RDX/R8/R9,更多参数在栈上.
* 简化处理:只处理前 3 个参数. */
const char *f = (const char *)fmt;
u64 args[3] = {a1, a2, a3};
int argi = 0;
@@ -244,17 +284,17 @@ static u64 __attribute__((ms_abi)) shim_putchar(u64 ch) {
}
static u64 __attribute__((ms_abi)) shim_malloc(u64 size) {
return (u64)kmem_alloc(size);
return (u64)shim_heap_alloc(size);
}
static u64 __attribute__((ms_abi)) shim_calloc(u64 count, u64 size) {
u64 total = count * size;
u8 *p = kmem_alloc(total);
u8 *p = shim_heap_alloc(total);
if (p) for (u64 i = 0; i < total; i++) p[i] = 0;
return (u64)p;
}
static u64 __attribute__((ms_abi)) shim_free(u64 ptr) { (void)ptr; return 0; }
static u64 __attribute__((ms_abi)) shim_free(u64 ptr) { shim_heap_free((void *)ptr); return 0; }
static u64 __attribute__((ms_abi)) shim_realloc(u64 ptr, u64 size) {
(void)ptr; return (u64)kmem_alloc(size);
return (u64)shim_heap_realloc((void *)ptr, size);
}
static u64 __attribute__((ms_abi)) shim_exit(u64 code) {
pe_shim_exit_process(code);
@@ -316,8 +356,8 @@ static u64 __attribute__((ms_abi)) shim_fputc(u64 ch, u64 stream) {
serial_putc((char)(ch & 0xFF));
return ch & 0xFF;
}
/* _initterm / _initterm_e — CRT 初始化,遍历函数指针表调用。
* 简化:直接跳过(返回 0)。 */
/* _initterm / _initterm_e — CRT 初始化,遍历函数指针表调用.
* 简化:直接跳过(返回 0). */
static u64 __attribute__((ms_abi)) shim_initterm(u64 start, u64 end) {
(void)start; (void)end;
return 0;
@@ -327,10 +367,866 @@ static u64 __attribute__((ms_abi)) shim_initterm_e(u64 start, u64 end) {
return 0;
}
/* 未实现 stub(64位)— 日志告警并返回 0 */
/* ============================================================
* 用户态堆(free-list,支持真正 free/realloc)
*
* Rust std 的 GlobalAlloc 走 GetProcessHeap/HeapAlloc/HeapReAlloc/
* HeapFree.arena 只增不减,GUI 主循环每帧的 Vec 分配会耗尽内存,
* 因此 shim 从 arena carve 一块 8MB 区域自行管理:
* 32B 块头 {size,used,next_free,pad},首次适应 + 分割 + 前向合并.
* ========================================================== */
#define SHIM_HEAP_BYTES (8ULL * 1024ULL * 1024ULL)
#define HEAP_HDR 32
typedef struct heap_blk {
u64 size; /* 数据区字节数(不含头) */
u64 used; /* 1=已分配 */
u64 next_free; /* 空闲链表(heap_blk*,0=尾) */
u64 pad;
} heap_blk;
static u8 *g_heap_region;
static heap_blk *g_heap_free_head;
static void shim_heap_init_once(void) {
if (g_heap_region) return;
g_heap_region = (u8 *)kmem_alloc_aligned(SHIM_HEAP_BYTES, 16);
if (!g_heap_region) {
log_error("[shim] heap region alloc failed");
return;
}
heap_blk *b = (heap_blk *)g_heap_region;
b->size = SHIM_HEAP_BYTES - HEAP_HDR;
b->used = 0;
b->next_free = 0;
b->pad = 0;
g_heap_free_head = b;
}
static void *shim_heap_alloc(u64 size) {
shim_heap_init_once();
if (!g_heap_region) return 0;
if (size == 0) size = 16;
size = (size + 15) & ~15ULL;
heap_blk *prev = 0, *b = g_heap_free_head;
while (b) {
if (b->size >= size) {
if (prev) prev->next_free = b->next_free;
else g_heap_free_head = (heap_blk *)b->next_free;
/* 剩余足够再分一块则分割 */
if (b->size >= size + HEAP_HDR + 16) {
heap_blk *nb = (heap_blk *)((u8 *)b + HEAP_HDR + size);
nb->size = b->size - size - HEAP_HDR;
nb->used = 0;
nb->pad = 0;
nb->next_free = (u64)g_heap_free_head;
g_heap_free_head = nb;
b->size = size;
}
b->used = 1;
b->next_free = 0;
return (u8 *)b + HEAP_HDR;
}
prev = b;
b = (heap_blk *)b->next_free;
}
log_error("[shim] heap OOM");
log_hex64("[shim] heap req=", size);
return 0;
}
static void shim_heap_free(void *ptr) {
if (!ptr) return;
heap_blk *b = (heap_blk *)((u8 *)ptr - HEAP_HDR);
b->used = 0;
/* 前向合并:物理下一块若空闲则吸收 */
heap_blk *nb = (heap_blk *)((u8 *)b + HEAP_HDR + b->size);
if ((u8 *)nb >= g_heap_region && (u8 *)nb < g_heap_region + SHIM_HEAP_BYTES
&& !nb->used && nb->size) {
/* 从空闲链摘除 nb */
heap_blk *prev = 0, *x = g_heap_free_head;
while (x && x != nb) { prev = x; x = (heap_blk *)x->next_free; }
if (x == nb) {
if (prev) prev->next_free = nb->next_free;
else g_heap_free_head = (heap_blk *)nb->next_free;
b->size += HEAP_HDR + nb->size;
}
}
b->next_free = (u64)g_heap_free_head;
g_heap_free_head = b;
}
static void *shim_heap_realloc(void *ptr, u64 size) {
if (!ptr) return shim_heap_alloc(size);
heap_blk *b = (heap_blk *)((u8 *)ptr - HEAP_HDR);
u64 old = b->size;
if (size <= old) return ptr;
u8 *np = (u8 *)shim_heap_alloc(size);
if (!np) return 0;
const u8 *s = (const u8 *)ptr;
for (u64 i = 0; i < old; i++) np[i] = s[i];
shim_heap_free(ptr);
return np;
}
/* ============================================================
* TSC 计时(QueryPerformanceCounter/Frequency、GetTickCount、Sleep)
* PIT channel 0 一次性校准(与 cmd.elf 同款手法).
* ========================================================== */
static __inline__ u64 shim_rdtsc(void) {
u32 lo, hi;
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
return ((u64)hi << 32) | lo;
}
static u64 g_tsc_per_ms = 0;
static void shim_tsc_init(void) {
if (g_tsc_per_ms) return;
outb(0x43, 0x30);
outb(0x40, 0x7c);
outb(0x40, 0x2e);
u64 t0 = shim_rdtsc();
u16 prev = 0; u64 loops = 0;
for (;;) {
outb(0x43, 0x00);
u16 cur = (u16)inb(0x40) | ((u16)inb(0x40) << 8);
if (cur > prev && loops > 10) break;
prev = cur; loops++;
}
u64 t1 = shim_rdtsc();
g_tsc_per_ms = (t1 - t0) / 10;
if (!g_tsc_per_ms) g_tsc_per_ms = 1000000; /* 兜底 1GHz */
}
static u64 __attribute__((ms_abi)) shim_QueryPerformanceFrequency(u64 freq_ptr) {
shim_tsc_init();
if (freq_ptr) *(u64 *)freq_ptr = g_tsc_per_ms * 1000;
return 1;
}
static u64 __attribute__((ms_abi)) shim_QueryPerformanceCounter(u64 count_ptr) {
shim_tsc_init();
if (count_ptr) *(u64 *)count_ptr = shim_rdtsc();
return 1;
}
static u64 __attribute__((ms_abi)) shim_GetTickCount(void) {
shim_tsc_init();
return shim_rdtsc() / g_tsc_per_ms;
}
static u64 __attribute__((ms_abi)) shim_Sleep(u64 ms) {
shim_tsc_init();
u64 end = shim_rdtsc() + ms * g_tsc_per_ms;
while (shim_rdtsc() < end) __asm__ volatile("pause");
return 0;
}
/* SYSTEM_INFO(x64,48 字节) */
static u64 __attribute__((ms_abi)) shim_GetSystemInfo(u64 si_p) {
if (!si_p) return 0;
u8 *p = (u8 *)si_p;
for (int i = 0; i < 48; i++) p[i] = 0;
*(u32 *)(p + 0) = 9; /* PROCESSOR_ARCHITECTURE_AMD64 */
*(u32 *)(p + 4) = 4096; /* dwPageSize */
*(u32 *)(p + 20) = 1; /* dwNumberOfProcessors */
return 0;
}
/* ============================================================
* kernel32 增量:控制台/目录/环境/进程/同步/Rtl/编码转换
* ========================================================== */
static u64 __attribute__((ms_abi)) shim_GetConsoleMode(u64 handle, u64 mode_ptr) {
(void)handle; (void)mode_ptr;
g_last_error = 6; /* ERROR_INVALID_HANDLE -> std 回退 WriteFile */
return 0;
}
static u64 __attribute__((ms_abi)) shim_GetConsoleOutputCP(void) { return 65001; }
static u64 __attribute__((ms_abi)) shim_WriteConsoleW(u64 handle, u64 buf, u64 nchars,
u64 written_ptr, u64 reserved) {
(void)reserved;
if (handle != SHIM_STDOUT_HANDLE && handle != SHIM_STDERR_HANDLE) return 0;
const u16 *s = (const u16 *)buf;
for (u64 i = 0; i < nchars; i++) {
u32 c = s[i];
if (c < 0x80) {
serial_putc((char)c);
} else if (c < 0x800) {
serial_putc((char)(0xC0 | (c >> 6)));
serial_putc((char)(0x80 | (c & 0x3F)));
} else {
serial_putc((char)(0xE0 | (c >> 12)));
serial_putc((char)(0x80 | ((c >> 6) & 0x3F)));
serial_putc((char)(0x80 | (c & 0x3F)));
}
}
if (written_ptr) *(u32 *)written_ptr = (u32)nchars;
return 1;
}
static u64 __attribute__((ms_abi)) shim_GetCurrentDirectoryW(u64 buflen, u64 buf) {
static const u16 cwd[] = { 'C', ':', '\\', 0 };
if (!buf || buflen < 4) return 4; /* 需要 4 个字符(含 NUL) */
u16 *out = (u16 *)buf;
for (int i = 0; i < 4; i++) out[i] = cwd[i];
return 3; /* 不含 NUL 的字符数 */
}
static u64 __attribute__((ms_abi)) shim_GetEnvironmentVariableW(u64 name, u64 buf, u64 size) {
(void)name; (void)buf; (void)size;
g_last_error = 203; /* ERROR_ENVVAR_NOT_FOUND */
return 0;
}
static u64 __attribute__((ms_abi)) shim_GetCurrentProcess(void) { return (u64)-1; }
static u64 __attribute__((ms_abi)) shim_GetCurrentProcessId(void) { return 1; }
static u64 __attribute__((ms_abi)) shim_GetCurrentThreadId(void) { return 1; }
static u64 __attribute__((ms_abi)) shim_CreateMutexA(u64 sa, u64 initial, u64 name) {
(void)sa; (void)initial; (void)name;
return 0x10000030;
}
static u64 __attribute__((ms_abi)) shim_ReleaseMutex(u64 h) { (void)h; return 1; }
static u64 __attribute__((ms_abi)) shim_WaitForSingleObject(u64 h, u64 ms) {
(void)h; (void)ms; return 0; /* WAIT_OBJECT_0 */
}
static u64 __attribute__((ms_abi)) shim_WaitForSingleObjectEx(u64 h, u64 ms, u64 alert) {
(void)h; (void)ms; (void)alert; return 0;
}
static u64 __attribute__((ms_abi)) shim_FormatMessageW(u64 flags, u64 src, u64 msgid,
u64 lang, u64 buf, u64 size, u64 args) {
(void)flags; (void)src; (void)msgid; (void)lang; (void)buf; (void)size; (void)args;
return 0;
}
static u64 __attribute__((ms_abi)) shim_LoadLibraryA(u64 name_p) {
if (!name_p) return 0;
const char *n = (const char *)name_p;
/* 已知 DLL 返回伪句柄(大小写不敏感子串匹配) */
static const char *known[] = { "kernel32", "ntdll", "user32", "gdi32", "msvcrt" };
for (int k = 0; k < 5; k++) {
const char *pat = known[k];
for (const char *p = n; *p; p++) {
int i = 0;
while (pat[i] && p[i]) {
char a = p[i], b = pat[i];
if (a >= 'A' && a <= 'Z') a += 32;
if (a != b) break;
i++;
}
if (pat[i] == 0) return 0x10000020;
}
}
g_last_error = 126; /* ERROR_MOD_NOT_FOUND */
return 0;
}
static u64 __attribute__((ms_abi)) shim_lstrlenW(u64 str_p) {
const u16 *s = (const u16 *)str_p;
u64 n = 0;
if (s) while (s[n]) n++;
return n;
}
/* GetProcAddress — 在 shim 表内按函数名全局查找(hModule 为伪句柄,不限定 DLL).
* lpProcName 高 16 位为 0 时是 ordinal(不支持,返回 0)。
* Rust std 用它动态探测 Rtl 系列/dbghelp API,命中返回真实 shim 地址,miss 返回 0。 */
static u64 __attribute__((ms_abi)) shim_GetProcAddress(u64 module, u64 name_p) {
(void)module;
if (!name_p) return 0;
if ((name_p >> 16) == 0) { /* ordinal 导入 */
g_last_error = 127; /* ERROR_PROC_NOT_FOUND */
return 0;
}
const char *name = (const char *)name_p;
int n = pe_shim_count();
for (int i = 0; i < n; i++) {
const pe_shim_entry *e = pe_shim_get(i);
if (!e || !e->func || !e->fn64) continue;
const char *a = e->func, *b = name;
while (*a && *b && *a == *b) { a++; b++; }
if (*a == *b) return (u64)e->fn64;
}
log_info("[shim] GetProcAddress miss");
serial_write(" -> ");
serial_write(name);
serial_write("\n");
g_last_error = 127;
return 0;
}
/* Rtl* — Rust panic/unwind 机制引用(panic=abort 下不会真正走到) */
static u64 __attribute__((ms_abi)) shim_RtlCaptureContext(u64 ctx_p) {
u8 *p = (u8 *)ctx_p;
if (p) for (int i = 0; i < 1232; i++) p[i] = 0; /* x64 CONTEXT ≈ 1232B */
return 0;
}
static u64 __attribute__((ms_abi)) shim_RtlLookupFunctionEntry(u64 rip, u64 base_p, u64 table_p) {
(void)rip;
if (base_p) *(u64 *)base_p = 0;
if (table_p) *(u64 *)table_p = 0;
return 0;
}
static u64 __attribute__((ms_abi)) shim_RtlVirtualUnwind(u64 a, u64 b, u64 c, u64 d,
u64 e, u64 f, u64 g, u64 h, u64 i2) {
(void)a; (void)b; (void)c; (void)d; (void)e; (void)f; (void)g; (void)h; (void)i2;
return 0;
}
/* ---- MultiByteToWideChar / WideCharToMultiByte(CP_UTF8 + Latin-1)---- */
static u64 __attribute__((ms_abi)) shim_MultiByteToWideChar(u64 cp, u64 flags, u64 mbs_p,
u64 cbmb, u64 wbuf_p, u64 cchw) {
(void)flags;
const u8 *s = (const u8 *)mbs_p;
u16 *out = (u16 *)wbuf_p;
i64 remain = (i64)cbmb; /* -1 = NUL 结尾 */
u64 need = 0;
if (!s) return 0;
for (;;) {
if (remain == 0) break;
u8 b0 = s[0];
if (b0 == 0) {
if (remain < 0) { /* -1 模式把 NUL 计入 */
if (out && cchw > need) out[need] = 0;
need++;
}
break;
}
u32 cp32; u64 adv;
if (cp == 65001 && b0 >= 0xC2 && b0 < 0xE0 && (remain < 0 || remain >= 2)
&& (s[1] & 0xC0) == 0x80) {
cp32 = ((u32)(b0 & 0x1F) << 6) | (s[1] & 0x3F); adv = 2;
} else if (cp == 65001 && b0 >= 0xE0 && b0 < 0xF0 && (remain < 0 || remain >= 3)
&& (s[1] & 0xC0) == 0x80 && (s[2] & 0xC0) == 0x80) {
cp32 = ((u32)(b0 & 0x0F) << 12) | ((u32)(s[1] & 0x3F) << 6) | (s[2] & 0x3F); adv = 3;
} else if (cp == 65001 && b0 >= 0xF0 && b0 < 0xF5 && (remain < 0 || remain >= 4)
&& (s[1] & 0xC0) == 0x80 && (s[2] & 0xC0) == 0x80 && (s[3] & 0xC0) == 0x80) {
cp32 = ((u32)(b0 & 0x07) << 18) | ((u32)(s[1] & 0x3F) << 12)
| ((u32)(s[2] & 0x3F) << 6) | (s[3] & 0x3F); adv = 4;
} else {
cp32 = b0; adv = 1; /* Latin-1 / 非法序列按字节 */
}
if (cp32 > 0xFFFF) {
if (out && cchw > need + 1) {
cp32 -= 0x10000;
out[need] = (u16)(0xD800 + (cp32 >> 10));
out[need + 1] = (u16)(0xDC00 + (cp32 & 0x3FF));
}
need += 2;
} else {
if (out && cchw > need) out[need] = (u16)cp32;
need++;
}
s += adv;
if (remain > 0) remain -= (i64)adv;
}
return need;
}
static u64 __attribute__((ms_abi)) shim_WideCharToMultiByte(u64 cp, u64 flags, u64 ws_p,
u64 cchw, u64 mbs_p, u64 cbmb,
u64 defc, u64 used_p) {
(void)flags; (void)defc;
const u16 *s = (const u16 *)ws_p;
u8 *out = (u8 *)mbs_p;
i64 remain = (i64)cchw; /* -1 = NUL 结尾 */
u64 need = 0;
if (used_p) *(u32 *)used_p = 0;
if (!s) return 0;
for (;;) {
if (remain == 0) break;
u16 w = s[0];
if (w == 0) {
if (remain < 0) {
if (out && cbmb > need) out[need] = 0;
need++;
}
break;
}
u32 cp32 = w; u64 adv = 1;
if (w >= 0xD800 && w < 0xDC00 && (remain < 0 || remain >= 2)
&& s[1] >= 0xDC00 && s[1] < 0xE000) {
cp32 = 0x10000 + (((u32)(w - 0xD800) << 10) | (s[1] - 0xDC00));
adv = 2;
}
u8 enc[4]; u64 elen;
if (cp == 65001) {
if (cp32 < 0x80) { enc[0] = (u8)cp32; elen = 1; }
else if (cp32 < 0x800) {
enc[0] = (u8)(0xC0 | (cp32 >> 6)); enc[1] = (u8)(0x80 | (cp32 & 0x3F)); elen = 2;
} else if (cp32 < 0x10000) {
enc[0] = (u8)(0xE0 | (cp32 >> 12)); enc[1] = (u8)(0x80 | ((cp32 >> 6) & 0x3F));
enc[2] = (u8)(0x80 | (cp32 & 0x3F)); elen = 3;
} else {
enc[0] = (u8)(0xF0 | (cp32 >> 18)); enc[1] = (u8)(0x80 | ((cp32 >> 12) & 0x3F));
enc[2] = (u8)(0x80 | ((cp32 >> 6) & 0x3F)); enc[3] = (u8)(0x80 | (cp32 & 0x3F));
elen = 4;
}
} else {
enc[0] = (u8)(cp32 < 256 ? cp32 : '?'); elen = 1;
}
if (out) for (u64 i = 0; i < elen; i++) { if (cbmb > need + i) out[need + i] = enc[i]; }
need += elen;
s += adv;
if (remain > 0) remain -= (i64)adv;
}
return need;
}
/* ============================================================
* ntdll.dll / bcryptprimitives.dll / api-ms-win-core-synch
* ========================================================== */
static u64 __attribute__((ms_abi)) shim_NtWriteFile(u64 fh, u64 ev, u64 apc_r, u64 apc_c,
u64 iosb, u64 buf, u64 len,
u64 off, u64 key) {
(void)ev; (void)apc_r; (void)apc_c; (void)off; (void)key;
if (fh == SHIM_STDOUT_HANDLE || fh == SHIM_STDERR_HANDLE) {
shim_output((const char *)buf, len);
}
if (iosb) { /* IO_STATUS_BLOCK: {NTSTATUS Status; ULONG_PTR Information} */
((u64 *)iosb)[0] = 0;
((u64 *)iosb)[1] = len;
}
return 0; /* STATUS_SUCCESS */
}
static u64 __attribute__((ms_abi)) shim_RtlNtStatusToDosError(u64 status) {
return status & 0xFFFFFFFF;
}
static u64 __attribute__((ms_abi)) shim_ProcessPrng(u64 buf, u64 len) {
u64 s = shim_rdtsc() ^ 0x9E3779B97F4A7C15ULL;
u8 *p = (u8 *)buf;
for (u64 i = 0; i < len; i++) {
s ^= s << 13; s ^= s >> 7; s ^= s << 17; /* xorshift64 */
p[i] = (u8)(s & 0xFF);
}
return 1;
}
/* WaitOnAddress 允许虚假唤醒(调用者自旋重检),立即返回 TRUE 合法 */
static u64 __attribute__((ms_abi)) shim_WaitOnAddress(u64 addr, u64 expected, u64 size, u64 timeout) {
(void)addr; (void)expected; (void)size; (void)timeout;
return 1;
}
static u64 __attribute__((ms_abi)) shim_WakeByAddress(u64 addr) { (void)addr; return 0; }
/* ============================================================
* user32.dll — 单窗口 + 消息泵(PS/2 键盘轮询)
* ========================================================== */
#define SHIM_HWND 0x20000001ULL
#define SHIM_HDC_WND 0x20000002ULL
#define SHIM_HCURSOR 0x20000003ULL
#define SHIM_WM_CLOSE 0x0010u
#define SHIM_WM_QUIT 0x0012u
#define SHIM_WM_KEYDOWN 0x0100u
#define SHIM_WM_KEYUP 0x0101u
#define SHIM_WM_CHAR 0x0102u
static u64 g_wnd_proc = 0;
static int g_wnd_created = 0;
static i32 g_wnd_x = 0, g_wnd_y = 0, g_wnd_w = 0, g_wnd_h = 0;
/* MSG 布局与 PE 侧 #[repr(C)] MSG 一致(48 字节) */
typedef struct {
u64 hwnd;
u32 message; u32 pad0;
u64 wparam;
u64 lparam;
u32 time; u32 pad1;
i32 ptx, pty;
} shim_msg_t;
#define SHIM_MSGQ_CAP 64
static shim_msg_t g_msgq[SHIM_MSGQ_CAP];
static int g_mq_head = 0, g_mq_count = 0;
static void shim_msg_push(u32 msg, u64 w, u64 l) {
if (g_mq_count >= SHIM_MSGQ_CAP) return; /* 满则丢弃 */
int idx = (g_mq_head + g_mq_count) % SHIM_MSGQ_CAP;
g_msgq[idx].hwnd = SHIM_HWND;
g_msgq[idx].message = msg;
g_msgq[idx].pad0 = 0;
g_msgq[idx].wparam = w;
g_msgq[idx].lparam = l;
g_msgq[idx].time = 0;
g_msgq[idx].pad1 = 0;
g_msgq[idx].ptx = 0;
g_msgq[idx].pty = 0;
g_mq_count++;
}
/* PS/2 键盘状态 */
static int s_kbd_shift = 0, s_kbd_ctrl = 0, s_kbd_alt = 0, s_kbd_e0 = 0;
static char shim_scan_ascii(u8 sc, int shift) {
static const char normal[58] = {
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=', 8, '\t',
'q','w','e','r','t','y','u','i','o','p','[',']','\n',0,
'a','s','d','f','g','h','j','k','l',';','\'', '`',0,'\\',
'z','x','c','v','b','n','m',',','.','/',0,'*',0,' '
};
static const char shifted[58] = {
0, 27, '!','@','#','$','%','^','&','*','(',')','_','+', 8, '\t',
'Q','W','E','R','T','Y','U','I','O','P','{','}','\n',0,
'A','S','D','F','G','H','J','K','L',':','"','~',0,'|',
'Z','X','C','V','B','N','M','<','>','?',0,'*',0,' '
};
if (sc >= 58) return 0;
return shift ? shifted[sc] : normal[sc];
}
/* scan code set 1 -> Win32 VK */
static u32 shim_scan_vk(u8 sc, int e0) {
if (e0) {
switch (sc) {
case 0x4B: return 0x25; /* VK_LEFT */
case 0x48: return 0x26; /* VK_UP */
case 0x4D: return 0x27; /* VK_RIGHT */
case 0x50: return 0x28; /* VK_DOWN */
case 0x53: return 0x2E; /* VK_DELETE */
case 0x1D: return 0x11; /* VK_CONTROL(右) */
case 0x38: return 0x12; /* VK_MENU(右) */
default: return 0;
}
}
if (sc >= 0x10 && sc <= 0x19) return 'Q' + (sc - 0x10);
if (sc >= 0x1E && sc <= 0x26) return 'A' + (sc - 0x1E);
if (sc >= 0x2C && sc <= 0x32) return 'Z' + (sc - 0x2C);
if (sc >= 0x02 && sc <= 0x0A) return '1' + (sc - 0x02);
if (sc == 0x0B) return '0';
switch (sc) {
case 0x1C: return 0x0D; /* VK_RETURN */
case 0x0E: return 0x08; /* VK_BACK */
case 0x39: return 0x20; /* VK_SPACE */
case 0x01: return 0x1B; /* VK_ESCAPE */
case 0x0F: return 0x09; /* VK_TAB */
case 0x2A: case 0x36: return 0x10; /* VK_SHIFT */
case 0x1D: return 0x11; /* VK_CONTROL */
case 0x38: return 0x12; /* VK_MENU */
default: return 0;
}
}
/* 排空 PS/2 输出缓冲,转成 Win32 消息入队 */
static void shim_kbd_poll(void) {
for (;;) {
u8 st = inb(0x64);
if (!(st & 1)) break;
u8 sc = inb(0x60);
if (st & 0x20) continue; /* 鼠标字节丢弃 */
if (sc == 0xE0) { s_kbd_e0 = 1; continue; }
int e0 = s_kbd_e0;
if (!e0) {
if (sc == 0x2A || sc == 0x36) { s_kbd_shift = 1; shim_msg_push(SHIM_WM_KEYDOWN, 0x10, sc); continue; }
if (sc == 0xAA || sc == 0xB6) { s_kbd_shift = 0; shim_msg_push(SHIM_WM_KEYUP, 0x10, sc); continue; }
if (sc == 0x1D) { s_kbd_ctrl = 1; shim_msg_push(SHIM_WM_KEYDOWN, 0x11, sc); continue; }
if (sc == 0x9D) { s_kbd_ctrl = 0; shim_msg_push(SHIM_WM_KEYUP, 0x11, sc); continue; }
if (sc == 0x38) { s_kbd_alt = 1; shim_msg_push(SHIM_WM_KEYDOWN, 0x12, sc); continue; }
if (sc == 0xB8) { s_kbd_alt = 0; shim_msg_push(SHIM_WM_KEYUP, 0x12, sc); continue; }
}
s_kbd_e0 = 0;
if (sc & 0x80) {
u32 vk = shim_scan_vk(sc & 0x7F, e0);
if (vk) shim_msg_push(SHIM_WM_KEYUP, vk, sc);
continue;
}
u32 vk = shim_scan_vk(sc, e0);
if (vk) {
shim_msg_push(SHIM_WM_KEYDOWN, vk, sc);
/* Esc -> 额外合成 WM_CLOSE:无鼠标环境下关闭窗口的唯一途径 */
if (vk == 0x1B && !e0) shim_msg_push(SHIM_WM_CLOSE, 0, 0);
}
if (!e0) {
char c = shim_scan_ascii(sc, s_kbd_shift);
if (c >= ' ' && c < 0x7F) shim_msg_push(SHIM_WM_CHAR, (u64)(u8)c, sc);
}
}
}
static u64 __attribute__((ms_abi)) shim_RegisterClassExW(u64 wc_p) {
if (!wc_p) return 0;
g_wnd_proc = *(u64 *)(wc_p + 8); /* cbSize(4)+style(4) -> lpfnWndProc */
log_info("[shim] RegisterClassExW ok");
return 0xC000;
}
static const struct limine_framebuffer *shim_fb(void) {
if (!g_fb_request.response || g_fb_request.response->framebuffer_count == 0) return 0;
return g_fb_request.response->framebuffers[0];
}
static u64 __attribute__((ms_abi)) shim_CreateWindowExW(
u64 exstyle, u64 class_name, u64 wnd_name, u64 style,
u64 x, u64 y, u64 w, u64 h,
u64 parent, u64 menu, u64 hinst, u64 param) {
(void)exstyle; (void)class_name; (void)wnd_name; (void)style;
(void)parent; (void)menu; (void)hinst; (void)param;
i32 ix = (i32)(u32)x, iy = (i32)(u32)y;
i32 iw = (i32)(u32)w, ih = (i32)(u32)h;
if (iw <= 0) iw = 800;
if (ih <= 0) ih = 600;
const struct limine_framebuffer *fb = shim_fb();
i32 fw = fb ? (i32)fb->width : 0;
i32 fh = fb ? (i32)fb->height : 0;
if (fw && iw > fw) iw = fw;
if (fh && ih > fh) ih = fh;
/* CW_USEDEFAULT(0x80000000) -> 居中 */
if (ix == (i32)0x80000000 || ix < 0) ix = fw ? (fw - iw) / 2 : 0;
if (iy == (i32)0x80000000 || iy < 0) iy = fh ? (fh - ih) / 2 : 0;
g_wnd_x = ix; g_wnd_y = iy; g_wnd_w = iw; g_wnd_h = ih;
g_wnd_created = 1;
log_info("[shim] CreateWindowExW ok");
log_hex64("[shim] wnd x=", (u64)(i64)ix);
log_hex64("[shim] wnd y=", (u64)(i64)iy);
log_hex64("[shim] wnd w=", (u64)(i64)iw);
log_hex64("[shim] wnd h=", (u64)(i64)ih);
return SHIM_HWND;
}
static u64 __attribute__((ms_abi)) shim_ShowWindow(u64 hwnd, u64 cmd) {
(void)hwnd; (void)cmd; return 1;
}
static u64 __attribute__((ms_abi)) shim_UpdateWindow(u64 hwnd) {
(void)hwnd; return 1;
}
static u64 __attribute__((ms_abi)) shim_DestroyWindow(u64 hwnd) {
(void)hwnd; g_wnd_created = 0; return 1;
}
static u64 __attribute__((ms_abi)) shim_LoadCursorW(u64 hinst, u64 name) {
(void)hinst; (void)name; return SHIM_HCURSOR;
}
static u64 __attribute__((ms_abi)) shim_SetCursor(u64 cur) {
(void)cur; return SHIM_HCURSOR;
}
static u64 __attribute__((ms_abi)) shim_GetCursorPos(u64 pt_p) {
if (pt_p) { ((i32 *)pt_p)[0] = g_wnd_w / 2; ((i32 *)pt_p)[1] = g_wnd_h / 2; }
return 1;
}
static u64 __attribute__((ms_abi)) shim_ScreenToClient(u64 hwnd, u64 pt_p) {
(void)hwnd; (void)pt_p; return 1; /* 窗口即全屏坐标系,无需转换 */
}
static u64 __attribute__((ms_abi)) shim_GetAsyncKeyState(u64 vk) {
(void)vk; return 0; /* 修饰键状态已由消息流维护 */
}
static u64 __attribute__((ms_abi)) shim_SetTimer(u64 hwnd, u64 id, u64 elapse, u64 cb) {
(void)hwnd; (void)elapse; (void)cb; return id ? id : 1;
}
static u64 __attribute__((ms_abi)) shim_KillTimer(u64 hwnd, u64 id) {
(void)hwnd; (void)id; return 1;
}
static u64 __attribute__((ms_abi)) shim_MessageBeep(u64 t) { (void)t; return 1; }
static u64 __attribute__((ms_abi)) shim_GetClientRect(u64 hwnd, u64 rect_p) {
(void)hwnd;
if (!rect_p) return 0;
i32 *r = (i32 *)rect_p;
r[0] = 0; r[1] = 0; r[2] = g_wnd_w; r[3] = g_wnd_h;
return 1;
}
static u64 __attribute__((ms_abi)) shim_InvalidateRect(u64 hwnd, u64 rect_p, u64 erase) {
(void)hwnd; (void)rect_p; (void)erase; return 1; /* 主循环每帧全量重绘 */
}
/* PAINTSTRUCT: {hdc(8), fErase(4), rcPaint(16), fRestore(4), fIncUpdate(4), rgb(32)} */
static u64 __attribute__((ms_abi)) shim_BeginPaint(u64 hwnd, u64 ps_p) {
(void)hwnd;
if (!ps_p) return 0;
u8 *p = (u8 *)ps_p;
for (int i = 0; i < 72; i++) p[i] = 0;
*(u64 *)p = SHIM_HDC_WND;
return SHIM_HDC_WND;
}
static u64 __attribute__((ms_abi)) shim_EndPaint(u64 hwnd, u64 ps_p) {
(void)hwnd; (void)ps_p; return 1;
}
static u64 __attribute__((ms_abi)) shim_ReleaseDC(u64 hwnd, u64 hdc) {
(void)hwnd; (void)hdc; return 1;
}
static u64 __attribute__((ms_abi)) shim_GetSystemMetrics(u64 idx) {
const struct limine_framebuffer *fb = shim_fb();
if (!fb) return 0;
if (idx == 0) return fb->width; /* SM_CXSCREEN */
if (idx == 1) return fb->height; /* SM_CYSCREEN */
return 0;
}
static u64 __attribute__((ms_abi)) shim_DefWindowProcW(u64 hwnd, u64 msg, u64 w, u64 l) {
(void)hwnd; (void)msg; (void)w; (void)l; return 0;
}
static u64 __attribute__((ms_abi)) shim_TranslateMessage(u64 msg_p) {
(void)msg_p; return 0; /* WM_CHAR 已在键盘轮询时合成 */
}
static u64 __attribute__((ms_abi)) shim_PeekMessageW(u64 msg_p, u64 hwnd,
u64 fmin, u64 fmax, u64 remove) {
(void)hwnd; (void)fmin; (void)fmax;
shim_kbd_poll();
if (g_mq_count == 0) return 0;
shim_msg_t *m = &g_msgq[g_mq_head];
if (msg_p) *(shim_msg_t *)msg_p = *m;
if (remove & 1) { /* PM_REMOVE */
g_mq_head = (g_mq_head + 1) % SHIM_MSGQ_CAP;
g_mq_count--;
}
return 1;
}
static u64 __attribute__((ms_abi)) shim_GetMessageW(u64 msg_p, u64 hwnd,
u64 fmin, u64 fmax) {
(void)hwnd; (void)fmin; (void)fmax;
for (;;) { /* 阻塞语义:轮询键盘直到有消息 */
shim_kbd_poll();
if (g_mq_count > 0) break;
__asm__ volatile("pause");
}
shim_msg_t *m = &g_msgq[g_mq_head];
if (msg_p) *(shim_msg_t *)msg_p = *m;
g_mq_head = (g_mq_head + 1) % SHIM_MSGQ_CAP;
g_mq_count--;
return (m->message == SHIM_WM_QUIT) ? 0 : 1;
}
static u64 __attribute__((ms_abi)) shim_PostQuitMessage(u64 exit_code) {
shim_msg_push(SHIM_WM_QUIT, exit_code, 0);
return 0;
}
typedef u64 (__attribute__((ms_abi)) *shim_wndproc_t)(u64, u64, u64, u64);
static u64 __attribute__((ms_abi)) shim_DispatchMessageW(u64 msg_p) {
if (!msg_p || !g_wnd_proc) return 0;
const shim_msg_t *m = (const shim_msg_t *)msg_p;
return ((shim_wndproc_t)g_wnd_proc)(m->hwnd, m->message, m->wparam, m->lparam);
}
/* ============================================================
* gdi32.dll — 内存 DC / DIBSection / BitBlt -> 帧缓冲
* ========================================================== */
typedef struct { u64 bmp; } shim_dc_t; /* 当前选中位图(0=无) */
typedef struct { i32 w, h; u32 *bits; } shim_bmp_t; /* 32bpp 0xAARRGGBB 位图 */
static u64 __attribute__((ms_abi)) shim_GetDC(u64 hwnd) {
(void)hwnd; return SHIM_HDC_WND;
}
static u64 __attribute__((ms_abi)) shim_CreateCompatibleDC(u64 hdc) {
(void)hdc;
shim_dc_t *dc = (shim_dc_t *)kmem_alloc(sizeof(shim_dc_t));
if (dc) dc->bmp = 0;
return (u64)dc;
}
static u64 __attribute__((ms_abi)) shim_CreateDIBSection(u64 hdc, u64 bmi_p, u64 usage,
u64 ppv, u64 hsec, u64 off) {
(void)hdc; (void)usage; (void)hsec; (void)off;
if (!bmi_p || !ppv) return 0;
const u8 *bmi = (const u8 *)bmi_p;
i32 w = *(const i32 *)(bmi + 4); /* biWidth */
i32 h = *(const i32 *)(bmi + 8); /* biHeight(负=top-down) */
u16 bpp = *(const u16 *)(bmi + 14); /* biBitCount */
if (h < 0) h = -h;
if (w <= 0 || h <= 0 || bpp != 32) return 0;
u64 npix = (u64)w * (u64)h;
u32 *bits = (u32 *)kmem_alloc(npix * 4);
if (!bits) return 0;
for (u64 i = 0; i < npix; i++) bits[i] = 0;
shim_bmp_t *b = (shim_bmp_t *)kmem_alloc(sizeof(shim_bmp_t));
if (!b) return 0;
b->w = w; b->h = h; b->bits = bits;
*(u64 *)ppv = (u64)bits;
log_info("[shim] CreateDIBSection ok");
log_hex64("[shim] dib w=", (u64)(i64)w);
log_hex64("[shim] dib h=", (u64)(i64)h);
log_hex64("[shim] dib bits=", (u64)bits);
return (u64)b;
}
static u64 __attribute__((ms_abi)) shim_SelectObject(u64 hdc, u64 obj) {
shim_dc_t *dc = (shim_dc_t *)hdc;
if (!dc) return 0;
u64 prev = dc->bmp;
dc->bmp = obj;
return prev;
}
static u64 __attribute__((ms_abi)) shim_DeleteDC(u64 hdc) {
if (hdc == SHIM_HDC_WND) return 1; /* 窗口 DC 不释放 */
shim_dc_t *dc = (shim_dc_t *)hdc;
/* kmem arena 不支持 free,小对象泄漏可接受 */
(void)dc;
return 1;
}
static u64 __attribute__((ms_abi)) shim_DeleteObject(u64 obj) {
(void)obj; return 1; /* 同上:arena 无 free,位图随进程退出回收 */
}
static u64 __attribute__((ms_abi)) shim_GetStockObject(u64 i) {
(void)i; return 0x20000010; /* 伪 GDI 对象句柄 */
}
static u64 __attribute__((ms_abi)) shim_GdiFlush(void) { return 1; }
static u64 g_blit_count = 0;
static u64 __attribute__((ms_abi)) shim_BitBlt(u64 dstdc, u64 x, u64 y, u64 cx, u64 cy,
u64 srcdc, u64 x1, u64 y1, u64 rop) {
(void)rop;
if (dstdc != SHIM_HDC_WND) return 1; /* 仅支持窗口 DC 目标 */
const struct limine_framebuffer *fb = shim_fb();
if (!fb || !fb->address) return 0;
if (fb->bpp != 32 && fb->bpp != 24) return 0;
shim_dc_t *sdc = (shim_dc_t *)srcdc;
if (!sdc || !sdc->bmp) return 0;
shim_bmp_t *bmp = (shim_bmp_t *)sdc->bmp;
i32 dx = (i32)(u32)x + g_wnd_x;
i32 dy = (i32)(u32)y + g_wnd_y;
i32 sx0 = (i32)(u32)x1, sy0 = (i32)(u32)y1;
i32 w = (i32)(u32)cx, h = (i32)(u32)cy;
u8 *fbb = (u8 *)fb->address;
u32 rsh = fb->red_mask_shift, gsh = fb->green_mask_shift, bsh = fb->blue_mask_shift;
u32 rsz = fb->red_mask_size ? fb->red_mask_size : 8;
u32 gsz = fb->green_mask_size ? fb->green_mask_size : 8;
u32 bsz = fb->blue_mask_size ? fb->blue_mask_size : 8;
int fast = (fb->bpp == 32 && rsh == 16 && gsh == 8 && bsh == 0
&& rsz == 8 && gsz == 8 && bsz == 8);
for (i32 row = 0; row < h; row++) {
i32 fy = dy + row, sy = sy0 + row;
if (fy < 0 || fy >= (i32)fb->height) continue;
if (sy < 0 || sy >= bmp->h) continue;
u8 *dst_row = fbb + (u64)fy * fb->pitch;
const u32 *src = bmp->bits + (u64)sy * (u64)bmp->w;
for (i32 col = 0; col < w; col++) {
i32 fx = dx + col, sx = sx0 + col;
if (fx < 0 || fx >= (i32)fb->width) continue;
if (sx < 0 || sx >= bmp->w) continue;
u32 px = src[sx];
if (fast) {
((u32 *)dst_row)[fx] = px;
} else {
u32 r = (px >> 16) & 0xFF, g = (px >> 8) & 0xFF, bl = px & 0xFF;
u32 v = ((r >> (8 - rsz)) << rsh)
| ((g >> (8 - gsz)) << gsh)
| ((bl >> (8 - bsz)) << bsh);
if (fb->bpp == 32) {
((u32 *)dst_row)[fx] = v;
} else {
u8 *p = dst_row + (u64)fx * 3;
p[0] = (u8)(v & 0xFF);
p[1] = (u8)((v >> 8) & 0xFF);
p[2] = (u8)((v >> 16) & 0xFF);
}
}
}
}
g_blit_count++;
if (g_blit_count == 1) log_info("[shim] BitBlt first frame on screen");
if ((g_blit_count % 600) == 0) log_hex64("[shim] BitBlt frames=", g_blit_count);
return 1;
}
/* 未实现 stub(64位)— 日志告警(含调用点返回地址)并返回 0 */
static u64 __attribute__((ms_abi)) shim_unimpl64(u64 a0, u64 a1, u64 a2, u64 a3) {
(void)a0; (void)a1; (void)a2; (void)a3;
log_warn("[PE] unimplemented API called");
log_hex64("[PE] caller rip=", (u64)__builtin_return_address(0));
return 0;
}
@@ -364,6 +1260,84 @@ static const pe_shim_entry g_shim_table[] = {
{"kernel32.dll", "CloseHandle", (void*)shim_CloseHandle, 0},
{"kernel32.dll", "GetFileSize", (void*)shim_GetFileSize, 0},
{"kernel32.dll", "SetFilePointer", (void*)shim_SetFilePointer, 0},
/* kernel32.dll — Deaicup GUI 增量 */
{"kernel32.dll", "HeapReAlloc", (void*)shim_HeapReAlloc, 0},
{"kernel32.dll", "GetProcessHeap", (void*)shim_GetProcessHeap, 0},
{"kernel32.dll", "QueryPerformanceFrequency", (void*)shim_QueryPerformanceFrequency, 0},
{"kernel32.dll", "QueryPerformanceCounter", (void*)shim_QueryPerformanceCounter, 0},
{"kernel32.dll", "GetTickCount", (void*)shim_GetTickCount, 0},
{"kernel32.dll", "Sleep", (void*)shim_Sleep, 0},
{"kernel32.dll", "GetSystemInfo", (void*)shim_GetSystemInfo, 0},
{"kernel32.dll", "GetConsoleMode", (void*)shim_GetConsoleMode, 0},
{"kernel32.dll", "GetConsoleOutputCP", (void*)shim_GetConsoleOutputCP, 0},
{"kernel32.dll", "WriteConsoleW", (void*)shim_WriteConsoleW, 0},
{"kernel32.dll", "GetCurrentDirectoryW", (void*)shim_GetCurrentDirectoryW, 0},
{"kernel32.dll", "GetEnvironmentVariableW", (void*)shim_GetEnvironmentVariableW, 0},
{"kernel32.dll", "GetCurrentProcess", (void*)shim_GetCurrentProcess, 0},
{"kernel32.dll", "GetCurrentProcessId", (void*)shim_GetCurrentProcessId, 0},
{"kernel32.dll", "GetCurrentThreadId", (void*)shim_GetCurrentThreadId, 0},
{"kernel32.dll", "CreateMutexA", (void*)shim_CreateMutexA, 0},
{"kernel32.dll", "ReleaseMutex", (void*)shim_ReleaseMutex, 0},
{"kernel32.dll", "WaitForSingleObject", (void*)shim_WaitForSingleObject, 0},
{"kernel32.dll", "WaitForSingleObjectEx", (void*)shim_WaitForSingleObjectEx, 0},
{"kernel32.dll", "FormatMessageW", (void*)shim_FormatMessageW, 0},
{"kernel32.dll", "LoadLibraryA", (void*)shim_LoadLibraryA, 0},
{"kernel32.dll", "GetProcAddress", (void*)shim_GetProcAddress, 0},
{"kernel32.dll", "lstrlenW", (void*)shim_lstrlenW, 0},
{"kernel32.dll", "MultiByteToWideChar", (void*)shim_MultiByteToWideChar, 0},
{"kernel32.dll", "WideCharToMultiByte", (void*)shim_WideCharToMultiByte, 0},
/* kernel32.dll 也转发导出这三个 Rtl*(Rust std 从 kernel32 静态导入) */
{"kernel32.dll", "RtlCaptureContext", (void*)shim_RtlCaptureContext, 0},
{"kernel32.dll", "RtlLookupFunctionEntry",(void*)shim_RtlLookupFunctionEntry, 0},
{"kernel32.dll", "RtlVirtualUnwind", (void*)shim_RtlVirtualUnwind, 0},
/* ntdll.dll */
{"ntdll.dll", "RtlCaptureContext", (void*)shim_RtlCaptureContext, 0},
{"ntdll.dll", "RtlLookupFunctionEntry",(void*)shim_RtlLookupFunctionEntry, 0},
{"ntdll.dll", "RtlVirtualUnwind", (void*)shim_RtlVirtualUnwind, 0},
{"ntdll.dll", "NtWriteFile", (void*)shim_NtWriteFile, 0},
{"ntdll.dll", "RtlNtStatusToDosError", (void*)shim_RtlNtStatusToDosError, 0},
/* bcryptprimitives.dll */
{"bcryptprimitives.dll", "ProcessPrng", (void*)shim_ProcessPrng, 0},
/* api-ms-win-core-synch-l1-2-0.dll */
{"api-ms-win-core-synch-l1-2-0.dll", "WaitOnAddress", (void*)shim_WaitOnAddress, 0},
{"api-ms-win-core-synch-l1-2-0.dll", "WakeByAddressSingle",(void*)shim_WakeByAddress, 0},
{"api-ms-win-core-synch-l1-2-0.dll", "WakeByAddressAll", (void*)shim_WakeByAddress, 0},
/* user32.dll */
{"user32.dll", "RegisterClassExW", (void*)shim_RegisterClassExW, 0},
{"user32.dll", "CreateWindowExW", (void*)shim_CreateWindowExW, 0},
{"user32.dll", "DestroyWindow", (void*)shim_DestroyWindow, 0},
{"user32.dll", "ShowWindow", (void*)shim_ShowWindow, 0},
{"user32.dll", "UpdateWindow", (void*)shim_UpdateWindow, 0},
{"user32.dll", "GetMessageW", (void*)shim_GetMessageW, 0},
{"user32.dll", "PeekMessageW", (void*)shim_PeekMessageW, 0},
{"user32.dll", "TranslateMessage", (void*)shim_TranslateMessage, 0},
{"user32.dll", "DispatchMessageW", (void*)shim_DispatchMessageW, 0},
{"user32.dll", "PostQuitMessage", (void*)shim_PostQuitMessage, 0},
{"user32.dll", "DefWindowProcW", (void*)shim_DefWindowProcW, 0},
{"user32.dll", "GetClientRect", (void*)shim_GetClientRect, 0},
{"user32.dll", "InvalidateRect", (void*)shim_InvalidateRect, 0},
{"user32.dll", "BeginPaint", (void*)shim_BeginPaint, 0},
{"user32.dll", "EndPaint", (void*)shim_EndPaint, 0},
{"user32.dll", "GetDC", (void*)shim_GetDC, 0},
{"user32.dll", "ReleaseDC", (void*)shim_ReleaseDC, 0},
{"user32.dll", "LoadCursorW", (void*)shim_LoadCursorW, 0},
{"user32.dll", "SetCursor", (void*)shim_SetCursor, 0},
{"user32.dll", "GetCursorPos", (void*)shim_GetCursorPos, 0},
{"user32.dll", "ScreenToClient", (void*)shim_ScreenToClient, 0},
{"user32.dll", "GetAsyncKeyState", (void*)shim_GetAsyncKeyState, 0},
{"user32.dll", "SetTimer", (void*)shim_SetTimer, 0},
{"user32.dll", "KillTimer", (void*)shim_KillTimer, 0},
{"user32.dll", "MessageBeep", (void*)shim_MessageBeep, 0},
{"user32.dll", "GetSystemMetrics", (void*)shim_GetSystemMetrics, 0},
/* gdi32.dll */
{"gdi32.dll", "CreateCompatibleDC", (void*)shim_CreateCompatibleDC, 0},
{"gdi32.dll", "CreateDIBSection", (void*)shim_CreateDIBSection, 0},
{"gdi32.dll", "SelectObject", (void*)shim_SelectObject, 0},
{"gdi32.dll", "DeleteObject", (void*)shim_DeleteObject, 0},
{"gdi32.dll", "DeleteDC", (void*)shim_DeleteDC, 0},
{"gdi32.dll", "BitBlt", (void*)shim_BitBlt, 0},
{"gdi32.dll", "GetStockObject", (void*)shim_GetStockObject, 0},
{"gdi32.dll", "GdiFlush", (void*)shim_GdiFlush, 0},
/* msvcrt.dll */
{"msvcrt.dll", "printf", (void*)shim_printf, 0},
{"msvcrt.dll", "puts", (void*)shim_puts, 0},
+7
View File
@@ -0,0 +1,7 @@
pe/pe_shim.o: pe\pe_shim.c pe\pe_shim.h include\utsm\types.h \
include\utsm\arena.h include\utsm\log.h pe\..\arch\x86_64\limine.h
pe\pe_shim.h:
include\utsm\types.h:
include\utsm\arena.h:
include\utsm\log.h:
pe\..\arch\x86_64\limine.h:
+6
View File
@@ -0,0 +1,6 @@
pe/x86emu32.o: pe\x86emu32.c pe\x86emu32.h include\utsm\types.h \
pe\pe_shim.h include\utsm\log.h
pe\x86emu32.h:
include\utsm\types.h:
pe\pe_shim.h:
include\utsm\log.h:
+5
View File
@@ -0,0 +1,5 @@
runtime/assert.o: runtime\assert.c include\utsm\assert.h \
include\utsm\log.h include\utsm\types.h
include\utsm\assert.h:
include\utsm\log.h:
include\utsm\types.h:
+2
View File
@@ -0,0 +1,2 @@
runtime/string.o: runtime\string.c include\utsm\types.h
include\utsm\types.h:
+24
View File
@@ -0,0 +1,24 @@
test/utsm_selftest.o: test\utsm_selftest.c include\utsm\utsm.h \
include\utsm\types.h include\utsm\status.h include\utsm\config.h \
include\utsm\uuid.h include\utsm\process.h include\utsm\capability.h \
include\utsm\segment.h include\utsm\dirty.h include\utsm\utrw.h \
include\utsm\vmm.h include\utsm\linux_loader.h include\utsm\ipc_shm.h \
..\utsm-ipc\ipc_proto.h include\utsm\hypercall.h include\utsm\log.h \
include\utsm\arena.h
include\utsm\utsm.h:
include\utsm\types.h:
include\utsm\status.h:
include\utsm\config.h:
include\utsm\uuid.h:
include\utsm\process.h:
include\utsm\capability.h:
include\utsm\segment.h:
include\utsm\dirty.h:
include\utsm\utrw.h:
include\utsm\vmm.h:
include\utsm\linux_loader.h:
include\utsm\ipc_shm.h:
..\utsm-ipc\ipc_proto.h:
include\utsm\hypercall.h:
include\utsm\log.h:
include\utsm\arena.h:
+14
View File
@@ -0,0 +1,14 @@
utrw/read.o: utrw\read.c include\utsm\utrw.h include\utsm\types.h \
include\utsm\status.h include\utsm\capability.h include\utsm\segment.h \
include\utsm\uuid.h include\utsm\dirty.h include\utsm\pckc.h \
include\utsm\config.h include\utsm\crypto.h
include\utsm\utrw.h:
include\utsm\types.h:
include\utsm\status.h:
include\utsm\capability.h:
include\utsm\segment.h:
include\utsm\uuid.h:
include\utsm\dirty.h:
include\utsm\pckc.h:
include\utsm\config.h:
include\utsm\crypto.h:
+6
View File
@@ -0,0 +1,6 @@
utrw/slow_path.o: utrw\slow_path.c include\utsm\utrw.h \
include\utsm\types.h include\utsm\status.h include\utsm\capability.h
include\utsm\utrw.h:
include\utsm\types.h:
include\utsm\status.h:
include\utsm\capability.h:
+15
View File
@@ -0,0 +1,15 @@
utrw/write.o: utrw\write.c include\utsm\utrw.h include\utsm\types.h \
include\utsm\status.h include\utsm\capability.h include\utsm\segment.h \
include\utsm\uuid.h include\utsm\dirty.h include\utsm\pckc.h \
include\utsm\config.h include\utsm\crypto.h include\utsm\drr.h
include\utsm\utrw.h:
include\utsm\types.h:
include\utsm\status.h:
include\utsm\capability.h:
include\utsm\segment.h:
include\utsm\uuid.h:
include\utsm\dirty.h:
include\utsm\pckc.h:
include\utsm\config.h:
include\utsm\crypto.h:
include\utsm\drr.h:
+134
View File
@@ -115,6 +115,140 @@ int ept_identity_map(u64 gpa, u64 size, u64 flags) {
return ept_map_range(gpa, gpa, size, flags);
}
/* ===== EPT 大页映射(2MB 大页,真机 MTRR 感知) =====
*
* 在 PD 层级直接映射 2MB 大页(bit 7 = EPT_LARGE_PAGE),
* 减少 EPT walk 深度(4 级 → 3 级)和 TLB 压力。
* 真机要求大页 memory type 与 MTRR 一致:
* - RAM 区域用 WB (6)
* - MMIO 区域用 UC (0)
* QEMU 忽略 MTRR,但真机会检查。
*
* 用法:ept_map_2m_page(GPA, HPA, flags, memtype)
* flags = EPT_RWX 等
* memtype = EPT_MEMORY_TYPE_WB / EPT_MEMORY_TYPE_UC 等 */
int ept_map_2m_page(u64 gpa, u64 hpa, u64 flags, u64 memtype) {
if (!g_ept_ready) return -1;
/* GPA 和 HPA 必须 2MB 对齐 */
if ((gpa & 0x1FFFFFULL) || (hpa & 0x1FFFFFULL)) {
log_error("[EPT] 2MB page unaligned");
return -2;
}
u64 *table = (u64 *)g_ept_pml4_virt;
u64 pml4_idx = (gpa >> 39) & 0x1FF;
u64 pdpt_idx = (gpa >> 30) & 0x1FF;
u64 pd_idx = (gpa >> 21) & 0x1FF;
/* PML4 */
u64 entry = table[pml4_idx];
if (!(entry & EPT_READ)) {
u64 new_phys = ept_alloc_page();
if (new_phys == 0) return -3;
table[pml4_idx] = new_phys | EPT_RWX | (EPT_MEMORY_TYPE_WB << 3);
table = (u64 *)phys_to_virt(new_phys);
} else {
table = (u64 *)phys_to_virt(entry & 0x000FFFFFFFFFF000ULL);
}
/* PDPT */
entry = table[pdpt_idx];
if (!(entry & EPT_READ)) {
u64 new_phys = ept_alloc_page();
if (new_phys == 0) return -4;
table[pdpt_idx] = new_phys | EPT_RWX | (EPT_MEMORY_TYPE_WB << 3);
table = (u64 *)phys_to_virt(new_phys);
} else {
table = (u64 *)phys_to_virt(entry & 0x000FFFFFFFFFF000ULL);
}
/* PD:直接写 2MB 大页项 */
u64 pd_entry = (hpa & 0x000FFFFFFFE00000ULL) /* 物理地址(2MB 对齐) */
| flags /* R/W/X 权限 */
| EPT_LARGE_PAGE /* bit 7 = 大页标志 */
| (memtype << 3); /* memory type */
table[pd_idx] = pd_entry;
return 0;
}
/* ===== INVVPID 支持(真机 VPID 刷新) =====
*
* 启用 VPID 后,真机要求在修改 EPT 映射后执行 INVVPID 刷新
* stale TLB entry。QEMU 不检查,但真机会在以下场景触发 VMX abort:
* - guest 修改了 CR3 但 TLB 中缓存了旧 VPID 的映射
* - EPT 重映射后未刷新
* - VMCS VPID 字段变更后未执行 INVVPID
*
* INVVPID 类型:
* 0 = 不支持
* 1 = 单个 VPID 刷新(INVVPID_DESC.vpid)
* 2 = 全局 VPID 刷新(所有 VPID)
* 3 = 单个 VPID + PCID 刷新
*
* 当前实现:使用类型 2(全局刷新),最安全但性能最差。
* 优化路径:在 EPT 重映射时调用类型 1 刷新特定 VPID。 */
static int g_invvpid_supported;
static int g_invept_supported;
void ept_check_vpid_support(void) {
u64 cap = vmx_read_msr(IA32_VMX_EPT_VPID_CAP);
/* INVVPID 类型 2 (all-context) 支持:bit 32 */
g_invvpid_supported = (cap & (1ULL << 32)) ? 1 : 0;
/* INVEPT 类型 2 (all-context) 支持:bit 25 */
g_invept_supported = (cap & (1ULL << 25)) ? 1 : 0;
log_hex64("[EPT] VPID cap=", cap);
log_info(g_invvpid_supported ? "[EPT] INVVPID supported" : "[EPT] INVVPID NOT supported");
log_info(g_invept_supported ? "[EPT] INVEPT supported" : "[EPT] INVEPT NOT supported");
}
/* 执行 INVEPT(EPT TLB 刷新)。真机要求在修改 EPT 后调用。 */
void ept_flush_ept(void) {
if (!g_invept_supported) return;
/* INVEPT 类型 2: all-context invalidate
* 操作数:{EPTP=0, reserved=0} 表示刷新所有 EPT 上下文 */
u64 desc[2] = {0, 0};
int err;
__asm__ volatile(
"invept (%2), %1\n"
"jnc 1f\n"
"mov $1, %0\n"
"jmp 2f\n"
"1:\n"
"mov $0, %0\n"
"2:\n"
: "=r"(err)
: "r"((u64)2), "r"(desc)
: "memory"
);
if (err) {
log_warn("[EPT] INVEPT failed (non-critical on QEMU)");
}
}
/* 执行 INVVPID(VPID TLB 刷新)。真机要求在 VPID 变更后调用。 */
void ept_flush_vpid(u16 vpid) {
if (!g_invvpid_supported) return;
/* INVVPID 类型 2: all-context invalidate */
u64 desc[2] = {0, 0};
desc[0] = (u64)vpid;
int err;
__asm__ volatile(
"invvpid (%2), %1\n"
"jnc 1f\n"
"mov $1, %0\n"
"jmp 2f\n"
"1:\n"
"mov $0, %0\n"
"2:\n"
: "=r"(err)
: "r"((u64)2), "r"(desc)
: "memory"
);
if (err) {
log_warn("[EPT] INVVPID failed (non-critical on QEMU)");
}
}
/* Walk the EPT to translate a GPA to its mapped HPA.
* Returns 0 if the GPA is not mapped (no present entry at any level).
* Handles 4KB pages and 2MB large pages (bit 7 = PS in PD entry). */
+9
View File
@@ -0,0 +1,9 @@
vmm/ept.o: vmm\ept.c include\utsm\ept.h include\utsm\types.h \
include\utsm\vmx.h include\utsm\log.h include\utsm\dma.h \
vmm\..\arch\x86_64\limine.h
include\utsm\ept.h:
include\utsm\types.h:
include\utsm\vmx.h:
include\utsm\log.h:
include\utsm\dma.h:
vmm\..\arch\x86_64\limine.h:
+81
View File
@@ -21,6 +21,7 @@
#include <utsm/ept.h>
#include <utsm/vmm.h>
#include <utsm/ipc_shm.h>
#include <utsm/linux_compat.h>
#include <utsm/log.h>
#include <utsm/types.h>
#include <ipc_proto.h>
@@ -179,6 +180,80 @@ static long hcall_console_read(u64 a0, u64 a1, u64 a2) {
return UTSM_HCALL_NOSYS;
}
/* ===== Phase 3: Linux guest ↔ UTSM FAT32 file transfer =====
*
* payload_pool at offset 0 is the bulk data buffer. ABI details are
* documented in ipc_proto.h ("Linux ↔ UTSM FAT32 hypercalls").
*
* Return packing for FILE_READ (positive RAX):
* low 20 bits = staged byte count (pool capacity < 1MB → fits)
* RAX >> 20 = total file size (FAT32 root files ≤ 256KB → fits) */
/* Read a NUL-terminated file name (max 63 chars) from guest memory. */
static int hcall_read_name(u64 gpa, char out[64]) {
if (guest_read_buf(gpa, out, 64) != 0) return -1;
out[63] = '\0';
return 0;
}
/* Map lxc_f32_* error codes to hypercall return codes. */
static long hcall_f32_err(int rc) {
if (rc == -10) return UTSM_HCALL_INVAL; /* illegal file name */
if (rc == -11) return UTSM_HCALL_NOENT; /* not found */
if (rc == -9) return UTSM_HCALL_IO; /* no block device */
return UTSM_HCALL_IO;
}
static long hcall_file_read(u64 a0, u64 a1, u64 a2) {
/* a0 = name GPA, a1 = file offset, a2 = max bytes to stage */
if (a0 == 0) return UTSM_HCALL_INVAL;
char name[64];
if (hcall_read_name(a0, name) != 0) return UTSM_HCALL_INVAL;
u8 *fdata = (u8 *)0;
u32 fsize = 0;
int rc = lxc_f32_read_file(name, &fdata, &fsize);
if (rc != 0) return hcall_f32_err(rc);
u64 cap = ipc_shm_payload_capacity();
u64 want = a2;
if (want > cap) want = cap;
u64 n = 0;
if (a1 < (u64)fsize) {
n = (u64)fsize - a1;
if (n > want) n = want;
}
if (n > 0) {
u8 *pool = (u8 *)ipc_shm_payload_ptr(0);
if (!pool) return UTSM_HCALL_NOMEM;
for (u64 i = 0; i < n; i++) pool[i] = fdata[a1 + i];
}
return (long)(((u64)fsize << 20) | n);
}
static long hcall_file_write(u64 a0, u64 a1, u64 a2) {
/* a0 = name GPA, a1 = reserved (0), a2 = bytes staged at pool[0] */
(void)a1;
if (a0 == 0) return UTSM_HCALL_INVAL;
if (a2 > ipc_shm_payload_capacity() || a2 > 262144) {
return UTSM_HCALL_INVAL; /* fat32_io 单文件上限 256KB */
}
char name[64];
if (hcall_read_name(a0, name) != 0) return UTSM_HCALL_INVAL;
const u8 *pool = (const u8 *)ipc_shm_payload_ptr(0);
if (!pool && a2 > 0) return UTSM_HCALL_NOMEM;
int rc = lxc_f32_write_file(name, pool, (u32)a2);
if (rc != 0) return hcall_f32_err(rc);
return (long)a2;
}
/* ===== Main hypercall dispatcher ===== */
int hypercall_handle(u64 guest_rax, u64 guest_rdi, u64 guest_rsi, u64 guest_rdx,
@@ -227,6 +302,12 @@ int hypercall_handle(u64 guest_rax, u64 guest_rdi, u64 guest_rsi, u64 guest_rdx,
case UTSM_HCALL_CONSOLE_READ:
result = hcall_console_read(guest_rdi, guest_rsi, guest_rdx);
break;
case UTSM_HCALL_FILE_READ:
result = hcall_file_read(guest_rdi, guest_rsi, guest_rdx);
break;
case UTSM_HCALL_FILE_WRITE:
result = hcall_file_write(guest_rdi, guest_rsi, guest_rdx);
break;
default:
log_hex64("[HCALL] unknown op: ", op);
result = UTSM_HCALL_NOSYS;
+15
View File
@@ -0,0 +1,15 @@
vmm/hypercall.o: vmm\hypercall.c include\utsm\hypercall.h \
include\utsm\types.h include\utsm\vmx.h include\utsm\ept.h \
include\utsm\vmm.h include\utsm\ipc_shm.h ..\utsm-ipc\ipc_proto.h \
include\utsm\linux_compat.h include\utsm\log.h \
vmm\..\arch\x86_64\limine.h
include\utsm\hypercall.h:
include\utsm\types.h:
include\utsm\vmx.h:
include\utsm\ept.h:
include\utsm\vmm.h:
include\utsm\ipc_shm.h:
..\utsm-ipc\ipc_proto.h:
include\utsm\linux_compat.h:
include\utsm\log.h:
vmm\..\arch\x86_64\limine.h:
+12
View File
@@ -121,6 +121,18 @@ u64 ipc_shm_get_size(void) {
return UTSM_IPC_SHM_SIZE;
}
/* ===== Payload pool access ===== */
void *ipc_shm_payload_ptr(u32 offset) {
if (!g_shm_ready || !g_shm) return (void *)0;
if (offset >= UTSM_IPC_PAYLOAD_SIZE) return (void *)0;
return (void *)(g_shm->payload_pool + offset);
}
u32 ipc_shm_payload_capacity(void) {
return UTSM_IPC_PAYLOAD_SIZE;
}
/* ===== Message API (UTSM-side) ===== */
int ipc_shm_send(u32 msg_type, const void *data, u32 data_len) {
+13
View File
@@ -0,0 +1,13 @@
vmm/ipc_shm.o: vmm\ipc_shm.c include\utsm\ipc_shm.h include\utsm\types.h \
..\utsm-ipc\ipc_proto.h include\utsm\vmx.h include\utsm\ept.h \
include\utsm\log.h include\utsm\dma.h include\utsm\linux_loader.h \
vmm\..\arch\x86_64\limine.h
include\utsm\ipc_shm.h:
include\utsm\types.h:
..\utsm-ipc\ipc_proto.h:
include\utsm\vmx.h:
include\utsm\ept.h:
include\utsm\log.h:
include\utsm\dma.h:
include\utsm\linux_loader.h:
vmm\..\arch\x86_64\limine.h:
+3
View File
@@ -292,6 +292,9 @@ int linux_launch(void) {
* virtio_mmio.device= 发现。幂等:重复调用直接返回。 */
virtio_mmio_init();
/* 真机 EPT TLB 刷新:在 vmlaunch 前确保 EPT 映射对 TLB 可见 */
ept_flush_ept();
/* Reset VM-Exit state */
g_guest_terminated = 0;
g_last_exit_reason = 0xFFFFFFFFULL;
+12
View File
@@ -0,0 +1,12 @@
vmm/linux_boot.o: vmm\linux_boot.c include\utsm\linux_loader.h \
include\utsm\types.h include\utsm\vmx.h include\utsm\ept.h \
include\utsm\vmm.h include\utsm\virtio_mmio.h include\utsm\log.h \
vmm\..\arch\x86_64\limine.h
include\utsm\linux_loader.h:
include\utsm\types.h:
include\utsm\vmx.h:
include\utsm\ept.h:
include\utsm\vmm.h:
include\utsm\virtio_mmio.h:
include\utsm\log.h:
vmm\..\arch\x86_64\limine.h:
+266
View File
@@ -20,7 +20,9 @@
#include <utsm/vmm.h>
#include <utsm/log.h>
#include <utsm/types.h>
#include <utsm/block.h>
#include <ipc_proto.h>
#include "../../tools/fat32_io.h"
/* ===== 内部辅助 ===== */
@@ -184,13 +186,277 @@ static int lxc_status(char *buf, u64 cap) {
return (int)n;
}
/* ===== Phase 3 文件传输(FILE_LIST / FILE_READ) =====
*
* 同步请求-响应模型(与 exec 相同):
* 1. 构建 ipc_file_request(指定 payload_pool 写入偏移与容量)
* 2. ipc_shm_send 入队 → linux_resume 唤醒 daemon
* 3. daemon 把批量数据直接写进 payload_pool,回 FILE_RESPONSE 后 HLT
* 4. 从 ring 取出响应头,按 data_len 从 payload_pool 拷出数据
*/
/* 发送文件请求并等待响应(公共子流程)。
* msg_type : UTSM_MSG_FILE_LIST_REQUEST / UTSM_MSG_FILE_READ_REQUEST
* path : Linux 绝对路径
* offset : FILE_READ 的文件偏移(LIST 传 0)
* want_cap : 期望读取的最大字节数(会钳制到 payload_pool 容量)
* 成功时 resp 填充并返回 0;失败返回负值(-2 发送失败, -3 resume 失败,
* -4 无响应)。 */
static int lxc_file_roundtrip(u32 msg_type, const char *path, u64 offset,
u32 want_cap, struct ipc_file_response *resp) {
if (!lxc_is_available()) return -1;
if (!path || !resp) return -1;
u32 pool_cap = ipc_shm_payload_capacity();
if (want_cap > pool_cap) want_cap = pool_cap;
struct ipc_file_request req;
my_memzero(&req, sizeof(req));
req.pool_offset = 0; /* 独占使用整个 pool(同步模型,无并发) */
req.pool_capacity = want_cap;
req.file_offset = offset;
u64 plen = my_strlen(path);
if (plen >= UTSM_FILE_PATH_MAX) plen = UTSM_FILE_PATH_MAX - 1;
my_memcpy(req.path, path, plen);
req.path[plen] = 0;
if (ipc_shm_send(msg_type, &req, sizeof(req)) != 0) {
log_warn("[LNXC] file: failed to enqueue request");
return -2;
}
int r = linux_resume();
if (r != 0) {
log_hex64("[LNXC] file: linux_resume failed=", (u64)(i64)r);
return -3;
}
/* 从 ring 中取 FILE_RESPONSE(忽略其间可能残留的 EXEC_* 消息) */
for (int i = 0; i < 256; i++) {
struct utsm_ipc_msg msg;
if (ipc_shm_recv(&msg) != 0) break; /* ring 空 */
if (msg.type == UTSM_MSG_FILE_RESPONSE &&
msg.data_len >= sizeof(struct ipc_file_response)) {
my_memcpy(resp, msg.data, sizeof(*resp));
return 0;
}
}
return -4; /* 无响应 */
}
/* 从 payload_pool 拷出数据到调用方缓冲。返回拷出的字节数。 */
static u64 lxc_pool_copyout(char *buf, u64 cap, u32 data_len) {
if (!buf || cap == 0 || data_len == 0) return 0;
u8 *pool = (u8 *)ipc_shm_payload_ptr(0);
if (!pool) return 0;
u64 n = data_len;
if (n > cap) n = cap;
if (n > ipc_shm_payload_capacity()) n = ipc_shm_payload_capacity();
my_memcpy(buf, pool, n);
return n;
}
static int lxc_file_list(const char *path, char *buf, u64 cap, u64 *out_len) {
struct ipc_file_response resp;
/* 请求的容量取调用方缓冲与 pool 容量的较小值 */
u32 want = (cap > 0xFFFFFFFFULL) ? 0xFFFFFFFFU : (u32)cap;
int rc = lxc_file_roundtrip(UTSM_MSG_FILE_LIST_REQUEST, path, 0, want, &resp);
if (rc != 0) {
if (out_len) *out_len = 0;
return rc;
}
if (resp.status != UTSM_FILE_OK) {
if (out_len) *out_len = 0;
log_hex64("[LNXC] file_list: linux side error=", resp.status);
return -5;
}
u64 n = lxc_pool_copyout(buf, cap, resp.data_len);
if (out_len) *out_len = n;
/* Linux 侧写出的数据超过调用方缓冲 → 截断提示 */
if (resp.data_len > n) return -6;
return 0;
}
static int lxc_file_read(const char *path, u64 offset, char *buf, u64 cap,
u64 *out_len, u64 *out_total) {
struct ipc_file_response resp;
u32 want = (cap > 0xFFFFFFFFULL) ? 0xFFFFFFFFU : (u32)cap;
int rc = lxc_file_roundtrip(UTSM_MSG_FILE_READ_REQUEST, path, offset, want, &resp);
if (rc != 0) {
if (out_len) *out_len = 0;
if (out_total) *out_total = 0;
return rc;
}
if (out_total) *out_total = resp.total_size;
if (resp.status != UTSM_FILE_OK) {
if (out_len) *out_len = 0;
log_hex64("[LNXC] file_read: linux side error=", resp.status);
return -5;
}
u64 n = lxc_pool_copyout(buf, cap, resp.data_len);
if (out_len) *out_len = n;
if (resp.data_len > n) return -6;
return 0;
}
/* 写入 Linux 文件:把调用方数据先搬进 payload_pool,再走同步请求-响应。
* 单次最多搬运 payload pool 容量(~1MB),大文件由调用方循环推进 offset。 */
static int lxc_file_write(const char *path, u64 offset, const char *buf,
u64 len, u64 *out_written) {
if (!lxc_is_available()) return -1;
if (!path || (!buf && len > 0)) return -1;
u32 pool_cap = ipc_shm_payload_capacity();
u64 n = len;
if (n > pool_cap) n = pool_cap;
if (n > 0) {
u8 *pool = (u8 *)ipc_shm_payload_ptr(0);
if (!pool) return -1;
my_memcpy(pool, buf, n);
utsm_ipc_mb(); /* 保证 pool 数据先于请求对 guest 可见 */
}
/* 复用公共子流程:WRITE 时 pool_capacity 字段表示已 staged 的字节数 */
struct ipc_file_response resp;
int rc = lxc_file_roundtrip(UTSM_MSG_FILE_WRITE_REQUEST, path, offset,
(u32)n, &resp);
if (rc != 0) {
if (out_written) *out_written = 0;
return rc;
}
if (resp.status != UTSM_FILE_OK) {
if (out_written) *out_written = 0;
log_hex64("[LNXC] file_write: linux side error=", resp.status);
return -5;
}
if (out_written) *out_written = resp.data_len;
return 0;
}
/* ===== UTSM FAT32 系统盘接入(file_pull / file_push / hypercall 共用) =====
*
* 复用 tools/fat32_io.h(static inline 库,仅根目录、单文件 ≤256KB),
* block 读写函数指针来自 UTSM block 注册表(block_get_api(),
* 等价于 DSK 侧 dkm_kernel_api +0xA8 block_read / +0x18 block_write)。 */
static int g_f32_inited; /* 1 = f32_init 已完成 */
/* 惰性初始化 FAT32 库。返回 0 可用,-9 无块设备。 */
static int lxc_f32_ensure(void) {
const dkm_block_api *api = block_get_api();
if (!api || !api->read || !api->write) return -9;
if (api->device_count() == 0) return -9;
if (!g_f32_inited) {
f32_init(api->read, api->write);
g_f32_inited = 1;
}
return 0;
}
int lxc_f32_read_file(const char *name, u8 **out_data, u32 *out_size) {
if (!name || !out_data || !out_size) return -10;
int rc = lxc_f32_ensure();
if (rc != 0) return rc;
char n11[11];
if (f32_name_to_83(name, n11) != 0) return -10;
int fr = f32_read_root_file(n11, out_data, out_size);
if (fr == -5) return -11; /* 根目录中未找到 */
if (fr != 0) return -12; /* 磁盘 / 格式错误 */
return 0;
}
int lxc_f32_write_file(const char *name, const u8 *data, u32 size) {
if (!name || (!data && size > 0)) return -10;
int rc = lxc_f32_ensure();
if (rc != 0) return rc;
char n11[11];
if (f32_name_to_83(name, n11) != 0) return -10;
if (f32_write_root_file(n11, data, size) != 0) return -12;
return 0;
}
/* pull 暂存缓冲:与 fat32_io 单文件上限一致(256KB) */
static u8 g_pull_stage[262144];
/* 跨内核拉取:Linux 文件 → UTSM FAT32 根目录。
* 先经 IPC 分块读完整文件到暂存缓冲(失败则不写盘,避免半成品),
* 再一次 f32_write_root_file 落盘。 */
static int lxc_file_pull(const char *linux_path, const char *fat32_name,
u64 *out_size) {
if (!lxc_is_available()) return -1;
if (!linux_path || !fat32_name) return -1;
int rc = lxc_f32_ensure();
if (rc != 0) { if (out_size) *out_size = 0; return rc; }
u64 off = 0;
u64 total = 0;
for (;;) {
u64 got = 0;
u64 space = (u64)sizeof(g_pull_stage) - off;
if (space == 0) {
if (out_size) *out_size = 0;
return -7; /* 超过 256KB 暂存上限 */
}
rc = lxc_file_read(linux_path, off, (char *)g_pull_stage + off,
space, &got, &total);
if (rc != 0) { if (out_size) *out_size = 0; return rc; }
off += got;
if (got == 0 || off >= total) break;
}
rc = lxc_f32_write_file(fat32_name, g_pull_stage, (u32)off);
if (rc != 0) { if (out_size) *out_size = 0; return rc; }
if (out_size) *out_size = off;
return 0;
}
/* 跨内核推送:UTSM FAT32 根目录 → Linux 文件(整文件替换)。
* f32_read_root_file 读出后经 lxc_file_write 按 pool 容量分块写入;
* 首块 offset=0 → daemon 侧 O_TRUNC,实现整文件替换语义。 */
static int lxc_file_push(const char *fat32_name, const char *linux_path,
u64 *out_size) {
if (!lxc_is_available()) return -1;
if (!fat32_name || !linux_path) return -1;
u8 *data = 0;
u32 size = 0;
int rc = lxc_f32_read_file(fat32_name, &data, &size);
if (rc != 0) { if (out_size) *out_size = 0; return rc; }
u32 pool_cap = ipc_shm_payload_capacity();
u64 off = 0;
for (;;) {
u64 remain = (u64)size - off;
u64 chunk = remain > pool_cap ? pool_cap : remain;
u64 written = 0;
rc = lxc_file_write(linux_path, off, (const char *)data + off,
chunk, &written);
if (rc != 0) { if (out_size) *out_size = off; return rc; }
if (written != chunk) { /* 短写:按 I/O 错误处理 */
if (out_size) *out_size = off + written;
return -5;
}
off += written;
if (off >= size) break;
}
if (out_size) *out_size = off;
return 0;
}
/* ===== 服务表 ===== */
static const linux_compat_service g_lxc_service = {
LINUX_COMPAT_MAGIC,
lxc_is_available,
lxc_exec,
lxc_file_list,
lxc_file_read,
lxc_status,
lxc_file_write,
lxc_file_pull,
lxc_file_push,
};
const linux_compat_service *linux_compat_get_service(void) {
+13
View File
@@ -0,0 +1,13 @@
vmm/linux_compat.o: vmm\linux_compat.c include\utsm\linux_compat.h \
include\utsm\types.h include\utsm\linux_resume.h \
include\utsm\ipc_shm.h ..\utsm-ipc\ipc_proto.h include\utsm\vmm.h \
include\utsm\log.h include\utsm\block.h vmm\..\..\tools\fat32_io.h
include\utsm\linux_compat.h:
include\utsm\types.h:
include\utsm\linux_resume.h:
include\utsm\ipc_shm.h:
..\utsm-ipc\ipc_proto.h:
include\utsm\vmm.h:
include\utsm\log.h:
include\utsm\block.h:
vmm\..\..\tools\fat32_io.h:
+40
View File
@@ -309,6 +309,46 @@ static void *linux_find_initrd_module(u64 *size_out) {
return (void *)0;
}
/* ===== rootfs module finder =====
*
* 在 Limine boot module 中查找 Arch rootfs 镜像(路径含 "rootfs")。
* 返回模块数据指针,*size_out 为大小;未找到返回 NULL。
* 该镜像通过 virtio-blk(memory-backed)暴露给 Linux guest 作为 /dev/vdb。 */
void *linux_find_rootfs_module(u64 *size_out) {
if (!g_module_request.response) return (void *)0;
struct limine_module_response *resp = g_module_request.response;
for (u64 i = 0; i < resp->module_count; i++) {
struct limine_file *file = resp->modules[i];
if (!file || !file->path) continue;
const char *p = file->path;
int match = 0;
for (const char *s = p; *s; s++) {
/* 匹配 "rootfs"(如 linux-rootfs.img) */
if ((s[0] == 'r' || s[0] == 'R') &&
(s[1] == 'o' || s[1] == 'O') &&
(s[2] == 'o' || s[2] == 'O') &&
(s[3] == 't' || s[3] == 'T') &&
(s[4] == 'f' || s[4] == 'F') &&
(s[5] == 's' || s[5] == 'S')) {
match = 1;
break;
}
}
if (!match) continue;
if (size_out) *size_out = file->size;
log_info("[LINUX] found rootfs module:");
log_info(file->path);
log_hex64("[LINUX] rootfs size=", file->size);
return file->address;
}
log_warn("[LINUX] no rootfs module found");
return (void *)0;
}
/* ===== bzImage parser ===== */
int linux_parse_bzimage(const void *bzimage, u64 size,
+10
View File
@@ -0,0 +1,10 @@
vmm/linux_loader.o: vmm\linux_loader.c include\utsm\linux_loader.h \
include\utsm\types.h include\utsm\vmx.h include\utsm\ept.h \
include\utsm\log.h include\utsm\dma.h vmm\..\arch\x86_64\limine.h
include\utsm\linux_loader.h:
include\utsm\types.h:
include\utsm\vmx.h:
include\utsm\ept.h:
include\utsm\log.h:
include\utsm\dma.h:
vmm\..\arch\x86_64\limine.h:
+8
View File
@@ -0,0 +1,8 @@
vmm/linux_resume.o: vmm\linux_resume.c include\utsm\linux_resume.h \
include\utsm\types.h include\utsm\vmx.h include\utsm\vmm.h \
include\utsm\log.h
include\utsm\linux_resume.h:
include\utsm\types.h:
include\utsm\vmx.h:
include\utsm\vmm.h:
include\utsm\log.h:
+196
View File
@@ -252,3 +252,199 @@ void virtio_blk_backend_init(void) {
virtio_mmio_register(&g_blk_backend);
}
/* ===== Memory-backed rootfs virtio-blk 后端 =====
*
* 第二个 virtio-blk 设备,后端为内存中的 Arch rootfs 镜像(Limine boot module)。
* guest 看到 /dev/vdb,挂载为真实根文件系统(ext4),switch_root 进入 Arch。
*
* 读写直接操作内存(memcpy),无需块设备 API。 */
/* byte-wise memcpy helper (freestanding, no libc) */
static void rf_memcpy(void *dst, const void *src, u64 n) {
u8 *d = (u8 *)dst;
const u8 *s = (const u8 *)src;
while (n--) *d++ = *s++;
}
static const u8 *g_rootfs_data; /* rootfs 镜像内存指针(HHDM 虚拟地址) */
static u64 g_rootfs_size; /* rootfs 镜像大小(字节) */
static u64 g_rootfs_capacity; /* rootfs 容量(扇区数,512B 单位) */
static u32 rootfs_blk_read_config(u32 offset, int width) {
(void)width;
struct virtio_blk_config cfg;
u8 *c = (u8 *)&cfg;
for (u32 i = 0; i < sizeof(cfg); i++) c[i] = 0;
cfg.capacity = g_rootfs_capacity;
cfg.size_max = 128;
cfg.seg_max = 32;
cfg.blk_size = 512;
if (offset + 4 <= sizeof(cfg)) {
u32 val = 0;
rf_memcpy(&val, c + offset, 4);
return val;
}
if (offset < sizeof(cfg)) {
u32 val = 0;
rf_memcpy(&val, c + offset, 4);
return val;
}
return 0;
}
/* rootfs 请求处理:直接内存拷贝 */
static u32 rootfs_blk_handle_chain(struct virtq_desc *desc, u16 head, u32 qnum) {
(void)qnum;
struct virtio_blk_outhdr hdr;
u8 *hptr = (u8 *)virtio_gpa_to_host(desc[head].addr);
if (!hptr) return 0;
rf_memcpy(&hdr, hptr, sizeof(hdr));
u32 type = hdr.type;
u64 sector = hdr.sector;
u16 data_idx = 0xFFFF;
u16 status_idx = 0xFFFF;
if (desc[head].flags & VIRTQ_DESC_F_NEXT) {
data_idx = desc[head].next;
u16 cur = data_idx;
int hops = 0;
while ((desc[cur].flags & VIRTQ_DESC_F_NEXT) && hops < 16) {
cur = desc[cur].next;
hops++;
}
status_idx = cur;
}
u8 *status = (u8 *)0;
if (status_idx != 0xFFFF && (desc[status_idx].flags & VIRTQ_DESC_F_WRITE)) {
status = (u8 *)virtio_gpa_to_host(desc[status_idx].addr);
}
u32 bytes_done = 0;
u8 result = VIRTIO_BLK_S_OK;
switch (type) {
case VIRTIO_BLK_T_IN: { /* 读:rootfs 内存 → guest */
if (data_idx == 0xFFFF || !g_rootfs_data) {
result = VIRTIO_BLK_S_IOERR;
break;
}
u8 *dbuf = (u8 *)virtio_gpa_to_host(desc[data_idx].addr);
u32 dlen = desc[data_idx].len;
if (!dbuf) { result = VIRTIO_BLK_S_IOERR; break; }
u64 offset = sector * 512ULL;
if (offset + dlen > g_rootfs_size) {
/* 超出范围:截断或填零 */
u64 avail = (offset < g_rootfs_size) ? (g_rootfs_size - offset) : 0;
if (avail > 0) {
rf_memcpy(dbuf, g_rootfs_data + offset, avail);
}
/* 剩余部分填零 */
if (dlen > avail) {
u8 *p = dbuf + avail;
u32 rem = dlen - (u32)avail;
while (rem--) *p++ = 0;
}
bytes_done = dlen;
} else {
rf_memcpy(dbuf, g_rootfs_data + offset, dlen);
bytes_done = dlen;
}
break;
}
case VIRTIO_BLK_T_OUT: /* 写:暂不支持(rootfs 只读) */
result = VIRTIO_BLK_S_IOERR;
break;
case VIRTIO_BLK_T_GET_ID:
if (data_idx != 0xFFFF) {
char *idbuf = (char *)virtio_gpa_to_host(desc[data_idx].addr);
if (idbuf) {
const char *id = "DESHAB-ROOTFS";
u32 i = 0;
for (; id[i] && i < desc[data_idx].len - 1; i++) idbuf[i] = id[i];
idbuf[i] = 0;
bytes_done = i + 1;
}
}
break;
case VIRTIO_BLK_T_FLUSH:
result = VIRTIO_BLK_S_OK;
break;
default:
result = VIRTIO_BLK_S_UNSUPP;
break;
}
if (status) *status = result;
return bytes_done;
}
static u16 g_rootfs_last_avail;
static void rootfs_blk_queue_notify(u32 queue_idx) {
struct virtq_desc *desc;
struct virtq_avail *avail;
struct virtq_used *used;
u32 qnum;
if (virtio_queue_get_ptrs(VIRTIO_ID_BLOCK, queue_idx,
&desc, &avail, &used, &qnum) != 0) {
return;
}
u16 cur = g_rootfs_last_avail;
u16 used_idx = used->idx;
while (cur != avail->idx) {
u16 head = avail->ring[cur % qnum];
u32 len = rootfs_blk_handle_chain(desc, head, qnum);
used->ring[used_idx % qnum].id = head;
used->ring[used_idx % qnum].len = len;
used_idx++;
cur++;
}
virtio_queue_bump_used(used, used_idx);
g_rootfs_last_avail = cur;
}
static void rootfs_blk_reset(void) {
g_rootfs_last_avail = 0;
}
static struct virtio_backend g_rootfs_blk_backend = {
.device_id = VIRTIO_ID_BLOCK,
.gpa_base = VIRTIO_MMIO_ROOTFS_GPA,
.irq = 7, /* guest ISA IRQ7(cmdline :7,vector 0x37) */
.num_queues = 1,
.queue_size = 128,
.device_features = (1ULL << VIRTIO_F_VERSION_1) |
(1ULL << VIRTIO_BLK_F_SIZE_MAX) |
(1ULL << VIRTIO_BLK_F_SEG_MAX) |
(1ULL << VIRTIO_BLK_F_BLK_SIZE) |
(1ULL << VIRTIO_BLK_F_FLUSH),
.config_len = sizeof(struct virtio_blk_config),
.read_config = rootfs_blk_read_config,
.queue_notify = rootfs_blk_queue_notify,
.reset = rootfs_blk_reset,
};
void virtio_rootfs_blk_init(void) {
u64 rootfs_size = 0;
void *rootfs = linux_find_rootfs_module(&rootfs_size);
if (!rootfs || rootfs_size == 0) {
log_warn("[VBLK] no rootfs module, rootfs-blk backend not registered");
return;
}
g_rootfs_data = (const u8 *)rootfs;
g_rootfs_size = rootfs_size;
g_rootfs_capacity = rootfs_size / 512; /* 扇区数 */
if (rootfs_size % 512) g_rootfs_capacity++;
log_info("[VBLK] rootfs-blk backend bound to memory module");
log_hex64("[VBLK] rootfs size=", rootfs_size);
log_hex64("[VBLK] rootfs capacity(sectors)=", g_rootfs_capacity);
virtio_mmio_register(&g_rootfs_blk_backend);
}
+8
View File
@@ -0,0 +1,8 @@
vmm/virtio_blk.o: vmm\virtio_blk.c include\utsm\virtio_mmio.h \
include\utsm\types.h include\utsm\linux_loader.h include\utsm\block.h \
include\utsm\log.h
include\utsm\virtio_mmio.h:
include\utsm\types.h:
include\utsm\linux_loader.h:
include\utsm\block.h:
include\utsm\log.h:
+17
View File
@@ -271,6 +271,18 @@ void virtio_queue_bump_used(struct virtq_used *used, u16 new_idx) {
__asm__ volatile("mfence" ::: "memory");
}
void virtio_mmio_raise_irq(u32 device_id) {
for (int i = 0; i < g_vdev_count; i++) {
struct virtio_dev_state *s = &g_vdevs[i];
if (!s->be || s->be->device_id != device_id) continue;
s->interrupt_status |= 1;
if (s->be->irq != 0) {
vmx_guest_queue_irq(0x30 + s->be->irq);
}
return;
}
}
/* ===== 框架初始化 =====
*
* 注册 block 与 net 后端。后端结构体由 virtio_blk.c / virtio_net.c 提供。 */
@@ -281,6 +293,7 @@ extern struct virtio_backend g_virtio_net_backend;
* 这里声明以便链接;具体注册在各自文件完成。 */
void virtio_blk_backend_init(void);
void virtio_net_backend_init(void);
void virtio_rootfs_blk_init(void); /* memory-backed Arch rootfs (/dev/vdb) */
void virtio_mmio_init(void) {
if (g_vio_ready) return;
@@ -288,6 +301,10 @@ void virtio_mmio_init(void) {
virtio_blk_backend_init();
virtio_net_backend_init();
/* Register memory-backed rootfs backend (no-op if no rootfs module found).
* Must come after blk/net so /dev/vda (SATA) and /dev/vdb (rootfs) order
* is deterministic. */
virtio_rootfs_blk_init();
g_vio_ready = 1;
log_info("[VIO] virtio-mmio backend init ok");
+10
View File
@@ -0,0 +1,10 @@
vmm/virtio_mmio.o: vmm\virtio_mmio.c include\utsm\virtio_mmio.h \
include\utsm\types.h include\utsm\linux_loader.h include\utsm\ept.h \
include\utsm\vmx.h include\utsm\log.h vmm\..\arch\x86_64\limine.h
include\utsm\virtio_mmio.h:
include\utsm\types.h:
include\utsm\linux_loader.h:
include\utsm\ept.h:
include\utsm\vmx.h:
include\utsm\log.h:
vmm\..\arch\x86_64\limine.h:

Some files were not shown because too many files have changed in this diff Show More