This commit is contained in:
xyou
2026-07-28 14:35:14 +08:00
parent 17a577f2ed
commit 537890df9e
44 changed files with 4903 additions and 404 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ CFLAGS := -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin -fno-
ASFLAGS := -target x86_64-unknown-none -ffreestanding -fno-pic -fno-pie -mcmodel=kernel -mno-red-zone -mno-sse -mno-sse2 -mno-mmx -msoft-float -m64 -Iinclude -I../utsm-ipc
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)
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)
+56
View File
@@ -0,0 +1,56 @@
#ifndef UTSM_LINUX_COMPAT_H
#define UTSM_LINUX_COMPAT_H
/* linux_compat.h — Deshab Linux 程序兼容层服务接口。
*
* 依赖 UTSM+Linux 双内核架构:Linux guest 作为 daemon 在 VMX guest 中
* park-and-resume 驻留。UTSM 侧的 linux_compat_service 通过 IPC 共享内存
* 向 Linux daemon 发送 exec 请求,并 vmresume 唤醒 guest 执行。
*
* 执行流程:
* 1. shell.elf / cmd.elf 通过 boot context 获取 linux_compat_service 指针
* 2. 调用 exec(path, argc, argv, ...) 写 IPC 请求到 utsm_to_linux ring
* 3. exec() 调用 linux_resume() → vmresume → Linux daemon fork+exec
* 4. daemon 通过 linux_to_utsm ring 回传 stdout/stderr/exit,然后 HLT park
* 5. exec() 从 ring 读取输出,返回给调用方
*
* 服务指针通过 dsk_boot_context.reserved[5] 暴露给 DSK 用户态(shell/cmd/desktop)。
*/
#include <utsm/types.h>
#define LINUX_COMPAT_MAGIC 0x4C4E58434F4D5000ULL /* "LNXCOMP\0" */
/* Linux 兼容层服务表 — 通过 boot context reserved[5] 传递 */
typedef struct linux_compat_service {
u64 magic; /* LINUX_COMPAT_MAGIC */
/* 查询 Linux 兼容层是否可用(Linux guest 已 park 且 IPC 就绪)。
* 返回 1 可用,0 不可用。 */
int (*is_available)(void);
/* 执行一个 Linux 程序。
* path : 程序路径(如 "/bin/ls"),NUL-terminated
* argc/argv : 参数向量(argv[0] 通常为程序名)
* stdout_buf : 接收 stdout 的缓冲区(可为 NULL,此时丢弃 stdout)
* stdout_cap : stdout_buf 容量(字节)
* stdout_len : 输出实际写入的字节数(可为 NULL)
* exit_code : 输出进程退出码(可为 NULL)
* 返回 0 成功,负值失败(-1=服务不可用, -2=IPC 发送失败,
* -3=linux_resume 失败, -4=超时无响应)。 */
int (*exec)(const char *path, int argc, const char *const *argv,
char *stdout_buf, u64 stdout_cap, u64 *stdout_len,
u64 *exit_code);
/* 查询 Linux guest 状态字符串(调试用),写入 buf,返回字符串长度。 */
int (*status)(char *buf, u64 cap);
} linux_compat_service;
/* 获取全局 Linux 兼容层服务实例指针(UTSM 内部使用,
* 外部通过 boot context reserved[5] 获取)。 */
const linux_compat_service *linux_compat_get_service(void);
/* 初始化 Linux 兼容层服务(在 linux_launch 成功后调用)。 */
void linux_compat_init(void);
#endif /* UTSM_LINUX_COMPAT_H */
+5 -2
View File
@@ -162,9 +162,12 @@ const struct linux_guest_info *linux_get_guest_info(void);
* Returns 0 on successful guest termination, negative on error. */
int linux_launch(void);
/* Default Linux command line (can be overridden). */
/* Default Linux command line (can be overridden).
* nohlt: prevent kernel idle loop from using HLT — only the exec daemon's
* explicit ioctl(PARK) HLT should trigger VM-Exit park, so that
* linux_launch() returns only after the daemon is ready. */
#define LINUX_DEFAULT_CMDLINE \
"console=ttyS0,115200 earlyprintk=serial nokaslr " \
"no_timer_check loglevel=7"
"no_timer_check loglevel=7 nohlt idle=poll"
#endif
+28
View File
@@ -0,0 +1,28 @@
#ifndef UTSM_LINUX_RESUME_H
#define UTSM_LINUX_RESUME_H
#include <utsm/types.h>
/* linux_resume.h — Linux guest park-and-resume 唤醒接口。
*
* linux_launch() 启动 Linux guest 后,guest daemon 完成 init 并 HLT 驻留(park)。
* linux_resume() 通过 vmresume 唤醒 guest,daemon 处理 IPC 请求后再次 HLT park,
* 控制权返回 host。
*
* 典型流程:
* 1. shell 调用 linux_compat_service->exec(path, argc, argv)
* 2. exec() 写 IPC 请求到 utsm_to_linux ring
* 3. exec() 调用 linux_resume() → vmresume → guest daemon 读取请求 → fork+exec
* 4. daemon 写输出到 linux_to_utsm ring → HLT park → linux_resume() 返回
* 5. exec() 从 ring 读取输出,返回给 shell
*/
/* 唤醒已 park 的 Linux guest。
* 前置条件:g_guest_parked == 1(linux_launch 已完成且 guest 已 HLT)。
* 返回 0 成功(guest 再次 park),负值失败。 */
int linux_resume(void);
/* 查询 Linux guest 是否已 park 就绪。 */
int linux_is_parked(void);
#endif /* UTSM_LINUX_RESUME_H */
+42
View File
@@ -0,0 +1,42 @@
#ifndef UTSM_PE_H
#define UTSM_PE_H
/* pe.h — Deshab PE/EXE 兼容层公共接口。
*
* UTSM 内置 PE32+(64位)与 PE32(32位)加载器:
* - PE32+:解析 → 映射节区 → 基址重定位 → import 解析(Windows API shim)→ Ring0 原生执行
* - PE32 :解析 → 映射节区 → 基址重定位 → import 解析 → x86-32 解释器执行
*
* pe_service 通过 dsk_boot_context.reserved[4] 暴露给 DSK/cmd.elf,
* 同地址空间 Ring0 直接调用。
*/
#include <utsm/types.h>
#define PE_SERVICE_MAGIC 0x5045535643200000ULL /* "PESVC\0\0" */
/* PE 加载结果 */
typedef struct pe_image_info {
u64 image_base; /* 实际加载基址(kmem_alloc_aligned 返回) */
u64 image_size; /* 映射后总大小(SizeOfImage) */
u64 entry_point; /* 绝对入口地址 = image_base + AddressOfEntryPoint */
int is_pe32_plus; /* 1=PE32+ 64位原生执行, 0=PE32 32位解释执行 */
int load_ok; /* 1=加载成功 */
} pe_image_info;
/* PE 服务表 — 通过 boot context reserved[4] 传递 */
typedef struct pe_service {
u64 magic; /* PE_SERVICE_MAGIC */
/* 加载 PE 到内存(不执行)。返回 0 成功,info 填充。 */
int (*load)(const void *pe_data, u64 size, pe_image_info *out);
/* 加载并执行 PE。cmdline = 命令行字符串(GetCommandLineA 返回值)。
* 返回 0 成功,*exit_code 为进程退出码。 */
int (*run)(const void *pe_data, u64 size, const char *cmdline, u64 *exit_code);
/* 释放 pe_load 分配的镜像内存。 */
void (*unload)(pe_image_info *info);
} pe_service;
/* 获取全局 PE 服务实例指针(UTSM 内部使用,外部通过 boot context 获取) */
const pe_service *pe_get_service(void);
#endif /* UTSM_PE_H */
+24
View File
@@ -42,6 +42,30 @@ struct vmexit_guest_regs {
* Non-static: shared between vmm.c, vmexit.c, hypercall.c, and vmexit_asm.S. */
extern volatile struct vmexit_guest_regs g_guest_regs;
/* ===== Linux guest park-and-resume 状态 =====
*
* g_linux_guest_active: 1 = 当前运行的 guest 是 Linux guest。
* handle_hlt 检查此标志:Linux guest HLT 时 park(推进 RIP,exit-to-host),
* self-test guest HLT 时 terminate。
* g_guest_parked: 1 = Linux guest 已 HLT 驻留,可被 linux_resume() 唤醒。
* linux_compat_service 通过此标志判断 guest 是否就绪。 */
extern volatile int g_linux_guest_active;
extern volatile int g_guest_parked;
/* ===== VM-Exit host 恢复点(vmm.c 定义,vmm.c / linux_boot.c / linux_resume.c 共用) =====
*
* g_saved_host_rsp: vmlaunch/vmresume 前保存的 host RSP。VM-Exit 处理器
* 终止 guest 时恢复此 RSP 并 jmp 到 g_saved_return_rip。
* g_saved_return_rip: vmlaunch/vmresume 后的返回地址(post_guest / post_resume 标签)。
* g_guest_terminated: 1 = guest 已终止(不再 vmresume)。dispatch 返回 0 时置位。
* g_last_exit_reason: 最近一次 VM-Exit 的 reason(vmexit_asm.S 路径写入)。
*
* 这些符号必须是非 static 全局变量,因为 vmexit_asm.S 通过 RIP 相对寻址引用。 */
extern volatile u64 g_saved_host_rsp;
extern volatile u64 g_saved_return_rip;
extern volatile int g_guest_terminated;
extern volatile u64 g_last_exit_reason;
/* ===== VMM API ===== */
/* 初始化 VMM:VMX root 模式 + EPT 表 + 分配 VMCS。
+14
View File
@@ -3,6 +3,8 @@
#include <utsm/dkm.h>
#include <utsm/log.h>
#include <utsm/types.h>
#include <utsm/pe.h>
#include <utsm/linux_compat.h>
#include "../arch/x86_64/limine.h"
#define DSK_PATH "/system/deshab64/deshab.elf"
@@ -319,6 +321,18 @@ static void dsk_fill_boot_context(dsk_boot_context *ctx) {
ctx->boot_modules_response = (u64)g_module_request.response;
ctx->dkm_kernel_api = (u64)dkm_get_kernel_api();
/* PE 兼容层服务(PE32+ 原生 + PE32 解释器) */
const pe_service *pe = pe_get_service();
if (pe && pe->magic == PE_SERVICE_MAGIC) {
ctx->reserved[4] = (u64)pe;
}
/* Linux 兼容层服务(依赖双内核 park-and-resume + IPC) */
const linux_compat_service *lxc = linux_compat_get_service();
if (lxc && lxc->magic == LINUX_COMPAT_MAGIC) {
ctx->reserved[5] = (u64)lxc;
}
u64 rsp;
__asm__ volatile ("movq %%rsp, %0" : "=r"(rsp));
ctx->kernel_stack_top = rsp;
Binary file not shown.
+5 -1
View File
@@ -8,6 +8,7 @@
#include <utsm/block.h>
#include <utsm/net.h>
#include <utsm/ipc_shm.h>
#include <utsm/linux_compat.h>
void arch_halt_forever(void);
@@ -71,7 +72,10 @@ void kernel_main(void) {
int lin_st = linux_launch();
if (lin_st == 0) {
log_info("[UTSM] Linux guest terminated");
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);
Binary file not shown.
+368
View File
@@ -0,0 +1,368 @@
/* pe_loader.c — PE32+/PE32 解析、节区映射、重定位、import 解析。
*
* 加载流程:
* 1. 验证 MZ + PE 签名
* 2. 区分 PE32(OptionalHeader.Magic=0x10b)/ PE32+(0x20b)
* 3. 分配 SizeOfImage 字节 RWX 内存(kmem_alloc_aligned)
* 4. 复制 SizeOfHeaders + 各节区 raw data 到 virtual_address
* 5. 应用基址重定位(.reloc 节区:DIR64 for PE32+,HIGHLOW for PE32)
* 6. 解析 import 表,用 shim 函数指针填充 IAT
* 7. 构建 IAT 条目表(供 32位解释器 CALL 拦截)
*/
#include "pe_loader.h"
#include "pe_shim.h"
#include "x86emu32.h"
#include "../include/utsm/pe.h"
#include <utsm/arena.h>
#include <utsm/log.h>
#include <utsm/types.h>
/* 合成 shim 地址范围(32位解释器用):0x00010000..0x0001FFFF */
#define PE_SHIM_ADDR_BASE 0x00010000u
#define PE_SHIM_ADDR_END 0x00020000u
#define PE_SHIM_UNIMPL 0x0001FFFFu
/* 全局 IAT 表(pe_loader 填充,x86emu32 读取) */
static pe_iat_entry g_iat_entries[256];
static int g_iat_count;
/* ---- 辅助:RVA → 文件偏移 ---- */
static u32 rva_to_offset(const image_section_header *sections, int nsec,
u32 rva, u32 *out_size) {
for (int i = 0; i < nsec; i++) {
u32 va = sections[i].virtual_address;
u32 vs = sections[i].virtual_size;
if (vs == 0) vs = sections[i].size_of_raw_data;
if (rva >= va && rva < va + vs) {
if (out_size) *out_size = vs;
return sections[i].pointer_to_raw_data + (rva - va);
}
}
if (out_size) *out_size = 0;
return 0xFFFFFFFF;
}
/* ---- 解析 NT 头 ---- */
typedef struct {
const image_file_header *file_hdr;
const void *optional_hdr;
int is_pe32_plus;
u32 image_base; /* 32位截断的加载基址(PE32+ 也截断用于 RVA 计算) */
u32 size_of_image;
u32 size_of_headers;
u32 entry_rva;
const image_data_directory *data_dir;
} pe_nt_info;
static int parse_nt_headers(const void *pe_data, u64 size, pe_nt_info *out) {
if (size < sizeof(image_dos_header)) return -1;
const image_dos_header *dos = (const image_dos_header *)pe_data;
if (dos->e_magic != IMAGE_DOS_SIGNATURE) return -2;
if (dos->e_lfanew + 4 + sizeof(image_file_header) > size) return -3;
const u8 *nt_base = (const u8 *)pe_data + dos->e_lfanew;
u32 sig = *(const u32 *)nt_base;
if (sig != IMAGE_NT_SIGNATURE) return -4;
const image_file_header *fh = (const image_file_header *)(nt_base + 4);
out->file_hdr = fh;
const void *opt = (const void *)(nt_base + 4 + sizeof(image_file_header));
out->optional_hdr = opt;
u16 magic = *(const u16 *)opt;
if (magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
const image_optional_header64 *oh = (const image_optional_header64 *)opt;
out->is_pe32_plus = 1;
out->image_base = (u32)oh->image_base;
out->size_of_image = oh->size_of_image;
out->size_of_headers = oh->size_of_headers;
out->entry_rva = oh->address_of_entry_point;
out->data_dir = oh->data_directory;
} else if (magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
const image_optional_header32 *oh = (const image_optional_header32 *)opt;
out->is_pe32_plus = 0;
out->image_base = oh->image_base;
out->size_of_image = oh->size_of_image;
out->size_of_headers = oh->size_of_headers;
out->entry_rva = oh->address_of_entry_point;
out->data_dir = oh->data_directory;
} else {
return -5;
}
if (out->size_of_image == 0 || out->size_of_image > 64 * 1024 * 1024) return -6;
if (out->entry_rva == 0 || out->entry_rva >= out->size_of_image) return -7;
return 0;
}
/* ---- 应用基址重定位 ---- */
static void apply_relocations(u8 *image, u32 image_size, u64 image_base_actual, u32 image_base_preferred,
const image_data_directory *reloc_dir,
const image_section_header *sections, int nsec,
const void *pe_data, u64 pe_size, int is_pe32_plus) {
if (reloc_dir->virtual_address == 0 || reloc_dir->size == 0) return;
u32 block_rva = reloc_dir->virtual_address;
u32 block_end = block_rva + reloc_dir->size;
i64 delta = (i64)image_base_actual - (i64)image_base_preferred;
if (delta == 0) return; /* 加载到首选基址,无需重定位 */
while (block_rva < block_end) {
u32 dummy_size;
u32 file_off = rva_to_offset(sections, nsec, block_rva, &dummy_size);
if (file_off == 0xFFFFFFFF || file_off + 8 > pe_size) break;
const u8 *block = (const u8 *)pe_data + file_off;
u32 page_rva = *(const u32 *)block;
u32 block_size = *(const u32 *)(block + 4);
if (block_size < 8 || block_rva + block_size > block_end) break;
u32 entry_count = (block_size - 8) / 2;
const u16 *entries = (const u16 *)(block + 8);
for (u32 i = 0; i < entry_count; i++) {
u16 e = entries[i];
u32 type = (e >> 12) & 0xF;
u32 offset = e & 0xFFF;
if (type == IMAGE_REL_BASED_ABSOLUTE) continue;
u32 target_rva = page_rva + offset;
/* image 缓冲区按 RVA 排列(image[0] = RVA 0) */
if (target_rva >= (u32)image_size) continue;
u8 *target = image + target_rva;
if (type == IMAGE_REL_BASED_DIR64) {
u64 val = *(u64 *)target;
val += (u64)delta;
*(u64 *)target = val;
} else if (type == IMAGE_REL_BASED_HIGHLOW) {
u32 val = *(u32 *)target;
val += (u32)delta;
*(u32 *)target = val;
} else {
/* 其他重定位类型暂不支持 */
}
}
block_rva += block_size;
}
(void)is_pe32_plus;
}
/* ---- 解析 imports,填充 IAT ---- */
static void resolve_imports(u8 *image, u64 image_base_actual,
const image_data_directory *import_dir,
const image_section_header *sections, int nsec,
const void *pe_data, u64 pe_size, int is_pe32_plus) {
(void)image_base_actual; /* PE32 IAT 用合成地址,不依赖 actual_base */
if (import_dir->virtual_address == 0 || import_dir->size == 0) return;
g_iat_count = 0;
u32 dummy;
u32 imp_off = rva_to_offset(sections, nsec, import_dir->virtual_address, &dummy);
if (imp_off == 0xFFFFFFFF) return;
const image_import_descriptor *imp = (const image_import_descriptor *)
((const u8 *)pe_data + imp_off);
for (int dll_idx = 0; ; dll_idx++) {
const image_import_descriptor *desc = &imp[dll_idx];
if (desc->name == 0 && desc->first_thunk == 0) break;
/* DLL 名 */
u32 name_off = rva_to_offset(sections, nsec, desc->name, &dummy);
if (name_off == 0xFFFFFFFF || name_off >= pe_size) continue;
const char *dll_name = (const char *)pe_data + name_off;
/* IAT (first_thunk) 与 INT (original_first_thunk) */
u32 iat_rva = desc->first_thunk;
u32 int_rva = desc->original_first_thunk;
if (int_rva == 0) int_rva = iat_rva; /* 无 INT,直接用 IAT */
u32 iat_off = rva_to_offset(sections, nsec, iat_rva, &dummy);
u32 int_off = rva_to_offset(sections, nsec, int_rva, &dummy);
for (int fn_idx = 0; ; fn_idx++) {
u32 iat_entry_off = iat_off + (u32)fn_idx * (is_pe32_plus ? 8 : 4);
if (iat_entry_off + (is_pe32_plus ? 8 : 4) > pe_size) break;
u32 int_entry_off = int_off + (u32)fn_idx * (is_pe32_plus ? 8 : 4);
if (int_entry_off + (is_pe32_plus ? 8 : 4) > pe_size) break;
/* 读 INT 条目判断函数名/序号 */
u64 thunk = 0;
if (is_pe32_plus) {
thunk = *(const u64 *)((const u8 *)pe_data + int_entry_off);
} else {
thunk = *(const u32 *)((const u8 *)pe_data + int_entry_off);
}
if (thunk == 0) break; /* 结束 */
const char *func_name = 0;
if (thunk & 0x80000000ULL) {
/* 序号导入:暂不支持,记为未实现 */
func_name = "#ordinal";
} else {
/* 名称导入:thunk 是 IMAGE_IMPORT_BY_NAME 的 RVA */
u32 hint_rva = (u32)thunk;
u32 hint_off = rva_to_offset(sections, nsec, hint_rva, &dummy);
if (hint_off != 0xFFFFFFFF && hint_off + 2 < pe_size) {
func_name = (const char *)pe_data + hint_off + 2; /* 跳过 hint(2字节) */
}
}
/* 查 shim 表 */
int shim_idx = -1;
if (func_name && func_name[0] != '#') {
shim_idx = pe_shim_lookup(dll_name, func_name);
}
/* 填充 IAT(image 缓冲区内) */
u8 *iat_ptr = image + iat_rva + (u32)fn_idx * (is_pe32_plus ? 8 : 4);
if (is_pe32_plus) {
u64 fn_addr;
if (shim_idx >= 0) {
const pe_shim_entry *se = pe_shim_get(shim_idx);
fn_addr = (u64)se->fn64;
} else {
fn_addr = pe_shim_unimpl_stub();
}
*(u64 *)iat_ptr = fn_addr;
} else {
/* 32位:填合成地址,解释器拦截 */
u32 synth_addr;
if (shim_idx >= 0) {
synth_addr = PE_SHIM_ADDR_BASE | (u32)(shim_idx & 0xFFFF);
} else {
synth_addr = PE_SHIM_UNIMPL;
}
*(u32 *)iat_ptr = synth_addr;
/* 记录 IAT 条目供解释器查询 */
if (g_iat_count < 255) {
g_iat_entries[g_iat_count].iat_rva = iat_rva + (u32)fn_idx * 4;
g_iat_entries[g_iat_count].shim_index = shim_idx;
g_iat_entries[g_iat_count].target_addr = synth_addr;
g_iat_count++;
}
}
if (shim_idx < 0 && func_name) {
log_info("[PE] unimplemented import");
serial_write(dll_name);
serial_write("!");
serial_write(func_name);
serial_write("\n");
}
}
}
}
/* ---- 主加载函数 ---- */
int pe_load_image(const void *pe_data, u64 size, pe_image_info *out) {
if (!pe_data || !out || size < sizeof(image_dos_header)) return -1;
pe_nt_info nt;
int rc = parse_nt_headers(pe_data, size, &nt);
if (rc != 0) {
log_error("[PE] NT header parse failed");
log_hex64("[PE] rc=", (u64)(i64)rc);
return -2;
}
/* 节区头 */
int nsec = nt.file_hdr->number_of_sections;
if (nsec <= 0 || nsec > 96) return -3;
usize opt_size = nt.file_hdr->size_of_optional_header;
const image_section_header *sections = (const image_section_header *)
((const u8 *)nt.optional_hdr + opt_size);
/* 分配 SizeOfImage RWX 内存 */
u32 img_size = nt.size_of_image;
u8 *image = (u8 *)kmem_alloc_aligned(img_size, 0x1000);
if (!image) {
log_error("[PE] alloc image failed");
return -4;
}
/* 清零 */
for (u32 i = 0; i < img_size; i++) image[i] = 0;
/* 复制 headers */
u32 hdr_copy = nt.size_of_headers;
if (hdr_copy > size) hdr_copy = (u32)size;
if (hdr_copy > img_size) hdr_copy = img_size;
for (u32 i = 0; i < hdr_copy; i++) image[i] = ((const u8 *)pe_data)[i];
/* 复制各节区 raw data */
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 >= img_size) continue;
u32 copy_size = raw_size;
if (va + copy_size > img_size) copy_size = img_size - va;
if (raw_off + copy_size > size) {
copy_size = (u32)(size - raw_off);
}
if (raw_off + copy_size > size) continue;
for (u32 j = 0; j < copy_size; j++) {
image[va + j] = ((const u8 *)pe_data)[raw_off + j];
}
}
/* 基址重定位 */
u64 actual_base = (u64)image;
u32 preferred_base = nt.image_base;
/* image 缓冲区按 RVA 排列(image[0]=RVA 0),重定位写入 image 内 */
/* 注意:apply_relocations 直接操作 image 缓冲区,delta = actual_base - preferred_base */
{
const image_data_directory *reloc_dir = &nt.data_dir[IMAGE_DIRECTORY_ENTRY_BASERELOC];
/* 重定位 target 是 RVA,写入 image[rva]。
* 但 image 加载在 actual_base,代码中绝对地址 = actual_base + RVA。
* 重定位修正量 = actual_base - preferred_base。
* image[rva] 处的值原为 preferred_base + rva_offset(链接时假设),
* 修正后应为 actual_base + rva_offset,即加 delta。 */
apply_relocations(image, img_size, actual_base, preferred_base, reloc_dir,
sections, nsec, pe_data, size, nt.is_pe32_plus);
}
/* 解析 imports */
{
const image_data_directory *import_dir = &nt.data_dir[IMAGE_DIRECTORY_ENTRY_IMPORT];
resolve_imports(image, actual_base, import_dir, sections, nsec,
pe_data, size, nt.is_pe32_plus);
}
out->image_base = actual_base;
out->image_size = img_size;
out->entry_point = actual_base + nt.entry_rva;
out->is_pe32_plus = nt.is_pe32_plus;
out->load_ok = 1;
log_hex64("[PE] loaded base=", actual_base);
log_hex64("[PE] image size=", img_size);
log_hex64("[PE] entry=", out->entry_point);
log_info(nt.is_pe32_plus ? "[PE] PE32+ (64-bit)" : "[PE] PE32 (32-bit)");
return 0;
}
void pe_unload_image(pe_image_info *info) {
if (!info || !info->load_ok) return;
/* kmem_alloc_aligned 无对应 free(arena 分配器),标记为未加载即可 */
info->load_ok = 0;
}
u64 pe_get_image_base(const pe_image_info *info) {
return info ? info->image_base : 0;
}
u64 pe_get_image_size(const pe_image_info *info) {
return info ? info->image_size : 0;
}
/* 供 x86emu32 获取 IAT 表 */
pe_iat_entry *pe_get_iat_entries(int *count) {
if (count) *count = g_iat_count;
return g_iat_entries;
}
+185
View File
@@ -0,0 +1,185 @@
#ifndef PE_LOADER_H
#define PE_LOADER_H
/* pe_loader.h — PE32+/PE32 解析与加载器内部接口。 */
#include <utsm/types.h>
#include <utsm/pe.h>
/* ===== PE 常量 ===== */
#define IMAGE_DOS_SIGNATURE 0x5A4D /* "MZ" */
#define IMAGE_NT_SIGNATURE 0x00004550 /* "PE\0\0" */
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
/* Section characteristics */
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
#define IMAGE_SCN_MEM_READ 0x40000000
#define IMAGE_SCN_MEM_WRITE 0x80000000
/* Data directory indices */
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
#define IMAGE_DIRECTORY_ENTRY_IAT 12
/* Relocation types */
#define IMAGE_REL_BASED_ABSOLUTE 0
#define IMAGE_REL_BASED_HIGHLOW 3 /* 32位: base + offset 写 32位 */
#define IMAGE_REL_BASED_DIR64 10 /* 64位: base + offset 写 64位 */
/* ===== PE 结构体定义(packed) ===== */
typedef struct __attribute__((packed)) {
u16 e_magic; /* "MZ" */
u16 e_cblp;
u16 e_cp;
u16 e_crlc;
u16 e_cparhdr;
u16 e_minalloc;
u16 e_maxalloc;
u16 e_ss;
u16 e_sp;
u16 e_csum;
u16 e_ip;
u16 e_cs;
u16 e_lfarlc;
u16 e_ovno;
u16 e_res[4];
u16 e_oemid;
u16 e_oeminfo;
u16 e_res2[10];
u32 e_lfanew; /* PE 头偏移 */
} image_dos_header;
typedef struct __attribute__((packed)) {
u16 machine;
u16 number_of_sections;
u32 time_date_stamp;
u32 pointer_to_symbol_table;
u32 number_of_symbols;
u16 size_of_optional_header;
u16 characteristics;
} image_file_header;
typedef struct __attribute__((packed)) {
u32 virtual_address;
u32 size;
} image_data_directory;
typedef struct __attribute__((packed)) {
u16 magic;
u8 major_linker_version;
u8 minor_linker_version;
u32 size_of_code;
u32 size_of_initialized_data;
u32 size_of_uninitialized_data;
u32 address_of_entry_point;
u32 base_of_code;
u32 base_of_data; /* PE32 only */
u32 image_base; /* PE32: 32位 */
u32 section_alignment;
u32 file_alignment;
u16 major_os_version;
u16 minor_os_version;
u16 major_image_version;
u16 minor_image_version;
u16 major_subsystem_version;
u16 minor_subsystem_version;
u32 win32_version_value;
u32 size_of_image;
u32 size_of_headers;
u32 check_sum;
u16 subsystem;
u16 dll_characteristics;
u32 size_of_stack_reserve;
u32 size_of_stack_commit;
u32 size_of_heap_reserve;
u32 size_of_heap_commit;
u32 loader_flags;
u32 number_of_rva_and_sizes;
image_data_directory data_directory[16];
} image_optional_header32;
typedef struct __attribute__((packed)) {
u16 magic;
u8 major_linker_version;
u8 minor_linker_version;
u32 size_of_code;
u32 size_of_initialized_data;
u32 size_of_uninitialized_data;
u32 address_of_entry_point;
u32 base_of_code;
u64 image_base; /* PE32+: 64位 */
u32 section_alignment;
u32 file_alignment;
u16 major_os_version;
u16 minor_os_version;
u16 major_image_version;
u16 minor_image_version;
u16 major_subsystem_version;
u16 minor_subsystem_version;
u32 win32_version_value;
u32 size_of_image;
u32 size_of_headers;
u32 check_sum;
u16 subsystem;
u16 dll_characteristics;
u64 size_of_stack_reserve;
u64 size_of_stack_commit;
u64 size_of_heap_reserve;
u64 size_of_heap_commit;
u32 loader_flags;
u32 number_of_rva_and_sizes;
image_data_directory data_directory[16];
} image_optional_header64;
typedef struct __attribute__((packed)) {
u8 name[8];
u32 virtual_size;
u32 virtual_address;
u32 size_of_raw_data;
u32 pointer_to_raw_data;
u32 pointer_to_relocations;
u32 pointer_to_linenumbers;
u16 number_of_relocations;
u16 number_of_linenumbers;
u32 characteristics;
} image_section_header;
typedef struct __attribute__((packed)) {
u32 original_first_thunk; /* INT (Import Name Table) RVA */
u32 time_date_stamp;
u32 forwarder_chain;
u32 name; /* DLL 名 RVA */
u32 first_thunk; /* IAT RVA */
} image_import_descriptor;
typedef struct __attribute__((packed)) {
u32 original_first_thunk; /* 指向 IMAGE_IMPORT_BY_NAME */
} image_import_by_name_ref;
/* ===== 加载器 API ===== */
/* 解析并加载 PE 到内存。
* - 分配 SizeOfImage 字节 RWX 内存
* - 复制 headers + 各节区
* - 应用基址重定位
* - 解析 imports(填 IAT 为 shim 函数指针)
* 返回 0 成功,info 填充;负数失败。 */
int pe_load_image(const void *pe_data, u64 size, pe_image_info *out);
/* 释放 pe_load_image 分配的内存 */
void pe_unload_image(pe_image_info *info);
/* 获取 PE 内部信息(供 shim/解释器使用) */
u64 pe_get_image_base(const pe_image_info *info);
u64 pe_get_image_size(const pe_image_info *info);
/* 获取 IAT 条目表(供 32位解释器 CALL 拦截)。
* pe_iat_entry 定义在 x86emu32.h。返回表指针,*count 填充条目数。 */
struct pe_iat_entry;
struct pe_iat_entry *pe_get_iat_entries(int *count);
#endif /* PE_LOADER_H */
+290
View File
@@ -0,0 +1,290 @@
/* pe_service.c — PE 兼容层服务装配。
*
* 将 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。
*/
#include "pe_loader.h"
#include "pe_shim.h"
#include "x86emu32.h"
#include "../include/utsm/pe.h"
#include <utsm/arena.h>
#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
/* 合成 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);
/* 全局服务表实例 */
static const pe_service g_pe_service = {
PE_SERVICE_MAGIC,
pe_service_load,
pe_service_run,
pe_service_unload,
};
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);
}
void pe_service_unload(pe_image_info *info) {
pe_unload_image(info);
}
/* ===== PE32 专用加载器(加载到指定缓冲区,base=preferred_base,无重定位)===== */
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);
/* 分配大缓冲区:[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;
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];
}
/* 解析 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 辅助 */
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;
}
/* ===== 运行 =====
* 加载 + 执行 + 卸载。返回 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) */
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;
int rc = pe_load_image(pe_data, size, &info);
if (rc != 0) {
log_error("[PE] PE32+ load failed");
return -5;
}
log_info("[PE] running PE32+ natively");
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();
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;
u64 code = 0;
int jumped = pe_shim_setup_exit();
if (jumped == 0) {
int rrc = x86emu32_run(&emu, &code);
if (rrc != 0) {
log_error("[PE32] emulator error");
code = 0xFFFFFFFFULL;
}
} else {
code = pe_shim_get_exit_code();
log_hex64("[PE32] ExitProcess code=", code);
}
if (emu.error && !emu.exited) {
log_warn("[PE32] emulator stopped with error");
}
if (exit_code) *exit_code = code;
return 0;
}
return -8; /* 未知 PE magic */
}
+421
View File
@@ -0,0 +1,421 @@
/* pe_shim.c — Windows API shim 实现。
*
* 所有 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)
*/
#include "pe_shim.h"
#include <utsm/arena.h>
#include <utsm/log.h>
#include <utsm/types.h>
/* setjmp/longjmp for ExitProcess — 使用 __builtin_setjmp/__builtin_longjmp
* (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;
static const char *g_cmdline = "";
void pe_shim_init(const char *cmdline) {
g_cmdline = cmdline ? cmdline : "";
g_exit_jmp_set = 0;
g_exit_code = 0;
}
/* pe_run 调用:保存上下文,返回 0 = 首次(继续执行),1 = ExitProcess 触发 */
int pe_shim_setup_exit(void) {
g_exit_jmp_set = 1;
return __builtin_setjmp(g_exit_jmp);
}
void pe_shim_exit_process(u64 exit_code) {
g_exit_code = exit_code;
if (g_exit_jmp_set) {
__builtin_longjmp(g_exit_jmp, 1);
}
/* 无 jmpbuf:直接返回 */
}
int pe_shim_is_exit_call(u64 target) {
/* 64位 ExitProcess shim 地址 */
extern u64 pe_shim_exitprocess64_addr(void);
if (target == pe_shim_exitprocess64_addr()) return 1;
/* 32位合成地址中 ExitProcess 的标记 */
return 0;
}
const char *pe_shim_get_cmdline(void) { return g_cmdline; }
u64 pe_shim_unimpl_stub(void) {
extern u64 pe_shim_unimpl64_addr(void);
return pe_shim_unimpl64_addr();
}
/* ===== 串口/帧缓冲输出(shim 内部复用) ===== */
static void shim_output(const char *s, u64 len) {
for (u64 i = 0; i < len; i++) {
serial_putc(s[i]);
}
}
static void shim_output_str(const char *s) {
serial_write(s);
}
/* ===== kernel32.dll shims (64位, ms_abi) ===== */
/* 句柄定义 */
#define STD_INPUT_HANDLE ((u64)0xFFFFFFF6)
#define STD_OUTPUT_HANDLE ((u64)0xFFFFFFF5)
#define STD_ERROR_HANDLE ((u64)0xFFFFFFF4)
#define SHIM_STDOUT_HANDLE ((u64)0x10000001)
#define SHIM_STDERR_HANDLE ((u64)0x10000002)
#define SHIM_STDIN_HANDLE ((u64)0x10000003)
static u64 __attribute__((ms_abi)) shim_GetStdHandle(u64 n_std_handle) {
if (n_std_handle == STD_OUTPUT_HANDLE) return SHIM_STDOUT_HANDLE;
if (n_std_handle == STD_ERROR_HANDLE) return SHIM_STDERR_HANDLE;
if (n_std_handle == STD_INPUT_HANDLE) return SHIM_STDIN_HANDLE;
return 0;
}
static u64 __attribute__((ms_abi)) shim_WriteFile(u64 handle, u64 buffer, u64 length,
u64 bytes_written_ptr, u64 overlapped) {
(void)overlapped;
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;
return 1; /* TRUE */
}
return 0;
}
static u64 __attribute__((ms_abi)) shim_ReadFile(u64 handle, u64 buffer, u64 max_length,
u64 bytes_read_ptr, u64 overlapped) {
(void)handle; (void)buffer; (void)max_length; (void)overlapped;
/* 暂不支持输入读取 */
if (bytes_read_ptr) *(u64 *)bytes_read_ptr = 0;
return 1;
}
static u64 __attribute__((ms_abi)) shim_ExitProcess(u64 exit_code) {
pe_shim_exit_process(exit_code);
return 0; /* 不返回 */
}
static u64 __attribute__((ms_abi)) shim_GetCommandLineA(void) {
return (u64)g_cmdline;
}
static u64 __attribute__((ms_abi)) shim_GetCommandLineW(void) {
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_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);
}
static u64 __attribute__((ms_abi)) shim_HeapFree(u64 heap, u64 flags, u64 ptr) {
(void)heap; (void)flags; (void)ptr;
return 1; /* arena 无 free,返回 TRUE */
}
static u64 __attribute__((ms_abi)) shim_VirtualAlloc(u64 addr, u64 size, u64 alloc_type, u64 protect) {
(void)addr; (void)alloc_type; (void)protect;
return (u64)kmem_alloc(size);
}
static u64 __attribute__((ms_abi)) shim_VirtualFree(u64 addr, u64 size, u64 free_type) {
(void)addr; (void)size; (void)free_type;
return 1;
}
static u64 __attribute__((ms_abi)) shim_GetModuleHandleA(u64 module_name) {
(void)module_name;
return 0x10000000; /* 假模块基址 */
}
static u64 __attribute__((ms_abi)) shim_GetModuleHandleW(u64 module_name) {
(void)module_name;
return 0x10000000;
}
static u64 __attribute__((ms_abi)) shim_GetEnvironmentVariableA(u64 name, u64 buf, u64 size) {
(void)name; (void)buf; (void)size;
return 0;
}
static u64 __attribute__((ms_abi)) shim_CreateFileA(u64 filename, u64 access, u64 share,
u64 sa, u64 disp, u64 flags, u64 template) {
(void)filename; (void)access; (void)share; (void)sa; (void)disp; (void)flags; (void)template;
return 0; /* 暂不支持文件 */
}
static u64 __attribute__((ms_abi)) shim_CloseHandle(u64 handle) { (void)handle; return 1; }
static u64 __attribute__((ms_abi)) shim_GetFileSize(u64 handle, u64 high) {
(void)handle; (void)high; return 0;
}
static u64 __attribute__((ms_abi)) shim_SetFilePointer(u64 handle, i64 dist, u64 high_ptr, u64 method) {
(void)handle; (void)dist; (void)high_ptr; (void)method; return 0;
}
/* ===== msvcrt.dll shims (64位, ms_abi) ===== */
static void shim_msvcrt_output(const char *s) {
shim_output_str(s);
}
/* 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 个参数。 */
const char *f = (const char *)fmt;
u64 args[3] = {a1, a2, a3};
int argi = 0;
char outbuf[512];
int oi = 0;
for (int i = 0; f[i] && oi < 510; i++) {
if (f[i] == '%' && f[i+1]) {
i++;
switch (f[i]) {
case 's': {
const char *s = (const char *)(args[argi++ & 3]);
if (s) while (*s && oi < 510) outbuf[oi++] = *s++;
break;
}
case 'd': {
i64 v = (i64)args[argi++ & 3];
if (v < 0) { outbuf[oi++] = '-'; v = -v; }
char tmp[24]; int ti = 0;
if (v == 0) tmp[ti++] = '0';
while (v > 0 && ti < 23) { tmp[ti++] = '0' + (v % 10); v /= 10; }
while (ti > 0 && oi < 510) outbuf[oi++] = tmp[--ti];
break;
}
case 'u': {
u64 v = args[argi++ & 3];
char tmp[24]; int ti = 0;
if (v == 0) tmp[ti++] = '0';
while (v > 0 && ti < 23) { tmp[ti++] = '0' + (v % 10); v /= 10; }
while (ti > 0 && oi < 510) outbuf[oi++] = tmp[--ti];
break;
}
case 'x': {
u64 v = args[argi++ & 3];
char tmp[24]; int ti = 0;
if (v == 0) tmp[ti++] = '0';
while (v > 0 && ti < 23) { int d = (int)(v & 0xF); tmp[ti++] = d < 10 ? '0'+d : 'a'+d-10; v >>= 4; }
while (ti > 0 && oi < 510) outbuf[oi++] = tmp[--ti];
break;
}
case 'c': {
outbuf[oi++] = (char)(args[argi++ & 3] & 0xFF);
break;
}
case '%': outbuf[oi++] = '%'; break;
default: outbuf[oi++] = '%'; outbuf[oi++] = f[i]; break;
}
} else {
outbuf[oi++] = f[i];
}
}
outbuf[oi] = 0;
shim_msvcrt_output(outbuf);
return (u64)oi;
}
static u64 __attribute__((ms_abi)) shim_puts(u64 str) {
const char *s = (const char *)str;
shim_msvcrt_output(s);
shim_msvcrt_output("\n");
return 0;
}
static u64 __attribute__((ms_abi)) shim_putchar(u64 ch) {
serial_putc((char)(ch & 0xFF));
return ch & 0xFF;
}
static u64 __attribute__((ms_abi)) shim_malloc(u64 size) {
return (u64)kmem_alloc(size);
}
static u64 __attribute__((ms_abi)) shim_calloc(u64 count, u64 size) {
u64 total = count * size;
u8 *p = kmem_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_realloc(u64 ptr, u64 size) {
(void)ptr; return (u64)kmem_alloc(size);
}
static u64 __attribute__((ms_abi)) shim_exit(u64 code) {
pe_shim_exit_process(code);
return 0;
}
static u64 __attribute__((ms_abi)) shim_memcpy(u64 dst, u64 src, u64 n) {
u8 *d = (u8 *)dst; const u8 *s = (const u8 *)src;
for (u64 i = 0; i < n; i++) d[i] = s[i];
return dst;
}
static u64 __attribute__((ms_abi)) shim_memset(u64 dst, u64 val, u64 n) {
u8 *d = (u8 *)dst; u8 v = (u8)(val & 0xFF);
for (u64 i = 0; i < n; i++) d[i] = v;
return dst;
}
static u64 __attribute__((ms_abi)) shim_memmove(u64 dst, u64 src, u64 n) {
u8 *d = (u8 *)dst; const u8 *s = (const u8 *)src;
if (d < s) { for (u64 i = 0; i < n; i++) d[i] = s[i]; }
else { for (u64 i = n; i > 0; i--) d[i-1] = s[i-1]; }
return dst;
}
static u64 __attribute__((ms_abi)) shim_strlen(u64 str) {
const char *s = (const char *)str;
u64 n = 0; while (s[n]) n++; return n;
}
static u64 __attribute__((ms_abi)) shim_strcmp(u64 a, u64 b) {
const char *pa = (const char *)a; const char *pb = (const char *)b;
while (*pa && *pa == *pb) { pa++; pb++; }
return (u64)(i64)(*pa - *pb);
}
static u64 __attribute__((ms_abi)) shim_strcpy(u64 dst, u64 src) {
char *d = (char *)dst; const char *s = (const char *)src;
while (*s) *d++ = *s++;
*d = 0;
return dst;
}
static u64 __attribute__((ms_abi)) shim_strncmp(u64 a, u64 b, u64 n) {
const char *pa = (const char *)a; const char *pb = (const char *)b;
for (u64 i = 0; i < n; i++) {
if (pa[i] != pb[i]) return (u64)(i64)(pa[i] - pb[i]);
if (pa[i] == 0) return 0;
}
return 0;
}
static u64 __attribute__((ms_abi)) shim_fwrite(u64 ptr, u64 size, u64 nmemb, u64 stream) {
(void)stream;
u64 total = size * nmemb;
shim_output((const char *)ptr, total);
return nmemb;
}
static u64 __attribute__((ms_abi)) shim_fputs(u64 str, u64 stream) {
(void)stream;
shim_output_str((const char *)str);
return 0;
}
static u64 __attribute__((ms_abi)) shim_fputc(u64 ch, u64 stream) {
(void)stream;
serial_putc((char)(ch & 0xFF));
return ch & 0xFF;
}
/* _initterm / _initterm_e — CRT 初始化,遍历函数指针表调用。
* 简化:直接跳过(返回 0)。 */
static u64 __attribute__((ms_abi)) shim_initterm(u64 start, u64 end) {
(void)start; (void)end;
return 0;
}
static u64 __attribute__((ms_abi)) shim_initterm_e(u64 start, u64 end) {
(void)start; (void)end;
return 0;
}
/* 未实现 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");
return 0;
}
/* 提供给 pe_shim.h 的地址获取函数 */
u64 pe_shim_unimpl64_addr(void) { return (u64)shim_unimpl64; }
u64 pe_shim_exitprocess64_addr(void) { return (u64)shim_ExitProcess; }
/* 获取退出码 */
u64 pe_shim_get_exit_code(void) { return g_exit_code; }
/* ===== shim 表 ===== */
static const pe_shim_entry g_shim_table[] = {
/* kernel32.dll */
{"kernel32.dll", "GetStdHandle", (void*)shim_GetStdHandle, 0},
{"kernel32.dll", "WriteFile", (void*)shim_WriteFile, 0},
{"kernel32.dll", "ReadFile", (void*)shim_ReadFile, 0},
{"kernel32.dll", "ExitProcess", (void*)shim_ExitProcess, 0},
{"kernel32.dll", "GetCommandLineA", (void*)shim_GetCommandLineA, 0},
{"kernel32.dll", "GetCommandLineW", (void*)shim_GetCommandLineW, 0},
{"kernel32.dll", "GetLastError", (void*)shim_GetLastError, 0},
{"kernel32.dll", "SetLastError", (void*)shim_SetLastError, 0},
{"kernel32.dll", "HeapCreate", (void*)shim_HeapCreate, 0},
{"kernel32.dll", "HeapAlloc", (void*)shim_HeapAlloc, 0},
{"kernel32.dll", "HeapFree", (void*)shim_HeapFree, 0},
{"kernel32.dll", "VirtualAlloc", (void*)shim_VirtualAlloc, 0},
{"kernel32.dll", "VirtualFree", (void*)shim_VirtualFree, 0},
{"kernel32.dll", "GetModuleHandleA", (void*)shim_GetModuleHandleA, 0},
{"kernel32.dll", "GetModuleHandleW", (void*)shim_GetModuleHandleW, 0},
{"kernel32.dll", "GetEnvironmentVariableA",(void*)shim_GetEnvironmentVariableA, 0},
{"kernel32.dll", "CreateFileA", (void*)shim_CreateFileA, 0},
{"kernel32.dll", "CloseHandle", (void*)shim_CloseHandle, 0},
{"kernel32.dll", "GetFileSize", (void*)shim_GetFileSize, 0},
{"kernel32.dll", "SetFilePointer", (void*)shim_SetFilePointer, 0},
/* msvcrt.dll */
{"msvcrt.dll", "printf", (void*)shim_printf, 0},
{"msvcrt.dll", "puts", (void*)shim_puts, 0},
{"msvcrt.dll", "putchar", (void*)shim_putchar, 0},
{"msvcrt.dll", "malloc", (void*)shim_malloc, 0},
{"msvcrt.dll", "calloc", (void*)shim_calloc, 0},
{"msvcrt.dll", "free", (void*)shim_free, 0},
{"msvcrt.dll", "realloc", (void*)shim_realloc, 0},
{"msvcrt.dll", "exit", (void*)shim_exit, 0},
{"msvcrt.dll", "memcpy", (void*)shim_memcpy, 0},
{"msvcrt.dll", "memset", (void*)shim_memset, 0},
{"msvcrt.dll", "memmove", (void*)shim_memmove, 0},
{"msvcrt.dll", "strlen", (void*)shim_strlen, 0},
{"msvcrt.dll", "strcmp", (void*)shim_strcmp, 0},
{"msvcrt.dll", "strcpy", (void*)shim_strcpy, 0},
{"msvcrt.dll", "strncmp", (void*)shim_strncmp, 0},
{"msvcrt.dll", "fwrite", (void*)shim_fwrite, 0},
{"msvcrt.dll", "fputs", (void*)shim_fputs, 0},
{"msvcrt.dll", "fputc", (void*)shim_fputc, 0},
{"msvcrt.dll", "_initterm", (void*)shim_initterm, 0},
{"msvcrt.dll", "_initterm_e", (void*)shim_initterm_e, 0},
};
int pe_shim_lookup(const char *dll, const char *func) {
if (!dll || !func) return -1;
for (int i = 0; i < (int)(sizeof(g_shim_table)/sizeof(g_shim_table[0])); i++) {
/* 大小写不敏感比较 DLL 名 */
const char *a = g_shim_table[i].dll;
const char *b = dll;
int match = 1;
while (*a && *b) {
char ca = *a, cb = *b;
if (ca >= 'A' && ca <= 'Z') ca += 32;
if (cb >= 'A' && cb <= 'Z') cb += 32;
if (ca != cb) { match = 0; break; }
a++; b++;
}
if (!match || *a != *b) continue;
/* 精确比较函数名 */
const char *fa = g_shim_table[i].func;
const char *fb = func;
while (*fa && *fb) { if (*fa != *fb) break; fa++; fb++; }
if (*fa == *fb) return i;
}
return -1;
}
const pe_shim_entry *pe_shim_get(int index) {
if (index < 0 || index >= (int)(sizeof(g_shim_table)/sizeof(g_shim_table[0]))) return 0;
return &g_shim_table[index];
}
int pe_shim_count(void) {
return (int)(sizeof(g_shim_table)/sizeof(g_shim_table[0]));
}
+65
View File
@@ -0,0 +1,65 @@
#ifndef PE_SHIM_H
#define PE_SHIM_H
/* pe_shim.h — Windows API shim 表。
*
* 将常见 Windows DLL 函数映射到 Deshab 等价实现:
* kernel32.dll!WriteFile → 写串口 + 帧缓冲
* kernel32.dll!HeapAlloc → kmem_alloc
* msvcrt.dll!printf → 串口输出
* ...
*
* 64位 PE:shim 用 __attribute__((ms_abi)) 声明,PE 代码以 MS x64 ABI 调用,
* IAT 直接填 shim 函数地址,原生执行。
* 32位 PE:解释器在 CALL IAT 时拦截,从模拟栈读参数调用 fn32,结果写 EAX。
*/
#include <utsm/types.h>
/* 32位 shim:从模拟栈读取参数(cdecl 语义,调用者清栈)。
* esp 指向模拟栈(第一个参数在 esp[0])。返回值 = EAX。 */
typedef u64 (*pe_shim_fn32)(void *esp);
/* shim 表条目 */
typedef struct pe_shim_entry {
const char *dll; /* 小写 DLL 名,如 "kernel32.dll" */
const char *func; /* 函数名,如 "WriteFile" */
void *fn64; /* 64位 ms_abi 函数地址(可为 NULL) */
pe_shim_fn32 fn32; /* 32位实现(可为 NULL) */
} pe_shim_entry;
/* 按 dll+func 名查找 shim。返回表索引,-1 未找到。 */
int pe_shim_lookup(const char *dll, const char *func);
/* 获取 shim 表条目 */
const pe_shim_entry *pe_shim_get(int index);
/* 获取 shim 表大小 */
int pe_shim_count(void);
/* 生成一个唯一的"未实现 stub"地址。
* 64位:返回一个固定 stub 函数地址,被调用时日志告警并返回 0。
* 32位:返回一个特殊标记值,解释器识别后日志告警。 */
u64 pe_shim_unimpl_stub(void);
/* 初始化 shim 子系统(注册全局状态,如 cmdline) */
void pe_shim_init(const char *cmdline);
/* ExitProcess 实现:通过 __builtin_longjmp 跳回 pe_run。
* 64位和32位共用。exit_code = 进程退出码。 */
void pe_shim_exit_process(u64 exit_code);
/* pe_run 调用:保存上下文(__builtin_setjmp)。
* 返回 0 = 首次(继续执行 PE),1 = ExitProcess 触发(longjmp 回来)。 */
int pe_shim_setup_exit(void);
/* 获取上次 ExitProcess 的退出码 */
u64 pe_shim_get_exit_code(void);
/* 判断地址是否为 ExitProcess shim(解释器用) */
int pe_shim_is_exit_call(u64 target);
/* 获取 cmdline(shim 内部用) */
const char *pe_shim_get_cmdline(void);
#endif /* PE_SHIM_H */
+975
View File
@@ -0,0 +1,975 @@
/* x86emu32.c — x86-32 指令解释器(PE32 执行引擎)。
*
* 寄存器级解释执行 32位 PE 代码。覆盖 mingw-w64 -O0/-O1 控制台程序常用指令:
* ALU(ADD/OR/ADC/SBB/AND/SUB/XOR/CMP)、MOV(全形式)、PUSH/POP、
* INC/DEC/NEG/NOT、MUL/IMUL/DIV/IDIV、移位/旋转、LEA、XCHG、MOVSX/MOVZX、
* JMP/Jcc/CALL/RET/LOOP、字符串指令(+REP)、ENTER/LEAVE、INT(shim 调度)。
*
* 遇不支持指令时设置 error 并停止。
*/
#include "x86emu32.h"
#include "pe_shim.h"
#include <utsm/log.h>
#include <utsm/types.h>
/* ===== 内存访问(带边界检查) ===== */
u8 x86emu32_read8(x86emu_state *emu, u32 addr) {
if (addr >= emu->mem_size) { emu->error = 1; emu->error_msg = "read8 OOB"; return 0; }
return emu->mem[addr];
}
u16 x86emu32_read16(x86emu_state *emu, u32 addr) {
if (addr + 1 >= emu->mem_size) { emu->error = 1; emu->error_msg = "read16 OOB"; return 0; }
return (u16)emu->mem[addr] | ((u16)emu->mem[addr+1] << 8);
}
u32 x86emu32_read32(x86emu_state *emu, u32 addr) {
if (addr + 3 >= emu->mem_size) { emu->error = 1; emu->error_msg = "read32 OOB"; return 0; }
return (u32)emu->mem[addr] | ((u32)emu->mem[addr+1] << 8) |
((u32)emu->mem[addr+2] << 16) | ((u32)emu->mem[addr+3] << 24);
}
void x86emu32_write8(x86emu_state *emu, u32 addr, u8 val) {
if (addr >= emu->mem_size) { emu->error = 1; emu->error_msg = "write8 OOB"; return; }
emu->mem[addr] = val;
}
void x86emu32_write16(x86emu_state *emu, u32 addr, u16 val) {
if (addr + 1 >= emu->mem_size) { emu->error = 1; emu->error_msg = "write16 OOB"; return; }
emu->mem[addr] = (u8)(val & 0xFF);
emu->mem[addr+1] = (u8)((val >> 8) & 0xFF);
}
void x86emu32_write32(x86emu_state *emu, u32 addr, u32 val) {
if (addr + 3 >= emu->mem_size) { emu->error = 1; emu->error_msg = "write32 OOB"; return; }
emu->mem[addr] = (u8)(val & 0xFF);
emu->mem[addr+1] = (u8)((val >> 8) & 0xFF);
emu->mem[addr+2] = (u8)((val >> 16) & 0xFF);
emu->mem[addr+3] = (u8)((val >> 24) & 0xFF);
}
/* ===== 栈操作 ===== */
void x86emu32_push32(x86emu_state *emu, u32 val) {
emu->regs[X86_ESP] -= 4;
x86emu32_write32(emu, emu->regs[X86_ESP], val);
}
u32 x86emu32_pop32(x86emu_state *emu) {
u32 val = x86emu32_read32(emu, emu->regs[X86_ESP]);
emu->regs[X86_ESP] += 4;
return val;
}
u64 x86emu32_read_arg(x86emu_state *emu, int esp_offset) {
return x86emu32_read32(emu, emu->regs[X86_ESP] + (u32)esp_offset * 4);
}
/* ===== 寄存器访问 ===== */
/* 32位寄存器名:EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI(对应 0-7) */
/* 8位寄存器映射:AL,CL,DL,BL,AH,CH,DH,BH(0-3 = 低8位, 4-7 = 高8位) */
static u8 get_reg8(x86emu_state *emu, int idx) {
if (idx < 4) return (u8)(emu->regs[idx] & 0xFF);
return (u8)((emu->regs[idx - 4] >> 8) & 0xFF);
}
static void set_reg8(x86emu_state *emu, int idx, u8 val) {
if (idx < 4) {
emu->regs[idx] = (emu->regs[idx] & 0xFFFFFF00) | val;
} else {
emu->regs[idx - 4] = (emu->regs[idx - 4] & 0xFFFF00FF) | ((u32)val << 8);
}
}
static u16 get_reg16(x86emu_state *emu, int idx) {
return (u16)(emu->regs[idx] & 0xFFFF);
}
static void set_reg16(x86emu_state *emu, int idx, u16 val) {
emu->regs[idx] = (emu->regs[idx] & 0xFFFF0000) | val;
}
static u32 get_reg32(x86emu_state *emu, int idx) { return emu->regs[idx]; }
static void set_reg32(x86emu_state *emu, int idx, u32 val) { emu->regs[idx] = val; }
/* ===== EFLAGS 辅助 ===== */
static void set_flag(x86emu_state *emu, u32 mask, int on) {
if (on) emu->eflags |= mask; else emu->eflags &= ~mask;
}
static int get_flag(x86emu_state *emu, u32 mask) { return (emu->eflags & mask) ? 1 : 0; }
static u8 parity8(u8 v) {
v ^= v >> 4; v ^= v >> 2; v ^= v >> 1;
return (v & 1) == 0;
}
static void set_zf_sf_pf(x86emu_state *emu, u32 result, int size) {
u32 mask = (size == 1) ? 0xFF : (size == 2) ? 0xFFFF : 0xFFFFFFFF;
result &= mask;
set_flag(emu, X86_ZF, result == 0);
if (size == 1) set_flag(emu, X86_SF, (result & 0x80) != 0);
else if (size == 2) set_flag(emu, X86_SF, (result & 0x8000) != 0);
else set_flag(emu, X86_SF, (result & 0x80000000) != 0);
set_flag(emu, X86_PF, parity8((u8)result));
}
static void set_cf_add(x86emu_state *emu, u32 a, u32 b, int size) {
u32 mask = (size == 1) ? 0xFF : (size == 2) ? 0xFFFF : 0xFFFFFFFF;
set_flag(emu, X86_CF, ((u64)(a & mask) + (u64)(b & mask)) > mask);
}
static void set_cf_sub(x86emu_state *emu, u32 a, u32 b, int size) {
u32 mask = (size == 1) ? 0xFF : (size == 2) ? 0xFFFF : 0xFFFFFFFF;
set_flag(emu, X86_CF, (a & mask) < (b & mask));
}
static void set_of_add(x86emu_state *emu, u32 a, u32 b, u32 r, int size) {
u32 sign = (size == 1) ? 0x80 : (size == 2) ? 0x8000 : 0x80000000;
set_flag(emu, X86_OF, (~(a ^ b) & (a ^ r) & sign) != 0);
}
static void set_of_sub(x86emu_state *emu, u32 a, u32 b, u32 r, int size) {
u32 sign = (size == 1) ? 0x80 : (size == 2) ? 0x8000 : 0x80000000;
set_flag(emu, X86_OF, ((a ^ b) & (a ^ r) & sign) != 0);
}
/* ===== 指令取 ===== */
static u8 fetch8(x86emu_state *emu) {
u8 v = x86emu32_read8(emu, emu->eip);
emu->eip++;
return v;
}
static u16 fetch16(x86emu_state *emu) {
u16 v = x86emu32_read16(emu, emu->eip);
emu->eip += 2;
return v;
}
static u32 fetch32(x86emu_state *emu) {
u32 v = x86emu32_read32(emu, emu->eip);
emu->eip += 4;
return v;
}
/* ===== ModR/M 解码 ===== */
typedef struct {
int mod;
int reg; /* reg 字段(也可作 opcode 扩展) */
int rm; /* rm 字段 */
u32 ea; /* 有效地址(若 mod != 3) */
int has_ea; /* 是否有内存操作数 */
} modrm_dec;
static modrm_dec decode_modrm(x86emu_state *emu) {
modrm_dec m;
u8 b = fetch8(emu);
m.mod = (b >> 6) & 3;
m.reg = (b >> 3) & 7;
m.rm = b & 7;
m.has_ea = 0;
m.ea = 0;
if (m.mod == 3) return m; /* 寄存器直接寻址 */
m.has_ea = 1;
u32 base = 0;
int has_sib = (m.rm == 4);
if (has_sib) {
u8 sib = fetch8(emu);
int scale = 1 << ((sib >> 6) & 3);
int index = (sib >> 3) & 7;
int base_reg = sib & 7;
base = emu->regs[base_reg];
if (index != 4) { /* ESP 不作 index */
base += emu->regs[index] * (u32)scale;
}
} else {
base = emu->regs[m.rm];
}
/* disp */
if (m.mod == 0) {
if (!has_sib && m.rm == 5) {
/* disp32 直接地址 */
base = fetch32(emu);
}
} else if (m.mod == 1) {
base += (u32)(i32)(i8)fetch8(emu); /* disp8 符号扩展 */
} else { /* mod == 2 */
base += fetch32(emu);
}
m.ea = base;
return m;
}
/* 读/写 modr/m 操作数 */
static u32 read_rm32(x86emu_state *emu, const modrm_dec *m) {
if (m->mod == 3) return get_reg32(emu, m->rm);
return x86emu32_read32(emu, m->ea);
}
static void write_rm32(x86emu_state *emu, const modrm_dec *m, u32 val) {
if (m->mod == 3) set_reg32(emu, m->rm, val);
else x86emu32_write32(emu, m->ea, val);
}
static u8 read_rm8(x86emu_state *emu, const modrm_dec *m) {
if (m->mod == 3) return get_reg8(emu, m->rm);
return x86emu32_read8(emu, m->ea);
}
static void write_rm8(x86emu_state *emu, const modrm_dec *m, u8 val) {
if (m->mod == 3) set_reg8(emu, m->rm, val);
else x86emu32_write8(emu, m->ea, val);
}
static u16 read_rm16(x86emu_state *emu, const modrm_dec *m) {
if (m->mod == 3) return get_reg16(emu, m->rm);
return x86emu32_read16(emu, m->ea);
}
static void write_rm16(x86emu_state *emu, const modrm_dec *m, u16 val) {
if (m->mod == 3) set_reg16(emu, m->rm, val);
else x86emu32_write16(emu, m->ea, val);
}
/* ===== ALU 操作(按 op 索引:0=ADD 1=OR 2=ADC 3=SBB 4=AND 5=SUB 6=XOR 7=CMP) ===== */
static u32 alu_op(x86emu_state *emu, int op, u32 a, u32 b, int size) {
u32 r = 0;
u32 mask = (size == 1) ? 0xFF : (size == 2) ? 0xFFFF : 0xFFFFFFFF;
a &= mask; b &= mask;
switch (op) {
case 0: r = a + b; set_cf_add(emu, a, b, size); set_of_add(emu, a, b, r, size); set_zf_sf_pf(emu, r, size); break;
case 1: r = a | b; set_flag(emu, X86_CF, 0); set_flag(emu, X86_OF, 0); set_zf_sf_pf(emu, r, size); break;
case 2: { int cf = get_flag(emu, X86_CF); r = a + b + cf; set_cf_add(emu, a + cf, b, size); set_of_add(emu, a, b, r, size); set_zf_sf_pf(emu, r, size); break; }
case 3: { int cf = get_flag(emu, X86_CF); r = a - b - cf; set_cf_sub(emu, a - cf, b, size); set_of_sub(emu, a, b, r, size); set_zf_sf_pf(emu, r, size); break; }
case 4: r = a & b; set_flag(emu, X86_CF, 0); set_flag(emu, X86_OF, 0); set_zf_sf_pf(emu, r, size); break;
case 5: r = a - b; set_cf_sub(emu, a, b, size); set_of_sub(emu, a, b, r, size); set_zf_sf_pf(emu, r, size); break;
case 6: r = a ^ b; set_flag(emu, X86_CF, 0); set_flag(emu, X86_OF, 0); set_zf_sf_pf(emu, r, size); break;
case 7: r = a - b; set_cf_sub(emu, a, b, size); set_of_sub(emu, a, b, r, size); set_zf_sf_pf(emu, r, size); break; /* CMP 不写回 */
}
return r & mask;
}
/* ===== 移位操作(按 op:ROL/ROR/RCL/RCR/SHL/SHR/SAR/SAL) ===== */
static u32 shift_op(x86emu_state *emu, int op, u32 val, u8 count, int size) {
u32 mask = (size == 1) ? 0xFF : (size == 2) ? 0xFFFF : 0xFFFFFFFF;
val &= mask;
count &= 0x1F;
if (count == 0) return val;
u32 r = val;
switch (op) {
case 4: case 6: /* SHL / SAL */
r = val << count;
set_flag(emu, X86_CF, (val >> (32 - count)) & 1);
break;
case 5: /* SHR */
r = val >> count;
set_flag(emu, X86_CF, (val >> (count - 1)) & 1);
break;
case 7: /* SAR */
r = (u32)((i32)val >> count);
set_flag(emu, X86_CF, (val >> (count - 1)) & 1);
break;
case 0: /* ROL */
r = ((val << count) | (val >> (size * 8 - count))) & mask;
set_flag(emu, X86_CF, r & 1);
break;
case 1: /* ROR */
r = ((val >> count) | (val << (size * 8 - count))) & mask;
set_flag(emu, X86_CF, (r >> (size * 8 - 1)) & 1);
break;
default: break; /* RCL/RCR 暂简化 */
}
if (op >= 4) set_zf_sf_pf(emu, r, size); /* SHL/SHR/SAR 影响 ZF/SF/PF */
return r & mask;
}
/* ===== IAT CALL 拦截 ===== */
/* stdcall 参数个数表(kernel32.dll 函数:callee 清栈)。
* msvcrt.dll 函数为 cdecl(caller 清栈),不在此表。
* key = shim 函数名首字符 + 长度组合的简单 hash,避免 strcmp。
* 简化:直接用函数指针地址查表。 */
static int try_iat_call(x86emu_state *emu, u32 target) {
/* 检查是否为合成 shim 地址 */
if (target >= 0x00010000 && target < 0x00020000) {
int shim_idx = target & 0xFFFF;
if (shim_idx == 0xFFFF) {
/* 未实现 stub */
log_warn("[PE32] call unimplemented API");
emu->regs[X86_EAX] = 0;
return 1;
}
const pe_shim_entry *se = pe_shim_get(shim_idx);
if (!se) {
log_warn("[PE32] shim index out of range");
emu->regs[X86_EAX] = 0;
return 1;
}
/* 从模拟栈读参数。CALL 被拦截前未 push 返回地址,
* 所以 ESP 指向第一个参数。 */
u32 esp_val = emu->regs[X86_ESP];
if (esp_val + 32 > emu->mem_size) {
emu->error = 1;
emu->error_msg = "shim esp OOB";
return 1;
}
u64 a0 = x86emu32_read32(emu, esp_val);
u64 a1 = x86emu32_read32(emu, esp_val + 4);
u64 a2 = x86emu32_read32(emu, esp_val + 8);
u64 a3 = x86emu32_read32(emu, esp_val + 12);
u64 ret;
if (se->fn32) {
/* 有专用 32位实现 */
void *esp_ptr = &emu->mem[esp_val];
ret = se->fn32(esp_ptr);
} else if (se->fn64) {
/* 回退:调用 64位 shim(最多 4 个参数)。
* MS x64 ABI 由 C 编译器处理寄存器分配。 */
typedef u64 (*fn4_t)(u64, u64, u64, u64);
fn4_t f = (fn4_t)se->fn64;
ret = f(a0, a1, a2, a3);
/* stdcall 清栈:kernel32.dll 函数 callee 清栈。
* 简化:按已知参数个数调整 ESP。
* msvcrt.dll (cdecl) 不清栈。 */
if (se->dll[0] == 'k') { /* kernel32.dll */
int nargs = 4; /* 默认假设 4 参数 */
/* 按函数名精化参数个数 */
const char *fn = se->func;
if (fn[0]=='G' && fn[1]=='e' && fn[2]=='t' && fn[3]=='S') nargs = 1;
else if (fn[0]=='W' && fn[1]=='r' && fn[2]=='i') nargs = 5;
else if (fn[0]=='R' && fn[1]=='e' && fn[2]=='a' && fn[3]=='d') nargs = 5;
else if (fn[0]=='E' && fn[1]=='x' && fn[2]=='i' && fn[3]=='t') nargs = 1;
else if (fn[0]=='G' && fn[1]=='e' && fn[2]=='t' && fn[3]=='C') nargs = 0;
else if (fn[0]=='G' && fn[1]=='e' && fn[2]=='t' && fn[3]=='L') nargs = 0;
else if (fn[0]=='S' && fn[1]=='e' && fn[2]=='t' && fn[3]=='L') nargs = 1;
else if (fn[0]=='H' && fn[1]=='e' && fn[2]=='a' && fn[3]=='p') nargs = 3;
else if (fn[0]=='V' && fn[1]=='i' && fn[2]=='r') nargs = 4;
else if (fn[0]=='G' && fn[1]=='e' && fn[2]=='t' && fn[3]=='M') nargs = 1;
else if (fn[0]=='C' && fn[1]=='l' && fn[2]=='o') nargs = 1;
else if (fn[0]=='C' && fn[1]=='r' && fn[2]=='e') nargs = 7;
emu->regs[X86_ESP] += (u32)(nargs * 4);
}
} else {
log_warn("[PE32] no shim impl");
ret = 0;
}
emu->regs[X86_EAX] = (u32)ret;
return 1;
}
/* 检查是否为 ExitProcess 特殊地址(64位 ExitProcess shim) */
if (pe_shim_is_exit_call((u64)target)) {
pe_shim_exit_process(emu->regs[X86_EAX] ? emu->regs[X86_EAX] : 0);
emu->exited = 1;
return 1;
}
return 0; /* 不是 IAT/shim 调用 */
}
/* ===== 条件跳转判断 ===== */
static int check_jcc(x86emu_state *emu, int cond) {
int zf = get_flag(emu, X86_ZF);
int sf = get_flag(emu, X86_SF);
int of = get_flag(emu, X86_OF);
int cf = get_flag(emu, X86_CF);
int pf = get_flag(emu, X86_PF);
switch (cond & 0xF) {
case 0x0: return of;
case 0x1: return !of;
case 0x2: return cf;
case 0x3: return !cf;
case 0x4: return zf;
case 0x5: return !zf;
case 0x6: return cf || zf;
case 0x7: return !cf && !zf;
case 0x8: return sf;
case 0x9: return !sf;
case 0xA: return pf;
case 0xB: return !pf;
case 0xC: return sf != of;
case 0xD: return sf == of;
case 0xE: return zf || (sf != of);
case 0xF: return !zf && (sf == of);
}
return 0;
}
/* ===== 主执行循环 ===== */
int x86emu32_run(x86emu_state *emu, u64 *exit_code) {
emu->insn_limit = 500000000ULL; /* 5亿指令上限防死循环 */
while (!emu->exited && !emu->error && emu->insn_count < emu->insn_limit) {
emu->insn_count++;
/* 前缀处理 */
int operand_size = 4; /* 默认 32位 */
int rep_prefix = 0; /* 0=无, 1=REP/REPE, 2=REPNE(记录但暂未用于字符串指令) */
u8 op;
int prefix_done = 0;
while (!prefix_done) {
op = fetch8(emu);
switch (op) {
case 0x66: operand_size = 2; break;
case 0x67: break; /* 地址大小前缀(忽略,32位寻址) */
case 0xF0: break; /* LOCK */
case 0xF2: rep_prefix = 2; break; /* REPNE */
case 0xF3: rep_prefix = 1; break; /* REP/REPE */
case 0x26: case 0x2E: case 0x36: case 0x3E: case 0x64: case 0x65: break; /* 段前缀忽略 */
default: prefix_done = 1; break;
}
}
(void)rep_prefix; /* 记录前缀,字符串指令暂未使用 */
/* 操作数大小:对 0x66 前缀,32位操作变 16位 */
int osz = operand_size; /* 4 或 2 */
switch (op) {
/* ---- ALU modr/m(0x00-0x3F)---- */
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x08: case 0x09: case 0x0A: case 0x0B:
case 0x10: case 0x11: case 0x12: case 0x13:
case 0x18: case 0x19: case 0x1A: case 0x1B:
case 0x20: case 0x21: case 0x22: case 0x23:
case 0x28: case 0x29: case 0x2A: case 0x2B:
case 0x30: case 0x31: case 0x32: case 0x33:
case 0x38: case 0x39: case 0x3A: case 0x3B: {
int alu = (op >> 3) & 7;
int dir = op & 1; /* 0: r/m8←r8, 1: r/m32←r32 (或反向) */
int is8 = !(op & 4); /* 0x00-0x03=8位, 0x04+ =32位 */
modrm_dec m = decode_modrm(emu);
if (is8) {
u8 a, b; int cmp_only = (alu == 7);
if (dir == 0) { a = read_rm8(emu, &m); b = get_reg8(emu, m.reg); }
else { a = get_reg8(emu, m.reg); b = read_rm8(emu, &m); }
u8 r = (u8)alu_op(emu, alu, a, b, 1);
if (alu != 7) { if (dir == 0) write_rm8(emu, &m, r); else set_reg8(emu, m.reg, r); }
(void)cmp_only;
} else {
u32 a, b;
if (dir == 0) { a = read_rm32(emu, &m); b = get_reg32(emu, m.reg); }
else { a = get_reg32(emu, m.reg); b = read_rm32(emu, &m); }
u32 r = alu_op(emu, alu, a, b, osz);
if (alu != 7) { if (dir == 0) write_rm32(emu, &m, r); else set_reg32(emu, m.reg, r); }
if (osz == 2) { if (alu != 7) { if (dir == 0) write_rm16(emu, &m, (u16)r); else set_reg16(emu, m.reg, (u16)r); } }
}
break;
}
/* ---- ALU AL/EAX, imm ---- */
case 0x04: case 0x0C: case 0x14: case 0x1C:
case 0x24: case 0x2C: case 0x34: case 0x3C: {
int alu = (op >> 3) & 7;
u8 imm = fetch8(emu);
u8 r = (u8)alu_op(emu, alu, get_reg8(emu, 0), imm, 1);
if (alu != 7) set_reg8(emu, 0, r);
break;
}
case 0x05: case 0x0D: case 0x15: case 0x1D:
case 0x25: case 0x2D: case 0x35: case 0x3D: {
int alu = (op >> 3) & 7;
if (osz == 2) {
u16 imm = fetch16(emu);
u16 r = (u16)alu_op(emu, alu, get_reg16(emu, 0), imm, 2);
if (alu != 7) set_reg16(emu, 0, r);
} else {
u32 imm = fetch32(emu);
u32 r = alu_op(emu, alu, get_reg32(emu, 0), imm, 4);
if (alu != 7) set_reg32(emu, 0, r);
}
break;
}
/* ---- INC/DEC reg(0x40-0x4F)---- */
case 0x40: case 0x41: case 0x42: case 0x43:
case 0x44: case 0x45: case 0x46: case 0x47: {
int r = op - 0x40;
int cf = get_flag(emu, X86_CF);
if (osz == 2) { u16 v = get_reg16(emu, r); u16 res = (u16)alu_op(emu, 0, v, 1, 2); set_reg16(emu, r, res); }
else { u32 v = get_reg32(emu, r); u32 res = alu_op(emu, 0, v, 1, 4); set_reg32(emu, r, res); }
set_flag(emu, X86_CF, cf); /* INC 不影响 CF */
break;
}
case 0x48: case 0x49: case 0x4A: case 0x4B:
case 0x4C: case 0x4D: case 0x4E: case 0x4F: {
int r = op - 0x48;
int cf = get_flag(emu, X86_CF);
if (osz == 2) { u16 v = get_reg16(emu, r); u16 res = (u16)alu_op(emu, 5, v, 1, 2); set_reg16(emu, r, res); }
else { u32 v = get_reg32(emu, r); u32 res = alu_op(emu, 5, v, 1, 4); set_reg32(emu, r, res); }
set_flag(emu, X86_CF, cf);
break;
}
/* ---- PUSH/POP reg ---- */
case 0x50: case 0x51: case 0x52: case 0x53:
case 0x54: case 0x55: case 0x56: case 0x57:
x86emu32_push32(emu, get_reg32(emu, op - 0x50));
break;
case 0x58: case 0x59: case 0x5A: case 0x5B:
case 0x5C: case 0x5D: case 0x5E: case 0x5F:
set_reg32(emu, op - 0x58, x86emu32_pop32(emu));
break;
/* ---- PUSHA/POPA ---- */
case 0x60: {
u32 sp = emu->regs[X86_ESP];
x86emu32_push32(emu, emu->regs[X86_EAX]);
x86emu32_push32(emu, emu->regs[X86_ECX]);
x86emu32_push32(emu, emu->regs[X86_EDX]);
x86emu32_push32(emu, emu->regs[X86_EBX]);
x86emu32_push32(emu, sp);
x86emu32_push32(emu, emu->regs[X86_EBP]);
x86emu32_push32(emu, emu->regs[X86_ESI]);
x86emu32_push32(emu, emu->regs[X86_EDI]);
break;
}
case 0x61: {
emu->regs[X86_EDI] = x86emu32_pop32(emu);
emu->regs[X86_ESI] = x86emu32_pop32(emu);
emu->regs[X86_EBP] = x86emu32_pop32(emu);
x86emu32_pop32(emu); /* 忽略原始 ESP */
emu->regs[X86_EBX] = x86emu32_pop32(emu);
emu->regs[X86_EDX] = x86emu32_pop32(emu);
emu->regs[X86_ECX] = x86emu32_pop32(emu);
emu->regs[X86_EAX] = x86emu32_pop32(emu);
break;
}
/* ---- PUSH imm ---- */
case 0x68: x86emu32_push32(emu, fetch32(emu)); break;
case 0x6A: x86emu32_push32(emu, (u32)(i32)(i8)fetch8(emu)); break;
/* ---- IMUL r, r/m, imm ---- */
case 0x69: case 0x6B: {
modrm_dec m = decode_modrm(emu);
u32 src = read_rm32(emu, &m);
u32 imm = (op == 0x69) ? fetch32(emu) : (u32)(i32)(i8)fetch8(emu);
i64 result = (i64)(i32)src * (i64)(i32)imm;
set_reg32(emu, m.reg, (u32)result);
set_flag(emu, X86_OF, result > 0x7FFFFFFFLL || result < -0x80000000LL);
set_flag(emu, X86_CF, get_flag(emu, X86_OF));
break;
}
/* ---- Jcc rel8 ---- */
case 0x70: case 0x71: case 0x72: case 0x73:
case 0x74: case 0x75: case 0x76: case 0x77:
case 0x78: case 0x79: case 0x7A: case 0x7B:
case 0x7C: case 0x7D: case 0x7E: case 0x7F: {
i8 rel = (i8)fetch8(emu);
if (check_jcc(emu, op & 0xF)) emu->eip += (u32)(i32)rel;
break;
}
/* ---- ALU r/m, imm8 (0x80/0x82) / r/m, imm32 (0x81) ---- */
case 0x80: case 0x82: {
modrm_dec m = decode_modrm(emu);
u8 imm = fetch8(emu);
u8 a = read_rm8(emu, &m);
u8 r = (u8)alu_op(emu, m.reg, a, imm, 1);
if (m.reg != 7) write_rm8(emu, &m, r);
break;
}
case 0x81: {
modrm_dec m = decode_modrm(emu);
if (osz == 2) {
u16 imm = fetch16(emu);
u16 a = read_rm16(emu, &m);
u16 r = (u16)alu_op(emu, m.reg, a, imm, 2);
if (m.reg != 7) write_rm16(emu, &m, r);
} else {
u32 imm = fetch32(emu);
u32 a = read_rm32(emu, &m);
u32 r = alu_op(emu, m.reg, a, imm, 4);
if (m.reg != 7) write_rm32(emu, &m, r);
}
break;
}
case 0x83: {
modrm_dec m = decode_modrm(emu);
u32 imm = (u32)(i32)(i8)fetch8(emu);
if (osz == 2) {
u16 a = read_rm16(emu, &m);
u16 r = (u16)alu_op(emu, m.reg, a, imm & 0xFFFF, 2);
if (m.reg != 7) write_rm16(emu, &m, r);
} else {
u32 a = read_rm32(emu, &m);
u32 r = alu_op(emu, m.reg, a, imm, 4);
if (m.reg != 7) write_rm32(emu, &m, r);
}
break;
}
/* ---- TEST ---- */
case 0x84: case 0x85: {
modrm_dec m = decode_modrm(emu);
if (op == 0x84) {
u8 a = read_rm8(emu, &m); u8 b = get_reg8(emu, m.reg);
alu_op(emu, 4, a, b, 1); /* AND 不写回 */
} else if (osz == 2) {
u16 a = read_rm16(emu, &m); u16 b = get_reg16(emu, m.reg);
alu_op(emu, 4, a, b, 2);
} else {
u32 a = read_rm32(emu, &m); u32 b = get_reg32(emu, m.reg);
alu_op(emu, 4, a, b, 4);
}
break;
}
/* ---- XCHG ---- */
case 0x86: case 0x87: {
modrm_dec m = decode_modrm(emu);
if (op == 0x86) {
u8 a = read_rm8(emu, &m); u8 b = get_reg8(emu, m.reg);
write_rm8(emu, &m, b); set_reg8(emu, m.reg, a);
} else if (osz == 2) {
u16 a = read_rm16(emu, &m); u16 b = get_reg16(emu, m.reg);
write_rm16(emu, &m, b); set_reg16(emu, m.reg, a);
} else {
u32 a = read_rm32(emu, &m); u32 b = get_reg32(emu, m.reg);
write_rm32(emu, &m, b); set_reg32(emu, m.reg, a);
}
break;
}
/* ---- MOV ---- */
case 0x88: { modrm_dec m = decode_modrm(emu); write_rm8(emu, &m, get_reg8(emu, m.reg)); break; }
case 0x89: {
modrm_dec m = decode_modrm(emu);
if (osz == 2) write_rm16(emu, &m, get_reg16(emu, m.reg));
else write_rm32(emu, &m, get_reg32(emu, m.reg));
break;
}
case 0x8A: { modrm_dec m = decode_modrm(emu); set_reg8(emu, m.reg, read_rm8(emu, &m)); break; }
case 0x8B: {
modrm_dec m = decode_modrm(emu);
if (osz == 2) set_reg16(emu, m.reg, read_rm16(emu, &m));
else set_reg32(emu, m.reg, read_rm32(emu, &m));
break;
}
/* ---- LEA ---- */
case 0x8D: {
modrm_dec m = decode_modrm(emu);
if (osz == 2) set_reg16(emu, m.reg, (u16)m.ea);
else set_reg32(emu, m.reg, m.ea);
break;
}
/* ---- NOP / XCHG EAX,reg ---- */
case 0x90: break; /* NOP */
case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: {
int r = op - 0x90;
u32 tmp = emu->regs[0]; emu->regs[0] = emu->regs[r]; emu->regs[r] = tmp;
break;
}
/* ---- CWDE/CDQ ---- */
case 0x98: /* CWDE (32位) / CBW (16位) */
if (osz == 2) set_reg16(emu, 0, (u16)(i16)(i8)get_reg8(emu, 0));
else emu->regs[0] = (u32)(i32)(i16)get_reg16(emu, 0);
break;
case 0x99: /* CDQ (32位) / CWD (16位) */
if (osz == 2) set_reg16(emu, 2, (get_reg16(emu, 0) & 0x8000) ? 0xFFFF : 0);
else emu->regs[2] = (emu->regs[0] & 0x80000000) ? 0xFFFFFFFF : 0;
break;
/* ---- MOV moffs ---- */
case 0xA0: { u32 addr = fetch32(emu); set_reg8(emu, 0, x86emu32_read8(emu, addr)); break; }
case 0xA1: { u32 addr = fetch32(emu); if (osz==2) set_reg16(emu,0,x86emu32_read16(emu,addr)); else set_reg32(emu,0,x86emu32_read32(emu,addr)); break; }
case 0xA2: { u32 addr = fetch32(emu); x86emu32_write8(emu, addr, get_reg8(emu, 0)); break; }
case 0xA3: { u32 addr = fetch32(emu); if (osz==2) x86emu32_write16(emu,addr,get_reg16(emu,0)); else x86emu32_write32(emu,addr,get_reg32(emu,0)); break; }
/* ---- 字符串指令(简化:无 REP 单步)---- */
case 0xA4: { /* MOVSB */
u32 si = emu->regs[X86_ESI], di = emu->regs[X86_EDI];
u8 v = x86emu32_read8(emu, si);
x86emu32_write8(emu, di, v);
int df = get_flag(emu, X86_DF);
si += df ? -1 : 1; di += df ? -1 : 1;
emu->regs[X86_ESI] = si; emu->regs[X86_EDI] = di;
break;
}
case 0xA5: { /* MOVSD/W */
u32 si = emu->regs[X86_ESI], di = emu->regs[X86_EDI];
int df = get_flag(emu, X86_DF); int step = (osz==2)?2:4;
if (osz==2) { u16 v=x86emu32_read16(emu,si); x86emu32_write16(emu,di,v); }
else { u32 v=x86emu32_read32(emu,si); x86emu32_write32(emu,di,v); }
si += df ? -step : step; di += df ? -step : step;
emu->regs[X86_ESI]=si; emu->regs[X86_EDI]=di;
break;
}
case 0xAA: { /* STOSB */
u32 di = emu->regs[X86_EDI];
x86emu32_write8(emu, di, get_reg8(emu, 0));
int df = get_flag(emu, X86_DF);
di += df ? -1 : 1; emu->regs[X86_EDI] = di;
break;
}
case 0xAB: { /* STOSD/W */
u32 di = emu->regs[X86_EDI]; int df = get_flag(emu, X86_DF); int step=(osz==2)?2:4;
if (osz==2) x86emu32_write16(emu,di,get_reg16(emu,0));
else x86emu32_write32(emu,di,emu->regs[0]);
di += df?-step:step; emu->regs[X86_EDI]=di;
break;
}
case 0xAC: { /* LODSB */
u32 si = emu->regs[X86_ESI];
set_reg8(emu, 0, x86emu32_read8(emu, si));
int df = get_flag(emu, X86_DF);
si += df ? -1 : 1; emu->regs[X86_ESI] = si;
break;
}
case 0xAD: { /* LODSD/W */
u32 si = emu->regs[X86_ESI]; int df=get_flag(emu,X86_DF); int step=(osz==2)?2:4;
if (osz==2) set_reg16(emu,0,x86emu32_read16(emu,si)); else set_reg32(emu,0,x86emu32_read32(emu,si));
si += df?-step:step; emu->regs[X86_ESI]=si;
break;
}
/* ---- TEST AL/EAX, imm ---- */
case 0xA8: { u8 imm = fetch8(emu); alu_op(emu, 4, get_reg8(emu,0), imm, 1); break; }
case 0xA9: {
if (osz==2) { u16 imm=fetch16(emu); alu_op(emu,4,get_reg16(emu,0),imm,2); }
else { u32 imm=fetch32(emu); alu_op(emu,4,emu->regs[0],imm,4); }
break;
}
/* ---- MOV reg, imm ---- */
case 0xB0: case 0xB1: case 0xB2: case 0xB3:
case 0xB4: case 0xB5: case 0xB6: case 0xB7:
set_reg8(emu, op - 0xB0, fetch8(emu));
break;
case 0xB8: case 0xB9: case 0xBA: case 0xBB:
case 0xBC: case 0xBD: case 0xBE: case 0xBF:
if (osz==2) set_reg16(emu, op-0xB8, fetch16(emu));
else set_reg32(emu, op-0xB8, fetch32(emu));
break;
/* ---- shift r/m, imm8 ---- */
case 0xC0: case 0xC1: {
modrm_dec m = decode_modrm(emu);
u8 count = fetch8(emu);
if (op == 0xC0) { u8 v = read_rm8(emu,&m); write_rm8(emu,&m,(u8)shift_op(emu,m.reg,v,count,1)); }
else if (osz==2) { u16 v=read_rm16(emu,&m); write_rm16(emu,&m,(u16)shift_op(emu,m.reg,v,count,2)); }
else { u32 v=read_rm32(emu,&m); write_rm32(emu,&m,shift_op(emu,m.reg,v,count,4)); }
break;
}
/* ---- RET ---- */
case 0xC2: { u16 imm = fetch16(emu); emu->eip = x86emu32_pop32(emu); emu->regs[X86_ESP] += imm; break; }
case 0xC3: { emu->eip = x86emu32_pop32(emu); break; }
/* ---- MOV r/m, imm ---- */
case 0xC6: { modrm_dec m = decode_modrm(emu); u8 imm = fetch8(emu); write_rm8(emu,&m,imm); break; }
case 0xC7: {
modrm_dec m = decode_modrm(emu);
if (osz==2) { u16 imm=fetch16(emu); write_rm16(emu,&m,imm); }
else { u32 imm=fetch32(emu); write_rm32(emu,&m,imm); }
break;
}
/* ---- LEAVE ---- */
case 0xC9:
emu->regs[X86_ESP] = emu->regs[X86_EBP];
emu->regs[X86_EBP] = x86emu32_pop32(emu);
break;
/* ---- INT3 / INT ---- */
case 0xCC: /* INT3 */
emu->error = 1; emu->error_msg = "INT3 breakpoint";
break;
case 0xCD: { /* INT imm8 */
u8 v = fetch8(emu); (void)v;
/* 简化:忽略软件中断 */
break;
}
/* ---- shift r/m, 1 / CL ---- */
case 0xD0: case 0xD1: case 0xD2: case 0xD3: {
modrm_dec m = decode_modrm(emu);
u8 count = (op & 2) ? (get_reg8(emu, 1) & 0x1F) : 1;
int is8 = !(op & 1);
if (is8) { u8 v=read_rm8(emu,&m); write_rm8(emu,&m,(u8)shift_op(emu,m.reg,v,count,1)); }
else if (osz==2) { u16 v=read_rm16(emu,&m); write_rm16(emu,&m,(u16)shift_op(emu,m.reg,v,count,2)); }
else { u32 v=read_rm32(emu,&m); write_rm32(emu,&m,shift_op(emu,m.reg,v,count,4)); }
break;
}
/* ---- CALL rel32 ---- */
case 0xE8: {
i32 rel = (i32)fetch32(emu);
x86emu32_push32(emu, emu->eip); /* return address */
emu->eip += (u32)rel;
break;
}
/* ---- JMP rel32 ---- */
case 0xE9: { i32 rel = (i32)fetch32(emu); emu->eip += (u32)rel; break; }
/* ---- JMP rel8 ---- */
case 0xEB: { i8 rel = (i8)fetch8(emu); emu->eip += (u32)(i32)rel; break; }
/* ---- LOOP ---- */
case 0xE0: case 0xE1: case 0xE2: {
i8 rel = (i8)fetch8(emu);
u32 cx = emu->regs[X86_ECX] - 1;
emu->regs[X86_ECX] = cx;
int do_jump = (cx != 0);
if (op == 0xE0 && get_flag(emu, X86_ZF)) do_jump = 0; /* LOOPNE */
if (op == 0xE1 && !get_flag(emu, X86_ZF)) do_jump = 0; /* LOOPE */
if (do_jump) emu->eip += (u32)(i32)rel;
break;
}
case 0xE3: { /* JECXZ */
i8 rel = (i8)fetch8(emu);
if (emu->regs[X86_ECX] == 0) emu->eip += (u32)(i32)rel;
break;
}
/* ---- CALL/JMP r/m ---- */
case 0xFF: {
modrm_dec m = decode_modrm(emu);
switch (m.reg) {
case 0: { /* INC r/m */
int cf=get_flag(emu,X86_CF);
if (osz==2) { u16 v=read_rm16(emu,&m); write_rm16(emu,&m,(u16)alu_op(emu,0,v,1,2)); }
else { u32 v=read_rm32(emu,&m); write_rm32(emu,&m,alu_op(emu,0,v,1,4)); }
set_flag(emu,X86_CF,cf);
break;
}
case 1: { /* DEC r/m */
int cf=get_flag(emu,X86_CF);
if (osz==2) { u16 v=read_rm16(emu,&m); write_rm16(emu,&m,(u16)alu_op(emu,5,v,1,2)); }
else { u32 v=read_rm32(emu,&m); write_rm32(emu,&m,alu_op(emu,5,v,1,4)); }
set_flag(emu,X86_CF,cf);
break;
}
case 2: { /* CALL r/m32 */
u32 target = read_rm32(emu, &m);
if (try_iat_call(emu, target)) break;
x86emu32_push32(emu, emu->eip);
emu->eip = target;
break;
}
case 4: { /* JMP r/m32 */
u32 target = read_rm32(emu, &m);
if (try_iat_call(emu, target)) { emu->exited = 1; break; }
emu->eip = target;
break;
}
case 6: { /* PUSH r/m32 */
x86emu32_push32(emu, read_rm32(emu, &m));
break;
}
default:
emu->error = 1; emu->error_msg = "FF /reg unsupported";
break;
}
break;
}
/* ---- F6/F7 组 ---- */
case 0xF6: {
modrm_dec m = decode_modrm(emu);
if (m.reg == 0 || m.reg == 1) { /* TEST r/m8, imm8 */
u8 imm = fetch8(emu);
alu_op(emu, 4, read_rm8(emu,&m), imm, 1);
} else if (m.reg == 2) { /* NOT r/m8 */
write_rm8(emu, &m, ~read_rm8(emu, &m));
} else if (m.reg == 3) { /* NEG r/m8 */
u8 v = read_rm8(emu, &m);
u8 r = (u8)(-(i8)v);
set_flag(emu, X86_CF, v != 0);
set_zf_sf_pf(emu, r, 1);
write_rm8(emu, &m, r);
} else if (m.reg == 4) { /* MUL r/m8 */
u16 result = (u16)get_reg8(emu, 0) * (u16)read_rm8(emu, &m);
set_reg8(emu, 0, (u8)result);
set_reg8(emu, 4, (u8)(result >> 8));
set_flag(emu, X86_CF, result >> 8 != 0);
set_flag(emu, X86_OF, get_flag(emu, X86_CF));
} else {
emu->error = 1; emu->error_msg = "F6 /reg unsupported";
}
break;
}
case 0xF7: {
modrm_dec m = decode_modrm(emu);
if (m.reg == 0 || m.reg == 1) { /* TEST r/m32, imm32 */
if (osz==2) { u16 imm=fetch16(emu); alu_op(emu,4,read_rm16(emu,&m),imm,2); }
else { u32 imm=fetch32(emu); alu_op(emu,4,read_rm32(emu,&m),imm,4); }
} else if (m.reg == 2) { /* NOT */
if (osz==2) write_rm16(emu,&m,~read_rm16(emu,&m));
else write_rm32(emu,&m,~read_rm32(emu,&m));
} else if (m.reg == 3) { /* NEG */
if (osz==2) { u16 v=read_rm16(emu,&m); u16 r=(u16)(-(i16)v); set_flag(emu,X86_CF,v!=0); set_zf_sf_pf(emu,r,2); write_rm16(emu,&m,r); }
else { u32 v=read_rm32(emu,&m); u32 r=(u32)(-(i32)v); set_flag(emu,X86_CF,v!=0); set_zf_sf_pf(emu,r,4); write_rm32(emu,&m,r); }
} else if (m.reg == 4) { /* MUL */
if (osz==2) { u32 result=(u32)get_reg16(emu,0)*(u32)read_rm16(emu,&m); set_reg16(emu,0,(u16)result); set_reg16(emu,2,(u16)(result>>16)); set_flag(emu,X86_CF,result>>16!=0); set_flag(emu,X86_OF,get_flag(emu,X86_CF)); }
else { u64 result=(u64)emu->regs[0]*(u64)read_rm32(emu,&m); emu->regs[0]=(u32)result; emu->regs[2]=(u32)(result>>32); set_flag(emu,X86_CF,result>>32!=0); set_flag(emu,X86_OF,get_flag(emu,X86_CF)); }
} else if (m.reg == 5) { /* IMUL */
if (osz==2) { i32 result=(i32)(i16)get_reg16(emu,0)*(i32)(i16)read_rm16(emu,&m); set_reg16(emu,0,(u16)result); set_reg16(emu,2,(u16)(result>>16)); set_flag(emu,X86_OF,result>32767||result<-32768); set_flag(emu,X86_CF,get_flag(emu,X86_OF)); }
else { i64 result=(i64)(i32)emu->regs[0]*(i64)(i32)read_rm32(emu,&m); emu->regs[0]=(u32)result; emu->regs[2]=(u32)(result>>32); set_flag(emu,X86_OF,result>0x7FFFFFFFLL||result<-0x80000000LL); set_flag(emu,X86_CF,get_flag(emu,X86_OF)); }
} else if (m.reg == 6) { /* DIV */
if (osz==2) { u32 dividend=((u32)get_reg16(emu,2)<<16)|get_reg16(emu,0); u16 divisor=read_rm16(emu,&m); if(divisor){set_reg16(emu,0,(u16)(dividend/divisor));set_reg16(emu,2,(u16)(dividend%divisor));} }
else { u64 dividend=((u64)emu->regs[2]<<32)|emu->regs[0]; u32 divisor=read_rm32(emu,&m); if(divisor){emu->regs[0]=(u32)(dividend/divisor);emu->regs[2]=(u32)(dividend%divisor);} }
} else if (m.reg == 7) { /* IDIV */
if (osz==2) { i32 dividend=((i32)(i16)get_reg16(emu,2)<<16)|(i16)get_reg16(emu,0); i16 divisor=(i16)read_rm16(emu,&m); if(divisor){set_reg16(emu,0,(u16)(dividend/divisor));set_reg16(emu,2,(u16)(dividend%divisor));} }
else { i64 dividend=((i64)(i32)emu->regs[2]<<32)|(i32)emu->regs[0]; i32 divisor=(i32)read_rm32(emu,&m); if(divisor){emu->regs[0]=(u32)(dividend/divisor);emu->regs[2]=(u32)(dividend%divisor);} }
}
break;
}
/* ---- CLC/STC/CLI/STI/CLD/STD ---- */
case 0xF8: set_flag(emu, X86_CF, 0); break;
case 0xF9: set_flag(emu, X86_CF, 1); break;
case 0xFA: break; /* CLI(忽略) */
case 0xFB: break; /* STI(忽略) */
case 0xFC: set_flag(emu, X86_DF, 0); break;
case 0xFD: set_flag(emu, X86_DF, 1); break;
/* ---- INC/DEC r/m8 ---- */
case 0xFE: {
modrm_dec m = decode_modrm(emu);
int cf = get_flag(emu, X86_CF);
u8 v = read_rm8(emu, &m);
if (m.reg == 0) write_rm8(emu, &m, (u8)alu_op(emu, 0, v, 1, 1));
else if (m.reg == 1) write_rm8(emu, &m, (u8)alu_op(emu, 5, v, 1, 1));
set_flag(emu, X86_CF, cf);
break;
}
/* ---- MOVSX/MOVZX 在 0x0F 两字节 opcode 中处理 ---- */
case 0x0F: { /* 两字节 opcode */
u8 op2 = fetch8(emu);
if (op2 >= 0x80 && op2 <= 0x8F) { /* Jcc rel32 */
i32 rel = (i32)fetch32(emu);
if (check_jcc(emu, op2 & 0xF)) emu->eip += (u32)rel;
} else if (op2 == 0xAF) { /* IMUL r32, r/m32 */
modrm_dec m = decode_modrm(emu);
i64 result = (i64)(i32)get_reg32(emu, m.reg) * (i64)(i32)read_rm32(emu, &m);
set_reg32(emu, m.reg, (u32)result);
set_flag(emu, X86_OF, result > 0x7FFFFFFFLL || result < -0x80000000LL);
set_flag(emu, X86_CF, get_flag(emu, X86_OF));
} else if (op2 == 0xB6 || op2 == 0xB7) { /* MOVZX r32, r/m8/16 */
modrm_dec m = decode_modrm(emu);
if (op2 == 0xB6) { set_reg32(emu, m.reg, (u32)read_rm8(emu, &m)); }
else { set_reg32(emu, m.reg, (u32)read_rm16(emu, &m)); }
} else if (op2 == 0xBE || op2 == 0xBF) { /* MOVSX r32, r/m8/16 */
modrm_dec m = decode_modrm(emu);
if (op2 == 0xBE) { set_reg32(emu, m.reg, (u32)(i32)(i8)read_rm8(emu, &m)); }
else { set_reg32(emu, m.reg, (u32)(i32)(i16)read_rm16(emu, &m)); }
} else if (op2 == 0x1F) { /* NOP r/m(多字节 NOP) */
decode_modrm(emu);
} else if (op2 == 0x05) { /* SYSCALL(不应出现在32位PE) */
emu->error = 1; emu->error_msg = "SYSCALL in 32-bit PE";
} else {
emu->error = 1; emu->error_msg = "0F opcode unsupported";
}
break;
}
default:
emu->error = 1; emu->error_msg = "unsupported opcode";
break;
} /* end switch(op) */
if (emu->error) {
log_hex64("[PE32] error at EIP=", emu->eip);
log_hex64("[PE32] opcode=", op);
log_info("[PE32] ");
log_info(emu->error_msg ? emu->error_msg : "(null)");
break;
}
} /* end while */
if (emu->insn_count >= emu->insn_limit) {
log_error("[PE32] instruction limit reached");
emu->error = 1;
}
if (exit_code) *exit_code = emu->exit_code;
return emu->error ? -1 : 0;
}
int x86emu32_init(x86emu_state *emu, u8 *mem, u64 mem_size,
u32 image_base, u32 image_size,
pe_iat_entry *iat_entries, int iat_count,
u32 stack_top) {
for (int i = 0; i < 8; i++) emu->regs[i] = 0;
emu->eip = 0;
emu->eflags = 0x2; /* 保留位 = 1 */
emu->mem = mem;
emu->mem_size = mem_size;
emu->image_base = image_base;
emu->image_size = image_size;
emu->iat_entries = iat_entries;
emu->iat_count = iat_count;
emu->stack_base = stack_top;
emu->stack_size = 0x10000; /* 64KB 栈 */
emu->heap_base = image_base + image_size;
emu->heap_size = 0x100000; /* 1MB heap */
emu->heap_next = emu->heap_base;
emu->exited = 0;
emu->exit_code = 0;
emu->error = 0;
emu->error_msg = 0;
emu->insn_count = 0;
/* 设置 ESP 到栈顶,对齐 16 */
emu->regs[X86_ESP] = stack_top & ~0xFu;
emu->regs[X86_EBP] = 0;
return 0;
}
+100
View File
@@ -0,0 +1,100 @@
#ifndef X86EMU32_H
#define X86EMU32_H
/* x86emu32.h — x86-32 指令解释器(PE32 执行引擎)。
*
* 寄存器级解释执行 32位 PE 代码。覆盖 mingw-w64 控制台程序常用指令集。
* 遇不支持的指令时日志告警并返回错误。
*/
#include <utsm/types.h>
/* x86 通用寄存器索引 */
enum {
X86_EAX = 0, X86_ECX, X86_EDX, X86_EBX,
X86_ESP, X86_EBP, X86_ESI, X86_EDI
};
/* EFLAGS 位 */
#define X86_CF (1u << 0)
#define X86_PF (1u << 2)
#define X86_AF (1u << 4)
#define X86_ZF (1u << 6)
#define X86_SF (1u << 7)
#define X86_OF (1u << 11)
#define X86_DF (1u << 10)
/* IAT 条目信息(解释器用于 CALL 拦截) */
typedef struct pe_iat_entry {
u32 iat_rva; /* IAT 中该条目的 RVA */
int shim_index; /* 对应 shim 表索引,-1 = 未实现 stub */
u32 target_addr; /* 模拟地址(iat_rva + image_base) */
} pe_iat_entry;
typedef struct x86emu_state {
u32 regs[8]; /* EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI */
u32 eip; /* 指令指针(相对 mem 基址的偏移) */
u32 eflags;
u8 *mem; /* guest 内存基址(= PE image_base) */
u64 mem_size; /* guest 内存大小 */
u32 image_base; /* PE 加载基址(= mem,32位截断) */
u32 image_size;
/* IAT 表(用于 CALL 拦截) */
pe_iat_entry *iat_entries;
int iat_count;
/* 栈区 */
u32 stack_base; /* 栈底(高地址) */
u32 stack_size;
/* heap 区 */
u32 heap_base;
u32 heap_size;
u32 heap_next; /* 下次分配偏移 */
/* 退出状态 */
int exited; /* ExitProcess 被调用 */
u64 exit_code;
int error; /* 解释错误 */
const char *error_msg;
/* 指令计数限制(防死循环) */
u64 insn_count;
u64 insn_limit;
} x86emu_state;
/* 初始化解释器状态。
* mem = PE image 加载基址(已映射节区+重定位+IAT 填充)。
* iat_entries / iat_count = pe_loader 解析的 IAT 表。
* stack_top = 栈顶 ESP 初始值(相对 mem 的偏移)。
* 返回 0 成功。 */
int x86emu32_init(x86emu_state *emu, u8 *mem, u64 mem_size,
u32 image_base, u32 image_size,
pe_iat_entry *iat_entries, int iat_count,
u32 stack_top);
/* 执行直到 ExitProcess 或错误。
* 返回 0 正常退出(exit_code 有效),负数错误。 */
int x86emu32_run(x86emu_state *emu, u64 *exit_code);
/* 从模拟栈读取 N 个参数(cdecl/stdcall)。
* esp_offset = 参数相对 ESP 的偏移(0=第一个参数)。
* 返回参数值。 */
u64 x86emu32_read_arg(x86emu_state *emu, int esp_offset);
/* 模拟栈 push/pop(供 shim32 回调使用) */
void x86emu32_push32(x86emu_state *emu, u32 val);
u32 x86emu32_pop32(x86emu_state *emu);
/* 读写模拟内存 */
u8 x86emu32_read8(x86emu_state *emu, u32 addr);
u16 x86emu32_read16(x86emu_state *emu, u32 addr);
u32 x86emu32_read32(x86emu_state *emu, u32 addr);
void x86emu32_write8(x86emu_state *emu, u32 addr, u8 val);
void x86emu32_write16(x86emu_state *emu, u32 addr, u16 val);
void x86emu32_write32(x86emu_state *emu, u32 addr, u32 val);
#endif /* X86EMU32_H */
+10 -9
View File
@@ -27,13 +27,9 @@ extern void vmx_vm_exit_handler(void);
extern int vmexit_dispatch(void);
extern u64 vmexit_get_count(void);
/* Globals shared with vmexit_asm.S (must match vmm.c) */
extern volatile u64 g_saved_host_rsp;
extern volatile u64 g_saved_return_rip;
extern volatile int g_guest_terminated;
extern volatile u64 g_last_exit_reason;
/* Host stack for VM-Exit (reuse the one from vmm.c) */
/* g_saved_host_rsp / g_saved_return_rip / g_guest_terminated /
* g_last_exit_reason / g_linux_guest_active / g_guest_parked /
* g_guest_regs / g_host_stack 通过 <utsm/vmm.h> 声明(vmm.c 定义)。 */
extern u8 g_host_stack[8192];
/* CR helpers */
@@ -288,6 +284,8 @@ int linux_launch(void) {
/* Reset VM-Exit state */
g_guest_terminated = 0;
g_last_exit_reason = 0xFFFFFFFFULL;
g_linux_guest_active = 1; /* 标记当前 guest 为 Linux(HLT 时 park) */
g_guest_parked = 0;
/* Configure VMCS */
linux_vmcs_setup_guest_state(gi);
@@ -331,11 +329,14 @@ int linux_launch(void) {
if (failed) {
u64 error = vmx_vmcs_read(VMCS_VMX_INSTRUCTION_ERROR);
log_hex64("[LINUX] vmlaunch failed, error=", error);
g_linux_guest_active = 0;
return -3;
}
/* Guest terminated */
log_info("[LINUX] guest terminated");
/* Guest parked (HLT) — Linux daemon 已驻留,等待 linux_resume() 唤醒 */
g_linux_guest_active = 0; /* 回到 host 上下文,清除 active 标志 */
g_guest_parked = 1; /* 标记 guest 已 park,linux_resume() 可唤醒 */
log_info("[LINUX] guest parked (daemon ready)");
log_hex64("[LINUX] last exit reason=", g_last_exit_reason);
log_hex64("[LINUX] vmexit count=", vmexit_get_count());
+198
View File
@@ -0,0 +1,198 @@
/* linux_compat.c — Deshab Linux 程序兼容层服务实现。
*
* 依赖 UTSM+Linux 双内核架构与 IPC 共享内存。Linux guest 作为 daemon
* 在 VMX guest 中 park-and-resume 驻留。UTSM 侧通过 IPC ring 向 daemon
* 发送 exec 请求,并 vmresume 唤醒 guest 执行。
*
* 执行流程(exec()):
* 1. 构建 ipc_exec_request,通过 ipc_shm_send(UTSM_MSG_EXEC_REQUEST) 入队
* 2. 调用 linux_resume() → vmresume → Linux daemon 读取请求 → fork+exec
* 3. daemon 通过 linux_to_utsm ring 回传 UTSM_MSG_EXEC_STDOUT/STDERR/EXIT
* 4. daemon HLT park → linux_resume() 返回
* 5. exec() 从 ring 读取所有响应消息,拼接 stdout,取 exit code
*
* 服务指针通过 dsk_boot_context.reserved[5] 暴露给 shell/cmd/desktop。
*/
#include <utsm/linux_compat.h>
#include <utsm/linux_resume.h>
#include <utsm/ipc_shm.h>
#include <utsm/vmm.h>
#include <utsm/log.h>
#include <utsm/types.h>
#include <ipc_proto.h>
/* ===== 内部辅助 ===== */
static u64 my_strlen(const char *s) {
u64 n = 0;
if (s) while (s[n]) n++;
return n;
}
static void my_memcpy(void *d, const void *s, u64 n) {
u8 *dd = (u8 *)d;
const u8 *ss = (const u8 *)s;
while (n--) *dd++ = *ss++;
}
static void my_memzero(void *d, u64 n) {
u8 *p = (u8 *)d;
while (n--) *p++ = 0;
}
/* ===== 服务状态 ===== */
static int g_compat_ready; /* 1 = linux_launch 已成功,服务可用 */
void linux_compat_init(void) {
/* 在 linux_launch 成功(guest parked)后由 kernel_main 调用 */
if (linux_is_parked() && ipc_shm_is_ready()) {
g_compat_ready = 1;
log_info("[LNXC] service ready (guest parked, IPC ok)");
} else {
g_compat_ready = 0;
log_warn("[LNXC] service not ready (guest not parked or IPC down)");
}
}
/* ===== 服务方法 ===== */
static int lxc_is_available(void) {
return (g_compat_ready && linux_is_parked() && ipc_shm_is_ready()) ? 1 : 0;
}
/* 等待 Linux daemon 的响应消息。
* linux_resume() 返回后,daemon 已 park,所有响应消息应已在 ring 中。
* 我们循环 pop 直到拿到 EXEC_EXIT 或 ring 空(超时保护)。 */
static int lxc_drain_responses(char *out_buf, u64 out_cap, u64 *out_len,
u64 *exit_code) {
u64 written = 0;
int got_exit = 0;
u64 exit_val = 0;
/* 最多消费 256 条消息(防止异常情况下死循环) */
for (int i = 0; i < 256; i++) {
struct utsm_ipc_msg msg;
if (ipc_shm_recv(&msg) != 0) {
/* ring 空 */
break;
}
switch (msg.type) {
case UTSM_MSG_EXEC_STDOUT:
case UTSM_MSG_EXEC_STDERR: {
/* 拼接到 stdout 缓冲区(stderr 也并入,简化调用方处理) */
u32 n = msg.data_len;
if (out_buf && out_cap > written) {
u32 space = (u32)(out_cap - written);
u32 to_copy = (n < space) ? n : space;
my_memcpy(out_buf + written, msg.data, to_copy);
written += to_copy;
}
break;
}
case UTSM_MSG_EXEC_EXIT: {
if (msg.data_len >= sizeof(struct ipc_exec_exit)) {
struct ipc_exec_exit ex;
my_memcpy(&ex, msg.data, sizeof(ex));
exit_val = ex.exit_code;
}
got_exit = 1;
break;
}
default:
/* 忽略其他消息(HELLO/PONG 等) */
break;
}
if (got_exit) break;
}
if (out_len) *out_len = written;
if (exit_code) *exit_code = exit_val;
return got_exit ? 0 : -4; /* -4 = 超时无 exit 响应 */
}
static int lxc_exec(const char *path, int argc, const char *const *argv,
char *stdout_buf, u64 stdout_cap, u64 *stdout_len,
u64 *exit_code) {
if (!lxc_is_available()) {
return -1;
}
if (!path) {
return -1;
}
/* 1. 构建 exec 请求 */
struct ipc_exec_request req;
my_memzero(&req, sizeof(req));
req.argc = (u32)argc;
req.flags = 0;
u64 plen = my_strlen(path);
if (plen >= UTSM_EXEC_PATH_MAX) plen = UTSM_EXEC_PATH_MAX - 1;
my_memcpy(req.path, path, plen);
req.path[plen] = 0;
/* 拼接 argv_blob:每个 argv[i] NUL-terminated */
u64 blob_off = 0;
if (argc > UTSM_EXEC_MAX_ARGS) argc = UTSM_EXEC_MAX_ARGS;
for (int i = 0; i < argc; i++) {
if (!argv[i]) continue;
u64 alen = my_strlen(argv[i]);
if (blob_off + alen + 1 > UTSM_EXEC_ARGV_MAX) break;
my_memcpy(req.argv_blob + blob_off, argv[i], alen);
blob_off += alen;
req.argv_blob[blob_off++] = 0;
}
/* 2. 发送 EXEC_REQUEST */
if (ipc_shm_send(UTSM_MSG_EXEC_REQUEST, &req, sizeof(req)) != 0) {
log_warn("[LNXC] exec: failed to enqueue request");
return -2;
}
/* 3. 唤醒 Linux guest 执行 */
int r = linux_resume();
if (r != 0) {
log_hex64("[LNXC] exec: linux_resume failed=", (u64)(i64)r);
return -3;
}
/* 4. 读取响应(daemon 已再次 park,响应在 ring 中) */
return lxc_drain_responses(stdout_buf, stdout_cap, stdout_len, exit_code);
}
static int lxc_status(char *buf, u64 cap) {
if (!buf || cap == 0) return 0;
const char *s;
if (!g_compat_ready) {
s = "linux_compat: not initialized";
} else if (!linux_is_parked()) {
s = "linux_compat: guest not parked";
} else if (!ipc_shm_is_ready()) {
s = "linux_compat: IPC down";
} else {
s = "linux_compat: ready";
}
u64 n = my_strlen(s);
if (n >= cap) n = cap - 1;
my_memcpy(buf, s, n);
buf[n] = 0;
return (int)n;
}
/* ===== 服务表 ===== */
static const linux_compat_service g_lxc_service = {
LINUX_COMPAT_MAGIC,
lxc_is_available,
lxc_exec,
lxc_status,
};
const linux_compat_service *linux_compat_get_service(void) {
return &g_lxc_service;
}
+68
View File
@@ -0,0 +1,68 @@
/* linux_resume.c — Linux guest park-and-resume 唤醒实现。
*
* linux_resume() 通过 vmresume 唤醒已 HLT park 的 Linux guest。
* guest daemon 处理 IPC 请求后再次 HLT park,控制权返回 host。
*
* 控制流与 linux_launch() 的 vmlaunch 对称:
* - 保存 host RSP 和返回 RIP
* - 执行 vmresume(成功则进入 guest,不返回)
* - guest HLT → VM-Exit → handle_hlt park → g_guest_terminated=1
* - vmexit_asm.S 恢复 host RSP,jmp 到返回 RIP
* - linux_resume() 继续执行,返回 0
*/
#include <utsm/linux_resume.h>
#include <utsm/vmx.h>
#include <utsm/vmm.h>
#include <utsm/log.h>
#include <utsm/types.h>
int linux_is_parked(void) {
return g_guest_parked ? 1 : 0;
}
int linux_resume(void) {
if (!g_guest_parked) {
log_warn("[LINUX] resume: guest not parked");
return -1;
}
/* 设置 active 标志:handle_hlt 检查此标志决定 park(而非 terminate) */
g_linux_guest_active = 1;
g_guest_terminated = 0;
g_guest_parked = 0;
/* vmresume 控制流(与 linux_launch 的 vmlaunch 对称):
* - 失败:执行下一条指令,failed=1
* - 成功:进入 guest,不返回。VM-Exit 后跳到 vmx_vm_exit_handler。
* - guest park 时,handler 恢复 saved_rsp 并 jmp 到 post_resume 标签。 */
int failed;
__asm__ volatile(
"movq %%rsp, g_saved_host_rsp(%%rip)\n\t" /* 保存当前 RSP */
"leaq 1f(%%rip), %%rax\n\t" /* 取 post_resume 标签地址 */
"movq %%rax, g_saved_return_rip(%%rip)\n\t" /* 保存返回 RIP */
"vmresume\n\t" /* 唤醒 guest */
/* ---- 失败路径 ---- */
"movl $1, %0\n\t"
"jmp 2f\n\t"
/* ---- post_resume: park 路径 jmp 到这里 ---- */
"1:\n\t"
"movl $0, %0\n\t"
"2:\n\t"
: "=r"(failed)
:: "rax", "rcx", "rdx", "rsi", "rdi",
"r8", "r9", "r10", "r11", "memory"
);
/* 回到 host 上下文 */
g_linux_guest_active = 0;
g_guest_parked = 1; /* guest 再次 park */
if (failed) {
u64 error = vmx_vmcs_read(VMCS_VMX_INSTRUCTION_ERROR);
log_hex64("[LINUX] vmresume failed, error=", error);
return -2;
}
return 0;
}
+14 -4
View File
@@ -23,11 +23,21 @@ static void log_exit_diagnostics(u64 reason, u64 qualification, u64 rip, u64 len
log_hex64("[VMEXIT] ilen=", len);
}
/* 处理 HLT:Phase 1.1 自检场景下表示 guest 完成测试,停止 guest。 */
/* 处理 HLT:
* - self-test guest:终止(guest 完成测试)
* - Linux guest:park(推进 RIP 越过 HLT,exit-to-host,设 g_guest_parked=1)
* host 调用 linux_resume() 时 vmresume 唤醒 guest 从 HLT 之后继续执行。 */
static int handle_hlt(u64 rip, u64 instr_len, int *out_resume) {
*out_resume = 0; /* 不 resume,guest 终止 */
log_info("[VMEXIT] HLT - guest halted");
(void)rip; (void)instr_len;
*out_resume = 0; /* 两种情况都 exit-to-host */
if (g_linux_guest_active) {
/* Linux guest: park — 推进 RIP 越过 HLT 指令 */
vmx_vmcs_write(VMCS_GUEST_RIP, rip + instr_len);
g_guest_parked = 1;
log_info("[VMEXIT] HLT - Linux guest parked");
} else {
/* self-test guest: 终止 */
log_info("[VMEXIT] HLT - guest halted");
}
return 0;
}
+6
View File
@@ -46,6 +46,12 @@ volatile u64 g_saved_return_rip;
volatile int g_guest_terminated;
volatile u64 g_last_exit_reason;
/* Linux guest park-and-resume 状态。
* g_linux_guest_active: 1 = 当前运行的 guest 是 Linux(HLT 时 park,不终止)
* g_guest_parked: 1 = Linux guest 已 HLT 驻留,等待 vmresume 唤醒 */
volatile int g_linux_guest_active;
volatile int g_guest_parked;
/* Guest GPR save area (referenced by vmexit_asm.S).
* VM-Exit 时 CPU 不自动保存 guest GPR,由汇编入口保存到此结构。
* C 处理器可读写此结构(如 VMCALL 返回值写入 rax)。 */