Files
Deshab-OS/CODE/UTSM/pe/pe_service.c
T

406 lines
16 KiB
C
Raw Normal View History

2026-07-31 13:53:49 +08:00
/* pe_service.c — PE 兼容层服务装配.
2026-07-28 14:35:14 +08:00
*
2026-07-31 13:53:49 +08:00
* 将 pe_loader + pe_shim + x86emu32 整合为统一的 pe_service,
* 通过 pe_get_service() 暴露给 DSK/cmd.elf(经 dsk_boot_context.reserved[4]).
2026-07-28 14:35:14 +08:00
*
2026-07-31 13:53:49 +08:00
* 执行策略:
* 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.
2026-07-28 14:35:14 +08:00
*/
#include "pe_loader.h"
#include "pe_shim.h"
2026-08-09 22:14:01 +08:00
#include "pe_dll_manager.h"
2026-07-28 14:35:14 +08:00
#include "x86emu32.h"
#include "../include/utsm/pe.h"
#include <utsm/arena.h>
#include <utsm/idt.h>
2026-07-28 14:35:14 +08:00
#include <utsm/log.h>
#include <utsm/types.h>
/* 32位 PE 用的栈与堆 */
#define PE32_STACK_SIZE (64 * 1024) /* 64KB 栈 */
#define PE32_HEAP_SIZE (256 * 1024) /* 256KB 堆 */
#define PE32_MAX_IAT 256
2026-07-31 13:53:49 +08:00
/* 合成 shim 地址范围(与 pe_loader.c 一致) */
2026-07-28 14:35:14 +08:00
#define PE32_SHIM_ADDR_BASE 0x00010000u
#define PE32_SHIM_UNIMPL 0x0001FFFFu
2026-07-31 13:53:49 +08:00
/* 前向声明(服务表引用) */
2026-07-28 14:35:14 +08:00
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);
2026-08-09 22:14:01 +08:00
int pe_service_run_windowed(const void *pe_data, u64 size, const char *cmdline,
u64 *exit_code, const pe_window_host *host);
2026-07-28 14:35:14 +08:00
2026-08-09 22:14:01 +08:00
/* 全局服务表实例(P5:ABI 尾部追加 run_windowed/inject_*,同镜像一致性
* 假设见 pe.h;旧调用方按前 4 字段使用不受影响) */
2026-07-28 14:35:14 +08:00
static const pe_service g_pe_service = {
PE_SERVICE_MAGIC,
pe_service_load,
pe_service_run,
pe_service_unload,
2026-08-09 22:14:01 +08:00
pe_service_run_windowed,
pe_shim_inject_scancode,
pe_shim_inject_pointer,
pe_shim_inject_input,
2026-07-28 14:35:14 +08:00
};
const pe_service *pe_get_service(void) {
return &g_pe_service;
}
2026-07-31 13:53:49 +08:00
/* ===== 加载(不执行)===== */
2026-07-28 14:35:14 +08:00
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);
}
void pe_service_unload(pe_image_info *info) {
pe_unload_image(info);
}
2026-07-31 13:53:49 +08:00
/* ===== PE32 专用加载器(加载到指定缓冲区,base=preferred_base,无重定位)===== */
2026-07-28 14:35:14 +08:00
typedef struct {
u8 *mem; /* 大缓冲区起始 */
u32 mem_size; /* 缓冲区总大小 */
u32 image_base; /* = preferred_base */
u32 image_size;
u32 entry_point; /* 绝对入口 = image_base + entry_rva */
pe_iat_entry iat[PE32_MAX_IAT];
int iat_count;
} pe32_interp_image;
static int pe32_load_into(const void *pe_data, u64 size, pe32_interp_image *img) {
const u8 *base = (const u8 *)pe_data;
if (size < sizeof(image_dos_header)) return -1;
const image_dos_header *dos = (const image_dos_header *)base;
if (dos->e_magic != IMAGE_DOS_SIGNATURE) return -2;
if ((u64)dos->e_lfanew + 4 + sizeof(image_file_header) > size) return -3;
const u8 *nt = base + dos->e_lfanew;
if (*(const u32 *)nt != IMAGE_NT_SIGNATURE) return -4;
const image_file_header *fh = (const image_file_header *)(nt + 4);
const void *opt = (const void *)(nt + 4 + sizeof(image_file_header));
u16 magic = *(const u16 *)opt;
if (magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return -5; /* 仅 PE32 */
const image_optional_header32 *oh = (const image_optional_header32 *)opt;
u32 preferred_base = oh->image_base;
u32 image_size = oh->size_of_image;
u32 entry_rva = oh->address_of_entry_point;
if (image_size == 0 || image_size > 64 * 1024 * 1024) return -6;
if (preferred_base > 0x10000000u) return -7; /* 解释器地址空间限制 */
int nsec = fh->number_of_sections;
if (nsec <= 0 || nsec > 96) return -8;
const image_section_header *sections = (const image_section_header *)
((const u8 *)opt + fh->size_of_optional_header);
2026-07-31 13:53:49 +08:00
/* 分配大缓冲区:[0 .. preferred_base + image_size + stack + heap] */
2026-07-28 14:35:14 +08:00
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;
for (u32 i = 0; i < total; i++) mem[i] = 0;
/* 复制 headers */
u32 hdr_copy = oh->size_of_headers;
if (hdr_copy > size) hdr_copy = (u32)size;
if (hdr_copy > image_size) hdr_copy = image_size;
u8 *img_start = mem + preferred_base;
for (u32 i = 0; i < hdr_copy; i++) img_start[i] = base[i];
/* 复制各节区 */
for (int i = 0; i < nsec; i++) {
u32 va = sections[i].virtual_address;
u32 raw_size = sections[i].size_of_raw_data;
u32 raw_off = sections[i].pointer_to_raw_data;
if (va >= image_size) continue;
u32 copy_size = raw_size;
if (va + copy_size > image_size) copy_size = image_size - va;
if ((u64)raw_off + copy_size > size) copy_size = (u32)(size - raw_off);
for (u32 j = 0; j < copy_size; j++) img_start[va + j] = base[raw_off + j];
}
2026-07-31 13:53:49 +08:00
/* 解析 imports,填充 IAT(合成地址) */
2026-07-28 14:35:14 +08:00
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) {
2026-07-31 13:53:49 +08:00
/* RVA->offset 辅助 */
2026-07-28 14:35:14 +08:00
for (int dll_idx = 0; ; dll_idx++) {
u32 imp_rva = import_dir->virtual_address + (u32)dll_idx * sizeof(image_import_descriptor);
/* imp_rva 在 image 内 */
if (imp_rva + sizeof(image_import_descriptor) > image_size) break;
const image_import_descriptor *desc = (const image_import_descriptor *)(img_start + imp_rva);
if (desc->name == 0 && desc->first_thunk == 0) break;
/* DLL 名 */
u32 name_rva = desc->name;
const char *dll_name = 0;
if (name_rva < image_size) dll_name = (const char *)(img_start + name_rva);
u32 iat_rva = desc->first_thunk;
u32 int_rva = desc->original_first_thunk;
if (int_rva == 0) int_rva = iat_rva;
for (int fn_idx = 0; ; fn_idx++) {
u32 int_entry_rva = int_rva + (u32)fn_idx * 4;
if (int_entry_rva + 4 > image_size) break;
u32 thunk = *(const u32 *)(img_start + int_entry_rva);
if (thunk == 0) break;
const char *func_name = 0;
if (thunk & 0x80000000u) {
func_name = "#ordinal";
} else {
u32 hint_rva = thunk;
if (hint_rva + 2 < image_size) {
func_name = (const char *)(img_start + hint_rva + 2);
}
}
int shim_idx = -1;
if (func_name && func_name[0] != '#') {
shim_idx = pe_shim_lookup(dll_name, func_name);
}
u32 synth_addr;
if (shim_idx >= 0) {
synth_addr = PE32_SHIM_ADDR_BASE | (u32)(shim_idx & 0xFFFF);
} else {
synth_addr = PE32_SHIM_UNIMPL;
}
u32 iat_entry_rva = iat_rva + (u32)fn_idx * 4;
if (iat_entry_rva + 4 <= image_size) {
*(u32 *)(img_start + iat_entry_rva) = synth_addr;
}
if (img->iat_count < PE32_MAX_IAT) {
img->iat[img->iat_count].iat_rva = iat_entry_rva;
img->iat[img->iat_count].shim_index = shim_idx;
img->iat[img->iat_count].target_addr = synth_addr;
img->iat_count++;
}
if (shim_idx < 0 && func_name) {
log_info("[PE32] unimplemented import");
if (dll_name) serial_write(dll_name);
serial_write("!");
serial_write(func_name);
serial_write("\n");
}
}
}
}
img->mem = mem;
img->mem_size = total;
img->image_base = preferred_base;
img->image_size = image_size;
img->entry_point = preferred_base + entry_rva;
return 0;
}
2026-07-31 13:53:49 +08:00
/* ===== 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");
}
2026-08-09 22:14:01 +08:00
/* PE32+ 大栈引导入口:先执行加载期延迟登记的真实 DLL DllMain(ATTACH),
* 再跳 PE 入口。此时 SSE 已启用且运行在 1MB PE 大栈上。 */
static pe_entry_fn g_pe_boot_entry;
static void pe_boot_with_dllmains(void) {
pe_dll_run_pending_dllmains();
g_pe_boot_entry();
}
2026-07-28 14:35:14 +08:00
/* ===== 运行 =====
2026-07-31 13:53:49 +08:00
* 加载 + 执行 + 卸载.返回 0 成功,*exit_code 为进程退出码. */
2026-07-28 14:35:14 +08:00
int pe_service_run(const void *pe_data, u64 size, const char *cmdline, u64 *exit_code) {
if (!pe_data || size == 0) return -1;
2026-07-31 13:53:49 +08:00
/* 初始化 shim 状态(cmdline for GetCommandLineA) */
2026-07-28 14:35:14 +08:00
pe_shim_init(cmdline ? cmdline : "");
/* 先解析 PE 判断 32/64 位 */
if (size < sizeof(image_dos_header)) return -2;
const image_dos_header *dos = (const image_dos_header *)pe_data;
if (dos->e_magic != IMAGE_DOS_SIGNATURE) return -3;
const u8 *nt_base = (const u8 *)pe_data + dos->e_lfanew;
if (*(const u32 *)nt_base != IMAGE_NT_SIGNATURE) return -4;
const void *opt = (const void *)(nt_base + 4 + sizeof(image_file_header));
u16 opt_magic = *(const u16 *)opt;
if (opt_magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
/* ===== PE32+ : Ring0 原生执行 ===== */
pe_image_info info;
2026-08-09 22:14:01 +08:00
/* SSE 必须在任何 PE/DLL 代码执行前启用:load 期会递归加载真实 DLL,
* MSVC CRT 代码含 SSE 指令,后置启用曾在 DllMain 内触发 #UD。 */
pe_enable_sse();
/* DllMain 延迟到 1MB PE 大栈上执行(16KB 内核栈跑不动 CRT init) */
pe_dll_defer_dllmain(1);
2026-07-28 14:35:14 +08:00
int rc = pe_load_image(pe_data, size, &info);
if (rc != 0) {
2026-08-09 22:14:01 +08:00
pe_dll_defer_dllmain(0);
2026-07-28 14:35:14 +08:00
log_error("[PE] PE32+ load failed");
return -5;
}
log_info("[PE] running PE32+ natively");
2026-07-31 13:53:49 +08:00
/* 恢复异常可见性:UTSM 交权 DSK 时 idt_halt_all() 将 IDT 全部
* 替换为静默 halt stub,PE 原生执行期间的 CPU 异常(PF/GP/UD)
* 会被无声吞掉。安装 PE 诊断 IDT 后异常走 idt_handler 打完整
* vector/err/rip/CR2/寄存器日志再安全停机。 */
idt_install_pe_diag();
2026-07-31 13:53:49 +08:00
/* 独立 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 对齐 */
2026-07-28 14:35:14 +08:00
/* BUG-20260801-006: __builtin_setjmp 必须直接出现在
* pe_service_run 本体内——该帧在 PE 执行全程存活,longjmp
* 恢复合法.原 pe_shim_setup_exit() 包装函数 setjmp 后即返回,
* longjmp 跨已销毁帧 = UB(实测从脏栈 pop 出 log_hex64 缓冲
* 残片充当 R12-R15/RBP → 野指针 call → 三重故障). */
2026-07-28 14:35:14 +08:00
u64 code = 0;
if (__builtin_setjmp(pe_shim_exit_jmpbuf()) == 0) {
2026-08-09 22:14:01 +08:00
log_hex64("[PE] entry=", (u64)info.entry_point);
2026-07-31 13:53:49 +08:00
log_hex64("[PE] stack_top=", stack_top);
2026-08-09 22:14:01 +08:00
g_pe_boot_entry = (pe_entry_fn)info.entry_point;
pe_call_on_stack(pe_boot_with_dllmains, stack_top);
2026-07-28 14:35:14 +08:00
code = 0;
} else {
code = pe_shim_get_exit_code();
log_hex64("[PE] ExitProcess code=", code);
}
pe_unload_image(&info);
if (exit_code) *exit_code = code;
return 0;
} else if (opt_magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
/* ===== PE32 : x86-32 解释器执行 ===== */
pe32_interp_image img;
int rc = pe32_load_into(pe_data, size, &img);
if (rc != 0) {
log_error("[PE] PE32 interp load failed");
log_hex64("[PE] rc=", (u64)(i64)rc);
return -6;
}
log_info("[PE] running PE32 via x86emu32");
u32 stack_top = img.image_base + img.image_size + PE32_STACK_SIZE - 16;
x86emu_state emu;
int irc = x86emu32_init(&emu, img.mem, img.mem_size,
img.image_base, img.image_size,
img.iat, img.iat_count, stack_top);
if (irc != 0) {
log_error("[PE32] emu init failed");
return -7;
}
emu.eip = img.entry_point;
/* BUG-20260801-007: fn64 回退 shim 收到的指针参数是 32 位
* guest VA,设置解释器内存基址使 shim 内 gp() 完成 guest→host
* 转换;运行结束立即复位(原生 PE32+ 路径恒为 0,gp 恒等映射). */
pe_shim_set_emu_base((u64)img.mem);
/* BUG-20260801-006: 同 PE32+ 路径,setjmp 直接出现在本体内.
* PE32 解释器路径同一 longjmp 机制,同样暴露在 UB 下. */
2026-07-28 14:35:14 +08:00
u64 code = 0;
if (__builtin_setjmp(pe_shim_exit_jmpbuf()) == 0) {
2026-07-28 14:35:14 +08:00
int rrc = x86emu32_run(&emu, &code);
if (rrc != 0) {
log_error("[PE32] emulator error");
code = 0xFFFFFFFFULL;
}
/* emu 字段只在未发生 longjmp 的正常返回路径读取
* (setjmp 语义:longjmp 后被修改的自动变量值不确定) */
if (emu.error && !emu.exited) {
log_warn("[PE32] emulator stopped with error");
}
2026-07-28 14:35:14 +08:00
} else {
code = pe_shim_get_exit_code();
log_hex64("[PE32] ExitProcess code=", code);
}
pe_shim_set_emu_base(0);
2026-07-28 14:35:14 +08:00
if (exit_code) *exit_code = code;
return 0;
}
return -8; /* 未知 PE magic */
}
2026-08-09 22:14:01 +08:00
/* ===== P5 窗口模式运行 =====
* 与 pe_service_run 相同的加载/执行路径,区别仅在 shim 行为:
* 渲染目标重定向到 host->surface,PS/2 轮询关闭,消息空转回调
* host->pump()(desktop 帧)。host==NULL/surface==NULL 时等价 run。 */
int pe_service_run_windowed(const void *pe_data, u64 size, const char *cmdline,
u64 *exit_code, const pe_window_host *host) {
if (host && host->surface) {
pe_shim_set_window_host(host);
log_info("[PE] run_windowed: surface mode");
} else {
pe_shim_set_window_host(0);
}
int rc = pe_service_run(pe_data, size, cmdline, exit_code);
pe_shim_set_window_host(0); /* 防止残留配置串到下一次 run */
return rc;
}