Files
Deshab-OS/docs/上下文/250729/Deshab Linux_EXE 兼容层开发.md
2026-07-31 13:53:49 +08:00

12 KiB
Raw Permalink Blame History

Deshab Linux/EXE 兼容层开发

架构总览

桌面命令行1: shell.elf (原生系统命令行 + linux 命令委托执行)
桌面命令行2: cmd.elf  (Windows 风格命令行 + PE/EXE 兼容)

三个垂直层次:

  1. 虚拟化底座:UTSM 作为 Type-1 hypervisor,VMX/EPT 完整虚拟化,park-and-resume 机制让 Linux guest 与 DSK 时分复用 CPU
  2. 双兼容引擎:Linux 兼容路径(IPC 委托 Linux guest 执行)+ PE/EXE 兼容路径(UTSM 内置 PE loader + x86emu32 解释器)
  3. 用户界面与文件系统:shell.elf / cmd.elf / desktop.elf / FAT32 / initramfs+virtio-blk

一、PE/EXE 兼容层(UTSM 内置,CODE/UTSM/pe/)

1. pe_service.c / pe.h — 统一服务入口

  • 全局 service table(函数指针表):pe_load() / pe_run() / pe_unload()
  • PE32+ → preferred_base 加载,Ring0 原生执行(MS x64 ABI)
  • PE32 → 专用大缓冲区,x86emu32 解释执行
  • 通过 dsk_boot_context.reserved[4] 暴露给 DSK

2. pe_loader.c — PE 解析/映射/重定位

  • DOS Header → PE Header → Section Table 解析
  • PE32+:__attribute__((ms_abi)) shim,原生 Ring0 执行
  • PE32:无需重定位,直接 preferred_base 加载
  • apply_relocations(image_size) — base relocation 处理
  • pe_get_iat_entries() — 暴露 IAT 给 shim 注册
  • import 解析 → 查 shim 表 → 填充 IAT

3. pe_shim.c / pe_shim.h — Windows API 拦截

  • IAT 拦截:按 DLL!Function 名查 shim 表填充函数指针
  • shim 函数签名用 __attribute__((ms_abi))
  • __builtin_setjmp/__builtin_longjmp(void **)用于 PE 入口异常恢复
  • 每条 IAT 条目可注册 fn32(PE32)和 fn64(PE32+),try_iat_call 在 fn32=NULL 时回退到 fn64

4. x86emu32.c / x86emu32.h — x86-32 指令解释器

  • 支持指令:MOV/ADD/SUB/AND/OR/XOR/CMP/TEST, SHL/SHR/SAR(含 CL 变长), PUSH/POP, JMP/Jcc/CALL/RET, MOVSX/MOVZX, rep_prefix, ModR/M+SIB 解码
  • emu->mem 指向大缓冲区起始(虚拟地址 0),mem[preferred_base + rva] 正确寻址
  • try_iat_call — 调用 IAT 中的 shim 函数

cmd.elf(CODE/cmd/main.c)

  • Windows cmd.exe 风格命令行,从 reserved[4] 读取 pe_svc
  • 内置命令:dir, cd, type, copy, del, exit 等
  • FAT32 I/O 通过 f32_list_root() 回调 API
  • Esc 键返回 DSK,支持从 FAT32 root 加载 PE 文件执行

二、Linux 兼容层(双内核 park-and-resume)

GPA 布局

GPA 区间 用途
0x00400000 - 0x02FFFFFF initrd / boot_params
0x03000000 - 0x03FFFFFF Linux guest initrd
0x04000000 IPC 共享内存(1MB)
0x05000000+ Linux guest RAM(64MB)
0x01000000 Kernel 映射
0x00600000 GDT

VMCS / VMEXIT 处理

  • vmexit_asm.S:保存 16 个 guest GPR 到 g_guest_regs,调用 C vmexit_dispatch()
  • dispatch 返回 0 → vmresume;返回非 0 → 恢复 host RSP/返回 RIP
  • g_saved_host_rsp / g_saved_return_rip 全局变量(vmm.h 声明,vmm.c 定义)

已实现 exit reason:

