ohhhhhhhhhhh (exclude linux-extra-rootfs.img build artifact)
This commit is contained in:
+479
-28
@@ -1,12 +1,19 @@
|
||||
/* DSK Main Kernel — boot entry, FAT32 firstInit check, ELF loader */
|
||||
|
||||
#include "../UTSM/include/utsm/dsk.h"
|
||||
#include "../UTSM/include/utsm/linux_compat.h"
|
||||
#include "port.h"
|
||||
#include "../tools/fat32_lfn.h"
|
||||
#include "../tools/fat32_part.h"
|
||||
|
||||
/* Embedded Logo.png RGBA data (auto-generated by png_to_rgba.py) */
|
||||
#include "logo_data.c"
|
||||
|
||||
/* Embedded dcplogo.png / xjlogo.png RGBA data (auto-generated by
|
||||
* png_to_rgba_prefixed.py; must stay file-local like logo_data.c) */
|
||||
#include "dcp_logo_data.c"
|
||||
#include "xj_logo_data.c"
|
||||
|
||||
/* Embedded ASCII bitmap font (Consolas 18px grayscale, 11x18 cell) */
|
||||
#include "../firstInit/ascii_bitmaps.c"
|
||||
|
||||
@@ -106,13 +113,14 @@ static int neq11(const char *a, const char *b) { for(int i=0;i<11;i++) if(a[i]!=
|
||||
static u64 g_fb_addr, g_fb_w, g_fb_h, g_fb_p;
|
||||
static block_read_fn g_block_read;
|
||||
static block_write_fn g_block_write;
|
||||
static u32 g_fat_lba_off = 0;
|
||||
static u64 g_tsc_per_ms = 0;
|
||||
static u8 g_disk[131072];
|
||||
static u8 g_cluster[4096];
|
||||
static u8 g_cluster[FAT32_MAX_CLUSTER_BYTES];
|
||||
static u8 g_fdata[10485760]; /* 10MB file data buffer (与 UTSM 端一致, 支持 SYSTEM/lib 大型 DLL) */
|
||||
/* BUG-019 修复: FAT 按需扇区读取缓冲区(仅 512 字节) */
|
||||
static u8 g_fat_sec[512];
|
||||
static u8 g_milestone_buf[4096]; /* milestone write cluster buffer */
|
||||
static u8 g_milestone_buf[FAT32_MAX_CLUSTER_BYTES]; /* milestone write cluster buffer */
|
||||
/* 网络租约缓冲:DSK 常驻持有,调度 netman 前经 reserved[7] 暴露指针,
|
||||
* netman 写入 DHCP/静态配置,后续模块(shell/desktop/工具)经同一指针读取。 */
|
||||
static net_lease_info g_net_lease;
|
||||
@@ -122,8 +130,19 @@ DSK_STAT_DECL(fat32_write);
|
||||
DSK_STAT_DECL(elf_load);
|
||||
DSK_STAT_DECL(mod_schedule);
|
||||
|
||||
static int fat32_read_sectors(u32 lba, u32 count, u8 *out) { DSK_STAT_INC(fat32_read); return g_block_read ? g_block_read(0,lba,count,out) : -1; }
|
||||
static int fat32_write_sectors(u32 lba, u32 count, const u8 *buf) { DSK_STAT_INC(fat32_write); return g_block_write ? g_block_write(0,lba,count,buf) : -1; }
|
||||
static int fat32_read_sectors(u32 lba, u32 count, u8 *out) {
|
||||
DSK_STAT_INC(fat32_read);
|
||||
return g_block_read ? g_block_read(0, (u64)lba + g_fat_lba_off, count, out) : -1;
|
||||
}
|
||||
static int fat32_write_sectors(u32 lba, u32 count, const u8 *buf) {
|
||||
DSK_STAT_INC(fat32_write);
|
||||
return g_block_write ? g_block_write(0, (u64)lba + g_fat_lba_off, count, buf) : -1;
|
||||
}
|
||||
|
||||
static void fat32_probe_esp(void) {
|
||||
g_fat_lba_off = (u32)fat32_part_probe(g_block_read, 0);
|
||||
logh("[DSK] FAT32 volume LBA=", (u64)g_fat_lba_off);
|
||||
}
|
||||
|
||||
/* BUG-019 修复: 按需读取 FAT 扇区获取下一个簇号。
|
||||
* 如果 FAT 条目在预读缓冲区内直接读取;
|
||||
@@ -249,6 +268,7 @@ static int fat32_find_in_dir(u32 start_clus, const char *name11, int is_dir,
|
||||
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
|
||||
u32 fat_byte_off = bpb->rsvd * 512;
|
||||
u32 spc = bpb->spc;
|
||||
if (spc == 0 || (u64)spc * 512u > sizeof(g_cluster)) return -2;
|
||||
|
||||
/* LFN 缓冲必须在簇循环外声明:跨簇 LFN 链需要持续存活 */
|
||||
fat32_lfn_buf lfn;
|
||||
@@ -261,7 +281,7 @@ static int fat32_find_in_dir(u32 start_clus, const char *name11, int is_dir,
|
||||
if((u64)lba*512+(u64)spc*512<=256ULL*512)
|
||||
cb = g_disk + (u64)lba*512;
|
||||
else {
|
||||
if(fat32_read_sectors(lba,8,g_cluster)!=0) return -3;
|
||||
if(fat32_read_sectors(lba,spc,g_cluster)!=0) return -3;
|
||||
cb = g_cluster;
|
||||
}
|
||||
const u8 *entries = (const u8 *)cb;
|
||||
@@ -348,7 +368,7 @@ static int fat32_read_path(const char *path, u8 **out_data, u32 *out_size) {
|
||||
if((u64)fc_lba*512+(u64)spc*512<=256ULL*512)
|
||||
fb=g_disk+(u64)fc_lba*512;
|
||||
else {
|
||||
if(fat32_read_sectors(fc_lba,8,g_cluster)!=0) { logh("[DSK] fat32_read_path: data cluster read failed lba=", (u64)fc_lba); return -6; }
|
||||
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; }
|
||||
fb=g_cluster;
|
||||
}
|
||||
for(u32 b=0;b<fc_bytes;b++) dst[b]=fb[b];
|
||||
@@ -457,6 +477,19 @@ static u32 dsk_bg_at_y(i64 y) {
|
||||
return blend_color(BG_TOP, BG_BOTTOM, (u32)(((u64)y * 255ULL) / (g_fb_h - 1)));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -479,26 +512,26 @@ static void dsk_fill_gradient_rect(u32 *fb, i64 x, i64 y, i64 w, i64 h) {
|
||||
* Framebuffer format: UEFI BGRX — u32 = 0xAARRGGBB
|
||||
* bits 0-7 = B, bits 8-15 = G, bits 16-23 = R, bits 24-31 = A/X
|
||||
*/
|
||||
static void dsk_draw_logo(u32 *fb) {
|
||||
/* Center the logo on screen */
|
||||
i64 ox = ((i64)g_fb_w - g_logo_w) / 2;
|
||||
i64 oy = ((i64)g_fb_h - g_logo_h) / 2;
|
||||
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;
|
||||
|
||||
for (int ly = 0; ly < g_logo_h; ly++) {
|
||||
for (int ly = 0; ly < h; ly++) {
|
||||
i64 fy = oy + ly;
|
||||
if (fy < 0 || (u64)fy >= g_fb_h) continue;
|
||||
u32 *line = (u32 *)((u8 *)fb + (u64)fy * g_fb_p);
|
||||
|
||||
for (int lx = 0; lx < g_logo_w; lx++) {
|
||||
for (int lx = 0; lx < w; lx++) {
|
||||
i64 fx = ox + lx;
|
||||
if (fx < 0 || (u64)fx >= g_fb_w) continue;
|
||||
|
||||
/* Read RGBA pixel from embedded data */
|
||||
int idx = (ly * g_logo_w + lx) * 4;
|
||||
u8 r = g_logo_rgba[idx + 0];
|
||||
u8 g = g_logo_rgba[idx + 1];
|
||||
u8 b = g_logo_rgba[idx + 2];
|
||||
u8 a = g_logo_rgba[idx + 3];
|
||||
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];
|
||||
|
||||
if (a == 0) continue; /* fully transparent: skip */
|
||||
if (a == 255) {
|
||||
@@ -517,6 +550,24 @@ static void dsk_draw_logo(u32 *fb) {
|
||||
}
|
||||
}
|
||||
|
||||
static void dsk_draw_logo(u32 *fb) {
|
||||
dsk_draw_rgba(fb, g_logo_rgba, g_logo_w, g_logo_h);
|
||||
}
|
||||
|
||||
/* 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");
|
||||
}
|
||||
|
||||
/* ---- Text rendering: ASCII bitmap font on framebuffer ----
|
||||
* Uses g_ascii[95][11*18] from ascii_bitmaps.c (Consolas 18px).
|
||||
* Framebuffer format: BGRX — u32 = 0xAARRGGBB.
|
||||
@@ -549,6 +600,31 @@ static void dsk_draw_char(u32 *fb, char ch, i64 x, i64 y, u32 fg) {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dsk_draw_string(u32 *fb, const char *s, i64 x, i64 y, u32 fg, int spacing) {
|
||||
i64 cx = x;
|
||||
while (*s) {
|
||||
@@ -591,6 +667,11 @@ static int fat32_read_root_file(const char *name11, u8 **out_data, u32 *out_size
|
||||
u32 fat_byte_off = bpb->rsvd * 512;
|
||||
u32 spc = bpb->spc;
|
||||
logh("[DSK] fat32 data_lba=", data_lba);
|
||||
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;
|
||||
}
|
||||
|
||||
/* walk root directory cluster chain */
|
||||
u32 clus = bpb->root_clus;
|
||||
@@ -602,7 +683,7 @@ static int fat32_read_root_file(const char *name11, u8 **out_data, u32 *out_size
|
||||
if ((u64)lba * 512 + (u64)spc * 512 <= 256ULL * 512)
|
||||
cb = disk + (u64)lba * 512;
|
||||
else {
|
||||
if (fat32_read_sectors(lba, 8, g_cluster) != 0) { logh("[DSK] fat32_read_root_file: dir cluster read failed lba=", (u64)lba); return -4; }
|
||||
if (fat32_read_sectors(lba, spc, g_cluster) != 0) { logh("[DSK] fat32_read_root_file: dir cluster read failed lba=", (u64)lba); return -4; }
|
||||
cb = g_cluster;
|
||||
}
|
||||
if (fat32_find_entry(cb, spc, name11, &found_clus, &found_size) == 0) { found = 1; break; }
|
||||
@@ -623,7 +704,7 @@ static int fat32_read_root_file(const char *name11, u8 **out_data, u32 *out_size
|
||||
if ((u64)fc_lba * 512 + (u64)spc * 512 <= 256ULL * 512)
|
||||
fb = disk + (u64)fc_lba * 512;
|
||||
else {
|
||||
if (fat32_read_sectors(fc_lba, 8, g_cluster) != 0) { logh("[DSK] fat32_read_root_file: data cluster read failed lba=", (u64)fc_lba); return -7; }
|
||||
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; }
|
||||
fb = g_cluster;
|
||||
}
|
||||
for (u32 b = 0; b < fc_bytes; b++) dst[b] = fb[b];
|
||||
@@ -1086,6 +1167,14 @@ static int dsk_check_firstinit(int *is_first, int *dev_mode) {
|
||||
*dev_mode = 0;
|
||||
logl("[DSK] fat32_read_path start");
|
||||
int rc = fat32_read_root_file(name, &data, &size);
|
||||
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);
|
||||
}
|
||||
}
|
||||
logh("[DSK] fat32_read_path rc=", (u64)(i64)rc);
|
||||
if (rc != 0) { logl("[DSK] firstInit.txt not found, assuming first boot"); *is_first = 1; DSK_TS_END(firstinit_check, "dsk_check_firstinit (not found)"); return 0; }
|
||||
if (data[0] == '0') { logl("[DSK] firstInit=0"); *is_first = 1; }
|
||||
@@ -1225,8 +1314,31 @@ static int dsk_load_and_run(const char name11[12], const dsk_boot_context *ctx)
|
||||
u8 *data=0; u32 size=0; void *entry=0;
|
||||
logl("[DSK] load_and_run: ");
|
||||
swrite(name11); swrite("\n");
|
||||
if (fat32_read_root_file(name11, &data, &size) != 0) { logl("[DSK] load_and_run: fat32 read failed for "); swrite(name11); swrite("\n"); return -1; }
|
||||
if (fat32_read_root_file(name11, &data, &size) != 0) {
|
||||
/* 依次回退:SYSTEM/DESHAB64/ → SYSTEM/USER/USE/(FirstInit.elf 部署位) */
|
||||
static const char *pfxs[] = { "SYSTEM /DESHAB64 /", "SYSTEM /USER /USE /" };
|
||||
int loaded = 0;
|
||||
for (int pi = 0; pi < 2 && !loaded; 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) {
|
||||
loaded = 1;
|
||||
}
|
||||
}
|
||||
if (!loaded) {
|
||||
logl("[DSK] load_and_run: fat32 read failed for ");
|
||||
swrite(name11); swrite("\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (dsk_load_elf(data, size, &entry) != 0) { logl("[DSK] load_and_run: elf load failed for "); swrite(name11); swrite("\n"); return -2; }
|
||||
logl("[DSK] jumping to module");
|
||||
void(*fn)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))entry;
|
||||
fn(ctx);
|
||||
DSK_TS_END(mod_run, "dsk_load_and_run");
|
||||
@@ -1241,6 +1353,309 @@ static void dsk_run_desktop(const dsk_boot_context *ctx) {
|
||||
for(;;)__asm__("hlt");
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
@@ -1321,7 +1736,8 @@ static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
|
||||
g_block_read = blk ? blk->read : 0;
|
||||
g_block_write = blk ? blk->write : 0;
|
||||
logh("[DSK] block_read fn=", (u64)g_block_read);
|
||||
logh("[DSK] block_write fn=", (u64)g_block_write); }
|
||||
logh("[DSK] block_write fn=", (u64)g_block_write);
|
||||
fat32_probe_esp(); }
|
||||
milestone_write(2, "block API ready");
|
||||
|
||||
g_fb_addr=ctx->framebuffer_address; g_fb_w=ctx->framebuffer_width;
|
||||
@@ -1337,7 +1753,20 @@ static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
|
||||
DSK_TS_BEGIN(fuck_config);
|
||||
dsk_ini_config dsk_cfg;
|
||||
int dsk_cfg_ok = 0;
|
||||
if (g_block_read) {
|
||||
/* 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) {
|
||||
logl("[DSK] reading BPB for FUCK config");
|
||||
int bpb_rc = fat32_read_sectors(0, 256, g_disk);
|
||||
if (bpb_rc == 0) {
|
||||
@@ -1408,6 +1837,13 @@ static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
|
||||
u64 logo_budget = g_tsc_per_ms * 5000; /* 5000 ms = 5 seconds */
|
||||
while (rdtsc_dsk() - logo_start < logo_budget) __asm__("pause");
|
||||
logl("[DSK] Logo 5s done, proceeding");
|
||||
|
||||
/* 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");
|
||||
} else {
|
||||
logl("[DSK] logo skipped by FUCK config");
|
||||
}
|
||||
@@ -1428,6 +1864,19 @@ static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
|
||||
DSK_TS_END(firstinit_phase, "firstInit check phase");
|
||||
milestone_write(4, "firstInit check done");
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 合并 FUCK dev_mode 和 firstInit.txt dev_mode */
|
||||
if (firstinit_dev_mode) dev_mode = 1;
|
||||
|
||||
@@ -1518,7 +1967,7 @@ static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
|
||||
logh("[DSK:STAT] elf_load_count=", (u64)elf_load_count);
|
||||
logh("[DSK:STAT] mod_schedule_count=", (u64)mod_schedule_count);
|
||||
milestone_write(6, "desktop loading");
|
||||
dsk_run_desktop(ctx);
|
||||
dsk_choose_and_run_session(ctx, sfb, &dsk_cfg, dsk_cfg_ok);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1543,14 +1992,16 @@ static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
|
||||
|
||||
/* FirstInit.elf — user setup wizard; returns to DSK when done */
|
||||
{ logl("[DSK:SCHED] scheduling FirstInit.elf");
|
||||
char en[12]; /* FIRSTINIT */
|
||||
en[0]='F';en[1]='I';en[2]='R';en[3]='S';en[4]='T';
|
||||
en[5]='I';en[6]='N';en[7]='I';en[8]='T';en[9]=' ';en[10]=0;
|
||||
/* "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;
|
||||
logl("[DSK] loading FirstInit");
|
||||
if (dsk_load_and_run(en, ctx) != 0) {
|
||||
logl("[DSK] FirstInit not found, loading desktop directly");
|
||||
milestone_write(6, "desktop loading");
|
||||
dsk_run_desktop(ctx);
|
||||
dsk_choose_and_run_session(ctx, sfb, &dsk_cfg, dsk_cfg_ok);
|
||||
return;
|
||||
}
|
||||
logl("[DSK] FirstInit returned, persisting user.conf");
|
||||
@@ -1561,7 +2012,7 @@ static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
|
||||
logh("[DSK:STAT] mod_schedule_count=", (u64)mod_schedule_count);
|
||||
logl("[DSK] loading desktop");
|
||||
milestone_write(6, "desktop loading");
|
||||
dsk_run_desktop(ctx);
|
||||
dsk_choose_and_run_session(ctx, sfb, &dsk_cfg, dsk_cfg_ok);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user