Files
Deshab-OS/CODE/sdk/docs/SDK.md
T
LinehuandCursor 8554a82677 feat(panic): FUCK [panic] mode=strict|fallback + realtest image variant
- UTSM panic_full returns in fallback mode (logs [PANIC:FALLBACK] + code + hit
  count); panic_halt keeps always-halt sites (CPU exception, VMM-E11 LA57,
  VMM-E15 DSK jump, UTSM-E42 test hook). Call sites given safe continuations.
- Mode passed to DSK/FirstInit/login/desktop via DSK_BOOT_FLAG_PANIC_FALLBACK;
  DKM kernel_api.panic / kern.log.panic return to driver; ext4 fatal aborts the
  op via setjmp/longjmp and DSK falls back to FAT32 ESP.
- build.ps1/Makefile: dev=strict, release=fallback, new realtest (release
  options + strict); default -Variant all; serialized iso packing under -j.
- Fix '*/' inside comments (dkm.h, kernel_api.h, bus.c) that broke the build.
- Includes pending work: dkm_bus service bus, mt7920/wlan drivers, desktop
  files/startmenu/prank, pe-tools, diskinfo, docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-12 23:57:19 +08:00

584 lines
22 KiB
Markdown
Raw 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.
# Deshab SDK 使用文档
## 1. 概述
Deshab SDK 是 Deshab 操作系统的应用与驱动统一开发工具包。在 SAS-R0 单地址空间 Ring0 模型下,应用(`.elf`)与驱动(`.drv`)共享同一套基础类型、ABI 契约和工具函数,仅链接形式不同:
- **应用**:PIE ELF,由 DSK 加载器加载执行,入口 `dsk_entry`。
- **驱动**:ET_REL 可重定位对象,由 DKM loader 装载,导出 `driver_desc` / `driver_init` / `driver_exit`。
所有 SDK 头文件均为 `static inline` 实现,无库依赖,包含即用。
### 目录结构
```
CODE/sdk/
├── include/deshab/ SDK 头文件(单一包含入口)
│ ├── deshab.h 伞头:基础层 + ABI 层 + 应用层(不含 fat32/net)
│ ├── types.h 基础类型 u8/u16/u32/u64/i8/i16/i32/i64
│ ├── portio.h 端口 I/O(dsb_inb/dsb_outb/inw/outw/inl/outl)
│ ├── serial.h COM1 串口日志(dsb_slog/dsb_swrite/dsb_sputc)
│ ├── tsc.h TSC 校准与延时(dsb_tsc_calibrate/dsb_delay_ms)
│ ├── string.h 基础内存操作(dsb_memset/dsb_memcpy/dsb_strlen)
│ ├── kernel_api.h dkm_kernel_api ABI 结构体(字段顺序不可变)
│ ├── boot_context.h dsk_boot_context 启动上下文与入口契约
│ ├── driver.h DKM 驱动描述符与状态机定义
│ ├── block.h block provider 便捷读写层
│ ├── app.h dsb_app_context 应用上下文初始化
│ ├── fb.h 帧缓冲绘制原语(pixel/fill_rect/blend/rounded_rect)
│ ├── font.h ASCII 位图字体渲染(dsb_draw_char/dsb_draw_string)
│ ├── cursor.h 鼠标光标 save/restore/draw
│ ├── input.h PS/2 键盘扫描码转 ASCII + 鼠标初始化与轮询
│ ├── ui.h 色板常量 + 标题栏/状态栏装饰 + LINUXAPP.CNF 解析
│ ├── rtc.h CMOS RTC 时分读取
│ ├── fat32.h FAT32 读写库 + LFN 长文件名(含 256KB+4KB+256KB BSS)
│ └── net.h 用户态网络协议栈 ARP/ICMP/DNS/TCP(含 64KB BSS)
├── scaffold/ 脚手架模板
│ ├── new-module.ps1 一键创建新应用/驱动模块
│ ├── app/ 应用模板(main.c / MAKEFILE / linker.ld)
│ └── driver/ 驱动模板(main.c)
├── examples/ 示例代码
│ ├── hello-app/ 最小应用示例
│ └── hello-driver/ 最小驱动示例
└── docs/
└── SDK.md 本文档
```
---
## 2. 快速开始
### 2.1 使用脚手架创建新模块
```powershell
# 创建应用(默认输出到 CODE/tools/<Name>,产物到 SYSTEM/system/deshab64/tools/<Name>.elf)
cd d:\Code\Deshab\CODE\sdk\scaffold
.\new-module.ps1 -Name myapp
# 创建驱动(默认输出到 CODE/DKM/<Name>)
.\new-module.ps1 -Name mydriver -Type driver -Class DKM_CLASS_NET -Stage 3
```
脚本自动计算相对路径并替换模板占位符,生成 `main.c` / `MAKEFILE` / `linker.ld`(应用)或 `main.c`(驱动)。
可选参数:
| 参数 | 说明 | 默认值 |
|------|------|--------|
| `-Name` | 模块名(必填) | — |
| `-Type` | `app` 或 `driver` | `app` |
| `-OutDir` | 输出目录 | app→`CODE/tools/$Name`,driver→`CODE/DKM/$Name` |
| `-Class` | 驱动类别 `DKM_CLASS_*` | `DKM_CLASS_MISC` |
| `-Stage` | 驱动加载阶段 0-3 | `3` |
### 2.2 构建命令
**应用**(需要 clang + ld.lld + make,make 需 `sh.exe` 在 PATH 中):
```powershell
cd CODE\tools\myapp # 或 CODE\sdk\examples\hello-app
make # 构建到 SYSTEM/system/deshab64/tools/myapp.elf
make clean # 清理
```
**驱动**(两步:编译 + 链接为可重定位对象):
```powershell
cd CODE\DKM\mydriver
clang -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin `
-fno-stack-protector -fno-pic -fno-pie -mcmodel=kernel `
-mno-red-zone -mno-sse -mno-sse2 -mno-mmx -msoft-float -m64 `
-Wall -Wextra -I..\sdk\include -O2 -c main.c -o mydriver.o
ld.lld -r -o mydriver.drv mydriver.o
```
> 提示:项目根目录的 `build.ps1` 会批量构建所有驱动并打包镜像,日常开发只需 `.\build.bat`。
---
## 3. 应用开发
### 3.1 入口契约
DSK 加载 `.elf` 后调用 `dsk_entry(dsk_boot_context *ctx)`。应用必须:
1. **校验 magic**:`ctx->magic == DSK_BOOT_MAGIC`(`0x44534B31424F4F54`,即 `"DSK1BOOT"`)。
2. **初始化上下文**:调用 `dsb_app_init(&ac, ctx)` 提取 framebuffer、block、kernel_api。
3. (可选)校验 `ctx->abi_version == DSK_BOOT_ABI_VERSION`。
```c
#include "../../../firstInit/ascii_bitmaps.c" /* 提供字体位图数据 */
#include "deshab/deshab.h"
#include "deshab/font.h" /* 需先有位图数据源 */
void dsk_entry(const dsk_boot_context *ctx) {
if (ctx->magic != DSK_BOOT_MAGIC) return;
dsb_app_context ac;
dsb_app_init(&ac, ctx);
/* ... 你的逻辑 ... */
}
```
### 3.2 dsb_app_context
`dsb_app_init` 从 boot context 一次性提取应用常用数据:
| 字段 | 类型 | 来源 |
|------|------|------|
| `fb` | `u32*` | `ctx->framebuffer_address`(32bpp BGRA) |
| `fb_w` | `u64` | `ctx->framebuffer_width` |
| `fb_h` | `u64` | `ctx->framebuffer_height` |
| `fb_pitch` | `u64` | `ctx->framebuffer_pitch` |
| `block` | `dsb_block` | 从 `ctx->dkm_kernel_api + DSB_KAPI_OFF_BLOCK` 解析 |
| `api` | `const dkm_kernel_api*` | `ctx->dkm_kernel_api` |
### 3.3 绘制 API
所有绘制函数以 `dsb_app_context*` 为首参,假设 32bpp BGRA 帧缓冲:
| 函数 | 说明 |
|------|------|
| `dsb_fill_bg(ac, color)` | 全屏填充 |
| `dsb_fill_rect(ac, x, y, w, h, color)` | 矩形填充 |
| `dsb_fill_rounded_rect(ac, x, y, w, h, color, radius)` | 圆角矩形填充 |
| `dsb_rect_outline(ac, x, y, w, h, color, radius)` | 矩形描边 |
| `dsb_pixel(ac, x, y, color)` | 单像素(自动越界保护) |
| `dsb_pixel_read(ac, x, y)` | 读单像素 |
| `dsb_blend(bg, fg, alpha)` | Alpha 混合(0-255) |
| `dsb_draw_char(ac, ch, x, y, fg, bg)` | 单字符(8 级灰度抗锯齿) |
| `dsb_draw_string(ac, s, x, y, fg, bg, step)` | 字符串(step=字间距,12 为常规) |
| `dsb_draw_titlebar(ac, title, w)` | 标题栏(含关闭按钮 + 分隔线) |
| `dsb_draw_statusbar(ac, text, w, h)` | 底部状态栏 |
**色板常量**(`ui.h`):
| 常量 | 值 | 用途 |
|------|----|------|
| `DSB_BG_PRIMARY` | `0xFF0A1428` | 主背景(深蓝) |
| `DSB_BG_SECONDARY` | `0xFF0F1E38` | 次背景(标题栏/状态栏) |
| `DSB_TEXT_PRIMARY` | `0xFFE8E8F0` | 主文字 |
| `DSB_TEXT_DIM` | `0xFF6A6A88` | 暗淡文字 |
| `DSB_ACCENT` | `0xFF00A8CC` | 强调色 |
| `DSB_ERROR` | `0xFFFF4466` | 错误/关闭按钮 |
| `DSB_SUCCESS` | `0xFF40C880` | 成功 |
| `DSB_WARNING` | `0xFFF0A030` | 警告 |
**字体前置条件**:`font.h` 依赖 `g_ascii[95]` / `g_ascii_w` / `g_ascii_h` 三个符号,必须先 `#include "ascii_bitmaps.c"`(或自定义位图源)再包含 `font.h`。
### 3.4 输入 API
**键盘**(轮询模式,scan code set 1):
```c
u8 st = dsb_inb(0x64);
if (st & 1) {
u8 sc = dsb_inb(0x60);
char ch = dsb_scan_to_ascii(sc, shift_pressed);
/* sc == 1 为 Esc,sc == 0x36/0x2A 为 Shift */
}
```
**鼠标**(PS/2 轮询模式):
```c
dsb_mouse mouse;
dsb_cursor cursor;
dsb_mouse_init(); /* 初始化 AUX 端口 + 流模式 */
dsb_cursor_init(&cursor, ac.fb_w, ac.fb_h);
/* 主循环中 */
if (dsb_mouse_poll(&mouse, &cursor, ac.fb_w, ac.fb_h)) {
/* cursor.mx / cursor.my / cursor.btn 已更新 */
dsb_cursor_save(&ac, &cursor); /* 先恢复旧位置背景 */
dsb_cursor_restore(&ac, &cursor); /* (需先 save 过) */
dsb_cursor_draw(&ac, &cursor, DSB_CURSOR_COLOR);
}
```
> 注意:`dsb_mouse_poll` 先检查 AUX 位(`0x20`)再读数据,避免吞掉键盘扫描码。
### 3.5 FAT32 与网络(按需引入)
`fat32.h` 和 `net.h` 因含较大 static 缓冲(分别约 516KB 和 64KB BSS),**不在** `deshab.h` 伞头中默认包含,需显式 `#include`:
```c
#include "deshab/deshab.h"
#include "deshab/fat32.h" /* 需要文件读写时 */
#include "deshab/net.h" /* 需要网络时 */
```
**FAT32 用法**:
```c
/* 从 block API 初始化(block_read/write 来自 kernel_api) */
dsb_block blk;
dsb_block_init(&blk, ctx->dkm_kernel_api);
f32_init(blk.read, blk.write);
/* 读根目录文件 */
u8 *data; u32 size;
char name11[11];
f32_name_to_83("CONFIG.TXT", name11);
if (f32_read_root_file(name11, &data, &size) == 0) {
/* data 指向 f32_data 内部缓冲,size 为字节数 */
}
/* 写文件 */
f32_write_root_file(name11, my_data, my_size);
/* 长路径 LFN 读取(支持子目录) */
if (f32_read_path_lfn("system/deshab64/FUCK", &data, &size) == 0) { ... }
```
**网络用法**(QEMU slirp 默认拓扑):
```c
ns_init(ctx->dkm_kernel_api); /* 绑定第一个有线 tx/rx ready 设备 */
ns_apply_lease_from_ctx((u64)ctx); /* 应用 netman DHCP 租约(若有) */
u32 ip;
if (ns_dns_resolve("example.com", &ip) == 0) {
u32 rtt; u8 ttl;
if (ns_ping(ip, 1, 3000, &rtt, &ttl) == 0) { /* ping 成功 */ }
}
/* TCP client */
if (ns_tcp_connect(ip, 80, 5000) == 0) {
ns_tcp_send((const u8*)"GET / HTTP/1.0\r\n\r\n", 18);
u8 buf[4096];
int n = ns_tcp_recv(buf, sizeof(buf), 5000);
ns_tcp_close();
}
```
---
## 4. 驱动开发
### 4.1 三符号契约
DKM 驱动为 ET_REL 可重定位对象(`.drv`),必须导出三个符号:
| 符号 | 类型 | 说明 |
|------|------|------|
| `driver_desc` | `const dkm_driver_desc` | 描述符(magic/类别/阶段/依赖/提供) |
| `driver_init` | `int (*)(const dkm_kernel_api *api, dkm_driver_handle *handle)` | 初始化,返回 0 成功 |
| `driver_exit` | `int (*)(dkm_driver_handle *handle)` | 卸载清理,返回 0 成功 |
三个符号均需 `__attribute__((visibility("default")))` 以确保不被隐藏。
### 4.2 driver_desc 字段
```c
const dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC, /* 0x444B4D31 "DKM1",必须 */
.abi_version = DKM_ABI_VERSION, /* 1 */
.desc_size = sizeof(dkm_driver_desc),
.name = "hello",
.version = "1.0",
.vendor = "Deshab",
.driver_class = DKM_CLASS_MISC, /* 类别,见下表 */
.stage = 3, /* 加载阶段 0-3 */
.flags = 0, /* DKM_F_* 标志 */
.priority = 100,
.depends = g_depends, /* 依赖的 provides 名 */
.depends_count = 0,
.provides = g_provides, /* 本驱动提供的能力名 */
.provides_count = 1,
.min_kernel_abi = DKM_KERNEL_API_VERSION,
.feature_bits = 0,
};
```
**驱动类别**(`driver.h`):
| 常量 | 值 | 说明 |
|------|----|------|
| `DKM_CLASS_PLATFORM` | 1 | 平台发现 |
| `DKM_CLASS_BUS` | 2 | 总线(PCI) |
| `DKM_CLASS_INTERRUPT` | 3 | 中断控制器 |
| `DKM_CLASS_TIMER` | 4 | 计时器 |
| `DKM_CLASS_CONSOLE` | 5 | 控制台/帧缓冲 |
| `DKM_CLASS_STORAGE` | 6 | 存储(AHCI/NVMe) |
| `DKM_CLASS_FS` | 7 | 文件系统 |
| `DKM_CLASS_NET` | 8 | 网络 |
| `DKM_CLASS_INPUT` | 9 | 输入(键鼠) |
| `DKM_CLASS_GPU` | 10 | GPU |
| `DKM_CLASS_MISC` | 11 | 杂项 |
**驱动标志**(`flags`):
| 常量 | 说明 |
|------|------|
| `DKM_F_REQUIRED` | 当前 stage 失败则 DRR recovery 或 panic |
| `DKM_F_BOOT_MODULE` | 可由 bootloader 预加载 |
| `DKM_F_NO_UNLOAD` | 不允许卸载 |
| `DKM_F_STRONG_RECOVERY` | data 段使用 UTSM 强恢复策略 |
| `DKM_F_DMA_REQUIRED` | 需要 DMA API |
| `DKM_F_EARLY_LOG` | init 期间允许 early log |
### 4.3 driver_init / driver_exit
```c
int driver_init(const dkm_kernel_api *api, dkm_driver_handle *handle) {
(void)handle;
/* 校验 kernel_api 可用性 */
if (!api || !api->log) return -1; /* 返回负数=失败 */
/* 通过 kernel_api 调用内核服务,不直接依赖内核符号 */
api->log->info("[hello] init");
/* 注册 IRQ、映射 MMIO、注册 block/net 设备等 */
return 0;
}
int driver_exit(dkm_driver_handle *handle) {
(void)handle;
/* 清理资源 */
return 0;
}
```
> `required` 驱动 init 失败会触发 DRR recovery 或 panic;非 required 驱动失败仅标记为 `DKM_STATE_FAILED` 并继续。
### 4.4 dkm_kernel_api 使用
驱动通过 `dkm_kernel_api` 调用内核服务,**不直接依赖任意内核符号**。主要能力:
| 字段 | 类型 | 用途 |
|------|------|------|
| `log` | `const dkm_log_api*` | 日志(info/warn/error/panic) |
| `dma` | `const dkm_dma_api*` | DMA 缓冲分配 |
| `net` | `const dkm_net_api*` | 网络设备注册/收发 |
| `block` | `const dkm_block_api*` | block 设备注册/读写 |
| `mmio` | `const dkm_mmio_api*` | MMIO 映射查询 |
| `mm_map_mmio` | `fn` | MMIO 独立窗口映射(PCD\|PWT) |
| `mm_unmap_mmio` | `fn` | 解除 MMIO 窗口映射 |
| `irq_register` | `fn` | 注册 IRQ handler |
| `register_apic_eoi` | `fn` | 注册 LAPIC EOI 钩子 |
| `irq_vector_alloc/free` | `fn` | 动态 IDT 向量分配(MSI/MSI-X) |
| `rsdp_address` | `const void*` | ACPI RSDP 物理地址 |
| `fb_address` / `fb_*` | — | 帧缓冲信息 |
| `hhdm_offset` | `u64` | 物理→虚拟偏移 |
| `boot_modules_response` | `const void*` | Limine boot module 响应 |
### 4.5 manifest 注册
驱动构建为 `.drv` 后,需在 `SYSTEM/driver/manifest.json` 注册:
```json
{
"name": "hello",
"path": "driver/misc/hello.drv",
"class": "misc",
"required": false,
"depends": [],
"provides": ["hello"]
}
```
条目放在对应 stage 的 `drivers` 数组中(stage 0-3)。`required: true` 的驱动 init 失败会触发 DRR recovery 或 panic。
如需 bootloader 预加载(stage0/stage1),还需在 `SYSTEM/boot/limine.conf` 添加 `module_path`。
### 4.6 服务总线(dkm_bus · D6 万物互联)
模块间通信不再走 `dsk_boot_context.reserved[]` 硬偏移,统一经 `api->bus` 按名注册-消费。**driver_init 里注册服务是模块的立身之本**:
```c
/* ---- 提供方:在 driver_init 里注册 ---- */
static const mouse_state_t *mouse_poll_fn(void) { return &g_mouse_state; }
int driver_init(const dkm_kernel_api *api, dkm_driver_handle *handle) {
/* ... 硬件初始化 ... */
/* 注册服务:名字必须 srv. 前缀,version 是你的契约版本 */
api->bus->register_service("srv.input.mouse.poll", 1, (void *)mouse_poll_fn);
return 0;
}
/* ---- 消费方:lookup(硬依赖,缺席即 panic 莲花屏) ---- */
void *fn; u32 ver;
api->bus->lookup("srv.input.mouse.poll", &fn, &ver);
const mouse_state_t *(*poll)(void) = (const mouse_state_t *(*)(void))fn;
/* ---- 消费方:probe(可选能力,缺席返回 -1 自己处理) ---- */
if (api->bus->probe("srv.fs.ext4.read", &fn, &ver) != 0) {
/* 无 ext4 服务——走设计内回退路径 */
}
```
**命名空间**:`kern.*` 仅内核可注册(log/dma/irq/mm/apic/drr/block/pe/lxc/config/load_by_name 等 22 条起步);`srv.*` 仅模块可注册。
**失败策略(零降级铁律)**:
| 操作 | 失败时 | 语义 |
|------|--------|------|
| `register_service` 名字非法/重名/表满 | BUS-E01/E02/E03 panic | 编程错误 |
| `lookup` 未命中 | BUS-E04 panic | 硬依赖未满足=编程错误 |
| `probe` 未命中 | 返回 -1 | 能力缺席=设计内双路径 |
| `unregister_service` 违规 | BUS-E05 panic | 生命周期违规 |
**"运行"也是服务**:长期模块把主循环入口注册为 `srv.<mod>.run`,由会话排序者(session.drv)按总线调用拉起。
完整设计见 [docs/RE/万物互联与服务总线设计.md](../../../docs/RE/万物互联与服务总线设计.md)。
---
## 5. 头文件索引
### 基础层
| 头文件 | 用途 | 关键 API |
|--------|------|----------|
| `types.h` | 基础类型 | `u8/u16/u32/u64/i8/i16/i32/i64/NULL` |
| `portio.h` | 端口 I/O | `dsb_inb/dsb_outb/dsb_inw/dsb_outw/dsb_inl/dsb_outl` |
| `serial.h` | COM1 串口日志 | `dsb_slog(tag,msg)` / `dsb_swrite(s)` / `dsb_sputc(c)` |
| `tsc.h` | TSC 校准与延时 | `dsb_tsc_calibrate()` / `dsb_rdtsc()` / `dsb_delay_ms/us()` |
| `string.h` | 基础内存操作 | `dsb_memset/dsb_memcpy/dsb_strlen` |
### ABI 层
| 头文件 | 用途 | 关键 API |
|--------|------|----------|
| `kernel_api.h` | kernel_api ABI 结构体 | `dkm_kernel_api` / `dkm_log_api` / `dkm_dma_api` / `dkm_net_api` / `dkm_block_api` / `dkm_mmio_api` |
| `boot_context.h` | 启动上下文 | `dsk_boot_context` / `DSK_BOOT_MAGIC` / `dsk_entry_fn` / `probe_info` / `net_lease_info` |
| `driver.h` | 驱动描述符 | `dkm_driver_desc` / `DKM_DRIVER_MAGIC` / `DKM_CLASS_*` / `DKM_F_*` / `dkm_driver_handle` |
| `block.h` | block 便捷层 | `dsb_block` / `dsb_block_init()` / `dsb_block_read/write()` |
### 应用层
| 头文件 | 用途 | 关键 API |
|--------|------|----------|
| `app.h` | 应用上下文 | `dsb_app_context` / `dsb_app_init()` |
| `fb.h` | 帧缓冲绘制 | `dsb_pixel/fill_rect/fill_bg/fill_rounded_rect/rect_outline/blend` |
| `font.h` | 字体渲染 | `dsb_draw_char/dsb_draw_string`(需先提供 `g_ascii` 位图源) |
| `cursor.h` | 鼠标光标 | `dsb_cursor` / `dsb_cursor_init/save/restore/draw` |
| `input.h` | 键鼠输入 | `dsb_scan_to_ascii()` / `dsb_mouse` / `dsb_mouse_init/poll()` |
| `ui.h` | 色板与装饰 | `DSB_BG_PRIMARY` 等色板 / `dsb_draw_titlebar/statusbar` / `dsb_linuxapp_parse()` |
| `rtc.h` | RTC 时钟 | `dsb_rtc_time(h, m)` |
### 领域层(按需包含,含大 static 缓冲)
| 头文件 | 用途 | BSS 占用 | 关键 API |
|--------|------|----------|----------|
| `fat32.h` | FAT32 读写 + LFN | ~516KB | `f32_init/read_root_file/write_root_file/delete_root_file/list_root/list_dir/read_path_lfn/write_path_lfn` |
| `net.h` | 网络协议栈 | ~64KB | `ns_init/ping/dns_resolve/tcp_connect/tcp_send/tcp_recv/tcp_close` |
### 伞头
| 头文件 | 包含范围 |
|--------|----------|
| `deshab.h` | 基础层 + ABI 层 + 应用层(不含 `fat32.h` / `net.h` / `font.h`) |
> `font.h` 需先提供位图数据源(`#include "ascii_bitmaps.c"`),故不在伞头中默认包含。
---
## 6. ABI 约束
### 6.1 kernel_api 布局不可变
`dkm_kernel_api` 结构体的**字段顺序和类型不可调整**。UTSM 端按固定偏移填充各 API 指针,DKM loader 和 DSK 按相同偏移读取。修改字段顺序会破坏所有已编译的驱动和应用。
### 6.2 字段只追加
新增能力只允许在结构体**末尾追加**字段(尾部追加保持 ABI 兼容)。旧驱动访问不到新字段不受影响;新驱动可通过 `api->size` 判断字段是否存在。
### 6.3 偏移常量
供不便通过结构体解引用的场景(如早期 boot context 解析、汇编代码)使用,消除散落的硬编码偏移:
| 常量 | 值 | 对应字段 |
|------|----|----------|
| `DSB_KAPI_OFF_NET` | `0x48` | `const dkm_net_api *net` |
| `DSB_KAPI_OFF_BLOCK` | `0xA8` | `const dkm_block_api *block` |
常规代码应直接通过 `api->net` / `api->block` 访问,仅在早期启动或指针不可解引用时使用偏移常量。
### 6.4 dsk_boot_context 同理
`dsk_boot_context` 的 `reserved[8]` 槽位有约定索引:
| 索引 | 常量 | 用途 |
|------|------|------|
| 4 | `DSB_BOOT_RESERVED_PE_SERVICE` | PE/EXE 兼容层服务指针 |
| 5 | `DSB_BOOT_RESERVED_LINUX_COMPAT` | Linux 兼容层服务指针 |
| 6 | `DSB_BOOT_RESERVED_PROBE_INFO` | 插桩 probe 缓冲指针 |
| 7 | `DSB_BOOT_RESERVED_NET_LEASE` | netman 网络租约指针 |
---
## 7. 构建参数速查
### 7.1 应用(PIE ELF)
应用编译为 PIE ELF,由 DSK 的 PIE ELF loader 加载(支持 `R_X86_64_RELATIVE` 重定位)。
**clang 编译参数**:
```
-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 # 未启用 FPU/SSE 前必须
-m64
-Wall -Wextra
-I<sdk/include> # SDK 头文件路径
-O2
```
**ld.lld 链接参数**:
```
-nostdlib
-static
-pie
-z max-page-size=0x1000
-T linker.ld # PIE ELF 布局,ENTRY(dsk_entry)
```
**linker.ld 布局**:text(PF_R\|PF_X)→ rodata(PF_R)→ data(PF_R\|PF_W)→ .rela.dyn → .dynamic → .bss(NOBITS)。
### 7.2 驱动(ET_REL)
驱动编译为可重定位对象(ET_REL),由 DKM loader 装载并做 ELF64 relocation(`R_X86_64_64/32/32S/PC32`)。
**clang 编译参数**(与应用的差异):
```
-fno-pic -fno-pie # 不可重定位代码(非 PIE)
-mcmodel=kernel # 内核代码模型
# 无 -fpie,无 linker.ld,无链接步骤
```
其余参数(`-target -std -ffreestanding -fno-builtin -mno-red-zone -mno-sse ...`)与应用一致。
**ld.lld 链接参数**:
```
-r # 合并为单个可重定位对象(不生成可执行文件)
-o <name>.drv
```
### 7.3 参数差异对照
| 参数 | 应用 | 驱动 |
|------|------|------|
| 位置无关 | `-fpie` | `-fno-pic -fno-pie` |
| 代码模型 | (默认 small) | `-mcmodel=kernel` |
| 链接 | `-nostdlib -static -pie -T linker.ld` | `-r`(仅合并) |
| 产物 | PIE ELF(`.elf`) | ET_REL(`.drv`) |
| 入口 | `dsk_entry` | `driver_desc` / `driver_init` / `driver_exit` |
| 重定位 | `R_X86_64_RELATIVE`(加载时) | `R_X86_64_64/32/32S/PC32`(装载时) |
### 7.4 通用约束
- **进入 C 前必须 `cli/cld`**(由 loader 保证)。
- **未启用 FPU/SSE 前编译必须** `-mno-sse -mno-sse2 -mno-mmx -msoft-float`。
- **DATA/BSS 段使用 `PF_R|PF_W|PF_X`**(SAS-R0 下驱动模块内存需可执行)。
- **无 libc**:所有内存操作使用 `dsb_memset/dsb_memcpy/dsb_strlen`,不可调用标准库函数。