diff options
| author | claude <[email protected]> | 2026-07-12 01:19:32 +0000 |
|---|---|---|
| committer | claude <[email protected]> | 2026-07-12 01:19:32 +0000 |
| commit | a4dce7f4d920e492d38c32ad3e42efdcfef3b3f1 (patch) | |
| tree | b0a0ad513792f5c0ddc524d67f6ab89e2044c642 /efi/mkesp.py | |
| download | plan9-kencc-linux-a4dce7f4d920e492d38c32ad3e42efdcfef3b3f1.tar.gz plan9-kencc-linux-a4dce7f4d920e492d38c32ad3e42efdcfef3b3f1.zip | |
🌭 plan9-kencc-linux: кросс-тулчейн Plan9 (cc/as/ld) + EFI-болванка
- build_arch.sh / build_al.sh: сборка kencc-компиляторов, ассемблеров,
линкеров всех арок (5/6/8/v/q/k) на Linux-хосте через plan9port.
- патчи под musl/gcc: sbrk->mmap, round/log2->p9*, Runemask, swcmp const,
-fcommon, machcap/omachcap, /sys рантайм-файлы. Подробно в PATCHES.md.
- bin/: готовые 8c 6c 5c vc qc kc + 6a 6l (Linux/musl x86_64).
- efi/: болваночный bootx64.efi (PE32+) тем же тулчейном (6a+6c+6l+dd),
референс — 9legacy nboot/efi; ESP-образ через mkesp.py.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Diffstat (limited to 'efi/mkesp.py')
| -rw-r--r-- | efi/mkesp.py | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/efi/mkesp.py b/efi/mkesp.py new file mode 100644 index 0000000..d9ab581 --- /dev/null +++ b/efi/mkesp.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# Собирает загрузочный ESP-образ (FAT16) c /EFI/BOOT/BOOTX64.EFI. +# Без mtools/mkfs — вручную по спецификации FAT, плюс самопроверка (обход обратно). +import struct, sys, os, math + +EFI = sys.argv[1] if len(sys.argv)>1 else "/data/work/chat_-1002129270612/plan9/build/efi/bootx64.efi" +OUT = sys.argv[2] if len(sys.argv)>2 else "/data/work/chat_-1002129270612/plan9/build/efi/esp.img" +data = open(EFI,"rb").read() + +BPS=512; SPC=1; RSVD=1; NFAT=2; ROOTENT=512; TOT=8192 +rootsecs=(ROOTENT*32+BPS-1)//BPS +tmp1=TOT-(RSVD+rootsecs); tmp2=256*SPC+NFAT +FATSZ=(tmp1+tmp2-1)//tmp2 +first_data=RSVD+NFAT*FATSZ+rootsecs +nclus=(TOT-first_data)//SPC +assert nclus>4085, f"стало бы FAT12 ({nclus} кластеров)" + +img=bytearray(TOT*BPS) +# --- boot sector / BPB --- +bs=img +bs[0:3]=b'\xEB\x3C\x90'; bs[3:11]=b'MSWIN4.1' +struct.pack_into('<H',bs,11,BPS); bs[13]=SPC +struct.pack_into('<H',bs,14,RSVD); bs[16]=NFAT +struct.pack_into('<H',bs,17,ROOTENT); struct.pack_into('<H',bs,19,TOT) +bs[21]=0xF8; struct.pack_into('<H',bs,22,FATSZ) +struct.pack_into('<H',bs,24,32); struct.pack_into('<H',bs,26,8) +bs[36]=0x80; bs[38]=0x29; struct.pack_into('<I',bs,39,0x12345678) +bs[43:54]=b'PLAN9 EFI '; bs[54:62]=b'FAT16 ' +bs[510]=0x55; bs[511]=0xAA + +# --- распределение кластеров --- +def nclus_for(n): return max(1,(n+BPS*SPC-1)//(BPS*SPC)) +# EFI(dir)=cl2, BOOT(dir)=cl3, файл=cl4.. +efi_cl=2; boot_cl=3; file_cl=4 +file_ncl=nclus_for(len(data)) +chain={efi_cl:[0xFFFF], boot_cl:[0xFFFF]} +file_clusters=list(range(file_cl,file_cl+file_ncl)) + +FAT=[0]*(nclus+2) +FAT[0]=0xFFF8; FAT[1]=0xFFFF +FAT[efi_cl]=0xFFFF; FAT[boot_cl]=0xFFFF +for i,c in enumerate(file_clusters): + FAT[c]=0xFFFF if i==len(file_clusters)-1 else file_clusters[i+1] + +def wfat(): + raw=bytearray(FATSZ*BPS) + for i,v in enumerate(FAT): + if i*2+2<=len(raw): struct.pack_into('<H',raw,i*2,v&0xFFFF) + for k in range(NFAT): + off=(RSVD+k*FATSZ)*BPS; img[off:off+len(raw)]=raw +wfat() + +def dirent(name,ext,attr,clus,size): + e=bytearray(32) + e[0:11]=(name.ljust(8)[:8]+ext.ljust(3)[:3]).encode('ascii').upper() + e[11]=attr + struct.pack_into('<H',e,26,clus&0xFFFF) + struct.pack_into('<I',e,28,size) + return e + +def clus_off(c): return (first_data+(c-2)*SPC)*BPS + +# root dir: EFI (dir -> cl2) +root_off=(RSVD+NFAT*FATSZ)*BPS +img[root_off:root_off+32]=dirent("EFI","",0x10,efi_cl,0) +# EFI dir (cl2): '.', '..', BOOT(dir->cl3) +o=clus_off(efi_cl) +img[o:o+32]=dirent(".","",0x10,efi_cl,0) +img[o+32:o+64]=dirent("..","",0x10,0,0) +img[o+64:o+96]=dirent("BOOT","",0x10,boot_cl,0) +# BOOT dir (cl3): '.', '..', BOOTX64.EFI(file->cl4) +o=clus_off(boot_cl) +img[o:o+32]=dirent(".","",0x10,boot_cl,0) +img[o+32:o+64]=dirent("..","",0x10,efi_cl,0) +img[o+64:o+96]=dirent("BOOTX64","EFI",0x20,file_cl,len(data)) +# данные файла +for i,c in enumerate(file_clusters): + chunk=data[i*BPS*SPC:(i+1)*BPS*SPC] + off=clus_off(c); img[off:off+len(chunk)]=chunk + +open(OUT,"wb").write(img) + +# --- САМОПРОВЕРКА: обойти FAT и достать /EFI/BOOT/BOOTX64.EFI --- +im=open(OUT,"rb").read() +def rd(a,n): return im[a:a+n] +def fat(c): return struct.unpack_from('<H',im,(RSVD*BPS)+c*2)[0] +def readdir(off): + ents={} + for i in range(0,BPS,32): + e=im[off+i:off+i+32] + if e[0] in (0,0xE5): continue + nm=e[0:8].decode().strip(); ex=e[8:11].decode().strip() + cl=struct.unpack_from('<H',e,26)[0]; sz=struct.unpack_from('<I',e,28)[0] + key=nm+('.'+ex if ex else '') + ents[key]=(cl,sz,e[11]) + return ents +root=readdir((RSVD+NFAT*FATSZ)*BPS) +efi=readdir(clus_off(root['EFI'][0])) +boot=readdir(clus_off(efi['BOOT'][0])) +cl,sz,_=boot['BOOTX64.EFI'] +out=bytearray() +while cl<0xFFF8: + out+=im[clus_off(cl):clus_off(cl)+BPS*SPC]; cl=fat(cl) +out=out[:sz] +ok = bytes(out)==data +print(f"ESP: {OUT} {len(im)} байт (FAT16, {nclus} кластеров, FATSz={FATSZ})") +print(f"путь /EFI/BOOT/BOOTX64.EFI: {sz} байт") +print("самопроверка (обход FAT == оригинал):", "OK" if ok else "FAIL") |
