Files
Deshab-OS/CODE/dsk/main.c
T
2026-07-31 13:53:49 +08:00

1502 lines
64 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* DSK Main Kernel — boot entry, FAT32 firstInit check, ELF loader */
#include "../UTSM/include/utsm/dsk.h"
#include "port.h"
/* Embedded Logo.png RGBA data (auto-generated by png_to_rgba.py) */
#include "logo_data.c"
/* Embedded ASCII bitmap font (Consolas 18px grayscale, 11x18 cell) */
#include "../firstInit/ascii_bitmaps.c"
#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);
typedef int (*block_write_fn)(u32 index, u64 lba, u32 count, const void *buf);
/* freestanding 无 stddef.h,本地提供 offsetof */
#ifndef offsetof
#define offsetof(type, member) __builtin_offsetof(type, member)
#endif
/* ---- BUG-021 修复: kernel_api 镜像结构体 + 编译期偏移校验 ----
* DSK 独立编译不含 dkm_kernel_api 定义,为避免硬偏移脆蠕性,
* 在此定义镜像结构体并用 _Static_assert 校验 block 字段偏移
* 与 dkm.h 中 dkm_kernel_api.block (0xA8) 一致。 */
typedef struct dsk_block_api_mirror {
void *pad0; void *pad1; /* register_device, device_count */
block_read_fn read;
block_write_fn write;
} dsk_block_api_mirror;
typedef struct dsk_kernel_api_mirror {
u32 version; u32 size; u64 feature_bits;
const void *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; u16 _pad_bpp;
const void *boot_modules_response;
int (*irq_register)(u8 irq, void *handler);
u64 hhdm_offset;
const dsk_block_api_mirror *block; /* 必须在偏移 0xA8 */
const void *mmio;
void *(*mm_map_mmio)(u64 phys, u64 size);
void (*mm_unmap_mmio)(void *virt, u64 size);
} dsk_kernel_api_mirror;
_Static_assert(offsetof(dsk_kernel_api_mirror, block) == 0xA8,
"dsk_kernel_api_mirror.block offset must be 0xA8 (matching dkm_kernel_api)");
_Static_assert(offsetof(dsk_block_api_mirror, read) == 16,
"dsk_block_api_mirror.read offset must be 16 (matching dkm_block_api)");
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"); }
/* ---- DSK 插桩: 轻量级 TSC 计时 (forward-declared, rdtsc_dsk defined later) ---- */
static u64 rdtsc_dsk(void);
#define DSK_TS_DECL(name) static u64 name##_ts = 0
#define DSK_TS_BEGIN(name) do { name##_ts = rdtsc_dsk(); } while(0)
#define DSK_TS_END(name, label) do { \
if (g_tsc_per_ms) { \
u64 _d = rdtsc_dsk() - name##_ts; \
u64 _ms = _d / g_tsc_per_ms; \
logl("[DSK:TS] " label); logh(" elapsed_ms=", _ms); \
} \
} while(0)
/* ---- DSK 插桩: 操作计数器 ---- */
#define DSK_STAT_DECL(name) static u32 name##_count = 0
#define DSK_STAT_INC(name) do { name##_count++; } while(0)
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; }
static u64 g_fb_addr, g_fb_w, g_fb_h, g_fb_p;
static block_read_fn g_block_read;
static block_write_fn g_block_write;
static u64 g_tsc_per_ms = 0;
static u8 g_disk[131072];
static u8 g_cluster[4096];
static u8 g_fdata[2097152]; /* 2MB file data buffer (与 UTSM 端一致) */
/* BUG-019 修复: FAT 按需扇区读取缓冲区(仅 512 字节) */
static u8 g_fat_sec[512];
static u8 g_milestone_buf[4096]; /* milestone write cluster buffer */
DSK_STAT_DECL(fat32_read);
DSK_STAT_DECL(fat32_write);
DSK_STAT_DECL(elf_load);
DSK_STAT_DECL(mod_schedule);
static int fat32_read_sectors(u32 lba, u32 count, u8 *out) { DSK_STAT_INC(fat32_read); return g_block_read ? g_block_read(0,lba,count,out) : -1; }
static int fat32_write_sectors(u32 lba, u32 count, const u8 *buf) { DSK_STAT_INC(fat32_write); return g_block_write ? g_block_write(0,lba,count,buf) : -1; }
/* BUG-019 修复: 按需读取 FAT 扇区获取下一个簇号。
* 如果 FAT 条目在预读缓冲区内直接读取;
* 否则只读取包含该条目的单个 FAT 扇区(512 字节)。 */
static u32 fat32_get_next_cluster(u32 fat_byte_off, u32 clus, u32 fat_rsvd_sec) {
u32 ent_off = fat_byte_off + clus * 4;
/* 情况 1: 在预读缓冲区内 */
if (ent_off + 4 <= sizeof(g_disk)) {
return r32(g_disk + ent_off) & 0x0FFFFFFF;
}
/* 情况 2: 超出预读缓冲区——按需读取单扇区 */
u32 fat_byte_in_fat = clus * 4;
u32 sec_idx = fat_byte_in_fat / 512;
u32 off_in_sec = fat_byte_in_fat % 512;
u32 sec_lba = fat_rsvd_sec + sec_idx;
if (fat32_read_sectors(sec_lba, 1, g_fat_sec) != 0) {
logl("[DSK] FAT32: on-demand FAT sector read failed");
logh("[DSK] FAT32: sec_lba=", (u64)sec_lba);
return 0x0FFFFFFF;
}
return r32(g_fat_sec + off_in_sec) & 0x0FFFFFFF;
}
/* ---- DSK 内嵌 INI 解析器 ---- */
typedef struct { char section[32]; char key[32]; char value[64]; } dsk_ini_entry;
typedef struct { dsk_ini_entry entries[64]; u32 count; } dsk_ini_config;
static int dsk_ini_streq(const char *a, const char *b) {
if(!a||!b) return 0;
while(*a&&*b){ if(*a!=*b) return 0; a++; b++; }
return *a==*b;
}
static int dsk_ini_atoi(const char *s) {
int neg=0, v=0;
if(!s) return 0;
while(*s==' '||*s=='\t') s++;
if(*s=='-'){neg=1;s++;}
while(*s>='0'&&*s<='9'){v=v*10+(*s-'0');s++;}
return neg?-v:v;
}
static int dsk_ini_parse_bool(const char *s) {
if(!s) return -1;
if(s[0]=='1') return 1;
if(s[0]=='0') return 0;
if(dsk_ini_streq(s,"true")) return 1;
if(dsk_ini_streq(s,"false")) return 0;
return -1;
}
static int dsk_ini_parse(const char *text, u32 size, dsk_ini_config *cfg) {
if(!text||!cfg) return -1;
cfg->count = 0;
char cur_sec[32]; for(int i=0;i<32;i++) cur_sec[i]=0;
u32 pos = 0;
while(pos < size) {
while(pos<size&&(text[pos]==' '||text[pos]=='\t')) pos++;
if(pos>=size) break;
char c = text[pos];
if(c=='\n'){pos++;continue;}
if(c=='#'||c==';'){while(pos<size&&text[pos]!='\n')pos++;continue;}
if(c=='['){
pos++;
u32 si=0;
while(pos<size&&text[pos]!=']'&&text[pos]!='\n'&&si+1<32) cur_sec[si++]=text[pos++];
cur_sec[si]=0;
while(pos<size&&text[pos]!='\n') pos++;
continue;
}
if(cfg->count>=64) break;
dsk_ini_entry *e = &cfg->entries[cfg->count];
u32 ki=0;
while(pos<size&&text[pos]!='='&&text[pos]!='\n'&&!(text[pos]==' '||text[pos]=='\t')&&ki+1<32) e->key[ki++]=text[pos++];
e->key[ki]=0;
while(pos<size&&(text[pos]==' '||text[pos]=='\t')&&text[pos]!='\n') pos++;
if(pos>=size||text[pos]!='='){while(pos<size&&text[pos]!='\n')pos++;continue;}
pos++;
while(pos<size&&(text[pos]==' '||text[pos]=='\t')&&text[pos]!='\n') pos++;
u32 vi=0;
while(pos<size&&text[pos]!='\n'&&vi+1<64) e->value[vi++]=text[pos++];
while(vi>0&&(e->value[vi-1]==' '||e->value[vi-1]=='\t')) vi--;
e->value[vi]=0;
for(int i=0;i<32;i++) e->section[i]=cur_sec[i];
cfg->count++;
}
return 0;
}
static const char *dsk_ini_get(const dsk_ini_config *cfg, const char *sec, const char *key) {
if(!cfg||!sec||!key) return 0;
for(u32 i=0;i<cfg->count;i++)
if(dsk_ini_streq(cfg->entries[i].section,sec)&&dsk_ini_streq(cfg->entries[i].key,key))
return cfg->entries[i].value;
return 0;
}
__attribute__((unused))
static int dsk_ini_get_int(const dsk_ini_config *cfg, const char *sec, const char *key, int def) {
const char *v=dsk_ini_get(cfg,sec,key);
if(!v||v[0]==0) return def;
return dsk_ini_atoi(v);
}
static int dsk_ini_get_bool(const dsk_ini_config *cfg, const char *sec, const char *key, int def) {
const char *v=dsk_ini_get(cfg,sec,key);
if(!v||v[0]==0) return def;
int b=dsk_ini_parse_bool(v);
return (b>=0)?b:def;
}
/* ---- DSK FAT32 子目录遍历 ---- */
/* 在指定起始 cluster 的目录中查找 name11。
* is_dir=1 只匹配子目录,is_dir=0 只匹配文件。
* 注意:需先调用 fat32_read_sectors(0,256,g_disk) 确保 BPB 缓冲可用。 */
static int fat32_find_in_dir(u32 start_clus, const char *name11, int is_dir, u32 *out_clus, u32 *out_size) {
const fat32_bpb *bpb = (const fat32_bpb *)g_disk;
if(bpb->boot_sig!=0xAA55||bpb->bps!=512) return -2;
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
u32 fat_byte_off = bpb->rsvd * 512;
u32 spc = bpb->spc;
u32 clus = start_clus;
while(clus>=2 && clus<0x0FFFFFF8) {
u32 lba = data_lba + (clus-2)*spc;
const u8 *cb;
if((u64)lba*512+(u64)spc*512<=256ULL*512)
cb = g_disk + (u64)lba*512;
else {
if(fat32_read_sectors(lba,8,g_cluster)!=0) return -3;
cb = g_cluster;
}
const fat32_de *dir = (const fat32_de *)cb;
for(u32 e=0; e*32<spc*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,name11)) continue;
int entry_is_dir = (dir[e].attr&0x10)?1:0;
if(entry_is_dir!=is_dir) continue;
*out_clus = r16((const u8*)&dir[e].clow)|((u32)r16((const u8*)&dir[e].chigh)<<16);
*out_size = dir[e].fsize;
return 0;
}
/* BUG-019: 使用按需 FAT 读取 */
clus = fat32_get_next_cluster(fat_byte_off, clus, bpb->rsvd);
}
return -4;
}
/* 按 '/' 分隔的 8.3 路径读取文件(如 "SYSTEM /DESHAB64 /FUCK ")。
* 需先调用 fat32_read_sectors(0,256,g_disk) 确保 BPB 可用。 */
static int fat32_read_path(const char *path, u8 **out_data, u32 *out_size) {
DSK_TS_DECL(fat32_path_read);
DSK_TS_BEGIN(fat32_path_read);
const fat32_bpb *bpb = (const fat32_bpb *)g_disk;
if(bpb->boot_sig!=0xAA55||bpb->bps!=512) { logl("[DSK] fat32_read_path: bad BPB"); return -2; }
u32 fat_byte_off = bpb->rsvd*512;
u32 data_lba = bpb->rsvd + (u32)bpb->fc*bpb->spf;
u32 spc = bpb->spc;
u32 pos=0, path_len=0;
while(path[path_len]) path_len++;
u32 cur_clus = bpb->root_clus;
while(pos<path_len) {
char comp[12]; u32 ci=0;
while(pos<path_len&&path[pos]!='/'&&ci<11) comp[ci++]=path[pos++];
while(ci<11) comp[ci++]=' ';
comp[11]=0;
if(pos<path_len&&path[pos]=='/') pos++;
int is_last = (pos>=path_len);
if(is_last) {
u32 found_clus=0, found_size=0;
if(fat32_find_in_dir(cur_clus,comp,0,&found_clus,&found_size)!=0) { logl("[DSK] fat32_read_path: file not found: "); swrite(path); swrite("\n"); return -4; }
if(found_size>sizeof(g_fdata)) { logh("[DSK] fat32_read_path: file too large size=", (u64)found_size); return -5; }
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=g_disk+(u64)fc_lba*512;
else {
if(fat32_read_sectors(fc_lba,8,g_cluster)!=0) { logh("[DSK] fat32_read_path: data cluster read failed lba=", (u64)fc_lba); return -6; }
fb=g_cluster;
}
for(u32 b=0;b<fc_bytes;b++) dst[b]=fb[b];
dst+=fc_bytes; remaining-=fc_bytes;
/* BUG-019: 使用按需 FAT 读取 */
fc = fat32_get_next_cluster(fat_byte_off, fc, bpb->rsvd);
}
*out_data=g_fdata; *out_size=found_size;
DSK_TS_END(fat32_path_read, "fat32_read_path");
return 0;
} else {
u32 sub_clus=0, sub_size=0;
if(fat32_find_in_dir(cur_clus,comp,1,&sub_clus,&sub_size)!=0) { logl("[DSK] fat32_read_path: dir not found in path: "); swrite(path); swrite("\n"); return -7; }
cur_clus=sub_clus;
}
}
DSK_TS_END(fat32_path_read, "fat32_read_path (failed)");
return -8;
}
/* Navigate a '/'-separated 8.3 path to find a directory cluster.
* Returns the cluster of the final directory, or 0 on failure.
* Requires g_disk to contain a valid BPB. */
static u32 fat32_find_dir_cluster(const char *path) {
const fat32_bpb *bpb = (const fat32_bpb *)g_disk;
if (bpb->boot_sig != 0xAA55 || bpb->bps != 512) return 0;
u32 pos = 0, path_len = 0;
while (path[path_len]) path_len++;
u32 cur_clus = bpb->root_clus;
while (pos < path_len) {
char comp[12]; u32 ci = 0;
while (pos < path_len && path[pos] != '/' && ci < 11) comp[ci++] = path[pos++];
while (ci < 11) comp[ci++] = ' ';
comp[11] = 0;
if (pos < path_len && path[pos] == '/') pos++;
u32 sub_clus = 0, sub_size = 0;
if (fat32_find_in_dir(cur_clus, comp, 1, &sub_clus, &sub_size) != 0) return 0;
cur_clus = sub_clus;
}
return cur_clus;
}
#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
/* ---- TSC-based timing ---- */
static u64 rdtsc_dsk(void) {
u32 lo, hi;
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
return ((u64)hi << 32) | lo;
}
static void tsc_calibrate_dsk(void) {
outb(0x43, 0x30); /* ch0, lo+hi, mode 0, binary */
outb(0x40, 0x7c); /* 11932 low = ~10ms */
outb(0x40, 0x2e); /* 11932 high */
u64 tsc_start = rdtsc_dsk();
u16 prev = 0; u64 loops = 0;
for (;;) {
outb(0x43, 0x00);
u16 cur = (u16)inb(0x40) | ((u16)inb(0x40) << 8);
if (cur > prev && loops > 10) break;
prev = cur; loops++;
}
u64 tsc_end = rdtsc_dsk();
g_tsc_per_ms = (tsc_end - tsc_start) / 10;
logh("[DSK] tsc_per_ms=", g_tsc_per_ms);
}
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;
}
}
}
/* ---- Spinner animation (removed — replaced by static Logo.png display) ---- */
/* ---- Logo rendering: center RGBA image with alpha blending on gradient bg ----
* g_logo_rgba / g_logo_w / g_logo_h are from logo_data.c (included above).
* Source pixel format: RGBA8888 (R at byte 0, G byte 1, B byte 2, A byte 3).
* Framebuffer format: UEFI BGRX — u32 = 0xAARRGGBB
* bits 0-7 = B, bits 8-15 = G, bits 16-23 = R, bits 24-31 = A/X
*/
static void dsk_draw_logo(u32 *fb) {
/* Center the logo on screen */
i64 ox = ((i64)g_fb_w - g_logo_w) / 2;
i64 oy = ((i64)g_fb_h - g_logo_h) / 2;
for (int ly = 0; ly < g_logo_h; ly++) {
i64 fy = oy + ly;
if (fy < 0 || (u64)fy >= g_fb_h) continue;
u32 *line = (u32 *)((u8 *)fb + (u64)fy * g_fb_p);
for (int lx = 0; lx < g_logo_w; lx++) {
i64 fx = ox + lx;
if (fx < 0 || (u64)fx >= g_fb_w) continue;
/* Read RGBA pixel from embedded data */
int idx = (ly * g_logo_w + lx) * 4;
u8 r = g_logo_rgba[idx + 0];
u8 g = g_logo_rgba[idx + 1];
u8 b = g_logo_rgba[idx + 2];
u8 a = g_logo_rgba[idx + 3];
if (a == 0) continue; /* fully transparent: skip */
if (a == 255) {
/* fully opaque: BGRX = 0xFF000000 | (R<<16) | (G<<8) | B */
line[(u64)fx] = 0xFF000000u | ((u32)r << 16) | ((u32)g << 8) | b;
} else {
/* alpha blend with background (BGRX channel order) */
u32 bg = line[(u64)fx];
u32 na = 256 - a;
u32 ob = (((bg & 0xFF) * na + (u32)b * a) >> 8) & 0xFF;
u32 og = ((((bg >> 8) & 0xFF) * na + (u32)g * a) >> 8) & 0xFF;
u32 or = ((((bg >> 16)& 0xFF) * na + (u32)r * a) >> 8) & 0xFF;
line[(u64)fx] = 0xFF000000u | (or << 16) | (og << 8) | ob;
}
}
}
}
/* ---- Text rendering: ASCII bitmap font on framebuffer ----
* Uses g_ascii[95][11*18] from ascii_bitmaps.c (Consolas 18px).
* Framebuffer format: BGRX — u32 = 0xAARRGGBB.
*/
static void dsk_draw_char(u32 *fb, char ch, i64 x, i64 y, u32 fg) {
u32 idx = (u32)(ch - ' ');
if (idx > 94) idx = 0;
const u8 *glyph = g_ascii[idx];
for (int r = 0; r < g_ascii_h; r++) {
i64 yy = y + r;
if (yy < 0 || (u64)yy >= g_fb_h) continue;
u32 *line = (u32 *)((u8 *)fb + (u64)yy * g_fb_p);
for (int c = 0; c < g_ascii_w; c++) {
u8 a = glyph[r * g_ascii_w + c];
if (a == 0) continue;
i64 xx = x + c;
if (xx < 0 || (u64)xx >= g_fb_w) continue;
if (a == 255) {
line[(u64)xx] = fg;
} else {
/* alpha blend with background */
u32 bg = line[(u64)xx];
u32 na = 256 - a;
u32 ob = (((bg & 0xFF) * na + ((fg & 0xFF) ) * a) >> 8) & 0xFF;
u32 og = ((((bg >> 8) & 0xFF) * na + (((fg >> 8) & 0xFF)) * a) >> 8) & 0xFF;
u32 or = ((((bg >> 16)& 0xFF) * na + (((fg >> 16)& 0xFF)) * a) >> 8) & 0xFF;
line[(u64)xx] = 0xFF000000u | (or << 16) | (og << 8) | ob;
}
}
}
}
static void dsk_draw_string(u32 *fb, const char *s, i64 x, i64 y, u32 fg, int spacing) {
i64 cx = x;
while (*s) {
dsk_draw_char(fb, *s, cx, y, fg);
cx += spacing;
s++;
}
}
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) | ((u32)r16((const u8*)&dir[e].chigh) << 16);
*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;
DSK_TS_DECL(fat32_root_read);
DSK_TS_BEGIN(fat32_root_read);
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) { logl("[DSK] fat32_read_root_file: BPB read failed"); return -1; }
const fat32_bpb *bpb = (const fat32_bpb *)disk;
if (bpb->boot_sig != 0xAA55 || bpb->bps != 512) { logl("[DSK] fat32_read_root_file: bad BPB sig/bps"); return -2; }
if (bpb->spf == 0 || bpb->root_clus < 2) { logh("[DSK] fat32_read_root_file: bad spf/root_clus spf=", (u64)bpb->spf); 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) { logh("[DSK] fat32_read_root_file: dir cluster read failed lba=", (u64)lba); return -4; }
cb = g_cluster;
}
if (fat32_find_entry(cb, spc, name11, &found_clus, &found_size) == 0) { found = 1; break; }
/* BUG-019: 使用按需 FAT 读取 */
clus = fat32_get_next_cluster(fat_byte_off, clus, bpb->rsvd);
}
if (!found) { logl("[DSK] fat32 entry not found: "); swrite(name11); swrite("\n"); return -5; }
logh("[DSK] fat32 found_clus=", found_clus);
logh("[DSK] fat32 found_size=", found_size);
if (found_size > sizeof(g_fdata)) { logh("[DSK] fat32_read_root_file: file too large size=", (u64)found_size); 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) { logh("[DSK] fat32_read_root_file: data cluster read failed lba=", (u64)fc_lba); return -7; }
fb = g_cluster;
}
for (u32 b = 0; b < fc_bytes; b++) dst[b] = fb[b];
dst += fc_bytes; remaining -= fc_bytes;
/* BUG-019: 使用按需 FAT 读取 */
fc = fat32_get_next_cluster(fat_byte_off, fc, bpb->rsvd);
}
*out_data = g_fdata; *out_size = found_size;
DSK_TS_END(fat32_root_read, "fat32_read_root_file");
logl("[DSK] fat32 file read done");
return 0;
}
/* Write a file to the FAT32 root directory by 11-char 8.3 name.
* If the file exists, its content is replaced. If not, a new entry is created.
* Uses g_disk (256-sector buffer) which must already contain the BPB+FAT+root.
* Returns 0 on success. */
static int fat32_write_root_file(const char *name11, const u8 *data, u32 size) {
u8 *disk = g_disk;
const fat32_bpb *bpb = (const fat32_bpb *)disk;
if (bpb->boot_sig != 0xAA55 || bpb->bps != 512) return -1;
u32 spc = bpb->spc;
u32 fat_lba = bpb->rsvd;
u32 fat_sectors = bpb->spf;
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
u32 fat_byte_off = bpb->rsvd * 512;
u32 root_clus = bpb->root_clus;
u32 cluster_bytes = spc * 512;
/* 1. Re-read BPB+FAT to ensure g_disk is fresh */
if (fat32_read_sectors(0, 256, disk) != 0) return -2;
/* 2. Find file entry in root directory — scan ALL clusters in FAT chain */
u32 cur_clus = root_clus;
int free_entry = -1;
u32 free_clus = 0; /* cluster number where free entry was found */
u32 existing_clus = 0;
int found = 0;
u32 found_clus = 0; /* cluster number where existing file was found */
while (cur_clus >= 2 && cur_clus < 0x0FFFFFF8) {
u32 clus_lba = data_lba + (cur_clus - 2) * spc;
int in_buf = ((u64)clus_lba * 512 + cluster_bytes <= 256ULL * 512);
u8 *buf;
if (in_buf) {
buf = disk + (u64)clus_lba * 512;
} else {
if (fat32_read_sectors(clus_lba, spc, g_milestone_buf) != 0) {
logl("[DSK] fat32 write: root dir cluster read failed");
break;
}
buf = g_milestone_buf;
}
u32 me = cluster_bytes / 32;
fat32_de *d = (fat32_de *)buf;
int cluster_done = 0;
for (u32 e = 0; e < me; e++) {
if (d[e].name[0] == 0) {
if (free_entry < 0) { free_entry = (int)e; free_clus = cur_clus; }
cluster_done = 1; break;
}
if ((u8)d[e].name[0] == 0xE5) {
if (free_entry < 0) { free_entry = (int)e; free_clus = cur_clus; }
continue;
}
if (d[e].attr == 0x0F) continue;
if (d[e].attr & 0x08) continue;
if (neq11(d[e].name, name11)) {
existing_clus = r16((const u8*)&d[e].clow) | ((u32)r16((const u8*)&d[e].chigh) << 16);
found = 1; found_clus = cur_clus;
cluster_done = 1; break;
}
}
if (cluster_done) break;
cur_clus = fat32_get_next_cluster(fat_byte_off, cur_clus, bpb->rsvd);
}
/* Re-read the active cluster (the one we'll modify) into root_buf */
u32 active_clus = found ? found_clus : free_clus;
u32 root_lba;
int root_in_buffer;
u8 *root_buf;
fat32_de *dir;
u32 max_entries = cluster_bytes / 32;
if (active_clus >= 2) {
root_lba = data_lba + (active_clus - 2) * spc;
root_in_buffer = ((u64)root_lba * 512 + cluster_bytes <= 256ULL * 512);
if (root_in_buffer) {
root_buf = disk + (u64)root_lba * 512;
} else {
if (fat32_read_sectors(root_lba, spc, g_milestone_buf) != 0) {
logl("[DSK] fat32 write: root dir re-read failed");
return -10;
}
root_buf = g_milestone_buf;
}
dir = (fat32_de *)root_buf;
} else {
root_lba = 0; root_in_buffer = 0; root_buf = 0; dir = 0;
}
/* 3. Allocate or reuse clusters */
u32 bytes_needed = size > 0 ? size : 1;
u32 clusters_needed = (bytes_needed + cluster_bytes - 1) / cluster_bytes;
u32 first_clus = 0;
u32 prev_clus = 0;
if (found && existing_clus >= 2) {
/* Reuse existing chain, extend or shrink as needed */
first_clus = existing_clus;
u32 cur = existing_clus;
u32 count = 0;
while (cur >= 2 && cur < 0x0FFFFFF8 && count < clusters_needed) {
prev_clus = cur;
u32 fo = fat_byte_off + cur * 4;
if (fo + 4 > sizeof(g_disk)) break;
cur = r32(disk + fo) & 0x0FFFFFFF;
count++;
}
/* If we need more clusters, allocate them */
while (count < clusters_needed) {
/* Find a free cluster in FAT */
u32 newc = 0;
for (u32 c = 2; c < (fat_sectors * 512) / 4; c++) {
u32 fo = fat_byte_off + c * 4;
if (fo + 4 > sizeof(g_disk)) break;
if ((r32(disk + fo) & 0x0FFFFFFF) == 0) { newc = c; break; }
}
if (newc == 0) { logl("[DSK] fat32 write: no free clusters"); return -3; }
/* BUG-20260730: Mark newly allocated cluster as EOC immediately to prevent re-allocation */
{
u32 nfo = fat_byte_off + newc * 4;
if (nfo + 4 <= sizeof(g_disk)) {
disk[nfo] = 0xF8; disk[nfo+1] = 0xFF; disk[nfo+2] = 0xFF; disk[nfo+3] = (disk[nfo+3] & 0xF0) | 0x0F;
}
}
/* Link previous cluster to new */
u32 pfo = fat_byte_off + prev_clus * 4;
if (pfo + 4 <= sizeof(g_disk)) {
disk[pfo] = (u8)(newc & 0xFF);
disk[pfo+1] = (u8)((newc >> 8) & 0xFF);
disk[pfo+2] = (u8)((newc >> 16) & 0xFF);
disk[pfo+3] = (disk[pfo+3] & 0xF0) | (u8)((newc >> 24) & 0x0F);
}
prev_clus = newc;
count++;
}
/* BUG-20260730: Terminate the chain, saving original next pointer before overwriting with EOC */
if (prev_clus >= 2) {
u32 fo = fat_byte_off + prev_clus * 4;
u32 original_next = 0;
if (fo + 4 <= sizeof(g_disk)) {
original_next = r32(disk + fo) & 0x0FFFFFFF;
disk[fo] = 0xF8; disk[fo+1] = 0xFF; disk[fo+2] = 0xFF; disk[fo+3] = (disk[fo+3] & 0xF0) | 0x0F;
}
/* Free excess clusters from the old chain using saved pointer */
u32 next = original_next;
while (next >= 2 && next < 0x0FFFFFF8) {
u32 nfo = fat_byte_off + next * 4;
u32 nn = 0;
if (nfo + 4 <= sizeof(g_disk)) nn = r32(disk + nfo) & 0x0FFFFFFF;
if (nfo + 4 <= sizeof(g_disk)) { disk[nfo] = 0; disk[nfo+1] = 0; disk[nfo+2] = 0; disk[nfo+3] = disk[nfo+3] & 0xF0; }
next = nn;
}
}
} else {
/* Allocate new clusters */
if (free_entry < 0) { logl("[DSK] fat32 write: no free dir entry"); return -4; }
for (u32 i = 0; i < clusters_needed; i++) {
u32 newc = 0;
for (u32 c = 2; c < (fat_sectors * 512) / 4; c++) {
u32 fo = fat_byte_off + c * 4;
if (fo + 4 > sizeof(g_disk)) break;
if ((r32(disk + fo) & 0x0FFFFFFF) == 0) { newc = c; break; }
}
if (newc == 0) { logl("[DSK] fat32 write: no free clusters"); return -3; }
/* BUG-20260730: Mark newly allocated cluster as EOC immediately to prevent re-allocation */
{
u32 nfo = fat_byte_off + newc * 4;
if (nfo + 4 <= sizeof(g_disk)) {
disk[nfo] = 0xF8; disk[nfo+1] = 0xFF; disk[nfo+2] = 0xFF; disk[nfo+3] = (disk[nfo+3] & 0xF0) | 0x0F;
}
}
if (i == 0) first_clus = newc;
if (prev_clus >= 2) {
u32 pfo = fat_byte_off + prev_clus * 4;
if (pfo + 4 <= sizeof(g_disk)) {
disk[pfo] = (u8)(newc & 0xFF);
disk[pfo+1] = (u8)((newc >> 8) & 0xFF);
disk[pfo+2] = (u8)((newc >> 16) & 0xFF);
disk[pfo+3] = (disk[pfo+3] & 0xF0) | (u8)((newc >> 24) & 0x0F);
}
}
prev_clus = newc;
}
/* Terminate chain */
/* BUG-20260730: Terminate chain preserving high 4 bits */
if (prev_clus >= 2) {
u32 fo = fat_byte_off + prev_clus * 4;
if (fo + 4 <= sizeof(g_disk)) {
disk[fo] = 0xF8; disk[fo+1] = 0xFF; disk[fo+2] = 0xFF; disk[fo+3] = (disk[fo+3] & 0xF0) | 0x0F;
}
}
}
/* 4. Write data to clusters */
u32 remaining = size;
const u8 *src = data;
u32 cur = first_clus;
u32 ci = 0;
while (cur >= 2 && cur < 0x0FFFFFF8 && ci < clusters_needed) {
u32 clba = data_lba + (cur - 2) * spc;
u32 chunk = remaining < cluster_bytes ? remaining : cluster_bytes;
/* Read cluster into g_cluster, overlay data, write back */
if ((u64)clba * 512 + cluster_bytes <= 256ULL * 512) {
/* In g_disk buffer — copy data directly */
u8 *dst = disk + (u64)clba * 512;
for (u32 b = 0; b < chunk; b++) dst[b] = src[b];
for (u32 b = chunk; b < cluster_bytes; b++) dst[b] = 0;
} else {
/* Out of buffer — use sector write */
if (fat32_read_sectors(clba, spc, g_cluster) != 0) return -5;
for (u32 b = 0; b < chunk; b++) g_cluster[b] = src[b];
for (u32 b = chunk; b < cluster_bytes; b++) g_cluster[b] = 0;
if (fat32_write_sectors(clba, spc, g_cluster) != 0) return -6;
}
src += chunk; remaining -= chunk; ci++;
u32 fo = fat_byte_off + cur * 4;
if (fo + 4 > sizeof(g_disk)) break;
cur = r32(disk + fo) & 0x0FFFFFFF;
}
/* 5. Update directory entry */
if (!found) {
fat32_de *e = &dir[free_entry];
for (int i = 0; i < 11; i++) e->name[i] = name11[i];
e->attr = 0x20; /* archive */
e->ntr = 0; e->ctenth = 0; e->ctime = 0; e->cdate = 0;
e->adate = 0; e->chigh = (u16)((first_clus >> 16) & 0xFFFF);
e->wtime = 0; e->wdate = 0; e->clow = (u16)(first_clus & 0xFFFF);
e->fsize = size;
} else {
/* 文件已存在:只更新匹配到的条目(不触碰 free_entry!) */
for (u32 e2 = 0; e2 < max_entries; e2++) {
if (neq11(dir[e2].name, name11)) {
dir[e2].chigh = (u16)((first_clus >> 16) & 0xFFFF);
dir[e2].clow = (u16)(first_clus & 0xFFFF);
dir[e2].fsize = size;
break;
}
}
}
/* 6. Write FAT + root directory + data sectors back to disk */
/* BUG-20260730: Only write back FAT sectors within g_disk buffer bounds */
{
u32 max_fat_sectors_in_buffer = (256 - fat_lba) / fat_sectors;
if (max_fat_sectors_in_buffer > bpb->fc) max_fat_sectors_in_buffer = bpb->fc;
for (u32 f = 0; f < max_fat_sectors_in_buffer; f++) {
u32 flba = fat_lba + f * fat_sectors;
u32 sectors_to_write = fat_sectors;
if (flba + sectors_to_write > 256) sectors_to_write = 256 - flba;
if (sectors_to_write > 0 && flba < 256) {
if (fat32_write_sectors(flba, sectors_to_write, disk + (u64)flba * 512) != 0) return -7;
}
}
}
/* Write root directory cluster that was modified */
{
if (root_in_buffer) {
if (fat32_write_sectors(root_lba, spc, disk + (u64)root_lba * 512) != 0) return -8;
} else {
if (fat32_write_sectors(root_lba, spc, g_milestone_buf) != 0) {
logl("[DSK] fat32 write: root dir write failed (bounce buffer)");
return -8;
}
}
}
/* Write data clusters that were in the g_disk buffer */
cur = first_clus;
ci = 0;
while (cur >= 2 && cur < 0x0FFFFFF8 && ci < clusters_needed) {
u32 clba = data_lba + (cur - 2) * spc;
if ((u64)clba * 512 + cluster_bytes <= 256ULL * 512) {
if (fat32_write_sectors(clba, spc, disk + (u64)clba * 512) != 0) return -9;
}
u32 fo = fat_byte_off + cur * 4;
if (fo + 4 > sizeof(g_disk)) break;
cur = r32(disk + fo) & 0x0FFFFFFF;
ci++;
}
logl("[DSK] fat32 write: success");
return 0;
}
/* Write a file into a directory identified by dir_clus, by 11-char 8.3 name.
* If the file exists, its content is replaced. If not, a new entry is created.
* Content must fit in one cluster (optimized for small marker files).
* Uses g_disk (BPB+FAT) and g_cluster (dir) and g_milestone_buf (data).
* Returns 0 on success. */
static int fat32_write_file_in_dir(u32 dir_clus, const char *name11, const u8 *data, u32 size) {
u8 *disk = g_disk;
const fat32_bpb *bpb = (const fat32_bpb *)disk;
if (bpb->boot_sig != 0xAA55 || bpb->bps != 512) return -1;
u32 spc = bpb->spc;
u32 fat_lba = bpb->rsvd;
u32 fat_sectors = bpb->spf;
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
u32 fat_byte_off = bpb->rsvd * 512;
u32 cluster_bytes = spc * 512;
if (size > cluster_bytes) return -1; /* content must fit in one cluster */
/* 1. Re-read BPB+FAT to ensure g_disk is fresh */
if (fat32_read_sectors(0, 256, disk) != 0) return -2;
/* 2. Read directory cluster */
u32 dir_lba = data_lba + (dir_clus - 2) * spc;
if (fat32_read_sectors(dir_lba, spc, g_cluster) != 0) return -3;
/* 3. Find existing entry or free slot */
u32 max_entries = cluster_bytes / 32;
fat32_de *dir = (fat32_de *)g_cluster;
int free_entry = -1;
u32 existing_clus = 0;
int found = 0;
for (u32 e = 0; e < max_entries; e++) {
if (dir[e].name[0] == 0) { if (free_entry < 0) free_entry = (int)e; break; }
if ((u8)dir[e].name[0] == 0xE5) { if (free_entry < 0) free_entry = (int)e; continue; }
if (dir[e].attr == 0x0F) continue;
if (dir[e].attr & 0x08) continue;
if (neq11(dir[e].name, name11)) {
existing_clus = r16((const u8*)&dir[e].clow) | ((u32)r16((const u8*)&dir[e].chigh) << 16);
found = 1;
break;
}
}
if (!found && free_entry < 0) return -4;
/* 4. Allocate or reuse data cluster */
u32 file_clus = 0;
if (found && existing_clus >= 2) {
file_clus = existing_clus;
} else {
/* Find free cluster in FAT */
for (u32 c = 2; c < (fat_sectors * 512) / 4; c++) {
u32 fo = fat_byte_off + c * 4;
if (fo + 4 > sizeof(g_disk)) break;
if ((r32(disk + fo) & 0x0FFFFFFF) == 0) { file_clus = c; break; }
}
if (file_clus == 0) return -5;
/* BUG-20260730: Mark as end-of-chain in FAT, preserving high 4 bits */
u32 fo = fat_byte_off + file_clus * 4;
if (fo + 4 <= sizeof(g_disk)) {
disk[fo] = 0xF8; disk[fo+1] = 0xFF; disk[fo+2] = 0xFF; disk[fo+3] = (disk[fo+3] & 0xF0) | 0x0F;
}
}
/* 5. Write file data to cluster */
u32 file_lba = data_lba + (file_clus - 2) * spc;
for (u32 b = 0; b < size; b++) g_milestone_buf[b] = data[b];
for (u32 b = size; b < cluster_bytes; b++) g_milestone_buf[b] = 0;
if (fat32_write_sectors(file_lba, spc, g_milestone_buf) != 0) return -6;
/* 6. Update directory entry */
if (found) {
for (u32 e = 0; e < max_entries; e++) {
if (neq11(dir[e].name, name11)) {
dir[e].chigh = (u16)((file_clus >> 16) & 0xFFFF);
dir[e].clow = (u16)(file_clus & 0xFFFF);
dir[e].fsize = size;
break;
}
}
} else {
fat32_de *e = &dir[free_entry];
for (int i = 0; i < 11; i++) e->name[i] = name11[i];
e->attr = 0x20; /* archive */
e->ntr = 0; e->ctenth = 0; e->ctime = 0; e->cdate = 0;
e->adate = 0; e->chigh = (u16)((file_clus >> 16) & 0xFFFF);
e->wtime = 0; e->wdate = 0; e->clow = (u16)(file_clus & 0xFFFF);
e->fsize = size;
}
/* 7. Write directory cluster back */
if (fat32_write_sectors(dir_lba, spc, g_cluster) != 0) return -7;
/* BUG-20260730: Only write back FAT sectors within g_disk buffer bounds */
{
u32 max_fat_sectors_in_buffer = (256 - fat_lba) / fat_sectors;
if (max_fat_sectors_in_buffer > bpb->fc) max_fat_sectors_in_buffer = bpb->fc;
for (u32 f = 0; f < max_fat_sectors_in_buffer; f++) {
u32 flba = fat_lba + f * fat_sectors;
u32 sectors_to_write = fat_sectors;
if (flba + sectors_to_write > 256) sectors_to_write = 256 - flba;
if (sectors_to_write > 0 && flba < 256) {
if (fat32_write_sectors(flba, sectors_to_write, disk + (u64)flba * 512) != 0) return -8;
}
}
}
logl("[DSK] fat32 write_in_dir: success");
return 0;
}
/* ---- DSK 启动链里程碑标记系统 ----
* 实机测试崩溃定位:每个启动阶段成功后写标记文件到 FAT32。
* 命名:BOOT01.TXT ~ BOOT07.TXT(8.3 短名)。
* 目标目录:DESHAB64/DEV/(不存在时回退根目录)。
* 写入失败静默忽略,不影响启动流程。
*
* 阶段定义:
* BOOT_01: FAT32 文件系统就绪
* BOOT_02: block_read/block_write API 就绪
* BOOT_03: FUCK 配置加载完成
* BOOT_04: firstInit 检查完成
* BOOT_05: dev_mode shell 加载完成
* BOOT_06: desktop.elf 加载完成
* BOOT_07: 网络管理器加载完成 */
static void milestone_write(int num, const char *desc) {
if (!g_block_write) return;
if (num < 1 || num > 9) return;
/* 构造 8.3 短名: "BOOTnn TXT" (FAT 8.3 format, 11 chars) */
char name11[12];
name11[0]='B'; name11[1]='O'; name11[2]='O'; name11[3]='T';
name11[4]=(char)('0' + (num / 10));
name11[5]=(char)('0' + (num % 10));
name11[6]=' '; name11[7]=' ';
name11[8]='T'; name11[9]='X'; name11[10]='T';
/* 构造内容: "OK\n" + desc + "\n" */
/* BUG-20260730: Enlarge buffer — "OK\n" + stage desc + " tsc=0x" + 16-hex + " ms=" + digits + "\n" can exceed 64 */
u8 buf[160];
u32 len = 0;
buf[len++]='O'; buf[len++]='K'; buf[len++]='\n';
while (*desc && len < 150) buf[len++] = (u8)*desc++;
buf[len++] = '\n';
/* 确保 BPB 在 g_disk 中可用 */
if (fat32_read_sectors(0, 256, g_disk) != 0) return;
/* 尝试写入 DESHAB64/DEV/ 目录,不存在则回退根目录 */
u32 dev_clus = fat32_find_dir_cluster("SYSTEM /DESHAB64 /DEV ");
int rc;
if (dev_clus >= 2) {
rc = fat32_write_file_in_dir(dev_clus, name11, buf, len);
} else {
rc = fat32_write_root_file(name11, buf, len);
}
if (rc == 0) {
swrite("[DSK] milestone BOOT_0");
sputc('0' + num);
logl(dev_clus >= 2 ? " written (DEV)" : " written (root)");
}
}
static int dsk_check_firstinit(int *is_first, int *dev_mode) {
DSK_TS_DECL(firstinit_check);
DSK_TS_BEGIN(firstinit_check);
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;
*dev_mode = 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, assuming first boot"); *is_first = 1; DSK_TS_END(firstinit_check, "dsk_check_firstinit (not found)"); return 0; }
if (data[0] == '0') { logl("[DSK] firstInit=0"); *is_first = 1; }
else { logl("[DSK] firstInit != 0"); *is_first = 0; }
/* 解析第二行 dev_mode 标志(firstInit.txt 格式: "0|1\n0|1") */
u32 i = 0;
while (i < size && data[i] != '\n') i++;
if (i < size) {
i++; /* 跳过换行 */
if (i < size && data[i] == '1') {
*dev_mode = 1;
logl("[DSK] dev_mode=1 (developer auto-test)");
}
}
DSK_TS_END(firstinit_check, "dsk_check_firstinit");
return 0;
}
static int dsk_load_elf(u8 *data, u32 size, void **entry_out) {
DSK_TS_DECL(elf_load);
DSK_TS_BEGIN(elf_load);
DSK_STAT_INC(elf_load);
const elf64_ehdr *eh = (const elf64_ehdr *)data;
if (size < sizeof(elf64_ehdr)) { logl("[DSK] ELF: data too small"); return -1; }
if (eh->ident[0] != EI_MAG0 || eh->ident[4] != ELFCLASS64) { logl("[DSK] ELF: bad magic/class"); return -1; }
if (eh->machine != EM_X86_64) { logl("[DSK] ELF: wrong machine"); return -2; }
/* P0 修复: 验证程序头在数据范围内 */
if (eh->phoff == 0 || eh->phnum == 0) { logl("[DSK] ELF: no program headers"); return -3; }
if ((u64)eh->phoff + (u64)eh->phnum * (u64)eh->phentsize > (u64)size) {
logl("[DSK] ELF: program headers beyond data bounds");
return -4;
}
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) { logl("[DSK] ELF: filesz > memsz"); return -5; }
/* P0 修复: 验证 PT_LOAD 段在数据范围内 */
if ((u64)ph->offset + (u64)ph->filesz > (u64)size) {
logl("[DSK] ELF: PT_LOAD beyond data bounds");
logh("[DSK] ELF: offset=", ph->offset);
logh("[DSK] ELF: filesz=", ph->filesz);
return -6;
}
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) { logl("[DSK] ELF: no PT_LOAD segments"); return -7; }
u64 isize = max_vaddr - min_vaddr;
isize = (isize + 0xFFF) & ~0xFFFULL;
logh("[DSK] elf total image size=", isize);
/* 加载缓冲:需容纳 desktop.elf(~1.67MB memsz span,含 Linux 窗口槽+16KB 缓冲 BSS)。2MB 留余量。 */
static u8 ibuf[8388608]; /* 8MB — cmd.elf 含 4MB PE 文件缓冲 BSS */
u8 *image = ibuf;
if (isize > 8388608) { logl("[DSK] ELF: image too large for 8MB ibuf"); logh("[DSK] ELF isize=", isize); return -8; }
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;
logh("[DSK] PT_LOAD vaddr=", ph->vaddr);
logh("[DSK] PT_LOAD filesz=", ph->filesz);
logh("[DSK] PT_LOAD memsz=", ph->memsz);
/* off + filesz 不会越界,已在上面的循环中验证 */
memcpy_dsk(image + off, data + ph->offset, ph->filesz);
}
/* P0 修复: 验证 entry 在映像范围内 */
if (eh->entry < min_vaddr || eh->entry >= max_vaddr) {
logl("[DSK] ELF: entry point out of bounds");
logh("[DSK] ELF: entry=", eh->entry);
logh("[DSK] ELF: min_vaddr=", min_vaddr);
logh("[DSK] ELF: max_vaddr=", max_vaddr);
return -9;
}
*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;
/* P0 修复: 验证 PT_DYNAMIC vaddr 在映像范围内 */
if (ph->vaddr < min_vaddr || ph->vaddr + ph->filesz > max_vaddr) {
logl("[DSK] ELF: PT_DYNAMIC out of image bounds");
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) {
/* P0 修复: 边界检查 rela_off 和 rela_off+rela_sz 必须在 [min_vaddr, min_vaddr+isize) 内 */
if (rela_off < min_vaddr || rela_off >= min_vaddr + isize) {
logl("[DSK] ELF: rela_off out of bounds, skipping reloc");
logh("[DSK] ELF: rela_off=", rela_off);
logh("[DSK] ELF: min_vaddr=", min_vaddr);
logh("[DSK] ELF: isize=", isize);
continue;
}
if (rela_off + rela_sz > min_vaddr + isize) {
logl("[DSK] ELF: rela table extends beyond image, clamping");
rela_sz = (min_vaddr + isize - rela_off) / rela_ent * rela_ent;
}
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) {
/* P0 修复: 验证 rel->offset 在映像范围内,防止无符号下溢 */
if (rel->offset < min_vaddr || rel->offset >= min_vaddr + isize) continue;
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);
DSK_TS_END(elf_load, "dsk_load_elf");
return 0;
}
/* Load an ELF module from the FAT32 root by 11-char 8.3 name, parse it into
* the shared image buffer, and jump to its entry with the boot context.
* Returns 0 if the module ran and returned, non-zero on load failure. */
static int dsk_load_and_run(const char name11[12], const dsk_boot_context *ctx) {
DSK_TS_DECL(mod_run);
DSK_TS_BEGIN(mod_run);
DSK_STAT_INC(mod_schedule);
u8 *data=0; u32 size=0; void *entry=0;
logl("[DSK] load_and_run: ");
swrite(name11); swrite("\n");
if (fat32_read_root_file(name11, &data, &size) != 0) { logl("[DSK] load_and_run: fat32 read failed for "); swrite(name11); swrite("\n"); return -1; }
if (dsk_load_elf(data, size, &entry) != 0) { logl("[DSK] load_and_run: elf load failed for "); swrite(name11); swrite("\n"); return -2; }
void(*fn)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))entry;
fn(ctx);
DSK_TS_END(mod_run, "dsk_load_and_run");
return 0;
}
/* Load desktop.elf and jump to it. Never returns on success. */
static void dsk_run_desktop(const dsk_boot_context *ctx) {
char dn[12]; /* DESKTOP ELF */
dn[0]='D';dn[1]='E';dn[2]='S';dn[3]='K';dn[4]='T';dn[5]='O';dn[6]='P';dn[7]=' ';dn[8]='E';dn[9]='L';dn[10]='F';
if (dsk_load_and_run(dn, ctx) != 0) logl("[DSK] desktop load failed");
for(;;)__asm__("hlt");
}
/* After FirstInit returns, persist the encrypted user.conf buffer (left in
* ctx->reserved[0/1]) to the FAT32 root as USER.CONF, then flip firstInit.txt
* from '0' to '1' so subsequent boots skip the wizard and go to login. */
static void dsk_persist_userconf(const dsk_boot_context *ctx) {
dsk_boot_context *ctx_mut = (dsk_boot_context *)ctx;
u64 conf_ptr = ctx_mut->reserved[0];
u64 conf_sz = ctx_mut->reserved[1];
if (!conf_ptr || !conf_sz) {
logl("[DSK] no conf buffer from FirstInit, skipping persist");
return;
}
if (!g_block_write) {
logl("[DSK] no block_write, cannot persist user.conf");
return;
}
const u8 *conf = (const u8 *)conf_ptr;
/* 1. Write USER.CONF (encrypted buffer as-is; login decrypts with password) */
char cn[12]; /* USER CON */
cn[0]='U';cn[1]='S';cn[2]='E';cn[3]='R';cn[4]=' ';cn[5]=' ';cn[6]=' ';cn[7]=' ';cn[8]='C';cn[9]='O';cn[10]='N';
logl("[DSK] writing USER.CONF");
int wrc = fat32_write_root_file(cn, conf, (u32)conf_sz);
logh("[DSK] USER.CONF write rc=", (u64)(i64)wrc);
/* 2. Flip firstInit.txt: '0' -> '1',保留第二行 dev_mode 标志 */
char fn[12]; /* FIRSTINTXT */
fn[0]='F';fn[1]='I';fn[2]='R';fn[3]='S';fn[4]='T';fn[5]='I';fn[6]='N';fn[7]='T';fn[8]='X';fn[9]='T';fn[10]=0;
/* 读取当前 firstInit.txt 以保留 dev_mode(第二行),格式 "0|1\n0|1" */
u8 dev_mode_byte = '0';
u8 *fi_data = 0; u32 fi_size = 0;
if (fat32_read_root_file(fn, &fi_data, &fi_size) == 0) {
u32 i = 0;
while (i < fi_size && fi_data[i] != '\n') i++;
if (i < fi_size) { i++; if (i < fi_size) dev_mode_byte = fi_data[i]; }
}
u8 fi_buf[3]; fi_buf[0] = '1'; fi_buf[1] = '\n'; fi_buf[2] = dev_mode_byte;
int frc = fat32_write_root_file(fn, fi_buf, 3);
logh("[DSK] firstInit.txt flip rc=", (u64)(i64)frc);
/* Clear reserved so login path doesn't see stale pointer */
ctx_mut->reserved[0] = 0;
ctx_mut->reserved[1] = 0;
}
/* Draw the spinning loader (comet-tail arc) on the gradient background,
* then run the firstInit check and dispatch system component loading.
* FUCK config controls: show_logo, skip_login, mouse_init, netman, dev_mode. */
static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
const dsk_boot_context *ctx = (const dsk_boot_context *)boot_ctx_ptr;
{ u64 api_addr = ctx->dkm_kernel_api;
logh("[DSK] kernel_api addr=", api_addr);
if (!api_addr) { logl("[DSK] FATAL: kernel_api is NULL"); for(;;)__asm__("hlt"); }
const dsk_kernel_api_mirror *api = (const dsk_kernel_api_mirror *)api_addr;
const dsk_block_api_mirror *blk = api->block;
logh("[DSK] block_api addr=", (u64)(u64)blk);
g_block_read = blk ? blk->read : 0;
g_block_write = blk ? blk->write : 0;
logh("[DSK] block_read fn=", (u64)g_block_read);
logh("[DSK] block_write fn=", (u64)g_block_write); }
milestone_write(2, "block API ready");
g_fb_addr=ctx->framebuffer_address; g_fb_w=ctx->framebuffer_width;
g_fb_h=ctx->framebuffer_height; g_fb_p=ctx->framebuffer_pitch;
if (!g_fb_addr) { logl("[DSK] FATAL: framebuffer address is NULL"); for(;;)__asm__("hlt"); }
u32 *sfb=(u32*)(u64)g_fb_addr;
logh("[DSK] block_read ptr=", (u64)g_block_read);
tsc_calibrate_dsk();
/* === 读取 FUCK 配置 === */
DSK_TS_DECL(fuck_config);
DSK_TS_BEGIN(fuck_config);
dsk_ini_config dsk_cfg;
int dsk_cfg_ok = 0;
if (g_block_read) {
logl("[DSK] reading BPB for FUCK config");
int bpb_rc = fat32_read_sectors(0, 256, g_disk);
if (bpb_rc == 0) {
milestone_write(1, "FAT32 ready");
u8 *fuck_data=0; u32 fuck_size=0;
int rc = fat32_read_path("SYSTEM /DESHAB64 /FUCK ", &fuck_data, &fuck_size);
logh("[DSK] fat32_read_path FUCK rc=", (u64)(i64)rc);
if (rc != 0) {
/* 扁平布局回退:SATA 测试盘等场景下 FUCK 直接放根目录 */
rc = fat32_read_path("FUCK ", &fuck_data, &fuck_size);
logh("[DSK] fat32_read_path root FUCK rc=", (u64)(i64)rc);
}
if (rc == 0 && fuck_size > 0) {
if (dsk_ini_parse((const char *)fuck_data, fuck_size, &dsk_cfg) == 0) {
dsk_cfg_ok = 1;
logl("[DSK] FUCK config loaded");
} else {
logl("[DSK] FUCK INI parse failed");
}
} else {
logl("[DSK] FUCK file not found or empty");
}
} else {
logl("[DSK] BPB read failed, cannot load FUCK");
}
}
DSK_TS_END(fuck_config, "FUCK config load");
/* === 应用 DSK 配置 === */
int show_logo = dsk_cfg_ok ? dsk_ini_get_bool(&dsk_cfg, "dsk", "show_logo", 1) : 1;
int skip_login = dsk_cfg_ok ? dsk_ini_get_bool(&dsk_cfg, "dsk", "skip_login", 0) : 0;
int load_mouse = dsk_cfg_ok ? dsk_ini_get_bool(&dsk_cfg, "dsk", "mouse_init", 1) : 1;
int load_netman = dsk_cfg_ok ? dsk_ini_get_bool(&dsk_cfg, "dsk", "netman", 1) : 1;
int dev_mode = dsk_cfg_ok ? dsk_ini_get_bool(&dsk_cfg, "boot", "dev_mode", 0) : 0;
milestone_write(3, "FUCK config loaded");
/* Gradient background + centered Logo.png (5 seconds) */
dsk_fill_gradient_rect(sfb, 0, 0, (i64)g_fb_w, (i64)g_fb_h);
if (show_logo) {
/* Draw Logo.png centered with alpha blending on gradient background */
dsk_draw_logo(sfb);
/* Draw "DESHAB P01" text centered below the logo */
{
i64 logo_cx = (i64)g_fb_w / 2;
i64 logo_cy = ((i64)g_fb_h - g_logo_h) / 2;
const char *ver_str = "DESHAB P01";
int len = 10; /* strlen("DESHAB P01") */
int spacing = g_ascii_w + 1; /* 11+1 = 12px per char */
i64 text_w = (i64)len * spacing;
i64 text_x = logo_cx - text_w / 2;
i64 text_y = logo_cy + g_logo_h + 12; /* 12px below logo */
/* White text: BGRX = 0xFF_RR_GG_BB = 0xFF_FFFFFF */
u32 fg = 0xFFFFFFFFu;
dsk_draw_string(sfb, ver_str, text_x, text_y, fg, spacing);
}
logh("[DSK] Logo.png displayed (", (u64)g_logo_w);
logh("[DSK] x", (u64)g_logo_h);
/* Hold Logo for 5 seconds */
u64 logo_start = rdtsc_dsk();
u64 logo_budget = g_tsc_per_ms * 5000; /* 5000 ms = 5 seconds */
while (rdtsc_dsk() - logo_start < logo_budget) __asm__("pause");
logl("[DSK] Logo 5s done, proceeding");
} else {
logl("[DSK] logo skipped by FUCK config");
}
if (!g_block_read) {
logl("[DSK] no block device, halting");
for(;;)__asm__("hlt");
}
logl("[DSK] checking firstInit...");
DSK_TS_DECL(firstinit_phase);
DSK_TS_BEGIN(firstinit_phase);
int is_first = 0, firstinit_dev_mode = 0;
if (dsk_check_firstinit(&is_first, &firstinit_dev_mode) != 0) {
logl("[DSK] firstInit check failed, halting");
for(;;)__asm__("hlt");
}
DSK_TS_END(firstinit_phase, "firstInit check phase");
milestone_write(4, "firstInit check done");
/* 合并 FUCK dev_mode 和 firstInit.txt dev_mode */
if (firstinit_dev_mode) dev_mode = 1;
/* 开发者模式:加载 shell.elf 自动测试命令序列(cp/mv/echo/ls/cat/rm) */
if (dev_mode) {
logl("[DSK:SCHED] decision: dev_mode -> shell.elf");
char sn[12]; /* SHELL ELF */
sn[0]='S';sn[1]='H';sn[2]='E';sn[3]='L';sn[4]='L';sn[5]=' ';sn[6]=' ';sn[7]=' ';sn[8]='E';sn[9]='L';sn[10]='F';
dsk_boot_context *ctx_mut = (dsk_boot_context *)ctx;
ctx_mut->reserved[3] = 1; /* dev mode flag for shell */
if (dsk_load_and_run(sn, ctx) == 0) logl("[DSK] shell auto-test returned");
else logl("[DSK] shell.elf not found, skipping dev test");
ctx_mut->reserved[3] = 0;
milestone_write(5, "dev shell loaded");
}
if (!is_first) {
logl("[DSK:SCHED] decision: is_first=0 -> login then desktop");
/* login — 可通过 skip_login=1 跳过 */
if (skip_login) {
logl("[DSK:SCHED] login skipped by FUCK config");
} else {
DSK_TS_DECL(login_phase);
DSK_TS_BEGIN(login_phase);
logl("[DSK:SCHED] scheduling login.elf");
char ln[12]; /* LOGIN ELF */
ln[0]='L';ln[1]='O';ln[2]='G';ln[3]='I';ln[4]='N';ln[5]=' ';ln[6]=' ';ln[7]=' ';ln[8]='E';ln[9]='L';ln[10]='F';
u8 *ld=0; u32 ls=0; void *le=0;
int login_ok = 0;
if (fat32_read_root_file(ln, &ld, &ls) == 0) {
if (dsk_load_elf(ld, ls, &le) == 0) {
char cn[12]; /* USER CON */
cn[0]='U';cn[1]='S';cn[2]='E';cn[3]='R';cn[4]=' ';cn[5]=' ';cn[6]=' ';cn[7]=' ';cn[8]='C';cn[9]='O';cn[10]='N';
u8 *conf_data=0; u32 conf_size=0;
if (fat32_read_root_file(cn, &conf_data, &conf_size) == 0) {
logl("[DSK] USER.CONF found, passing to login");
dsk_boot_context *ctx_mut = (dsk_boot_context *)ctx;
ctx_mut->reserved[0] = (u64)conf_data;
ctx_mut->reserved[1] = (u64)conf_size;
ctx_mut->reserved[2] = 0; /* login success flag */
logl("[DSK] jumping to login");
void(*lentry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))le;
lentry(ctx);
logl("[DSK] login returned");
if (ctx_mut->reserved[2] == 1) {
logl("[DSK] login success");
login_ok = 1;
} else {
logl("[DSK] login skipped or failed");
}
} else {
logl("[DSK] USER.CONF not found, skipping login");
}
} else {
logl("[DSK] login.elf load failed, skipping login");
}
} else {
logl("[DSK] login.elf not found, skipping login");
}
(void)login_ok;
DSK_TS_END(login_phase, "login phase");
}
/* default_shell=cmd → 直接进 CMD.ELF(PE/EXE 兼容层前端),
* cmd 退出后回落桌面。 */
const char *def_shell = dsk_cfg_ok ? dsk_ini_get(&dsk_cfg, "dsk", "default_shell") : 0;
if (def_shell && dsk_ini_streq(def_shell, "cmd")) {
logl("[DSK:SCHED] default_shell=cmd -> cmd.elf");
char cn[12]; /* CMD ELF */
cn[0]='C';cn[1]='M';cn[2]='D';cn[3]=' ';cn[4]=' ';cn[5]=' ';cn[6]=' ';cn[7]=' ';cn[8]='E';cn[9]='L';cn[10]='F';
if (dsk_load_and_run(cn, ctx) == 0) logl("[DSK] cmd.elf returned, falling back to desktop");
else logl("[DSK] cmd.elf load failed, falling back to desktop");
}
logl("[DSK:SCHED] loading desktop");
logh("[DSK:STAT] fat32_read_count=", (u64)fat32_read_count);
logh("[DSK:STAT] fat32_write_count=", (u64)fat32_write_count);
logh("[DSK:STAT] elf_load_count=", (u64)elf_load_count);
logh("[DSK:STAT] mod_schedule_count=", (u64)mod_schedule_count);
milestone_write(6, "desktop loading");
dsk_run_desktop(ctx);
return;
}
/* First boot: run system initializers, then FirstInit, then desktop */
logl("[DSK:SCHED] decision: is_first=1 -> mouseInit -> netman -> FirstInit -> desktop");
/* mouseInit.elf — 可通过 FUCK mouse_init=0 跳过 */
if (load_mouse) {
logl("[DSK:SCHED] scheduling mouseInit.elf");
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';
logl("[DSK] loading mouseInit");
if (dsk_load_and_run(mn, ctx) == 0) logl("[DSK] mouseInit returned");
else logl("[DSK] mouseInit not found");
} else {
logl("[DSK] mouseInit skipped by FUCK config");
}
/* netman.elf — 可通过 FUCK netman=0 跳过 */
if (load_netman) {
logl("[DSK:SCHED] scheduling netman.elf");
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';
logl("[DSK] loading netman");
if (dsk_load_and_run(nn, ctx) == 0) logl("[DSK] netman returned");
else logl("[DSK] netman not found");
} else {
logl("[DSK] netman skipped by FUCK config");
}
milestone_write(7, "netman loaded");
/* FirstInit.elf — user setup wizard; returns to DSK when done */
{ logl("[DSK:SCHED] scheduling 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;
logl("[DSK] loading FirstInit");
if (dsk_load_and_run(en, ctx) != 0) {
logl("[DSK] FirstInit not found, loading desktop directly");
milestone_write(6, "desktop loading");
dsk_run_desktop(ctx);
return;
}
logl("[DSK] FirstInit returned, persisting user.conf");
dsk_persist_userconf(ctx);
logh("[DSK:STAT] fat32_read_count=", (u64)fat32_read_count);
logh("[DSK:STAT] fat32_write_count=", (u64)fat32_write_count);
logh("[DSK:STAT] elf_load_count=", (u64)elf_load_count);
logh("[DSK:STAT] mod_schedule_count=", (u64)mod_schedule_count);
logl("[DSK] loading desktop");
milestone_write(6, "desktop loading");
dsk_run_desktop(ctx);
}
}
__attribute__((noreturn, visibility("default")))
void dsk_entry(const dsk_boot_context *ctx) {
__asm__ volatile("cli"); /* disable IRQs — ps2kbd/IRQ1 & mouse/IRQ12 handlers crash during boot */
logl("[DSK] boot");
if(!ctx||ctx->magic!=DSK_BOOT_MAGIC){logl("[DSK] bad context");for(;;)__asm__("hlt");}
logl("[DSK] context ok");
dsk_spinner_and_check(ctx);
logl("[DSK] SELFTEST PASS");
for(;;)__asm__("hlt");
}