summaryrefslogtreecommitdiff
path: root/kernel/loader.c
diff options
context:
space:
mode:
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();
+}