Exit Reason 处理
EXIT_HLT park-and-resume:self-test 终止,Linux guest park
EXIT_EPT_VIOLATION 按需分配 HPA,区分 RAM/MMIO
EXIT_CPUID host passthrough + 屏蔽 VMX 位
EXIT_IO_INSTRUCTION COM1/PIC/PIT 模拟
EXIT_RDMSR/WRMSR MSR 读写处理
EXIT_VMCALL 9+ hypercall 分发
EXIT_INTERRUPT_WINDOW guest 开中断时注入 pending IRQ
EXIT_VMX_PREEMPTION_TIMER 1ms 周期 exit

park-and-resume 机制

  • handle_hlt 区分 self-test(终止)和 Linux guest(park)
  • Linux guest HLT → 推进 guest RIP → g_guest_parked = 1 → 返回非 0 → asm 恢复 host 上下文
  • linux_is_parked() 查询状态,linux_compat_exec() 调用 linux_resume() 唤醒
  • linux_launch() 成功后设 g_guest_parked = 1

IPC 协议

Hypercall ABI:guest RAX = 操作码,RDI/RSI/RDX = 参数,返回值写入 guest RAX

  • VMCALL 魔数 0x5554534D48430000("UTSMHC\0\0")
  • 9 种基础 op:PING/HELLO/SHM_INFO/CAP_VALIDATE/UTRW_READ/UTRW_WRITE/DRR_CHECKPOINT/CONSOLE_WRITE/CONSOLE_READ

IPC EXEC 协议(消息号 16-20):

消息号 常量 用途
16 UTSM_MSG_EXEC_REQUEST shell 请求 Linux 执行命令
17 UTSM_MSG_EXEC_STDOUT daemon 回传 stdout
18 UTSM_MSG_EXEC_STDERR daemon 回传 stderr
19 UTSM_MSG_EXEC_EXIT daemon 回传退出码
20 UTSM_MSG_EXEC_READY daemon 就绪通知

ipc_exec_request 结构体约束 ≤240 字节(适配 IPC 单消息槽)。

linux_compat 服务(CODE/UTSM/vmm/linux_compat.c)

  • exec() 实现:构建 ipc_exec_request → ipc_shm_send() → linux_resume() → 读取响应
  • 通过 dsk_boot_context.reserved[5] 暴露

shell linux 命令(CODE/shell/main.c)

  • cmd_linux 函数:linux ls -la → g_lxc_svc->exec("/bin/ls -la")
  • 支持绝对路径,Linux 未构建时显示"兼容层不可用"

virtio 模拟

  • 模型:virtio-mmio(非 PCI)
  • IRQ 路由:virtio-blk → IRQ5(0x35),virtio-net → IRQ6(0x36),公式 IRQ_vector = 0x30 + irq
  • MMIO 处理:EPT misconfig exit → 解码 guest 指令访问大小/数据 → 寄存器分发
  • QUEUE_NOTIFY 后调用 vmx_guest_queue_irq(0x30+irq) 注入中断
  • maybe_inject_irq 按 guest IMR/IF 决定投递时机

virtio-blk:桥接到 UTSM block API(ahci0 SATA 盘),8GB 容量 virtio-net:桥接到 UTSM net API,TX/RX ring 实现占位 virtio-rootfs-blk:memory-backed 后端,从 Limine boot module 加载 Arch rootfs 镜像

EPT 动态页映射

  • 4 级 EPT 页表 walk,支持 4KB/2MB/1GB
  • ept_identity_map(gpa, RWX) — 1:1 恒等映射
  • ept_gpa_to_hpa(gpa) — hypercall 访问 guest 内存
  • EPT violation handler:RAM 区按需分配 HPA,MMIO 区路由到设备模拟

Linux guest 启动流程(kernel/main.c)

  1. vmm_init() — 启用 VMX、初始化 EPT、分配 VMCS
  2. vmm_self_test() — 自测 guest vmlaunch
  3. ipc_shm_init() — 分配 1MB 共享内存、EPT 映射到 GPA 0x04000000
  4. linux_loader_init() — 加载 bzImage、setup boot_params、e820 映射
  5. linux_launch() — 配置 VMCS、virtio_mmio_init()、arm preemption timer、vmlaunch
  6. linux_compat_init() — 初始化 Linux 兼容服务
  7. dsk_load_and_jump() — 加载 DSK 主内核

