This commit is contained in:
Linehu
2026-08-09 22:20:01 +08:00
parent 8717ea8f20
commit 2a50fa58c7
185 changed files with 19890 additions and 710 deletions
+106 -34
View File
@@ -2,6 +2,7 @@
#include "../UTSM/include/utsm/dsk.h"
#include "port.h"
#include "../tools/fat32_lfn.h"
/* Embedded Logo.png RGBA data (auto-generated by png_to_rgba.py) */
#include "logo_data.c"
@@ -104,10 +105,13 @@ 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 端一致) */
static u8 g_fdata[10485760]; /* 10MB file data buffer (与 UTSM 端一致, 支持 SYSTEM/lib 大型 DLL) */
/* BUG-019 修复: FAT 按需扇区读取缓冲区(仅 512 字节) */
static u8 g_fat_sec[512];
static u8 g_milestone_buf[4096]; /* milestone write cluster buffer */
/* 网络租约缓冲:DSK 常驻持有,调度 netman 前经 reserved[7] 暴露指针,
* netman 写入 DHCP/静态配置,后续模块(shell/desktop/工具)经同一指针读取。 */
static net_lease_info g_net_lease;
DSK_STAT_DECL(fat32_read);
DSK_STAT_DECL(fat32_write);
@@ -229,16 +233,23 @@ static int dsk_ini_get_bool(const dsk_ini_config *cfg, const char *sec, const ch
/* ---- DSK FAT32 子目录遍历 ---- */
/* 在指定起始 cluster 的目录中查找 name11。
/* 在指定起始 cluster 的目录中查找 name11(8.3)或 long_name(LFN 长名)。
* long_name 为 NULL 时仅按 8.3 匹配(向后兼容)。
* 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) {
* 注意:需先调用 fat32_read_sectors(0,256,g_disk) 确保 BPB 缓冲可用。
* LFN 缓冲跨簇遍历持续存活,支持跨簇边界的 LFN 链。 */
static int fat32_find_in_dir(u32 start_clus, const char *name11, int is_dir,
u32 *out_clus, u32 *out_size, const char *long_name) {
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;
/* LFN 缓冲必须在簇循环外声明:跨簇 LFN 链需要持续存活 */
fat32_lfn_buf lfn;
fat32_lfn_init(&lfn);
u32 clus = start_clus;
while(clus>=2 && clus<0x0FFFFFF8) {
u32 lba = data_lba + (clus-2)*spc;
@@ -249,18 +260,40 @@ static int fat32_find_in_dir(u32 start_clus, const char *name11, int is_dir, u32
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;
const u8 *entries = (const u8 *)cb;
u32 entry_count = (spc*512)/32;
for(u32 e=0; e<entry_count; e++) {
const u8 *entry = entries + e*32;
if(entry[0]==0) break;
if((u8)entry[0]==0xE5) { fat32_lfn_init(&lfn); continue; }
const fat32_de *de = (const fat32_de *)entry;
int is_short = fat32_lfn_process(&lfn, entry);
if(!is_short) continue; /* LFN 片段 */
if(de->attr&0x08) { fat32_lfn_init(&lfn); continue; } /* 卷标 */
int entry_is_dir = (de->attr&0x10)?1:0;
if(entry_is_dir!=is_dir) { fat32_lfn_init(&lfn); continue; }
/* 匹配检查:先 8.3 短名,再 LFN 长名 */
int matched = 0;
if(name11 && neq11(de->name, name11)) {
matched = 1;
} else if(long_name) {
if(lfn.valid) {
char ascii[FAT32_LFN_MAX];
int n = fat32_lfn_to_ascii(&lfn, ascii, sizeof(ascii));
if(n>=0 && fat32_lfn_streq_ci(ascii, long_name)) matched = 1;
}
if(!matched) {
char short_disp[13];
fat32_lfn_short_to_str((const u8 *)de->name, short_disp);
if(fat32_lfn_streq_ci(short_disp, long_name)) matched = 1;
}
}
if(matched) {
*out_clus = r16((const u8*)&de->clow)|((u32)r16((const u8*)&de->chigh)<<16);
*out_size = de->fsize;
return 0;
}
fat32_lfn_init(&lfn);
}
/* BUG-019: 使用按需 FAT 读取 */
clus = fat32_get_next_cluster(fat_byte_off, clus, bpb->rsvd);
@@ -268,7 +301,7 @@ static int fat32_find_in_dir(u32 start_clus, const char *name11, int is_dir, u32
return -4;
}
/* 按 '/' 分隔的 8.3 路径读取文件(如 "SYSTEM /DESHAB64 /FUCK ")。
/* 按 '/' 分隔的路径读取文件。支持 8.3 路径与长名路径两种格式。
* 需先调用 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);
@@ -285,15 +318,22 @@ static int fat32_read_path(const char *path, u8 **out_data, u32 *out_size) {
while(pos<path_len) {
char comp[12]; u32 ci=0;
while(pos<path_len&&path[pos]!='/'&&ci<11) comp[ci++]=path[pos++];
char orig[260]; u32 oi=0;
while(pos<path_len&&path[pos]!='/') {
if(ci<11) comp[ci++]=path[pos];
if(oi+1<sizeof(orig)) orig[oi++]=path[pos];
pos++;
}
while(ci<11) comp[ci++]=' ';
comp[11]=0;
orig[oi]=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(fat32_find_in_dir(cur_clus,comp,0,&found_clus,&found_size,
(oi>0 && oi!=11)?orig:0)!=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) {
@@ -317,7 +357,8 @@ static int fat32_read_path(const char *path, u8 **out_data, u32 *out_size) {
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; }
if(fat32_find_in_dir(cur_clus,comp,1,&sub_clus,&sub_size,
(oi>0 && oi!=11)?orig:0)!=0) { logl("[DSK] fat32_read_path: dir not found in path: "); swrite(path); swrite("\n"); return -7; }
cur_clus=sub_clus;
}
}
@@ -325,7 +366,7 @@ static int fat32_read_path(const char *path, u8 **out_data, u32 *out_size) {
return -8;
}
/* Navigate a '/'-separated 8.3 path to find a directory cluster.
/* Navigate a '/'-separated path (8.3 or LFN) 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) {
@@ -336,12 +377,19 @@ static u32 fat32_find_dir_cluster(const char *path) {
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++];
char orig[260]; u32 oi = 0;
while (pos < path_len && path[pos] != '/') {
if (ci < 11) comp[ci++] = path[pos];
if (oi + 1 < sizeof(orig)) orig[oi++] = path[pos];
pos++;
}
while (ci < 11) comp[ci++] = ' ';
comp[11] = 0;
orig[oi] = 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;
if (fat32_find_in_dir(cur_clus, comp, 1, &sub_clus, &sub_size,
(oi > 0 && oi != 11) ? orig : 0) != 0) return 0;
cur_clus = sub_clus;
}
return cur_clus;
@@ -1233,6 +1281,28 @@ static void dsk_persist_userconf(const dsk_boot_context *ctx) {
ctx_mut->reserved[1] = 0;
}
/* 调度 netman.elf:先初始化租约缓冲并经 reserved[7] 暴露给 netman/后续工具。
* 每次启动(含 is_first=0)都应调用,保证联网配置在进桌面前就绪。 */
static void dsk_schedule_netman(const dsk_boot_context *ctx, int load_netman) {
dsk_boot_context *ctx_mut = (dsk_boot_context *)ctx;
g_net_lease.magic = NET_LEASE_MAGIC;
g_net_lease.flags = 0;
g_net_lease.ip = 0; g_net_lease.gateway = 0;
g_net_lease.dns = 0; g_net_lease.server = 0;
g_net_lease.reserved[0] = 0; g_net_lease.reserved[1] = 0;
ctx_mut->reserved[7] = (u64)&g_net_lease;
if (!load_netman) {
logl("[DSK] netman skipped by FUCK config");
return;
}
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");
}
/* 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. */
@@ -1298,6 +1368,10 @@ static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
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;
/* [compat] 段: DSK 侧只读不写,仅记录 PE DLL 搜索开关(实际加载在 UTSM 侧) */
int pe_dll_search = dsk_cfg_ok ? dsk_ini_get_bool(&dsk_cfg, "compat", "pe_dll_search", 1) : 1;
if (pe_dll_search) logl("[DSK] compat: PE DLL search enabled (UTSM side)");
else logl("[DSK] compat: PE DLL search disabled");
milestone_write(3, "FUCK config loaded");
/* Gradient background + centered Logo.png (5 seconds) */
@@ -1356,6 +1430,9 @@ static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
/* 开发者模式:加载 shell.elf 自动测试命令序列(cp/mv/echo/ls/cat/rm) */
if (dev_mode) {
logl("[DSK:SCHED] decision: dev_mode -> shell.elf");
/* dev_mode 同样需要网络就绪:先调度 netman(DHCP/静态 + ARP/DNS 自验),
* 租约写入 g_net_lease 供 shell 内 ping/curl/browser 经 reserved[7] 取用。 */
dsk_schedule_netman(ctx, load_netman);
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;
@@ -1367,7 +1444,11 @@ static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
}
if (!is_first) {
logl("[DSK:SCHED] decision: is_first=0 -> login then desktop");
logl("[DSK:SCHED] decision: is_first=0 -> netman -> login then desktop");
/* netman.elf — 每次启动都调度,进桌面前获取 IP(可通过 FUCK netman=0 跳过) */
dsk_schedule_netman(ctx, load_netman);
milestone_write(7, "netman loaded");
/* login — 可通过 skip_login=1 跳过 */
if (skip_login) {
@@ -1453,16 +1534,7 @@ static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
}
/* 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");
}
dsk_schedule_netman(ctx, load_netman);
milestone_write(7, "netman loaded");
/* FirstInit.elf — user setup wizard; returns to DSK when done */