summaryrefslogtreecommitdiff
path: root/kernel/loader.c
diff options
context:
space:
mode:
authorclaude <[email protected]>2026-07-12 01:31:26 +0000
committerclaude <[email protected]>2026-07-12 01:31:26 +0000
commitc480e76433f9bb8ce8ce9d5802cdada8883db184 (patch)
treef84928e5a12c234ec44e899198dca9a41d02170b /kernel/loader.c
parenta4dce7f4d920e492d38c32ad3e42efdcfef3b3f1 (diff)
downloadplan9-kencc-linux-c480e76433f9bb8ce8ce9d5802cdada8883db184.tar.gz
plan9-kencc-linux-c480e76433f9bb8ce8ce9d5802cdada8883db184.zip
🌭 kernel/: болваночное ядро (пишет в 0xB8000) + загрузчик Plan9 a.out
- kernel.c + kern.s: 386-ядро, пишет строку в VGA-текстбуфер 0xB8000, halt. Собирается 8a+8c+8l в Plan9 a.out (I_MAGIC, entry 0x100000). - loader.c: загрузчик a.out (не ELF — выхлоп у нас a.out): разбор big-endian заголовка, загрузка сегментов по entry, зануление bss, прыжок. - проверено: kernel = валидный a.out с 0xB8000 в коде; loader.aout_parse корректно разбирает реальное ядро (entry/размеры сходятся). - bin/: добавлены 8a, 8l (386 ассемблер + линкер). Co-Authored-By: Claude Opus 4.8 <[email protected]>
Diffstat (limited to 'kernel/loader.c')
-rw-r--r--kernel/loader.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/kernel/loader.c b/kernel/loader.c
new file mode 100644
index 0000000..0246628
--- /dev/null
+++ b/kernel/loader.c
@@ -0,0 +1,63 @@
+/*
+ * Загрузчик ядра в формате Plan9 a.out (386, I_MAGIC).
+ * Чистый C без хедеров: собирается и нашим 8c (часть a.out-тулчейна),
+ * и хостовым gcc (тест разбора заголовка). "Выхлоп у нас в а.аут" —
+ * поэтому разбираем именно Plan9 a.out, а не ELF.
+ */
+typedef unsigned int u32; /* 4 байта и на 386, и на x86_64 */
+typedef unsigned char u8;
+
+typedef struct Exec {
+ u32 magic, text, data, bss, syms, entry, spsz, pcsz;
+} Exec;
+
+#define I_MAGIC 0x1EB /* intel 386 = _MAGIC(0,11) */
+#define HDRSZ 32 /* 8 x 4 байта, big-endian */
+
+static u32
+be32(u8 *p) /* заголовок Plan9 a.out хранится big-endian */
+{
+ return ((u32)p[0]<<24) | ((u32)p[1]<<16) | ((u32)p[2]<<8) | (u32)p[3];
+}
+
+/* разбор заголовка. 0 = ок (это наш 386 a.out), заполняет e. */
+int
+aout_parse(u8 *img, Exec *e)
+{
+ e->magic = be32(img+0); e->text = be32(img+4);
+ e->data = be32(img+8); e->bss = be32(img+12);
+ e->syms = be32(img+16); e->entry= be32(img+20);
+ e->spsz = be32(img+24); e->pcsz = be32(img+28);
+ return e->magic == I_MAGIC ? 0 : -1;
+}
+
+/* загрузить сегменты [text][data] по адресу линковки и обнулить bss;
+ * вернуть адрес входа. freestanding — пишет по абсолютному адресу. */
+void *
+aout_load(u8 *img)
+{
+ Exec e;
+ u8 *src, *dst;
+ u32 i;
+
+ if(aout_parse(img, &e) < 0)
+ return (void*)0;
+ src = img + HDRSZ; /* сегменты идут сразу за заголовком */
+ dst = (u8*)e.entry; /* грузим по entry (= -T линкера) */
+ for(i = 0; i < e.text + e.data; i++)
+ dst[i] = src[i];
+ for(i = 0; i < e.bss; i++)
+ dst[e.text + e.data + i] = 0;
+ return (void*)e.entry;
+}
+
+/* точка входа загрузчика: грузит ядро и прыгает в него (назад не вернётся). */
+void
+bootkernel(u8 *kern)
+{
+ void (*entry)(void);
+
+ entry = (void(*)(void))aout_load(kern);
+ if(entry)
+ entry();
+}