Record networking and DMA development progress

Add the current OS source tree, build scripts, system image layout, and development notes covering DMA page allocation, e1000 bring-up, net API dispatch, and DHCP work in progress.
This commit is contained in:
xyou
2026-07-02 16:17:09 +08:00
parent fbc14631e3
commit f1a2a110d7
182 changed files with 16472 additions and 0 deletions
+691
View File
@@ -0,0 +1,691 @@
# DKM 驱动模块系统
```text
DKM = Deshab Kernel Module
DSM = Driver Startup Manager
```
DKM 是 Deshab 内核的驱动模块系统,负责在内核启动时加载 `SYSTEM/driver` 下的 ELF64 `.drv` 驱动模块,并把驱动注册到内核服务体系中。
当前实现状态:CODE/UTSM 内核已接入完整 DKM/DSM 驱动加载系统。内置 `console_early` + manifest.json 解析 + Limine boot module 预加载 + 4 stage 分阶段加载。全部 14 个外部 `.drv` 已完成 ET_REL 装载全链路:ELF64 校验、符号扫描、section 拷贝到 arena、SHT_NOBITS 清零、R_X86_64_64/32/32S/PC32 重定位、driver_desc magic 校验、外部 driver_init 调用进入 ACTIVE。当前镜像还预加载 `driver/test.fat32` 作为 FAT32 驱动测试镜像。
Linux/Windows 已编译驱动不能直接作为 DKM 驱动使用。真实驱动必须按本文件定义的 DKM ABI 编译,导出 `driver_desc`、`driver_init`、`driver_exit`,并只通过 `dkm_kernel_api` 调用内核服务。
当前真实驱动进度:14/14。
```text
stage0: timer, apic, acpi, pci
stage1: console_fb, ahci, nvme, bootfs
stage2: vfs, devfs, fat32
stage3: ps2kbd, e1000, virtio_net
```
manifest 中 14 个外部 `.drv` 均已替换为真实 DKM 驱动并可加载执行。当前 IDT/PIC/IRQ 基础设施已在内核侧实现,`apic` 已完成 APIC discovery 并保留 PIC IRQ 路由,`ahci` 已完成 PCI/ABAR/HBA/port discovery,并通过 `kernel_api.dma.alloc_pages` 接入早期低位 DMA buffer,支持 SATA disk IDENTIFY 与 LBA0 READ 最小路径;识别 SATA disk 后可向 `kernel_api.block` 注册 `ahci0` block provider。`fat32` 已优先通过 block provider 读取 FAT32 镜像,无设备或 BPB 无效时回退 boot module。`nvme` 已完成 PCI discovery 并能识别 QEMU NVMe 控制器;由于当前 QEMU BAR0 位于 4G 以上,NVMe MMIO register 读取等待高位 PCI MMIO 映射能力。`ps2kbd` 和 `e1000` 已通过 `kernel_api.irq_register` 验证 IRQ handler 注册路径。`virtio_net` 已完成 PCI discovery 和 modern virtio capability 枚举,尚未进行 feature negotiation / virtqueue / RX-TX。
下一阶段 DKM/驱动路线:
```text
P0: 物理页分配器 + 页表/MMIO 映射接口
P1: DMA buffer/屏障约定 + AHCI/NVMe block 数据路径
P2: IDT 256 vectors + vector allocator + APIC/IOAPIC/MSI IRQ backend
P3: e1000 与 virtio_net RX/TX 数据路径
P4: FAT32 接入真实 block provider,替代 test.fat32 启动镜像
P5: 驱动 ABI 公共头、warning 清理、QEMU 场景自动化
```
---
## 1. 模块目标
DKM 的目标:
```text
1. 从 SYSTEM/driver/manifest.json 读取驱动清单。
2. 按 stage 分阶段加载驱动。
3. 支持 ELF64 .drv 模块加载和重定位。
4. 提供稳定的 driver_desc ABI。
5. 通过 dkm_kernel_api 向驱动暴露内核服务。
6. 支持 stage0/stage1 boot module 早期加载。
7. 将驱动内存纳入 UTSM。
8. 将驱动状态和恢复操作纳入 DRR。
```
---
## 2. 系统目录约定
打包为 IMG 后,`SYSTEM` 是系统根目录。
```text
SYSTEM/
boot/
utsm.elf
limine.conf
driver/
manifest.json
platform/
timer.drv
apic.drv
acpi.drv
bus/
pci.drv
block/
ahci.drv
nvme.drv
fs/
bootfs.drv
vfs.drv
fat32.drv
devfs.drv
net/
e1000.drv
virtio_net.drv
input/
ps2kbd.drv
console/
console_fb.drv
```
当前驱动清单:
```text
SYSTEM/driver/manifest.json
```
---
## 3. 启动阶段
DKM 使用分阶段加载。
```text
stage0: platform
timer / apic / acpi / pci
建立平台发现、中断、总线和基础计时能力。
stage1: boot
console / block / bootfs
建立启动日志、块设备和启动文件访问能力。
stage2: filesystem
vfs / fat32 / devfs
建立完整 VFS 和可挂载文件系统。
stage3: optional
net / input / gpu
加载网络、输入、图形等非启动关键驱动。
```
规则:
```text
1. stage0/stage1 可由 bootloader 预加载为 boot module。
2. stage2/stage3 默认从 SYSTEM/driver 加载。
3. required=true 的驱动失败时进入 DRR recovery 或 panic。
4. required=false 的驱动失败时标记 FAILED 并继续启动。
```
---
## 4. driver_desc ABI
每个 `.drv` 必须导出三个符号:
```text
driver_desc
driver_init
driver_exit
```
### 4.1 常量
```c
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1
```
`0x444B4D31` 表示:
```text
DKM1
```
### 4.2 driver_desc 结构
```c
struct dkm_driver_desc {
uint32_t magic;
uint16_t abi_version;
uint16_t desc_size;
const char *name;
const char *version;
const char *vendor;
uint32_t driver_class;
uint32_t stage;
uint32_t flags;
uint32_t priority;
const char *const *depends;
uint32_t depends_count;
const char *const *provides;
uint32_t provides_count;
uint64_t min_kernel_abi;
uint64_t feature_bits;
uint64_t reserved0;
uint64_t reserved1;
};
```
### 4.3 driver_class
```text
DKM_CLASS_PLATFORM
DKM_CLASS_BUS
DKM_CLASS_INTERRUPT
DKM_CLASS_TIMER
DKM_CLASS_CONSOLE
DKM_CLASS_STORAGE
DKM_CLASS_FS
DKM_CLASS_NET
DKM_CLASS_INPUT
DKM_CLASS_GPU
DKM_CLASS_MISC
```
### 4.4 flags
```text
DKM_F_REQUIRED
当前 stage 中失败则进入 DRR recovery 或 panic。
DKM_F_BOOT_MODULE
可由 bootloader 预加载。
DKM_F_NO_UNLOAD
不允许卸载。
DKM_F_STRONG_RECOVERY
驱动 data/bss 段使用 UTSM 强恢复策略。
DKM_F_DMA_REQUIRED
驱动需要 DMA API。
DKM_F_EARLY_LOG
驱动 init 期间允许使用 early log。
```
---
## 5. 驱动入口
```c
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle);
int driver_exit(struct dkm_driver_handle *handle);
```
约定:
```text
1. driver_init 返回 0 表示成功。
2. driver_init 返回负数表示失败。
3. driver_exit 仅用于非 DKM_F_NO_UNLOAD 驱动。
4. required 驱动失败会触发 DRR recovery 或 panic。
5. optional 驱动失败会被标记为 FAILED。
```
---
## 6. kernel_api ABI
驱动默认不直接依赖任意内核符号,而是通过 `dkm_kernel_api` 调用内核服务。
```c
#define DKM_KERNEL_API_VERSION 1
struct dkm_kernel_api {
uint32_t version;
uint32_t size;
uint64_t feature_bits;
const struct dkm_log_api *log;
const void *mem;
const void *utsm;
const void *irq;
const void *pci;
const void *dma;
const void *vfs;
const void *net;
const void *timer;
const void *drr;
const void *rsdp_address;
const void *fb_address;
uint64_t fb_width;
uint64_t fb_height;
uint64_t fb_pitch;
uint16_t fb_bpp;
const void *boot_modules_response;
int (*irq_register)(uint8_t irq, void *handler);
uint64_t hhdm_offset;
};
```
### 6.1 log API
```c
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
```
### 6.2 memory API
```c
struct dkm_mem_api {
void *(*alloc)(uint64_t size, uint32_t flags);
void (*free)(void *ptr);
void *(*alloc_pages)(uint32_t order, uint32_t flags);
void (*free_pages)(void *ptr, uint32_t order);
void *(*mmio_map)(uint64_t phys, uint64_t size, uint32_t flags);
void (*mmio_unmap)(void *virt, uint64_t size);
};
```
### 6.3 UTSM API
```c
struct dkm_utsm_api {
int (*create_segment)(uint64_t size, uint32_t flags, struct utsm_capability *out);
int (*read)(struct utsm_capability cap, uint64_t off, void *dst, uint64_t len);
int (*write)(struct utsm_capability cap, uint64_t off, const void *src, uint64_t len);
int (*pin)(struct utsm_capability cap, uint64_t off, uint64_t len, void **window);
int (*unpin)(void *window, uint32_t flags);
};
```
### 6.4 当前平台直通能力
当前内核已通过 `dkm_kernel_api` 直接暴露早期平台信息和 IRQ/HHDM 能力:
```text
rsdp_address Limine RSDP 地址,用于 ACPI 驱动
fb_address/width/height Limine framebuffer 信息,用于 console_fb
fb_pitch/fb_bpp framebuffer 行跨度和像素格式
boot_modules_response Limine module response,用于 bootfs/fat32 测试镜像
irq_register 注册 PIC IRQ0–15 handler,用于 ps2kbd/e1000
hhdm_offset physical → virtual direct map,用于 PCI BAR MMIO
```
### 6.5 IRQ / PCI / DMA API
```c
struct dkm_irq_api {
int (*register_irq)(uint32_t vector, int (*handler)(void *ctx), void *ctx, uint32_t flags);
int (*unregister_irq)(uint32_t vector);
void (*ack)(uint32_t vector);
};
struct dkm_pci_api {
int (*scan)(int (*cb)(const struct pci_device *dev, void *ctx), void *ctx);
int (*enable_device)(const struct pci_device *dev);
uint64_t (*bar_phys)(const struct pci_device *dev, uint32_t bar);
uint64_t (*bar_size)(const struct pci_device *dev, uint32_t bar);
};
struct dkm_dma_api {
int (*alloc)(uint64_t size, uint32_t flags, struct dkm_dma_buffer *out);
void (*free)(struct dkm_dma_buffer *buf);
int (*sync_for_device)(struct dkm_dma_buffer *buf);
int (*sync_for_cpu)(struct dkm_dma_buffer *buf);
};
```
---
## 7. ELF64 .drv Loader
第一版仅支持 x86_64 ELF64 小型内核模型。
### 7.1 必须支持的 relocation
```text
R_X86_64_64
绝对 64-bit 地址重定位。
R_X86_64_RELATIVE
base + addend。
R_X86_64_GLOB_DAT
GOT 符号地址。
R_X86_64_JUMP_SLOT
PLT 函数地址。
```
### 7.2 建议支持的 relocation
```text
R_X86_64_PC32
32-bit PC-relative 调用。
R_X86_64_PLT32
PLT-relative 调用。
R_X86_64_32 / R_X86_64_32S
仅允许确认地址范围安全时使用。
```
### 7.3 第一版禁止
```text
TLS relocation
IFUNC
lazy binding
外部动态库依赖
用户态 libc 依赖
异常展开表强依赖
```
### 7.4 加载流程
```text
DKM_ELF_LOAD(path_or_boot_module)
1. 读取 ELF header。
2. 校验 ELFCLASS64 / EM_X86_64 / endian / ABI。
3. 读取 program headers 或 section headers。
4. 计算模块内存大小和对齐。
5. 通过 UTSM 创建 code/data 段。
6. 加载 PT_LOAD 或 SHF_ALLOC section。
7. 清零 .bss。
8. 解析 symbol table。
9. 解析 relocation section。
10. 解析内核导出符号和 dkm_kernel_api。
11. 执行 relocation。
12. 查找 driver_desc / driver_init / driver_exit。
13. 设置 code 段 READ|EXEC|SEALED。
14. 设置 data 段 READ|WRITE|STRONG_RECOVERY。
15. 返回 module handle。
```
---
## 8. manifest.json 格式
路径:
```text
SYSTEM/driver/manifest.json
```
顶层结构:
```json
{
"schema": "deshab.driver.manifest.v1",
"root": "SYSTEM",
"driverRoot": "SYSTEM/driver",
"format": "elf64-drv",
"abi": {},
"policy": {},
"stages": []
}
```
驱动项示例:
```json
{
"name": "pci",
"path": "driver/bus/pci.drv",
"class": "bus",
"required": true,
"depends": ["irq"],
"provides": ["pci"]
}
```
路径规则:
```text
manifest 中的 path 相对 SYSTEM 根目录。
SYSTEM/driver/manifest.json 内的 driver/bus/pci.drv 指向 SYSTEM/driver/bus/pci.drv。
stage0/stage1 驱动允许来自 boot module。
stage2/stage3 驱动默认从 SYSTEM/driver 加载。
```
---
## 9. 驱动加载状态机
正常加载:
```text
DISCOVERED
-> QUEUED
-> DEP_WAIT
-> LOADING
-> ELF_CHECKED
-> MEMORY_ALLOCATED
-> RELOCATED
-> ABI_CHECKED
-> INITING
-> ACTIVE
```
失败状态:
```text
FAILED_ELF
FAILED_RELOCATION
FAILED_DEPENDENCY
FAILED_ABI
FAILED_INIT
FAILED_REQUIRED
```
卸载状态:
```text
ACTIVE
-> QUIESCING
-> EXITING
-> UNLOADING
-> UNLOADED
```
DRR 恢复状态:
```text
ACTIVE
-> SUSPENDED_BY_DRR
-> RECOVERING
-> REINITING
-> ACTIVE
```
---
## 10. DSM 加载策略
```text
DSM_LOAD_ALL()
1. 读取 SYSTEM/driver/manifest.json。
2. 校验 schema / abi / policy。
3. 按 stage 顺序加载。
4. 每个 stage 内按 priority 排序。
5. 检查 depends 是否已由 provides 满足。
6. 未满足依赖的驱动进入 DEP_WAIT。
7. 每轮加载成功后更新 provides set。
8. 一轮后仍 DEP_WAIT 的 required 驱动进入 FAILED_REQUIRED。
9. optional 驱动失败只记录状态。
```
required 失败策略:
```text
stage0/stage1 required 失败:
DRR report_fault -> boot fallback -> panic / system rollback
stage2 required 失败:
DRR recovery -> fallback 到 bootfs 或只读模式
stage3 optional 失败:
mark FAILED -> continue boot
```
---
## 11. stage0/stage1 boot module 方案
stage0/stage1 不应依赖普通 VFS。
bootloader 应预加载:
```text
SYSTEM/driver/manifest.json
SYSTEM/driver/platform/timer.drv
SYSTEM/driver/platform/acpi.drv
SYSTEM/driver/platform/apic.drv
SYSTEM/driver/bus/pci.drv
SYSTEM/driver/console/console_fb.drv
SYSTEM/driver/fs/bootfs.drv
SYSTEM/driver/test.fat32
```
可选预加载:
```text
SYSTEM/driver/block/ahci.drv
SYSTEM/driver/block/nvme.drv
SYSTEM/driver/fs/vfs.drv
SYSTEM/driver/fs/devfs.drv
SYSTEM/driver/fs/fat32.drv
SYSTEM/driver/net/e1000.drv
SYSTEM/driver/net/virtio_net.drv
SYSTEM/driver/input/ps2kbd.drv
```
boot module 表:
```c
struct dkm_boot_module {
const char *path;
void *base;
uint64_t size;
uint32_t type;
uint32_t flags;
uint64_t checksum;
};
struct dkm_boot_module_table {
uint32_t count;
struct dkm_boot_module modules[];
};
```
查找规则:
```text
DSM_LOAD_DRIVER(path)
1. 如果 path 在 boot module table 中,直接从内存加载。
2. 否则如果 VFS 已可用,从 SYSTEM/path 加载。
3. 否则返回 BOOT_MODULE_NOT_FOUND。
```
---
## 12. 与 UTSM / DRR 的关系
### 12.1 UTSM 内存策略
```text
驱动 text:READ | EXEC | SEALED
驱动 rodata:READ | SEALED
驱动 data:READ | WRITE | STRONG_RECOVERY
驱动 bss:READ | WRITE | STRONG_RECOVERY
驱动 DMA:DMA | PINNED,必要时 CIPHERTEXT_DMA 或 NO_ENCRYPT
```
### 12.2 DRR 记录项
```text
driver name
stage
state
module memory range
provided services
recovery ops
init result
last fault
```
### 12.3 recovery ops
```c
struct dkm_driver_recovery_ops {
int (*quiesce)(void *ctx);
int (*reset)(void *ctx);
int (*reinit)(void *ctx);
int (*dump_state)(void *ctx, void *buf, uint64_t len);
};
```
DRR recovery 顺序:
```text
quiesce -> UTSM rollback -> device reset -> driver reinit -> resume
```
---
## 13. 第一版实现清单
```text
1. manifest.json parser
2. boot module table lookup
3. ELF64 header 校验
4. ELF64 section/program loading
5. relocation 处理
6. driver_desc 校验
7. kernel_api table 初始化
8. depends/provides resolver
9. staged loader
10. driver state table
11. DRR driver fault reporting
12. UTSM module memory allocation
```
---
## 14. 相关文件
```text
SYSTEM/driver/manifest.json
驱动启动清单。
RE/驱动模块ABI设计.md
DKM ABI 详细设计。
CODE/UTSM/README.md
UTSM 与驱动加载的整合说明。
```
+298
View File
@@ -0,0 +1,298 @@
/* DKM ACPI Driver - RSDP scan / RSDT parse / table enumeration
* Stage 0, optional, provides "acpi".
* Scans BIOS memory for RSDP, then walks RSDT/XSDT to list all ACPI tables.
*/
#include <stdint.h>
/* ---------------------------------------------------------------
* DKM ABI types
* --------------------------------------------------------------- */
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_kernel_api {
u32 version;
u32 size;
u64 feature_bits;
const struct dkm_log_api *log;
const void *mem;
const void *utsm;
const void *irq;
const void *pci;
const void *dma;
const void *vfs;
const void *net;
const void *timer;
const void *drr;
const void *rsdp_address;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic;
u16 abi_version;
u16 desc_size;
const char *name;
const char *version;
const char *vendor;
u32 driver_class;
u32 stage;
u32 flags;
u32 priority;
const char *const *depends;
u32 depends_count;
const char *const *provides;
u32 provides_count;
u64 min_kernel_abi;
u64 feature_bits;
u64 reserved0;
u64 reserved1;
};
/* ---------------------------------------------------------------
* ACPI structures
* --------------------------------------------------------------- */
typedef struct __attribute__((packed)) {
char signature[8];
u8 checksum;
char oem_id[6];
u8 revision;
u32 rsdt_addr;
} acpi_rsdp_v1;
typedef struct __attribute__((packed)) {
/* RSDP v1 fields */
char signature[8];
u8 checksum;
char oem_id[6];
u8 revision;
u32 rsdt_addr;
/* RSDP v2+ fields */
u32 length;
u64 xsdt_addr;
u8 ext_checksum;
u8 reserved[3];
} acpi_rsdp_v2;
typedef struct __attribute__((packed)) {
char signature[4];
u32 length;
u8 revision;
u8 checksum;
char oem_id[6];
char oem_table_id[8];
u32 oem_revision;
u32 creator_id;
u32 creator_revision;
} acpi_sdt_header;
/* ---------------------------------------------------------------
* Driver descriptor
* --------------------------------------------------------------- */
static const char *const g_provides[] = { "acpi" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC,
.abi_version = DKM_ABI_VERSION,
.desc_size = sizeof(struct dkm_driver_desc),
.name = "acpi",
.version = "0.1.0",
.vendor = "Deshab",
.driver_class = 1, /* DKM_CLASS_PLATFORM */
.stage = 0,
.flags = 0, /* optional */
.priority = 0,
.depends = NULL,
.depends_count = 0,
.provides = g_provides,
.provides_count = 1,
.min_kernel_abi = 1,
.feature_bits = 0,
.reserved0 = 0,
.reserved1 = 0
};
/* ---------------------------------------------------------------
* Helpers
* --------------------------------------------------------------- */
static const struct dkm_log_api *g_log;
static u32 min_u32(u32 a, u32 b) { return a < b ? a : b; }
static int memneq(const char *a, const char *b, u32 n) {
for (u32 i = 0; i < n; i++) {
if (a[i] != b[i]) return 1;
}
return 0;
}
static u8 checksum8(const u8 *data, u32 len) {
u8 sum = 0;
for (u32 i = 0; i < len; i++) {
sum += data[i];
}
return sum;
}
static void log_hex(const char *prefix, u64 val) {
static const char hex[] = "0123456789abcdef";
char buf[32];
u32 pos = 0;
while (pos < 30) { buf[pos] = 0; pos++; }
pos = 0;
buf[pos++] = '0';
buf[pos++] = 'x';
for (int i = 15; i >= 0; i--) {
buf[pos++] = hex[(val >> (i * 4)) & 0xf];
}
buf[pos] = 0;
/* manual concat via serial_write-like approach: pass prefix then buf */
g_log->info(prefix);
g_log->info(buf);
}
/* ---------------------------------------------------------------
* RSDP scan
* --------------------------------------------------------------- */
static const acpi_rsdp_v2 *acpi_find_rsdp(const void *limine_rsdp) {
/* If Limine gave us the RSDP, use it directly */
if (limine_rsdp) {
const acpi_rsdp_v2 *rsdp = (const acpi_rsdp_v2 *)limine_rsdp;
if (memneq(rsdp->signature, "RSD PTR ", 8) == 0) {
if (checksum8((const u8 *)rsdp, 20) == 0) {
return rsdp;
}
}
}
/* EBDA: extended BIOS data area, base at 0x40E */
{
u16 ebda_seg = *(const volatile u16 *)(uintptr_t)0x40E;
u64 ebda_base = (u64)ebda_seg << 4;
if (ebda_base >= 0x80000ULL && ebda_base < 0x100000ULL) {
for (u64 off = 0; off < 1024; off += 16) {
const acpi_rsdp_v2 *rsdp = (const acpi_rsdp_v2 *)(uintptr_t)(ebda_base + off);
if (off + sizeof(acpi_rsdp_v1) > 1024) break;
if (memneq(rsdp->signature, "RSD PTR ", 8) == 0) {
if (checksum8((const u8 *)rsdp, 20) == 0) {
return rsdp;
}
}
}
}
}
/* BIOS read-only area: 0x000E0000 - 0x000FFFFF */
for (u64 addr = 0x000E0000ULL; addr < 0x00100000ULL; addr += 16) {
const acpi_rsdp_v2 *rsdp = (const acpi_rsdp_v2 *)(uintptr_t)addr;
if (memneq(rsdp->signature, "RSD PTR ", 8) == 0) {
if (checksum8((const u8 *)rsdp, 20) == 0) {
return rsdp;
}
}
}
return NULL;
}
/* ---------------------------------------------------------------
* Table enumeration
* --------------------------------------------------------------- */
static void acpi_enumerate_rsdt(const acpi_sdt_header *rsdt, u32 entry_size) {
u32 entry_count = (rsdt->length - sizeof(acpi_sdt_header)) / entry_size;
const u8 *entries = (const u8 *)rsdt + sizeof(acpi_sdt_header);
g_log->info("[acpi] tables found");
for (u32 i = 0; i < entry_count; i++) {
u64 addr;
if (entry_size == 4) {
addr = (u64)((const u32 *)entries)[i];
} else {
addr = ((const u64 *)entries)[i];
}
if (addr == 0) continue;
const acpi_sdt_header *hdr = (const acpi_sdt_header *)(uintptr_t)addr;
char sig[5];
sig[0] = hdr->signature[0];
sig[1] = hdr->signature[1];
sig[2] = hdr->signature[2];
sig[3] = hdr->signature[3];
sig[4] = 0;
g_log->info("[acpi] ");
g_log->info(sig);
log_hex("[acpi] addr=", addr);
log_hex("[acpi] len =", (u64)hdr->length);
}
}
/* ---------------------------------------------------------------
* Driver entry points
* --------------------------------------------------------------- */
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) {
return -1;
}
g_log = api->log;
g_log->info("[acpi] scanning for RSDP");
const acpi_rsdp_v2 *rsdp = acpi_find_rsdp(api->rsdp_address);
if (!rsdp) {
g_log->error("[acpi] RSDP not found");
return 0; /* optional driver, don't fail boot */
}
g_log->info("[acpi] RSDP found");
log_hex("[acpi] revision =", (u64)rsdp->revision);
g_log->info("[acpi] oem_id");
{
char oem[7];
for (int i = 0; i < 6; i++) oem[i] = rsdp->oem_id[i];
oem[6] = 0;
g_log->info(oem);
}
if (rsdp->revision >= 2 && rsdp->xsdt_addr) {
g_log->info("[acpi] using XSDT");
const acpi_sdt_header *xsdt = (const acpi_sdt_header *)(uintptr_t)rsdp->xsdt_addr;
acpi_enumerate_rsdt(xsdt, 8);
} else if (rsdp->rsdt_addr) {
g_log->info("[acpi] using RSDT");
const acpi_sdt_header *rsdt = (const acpi_sdt_header *)(uintptr_t)rsdp->rsdt_addr;
acpi_enumerate_rsdt(rsdt, 4);
} else {
g_log->warn("[acpi] no RSDT/XSDT address");
}
g_log->info("[acpi] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}
+645
View File
@@ -0,0 +1,645 @@
/* DKM AHCI Driver — PCI AHCI discovery and ABAR read-only enumeration
* Stage 1 optional storage driver, depends on "pci" and "irq", provides "block".
* This first version does not issue DMA commands; it only discovers the HBA
* and ports so later block I/O can be added safely.
*/
#include <stdint.h>
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_dma_buffer {
void *virt;
u64 phys;
u64 size;
};
struct dkm_dma_api {
int (*alloc_pages)(u64 page_count, u64 alignment, u64 max_phys, struct dkm_dma_buffer *out);
};
struct dkm_block_device_desc {
const char *name;
u64 sector_size;
u64 sector_count;
void *ctx;
int (*read)(void *ctx, u64 lba, u32 count, void *buffer);
};
struct dkm_block_api {
int (*register_device)(const struct dkm_block_device_desc *desc);
u32 (*device_count)(void);
int (*read)(u32 index, u64 lba, u32 count, void *buffer);
u64 (*sector_size)(u32 index);
const char *(*device_name)(u32 index);
};
struct dkm_kernel_api {
u32 version;
u32 size;
u64 feature_bits;
const struct dkm_log_api *log;
const void *mem;
const void *utsm;
const void *irq;
const void *pci;
const struct dkm_dma_api *dma;
const void *vfs;
const void *net;
const void *timer;
const void *drr;
const void *rsdp_address;
const void *fb_address;
u64 fb_width;
u64 fb_height;
u64 fb_pitch;
u16 fb_bpp;
const void *boot_modules_response;
int (*irq_register)(u8 irq, void *handler);
u64 hhdm_offset;
const struct dkm_block_api *block;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic;
u16 abi_version;
u16 desc_size;
const char *name;
const char *version;
const char *vendor;
u32 driver_class;
u32 stage;
u32 flags;
u32 priority;
const char *const *depends;
u32 depends_count;
const char *const *provides;
u32 provides_count;
u64 min_kernel_abi;
u64 feature_bits;
u64 reserved0;
u64 reserved1;
};
static const char *const g_depends[] = { "pci", "irq" };
static const char *const g_provides[] = { "block" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC,
.abi_version = DKM_ABI_VERSION,
.desc_size = sizeof(struct dkm_driver_desc),
.name = "ahci",
.version = "0.1.0",
.vendor = "Deshab",
.driver_class = 6, /* DKM_CLASS_STORAGE */
.stage = 1,
.flags = 0, /* optional */
.priority = 0,
.depends = g_depends,
.depends_count = 2,
.provides = g_provides,
.provides_count = 1,
.min_kernel_abi = 1,
.feature_bits = 0,
.reserved0 = 0,
.reserved1 = 0
};
#define PCI_ADDR 0xCF8
#define PCI_DATA 0xCFC
#define PCI_VENDOR_ID 0x00
#define PCI_COMMAND 0x04
#define PCI_PROG_IF 0x09
#define PCI_SUBCLASS 0x0A
#define PCI_CLASS 0x0B
#define PCI_HEADER 0x0E
#define PCI_BAR5 0x24
#define PCI_IRQ_LINE 0x3C
#define PCI_CMD_IO (1u << 0)
#define PCI_CMD_MEM (1u << 1)
#define PCI_CMD_BUSM (1u << 2)
#define AHCI_CLASS_STORAGE 0x01
#define AHCI_SUBCLASS_SATA 0x06
#define AHCI_PROGIF_AHCI 0x01
#define HBA_CAP 0x00
#define HBA_GHC 0x04
#define HBA_IS 0x08
#define HBA_PI 0x0C
#define HBA_VS 0x10
#define HBA_CAP2 0x24
#define HBA_BOHC 0x28
#define HBA_PORT_BASE 0x100
#define HBA_PORT_SIZE 0x80
#define PxCLB 0x00
#define PxFB 0x08
#define PxIS 0x10
#define PxIE 0x14
#define PxCMD 0x18
#define PxTFD 0x20
#define PxSIG 0x24
#define PxSSTS 0x28
#define PxSCTL 0x2C
#define PxSERR 0x30
#define PxSACT 0x34
#define PxCI 0x38
#define PxSNTF 0x3C
#define PxFBS 0x40
#define AHCI_CMD_ST (1u << 0)
#define AHCI_CMD_FRE (1u << 4)
#define AHCI_CMD_FR (1u << 14)
#define AHCI_CMD_CR (1u << 15)
#define AHCI_CMD_ICC_ACTIVE (1u << 28)
#define ATA_CMD_IDENTIFY 0xEC
#define ATA_CMD_IDENTIFY_PACKET 0xA1
typedef struct __attribute__((packed)) ahci_cmd_header {
u16 flags;
u16 prdtl;
u32 prdbc;
u32 ctba;
u32 ctbau;
u32 reserved[4];
} ahci_cmd_header;
typedef struct __attribute__((packed)) ahci_prdt_entry {
u32 dba;
u32 dbau;
u32 reserved;
u32 dbc_i;
} ahci_prdt_entry;
typedef struct __attribute__((packed)) ahci_cmd_table {
u8 cfis[64];
u8 acmd[16];
u8 reserved[48];
ahci_prdt_entry prdt[1];
} ahci_cmd_table;
static const struct dkm_log_api *g_log;
static volatile u32 *g_abar;
static u32 g_ready_port = 0xffffffffu;
static ahci_cmd_header *g_cmd_header;
static struct dkm_dma_buffer g_cmd_table;
static struct dkm_dma_buffer g_data;
static __inline__ void outl(u16 port, u32 value) {
__asm__ volatile ("outl %0, %1" :: "a"(value), "Nd"(port));
}
static __inline__ u32 inl(u16 port) {
u32 value;
__asm__ volatile ("inl %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
static u32 pci_read(u8 bus, u8 dev, u8 func, u8 reg) {
u32 addr = (1u << 31)
| ((u32)bus << 16)
| ((u32)dev << 11)
| ((u32)func << 8)
| ((u32)reg & 0xFC);
outl(PCI_ADDR, addr);
return inl(PCI_DATA);
}
static void pci_write(u8 bus, u8 dev, u8 func, u8 reg, u32 value) {
u32 addr = (1u << 31)
| ((u32)bus << 16)
| ((u32)dev << 11)
| ((u32)func << 8)
| ((u32)reg & 0xFC);
outl(PCI_ADDR, addr);
outl(PCI_DATA, value);
}
static void log_hex(const char *prefix, u64 value) {
static const char hex[] = "0123456789abcdef";
char buf[19];
u32 pos = 0;
buf[pos++] = '0';
buf[pos++] = 'x';
for (int i = 15; i >= 0; i--) {
buf[pos++] = hex[(value >> (i * 4)) & 0xf];
}
buf[pos] = 0;
g_log->info(prefix);
g_log->info(buf);
}
static void ahci_zero(void *ptr, u32 len) {
u8 *p = (u8 *)ptr;
for (u32 i = 0; i < len; i++) p[i] = 0;
}
static int ahci_find(u8 *out_bus, u8 *out_dev, u8 *out_func) {
for (u8 bus = 0; bus < 8; bus++) {
for (u8 dev = 0; dev < 32; dev++) {
u32 vd = pci_read(bus, dev, 0, PCI_VENDOR_ID);
if ((vd & 0xffff) == 0xffff) continue;
u8 header = (u8)(pci_read(bus, dev, 0, PCI_HEADER) >> 16);
u8 func_count = (header & 0x80) ? 8 : 1;
for (u8 func = 0; func < func_count; func++) {
u32 vd2 = pci_read(bus, dev, func, PCI_VENDOR_ID);
if ((vd2 & 0xffff) == 0xffff) continue;
u32 class_reg = pci_read(bus, dev, func, 0x08);
u8 prog_if = (u8)((class_reg >> 8) & 0xff);
u8 subclass = (u8)((class_reg >> 16) & 0xff);
u8 class_code = (u8)((class_reg >> 24) & 0xff);
if (class_code == AHCI_CLASS_STORAGE &&
subclass == AHCI_SUBCLASS_SATA &&
prog_if == AHCI_PROGIF_AHCI) {
*out_bus = bus;
*out_dev = dev;
*out_func = func;
return 0;
}
}
}
}
return -1;
}
static const char *sata_sig_name(u32 sig) {
if (sig == 0x00000101u) return "SATA drive";
if (sig == 0xEB140101u) return "ATAPI device";
if (sig == 0xC33C0101u) return "Enclosure mgmt";
if (sig == 0x96690101u) return "Port multiplier";
if (sig == 0x00000000u) return "empty/unknown";
return "unknown signature";
}
static void ahci_log_port(u32 port) {
if (!g_abar || port >= 32) {
return;
}
u32 base = HBA_PORT_BASE + port * HBA_PORT_SIZE;
u32 ssts = g_abar[(base + PxSSTS) / 4];
u32 sig = g_abar[(base + PxSIG) / 4];
u32 cmd = g_abar[(base + PxCMD) / 4];
u32 tfd = g_abar[(base + PxTFD) / 4];
u32 serr = g_abar[(base + PxSERR) / 4];
u32 ci = g_abar[(base + PxCI) / 4];
u32 sact = g_abar[(base + PxSACT) / 4];
u32 det = ssts & 0xf;
u32 spd = (ssts >> 4) & 0xf;
u32 ipm = (ssts >> 8) & 0xf;
log_hex("[ahci] port=", port);
log_hex("[ahci] SSTS=", ssts);
log_hex("[ahci] DET=", det);
log_hex("[ahci] SPD=", spd);
log_hex("[ahci] IPM=", ipm);
log_hex("[ahci] SIG=", sig);
g_log->info("[ahci] type");
g_log->info(sata_sig_name(sig));
log_hex("[ahci] CMD=", cmd);
log_hex("[ahci] TFD=", tfd);
log_hex("[ahci] SERR=", serr);
log_hex("[ahci] CI=", ci);
log_hex("[ahci] SACT=", sact);
}
static int ahci_stop_port(u32 port) {
u32 base = HBA_PORT_BASE + port * HBA_PORT_SIZE;
u32 cmd = g_abar[(base + PxCMD) / 4];
cmd &= ~AHCI_CMD_ST;
g_abar[(base + PxCMD) / 4] = cmd;
for (u32 i = 0; i < 100000; i++) {
cmd = g_abar[(base + PxCMD) / 4];
if (!(cmd & AHCI_CMD_CR)) break;
}
cmd &= ~AHCI_CMD_FRE;
g_abar[(base + PxCMD) / 4] = cmd;
for (u32 i = 0; i < 100000; i++) {
cmd = g_abar[(base + PxCMD) / 4];
if (!(cmd & AHCI_CMD_FR)) return 0;
}
return -1;
}
static int ahci_start_port(u32 port) {
u32 base = HBA_PORT_BASE + port * HBA_PORT_SIZE;
u32 cmd = g_abar[(base + PxCMD) / 4];
cmd |= AHCI_CMD_FRE;
g_abar[(base + PxCMD) / 4] = cmd;
cmd |= AHCI_CMD_ST;
g_abar[(base + PxCMD) / 4] = cmd;
return 0;
}
static void ahci_fill_identify_fis(u8 *fis, u8 command) {
for (u32 i = 0; i < 64; i++) fis[i] = 0;
fis[0] = 0x27; /* Register H2D FIS */
fis[1] = 1u << 7; /* command */
fis[2] = command;
fis[7] = 1u << 6; /* LBA mode */
}
static void ahci_fill_read_fis(u8 *fis, u64 lba, u32 count) {
ahci_zero(fis, 64);
fis[0] = 0x27;
fis[1] = 1u << 7;
fis[2] = 0x25; /* READ DMA EXT */
fis[4] = (u8)(lba & 0xff);
fis[5] = (u8)((lba >> 8) & 0xff);
fis[6] = (u8)((lba >> 16) & 0xff);
fis[7] = (1u << 6) | (u8)((lba >> 24) & 0x0f);
fis[8] = (u8)((lba >> 24) & 0xff);
fis[9] = (u8)((lba >> 32) & 0xff);
fis[10] = (u8)((lba >> 40) & 0xff);
fis[12] = (u8)(count & 0xff);
fis[13] = (u8)((count >> 8) & 0xff);
}
static int ahci_read_blocks_internal(u32 port, ahci_cmd_header *hdr, struct dkm_dma_buffer *table, struct dkm_dma_buffer *data, u64 lba, u32 count, void *buffer) {
if (!buffer || count == 0) return -1;
if (count > 8) return -2;
u32 base = HBA_PORT_BASE + port * HBA_PORT_SIZE;
ahci_cmd_table *tbl = (ahci_cmd_table *)table->virt;
u32 bytes = count * 512;
ahci_zero(tbl, sizeof(ahci_cmd_table));
ahci_zero(data->virt, bytes);
hdr[0].flags = 5;
hdr[0].prdtl = 1;
hdr[0].prdbc = 0;
hdr[0].ctba = (u32)(table->phys & 0xffffffffu);
hdr[0].ctbau = (u32)(table->phys >> 32);
tbl->prdt[0].dba = (u32)(data->phys & 0xffffffffu);
tbl->prdt[0].dbau = (u32)(data->phys >> 32);
tbl->prdt[0].dbc_i = (bytes - 1) | (1u << 31);
ahci_fill_read_fis(tbl->cfis, lba, count);
g_abar[(base + PxIS) / 4] = 0xffffffffu;
g_abar[HBA_IS / 4] = (1u << port);
g_abar[(base + PxCI) / 4] = 1;
for (u32 i = 0; i < 5000000; i++) {
if ((g_abar[(base + PxCI) / 4] & 1u) == 0) {
u8 *dst = (u8 *)buffer;
u8 *src = (u8 *)data->virt;
for (u32 j = 0; j < bytes; j++) dst[j] = src[j];
return 0;
}
}
g_log->warn("[ahci] READ timeout");
log_hex("[ahci] READ lba=", lba);
log_hex("[ahci] READ count=", count);
log_hex("[ahci] READ CI=", g_abar[(base + PxCI) / 4]);
log_hex("[ahci] READ IS=", g_abar[(base + PxIS) / 4]);
log_hex("[ahci] READ TFD=", g_abar[(base + PxTFD) / 4]);
return -3;
}
static int ahci_block_read(void *ctx, u64 lba, u32 count, void *buffer) {
(void)ctx;
if (g_ready_port == 0xffffffffu || !g_cmd_header) return -1;
/* ensure port is in ST+FRE state */
u32 base = HBA_PORT_BASE + g_ready_port * HBA_PORT_SIZE;
u32 cmd = g_abar[(base + PxCMD) / 4];
if (!(cmd & AHCI_CMD_ST) || !(cmd & AHCI_CMD_FRE)) {
g_log->warn("[ahci] port not ready; restarting");
ahci_stop_port(g_ready_port);
ahci_start_port(g_ready_port);
}
while (count > 0) {
u32 chunk = count > 8 ? 8 : count;
int status = ahci_read_blocks_internal(g_ready_port, g_cmd_header, &g_cmd_table, &g_data, lba, chunk, buffer);
if (status != 0) return status;
lba += chunk;
count -= chunk;
buffer = (void *)((u8 *)buffer + (chunk * 512));
}
return 0;
}
static int ahci_read_lba0(u32 port, ahci_cmd_header *hdr, struct dkm_dma_buffer *table, struct dkm_dma_buffer *data) {
int status = ahci_read_blocks_internal(port, hdr, table, data, 0, 1, data->virt);
if (status == 0) {
log_hex("[ahci] READ LBA0 port=", port);
log_hex("[ahci] READ LBA0 bytes=", hdr[0].prdbc);
log_hex("[ahci] READ LBA0 word0=", ((u16 *)data->virt)[0]);
log_hex("[ahci] READ LBA0 word255=", ((u16 *)data->virt)[255]);
return 1;
}
return status;
}
static int ahci_identify_port(u32 port, const struct dkm_dma_api *dma) {
if (!dma || !dma->alloc_pages) return -1;
u32 base = HBA_PORT_BASE + port * HBA_PORT_SIZE;
u32 ssts = g_abar[(base + PxSSTS) / 4];
u32 sig = g_abar[(base + PxSIG) / 4];
u32 det = ssts & 0xf;
u32 ipm = (ssts >> 8) & 0xf;
if (det != 3 || ipm != 1) return 0;
if (sig != 0x00000101u) {
g_log->info("[ahci] IDENTIFY skipped non-SATA port");
log_hex("[ahci] IDENTIFY skip port=", port);
log_hex("[ahci] IDENTIFY skip sig=", sig);
return 0;
}
struct dkm_dma_buffer clb;
struct dkm_dma_buffer fis;
struct dkm_dma_buffer table;
struct dkm_dma_buffer data;
if (dma->alloc_pages(1, 1024, 0x100000000ULL, &clb) != 0) return -2;
if (dma->alloc_pages(1, 256, 0x100000000ULL, &fis) != 0) return -3;
if (dma->alloc_pages(1, 128, 0x100000000ULL, &table) != 0) return -4;
if (dma->alloc_pages(1, 512, 0x100000000ULL, &data) != 0) return -5;
if (ahci_stop_port(port) != 0) {
g_log->warn("[ahci] port stop timeout");
return -6;
}
g_abar[(base + PxCLB) / 4] = (u32)(clb.phys & 0xffffffffu);
g_abar[(base + PxCLB + 4) / 4] = (u32)(clb.phys >> 32);
g_abar[(base + PxFB) / 4] = (u32)(fis.phys & 0xffffffffu);
g_abar[(base + PxFB + 4) / 4] = (u32)(fis.phys >> 32);
ahci_cmd_header *hdr = (ahci_cmd_header *)clb.virt;
ahci_cmd_table *tbl = (ahci_cmd_table *)table.virt;
hdr[0].flags = 5; /* FIS length in DWORDS */
hdr[0].prdtl = 1;
hdr[0].ctba = (u32)(table.phys & 0xffffffffu);
hdr[0].ctbau = (u32)(table.phys >> 32);
tbl->prdt[0].dba = (u32)(data.phys & 0xffffffffu);
tbl->prdt[0].dbau = (u32)(data.phys >> 32);
tbl->prdt[0].dbc_i = (512 - 1) | (1u << 31);
u8 cmd = ATA_CMD_IDENTIFY;
ahci_fill_identify_fis(tbl->cfis, cmd);
g_abar[(base + PxIS) / 4] = 0xffffffffu;
g_abar[HBA_IS / 4] = (1u << port);
ahci_start_port(port);
g_abar[(base + PxCI) / 4] = 1;
for (u32 i = 0; i < 5000000; i++) {
if ((g_abar[(base + PxCI) / 4] & 1u) == 0) {
log_hex("[ahci] IDENTIFY port=", port);
log_hex("[ahci] IDENTIFY status=", g_abar[(base + PxTFD) / 4]);
log_hex("[ahci] IDENTIFY bytes=", hdr[0].prdbc);
u16 *id = (u16 *)data.virt;
log_hex("[ahci] IDENTIFY word0=", id[0]);
log_hex("[ahci] IDENTIFY word49=", id[49]);
log_hex("[ahci] IDENTIFY word83=", id[83]);
ahci_read_lba0(port, hdr, &table, &data);
g_ready_port = port;
g_cmd_header = hdr;
g_cmd_table = table;
g_data = data;
return 1;
}
}
g_log->warn("[ahci] IDENTIFY timeout");
log_hex("[ahci] IDENTIFY CI=", g_abar[(base + PxCI) / 4]);
log_hex("[ahci] IDENTIFY IS=", g_abar[(base + PxIS) / 4]);
log_hex("[ahci] IDENTIFY TFD=", g_abar[(base + PxTFD) / 4]);
return -7;
}
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) return -1;
g_log = api->log;
g_log->info("[ahci] init begin");
u8 bus = 0;
u8 dev = 0;
u8 func = 0;
if (ahci_find(&bus, &dev, &func) != 0) {
g_log->warn("[ahci] AHCI controller not found");
g_log->info("[ahci] driver ready");
return 0;
}
g_log->info("[ahci] AHCI controller found");
log_hex("[ahci] bus=", bus);
log_hex("[ahci] dev=", dev);
log_hex("[ahci] func=", func);
u32 vd = pci_read(bus, dev, func, PCI_VENDOR_ID);
log_hex("[ahci] vendor=", vd & 0xffff);
log_hex("[ahci] device=", vd >> 16);
u32 command = pci_read(bus, dev, func, PCI_COMMAND) & 0xffff;
command |= PCI_CMD_MEM | PCI_CMD_BUSM;
pci_write(bus, dev, func, PCI_COMMAND, command);
log_hex("[ahci] PCI command=", command);
u64 abar_phys = (u64)(pci_read(bus, dev, func, PCI_BAR5) & 0xFFFFFFF0u);
u32 irq_line = pci_read(bus, dev, func, PCI_IRQ_LINE) & 0xff;
log_hex("[ahci] ABAR phys=", abar_phys);
log_hex("[ahci] PCI IRQ line=", irq_line);
if (!api->hhdm_offset || !abar_phys) {
g_log->warn("[ahci] missing HHDM or ABAR; skip MMIO enumeration");
g_log->info("[ahci] driver ready");
return 0;
}
g_abar = (volatile u32 *)(uintptr_t)(api->hhdm_offset + abar_phys);
log_hex("[ahci] HHDM offset=", api->hhdm_offset);
u32 cap = g_abar[HBA_CAP / 4];
u32 ghc = g_abar[HBA_GHC / 4];
u32 is = g_abar[HBA_IS / 4];
u32 pi = g_abar[HBA_PI / 4];
u32 vs = g_abar[HBA_VS / 4];
u32 cap2 = g_abar[HBA_CAP2 / 4];
u32 bohc = g_abar[HBA_BOHC / 4];
log_hex("[ahci] CAP=", cap);
log_hex("[ahci] GHC=", ghc);
log_hex("[ahci] IS=", is);
log_hex("[ahci] PI=", pi);
log_hex("[ahci] VS=", vs);
log_hex("[ahci] CAP2=", cap2);
log_hex("[ahci] BOHC=", bohc);
log_hex("[ahci] ports count=", (cap & 0x1f) + 1);
log_hex("[ahci] cmd slots=", ((cap >> 8) & 0x1f) + 1);
u32 implemented = 0;
for (u32 port = 0; port < 32; port++) {
if (pi & (1u << port)) {
implemented++;
ahci_log_port(port);
}
}
log_hex("[ahci] implemented ports=", implemented);
u32 identified = 0;
if (api->dma) {
for (u32 port = 0; port < 32; port++) {
if (pi & (1u << port)) {
int ident = ahci_identify_port(port, api->dma);
if (ident > 0) {
identified++;
break;
}
}
}
} else {
g_log->warn("[ahci] DMA API unavailable; skip IDENTIFY");
}
log_hex("[ahci] identified ports=", identified);
if (identified && api->block && api->block->register_device) {
struct dkm_block_device_desc desc;
desc.name = "ahci0";
desc.sector_size = 512;
desc.sector_count = 0;
desc.ctx = 0;
desc.read = ahci_block_read;
int index = api->block->register_device(&desc);
log_hex("[ahci] block provider index=", (u64)(i64)index);
} else if (identified) {
g_log->warn("[ahci] block API unavailable; provider not registered");
}
g_log->info("[ahci] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}
+358
View File
@@ -0,0 +1,358 @@
/* DKM APIC Driver — APIC discovery with PIC fallback
* Stage 0, required, depends on "timer", provides "irq" and "apic".
* Current kernel IRQ backend is still PIC; this driver only discovers APIC
* topology and keeps PIC routing active.
*/
#include <stdint.h>
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_kernel_api {
u32 version;
u32 size;
u64 feature_bits;
const struct dkm_log_api *log;
const void *mem;
const void *utsm;
const void *irq;
const void *pci;
const void *dma;
const void *vfs;
const void *net;
const void *timer;
const void *drr;
const void *rsdp_address;
const void *fb_address;
u64 fb_width;
u64 fb_height;
u64 fb_pitch;
u16 fb_bpp;
const void *boot_modules_response;
int (*irq_register)(u8 irq, void *handler);
u64 hhdm_offset;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic;
u16 abi_version;
u16 desc_size;
const char *name;
const char *version;
const char *vendor;
u32 driver_class;
u32 stage;
u32 flags;
u32 priority;
const char *const *depends;
u32 depends_count;
const char *const *provides;
u32 provides_count;
u64 min_kernel_abi;
u64 feature_bits;
u64 reserved0;
u64 reserved1;
};
static const char *const g_depends[] = { "timer" };
static const char *const g_provides[] = { "irq", "apic" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC,
.abi_version = DKM_ABI_VERSION,
.desc_size = sizeof(struct dkm_driver_desc),
.name = "apic",
.version = "0.1.0",
.vendor = "Deshab",
.driver_class = 3, /* DKM_CLASS_INTERRUPT */
.stage = 0,
.flags = 1, /* DKM_F_REQUIRED */
.priority = 0,
.depends = g_depends,
.depends_count = 1,
.provides = g_provides,
.provides_count = 2,
.min_kernel_abi = 1,
.feature_bits = 0,
.reserved0 = 0,
.reserved1 = 0
};
typedef struct __attribute__((packed)) {
char signature[8];
u8 checksum;
char oem_id[6];
u8 revision;
u32 rsdt_addr;
} acpi_rsdp_v1;
typedef struct __attribute__((packed)) {
char signature[8];
u8 checksum;
char oem_id[6];
u8 revision;
u32 rsdt_addr;
u32 length;
u64 xsdt_addr;
u8 ext_checksum;
u8 reserved[3];
} acpi_rsdp_v2;
typedef struct __attribute__((packed)) {
char signature[4];
u32 length;
u8 revision;
u8 checksum;
char oem_id[6];
char oem_table_id[8];
u32 oem_revision;
u32 creator_id;
u32 creator_revision;
} acpi_sdt_header;
typedef struct __attribute__((packed)) {
acpi_sdt_header hdr;
u32 lapic_addr;
u32 flags;
} acpi_madt;
struct madt_info {
u64 lapic_phys;
u32 flags;
u32 lapic_count;
u32 ioapic_count;
u32 iso_count;
};
static const struct dkm_log_api *g_log;
static int memeq(const char *a, const char *b, u32 n) {
for (u32 i = 0; i < n; i++) {
if (a[i] != b[i]) return 0;
}
return 1;
}
static u8 checksum8(const u8 *data, u32 len) {
u8 sum = 0;
for (u32 i = 0; i < len; i++) sum += data[i];
return sum;
}
static void log_hex(const char *prefix, u64 val) {
static const char hex[] = "0123456789abcdef";
char buf[19];
u32 pos = 0;
buf[pos++] = '0';
buf[pos++] = 'x';
for (int i = 15; i >= 0; i--) {
buf[pos++] = hex[(val >> (i * 4)) & 0xf];
}
buf[pos] = 0;
g_log->info(prefix);
g_log->info(buf);
}
static void cpuid(u32 leaf, u32 *a, u32 *b, u32 *c, u32 *d) {
__asm__ volatile ("cpuid"
: "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d)
: "a"(leaf), "c"(0));
}
static u64 rdmsr(u32 msr) {
u32 lo;
u32 hi;
__asm__ volatile ("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
return ((u64)hi << 32) | lo;
}
static int cpu_has_lapic(void) {
u32 a, b, c, d;
cpuid(1, &a, &b, &c, &d);
(void)a;
(void)b;
(void)c;
return (d & (1u << 9)) != 0;
}
static const acpi_sdt_header *find_table_from_rsdt(const acpi_sdt_header *rsdt, const char sig[4], u32 entry_size) {
if (!rsdt || rsdt->length < sizeof(acpi_sdt_header)) return NULL;
if (checksum8((const u8 *)rsdt, rsdt->length) != 0) return NULL;
u32 count = (rsdt->length - sizeof(acpi_sdt_header)) / entry_size;
const u8 *entries = (const u8 *)rsdt + sizeof(acpi_sdt_header);
for (u32 i = 0; i < count; i++) {
u64 addr;
if (entry_size == 4) {
addr = (u64)((const u32 *)entries)[i];
} else {
addr = ((const u64 *)entries)[i];
}
if (!addr) continue;
const acpi_sdt_header *hdr = (const acpi_sdt_header *)(uintptr_t)addr;
if (hdr->length >= sizeof(acpi_sdt_header) && memeq(hdr->signature, sig, 4)) {
if (checksum8((const u8 *)hdr, hdr->length) == 0) return hdr;
}
}
return NULL;
}
static const acpi_madt *find_madt(const void *rsdp_addr) {
if (!rsdp_addr) return NULL;
const acpi_rsdp_v2 *rsdp = (const acpi_rsdp_v2 *)rsdp_addr;
if (!memeq(rsdp->signature, "RSD PTR ", 8)) return NULL;
if (checksum8((const u8 *)rsdp, 20) != 0) return NULL;
if (rsdp->revision >= 2 && rsdp->length >= sizeof(acpi_rsdp_v2) && rsdp->xsdt_addr) {
if (checksum8((const u8 *)rsdp, rsdp->length) == 0) {
const acpi_sdt_header *xsdt = (const acpi_sdt_header *)(uintptr_t)rsdp->xsdt_addr;
const acpi_sdt_header *madt = find_table_from_rsdt(xsdt, "APIC", 8);
if (madt) return (const acpi_madt *)madt;
}
}
if (rsdp->rsdt_addr) {
const acpi_sdt_header *rsdt = (const acpi_sdt_header *)(uintptr_t)(u64)rsdp->rsdt_addr;
const acpi_sdt_header *madt = find_table_from_rsdt(rsdt, "APIC", 4);
if (madt) return (const acpi_madt *)madt;
}
return NULL;
}
static void parse_madt_entries(const acpi_madt *madt, struct madt_info *info) {
const u8 *base = (const u8 *)madt;
u32 off = (u32)sizeof(acpi_madt);
while (off + 2 <= madt->hdr.length) {
const u8 *entry = base + off;
u8 type = entry[0];
u8 len = entry[1];
if (len < 2 || off + len > madt->hdr.length) {
g_log->warn("[apic] malformed MADT entry");
return;
}
if (type == 0 && len >= 8) {
u8 apic_id = entry[3];
u32 flags = *(const u32 *)(const void *)(entry + 4);
if (flags & 1u) info->lapic_count++;
log_hex("[apic] CPU LAPIC id=", apic_id);
} else if (type == 1 && len >= 12) {
u8 ioapic_id = entry[2];
u32 addr = *(const u32 *)(const void *)(entry + 4);
u32 gsi = *(const u32 *)(const void *)(entry + 8);
info->ioapic_count++;
log_hex("[apic] IOAPIC id=", ioapic_id);
log_hex("[apic] IOAPIC addr=", addr);
log_hex("[apic] IOAPIC gsi_base=", gsi);
} else if (type == 2 && len >= 10) {
u8 source = entry[3];
u32 gsi = *(const u32 *)(const void *)(entry + 4);
u16 flags = *(const u16 *)(const void *)(entry + 8);
info->iso_count++;
log_hex("[apic] ISO source=", source);
log_hex("[apic] ISO gsi=", gsi);
log_hex("[apic] ISO flags=", flags);
} else if (type == 5 && len >= 12) {
u64 override = *(const u64 *)(const void *)(entry + 4);
info->lapic_phys = override;
log_hex("[apic] LAPIC override=", override);
}
off += len;
}
}
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) return -1;
g_log = api->log;
g_log->info("[apic] init begin");
if (!api->irq_register) {
g_log->error("[apic] kernel irq_register missing");
return -1;
}
g_log->info("[apic] kernel IRQ backend present: PIC");
if (!cpu_has_lapic()) {
g_log->warn("[apic] CPUID local APIC not present; PIC fallback active");
g_log->info("[apic] driver ready");
return 0;
}
g_log->info("[apic] CPUID local APIC present");
u64 apic_base = rdmsr(0x1B);
u64 lapic_phys = apic_base & 0xFFFFF000ULL;
log_hex("[apic] IA32_APIC_BASE=", apic_base);
log_hex("[apic] LAPIC phys base=", lapic_phys);
if (apic_base & (1ULL << 8)) g_log->info("[apic] bootstrap processor");
if (apic_base & (1ULL << 11)) g_log->info("[apic] LAPIC enabled by firmware");
struct madt_info info;
info.lapic_phys = lapic_phys;
info.flags = 0;
info.lapic_count = 0;
info.ioapic_count = 0;
info.iso_count = 0;
const acpi_madt *madt = find_madt(api->rsdp_address);
if (madt) {
g_log->info("[apic] MADT found");
info.lapic_phys = (u64)madt->lapic_addr;
info.flags = madt->flags;
log_hex("[apic] MADT lapic_phys=", info.lapic_phys);
log_hex("[apic] MADT flags=", info.flags);
parse_madt_entries(madt, &info);
log_hex("[apic] CPU LAPIC count=", info.lapic_count);
log_hex("[apic] IOAPIC count=", info.ioapic_count);
log_hex("[apic] ISO count=", info.iso_count);
} else {
g_log->warn("[apic] MADT not found; PIC fallback active");
}
if (api->hhdm_offset && info.lapic_phys) {
volatile u32 *lapic = (volatile u32 *)(uintptr_t)(api->hhdm_offset + info.lapic_phys);
log_hex("[apic] LAPIC ID reg=", lapic[0x20 / 4]);
log_hex("[apic] LAPIC version reg=", lapic[0x30 / 4]);
log_hex("[apic] LAPIC SVR reg=", lapic[0xF0 / 4]);
} else {
g_log->warn("[apic] HHDM unavailable; skip LAPIC MMIO read");
}
g_log->info("[apic] discovery complete; PIC routing retained");
g_log->info("[apic] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}
+191
View File
@@ -0,0 +1,191 @@
/* DKM BootFS Driver — exposes Limine boot modules as a simple filesystem
* Stage 1, required, provides "bootfs".
* Lists all boot modules with path, size, and address.
*/
#include <stdint.h>
/* ---------------------------------------------------------------
* DKM ABI types
* --------------------------------------------------------------- */
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_kernel_api {
u32 version;
u32 size;
u64 feature_bits;
const struct dkm_log_api *log;
const void *mem;
const void *utsm;
const void *irq;
const void *pci_api;
const void *dma;
const void *vfs;
const void *net;
const void *timer;
const void *drr;
const void *rsdp_address;
const void *fb_address;
u64 fb_width;
u64 fb_height;
u64 fb_pitch;
u16 fb_bpp;
const void *boot_modules_response;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic;
u16 abi_version;
u16 desc_size;
const char *name;
const char *version;
const char *vendor;
u32 driver_class;
u32 stage;
u32 flags;
u32 priority;
const char *const *depends;
u32 depends_count;
const char *const *provides;
u32 provides_count;
u64 min_kernel_abi;
u64 feature_bits;
u64 reserved0;
u64 reserved1;
};
/* minimal limine types matching kernel */
struct limine_file {
u64 revision;
void *address;
u64 size;
char *path;
char *cmdline;
u32 media_type;
u32 unused;
u32 tftp_ip;
u32 tftp_port;
u32 partition_index;
u32 mbr_disk_id;
u8 gpt_disk_uuid[16];
u8 gpt_part_uuid[16];
u8 part_uuid[16];
};
struct limine_module_response {
u64 revision;
u64 module_count;
struct limine_file **modules;
};
/* ---------------------------------------------------------------
* Driver descriptor
* --------------------------------------------------------------- */
static const char *const g_provides[] = { "bootfs" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC,
.abi_version = DKM_ABI_VERSION,
.desc_size = sizeof(struct dkm_driver_desc),
.name = "bootfs",
.version = "0.1.0",
.vendor = "Deshab",
.driver_class = 7, /* DKM_CLASS_FS */
.stage = 1,
.flags = 1, /* DKM_F_REQUIRED */
.priority = 0,
.depends = NULL,
.depends_count = 0,
.provides = g_provides,
.provides_count = 1,
.min_kernel_abi = 1,
.feature_bits = 0,
.reserved0 = 0,
.reserved1 = 0
};
/* ---------------------------------------------------------------
* Log helpers
* --------------------------------------------------------------- */
static const struct dkm_log_api *g_log;
static void log_hex(const char *prefix, u64 val) {
static const char hex[] = "0123456789abcdef";
char buf[19];
u32 pos = 0;
buf[pos++] = '0'; buf[pos++] = 'x';
for (int i = 15; i >= 0; i--) {
buf[pos++] = hex[(val >> (i * 4)) & 0xf];
}
buf[pos] = 0;
g_log->info(prefix);
g_log->info(buf);
}
/* ---------------------------------------------------------------
* Driver entry
* --------------------------------------------------------------- */
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) return -1;
g_log = api->log;
const struct limine_module_response *rsp =
(const struct limine_module_response *)api->boot_modules_response;
if (!rsp) {
g_log->error("[bootfs] no boot module response");
return -1;
}
g_log->info("[bootfs] boot module filesystem");
log_hex("[bootfs] file count=", rsp->module_count);
for (u64 i = 0; i < rsp->module_count; i++) {
struct limine_file *f = rsp->modules[i];
if (!f) continue;
g_log->info("[bootfs] ----------");
if (f->path) {
g_log->info("[bootfs] file");
g_log->info(f->path);
}
log_hex("[bootfs] size=", f->size);
log_hex("[bootfs] addr=", (u64)(uintptr_t)f->address);
if (f->cmdline) {
g_log->info("[bootfs] cmd");
g_log->info(f->cmdline);
}
}
g_log->info("[bootfs] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}
+259
View File
@@ -0,0 +1,259 @@
/* DKM Console Framebuffer Driver
* Stage 1, optional, provides "console".
* Light-blue background + centered circular loading animation (4-color arc ring).
*/
#include <stdint.h>
/* ---------------------------------------------------------------
* DKM ABI types
* --------------------------------------------------------------- */
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_kernel_api {
u32 version; u32 size; u64 feature_bits;
const struct dkm_log_api *log;
const void *mem, *utsm, *irq, *pci_api, *dma, *vfs, *net, *timer, *drr;
const void *rsdp_address, *fb_address;
u64 fb_width, fb_height, fb_pitch; u16 fbpp;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic; u16 abi_version; u16 desc_size;
const char *name, *version, *vendor;
u32 driver_class, stage, flags, priority;
const char *const *depends; u32 depends_count;
const char *const *provides; u32 provides_count;
u64 min_kernel_abi, feature_bits, reserved0, reserved1;
};
static const char *const g_provides[] = { "console" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic=DKM_DRIVER_MAGIC, .abi_version=DKM_ABI_VERSION,
.desc_size=sizeof(struct dkm_driver_desc),
.name="console_fb", .version="0.2.0", .vendor="Deshab",
.driver_class=5, .stage=1, .flags=0, .priority=0,
.depends=NULL, .depends_count=0,
.provides=g_provides, .provides_count=1,
.min_kernel_abi=1,
};
/* ---------------------------------------------------------------
* Colors
* --------------------------------------------------------------- */
static const u32 BG = 0xFFC8E0F0; /* light blue background */
static const u32 ARC[4] = { 0xFF4488CC, 0xFF2266AA, 0xFF66AAEE, 0xFF88CCFF };
/* ---------------------------------------------------------------
* Drawing helpers – all integer arithmetic, no soft-float
* --------------------------------------------------------------- */
static u64 fb_w, fb_h, fb_p;
/* double-buffer sprite for ring area (128×128 = no flicker) */
#define SPR_SIZE 128
static u32 g_sprite[SPR_SIZE * SPR_SIZE];
static void fb_fill(u32 *fb, u64 pitch, u64 w, u64 h, u32 color) {
for (u64 y = 0; y < h; y++) {
u32 *line = (u32 *)((u8 *)fb + y * pitch);
for (u64 x = 0; x < w; x++) line[x] = color;
}
}
/* alpha-blend c2 over c1, alpha 0-255 */
static u32 blend(u32 c1, u32 c2, u32 a) {
u32 na = 256 - a;
u32 r = ((c1 & 0xFF) * na + (c2 & 0xFF) * a) >> 8;
u32 g = (((c1 >> 8) & 0xFF) * na + ((c2 >> 8) & 0xFF) * a) >> 8;
u32 b = (((c1 >> 16) & 0xFF) * na + ((c2 >> 16) & 0xFF) * a) >> 8;
return 0xFF000000 | (b << 16) | (g << 8) | r;
}
/* integer sqrt – returns floor(sqrt(v)) */
static u64 isqrt(u64 v) {
u64 x = v, y = (x + 1) >> 1;
while (y < x) { x = y; y = (y + v / y) >> 1; }
return x;
}
/* approximate atan2 in degrees (0=right, CCW). dx,dy = pixel offset from center */
static i64 approx_angle(i64 dx, i64 dy) {
if (dx == 0) return dy < 0 ? 90 : 270;
i64 ax = dx < 0 ? -dx : dx;
i64 ay = dy < 0 ? -dy : dy;
i64 a;
if (ax > ay) {
a = ay * 45 / ax;
} else {
a = 90 - ax * 45 / (ay ? ay : 1);
}
/* quadrant correction */
if (dx >= 0 && dy <= 0) return a; /* Q1 */
else if (dx < 0 && dy <= 0) return 180 - a; /* Q2 */
else if (dx < 0 && dy > 0) return 180 + a; /* Q3 */
else return 360 - a; /* Q4 */
}
/* draw one arc segment: rounded caps (6° head/tail), bright mid, comet-tail fade */
static void arc_segment(u32 *fb, i64 cx, i64 cy, i64 r, i64 start, i64 sweep, u32 color, i64 thk) {
i64 ro = r + thk, ri = r - thk;
i64 ri2 = ri * ri, ro2 = (ro + 1) * (ro + 1);
i64 rnd = 6; /* rounding zone at each end, in degrees */
for (i64 dy = -ro - 1; dy <= ro + 1; dy++) {
i64 y = cy + dy;
if ((u64)y >= fb_h) continue;
u32 *line = (u32 *)((u8 *)fb + (u64)y * fb_p);
for (i64 dx = -ro - 1; dx <= ro + 1; dx++) {
i64 x = cx + dx;
if ((u64)x >= fb_w) continue;
i64 d2 = dx * dx + dy * dy;
if (d2 < ri2 - 2 || d2 > ro2 + 2) continue;
i64 ang = approx_angle(dx, dy);
i64 a = ang - start;
if (a < 0) a += 360;
if ((u64)a > (u64)sweep) continue;
/* rounded-cap fade: 0→255 over rnd°, then 255→0 over last rnd° */
u32 fade;
if ((u64)a < (u64)rnd) {
fade = (u32)(a * 255 / rnd);
} else if ((u64)a > (u64)(sweep - rnd)) {
fade = (u32)((sweep - a) * 255 / rnd);
} else {
fade = 255;
}
i64 dist = (i64)isqrt((u64)d2);
u32 effective = blend(BG, color, fade);
if (dist >= ri && dist <= ro) {
line[(u64)x] = effective;
} else if (dist >= ri - 2 && dist < ri) {
line[(u64)x] = blend(BG, effective, (u32)((dist - (ri - 2)) * 85));
} else if (dist > ro && dist <= ro + 2) {
line[(u64)x] = blend(effective, BG, (u32)((dist - ro) * 85));
}
}
}
}
/* filled disc with anti-aliased edge */
static void fill_disc(u32 *fb, i64 cx, i64 cy, i64 r, u32 color) {
i64 r2 = r * r, o2 = (r + 1) * (r + 1);
for (i64 dy = -r - 2; dy <= r + 2; dy++) {
i64 y = cy + dy;
if ((u64)y >= fb_h) continue;
u32 *line = (u32 *)((u8 *)fb + (u64)y * fb_p);
for (i64 dx = -r - 2; dx <= r + 2; dx++) {
i64 x = cx + dx;
if ((u64)x >= fb_w) continue;
i64 d2 = dx * dx + dy * dy;
if (d2 <= r2) {
line[(u64)x] = color;
} else if (d2 <= o2) {
u32 a = (u32)((o2 - d2) * 255 / (o2 - r2));
line[(u64)x] = blend(BG, color, a);
}
}
}
}
/* ---------------------------------------------------------------
* Driver entry
* --------------------------------------------------------------- */
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) return -1;
if (!api->fb_address || !api->fb_width) {
api->log->warn("[console_fb] no framebuffer");
return 0;
}
api->log->info("[console_fb] boot screen");
fb_w = api->fb_width; fb_h = api->fb_height; fb_p = api->fb_pitch;
u32 *fb = (u32 *)api->fb_address;
i64 cx = (i64)fb_w / 2, cy = (i64)fb_h / 2, r = 48, thk = 4;
/* light-blue background */
fb_fill(fb, fb_p, fb_w, fb_h, BG);
/* animation: 2000 frames × 2° clockwise × ~1ms, no flicker */
i64 spr_p = SPR_SIZE * 4;
i64 scx = SPR_SIZE / 2;
i64 scy = SPR_SIZE / 2;
i64 frame = 0, base = 0;
i64 bx = cx - scx; /* screen position of sprite top-left */
i64 by = cy - scy;
while (frame < 2000) {
/* draw into sprite buffer — swap globals to sprite layout */
u64 save_w = fb_w, save_h = fb_h, save_p = fb_p;
fb_w = SPR_SIZE; fb_h = SPR_SIZE; fb_p = spr_p;
fb_fill(g_sprite, spr_p, SPR_SIZE, SPR_SIZE, BG);
arc_segment(g_sprite, scx, scy, r, base + 0, 82, ARC[0], thk);
arc_segment(g_sprite, scx, scy, r, base + 90, 82, ARC[1], thk);
arc_segment(g_sprite, scx, scy, r, base +180, 82, ARC[2], thk);
arc_segment(g_sprite, scx, scy, r, base +270, 82, ARC[3], thk);
fill_disc(g_sprite, scx, scy, r - 8, blend(BG, 0xFFD0F0FF, 80));
/* restore screen globals for blit */
fb_w = save_w; fb_h = save_h; fb_p = save_p;
/* blit sprite to screen */
for (i64 sr = 0; sr < SPR_SIZE; sr++) {
i64 sy = by + sr;
if ((u64)sy >= fb_h) continue;
u32 *dst = (u32 *)((u8 *)fb + (u64)sy * fb_p) + bx;
u32 *src = &g_sprite[sr * SPR_SIZE];
for (i64 sc = 0; sc < SPR_SIZE; sc++) {
i64 sx = bx + sc;
if ((u64)sx >= fb_w) continue;
dst[sc] = src[sc];
}
}
for (volatile u32 d = 0; d < 72000; d++) {
__asm__ volatile ("pause");
}
base -= 2;
if (base < 0) base += 360;
frame++;
}
api->log->info("[console_fb] ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}
+224
View File
@@ -0,0 +1,224 @@
/* DKM DevFS Driver — virtual device filesystem
* Stage 2, optional, depends on "vfs", provides "devfs".
* Exposes kernel platform info as virtual files under /dev/.
*/
#include <stdint.h>
/* ---------------------------------------------------------------
* DKM ABI types
* --------------------------------------------------------------- */
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_kernel_api {
u32 version;
u32 size;
u64 feature_bits;
const struct dkm_log_api *log;
const void *mem;
const void *utsm;
const void *irq;
const void *pci_api;
const void *dma;
const void *vfs_api;
const void *net;
const void *timer;
const void *drr;
const void *rsdp_address;
const void *fb_address;
u64 fb_width;
u64 fb_height;
u64 fb_pitch;
u16 fb_bpp;
const void *boot_modules_response;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic;
u16 abi_version;
u16 desc_size;
const char *name;
const char *version;
const char *vendor;
u32 driver_class;
u32 stage;
u32 flags;
u32 priority;
const char *const *depends;
u32 depends_count;
const char *const *provides;
u32 provides_count;
u64 min_kernel_abi;
u64 feature_bits;
u64 reserved0;
u64 reserved1;
};
struct limine_file {
u64 revision;
void *address;
u64 size;
char *path;
char *cmdline;
u8 _pad[56];
};
struct limine_module_response {
u64 revision;
u64 module_count;
struct limine_file **modules;
};
/* ---------------------------------------------------------------
* Driver descriptor
* --------------------------------------------------------------- */
static const char *const g_depends[] = { "vfs" };
static const char *const g_provides[] = { "devfs" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC,
.abi_version = DKM_ABI_VERSION,
.desc_size = sizeof(struct dkm_driver_desc),
.name = "devfs",
.version = "0.1.0",
.vendor = "Deshab",
.driver_class = 7,
.stage = 2,
.flags = 0,
.priority = 0,
.depends = g_depends,
.depends_count = 1,
.provides = g_provides,
.provides_count = 1,
.min_kernel_abi = 1,
.feature_bits = 0,
.reserved0 = 0,
.reserved1 = 0
};
/* ---------------------------------------------------------------
* Helpers
* --------------------------------------------------------------- */
static const struct dkm_log_api *g_log;
static void log_hex(const char *prefix, u64 val) {
static const char h[] = "0123456789abcdef";
char buf[19]; u32 p = 0;
buf[p++] = '0'; buf[p++] = 'x';
for (int i = 15; i >= 0; i--) buf[p++] = h[(val>>(i*4))&0xf];
buf[p] = 0;
g_log->info(prefix); g_log->info(buf);
}
/* ---------------------------------------------------------------
* Virtual file helpers
* --------------------------------------------------------------- */
static void devfs_file(const char *name, const char *content) {
g_log->info("[devfs] /dev/");
g_log->info(name);
g_log->info("[devfs] ");
g_log->info(content);
}
/* ---------------------------------------------------------------
* Driver entry
* --------------------------------------------------------------- */
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) return -1;
g_log = api->log;
g_log->info("[devfs] virtual device filesystem");
/* /dev/version */
devfs_file("version", "Deshab kernel 0.1.0");
/* /dev/platform */
devfs_file("platform", "x86_64 SAS-R0");
/* /dev/fb0 */
if (api->fb_address) {
char info[64];
info[0] = 0;
/* manual number conversion for width */
{
u64 v = api->fb_width;
char tmp[24]; u32 p = 0;
if (v == 0) tmp[p++] = '0';
else { char r[24]; u32 q = 0; while (v) { r[q++] = '0' + (char)(v%10); v/=10; } while (q) tmp[p++] = r[--q]; }
tmp[p++] = 'x';
v = api->fb_height;
if (v == 0) tmp[p++] = '0';
else { char r[24]; u32 q = 0; while (v) { r[q++] = '0' + (char)(v%10); v/=10; } while (q) tmp[p++] = r[--q]; }
tmp[p++] = 'x';
v = api->fb_bpp;
if (v == 0) tmp[p++] = '0';
else { char r[24]; u32 q = 0; while (v) { r[q++] = '0' + (char)(v%10); v/=10; } while (q) tmp[p++] = r[--q]; }
tmp[p++] = ' ';
tmp[p++] = 'f';
tmp[p++] = 'b';
tmp[p++] = '0';
tmp[p] = 0;
for (u32 i = 0; i <= p; i++) info[i] = tmp[i];
}
devfs_file("fb0", info);
}
/* /dev/modules — count from boot_modules */
const struct limine_module_response *rsp =
(const struct limine_module_response *)api->boot_modules_response;
if (rsp) {
char buf[24];
buf[0] = '0'; buf[1] = 'x';
u64 v = rsp->module_count;
u32 p = 2;
if (v == 0) buf[p++] = '0';
else {
char r[18]; u32 q = 0;
while (v) { r[q++] = "0123456789abcdef"[v&0xf]; v>>=4; }
while (q) buf[p++] = r[--q];
}
buf[p] = 0;
devfs_file("modules", buf);
/* /dev/boot — list paths */
g_log->info("[devfs] /dev/boot/");
for (u64 i = 0; i < rsp->module_count; i++) {
struct limine_file *f = rsp->modules[i];
if (f && f->path) {
g_log->info("[devfs] ");
g_log->info(f->path);
}
}
}
g_log->info("[devfs] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}
+464
View File
@@ -0,0 +1,464 @@
/* DKM e1000 Driver — Intel 8254x Gigabit Ethernet
* Stage 3, optional, depends on "pci" and "irq", provides "netdev".
* Finds e1000 via PCI, maps MMIO, reads MAC address.
*/
#include <stdint.h>
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_net_device_desc {
const char *name;
u8 mac[6];
u32 flags;
void *ctx;
int (*tx)(void *ctx, const void *packet, u32 length);
int (*rx_poll)(void *ctx, void *buffer, u32 capacity, u32 *out_length);
};
struct dkm_net_api {
int (*register_device)(const struct dkm_net_device_desc *desc);
u32 (*device_count)(void);
int (*device_info)(u32 index, void *out);
};
struct dkm_dma_buffer {
void *virt;
u64 phys;
u64 size;
};
struct dkm_dma_api {
int (*alloc_pages)(u64 page_count, u64 alignment, u64 max_phys, struct dkm_dma_buffer *out);
};
#define DKM_NET_F_LINK_UP (1u << 0)
#define DKM_NET_F_TX_READY (1u << 1)
#define DKM_NET_F_RX_READY (1u << 2)
struct dkm_kernel_api {
u32 version; u32 size; u64 feature_bits;
const struct dkm_log_api *log;
const void *mem,*utsm,*irq_api,*pci_api;
const struct dkm_dma_api *dma;
const void *vfs_api;
const struct dkm_net_api *net;
const void *timer,*drr;
const void *rsdp_address,*fb_address;
u64 fb_width,fb_height,fb_pitch; u16 fb_bpp;
const void *boot_modules_response;
int (*irq_register)(u8 irq, void *handler);
u64 hhdm_offset;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic; u16 abi_version; u16 desc_size;
const char *name,*version,*vendor;
u32 driver_class,stage,flags,priority;
const char *const *depends; u32 depends_count;
const char *const *provides; u32 provides_count;
u64 min_kernel_abi,feature_bits,reserved0,reserved1;
};
static const char *const g_depends[] = {"pci","irq"};
static const char *const g_provides[] = {"netdev"};
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic=DKM_DRIVER_MAGIC,.abi_version=DKM_ABI_VERSION,
.desc_size=sizeof(struct dkm_driver_desc),
.name="e1000",.version="0.1.0",.vendor="Deshab",
.driver_class=9,.stage=3,.flags=0,.priority=0,
.depends=g_depends,.depends_count=2,
.provides=g_provides,.provides_count=1,.min_kernel_abi=1,
};
/* PCI config ports */
#define PCI_ADDR 0xCF8
#define PCI_DATA 0xCFC
#define PCI_VENDOR_ID 0x00
#define PCI_DEVICE_ID 0x02
#define PCI_COMMAND 0x04
#define PCI_BAR0 0x10
#define PCI_IRQ_LINE 0x3C
/* e1000 MMIO registers */
#define E1000_CTRL 0x0000
#define E1000_STATUS 0x0008
#define E1000_EERD 0x0014
#define E1000_ICR 0x00C0
#define E1000_IMS 0x00D0
#define E1000_IMC 0x00D8
#define E1000_RAL 0x5400
#define E1000_RAH 0x5404
#define E1000_RDBAL 0x2800
#define E1000_RDBAH 0x2804
#define E1000_RDLEN 0x2808
#define E1000_RDH 0x2810
#define E1000_RDT 0x2818
#define E1000_RXDCTL 0x2828
#define E1000_RCTL 0x0100
#define E1000_TDBAL 0x3800
#define E1000_TDBAH 0x3804
#define E1000_TDLEN 0x3808
#define E1000_TDH 0x3810
#define E1000_TDT 0x3818
#define E1000_TXDCTL 0x3828
#define E1000_TCTL 0x0400
#define E1000_TIPG 0x0410
#define E1000_RX_DESC_COUNT 8u
#define E1000_TX_DESC_COUNT 8u
#define E1000_RX_BUF_SIZE 2048u
#define E1000_TX_BUF_SIZE 2048u
#define E1000_POOL_BYTES(count, size) ((u32)((count) * (size)))
#define E1000_POOL_PAGES(bytes) (((bytes) + 4095u) / 4096u)
#define E1000_RCTL_EN (1u << 1)
#define E1000_RCTL_SBP (1u << 2)
#define E1000_RCTL_UPE (1u << 3)
#define E1000_RCTL_MPE (1u << 4)
#define E1000_RCTL_BAM (1u << 15)
#define E1000_RCTL_SECRC (1u << 26)
#define E1000_RCTL_BSIZE_2048 0u
#define E1000_TCTL_EN (1u << 1)
#define E1000_TCTL_PSP (1u << 3)
#define E1000_TCTL_CT_SHIFT 4
#define E1000_TCTL_COLD_SHIFT 12
#define E1000_TX_CMD_EOP (1u << 0)
#define E1000_TX_CMD_IFCS (1u << 1)
#define E1000_TX_CMD_RS (1u << 3)
#define E1000_TX_STA_DD (1u << 0)
#define E1000_RX_STA_DD (1u << 0)
#define E1000_CTRL_FD (1u << 0)
#define E1000_CTRL_SLU (1u << 6)
struct e1000_rx_desc {
u64 addr;
u16 length;
u16 checksum;
u8 status;
u8 errors;
u16 special;
} __attribute__((packed));
struct e1000_tx_desc {
u64 addr;
u16 length;
u8 cso;
u8 cmd;
u8 status;
u8 css;
u16 special;
} __attribute__((packed));
static const struct dkm_log_api *g_log;
static volatile u32 *g_mmio;
static u64 g_bar0_phys;
static struct e1000_rx_desc *g_rx_desc;
static struct e1000_tx_desc *g_tx_desc;
static u64 g_rx_desc_phys;
static u64 g_tx_desc_phys;
static u8 *g_rx_buf[E1000_RX_DESC_COUNT];
static u64 g_rx_buf_phys[E1000_RX_DESC_COUNT];
static u8 *g_tx_buf[E1000_TX_DESC_COUNT];
static u64 g_tx_buf_phys[E1000_TX_DESC_COUNT];
static u32 g_rx_tail;
static u32 g_tx_tail;
static int g_rings_ready;
static __inline__ void outl(u16 p, u32 v) { __asm__("outl %0,%1"::"a"(v),"Nd"(p)); }
static __inline__ u32 inl(u16 p) { u32 v; __asm__("inl %1,%0":"=a"(v):"Nd"(p)); return v; }
static u8 inb(u16 p) { u8 v; __asm__("inb %1,%0":"=a"(v):"Nd"(p)); return v; }
static void outb(u16 p, u8 v) { __asm__("outb %0,%1"::"a"(v),"Nd"(p)); }
static void raw_log(const char *s) {
while (*s) {
char c = *s++;
if (c == '\n') {
for (u32 i=0;i<100000;i++) if (inb(0x3F8+5)&0x20) break;
outb(0x3F8, '\r');
}
for (u32 i=0;i<100000;i++) if (inb(0x3F8+5)&0x20) break;
outb(0x3F8, (u8)c);
}
}
static u32 pci_read(u8 bus, u8 dev, u8 func, u8 reg) {
u32 a = (1u<<31)|((u32)bus<<16)|((u32)dev<<11)|((u32)func<<8)|((u32)reg&0xFC);
outl(PCI_ADDR,a); return inl(PCI_DATA);
}
static void pci_write(u8 bus, u8 dev, u8 func, u8 reg, u32 v) {
u32 a = (1u<<31)|((u32)bus<<16)|((u32)dev<<11)|((u32)func<<8)|((u32)reg&0xFC);
outl(PCI_ADDR,a); outl(PCI_DATA,v);
}
static int e1000_find(u8 *bus, u8 *dev) {
for (u8 d=0; d<32; d++) {
u32 vd = pci_read(0,d,0,PCI_VENDOR_ID);
if ((vd&0xffff)==0xffff) continue;
if ((vd&0xffff)!=0x8086) continue;
u16 did = (u16)(vd>>16);
/* 82540EM(0x100E) / 82545 等经典 e1000,以及 82574L(0x10D3) e1000e */
if (did==0x100E || did==0x10D3 || did==0x1004 || did==0x100F ||
did==0x10D3 || did==0x153A || did==0x1533) {
*bus=0; *dev=d; return 0;
}
}
return -1;
}
/* 读取 EEPROM 一个 16-bit 字(经典 e1000 EERD 接口)。失败返回 0xffff。 */
static u16 e1000_eeprom_read(u16 addr) {
/* EERD: bit0=START, addr<<8, 完成后 bit4=DONE, data 在高 16 位 */
g_mmio[E1000_EERD/4] = ((u32)addr << 8) | 1u;
for (u32 i=0;i<100000;i++) {
u32 v = g_mmio[E1000_EERD/4];
if (v & (1u<<4)) return (u16)(v >> 16);
}
return 0xffff;
}
static int irq_handler(u8 irq) {
(void)irq;
if (!g_mmio) return 0;
u32 icr = g_mmio[E1000_ICR/4];
if (icr) {
g_mmio[E1000_ICR/4] = icr; /* clear */
}
return 0;
}
static void copy_bytes(void *dst, const void *src, u32 len) {
u8 *d = (u8 *)dst;
const u8 *s = (const u8 *)src;
for (u32 i=0;i<len;i++) d[i]=s[i];
}
static int e1000_init_rings(const struct dkm_dma_api *dma) {
if (!dma || !dma->alloc_pages || !g_mmio) return -1;
struct dkm_dma_buffer rx_ring, tx_ring;
if (dma->alloc_pages(1, 16, 0x100000000ULL, &rx_ring) != 0) return -2;
if (dma->alloc_pages(1, 16, 0x100000000ULL, &tx_ring) != 0) return -3;
g_rx_desc = (struct e1000_rx_desc *)rx_ring.virt;
g_tx_desc = (struct e1000_tx_desc *)tx_ring.virt;
g_rx_desc_phys = rx_ring.phys;
g_tx_desc_phys = tx_ring.phys;
for (u32 i=0;i<E1000_RX_DESC_COUNT;i++) {
struct dkm_dma_buffer b;
if (dma->alloc_pages(1, 16, 0x100000000ULL, &b) != 0) return -4;
g_rx_buf[i] = (u8 *)b.virt;
g_rx_buf_phys[i] = b.phys;
g_rx_desc[i].addr = b.phys;
g_rx_desc[i].status = 0;
}
for (u32 i=0;i<E1000_TX_DESC_COUNT;i++) {
struct dkm_dma_buffer b;
if (dma->alloc_pages(1, 16, 0x100000000ULL, &b) != 0) return -5;
g_tx_buf[i] = (u8 *)b.virt;
g_tx_buf_phys[i] = b.phys;
g_tx_desc[i].addr = b.phys;
g_tx_desc[i].status = E1000_TX_STA_DD;
}
raw_log("[e1000.raw] ring/buffers allocated\n");
g_mmio[E1000_RCTL/4] = 0;
g_mmio[E1000_TCTL/4] = 0;
g_mmio[E1000_RDBAL/4] = (u32)(g_rx_desc_phys & 0xffffffffu);
g_mmio[E1000_RDBAH/4] = (u32)(g_rx_desc_phys >> 32);
g_mmio[E1000_RDLEN/4] = E1000_RX_DESC_COUNT * sizeof(struct e1000_rx_desc);
g_mmio[E1000_RDH/4] = 0;
g_rx_tail = E1000_RX_DESC_COUNT - 1;
g_mmio[E1000_RDT/4] = g_rx_tail;
g_mmio[E1000_TDBAL/4] = (u32)(g_tx_desc_phys & 0xffffffffu);
g_mmio[E1000_TDBAH/4] = (u32)(g_tx_desc_phys >> 32);
g_mmio[E1000_TDLEN/4] = E1000_TX_DESC_COUNT * sizeof(struct e1000_tx_desc);
g_mmio[E1000_TDH/4] = 0;
g_tx_tail = 0;
g_mmio[E1000_TDT/4] = 0;
/* e1000e/部分实现需要显式打开队列描述符控制;经典 e1000 会忽略/兼容。 */
g_mmio[E1000_RXDCTL/4] = (1u << 25);
g_mmio[E1000_TXDCTL/4] = (1u << 25);
g_mmio[E1000_TIPG/4] = 0x0060200Au;
g_mmio[E1000_RCTL/4] = E1000_RCTL_EN | E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_BAM | E1000_RCTL_SECRC | E1000_RCTL_BSIZE_2048;
g_mmio[E1000_TCTL/4] = E1000_TCTL_EN | E1000_TCTL_PSP | (0x0Fu << E1000_TCTL_CT_SHIFT) | (0x40u << E1000_TCTL_COLD_SHIFT);
g_rings_ready = 1;
raw_log("[e1000.raw] RX/TX rings initialized\n");
return 0;
}
static int e1000_tx(void *ctx, const void *packet, u32 length) {
(void)ctx;
raw_log("[e1000.raw] tx enter\n");
if (!g_rings_ready || !packet || length == 0 || length > E1000_RX_BUF_SIZE) return -1;
u32 index = g_tx_tail;
if (!(g_tx_desc[index].status & E1000_TX_STA_DD)) return -2;
copy_bytes(g_tx_buf[index], packet, length);
raw_log("[e1000.raw] tx copied\n");
g_tx_desc[index].length = (u16)length;
g_tx_desc[index].cmd = E1000_TX_CMD_EOP | E1000_TX_CMD_IFCS | E1000_TX_CMD_RS;
g_tx_desc[index].status = 0;
g_tx_tail = (index + 1) % E1000_TX_DESC_COUNT;
g_mmio[E1000_TDT/4] = g_tx_tail;
raw_log("[e1000.raw] tx tdt written\n");
return 0;
}
static int e1000_rx_poll(void *ctx, void *buffer, u32 capacity, u32 *out_length) {
(void)ctx;
if (!g_rings_ready || !buffer || !out_length) return -1;
u32 next = (g_rx_tail + 1) % E1000_RX_DESC_COUNT;
if (!(g_rx_desc[next].status & E1000_RX_STA_DD)) return 1;
u32 len = g_rx_desc[next].length;
if (len > capacity) return -2;
copy_bytes(buffer, g_rx_buf[next], len);
*out_length = len;
g_rx_desc[next].status = 0;
g_rx_tail = next;
g_mmio[E1000_RDT/4] = g_rx_tail;
return 0;
}
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
raw_log("[e1000.raw] driver_init entered\n");
(void)handle;
if (!api||!api->log) return -1;
g_log=api->log;
raw_log("[e1000.raw] before find\n");
u8 bus, dev;
if (e1000_find(&bus,&dev)!=0) {
raw_log("[e1000.raw] device not found\n");
return 0;
}
raw_log("[e1000.raw] found device\n");
u32 cmd = pci_read(bus, dev, 0, PCI_COMMAND);
cmd |= 0x0007u; /* IO Space | Memory Space | Bus Master */
pci_write(bus, dev, 0, PCI_COMMAND, cmd);
raw_log("[e1000.raw] PCI command enabled\n");
g_bar0_phys = (u64)pci_read(bus,dev,0,PCI_BAR0) & 0xFFFFFFF0ULL;
if (!g_bar0_phys) {
raw_log("[e1000.raw] BAR0 unavailable\n");
return 0;
}
raw_log("[e1000.raw] BAR0 ok\n");
u64 hhdm = api->hhdm_offset;
g_mmio = (volatile u32*)(uintptr_t)(hhdm + g_bar0_phys);
(void)g_mmio[E1000_STATUS/4];
raw_log("[e1000.raw] MMIO status read ok\n");
/* 软件复位,确保 RX/TX/RAL/RAH 从已知状态开始配置。 */
g_mmio[E1000_CTRL/4] = g_mmio[E1000_CTRL/4] | (1u << 26);
for (u32 wait=0; wait<1000000; wait++) {
if (!(g_mmio[E1000_CTRL/4] & (1u << 26))) break;
}
raw_log("[e1000.raw] reset done\n");
u32 ral = g_mmio[E1000_RAL/4];
u32 rah = g_mmio[E1000_RAH/4];
u8 mac[6];
mac[0] = (u8)(ral & 0xff);
mac[1] = (u8)((ral>>8) & 0xff);
mac[2] = (u8)((ral>>16) & 0xff);
mac[3] = (u8)((ral>>24) & 0xff);
mac[4] = (u8)(rah & 0xff);
mac[5] = (u8)((rah>>8) & 0xff);
/* RAL/RAH 为空时从 EEPROM 读 MAC */
if (ral == 0 && (rah & 0xffff) == 0) {
u16 w0 = e1000_eeprom_read(0);
u16 w1 = e1000_eeprom_read(1);
u16 w2 = e1000_eeprom_read(2);
if (!(w0==0xffff && w1==0xffff && w2==0xffff)) {
mac[0]=(u8)(w0&0xff); mac[1]=(u8)(w0>>8);
mac[2]=(u8)(w1&0xff); mac[3]=(u8)(w1>>8);
mac[4]=(u8)(w2&0xff); mac[5]=(u8)(w2>>8);
}
}
/* 仍为全 0 时使用与虚拟机配置一致的回退 MAC,保证收发地址匹配 */
if (mac[0]==0&&mac[1]==0&&mac[2]==0&&mac[3]==0&&mac[4]==0&&mac[5]==0) {
mac[0]=0x52; mac[1]=0x54; mac[2]=0x00; mac[3]=0x12; mac[4]=0x34; mac[5]=0x56;
raw_log("[e1000.raw] using fallback MAC 52:54:00:12:34:56\n");
}
/* 写入 RAL/RAH 并置 AV(bit31) 使能接收该单播地址 */
g_mmio[E1000_RAL/4] = (u32)mac[0] | ((u32)mac[1]<<8) | ((u32)mac[2]<<16) | ((u32)mac[3]<<24);
g_mmio[E1000_RAH/4] = (u32)mac[4] | ((u32)mac[5]<<8) | (1u<<31);
raw_log("[e1000.raw] MAC read ok\n");
u32 irq_line = pci_read(bus,dev,0,PCI_IRQ_LINE) & 0xff;
g_mmio[E1000_CTRL/4] = g_mmio[E1000_CTRL/4] | E1000_CTRL_FD | E1000_CTRL_SLU;
raw_log("[e1000.raw] link setup\n");
g_mmio[E1000_IMC/4] = 0xffffffffu;
(void)g_mmio[E1000_ICR/4];
raw_log("[e1000.raw] interrupts masked\n");
int ring_rc = e1000_init_rings(api->dma);
if (ring_rc != 0) raw_log("[e1000.raw] ring init failed\n");
if (api->net && api->net->register_device) {
struct dkm_net_device_desc netdev;
netdev.name = "e1000";
for (int i=0;i<6;i++) netdev.mac[i] = mac[i];
netdev.flags = DKM_NET_F_LINK_UP;
if (g_rings_ready) netdev.flags |= DKM_NET_F_TX_READY | DKM_NET_F_RX_READY;
netdev.ctx = 0;
netdev.tx = g_rings_ready ? e1000_tx : 0;
netdev.rx_poll = g_rings_ready ? e1000_rx_poll : 0;
int net_index = api->net->register_device(&netdev);
(void)net_index;
raw_log("[e1000.raw] netdev registered\n");
} else {
raw_log("[e1000.raw] net API unavailable\n");
}
g_mmio[E1000_IMC/4] = 0xffffffffu;
if (api->irq_register && irq_line < 16) {
api->irq_register((u8)irq_line, (void*)(uintptr_t)irq_handler);
raw_log("[e1000.raw] IRQ registered\n");
}
raw_log("[e1000.raw] driver ready\n");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle; return 0;
}
+307
View File
@@ -0,0 +1,307 @@
/* DKM FAT32 Driver — read-only FAT32 filesystem parser
* Stage 2, optional, depends on "vfs" and "block".
* Reads from an embedded FAT32 test image (boot module "dkm:test_fat32").
* Parses BPB, walks FAT, reads root dir, lists files, reads a file.
*/
#include <stdint.h>
/* ---------------------------------------------------------------
* DKM ABI types
* --------------------------------------------------------------- */
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_block_api {
int (*register_device)(const void *desc);
u32 (*device_count)(void);
int (*read)(u32 index, u64 lba, u32 count, void *buffer);
u64 (*sector_size)(u32 index);
const char *(*device_name)(u32 index);
};
struct dkm_kernel_api {
u32 version; u32 size; u64 feature_bits;
const struct dkm_log_api *log;
const void *mem,*utsm,*irq,*pci_api,*dma,*vfs_api,*net,*timer,*drr;
const void *rsdp_address;
const void *fb_address;
u64 fb_width,fb_height,fb_pitch; u16 fb_bpp;
const void *boot_modules_response;
int (*irq_register)(u8 irq, void *handler);
u64 hhdm_offset;
const struct dkm_block_api *block;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic; u16 abi_version; u16 desc_size;
const char *name,*version,*vendor;
u32 driver_class,stage,flags,priority;
const char *const *depends; u32 depends_count;
const char *const *provides; u32 provides_count;
u64 min_kernel_abi,feature_bits,reserved0,reserved1;
};
struct limine_file {
u64 revision; void *address; u64 size; char *path; char *cmdline; u8 _pad[56];
};
struct limine_module_response {
u64 revision; u64 module_count; struct limine_file **modules;
};
/* ---------------------------------------------------------------
* FAT32 BPB
* --------------------------------------------------------------- */
typedef struct __attribute__((packed)) {
u8 jmp[3];
char oem[8];
u16 bytes_per_sector;
u8 sectors_per_cluster;
u16 reserved_sector_count;
u8 fat_count;
u16 root_entry_count;
u16 total_sectors_16;
u8 media;
u16 sectors_per_fat_16;
u16 sectors_per_track;
u16 heads;
u32 hidden_sectors;
u32 total_sectors_32;
/* FAT32 extended */
u32 sectors_per_fat;
u16 flags;
u16 version;
u32 root_cluster;
u16 fsinfo_sector;
u16 backup_boot;
u8 reserved[12];
u8 drive;
u8 nt_flags;
u8 signature;
u32 serial;
char label[11];
char type[8];
u8 code[420];
u16 boot_sig;
} fat32_bpb;
typedef struct __attribute__((packed)) {
char name[11];
u8 attr;
u8 nt_reserved;
u8 creation_tenth;
u16 creation_time;
u16 creation_date;
u16 access_date;
u16 cluster_high;
u16 write_time;
u16 write_date;
u16 cluster_low;
u32 file_size;
} fat32_dir_entry;
/* ---------------------------------------------------------------
* Driver descriptor
* --------------------------------------------------------------- */
static const char *const g_depends[] = { "vfs", "block" };
static const char *const g_provides[] = { "fat32" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic=DKM_DRIVER_MAGIC, .abi_version=DKM_ABI_VERSION,
.desc_size=sizeof(struct dkm_driver_desc),
.name="fat32", .version="0.1.0", .vendor="Deshab",
.driver_class=7, .stage=2, .flags=0, .priority=0,
.depends=g_depends, .depends_count=2,
.provides=g_provides, .provides_count=1,
.min_kernel_abi=1,
};
/* ---------------------------------------------------------------
* Helpers
* --------------------------------------------------------------- */
static const struct dkm_log_api *g_log;
static u8 g_block_image[65536];
static int fat32_bpb_valid(const u8 *disk, u64 disk_size) {
if (!disk || disk_size < 512) return 0;
const fat32_bpb *bpb = (const fat32_bpb *)disk;
if (bpb->boot_sig != 0xAA55) return 0;
if (bpb->bytes_per_sector != 512) return 0;
if (bpb->sectors_per_cluster == 0) return 0;
if (bpb->reserved_sector_count == 0) return 0;
if (bpb->fat_count == 0) return 0;
if (bpb->sectors_per_fat == 0) return 0;
if (bpb->root_cluster < 2) return 0;
return 1;
}
static void log_hex(const char *p, u64 v) {
static const char h[] = "0123456789abcdef";
char b[19]; u32 i=0; b[i++]='0'; b[i++]='x';
for (int j=15;j>=0;j--) b[i++]=h[(v>>(j*4))&0xf];
b[i]=0; g_log->info(p); g_log->info(b);
}
static u32 read_u32_le(const u8 *p) {
return (u32)p[0]|((u32)p[1]<<8)|((u32)p[2]<<16)|((u32)p[3]<<24);
}
static u16 read_u16_le(const u8 *p) {
return (u16)p[0]|((u16)p[1]<<8);
}
static int strneq(const char *a, const char *b, int n) {
for (int i=0;i<n;i++) { if (a[i]!=b[i]) return 0; }
return 1;
}
static void log_name11(const char *n) {
char buf[13]; int j=0;
for (int i=0;i<8 && n[i]!=0x20 && n[i];i++) buf[j++]=n[i];
if (n[8]!=0x20 || (n[9]!=0x20 && n[9]!=0)) {
buf[j++]='.';
for (int i=8;i<11 && n[i]!=0x20 && n[i];i++) buf[j++]=n[i];
}
buf[j]=0; g_log->info(buf);
}
static const u8 *fat32_find_boot_module_image(const struct dkm_kernel_api *api, u64 *size_out) {
const struct limine_module_response *rsp =
(const struct limine_module_response *)api->boot_modules_response;
if (!rsp) return NULL;
for (u64 i=0;i<rsp->module_count;i++) {
struct limine_file *f=rsp->modules[i];
if (f&&f->cmdline&&strneq(f->cmdline,"dkm:test_fat32",13)) {
if (size_out) *size_out=f->size;
return (const u8*)f->address;
}
}
return NULL;
}
static const u8 *fat32_select_disk_image(const struct dkm_kernel_api *api, u64 *size_out) {
if (api->block && api->block->device_count && api->block->read && api->block->sector_size) {
u32 count = api->block->device_count();
log_hex("[fat32] block devices=", count);
if (count > 0 && api->block->sector_size(0) == 512) {
const char *name = api->block->device_name ? api->block->device_name(0) : NULL;
g_log->info("[fat32] trying block provider");
if (name) g_log->info(name);
int st = api->block->read(0, 0, 128, g_block_image);
log_hex("[fat32] block read status=", (u64)(i64)st);
if (st == 0 && fat32_bpb_valid(g_block_image, sizeof(g_block_image))) {
g_log->info("[fat32] using block provider image");
if (size_out) *size_out = sizeof(g_block_image);
return g_block_image;
}
g_log->warn("[fat32] block provider image is not FAT32; fallback");
}
}
u64 module_size = 0;
const u8 *module = fat32_find_boot_module_image(api, &module_size);
if (module) {
g_log->info("[fat32] using boot module image");
if (size_out) *size_out = module_size;
return module;
}
return NULL;
}
/* ---------------------------------------------------------------
* Driver entry
* --------------------------------------------------------------- */
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api||!api->log) return -1;
g_log=api->log;
u64 disk_size = 0;
const u8 *disk = fat32_select_disk_image(api, &disk_size);
if (!disk) { g_log->warn("[fat32] no FAT32 image source"); return 0; }
if (!fat32_bpb_valid(disk, disk_size)) { g_log->warn("[fat32] invalid FAT32 BPB"); return 0; }
g_log->info("[fat32] parsing FAT32 image");
const fat32_bpb *bpb=(const fat32_bpb*)disk;
u32 bps=bpb->bytes_per_sector;
u32 spc=bpb->sectors_per_cluster;
u32 rsc=bpb->reserved_sector_count;
u32 spf=bpb->sectors_per_fat;
u32 root_clus=bpb->root_cluster;
log_hex("[fat32] bytes/sec=",bps);
log_hex("[fat32] sec/cluster=",spc);
log_hex("[fat32] fat start sec=",rsc);
log_hex("[fat32] sec/fat=",spf);
log_hex("[fat32] root cluster=",root_clus);
/* read root directory */
u32 cluster_size = bps * spc;
u32 fat_start = rsc * bps;
u32 data_start = fat_start + spf * bps;
g_log->info("[fat32] root dir entries:");
u32 clus = root_clus;
while (clus >= 2 && clus < 0x0FFFFFF8) {
u32 clus_off = data_start + (clus - 2) * cluster_size;
const fat32_dir_entry *dir = (const fat32_dir_entry *)(disk + clus_off);
for (u32 e=0; e*32 < cluster_size; e++) {
if (dir[e].name[0]==0) break;
if ((u8)dir[e].name[0]==0xE5) continue;
if (dir[e].attr==0x0F) continue; /* skip LFN */
if (dir[e].attr & 0x08) continue; /* skip volume label */
g_log->info("[fat32] ");
log_name11(dir[e].name);
log_hex("[fat32] size=",dir[e].file_size);
/* try to read README.TXT content */
if (strneq(dir[e].name,"README TXT",11)) {
u32 f_clus = read_u16_le((const u8*)&dir[e].cluster_low);
u32 f_off = data_start + (f_clus - 2)*cluster_size;
u32 f_size = dir[e].file_size;
g_log->info("[fat32] --- README.TXT content ---");
u32 n = f_size < 128 ? f_size : 128;
char line[80]; u32 lp=0;
for (u32 k=0;k<n;k++) {
u8 c = disk[f_off+k];
line[lp++]=c;
if (c=='\n'||lp>=78||k==n-1) { line[lp]=0; g_log->info("[fat32] "); g_log->info(line); lp=0; }
}
g_log->info("[fat32] --- end ---");
}
}
/* read next cluster from FAT */
u32 fat_ent_off = fat_start + clus * 4;
clus = read_u32_le(disk + fat_ent_off) & 0x0FFFFFFF;
}
g_log->info("[fat32] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle; return 0;
}
+347
View File
@@ -0,0 +1,347 @@
/* DKM NVMe Driver — PCI NVMe discovery and controller register enumeration
* Stage 1 optional storage driver, depends on "pci" and "irq", provides "block".
* This first version only discovers NVMe controllers and reads BAR0 registers;
* it does not enable queues or submit admin commands.
*/
#include <stdint.h>
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_kernel_api {
u32 version;
u32 size;
u64 feature_bits;
const struct dkm_log_api *log;
const void *mem;
const void *utsm;
const void *irq;
const void *pci;
const void *dma;
const void *vfs;
const void *net;
const void *timer;
const void *drr;
const void *rsdp_address;
const void *fb_address;
u64 fb_width;
u64 fb_height;
u64 fb_pitch;
u16 fb_bpp;
const void *boot_modules_response;
int (*irq_register)(u8 irq, void *handler);
u64 hhdm_offset;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic;
u16 abi_version;
u16 desc_size;
const char *name;
const char *version;
const char *vendor;
u32 driver_class;
u32 stage;
u32 flags;
u32 priority;
const char *const *depends;
u32 depends_count;
const char *const *provides;
u32 provides_count;
u64 min_kernel_abi;
u64 feature_bits;
u64 reserved0;
u64 reserved1;
};
static const char *const g_depends[] = { "pci", "irq" };
static const char *const g_provides[] = { "block" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC,
.abi_version = DKM_ABI_VERSION,
.desc_size = sizeof(struct dkm_driver_desc),
.name = "nvme",
.version = "0.1.0",
.vendor = "Deshab",
.driver_class = 6, /* DKM_CLASS_STORAGE */
.stage = 1,
.flags = 0, /* optional */
.priority = 0,
.depends = g_depends,
.depends_count = 2,
.provides = g_provides,
.provides_count = 1,
.min_kernel_abi = 1,
.feature_bits = 0,
.reserved0 = 0,
.reserved1 = 0
};
#define PCI_ADDR 0xCF8
#define PCI_DATA 0xCFC
#define PCI_VENDOR_ID 0x00
#define PCI_COMMAND 0x04
#define PCI_CLASS_REG 0x08
#define PCI_HEADER 0x0E
#define PCI_BAR0 0x10
#define PCI_BAR1 0x14
#define PCI_IRQ_LINE 0x3C
#define PCI_CMD_MEM (1u << 1)
#define PCI_CMD_BUSM (1u << 2)
#define NVME_CLASS_STORAGE 0x01
#define NVME_SUBCLASS_NVM 0x08
#define NVME_PROGIF_NVME 0x02
#define NVME_CAP 0x00
#define NVME_VS 0x08
#define NVME_INTMS 0x0C
#define NVME_INTMC 0x10
#define NVME_CC 0x14
#define NVME_CSTS 0x1C
#define NVME_NSSR 0x20
#define NVME_AQA 0x24
#define NVME_ASQ 0x28
#define NVME_ACQ 0x30
#define NVME_CMBLOC 0x38
#define NVME_CMBSZ 0x3C
static const struct dkm_log_api *g_log;
static volatile u8 *g_regs;
static __inline__ void outl(u16 port, u32 value) {
__asm__ volatile ("outl %0, %1" :: "a"(value), "Nd"(port));
}
static __inline__ u32 inl(u16 port) {
u32 value;
__asm__ volatile ("inl %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
static u32 pci_read(u8 bus, u8 dev, u8 func, u8 reg) {
u32 addr = (1u << 31)
| ((u32)bus << 16)
| ((u32)dev << 11)
| ((u32)func << 8)
| ((u32)reg & 0xFC);
outl(PCI_ADDR, addr);
return inl(PCI_DATA);
}
static void pci_write(u8 bus, u8 dev, u8 func, u8 reg, u32 value) {
u32 addr = (1u << 31)
| ((u32)bus << 16)
| ((u32)dev << 11)
| ((u32)func << 8)
| ((u32)reg & 0xFC);
outl(PCI_ADDR, addr);
outl(PCI_DATA, value);
}
static u32 mmio_read32(u32 off) {
return *(volatile u32 *)(void *)(g_regs + off);
}
static u64 mmio_read64(u32 off) {
u32 lo = mmio_read32(off);
u32 hi = mmio_read32(off + 4);
return ((u64)hi << 32) | lo;
}
static void log_hex(const char *prefix, u64 value) {
static const char hex[] = "0123456789abcdef";
char buf[19];
u32 pos = 0;
buf[pos++] = '0';
buf[pos++] = 'x';
for (int i = 15; i >= 0; i--) {
buf[pos++] = hex[(value >> (i * 4)) & 0xf];
}
buf[pos] = 0;
g_log->info(prefix);
g_log->info(buf);
}
static int nvme_find(u8 *out_bus, u8 *out_dev, u8 *out_func) {
for (u8 bus = 0; bus < 16; bus++) {
for (u8 dev = 0; dev < 32; dev++) {
u32 vd = pci_read(bus, dev, 0, PCI_VENDOR_ID);
if ((vd & 0xffff) == 0xffff) continue;
u8 header = (u8)(pci_read(bus, dev, 0, PCI_HEADER) >> 16);
u8 func_count = (header & 0x80) ? 8 : 1;
for (u8 func = 0; func < func_count; func++) {
u32 vd2 = pci_read(bus, dev, func, PCI_VENDOR_ID);
if ((vd2 & 0xffff) == 0xffff) continue;
u32 class_reg = pci_read(bus, dev, func, PCI_CLASS_REG);
u8 prog_if = (u8)((class_reg >> 8) & 0xff);
u8 subclass = (u8)((class_reg >> 16) & 0xff);
u8 class_code = (u8)((class_reg >> 24) & 0xff);
if (class_code == NVME_CLASS_STORAGE &&
subclass == NVME_SUBCLASS_NVM &&
prog_if == NVME_PROGIF_NVME) {
*out_bus = bus;
*out_dev = dev;
*out_func = func;
return 0;
}
}
}
}
return -1;
}
static void log_nvme_version(u32 vs) {
log_hex("[nvme] version major=", (vs >> 16) & 0xffff);
log_hex("[nvme] version minor=", (vs >> 8) & 0xff);
log_hex("[nvme] version tertiary=", vs & 0xff);
}
static void log_cap_fields(u64 cap) {
log_hex("[nvme] CAP.MQES=", cap & 0xffff);
log_hex("[nvme] CAP.CQR=", (cap >> 16) & 1);
log_hex("[nvme] CAP.AMS=", (cap >> 17) & 3);
log_hex("[nvme] CAP.TO=", (cap >> 24) & 0xff);
log_hex("[nvme] CAP.DSTRD=", (cap >> 32) & 0xf);
log_hex("[nvme] CAP.NSSRS=", (cap >> 36) & 1);
log_hex("[nvme] CAP.CSS=", (cap >> 37) & 0xff);
log_hex("[nvme] CAP.MPSMIN=", (cap >> 48) & 0xf);
log_hex("[nvme] CAP.MPSMAX=", (cap >> 52) & 0xf);
}
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) return -1;
g_log = api->log;
g_log->info("[nvme] init begin");
u8 bus = 0;
u8 dev = 0;
u8 func = 0;
if (nvme_find(&bus, &dev, &func) != 0) {
g_log->warn("[nvme] NVMe controller not found");
g_log->info("[nvme] driver ready");
return 0;
}
g_log->info("[nvme] NVMe controller found");
log_hex("[nvme] bus=", bus);
log_hex("[nvme] dev=", dev);
log_hex("[nvme] func=", func);
u32 vd = pci_read(bus, dev, func, PCI_VENDOR_ID);
log_hex("[nvme] vendor=", vd & 0xffff);
log_hex("[nvme] device=", vd >> 16);
u32 command = pci_read(bus, dev, func, PCI_COMMAND) & 0xffff;
command |= PCI_CMD_MEM | PCI_CMD_BUSM;
pci_write(bus, dev, func, PCI_COMMAND, command);
log_hex("[nvme] PCI command=", command);
u32 bar0_lo = pci_read(bus, dev, func, PCI_BAR0);
u32 bar1_hi = pci_read(bus, dev, func, PCI_BAR1);
u64 bar_phys;
if (bar0_lo & 1u) {
g_log->warn("[nvme] BAR0 is IO space; unsupported");
g_log->info("[nvme] driver ready");
return 0;
}
if ((bar0_lo & 0x6u) == 0x4u) {
bar_phys = ((u64)bar1_hi << 32) | (u64)(bar0_lo & 0xFFFFFFF0u);
} else {
bar_phys = (u64)(bar0_lo & 0xFFFFFFF0u);
}
u32 irq_line = pci_read(bus, dev, func, PCI_IRQ_LINE) & 0xff;
log_hex("[nvme] BAR0 phys=", bar_phys);
log_hex("[nvme] PCI IRQ line=", irq_line);
if (!api->hhdm_offset || !bar_phys) {
g_log->warn("[nvme] missing HHDM or BAR0; skip MMIO enumeration");
g_log->info("[nvme] driver ready");
return 0;
}
if (bar_phys >= 0x100000000ULL) {
g_log->warn("[nvme] BAR0 is above 4G; current HHDM MMIO map cannot safely read it");
g_log->info("[nvme] discovery only; MMIO enumeration skipped");
g_log->info("[nvme] driver ready");
return 0;
}
g_regs = (volatile u8 *)(uintptr_t)(api->hhdm_offset + bar_phys);
log_hex("[nvme] HHDM offset=", api->hhdm_offset);
u64 cap = mmio_read64(NVME_CAP);
u32 vs = mmio_read32(NVME_VS);
u32 intms = mmio_read32(NVME_INTMS);
u32 intmc = mmio_read32(NVME_INTMC);
u32 cc = mmio_read32(NVME_CC);
u32 csts = mmio_read32(NVME_CSTS);
u32 nssr = mmio_read32(NVME_NSSR);
u32 aqa = mmio_read32(NVME_AQA);
u64 asq = mmio_read64(NVME_ASQ);
u64 acq = mmio_read64(NVME_ACQ);
u32 cmbloc = mmio_read32(NVME_CMBLOC);
u32 cmbsz = mmio_read32(NVME_CMBSZ);
log_hex("[nvme] CAP=", cap);
log_cap_fields(cap);
log_hex("[nvme] VS=", vs);
log_nvme_version(vs);
log_hex("[nvme] INTMS=", intms);
log_hex("[nvme] INTMC=", intmc);
log_hex("[nvme] CC=", cc);
log_hex("[nvme] CSTS=", csts);
log_hex("[nvme] NSSR=", nssr);
log_hex("[nvme] AQA=", aqa);
log_hex("[nvme] ASQ=", asq);
log_hex("[nvme] ACQ=", acq);
log_hex("[nvme] CMBLOC=", cmbloc);
log_hex("[nvme] CMBSZ=", cmbsz);
if (cc & 1u) {
g_log->warn("[nvme] controller already enabled; leaving state unchanged");
} else {
g_log->info("[nvme] controller disabled; queues not configured");
}
g_log->info("[nvme] discovery only; admin queues disabled");
g_log->info("[nvme] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}
+251
View File
@@ -0,0 +1,251 @@
/* DKM PCI Driver — PCI bus enumeration via config space (0xCF8/0xCFC)
* Stage 0, required, depends on "irq", provides "pci".
* No IRQ needed for enumeration. Scans all buses/devices/functions.
*/
#include <stdint.h>
/* ---------------------------------------------------------------
* DKM ABI types
* --------------------------------------------------------------- */
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_kernel_api {
u32 version;
u32 size;
u64 feature_bits;
const struct dkm_log_api *log;
const void *mem;
const void *utsm;
const void *irq;
const void *pci_api;
const void *dma;
const void *vfs;
const void *net;
const void *timer;
const void *drr;
const void *rsdp_address;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic;
u16 abi_version;
u16 desc_size;
const char *name;
const char *version;
const char *vendor;
u32 driver_class;
u32 stage;
u32 flags;
u32 priority;
const char *const *depends;
u32 depends_count;
const char *const *provides;
u32 provides_count;
u64 min_kernel_abi;
u64 feature_bits;
u64 reserved0;
u64 reserved1;
};
/* ---------------------------------------------------------------
* PCI constants
* --------------------------------------------------------------- */
#define PCI_CFG_ADDR 0xCF8
#define PCI_CFG_DATA 0xCFC
#define PCI_VENDOR_ID 0x00
#define PCI_DEVICE_ID 0x02
#define PCI_COMMAND 0x04
#define PCI_STATUS 0x06
#define PCI_CLASS 0x0B /* class code */
#define PCI_SUBCLASS 0x0A /* subclass */
#define PCI_PROG_IF 0x09 /* prog IF */
#define PCI_HEADER_TYPE 0x0E
#define PCI_BAR0 0x10
/* ---------------------------------------------------------------
* Driver descriptor
* --------------------------------------------------------------- */
static const char *const g_depends[] = { "irq" };
static const char *const g_provides[] = { "pci" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC,
.abi_version = DKM_ABI_VERSION,
.desc_size = sizeof(struct dkm_driver_desc),
.name = "pci",
.version = "0.1.0",
.vendor = "Deshab",
.driver_class = 2, /* DKM_CLASS_BUS */
.stage = 0,
.flags = 1, /* DKM_F_REQUIRED */
.priority = 0,
.depends = g_depends,
.depends_count = 1,
.provides = g_provides,
.provides_count = 1,
.min_kernel_abi = 1,
.feature_bits = 0,
.reserved0 = 0,
.reserved1 = 0
};
/* ---------------------------------------------------------------
* I/O helpers
* --------------------------------------------------------------- */
static const struct dkm_log_api *g_log;
static __inline__ void outl(u16 port, u32 value) {
__asm__ volatile ("outl %0, %1" :: "a"(value), "Nd"(port));
}
static __inline__ u32 inl(u16 port) {
u32 value;
__asm__ volatile ("inl %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
/* ---------------------------------------------------------------
* PCI config access
* --------------------------------------------------------------- */
static u32 pci_cfg_read(u8 bus, u8 dev, u8 func, u8 reg) {
u32 addr = (u32)((1u << 31)
| ((u32)bus << 16)
| ((u32)dev << 11)
| ((u32)func << 8)
| ((u32)reg & 0xFC));
outl(PCI_CFG_ADDR, addr);
return inl(PCI_CFG_DATA);
}
static void pci_cfg_write(u8 bus, u8 dev, u8 func, u8 reg, u32 val) {
u32 addr = (u32)((1u << 31)
| ((u32)bus << 16)
| ((u32)dev << 11)
| ((u32)func << 8)
| ((u32)reg & 0xFC));
outl(PCI_CFG_ADDR, addr);
outl(PCI_CFG_DATA, val);
}
/* ---------------------------------------------------------------
* Log helpers
* --------------------------------------------------------------- */
static void log_hex(const char *prefix, u64 val) {
static const char hex[] = "0123456789abcdef";
char buf[19];
u32 pos = 0;
buf[pos++] = '0'; buf[pos++] = 'x';
for (int i = 15; i >= 0; i--) {
buf[pos++] = hex[(val >> (i * 4)) & 0xf];
}
buf[pos] = 0;
g_log->info(prefix);
g_log->info(buf);
}
static const char *pci_class_name(u8 base, u8 sub) {
switch (base) {
case 0x00: return "Legacy";
case 0x01: return "Storage";
case 0x02: return "Network";
case 0x03: return "Display";
case 0x04: return "Multimedia";
case 0x05: return "Memory";
case 0x06: return "Bridge";
case 0x07: return "SimpleComm";
case 0x08: return "BasePeriph";
case 0x09: return "Input";
case 0x0A: return "Docking";
case 0x0B: return "CPU";
case 0x0C: return "SerialBus";
case 0x0D: return "Wireless";
case 0x0E: return "IntelligentIO";
case 0x0F: return "Satellite";
case 0x10: return "Crypto";
case 0x11: return "SignalProc";
case 0x12: return "Accelerator";
default: return "Unknown";
}
(void)sub;
}
/* ---------------------------------------------------------------
* Enumeration
* --------------------------------------------------------------- */
static void pci_scan_bus(u8 bus) {
for (u8 dev = 0; dev < 32; dev++) {
u32 vid_dev = pci_cfg_read(bus, dev, 0, PCI_VENDOR_ID);
u16 vendor = (u16)(vid_dev & 0xffff);
if (vendor == 0xffff) continue;
u8 header_type = (u8)(pci_cfg_read(bus, dev, 0, PCI_HEADER_TYPE) >> 16);
int multi_func = (header_type & 0x80) != 0;
u8 func_count = multi_func ? 8 : 1;
for (u8 func = 0; func < func_count; func++) {
u32 vid_dev2 = pci_cfg_read(bus, dev, func, PCI_VENDOR_ID);
u16 vendor2 = (u16)(vid_dev2 & 0xffff);
if (vendor2 == 0xffff) continue;
u16 device = (u16)(vid_dev2 >> 16);
u32 cc = pci_cfg_read(bus, dev, func, PCI_CLASS);
u8 class_code = (u8)(cc >> 24);
u8 subclass = (u8)((cc >> 16) & 0xff);
g_log->info("[pci]");
log_hex("[pci] bus=", bus);
log_hex("[pci] dev=", dev);
log_hex("[pci] func=", func);
log_hex("[pci] vendor=", vendor2);
log_hex("[pci] device=", device);
g_log->info("[pci] class");
g_log->info(pci_class_name(class_code, subclass));
log_hex("[pci] class_hex=", class_code);
log_hex("[pci] subclass=", subclass);
}
}
}
/* ---------------------------------------------------------------
* Driver entry
* --------------------------------------------------------------- */
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) return -1;
g_log = api->log;
g_log->info("[pci] scanning PCI bus");
pci_scan_bus(0);
g_log->info("[pci] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}
+139
View File
@@ -0,0 +1,139 @@
/* DKM PS/2 Keyboard Driver — IRQ1 scan code → ASCII
* Stage 3, optional, depends on "irq", provides "keyboard".
* Registers IRQ1 handler, translates scan codes via lookup table.
*/
#include <stdint.h>
/* DKM ABI types */
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_kernel_api {
u32 version; u32 size; u64 feature_bits;
const struct dkm_log_api *log;
const void *mem,*utsm,*irq_api,*pci_api,*dma,*vfs_api,*net,*timer,*drr;
const void *rsdp_address,*fb_address;
u64 fb_width,fb_height,fb_pitch; u16 fb_bpp;
const void *boot_modules_response;
int (*irq_register)(u8 irq, void *handler);
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic; u16 abi_version; u16 desc_size;
const char *name,*version,*vendor;
u32 driver_class,stage,flags,priority;
const char *const *depends; u32 depends_count;
const char *const *provides; u32 provides_count;
u64 min_kernel_abi,feature_bits,reserved0,reserved1;
};
/* Driver descriptor */
static const char *const g_depends[] = {"irq"};
static const char *const g_provides[] = {"keyboard"};
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic=DKM_DRIVER_MAGIC, .abi_version=DKM_ABI_VERSION,
.desc_size=sizeof(struct dkm_driver_desc),
.name="ps2kbd", .version="0.1.0", .vendor="Deshab",
.driver_class=10, .stage=3, .flags=0, .priority=0,
.depends=g_depends, .depends_count=1,
.provides=g_provides, .provides_count=1,
.min_kernel_abi=1,
};
/* Scan code set 1 → ASCII (lowercase) */
static const char sc_ascii[] = {
0,0,'1','2','3','4','5','6','7','8','9','0','-','=',0,
0,'q','w','e','r','t','y','u','i','o','p','[',']',0,
0,'a','s','d','f','g','h','j','k','l',';','\'','`',0,
'\\','z','x','c','v','b','n','m',',','.','/',0,
'*',0,' ',0
};
static const struct dkm_log_api *g_log;
static volatile int g_has_key;
static volatile u8 g_last_sc;
/* inline I/O */
static u8 inb(u16 p) { u8 v; __asm__("inb %1,%0":"=a"(v):"Nd"(p)); return v; }
static void outb(u16 p, u8 v) { __asm__("outb %0,%1"::"a"(v),"Nd"(p)); }
static void log_hex(const char *prefix, u64 v) {
static const char h[]="0123456789abcdef";
char b[19]; u32 i=0; b[i++]='0'; b[i++]='x';
for (int j=15;j>=0;j--) b[i++]=h[(v>>(j*4))&0xf];
b[i]=0; g_log->info(prefix); g_log->info(b);
}
static int kbd_handler(u8 irq) {
(void)irq;
g_last_sc = inb(0x60);
g_has_key = 1;
return 0; /* let kernel send EOI */
}
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api||!api->log) return -1;
g_log=api->log;
if (!api->irq_register) {
g_log->warn("[kbd] irq_register not available");
return 0;
}
if (api->irq_register(1, (void*)(uintptr_t)kbd_handler) != 0) {
g_log->error("[kbd] failed to register IRQ1");
return -1;
}
g_log->info("[kbd] IRQ1 registered, waiting for keypress");
g_log->info("[kbd] (boot will continue, key echo in ISR)");
/* spin briefly to show a key echo demo */
int ticks = 0;
while (ticks < 200000) {
if (g_has_key) {
u8 sc = g_last_sc;
g_has_key = 0;
if (sc < 0x80) {
/* make code */
log_hex("[kbd] sc=", sc);
if (sc < sizeof(sc_ascii) && sc_ascii[sc]) {
char buf[2] = {sc_ascii[sc], 0};
g_log->info("[kbd] key");
g_log->info(buf);
}
}
}
for (volatile int z=0;z<100;z++) {}
ticks++;
}
g_log->info("[kbd] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle; return 0;
}
+105
View File
@@ -0,0 +1,105 @@
$ErrorActionPreference = 'Stop'
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$Root = Split-Path -Parent (Split-Path -Parent (Split-Path -Parent $ScriptDir))
$Source = Join-Path $Root 'CODE\DKM\stub_driver\stub_driver.c'
$Manifest = Join-Path $Root 'SYSTEM\driver\manifest.json'
$SystemDriver = Join-Path $Root 'SYSTEM\driver'
$BuildDir = Join-Path $Root '.build_tmp\drivers'
function Find-Tool($Name, $ExtraNames = @()) {
$names = @($Name) + $ExtraNames
foreach ($n in $names) {
$cmd = Get-Command $n -ErrorAction SilentlyContinue
if ($cmd) { return $cmd.Source }
}
$dirs = @(
'C:\Program Files\LLVM\bin',
'C:\Program Files (x86)\LLVM\bin',
'C:\LLVM\bin',
'D:\LLVM\bin',
'D:\Program Files\LLVM\bin',
'D:\Code\LLVM\bin',
'C:\msys64\clang64\bin',
'C:\msys64\mingw64\bin',
'C:\mingw64\bin'
)
foreach ($dir in $dirs) {
foreach ($n in $names) {
$candidate = Join-Path $dir $n
if (Test-Path $candidate) { return $candidate }
if (-not $n.EndsWith('.exe')) {
$candidateExe = Join-Path $dir "$n.exe"
if (Test-Path $candidateExe) { return $candidateExe }
}
}
}
return $null
}
function Get-DriverClassValue([string]$Class) {
switch ($Class) {
'platform' { return 1 }
'bus' { return 2 }
'interrupt' { return 3 }
'timer' { return 4 }
'console' { return 5 }
'storage' { return 6 }
'fs' { return 7 }
'fs-core' { return 8 }
'net' { return 9 }
'input' { return 10 }
'gpu' { return 11 }
default { return 0 }
}
}
$clang = Find-Tool 'clang'
$lld = Find-Tool 'ld.lld'
if (-not $clang) {
throw 'clang was not found. Install LLVM/Clang.'
}
if (-not $lld) {
throw 'ld.lld was not found. Install LLVM lld.'
}
New-Item -ItemType Directory -Force -Path $BuildDir | Out-Null
$manifestData = Get-Content -Raw -LiteralPath $Manifest | ConvertFrom-Json
$count = 0
foreach ($stage in $manifestData.stages) {
foreach ($driver in $stage.drivers) {
$relative = [string]$driver.path
if (-not $relative.StartsWith('driver/')) {
throw "Unexpected driver path: $relative"
}
$destRelative = $relative.Substring('driver/'.Length).Replace('/', '\')
$dest = Join-Path $SystemDriver $destRelative
$destDir = Split-Path -Parent $dest
New-Item -ItemType Directory -Force -Path $destDir | Out-Null
$name = [string]$driver.name
$classValue = Get-DriverClassValue ([string]$driver.class)
$stageValue = [int]$stage.id
$flags = 0
if ([bool]$driver.required) { $flags = $flags -bor 1 }
if ($stageValue -le 1) { $flags = $flags -bor 2 }
$obj = Join-Path $BuildDir "$name.o"
$drv = Join-Path $BuildDir "$name.drv"
$driverNameDefine = 'DRIVER_NAME=' + $name
& $clang -target x86_64-unknown-none -std=c11 -ffreestanding -fno-stack-protector -fno-pic -fno-pie -mno-red-zone -Wall -Wextra -O2 -c $Source -o $obj "-D$driverNameDefine" "-DDRIVER_CLASS=$classValue" "-DDRIVER_STAGE=$stageValue" "-DDRIVER_FLAGS=$flags"
if ($LASTEXITCODE -ne 0) { throw "failed to compile stub driver: $name" }
& $lld -r -o $drv $obj
if ($LASTEXITCODE -ne 0) { throw "failed to link stub driver: $name" }
Copy-Item -LiteralPath $drv -Destination $dest -Force
Write-Host "[drivers] installed $relative"
$count++
}
}
Write-Host "[drivers] installed $count DKM stub drivers"
+93
View File
@@ -0,0 +1,93 @@
#include <stdint.h>
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1
#ifndef DRIVER_NAME
#define DRIVER_NAME stub
#endif
#define DKM_STRINGIFY_INNER(x) #x
#define DKM_STRINGIFY(x) DKM_STRINGIFY_INNER(x)
#define DRIVER_NAME_STRING DKM_STRINGIFY(DRIVER_NAME)
#ifndef DRIVER_CLASS
#define DRIVER_CLASS 0
#endif
#ifndef DRIVER_STAGE
#define DRIVER_STAGE 0
#endif
#ifndef DRIVER_FLAGS
#define DRIVER_FLAGS 0
#endif
#ifndef DRIVER_PRIORITY
#define DRIVER_PRIORITY 0
#endif
struct dkm_driver_desc {
uint32_t magic;
uint16_t abi_version;
uint16_t desc_size;
const char *name;
const char *version;
const char *vendor;
uint32_t driver_class;
uint32_t stage;
uint32_t flags;
uint32_t priority;
const char *const *depends;
uint32_t depends_count;
const char *const *provides;
uint32_t provides_count;
uint64_t min_kernel_abi;
uint64_t feature_bits;
uint64_t reserved0;
uint64_t reserved1;
};
struct dkm_kernel_api;
struct dkm_driver_handle;
__attribute__((visibility("default")))
const struct dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC,
.abi_version = DKM_ABI_VERSION,
.desc_size = sizeof(struct dkm_driver_desc),
.name = DRIVER_NAME_STRING,
.version = "0.1.0-stub",
.vendor = "Deshab",
.driver_class = DRIVER_CLASS,
.stage = DRIVER_STAGE,
.flags = DRIVER_FLAGS,
.priority = DRIVER_PRIORITY,
.depends = 0,
.depends_count = 0,
.provides = 0,
.provides_count = 0,
.min_kernel_abi = 1,
.feature_bits = 0,
.reserved0 = 0,
.reserved1 = 0
};
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api, struct dkm_driver_handle *handle) {
(void)api;
(void)handle;
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}
+192
View File
@@ -0,0 +1,192 @@
/* DKM Timer Driver - PIT (Programmable Interval Timer)
* Stage 0 platform driver, provides "timer".
* No IDT/IRQ required - uses PIT counter polling for busy-wait delay.
*/
#include <stdint.h>
/* ---------------------------------------------------------------
* DKM ABI types (standalone, no kernel headers)
* --------------------------------------------------------------- */
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_kernel_api {
u32 version;
u32 size;
u64 feature_bits;
const struct dkm_log_api *log;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic;
u16 abi_version;
u16 desc_size;
const char *name;
const char *version;
const char *vendor;
u32 driver_class;
u32 stage;
u32 flags;
u32 priority;
const char *const *depends;
u32 depends_count;
const char *const *provides;
u32 provides_count;
u64 min_kernel_abi;
u64 feature_bits;
u64 reserved0;
u64 reserved1;
};
/* ---------------------------------------------------------------
* PIT I/O ports
* --------------------------------------------------------------- */
#define PIT_CH0_DATA 0x40
#define PIT_CH1_DATA 0x41
#define PIT_CH2_DATA 0x42
#define PIT_CMD 0x43
/* PIT frequency: 1.193182 MHz */
#define PIT_BASE_FREQ 1193182ULL
static const char *const g_provides[] = { "timer" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC,
.abi_version = DKM_ABI_VERSION,
.desc_size = sizeof(struct dkm_driver_desc),
.name = "timer",
.version = "0.1.0",
.vendor = "Deshab",
.driver_class = 4, /* DKM_CLASS_TIMER */
.stage = 0,
.flags = 1, /* DKM_F_REQUIRED */
.priority = 0,
.depends = NULL,
.depends_count = 0,
.provides = g_provides,
.provides_count = 1,
.min_kernel_abi = 1,
.feature_bits = 0,
.reserved0 = 0,
.reserved1 = 0
};
/* ---------------------------------------------------------------
* Inline assembly for port I/O (works in Ring0 SAS-R0)
* --------------------------------------------------------------- */
static __inline__ void outb(u16 port, u8 value) {
__asm__ volatile ("outb %0, %1" :: "a"(value), "Nd"(port));
}
static __inline__ u8 inb(u16 port) {
u8 value;
__asm__ volatile ("inb %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
/* ---------------------------------------------------------------
* PIT operations
* --------------------------------------------------------------- */
static const struct dkm_log_api *g_log;
static void pit_set_channel(u8 channel, u8 mode, u16 count) {
u8 cmd = (u8)((channel << 6) | (3 << 4) | (mode << 1));
outb(PIT_CMD, cmd);
outb((u16)(PIT_CH0_DATA + channel), (u8)(count & 0xff));
outb((u16)(PIT_CH0_DATA + channel), (u8)((count >> 8) & 0xff));
}
/* Read back current counter value via latch command */
static u16 pit_read_counter(void) {
u8 cmd = 0xD0; /* read-back: channel 0, latch count, no status */
outb(PIT_CMD, cmd);
u8 lo = inb(PIT_CH0_DATA);
u8 hi = inb(PIT_CH0_DATA);
return (u16)(((u16)hi << 8) | lo);
}
/* Busy-wait delay using PIT channel 0 counter.
* count: PIT divisor (1193182 = ~1 second)
* The counter counts DOWN from 'count' to 0.
* We set it to 'count', then poll until it reaches near 0.
*/
static void pit_delay(u16 count) {
pit_set_channel(0, 0, count); /* mode 0: interrupt on terminal count */
u16 prev = pit_read_counter();
u64 loops = 0;
while (1) {
u16 cur = pit_read_counter();
if (cur > prev && loops > 10) {
break; /* counter wrapped → terminal count reached */
}
prev = cur;
loops++;
}
}
/* ---------------------------------------------------------------
* Driver entry points
* --------------------------------------------------------------- */
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) {
return -1;
}
g_log = api->log;
g_log->info("[timer] PIT driver initializing");
/* Quick calibration: set PIT to max count, measure how many
* iterations of read_counter() happen before terminal count.
*/
pit_set_channel(0, 0, 0xFFFF); /* 0xFFFF = max, ~55ms at 1.193 MHz */
u16 prev = pit_read_counter();
u64 cal_loops = 0;
while (1) {
u16 cur = pit_read_counter();
cal_loops++;
if (cur > prev && cal_loops > 5) break;
prev = cur;
}
/* Expected: PIT_BASE_FREQ / 0xFFFF ≈ 18.2 Hz, period ≈ 55 ms */
g_log->info("[timer] PIT calibration complete");
g_log->info("[timer] PIT channel 0 operational");
/* Do a quick ~100ms delay demo */
g_log->info("[timer] running 100ms busy-wait demo");
pit_delay((u16)(PIT_BASE_FREQ / 10)); /* ~0.1 sec = 119318 counts */
g_log->info("[timer] 100ms delay done");
g_log->info("[timer] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}
+222
View File
@@ -0,0 +1,222 @@
/* DKM VFS Driver — Virtual File System layer
* Stage 2, required, depends on "bootfs", provides "vfs".
* Mounts bootfs modules as files, implements basic open/read.
* Demo: reads and displays first 64 bytes of manifest.json.
*/
#include <stdint.h>
/* ---------------------------------------------------------------
* DKM ABI types
* --------------------------------------------------------------- */
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_kernel_api {
u32 version;
u32 size;
u64 feature_bits;
const struct dkm_log_api *log;
const void *mem;
const void *utsm;
const void *irq;
const void *pci_api;
const void *dma;
const void *vfs_api;
const void *net;
const void *timer;
const void *drr;
const void *rsdp_address;
const void *fb_address;
u64 fb_width;
u64 fb_height;
u64 fb_pitch;
u16 fb_bpp;
const void *boot_modules_response;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic;
u16 abi_version;
u16 desc_size;
const char *name;
const char *version;
const char *vendor;
u32 driver_class;
u32 stage;
u32 flags;
u32 priority;
const char *const *depends;
u32 depends_count;
const char *const *provides;
u32 provides_count;
u64 min_kernel_abi;
u64 feature_bits;
u64 reserved0;
u64 reserved1;
};
struct limine_file {
u64 revision;
void *address;
u64 size;
char *path;
char *cmdline;
u8 _pad[56];
};
struct limine_module_response {
u64 revision;
u64 module_count;
struct limine_file **modules;
};
/* ---------------------------------------------------------------
* Driver descriptor
* --------------------------------------------------------------- */
static const char *const g_depends[] = { "bootfs" };
static const char *const g_provides[] = { "vfs" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC,
.abi_version = DKM_ABI_VERSION,
.desc_size = sizeof(struct dkm_driver_desc),
.name = "vfs",
.version = "0.1.0",
.vendor = "Deshab",
.driver_class = 8, /* DKM_CLASS_FS_CORE */
.stage = 2,
.flags = 1,
.priority = 0,
.depends = g_depends,
.depends_count = 1,
.provides = g_provides,
.provides_count = 1,
.min_kernel_abi = 1,
.feature_bits = 0,
.reserved0 = 0,
.reserved1 = 0
};
/* ---------------------------------------------------------------
* Helpers
* --------------------------------------------------------------- */
static const struct dkm_log_api *g_log;
static void log_hex(const char *prefix, u64 val) {
static const char h[] = "0123456789abcdef";
char buf[19];
u32 p = 0;
buf[p++] = '0'; buf[p++] = 'x';
for (int i = 15; i >= 0; i--) buf[p++] = h[(val >> (i*4)) & 0xf];
buf[p] = 0;
g_log->info(prefix); g_log->info(buf);
}
static u64 min64(u64 a, u64 b) { return a < b ? a : b; }
static int path_match(const char *bp, const char *mp) {
/* strip leading '/' from bootloader path */
while (*bp == '/') bp++;
u64 i = 0;
while (bp[i] && mp[i] && bp[i] == mp[i]) i++;
return bp[i] == 0 && mp[i] == 0;
}
static int str_len(const char *s) {
int l = 0; while (s[l]) l++; return l;
}
/* ---------------------------------------------------------------
* Driver entry
* --------------------------------------------------------------- */
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) return -1;
g_log = api->log;
const struct limine_module_response *rsp =
(const struct limine_module_response *)api->boot_modules_response;
if (!rsp) { g_log->error("[vfs] no modules"); return -1; }
g_log->info("[vfs] mounting bootfs as root");
log_hex("[vfs] files=", rsp->module_count);
/* list all files */
for (u64 i = 0; i < rsp->module_count; i++) {
struct limine_file *f = rsp->modules[i];
if (!f || !f->path) continue;
g_log->info("[vfs] /");
g_log->info(f->path);
}
/* ---- demo: open & read /driver/manifest.json ---- */
g_log->info("[vfs] demo: open //driver/manifest.json");
struct limine_file *target = NULL;
for (u64 i = 0; i < rsp->module_count; i++) {
struct limine_file *f = rsp->modules[i];
if (f && f->path && path_match(f->path, "driver/manifest.json")) {
target = f; break;
}
}
if (!target) {
g_log->warn("[vfs] manifest.json not found");
} else {
log_hex("[vfs] size=", target->size);
g_log->info("[vfs] content (first 64 bytes):");
/* dump first 64 bytes as hex + ascii */
u64 n = min64(64, target->size);
const u8 *data = (const u8 *)target->address;
char line[80];
for (u64 off = 0; off < n; off += 16) {
u32 pos = 0;
for (u32 j = 0; j < 16 && off + j < n; j++) {
u8 b = data[off + j];
line[pos++] = "0123456789abcdef"[b >> 4];
line[pos++] = "0123456789abcdef"[b & 0xf];
line[pos++] = ' ';
}
/* ascii */
line[pos++] = ' ';
for (u32 j = 0; j < 16 && off + j < n; j++) {
u8 c = data[off + j];
line[pos++] = (c >= 32 && c < 127) ? (char)c : '.';
}
line[pos] = 0;
g_log->info(line);
}
}
g_log->info("[vfs] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}
+379
View File
@@ -0,0 +1,379 @@
/* DKM virtio-net Driver — PCI virtio network discovery
* Stage 3 optional network driver, depends on "pci" and "irq", provides "netdev".
* This first version discovers virtio-net devices and logs PCI capabilities;
* it does not negotiate features, create virtqueues, or transmit packets.
*/
#include <stdint.h>
#define DKM_DRIVER_MAGIC 0x444B4D31u
#define DKM_ABI_VERSION 1u
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define NULL ((void *)0)
struct dkm_log_api {
void (*info)(const char *msg);
void (*warn)(const char *msg);
void (*error)(const char *msg);
void (*panic)(const char *msg);
};
struct dkm_net_device_desc {
const char *name;
u8 mac[6];
u32 flags;
void *ctx;
int (*tx)(void *ctx, const void *packet, u32 length);
int (*rx_poll)(void *ctx, void *buffer, u32 capacity, u32 *out_length);
};
struct dkm_net_api {
int (*register_device)(const struct dkm_net_device_desc *desc);
u32 (*device_count)(void);
int (*device_info)(u32 index, void *out);
};
#define DKM_NET_F_LINK_UP (1u << 0)
struct dkm_kernel_api {
u32 version;
u32 size;
u64 feature_bits;
const struct dkm_log_api *log;
const void *mem;
const void *utsm;
const void *irq;
const void *pci;
const void *dma;
const void *vfs;
const struct dkm_net_api *net;
const void *timer;
const void *drr;
const void *rsdp_address;
const void *fb_address;
u64 fb_width;
u64 fb_height;
u64 fb_pitch;
u16 fb_bpp;
const void *boot_modules_response;
int (*irq_register)(u8 irq, void *handler);
u64 hhdm_offset;
};
struct dkm_driver_handle;
struct dkm_driver_desc {
u32 magic;
u16 abi_version;
u16 desc_size;
const char *name;
const char *version;
const char *vendor;
u32 driver_class;
u32 stage;
u32 flags;
u32 priority;
const char *const *depends;
u32 depends_count;
const char *const *provides;
u32 provides_count;
u64 min_kernel_abi;
u64 feature_bits;
u64 reserved0;
u64 reserved1;
};
static const char *const g_depends[] = { "pci", "irq" };
static const char *const g_provides[] = { "netdev" };
__attribute__((visibility("default"), used))
const struct dkm_driver_desc driver_desc = {
.magic = DKM_DRIVER_MAGIC,
.abi_version = DKM_ABI_VERSION,
.desc_size = sizeof(struct dkm_driver_desc),
.name = "virtio_net",
.version = "0.1.0",
.vendor = "Deshab",
.driver_class = 9, /* DKM_CLASS_NET */
.stage = 3,
.flags = 0,
.priority = 0,
.depends = g_depends,
.depends_count = 2,
.provides = g_provides,
.provides_count = 1,
.min_kernel_abi = 1,
.feature_bits = 0,
.reserved0 = 0,
.reserved1 = 0
};
#define PCI_ADDR 0xCF8
#define PCI_DATA 0xCFC
#define PCI_VENDOR_ID 0x00
#define PCI_COMMAND 0x04
#define PCI_CLASS_REG 0x08
#define PCI_HEADER 0x0E
#define PCI_CAP_PTR 0x34
#define PCI_IRQ_LINE 0x3C
#define PCI_BAR0 0x10
#define PCI_BAR1 0x14
#define PCI_BAR2 0x18
#define PCI_BAR3 0x1C
#define PCI_BAR4 0x20
#define PCI_BAR5 0x24
#define PCI_CMD_IO (1u << 0)
#define PCI_CMD_MEM (1u << 1)
#define PCI_CMD_BUSM (1u << 2)
#define PCI_VENDOR_VIRTIO 0x1AF4u
#define VIRTIO_TRANS_DEVICE_MIN 0x1000u
#define VIRTIO_TRANS_DEVICE_MAX 0x103Fu
#define VIRTIO_MODERN_DEVICE_MIN 0x1040u
#define VIRTIO_MODERN_DEVICE_MAX 0x107Fu
#define VIRTIO_NET_DEVICE_ID 1u
#define VIRTIO_PCI_CAP_COMMON_CFG 1u
#define VIRTIO_PCI_CAP_NOTIFY_CFG 2u
#define VIRTIO_PCI_CAP_ISR_CFG 3u
#define VIRTIO_PCI_CAP_DEVICE_CFG 4u
#define VIRTIO_PCI_CAP_PCI_CFG 5u
static const struct dkm_log_api *g_log;
static __inline__ void outl(u16 port, u32 value) {
__asm__ volatile ("outl %0, %1" :: "a"(value), "Nd"(port));
}
static __inline__ u32 inl(u16 port) {
u32 value;
__asm__ volatile ("inl %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
static u32 pci_read(u8 bus, u8 dev, u8 func, u8 reg) {
u32 addr = (1u << 31)
| ((u32)bus << 16)
| ((u32)dev << 11)
| ((u32)func << 8)
| ((u32)reg & 0xFC);
outl(PCI_ADDR, addr);
return inl(PCI_DATA);
}
static void pci_write(u8 bus, u8 dev, u8 func, u8 reg, u32 value) {
u32 addr = (1u << 31)
| ((u32)bus << 16)
| ((u32)dev << 11)
| ((u32)func << 8)
| ((u32)reg & 0xFC);
outl(PCI_ADDR, addr);
outl(PCI_DATA, value);
}
static u8 pci_read8(u8 bus, u8 dev, u8 func, u8 reg) {
u32 v = pci_read(bus, dev, func, reg);
return (u8)((v >> ((reg & 3) * 8)) & 0xff);
}
static void log_hex(const char *prefix, u64 value) {
static const char hex[] = "0123456789abcdef";
char buf[19];
u32 pos = 0;
buf[pos++] = '0';
buf[pos++] = 'x';
for (int i = 15; i >= 0; i--) {
buf[pos++] = hex[(value >> (i * 4)) & 0xf];
}
buf[pos] = 0;
g_log->info(prefix);
g_log->info(buf);
}
static u16 virtio_subsystem_id(u16 device_id) {
if (device_id >= VIRTIO_TRANS_DEVICE_MIN && device_id <= VIRTIO_TRANS_DEVICE_MAX) {
return (u16)(device_id - VIRTIO_TRANS_DEVICE_MIN);
}
if (device_id >= VIRTIO_MODERN_DEVICE_MIN && device_id <= VIRTIO_MODERN_DEVICE_MAX) {
return (u16)(device_id - VIRTIO_MODERN_DEVICE_MIN);
}
return 0xffff;
}
static int virtio_net_find(u8 *out_bus, u8 *out_dev, u8 *out_func) {
for (u8 bus = 0; bus < 16; bus++) {
for (u8 dev = 0; dev < 32; dev++) {
u32 vd = pci_read(bus, dev, 0, PCI_VENDOR_ID);
if ((vd & 0xffff) == 0xffff) continue;
u8 header = (u8)(pci_read(bus, dev, 0, PCI_HEADER) >> 16);
u8 func_count = (header & 0x80) ? 8 : 1;
for (u8 func = 0; func < func_count; func++) {
u32 vd2 = pci_read(bus, dev, func, PCI_VENDOR_ID);
u16 vendor = (u16)(vd2 & 0xffff);
u16 device = (u16)(vd2 >> 16);
if (vendor != PCI_VENDOR_VIRTIO) continue;
u16 virtio_id = virtio_subsystem_id(device);
u32 class_reg = pci_read(bus, dev, func, PCI_CLASS_REG);
u8 class_code = (u8)(class_reg >> 24);
if (virtio_id == VIRTIO_NET_DEVICE_ID && class_code == 0x02) {
*out_bus = bus;
*out_dev = dev;
*out_func = func;
return 0;
}
}
}
}
return -1;
}
static const char *virtio_cap_name(u8 cfg_type) {
if (cfg_type == VIRTIO_PCI_CAP_COMMON_CFG) return "common_cfg";
if (cfg_type == VIRTIO_PCI_CAP_NOTIFY_CFG) return "notify_cfg";
if (cfg_type == VIRTIO_PCI_CAP_ISR_CFG) return "isr_cfg";
if (cfg_type == VIRTIO_PCI_CAP_DEVICE_CFG) return "device_cfg";
if (cfg_type == VIRTIO_PCI_CAP_PCI_CFG) return "pci_cfg";
return "unknown_cfg";
}
static u32 read_bar_raw(u8 bus, u8 dev, u8 func, u8 bar) {
return pci_read(bus, dev, func, (u8)(PCI_BAR0 + bar * 4));
}
static void log_bars(u8 bus, u8 dev, u8 func) {
for (u8 bar = 0; bar < 6; bar++) {
u32 raw = read_bar_raw(bus, dev, func, bar);
if (raw == 0 || raw == 0xffffffffu) continue;
log_hex("[virtio_net] BAR index=", bar);
log_hex("[virtio_net] raw=", raw);
if (raw & 1u) {
log_hex("[virtio_net] io base=", raw & 0xfffffffcU);
} else {
log_hex("[virtio_net] mmio base=", raw & 0xfffffff0U);
}
}
}
static void log_virtio_caps(u8 bus, u8 dev, u8 func) {
u8 cap = pci_read8(bus, dev, func, PCI_CAP_PTR) & 0xfc;
u32 guard = 0;
u32 found = 0;
while (cap && guard++ < 32) {
u8 cap_id = pci_read8(bus, dev, func, cap + 0);
u8 next = pci_read8(bus, dev, func, cap + 1) & 0xfc;
if (cap_id == 0x09) {
u8 cfg_type = pci_read8(bus, dev, func, cap + 3);
u8 bar = pci_read8(bus, dev, func, cap + 4);
u32 offset = pci_read(bus, dev, func, cap + 8);
u32 length = pci_read(bus, dev, func, cap + 12);
found++;
g_log->info("[virtio_net] virtio capability");
g_log->info(virtio_cap_name(cfg_type));
log_hex("[virtio_net] cap_offset=", cap);
log_hex("[virtio_net] cfg_type=", cfg_type);
log_hex("[virtio_net] bar=", bar);
log_hex("[virtio_net] offset=", offset);
log_hex("[virtio_net] length=", length);
if (cfg_type == VIRTIO_PCI_CAP_NOTIFY_CFG) {
u32 mult = pci_read(bus, dev, func, cap + 16);
log_hex("[virtio_net] notify_off_multiplier=", mult);
}
}
cap = next;
}
log_hex("[virtio_net] virtio cap count=", found);
if (!found) {
g_log->warn("[virtio_net] no modern virtio capabilities; transitional IO path expected");
}
}
__attribute__((visibility("default")))
int driver_init(const struct dkm_kernel_api *api,
struct dkm_driver_handle *handle) {
(void)handle;
if (!api || !api->log) return -1;
g_log = api->log;
g_log->info("[virtio_net] init begin");
u8 bus = 0;
u8 dev = 0;
u8 func = 0;
if (virtio_net_find(&bus, &dev, &func) != 0) {
g_log->warn("[virtio_net] virtio-net device not found");
g_log->info("[virtio_net] driver ready");
return 0;
}
g_log->info("[virtio_net] virtio-net device found");
log_hex("[virtio_net] bus=", bus);
log_hex("[virtio_net] dev=", dev);
log_hex("[virtio_net] func=", func);
u32 vd = pci_read(bus, dev, func, PCI_VENDOR_ID);
u16 vendor = (u16)(vd & 0xffff);
u16 device = (u16)(vd >> 16);
u16 virtio_id = virtio_subsystem_id(device);
u32 class_reg = pci_read(bus, dev, func, PCI_CLASS_REG);
u8 revision = (u8)(class_reg & 0xff);
u8 prog_if = (u8)((class_reg >> 8) & 0xff);
u8 subclass = (u8)((class_reg >> 16) & 0xff);
u8 class_code = (u8)((class_reg >> 24) & 0xff);
log_hex("[virtio_net] vendor=", vendor);
log_hex("[virtio_net] device=", device);
log_hex("[virtio_net] virtio_id=", virtio_id);
log_hex("[virtio_net] class=", class_code);
log_hex("[virtio_net] subclass=", subclass);
log_hex("[virtio_net] prog_if=", prog_if);
log_hex("[virtio_net] revision=", revision);
u32 command = pci_read(bus, dev, func, PCI_COMMAND) & 0xffff;
command |= PCI_CMD_IO | PCI_CMD_MEM | PCI_CMD_BUSM;
pci_write(bus, dev, func, PCI_COMMAND, command);
log_hex("[virtio_net] PCI command=", command);
u32 irq_line = pci_read(bus, dev, func, PCI_IRQ_LINE) & 0xff;
log_hex("[virtio_net] PCI IRQ line=", irq_line);
log_bars(bus, dev, func);
log_virtio_caps(bus, dev, func);
if (api->net && api->net->register_device) {
struct dkm_net_device_desc netdev;
netdev.name = "virtio-net";
for (int i = 0; i < 6; i++) netdev.mac[i] = 0;
netdev.flags = DKM_NET_F_LINK_UP;
netdev.ctx = 0;
netdev.tx = 0;
netdev.rx_poll = 0;
int net_index = api->net->register_device(&netdev);
log_hex("[virtio_net] netdev register rc=", (u64)(i64)net_index);
} else {
g_log->warn("[virtio_net] net API unavailable; netdev not registered");
}
g_log->info("[virtio_net] discovery only; virtqueues disabled");
g_log->info("[virtio_net] driver ready");
return 0;
}
__attribute__((visibility("default")))
int driver_exit(struct dkm_driver_handle *handle) {
(void)handle;
return 0;
}