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 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 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) S_SOURCES := $(wildcard arch/x86_64/*.S vmm/*.S)
OBJECTS := $(C_SOURCES:.c=.o) $(S_SOURCES:.S=.o) 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. */ * Returns 0 on successful guest termination, negative on error. */
int linux_launch(void); 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 \ #define LINUX_DEFAULT_CMDLINE \
"console=ttyS0,115200 earlyprintk=serial nokaslr " \ "console=ttyS0,115200 earlyprintk=serial nokaslr " \
"no_timer_check loglevel=7" "no_timer_check loglevel=7 nohlt idle=poll"
#endif #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. */ * Non-static: shared between vmm.c, vmexit.c, hypercall.c, and vmexit_asm.S. */
extern volatile struct vmexit_guest_regs g_guest_regs; 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 API ===== */
/* 初始化 VMM:VMX root 模式 + EPT 表 + 分配 VMCS。 /* 初始化 VMM:VMX root 模式 + EPT 表 + 分配 VMCS。
+14
View File
@@ -3,6 +3,8 @@
#include <utsm/dkm.h> #include <utsm/dkm.h>
#include <utsm/log.h> #include <utsm/log.h>
#include <utsm/types.h> #include <utsm/types.h>
#include <utsm/pe.h>
#include <utsm/linux_compat.h>
#include "../arch/x86_64/limine.h" #include "../arch/x86_64/limine.h"
#define DSK_PATH "/system/deshab64/deshab.elf" #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->boot_modules_response = (u64)g_module_request.response;
ctx->dkm_kernel_api = (u64)dkm_get_kernel_api(); 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; u64 rsp;
__asm__ volatile ("movq %%rsp, %0" : "=r"(rsp)); __asm__ volatile ("movq %%rsp, %0" : "=r"(rsp));
ctx->kernel_stack_top = rsp; ctx->kernel_stack_top = rsp;
Binary file not shown.
+5 -1
View File
@@ -8,6 +8,7 @@
#include <utsm/block.h> #include <utsm/block.h>
#include <utsm/net.h> #include <utsm/net.h>
#include <utsm/ipc_shm.h> #include <utsm/ipc_shm.h>
#include <utsm/linux_compat.h>
void arch_halt_forever(void); void arch_halt_forever(void);
@@ -71,7 +72,10 @@ void kernel_main(void) {
int lin_st = linux_launch(); int lin_st = linux_launch();
if (lin_st == 0) { 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 { } else {
log_error("[UTSM] Linux launch failed"); log_error("[UTSM] Linux launch failed");
log_hex64("[UTSM] Linux st=", (u64)(i64)lin_st); 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 int vmexit_dispatch(void);
extern u64 vmexit_get_count(void); extern u64 vmexit_get_count(void);
/* Globals shared with vmexit_asm.S (must match vmm.c) */ /* g_saved_host_rsp / g_saved_return_rip / g_guest_terminated /
extern volatile u64 g_saved_host_rsp; * g_last_exit_reason / g_linux_guest_active / g_guest_parked /
extern volatile u64 g_saved_return_rip; * g_guest_regs / g_host_stack 通过 <utsm/vmm.h> 声明(vmm.c 定义)。 */
extern volatile int g_guest_terminated;
extern volatile u64 g_last_exit_reason;
/* Host stack for VM-Exit (reuse the one from vmm.c) */
extern u8 g_host_stack[8192]; extern u8 g_host_stack[8192];
/* CR helpers */ /* CR helpers */
@@ -288,6 +284,8 @@ int linux_launch(void) {
/* Reset VM-Exit state */ /* Reset VM-Exit state */
g_guest_terminated = 0; g_guest_terminated = 0;
g_last_exit_reason = 0xFFFFFFFFULL; g_last_exit_reason = 0xFFFFFFFFULL;
g_linux_guest_active = 1; /* 标记当前 guest 为 Linux(HLT 时 park) */
g_guest_parked = 0;
/* Configure VMCS */ /* Configure VMCS */
linux_vmcs_setup_guest_state(gi); linux_vmcs_setup_guest_state(gi);
@@ -331,11 +329,14 @@ int linux_launch(void) {
if (failed) { if (failed) {
u64 error = vmx_vmcs_read(VMCS_VMX_INSTRUCTION_ERROR); u64 error = vmx_vmcs_read(VMCS_VMX_INSTRUCTION_ERROR);
log_hex64("[LINUX] vmlaunch failed, error=", error); log_hex64("[LINUX] vmlaunch failed, error=", error);
g_linux_guest_active = 0;
return -3; return -3;
} }
/* Guest terminated */ /* Guest parked (HLT) — Linux daemon 已驻留,等待 linux_resume() 唤醒 */
log_info("[LINUX] guest terminated"); 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] last exit reason=", g_last_exit_reason);
log_hex64("[LINUX] vmexit count=", vmexit_get_count()); 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); 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) { static int handle_hlt(u64 rip, u64 instr_len, int *out_resume) {
*out_resume = 0; /* 不 resume,guest 终止 */ *out_resume = 0; /* 两种情况都 exit-to-host */
log_info("[VMEXIT] HLT - guest halted"); if (g_linux_guest_active) {
(void)rip; (void)instr_len; /* 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; return 0;
} }
+6
View File
@@ -46,6 +46,12 @@ volatile u64 g_saved_return_rip;
volatile int g_guest_terminated; volatile int g_guest_terminated;
volatile u64 g_last_exit_reason; 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). /* Guest GPR save area (referenced by vmexit_asm.S).
* VM-Exit 时 CPU 不自动保存 guest GPR,由汇编入口保存到此结构。 * VM-Exit 时 CPU 不自动保存 guest GPR,由汇编入口保存到此结构。
* C 处理器可读写此结构(如 VMCALL 返回值写入 rax)。 */ * C 处理器可读写此结构(如 VMCALL 返回值写入 rax)。 */
+25
View File
@@ -0,0 +1,25 @@
CC := clang
LD := ld.lld
ROOT := ../..
OUT := $(ROOT)/SYSTEM/system/deshab64/cmd.elf
CFLAGS := -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin -fno-stack-protector -fpie -mno-red-zone -mno-sse -mno-sse2 -mno-mmx -msoft-float -m64 -Wall -Wextra -I../UTSM/include -O2
LDFLAGS := -nostdlib -static -pie -z max-page-size=0x1000 -T linker.ld
C_SOURCES := main.c
OBJECTS := $(C_SOURCES:.c=.o)
.PHONY: all clean
all: $(OUT)
$(OUT): $(OBJECTS) linker.ld
@if not exist "$(ROOT)\SYSTEM\system\deshab64" mkdir "$(ROOT)\SYSTEM\system\deshab64"
$(LD) $(LDFLAGS) -o $@ $(OBJECTS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
powershell -NoProfile -Command "Get-ChildItem -Path . -Recurse -Filter *.o | Remove-Item -Force; if (Test-Path '$(OUT)') { Remove-Item '$(OUT)' -Force }"
+24
View File
@@ -0,0 +1,24 @@
ENTRY(dsk_entry)
PHDRS
{
text PT_LOAD FLAGS(5);
rodata PT_LOAD FLAGS(4);
data PT_LOAD FLAGS(6);
dynamic PT_DYNAMIC FLAGS(4);
}
SECTIONS
{
. = 0x1000;
.text : ALIGN(4K) { *(.text*) } :text
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
.data : ALIGN(4K) {
*(.data*)
*(.data.rel.ro*)
*(COMMON)
*(.bss*)
} :data
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
}
+961
View File
@@ -0,0 +1,961 @@
/* Deshab CMD — Windows 风格命令行(PE/EXE 兼容层前端)
*
* 黑底白字 cmd.exe 风格,PS/2 键盘输入。
* 内置命令:dir/cd/type/copy/del/ren/mkdir/rmdir/echo/cls/ver/set/help/exit
* PE 执行:输入 foo.exe 或 foo → 从 FAT32 根读取 → 调用 UTSM PE 服务执行
* - PE32+ (64位):UTSM 原生 Ring0 执行
* - PE32 (32位):UTSM 内嵌 x86-32 解释器执行
* Esc 返回桌面。
*/
#include "../UTSM/include/utsm/dsk.h"
#include "../UTSM/include/utsm/pe.h"
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define COM1 0x3F8
static __inline__ void outb(u16 port, u8 value) { __asm__ volatile("outb %0,%1"::"a"(value),"Nd"(port)); }
static __inline__ u8 inb(u16 port) { u8 v; __asm__ volatile("inb %1,%0":"=a"(v):"Nd"(port)); return v; }
/* ---- TSC 计时 ---- */
static u64 g_tsc_per_ms = 0;
static __inline__ u64 rdtsc_cmd(void) {
u32 lo, hi;
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
return ((u64)hi << 32) | lo;
}
static void tsc_calibrate_cmd(void) {
outb(0x43, 0x30);
outb(0x40, 0x7c);
outb(0x40, 0x2e);
u64 tsc_start = rdtsc_cmd();
u16 prev = 0; u64 loops = 0;
for (;;) {
outb(0x43, 0x00);
u16 cur = (u16)inb(0x40) | ((u16)inb(0x40) << 8);
if (cur > prev && loops > 10) break;
prev = cur; loops++;
}
u64 tsc_end = rdtsc_cmd();
g_tsc_per_ms = (tsc_end - tsc_start) / 10;
}
static void serial_wait_tx(void) {
if (g_tsc_per_ms == 0) tsc_calibrate_cmd();
if (g_tsc_per_ms == 0) {
for (u32 i = 0; i < 100000; i++) { if (inb(COM1 + 5) & 0x20) break; }
return;
}
u64 deadline = rdtsc_cmd() + g_tsc_per_ms / 10;
while (rdtsc_cmd() < deadline) {
if (inb(COM1 + 5) & 0x20) break;
__asm__ volatile("pause");
}
}
static void sputc(char c) { serial_wait_tx(); outb(COM1, (unsigned char)c); }
static void swrite(const char *s) { while (*s) { if (*s == '\n') sputc('\r'); sputc(*s++); } }
static void logl(const char *s) { swrite(s); swrite("\n"); }
/* ASCII 字体 — 必须在 deshab_ui.h 之前包含 */
#include "../firstInit/ascii_bitmaps.c"
#include "../UTSM/include/utsm/deshab_ui.h"
/* FAT32 共享读写库 */
#include "../tools/fat32_io.h"
/* ============================================================
* 颜色定义 — Windows cmd.exe 风格(黑底浅灰字)
* ============================================================ */
#define CMD_BG 0xFF000000u /* 纯黑背景 */
#define CMD_TEXT 0xFFC0C0C0u /* 浅灰文字(cmd.exe 默认) */
#define CMD_PROMPT 0xFFFFFFFFu /* 白色提示符 */
#define CMD_ERROR 0xFFFF6060u /* 浅红错误 */
#define CMD_OK 0xFF60FF60u /* 浅绿成功 */
#define CMD_INFO 0xFF60A0FFu /* 浅蓝信息 */
#define CMD_DIM 0xFF808080u /* 灰色暗淡 */
#define CMD_WARN 0xFFFFFF60u /* 黄色警告 */
/* ============================================================
* 终端缓冲区与渲染
* ============================================================ */
#define TERM_COLS 100
#define TERM_ROWS 40
#define TERM_MAX_CHARS (TERM_COLS * TERM_ROWS)
static du_context g_ctx;
static u64 fb_a, fb_w, fb_h, fb_p;
static u8 term_ch[TERM_MAX_CHARS];
static u32 term_fg[TERM_MAX_CHARS];
static int term_w = TERM_COLS;
static int term_h = TERM_ROWS;
static int cur_col = 0;
static int cur_row = 0;
static int cur_visible = 1;
static int term_start_x, term_start_y;
static const dsk_boot_context *g_boot_ctx = 0;
static u64 g_kernel_api = 0;
static const pe_service *g_pe_svc = 0;
/* dev_mode 串口镜像 */
static int g_serial_mirror = 0;
static void term_init_pos(void) {
int margin = 4;
term_start_x = margin;
term_start_y = margin;
int avail_w = (int)fb_w - margin * 2;
int avail_h = (int)fb_h - margin * 2;
term_w = avail_w / (int)DU_ASCII_STEP;
term_h = avail_h / (int)DU_ASCII_LINE_H;
if (term_w < 10) term_w = 10;
if (term_h < 5) term_h = 5;
if (term_w > TERM_COLS) term_w = TERM_COLS;
if (term_h > TERM_ROWS) term_h = TERM_ROWS;
}
static void term_clear_buf(void) {
for (int i = 0; i < TERM_MAX_CHARS; i++) {
term_ch[i] = ' ';
term_fg[i] = CMD_TEXT;
}
cur_col = 0;
cur_row = 0;
}
static void term_scroll(void) {
for (int r = 1; r < term_h; r++) {
for (int c = 0; c < term_w; c++) {
int src = r * TERM_COLS + c;
int dst = (r - 1) * TERM_COLS + c;
term_ch[dst] = term_ch[src];
term_fg[dst] = term_fg[src];
}
}
for (int c = 0; c < term_w; c++) {
term_ch[(term_h - 1) * TERM_COLS + c] = ' ';
term_fg[(term_h - 1) * TERM_COLS + c] = CMD_TEXT;
}
cur_row = term_h - 1;
cur_col = 0;
}
static void term_newline(void) {
cur_col = 0;
cur_row++;
if (cur_row >= term_h) term_scroll();
}
static void term_putc_color(char c, u32 color) {
if (g_serial_mirror) { if (c == '\n') sputc('\r'); sputc(c); }
if (c == '\n') { term_newline(); return; }
if (c == '\r') { cur_col = 0; return; }
if (c == '\t') {
int spaces = 8 - (cur_col % 8);
for (int i = 0; i < spaces; i++) term_putc_color(' ', color);
return;
}
if (c < ' ' || c > '~') c = '.';
if (cur_col >= term_w) term_newline();
int idx = cur_row * TERM_COLS + cur_col;
term_ch[idx] = (u8)c;
term_fg[idx] = color;
cur_col++;
}
static void term_putc(char c) { term_putc_color(c, CMD_TEXT); }
static void term_puts_color(const char *s, u32 color) { while (*s) term_putc_color(*s++, color); }
static void term_puts(const char *s) { term_puts_color(s, CMD_TEXT); }
/* ---- 数字转字符串 ---- */
static void term_putu(u32 v) {
char buf[12];
int i = 11;
buf[i--] = 0;
if (v == 0) { buf[i--] = '0'; }
while (v > 0 && i >= 0) { buf[i--] = (char)('0' + (v % 10)); v /= 10; }
term_puts(&buf[i + 1]);
}
static void term_putx(u32 v) {
static const char hex[] = "0123456789ABCDEF";
term_putc('0'); term_putc('x');
for (int i = 28; i >= 0; i -= 4) {
u32 nib = (v >> i) & 0xF;
if (nib != 0 || i <= 12) term_putc(hex[nib]);
}
}
/* ---- 终端全屏渲染 ---- */
static void term_redraw_all(void) {
du_fill_rect(&g_ctx, 0, 0, (i64)fb_w, (i64)fb_h, CMD_BG);
for (int r = 0; r < term_h; r++) {
i64 y = term_start_y + (i64)r * (i64)DU_ASCII_LINE_H;
for (int c = 0; c < term_w; c++) {
int idx = r * TERM_COLS + c;
i64 x = term_start_x + (i64)c * (i64)DU_ASCII_STEP;
du_draw_char(&g_ctx, (char)term_ch[idx], x, y, term_fg[idx], CMD_BG);
}
}
}
static void term_redraw_cursor(void) {
if (cur_col >= term_w) return;
i64 x = term_start_x + (i64)cur_col * (i64)DU_ASCII_STEP;
i64 y = term_start_y + (i64)cur_row * (i64)DU_ASCII_LINE_H;
du_fill_rect(&g_ctx, x, y, (i64)DU_ASCII_STEP - 1, (i64)DU_ASCII_CELL_H, CMD_PROMPT);
}
static void term_clear_cursor(void) {
if (cur_col >= term_w) return;
i64 x = term_start_x + (i64)cur_col * (i64)DU_ASCII_STEP;
i64 y = term_start_y + (i64)cur_row * (i64)DU_ASCII_LINE_H;
int idx = cur_row * TERM_COLS + cur_col;
du_fill_rect(&g_ctx, x, y, (i64)DU_ASCII_STEP - 1, (i64)DU_ASCII_CELL_H, CMD_BG);
du_draw_char(&g_ctx, (char)term_ch[idx], x, y, term_fg[idx], CMD_BG);
}
/* ============================================================
* 键盘输入(PS/2 Scan Code Set 1)
* ============================================================ */
static char scan_to_ascii(u8 sc, int shift) {
static const char normal[58] = {
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=', 8, '\t',
'q','w','e','r','t','y','u','i','o','p','[',']','\n',0,
'a','s','d','f','g','h','j','k','l',';','\'', '`',0,'\\',
'z','x','c','v','b','n','m',',','.','/',0,'*',0,' '
};
static const char shifted[58] = {
0, 27, '!','@','#','$','%','^','&','*','(',')','_','+', 8, '\t',
'Q','W','E','R','T','Y','U','I','O','P','{','}','\n',0,
'A','S','D','F','G','H','J','K','L',':','"','~',0,'|',
'Z','X','C','V','B','N','M','<','>','?',0,'*',0,' '
};
if (sc >= 58) return 0;
return shift ? shifted[sc] : normal[sc];
}
/* ============================================================
* 字符串工具
* ============================================================ */
static int str_eq(const char *a, const char *b) {
while (*a && *b) { if (*a != *b) return 0; a++; b++; }
return *a == *b;
}
static int str_len(const char *s) {
int n = 0;
while (s[n]) n++;
return n;
}
static void str_copy(char *dst, const char *src, int max) {
int i = 0;
while (src[i] && i < max - 1) { dst[i] = src[i]; i++; }
dst[i] = 0;
}
static int str_ieq(const char *a, const char *b) {
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) return 0;
a++; b++;
}
return *a == *b;
}
/* ============================================================
* 输入行编辑
* ============================================================ */
static char input_buf[256];
static int input_len = 0;
static int input_cursor = 0;
static const char *PROMPT = "C:\\> ";
static void redraw_input_line(void) {
int prompt_len = str_len(PROMPT);
i64 y = term_start_y + (i64)cur_row * (i64)DU_ASCII_LINE_H;
du_fill_rect(&g_ctx, term_start_x, y,
(i64)term_w * (i64)DU_ASCII_STEP,
(i64)DU_ASCII_CELL_H, CMD_BG);
for (int i = 0; i < prompt_len; i++) {
i64 x = term_start_x + (i64)i * (i64)DU_ASCII_STEP;
du_draw_char(&g_ctx, PROMPT[i], x, y, CMD_PROMPT, CMD_BG);
}
for (int i = 0; i < input_len; i++) {
i64 x = term_start_x + (i64)(prompt_len + i) * (i64)DU_ASCII_STEP;
du_draw_char(&g_ctx, input_buf[i], x, y, CMD_TEXT, CMD_BG);
}
cur_col = prompt_len + input_cursor;
term_redraw_cursor();
}
static void insert_char(char c) {
if (input_len >= 255) return;
for (int i = input_len; i > input_cursor; i--)
input_buf[i] = input_buf[i - 1];
input_buf[input_cursor] = c;
input_len++;
input_cursor++;
redraw_input_line();
}
static void delete_char_back(void) {
if (input_cursor == 0) return;
for (int i = input_cursor - 1; i < input_len - 1; i++)
input_buf[i] = input_buf[i + 1];
input_len--;
input_cursor--;
input_buf[input_len] = 0;
redraw_input_line();
}
static void cursor_left(void) {
if (input_cursor > 0) { input_cursor--; redraw_input_line(); }
}
static void cursor_right(void) {
if (input_cursor < input_len) { input_cursor++; redraw_input_line(); }
}
static void cursor_home(void) {
input_cursor = 0;
redraw_input_line();
}
static void cursor_end(void) {
input_cursor = input_len;
redraw_input_line();
}
static void kill_line(void) {
input_len = 0;
input_cursor = 0;
input_buf[0] = 0;
redraw_input_line();
}
/* ============================================================
* 内置命令
* ============================================================ */
static void cmd_help(void) {
term_puts_color("Deshab CMD — 命令列表:\r\n", CMD_INFO);
term_puts(" dir 列出文件\r\n");
term_puts(" cd 显示当前目录\r\n");
term_puts(" type <file> 显示文件内容\r\n");
term_puts(" copy <a> <b> 复制文件\r\n");
term_puts(" del <file> 删除文件\r\n");
term_puts(" ren <a> <b> 重命名文件\r\n");
term_puts(" echo <text> 显示文本 (echo text > file 写入)\r\n");
term_puts(" cls 清屏\r\n");
term_puts(" ver 显示版本\r\n");
term_puts(" set 显示环境变量\r\n");
term_puts(" help 显示此帮助\r\n");
term_puts(" exit 返回桌面\r\n");
term_puts_color("\nPE 程序执行:\r\n", CMD_WARN);
term_puts(" <name>.exe 运行 PE32+/PE32 程序 (如 hello.exe)\r\n");
term_puts(" <name> 自动查找 name.exe 并运行\r\n");
}
static void cmd_ver(void) {
term_puts_color("Deshab CMD [Version 0.1.0]\r\n", CMD_OK);
term_puts_color("(c) 2026 Deshab Project. PE/EXE 兼容层 by UTSM.\r\n", CMD_DIM);
}
static void cmd_cls(void) {
term_clear_buf();
term_redraw_all();
}
static void cmd_cd(void) {
term_puts("C:\\\r\n");
}
static void cmd_set(void) {
term_puts_color("环境变量:\r\n", CMD_INFO);
term_puts(" PATH=C:\\;C:\\bin\r\n");
term_puts(" PROMPT=$P$G\r\n");
term_puts(" OS=Deshab\r\n");
term_puts(" PE_COMPAT=UTSM_PE32+_PE32\r\n");
}
/* dir — 列出 FAT32 根目录文件 */
typedef struct {
int count;
u32 total_bytes;
} dir_ctx_static;
static int dir_list_cb(const char *name, u32 size, u8 attr, void *ud) {
dir_ctx_static *st = (dir_ctx_static *)ud;
if (attr & 0x10) {
term_puts_color(name, CMD_INFO);
term_puts_color(" <DIR> ", CMD_DIM);
} else {
term_puts(name);
term_puts(" ");
/* 右对齐文件大小 */
u32 sz = size;
char numbuf[12];
int ni = 11;
numbuf[ni--] = 0;
if (sz == 0) numbuf[ni--] = '0';
while (sz > 0 && ni >= 0) { numbuf[ni--] = (char)('0' + sz % 10); sz /= 10; }
while (ni >= 0) numbuf[ni--] = ' ';
term_puts(&numbuf[0]);
st->total_bytes += size;
}
term_puts("\r\n");
st->count++;
return 0;
}
static void cmd_dir(void) {
if (!f32_blk_read) {
term_puts_color("dir: 无块设备\r\n", CMD_ERROR);
return;
}
term_puts_color(" C 盘的卷是 DESHAB\r\n", CMD_DIM);
term_puts_color(" 卷序列号为 DE5A-B002\r\n", CMD_DIM);
term_puts("\r\n C:\\ 的目录\r\n\r\n");
dir_ctx_static st = {0, 0};
f32_list_root(dir_list_cb, &st);
term_puts("\r\n");
term_putu((u32)st.count);
term_puts(" 个文件 ");
term_putu(st.total_bytes);
term_puts(" 字节\r\n");
}
/* type <file> — 显示文件内容 */
static void cmd_type(const char *args) {
if (!*args) { term_puts_color("type: 缺少文件名\r\n", CMD_ERROR); return; }
if (!f32_blk_read) { term_puts_color("type: 无块设备\r\n", CMD_ERROR); return; }
char name11[11];
if (f32_name_to_83(args, name11) != 0) {
term_puts_color("type: 无效文件名\r\n", CMD_ERROR);
return;
}
u8 *data = 0; u32 size = 0;
if (f32_read_root_file(name11, &data, &size) != 0) {
term_puts_color("type: 文件不存在\r\n", CMD_ERROR);
return;
}
/* 输出文件内容(按字符) */
for (u32 i = 0; i < size; i++) {
char c = (char)data[i];
if (c == '\n') term_putc('\r');
term_putc(c);
}
if (size > 0 && data[size - 1] != '\n') term_putc('\r');
term_putc('\n');
}
/* echo <text> — 显示文本或重定向到文件 */
static void cmd_echo(const char *args) {
/* 检查重定向: echo text > file */
char text[256];
str_copy(text, args, sizeof(text));
/* 查找 > */
int redir = -1;
for (int i = 0; text[i]; i++) {
if (text[i] == '>') { redir = i; break; }
}
if (redir >= 0) {
/* 重定向到文件 */
text[redir] = 0;
/* 去尾部空格 */
int tl = str_len(text);
while (tl > 0 && text[tl - 1] == ' ') text[--tl] = 0;
/* 获取文件名 */
char *fn = text + redir + 1;
while (*fn == ' ') fn++;
if (!*fn) { term_puts_color("echo: 重定向缺少文件名\r\n", CMD_ERROR); return; }
char name11[11];
if (f32_name_to_83(fn, name11) != 0) {
term_puts_color("echo: 无效文件名\r\n", CMD_ERROR);
return;
}
if (!f32_blk_write) { term_puts_color("echo: 无块设备写能力\r\n", CMD_ERROR); return; }
/* 构造写入内容 */
char content[256];
int ci = 0;
for (int i = 0; i < tl && ci < 254; i++) content[ci++] = text[i];
content[ci++] = '\r';
content[ci++] = '\n';
if (f32_write_root_file(name11, (const u8 *)content, (u32)ci) != 0) {
term_puts_color("echo: 写入失败\r\n", CMD_ERROR);
return;
}
term_puts_color("echo: 已写入 ", CMD_OK);
term_puts(fn);
term_puts("\r\n");
} else {
/* 直接显示 */
if (*args) {
term_puts(args);
}
term_puts("\r\n");
}
}
/* copy <src> <dst> — 复制文件 */
static void cmd_copy(const char *args) {
char src[64], dst[64];
int si = 0, di = 0;
const char *p = args;
while (*p == ' ') p++;
while (*p && *p != ' ' && si < 63) src[si++] = *p++;
src[si] = 0;
while (*p == ' ') p++;
while (*p && di < 63) dst[di++] = *p++;
dst[di] = 0;
if (!src[0] || !dst[0]) {
term_puts_color("copy: 用法 copy <源文件> <目标文件>\r\n", CMD_ERROR);
return;
}
if (!f32_blk_read || !f32_blk_write) {
term_puts_color("copy: 无块设备\r\n", CMD_ERROR);
return;
}
char s83[11], d83[11];
if (f32_name_to_83(src, s83) != 0 || f32_name_to_83(dst, d83) != 0) {
term_puts_color("copy: 无效文件名\r\n", CMD_ERROR);
return;
}
u8 *data = 0; u32 size = 0;
if (f32_read_root_file(s83, &data, &size) != 0) {
term_puts_color("copy: 源文件不存在\r\n", CMD_ERROR);
return;
}
if (f32_write_root_file(d83, data, size) != 0) {
term_puts_color("copy: 写入失败\r\n", CMD_ERROR);
return;
}
term_puts_color(" 1 个文件已复制。\r\n", CMD_OK);
}
/* del <file> — 删除文件 */
static void cmd_del(const char *args) {
if (!*args) { term_puts_color("del: 缺少文件名\r\n", CMD_ERROR); return; }
if (!f32_blk_write) { term_puts_color("del: 无块设备写能力\r\n", CMD_ERROR); return; }
char name11[11];
if (f32_name_to_83(args, name11) != 0) {
term_puts_color("del: 无效文件名\r\n", CMD_ERROR);
return;
}
if (f32_delete_root_file(name11) != 0) {
term_puts_color("del: 文件不存在或删除失败\r\n", CMD_ERROR);
return;
}
term_puts_color("del: 已删除\r\n", CMD_OK);
}
/* ren <old> <new> — 重命名文件 */
static void cmd_ren(const char *args) {
char old[64], nw[64];
int oi = 0, ni = 0;
const char *p = args;
while (*p == ' ') p++;
while (*p && *p != ' ' && oi < 63) old[oi++] = *p++;
old[oi] = 0;
while (*p == ' ') p++;
while (*p && ni < 63) nw[ni++] = *p++;
nw[ni] = 0;
if (!old[0] || !nw[0]) {
term_puts_color("ren: 用法 ren <旧名> <新名>\r\n", CMD_ERROR);
return;
}
if (!f32_blk_read || !f32_blk_write) {
term_puts_color("ren: 无块设备\r\n", CMD_ERROR);
return;
}
char o83[11], n83[11];
if (f32_name_to_83(old, o83) != 0 || f32_name_to_83(nw, n83) != 0) {
term_puts_color("ren: 无效文件名\r\n", CMD_ERROR);
return;
}
u8 *data = 0; u32 size = 0;
if (f32_read_root_file(o83, &data, &size) != 0) {
term_puts_color("ren: 源文件不存在\r\n", CMD_ERROR);
return;
}
if (f32_write_root_file(n83, data, size) != 0) {
term_puts_color("ren: 写入新文件失败\r\n", CMD_ERROR);
return;
}
if (f32_delete_root_file(o83) != 0) {
term_puts_color("ren: 删除旧文件失败(警告)\r\n", CMD_WARN);
}
term_puts_color("ren: 已重命名\r\n", CMD_OK);
}
static void cmd_mkdir(void) { term_puts_color("mkdir: FAT32 根目录不支持子目录\r\n", CMD_WARN); }
static void cmd_rmdir(void) { term_puts_color("rmdir: FAT32 根目录不支持子目录\r\n", CMD_WARN); }
/* ============================================================
* PE/EXE 程序执行
* ============================================================ */
/* 检查文件名是否以 .exe/.com/.bat 结尾(不区分大小写) */
static int has_exec_ext(const char *name) {
int len = str_len(name);
if (len < 4) return 0;
const char *ext = name + len - 4;
if (ext[0] != '.') return 0;
if (str_ieq(ext, ".exe")) return 1;
if (str_ieq(ext, ".com")) return 1;
if (str_ieq(ext, ".bat")) return 2;
return 0;
}
/* 执行 PE/EXE 程序。
* prog_name = 程序名(可能带或不带 .exe 后缀)
* full_cmdline = 完整命令行(程序名 + 参数,即 GetCommandLineA 返回值)
*/
static void exec_pe(const char *prog_name, const char *full_cmdline) {
if (!g_pe_svc) {
term_puts_color("PE 兼容层不可用(UTSM PE 服务未初始化)\r\n", CMD_ERROR);
return;
}
if (!f32_blk_read) {
term_puts_color("无块设备,无法读取 PE 文件\r\n", CMD_ERROR);
return;
}
/* 构造 8.3 文件名 */
char base[64];
str_copy(base, prog_name, sizeof(base));
/* 如果没有扩展名,自动补 .exe */
int has_dot = 0;
for (int i = 0; base[i]; i++) {
if (base[i] == '.') { has_dot = 1; break; }
}
if (!has_dot) {
int bl = str_len(base);
if (bl > 59) bl = 59;
base[bl] = '.'; base[bl + 1] = 'e'; base[bl + 2] = 'x';
base[bl + 3] = 'e'; base[bl + 4] = 0;
}
char name11[11];
if (f32_name_to_83(base, name11) != 0) {
term_puts_color("无效文件名\r\n", CMD_ERROR);
return;
}
/* 从 FAT32 根目录读取 */
u8 *pe_data = 0; u32 pe_size = 0;
if (f32_read_root_file(name11, &pe_data, &pe_size) != 0) {
term_puts_color("'", CMD_ERROR);
term_puts_color(prog_name, CMD_ERROR);
term_puts_color("' 不是内部或外部命令,也不是可运行的程序。\r\n", CMD_ERROR);
return;
}
/* 验证 PE 头(MZ 签名) */
if (pe_size < 2 || pe_data[0] != 'M' || pe_data[1] != 'Z') {
term_puts_color("不是有效的 PE/EXE 文件(缺少 MZ 签名)\r\n", CMD_ERROR);
return;
}
term_puts_color("正在执行 ", CMD_INFO);
term_puts_color(prog_name, CMD_WARN);
term_puts_color(" ...\r\n", CMD_INFO);
term_redraw_all();
/* 调用 UTSM PE 服务执行 */
logl("[cmd] PE run begin");
swrite("[cmd] cmdline: "); swrite(full_cmdline); swrite("\n");
u64 exit_code = 0;
int rc = g_pe_svc->run(pe_data, (u64)pe_size, full_cmdline, &exit_code);
if (rc != 0) {
term_puts_color("PE 执行失败,错误码: ", CMD_ERROR);
term_putx((u32)rc);
term_puts("\r\n");
} else {
term_puts_color("程序退出,返回码: ", CMD_DIM);
term_putu((u32)exit_code);
term_puts("\r\n");
}
logl("[cmd] PE run end");
}
/* ============================================================
* 命令解析与分发
* ============================================================ */
static int g_should_exit = 0;
static void execute_command(const char *cmd) {
while (*cmd == ' ') cmd++;
if (*cmd == 0) return;
/* 提取命令名 */
const char *args = cmd;
while (*args && *args != ' ') args++;
int cmd_name_len = (int)(args - cmd);
char name[64];
if (cmd_name_len >= 64) cmd_name_len = 63;
for (int i = 0; i < cmd_name_len; i++) name[i] = cmd[i];
name[cmd_name_len] = 0;
while (*args == ' ') args++;
/* 内置命令(不区分大小写) */
if (str_ieq(name, "help") || str_eq(name, "?")) { cmd_help(); return; }
if (str_ieq(name, "ver")) { cmd_ver(); return; }
if (str_ieq(name, "cls") || str_ieq(name, "clear")) { cmd_cls(); return; }
if (str_ieq(name, "dir") || str_ieq(name, "ls")) { cmd_dir(); return; }
if (str_ieq(name, "cd")) { cmd_cd(); return; }
if (str_ieq(name, "type") || str_ieq(name, "cat")) { cmd_type(args); return; }
if (str_ieq(name, "copy") || str_ieq(name, "cp")) { cmd_copy(args); return; }
if (str_ieq(name, "del") || str_ieq(name, "rm")) { cmd_del(args); return; }
if (str_ieq(name, "ren") || str_ieq(name, "mv")) { cmd_ren(args); return; }
if (str_ieq(name, "mkdir") || str_ieq(name, "md")) { cmd_mkdir(); return; }
if (str_ieq(name, "rmdir") || str_ieq(name, "rd")) { cmd_rmdir(); return; }
if (str_ieq(name, "echo")) { cmd_echo(args); return; }
if (str_ieq(name, "set")) { cmd_set(); return; }
if (str_ieq(name, "exit") || str_ieq(name, "quit")) {
term_puts_color("返回桌面...\r\n", CMD_DIM);
g_should_exit = 1;
return;
}
if (str_ieq(name, "reboot")) {
term_puts_color("重启中...\r\n", CMD_WARN);
term_redraw_all();
for (u64 i = 0; i < 100000000ULL; i++) __asm__ volatile("pause");
/* 触发三重故障重启 */
__asm__ volatile("int $0x03");
return;
}
/* PE/EXE 执行:检查是否为可执行文件 */
int ext_type = has_exec_ext(name);
if (ext_type == 1) {
/* .exe/.com → PE 执行 */
exec_pe(name, cmd);
return;
}
if (ext_type == 2) {
/* .bat → 批处理(暂不支持) */
term_puts_color("批处理文件 (.bat) 暂不支持\r\n", CMD_WARN);
return;
}
/* 无扩展名 → 尝试自动补 .exe 执行 */
if (cmd_name_len > 0 && name[0] != '.') {
exec_pe(name, cmd);
return;
}
/* 未知命令 */
term_puts_color("'", CMD_ERROR);
term_puts_color(name, CMD_ERROR);
term_puts_color("' 不是内部或外部命令,也不是可运行的程序。\r\n", CMD_ERROR);
}
/* ============================================================
* 主入口
* ============================================================ */
__attribute__((visibility("default")))
void dsk_entry(const dsk_boot_context *ctx) {
__asm__ volatile("cli");
logl("[cmd] boot");
if (!ctx || ctx->magic != 0x44534B31424F4F54ULL) {
logl("[cmd] bad context");
for (;;) __asm__("hlt");
}
fb_a = ctx->framebuffer_address;
fb_w = ctx->framebuffer_width;
fb_h = ctx->framebuffer_height;
fb_p = ctx->framebuffer_pitch;
g_kernel_api = ctx->dkm_kernel_api;
g_boot_ctx = ctx;
/* 获取 block 设备 read/write */
{
u64 api = ctx->dkm_kernel_api;
u64 blk = *(u64 *)(api + 0xA8);
f32_block_read_fn bread = blk ? (f32_block_read_fn)*(u64 *)(blk + 16) : 0;
f32_block_write_fn bwrite = blk ? (f32_block_write_fn)*(u64 *)(blk + 24) : 0;
f32_init(bread, bwrite);
}
if (f32_blk_read) logl("[cmd] block_read ok");
if (f32_blk_write) logl("[cmd] block_write ok");
/* 获取 PE 服务(reserved[4]) */
{
u64 pe_addr = ctx->reserved[4];
if (pe_addr) {
const pe_service *pe = (const pe_service *)pe_addr;
if (pe->magic == PE_SERVICE_MAGIC) {
g_pe_svc = pe;
logl("[cmd] PE service ok");
} else {
logl("[cmd] PE service magic mismatch");
}
} else {
logl("[cmd] PE service not available");
}
}
/* dev_mode 串口镜像 */
if (ctx->reserved[3] == 1) {
g_serial_mirror = 1;
}
/* 初始化渲染上下文 */
du_context_init(&g_ctx, fb_a, fb_w, fb_h, fb_p);
term_init_pos();
term_clear_buf();
term_redraw_all();
/* 启动 banner */
term_puts_color("Deshab CMD [Version 0.1.0]\r\n", CMD_OK);
term_puts_color("(c) 2026 Deshab Project. PE/EXE 兼容层 by UTSM.\r\n", CMD_DIM);
term_putc('\r');
term_putc('\n');
if (g_pe_svc) {
term_puts_color("PE 兼容层已就绪 (PE32+ 原生 + PE32 解释器)\r\n", CMD_OK);
} else {
term_puts_color("警告: PE 兼容层不可用\r\n", CMD_WARN);
}
term_putc('\r');
term_putc('\n');
term_redraw_all();
/* 主循环 */
int shift = 0;
int e0 = 0;
u64 blink_start = rdtsc_cmd();
g_should_exit = 0;
for (;;) {
/* 绘制提示符 */
term_puts_color(PROMPT, CMD_PROMPT);
input_len = 0;
input_cursor = 0;
input_buf[0] = 0;
int prompt_len = str_len(PROMPT);
cur_col = prompt_len;
cur_visible = 1;
redraw_input_line();
int cmd_done = 0;
while (!cmd_done && !g_should_exit) {
/* 光标闪烁 */
if (g_tsc_per_ms) {
u64 now = rdtsc_cmd();
u64 elapsed = now - blink_start;
int want_vis = (elapsed / (g_tsc_per_ms * 530)) & 1;
if (want_vis != cur_visible) {
if (want_vis) term_redraw_cursor();
else term_clear_cursor();
cur_visible = want_vis;
}
}
u8 st = inb(0x64);
if (!(st & 1)) { __asm__("pause"); continue; }
u8 data = inb(0x60);
if (st & 0x20) continue; /* 忽略鼠标数据 */
u8 sc = data;
blink_start = rdtsc_cmd();
if (!cur_visible) { cur_visible = 1; term_redraw_cursor(); }
if (sc == 0xE0) { e0 = 1; continue; }
if (sc == 0x2A || sc == 0x36) { shift = 1; continue; }
if (sc == 0xAA || sc == 0xB6) { shift = 0; continue; }
if (sc & 0x80) {
/* 按键释放 */
e0 = 0;
continue;
}
if (e0) {
if (sc == 0x4B) cursor_left();
else if (sc == 0x4D) cursor_right();
else if (sc == 0x47) cursor_home();
else if (sc == 0x4F) cursor_end();
else if (sc == 0x53) { /* Delete */ }
e0 = 0;
continue;
}
if (sc == 0x1C) {
/* Enter — 提交命令 */
term_clear_cursor();
input_buf[input_len] = 0;
term_putc('\r');
term_putc('\n');
execute_command(input_buf);
input_len = 0;
input_cursor = 0;
input_buf[0] = 0;
cmd_done = 1;
term_redraw_all();
continue;
}
if (sc == 0x0E) { delete_char_back(); continue; }
if (sc == 0x01) {
/* Esc — 返回桌面 */
logl("[cmd] esc -> return to DSK");
g_should_exit = 1;
cmd_done = 1;
continue;
}
if (sc == 0x15 && !shift) { kill_line(); continue; }
char c = scan_to_ascii(sc, shift);
if (c && c >= 32 && c <= 126) {
insert_char(c);
}
}
if (g_should_exit) break;
}
logl("[cmd] exit");
}
+110 -171
View File
@@ -3,12 +3,11 @@
* 布局结构与 D:\Code\Winux-Kate 完全一致: * 布局结构与 D:\Code\Winux-Kate 完全一致:
* app-shell * app-shell
* ├── topbar (34px):品牌 + 工作区切换 + 页面切换 + PG 时钟 * ├── topbar (34px):品牌 + 工作区切换 + 页面切换 + PG 时钟
* ├── page-host * page-host
* │ ├── 1·DASHBOARD:TERM-01 / TERM-02 / EDITOR / FILES 四面板 + StatusBar * │ ├── 1·DASHBOARD:TERM-01 / TERM-02 / EDITOR / FILES 四面板 + StatusBar
* │ ├── 2·IDE:标签栏 + 编辑宿主 * │ ├── 2·IDE:标签栏 + 编辑宿主
* │ ├── 3·IM:栏 + 分屏槽(未检测卡片) * │ ├── 3·DESKTOP:图标网格 + 窗口 + 任务栏
* │ ├── 4·DESKTOP:图标网格 + 窗口 + 任务栏 * │ └── 4+/CUSTOM:外部 .elf 全屏宿主(双击启动)
* │ └── 5+/CUSTOM:外部 .elf 全屏宿主(双击启动)
* └── task-view overlay(工作区卡片) * └── task-view overlay(工作区卡片)
* *
* 新 UI 特性(Kate 之外): * 新 UI 特性(Kate 之外):
@@ -204,6 +203,10 @@ typedef struct {
static du_context g_fb; static du_context g_fb;
static u64 g_fb_addr, g_fb_w, g_fb_h, g_fb_pitch; static u64 g_fb_addr, g_fb_w, g_fb_h, g_fb_pitch;
static const void *g_kernel_api; static const void *g_kernel_api;
/* 双缓冲:渲染到 sprite buffer,完成后一次性 flip 到真实 framebuffer */
#define SPRITE_BUF_ADDR 0x7000000ULL /* 112MB,在 identity-mapped 区域 */
static u8 *g_real_fb = 0; /* 真实 framebuffer 地址 */
static desktop_block_read_fn g_block_read; static desktop_block_read_fn g_block_read;
static desktop_block_write_fn g_block_write; static desktop_block_write_fn g_block_write;
static const dsk_boot_context *g_boot_ctx = 0; static const dsk_boot_context *g_boot_ctx = 0;
@@ -246,7 +249,7 @@ static int g_icon_count = 0;
/* ---- Kate 外壳状态 ---- */ /* ---- Kate 外壳状态 ---- */
static int g_booted = 0; static int g_booted = 0;
static int g_page = 1; /* 1..4 内置, 5..8 自定义 */ static int g_page = 1; /* 1..3 内置, 4..8 自定义 */
static int g_taskview = 0; static int g_taskview = 0;
static int g_dash_focus = 0; /* 0=t1 1=t2 2=ed 3=files */ static int g_dash_focus = 0; /* 0=t1 1=t2 2=ed 3=files */
@@ -307,7 +310,6 @@ static int g_ctx_item_ws[MAX_WS + 1]; /* 菜单行 → 真实工作区索引
static int g_ide_host[4]; static int g_ide_host[4];
static int g_ide_tabx[4]; /* IDE 标签 × */ static int g_ide_tabx[4]; /* IDE 标签 × */
static int g_ide_new_rect[4]; /* IDE "+ NEW IDE" 按钮 */ static int g_ide_new_rect[4]; /* IDE "+ NEW IDE" 按钮 */
static int g_im_toggle_rect[4]; /* IM bar 切换视图按钮 */
static int g_cp_host[4]; /* 自定义页宿主 */ static int g_cp_host[4]; /* 自定义页宿主 */
/* ============================================================ /* ============================================================
@@ -511,16 +513,47 @@ static void cursor_draw(int mx, int my) {
} }
} }
/* ---- 双缓冲 flip ---- */
/* 将 sprite buffer 完整复制到真实 framebuffer */
static void flip_buffer(void) {
if (!g_real_fb) return;
u64 total = g_fb_h * g_fb_pitch / 4;
u32 *dst = (u32 *)g_real_fb;
u32 *src = (u32 *)SPRITE_BUF_ADDR;
for (u64 i = 0; i < total; i++) dst[i] = src[i];
}
/* 仅复制指定矩形区域(用于鼠标移动时的局部更新) */
static void flip_rect(int x, int y, int w, int h) {
if (!g_real_fb) return;
for (int r = 0; r < h; r++) {
int ry = y + r;
if (ry < 0 || (u64)ry >= g_fb_h) continue;
u32 *dst = (u32 *)(g_real_fb + (u64)ry * g_fb_pitch);
u32 *src = (u32 *)((u8 *)SPRITE_BUF_ADDR + (u64)ry * g_fb_pitch);
for (int c = 0; c < w; c++) {
int rx = x + c;
if (rx < 0 || (u64)rx >= g_fb_w) continue;
dst[rx] = src[rx];
}
}
}
/* 非阻塞延时:动画期间持续轮询鼠标,保持光标响应。 */ /* 非阻塞延时:动画期间持续轮询鼠标,保持光标响应。 */
__attribute__((unused))
static void anim_delay_poll_mouse(u32 ms) { static void anim_delay_poll_mouse(u32 ms) {
for (u32 i = 0; i < ms; i++) { for (u32 i = 0; i < ms; i++) {
for (volatile u32 j = 0; j < 50000; j++) { for (volatile u32 j = 0; j < 50000; j++) {
__asm__ volatile("pause"); __asm__ volatile("pause");
} }
if (ps2_mouse_poll()) { if (ps2_mouse_poll()) {
int old_x = g_cursor_old_x, old_y = g_cursor_old_y;
cursor_restore_bg(); cursor_restore_bg();
flip_rect(old_x, old_y, CURSOR_SIZE, CURSOR_SIZE);
cursor_save_bg(g_mouse_x, g_mouse_y); cursor_save_bg(g_mouse_x, g_mouse_y);
cursor_draw(g_mouse_x, g_mouse_y); cursor_draw(g_mouse_x, g_mouse_y);
flip_rect(g_mouse_x, g_mouse_y, CURSOR_SIZE, CURSOR_SIZE);
} }
} }
} }
@@ -598,28 +631,8 @@ static void win_destroy(desktop_window *w) {
} }
if (idx < 0) return; if (idx < 0) return;
/* 窗口关闭动画 — 收缩矩形 */ /* 直接隐藏窗口(去掉关闭动画以避免卡顿和闪屏) */
{ w->visible = 0;
int wx = w->x, wy = w->y, ww = w->w, wh = w->h;
int was_cur = (w->ws == g_ws_cur);
w->visible = 0;
if (was_cur) {
for (int step = 5; step >= 0; step--) {
int scale = (step + 1) * 100 / 6;
int aw = ww * scale / 100;
int ah = wh * scale / 100;
int ax = wx + (ww - aw) / 2;
int ay = wy + (wh - ah) / 2;
cursor_restore_bg();
redraw_all();
cursor_restore_bg();
du_rect_outline(&g_fb, ax, ay, aw, ah, KS_ACCENT, DU_RADIUS_SM);
cursor_save_bg(g_mouse_x, g_mouse_y);
cursor_draw(g_mouse_x, g_mouse_y);
anim_delay_poll_mouse(16);
}
}
}
if (w->app_id >= 0 && w->app_id < g_app_count && g_apps[w->app_id].on_destroy && w->app_state) { if (w->app_id >= 0 && w->app_id < g_app_count && g_apps[w->app_id].on_destroy && w->app_state) {
g_apps[w->app_id].on_destroy(w->app_state); g_apps[w->app_id].on_destroy(w->app_state);
@@ -977,21 +990,25 @@ static void bash_draw_to(bash_state *s, int cx, int cy, int cw, int ch) {
} }
/* ---- 窗口适配 ---- */ /* ---- 窗口适配 ---- */
__attribute__((unused))
static void *bash_on_create(app_ctx *ctx) { static void *bash_on_create(app_ctx *ctx) {
bash_state *s = (bash_state *)ADDR_TERMWIN; bash_state *s = (bash_state *)ADDR_TERMWIN;
bash_reset(s, ctx->client_w, ctx->client_h); bash_reset(s, ctx->client_w, ctx->client_h);
bash_puts(s, "Deshab Bash v0.1\nType help for commands\n\n", KS_TEXT_PRIMARY); bash_puts(s, "Deshab Bash v0.1\nType help for commands\n\n", KS_TEXT_PRIMARY);
return s; return s;
} }
__attribute__((unused))
static void bash_on_event(void *state, app_ctx *ctx, desktop_event *ev) { static void bash_on_event(void *state, app_ctx *ctx, desktop_event *ev) {
if (ev->type != EV_KEY_DOWN) return; if (ev->type != EV_KEY_DOWN) return;
bash_key((bash_state *)state, ev->scancode, ev->shift); bash_key((bash_state *)state, ev->scancode, ev->shift);
ctx->win->dirty = 1; ctx->win->dirty = 1;
} }
__attribute__((unused))
static void bash_on_draw(void *state, app_ctx *ctx) { static void bash_on_draw(void *state, app_ctx *ctx) {
bash_draw_to((bash_state *)state, ctx->client_x, ctx->client_y, bash_draw_to((bash_state *)state, ctx->client_x, ctx->client_y,
ctx->client_w, ctx->client_h); ctx->client_w, ctx->client_h);
} }
__attribute__((unused))
static void bash_on_destroy(void *state) { (void)state; } static void bash_on_destroy(void *state) { (void)state; }
/* ============================================================ /* ============================================================
@@ -1313,27 +1330,34 @@ static void calc_on_destroy(void *state) { (void)state; }
* ============================================================ */ * ============================================================ */
static void register_apps(void) { static void register_apps(void) {
/* 命令行1:shell.elf(原生命令行 + 可运行 Linux 程序)*/
g_apps[0] = (app_descriptor){ g_apps[0] = (app_descriptor){
"bash", "Terminal", 640, 440, "shell", "Terminal", 720, 480,
bash_on_create, bash_on_event, bash_on_draw, bash_on_destroy, 0 0, 0, 0, 0, "SHELL ELF"
}; };
g_app_count++; g_app_count++;
/* 命令行2:cmd.elf(Windows 风格命令行 + PE/EXE 执行)*/
g_apps[1] = (app_descriptor){ g_apps[1] = (app_descriptor){
"cmd", "CMD", 720, 480,
0, 0, 0, 0, "CMD ELF"
};
g_app_count++;
g_apps[2] = (app_descriptor){
"editor", "Editor", 600, 450, "editor", "Editor", 600, 450,
editor_on_create, editor_on_event, editor_on_draw, editor_on_destroy, 0 editor_on_create, editor_on_event, editor_on_draw, editor_on_destroy, 0
}; };
g_app_count++; g_app_count++;
g_apps[2] = (app_descriptor){ g_apps[3] = (app_descriptor){
"fileman", "Files", 500, 400, "fileman", "Files", 500, 400,
0, 0, 0, 0, "FILEMAN ELF" 0, 0, 0, 0, "FILEMAN ELF"
}; };
g_app_count++; g_app_count++;
g_apps[3] = (app_descriptor){ g_apps[4] = (app_descriptor){
"calc", "Calculator", 280, 400, "calc", "Calculator", 280, 400,
calc_on_create, calc_on_event, calc_on_draw, calc_on_destroy, 0 calc_on_create, calc_on_event, calc_on_draw, calc_on_destroy, 0
}; };
g_app_count++; g_app_count++;
g_apps[4] = (app_descriptor){ g_apps[5] = (app_descriptor){
"browser", "Browser", 700, 500, "browser", "Browser", 700, 500,
0, 0, 0, 0, "BROWSER ELF" 0, 0, 0, 0, "BROWSER ELF"
}; };
@@ -1510,21 +1534,7 @@ static void launch_app(int app_id) {
win->app_state = app->on_create(&ctx); win->app_state = app->on_create(&ctx);
win->dirty = 1; win->dirty = 1;
/* 窗口打开动画 — 展开矩形 */ /* 直接显示窗口(去掉打开动画以避免卡顿和闪屏) */
for (int step = 0; step < 6; step++) {
int scale = (step + 1) * 100 / 6;
int aw = win->w * scale / 100;
int ah = win->h * scale / 100;
int ax = win->x + (win->w - aw) / 2;
int ay = win->y + (win->h - ah) / 2;
cursor_restore_bg();
redraw_all();
cursor_restore_bg();
du_rect_outline(&g_fb, ax, ay, aw, ah, KS_ACCENT, DU_RADIUS_SM);
cursor_save_bg(g_mouse_x, g_mouse_y);
cursor_draw(g_mouse_x, g_mouse_y);
anim_delay_poll_mouse(16);
}
slog("app launched"); slog("app launched");
} }
@@ -1537,6 +1547,16 @@ static int files_list_cb(const char *name, u32 size, u8 attr, void *ud) {
(void)ud; (void)ud;
if (attr & 0x10) return 0; /* 跳过子目录 */ if (attr & 0x10) return 0; /* 跳过子目录 */
if (g_file_count >= MAX_FILES) return 1; /* 停止 */ if (g_file_count >= MAX_FILES) return 1; /* 停止 */
/* 只显示 user 文件:跳过 .ELF 可执行文件和系统模块 */
int nl = kstrlen(name);
if (nl >= 4 && name[nl-4] == '.' && name[nl-3] == 'E' &&
name[nl-2] == 'L' && name[nl-1] == 'F') return 0;
/* FIRSTINI* (FirstInit.elf,Name83=FIRSTINIT → 显示名 FIRSTINI.T) */
if (nl >= 8 && name[0] == 'F' && name[1] == 'I' && name[2] == 'R' &&
name[3] == 'S' && name[4] == 'T' && name[5] == 'I' && name[6] == 'N' &&
name[7] == 'I') return 0;
fentry *f = &g_files[g_file_count]; fentry *f = &g_files[g_file_count];
f->size = size; f->size = size;
kstrcpy(f->disp, name, 13); kstrcpy(f->disp, name, 13);
@@ -1614,7 +1634,7 @@ static void draw_centered(const char *s, int cx, int y, u32 fg, u32 bg) {
du_draw_string(&g_fb, s, cx - l * (int)DU_ASCII_STEP / 2, y, fg, bg, DU_ASCII_STEP); du_draw_string(&g_fb, s, cx - l * (int)DU_ASCII_STEP / 2, y, fg, bg, DU_ASCII_STEP);
} }
/* 虚线矩形(ide-host / im-slot / custom host) */ /* 虚线矩形(ide-host / custom host) */
static void draw_dashed_rect(int x, int y, int w, int h, u32 color) { static void draw_dashed_rect(int x, int y, int w, int h, u32 color) {
for (int i = x; i < x + w; i += 8) { for (int i = x; i < x + w; i += 8) {
du_fill_rect(&g_fb, i, y, 4, 1, color); du_fill_rect(&g_fb, i, y, 4, 1, color);
@@ -1651,6 +1671,7 @@ static void busy_delay(u32 cycles) {
static void boot_screen(void) { static void boot_screen(void) {
int W = (int)g_fb_w, H = (int)g_fb_h; int W = (int)g_fb_w, H = (int)g_fb_h;
du_fill_bg_solid(&g_fb, KS_BG_PRIMARY); du_fill_bg_solid(&g_fb, KS_BG_PRIMARY);
flip_buffer();
int lw = 46 * (int)DU_ASCII_STEP; int lw = 46 * (int)DU_ASCII_STEP;
int lx = (W - lw) / 2; int lx = (W - lw) / 2;
@@ -1663,13 +1684,15 @@ static void boot_screen(void) {
char t[2] = { title[i], 0 }; char t[2] = { title[i], 0 };
du_draw_string(&g_fb, t, W / 2 - tl * (int)DU_ASCII_STEP + i * (int)DU_ASCII_STEP * 2, du_draw_string(&g_fb, t, W / 2 - tl * (int)DU_ASCII_STEP + i * (int)DU_ASCII_STEP * 2,
ty, KS_ACCENT, 0, DU_ASCII_STEP * 2); ty, KS_ACCENT, 0, DU_ASCII_STEP * 2);
busy_delay(8000000); flip_buffer();
busy_delay(2000000);
} }
du_divider_h(&g_fb, W / 2 - 120, ty + 30, 240, KS_ACCENT); du_divider_h(&g_fb, W / 2 - 120, ty + 30, 240, KS_ACCENT);
/* boot-subtitle(对应 Kate "由 Deaicup 工作室制作") */ /* boot-subtitle(对应 Kate "由 Deaicup 工作室制作") */
draw_centered("DEAICUP STUDIO", W / 2, ty + 44, KS_ACCENT2, 0); draw_centered("DEAICUP STUDIO", W / 2, ty + 44, KS_ACCENT2, 0);
busy_delay(10000000); flip_buffer();
busy_delay(2500000);
/* boot-lines 打字机;进度条固定在全部行下方(对应 Kate .boot-bar) */ /* boot-lines 打字机;进度条固定在全部行下方(对应 Kate .boot-bar) */
int ly = ty + 76; int ly = ty + 76;
@@ -1683,7 +1706,8 @@ static void boot_screen(void) {
char t[2] = { s[ci], 0 }; char t[2] = { s[ci], 0 };
du_draw_string(&g_fb, t, lx + (ci + 1) * (int)DU_ASCII_STEP, ly, du_draw_string(&g_fb, t, lx + (ci + 1) * (int)DU_ASCII_STEP, ly,
fg, 0, DU_ASCII_STEP); fg, 0, DU_ASCII_STEP);
busy_delay(500000); flip_buffer();
busy_delay(125000);
} }
ly += (int)DU_ASCII_LINE_H + 2; ly += (int)DU_ASCII_LINE_H + 2;
/* boot-bar:渐变填充(accent → accent2) */ /* boot-bar:渐变填充(accent → accent2) */
@@ -1691,12 +1715,14 @@ static void boot_screen(void) {
du_rect_outline(&g_fb, W / 2 - bw / 2, bar_y, bw, 6, KS_BORDER, 1); du_rect_outline(&g_fb, W / 2 - bw / 2, bar_y, bw, 6, KS_BORDER, 1);
if (fill > 2) du_fill_rect_gradient(&g_fb, W / 2 - bw / 2 + 1, bar_y + 1, if (fill > 2) du_fill_rect_gradient(&g_fb, W / 2 - bw / 2 + 1, bar_y + 1,
fill - 2, 4, KS_ACCENT, KS_ACCENT2); fill - 2, 4, KS_ACCENT, KS_ACCENT2);
flip_buffer();
} }
/* boot-hint + credit(对应 Kate "SYSTEM ONLINE" + "© 2026 Deaicup Studio") */ /* boot-hint + credit(对应 Kate "SYSTEM ONLINE" + "© 2026 Deaicup Studio") */
draw_centered("SYSTEM ONLINE", W / 2, H - 64, KS_ACCENT2, 0); draw_centered("SYSTEM ONLINE", W / 2, H - 64, KS_ACCENT2, 0);
draw_centered("(C) 2026 DEAICUP STUDIO", W / 2, H - 40, KS_TEXT_DIM, 0); draw_centered("(C) 2026 DEAICUP STUDIO", W / 2, H - 40, KS_TEXT_DIM, 0);
busy_delay(40000000); flip_buffer();
busy_delay(10000000);
} }
/* ============================================================ /* ============================================================
@@ -1778,8 +1804,8 @@ static void draw_topbar(void) {
x += 4; x += 4;
/* 页面切换 */ /* 页面切换 */
static const char *pg_names[4] = { "1.DASHBOARD", "2.IDE", "3.IM", "4.DESKTOP" }; static const char *pg_names[3] = { "1.DASHBOARD", "2.IDE", "3.DESKTOP" };
for (int i = 0; i < 4; i++) { for (int i = 0; i < 3; i++) {
int bw = kstrlen(pg_names[i]) * (int)DU_ASCII_STEP + 16; int bw = kstrlen(pg_names[i]) * (int)DU_ASCII_STEP + 16;
int active = (g_page == i + 1); int active = (g_page == i + 1);
int hover = g_mouse_x >= x && g_mouse_x < x + bw && int hover = g_mouse_x >= x && g_mouse_x < x + bw &&
@@ -1816,10 +1842,10 @@ static void draw_topbar(void) {
du_draw_string(&g_fb, label, x + 6, ty, du_draw_string(&g_fb, label, x + 6, ty,
active ? KS_TEXT_INVERT : KS_TEXT_DIM, 0, DU_ASCII_STEP); active ? KS_TEXT_INVERT : KS_TEXT_DIM, 0, DU_ASCII_STEP);
du_draw_string(&g_fb, "x", x + bw - 14, ty, KS_DANGER, 0, DU_ASCII_STEP); du_draw_string(&g_fb, "x", x + bw - 14, ty, KS_DANGER, 0, DU_ASCII_STEP);
g_pg_rect[4 + i][0] = x; g_pg_rect[4 + i][1] = 5; g_pg_rect[3 + i][0] = x; g_pg_rect[3 + i][1] = 5;
g_pg_rect[4 + i][2] = bw; g_pg_rect[4 + i][3] = 24; g_pg_rect[3 + i][2] = bw; g_pg_rect[3 + i][3] = 24;
g_pg_rm_rect[4 + i][0] = x + bw - 20; g_pg_rm_rect[4 + i][1] = 5; g_pg_rm_rect[3 + i][0] = x + bw - 20; g_pg_rm_rect[3 + i][1] = 5;
g_pg_rm_rect[4 + i][2] = 20; g_pg_rm_rect[4 + i][3] = 24; g_pg_rm_rect[3 + i][2] = 20; g_pg_rm_rect[3 + i][3] = 24;
x += bw + 6; x += bw + 6;
} }
/* pg-add "+" */ /* pg-add "+" */
@@ -1948,7 +1974,7 @@ static void draw_statusbar_full(void) {
du_draw_string(&g_fb, "WIFI --", x, ty, KS_TEXT_DIM, 0, DU_ASCII_STEP); du_draw_string(&g_fb, "WIFI --", x, ty, KS_TEXT_DIM, 0, DU_ASCII_STEP);
/* 右侧 hint */ /* 右侧 hint */
const char *hint = "Ctrl+Tab PAGE . Ctrl+Shift+Tab CTX"; const char *hint = "Ctrl+Tab PAGE";
du_draw_string(&g_fb, hint, W - 12 - kstrlen(hint) * (int)DU_ASCII_STEP, ty, du_draw_string(&g_fb, hint, W - 12 - kstrlen(hint) * (int)DU_ASCII_STEP, ty,
KS_TEXT_DIM, 0, DU_ASCII_STEP); KS_TEXT_DIM, 0, DU_ASCII_STEP);
} }
@@ -2049,7 +2075,7 @@ static void draw_dashboard(void) {
du_fill_rect(&g_fb, fx, fy, fw, fh, KS_BG_PRIMARY); du_fill_rect(&g_fb, fx, fy, fw, fh, KS_BG_PRIMARY);
char path_buf[32]; char path_buf[32];
kstrcpy(path_buf, "FAT32:/ROOT (", 32); kstrcpy(path_buf, "FAT32:/USER (", 32);
int pl = kstrlen(path_buf); int pl = kstrlen(path_buf);
if (g_file_count >= 10) path_buf[pl++] = '0' + (char)(g_file_count / 10); if (g_file_count >= 10) path_buf[pl++] = '0' + (char)(g_file_count / 10);
path_buf[pl++] = '0' + (char)(g_file_count % 10); path_buf[pl++] = '0' + (char)(g_file_count % 10);
@@ -2167,93 +2193,7 @@ static void draw_ide(void) {
} }
} }
/* ---- 3·IM ---- */ /* ---- 3·DESKTOP ---- */
static int g_im_view = 0; /* 0=split(WECHAT/QQ) 1=full(WECOM),对应 Kate imView */
/* Kate .missing-card:h2 + p + a.btn 下载按钮 */
static void draw_missing_card(int sx, int sy, int sw, int sh,
const char *title, const char *desc,
const char *btn) {
int cw = 340, ch = 150;
int cx = sx + (sw - cw) / 2, cy = sy + (sh - ch) / 2;
du_kate_panel(&g_fb, cx, cy, cw, ch, 0);
draw_centered(title, sx + sw / 2, cy + 28, KS_ACCENT, 0);
draw_centered(desc, sx + sw / 2, cy + 56, KS_TEXT_DIM, 0);
/* .btn 下载按钮(视觉复刻,Deshab 无网络安装渠道) */
int bw = kstrlen(btn) * (int)DU_ASCII_STEP + 20;
int bx = sx + sw / 2 - bw / 2, by = cy + 88;
int hover = g_mouse_x >= bx && g_mouse_x < bx + bw &&
g_mouse_y >= by && g_mouse_y < by + 22;
if (hover) du_fill_rect(&g_fb, bx, by, bw, 22, KS_ACCENT_DIM);
du_rect_outline(&g_fb, bx, by, bw, 22, KS_BORDER, 1);
du_draw_string(&g_fb, btn, bx + 10, by + 3, KS_ACCENT, 0, DU_ASCII_STEP);
}
static void draw_im(void) {
int W = (int)g_fb_w;
int top = KATE_TOPBAR_H;
/* im-bar(36px):dot + 视图标签 + page-credit + 切换按钮(margin-left:auto) */
du_fill_rect(&g_fb, 0, top, W, 36, 0xFF051828u);
du_divider_h(&g_fb, 0, top + 36, W, KS_BORDER);
int ty = top + (36 - (int)DU_ASCII_LINE_H) / 2 + 1;
/* .dot(8×8 accent2 发光点) */
du_fill_rect(&g_fb, 12, top + 14, 8, 8, KS_ACCENT2);
du_draw_string(&g_fb,
g_im_view ? "WECOM FULLSCREEN" : "WECHAT / QQ SPLIT",
28, ty, KS_ACCENT, 0, DU_ASCII_STEP);
/* page-credit(对应 Kate "由 Deaicup 工作室制作") */
du_draw_string(&g_fb, "DEAICUP STUDIO",
28 + (g_im_view ? 16 : 17) * (int)DU_ASCII_STEP + 12,
ty + 1, KS_TEXT_DIM, 0, DU_ASCII_STEP);
/* 切换按钮(对应 Kate im_toggle,Ctrl+Shift+Tab) */
{
const char *tb = "CTRL+SHIFT+TAB SWITCH";
int bw = kstrlen(tb) * (int)DU_ASCII_STEP + 20;
int bx = W - 12 - bw;
g_im_toggle_rect[0] = bx; g_im_toggle_rect[1] = top + 7;
g_im_toggle_rect[2] = bw; g_im_toggle_rect[3] = 22;
int hover = g_mouse_x >= bx && g_mouse_x < bx + bw &&
g_mouse_y >= top + 7 && g_mouse_y < top + 29;
if (hover) du_fill_rect(&g_fb, bx, top + 7, bw, 22, KS_ACCENT_DIM);
du_rect_outline(&g_fb, bx, top + 7, bw, 22, KS_BORDER, 1);
du_draw_string(&g_fb, tb, bx + 10, ty, KS_ACCENT, 0, DU_ASCII_STEP);
}
if (g_im_view == 0) {
/* im-split 双槽(grid 1fr 1fr, gap/padding 8px) */
int pad = 8, gap = 8;
int hy = top + 36 + pad;
int hh = (int)g_fb_h - hy - pad;
int sw = (W - 2 * pad - gap) / 2;
for (int i = 0; i < 2; i++) {
int sx = pad + i * (sw + gap);
draw_dashed_rect(sx, hy, sw, hh, KS_BORDER);
}
draw_missing_card(pad, hy, sw, hh,
"WECHAT NOT DETECTED",
"IM MODULE NOT AVAILABLE IN DESHAB",
"DOWNLOAD WECHAT");
draw_missing_card(pad + sw + gap, hy, sw, hh,
"QQ NOT DETECTED",
"IM MODULE NOT AVAILABLE IN DESHAB",
"DOWNLOAD QQ");
} else {
/* im-full 单槽(margin 8px) */
int hx = 8, hy = top + 36 + 8;
int hw = W - 16, hh = (int)g_fb_h - hy - 8;
draw_dashed_rect(hx, hy, hw, hh, KS_BORDER);
draw_missing_card(hx, hy, hw, hh,
"WECOM NOT DETECTED",
"IM MODULE NOT AVAILABLE IN DESHAB",
"DOWNLOAD WECOM");
}
}
/* ---- 4·DESKTOP ---- */
static void draw_desktop_page(void) { static void draw_desktop_page(void) {
/* 图标网格 */ /* 图标网格 */
draw_desktop_icons(); draw_desktop_icons();
@@ -2610,8 +2550,7 @@ static void redraw_all(void) {
/* 页面 */ /* 页面 */
if (g_page == 1) draw_dashboard(); if (g_page == 1) draw_dashboard();
else if (g_page == 2) draw_ide(); else if (g_page == 2) draw_ide();
else if (g_page == 3) draw_im(); else if (g_page == 3) draw_desktop_page();
else if (g_page == 4) draw_desktop_page();
else { else {
int idx = -1; int idx = -1;
for (int i = 0; i < g_cpage_count; i++) for (int i = 0; i < g_cpage_count; i++)
@@ -2672,7 +2611,7 @@ static void ws_close(int id) {
} }
static void page_switch(int p) { static void page_switch(int p) {
if (p < 1 || p > 4 + g_cpage_count) return; if (p < 1 || p > 3 + g_cpage_count) return;
g_page = p; g_page = p;
} }
@@ -2691,7 +2630,7 @@ static void cpage_add(void) {
for (int i = 0; i < n; i++) cp->name[i] = g_apps[a].display_name[i]; for (int i = 0; i < n; i++) cp->name[i] = g_apps[a].display_name[i];
cp->name[n] = 0; cp->name[n] = 0;
for (int i = 0; i < 11; i++) cp->elf11[i] = g_apps[a].elf_name[i]; for (int i = 0; i < 11; i++) cp->elf11[i] = g_apps[a].elf_name[i];
cp->id = 5 + g_cpage_count; cp->id = 4 + g_cpage_count;
g_cpage_count++; g_cpage_count++;
g_page = cp->id; g_page = cp->id;
return; return;
@@ -2703,7 +2642,7 @@ static void cpage_remove(int idx) {
int removed_page = g_cpages[idx].id; int removed_page = g_cpages[idx].id;
for (int i = idx; i < g_cpage_count - 1; i++) g_cpages[i] = g_cpages[i + 1]; for (int i = idx; i < g_cpage_count - 1; i++) g_cpages[i] = g_cpages[i + 1];
g_cpage_count--; g_cpage_count--;
for (int i = 0; i < g_cpage_count; i++) g_cpages[i].id = 5 + i; for (int i = 0; i < g_cpage_count; i++) g_cpages[i].id = 4 + i;
if (g_page == removed_page) g_page = 1; if (g_page == removed_page) g_page = 1;
else if (g_page > removed_page) g_page--; else if (g_page > removed_page) g_page--;
} }
@@ -2911,9 +2850,9 @@ static int on_left_press(void) {
for (int i = 0; i < g_ws_count; i++) for (int i = 0; i < g_ws_count; i++)
if (rect_hit(g_ws_rect[i], mx, my)) { ws_switch(i); return 1; } if (rect_hit(g_ws_rect[i], mx, my)) { ws_switch(i); return 1; }
if (rect_hit(g_wsadd_rect, mx, my)) { ws_create(); return 1; } if (rect_hit(g_wsadd_rect, mx, my)) { ws_create(); return 1; }
for (int i = 0; i < 4 + g_cpage_count; i++) { for (int i = 0; i < 3 + g_cpage_count; i++) {
if (i >= 4 && rect_hit(g_pg_rm_rect[i], mx, my)) { if (i >= 3 && rect_hit(g_pg_rm_rect[i], mx, my)) {
cpage_remove(i - 4); cpage_remove(i - 3);
return 1; return 1;
} }
if (rect_hit(g_pg_rect[i], mx, my)) { page_switch(i + 1); return 1; } if (rect_hit(g_pg_rect[i], mx, my)) { page_switch(i + 1); return 1; }
@@ -2925,13 +2864,8 @@ static int on_left_press(void) {
/* 页面内容 */ /* 页面内容 */
if (g_page == 1) return dash_click(mx, my, dbl); if (g_page == 1) return dash_click(mx, my, dbl);
if (g_page == 2) return ide_click(mx, my, dbl); if (g_page == 2) return ide_click(mx, my, dbl);
if (g_page == 3) { if (g_page == 3) return desktop_click(mx, my, dbl);
/* IM 切换视图按钮(对应 Kate im_toggle) */ if (g_page >= 4) {
if (rect_hit(g_im_toggle_rect, mx, my)) { g_im_view ^= 1; return 1; }
return 0;
}
if (g_page == 4) return desktop_click(mx, my, dbl);
if (g_page >= 5) {
int launch = 0; int launch = 0;
if (rect_hit(g_cp_new_rect, mx, my)) launch = 1; if (rect_hit(g_cp_new_rect, mx, my)) launch = 1;
if (dbl && rect_hit(g_cp_host, mx, my)) launch = 1; if (dbl && rect_hit(g_cp_host, mx, my)) launch = 1;
@@ -2954,7 +2888,7 @@ static int on_right_press(void) {
if (g_taskview) { g_taskview = 0; return 1; } if (g_taskview) { g_taskview = 0; return 1; }
if (g_ctx_open) { g_ctx_open = 0; return 1; } if (g_ctx_open) { g_ctx_open = 0; return 1; }
if (g_page != 4) return 0; if (g_page != 3) return 0;
int tb_y = (int)g_fb_h - KATE_TASKBAR_H; int tb_y = (int)g_fb_h - KATE_TASKBAR_H;
if (my >= tb_y) { if (my >= tb_y) {
@@ -3002,12 +2936,11 @@ static int handle_key(u8 sc) {
} }
if (g_taskview || g_ctx_open) return 0; /* 模态期间吞掉按键 */ if (g_taskview || g_ctx_open) return 0; /* 模态期间吞掉按键 */
/* Ctrl+Tab 切页 / Ctrl+Shift+Tab 上下文菜单(IM 页为切换视图,对应 Kate imView) */ /* Ctrl+Tab 切页 / Ctrl+Shift+Tab 上下文菜单(DESKTOP 页) */
if (g_ctrl && sc == 0x0F) { if (g_ctrl && sc == 0x0F) {
if (g_shift) { if (g_shift) {
if (g_page == 3) { g_im_view ^= 1; return 1; }
/* Ctrl+Shift+Tab:对当前聚焦窗口打开"移到工作区"菜单 */ /* Ctrl+Shift+Tab:对当前聚焦窗口打开"移到工作区"菜单 */
if (g_page == 4 && win_find(g_focused_win)) { if (g_page == 3 && win_find(g_focused_win)) {
g_ctx_win = g_focused_win; g_ctx_win = g_focused_win;
g_ctx_x = g_mouse_x; g_ctx_y = g_mouse_y; g_ctx_x = g_mouse_x; g_ctx_y = g_mouse_y;
g_ctx_open = 1; g_ctx_open = 1;
@@ -3015,7 +2948,7 @@ static int handle_key(u8 sc) {
} }
return 0; return 0;
} }
int maxp = 4 + g_cpage_count; int maxp = 3 + g_cpage_count;
int p = g_page + 1; int p = g_page + 1;
if (p > maxp) p = 1; if (p > maxp) p = 1;
page_switch(p); page_switch(p);
@@ -3047,7 +2980,7 @@ static int handle_key(u8 sc) {
} }
return 0; return 0;
} }
if (g_page == 4) { if (g_page == 3) {
desktop_window *fw = win_find(g_focused_win); desktop_window *fw = win_find(g_focused_win);
if (fw && fw->ws == g_ws_cur && fw->app_id >= 0 && fw->app_id < g_app_count && if (fw && fw->ws == g_ws_cur && fw->app_id >= 0 && fw->app_id < g_app_count &&
g_apps[fw->app_id].on_event && fw->app_state) { g_apps[fw->app_id].on_event && fw->app_state) {
@@ -3095,6 +3028,9 @@ void dsk_entry(const dsk_boot_context *ctx) {
} }
du_context_init(&g_fb, g_fb_addr, g_fb_w, g_fb_h, g_fb_pitch); du_context_init(&g_fb, g_fb_addr, g_fb_w, g_fb_h, g_fb_pitch);
/* 双缓冲:保存真实 fb,切换到 sprite buffer 渲染 */
g_real_fb = (u8 *)g_fb_addr;
g_fb.fb = (du_u32 *)SPRITE_BUF_ADDR;
f32_init(g_block_read, g_block_write); f32_init(g_block_read, g_block_write);
tsc_calibrate(); tsc_calibrate();
@@ -3201,13 +3137,16 @@ void dsk_entry(const dsk_boot_context *ctx) {
} }
if (need_redraw) { if (need_redraw) {
cursor_restore_bg();
redraw_all(); redraw_all();
flip_buffer(); /* 全屏 flip:无闪烁 */
} else if (moved) { } else if (moved) {
/* 仅光标移动:局部更新 */ /* 仅光标移动:局部 flip(双缓冲 → 无闪烁) */
int old_x = g_cursor_old_x, old_y = g_cursor_old_y;
cursor_restore_bg(); cursor_restore_bg();
flip_rect(old_x, old_y, CURSOR_SIZE, CURSOR_SIZE);
cursor_save_bg(g_mouse_x, g_mouse_y); cursor_save_bg(g_mouse_x, g_mouse_y);
cursor_draw(g_mouse_x, g_mouse_y); cursor_draw(g_mouse_x, g_mouse_y);
flip_rect(g_mouse_x, g_mouse_y, CURSOR_SIZE, CURSOR_SIZE);
} }
__asm__("pause"); __asm__("pause");
+3 -11
View File
@@ -207,7 +207,7 @@ static int fat32_find_entry(const u8 *clus, u32 clus_sectors, const char *target
if (dir[e].attr==0x0F) continue; if (dir[e].attr==0x0F) continue;
if (dir[e].attr & 0x08) continue; if (dir[e].attr & 0x08) continue;
if (neq11(dir[e].name, target)) { if (neq11(dir[e].name, target)) {
*out_clus = r16((const u8*)&dir[e].clow); *out_clus = r16((const u8*)&dir[e].clow) | ((u32)r16((const u8*)&dir[e].chigh) << 16);
*out_size = dir[e].fsize; *out_size = dir[e].fsize;
return 0; return 0;
} }
@@ -436,10 +436,9 @@ static int fat32_write_root_file(const char *name11, const u8 *data, u32 size) {
e->ntr = 0; e->ctenth = 0; e->ctime = 0; e->cdate = 0; e->ntr = 0; e->ctenth = 0; e->ctime = 0; e->cdate = 0;
e->adate = 0; e->chigh = (u16)((first_clus >> 16) & 0xFFFF); e->adate = 0; e->chigh = (u16)((first_clus >> 16) & 0xFFFF);
e->wtime = 0; e->wdate = 0; e->clow = (u16)(first_clus & 0xFFFF); e->wtime = 0; e->wdate = 0; e->clow = (u16)(first_clus & 0xFFFF);
e->fsize = size;
} else { } else {
dir[free_entry >= 0 ? (u32)free_entry : 0].chigh = (u16)((first_clus >> 16) & 0xFFFF); /* 文件已存在:只更新匹配到的条目(不触碰 free_entry!) */
dir[free_entry >= 0 ? (u32)free_entry : 0].clow = (u16)(first_clus & 0xFFFF);
/* Find the existing entry again to update it */
for (u32 e2 = 0; e2 < max_entries; e2++) { for (u32 e2 = 0; e2 < max_entries; e2++) {
if (neq11(dir[e2].name, name11)) { if (neq11(dir[e2].name, name11)) {
dir[e2].chigh = (u16)((first_clus >> 16) & 0xFFFF); dir[e2].chigh = (u16)((first_clus >> 16) & 0xFFFF);
@@ -449,13 +448,6 @@ static int fat32_write_root_file(const char *name11, const u8 *data, u32 size) {
} }
} }
} }
/* Set file size in the directory entry */
for (u32 e2 = 0; e2 < max_entries; e2++) {
if (neq11(dir[e2].name, name11)) {
dir[e2].fsize = size;
break;
}
}
/* 6. Write FAT + root directory + data sectors back to disk */ /* 6. Write FAT + root directory + data sectors back to disk */
/* Write FAT (both copies) */ /* Write FAT (both copies) */
BIN
View File
Binary file not shown.
+11
View File
@@ -109,6 +109,17 @@ if [ -d "$INITRAMFS_DIR" ]; then
# Copy initramfs contents # Copy initramfs contents
cp -a "$INITRAMFS_DIR"/* "$INITRAMFS_TMP"/ cp -a "$INITRAMFS_DIR"/* "$INITRAMFS_TMP"/
# Build utsm_exec_daemon (static binary for initramfs)
DAEMON_SRC="$INITRAMFS_DIR/bin/utsm_exec_daemon.c"
if [ -f "$DAEMON_SRC" ]; then
echo "[build] Compiling utsm_exec_daemon (static)..."
mkdir -p "$INITRAMFS_TMP/bin"
cc -static -O2 -Wall -I"$PROJECT_ROOT/CODE/utsm-ipc" \
-o "$INITRAMFS_TMP/bin/utsm_exec_daemon" "$DAEMON_SRC"
strip "$INITRAMFS_TMP/bin/utsm_exec_daemon" 2>/dev/null || true
echo "[build] daemon: $(du -h "$INITRAMFS_TMP/bin/utsm_exec_daemon" | cut -f1)"
fi
# Create init script if not present # Create init script if not present
if [ ! -f "$INITRAMFS_TMP/init" ]; then if [ ! -f "$INITRAMFS_TMP/init" ]; then
cat > "$INITRAMFS_TMP/init" <<'INITEOF' cat > "$INITRAMFS_TMP/init" <<'INITEOF'
+218
View File
@@ -0,0 +1,218 @@
// SPDX-License-Identifier: GPL-2.0
/*
* utsm_exec_daemon — Linux guest side exec daemon for Deshab Linux compat layer.
*
* Runs as the first userspace process (PID 2, after init) in the Linux guest.
* Communicates with UTSM via /dev/utsm ioctl interface:
*
* 1. Send EXEC_READY, then ioctl(PARK) → HLT → guest parks
* (this is the first HLT; linux_launch() returns to UTSM)
* 2. On vmresume: ioctl(RECV_MSG) → EXEC_REQUEST
* 3. fork + exec the requested program, capture stdout/stderr via pipe
* 4. Stream output back via ioctl(SEND_MSG, EXEC_STDOUT/STDERR)
* 5. Send EXEC_EXIT with waitpid exit code
* 6. Loop: ioctl(PARK) → wait for next request
*
* Build: static musl/glibc binary, stripped, copied into initramfs /bin/.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/types.h>
/* Shared IPC protocol — must match UTSM side */
#include "../../../utsm-ipc/ipc_proto.h"
/* Ioctl definitions — must match utsm_hcall.c driver */
#define UTSM_IOCTL_RECV_MSG _IOWR('U', 1, struct utsm_ioctl_msg)
#define UTSM_IOCTL_SEND_MSG _IOWR('U', 2, struct utsm_ioctl_msg)
#define UTSM_IOCTL_PARK _IO('U', 3)
#define UTSM_IOCTL_GET_READY _IOR('U', 4, int)
struct utsm_ioctl_msg {
unsigned int type;
unsigned int data_len;
unsigned int reserved;
unsigned int buf_size;
unsigned char data[UTSM_IPC_MSG_DATA_SIZE];
};
static int g_utsm_fd = -1;
/* Send a typed message to UTSM via the linux_to_utsm ring */
static int send_msg(unsigned int type, const void *data, unsigned int len)
{
struct utsm_ioctl_msg umsg;
memset(&umsg, 0, sizeof(umsg));
umsg.type = type;
umsg.data_len = len;
umsg.buf_size = UTSM_IPC_MSG_DATA_SIZE;
if (data && len > 0) {
if (len > UTSM_IPC_MSG_DATA_SIZE)
len = UTSM_IPC_MSG_DATA_SIZE;
memcpy(umsg.data, data, len);
umsg.data_len = len;
}
return ioctl(g_utsm_fd, UTSM_IOCTL_SEND_MSG, &umsg);
}
/* Receive a message from UTSM (non-blocking). Returns 0 on success, -EAGAIN if empty. */
static int recv_msg(struct utsm_ioctl_msg *umsg)
{
memset(umsg, 0, sizeof(*umsg));
umsg->buf_size = UTSM_IPC_MSG_DATA_SIZE;
return ioctl(g_utsm_fd, UTSM_IOCTL_RECV_MSG, umsg);
}
/* Park: HLT → VM-Exit → UTSM parks guest. Returns on vmresume. */
static int park(void)
{
return ioctl(g_utsm_fd, UTSM_IOCTL_PARK);
}
/* ===== Exec request handler =====
*
* Fork a child to exec the requested program. Parent reads stdout/stderr
* from a pipe and streams chunks back to UTSM via EXEC_STDOUT/EXEC_STDERR
* messages. Finally sends EXEC_EXIT with the child's exit status.
*
* argv parsing: argv_blob contains NUL-terminated argv[0..argc-1]
* concatenated. We split it into a char* array for execv. */
static void handle_exec_request(const struct ipc_exec_request *req)
{
/* Parse argv_blob into argv[] array */
char *argv[UTSM_EXEC_MAX_ARGS + 1];
int argc = (int)req->argc;
if (argc > UTSM_EXEC_MAX_ARGS) argc = UTSM_EXEC_MAX_ARGS;
if (argc < 1) {
struct ipc_exec_exit ex = { .exit_code = 1, .reserved = 0 };
send_msg(UTSM_MSG_EXEC_EXIT, &ex, sizeof(ex));
return;
}
const char *blob = req->argv_blob;
int blob_consumed = 0;
for (int i = 0; i < argc; i++) {
if (blob_consumed >= UTSM_EXEC_ARGV_MAX) {
argv[i] = (char *)"";
continue;
}
argv[i] = (char *)(blob + blob_consumed);
int slen = strnlen(blob + blob_consumed, UTSM_EXEC_ARGV_MAX - blob_consumed);
blob_consumed += slen + 1;
}
argv[argc] = NULL;
/* Create a pipe for child stdout+stderr */
int pipefd[2];
if (pipe(pipefd) != 0) {
struct ipc_exec_exit ex = { .exit_code = 126, .reserved = 0 };
send_msg(UTSM_MSG_EXEC_EXIT, &ex, sizeof(ex));
return;
}
pid_t pid = fork();
if (pid < 0) {
/* fork failed */
close(pipefd[0]);
close(pipefd[1]);
struct ipc_exec_exit ex = { .exit_code = 127, .reserved = 0 };
send_msg(UTSM_MSG_EXEC_EXIT, &ex, sizeof(ex));
return;
}
if (pid == 0) {
/* Child: redirect stdout + stderr to pipe write end, then exec */
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
dup2(pipefd[1], STDERR_FILENO);
close(pipefd[1]);
execv(req->path, argv);
/* execv only returns on failure */
const char *err1 = "utsm_exec_daemon: exec failed: ";
write(STDERR_FILENO, err1, strlen(err1));
write(STDERR_FILENO, req->path, strnlen(req->path, UTSM_EXEC_PATH_MAX));
const char *err2 = ": ";
write(STDERR_FILENO, err2, strlen(err2));
const char *emsg = strerror(errno);
write(STDERR_FILENO, emsg, strlen(emsg));
write(STDERR_FILENO, "\n", 1);
_exit(127);
}
/* Parent: read child output from pipe, stream to UTSM */
close(pipefd[1]);
char buf[UTSM_IPC_MSG_DATA_SIZE];
ssize_t n;
while ((n = read(pipefd[0], buf, sizeof(buf))) > 0) {
send_msg(UTSM_MSG_EXEC_STDOUT, buf, (unsigned int)n);
}
close(pipefd[0]);
/* Wait for child and send exit code */
int status = 0;
waitpid(pid, &status, 0);
struct ipc_exec_exit ex;
ex.reserved = 0;
if (WIFEXITED(status)) {
ex.exit_code = (unsigned int)WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
ex.exit_code = 128u + (unsigned int)WTERMSIG(status);
} else {
ex.exit_code = 1;
}
send_msg(UTSM_MSG_EXEC_EXIT, &ex, sizeof(ex));
}
/* ===== Main loop ===== */
int main(void)
{
g_utsm_fd = open("/dev/utsm", O_RDWR);
if (g_utsm_fd < 0) {
/* Cannot communicate with UTSM — exit */
return 1;
}
/* Announce daemon ready. UTSM's linux_launch() will see the subsequent
* HLT (via PARK ioctl) and return, marking the compat layer ready. */
send_msg(UTSM_MSG_EXEC_READY, NULL, 0);
/* First park: this is the HLT that causes linux_launch() to return. */
park();
/* Main loop: process exec requests */
for (;;) {
struct utsm_ioctl_msg umsg;
/* Drain any pending messages (there may be multiple if UTSM
* queued several before vmresume). */
int got_request = 0;
while (recv_msg(&umsg) == 0) {
if (umsg.type == UTSM_MSG_EXEC_REQUEST &&
umsg.data_len >= sizeof(struct ipc_exec_request)) {
handle_exec_request((const struct ipc_exec_request *)umsg.data);
got_request = 1;
}
/* Ignore other message types (HELLO, PING, etc.) */
}
/* If we processed a request, the response is already sent.
* Park to let UTSM read the response and return to shell.
* If no request (spurious wakeup), just park again. */
park();
}
close(g_utsm_fd);
return 0;
}
+47
View File
@@ -0,0 +1,47 @@
#!/bin/sh
#
# init — Linux guest init script for UTSM dual-kernel Linux compat layer.
#
# Boot sequence:
# 1. Mount essential filesystems
# 2. Load UTSM driver (built-in, /dev/utsm auto-created)
# 3. Start utsm_exec_daemon (background)
# 4. Daemon sends EXEC_READY, then HLT (park) → linux_launch() returns to UTSM
# 5. UTSM proceeds to load DSK; Linux guest stays parked until shell
# invokes `linux <prog>` which triggers vmresume.
#
# The daemon runs forever, parking between requests. This init script
# should NOT exit (would panic the kernel); it sleeps indefinitely after
# starting the daemon so the kernel has a runnable init task.
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
# Mount essential filesystems
mount -t proc none /proc 2>/dev/null
mount -t sysfs none /sys 2>/dev/null
mount -t devtmpfs none /dev 2>/dev/null
echo "[utsm-linux] init started"
echo "[utsm-linux] kernel: $(uname -r)"
# Verify /dev/utsm exists (driver is built-in, should be auto-created)
if [ ! -e /dev/utsm ]; then
echo "[utsm-linux] WARNING: /dev/utsm not found — UTSM driver not loaded"
fi
# Start the exec daemon in the background.
# The daemon sends EXEC_READY then HLTs (parks the guest).
# UTSM's linux_launch() returns after this first HLT.
echo "[utsm-linux] starting utsm_exec_daemon..."
/bin/utsm_exec_daemon &
DAEMON_PID=$!
echo "[utsm-linux] daemon PID=$DAEMON_PID"
# init must not exit — sleep forever to keep the kernel happy.
# The daemon handles all UTSM exec requests; init just keeps the
# root task alive so the kernel doesn't panic.
echo "[utsm-linux] init: daemon running, entering idle hold"
while true; do
sleep 3600
done
+140 -3
View File
@@ -23,12 +23,43 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/poll.h>
/* Shared IPC protocol header (included via build.sh -I flag) */ /* Shared IPC protocol header (included via build.sh -I flag) */
#include <ipc_proto.h> #include <ipc_proto.h>
#define UTSM_DEV_NAME "utsm" #define UTSM_DEV_NAME "utsm"
/* ===== Ioctl interface for exec daemon =====
*
* The exec daemon (userspace) uses these ioctls to:
* 1. RECV_MSG: poll utsm_to_linux ring for EXEC_REQUEST (non-blocking)
* 2. SEND_MSG: push STDOUT/STDERR/EXIT to linux_to_utsm ring
* 3. PARK: execute HLT to trigger VM-Exit → UTSM parks guest,
* returning control to the host. vmresume causes the
* ioctl to return, at which point the daemon re-checks
* the ring for new requests.
*
* This explicit-park model avoids the need for timer emulation or
* IRQ injection: the daemon HLTs only when it has nothing to do,
* and UTSM vmresumes only when there is work. */
#define UTSM_IOCTL_RECV_MSG _IOWR('U', 1, struct utsm_ioctl_msg)
#define UTSM_IOCTL_SEND_MSG _IOWR('U', 2, struct utsm_ioctl_msg)
#define UTSM_IOCTL_PARK _IO('U', 3)
#define UTSM_IOCTL_GET_READY _IOR('U', 4, int)
/* Ioctl message wrapper: carries type + data in a single call */
struct utsm_ioctl_msg {
u32 type; /* message type (in/out) */
u32 data_len; /* actual bytes in data (in/out) */
u32 reserved;
u32 buf_size; /* capacity of data buffer (in) */
u8 data[UTSM_IPC_MSG_DATA_SIZE]; /* payload */
};
/* ===== Hypercall ABI ===== /* ===== Hypercall ABI =====
* *
* Linux calls VMCALL with: * Linux calls VMCALL with:
@@ -169,10 +200,116 @@ static ssize_t utsm_dev_read(struct file *f, char __user *buf,
return (ssize_t)msg.data_len; return (ssize_t)msg.data_len;
} }
/* ===== Ioctl handlers for exec daemon ===== */
static long utsm_dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
if (!g_shm_mapped)
return -ENODEV;
switch (cmd) {
case UTSM_IOCTL_RECV_MSG: {
/* Non-blocking dequeue from utsm_to_linux ring */
struct utsm_ioctl_msg umsg;
struct utsm_ipc_msg msg;
int ret;
if (copy_from_user(&umsg, (void __user *)arg, sizeof(umsg)))
return -EFAULT;
ret = utsm_ipc_ring_pop(&g_shm->utsm_to_linux, &msg);
if (ret != 0)
return -EAGAIN; /* ring empty */
umsg.type = msg.type;
umsg.data_len = msg.data_len;
if (umsg.buf_size < msg.data_len)
return -EINVAL;
if (msg.data_len > 0) {
if (copy_to_user(umsg.data, msg.data, msg.data_len))
return -EFAULT;
}
if (copy_to_user((void __user *)arg, &umsg, sizeof(umsg)))
return -EFAULT;
return 0;
}
case UTSM_IOCTL_SEND_MSG: {
/* Enqueue to linux_to_utsm ring */
struct utsm_ioctl_msg umsg;
struct utsm_ipc_msg msg;
if (copy_from_user(&umsg, (void __user *)arg, sizeof(umsg)))
return -EFAULT;
memset(&msg, 0, sizeof(msg));
msg.type = umsg.type;
msg.data_len = min_t(u32, umsg.data_len, UTSM_IPC_MSG_DATA_SIZE);
if (msg.data_len > 0) {
if (copy_from_user(msg.data, umsg.data, msg.data_len))
return -EFAULT;
}
if (utsm_ipc_ring_push(&g_shm->linux_to_utsm, &msg) != 0) {
pr_warn("[utsm] linux_to_utsm ring full\n");
return -EAGAIN;
}
return 0;
}
case UTSM_IOCTL_PARK: {
/* Execute HLT to trigger VM-Exit → UTSM parks guest.
* Interrupts must be enabled so that on vmresume the guest
* can continue (HLT with interrupts disabled would hang).
*
* Flow:
* 1. daemon calls ioctl(PARK) → driver executes HLT
* 2. HLT → VM-Exit (CPU_BASED_HLT_EXITING) → UTSM handle_hlt
* 3. UTSM advances RIP past HLT, exits to host (park)
* 4. UTSM writes request + vmresume
* 5. Guest continues from after HLT → ioctl returns
* 6. Daemon re-checks ring for new EXEC_REQUEST
*/
mb(); /* ensure prior ring writes are visible before HLT */
asm volatile("hlt" ::: "memory");
return 0;
}
case UTSM_IOCTL_GET_READY: {
int ready = (g_shm->header.utsm_ready && g_shm->header.linux_ready) ? 1 : 0;
if (copy_to_user((void __user *)arg, &ready, sizeof(ready)))
return -EFAULT;
return 0;
}
default:
return -ENOTTY;
}
}
static __poll_t utsm_dev_poll(struct file *f, struct poll_table_struct *wait)
{
__poll_t mask = 0;
if (!g_shm_mapped)
return EPOLLERR;
/* Report readable if utsm_to_linux ring has messages */
if (!utsm_ipc_ring_empty(&g_shm->utsm_to_linux))
mask |= EPOLLIN | EPOLLRDNORM;
/* Always writable (ring push may still fail with -EAGAIN) */
mask |= EPOLLOUT | EPOLLWRNORM;
return mask;
}
static const struct file_operations utsm_fops = { static const struct file_operations utsm_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.write = utsm_dev_write, .write = utsm_dev_write,
.read = utsm_dev_read, .read = utsm_dev_read,
.unlocked_ioctl = utsm_dev_ioctl,
.poll = utsm_dev_poll,
}; };
static struct miscdevice utsm_miscdev = { static struct miscdevice utsm_miscdev = {
+117 -2
View File
@@ -226,6 +226,104 @@ static void draw_rounded_input(u32 *fb, i64 x, i64 y, i64 w, i64 h, const char *
} }
} }
/* ---- PS/2 鼠标光标 ---- */
#define CURSZ 16
static int g_mouse_x = 400, g_mouse_y = 300;
static int g_mouse_btn = 0;
static u32 g_cursor_bg[CURSZ * CURSZ];
static int g_cursor_saved = 0;
static int g_cursor_old_x = -1, g_cursor_old_y = -1;
static u8 g_mouse_buf[3];
static int g_mouse_idx = 0;
/* 16×16 箭头光标(与 desktop 一致) */
static const u8 cursor_shape[16][16] = {
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
{1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
{1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0},
{1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0},
{1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0},
{1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0},
{1,1,1,1,1,0,1,1,0,0,0,0,0,0,0,0},
{1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0},
{1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
};
static void cursor_save_bg(u32 *fb, int mx, int my) {
for (int r = 0; r < CURSZ; r++) {
for (int c = 0; c < CURSZ; c++) {
int x = mx + c, y = my + r;
if (x >= 0 && (u64)x < fb_w && y >= 0 && (u64)y < fb_h) {
u32 *line = (u32 *)((u8 *)fb + (u64)y * fb_p);
g_cursor_bg[r * CURSZ + c] = line[x];
} else {
g_cursor_bg[r * CURSZ + c] = 0;
}
}
}
g_cursor_saved = 1;
g_cursor_old_x = mx;
g_cursor_old_y = my;
}
static void cursor_restore_bg(u32 *fb) {
if (!g_cursor_saved) return;
for (int r = 0; r < CURSZ; r++) {
for (int c = 0; c < CURSZ; c++) {
int x = g_cursor_old_x + c, y = g_cursor_old_y + r;
if (x >= 0 && (u64)x < fb_w && y >= 0 && (u64)y < fb_h) {
u32 *line = (u32 *)((u8 *)fb + (u64)y * fb_p);
line[x] = g_cursor_bg[r * CURSZ + c];
}
}
}
g_cursor_saved = 0;
}
static void cursor_draw(u32 *fb, int mx, int my) {
u32 fg = ACCENT;
for (int r = 0; r < CURSZ; r++) {
for (int c = 0; c < CURSZ; c++) {
if (!cursor_shape[r][c]) continue;
int x = mx + c, y = my + r;
if (x >= 0 && (u64)x < fb_w && y >= 0 && (u64)y < fb_h) {
u32 *line = (u32 *)((u8 *)fb + (u64)y * fb_p);
line[x] = fg;
}
}
}
}
static int ps2_mouse_poll(void) {
u8 st = inb(0x64);
if (!(st & 1)) return 0;
if (!(st & 0x20)) return 0;
u8 data = inb(0x60);
g_mouse_buf[g_mouse_idx++] = data;
if (g_mouse_idx < 3) return 0;
g_mouse_idx = 0;
if (!(g_mouse_buf[0] & 0x08)) return 0;
int dx = (int)(i8)g_mouse_buf[1];
int dy = -(int)(i8)g_mouse_buf[2];
g_mouse_x += dx;
g_mouse_y += dy;
if (g_mouse_x < 0) g_mouse_x = 0;
if (g_mouse_y < 0) g_mouse_y = 0;
if (g_mouse_x >= (int)fb_w - CURSZ) g_mouse_x = (int)fb_w - CURSZ;
if (g_mouse_y >= (int)fb_h - CURSZ) g_mouse_y = (int)fb_h - CURSZ;
int old_btn = g_mouse_btn;
g_mouse_btn = g_mouse_buf[0] & 0x03;
if (dx == 0 && dy == 0 && g_mouse_btn == old_btn) return 0;
return 1;
}
/* ---- PS/2 scan code set 1 → ASCII ---- */ /* ---- PS/2 scan code set 1 → ASCII ---- */
static char scan_to_ascii(u8 sc, int shift) { static char scan_to_ascii(u8 sc, int shift) {
static const char normal[58] = { static const char normal[58] = {
@@ -406,6 +504,7 @@ static void draw_login_card(u32 *fb, i64 card_x, i64 card_y, const char *pass, i
u32 card = CARD_BG; u32 card = CARD_BG;
u32 sub_fg = 0xFF9098A0; u32 sub_fg = 0xFF9098A0;
/* Background + card */ /* Background + card */
cursor_restore_bg(fb);
fill_gradient_rect(fb, card_x - 24, card_y - 24, CARD_W + 48, CARD_H + 48); fill_gradient_rect(fb, card_x - 24, card_y - 24, CARD_W + 48, CARD_H + 48);
draw_card(fb, card_x, card_y, CARD_W, CARD_H, card); draw_card(fb, card_x, card_y, CARD_W, CARD_H, card);
/* Title */ /* Title */
@@ -432,14 +531,19 @@ static void draw_login_card(u32 *fb, i64 card_x, i64 card_y, const char *pass, i
/* Bottom hint */ /* Bottom hint */
fb_text(fb, "Enter=login Esc=skip Backspace=delete", fb_text(fb, "Enter=login Esc=skip Backspace=delete",
card_x + 40, card_y + CARD_H - 28, DIM_FG, card); card_x + 40, card_y + CARD_H - 28, DIM_FG, card);
cursor_save_bg(fb, g_mouse_x, g_mouse_y);
cursor_draw(fb, g_mouse_x, g_mouse_y);
} }
/* Redraw only the password input field (avoids full card redraw on each keystroke) */ /* Redraw only the password input field (avoids full card redraw on each keystroke) */
static void redraw_password_only(u32 *fb, i64 card_x, i64 card_y, const char *pass, u32 fg) { static void redraw_password_only(u32 *fb, i64 card_x, i64 card_y, const char *pass, u32 fg) {
u32 card = CARD_BG; u32 card = CARD_BG;
i64 fy = card_y + 240; i64 fy = card_y + 240;
cursor_restore_bg(fb);
fill_rect(fb, card_x + 40, fy, CARD_W - 80, 44, card); fill_rect(fb, card_x + 40, fy, CARD_W - 80, 44, card);
draw_rounded_input(fb, card_x + 40, fy, CARD_W - 80, 44, pass, 1, fg, card, 1); draw_rounded_input(fb, card_x + 40, fy, CARD_W - 80, 44, pass, 1, fg, card, 1);
cursor_save_bg(fb, g_mouse_x, g_mouse_y);
cursor_draw(fb, g_mouse_x, g_mouse_y);
} }
/* ---- verify password against stored hash or encrypted conf ---- /* ---- verify password against stored hash or encrypted conf ----
@@ -562,15 +666,26 @@ void dsk_entry(const dsk_boot_context *ctx) {
/* Draw initial UI */ /* Draw initial UI */
draw_login_card(fb, card_x, card_y, pass, 1, msg, msg_color, fg); draw_login_card(fb, card_x, card_y, pass, 1, msg, msg_color, fg);
/* 初始鼠标光标 */
cursor_save_bg(fb, g_mouse_x, g_mouse_y);
cursor_draw(fb, g_mouse_x, g_mouse_y);
/* Input loop */ /* Input loop */
int shift = 0; int shift = 0;
int release = 0; int release = 0;
for (;;) { for (;;) {
/* 鼠标轮询:处理鼠标移动并更新光标 */
if (ps2_mouse_poll()) {
cursor_restore_bg(fb);
cursor_save_bg(fb, g_mouse_x, g_mouse_y);
cursor_draw(fb, g_mouse_x, g_mouse_y);
}
u8 st = inb(0x64); u8 st = inb(0x64);
if (!(st & 1)) { __asm__("pause"); continue; } if (!(st & 1)) { __asm__("pause"); continue; }
/* 跳过鼠标数据(由 ps2_mouse_poll 处理) */
if (st & 0x20) { inb(0x60); continue; }
u8 data = inb(0x60); u8 data = inb(0x60);
/* Skip mouse data (bit 5 of status) */
if (st & 0x20) continue;
u8 sc = data; u8 sc = data;
/* Handle extended (E0) sequences — ignore (no arrow keys needed for login) */ /* Handle extended (E0) sequences — ignore (no arrow keys needed for login) */
+304 -198
View File
@@ -4,6 +4,8 @@
*/ */
#include "../UTSM/include/utsm/dsk.h" #include "../UTSM/include/utsm/dsk.h"
#include "../UTSM/include/utsm/pe.h"
#include "../UTSM/include/utsm/linux_compat.h"
typedef unsigned char u8; typedef unsigned char u8;
typedef unsigned short u16; typedef unsigned short u16;
@@ -72,8 +74,6 @@ static void logl(const char *s) { swrite(s); swrite("\n"); }
/* ASCII 字体 — 必须在 deshab_ui.h 之前包含,因为 du_draw_char 引用 g_ascii */ /* ASCII 字体 — 必须在 deshab_ui.h 之前包含,因为 du_draw_char 引用 g_ascii */
#include "../firstInit/ascii_bitmaps.c" #include "../firstInit/ascii_bitmaps.c"
#include "../UTSM/include/utsm/deshab_ui.h" #include "../UTSM/include/utsm/deshab_ui.h"
/* 用户态共享协议栈(ping/curl 内建命令使用) */
#include "../tools/net_stack.h"
/* ============================================================ /* ============================================================
* Block 设备 + FAT32 读写(移植自 DSK,支持 cp/mv/cat/ls) * Block 设备 + FAT32 读写(移植自 DSK,支持 cp/mv/cat/ls)
@@ -190,16 +190,57 @@ static int fat32_find_in_root(const u8 *clus, u32 clus_sectors, const char *targ
return -1; return -1;
} }
/* 读取根目录下指定 8.3 名文件到 g_fdata。 /* 在目录簇链中查找名为 name11 的子目录(attr & 0x10),返回首簇号。
* dir_clus: 目录起始簇号。返回 0 成功,-1 未找到。 */
static int fat32_find_dir(u32 dir_clus, const char *name11, u32 *out_clus) {
if (sh_disk_load() != 0) return -2;
const shell_fat32_bpb *bpb = (const shell_fat32_bpb *)g_disk;
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
u32 fat_byte_off = bpb->rsvd * 512;
u32 spc = bpb->spc;
u32 clus = dir_clus;
while (clus >= 2 && clus < 0x0FFFFFF8) {
u32 lba = data_lba + (clus - 2) * spc;
const u8 *cb;
if ((u64)lba * 512 + (u64)spc * 512 <= 256ULL * 512)
cb = g_disk + (u64)lba * 512;
else {
if (sh_read_sectors(lba, 8, g_cluster) != 0) return -4;
cb = g_cluster;
}
const shell_fat32_de *dir = (const shell_fat32_de *)cb;
for (u32 e = 0; e * 32 < spc * 512; e++) {
if (dir[e].name[0] == 0) goto done_dir;
if ((u8)dir[e].name[0] == 0xE5) continue;
if (dir[e].attr == 0x0F) continue;
if (dir[e].attr & 0x08) continue;
if (!(dir[e].attr & 0x10)) continue; /* 只匹配目录 */
if (sh_neq11(dir[e].name, name11)) {
*out_clus = (u32)sh_r16((const u8*)&dir[e].clow)
| ((u32)sh_r16((const u8*)&dir[e].chigh) << 16);
return 0;
}
}
u32 fo = fat_byte_off + clus * 4;
if (fo + 4 > sizeof(g_disk)) break;
clus = sh_r32(g_disk + fo) & 0x0FFFFFFF;
}
done_dir:
return -1;
}
/* 从指定目录首簇读取文件到 g_fdata。
* dir_clus: 目录起始簇号。name11: 8.3 名。
* 返回 0 成功,*out_data 指向 g_fdata,*out_size 为字节数;非 0 失败。 */ * 返回 0 成功,*out_data 指向 g_fdata,*out_size 为字节数;非 0 失败。 */
static int fat32_read_root_file(const char *name11, u8 **out_data, u32 *out_size) { static int fat32_read_file_in_dir(u32 dir_clus, const char *name11,
u8 **out_data, u32 *out_size) {
if (sh_disk_load() != 0) return -1; if (sh_disk_load() != 0) return -1;
const shell_fat32_bpb *bpb = (const shell_fat32_bpb *)g_disk; const shell_fat32_bpb *bpb = (const shell_fat32_bpb *)g_disk;
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf; u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
u32 fat_byte_off = bpb->rsvd * 512; u32 fat_byte_off = bpb->rsvd * 512;
u32 spc = bpb->spc; u32 spc = bpb->spc;
u32 clus = bpb->root_clus; u32 clus = dir_clus;
u32 found_clus = 0, found_size = 0; u32 found_clus = 0, found_size = 0;
int found = 0; int found = 0;
while (clus >= 2 && clus < 0x0FFFFFF8 && !found) { while (clus >= 2 && clus < 0x0FFFFFF8 && !found) {
@@ -241,6 +282,37 @@ static int fat32_read_root_file(const char *name11, u8 **out_data, u32 *out_size
return 0; return 0;
} }
/* 读取根目录下指定 8.3 名文件到 g_fdata。
* 返回 0 成功,*out_data 指向 g_fdata,*out_size 为字节数;非 0 失败。 */
static int fat32_read_root_file(const char *name11, u8 **out_data, u32 *out_size) {
if (sh_disk_load() != 0) return -1;
const shell_fat32_bpb *bpb = (const shell_fat32_bpb *)g_disk;
return fat32_read_file_in_dir(bpb->root_clus, name11, out_data, out_size);
}
/* /bin 目录首簇号缓存 */
static u32 g_bin_clus = 0;
static int g_bin_checked = 0;
/* 获取 /bin 目录首簇号。返回 0 成功,-1 未找到。 */
static int get_bin_cluster(u32 *out_clus) {
if (g_bin_checked) {
if (g_bin_clus == 0) return -1;
*out_clus = g_bin_clus;
return 0;
}
g_bin_checked = 1;
if (sh_disk_load() != 0) { g_bin_clus = 0; return -1; }
const shell_fat32_bpb *bpb = (const shell_fat32_bpb *)g_disk;
char bin83[11] = {'B','I','N',' ',' ',' ',' ',' ',' ',' ',' '};
if (fat32_find_dir(bpb->root_clus, bin83, &g_bin_clus) != 0) {
g_bin_clus = 0;
return -1;
}
*out_clus = g_bin_clus;
return 0;
}
/* 写入根目录下指定 8.3 名文件(存在则替换,不存在则新建)。 /* 写入根目录下指定 8.3 名文件(存在则替换,不存在则新建)。
* 依赖 g_disk 已加载 BPB+FAT。返回 0 成功。 */ * 依赖 g_disk 已加载 BPB+FAT。返回 0 成功。 */
static int fat32_write_root_file(const char *name11, const u8 *data, u32 size) { static int fat32_write_root_file(const char *name11, const u8 *data, u32 size) {
@@ -804,11 +876,14 @@ static void cmd_help(void) {
term_puts(" date 显示当前日期\n"); term_puts(" date 显示当前日期\n");
term_puts(" about 关于 Deshab\n"); term_puts(" about 关于 Deshab\n");
term_puts(" pci 列出 PCI 设备\n"); term_puts(" pci 列出 PCI 设备\n");
term_puts(" ping [ip] ICMP echo 测试(缺省网关 10.0.2.2)\n");
term_puts(" curl <url> HTTP GET 请求(http://host[:port]/path)\n");
term_puts(" run <NAME.ELF> 运行根目录下的工具程序\n"); term_puts(" run <NAME.ELF> 运行根目录下的工具程序\n");
term_puts(" linux <prog> [args] 通过双内核兼容层运行 Linux 程序\n");
term_puts(" reboot 重启系统\n"); term_puts(" reboot 重启系统\n");
term_puts(" halt 关机(停止 CPU)\n"); term_puts(" halt 关机(停止 CPU)\n");
term_putc('\n');
term_puts_color("外部命令(/bin/ 目录,PATH 自动查找):\n", DIM_FG);
term_puts(" ping ICMP echo 测试工具\n");
term_puts(" curl HTTP GET 请求工具\n");
} }
static void cmd_version(void) { static void cmd_version(void) {
@@ -1234,193 +1309,9 @@ static void cmd_pci(void) {
term_puts_color(tail, DIM_FG); term_puts_color(tail, DIM_FG);
} }
/* ============================================================
* 网络命令:ping / curl(共享协议栈 net_stack.h)
* ============================================================ */
static u64 g_kernel_api = 0; static u64 g_kernel_api = 0;
static const dsk_boot_context *g_boot_ctx = 0; static const dsk_boot_context *g_boot_ctx = 0;
static int g_ns_status = 0; /* 0=未尝试, 1=就绪, <0=初始化失败 */ static const linux_compat_service *g_lxc_svc = 0;
static int shell_net_ready(void) {
if (g_ns_status == 1) return 1;
if (g_ns_status < 0) return 0;
int rc = ns_init(g_kernel_api);
g_ns_status = (rc == 0) ? 1 : -1;
if (rc != 0) {
logl("[shell] ns_init failed");
term_puts_color("网络初始化失败 (rc=", ERROR_FG);
char rcbuf[4];
rcbuf[0] = (char)('0' + (-rc % 10));
rcbuf[1] = 0;
term_puts_color(rcbuf, ERROR_FG);
term_puts_color("),无可用网卡或 net API\n", ERROR_FG);
return 0;
}
logl("[shell] ns_init ok");
return 1;
}
/* ping [a.b.c.d] — 缺省网关 10.0.2.2,4 次 echo */
static void cmd_ping(const char *args) {
u32 ip;
if (!args || !*args) {
ip = NS_GATEWAY_IP;
} else if (ns_parse_ip(args, &ip) != 0) {
term_puts_color("用法: ping [a.b.c.d]\n", ERROR_FG);
return;
}
if (!shell_net_ready()) return;
char ipstr[24];
ns_fmt_ip(ip, ipstr);
term_puts_color("PING ", PROMPT_FG);
term_puts_color(ipstr, ACCENT_FG);
term_puts_color(" 32 data bytes\n", DIM_FG);
int sent = 0, recv = 0;
u32 sum = 0, min = 0xFFFFFFFFu, max = 0;
for (u16 seq = 1; seq <= 4; seq++) {
u32 rtt = 0; u8 ttl = 0;
int rc = ns_ping(ip, seq, 2000, &rtt, &ttl);
sent++;
if (rc == 0) {
recv++;
sum += rtt;
if (rtt < min) min = rtt;
if (rtt > max) max = rtt;
term_puts("reply from ");
term_puts(ipstr);
term_puts(": bytes=32 time=");
char nb[12]; ns_u32_dec(nb, rtt);
term_puts(nb);
term_puts("ms TTL=");
ns_u32_dec(nb, ttl);
term_puts(nb);
term_putc('\n');
} else if (rc == -1) {
term_puts_color("ARP 解析失败,目标不可达\n", ERROR_FG);
break;
} else {
term_puts_color("request timed out\n", DIM_FG);
}
}
/* 统计行 */
char nb[12];
ns_u32_dec(nb, (u32)sent);
term_puts_color("--- ", DIM_FG);
term_puts_color(ipstr, DIM_FG);
term_puts_color(" ping statistics ---\n ", DIM_FG);
term_puts(nb);
term_puts(" transmitted, ");
ns_u32_dec(nb, (u32)recv);
term_puts(nb);
term_puts(" received, ");
u32 loss = sent ? (u32)(sent - recv) * 100 / (u32)sent : 100;
ns_u32_dec(nb, loss);
term_puts(nb);
term_puts("% loss");
if (recv > 0) {
term_puts(", min/avg/max = ");
ns_u32_dec(nb, min); term_puts(nb); term_puts("/");
ns_u32_dec(nb, sum / (u32)recv); term_puts(nb); term_puts("/");
ns_u32_dec(nb, max); term_puts(nb); term_puts(" ms");
}
term_putc('\n');
}
/* curl http://host[:port][/path] — HTTP/1.0 GET,打印 status + body */
static void cmd_curl(const char *args) {
if (!args || !*args) {
term_puts_color("用法: curl http://host[:port][/path]\n", ERROR_FG);
return;
}
if (!shell_net_ready()) return;
const char *p = args;
if (p[0]=='h'&&p[1]=='t'&&p[2]=='t'&&p[3]=='p'&&p[4]==':'&&p[5]=='/'&&p[6]=='/') p += 7;
char host[128]; int hl = 0;
while (*p && *p != ':' && *p != '/' && hl < 127) host[hl++] = *p++;
host[hl] = 0;
if (!hl) { term_puts_color("curl: 缺少主机名\n", ERROR_FG); return; }
u16 port = 80;
if (*p == ':') {
p++;
u32 pv = 0; int digits = 0;
while (*p >= '0' && *p <= '9') { pv = pv * 10 + (u32)(*p - '0'); p++; digits++; }
if (digits && pv <= 65535) port = (u16)pv;
}
char path[128]; int pl = 0;
if (*p == '/') {
while (*p && *p != ' ' && pl < 127) path[pl++] = *p++;
}
if (!pl) { path[0] = '/'; pl = 1; }
path[pl] = 0;
/* 解析主机 */
u32 ip;
term_puts_color("-> 解析 ", DIM_FG);
term_puts_color(host, DIM_FG);
term_puts_color("...\n", DIM_FG);
if (ns_dns_resolve(host, &ip) != 0) {
term_puts_color("curl: DNS 解析失败\n", ERROR_FG);
return;
}
char ipstr[24]; ns_fmt_ip(ip, ipstr);
term_puts_color("-> ", DIM_FG);
term_puts_color(ipstr, DIM_FG);
term_putc('\n');
/* 连接 */
term_puts_color("-> TCP 连接...\n", DIM_FG);
if (ns_tcp_connect(ip, port, 2000) != 0) {
term_puts_color("curl: TCP 连接失败(超时/RST)\n", ERROR_FG);
return;
}
term_puts_color("-> 已连接,发送请求\n", DIM_FG);
/* 构造 HTTP/1.0 请求 */
static char req[512];
int r = 0;
const char *m = "GET "; while (*m) req[r++] = *m++;
for (int i = 0; i < pl; i++) req[r++] = path[i];
m = " HTTP/1.0\r\nHost: "; while (*m) req[r++] = *m++;
for (int i = 0; i < hl; i++) req[r++] = host[i];
m = "\r\nConnection: close\r\n\r\n"; while (*m) req[r++] = *m++;
req[r] = 0;
if (ns_tcp_send((const u8 *)req, (u32)r) != 0) {
term_puts_color("curl: 发送失败\n", ERROR_FG);
ns_tcp_close();
return;
}
/* 收至 FIN(数据在协议栈 ns_tcp_rx 中累计) */
int n = ns_tcp_recv(0, 0, 5000);
ns_tcp_close();
if (n < 0) {
term_puts_color("curl: 连接被重置\n", ERROR_FG);
return;
}
if (n == 0) {
term_puts_color("curl: 无响应数据(超时)\n", ERROR_FG);
return;
}
/* 打印状态行 + body(截断提示) */
u32 total = ns_tcp_rx_len;
u32 show = (u32)n;
for (u32 i = 0; i < show; i++) term_putc((char)ns_tcp_rx[i]);
if (total > show) {
term_puts_color("\n[... 已截断,共 ", DIM_FG);
char nb[12]; ns_u32_dec(nb, total);
term_puts_color(nb, DIM_FG);
term_puts_color(" 字节]\n", DIM_FG);
}
term_putc('\n');
}
/* ============================================================ /* ============================================================
* run 命令:从 FAT32 根目录加载并跳转 PIE ELF 工具 * run 命令:从 FAT32 根目录加载并跳转 PIE ELF 工具
@@ -1526,6 +1417,185 @@ static void cmd_run(const char *args) {
term_redraw_all(); term_redraw_all();
} }
/* ============================================================
* PATH 查找:在 /bin 子目录中搜索 name.ELF 并执行
* 返回 1 表示找到并已处理(成功或报错),0 表示未找到
* ============================================================ */
static int path_search_and_run(const char *name, const char *args) {
(void)args; /* 参数保留供未来扩展 */
if (!g_block_read) return 0;
/* 构造 "NAME.ELF" → 8.3 名 */
char full[64];
int nl = 0;
while (name[nl] && nl < 55) nl++;
int p = 0;
for (int i = 0; i < nl; i++) full[p++] = name[i];
full[p++] = '.'; full[p++] = 'E'; full[p++] = 'L';
full[p++] = 'F'; full[p] = 0;
char n83[11];
if (name_to_83(full, n83) != 0) return 0;
/* 获取 /bin 目录首簇 */
u32 bin_clus;
if (get_bin_cluster(&bin_clus) != 0) return 0;
/* 从 /bin 子目录读取 ELF */
u8 *data = 0; u32 size = 0;
if (fat32_read_file_in_dir(bin_clus, n83, &data, &size) != 0) return 0;
/* 加载 ELF */
void *entry = 0;
int rc = sh_load_elf(data, &entry);
if (rc != 0) {
term_puts_color(name, ERROR_FG);
term_puts_color(": ELF 加载失败\n", ERROR_FG);
return 1;
}
/* 执行 */
logl("[shell] path: running /bin/ tool");
void (*fn_entry)(const dsk_boot_context *) = (void (*)(const dsk_boot_context *))entry;
fn_entry(g_boot_ctx);
logl("[shell] path: tool returned");
g_disk_loaded = 0;
term_redraw_all();
return 1;
}
/* ============================================================
* linux 命令:通过双内核兼容层执行 Linux 程序
*
* 用法:
* linux 显示兼容层状态
* linux <prog> [args] 执行 /bin/<prog>(或完整路径)
* linux ls -la → 执行 /bin/ls -la
* linux uname -a → 执行 /bin/uname -a
*
* 依赖 UTSM+Linux 双内核架构: Linux guest 作为 daemon park 在 VMX
* guest 中,shell 通过 g_lxc_svc->exec 写 IPC 请求并 vmresume 唤醒。
* ============================================================ */
/* 简单 token 分词:将 args 按空格切分为 argv[],返回 argc。
* 不支持引号转义(保持与 shell 其余部分一致的简单分词)。 */
static int split_args(const char *args, char argv[16][64], int max_argc) {
int argc = 0;
const char *p = args;
while (*p && argc < max_argc) {
while (*p == ' ') p++;
if (*p == 0) break;
int len = 0;
while (*p && *p != ' ' && len < 63) {
argv[argc][len++] = *p++;
}
argv[argc][len] = 0;
argc++;
}
return argc;
}
static void cmd_linux(const char *args) {
if (!g_lxc_svc) {
term_puts_color("linux: 兼容层服务未初始化(boot context 未提供)\n", ERROR_FG);
return;
}
if (!g_lxc_svc->is_available()) {
term_puts_color("linux: 兼容层不可用(Linux guest 未驻留或 IPC 未就绪)\n", ERROR_FG);
char status[128];
g_lxc_svc->status(status, sizeof(status));
term_puts_color(status, ERROR_FG);
term_putc('\n');
return;
}
/* 无参数:显示状态 */
while (*args == ' ') args++;
if (*args == 0) {
term_puts_color("Linux 兼容层已就绪 (双内核 park-and-resume)\n", OK_FG);
term_puts_color("用法: linux <程序> [参数...]\n", DIM_FG);
term_puts_color("示例: linux ls -la / linux uname -a / linux cat /etc/hostname\n", DIM_FG);
return;
}
/* 分词参数 */
char argv_buf[16][64];
int argc = split_args(args, argv_buf, 16);
if (argc == 0) {
term_puts_color("linux: 参数解析失败\n", ERROR_FG);
return;
}
/* 构造程序路径:
* - 以 '/' 开头视为绝对路径
* - 否则前缀 "/bin/" */
char path[160];
const char *prog = argv_buf[0];
if (prog[0] == '/') {
int i = 0;
while (prog[i] && i < 159) { path[i] = prog[i]; i++; }
path[i] = 0;
} else {
const char *prefix = "/bin/";
int i = 0;
while (prefix[i]) { path[i] = prefix[i]; i++; }
int j = 0;
while (prog[j] && i < 159) { path[i++] = prog[j++]; }
path[i] = 0;
}
/* 构造 argv 指针数组(argv[0] = 程序名) */
const char *argv_ptrs[16];
argv_ptrs[0] = prog; /* argv[0] 用程序名(不带 /bin/ 前缀) */
for (int i = 1; i < argc; i++) argv_ptrs[i] = argv_buf[i];
/* 执行:stdout 缓冲区 */
static char stdout_buf[8192];
u64 stdout_len = 0;
u64 exit_code = 0;
logl("[shell] linux: exec ");
logl(path);
int rc = g_lxc_svc->exec(path, argc, argv_ptrs,
stdout_buf, sizeof(stdout_buf) - 1,
&stdout_len, &exit_code);
if (rc != 0) {
term_puts_color("linux: 执行失败 (code=", ERROR_FG);
char num[16];
int neg = rc < 0;
unsigned int v = neg ? (unsigned int)(-rc) : (unsigned int)rc;
int n = 0;
if (v == 0) num[n++] = '0';
while (v) { num[n++] = '0' + (v % 10); v /= 10; }
if (neg) term_putc('-');
for (int i = n - 1; i >= 0; i--) term_putc(num[i]);
term_puts_color(")\n", ERROR_FG);
return;
}
/* 输出 stdout */
if (stdout_len > 0) {
stdout_buf[stdout_len] = 0;
term_puts(stdout_buf);
/* 确保末尾换行 */
if (stdout_buf[stdout_len - 1] != '\n') {
term_putc('\n');
}
}
/* 非零退出码提示 */
if (exit_code != 0) {
term_puts_color("[exit ", DIM_FG);
char ec[16];
unsigned int ev = (unsigned int)exit_code;
int en = 0;
if (ev == 0) ec[en++] = '0';
while (ev) { ec[en++] = '0' + (ev % 10); ev /= 10; }
for (int i = en - 1; i >= 0; i--) term_putc(ec[i]);
term_puts_color("]\n", DIM_FG);
}
}
static void execute_command(const char *cmd) { static void execute_command(const char *cmd) {
while (*cmd == ' ') cmd++; while (*cmd == ' ') cmd++;
if (*cmd == 0) return; if (*cmd == 0) return;
@@ -1552,14 +1622,16 @@ static void execute_command(const char *cmd) {
else if (str_eq(name, "cp")) cmd_cp(args); else if (str_eq(name, "cp")) cmd_cp(args);
else if (str_eq(name, "mv")) cmd_mv(args); else if (str_eq(name, "mv")) cmd_mv(args);
else if (str_eq(name, "rm") || str_eq(name, "del")) cmd_rm(args); else if (str_eq(name, "rm") || str_eq(name, "del")) cmd_rm(args);
else if (str_eq(name, "ping")) cmd_ping(args);
else if (str_eq(name, "curl")) cmd_curl(args);
else if (str_eq(name, "run")) cmd_run(args); else if (str_eq(name, "run")) cmd_run(args);
else if (str_eq(name, "linux")) cmd_linux(args);
else if (str_eq(name, "cd")) cmd_not_impl("cd"); else if (str_eq(name, "cd")) cmd_not_impl("cd");
else if (str_eq(name, "pwd")) { term_puts("/\n"); } else if (str_eq(name, "pwd")) { term_puts("/\n"); }
else if (str_eq(name, "whoami")) { term_puts("root\n"); } else if (str_eq(name, "whoami")) { term_puts("root\n"); }
else if (str_eq(name, "id")) { term_puts("uid=0(root) gid=0(root)\n"); } else if (str_eq(name, "id")) { term_puts("uid=0(root) gid=0(root)\n"); }
else cmd_unknown(name); /* ---- PATH 查找:未匹配内建时搜索 /bin/ ---- */
else if (!path_search_and_run(name, args)) {
cmd_unknown(name);
}
} }
/* ---- CMOS RTC 读取 ---- */ /* ---- CMOS RTC 读取 ---- */
@@ -1721,8 +1793,7 @@ static void run_dev_tests(void) {
term_puts_color("[10] ls — 确认清理\n", ACCENT_FG); term_puts_color("[10] ls — 确认清理\n", ACCENT_FG);
cmd_ls(); cmd_ls();
term_puts_color("[11] ping 10.0.2.2 — 网络回归(失败不阻断)\n", ACCENT_FG); term_puts_color("[11] ping — 外部命令(/bin/ping.elf),跳过内联测试\n", ACCENT_FG);
cmd_ping("10.0.2.2");
term_putc('\n'); term_putc('\n');
term_puts_color("=== 自动测试完成 ===\n", OK_FG); term_puts_color("=== 自动测试完成 ===\n", OK_FG);
@@ -1760,6 +1831,22 @@ void dsk_entry(const dsk_boot_context *ctx) {
if (g_block_read) logl("[shell] block_read ok"); if (g_block_read) logl("[shell] block_read ok");
if (g_block_write) logl("[shell] block_write ok"); if (g_block_write) logl("[shell] block_write ok");
/* 获取 Linux 兼容层服务(reserved[5])—— 双内核 park-and-resume */
{
u64 lxc_addr = ctx->reserved[5];
if (lxc_addr) {
const linux_compat_service *lxc = (const linux_compat_service *)lxc_addr;
if (lxc->magic == LINUX_COMPAT_MAGIC) {
g_lxc_svc = lxc;
logl("[shell] linux_compat service ok");
} else {
logl("[shell] linux_compat magic mismatch");
}
} else {
logl("[shell] linux_compat service not available");
}
}
/* 初始化风格系统渲染上下文 */ /* 初始化风格系统渲染上下文 */
du_context_init(&g_ctx, fb_a, fb_w, fb_h, fb_p); du_context_init(&g_ctx, fb_a, fb_w, fb_h, fb_p);
@@ -1782,9 +1869,13 @@ void dsk_entry(const dsk_boot_context *ctx) {
run_dev_tests(); run_dev_tests();
} }
/* 将 banner + dev test 输出刷新到 framebuffer */
term_redraw_all();
/* 主循环 */ /* 主循环 */
int shift = 0; int shift = 0;
int e0 = 0; int e0 = 0;
u64 blink_start = rdtsc_shell();
for (;;) { for (;;) {
draw_prompt(); draw_prompt();
input_len = 0; input_len = 0;
@@ -1793,15 +1884,30 @@ void dsk_entry(const dsk_boot_context *ctx) {
int prompt_len = 0; int prompt_len = 0;
while (PROMPT[prompt_len]) prompt_len++; while (PROMPT[prompt_len]) prompt_len++;
cur_col = prompt_len; cur_col = prompt_len;
term_redraw_cursor(); cur_visible = 1;
redraw_input_line();
int cmd_done = 0; int cmd_done = 0;
while (!cmd_done) { while (!cmd_done) {
/* 光标闪烁:每 ~530ms 切换一次可见性 */
if (g_tsc_per_ms) {
u64 now = rdtsc_shell();
u64 elapsed = now - blink_start;
int want_vis = (elapsed / (g_tsc_per_ms * 530)) & 1;
if (want_vis != cur_visible) {
if (want_vis) term_redraw_cursor();
else term_clear_cursor();
cur_visible = want_vis;
}
}
u8 st = inb(0x64); u8 st = inb(0x64);
if (!(st & 1)) { __asm__("pause"); continue; } if (!(st & 1)) { __asm__("pause"); continue; }
u8 data = inb(0x60); u8 data = inb(0x60);
if (st & 0x20) continue; if (st & 0x20) continue;
u8 sc = data; u8 sc = data;
/* 有键盘输入时重置闪烁,让光标保持可见 */
blink_start = rdtsc_shell();
if (!cur_visible) { cur_visible = 1; term_redraw_cursor(); }
if (sc == 0xE0) { e0 = 1; continue; } if (sc == 0xE0) { e0 = 1; continue; }
if (sc == 0x2A || sc == 0x36) { shift = 1; continue; } if (sc == 0x2A || sc == 0x36) { shift = 1; continue; }
if (sc == 0xAA || sc == 0xB6) { shift = 0; continue; } if (sc == 0xAA || sc == 0xB6) { shift = 0; continue; }
BIN
View File
Binary file not shown.
+35
View File
@@ -67,8 +67,43 @@ enum utsm_ipc_msg_type {
UTSM_MSG_ACK = 6, /* Acknowledgment */ UTSM_MSG_ACK = 6, /* Acknowledgment */
UTSM_MSG_NACK = 7, /* Negative acknowledgment */ UTSM_MSG_NACK = 7, /* Negative acknowledgment */
UTSM_MSG_SHUTDOWN = 8, /* Shutdown notification */ UTSM_MSG_SHUTDOWN = 8, /* Shutdown notification */
/* Linux compat exec protocol (UTSM → Linux → UTSM) */
UTSM_MSG_EXEC_REQUEST = 16, /* UTSM→Linux: exec a program (payload=ipc_exec_request) */
UTSM_MSG_EXEC_STDOUT = 17, /* Linux→UTSM: stdout chunk (payload=raw bytes) */
UTSM_MSG_EXEC_STDERR = 18, /* Linux→UTSM: stderr chunk (payload=raw bytes) */
UTSM_MSG_EXEC_EXIT = 19, /* Linux→UTSM: process exited (payload=ipc_exec_exit) */
UTSM_MSG_EXEC_READY = 20, /* Linux→UTSM: daemon ready to accept exec requests */
}; };
/* ===== Linux compat exec payload structures =====
*
* Flow:
* 1. UTSM writes UTSM_MSG_EXEC_REQUEST into utsm_to_linux ring,
* then calls linux_resume() to wake the parked Linux guest.
* 2. Linux daemon reads the request, fork+exec's the program,
* streams stdout/stderr back via UTSM_MSG_EXEC_STDOUT/STDERR.
* 3. Linux daemon writes UTSM_MSG_EXEC_EXIT with exit code, then HLTs (park).
* 4. UTSM reads the responses from linux_to_utsm ring, returns to caller.
*
* All strings are NUL-terminated. argv_blob contains argv[0..argc-1] each
* NUL-terminated, concatenated. path is the program path to execute. */
#define UTSM_EXEC_PATH_MAX 128
#define UTSM_EXEC_ARGV_MAX 96 /* total argv blob size */
#define UTSM_EXEC_MAX_ARGS 16
struct ipc_exec_request {
uint32_t argc; /* number of arguments */
uint32_t flags; /* reserved (0) */
char path[UTSM_EXEC_PATH_MAX]; /* program path (NUL-terminated) */
char argv_blob[UTSM_EXEC_ARGV_MAX]; /* argv strings, each NUL-terminated */
} __attribute__((packed));
struct ipc_exec_exit {
uint32_t exit_code; /* process exit status */
uint32_t reserved;
} __attribute__((packed));
/* ===== Ring buffer structures ===== */ /* ===== Ring buffer structures ===== */
/* Single IPC message (256 bytes, cache-line aligned) */ /* Single IPC message (256 bytes, cache-line aligned) */
Binary file not shown.
+14 -2
View File
@@ -43,8 +43,20 @@ verbose: yes
module_path: boot():/driver/test.fat32 module_path: boot():/driver/test.fat32
module_cmdline: dkm:test_fat32 module_cmdline: dkm:test_fat32
# Linux 6.6 LTS guest kernel (for UTSM+Linux dual-kernel architecture) # Linux 6.6 LTS guest kernel (UTSM+Linux dual-kernel Linux compat layer)
# Uncomment after building Linux via CODE/linux/build.sh # Uncomment after building Linux via CODE/linux/build.sh (requires WSL/Linux).
#
# Boot flow with these modules:
# 1. Limine loads utsm.elf + all .drv modules + bzImage + initrd
# 2. UTSM boots, init VMM/EPT, self-test
# 3. UTSM linux_loader_init() finds bzImage module, parses + maps guest
# 4. UTSM ipc_shm_init() allocates 1MB IPC shared memory (EPT-mapped)
# 5. UTSM linux_launch() → vmlaunch → Linux boots → init starts daemon
# 6. Daemon sends EXEC_READY, then ioctl(PARK) → HLT → VM-Exit → park
# 7. UTSM linux_compat_init() marks Linux compat layer ready
# 8. UTSM loads DSK (deshab.elf) → shell.elf → `linux <prog>` command
# invokes linux_compat_service->exec() → vmresume → daemon runs prog
#
# module_path: boot():/boot/linux-bzImage # module_path: boot():/boot/linux-bzImage
# module_cmdline: linux:bzImage # module_cmdline: linux:bzImage
# module_path: boot():/boot/linux-initrd.img # module_path: boot():/boot/linux-initrd.img
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+19
View File
@@ -603,6 +603,25 @@ if (-not (Test-Path $DesktopOutput)) {
} }
Write-Host "[build] desktop Output: $DesktopOutput" Write-Host "[build] desktop Output: $DesktopOutput"
# ---------- CMD (Windows-style command line + PE/EXE compat) ----------
$CmdDir = Join-Path $Root 'CODE\cmd'
$CmdOutput = Join-Path $SystemDir 'system\deshab64\cmd.elf'
Write-Host '[build] Building cmd.elf...'
try {
& $make -C "$CmdDir" -f MAKEFILE "CC=$clang" "LD=$lld"
if ($LASTEXITCODE -ne 0) {
throw "make cmd failed with exit code $LASTEXITCODE"
}
}
finally {
}
if (-not (Test-Path $CmdOutput)) {
throw "cmd build did not produce $CmdOutput"
}
Write-Host "[build] cmd Output: $CmdOutput"
# ---------- Tool applications ---------- # ---------- Tool applications ----------
$ToolsDir = Join-Path $Root 'CODE\tools' $ToolsDir = Join-Path $Root 'CODE\tools'
$ToolsOutDir = Join-Path $SystemDir 'system\deshab64\tools' $ToolsOutDir = Join-Path $SystemDir 'system\deshab64\tools'