cmdline 关键参数:nohlt + idle=poll(禁止 guest HLT idle),仅 daemon 显式 park 时触发 UTSM resume

Linux exec daemon(CODE/linux/initramfs/bin/utsm_exec_daemon.c)

  • 静态编译,打包进 initramfs
  • 流程:fork → exec 命令 → pipe 捕获 stdout/stderr → IPC 发送 EXEC_STDOUT/STDERR/EXIT → HLT park
  • 缺失时 init 回退到 setsid cttyhack sh(ttyS0 交互 shell)

UTSM driver(CODE/linux/patches/utsm_hcall.c)

  • /dev/utsm 字符设备,VMCALL hypercall 封装
  • SHM 映射(mmap 共享内存 GPA 0x04000000)
  • ioctl 接口:RECV_MSG / SEND_MSG / PARK / GET_READY

三、WSL 构建 Linux 内核

构建步骤

# WSL 内执行
cd ~
curl -L -o linux-6.6.tar.xz https://mirrors.tuna.tsinghua.edu.cn/kernel/v6.x/linux-6.6.tar.xz
tar xf linux-6.6.tar.xz && cd linux-6.6

# 安装 UTSM 驱动
mkdir -p drivers/utsm/include
cp /mnt/d/Code/Deshab/CODE/linux/patches/utsm_hcall.c drivers/utsm/
cp /mnt/d/Code/Deshab/CODE/linux/patches/utsm_Kconfig drivers/utsm/Kconfig
cp /mnt/d/Code/Deshab/CODE/linux/patches/utsm_Makefile drivers/utsm/Makefile
cp /mnt/d/Code/Deshab/CODE/utsm-ipc/ipc_proto.h drivers/utsm/include/
bash /mnt/d/Code/Deshab/CODE/linux/fix_driver.sh ~/linux-6.6

# 配置 + 编译
cp /mnt/d/Code/Deshab/CODE/linux/configs/utsm_x86_64_defconfig .config
make olddefconfig
make -j$(nproc) KCFLAGS='-std=gnu17' bzImage   # KCFLAGS 修复 gcc 15 C23 兼容

# 拷贝产物
mkdir -p /mnt/d/Code/Deshab/SYSTEM/boot
cp arch/x86/boot/bzImage /mnt/d/Code/Deshab/SYSTEM/boot/linux-bzImage

关键修复

  1. ipc_proto.h 条件编译:<stdint.h> 在 Linux 内核不可用,需 #ifdef __UTSM_KERNEL__ / #include <linux/types.h> 分支
  2. gcc 15 C23 兼容:bool/false 变关键字,需 KCFLAGS='-std=gnu17';顶层 Makefile -std=gnu11 改为 -std=gnu17;arch/x86/boot/compressed/ 也需同步修改
  3. WSL ext4 I/O 错误:WSL 虚拟磁盘可能损坏,需 wsl --shutdown + wsl --unregister Ubuntu + 重装
  4. WSL 网络问题:GitHub 访问被墙,需用清华镜像下载内核 tarball

initramfs 构建(build.sh / build_initrd.sh)

  • busybox 1.35.0 静态二进制下载(缓存 .cache/)
  • 内核自带 gen_init_cpio 打包(无 root、无 cpio 依赖)
  • spec 声明 /dev/console、/dev/ttyS0 节点 + 14 个 applet symlink(含 switch_root、mkdir)
  • daemon 静态编译
  • init 脚本:daemon 缺失时回退 setsid cttyhack sh(ttyS0 交互 shell,bring-up 用)

四、WHPX 嵌套虚拟化问题

问题:WHPX 下 CPUID 报告 VMX 支持但 VMXON 不可用,导致 QEMU exit code 4 不可恢复崩溃。

解决方案(vmx.c vmx_truly_available()):

  1. 检查 CPUID.01H:ECX[31] hypervisor present bit
  2. 检测 Hyper-V 签名 → 通过 CPUID 检查嵌套 VMX 支持 → 无则跳过
  3. 检测 KVM 签名 → 允许(KVM 通常支持嵌套 VMX)
  4. 未知 Hypervisor → 保守跳过
  5. run_qemu.bat:WHPX 下使用 -cpu qemu64,-vmx 禁用 VMX CPUID 标志

