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:
@@ -0,0 +1,25 @@
|
||||
CC := clang
|
||||
LD := ld.lld
|
||||
|
||||
ROOT := ../..
|
||||
OUT := $(ROOT)/SYSTEM/system/deshab64/deshab.elf
|
||||
|
||||
CFLAGS := -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin -fno-stack-protector -fpie -mno-red-zone -mno-sse -mno-sse2 -mno-mmx -msoft-float -m64 -Wall -Wextra -I../UTSM/include -O2
|
||||
LDFLAGS := -nostdlib -static -pie -z max-page-size=0x1000 -T linker.ld
|
||||
|
||||
C_SOURCES := $(wildcard *.c)
|
||||
OBJECTS := $(C_SOURCES:.c=.o)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(OUT)
|
||||
|
||||
$(OUT): $(OBJECTS) linker.ld
|
||||
@if not exist "$(ROOT)\SYSTEM\system\deshab64" mkdir "$(ROOT)\SYSTEM\system\deshab64"
|
||||
$(LD) $(LDFLAGS) -o $@ $(OBJECTS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
powershell -NoProfile -Command "Get-ChildItem -Path . -Recurse -Filter *.o | Remove-Item -Force; if (Test-Path '$(OUT)') { Remove-Item '$(OUT)' -Force }"
|
||||
+366
@@ -0,0 +1,366 @@
|
||||
# DSK 主内核说明
|
||||
|
||||
`CODE/dsk` 是 Deshab 的主内核工程目录,目标产物为:
|
||||
|
||||
```text
|
||||
CODE/dsk -> SYSTEM/system/deshab64/deshab.elf
|
||||
```
|
||||
|
||||
当前启动链路分为两层:
|
||||
|
||||
```text
|
||||
bootloader
|
||||
-> SYSTEM/boot/utsm.elf
|
||||
UTSM 首阶段内核 / DKM 驱动加载 / 平台发现
|
||||
-> SYSTEM/system/deshab64/deshab.elf
|
||||
DSK 主内核
|
||||
```
|
||||
|
||||
也就是说,`utsm.elf` 不是最终长期运行的完整主内核,而是当前已经具备启动、封缄内存、DKM 驱动加载、平台发现和早期系统服务能力的前置内核阶段。后续 UTSM 需要继续执行到 `deshab.elf`,把控制权交给 DSK 主内核。
|
||||
|
||||
---
|
||||
|
||||
## 1. 模块定位
|
||||
|
||||
DSK 是 Deshab 的主内核,负责承接 UTSM 阶段已经建立的系统基础,并进入完整内核运行期。
|
||||
|
||||
DSK 的职责:
|
||||
|
||||
```text
|
||||
1. 接收 UTSM 传入的 boot context / platform context。
|
||||
2. 接管主调度器、内存管理、系统服务和长期运行状态。
|
||||
3. 使用 UTSM/DKM 已完成的平台发现结果。
|
||||
4. 继续使用或接管 DKM 驱动状态。
|
||||
5. 推进真实块设备、网络、VFS 和用户任务模型。
|
||||
6. 与 DRR 恢复根协作,支持 checkpoint / recovery / rollback。
|
||||
```
|
||||
|
||||
DSK 不应重复做已经由 UTSM 阶段完成的早期工作,例如:
|
||||
|
||||
```text
|
||||
- Limine request 原始解析
|
||||
- early serial 初始化
|
||||
- 早期 arena 初始化
|
||||
- DKM manifest 的首轮 stage 加载
|
||||
- 纯 discovery 型平台枚举
|
||||
```
|
||||
|
||||
DSK 应关注从“可启动实验内核”进入“可长期运行主内核”。
|
||||
|
||||
---
|
||||
|
||||
## 2. 产物路径
|
||||
|
||||
主内核 ELF 固定输出到:
|
||||
|
||||
```text
|
||||
SYSTEM/system/deshab64/deshab.elf
|
||||
```
|
||||
|
||||
建议目录语义:
|
||||
|
||||
```text
|
||||
SYSTEM/
|
||||
boot/
|
||||
utsm.elf # bootloader 直接加载的首阶段内核
|
||||
|
||||
system/
|
||||
deshab64/
|
||||
deshab.elf # DSK 主内核
|
||||
|
||||
driver/
|
||||
manifest.json
|
||||
... *.drv # DKM 驱动模块
|
||||
```
|
||||
|
||||
`deshab64` 表示当前主内核目标架构为 x86_64 long mode。
|
||||
|
||||
---
|
||||
|
||||
## 3. UTSM 到 DSK 的执行关系
|
||||
|
||||
当前 UTSM 已完成:
|
||||
|
||||
```text
|
||||
- long mode C 入口
|
||||
- serial log
|
||||
- UTSM/PCKC/UTRW selftest
|
||||
- IDT 0-47
|
||||
- PIC IRQ fallback
|
||||
- irq_register
|
||||
- Limine RSDP/framebuffer/module/HHDM request
|
||||
- DKM/DSM 外部 .drv 加载
|
||||
- 14/14 真实 DKM 驱动 discovery/加载闭环
|
||||
```
|
||||
|
||||
下一步需要让 UTSM 在完成早期阶段后定位并加载:
|
||||
|
||||
```text
|
||||
/system/deshab64/deshab.elf
|
||||
```
|
||||
|
||||
推荐执行链:
|
||||
|
||||
```text
|
||||
kernel_main()
|
||||
-> serial_init()
|
||||
-> idt_init()
|
||||
-> utsm_init()
|
||||
-> dkm_init()
|
||||
-> dsm_load_from_manifest()
|
||||
-> utsm_selftest()
|
||||
-> dsk_load_main_kernel("/system/deshab64/deshab.elf")
|
||||
-> dsk_build_boot_context()
|
||||
-> dsk_jump_entry()
|
||||
```
|
||||
|
||||
DSK 入口不应假设自己由 bootloader 直接加载,而应假设由 UTSM 传入上下文。
|
||||
|
||||
---
|
||||
|
||||
## 4. DSK Boot Context
|
||||
|
||||
UTSM 跳转 DSK 时应传入一个明确版本化的上下文结构。
|
||||
|
||||
建议第一版结构:
|
||||
|
||||
```c
|
||||
#define DSK_BOOT_MAGIC 0x44534B31424F4F54ULL /* "DSK1BOOT" */
|
||||
#define DSK_BOOT_ABI_VERSION 1
|
||||
|
||||
struct dsk_boot_context {
|
||||
uint64_t magic;
|
||||
uint32_t abi_version;
|
||||
uint32_t size;
|
||||
|
||||
uint64_t flags;
|
||||
|
||||
uint64_t hhdm_offset;
|
||||
|
||||
uint64_t rsdp_address;
|
||||
|
||||
uint64_t framebuffer_address;
|
||||
uint64_t framebuffer_width;
|
||||
uint64_t framebuffer_height;
|
||||
uint64_t framebuffer_pitch;
|
||||
uint32_t framebuffer_bpp;
|
||||
uint32_t reserved_fb;
|
||||
|
||||
uint64_t boot_modules_response;
|
||||
|
||||
uint64_t dkm_kernel_api;
|
||||
uint64_t dkm_driver_table;
|
||||
uint64_t dkm_driver_count;
|
||||
|
||||
uint64_t utsm_state;
|
||||
uint64_t drr_state;
|
||||
|
||||
uint64_t memory_map;
|
||||
uint64_t memory_map_count;
|
||||
uint64_t memory_map_entry_size;
|
||||
|
||||
uint64_t kernel_stack_top;
|
||||
uint64_t reserved[8];
|
||||
};
|
||||
```
|
||||
|
||||
传参建议:
|
||||
|
||||
```text
|
||||
RDI = struct dsk_boot_context *
|
||||
RSI = 0
|
||||
RDX = 0
|
||||
interrupt state = disabled 或明确约定
|
||||
paging = UTSM 当前页表
|
||||
address model = higher-half + HHDM
|
||||
```
|
||||
|
||||
第一版可以只填必要字段:
|
||||
|
||||
```text
|
||||
magic / abi_version / size
|
||||
hhdm_offset
|
||||
rsdp_address
|
||||
framebuffer 信息
|
||||
boot_modules_response
|
||||
dkm_kernel_api
|
||||
```
|
||||
|
||||
其余字段后续逐步补齐。
|
||||
|
||||
---
|
||||
|
||||
## 5. DSK ELF 加载要求
|
||||
|
||||
`deshab.elf` 建议先采用 ELF64 executable 或 relocatable-friendly layout。
|
||||
|
||||
第一版 loader 可只支持最小集合:
|
||||
|
||||
```text
|
||||
ELFCLASS64
|
||||
ELFDATA2LSB
|
||||
EM_X86_64
|
||||
ET_EXEC 或 ET_DYN(二选一先固定)
|
||||
PT_LOAD segment
|
||||
PF_R / PF_W / PF_X
|
||||
入口 e_entry
|
||||
```
|
||||
|
||||
推荐第一版限制:
|
||||
|
||||
```text
|
||||
1. 不支持动态链接。
|
||||
2. 不支持 TLS。
|
||||
3. 不支持用户态权限切换。
|
||||
4. 不支持 demand paging。
|
||||
5. 不支持 symbol resolution。
|
||||
6. 所有 PT_LOAD 一次性复制/清零。
|
||||
7. 入口地址由 e_entry 给出。
|
||||
```
|
||||
|
||||
加载路径:
|
||||
|
||||
```text
|
||||
1. 从 bootfs/VFS 或 Limine module 查找 /system/deshab64/deshab.elf。
|
||||
2. 校验 ELF header。
|
||||
3. 计算 PT_LOAD 覆盖范围。
|
||||
4. 分配或确认目标虚拟地址范围。
|
||||
5. 复制 file-backed bytes。
|
||||
6. 清零 memsz - filesz。
|
||||
7. 设置段权限(第一版可沿用当前 RWX 简化策略)。
|
||||
8. 构造 dsk_boot_context。
|
||||
9. 跳转 e_entry。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. DSK 初始功能目标
|
||||
|
||||
第一阶段 DSK 不追求完整功能,先做可验证闭环。
|
||||
|
||||
最小启动目标:
|
||||
|
||||
```text
|
||||
1. 接收 dsk_boot_context。
|
||||
2. 校验 magic / abi_version / size。
|
||||
3. 复用 serial log 或 framebuffer log。
|
||||
4. 打印 DSK boot banner。
|
||||
5. 打印 hhdm / rsdp / framebuffer / driver_count。
|
||||
6. 执行 DSK selftest。
|
||||
7. 返回或 halt。
|
||||
```
|
||||
|
||||
成功日志建议:
|
||||
|
||||
```text
|
||||
[DSK] boot
|
||||
[DSK] context ok
|
||||
[DSK] hhdm offset=...
|
||||
[DSK] framebuffer=...
|
||||
[DSK] dkm drivers=...
|
||||
[DSK] SELFTEST PASS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 后续主内核路线
|
||||
|
||||
DSK 阶段建议按以下顺序推进:
|
||||
|
||||
```text
|
||||
P0: DSK ELF loader + dsk_boot_context + 跳转入口
|
||||
P1: 物理页分配器 + 页表/MMIO 映射接口
|
||||
P2: DMA buffer / cache barrier / IOMMU 预留接口
|
||||
P3: AHCI IDENTIFY/READ 已具备最小 DMA 验证路径;继续推进 AHCI block provider 与 NVMe admin queue/identify
|
||||
P4: FAT32 接入真实 block provider,替代 test.fat32
|
||||
P5: IDT 256 vectors + APIC/IOAPIC/MSI IRQ backend
|
||||
P6: e1000 / virtio_net RX-TX 数据路径
|
||||
P7: 主调度器 SAS-R0-PCQ 与任务模型
|
||||
P8: DRR checkpoint / recovery log / A-B rollback
|
||||
```
|
||||
|
||||
优先级原则:
|
||||
|
||||
```text
|
||||
先让 UTSM 能加载并跳到 DSK。
|
||||
再补内存/MMIO/DMA。
|
||||
再做块设备真实读取。
|
||||
再迁移文件系统和网络数据路径。
|
||||
最后进入调度器和恢复系统深化。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 与 UTSM 的边界
|
||||
|
||||
UTSM 保留职责:
|
||||
|
||||
```text
|
||||
- 封缄内存模型
|
||||
- UTRW 明文读写路径
|
||||
- DMP/PCKC
|
||||
- DKM 首轮驱动加载
|
||||
- early recovery hook
|
||||
- DSK 加载前的早期平台发现
|
||||
```
|
||||
|
||||
DSK 接管职责:
|
||||
|
||||
```text
|
||||
- 主内核生命周期
|
||||
- 完整内存管理
|
||||
- 完整 IRQ backend
|
||||
- 块设备与文件系统运行期
|
||||
- 网络栈运行期
|
||||
- 调度器和任务模型
|
||||
- 系统调用或内核服务入口
|
||||
```
|
||||
|
||||
二者关系不是互斥,而是阶段化:
|
||||
|
||||
```text
|
||||
UTSM = boot/runtime substrate
|
||||
DSK = main kernel runtime
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 当前待办
|
||||
|
||||
短期需要实现:
|
||||
|
||||
```text
|
||||
1. 已完成:build.ps1 增加 CODE/dsk -> SYSTEM/system/deshab64/deshab.elf 构建目标。
|
||||
2. 已完成:SYSTEM/boot/limine.conf 预加载 /system/deshab64/deshab.elf。
|
||||
3. 已完成:UTSM 中实现 DSK ELF64 PT_LOAD loader,优先通过 `kernel_api.block` + 内嵌 FAT32 解析从真实块设备读取 `DESHAB.ELF`(SATA FAT32 盘已验证);无块设备时自动回退 Limine boot module 预加载。
|
||||
4. 已完成:定义 dsk_boot_context 头文件,UTSM 与 DSK 共用。
|
||||
5. 已完成:编写 DSK 最小入口,打印 boot banner 和 SELFTEST PASS。
|
||||
6. 已完成:QEMU 验证从 UTSM 继续执行到 DSK。
|
||||
7. 已完成:把 "Limine 预加载 deshab.elf" 替换为 UTSM 通过 FAT32 block provider 读取。
|
||||
后续:在 FAT32 中支持子目录路径,统一 DSK 加载与 VFS 路径语义。
|
||||
8. 下一步:按“块设备优先”推进 AHCI/NVMe IDENTIFY/READ 和真实 FAT32 挂载。
|
||||
```
|
||||
|
||||
当前验证日志:
|
||||
|
||||
```text
|
||||
[UTSM] SELFTEST PASS
|
||||
[UTSM] loading DSK
|
||||
[UTSM] DSK module size=...
|
||||
[UTSM] DSK image base=...
|
||||
[UTSM] DSK entry=...
|
||||
[UTSM] jumping to DSK
|
||||
[DSK] boot
|
||||
[DSK] context ok
|
||||
[DSK] SELFTEST PASS
|
||||
```
|
||||
|
||||
验证标准:
|
||||
|
||||
```text
|
||||
[UTSM] SELFTEST PASS
|
||||
[UTSM] loading DSK
|
||||
[DSK] boot
|
||||
[DSK] context ok
|
||||
[DSK] SELFTEST PASS
|
||||
```
|
||||
@@ -0,0 +1,27 @@
|
||||
ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5); /* R-X */
|
||||
rodata PT_LOAD FLAGS(4); /* R-- */
|
||||
data PT_LOAD FLAGS(6); /* RW- */
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x1000;
|
||||
|
||||
.text : ALIGN(4K) {
|
||||
*(.text*)
|
||||
} :text
|
||||
|
||||
.rodata : ALIGN(4K) {
|
||||
*(.rodata*)
|
||||
} :rodata
|
||||
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
}
|
||||
+391
@@ -0,0 +1,391 @@
|
||||
/* DSK Main Kernel — boot entry, FAT32 firstInit check, ELF loader */
|
||||
|
||||
#include "../UTSM/include/utsm/dsk.h"
|
||||
#include "port.h"
|
||||
|
||||
#define COM1 0x3F8
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef long long i64;
|
||||
|
||||
typedef int (*block_read_fn)(u32 index, u64 lba, u32 count, void *buf);
|
||||
|
||||
static void sputc(char c) { for(unsigned i=0;i<100000;i++){if(inb(COM1+5)&0x20)break;} outb(COM1,(u8)c); }
|
||||
static void swrite(const char *s) { while(*s){if(*s=='\n')sputc('\r');sputc(*s++);} }
|
||||
static void logl(const char *s) { swrite(s); swrite("\n"); }
|
||||
static void logh(const char *p, u64 v) { static const char h[]="0123456789abcdef"; char b[19]; int 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; swrite(p);swrite(b);swrite("\n"); }
|
||||
|
||||
static void *memset_dsk(void *d, int c, u64 n) { u8 *p=(u8*)d; while(n--)*p++=(u8)c; return d; }
|
||||
static void *memcpy_dsk(void *d, const void *s, u64 n) { u8 *dd=(u8*)d; const u8 *ss=(const u8*)s; while(n--)*dd++=*ss++; return d; }
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
u8 jmp[3]; char oem[8]; u16 bps; u8 spc; u16 rsvd; u8 fc; u16 root_ent;
|
||||
u16 ts16; u8 media; u16 spf16; u16 spt; u16 heads; u32 hidden; u32 ts32;
|
||||
u32 spf; u16 flags; u16 ver; u32 root_clus; u16 fsi; u16 bkboot;
|
||||
u8 res[12]; u8 drv; u8 ntfl; u8 sig; u32 ser; char lbl[11]; char typ[8];
|
||||
u8 code[420]; u16 boot_sig;
|
||||
} fat32_bpb;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
char name[11]; u8 attr; u8 ntr; u8 ctenth;
|
||||
u16 ctime; u16 cdate; u16 adate; u16 chigh;
|
||||
u16 wtime; u16 wdate; u16 clow; u32 fsize;
|
||||
} fat32_de;
|
||||
|
||||
static u32 r32(const u8 *p) { return (u32)p[0]|((u32)p[1]<<8)|((u32)p[2]<<16)|((u32)p[3]<<24); }
|
||||
static u16 r16(const u8 *p) { return (u16)p[0]|((u16)p[1]<<8); }
|
||||
static int neq11(const char *a, const char *b) { for(int i=0;i<11;i++) if(a[i]!=b[i]) return 0; return 1; }
|
||||
|
||||
#define EI_MAG0 0x7f
|
||||
#define ELFCLASS64 2
|
||||
#define ELFDATA2LSB 1
|
||||
#define EM_X86_64 62
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define DT_RELA 7
|
||||
#define DT_RELASZ 8
|
||||
#define DT_RELAENT 9
|
||||
#define R_X86_64_RELATIVE 8
|
||||
typedef struct { u8 ident[16]; u16 type,machine; u32 ver; u64 entry,phoff,shoff; u32 flags; u16 ehsize,phentsize,phnum,shentsize,shnum,shstrndx; } elf64_ehdr;
|
||||
typedef struct { u32 type,flags; u64 offset,vaddr,paddr,filesz,memsz,align; } elf64_phdr;
|
||||
typedef struct { i64 tag; u64 val; } elf64_dyn;
|
||||
typedef struct { u64 offset; u64 info; i64 addend; } elf64_rela;
|
||||
|
||||
#define BG_TOP 0xFFC8E0F0u
|
||||
#define BG_BOTTOM 0xFF49306Fu
|
||||
#define BG_MID 0xFF8888B0u
|
||||
|
||||
static u64 g_fb_addr, g_fb_w, g_fb_h, g_fb_p;
|
||||
static block_read_fn g_block_read;
|
||||
static u8 g_disk[131072];
|
||||
static u8 g_cluster[4096];
|
||||
static u8 g_fdata[262144];
|
||||
|
||||
static int fat32_read_sectors(u32 lba, u32 count, u8 *out) { return g_block_read ? g_block_read(0,lba,count,out) : -1; }
|
||||
|
||||
static u32 blend_color(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;
|
||||
}
|
||||
|
||||
static u32 dsk_bg_at_y(i64 y) {
|
||||
if (g_fb_h <= 1) return BG_TOP;
|
||||
if (y < 0) y = 0;
|
||||
if ((u64)y >= g_fb_h) y = (i64)g_fb_h - 1;
|
||||
return blend_color(BG_TOP, BG_BOTTOM, (u32)(((u64)y * 255ULL) / (g_fb_h - 1)));
|
||||
}
|
||||
|
||||
static void dsk_fill_gradient_rect(u32 *fb, i64 x, i64 y, i64 w, i64 h) {
|
||||
for (i64 r = 0; r < h; r++) {
|
||||
i64 yy = y + r;
|
||||
if (yy < 0 || (u64)yy >= g_fb_h) continue;
|
||||
u32 color = dsk_bg_at_y(yy);
|
||||
u32 *line = (u32 *)((u8 *)fb + (u64)yy * g_fb_p);
|
||||
for (i64 c = 0; c < w; c++) {
|
||||
i64 xx = x + c;
|
||||
if (xx < 0 || (u64)xx >= g_fb_w) continue;
|
||||
line[(u64)xx] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int fat32_find_entry(const u8 *clus, u32 clus_sectors, const char *target, u32 *out_clus, u32 *out_size) {
|
||||
const fat32_de *dir = (const fat32_de *)clus;
|
||||
for (u32 e=0; e*32 < clus_sectors*512; e++) {
|
||||
if (dir[e].name[0]==0) break;
|
||||
if ((u8)dir[e].name[0]==0xE5) continue;
|
||||
if (dir[e].attr==0x0F) continue;
|
||||
if (dir[e].attr & 0x08) continue;
|
||||
if (neq11(dir[e].name, target)) {
|
||||
*out_clus = r16((const u8*)&dir[e].clow);
|
||||
*out_size = dir[e].fsize;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* find a single file in root directory by 11-char 8.3 name (avoids PIE pointer reloc) */
|
||||
static int fat32_read_root_file(const char *name11, u8 **out_data, u32 *out_size) {
|
||||
u8 *disk = g_disk;
|
||||
logl("[DSK] fat32 reading 256 sectors from LBA 0");
|
||||
int st = fat32_read_sectors(0, 256, disk);
|
||||
logh("[DSK] fat32 read_sectors rc=", (u64)(i64)st);
|
||||
if (st != 0) return -1;
|
||||
const fat32_bpb *bpb = (const fat32_bpb *)disk;
|
||||
if (bpb->boot_sig != 0xAA55 || bpb->bps != 512) return -2;
|
||||
if (bpb->spf == 0 || bpb->root_clus < 2) return -3;
|
||||
|
||||
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
|
||||
u32 fat_byte_off = bpb->rsvd * 512;
|
||||
u32 spc = bpb->spc;
|
||||
logh("[DSK] fat32 data_lba=", data_lba);
|
||||
|
||||
/* walk root directory cluster chain */
|
||||
u32 clus = bpb->root_clus;
|
||||
u32 found_clus = 0, found_size = 0;
|
||||
int found = 0;
|
||||
while (clus >= 2 && clus < 0x0FFFFFF8 && !found) {
|
||||
u32 lba = data_lba + (clus - 2) * spc;
|
||||
const u8 *cb;
|
||||
if ((u64)lba * 512 + (u64)spc * 512 <= 256ULL * 512)
|
||||
cb = disk + (u64)lba * 512;
|
||||
else {
|
||||
if (fat32_read_sectors(lba, 8, g_cluster) != 0) return -4;
|
||||
cb = g_cluster;
|
||||
}
|
||||
if (fat32_find_entry(cb, spc, name11, &found_clus, &found_size) == 0) { found = 1; break; }
|
||||
u32 fo = fat_byte_off + clus * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
clus = r32(disk + fo) & 0x0FFFFFFF;
|
||||
}
|
||||
if (!found) { logl("[DSK] fat32 entry not found"); return -5; }
|
||||
logh("[DSK] fat32 found_clus=", found_clus);
|
||||
logh("[DSK] fat32 found_size=", found_size);
|
||||
|
||||
if (found_size > sizeof(g_fdata)) return -6;
|
||||
u8 *dst = g_fdata; u32 remaining = found_size; u32 fc = found_clus;
|
||||
while (fc >= 2 && fc < 0x0FFFFFF8 && remaining > 0) {
|
||||
u32 fc_lba = data_lba + (fc - 2) * spc;
|
||||
u32 fc_bytes = spc * 512;
|
||||
if (fc_bytes > remaining) fc_bytes = remaining;
|
||||
const u8 *fb;
|
||||
if ((u64)fc_lba * 512 + (u64)spc * 512 <= 256ULL * 512)
|
||||
fb = disk + (u64)fc_lba * 512;
|
||||
else {
|
||||
if (fat32_read_sectors(fc_lba, 8, g_cluster) != 0) return -7;
|
||||
fb = g_cluster;
|
||||
}
|
||||
for (u32 b = 0; b < fc_bytes; b++) dst[b] = fb[b];
|
||||
dst += fc_bytes; remaining -= fc_bytes;
|
||||
u32 fo = fat_byte_off + fc * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
fc = r32(disk + fo) & 0x0FFFFFFF;
|
||||
}
|
||||
*out_data = g_fdata; *out_size = found_size;
|
||||
logl("[DSK] fat32 file read done");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsk_check_firstinit(int *is_first) {
|
||||
char name[12]; /* "FIRSTINTXT" on stack — no PIE reloc */
|
||||
name[0]='F';name[1]='I';name[2]='R';name[3]='S';name[4]='T';
|
||||
name[5]='I';name[6]='N';name[7]='T';name[8]='X';name[9]='T';name[10]=0;
|
||||
u8 *data = 0; u32 size = 0;
|
||||
logl("[DSK] fat32_read_path start");
|
||||
int rc = fat32_read_root_file(name, &data, &size);
|
||||
logh("[DSK] fat32_read_path rc=", (u64)(i64)rc);
|
||||
if (rc != 0) { logl("[DSK] firstInit.txt not found"); *is_first = 1; return 0; }
|
||||
if (data[0] == '0') { logl("[DSK] firstInit=0"); *is_first = 1; return 0; }
|
||||
logl("[DSK] firstInit != 0"); *is_first = 0; return 0;
|
||||
}
|
||||
|
||||
static int dsk_load_elf(u8 *data, u32 size, void **entry_out) {
|
||||
(void)size;
|
||||
const elf64_ehdr *eh = (const elf64_ehdr *)data;
|
||||
if (eh->ident[0] != EI_MAG0 || eh->ident[4] != ELFCLASS64) return -1;
|
||||
if (eh->machine != EM_X86_64) return -2;
|
||||
u64 min_vaddr = ~0ULL, max_vaddr = 0;
|
||||
u32 lc = 0;
|
||||
for (u16 i = 0; i < eh->phnum; i++) {
|
||||
const elf64_phdr *ph = (const elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize);
|
||||
if (ph->type != PT_LOAD) continue;
|
||||
if (ph->filesz > ph->memsz) return -3;
|
||||
if (ph->vaddr < min_vaddr) min_vaddr = ph->vaddr;
|
||||
if (ph->vaddr + ph->memsz > max_vaddr) max_vaddr = ph->vaddr + ph->memsz;
|
||||
lc++;
|
||||
}
|
||||
if (!lc || min_vaddr == ~0ULL) return -4;
|
||||
u64 isize = max_vaddr - min_vaddr;
|
||||
isize = (isize + 0xFFF) & ~0xFFFULL;
|
||||
static u8 ibuf[262144];
|
||||
u8 *image = ibuf;
|
||||
memset_dsk(image, 0, isize);
|
||||
for (u16 i = 0; i < eh->phnum; i++) {
|
||||
const elf64_phdr *ph = (const elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize);
|
||||
if (ph->type != PT_LOAD) continue;
|
||||
u64 off = ph->vaddr - min_vaddr;
|
||||
memcpy_dsk(image + off, data + ph->offset, ph->filesz);
|
||||
}
|
||||
*entry_out = image + (eh->entry - min_vaddr);
|
||||
|
||||
/* apply R_X86_64_RELATIVE relocations from PT_DYNAMIC (PIE) */
|
||||
u64 load_bias = (u64)image - min_vaddr;
|
||||
for (u16 i = 0; i < eh->phnum; i++) {
|
||||
const elf64_phdr *ph = (const elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize);
|
||||
if (ph->type != PT_DYNAMIC) continue;
|
||||
const elf64_dyn *dyn = (const elf64_dyn *)(image + (ph->vaddr - min_vaddr));
|
||||
u64 rela_off = 0, rela_sz = 0, rela_ent = 24;
|
||||
for (; dyn->tag != 0; dyn++) {
|
||||
if (dyn->tag == DT_RELA) rela_off = dyn->val;
|
||||
else if (dyn->tag == DT_RELASZ) rela_sz = dyn->val;
|
||||
else if (dyn->tag == DT_RELAENT) rela_ent = dyn->val;
|
||||
}
|
||||
if (rela_off && rela_sz) {
|
||||
u64 n = rela_sz / rela_ent;
|
||||
logh("[DSK] elf relocs=", n);
|
||||
for (u64 r = 0; r < n; r++) {
|
||||
const elf64_rela *rel = (const elf64_rela *)(image + (rela_off - min_vaddr) + r * rela_ent);
|
||||
u32 rtype = (u32)(rel->info & 0xFFFFFFFF);
|
||||
if (rtype == R_X86_64_RELATIVE) {
|
||||
u64 *slot = (u64 *)(image + (rel->offset - min_vaddr));
|
||||
*slot = load_bias + (u64)rel->addend;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logh("[DSK] elf image base=", (u64)image);
|
||||
logh("[DSK] elf entry=", (u64)*entry_out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dsk_spinner_and_check(u32 *fb_arg, i64 cx, i64 cy, i64 r, i64 thk,
|
||||
const u32 arc_colors[4], u32 bg, const void *boot_ctx_ptr) {
|
||||
(void)bg;
|
||||
(void)fb_arg;
|
||||
const dsk_boot_context *ctx = (const dsk_boot_context *)boot_ctx_ptr;
|
||||
{ u64 api = ctx->dkm_kernel_api;
|
||||
g_block_read = (block_read_fn)*(u64 *)(api + 0xA8);
|
||||
if (g_block_read) g_block_read = (block_read_fn)*(u64 *)((u64)g_block_read + 16); }
|
||||
|
||||
#define SPR 128
|
||||
static u32 sprite[SPR*SPR];
|
||||
i64 sp=SPR*4, scx=SPR/2, scy=SPR/2, bx=cx-scx, by=cy-scy;
|
||||
i64 frame=0, base=0; int checked=0; void *fe_entry=0;
|
||||
|
||||
g_fb_addr=ctx->framebuffer_address; g_fb_w=ctx->framebuffer_width;
|
||||
g_fb_h=ctx->framebuffer_height; g_fb_p=ctx->framebuffer_pitch;
|
||||
u32 *sfb=(u32*)(u64)g_fb_addr;
|
||||
dsk_fill_gradient_rect(sfb, 0, 0, (i64)g_fb_w, (i64)g_fb_h);
|
||||
u64 sw=g_fb_w, sh=g_fb_h, spv=g_fb_p;
|
||||
logh("[DSK] block_read ptr=", (u64)g_block_read);
|
||||
logl("[DSK] entering spinner loop");
|
||||
|
||||
while (1) {
|
||||
g_fb_w=SPR; g_fb_h=SPR; g_fb_p=sp;
|
||||
/* per-row gradient so sprite interior matches background */
|
||||
static u32 row_bg[SPR];
|
||||
for (i64 y0=0; y0<SPR; y0++) {
|
||||
i64 ry = by + y0;
|
||||
if (ry < 0) ry = 0;
|
||||
if ((u64)ry >= sh) ry = (i64)sh - 1;
|
||||
row_bg[y0] = blend_color(BG_TOP, BG_BOTTOM, (u32)(((u64)ry * 255ULL) / (sh - 1)));
|
||||
u32 *ln=&sprite[y0*SPR]; for(i64 x0=0;x0<SPR;x0++) ln[x0]=row_bg[y0];
|
||||
}
|
||||
{
|
||||
i64 ro=r+thk, ri=r-thk;
|
||||
for (i64 dq=0; dq<4; dq++) {
|
||||
i64 sa=base+dq*90, sw2=82; u32 clr=arc_colors[dq];
|
||||
for(i64 dy=-ro-1;dy<=ro+1;dy++){i64 yy=scy+dy; if(yy<0||yy>=SPR)continue;
|
||||
u32 sbg=row_bg[yy];
|
||||
for(i64 dx=-ro-1;dx<=ro+1;dx++){i64 xx=scx+dx; if(xx<0||xx>=SPR)continue;
|
||||
i64 d2=dx*dx+dy*dy; if(d2<ri*ri-2||d2>(ro+1)*(ro+1)+2)continue;
|
||||
i64 ang; if(dx==0)ang=dy<0?90:270;
|
||||
else{i64 ax=dx<0?-dx:dx,ay=dy<0?-dy:dy,a0=ax>ay?ay*45/ax:90-ax*45/(ay?ay:1);
|
||||
if(dx>=0&&dy<=0)ang=a0;else if(dx<0&&dy<=0)ang=180-a0;
|
||||
else if(dx<0&&dy>0)ang=180+a0;else ang=360-a0;}
|
||||
i64 a=ang-sa; if(a<0)a+=360; if((u64)a>(u64)sw2)continue;
|
||||
u32 fade; if((u64)a<6)fade=(u32)(a*255/6);else if((u64)a>(u64)(sw2-6))fade=(u32)((sw2-a)*255/6);else fade=255;
|
||||
u64 vv=(u64)d2; u64 xr=vv,yr=(xr+1)>>1; while(yr<xr){xr=yr;yr=(yr+vv/yr)>>1;} i64 dist=(i64)xr;
|
||||
u32 eff=((sbg&0xFF)*(256-fade)+(clr&0xFF)*fade)>>8;
|
||||
u32 ge=(((sbg>>8)&0xFF)*(256-fade)+((clr>>8)&0xFF)*fade)>>8;
|
||||
u32 be=(((sbg>>16)&0xFF)*(256-fade)+((clr>>16)&0xFF)*fade)>>8;
|
||||
eff=0xFF000000|(be<<16)|(ge<<8)|eff;
|
||||
if(dist>=ri&&dist<=ro)sprite[(u64)yy*SPR+(u64)xx]=eff;
|
||||
}}
|
||||
}
|
||||
i64 ri2=r-8;
|
||||
for(i64 dy=-ri2-2;dy<=ri2+2;dy++){i64 yy2=scy+dy; if(yy2<0||yy2>=SPR)continue;
|
||||
u32 sbg2=row_bg[yy2];
|
||||
for(i64 dx=-ri2-2;dx<=ri2+2;dx++){i64 xx2=scx+dx; if(xx2<0||xx2>=SPR)continue;
|
||||
i64 d2=dx*dx+dy*dy;
|
||||
if(d2<=ri2*ri2){
|
||||
u32 ic=((sbg2&0xFF)*176+0xD0*80)>>8;
|
||||
u32 ig=(((sbg2>>8)&0xFF)*176+0xF0*80)>>8;
|
||||
u32 ib=(((sbg2>>16)&0xFF)*176+0xFF*80)>>8;
|
||||
sprite[(u64)yy2*SPR+(u64)xx2]=0xFF000000|(ib<<16)|(ig<<8)|ic;
|
||||
}
|
||||
}}
|
||||
}
|
||||
g_fb_w=sw; g_fb_h=sh; g_fb_p=spv;
|
||||
dsk_fill_gradient_rect(sfb, bx, by, SPR, SPR);
|
||||
for(i64 sr=0;sr<SPR;sr++){i64 sy=by+sr; if(sy<0||(u64)sy>=g_fb_h)continue;
|
||||
u32 *dst=(u32*)((u8*)sfb+(u64)sy*g_fb_p)+bx; u32 *src=&sprite[sr*SPR];
|
||||
for(i64 sc=0;sc<SPR;sc++){i64 sx=bx+sc; if(sx<0||(u64)sx>=g_fb_w)continue; dst[sc]=src[sc];}}
|
||||
for(volatile u32 d=0;d<72000;d++)__asm__("pause");
|
||||
base-=2; if(base<0)base+=360; frame++;
|
||||
|
||||
if(frame>=100&&!checked){checked=1; /* was 540, reduced for test */
|
||||
logl("[DSK] checking firstInit...");
|
||||
if(g_block_read){logl("[DSK] have block read, calling dsk_check_firstinit");
|
||||
int is_first=0;
|
||||
if(dsk_check_firstinit(&is_first)==0&&is_first){
|
||||
logl("[DSK] first init detected; running system initializers");
|
||||
|
||||
/* DSK owns system component initialization. FirstInit is only user setup. */
|
||||
char mn[12]; /* MOUSE ELF */
|
||||
mn[0]='M';mn[1]='O';mn[2]='U';mn[3]='S';mn[4]='E';mn[5]=' ';mn[6]=' ';mn[7]=' ';mn[8]='E';mn[9]='L';mn[10]='F';
|
||||
u8 *md=0; u32 ms=0; void *me=0;
|
||||
if(fat32_read_root_file(mn,&md,&ms)==0){
|
||||
if(dsk_load_elf(md,ms,&me)==0){
|
||||
logl("[DSK] jumping to mouseInit");
|
||||
void(*mentry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))me;
|
||||
mentry(ctx);
|
||||
logl("[DSK] mouseInit returned");
|
||||
}
|
||||
}
|
||||
|
||||
char nn[12]; /* NETMAN ELF */
|
||||
nn[0]='N';nn[1]='E';nn[2]='T';nn[3]='M';nn[4]='A';nn[5]='N';nn[6]=' ';nn[7]=' ';nn[8]='E';nn[9]='L';nn[10]='F';
|
||||
u8 *nd=0; u32 ns=0; void *ne=0;
|
||||
if(fat32_read_root_file(nn,&nd,&ns)==0){
|
||||
if(dsk_load_elf(nd,ns,&ne)==0){
|
||||
logl("[DSK] jumping to netman");
|
||||
void(*nentry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))ne;
|
||||
nentry(ctx);
|
||||
logl("[DSK] netman returned");
|
||||
}
|
||||
}
|
||||
|
||||
logl("[DSK] loading FirstInit.elf");
|
||||
char en[12]; /* FIRSTINIT */
|
||||
en[0]='F';en[1]='I';en[2]='R';en[3]='S';en[4]='T';
|
||||
en[5]='I';en[6]='N';en[7]='I';en[8]='T';en[9]=' ';en[10]=0;
|
||||
u8 *fd=0; u32 fs=0;
|
||||
if(fat32_read_root_file(en,&fd,&fs)==0){
|
||||
if(dsk_load_elf(fd,fs,&fe_entry)==0) logl("[DSK] FirstInit.elf loaded");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(fe_entry&&frame>150){logl("[DSK] jumping to FirstInit"); /* was 600 */
|
||||
void(*entry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))fe_entry;
|
||||
entry(ctx); for(;;)__asm__("hlt");
|
||||
}
|
||||
if(!g_block_read&&frame>800){logl("[DSK] no block device, skipping firstInit");break;}
|
||||
if(checked&&!fe_entry&&frame>800){logl("[DSK] firstInit not found, continuing normal boot");break;}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noreturn, visibility("default")))
|
||||
void dsk_entry(const dsk_boot_context *ctx) {
|
||||
__asm__ volatile("cli"); /* disable IRQs — ps2kbd/IRQ1 & mouse/IRQ12 handlers crash during spinner */
|
||||
logl("[DSK] boot");
|
||||
if(!ctx||ctx->magic!=DSK_BOOT_MAGIC){logl("[DSK] bad context");for(;;)__asm__("hlt");}
|
||||
logl("[DSK] context ok");
|
||||
g_fb_addr=ctx->framebuffer_address; g_fb_w=ctx->framebuffer_width;
|
||||
g_fb_h=ctx->framebuffer_height; g_fb_p=ctx->framebuffer_pitch;
|
||||
u32 bg=BG_MID, arcs[4]={0xFF4488CC,0xFF2266AA,0xFF66AAEE,0xFF88CCFF};
|
||||
i64 cx=(i64)g_fb_w/2,cy=(i64)g_fb_h/2,r=48,thk=4;
|
||||
dsk_spinner_and_check((u32*)(u64)g_fb_addr,cx,cy,r,thk,arcs,bg,ctx);
|
||||
logl("[DSK] SELFTEST PASS");
|
||||
for(;;)__asm__("hlt");
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
#ifndef DSK_PORT_H
|
||||
#define DSK_PORT_H
|
||||
|
||||
static inline void outb(unsigned short port, unsigned char value) {
|
||||
__asm__ volatile ("outb %0, %1" :: "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline unsigned char inb(unsigned short port) {
|
||||
unsigned char value;
|
||||
__asm__ volatile ("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user