summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorclaude <[email protected]>2026-07-12 01:19:32 +0000
committerclaude <[email protected]>2026-07-12 01:19:32 +0000
commita4dce7f4d920e492d38c32ad3e42efdcfef3b3f1 (patch)
treeb0a0ad513792f5c0ddc524d67f6ab89e2044c642
downloadplan9-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]>
-rw-r--r--.gitignore15
-rw-r--r--NOTICE22
-rw-r--r--PATCHES.md58
-rw-r--r--README.md75
-rwxr-xr-xbin/5cbin0 -> 1006072 bytes
-rwxr-xr-xbin/6abin0 -> 408832 bytes
-rwxr-xr-xbin/6cbin0 -> 1094136 bytes
-rwxr-xr-xbin/6lbin0 -> 546056 bytes
-rwxr-xr-xbin/8cbin0 -> 1135776 bytes
-rwxr-xr-xbin/kcbin0 -> 979568 bytes
-rwxr-xr-xbin/qcbin0 -> 1053832 bytes
-rwxr-xr-xbin/vcbin0 -> 981056 bytes
-rw-r--r--efi/README.md35
-rw-r--r--efi/efi_build.sh32
-rw-r--r--efi/fetch_ref.sh24
-rw-r--r--efi/hello.c52
-rw-r--r--efi/mkesp.py108
-rw-r--r--scripts/build_al.sh57
-rw-r--r--scripts/build_all.sh19
-rw-r--r--scripts/build_arch.sh68
-rw-r--r--scripts/setup.sh30
21 files changed, 595 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..65f10ac
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+# зависимости, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ тянутся скриптами
+deps/
+efi/nboot.diff
+efi/pe64.s
+efi/pe64min.s
+efi/efi.h
+efi/mem.h
+# Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚Ρ‹ сборки
+build/
+*.o
+*.6 *.5 *.8 *.v *.q *.k
+*.out
+efi/bootx64.efi
+efi/*.img
+y.tab.*
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..d00feff
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,22 @@
+plan9-kencc-linux β€” авторство ΠΈ Π»ΠΈΡ†Π΅Π½Π·ΠΈΠΈ
+========================================
+
+Наш ΠΊΠΎΠ΄ (сборочныС скрипты, efi/hello.c, efi/efi_build.sh, efi/mkesp.py,
+efi/fetch_ref.sh, докумСнтация) β€” свободно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅.
+
+БобираСтся ΠΈΠ· стороннСго ΠΊΠΎΠ΄Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ НЕ Π²Ρ…ΠΎΠ΄ΠΈΡ‚ Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ, Π° тянСтся
+скриптами:
+
+* ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ‚ΠΎΡ€Ρ‹/ассСмблСры/Π»ΠΈΠ½ΠΊΠ΅Ρ€Ρ‹ Plan 9 (kencc) ΠΈ систСмныС Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ β€”
+ ΠΈΠ· Π΄Π΅Ρ€Π΅Π²Π° исходников Plan 9 (plan9foundation / совмСстимого).
+ ΠžΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹Π΅ Π»ΠΈΡ†Π΅Π½Π·ΠΈΠΈ Plan 9 (MIT-style, Ρ€Π°Π½Π΅Π΅ Lucent Public License).
+
+* Π’ΡƒΠ»Ρ‡Π΅ΠΉΠ½-обвязка lib9/libbio/libmach ΠΈ 9c/9l/9ar/yacc β€” plan9port
+ (https://github.com/9fans/plan9port), Π»ΠΈΡ†Π΅Π½Π·ΠΈΠΈ plan9port.
+
+* РСфСрСнсный EFI-Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊ (pe64.s, efi.h, mem.h) β€” 9legacy, nboot/efi
+ (http://9legacy.org/9legacy/patch/nboot.diff). ВянСтся efi/fetch_ref.sh,
+ Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ НЕ хранится. ЛицСнзия β€” ΠΊΠ°ΠΊ Ρƒ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ ΠΊΠΎΠ΄Π° Plan 9.
+
+Π“ΠΎΡ‚ΠΎΠ²Ρ‹Π΅ Π±ΠΈΠ½Π°Ρ€ΠΈ Π² bin/ собраны ΠΈΠ· Π²Ρ‹ΡˆΠ΅ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹Ρ… исходников нашими скриптами
+ΠΈ Π½Π°ΡΠ»Π΅Π΄ΡƒΡŽΡ‚ ΠΈΡ… Π»ΠΈΡ†Π΅Π½Π·ΠΈΠΈ.
diff --git a/PATCHES.md b/PATCHES.md
new file mode 100644
index 0000000..f8b20aa
--- /dev/null
+++ b/PATCHES.md
@@ -0,0 +1,58 @@
+# ΠŸΠ°Ρ‚Ρ‡ΠΈ ΠΏΠΎΠ΄ сборку kencc Π½Π° Linux-хостС
+
+ВсС ΠΏΡ€Π°Π²ΠΊΠΈ автоматичСски Π½Π°ΠΊΠ»Π°Π΄Ρ‹Π²Π°ΡŽΡ‚ΡΡ `scripts/build_arch.sh` ΠΈ `build_al.sh`
+Π½Π° свСТиС ΠΊΠΎΠΏΠΈΠΈ исходников (ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ Π΄Π΅Ρ€Π΅Π²ΠΎ Π½Π΅ трогаСтся). НиТС β€” Ρ‡Ρ‚ΠΎ ΠΈ Π·Π°Ρ‡Π΅ΠΌ.
+
+## 1. `round` / `log2` β†’ `p9round` / `p9log2`
+`cc/` опрСдСляСт свои `round()` ΠΈ `log2()`, ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΡƒΡŽΡ‰ΠΈΠ΅ ΠΏΠΎ Ρ‚ΠΈΠΏΡƒ с ΠΏΡ€ΠΎΡ‚ΠΎΡ‚ΠΈΠΏΠ°ΠΌΠΈ
+ΠΈΠ· musl `math.h`. ΠŸΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Ρ‹Π²Π°Π΅ΠΌ опрСдСлСния ΠΈ Π²Ρ‹Π·ΠΎΠ²Ρ‹ Π²ΠΎ всСх Ρ„Π°ΠΉΠ»Π°Ρ… (ΠΈ Π²
+сгСнСрённом `y.tab.c`). Π€Π°ΠΉΠ»Ρ‹: `cc/dcl.c`, `cc/pgen.c`, `cc/sub.c`, `cc/cc.h`,
+`Xc/swt.c`, `Xc/cgen.c`.
+
+## 2. ΠŸΠΎΡ€ΡΠ΄ΠΎΠΊ ΠΈ Π΅Π΄ΠΈΠ½ΠΈΡ‡Π½ΠΎΡΡ‚ΡŒ `#include "y.tab.h"`
+`y.tab.h` (Π³Π΅Π½Π΅Ρ€ΠΈΡ‚ yacc) ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Ρ‚ΠΈΠΏ `Node`, ΠΎΠ±ΡŠΡΠ²Π»Π΅Π½Π½Ρ‹ΠΉ Π² `cc.h`, ΠΈ Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚
+include-guard. Π—Π½Π°Ρ‡ΠΈΡ‚: Π²ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ строго ΠŸΠžΠ‘Π›Π• `cc.h` ΠΈ Ρ€ΠΎΠ²Π½ΠΎ ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π· (ΠΈΠ½Π°Ρ‡Π΅
+ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ пСрСопрСдСлСния `YYSTYPE`/`yylval`). Π’ свСТСм `lex.c` порядок ΡƒΠΆΠ΅
+Π²Π΅Ρ€Π½Ρ‹ΠΉ β€” ΠΏΡ€Π°Π²ΠΊΠ° Π½ΡƒΠΆΠ½Π° Π±Ρ‹Π»Π° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΡ€ΠΈ Ρ€ΡƒΡ‡Π½ΠΎΠΉ Π²ΠΎΠ·Π½Π΅.
+
+## 3. Плоская раскладка include
+Π˜ΡΡ…ΠΎΠ΄Π½ΠΈΠΊΠΈ ΡΡΡ‹Π»Π°ΡŽΡ‚ΡΡ Π½Π° сосСдниС ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ΠΈ: `#include "../cc/cc.h"`,
+`"../6c/6.out.h"`, `"../8l/elf.h"`, extension-less `"compat"`, `"macbody"`,
+`"lexbody"`. Π‘ΠΊΠ»Π°Π΄Ρ‹Π²Π°Π΅ΠΌ всё Π² ΠΎΠ΄ΠΈΠ½ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ сборки ΠΈ срСзаСм `../*/` ΠΈΠ· include.
+Extension-less Ρ„Π°ΠΉΠ»Ρ‹ ΠΊΠΎΠΏΠΈΡ€ΡƒΠ΅ΠΌ явно.
+
+## 4. `Runemask`
+Плановская libc-константа `Runemask` (маска 21-Π±ΠΈΡ‚Π½ΠΎΠΉ Ρ€ΡƒΠ½Ρ‹) Π΅ΡΡ‚ΡŒ Π² Ρ€ΠΎΠ΄Π½ΠΎΠΉ Plan9,
+Π½ΠΎ НЕ Π² plan9port. ДобавляСм `#define Runemask 0x1FFFFF` Π² `lex.c`.
+
+## 5. ΠŸΡ€ΠΎΡ‚ΠΎΡ‚ΠΈΠΏ `swcmp` β†’ `const`
+`swcmp` β€” ΠΊΠΎΠΌΠΏΠ°Ρ€Π°Ρ‚ΠΎΡ€ для `qsort`. Π£ musl сигнатура `int(const void*, const void*)`,
+Π° плановский ΠΏΡ€ΠΎΡ‚ΠΎΡ‚ΠΈΠΏ Π² `gc.h` β€” `int(void*, void*)`. ΠŸΡ€ΠΈΠ²ΠΎΠ΄ΠΈΠΌ ΠΏΡ€ΠΎΡ‚ΠΎΡ‚ΠΈΠΏ ΠΊ `const`.
+
+## 6. `-fcommon`
+Π‘Ρ‚Π°Ρ€Ρ‹ΠΉ ΠΊΠΎΠ΄ Π΄Π΅Ρ€ΠΆΠΈΡ‚ tentative-Π΄Π΅Ρ„ΠΈΠ½ΠΈΡ†ΠΈΠΈ Π³Π»ΠΎΠ±Π°Π»ΠΎΠ² (Π½Π°ΠΏΡ€. `hintabsize` Π² Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ…
+`.c` Ρ‡Π΅Ρ€Π΅Π· ΠΎΠ±Ρ‰ΠΈΠΉ `gc.h`). Π‘ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ gcc ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ `-fno-common` ΠΈ ругаСтся Π½Π°
+multiple definition. ΠšΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΠ΅ΠΌ с `-fcommon` (ΠΊΠ°ΠΊ Ρ€Π°Π½ΡŒΡˆΠ΅).
+
+## 7. `mysbrk`: `sbrk()` β†’ `mmap()` ← ΠΊΠ»ΡŽΡ‡Π΅Π²ΠΎΠΉ
+Hunk-Π°Π»Π»ΠΎΠΊΠ°Ρ‚ΠΎΡ€ kencc Π±Π΅Ρ€Ρ‘Ρ‚ ΠΏΠ°ΠΌΡΡ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· `mysbrk` β†’ `sbrk()`. На musl `sbrk()`
+Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ `-1` (Π½Π΅ поддСрТиваСтся совмСстно с malloc), ΠΈΠ·-Π·Π° Ρ‡Π΅Π³ΠΎ `gethunk()`
+ΠΏΠ°Π΄Π°Π» Π² Β«out of memoryΒ» β†’ `exits`, ΠΏΡ€ΠΈΡ‡Ρ‘ΠΌ диагностика ΡƒΡ…ΠΎΠ΄ΠΈΠ»Π° Π² Π½Π΅ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ
+Bio-Π±ΡƒΡ„Π΅Ρ€ ΠΈ Ρ‚Π΅Ρ€ΡΠ»Π°ΡΡŒ (компилятор ΠΌΠΎΠ»Ρ‡Π° Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠ» с ΠΊΠΎΠ΄ΠΎΠΌ 1). ЗамСняСм Ρ‚Π΅Π»ΠΎ `mysbrk`
+Π½Π° Π°Π½ΠΎΠ½ΠΈΠΌΠ½Ρ‹ΠΉ `mmap`. Π‘Π΅Π· этого ΠΏΠ°Ρ‚Ρ‡Π° компиляторы Π»ΠΈΠ½ΠΊΡƒΡŽΡ‚ΡΡ, Π½ΠΎ Π½Π΅ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΡŽΡ‚.
+
+## 8. Π”ΡƒΠ±Π»ΠΈΠΊΠ°Ρ‚ `machcap` / `omachcap`
+`cc/omachcap.c` (старый machcap) ΠΈ `Xc/machcap.c` (Π½ΠΎΠ²Ρ‹ΠΉ) ΠΎΠ±Π° ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ `machcap`.
+Π’ Ρ€ΠΎΠ΄Π½ΠΎΠΉ сборкС `omachcap.o` Π΄Ρ€Π΅ΠΌΠ»Π΅Ρ‚ Π² Π°Ρ€Ρ…ΠΈΠ²Π΅ `cc.a` ΠΈ Π½Π΅ тянСтся. Π£ нас β€” Π»ΠΈΠ½ΠΊΡƒΠ΅ΠΌ
+плоско, поэтому: Ссли Ρƒ Π°Ρ€ΠΊΠΈ Π΅ΡΡ‚ΡŒ свой `machcap.o` (6c/8c/qc) β€” Π²Ρ‹ΠΊΠΈΠ΄Ρ‹Π²Π°Π΅ΠΌ
+`omachcap.o`; Ссли Π½Π΅Ρ‚ (5c/vc/kc) β€” `omachcap.o` ΠΈ прСдоставляСт `machcap`.
+
+## 9. ПлановскиС Ρ€Π°Π½Ρ‚Π°ΠΉΠΌ-Ρ„Π°ΠΉΠ»Ρ‹ Π²ΠΎΠ½
+Π€Π°ΠΉΠ»Ρ‹ Π²Ρ€ΠΎΠ΄Π΅ `Xc/sys.c` тянут `#include "/sys/src/libc/9syscall/sys.h"` β€” это
+Ρ€Π°Π½Ρ‚Π°ΠΉΠΌ ОБ, Π½Π΅ Ρ‡Π°ΡΡ‚ΡŒ компилятора, ΠΈ Π² `OFILES` mkfile ΠΈΡ… Π½Π΅Ρ‚. Π’Ρ‹ΠΊΠΈΠ΄Ρ‹Π²Π°Π΅ΠΌ Π»ΡŽΠ±Ρ‹Π΅
+`.c` с include ΠΏΠΎ Π°Π±ΡΠΎΠ»ΡŽΡ‚Π½ΠΎΠΌΡƒ `/sys/...`.
+
+## 10. ΠΠ²Ρ‚ΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π½ΠΎΡΡ‚ΡŒ `cc/` ΠΏΡ€ΠΈ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚Π΅ ΠΈΠΌΡ‘Π½ (kc)
+Π£ `kc` завалялся собствСнный ΡƒΡΡ‚Π°Ρ€Π΅Π²ΡˆΠΈΠΉ `bits.c`, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠΉ ΡƒΠΆΠ΅ Π²Ρ‹Ρ€Π΅Π·Π°Π½Π½Ρ‹ΠΉ ΠΈΠ·
+plan9port Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ `Fconv`. ΠšΠΎΠΏΠΈΡ€ΡƒΠ΅ΠΌ `cc/`-Ρ„Π°ΠΉΠ»Ρ‹ ΠŸΠžΠ‘Π›Π• Π°Ρ€ΠΎΡ‡Π½Ρ‹Ρ…, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ±Ρ‰ΠΈΠΉ
+`cc/bits.c` (Π½ΠΎΠ²Ρ‹ΠΉ fmt API) ΠΏΠΎΠ±Π΅ΠΆΠ΄Π°Π».
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ba80bb4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,75 @@
+# plan9-kencc-linux
+
+ΠšΡ€ΠΎΡΡ-сборка **компиляторов / ассСмблСров / Π»ΠΈΠ½ΠΊΠ΅Ρ€ΠΎΠ² Plan 9 (kencc)** для всСх
+Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€ **с Linux-хоста**, плюс Π±ΠΎΠ»Π²Π°Π½ΠΎΡ‡Π½ΠΎΠ΅ **UEFI-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅** (PE32+),
+собранноС этим ΠΆΠ΅ Ρ‚ΡƒΠ»Ρ‡Π΅ΠΉΠ½ΠΎΠΌ. НичСго юниксового Π² Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅ сборки самих `.efi`.
+
+Π‘ΠΎΠ±Ρ€Π°Π½ΠΎ ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€Π΅Π½ΠΎ Π½Π° Linux/musl. Пилилось Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-Π±ΠΎΡ‚ΠΎΠΌ (Claude) ΠΏΠΎ Π·Π°ΠΊΠ°Π·Ρƒ
+Ρ‡Π°Ρ‚Π° ancap.in.ua.
+
+## Π§Ρ‚ΠΎ Π²Π½ΡƒΡ‚Ρ€ΠΈ
+```
+bin/ Π³ΠΎΡ‚ΠΎΠ²Ρ‹Π΅ Π±ΠΈΠ½Π°Ρ€ΠΈ: 8c 6c 5c vc qc kc (компиляторы) + 6a 6l
+scripts/
+ setup.sh ΠΊΠ»ΠΎΠ½ΠΈΡ€ΡƒΠ΅Ρ‚ plan9foundation + plan9port, собираСт plan9port
+ build_arch.sh <X> собираСт C-компилятор Π°Ρ€ΠΊΠΈ X (5|6|8|v|q|k)
+ build_al.sh <Xa|Xl> собираСт ассСмблСр/Π»ΠΈΠ½ΠΊΠ΅Ρ€
+ build_all.sh собираСт вСсь кросс-ΠΊΠΈΡ‚
+efi/
+ hello.c сам EFI-апп (наш код)
+ fetch_ref.sh тянСт pe64.s/efi.h/mem.h ΠΈΠ· 9legacy (nboot/efi)
+ efi_build.sh 6a+6c+6l -> dd -> bootx64.efi (PE32+)
+ mkesp.py Π·Π°Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅Ρ‚ .efi Π² Π·Π°Π³Ρ€ΡƒΠ·ΠΎΡ‡Π½Ρ‹ΠΉ ESP (FAT16)
+patches/ ΠΏΠ°Ρ‚Ρ‡ΠΈ ΠΏΠΎ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΏΡ€Π°Π²ΠΊΠ΅ (докумСнтация)
+PATCHES.md ΠΏΠΎΡ‡Π΅ΠΌΡƒ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΏΠ°Ρ‚Ρ‡ Π½ΡƒΠΆΠ΅Π½
+```
+
+## ИдСя
+Π€Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄-компилятора Plan 9 (`cc/`) + ΠΊΠΎΠ΄ΠΎΠ³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€Ρ‹ Π°Ρ€ΠΎΠΊ (`5c`,`6c`,`8c`,`vc`,`qc`,`kc`)
+ΠΏΠΈΡˆΡƒΡ‚ΡΡ Π½Π° Plan 9 C ΠΈ рассчитаны Π½Π° Ρ€ΠΎΠ΄Π½ΡƒΡŽ сборку Π² Plan 9. ΠœΡ‹ собираСм ΠΈΡ… Π½Π° Linux,
+компилируя **plan9port**-овским `9c`/`9l` (ΠΎΠ½ΠΈ Π΄Π°ΡŽΡ‚ `lib9`/`libbio`/`libmach` ΠΈ
+Π΄Ρ€ΡƒΠΆΠ°Ρ‚ с хостовым gcc/musl). Всё, Ρ‡Ρ‚ΠΎ ΠΌΠ΅ΡˆΠ°Π΅Ρ‚, лСчится нСбольшими ΠΏΠ°Ρ‚Ρ‡Π°ΠΌΠΈ (см. `PATCHES.md`).
+
+| Π°Ρ€ΠΊΠ° | ΠΊΠΎΠΌΠΏ | ассСмблСр | Π»ΠΈΠ½ΠΊΠ΅Ρ€ |
+|------|------|-----------|--------|
+| 386 | 8c | 8a | 8l |
+| amd64 | 6c | 6a | 6l |
+| arm | 5c | 5a | 5l |
+| mips | vc | va | vl |
+| power | qc | qa | ql |
+| sparc | kc | ka | kl |
+
+## Быстрый старт
+```sh
+# 1. зависимости (plan9foundation + plan9port)
+bash scripts/setup.sh
+export PLAN9SRC=$PWD/deps/plan9foundation
+export PLAN9PORT=$PWD/deps/plan9port
+# (ΠΎΠΏΡ†. musl: export MUSL_ENV=/path/to/env.sh)
+
+# 2. ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ всё
+bash scripts/build_all.sh # -> build/*/{6c,6a,6l,...}
+
+# 3. ΠΎΠ΄ΠΈΠ½ компилятор
+bash scripts/build_arch.sh 6 # -> build/6c/6c
+
+# 4. ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ
+echo 'int f(void){return 42;}' > t.c
+build/6c/6c t.c && ls t.6 # ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΈΠΊ Plan9 .6
+```
+
+## EFI-Π±ΠΎΠ»Π²Π°Π½ΠΊΠ°
+```sh
+cd efi
+./fetch_ref.sh # pe64.s/efi.h/mem.h ΠΈΠ· 9legacy
+PLAN9SRC=$PWD/../deps/plan9foundation ./efi_build.sh
+# -> bootx64.efi : PE32+ x64 EFI_APPLICATION
+python3 mkesp.py bootx64.efi esp.img # -> Π·Π°Π³Ρ€ΡƒΠ·ΠΎΡ‡Π½Ρ‹ΠΉ ESP (/EFI/BOOT/BOOTX64.EFI)
+# запуск: qemu-system-x86_64 -bios OVMF.fd -drive format=raw,file=esp.img
+```
+
+## Π“ΠΎΡ‚ΠΎΠ²Ρ‹Π΅ Π±ΠΈΠ½Π°Ρ€ΠΈ
+Π’ `bin/` Π»Π΅ΠΆΠ°Ρ‚ ΡƒΠΆΠ΅ собранныС компиляторы/асм/Π»ΠΈΠ½ΠΊΠ΅Ρ€ (Linux/musl x86_64).
+Под свой хост пСрСсобСри скриптами β€” Π±Π°ΠΉΡ‚-Π²-Π±Π°ΠΉΡ‚ воспроизводимо.
+
+Π›ΠΈΡ†Π΅Π½Π·ΠΈΠΈ ΠΈ авторство исходников β€” см. `NOTICE`.
diff --git a/bin/5c b/bin/5c
new file mode 100755
index 0000000..c1e6fcf
--- /dev/null
+++ b/bin/5c
Binary files differ
diff --git a/bin/6a b/bin/6a
new file mode 100755
index 0000000..122bd1d
--- /dev/null
+++ b/bin/6a
Binary files differ
diff --git a/bin/6c b/bin/6c
new file mode 100755
index 0000000..dfa9c13
--- /dev/null
+++ b/bin/6c
Binary files differ
diff --git a/bin/6l b/bin/6l
new file mode 100755
index 0000000..ee75a69
--- /dev/null
+++ b/bin/6l
Binary files differ
diff --git a/bin/8c b/bin/8c
new file mode 100755
index 0000000..c178f5f
--- /dev/null
+++ b/bin/8c
Binary files differ
diff --git a/bin/kc b/bin/kc
new file mode 100755
index 0000000..1e44e92
--- /dev/null
+++ b/bin/kc
Binary files differ
diff --git a/bin/qc b/bin/qc
new file mode 100755
index 0000000..8980901
--- /dev/null
+++ b/bin/qc
Binary files differ
diff --git a/bin/vc b/bin/vc
new file mode 100755
index 0000000..574f14c
--- /dev/null
+++ b/bin/vc
Binary files differ
diff --git a/efi/README.md b/efi/README.md
new file mode 100644
index 0000000..fa1cdd1
--- /dev/null
+++ b/efi/README.md
@@ -0,0 +1,35 @@
+# efi β€” Π±ΠΎΠ»Π²Π°Π½ΠΎΡ‡Π½Ρ‹ΠΉ UEFI-Π°ΠΏΠΏ Π½Π° ΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠΌ Ρ‚ΡƒΠ»Ρ‡Π΅ΠΉΠ½Π΅ Plan 9
+
+МинимальноС `bootx64.efi` (amd64, Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ **PE32+**), собранноС **Ρ‚ΠΎΠ»ΡŒΠΊΠΎ**
+ΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΌΠΈ Plan 9 kencc `6a`/`6c`/`6l` β€” Π±Π΅Π· ΡŽΠ½ΠΈΠΊΡΠΎΠ²Ρ‹Ρ… компиляторов/Π»ΠΈΠ½ΠΊΠ΅Ρ€ΠΎΠ².
+
+## Π¦Π΅ΠΏΠΎΡ‡ΠΊΠ°
+| шаг | ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π° | Ρ‡Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚ |
+|-----|---------|-----------|
+| 1 | **6a** | ассСмблируСт `pe64min.s` β€” DOS/PE32+ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ + entry + `eficall` |
+| 2 | **6c** | ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΠ΅Ρ‚ `hello.c` (плановскиС `<u.h>` ΠΈ Ρ‚.Π΄.) |
+| 3 | **6l** | Π»ΠΈΠ½ΠΊΡƒΠ΅Ρ‚ свободностоящий ΠΎΠ±Ρ€Π°Π· ΠΏΠΎ `-T0x8000` |
+| 4 | `dd skip=40` | срСзаСт 40-Π±Π°ΠΉΡ‚Π½Ρ‹ΠΉ plan9 a.out Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ β†’ ΠΎΠ±Π½Π°ΠΆΠ°Π΅Ρ‚ PE32+ |
+
+`pe64.s` ΠΊΠ»Π°Π΄Ρ‘Ρ‚ DOS+PE32+ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ ΠΏΠ΅Ρ€Π²Ρ‹ΠΌΠΈ Π² тСкст-сСгмСнт; Π»ΠΈΠ½ΠΊΠ΅Ρ€ раскладываСт
+ΠΎΠ±Ρ€Π°Π· ΠΎΡ‚ `IMAGEBASE`, Π° `dd` срСзаСт плановский Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ β€” остаётся чистый PE,
+ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠ° Π³Ρ€ΡƒΠ·ΠΈΡ‚ ΠΈΠ· `/EFI/BOOT/BOOTX64.EFI`.
+
+## Π‘Π±ΠΎΡ€ΠΊΠ°
+```sh
+./fetch_ref.sh # pe64.s/efi.h/mem.h ΠΈΠ· 9legacy
+PLAN9SRC=.../plan9foundation ./efi_build.sh # -> bootx64.efi
+python3 mkesp.py bootx64.efi esp.img # -> Π·Π°Π³Ρ€ΡƒΠ·ΠΎΡ‡Π½Ρ‹ΠΉ ESP (FAT16)
+qemu-system-x86_64 -bios OVMF.fd -drive format=raw,file=esp.img
+```
+
+## Π§Ρ‚ΠΎ своё, Ρ‡Ρ‚ΠΎ рСфСрСнс
+* `hello.c`, `efi_build.sh`, `mkesp.py`, `fetch_ref.sh` β€” наш ΠΊΠΎΠ΄.
+* `pe64.s`, `efi.h`, `mem.h` β€” ΠΈΠ· 9legacy `nboot/efi` (тянутся, Π½Π΅ хранятся).
+ Для Π±ΠΎΠ»Π²Π°Π½ΠΊΠΈ ΠΎΡ‚ `pe64.s` Π±Π΅Ρ€Ρ‘ΠΌ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ+entry+`eficall` (`head -162`);
+ ΠΌΠ°ΡˆΠΈΠ½Π΅Ρ€ΠΈΡŽ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ядра (`jump`/`_warp32`/`_gdt`) отбрасываСм β€” Π΅ΠΉ Ρ‚ΡƒΡ‚ Π½Π΅Ρ‡Π΅Π³ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ.
+
+## ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°
+`MZ` + `PE\0\0` + Machine `0x8664` + Magic `0x20B` (PE32+) + Subsystem `10`
+(EFI_APPLICATION). `mkesp.py` Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ сам ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΡ‚ FAT ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ ΠΈ свСряСт
+`/EFI/BOOT/BOOTX64.EFI` Π±Π°ΠΉΡ‚-Π²-Π±Π°ΠΉΡ‚ с исходным `.efi`.
diff --git a/efi/efi_build.sh b/efi/efi_build.sh
new file mode 100644
index 0000000..51f0ff9
--- /dev/null
+++ b/efi/efi_build.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Π‘ΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚ Π±ΠΎΠ»Π²Π°Π½ΠΎΡ‡Π½Ρ‹ΠΉ bootx64.efi (PE32+) ΠŸΠžΠ Π’Π˜Π ΠžΠ’ΠΠΠΠ«Πœ Ρ‚ΡƒΠ»Ρ‡Π΅ΠΉΠ½ΠΎΠΌ 6a/6c/6l.
+# ΠŸΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ: ./fetch_ref.sh (достаёт pe64.s/efi.h/mem.h ΠΈΠ· 9legacy).
+# Π’Ρ€Π΅Π±ΡƒΠ΅Ρ‚: BINDIR с 6a/6c/6l (ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡. ../bin) ΠΈ PLAN9SRC (плановскиС include).
+set -e
+cd "$(dirname "$0")"
+BINDIR="${BINDIR:-$PWD/../bin}"
+: "${PLAN9SRC:?export PLAN9SRC β€” Π½ΡƒΠΆΠ½Ρ‹ плановскиС include (amd64/include, sys/include)}"
+IMAGEBASE=0x8000
+export objtype=amd64
+
+[ -f pe64.s ] || { echo "Π½Π΅Ρ‚ pe64.s β€” сначала ./fetch_ref.sh"; exit 1; }
+# ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ pe64: MZ+PE Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ + entry + eficall (Π±Π΅Π· Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊΠ° ядра)
+head -162 pe64.s > pe64min.s
+
+rm -f *.6 *.out bootx64.efi
+echo "1) 6a pe64min.s"; "$BINDIR/6a" -DIMAGEBASE=$IMAGEBASE pe64min.s
+echo "2) 6c hello.c"; "$BINDIR/6c" -I"$PLAN9SRC/amd64/include" -I"$PLAN9SRC/sys/include" hello.c
+echo "3) 6l link"; "$BINDIR/6l" -l -s -R1 -T$IMAGEBASE -o bootx64.out pe64min.6 hello.6
+echo "4) dd strip 40b (plan9 a.out header) -> PE32+"
+dd if=bootx64.out bs=1 skip=40 of=bootx64.efi 2>/dev/null
+
+echo "bootx64.efi: $(ls -la bootx64.efi | awk '{print $5}') Π±Π°ΠΉΡ‚"
+python3 - <<'PY'
+d=open('bootx64.efi','rb').read(); po=int.from_bytes(d[0x3c:0x40],'little'); o=po+24
+ok = d[:2]==b'MZ' and d[po:po+4]==b'PE\x00\x00' \
+ and int.from_bytes(d[po+4:po+6],'little')==0x8664 \
+ and int.from_bytes(d[o:o+2],'little')==0x20b \
+ and int.from_bytes(d[o+68:o+70],'little')==10
+print("PE32+ x64 EFI_APPLICATION:", "OK" if ok else "BAD")
+PY
+echo "ESP-ΠΎΠ±Ρ€Π°Π·: python3 mkesp.py bootx64.efi esp.img"
diff --git a/efi/fetch_ref.sh b/efi/fetch_ref.sh
new file mode 100644
index 0000000..67b726b
--- /dev/null
+++ b/efi/fetch_ref.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# ВянСт ΠΈΠ· 9legacy рСфСрСнсный EFI-Π·Π°Π³Ρ€ΡƒΠ·Ρ‡ΠΈΠΊ (nboot/efi) ΠΈ достаёт ΠΈΠ· Π½Π΅Π³ΠΎ
+# pe64.s (PE32+ ΠΎΠ±Ρ‘Ρ€Ρ‚ΠΊΠ°), efi.h ΠΈ mem.h. Π­Ρ‚ΠΎ НЕ наш ΠΊΠΎΠ΄ β€” это Plan9/9legacy,
+# поэтому ΠΊΠ°Ρ‡Π°Π΅ΠΌ, Π° Π½Π΅ Ρ…Ρ€Π°Π½ΠΈΠΌ Π² Ρ€Π΅ΠΏΠ΅. Наш ΠΊΠΎΠ΄ β€” hello.c/efi_build.sh/mkesp.py.
+set -e
+cd "$(dirname "$0")"
+echo ">> ΠΊΠ°Ρ‡Π°ΡŽ 9legacy nboot.diff ..."
+python3 -c "import urllib.request; urllib.request.urlretrieve('http://9legacy.org/9legacy/patch/nboot.diff','nboot.diff')"
+python3 - <<'PY'
+import re
+d=open('nboot.diff').read().splitlines()
+want={'pe64.s','efi.h','mem.h'}; cur=None; buf=[]; out={}
+for l in d:
+ m=re.match(r'^\+\+\+ .*/nboot/efi/(\S+)', l)
+ if m:
+ if cur: out[cur]='\n'.join(buf)
+ cur=m.group(1) if m.group(1) in want else None; buf=[]; continue
+ if cur is not None:
+ if l.startswith('--- '): out[cur]='\n'.join(buf); cur=None; continue
+ if l.startswith('+'): buf.append(l[1:])
+if cur: out[cur]='\n'.join(buf)
+for k,v in sorted(out.items()): open(k,'w').write(v); print(' ΠΈΠ·Π²Π»Ρ‘ΠΊ', k, f'({len(v.splitlines())} строк)')
+PY
+echo ">> Π³ΠΎΡ‚ΠΎΠ²ΠΎ: pe64.s efi.h mem.h (рСфСрСнс 9legacy)"
diff --git a/efi/hello.c b/efi/hello.c
new file mode 100644
index 0000000..35cd86d
--- /dev/null
+++ b/efi/hello.c
@@ -0,0 +1,52 @@
+/*
+ * Π‘ΠΎΠ»Π²Π°Π½ΠΎΡ‡Π½Ρ‹ΠΉ EFI-Π°ΠΏΠΏ для amd64 (bootx64.efi), PE32+.
+ * БобираСтся ΠŸΠžΠ Π’Π˜Π ΠžΠ’ΠΠΠΠ«Πœ Ρ‚ΡƒΠ»Ρ‡Π΅ΠΉΠ½ΠΎΠΌ Plan9 (6c/6a/6l) Π½Π° Linux/musl:
+ * PE-Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ ΠΈ entry -> pe64.s (ассСмблСр 6a), ΠΈΠ· 9legacy nboot/efi.
+ * ΠŸΠ΅Ρ‡Π°Ρ‚ΡŒ -> UEFI SIMPLE_TEXT_OUTPUT_PROTOCOL (efi.h ΠΈΠ· 9legacy).
+ * ΠšΠΎΠ½Ρ‚Ρ€Π°ΠΊΡ‚ Π²Ρ…ΠΎΠ΄Π° Π·Π°Π΄Π°Ρ‘Ρ‚ pe64.s: reloc ΠΊΠ»Π°Π΄Ρ‘Ρ‚ SystemTable, ΠΏΡ€Ρ‹Π³Π°Π΅Ρ‚ Π½Π° efimain(ih, st).
+ */
+#include <u.h>
+#include "efi.h"
+
+/* Π³Π»ΠΎΠ±Π°Π»Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΆΠ΄Ρ‘Ρ‚ ΠΊΠΎΠ½Ρ‚Ρ€Π°ΠΊΡ‚ (ΠΊΠ°ΠΊ Π² рСфСрСнсном efi.c) */
+EFI_HANDLE IH;
+EFI_SYSTEM_TABLE *ST;
+
+/* Π²Ρ‹Π·ΠΎΠ² EFI-Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΠΎ MS-x64 ABI β€” Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ Π² pe64.s */
+extern uintptr eficall(void *fn, ...);
+
+/* ΠΏΠ΅Ρ‡Π°Ρ‚ΡŒ ASCII-строки Ρ‡Π΅Ρ€Π΅Π· ConOut (ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ Π² UTF-16, \n -> \r\n) */
+static void
+eputs(char *s)
+{
+ CHAR16 w[2];
+
+ w[1] = 0;
+ for(; *s; s++){
+ if(*s == '\n'){
+ w[0] = '\r';
+ eficall(ST->ConOut->OutputString, ST->ConOut, w);
+ }
+ w[0] = (uchar)*s;
+ eficall(ST->ConOut->OutputString, ST->ConOut, w);
+ }
+}
+
+void
+efimain(EFI_HANDLE ih, EFI_SYSTEM_TABLE *st)
+{
+ IH = ih;
+ ST = st;
+
+ eputs("\n");
+ eputs("+--------------------------------------------------+\n");
+ eputs("| Hello from a Plan 9 kencc EFI application |\n");
+ eputs("| compiler/assembler/linker: 6c / 6a / 6l |\n");
+ eputs("| cross-built on Linux/musl, wrapped as PE32+ |\n");
+ eputs("+--------------------------------------------------+\n");
+ eputs("\nefimain reached OK. Idling via BootServices->Stall.\n");
+
+ /* Π±ΠΎΠ»Π²Π°Π½ΠΊΠ°: просто крутимся, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠ° Π½Π΅ считала нас ΡƒΠΏΠ°Π²ΡˆΠΈΠΌΠΈ */
+ for(;;)
+ eficall(ST->BootServices->Stall, (UINTN)1000000);
+}
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")
diff --git a/scripts/build_al.sh b/scripts/build_al.sh
new file mode 100644
index 0000000..750f9e0
--- /dev/null
+++ b/scripts/build_al.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+# Π‘ΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚ Plan9 ассСмблСр (Xa) ΠΈΠ»ΠΈ Π»ΠΈΠ½ΠΊΠ΅Ρ€ (Xl) Π½Π° Linux-хостС.
+# ИспользованиС: PLAN9SRC=... PLAN9PORT=... build_al.sh 6a | build_al.sh 6l
+set -e
+T="$1"; [ -z "$T" ] && { echo "usage: $0 <Π½Π°ΠΏΡ€. 6a|6l|8a|8l>"; exit 1; }
+X="${T:0:1}"; K="${T:1:1}"
+
+: "${PLAN9SRC:?ΡƒΠΊΠ°ΠΆΠΈ PLAN9SRC}"; : "${PLAN9PORT:?ΡƒΠΊΠ°ΠΆΠΈ PLAN9PORT}"
+[ -n "$MUSL_ENV" ] && . "$MUSL_ENV"
+export PLAN9="$PLAN9PORT"; export PATH="$PLAN9/bin:$PATH"
+SRC="$PLAN9SRC/sys/src/cmd"
+OUT="${OUT:-$PWD/build}"; B="$OUT/$T"
+
+rm -rf "$B"; mkdir -p "$B"; cd "$B"
+cp "$SRC/$T"/* "$B"/ 2>/dev/null || true
+cp "$SRC/${X}c"/*.h "$B"/ 2>/dev/null || true # X.out.h
+cp "$SRC"/cc/compat "$SRC"/cc/macbody "$SRC"/cc/lexbody "$SRC"/cc/cc.h "$B"/ 2>/dev/null || true
+if [ "$K" = "l" ]; then # Π»ΠΈΠ½ΠΊΠ΅Ρ€Ρƒ: ΠΈΠΌΠ΅Π½Π° ΠΎΠΏΠΊΠΎΠ΄ΠΎΠ² + ΠΎΠ±Ρ‰ΠΈΠΉ ELF-Π²Ρ‹Π²ΠΎΠ΄
+ cp "$SRC/${X}c"/enam.c "$B"/ 2>/dev/null || true
+ cp "$SRC"/8l/elf.c "$SRC"/8l/elf.h "$B"/ 2>/dev/null || true
+fi
+
+# ---- ΠΏΠ°Ρ‚Ρ‡ΠΈ (Ρ‚Π΅ ΠΆΠ΅, Ρ‡Ρ‚ΠΎ ΠΈ для компиляторов) ----
+for c in *.c; do grep -qE '#include[ \t]*[<"]/sys/' "$c" 2>/dev/null && { echo " пропуск: $c"; rm -f "$c"; }; done
+sed -i 's|"\.\./[a-zA-Z0-9]*/|"|g' *.c *.h 2>/dev/null || true
+sed -i -E 's/\bround\b/p9round/g; s/\blog2\b/p9log2/g' *.c *.h compat macbody lexbody 2>/dev/null || true
+python3 - <<'PY'
+import glob,re
+pat=re.compile(r'\{\s*return\s+sbrk\s*\(\s*(\w+)\s*\)\s*;\s*\}')
+mm='''{
+\tvoid *p;
+\tp = mmap(0, %s, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+\tif(p == MAP_FAILED) return (void*)-1;
+\treturn p;
+}'''
+for f in glob.glob('*')+['compat']:
+ try: s=open(f).read()
+ except: continue
+ if 'sbrk(' in s and 'mmap' not in s:
+ m=pat.search(s)
+ if m:
+ s2=pat.sub(mm%m.group(1), s, count=1)
+ if '#include <sys/mman.h>' not in s2: s2='#include <sys/mman.h>\n'+s2
+ open(f,'w').write(s2); print(" mmap-ΠΏΠ°Ρ‚Ρ‡:",f)
+PY
+[ -f a.y ] && { yacc -d a.y; sed -i -E 's/\bround\b/p9round/g; s/\blog2\b/p9log2/g' y.tab.c 2>/dev/null || true; }
+
+ok=0; fail=0; errf=""; rm -f *.o
+for f in *.c; do
+ if 9c -fcommon -I. "$f" >/tmp/al_$$ 2>&1; then ok=$((ok+1)); else fail=$((fail+1)); [ -z "$errf" ] && errf="$f" && cp /tmp/al_$$ /tmp/alf_$$; fi
+done
+echo "[$T] компиляция: OK=$ok FAIL=$fail"
+[ "$fail" != 0 ] && { echo "пСрвая ошибка ($errf):"; head -10 /tmp/alf_$$; exit 2; }
+
+if [ "$K" = "l" ]; then EXTRA="-lmach"; else EXTRA=""; fi # Π»ΠΈΠ½ΠΊΠ΅Ρ€Ρƒ Π½ΡƒΠΆΠ΅Π½ libmach
+9l -o "$T" *.o $EXTRA
+echo "[$T] Π±ΠΈΠ½Π°Ρ€ΡŒ: $(ls -la $T | awk '{print $5}') Π±Π°ΠΉΡ‚ -> $B/$T"
diff --git a/scripts/build_all.sh b/scripts/build_all.sh
new file mode 100644
index 0000000..7f058aa
--- /dev/null
+++ b/scripts/build_all.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Π‘ΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚ Π’Π•Π‘Π¬ кросс-ΠΊΠΈΡ‚: C-компиляторы + ассСмблСры + Π»ΠΈΠ½ΠΊΠ΅Ρ€Ρ‹ всСх Π°Ρ€ΠΎΠΊ.
+# Π’Ρ€Π΅Π±ΡƒΠ΅Ρ‚ экспортированных PLAN9SRC ΠΈ PLAN9PORT (см. setup.sh).
+set -e
+here="$(cd "$(dirname "$0")" && pwd)"
+: "${PLAN9SRC:?export PLAN9SRC (см. scripts/setup.sh)}"
+: "${PLAN9PORT:?export PLAN9PORT (см. scripts/setup.sh)}"
+export OUT="${OUT:-$PWD/build}"
+
+echo "=== C-компиляторы ==="
+for X in 5 6 8 v q k; do bash "$here/build_arch.sh" $X; done
+echo "=== ассСмблСры ==="
+for X in 5 6 8 v q k; do bash "$here/build_al.sh" ${X}a || echo " (${X}a β€” ΠΏΡ€ΠΎΠΏΡƒΡ‰Π΅Π½/ошибка)"; done
+echo "=== Π»ΠΈΠ½ΠΊΠ΅Ρ€Ρ‹ ==="
+for X in 5 6 8 v q k; do bash "$here/build_al.sh" ${X}l || echo " (${X}l β€” ΠΏΡ€ΠΎΠΏΡƒΡ‰Π΅Π½/ошибка)"; done
+
+echo
+echo "=== собранныС Π±ΠΈΠ½Π°Ρ€ΠΈ ($OUT) ==="
+find "$OUT" -maxdepth 2 -type f -perm -u+x \( -name '[0-9kvq][cal]' \) -printf '%f %s Π±Π°ΠΉΡ‚\n' 2>/dev/null | sort
diff --git a/scripts/build_arch.sh b/scripts/build_arch.sh
new file mode 100644
index 0000000..3cdc4fb
--- /dev/null
+++ b/scripts/build_arch.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+# Π‘ΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚ Plan9 kencc C-компилятор для Π°Ρ€ΠΊΠΈ X (5,6,8,v,q,k) Π½Π° Linux-хостС.
+# ИспользованиС: PLAN9SRC=.../plan9foundation PLAN9PORT=.../plan9port build_arch.sh 6
+# ΠžΠΏΡ†.: MUSL_ENV=.../env.sh (Π°ΠΊΡ‚ΠΈΠ²Π°Ρ‚ΠΎΡ€ musl-Ρ‚ΡƒΠ»Ρ‡Π΅ΠΉΠ½Π°), OUT=ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ сборки.
+set -e
+X="$1"; [ -z "$X" ] && { echo "usage: $0 <arch: 5|6|8|v|q|k>"; exit 1; }
+A="${X}c"
+
+: "${PLAN9SRC:?ΡƒΠΊΠ°ΠΆΠΈ PLAN9SRC β€” Π΄Π΅Ρ€Π΅Π²ΠΎ исходников plan9 (plan9foundation)}"
+: "${PLAN9PORT:?ΡƒΠΊΠ°ΠΆΠΈ PLAN9PORT β€” собранный plan9port (bin/9c,9l,9ar,yacc + lib/)}"
+[ -n "$MUSL_ENV" ] && . "$MUSL_ENV"
+export PLAN9="$PLAN9PORT"; export PATH="$PLAN9/bin:$PATH"
+SRC="$PLAN9SRC/sys/src/cmd"
+OUT="${OUT:-$PWD/build}"
+B="$OUT/$A"
+
+rm -rf "$B"; mkdir -p "$B"; cd "$B"
+# ΠΊΠΎΠ΄ΠΎΠ³Π΅Π½ Π°Ρ€ΠΊΠΈ БНАЧАЛА, ΠΏΠΎΡ‚ΠΎΠΌ Ρ„Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄ cc/ β€” cc/ Π°Π²Ρ‚ΠΎΡ€ΠΈΡ‚Π΅Ρ‚Π΅Π½ ΠΏΡ€ΠΈ совпадСнии ΠΈΠΌΡ‘Π½
+# (Ρƒ kc свой ΡƒΡΡ‚Π°Ρ€Π΅Π²ΡˆΠΈΠΉ bits.c с Fconv β€” Π±Π΅Ρ€Ρ‘ΠΌ cc/bits.c)
+cp "$SRC/$A"/*.c "$SRC/$A"/*.h "$B"/
+cp "$SRC"/cc/*.c "$SRC"/cc/*.h "$B"/
+cp "$SRC"/cc/compat "$SRC"/cc/macbody "$SRC"/cc/lexbody "$B"/ 2>/dev/null || true
+
+# ---- ПАВЧИ ΠΏΠΎΠ΄ линукс-хост ----
+# 0) Π²Ρ‹ΠΊΠΈΠ½ΡƒΡ‚ΡŒ плановскиС Ρ€Π°Π½Ρ‚Π°ΠΉΠΌ-Ρ„Π°ΠΉΠ»Ρ‹ (тянут /sys/... Ρ…Π΅Π΄Π΅Ρ€Ρ‹, Π½Π΅ Ρ‡Π°ΡΡ‚ΡŒ компилятора)
+for c in *.c; do grep -qE '#include[ \t]*[<"]/sys/' "$c" 2>/dev/null && { echo " пропуск Ρ€Π°Π½Ρ‚Π°ΠΉΠΌ: $c"; rm -f "$c"; }; done
+# 1) плоская раскладка: ΡƒΠ±Ρ€Π°Ρ‚ΡŒ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ../cc/ ../Xc/
+sed -i "s|\"\.\./cc/|\"|g; s|\"\.\./${A}/|\"|g" *.c *.h 2>/dev/null || true
+# 2) round/log2 ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΡƒΡŽΡ‚ с musl math.h -> p9round/p9log2
+sed -i -E 's/\bround\b/p9round/g; s/\blog2\b/p9log2/g' *.c *.h compat macbody lexbody 2>/dev/null || true
+# 3) Runemask Π½Π΅Ρ‚ Π² plan9port
+grep -q 'define Runemask' lex.c || sed -i '/#include[ \t]*"y.tab.h"/a #ifndef Runemask\n#define Runemask 0x1FFFFF\n#endif' lex.c
+# 3b) ΠΏΡ€ΠΎΡ‚ΠΎΡ‚ΠΈΠΏ swcmp -> const (musl qsort-ΠΊΠΎΠΌΠΏΠ°Ρ€Π°Ρ‚ΠΎΡ€)
+sed -i 's/swcmp(void\*, *void\*)/swcmp(const void*, const void*)/' gc.h *.h 2>/dev/null || true
+# 4) mysbrk: sbrk() Π½Π° musl ΠΎΡ‚Π΄Π°Ρ‘Ρ‚ -1 -> mmap
+python3 - "$B/compat" <<'PY'
+import sys
+p=sys.argv[1]; s=open(p).read()
+old='void*\nmysbrk(ulong size)\n{\n\treturn sbrk(size);\n}'
+new='''#include <sys/mman.h>
+void*
+mysbrk(ulong size)
+{
+\tvoid *p;
+\tp = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+\tif(p == MAP_FAILED) return (void*)-1;
+\treturn p;
+}'''
+if old in s: open(p,'w').write(s.replace(old,new)); print(" mmap-ΠΏΠ°Ρ‚Ρ‡: ΠΎΠΊ")
+else: print(" mmap-ΠΏΠ°Ρ‚Ρ‡: ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½")
+PY
+
+# ---- yacc: cc.y -> y.tab.c / y.tab.h ----
+yacc -d cc.y 2>/dev/null || yacc -d "$SRC/cc/cc.y"
+sed -i -E 's/\bround\b/p9round/g; s/\blog2\b/p9log2/g' y.tab.c 2>/dev/null || true
+
+# ---- компиляция (-fcommon: tentative-Π³Π»ΠΎΠ±Π°Π»Ρ‹ ΠΏΠΎΠ΄ gcc -fno-common) ----
+ok=0; fail=0; errf=""; rm -f *.o
+for f in *.c; do
+ if 9c -fcommon -I. "$f" >/tmp/ba_$$ 2>&1; then ok=$((ok+1)); else fail=$((fail+1)); [ -z "$errf" ] && errf="$f" && cp /tmp/ba_$$ /tmp/baf_$$; fi
+done
+echo "[$A] компиляция: OK=$ok FAIL=$fail"
+[ "$fail" != 0 ] && { echo "пСрвая ошибка ($errf):"; head -8 /tmp/baf_$$; exit 2; }
+
+# ---- Π»ΠΈΠ½ΠΊΠΎΠ²ΠΊΠ°: свой machcap.o -> Π²Ρ‹ΠΊΠΈΠ½ΡƒΡ‚ΡŒ omachcap.o; ΠΈΠ½Π°Ρ‡Π΅ omachcap ΠΈ Π΅ΡΡ‚ΡŒ machcap ----
+if [ -f machcap.o ]; then LINK=$(ls *.o | grep -v '^omachcap.o$'); else LINK=$(ls *.o); fi
+9l -o "$A" $LINK
+echo "[$A] Π±ΠΈΠ½Π°Ρ€ΡŒ: $(ls -la $A | awk '{print $5}') Π±Π°ΠΉΡ‚ -> $B/$A"
diff --git a/scripts/setup.sh b/scripts/setup.sh
new file mode 100644
index 0000000..2d693f0
--- /dev/null
+++ b/scripts/setup.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Π“ΠΎΡ‚ΠΎΠ²ΠΈΡ‚ зависимости для сборки Ρ‚ΡƒΠ»Ρ‡Π΅ΠΉΠ½Π°: исходники plan9 + собранный plan9port.
+# ВрСбуСтся: git, gcc/clang, make, yacc (ΠΈΠ»ΠΈ plan9port-овский). ΠšΠ°Ρ‚Π°Π»ΠΎΠ³ΠΈ кладутся
+# рядом со скриптом (ΠΈΠ»ΠΈ Π² $DEPS). ПослС β€” экспортни PLAN9SRC/PLAN9PORT (ΠΏΠ΅Ρ‡Π°Ρ‚Π°Π΅Ρ‚ Π² ΠΊΠΎΠ½Ρ†Π΅).
+set -e
+DEPS="${DEPS:-$PWD/deps}"
+mkdir -p "$DEPS"; cd "$DEPS"
+
+# 1) Π΄Π΅Ρ€Π΅Π²ΠΎ исходников plan9 (plan9foundation β€” Ρ‚ΡƒΡ‚ ΠΆΠΈΠ²ΡƒΡ‚ cc/ ΠΈ Xc/Xa/Xl)
+if [ ! -d plan9foundation ]; then
+ echo ">> ΠΊΠ»ΠΎΠ½ΠΈΡ€ΡƒΡŽ plan9foundation ..."
+ git clone --depth 1 https://github.com/plan9foundation/plan9.git plan9foundation \
+ || git clone --depth 1 https://git.9front.org/plan9front/plan9front plan9foundation
+fi
+
+# 2) plan9port (Π΄Π°Ρ‘Ρ‚ 9c/9l/9ar/yacc + lib9/libbio/libmach β€” ΠΈΠΌΠΈ ΠΈ собираСм kencc)
+if [ ! -d plan9port ]; then
+ echo ">> ΠΊΠ»ΠΎΠ½ΠΈΡ€ΡƒΡŽ plan9port ..."
+ git clone --depth 1 https://github.com/9fans/plan9port.git plan9port
+fi
+if [ ! -x plan9port/bin/9c ]; then
+ echo ">> ΡΠΎΠ±ΠΈΡ€Π°ΡŽ plan9port (ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°Π½ΡΡ‚ΡŒ ΠΏΠ°Ρ€Ρƒ ΠΌΠΈΠ½ΡƒΡ‚) ..."
+ ( cd plan9port && ./INSTALL -b ) # -b: Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ, Π±Π΅Π· установки Π² систСму
+fi
+
+echo
+echo "Π“ΠΎΡ‚ΠΎΠ²ΠΎ. Экспортни:"
+echo " export PLAN9SRC=$DEPS/plan9foundation"
+echo " export PLAN9PORT=$DEPS/plan9port"
+echo " # Ссли ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΡˆΡŒ musl-Ρ‚ΡƒΠ»Ρ‡Π΅ΠΉΠ½: export MUSL_ENV=/path/to/env.sh"