QEMU 验证结果:UTSM → VMM init → 检测 Hyper-V 无嵌套 VMX → 安全跳过 → 加载 DSK → shell.elf 正常运行

五、Arch rootfs 构建(第二阶段)

build_arch_rootfs.sh 关键步骤

  1. 下载 Arch bootstrap tarball(.tar.zst 格式,需 zstd 包)
  2. 解压到 WSL 原生 ext4(/tmp,避免 9P 慢速 I/O)
  3. 编译 utsm_exec_daemon 静态二进制并安装到 rootfs
  4. stripping:删除 locale(109M)/man(37M)/include(39M)/doc(13M)/info(7.3M)/.a libs → 597M→363M
  5. 创建 512MB ext4 镜像,rsync rootfs 内容
  6. 拷贝最终 rootfs.img 到 SYSTEM/boot/

内核配置确认

  • CONFIG_EXT4_FS=y, CONFIG_VIRTIO_BLK=y, CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y, CONFIG_DEVTMPFS_MOUNT=y, CONFIG_VIRTIO_NET=y

init 脚本修改

  • 挂载 /dev/vdb(Arch rootfs)→ switch_root 到 Arch
  • 保留 phase-1 回退:无 rootfs 时 ttyS0 交互 shell

limine.conf 修改

  • 添加 linux-rootfs.img boot module
  • cmdline 添加第三个 virtio_mmio.device 条目

六、Pacman 包管理方案(WSL 互操作模式)

核心矛盾

  • pacman 依赖 glibc + POSIX syscall + libalpm + libcurl + gpgme + zlib/zstd/xz + 可写 Unix 文件层级 + fork/exec
  • Deshab 是 SAS-R0 单地址空间 Ring0,无 POSIX 层、无动态链接器、无 syscall 入口

方案 C(推荐):IPC 委托执行

  • SYSTEM/bin/ 放 stub,PATH 命中后通过 IPC 委托 Linux guest 执行 /usr/bin/xxx
  • Linux 程序在 Linux guest 内原生执行,依赖 glibc + Linux syscall ABI

五阶段实现

阶段 核心任务 状态
第一阶段 Linux guest 跑到 shell 代码就绪,需真机 VT-x 验证
第二阶段 Arch rootfs + pacman + 网络 rootfs 已构建,需 VMX 环境验证
第三阶段 FILE_TRANSFER hypercall + payload_pool 分块传输 未实现
第四阶段 EXEC_FORWARD hypercall + shell 委托执行 未实现
第五阶段 desktop 动态注册 Linux 命令图标 未实现

七、已实现 vs 待实现

已实现

  • PE 兼容层完整(pe_service/loader/shim/x86emu32),零警告
  • cmd.elf + shell.elf linux 命令 + desktop 双命令行
  • park-and-resume + IPC exec 协议(消息 16-20)+ linux_compat 服务
  • Linux driver ioctl(RECV_MSG/SEND_MSG/PARK/GET_READY)+ exec daemon
  • virtio-mmio 框架 + virtio-blk/net/rootfs-blk 后端 + EPT 动态页映射
  • vmexit dispatch 接线(CPUID/IO/INT_WINDOW/PREEMPTION_TIMER)+ virtio IRQ 注入
  • WHPX 安全 VMX 检测 + 优雅回退
  • build.sh busybox initramfs 打包 + Arch rootfs 构建脚本
  • Linux bzImage(5.7MB) + initrd(1MB) + rootfs.img(512MB stripped) 已构建
  • FAT32 镜像含 CMD ELF

待实现

  • 真机 VT-x / KVM 环境验证 Linux guest 启动
  • FILE_TRANSFER / EXEC_FORWARD hypercall
  • 完整 Win32 API + .NET API 覆盖
  • virtio-net 完整 TX/RX ring
  • Arch rootfs 在 VMX 环境中实际运行验证
  • pacman 镜像源配置 + AUR helper
  • desktop 动态注册 Linux 命令图标
  • FAT32 ESP 容量扩展(当前 128MB 不够容纳 rootfs.img)