Files
Deshab-OS/docs/上下文/260805/更改桌面启动逻辑.md
2026-08-09 22:20:01 +08:00

271 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 更改桌面启动逻辑
> **Workspace:** d:\Code\Deshab
---
**User**
更改桌面启动逻辑,用来适配直接在linux下也可以直接启动系统桌面测试
**Assistant**
我先了解一下当前桌面启动逻辑的实现,然后再设计适配方案。
### Relevant Code Snippets
1. 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_RELATIVE` PIE 重定位。
2. 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`。
3. d:\Code\Deshab\CODE\dsk\main.c:L1430-L1437
— 非首次启动路径中 DSK 调度桌面:记录加载统计、写 `BOOT_06` 里程碑、调用 `dsk_run_desktop(ctx)`,这是 `deshab.elf` 启动桌面的直接入口。
4. d:\Code\Deshab\CODE\dsk\main.c:L1440-L1488
— 首次启动路径:按 `mouseInit -> netman -> FirstInit -> desktop` 顺序加载运行模块,最终在 `FirstInit` 返回后调用 `dsk_run_desktop(ctx)` 启动桌面。
5. d:\Code\Deshab\CODE\UTSM\kernel\dsk_loader.c:L221-L342
— UTSM 侧 DSK 加载器:通过 block provider 读取 FAT32,定位根目录中的 `DESHAB ELF`,按 FAT 链读取 `deshab.elf` 数据并交给 DSK 加载流程。
6. d:\Code\Deshab\CODE\UTSM\kernel\dsk_loader.c:L643-L689
— UTSM 启动 DSK 的入口逻辑:优先从 FAT32 block provider 加载 `deshab.elf`,失败则回退到 Limine boot module;校验 ELF 后加载映像、构造 boot context,然后跳转。
7. d:\Code\Deshab\SYSTEM\system\deshab64\FUCK:L76-L82
— DSK 启动行为配置:`[dsk]` 分区控制 `show_logo`、`skip_login`、`default_shell`、`mouse_init`、`netman`,影响 DSK 是否显示 Logo、是否跳过登录、是否加载鼠标/网络管理器,以及默认 shell 行为。
8. d:\Code\Deshab\CODE\desktop\main.c:L224-L233
— 桌面进程依赖的运行时资源:保存 framebuffer 地址/宽高/pitch、kernel API、block read/write 回调,以及双缓冲 sprite buffer,说明桌面启动后依赖 framebuffer 和块设备接口。
让我进一步查看桌面主代码和 DSK 加载桌面的具体逻辑。
这是个涉及架构决策的复杂任务。让我先充分探索现有的 Linux 兼容层和桌面入口逻辑,再设计适配方案。
### Relevant Code Snippets
1. 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。
2. 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` 等兼容层能力。
3. d:\Code\Deshab\CODE\UTSM\include\utsm\dsk.h:L30-L64
— `dsk_boot_context` 结构体定义;桌面入口函数接收该上下文,其中 `reserved[5]` 用于传递 Linux 兼容层服务指针。
4. d:\Code\Deshab\CODE\desktop\main.c:L21-L23
— `desktop/main.c` 包含 `dsk.h` 与 `linux_compat.h`,表明桌面代码直接依赖 DSK boot context 和 Linux 兼容层服务接口。
5. d:\Code\Deshab\CODE\desktop\main.c:L42-L50
— 桌面入口附近定义 COM1 串口 I/O、`outb/inb`、`rdtsc`,并包含 `tools/desktop_app.h` 的 Linux 桌面应用配置契约。
6. 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 兼容层服务。
7. d:\Code\Deshab\CODE\desktop\main.c:L3604-L3704
— 桌面主事件循环:轮询 PS/2 鼠标、处理按键、更新 RTC、按需重绘并 flip framebuffer,循环退出后返回 DSK。
8. d:\Code\Deshab\CODE\desktop\main.c:L891-L922
— PS/2 鼠标端口读取实现:通过 `inb(0x64)` 状态和 `inb(0x60)` 数据读取鼠标包,并更新光标位置与按键状态。
9. d:\Code\Deshab\CODE\desktop\main.c:L1157-L1320
— Linux 兼容层应用执行路径:`lnx_on_create` 创建终端窗口,调用 `g_lxc_svc->exec(...)` 同步执行 Linux 命令并收集 stdout。
10. d:\Code\Deshab\CODE\desktop\main.c:L1362-L1418
— Linux 应用注册逻辑:从 FAT32 根目录读取 `LINUXAPPCNF`,解析 Linux 命令列表,并注册为桌面 Linux 兼容层应用。
11. 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
1. d:\Code\Deshab\CODE\desktop\main.c:L42-L55
— 定义 `COM1=0x3F8`,并提供 `outb/inb` 内联端口 I/O;`sputc` 通过 `inb(COM1+5)` 等待发送缓冲区空,再 `outb(COM1,...)` 写串口日志。
2. d:\Code\Deshab\CODE\desktop\main.c:L70-L74
— `rdtsc()` 内联汇编读取 CPU 时间戳计数器,是 TSC 校准和双击间隔判定的底层来源。
3. 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` 等待。
4. d:\Code\Deshab\CODE\desktop\main.c:L630-L653
— framebuffer 直写核心:`flip_buffer()` 将 `SPRITE_BUF_ADDR` sprite buffer 完整拷贝到 `g_real_fb`;`flip_rect()` 按 pitch 计算源/目标地址并复制矩形区域,用于光标/脏矩形更新。
5. 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` 解析鼠标包。
6. 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`。
7. d:\Code\Deshab\CODE\desktop\main.c:L3604-L3700
— 主事件循环中的硬件轮询与渲染边界:循环读取 PS/2 鼠标、键盘扫描码,读取 RTC 秒 tick,根据脏矩形调用 `redraw_all()`、`flip_buffer()` 或 `flip_rect()`,最后 `pause` 等待下一轮。
8. d:\Code\Deshab\CODE\desktop\main.c:L1055-L1061
— 命令行 reboot/halt 路径直接写 `0x64` 并执行 `hlt`,属于直接硬件控制入口。
### Relevant Code Snippets
1. d:\Code\Deshab\CODE\desktop\main.c:L21-L34
— 桌面主入口直接依赖的头文件/源文件:`dsk.h`、`linux_compat.h`、`ascii_bitmaps.c`、`deshab_ui.h`、`fat32_io.h`,是追踪 Linux 用户态宿主兼容层依赖链的起点。
2. d:\Code\Deshab\CODE\desktop\main.c:L47-L50
— 桌面应用配置契约入口:包含 `tools/desktop_app.h`,并定义 `DA_NO_PORTIO` 以避免与宿主自带端口 I/O 冲突。
3. d:\Code\Deshab\CODE\UTSM\include\utsm\deshab_ui.h:L229-L243
— `du_context` 渲染上下文定义及 `du_context_init`,说明 UI 渲染 API 依赖的 framebuffer 基址、宽高、行宽参数。
4. d:\Code\Deshab\CODE\UTSM\include\utsm\deshab_ui.h:L273-L327
— 核心渲染原语:`du_pixel`、`du_pixel_read`、`du_fill_rect`、渐变填充、全屏填充等;这些都是纯内存 framebuffer 操作,不直接访问硬件。
5. d:\Code\Deshab\CODE\tools\fat32_io.h:L24-L70
— FAT32 用户态读写抽象:通过 `f32_init()` 注入 `block_read` / `block_write` 回调,并维护 `f32_disk`、`f32_cluster`、`f32_data` 缓冲。
6. d:\Code\Deshab\CODE\tools\fat32_io.h:L160-L209
— `f32_read_root_file()` 实现根目录文件读取,依赖 FAT 链跟随、目录项查找和 block read 回调,是 Linux 宿主访问 DESHAB FAT32 资产的重要逻辑。
7. d:\Code\Deshab\build.ps1:L613-L629
— `desktop.elf` 构建流程:使用 `make -C CODE/desktop`,由 `MAKEFILE` 驱动编译链接;这是桌面资产进入 `SYSTEM/system/deshab64/desktop.elf` 的路径。
8. 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 CMOS `0x70/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](file:///d:/Code/Deshab/CODE/desktop/host_main.h) — 宿主对外接口声明(日志、时钟、鼠标/键盘轮询、帧末 present、缓冲 extern)
- [host_main.c](file:///d:/Code/Deshab/CODE/desktop/host_main.c) — SDL2 宿主核心:窗口+streaming texture、GPT ESP 解析 + `deshab.img` block 后端(pread/pwrite)、鼠标/键盘事件队列、SDL_Scancode→set-1 映射、伪造 kernel_api 让现有 block 获取路径零改动
- [Makefile.linux](file:///d:/Code/Deshab/CODE/desktop/Makefile.linux) — `make -f Makefile.linux` 产出 `desktop_host`,支持 `run` 目标
- [run_desktop_host.sh](file:///d:/Code/Deshab/ISO/run_desktop_host.sh) — 检测 SDL2、编译并启动的便利脚本
### 修改文件
- [main.c](file:///d:/Code/Deshab/CODE/desktop/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 下使用
```bash
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 编译遇问题,把报错贴回来我来修。
---