2026-07-02 15:40:39 +08:00
/* DSK Main Kernel — boot entry, FAT32 firstInit check, ELF loader */
#include "../UTSM/include/utsm/dsk.h"
2026-10-01 23:13:42 +08:00
#include "../UTSM/include/utsm/linux_compat.h"
2026-07-02 15:40:39 +08:00
#include "port.h"
2026-08-09 22:14:01 +08:00
#include "../tools/fat32_lfn.h"
2026-10-01 23:13:42 +08:00
#include "../tools/fat32_part.h"
2026-10-02 23:49:05 +08:00
#include "ext4.h"
2026-07-31 13:53:49 +08:00
2026-10-01 23:13:42 +08:00
/* Embedded dcplogo.png / xjlogo.png RGBA data (auto-generated by
2026-10-02 23:49:05 +08:00
* png_to_rgba_prefixed.py from TEXTURES directory; must stay file-local like
* other embedded art) */
2026-10-01 23:13:42 +08:00
#include "dcp_logo_data.c"
#include "xj_logo_data.c"
2026-07-31 13:53:49 +08:00
/* Embedded ASCII bitmap font (Consolas 18px grayscale, 11x18 cell) */
#include "../firstInit/ascii_bitmaps.c"
2026-10-02 23:49:05 +08:00
/* Embedded ohMyLogo.png RGBA data(莲花 panic 界面用,与 login.elf 同源) */
#include "../login/ohmylogo_data.c"
2026-07-02 15:40:39 +08:00
#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 );
2026-07-26 21:07:36 +08:00
typedef int ( * block_write_fn )( u32 index , u64 lba , u32 count , const void * buf );
2026-07-02 15:40:39 +08:00
2026-07-31 13:53:49 +08:00
/* 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 {
2026-10-12 23:57:19 +08:00
void * pad0 ;
u32 ( * device_count )( void );
2026-07-31 13:53:49 +08:00
block_read_fn read ;
block_write_fn write ;
2026-08-29 18:47:54 +08:00
void * pad2 ; void * pad3 ; void * pad4 ; /* sector_size, device_name, set_write_fn */
u64 ( * sector_count )( u32 index ); /* 0x38: tail-append, 老内核该槽为 NULL */
2026-07-31 13:53:49 +08:00
} 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)" );
2026-08-29 18:47:54 +08:00
_Static_assert ( offsetof ( dsk_block_api_mirror , sector_count ) == 0x38 ,
"dsk_block_api_mirror.sector_count offset must be 0x38 (matching dkm_block_api tail-append)" );
2026-07-31 13:53:49 +08:00
2026-07-02 15:40:39 +08:00
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 " ); }
2026-07-31 13:53:49 +08:00
/* ---- 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)
2026-07-02 15:40:39 +08:00
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 ; }
2026-07-31 13:53:49 +08:00
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 ;
2026-10-01 23:13:42 +08:00
static u32 g_fat_lba_off = 0 ;
2026-07-31 13:53:49 +08:00
static u64 g_tsc_per_ms = 0 ;
static u8 g_disk [ 131072 ];
2026-10-01 23:13:42 +08:00
static u8 g_cluster [ FAT32_MAX_CLUSTER_BYTES ];
2026-08-09 22:14:01 +08:00
static u8 g_fdata [ 10485760 ]; /* 10MB file data buffer (与 UTSM 端一致, 支持 SYSTEM/lib 大型 DLL) */
2026-07-31 13:53:49 +08:00
/* BUG-019 修复: FAT 按需扇区读取缓冲区(仅 512 字节) */
static u8 g_fat_sec [ 512 ];
2026-10-01 23:13:42 +08:00
static u8 g_milestone_buf [ FAT32_MAX_CLUSTER_BYTES ]; /* milestone write cluster buffer */
2026-08-09 22:14:01 +08:00
/* 网络租约缓冲:DSK 常驻持有,调度 netman 前经 reserved[7] 暴露指针,
* netman 写入 DHCP/静态配置,后续模块(shell/desktop/工具)经同一指针读取。 */
static net_lease_info g_net_lease ;
2026-07-31 13:53:49 +08:00
DSK_STAT_DECL ( fat32_read );
DSK_STAT_DECL ( fat32_write );
DSK_STAT_DECL ( elf_load );
DSK_STAT_DECL ( mod_schedule );
2026-10-12 23:57:19 +08:00
static u32 g_fat_dev ;
2026-10-01 23:13:42 +08:00
static int fat32_read_sectors ( u32 lba , u32 count , u8 * out ) {
DSK_STAT_INC ( fat32_read );
2026-10-12 23:57:19 +08:00
return g_block_read ? g_block_read ( g_fat_dev , ( u64 ) lba + g_fat_lba_off , count , out ) : - 1 ;
2026-10-01 23:13:42 +08:00
}
static int fat32_write_sectors ( u32 lba , u32 count , const u8 * buf ) {
DSK_STAT_INC ( fat32_write );
2026-10-12 23:57:19 +08:00
return g_block_write ? g_block_write ( g_fat_dev , ( u64 ) lba + g_fat_lba_off , count , buf ) : - 1 ;
2026-10-01 23:13:42 +08:00
}
static void fat32_probe_esp ( void ) {
2026-10-12 23:57:19 +08:00
g_fat_lba_off = ( u32 ) fat32_part_probe ( g_block_read , g_fat_dev );
2026-10-01 23:13:42 +08:00
logh ( "[DSK] FAT32 volume LBA=" , ( u64 ) g_fat_lba_off );
}
2026-07-31 13:53:49 +08:00
/* 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 子目录遍历 ---- */
2026-08-09 22:14:01 +08:00
/* 在指定起始 cluster 的目录中查找 name11( 8.3)或 long_name( LFN 长名)。
* long_name 为 NULL 时仅按 8.3 匹配(向后兼容)。
2026-07-31 13:53:49 +08:00
* is_dir=1 只匹配子目录,is_dir=0 只匹配文件。
2026-08-09 22:14:01 +08:00
* 注意:需先调用 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 ) {
2026-07-31 13:53:49 +08:00
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 ;
2026-10-01 23:13:42 +08:00
if ( spc == 0 || ( u64 ) spc * 512u > sizeof ( g_cluster )) return - 2 ;
2026-07-31 13:53:49 +08:00
2026-08-09 22:14:01 +08:00
/* LFN 缓冲必须在簇循环外声明:跨簇 LFN 链需要持续存活 */
fat32_lfn_buf lfn ;
fat32_lfn_init ( & lfn );
2026-07-31 13:53:49 +08:00
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 {
2026-10-01 23:13:42 +08:00
if ( fat32_read_sectors ( lba , spc , g_cluster ) != 0 ) return - 3 ;
2026-07-31 13:53:49 +08:00
cb = g_cluster ;
}
2026-08-09 22:14:01 +08:00
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 );
2026-07-31 13:53:49 +08:00
}
/* BUG-019: 使用按需 FAT 读取 */
clus = fat32_get_next_cluster ( fat_byte_off , clus , bpb -> rsvd );
}
return - 4 ;
}
2026-08-09 22:14:01 +08:00
/* 按 '/' 分隔的路径读取文件。支持 8.3 路径与长名路径两种格式。
2026-07-31 13:53:49 +08:00
* 需先调用 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 ;
2026-08-09 22:14:01 +08:00
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 ++ ;
}
2026-07-31 13:53:49 +08:00
while ( ci < 11 ) comp [ ci ++ ] = ' ' ;
comp [ 11 ] = 0 ;
2026-08-09 22:14:01 +08:00
orig [ oi ] = 0 ;
2026-07-31 13:53:49 +08:00
if ( pos < path_len && path [ pos ] == '/' ) pos ++ ;
int is_last = ( pos >= path_len );
if ( is_last ) {
u32 found_clus = 0 , found_size = 0 ;
2026-08-09 22:14:01 +08:00
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 ; }
2026-07-31 13:53:49 +08:00
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 {
2026-10-01 23:13:42 +08:00
if ( fat32_read_sectors ( fc_lba , spc , g_cluster ) != 0 ) { logh ( "[DSK] fat32_read_path: data cluster read failed lba=" , ( u64 ) fc_lba ); return - 6 ; }
2026-07-31 13:53:49 +08:00
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 ;
2026-08-09 22:14:01 +08:00
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 ; }
2026-07-31 13:53:49 +08:00
cur_clus = sub_clus ;
}
}
DSK_TS_END ( fat32_path_read , "fat32_read_path (failed)" );
return - 8 ;
}
2026-08-09 22:14:01 +08:00
/* Navigate a '/'-separated path (8.3 or LFN) to find a directory cluster.
2026-07-31 13:53:49 +08:00
* 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 ;
2026-08-09 22:14:01 +08:00
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 ++ ;
}
2026-07-31 13:53:49 +08:00
while ( ci < 11 ) comp [ ci ++ ] = ' ' ;
comp [ 11 ] = 0 ;
2026-08-09 22:14:01 +08:00
orig [ oi ] = 0 ;
2026-07-31 13:53:49 +08:00
if ( pos < path_len && path [ pos ] == '/' ) pos ++ ;
u32 sub_clus = 0 , sub_size = 0 ;
2026-08-09 22:14:01 +08:00
if ( fat32_find_in_dir ( cur_clus , comp , 1 , & sub_clus , & sub_size ,
( oi > 0 && oi != 11 ) ? orig : 0 ) != 0 ) return 0 ;
2026-07-31 13:53:49 +08:00
cur_clus = sub_clus ;
}
return cur_clus ;
}
2026-07-02 15:40:39 +08:00
#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
2026-07-26 21:07:36 +08:00
/* ---- 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 );
}
2026-07-02 15:40:39 +08:00
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 )));
}
2026-10-01 23:13:42 +08:00
static void dsk_fill_rect ( u32 * fb , i64 x , i64 y , i64 w , i64 h , u32 color ) {
for ( i64 r = 0 ; r < 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 ( i64 c = 0 ; c < w ; c ++ ) {
i64 xx = x + c ;
if ( xx < 0 || ( u64 ) xx >= g_fb_w ) continue ;
line [( u64 ) xx ] = color ;
}
}
}
2026-07-02 15:40:39 +08:00
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 ;
}
}
}
2026-07-31 13:53:49 +08:00
/* ---- 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
*/
2026-10-01 23:13:42 +08:00
static void dsk_draw_rgba ( u32 * fb , const u8 * pix , int w , int h ) {
/* Center the image on screen */
i64 ox = (( i64 ) g_fb_w - w ) / 2 ;
i64 oy = (( i64 ) g_fb_h - h ) / 2 ;
2026-07-31 13:53:49 +08:00
2026-10-01 23:13:42 +08:00
for ( int ly = 0 ; ly < h ; ly ++ ) {
2026-07-31 13:53:49 +08:00
i64 fy = oy + ly ;
if ( fy < 0 || ( u64 ) fy >= g_fb_h ) continue ;
u32 * line = ( u32 * )(( u8 * ) fb + ( u64 ) fy * g_fb_p );
2026-10-01 23:13:42 +08:00
for ( int lx = 0 ; lx < w ; lx ++ ) {
2026-07-31 13:53:49 +08:00
i64 fx = ox + lx ;
if ( fx < 0 || ( u64 ) fx >= g_fb_w ) continue ;
/* Read RGBA pixel from embedded data */
2026-10-01 23:13:42 +08:00
int idx = ( ly * w + lx ) * 4 ;
u8 r = pix [ idx + 0 ];
u8 g = pix [ idx + 1 ];
u8 b = pix [ idx + 2 ];
u8 a = pix [ idx + 3 ];
2026-07-31 13:53:49 +08:00
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 ;
}
2026-07-26 21:07:36 +08:00
}
}
}
2026-10-01 23:13:42 +08:00
/* Splash sequence entry: one image + hold for the given milliseconds.
* Redraws the gradient background first so successive images replace
* each other cleanly. */
static void dsk_splash ( u32 * fb , const u8 * pix , int w , int h , u64 hold_ms ,
const char * name ) {
dsk_fill_gradient_rect ( fb , 0 , 0 , ( i64 ) g_fb_w , ( i64 ) g_fb_h );
dsk_draw_rgba ( fb , pix , w , h );
logl ( "[DSK] splash: showing" );
logl ( name );
u64 start = rdtsc_dsk ();
u64 budget = g_tsc_per_ms * hold_ms ;
while ( rdtsc_dsk () - start < budget ) __asm__ ( "pause" );
}
2026-07-31 13:53:49 +08:00
/* ---- 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 ;
}
2026-07-26 21:07:36 +08:00
}
}
}
2026-10-01 23:13:42 +08:00
static void dsk_draw_char_scaled ( u32 * fb , char ch , i64 x , i64 y , u32 fg , int scale ) {
u32 idx = ( u32 )( ch - ' ' );
int r , c , sy , sx ;
if ( idx > 94 ) idx = 0 ;
if ( scale < 1 ) scale = 1 ;
const u8 * glyph = g_ascii [ idx ];
for ( r = 0 ; r < g_ascii_h ; r ++ ) {
for ( c = 0 ; c < g_ascii_w ; c ++ ) {
u8 a = glyph [ r * g_ascii_w + c ];
if ( a == 0 ) continue ;
for ( sy = 0 ; sy < scale ; sy ++ ) {
i64 yy = y + ( i64 ) r * scale + sy ;
u32 * line ;
if ( yy < 0 || ( u64 ) yy >= g_fb_h ) continue ;
line = ( u32 * )(( u8 * ) fb + ( u64 ) yy * g_fb_p );
for ( sx = 0 ; sx < scale ; sx ++ ) {
i64 xx = x + ( i64 ) c * scale + sx ;
if ( xx < 0 || ( u64 ) xx >= g_fb_w ) continue ;
line [( u64 ) xx ] = fg ;
}
}
}
}
}
2026-07-31 13:53:49 +08:00
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 ++ ;
2026-07-26 21:07:36 +08:00
}
}
2026-10-02 23:49:05 +08:00
/* ===================================================================
* 严格错误策略插桩:FS/调度层任何错误(含未实现路径)不再降级、
* 不再静默跳过,必须整屏 fatal 显示错误码后停机。
* 错误码体系:FS-E<nn>(文件系统层)。
* =================================================================== */
/* 莲花 panic 界面:深蓝底 + ohMyLogo 莲花居中 + 错误码 + 停机落款。
* 与 login.elf / UTSM F1 panic 同一视觉体系。 */
static void dsk_fatal_lotus ( u32 * fb , const char * sym ) {
/* 深蓝底 */
for ( u64 y = 0 ; y < g_fb_h ; y ++ ) {
u32 * line = ( u32 * )(( u8 * ) fb + y * g_fb_p );
for ( u64 x = 0 ; x < g_fb_w ; x ++ ) line [ x ] = 0xFF020F22u ;
}
2026-10-12 23:57:19 +08:00
/* 莲花按步进缩小,错误码折行钉在屏内(长串不再被左右裁掉) */
i64 spacing = g_ascii_w ;
i64 text_need = ( g_ascii_h + 6 ) * 4 ;
i64 step = 1 ;
while ( step < 8 &&
( i64 ) g_panic_logo_h / step + text_need + 24 > ( i64 ) g_fb_h )
step ++ ;
i64 dw = ( i64 ) g_panic_logo_w / step ;
i64 dh = ( i64 ) g_panic_logo_h / step ;
i64 lx2 = (( i64 ) g_fb_w - dw ) / 2 ;
i64 ly2 = (( i64 ) g_fb_h - dh - text_need ) / 2 ;
if ( ly2 < 4 ) ly2 = 4 ;
for ( i64 r = 0 ; r < dh ; r ++ ) {
for ( i64 c = 0 ; c < dw ; c ++ ) {
2026-10-02 23:49:05 +08:00
const unsigned char * px4 =
2026-10-12 23:57:19 +08:00
g_panic_logo_rgba + ((( u64 ) r * ( u64 ) step ) * ( u64 ) g_panic_logo_w
+ ( u64 ) c * ( u64 ) step ) * 4 ;
2026-10-02 23:49:05 +08:00
u32 a = px4 [ 3 ];
if ( a < 8 ) continue ;
u32 col = 0xFF000000u | (( u32 ) px4 [ 0 ] << 16 ) | (( u32 ) px4 [ 1 ] << 8 ) | px4 [ 2 ];
if ( a < 250 ) {
u32 bg = 0xFF020F22u ;
u32 na = 256 - a ;
u32 rr = ((( bg >> 16 ) & 0xFF ) * na + (( col >> 16 ) & 0xFF ) * a ) >> 8 ;
u32 gg = ((( bg >> 8 ) & 0xFF ) * na + (( col >> 8 ) & 0xFF ) * a ) >> 8 ;
u32 bb = (( bg & 0xFF ) * na + ( col & 0xFF ) * a ) >> 8 ;
col = 0xFF000000u | ( rr << 16 ) | ( gg << 8 ) | bb ;
}
2026-10-12 23:57:19 +08:00
i64 xx = lx2 + c , yy = ly2 + r ;
2026-10-02 23:49:05 +08:00
if ( xx < 0 || ( u64 ) xx >= g_fb_w || yy < 0 || ( u64 ) yy >= g_fb_h ) continue ;
* ( u32 * )(( u8 * ) fb + ( u64 ) yy * g_fb_p + ( u64 ) xx * 4 ) = col ;
}
}
2026-10-12 23:57:19 +08:00
i64 ty = ly2 + dh + 12 ;
i64 y_limit = ( i64 ) g_fb_h - 4 ;
if ( ty + text_need > y_limit ) ty = y_limit - text_need ;
if ( ty < 4 ) ty = 4 ;
i64 cols = ( i64 ) g_fb_w / spacing - 2 ;
if ( cols < 8 ) cols = 8 ;
if ( cols > 120 ) cols = 120 ;
{
const char * s = sym ? sym : "" ;
while ( * s && ty + g_ascii_h <= y_limit ) {
char line [ 121 ];
i64 n = 0 ;
while ( s [ n ] && n < cols ) { line [ n ] = s [ n ]; n ++ ; }
line [ n ] = 0 ;
s += n ;
dsk_draw_string ( fb , line , (( i64 ) g_fb_w - n * spacing ) / 2 , ty ,
0xFFF2D8D8u , ( int ) spacing );
ty += g_ascii_h + 6 ;
}
}
if ( ty + g_ascii_h <= y_limit ) {
dsk_draw_string ( fb , "DESHAB FS FATAL - SYSTEM HALTED" ,
(( i64 ) g_fb_w - 31 * spacing ) / 2 , ty ,
0xFFB08890u , ( int ) spacing );
}
2026-10-02 23:49:05 +08:00
}
2026-10-12 23:57:19 +08:00
/* DSK_BOOT_FLAG_PANIC_FALLBACK( FUCK [panic] mode=fallback):dsk_fatal 只留
* 串口坐标后返回,调用点紧跟备用路径;未置位 = strict,整屏莲花后停机。 */
static int g_panic_fallback ;
2026-10-02 23:49:05 +08:00
static void dsk_fatal ( const char * sym ) {
logl ( sym );
2026-10-12 23:57:19 +08:00
if ( g_panic_fallback ) {
logl ( "[DSK:FALLBACK] fatal point hit, taking backup path" );
return ;
}
2026-10-02 23:49:05 +08:00
if ( g_fb_addr ) {
dsk_fatal_lotus (( u32 * )( u64 ) g_fb_addr , sym );
}
for (;;) __asm__ ( "cli; hlt" );
}
2026-07-02 15:40:39 +08:00
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 )) {
2026-07-28 14:35:14 +08:00
* out_clus = r16 (( const u8 * ) & dir [ e ]. clow ) | (( u32 ) r16 (( const u8 * ) & dir [ e ]. chigh ) << 16 );
2026-07-02 15:40:39 +08:00
* 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 ;
2026-07-31 13:53:49 +08:00
DSK_TS_DECL ( fat32_root_read );
DSK_TS_BEGIN ( fat32_root_read );
2026-07-02 15:40:39 +08:00
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 );
2026-07-31 13:53:49 +08:00
if ( st != 0 ) { logl ( "[DSK] fat32_read_root_file: BPB read failed" ); return - 1 ; }
2026-07-02 15:40:39 +08:00
const fat32_bpb * bpb = ( const fat32_bpb * ) disk ;
2026-07-31 13:53:49 +08:00
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 ; }
2026-07-02 15:40:39 +08:00
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 );
2026-10-01 23:13:42 +08:00
logh ( "[DSK] fat32 spc=" , ( u64 ) spc );
if ( spc == 0 || ( u64 ) spc * 512u > sizeof ( g_cluster )) {
logl ( "[DSK] fat32 cluster larger than g_cluster" );
return - 3 ;
}
2026-07-02 15:40:39 +08:00
/* 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 {
2026-10-01 23:13:42 +08:00
if ( fat32_read_sectors ( lba , spc , g_cluster ) != 0 ) { logh ( "[DSK] fat32_read_root_file: dir cluster read failed lba=" , ( u64 ) lba ); return - 4 ; }
2026-07-02 15:40:39 +08:00
cb = g_cluster ;
}
if ( fat32_find_entry ( cb , spc , name11 , & found_clus , & found_size ) == 0 ) { found = 1 ; break ; }
2026-07-31 13:53:49 +08:00
/* BUG-019: 使用按需 FAT 读取 */
clus = fat32_get_next_cluster ( fat_byte_off , clus , bpb -> rsvd );
2026-07-02 15:40:39 +08:00
}
2026-07-31 13:53:49 +08:00
if ( ! found ) { logl ( "[DSK] fat32 entry not found: " ); swrite ( name11 ); swrite ( " \n " ); return - 5 ; }
2026-07-02 15:40:39 +08:00
logh ( "[DSK] fat32 found_clus=" , found_clus );
logh ( "[DSK] fat32 found_size=" , found_size );
2026-07-31 13:53:49 +08:00
if ( found_size > sizeof ( g_fdata )) { logh ( "[DSK] fat32_read_root_file: file too large size=" , ( u64 ) found_size ); return - 6 ; }
2026-07-02 15:40:39 +08:00
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 {
2026-10-01 23:13:42 +08:00
if ( fat32_read_sectors ( fc_lba , spc , g_cluster ) != 0 ) { logh ( "[DSK] fat32_read_root_file: data cluster read failed lba=" , ( u64 ) fc_lba ); return - 7 ; }
2026-07-02 15:40:39 +08:00
fb = g_cluster ;
}
for ( u32 b = 0 ; b < fc_bytes ; b ++ ) dst [ b ] = fb [ b ];
dst += fc_bytes ; remaining -= fc_bytes ;
2026-07-31 13:53:49 +08:00
/* BUG-019: 使用按需 FAT 读取 */
fc = fat32_get_next_cluster ( fat_byte_off , fc , bpb -> rsvd );
2026-07-02 15:40:39 +08:00
}
* out_data = g_fdata ; * out_size = found_size ;
2026-07-31 13:53:49 +08:00
DSK_TS_END ( fat32_root_read , "fat32_read_root_file" );
2026-07-02 15:40:39 +08:00
logl ( "[DSK] fat32 file read done" );
return 0 ;
}
2026-07-26 21:07:36 +08:00
/* 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. */
2026-10-02 23:49:05 +08:00
/* BUG-20261002 修复: 按需 FAT 表项读写(支持 FAT 超出 g_disk 256 扇区的大容量 ESP)。
* 缓冲内直接改写(随后由步骤 6 回写),缓冲外读单扇区到 g_fat_sec 改写后立即落盘。 */
static u32 fat32_fat_read_entry ( u32 fat_byte_off , u32 c ) {
u32 fo = fat_byte_off + c * 4 ;
if ( fo + 4 <= sizeof ( g_disk )) return r32 ( g_disk + fo ) & 0x0FFFFFFF ;
u32 sec = fo / 512 , off = fo % 512 ;
if ( fat32_read_sectors ( sec , 1 , g_fat_sec ) != 0 ) return 0x0FFFFFF7 ; /* 读失败视作坏簇 */
return r32 ( g_fat_sec + off ) & 0x0FFFFFFF ;
}
static int fat32_fat_write_entry ( u32 fat_byte_off , u32 c , u32 val ) {
u32 fo = fat_byte_off + c * 4 ;
if ( fo + 4 <= sizeof ( g_disk )) {
g_disk [ fo ] = ( u8 )( val & 0xFF );
g_disk [ fo + 1 ] = ( u8 )(( val >> 8 ) & 0xFF );
g_disk [ fo + 2 ] = ( u8 )(( val >> 16 ) & 0xFF );
g_disk [ fo + 3 ] = ( u8 )(( g_disk [ fo + 3 ] & 0xF0 ) | (( val >> 24 ) & 0x0F ));
return fat32_write_sectors ( fo / 512 , 1 , g_disk + ( u64 )( fo / 512 ) * 512 );
}
u32 sec = fo / 512 , off = fo % 512 ;
if ( fat32_read_sectors ( sec , 1 , g_fat_sec ) != 0 ) return - 1 ;
g_fat_sec [ off ] = ( u8 )( val & 0xFF );
g_fat_sec [ off + 1 ] = ( u8 )(( val >> 8 ) & 0xFF );
g_fat_sec [ off + 2 ] = ( u8 )(( val >> 16 ) & 0xFF );
g_fat_sec [ off + 3 ] = ( u8 )(( g_fat_sec [ off + 3 ] & 0xF0 ) | (( val >> 24 ) & 0x0F ));
return fat32_write_sectors ( sec , 1 , g_fat_sec );
}
/* 块状空闲簇扫描:每次读 8 扇区(1024 表项),fat_byte_off 必须扇区对齐。
* chunk k 覆盖表项 [k*1024, (k+1)*1024)。 */
static u8 g_fatscan [ 4096 ];
static u32 fat32_find_free_cluster ( u32 fat_byte_off , u32 max_c ) {
for ( u32 k = 0 ; k * 1024 < max_c ; k ++ ) {
u32 base = k * 1024 ;
if ( fat32_read_sectors ( fat_byte_off / 512 + k * 8 , 8 , g_fatscan ) != 0 )
continue ;
u32 n = max_c - base ; if ( n > 1024 ) n = 1024 ;
for ( u32 i = 0 ; i < n ; i ++ ) {
u32 c = base + i ;
if ( c < 2 ) continue ;
if (( r32 ( g_fatscan + i * 4 ) & 0x0FFFFFFF ) == 0 ) return c ;
}
}
return 0 ;
}
2026-07-26 21:07:36 +08:00
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 ;
2026-07-31 13:53:49 +08:00
/* 2. Find file entry in root directory — scan ALL clusters in FAT chain */
u32 cur_clus = root_clus ;
2026-07-26 21:07:36 +08:00
int free_entry = - 1 ;
2026-07-31 13:53:49 +08:00
u32 free_clus = 0 ; /* cluster number where free entry was found */
2026-07-26 21:07:36 +08:00
u32 existing_clus = 0 ;
int found = 0 ;
2026-07-31 13:53:49 +08:00
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 ;
2026-07-26 21:07:36 +08:00
}
2026-07-31 13:53:49 +08:00
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 ;
2026-07-26 21:07:36 +08:00
}
/* 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 ;
2026-10-02 23:49:05 +08:00
cur = fat32_fat_read_entry ( fat_byte_off , cur );
2026-07-26 21:07:36 +08:00
count ++ ;
}
/* If we need more clusters, allocate them */
while ( count < clusters_needed ) {
2026-10-02 23:49:05 +08:00
u32 newc = fat32_find_free_cluster ( fat_byte_off , ( fat_sectors * 512 ) / 4 );
2026-07-26 21:07:36 +08:00
if ( newc == 0 ) { logl ( "[DSK] fat32 write: no free clusters" ); return - 3 ; }
2026-10-02 23:49:05 +08:00
logh ( "[DSK] fat32 write: alloc clus=" , newc );
/* Mark newly allocated cluster as EOC immediately to prevent re-allocation */
if ( fat32_fat_write_entry ( fat_byte_off , newc , 0x0FFFFFF8 ) != 0 ) return - 7 ;
2026-07-26 21:07:36 +08:00
/* Link previous cluster to new */
2026-10-02 23:49:05 +08:00
if ( prev_clus >= 2 ) {
if ( fat32_fat_write_entry ( fat_byte_off , prev_clus , newc ) != 0 ) return - 7 ;
2026-07-26 21:07:36 +08:00
}
prev_clus = newc ;
count ++ ;
}
2026-10-02 23:49:05 +08:00
/* Terminate the chain, saving original next pointer before overwriting with EOC */
2026-07-26 21:07:36 +08:00
if ( prev_clus >= 2 ) {
2026-10-02 23:49:05 +08:00
u32 original_next = fat32_fat_read_entry ( fat_byte_off , prev_clus );
fat32_fat_write_entry ( fat_byte_off , prev_clus , 0x0FFFFFF8 );
2026-07-31 13:53:49 +08:00
/* Free excess clusters from the old chain using saved pointer */
u32 next = original_next ;
while ( next >= 2 && next < 0x0FFFFFF8 ) {
2026-10-02 23:49:05 +08:00
u32 nn = fat32_fat_read_entry ( fat_byte_off , next );
fat32_fat_write_entry ( fat_byte_off , next , 0 );
2026-07-31 13:53:49 +08:00
next = nn ;
2026-07-26 21:07:36 +08:00
}
}
} else {
/* Allocate new clusters */
2026-10-05 18:32:24 +08:00
if ( free_entry < 0 ) {
/* 根目录链里没有空位 —— 按 FAT32 规范扩展目录链:分配一个新簇,
* 挂到根目录链尾,在新簇的第一个条目里放目录项。(原来这里直接
* return -4,导致 ESP 根目录一簇写满后 USER.CONF 永远写不进去。) */
u32 tail = root_clus ;
if ( tail < 2 ) { logl ( "[DSK] fat32 write: bad root cluster" ); return - 4 ; }
for (;;) {
u32 nxt = fat32_fat_read_entry ( fat_byte_off , tail );
if ( nxt >= 2 && nxt < 0x0FFFFFF8 ) { tail = nxt ; continue ; }
break ;
}
u32 newdir = fat32_find_free_cluster ( fat_byte_off , ( fat_sectors * 512 ) / 4 );
if ( newdir == 0 ) { logl ( "[DSK] fat32 write: no free cluster for dir growth" ); return - 3 ; }
if ( fat32_fat_write_entry ( fat_byte_off , newdir , 0x0FFFFFF8 ) != 0 ) return - 7 ;
if ( fat32_fat_write_entry ( fat_byte_off , tail , newdir ) != 0 ) return - 7 ;
logh ( "[DSK] fat32 write: root dir grown, new clus=" , newdir );
/* 新簇整簇清零(0x00 = 目录结束标记),再把目录项写在首项 */
u8 * nb = g_cluster ;
for ( u32 b = 0 ; b < cluster_bytes ; b ++ ) nb [ b ] = 0 ;
fat32_de * nd = ( fat32_de * ) nb ;
for ( int i = 0 ; i < 11 ; i ++ ) nd [ 0 ]. name [ i ] = name11 [ i ];
nd [ 0 ]. attr = 0x20 ;
nd [ 0 ]. ntr = 0 ; nd [ 0 ]. ctenth = 0 ; nd [ 0 ]. ctime = 0 ; nd [ 0 ]. cdate = 0 ;
nd [ 0 ]. adate = 0 ; nd [ 0 ]. wtime = 0 ; nd [ 0 ]. wdate = 0 ;
/* 数据簇先分配好,再填进目录项(与下方 !found 分支同序) */
u32 dfirst = 0 , dprev = 0 ;
for ( u32 i = 0 ; i < clusters_needed ; i ++ ) {
u32 newc = fat32_find_free_cluster ( fat_byte_off , ( fat_sectors * 512 ) / 4 );
if ( newc == 0 ) { logl ( "[DSK] fat32 write: no free clusters" ); return - 3 ; }
logh ( "[DSK] fat32 write: alloc clus=" , newc );
if ( fat32_fat_write_entry ( fat_byte_off , newc , 0x0FFFFFF8 ) != 0 ) return - 7 ;
if ( i == 0 ) dfirst = newc ;
if ( dprev >= 2 ) {
if ( fat32_fat_write_entry ( fat_byte_off , dprev , newc ) != 0 ) return - 7 ;
}
dprev = newc ;
}
nd [ 0 ]. chigh = ( u16 )(( dfirst >> 16 ) & 0xFFFF );
nd [ 0 ]. clow = ( u16 )( dfirst & 0xFFFF );
nd [ 0 ]. fsize = size ;
u32 nlba = data_lba + ( newdir - 2 ) * spc ;
if ( fat32_write_sectors ( nlba , spc , nb ) != 0 ) {
logl ( "[DSK] fat32 write: new dir cluster write failed" );
return - 8 ;
}
/* 写数据簇 */
u32 rem2 = size ;
const u8 * s2 = data ;
u32 c2 = dfirst ;
u32 ci2 = 0 ;
while ( c2 >= 2 && c2 < 0x0FFFFFF8 && ci2 < clusters_needed ) {
u32 clba2 = data_lba + ( c2 - 2 ) * spc ;
u32 chunk2 = rem2 < cluster_bytes ? rem2 : cluster_bytes ;
if ( fat32_read_sectors ( clba2 , spc , g_cluster ) != 0 ) return - 5 ;
for ( u32 b = 0 ; b < chunk2 ; b ++ ) g_cluster [ b ] = s2 [ b ];
for ( u32 b = chunk2 ; b < cluster_bytes ; b ++ ) g_cluster [ b ] = 0 ;
if ( fat32_write_sectors ( clba2 , spc , g_cluster ) != 0 ) return - 6 ;
s2 += chunk2 ; rem2 -= chunk2 ; ci2 ++ ;
c2 = fat32_fat_read_entry ( fat_byte_off , c2 );
}
/* FAT 表写回(与下方第 6 步同逻辑:只写 g_disk 缓冲覆盖得到的那些 FAT 副本) */
{
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 ;
}
}
}
return 0 ; /* 已自行完成写入,跳过下方通用路径 */
}
2026-07-26 21:07:36 +08:00
for ( u32 i = 0 ; i < clusters_needed ; i ++ ) {
2026-10-02 23:49:05 +08:00
u32 newc = fat32_find_free_cluster ( fat_byte_off , ( fat_sectors * 512 ) / 4 );
2026-07-26 21:07:36 +08:00
if ( newc == 0 ) { logl ( "[DSK] fat32 write: no free clusters" ); return - 3 ; }
2026-10-02 23:49:05 +08:00
logh ( "[DSK] fat32 write: alloc clus=" , newc );
/* Mark newly allocated cluster as EOC immediately to prevent re-allocation */
if ( fat32_fat_write_entry ( fat_byte_off , newc , 0x0FFFFFF8 ) != 0 ) return - 7 ;
2026-07-26 21:07:36 +08:00
if ( i == 0 ) first_clus = newc ;
if ( prev_clus >= 2 ) {
2026-10-02 23:49:05 +08:00
if ( fat32_fat_write_entry ( fat_byte_off , prev_clus , newc ) != 0 ) return - 7 ;
2026-07-26 21:07:36 +08:00
}
prev_clus = newc ;
}
}
/* 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 ++ ;
2026-10-02 23:49:05 +08:00
cur = fat32_fat_read_entry ( fat_byte_off , cur );
2026-07-26 21:07:36 +08:00
}
/* 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 );
2026-07-28 14:35:14 +08:00
e -> fsize = size ;
2026-07-26 21:07:36 +08:00
} else {
2026-07-28 14:35:14 +08:00
/* 文件已存在:只更新匹配到的条目(不触碰 free_entry!) */
2026-07-26 21:07:36 +08:00
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 */
2026-07-31 13:53:49 +08:00
/* 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 ;
}
}
2026-07-26 21:07:36 +08:00
}
2026-07-31 13:53:49 +08:00
/* 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 ;
}
}
2026-07-26 21:07:36 +08:00
}
/* 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 ;
}
2026-07-31 13:53:49 +08:00
/* 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)" );
}
}
2026-07-26 21:07:36 +08:00
static int dsk_check_firstinit ( int * is_first , int * dev_mode ) {
2026-07-31 13:53:49 +08:00
DSK_TS_DECL ( firstinit_check );
DSK_TS_BEGIN ( firstinit_check );
2026-07-02 15:40:39 +08:00
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 ;
2026-07-26 21:07:36 +08:00
* dev_mode = 0 ;
2026-07-02 15:40:39 +08:00
logl ( "[DSK] fat32_read_path start" );
int rc = fat32_read_root_file ( name , & data , & size );
2026-10-01 23:13:42 +08:00
if ( rc != 0 ) {
logl ( "[DSK] firstInit.txt not in FAT32 root, trying system/user/use" );
if ( fat32_read_sectors ( 0 , 256 , g_disk ) == 0 ) {
rc = fat32_read_path ( "system/user/use/firstInit.txt" , & data , & size );
if ( rc != 0 )
rc = fat32_read_path ( "user/use/firstInit.txt" , & data , & size );
}
}
2026-07-02 15:40:39 +08:00
logh ( "[DSK] fat32_read_path rc=" , ( u64 )( i64 ) rc );
2026-07-31 13:53:49 +08:00
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 ; }
2026-07-26 21:07:36 +08:00
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)" );
}
}
2026-07-31 13:53:49 +08:00
DSK_TS_END ( firstinit_check , "dsk_check_firstinit" );
2026-07-26 21:07:36 +08:00
return 0 ;
2026-07-02 15:40:39 +08:00
}
static int dsk_load_elf ( u8 * data , u32 size , void ** entry_out ) {
2026-07-31 13:53:49 +08:00
DSK_TS_DECL ( elf_load );
DSK_TS_BEGIN ( elf_load );
DSK_STAT_INC ( elf_load );
2026-07-02 15:40:39 +08:00
const elf64_ehdr * eh = ( const elf64_ehdr * ) data ;
2026-07-31 13:53:49 +08:00
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 ;
}
2026-07-02 15:40:39 +08:00
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 ;
2026-07-31 13:53:49 +08:00
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 ;
}
2026-07-02 15:40:39 +08:00
if ( ph -> vaddr < min_vaddr ) min_vaddr = ph -> vaddr ;
if ( ph -> vaddr + ph -> memsz > max_vaddr ) max_vaddr = ph -> vaddr + ph -> memsz ;
lc ++ ;
}
2026-07-31 13:53:49 +08:00
if ( ! lc || min_vaddr == ~ 0ULL ) { logl ( "[DSK] ELF: no PT_LOAD segments" ); return - 7 ; }
2026-07-02 15:40:39 +08:00
u64 isize = max_vaddr - min_vaddr ;
isize = ( isize + 0xFFF ) & ~ 0xFFFULL ;
2026-07-31 13:53:49 +08:00
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 */
2026-07-02 15:40:39 +08:00
u8 * image = ibuf ;
2026-07-31 13:53:49 +08:00
if ( isize > 8388608 ) { logl ( "[DSK] ELF: image too large for 8MB ibuf" ); logh ( "[DSK] ELF isize=" , isize ); return - 8 ; }
2026-07-02 15:40:39 +08:00
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 ;
2026-07-31 13:53:49 +08:00
logh ( "[DSK] PT_LOAD vaddr=" , ph -> vaddr );
logh ( "[DSK] PT_LOAD filesz=" , ph -> filesz );
logh ( "[DSK] PT_LOAD memsz=" , ph -> memsz );
/* off + filesz 不会越界,已在上面的循环中验证 */
2026-07-02 15:40:39 +08:00
memcpy_dsk ( image + off , data + ph -> offset , ph -> filesz );
}
2026-07-31 13:53:49 +08:00
/* 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 ;
}
2026-07-02 15:40:39 +08:00
* 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 ;
2026-07-31 13:53:49 +08:00
/* 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 ;
}
2026-07-02 15:40:39 +08:00
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 ) {
2026-07-31 13:53:49 +08:00
/* P0 修复: 边界检查 rela_off 和 rela_off+rela_sz 必须在 [min_vaddr, min_vaddr+isize) 内 */
if ( rela_off < min_vaddr || rela_off >= min_vaddr + isize ) {
2026-10-03 00:30:54 +08:00
/* 严格错误策略:重定位表越界 = 镜像损坏,零降级 panic */
2026-07-31 13:53:49 +08:00
logh ( "[DSK] ELF: rela_off=" , rela_off );
logh ( "[DSK] ELF: min_vaddr=" , min_vaddr );
logh ( "[DSK] ELF: isize=" , isize );
2026-10-03 00:30:54 +08:00
dsk_fatal ( "ELF-E01 RELA OUT OF BOUNDS" );
2026-10-12 23:57:19 +08:00
return - 1 ; /* fallback:拒绝加载未重定位的镜像 */
2026-07-31 13:53:49 +08:00
}
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 ;
}
2026-07-02 15:40:39 +08:00
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 ) {
2026-07-31 13:53:49 +08:00
/* P0 修复: 验证 rel->offset 在映像范围内,防止无符号下溢 */
if ( rel -> offset < min_vaddr || rel -> offset >= min_vaddr + isize ) continue ;
2026-07-02 15:40:39 +08:00
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 );
2026-07-31 13:53:49 +08:00
DSK_TS_END ( elf_load , "dsk_load_elf" );
2026-07-02 15:40:39 +08:00
return 0 ;
}
2026-07-26 21:07:36 +08:00
/* 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. */
2026-10-02 23:49:05 +08:00
/* 按名字加载模块 ELF:先根目录,后 SYSTEM/DESHAB64/ 与 SYSTEM/USER/USE/ 回退。 */
static int dsk_load_module ( const char name11 [ 12 ], u8 ** data , u32 * size ) {
if ( fat32_read_root_file ( name11 , data , size ) == 0 ) return 0 ;
static const char * pfxs [] = { "SYSTEM /DESHAB64 /" , "SYSTEM /USER /USE /" };
for ( int pi = 0 ; pi < 2 ; pi ++ ) {
char path [ 40 ];
int i = 0 , j ;
const char * pfx = pfxs [ pi ];
while ( pfx [ i ]) { path [ i ] = pfx [ i ]; i ++ ; }
for ( j = 0 ; j < 11 ; j ++ ) path [ i ++ ] = name11 [ j ];
path [ i ] = 0 ;
logl ( "[DSK] load_and_run: trying fallback path" );
if ( fat32_read_sectors ( 0 , 256 , g_disk ) == 0 &&
fat32_read_path ( path , data , size ) == 0 ) return 0 ;
}
logl ( "[DSK] load_and_run: fat32 read failed for " );
swrite ( name11 ); swrite ( " \n " );
return - 1 ;
}
2026-07-26 21:07:36 +08:00
static int dsk_load_and_run ( const char name11 [ 12 ], const dsk_boot_context * ctx ) {
2026-07-31 13:53:49 +08:00
DSK_TS_DECL ( mod_run );
DSK_TS_BEGIN ( mod_run );
DSK_STAT_INC ( mod_schedule );
2026-07-26 21:07:36 +08:00
u8 * data = 0 ; u32 size = 0 ; void * entry = 0 ;
2026-07-31 13:53:49 +08:00
logl ( "[DSK] load_and_run: " );
swrite ( name11 ); swrite ( " \n " );
2026-10-02 23:49:05 +08:00
if ( dsk_load_module ( name11 , & data , & size ) != 0 ) return - 1 ;
2026-07-31 13:53:49 +08:00
if ( dsk_load_elf ( data , size , & entry ) != 0 ) { logl ( "[DSK] load_and_run: elf load failed for " ); swrite ( name11 ); swrite ( " \n " ); return - 2 ; }
2026-10-01 23:13:42 +08:00
logl ( "[DSK] jumping to module" );
2026-07-26 21:07:36 +08:00
void ( * fn )( const dsk_boot_context * ) = ( void ( * )( const dsk_boot_context * )) entry ;
fn ( ctx );
2026-07-31 13:53:49 +08:00
DSK_TS_END ( mod_run , "dsk_load_and_run" );
2026-07-26 21:07:36 +08:00
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" );
}
2026-10-01 23:13:42 +08:00
#define DSK_SESSION_NATIVE 0
#define DSK_SESSION_KDE 1
#define DSK_SESSION_ASK (-1)
static int dsk_poll_scancode ( void ) {
u8 st = inb ( 0x64 );
if ( ! ( st & 1 )) return - 1 ;
if ( st & 0x20 ) { ( void ) inb ( 0x60 ); return - 1 ; }
return ( int ) inb ( 0x60 );
}
static int dsk_poll_serial ( void ) {
if ( ! ( inb ( COM1 + 5 ) & 1 )) return - 1 ;
return ( int ) inb ( COM1 );
}
static int dsk_session_from_cfg ( const dsk_ini_config * cfg , int cfg_ok ) {
const char * s = cfg_ok ? dsk_ini_get ( cfg , "dsk" , "session" ) : 0 ;
if ( s && dsk_ini_streq ( s , "kde" )) return DSK_SESSION_KDE ;
if ( s && dsk_ini_streq ( s , "ask" )) return DSK_SESSION_ASK ;
return DSK_SESSION_NATIVE ;
}
static int dsk_fuck_from_modules ( const dsk_boot_context * ctx , u8 ** out , u32 * out_size ) {
typedef struct {
u64 revision ;
void * address ;
u64 size ;
char * path ;
char * cmdline ;
} dsk_limine_file ;
typedef struct {
u64 revision ;
u64 module_count ;
dsk_limine_file ** modules ;
} dsk_limine_mods ;
const dsk_limine_mods * rsp = ( const dsk_limine_mods * ) ctx -> boot_modules_response ;
if ( ! rsp || ! rsp -> modules ) return - 1 ;
const char * tag = "fuck:config" ;
for ( u64 i = 0 ; i < rsp -> module_count ; i ++ ) {
dsk_limine_file * f = rsp -> modules [ i ];
if ( ! f || ! f -> cmdline || ! f -> address || f -> size == 0 ) continue ;
const char * c = f -> cmdline ;
int match = 1 ;
for ( int j = 0 ; tag [ j ]; j ++ ) {
if ( c [ j ] != tag [ j ]) { match = 0 ; break ; }
}
if ( ! match || c [ 11 ] != 0 ) continue ;
if ( f -> size > sizeof ( g_fdata )) return - 2 ;
memcpy_dsk ( g_fdata , f -> address , ( u64 ) f -> size );
* out = g_fdata ;
* out_size = ( u32 ) f -> size ;
return 0 ;
}
return - 1 ;
}
/* argv_blob is only 96 bytes. Keep guest commands tiny. */
static int dsk_sh_status ( const linux_compat_service * lxc , const char * cmd ) {
const char * argv [ 4 ];
u64 ec = 1 ;
if ( ! lxc || ! lxc -> exec || ! cmd ) return - 1 ;
argv [ 0 ] = "sh" ;
argv [ 1 ] = "-c" ;
argv [ 2 ] = cmd ;
argv [ 3 ] = 0 ;
int rc = lxc -> exec ( "/bin/sh" , 3 , argv , 0 , 0 , 0 , & ec );
if ( rc != 0 ) return rc ;
return ( int ) ec ;
}
static void dsk_blit_scanout ( u32 * fb , const struct linux_compat_scanout_info * si ) {
u32 sw , sh , stride , copy_w , row ;
i64 ox , oy ;
const u8 * src ;
if ( ! fb || ! si || ! si -> enabled || ! si -> host_vaddr ) return ;
sw = si -> width ;
sh = si -> height ;
stride = si -> stride ;
if ( ! sw || ! sh || stride < sw * 4 ) return ;
ox = (( i64 ) g_fb_w - ( i64 ) sw ) / 2 ;
oy = (( i64 ) g_fb_h - ( i64 ) sh ) / 2 ;
if ( ox < 0 ) ox = 0 ;
if ( oy < 0 ) oy = 0 ;
src = ( const u8 * ) si -> host_vaddr ;
for ( row = 0 ; row < sh ; row ++ ) {
if (( u64 )( oy + ( i64 ) row ) >= g_fb_h ) break ;
copy_w = sw ;
if (( u64 ) ox + copy_w > g_fb_w ) copy_w = ( u32 )( g_fb_w - ( u64 ) ox );
memcpy_dsk (( u8 * ) fb + ( u64 )( oy + ( i64 ) row ) * g_fb_p + ( u64 ) ox * 4 ,
src + ( u64 ) row * stride ,
( u64 ) copy_w * 4 );
}
}
static int dsk_kde_host_loop ( u32 * fb , const linux_compat_service * lxc ) {
int scanout_ok = 0 ;
u64 start , budget ;
logl ( "[DSK] KDE host loop" );
dsk_fill_gradient_rect ( fb , 0 , 0 , ( i64 ) g_fb_w , ( i64 ) g_fb_h );
dsk_draw_string ( fb , "Starting KDE ..." , 32 , 32 , 0xFFFFFFFFu , g_ascii_w + 1 );
start = rdtsc_dsk ();
budget = g_tsc_per_ms ? g_tsc_per_ms * 90000ULL : 0 ;
( void ) dsk_sh_status ( lxc , "rm -f /tmp/deshab-native /tmp/deshab-native-app" );
{
int native_chk = 0 ;
for (;;) {
struct linux_compat_scanout_info si ;
int sc = dsk_poll_scancode ();
if ( sc == 0x01 || sc == 0x02 ) {
logl ( "[DSK] KDE host loop aborted" );
return - 1 ;
}
if ( lxc -> run_slice ) {
int sl ;
for ( sl = 0 ; sl < 4 ; sl ++ )
( void ) lxc -> run_slice ();
} else {
( void ) dsk_sh_status ( lxc , ":" );
}
native_chk ++ ;
if (( native_chk & 31 ) == 0 &&
dsk_sh_status ( lxc , "test -f /tmp/deshab-native" ) == 0 ) {
logl ( "[DSK] KDE host loop: native switch" );
return 0 ;
}
if ( lxc -> gpu_get_scanout_info &&
lxc -> gpu_get_scanout_info ( & si ) == 0 &&
si . enabled && si . host_vaddr ) {
if ( ! scanout_ok ) {
logh ( "[DSK] KDE scanout w=" , si . width );
logh ( "[DSK] KDE scanout h=" , si . height );
scanout_ok = 1 ;
}
dsk_blit_scanout ( fb , & si );
} else if ( ! scanout_ok && budget && rdtsc_dsk () - start > budget ) {
logl ( "[DSK] KDE scanout timeout" );
return - 1 ;
}
__asm__ ( "pause" );
}
}
}
static int dsk_try_kde ( const dsk_boot_context * ctx , u32 * fb ) {
const linux_compat_service * lxc =
( const linux_compat_service * ) ctx -> reserved [ 5 ];
int dri , persist , script ;
const char * path ;
const char * argv [ 2 ];
int rc ;
if ( ! lxc || lxc -> magic != LINUX_COMPAT_MAGIC ||
! lxc -> is_available || ! lxc -> exec_async ) {
logl ( "[DSK] KDE: linux_compat unavailable" );
return - 1 ;
}
if ( ! lxc -> is_available ()) {
logl ( "[DSK] KDE: Linux guest not parked" );
return - 1 ;
}
dri = dsk_sh_status ( lxc , "test -e /dev/dri/card0" );
persist = dsk_sh_status ( lxc , "test -d /mnt/persist/usr" );
script = dsk_sh_status ( lxc , "test -x /usr/local/bin/deshab-kde-session" );
logh ( "[DSK] KDE preflight dri=" , ( u64 )( i64 ) dri );
logh ( "[DSK] KDE preflight persist=" , ( u64 )( i64 ) persist );
logh ( "[DSK] KDE preflight script=" , ( u64 )( i64 ) script );
if ( dri != 0 || script != 0 ) {
logl ( "[DSK] KDE preflight missing dri/script" );
return - 1 ;
}
path = "/usr/local/bin/deshab-kde-session" ;
argv [ 0 ] = path ;
argv [ 1 ] = 0 ;
rc = lxc -> exec_async ( path , 1 , argv );
logh ( "[DSK] KDE exec_async rc=" , ( u64 )( i64 ) rc );
if ( rc != 0 ) return rc ;
logl ( "[DSK] KDE spawned" );
return dsk_kde_host_loop ( fb , lxc );
}
static void dsk_chooser_paint ( u32 * fb , int left ) {
i64 cw = 620 , ch = 300 ;
i64 cx = (( i64 ) g_fb_w - cw ) / 2 ;
i64 cy = (( i64 ) g_fb_h - ch ) / 2 ;
int spacing = g_ascii_w + 1 ;
u32 fg = 0xFFFFFFFFu ;
u32 dim = 0xFF8A96A0u ;
u32 hot = 0xFFFFD24Au ;
i64 tx ;
int n ;
char big ;
if ( left < 1 ) left = 1 ;
if ( left > 8 ) left = 8 ;
dsk_fill_gradient_rect ( fb , 0 , 0 , ( i64 ) g_fb_w , ( i64 ) g_fb_h );
dsk_fill_rect ( fb , cx , cy , cw , ch , 0xFF2B3A4A );
dsk_fill_rect ( fb , cx + 4 , cy + 4 , cw - 8 , ch - 8 , 0xFF1A2733 );
dsk_draw_string ( fb , "Choose desktop" , cx + 32 , cy + 24 , fg , spacing );
dsk_draw_string ( fb , "1 Native Deshab" , cx + 32 , cy + 64 , fg , spacing );
dsk_draw_string ( fb , "2 Guest KDE / Wayland" , cx + 32 , cy + 92 , fg , spacing );
big = ( char )( '0' + left );
dsk_draw_char_scaled ( fb , big , cx + cw - 32 - g_ascii_w * 3 , cy + 28 , hot , 3 );
tx = cx + 48 ;
for ( n = 8 ; n >= 1 ; n -- ) {
char d = ( char )( '0' + n );
u32 col = ( n == left ) ? hot : ( n > left ? 0xFF3A4550u : dim );
dsk_draw_char_scaled ( fb , d , tx , cy + 140 , col , ( n == left ) ? 2 : 1 );
tx += ( n == left ) ? ( g_ascii_w * 2 + 16 ) : ( g_ascii_w + 14 );
}
dsk_draw_string ( fb , "timeout -> native" , cx + 32 , cy + 240 , dim , spacing );
}
static int dsk_chooser_read_key ( void ) {
int sc = dsk_poll_scancode ();
int ch ;
if ( sc >= 0 && sc < 0x80 ) {
if ( sc == 0x02 || sc == 0x4F ) return DSK_SESSION_NATIVE ;
if ( sc == 0x03 || sc == 0x50 ) return DSK_SESSION_KDE ;
}
ch = dsk_poll_serial ();
if ( ch == '1' ) {
logl ( "[DSK] session from serial=1" );
return DSK_SESSION_NATIVE ;
}
if ( ch == '2' ) {
logl ( "[DSK] session from serial=2" );
return DSK_SESSION_KDE ;
}
return 0 ;
}
static int dsk_session_chooser ( u32 * fb ) {
int left = 8 ;
int last_left = - 1 ;
dsk_chooser_paint ( fb , left );
if ( ! g_tsc_per_ms ) {
u64 spin ;
logl ( "[DSK] chooser: no TSC, spinning 8s" );
for ( left = 8 ; left >= 1 ; left -- ) {
if ( left != last_left ) {
dsk_chooser_paint ( fb , left );
last_left = left ;
logh ( "[DSK] chooser left=" , ( u64 ) left );
}
for ( spin = 0 ; spin < 40000000ULL ; spin ++ ) {
int choice = dsk_chooser_read_key ();
if ( choice ) return choice ;
__asm__ ( "pause" );
}
}
logl ( "[DSK] session chooser timed out -> native" );
return DSK_SESSION_NATIVE ;
}
{
u64 start = rdtsc_dsk ();
u64 one_s = g_tsc_per_ms * 1000ULL ;
u64 budget = one_s * 8ULL ;
while ( rdtsc_dsk () - start < budget ) {
u64 elapsed = rdtsc_dsk () - start ;
int now = 8 - ( int )( elapsed / one_s );
int choice ;
if ( now < 1 ) now = 1 ;
if ( now != last_left ) {
last_left = now ;
dsk_chooser_paint ( fb , now );
logh ( "[DSK] chooser left=" , ( u64 ) now );
}
choice = dsk_chooser_read_key ();
if ( choice ) return choice ;
__asm__ ( "pause" );
}
}
logl ( "[DSK] session chooser timed out -> native" );
return DSK_SESSION_NATIVE ;
}
static void dsk_choose_and_run_session ( const dsk_boot_context * ctx , u32 * fb ,
const dsk_ini_config * cfg , int cfg_ok ) {
int choice = dsk_session_from_cfg ( cfg , cfg_ok );
if ( choice == DSK_SESSION_ASK ) {
logl ( "[DSK] session=ask, waiting for 1/2" );
choice = dsk_session_chooser ( fb );
}
if ( choice == DSK_SESSION_KDE ) {
logl ( "[DSK] session=kde" );
if ( dsk_try_kde ( ctx , fb ) != 0 ) {
logl ( "[DSK] KDE failed, falling back to native desktop" );
dsk_fill_gradient_rect ( fb , 0 , 0 , ( i64 ) g_fb_w , ( i64 ) g_fb_h );
dsk_draw_string ( fb , "KDE failed, starting native desktop" ,
32 , 32 , 0xFFFFD24Au , g_ascii_w + 1 );
if ( g_tsc_per_ms ) {
u64 t0 = rdtsc_dsk ();
while ( rdtsc_dsk () - t0 < g_tsc_per_ms * 1500ULL )
__asm__ ( "pause" );
}
} else {
logl ( "[DSK] KDE session ended" );
}
} else {
logl ( "[DSK] session=native" );
}
dsk_run_desktop ( ctx );
}
2026-07-26 21:07:36 +08:00
/* 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 ) {
2026-10-02 23:49:05 +08:00
/* 严格错误策略:FirstInit 返回却没留下配置缓冲 = 向导失败,零降级 */
dsk_fatal ( "FS-E05 FIRSTINIT NO CONF BUFFER" );
2026-07-26 21:07:36 +08:00
return ;
}
if ( ! g_block_write ) {
2026-10-02 23:49:05 +08:00
/* 严格错误策略:块层无写通道 = FS 不可写,零降级 */
dsk_fatal ( "FS-E01 NO BLOCK WRITE PROVIDER" );
2026-07-26 21:07:36 +08:00
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 );
2026-10-12 23:57:19 +08:00
if ( wrc != 0 ) {
dsk_fatal ( "FS-E02 USER.CONF WRITE FAILED" );
/* fallback:不翻 firstInit.txt,下次启动重跑向导 */
return ;
}
2026-10-02 23:49:05 +08:00
/* 1b. Write-verify: 回读 USER.CONF 逐字节比对,确保 FAT32 写路径真的落盘 */
{
u8 * vdata = 0 ; u32 vsize = 0 ;
2026-10-12 23:57:19 +08:00
if ( fat32_read_root_file ( cn , & vdata , & vsize ) != 0 ) {
2026-10-02 23:49:05 +08:00
dsk_fatal ( "FS-E04 USER.CONF VERIFY READ FAILED" );
2026-10-12 23:57:19 +08:00
return ;
}
if ( vsize != ( u32 ) conf_sz ) {
2026-10-02 23:49:05 +08:00
dsk_fatal ( "FS-E04 USER.CONF VERIFY SIZE MISMATCH" );
2026-10-12 23:57:19 +08:00
return ;
}
2026-10-02 23:49:05 +08:00
for ( u32 i = 0 ; i < ( u32 ) conf_sz ; i ++ ) {
2026-10-12 23:57:19 +08:00
if ( vdata [ i ] != conf [ i ]) {
dsk_fatal ( "FS-E04 USER.CONF VERIFY DATA MISMATCH" );
return ;
}
2026-10-02 23:49:05 +08:00
}
logl ( "[DSK] USER.CONF verify ok" );
}
2026-07-26 21:07:36 +08:00
/* 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 );
2026-10-02 23:49:05 +08:00
if ( frc != 0 ) dsk_fatal ( "FS-E03 FIRSTINIT.TXT WRITE FAILED" );
2026-07-26 21:07:36 +08:00
/* Clear reserved so login path doesn't see stale pointer */
ctx_mut -> reserved [ 0 ] = 0 ;
ctx_mut -> reserved [ 1 ] = 0 ;
}
2026-08-09 22:14:01 +08:00
/* 调度 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" );
}
2026-10-02 23:49:05 +08:00
/* 调度 login.elf:读取 USER.CONF 传给 login,成功置 reserved[2]=1。
* 返回 1 = 登录成功;0 = 失败(调用方决定是否 fatal)。
* 首次启动(向导后强制重登)与常规启动共用此路径。 */
static int dsk_run_login ( const dsk_boot_context * ctx ) {
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 ( dsk_load_module ( 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" );
}
} else {
logl ( "[DSK] login.elf load failed" );
}
} else {
logl ( "[DSK] login.elf not found" );
}
DSK_TS_END ( login_phase , "login phase" );
return login_ok ;
}
2026-07-26 21:07:36 +08:00
/* Draw the spinning loader (comet-tail arc) on the gradient background,
2026-07-31 13:53:49 +08:00
* then run the firstInit check and dispatch system component loading.
* FUCK config controls: show_logo, skip_login, mouse_init, netman, dev_mode. */
2026-07-26 21:07:36 +08:00
static void dsk_spinner_and_check ( const void * boot_ctx_ptr ) {
2026-07-02 15:40:39 +08:00
const dsk_boot_context * ctx = ( const dsk_boot_context * ) boot_ctx_ptr ;
2026-10-12 23:57:19 +08:00
u32 ( * block_dev_count )( void ) = 0 ;
2026-07-31 13:53:49 +08:00
{ 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 ;
2026-10-12 23:57:19 +08:00
block_dev_count = blk ? blk -> device_count : 0 ;
2026-07-31 13:53:49 +08:00
logh ( "[DSK] block_read fn=" , ( u64 ) g_block_read );
2026-10-01 23:13:42 +08:00
logh ( "[DSK] block_write fn=" , ( u64 ) g_block_write );
2026-10-12 23:57:19 +08:00
}
2026-07-02 15:40:39 +08:00
g_fb_addr = ctx -> framebuffer_address ; g_fb_w = ctx -> framebuffer_width ;
g_fb_h = ctx -> framebuffer_height ; g_fb_p = ctx -> framebuffer_pitch ;
2026-07-31 13:53:49 +08:00
if ( ! g_fb_addr ) { logl ( "[DSK] FATAL: framebuffer address is NULL" ); for (;;) __asm__ ( "hlt" ); }
2026-10-02 23:49:05 +08:00
2026-10-12 23:57:19 +08:00
/* 先选中卷标 DESHAB 的盘,FAT 与 ext4 共用该设备号。 */
if ( block_dev_count ) ext4_set_device_count ( block_dev_count ());
2026-10-02 23:49:05 +08:00
ext4_mount ( g_block_read , g_block_write , dsk_fatal , logl , logh );
2026-10-12 23:57:19 +08:00
g_fat_dev = ext4_device_index ();
fat32_probe_esp ();
milestone_write ( 2 , "block API ready" );
2026-10-02 23:49:05 +08:00
ext4_boot_selftest ();
2026-07-02 15:40:39 +08:00
u32 * sfb = ( u32 * )( u64 ) g_fb_addr ;
logh ( "[DSK] block_read ptr=" , ( u64 ) g_block_read );
2026-07-26 21:07:36 +08:00
tsc_calibrate_dsk ();
2026-07-31 13:53:49 +08:00
/* === 读取 FUCK 配置 === */
DSK_TS_DECL ( fuck_config );
DSK_TS_BEGIN ( fuck_config );
dsk_ini_config dsk_cfg ;
int dsk_cfg_ok = 0 ;
2026-10-01 23:13:42 +08:00
/* Prefer the Limine fuck:config module (SYSTEM/ on ext4 after GPT split).
* FAT32 on the SATA test disk is only a fallback. */
{
u8 * fuck_data = 0 ;
u32 fuck_size = 0 ;
int mrc = dsk_fuck_from_modules ( ctx , & fuck_data , & fuck_size );
logh ( "[DSK] FUCK boot-module rc=" , ( u64 )( i64 ) mrc );
if ( mrc == 0 && fuck_size > 0 &&
dsk_ini_parse (( const char * ) fuck_data , fuck_size , & dsk_cfg ) == 0 ) {
dsk_cfg_ok = 1 ;
logl ( "[DSK] FUCK config loaded from boot module" );
}
}
if ( ! dsk_cfg_ok && g_block_read ) {
2026-07-31 13:53:49 +08:00
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 ;
2026-10-01 23:29:49 +08:00
/* F5: skip_firstinit=1 → 跳过首次启动向导与登录,直达 desktop */
int skip_firstinit = dsk_cfg_ok ? dsk_ini_get_bool ( & dsk_cfg , "dsk" , "skip_firstinit" , 0 ) : 0 ;
2026-07-31 13:53:49 +08:00
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 ;
2026-08-09 22:14:01 +08:00
/* [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" );
2026-07-31 13:53:49 +08:00
milestone_write ( 3 , "FUCK config loaded" );
2026-10-02 23:49:05 +08:00
/* Gradient background + centered "DESHAB P01" text( Logo.png 图像已移除) */
2026-07-26 21:07:36 +08:00
dsk_fill_gradient_rect ( sfb , 0 , 0 , ( i64 ) g_fb_w , ( i64 ) g_fb_h );
2026-07-31 13:53:49 +08:00
if ( show_logo ) {
2026-10-02 23:49:05 +08:00
/* "DESHAB P01" 文字垂直居中(不再绘制 Logo 图像) */
2026-07-31 13:53:49 +08:00
{
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 ;
2026-10-02 23:49:05 +08:00
i64 text_x = ( i64 ) g_fb_w / 2 - text_w / 2 ;
i64 text_y = ( i64 ) g_fb_h / 2 - g_ascii_h / 2 ;
2026-07-31 13:53:49 +08:00
/* White text: BGRX = 0xFF_RR_GG_BB = 0xFF_FFFFFF */
u32 fg = 0xFFFFFFFFu ;
dsk_draw_string ( sfb , ver_str , text_x , text_y , fg , spacing );
}
2026-10-02 23:49:05 +08:00
/* Hold text for 5 seconds */
2026-07-31 13:53:49 +08:00
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" );
2026-10-02 23:49:05 +08:00
logl ( "[DSK] boot text 5s done, proceeding" );
2026-10-01 23:13:42 +08:00
/* Follow-up splash: dcplogo.png 3s, then OpenXJ380 xjlogo.png 3s */
dsk_splash ( sfb , g_dcp_logo_rgba , g_dcp_logo_w , g_dcp_logo_h ,
3000 , "[DSK] splash: dcplogo.png (3s)" );
dsk_splash ( sfb , g_xj_logo_rgba , g_xj_logo_w , g_xj_logo_h ,
3000 , "[DSK] splash: xjlogo.png (3s)" );
logl ( "[DSK] splash sequence done" );
2026-07-31 13:53:49 +08:00
} else {
logl ( "[DSK] logo skipped by FUCK config" );
2026-07-26 21:07:36 +08:00
}
if ( ! g_block_read ) {
logl ( "[DSK] no block device, halting" );
for (;;) __asm__ ( "hlt" );
}
logl ( "[DSK] checking firstInit..." );
2026-07-31 13:53:49 +08:00
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 ) {
2026-07-26 21:07:36 +08:00
logl ( "[DSK] firstInit check failed, halting" );
for (;;) __asm__ ( "hlt" );
}
2026-07-31 13:53:49 +08:00
DSK_TS_END ( firstinit_phase , "firstInit check phase" );
milestone_write ( 4 , "firstInit check done" );
2026-10-01 23:13:42 +08:00
/* session=ask|kde: packed SYSTEM/FUCK selected a desktop path.
* Do not trap on FirstInit or the SATA firstInit.txt dev_mode shell. */
{
int sess = dsk_session_from_cfg ( & dsk_cfg , dsk_cfg_ok );
if ( sess == DSK_SESSION_ASK || sess == DSK_SESSION_KDE ) {
if ( is_first || firstinit_dev_mode ) {
logl ( "[DSK] session chooser armed, skipping first-boot wizard/dev shell" );
}
is_first = 0 ;
firstinit_dev_mode = 0 ;
}
}
2026-07-31 13:53:49 +08:00
/* 合并 FUCK dev_mode 和 firstInit.txt dev_mode */
if ( firstinit_dev_mode ) dev_mode = 1 ;
2026-07-26 21:07:36 +08:00
2026-10-01 23:29:49 +08:00
/* F5: skip_firstinit=1 → 直达 desktop(跳过向导与登录)。
* 优先级最高:即便 firstInit.txt 为 0(首次)也视作已完成。 */
if ( skip_firstinit ) {
logl ( "[DSK] skip_firstinit=1: direct to desktop (wizard+login skipped)" );
is_first = 0 ;
firstinit_dev_mode = 0 ;
}
2026-07-26 21:07:36 +08:00
/* 开发者模式:加载 shell.elf 自动测试命令序列(cp/mv/echo/ls/cat/rm) */
if ( dev_mode ) {
2026-07-31 13:53:49 +08:00
logl ( "[DSK:SCHED] decision: dev_mode -> shell.elf" );
2026-08-09 22:14:01 +08:00
/* dev_mode 同样需要网络就绪:先调度 netman( DHCP/静态 + ARP/DNS 自验),
* 租约写入 g_net_lease 供 shell 内 ping/curl/browser 经 reserved[7] 取用。 */
dsk_schedule_netman ( ctx , load_netman );
2026-07-26 21:07:36 +08:00
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 ;
2026-07-31 13:53:49 +08:00
milestone_write ( 5 , "dev shell loaded" );
2026-07-26 21:07:36 +08:00
}
if ( ! is_first ) {
2026-08-09 22:14:01 +08:00
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" );
2026-07-31 13:53:49 +08:00
2026-10-01 23:29:49 +08:00
/* login — 可通过 skip_login=1 跳过;skip_firstinit=1 时一并跳过(F5) */
if ( skip_login || skip_firstinit ) {
2026-07-31 13:53:49 +08:00
logl ( "[DSK:SCHED] login skipped by FUCK config" );
} else {
2026-10-02 23:49:05 +08:00
dsk_run_login ( ctx );
2026-07-02 15:40:39 +08:00
}
2026-07-26 21:07:36 +08:00
2026-10-03 15:40:00 +08:00
/* default_shell=cmd → 直接进 CMD.ELF( PE/EXE 兼容层前端)。
* 严格错误策略:FUCK 明确要求 cmd 却加载失败 = 零降级 panic( DSK-E09)。 */
2026-07-31 13:53:49 +08:00
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" );
2026-10-03 15:40:00 +08:00
else dsk_fatal ( "DSK-E09 DEFAULT SHELL CMD.ELF MISSING" );
2026-07-31 13:53:49 +08:00
}
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" );
2026-10-01 23:13:42 +08:00
dsk_choose_and_run_session ( ctx , sfb , & dsk_cfg , dsk_cfg_ok );
2026-07-26 21:07:36 +08:00
return ;
}
/* First boot: run system initializers, then FirstInit, then desktop */
2026-07-31 13:53:49 +08:00
logl ( "[DSK:SCHED] decision: is_first=1 -> mouseInit -> netman -> FirstInit -> desktop" );
2026-07-26 21:07:36 +08:00
2026-07-31 13:53:49 +08:00
/* mouseInit.elf — 可通过 FUCK mouse_init=0 跳过 */
if ( load_mouse ) {
logl ( "[DSK:SCHED] scheduling mouseInit.elf" );
char mn [ 12 ]; /* MOUSE ELF */
2026-07-26 21:07:36 +08:00
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" );
2026-07-31 13:53:49 +08:00
} else {
logl ( "[DSK] mouseInit skipped by FUCK config" );
2026-07-26 21:07:36 +08:00
}
2026-07-31 13:53:49 +08:00
/* netman.elf — 可通过 FUCK netman=0 跳过 */
2026-08-09 22:14:01 +08:00
dsk_schedule_netman ( ctx , load_netman );
2026-07-31 13:53:49 +08:00
milestone_write ( 7 , "netman loaded" );
2026-07-26 21:07:36 +08:00
/* FirstInit.elf — user setup wizard; returns to DSK when done */
2026-07-31 13:53:49 +08:00
{ logl ( "[DSK:SCHED] scheduling FirstInit.elf" );
2026-10-01 23:13:42 +08:00
/* "FirstInit.elf" 9 字符长名 → FAT32 8.3 别名 FIRSTI~1.ELF
* ( mtools 打包时生成;mtools 量产命名,首个同名前缀稳定为 ~1) */
char en [ 12 ]; /* FIRSTI~1ELF */
en [ 0 ] = 'F' ; en [ 1 ] = 'I' ; en [ 2 ] = 'R' ; en [ 3 ] = 'S' ; en [ 4 ] = 'T' ; en [ 5 ] = 'I' ;
en [ 6 ] = '~' ; en [ 7 ] = '1' ; en [ 8 ] = 'E' ; en [ 9 ] = 'L' ; en [ 10 ] = 'F' ; en [ 11 ] = 0 ;
2026-07-26 21:07:36 +08:00
logl ( "[DSK] loading FirstInit" );
if ( dsk_load_and_run ( en , ctx ) != 0 ) {
2026-10-12 23:57:19 +08:00
/* 严格错误策略:首次启动却没有 FirstInit.elf = 未实现路径,零降级。
* fallback:跳过向导与登录,直接进桌面。 */
2026-10-02 23:49:05 +08:00
dsk_fatal ( "FS-E07 FIRSTINIT.ELF NOT FOUND" );
2026-10-12 23:57:19 +08:00
} else {
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 );
/* 向导完成后强制重新登录:进桌面前必须再走一次 login.elf。
* 零降级策略:登录被跳过/失败(如 Esc 跳过)不允许静默进桌面。 */
if ( skip_login ) {
logl ( "[DSK:SCHED] first-boot login skipped by FUCK config" );
} else if ( ! dsk_run_login ( ctx )) {
dsk_fatal ( "FS-E06 LOGIN REQUIRED AFTER FIRSTINIT" );
}
2026-10-02 23:49:05 +08:00
}
2026-07-26 21:07:36 +08:00
logl ( "[DSK] loading desktop" );
2026-07-31 13:53:49 +08:00
milestone_write ( 6 , "desktop loading" );
2026-10-01 23:13:42 +08:00
dsk_choose_and_run_session ( ctx , sfb , & dsk_cfg , dsk_cfg_ok );
2026-07-02 15:40:39 +08:00
}
}
__attribute__ (( noreturn , visibility ( "default" )))
void dsk_entry ( const dsk_boot_context * ctx ) {
2026-07-26 21:07:36 +08:00
__asm__ volatile ( "cli" ); /* disable IRQs — ps2kbd/IRQ1 & mouse/IRQ12 handlers crash during boot */
2026-07-02 15:40:39 +08:00
logl ( "[DSK] boot" );
if ( ! ctx || ctx -> magic != DSK_BOOT_MAGIC ){ logl ( "[DSK] bad context" ); for (;;) __asm__ ( "hlt" );}
logl ( "[DSK] context ok" );
2026-10-12 23:57:19 +08:00
g_panic_fallback = ( ctx -> flags & DSK_BOOT_FLAG_PANIC_FALLBACK ) ? 1 : 0 ;
if ( g_panic_fallback ) logl ( "[DSK] panic mode=fallback" );
2026-07-26 21:07:36 +08:00
dsk_spinner_and_check ( ctx );
2026-07-02 15:40:39 +08:00
logl ( "[DSK] SELFTEST PASS" );
for (;;) __asm__ ( "hlt" );
}