17 KiB
更改桌面启动逻辑
Workspace: d:\Code\Deshab
User
更改桌面启动逻辑,用来适配直接在linux下也可以直接启动系统桌面测试
Assistant
我先了解一下当前桌面启动逻辑的实现,然后再设计适配方案。
Relevant Code Snippets
-
d:\Code\Deshab\CODE\dsk\main.c:L1055-L1163 — DSK 主内核中的 ELF 加载器:校验
desktop.elf/模块 ELF 的 magic、机器类型、program headers、PT_LOAD 段和 entry point,将 ELF 映射到 8MB 缓冲,并应用R_X86_64_RELATIVEPIE 重定位。 -
d:\Code\Deshab\CODE\dsk\main.c:L1166-L1190 — DSK 加载并运行 ELF 模块的核心链路:
dsk_load_and_run()从 FAT32 根目录按 8.3 名读取文件,调用dsk_load_elf(),然后跳转到 ELF entry;dsk_run_desktop()专门加载DESKTOP ELF,即desktop.elf。 -
d:\Code\Deshab\CODE\dsk\main.c:L1430-L1437 — 非首次启动路径中 DSK 调度桌面:记录加载统计、写
BOOT_06里程碑、调用dsk_run_desktop(ctx),这是deshab.elf启动桌面的直接入口。 -
d:\Code\Deshab\CODE\dsk\main.c:L1440-L1488 — 首次启动路径:按
mouseInit -> netman -> FirstInit -> desktop顺序加载运行模块,最终在FirstInit返回后调用dsk_run_desktop(ctx)启动桌面。 -
d:\Code\Deshab\CODE\UTSM\kernel\dsk_loader.c:L221-L342 — UTSM 侧 DSK 加载器:通过 block provider 读取 FAT32,定位根目录中的
DESHAB ELF,按 FAT 链读取deshab.elf数据并交给 DSK 加载流程。 -
d:\Code\Deshab\CODE\UTSM\kernel\dsk_loader.c:L643-L689 — UTSM 启动 DSK 的入口逻辑:优先从 FAT32 block provider 加载
deshab.elf,失败则回退到 Limine boot module;校验 ELF 后加载映像、构造 boot context,然后跳转。 -
d:\Code\Deshab\SYSTEM\system\deshab64\FUCK:L76-L82 — DSK 启动行为配置:
[dsk]分区控制show_logo、skip_login、default_shell、mouse_init、netman,影响 DSK 是否显示 Logo、是否跳过登录、是否加载鼠标/网络管理器,以及默认 shell 行为。 -
d:\Code\Deshab\CODE\desktop\main.c:L224-L233 — 桌面进程依赖的运行时资源:保存 framebuffer 地址/宽高/pitch、kernel API、block read/write 回调,以及双缓冲 sprite buffer,说明桌面启动后依赖 framebuffer 和块设备接口。
让我进一步查看桌面主代码和 DSK 加载桌面的具体逻辑。
这是个涉及架构决策的复杂任务。让我先充分探索现有的 Linux 兼容层和桌面入口逻辑,再设计适配方案。
Relevant Code Snippets
-
d:\Code\Deshab\CODE\UTSM\include\utsm\linux_compat.h:L4-L18 — Linux 兼容层服务接口说明:UTSM 侧通过 IPC/shared memory 向 Linux daemon 发送 exec 请求,并经由
reserved[5]暴露给 shell/cmd/desktop。 -
d:\Code\Deshab\CODE\UTSM\include\utsm\linux_compat.h:L24-L96 —
linux_compat_service完整结构体定义,包含is_available、exec、file_list、file_read、file_write、file_pull、file_push、status等兼容层能力。 -
d:\Code\Deshab\CODE\UTSM\include\utsm\dsk.h:L30-L64 —
dsk_boot_context结构体定义;桌面入口函数接收该上下文,其中reserved[5]用于传递 Linux 兼容层服务指针。 -
d:\Code\Deshab\CODE\desktop\main.c:L21-L23 —
desktop/main.c包含dsk.h与linux_compat.h,表明桌面代码直接依赖 DSK boot context 和 Linux 兼容层服务接口。 -
d:\Code\Deshab\CODE\desktop\main.c:L42-L50 — 桌面入口附近定义 COM1 串口 I/O、
outb/inb、rdtsc,并包含tools/desktop_app.h的 Linux 桌面应用配置契约。 -
d:\Code\Deshab\CODE\desktop\main.c:L3517-L3561 — 桌面主入口
dsk_entry(const dsk_boot_context *ctx):校验 boot context,初始化 framebuffer/block API,并从ctx->reserved[5]加载 Linux 兼容层服务。 -
d:\Code\Deshab\CODE\desktop\main.c:L3604-L3704 — 桌面主事件循环:轮询 PS/2 鼠标、处理按键、更新 RTC、按需重绘并 flip framebuffer,循环退出后返回 DSK。
-
d:\Code\Deshab\CODE\desktop\main.c:L891-L922 — PS/2 鼠标端口读取实现:通过
inb(0x64)状态和inb(0x60)数据读取鼠标包,并更新光标位置与按键状态。 -
d:\Code\Deshab\CODE\desktop\main.c:L1157-L1320 — Linux 兼容层应用执行路径:
lnx_on_create创建终端窗口,调用g_lxc_svc->exec(...)同步执行 Linux 命令并收集 stdout。 -
d:\Code\Deshab\CODE\desktop\main.c:L1362-L1418 — Linux 应用注册逻辑:从 FAT32 根目录读取
LINUXAPPCNF,解析 Linux 命令列表,并注册为桌面 Linux 兼容层应用。 -
d:\Code\Deshab\CODE\tools\desktop_app.h:L433-L496 —
DA_LINUXAPP_*常量与da_linuxapp_parse完整实现,用于解析LINUXAPP.CNF的显示名|linux命令配置。
这是个架构级改动。我先查一下项目记忆中是否有相关历史,然后进入计划模式设计方案。
我已经理清了现状:
- 桌面
desktop.elf是 freestanding 裸机 ELF,入口dsk_entry(ctx),直接依赖:framebuffer 显存直写、PS/2 鼠标/键盘端口 I/O(inb(0x64/0x60))、COM1 串口、RTC CMOS、rdtsc/cli/hlt/pause、kernel_api block 接口读写 FAT32。 - 没有任何 Linux 宿主代码。
要在 Linux 下直接跑桌面测试,需要引入硬件抽象层 + Linux 宿主。这是个多文件架构改动,有多种实现方式,我先进入计划模式设计方案并和你确认。
现在进入计划模式的第一阶段:全面梳理桌面代码的硬件依赖与可复用资产。我并行启动探索代理。
Relevant Code Snippets
-
d:\Code\Deshab\CODE\desktop\main.c:L42-L55 — 定义
COM1=0x3F8,并提供outb/inb内联端口 I/O;sputc通过inb(COM1+5)等待发送缓冲区空,再outb(COM1,...)写串口日志。 -
d:\Code\Deshab\CODE\desktop\main.c:L70-L74 —
rdtsc()内联汇编读取 CPU 时间戳计数器,是 TSC 校准和双击间隔判定的底层来源。 -
d:\Code\Deshab\CODE\desktop\main.c:L444-L475 — RTC/CMOS 直接访问点:
rtc_read通过outb(0x70, register)+inb(0x71)读取秒/分/时/日/月/年;rtc_day_sec()转换为当天秒;tsc_calibrate()用 RTC 秒和rdtsc()测量 TSC/秒,并用pause等待。 -
d:\Code\Deshab\CODE\desktop\main.c:L630-L653 — framebuffer 直写核心:
flip_buffer()将SPRITE_BUF_ADDRsprite buffer 完整拷贝到g_real_fb;flip_rect()按 pitch 计算源/目标地址并复制矩形区域,用于光标/脏矩形更新。 -
d:\Code\Deshab\CODE\desktop\main.c:L823-L923 — PS/2 鼠标直接访问点:
ps2_wait_write/read轮询0x64状态并pause;ps2_drain读取0x60清空缓冲区;ps2_mouse_init()通过0x64/0x60配置鼠标;ps2_mouse_poll()读取0x64和0x60解析鼠标包。 -
d:\Code\Deshab\CODE\desktop\main.c:L3517-L3568 — boot entry 中的硬件初始化顺序:
cli关中断,读取dsk_boot_context的 framebuffer/kernel API/blocks,设置g_real_fb和g_fb.fb,调用f32_init、tsc_calibrate、rtc_day_sec、ps2_mouse_init。 -
d:\Code\Deshab\CODE\desktop\main.c:L3604-L3700 — 主事件循环中的硬件轮询与渲染边界:循环读取 PS/2 鼠标、键盘扫描码,读取 RTC 秒 tick,根据脏矩形调用
redraw_all()、flip_buffer()或flip_rect(),最后pause等待下一轮。 -
d:\Code\Deshab\CODE\desktop\main.c:L1055-L1061 — 命令行 reboot/halt 路径直接写
0x64并执行hlt,属于直接硬件控制入口。
Relevant Code Snippets
-
d:\Code\Deshab\CODE\desktop\main.c:L21-L34 — 桌面主入口直接依赖的头文件/源文件:
dsk.h、linux_compat.h、ascii_bitmaps.c、deshab_ui.h、fat32_io.h,是追踪 Linux 用户态宿主兼容层依赖链的起点。 -
d:\Code\Deshab\CODE\desktop\main.c:L47-L50 — 桌面应用配置契约入口:包含
tools/desktop_app.h,并定义DA_NO_PORTIO以避免与宿主自带端口 I/O 冲突。 -
d:\Code\Deshab\CODE\UTSM\include\utsm\deshab_ui.h:L229-L243 —
du_context渲染上下文定义及du_context_init,说明 UI 渲染 API 依赖的 framebuffer 基址、宽高、行宽参数。 -
d:\Code\Deshab\CODE\UTSM\include\utsm\deshab_ui.h:L273-L327 — 核心渲染原语:
du_pixel、du_pixel_read、du_fill_rect、渐变填充、全屏填充等;这些都是纯内存 framebuffer 操作,不直接访问硬件。 -
d:\Code\Deshab\CODE\tools\fat32_io.h:L24-L70 — FAT32 用户态读写抽象:通过
f32_init()注入block_read/block_write回调,并维护f32_disk、f32_cluster、f32_data缓冲。 -
d:\Code\Deshab\CODE\tools\fat32_io.h:L160-L209 —
f32_read_root_file()实现根目录文件读取,依赖 FAT 链跟随、目录项查找和 block read 回调,是 Linux 宿主访问 DESHAB FAT32 资产的重要逻辑。 -
d:\Code\Deshab\build.ps1:L613-L629 —
desktop.elf构建流程:使用make -C CODE/desktop,由MAKEFILE驱动编译链接;这是桌面资产进入SYSTEM/system/deshab64/desktop.elf的路径。 -
d:\Code\Deshab\SYSTEM\system\deshab64
— 构建产物目录,包含desktop.elf、shell.elf、deshab.elf、cmd.elf、FUCK等,是 FAT32/ESP 镜像中 Linux 宿主需要访问的桌面及相关 ELF 资产。
信息已经比较充分。让我读取几个关键实现细节,确认 HAL 边界设计可行。
我已经完全摸清了硬件访问边界。桌面代码分层很清晰:
- 渲染层(
du_context系列 +flip_buffer/flip_rect):纯内存像素操作,可原样复用 - FAT32 层(
f32_init注入 block 回调):纯回调驱动,可原样复用 - 硬件访问点(需抽象):COM1 串口日志、PS/2 鼠标
inb(0x64/0x60)、PS/2 键盘扫描码、RTC CMOS0x70/0x71、rdtsc/tsc_calibrate、cli/hlt/pause、framebuffer flip 目标地址、reboot/halt
这意味着只要把约 10 个硬件访问函数 + 几条内联汇编做编译期替换,桌面 UI 主体逻辑就能在 Linux 用户态跑起来。在设计最终方案前,有几个关键决策需要你拍板。
方案确定:SDL2 + 直读 deshab.img + 编译期 #ifdef。让我再确认几个实施细节(链接脚本、types 兼容性、镜像内容、是否有遗漏的硬件点),然后产出最终计划。
所有实施细节都已确认。关键发现:
types.h是纯 typedef,Linux 用户态完全兼容fat32_io.h是 static inline 注入回调库,可原样复用deshab_ui.h渲染原语纯内存操作,可原样复用linker.ld是裸机 PIE 脚本,Linux 宿主用普通 gcc 链接即可- desktop 的 block 路径走
ctx->dkm_kernel_api + 0xA8,宿主只需伪造一个 kernel_api 结构即可让现有代码零改动取到宿主 block 函数
现在写最终计划文件。
计划已写好。我来通知你审阅。
计划已批准。开始实施。先建立任务清单,然后精确定位 main.c 中所有需要改动的位置。
现在精确定位 main.c 中所有 __asm__ 出现位置和关键全局变量定义,确保 HAL_* 宏替换无遗漏。
改动点已全部定位。让我确认双击判定的 TSC 赋值位置,以及 build.ps1 中 ESP 分区偏移(决定 host block 后端实现)。
ESP 分区起始 LBA=2048(1MB 对齐),类型 GUID c12a7328-...。双击 TSC 赋值在 L3320 g_last_click_tsc = rdtsc(),host 下用 host_now_us() 替换即可。
设计全部确认。开始写代码。先写 host_main.h。
host_main.h 完成。现在写核心宿主实现 host_main.c。
host_main.c 完成。现在改 main.c。先确认 rtc_read 是否在别处调用,以及 swrite 的使用范围,确保 #ifdef 包裹无遗漏。
rtc_read 在 L2387 另有调用。让我看那个调用点,host 下也需提供 rtc_read 实现。
rtc_read 用于状态栏完整日期时间,host 下用 localtime 提供实现。现在开始批量编辑 main.c。先处理顶部平台层(HAL 宏、outb/inb/rdtsc/SPRITE_BUF_ADDR/sputc)。
顶部平台层完成。现在处理 RTC、tsc_calibrate(含 pause→HAL_PAUSE)。
PS/2 鼠标块需要整体 #ifdef 包裹。让我先确认当前确切文本。
现在替换整个 PS/2 鼠标块为 #ifdef 分支。
PS/2 块完成。现在并行处理剩余的 __asm__ 替换:reboot/halt、dsk_entry 的 cli/hlt、键盘轮询、主循环末尾、anim_delay、busy_delay。
现在处理键盘轮询循环和主循环末尾 pause——这两个是 host 模式事件接入的关键点。
所有 main.c 编辑完成。让我验证没有遗漏的 __asm__,并确认 #ifdef 配对正确。
有几处 __asm__ 似乎未替换。让我确认当前实际内容。
奇怪——anim_delay、reboot/halt、dsk_entry 的修改似乎未持久化。让我重新读 dsk_entry 确认当前状态,然后重新应用这些编辑。
确认这 3 处仍是原始 __asm__。重新应用这些编辑。
这次都生效了。再次验证剩余 __asm__ 是否都在裸机分支内。
所有 __asm__ 现在都在裸机 #else 分支内,host 编译不会触及。main.c 改动完成。
现在写 Makefile.linux。
Makefile.linux 完成。现在写便利脚本 run_desktop_host.sh。
便利脚本完成。现在做验证。先检查 #ifdef DESHAB_HOST 配对正确性,然后尝试裸机编译回归。
9 个 #ifdef / 9 个 #else / 9 个 #endif 完全配对。让我列出所有位置确认覆盖完整。
只有 9 个,但键盘轮询的 #ifdef 不在列表里。让我确认键盘轮询是否生效。
键盘轮询的编辑也未持久化。重新应用。
键盘轮询修复完成。现在做最终验证:确认 #ifdef 配对完整,然后尝试裸机语法检查(验证回归不影响裸机编译)。
10 个 #ifdef / 10 个 #endif,配对完整。现在用 clang 做裸机语法检查,验证回归安全(不带 -DDESHAB_HOST)。
clang 路径不对。让我找 clang 实际位置。
找到了 clang。现在做裸机语法检查,验证 #ifdef 裸机分支完整。
裸机语法检查通过(零错误零警告),回归安全。现在验证 host 分支语法(用 -DDESHAB_HOST,Windows 下可检查 main.c 逻辑,SDL2 部分留待 Linux)。
host 分支语法检查通过——仅 6 个 warning(localtime 在 Windows MSVC 下的安全提示、host 模式下未使用的裸机辅助函数/变量),零 error。这些 warning 在 Linux 下不会出现(localtime 非 deprecated)或无害。
接口一致性也确认匹配。现在做完整裸机编译链接,确保 desktop.elf 回归正常。
裸机编译链接成功,产物 153560 字节,与现有 desktop.elf 完全一致——字节级回归零影响。清理临时文件。
所有任务完成。更新最终状态。
已完成 Linux 桌面宿主适配。下面是变更总结。
改动概览
通过编译期 #ifdef DESHAB_HOST 切换,桌面 UI 主体逻辑(渲染、FAT32、窗口管理、事件处理)原样复用同一份 main.c,仅替换硬件访问点。裸机 desktop.elf 字节级零影响。
新增文件
- host_main.h — 宿主对外接口声明(日志、时钟、鼠标/键盘轮询、帧末 present、缓冲 extern)
- host_main.c — SDL2 宿主核心:窗口+streaming texture、GPT ESP 解析 +
deshab.imgblock 后端(pread/pwrite)、鼠标/键盘事件队列、SDL_Scancode→set-1 映射、伪造 kernel_api 让现有 block 获取路径零改动 - Makefile.linux —
make -f Makefile.linux产出desktop_host,支持run目标 - run_desktop_host.sh — 检测 SDL2、编译并启动的便利脚本
修改文件
- main.c — 10 处
#ifdef DESHAB_HOST分支 +HAL_CLI/HAL_HLT/HAL_PAUSE宏替换所有散落__asm__:- 平台层(HAL 宏、outb/inb/rdtsc/SPRITE_BUF_ADDR)
- 串口日志 sputc/swrite/slog → host_log/fprintf
- RTC → localtime、TSC → clock_gettime(微秒)
- PS/2 鼠标 → host_mouse_poll、键盘轮询 → host_kb_poll
- reboot → exit(0)、主循环末尾 pause → host_pump_and_present
验证结果
- 裸机回归:clang 完整编译链接
desktop.elf,产物 153560 字节,与现有镜像完全一致,10 个#ifdef/#endif全配对,所有__asm__仅在裸机#else分支内 - host 语法:
-DDESHAB_HOST下 main.c 语法检查零 error(6 个 warning 均为 host 模式下未使用的裸机辅助符号 + Windows MSVC 的 localtime 安全提示,Linux 下不出现)
在 Linux 下使用
sudo apt install libsdl2-dev # 一次性安装依赖
./ISO/run_desktop_host.sh # 编译并启动,默认读 ISO/deshab.img
# 或手动:
cd CODE/desktop && make -f Makefile.linux && ./desktop_host --img ../../ISO/deshab.img
宿主会打开 1280×720 SDL 窗口,直读 deshab.img 的 GPT ESP 分区作为 FAT32 block 后端,鼠标/键盘由 SDL 事件注入。首次启动需先在 Windows 下 build.bat 生成 ISO/deshab.img(确保 firstInit.txt 已是 1、USER.CONF 已存在,从而直接进桌面)。
注意:
host_main.c的完整编译需在 Linux 下进行(依赖 SDL2 头),Windows 仅做了语法检查。若 Linux 编译遇问题,把报错贴回来我来修。