/* DSK Main Kernel — boot entry, FAT32 firstInit check, ELF loader */ #include "../UTSM/include/utsm/dsk.h" #include "port.h" #define COM1 0x3F8 typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; typedef long long i64; typedef int (*block_read_fn)(u32 index, u64 lba, u32 count, void *buf); static void sputc(char c) { for(unsigned i=0;i<100000;i++){if(inb(COM1+5)&0x20)break;} outb(COM1,(u8)c); } static void swrite(const char *s) { while(*s){if(*s=='\n')sputc('\r');sputc(*s++);} } static void logl(const char *s) { swrite(s); swrite("\n"); } static void logh(const char *p, u64 v) { static const char h[]="0123456789abcdef"; char b[19]; int i=0; b[i++]='0';b[i++]='x'; for(int j=15;j>=0;j--)b[i++]=h[(v>>(j*4))&0xf];b[i]=0; swrite(p);swrite(b);swrite("\n"); } static void *memset_dsk(void *d, int c, u64 n) { u8 *p=(u8*)d; while(n--)*p++=(u8)c; return d; } static void *memcpy_dsk(void *d, const void *s, u64 n) { u8 *dd=(u8*)d; const u8 *ss=(const u8*)s; while(n--)*dd++=*ss++; return d; } typedef struct __attribute__((packed)) { u8 jmp[3]; char oem[8]; u16 bps; u8 spc; u16 rsvd; u8 fc; u16 root_ent; u16 ts16; u8 media; u16 spf16; u16 spt; u16 heads; u32 hidden; u32 ts32; u32 spf; u16 flags; u16 ver; u32 root_clus; u16 fsi; u16 bkboot; u8 res[12]; u8 drv; u8 ntfl; u8 sig; u32 ser; char lbl[11]; char typ[8]; u8 code[420]; u16 boot_sig; } fat32_bpb; typedef struct __attribute__((packed)) { char name[11]; u8 attr; u8 ntr; u8 ctenth; u16 ctime; u16 cdate; u16 adate; u16 chigh; u16 wtime; u16 wdate; u16 clow; u32 fsize; } fat32_de; static u32 r32(const u8 *p) { return (u32)p[0]|((u32)p[1]<<8)|((u32)p[2]<<16)|((u32)p[3]<<24); } static u16 r16(const u8 *p) { return (u16)p[0]|((u16)p[1]<<8); } static int neq11(const char *a, const char *b) { for(int i=0;i<11;i++) if(a[i]!=b[i]) return 0; return 1; } #define EI_MAG0 0x7f #define ELFCLASS64 2 #define ELFDATA2LSB 1 #define EM_X86_64 62 #define PT_LOAD 1 #define PT_DYNAMIC 2 #define DT_RELA 7 #define DT_RELASZ 8 #define DT_RELAENT 9 #define R_X86_64_RELATIVE 8 typedef struct { u8 ident[16]; u16 type,machine; u32 ver; u64 entry,phoff,shoff; u32 flags; u16 ehsize,phentsize,phnum,shentsize,shnum,shstrndx; } elf64_ehdr; typedef struct { u32 type,flags; u64 offset,vaddr,paddr,filesz,memsz,align; } elf64_phdr; typedef struct { i64 tag; u64 val; } elf64_dyn; typedef struct { u64 offset; u64 info; i64 addend; } elf64_rela; #define BG_TOP 0xFFC8E0F0u #define BG_BOTTOM 0xFF49306Fu #define BG_MID 0xFF8888B0u static u64 g_fb_addr, g_fb_w, g_fb_h, g_fb_p; static block_read_fn g_block_read; static u8 g_disk[131072]; static u8 g_cluster[4096]; static u8 g_fdata[262144]; static int fat32_read_sectors(u32 lba, u32 count, u8 *out) { return g_block_read ? g_block_read(0,lba,count,out) : -1; } static u32 blend_color(u32 c1, u32 c2, u32 a) { u32 na = 256 - a; u32 r = ((c1 & 0xFF) * na + (c2 & 0xFF) * a) >> 8; u32 g = (((c1 >> 8) & 0xFF) * na + ((c2 >> 8) & 0xFF) * a) >> 8; u32 b = (((c1 >> 16) & 0xFF) * na + ((c2 >> 16) & 0xFF) * a) >> 8; return 0xFF000000 | (b << 16) | (g << 8) | r; } static u32 dsk_bg_at_y(i64 y) { if (g_fb_h <= 1) return BG_TOP; if (y < 0) y = 0; if ((u64)y >= g_fb_h) y = (i64)g_fb_h - 1; return blend_color(BG_TOP, BG_BOTTOM, (u32)(((u64)y * 255ULL) / (g_fb_h - 1))); } static void dsk_fill_gradient_rect(u32 *fb, i64 x, i64 y, i64 w, i64 h) { for (i64 r = 0; r < h; r++) { i64 yy = y + r; if (yy < 0 || (u64)yy >= g_fb_h) continue; u32 color = dsk_bg_at_y(yy); u32 *line = (u32 *)((u8 *)fb + (u64)yy * g_fb_p); for (i64 c = 0; c < w; c++) { i64 xx = x + c; if (xx < 0 || (u64)xx >= g_fb_w) continue; line[(u64)xx] = color; } } } static int fat32_find_entry(const u8 *clus, u32 clus_sectors, const char *target, u32 *out_clus, u32 *out_size) { const fat32_de *dir = (const fat32_de *)clus; for (u32 e=0; e*32 < clus_sectors*512; e++) { if (dir[e].name[0]==0) break; if ((u8)dir[e].name[0]==0xE5) continue; if (dir[e].attr==0x0F) continue; if (dir[e].attr & 0x08) continue; if (neq11(dir[e].name, target)) { *out_clus = r16((const u8*)&dir[e].clow); *out_size = dir[e].fsize; return 0; } } return -1; } /* find a single file in root directory by 11-char 8.3 name (avoids PIE pointer reloc) */ static int fat32_read_root_file(const char *name11, u8 **out_data, u32 *out_size) { u8 *disk = g_disk; logl("[DSK] fat32 reading 256 sectors from LBA 0"); int st = fat32_read_sectors(0, 256, disk); logh("[DSK] fat32 read_sectors rc=", (u64)(i64)st); if (st != 0) return -1; const fat32_bpb *bpb = (const fat32_bpb *)disk; if (bpb->boot_sig != 0xAA55 || bpb->bps != 512) return -2; if (bpb->spf == 0 || bpb->root_clus < 2) return -3; u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf; u32 fat_byte_off = bpb->rsvd * 512; u32 spc = bpb->spc; logh("[DSK] fat32 data_lba=", data_lba); /* walk root directory cluster chain */ u32 clus = bpb->root_clus; u32 found_clus = 0, found_size = 0; int found = 0; while (clus >= 2 && clus < 0x0FFFFFF8 && !found) { u32 lba = data_lba + (clus - 2) * spc; const u8 *cb; if ((u64)lba * 512 + (u64)spc * 512 <= 256ULL * 512) cb = disk + (u64)lba * 512; else { if (fat32_read_sectors(lba, 8, g_cluster) != 0) return -4; cb = g_cluster; } if (fat32_find_entry(cb, spc, name11, &found_clus, &found_size) == 0) { found = 1; break; } u32 fo = fat_byte_off + clus * 4; if (fo + 4 > sizeof(g_disk)) break; clus = r32(disk + fo) & 0x0FFFFFFF; } if (!found) { logl("[DSK] fat32 entry not found"); return -5; } logh("[DSK] fat32 found_clus=", found_clus); logh("[DSK] fat32 found_size=", found_size); if (found_size > sizeof(g_fdata)) return -6; u8 *dst = g_fdata; u32 remaining = found_size; u32 fc = found_clus; while (fc >= 2 && fc < 0x0FFFFFF8 && remaining > 0) { u32 fc_lba = data_lba + (fc - 2) * spc; u32 fc_bytes = spc * 512; if (fc_bytes > remaining) fc_bytes = remaining; const u8 *fb; if ((u64)fc_lba * 512 + (u64)spc * 512 <= 256ULL * 512) fb = disk + (u64)fc_lba * 512; else { if (fat32_read_sectors(fc_lba, 8, g_cluster) != 0) return -7; fb = g_cluster; } for (u32 b = 0; b < fc_bytes; b++) dst[b] = fb[b]; dst += fc_bytes; remaining -= fc_bytes; u32 fo = fat_byte_off + fc * 4; if (fo + 4 > sizeof(g_disk)) break; fc = r32(disk + fo) & 0x0FFFFFFF; } *out_data = g_fdata; *out_size = found_size; logl("[DSK] fat32 file read done"); return 0; } static int dsk_check_firstinit(int *is_first) { char name[12]; /* "FIRSTINTXT" on stack — no PIE reloc */ name[0]='F';name[1]='I';name[2]='R';name[3]='S';name[4]='T'; name[5]='I';name[6]='N';name[7]='T';name[8]='X';name[9]='T';name[10]=0; u8 *data = 0; u32 size = 0; logl("[DSK] fat32_read_path start"); int rc = fat32_read_root_file(name, &data, &size); logh("[DSK] fat32_read_path rc=", (u64)(i64)rc); if (rc != 0) { logl("[DSK] firstInit.txt not found"); *is_first = 1; return 0; } if (data[0] == '0') { logl("[DSK] firstInit=0"); *is_first = 1; return 0; } logl("[DSK] firstInit != 0"); *is_first = 0; return 0; } static int dsk_load_elf(u8 *data, u32 size, void **entry_out) { (void)size; const elf64_ehdr *eh = (const elf64_ehdr *)data; if (eh->ident[0] != EI_MAG0 || eh->ident[4] != ELFCLASS64) return -1; if (eh->machine != EM_X86_64) return -2; u64 min_vaddr = ~0ULL, max_vaddr = 0; u32 lc = 0; for (u16 i = 0; i < eh->phnum; i++) { const elf64_phdr *ph = (const elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize); if (ph->type != PT_LOAD) continue; if (ph->filesz > ph->memsz) return -3; if (ph->vaddr < min_vaddr) min_vaddr = ph->vaddr; if (ph->vaddr + ph->memsz > max_vaddr) max_vaddr = ph->vaddr + ph->memsz; lc++; } if (!lc || min_vaddr == ~0ULL) return -4; u64 isize = max_vaddr - min_vaddr; isize = (isize + 0xFFF) & ~0xFFFULL; static u8 ibuf[262144]; u8 *image = ibuf; memset_dsk(image, 0, isize); for (u16 i = 0; i < eh->phnum; i++) { const elf64_phdr *ph = (const elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize); if (ph->type != PT_LOAD) continue; u64 off = ph->vaddr - min_vaddr; memcpy_dsk(image + off, data + ph->offset, ph->filesz); } *entry_out = image + (eh->entry - min_vaddr); /* apply R_X86_64_RELATIVE relocations from PT_DYNAMIC (PIE) */ u64 load_bias = (u64)image - min_vaddr; for (u16 i = 0; i < eh->phnum; i++) { const elf64_phdr *ph = (const elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize); if (ph->type != PT_DYNAMIC) continue; const elf64_dyn *dyn = (const elf64_dyn *)(image + (ph->vaddr - min_vaddr)); u64 rela_off = 0, rela_sz = 0, rela_ent = 24; for (; dyn->tag != 0; dyn++) { if (dyn->tag == DT_RELA) rela_off = dyn->val; else if (dyn->tag == DT_RELASZ) rela_sz = dyn->val; else if (dyn->tag == DT_RELAENT) rela_ent = dyn->val; } if (rela_off && rela_sz) { u64 n = rela_sz / rela_ent; logh("[DSK] elf relocs=", n); for (u64 r = 0; r < n; r++) { const elf64_rela *rel = (const elf64_rela *)(image + (rela_off - min_vaddr) + r * rela_ent); u32 rtype = (u32)(rel->info & 0xFFFFFFFF); if (rtype == R_X86_64_RELATIVE) { u64 *slot = (u64 *)(image + (rel->offset - min_vaddr)); *slot = load_bias + (u64)rel->addend; } } } } logh("[DSK] elf image base=", (u64)image); logh("[DSK] elf entry=", (u64)*entry_out); return 0; } static void dsk_spinner_and_check(u32 *fb_arg, i64 cx, i64 cy, i64 r, i64 thk, const u32 arc_colors[4], u32 bg, const void *boot_ctx_ptr) { (void)bg; (void)fb_arg; const dsk_boot_context *ctx = (const dsk_boot_context *)boot_ctx_ptr; { u64 api = ctx->dkm_kernel_api; g_block_read = (block_read_fn)*(u64 *)(api + 0xA8); if (g_block_read) g_block_read = (block_read_fn)*(u64 *)((u64)g_block_read + 16); } #define SPR 128 static u32 sprite[SPR*SPR]; i64 sp=SPR*4, scx=SPR/2, scy=SPR/2, bx=cx-scx, by=cy-scy; i64 frame=0, base=0; int checked=0; void *fe_entry=0; g_fb_addr=ctx->framebuffer_address; g_fb_w=ctx->framebuffer_width; g_fb_h=ctx->framebuffer_height; g_fb_p=ctx->framebuffer_pitch; u32 *sfb=(u32*)(u64)g_fb_addr; dsk_fill_gradient_rect(sfb, 0, 0, (i64)g_fb_w, (i64)g_fb_h); u64 sw=g_fb_w, sh=g_fb_h, spv=g_fb_p; logh("[DSK] block_read ptr=", (u64)g_block_read); logl("[DSK] entering spinner loop"); while (1) { g_fb_w=SPR; g_fb_h=SPR; g_fb_p=sp; /* per-row gradient so sprite interior matches background */ static u32 row_bg[SPR]; for (i64 y0=0; y0= sh) ry = (i64)sh - 1; row_bg[y0] = blend_color(BG_TOP, BG_BOTTOM, (u32)(((u64)ry * 255ULL) / (sh - 1))); u32 *ln=&sprite[y0*SPR]; for(i64 x0=0;x0=SPR)continue; u32 sbg=row_bg[yy]; for(i64 dx=-ro-1;dx<=ro+1;dx++){i64 xx=scx+dx; if(xx<0||xx>=SPR)continue; i64 d2=dx*dx+dy*dy; if(d2(ro+1)*(ro+1)+2)continue; i64 ang; if(dx==0)ang=dy<0?90:270; else{i64 ax=dx<0?-dx:dx,ay=dy<0?-dy:dy,a0=ax>ay?ay*45/ax:90-ax*45/(ay?ay:1); if(dx>=0&&dy<=0)ang=a0;else if(dx<0&&dy<=0)ang=180-a0; else if(dx<0&&dy>0)ang=180+a0;else ang=360-a0;} i64 a=ang-sa; if(a<0)a+=360; if((u64)a>(u64)sw2)continue; u32 fade; if((u64)a<6)fade=(u32)(a*255/6);else if((u64)a>(u64)(sw2-6))fade=(u32)((sw2-a)*255/6);else fade=255; u64 vv=(u64)d2; u64 xr=vv,yr=(xr+1)>>1; while(yr>1;} i64 dist=(i64)xr; u32 eff=((sbg&0xFF)*(256-fade)+(clr&0xFF)*fade)>>8; u32 ge=(((sbg>>8)&0xFF)*(256-fade)+((clr>>8)&0xFF)*fade)>>8; u32 be=(((sbg>>16)&0xFF)*(256-fade)+((clr>>16)&0xFF)*fade)>>8; eff=0xFF000000|(be<<16)|(ge<<8)|eff; if(dist>=ri&&dist<=ro)sprite[(u64)yy*SPR+(u64)xx]=eff; }} } i64 ri2=r-8; for(i64 dy=-ri2-2;dy<=ri2+2;dy++){i64 yy2=scy+dy; if(yy2<0||yy2>=SPR)continue; u32 sbg2=row_bg[yy2]; for(i64 dx=-ri2-2;dx<=ri2+2;dx++){i64 xx2=scx+dx; if(xx2<0||xx2>=SPR)continue; i64 d2=dx*dx+dy*dy; if(d2<=ri2*ri2){ u32 ic=((sbg2&0xFF)*176+0xD0*80)>>8; u32 ig=(((sbg2>>8)&0xFF)*176+0xF0*80)>>8; u32 ib=(((sbg2>>16)&0xFF)*176+0xFF*80)>>8; sprite[(u64)yy2*SPR+(u64)xx2]=0xFF000000|(ib<<16)|(ig<<8)|ic; } }} } g_fb_w=sw; g_fb_h=sh; g_fb_p=spv; dsk_fill_gradient_rect(sfb, bx, by, SPR, SPR); for(i64 sr=0;sr=g_fb_h)continue; u32 *dst=(u32*)((u8*)sfb+(u64)sy*g_fb_p)+bx; u32 *src=&sprite[sr*SPR]; for(i64 sc=0;sc=g_fb_w)continue; dst[sc]=src[sc];}} for(volatile u32 d=0;d<72000;d++)__asm__("pause"); base-=2; if(base<0)base+=360; frame++; if(frame>=100&&!checked){checked=1; /* was 540, reduced for test */ logl("[DSK] checking firstInit..."); if(g_block_read){logl("[DSK] have block read, calling dsk_check_firstinit"); int is_first=0; if(dsk_check_firstinit(&is_first)==0&&is_first){ logl("[DSK] first init detected; running system initializers"); /* DSK owns system component initialization. FirstInit is only user setup. */ char mn[12]; /* MOUSE ELF */ mn[0]='M';mn[1]='O';mn[2]='U';mn[3]='S';mn[4]='E';mn[5]=' ';mn[6]=' ';mn[7]=' ';mn[8]='E';mn[9]='L';mn[10]='F'; u8 *md=0; u32 ms=0; void *me=0; if(fat32_read_root_file(mn,&md,&ms)==0){ if(dsk_load_elf(md,ms,&me)==0){ logl("[DSK] jumping to mouseInit"); void(*mentry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))me; mentry(ctx); logl("[DSK] mouseInit returned"); } } char nn[12]; /* NETMAN ELF */ nn[0]='N';nn[1]='E';nn[2]='T';nn[3]='M';nn[4]='A';nn[5]='N';nn[6]=' ';nn[7]=' ';nn[8]='E';nn[9]='L';nn[10]='F'; u8 *nd=0; u32 ns=0; void *ne=0; if(fat32_read_root_file(nn,&nd,&ns)==0){ if(dsk_load_elf(nd,ns,&ne)==0){ logl("[DSK] jumping to netman"); void(*nentry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))ne; nentry(ctx); logl("[DSK] netman returned"); } } logl("[DSK] loading FirstInit.elf"); char en[12]; /* FIRSTINIT */ en[0]='F';en[1]='I';en[2]='R';en[3]='S';en[4]='T'; en[5]='I';en[6]='N';en[7]='I';en[8]='T';en[9]=' ';en[10]=0; u8 *fd=0; u32 fs=0; if(fat32_read_root_file(en,&fd,&fs)==0){ if(dsk_load_elf(fd,fs,&fe_entry)==0) logl("[DSK] FirstInit.elf loaded"); } } } } if(fe_entry&&frame>150){logl("[DSK] jumping to FirstInit"); /* was 600 */ void(*entry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))fe_entry; entry(ctx); for(;;)__asm__("hlt"); } if(!g_block_read&&frame>800){logl("[DSK] no block device, skipping firstInit");break;} if(checked&&!fe_entry&&frame>800){logl("[DSK] firstInit not found, continuing normal boot");break;} } } __attribute__((noreturn, visibility("default"))) void dsk_entry(const dsk_boot_context *ctx) { __asm__ volatile("cli"); /* disable IRQs — ps2kbd/IRQ1 & mouse/IRQ12 handlers crash during spinner */ logl("[DSK] boot"); if(!ctx||ctx->magic!=DSK_BOOT_MAGIC){logl("[DSK] bad context");for(;;)__asm__("hlt");} logl("[DSK] context ok"); g_fb_addr=ctx->framebuffer_address; g_fb_w=ctx->framebuffer_width; g_fb_h=ctx->framebuffer_height; g_fb_p=ctx->framebuffer_pitch; u32 bg=BG_MID, arcs[4]={0xFF4488CC,0xFF2266AA,0xFF66AAEE,0xFF88CCFF}; i64 cx=(i64)g_fb_w/2,cy=(i64)g_fb_h/2,r=48,thk=4; dsk_spinner_and_check((u32*)(u64)g_fb_addr,cx,cy,r,thk,arcs,bg,ctx); logl("[DSK] SELFTEST PASS"); for(;;)__asm__("hlt"); }