summaryrefslogtreecommitdiff
path: root/efi-kernel/efi_load.c
blob: 24539ae5b4a973adad6ab8f5c6597915f4e1a475 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/*
 * EFI-загрузчик amd64-ядра (Plan9 a.out) для UEFI. Сам — PE32+ (bootx64.efi).
 * Печатает статус через UEFI ConOut, разбирает встроенное ядро (a.out, S_MAGIC),
 * копирует сегменты по адресу линковки и прыгает в него (long mode). Ядро пишет 0xB8000.
 */
#include <u.h>
#include "efi.h"
#include "kernel_blob.h"

EFI_HANDLE IH;
EFI_SYSTEM_TABLE *ST;
extern uintptr eficall(void *fn, ...);

typedef unsigned int  u32;
typedef unsigned char u8;

static void
eputs(char *s)                             /* ASCII -> UTF-16 -> ConOut */
{
	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);
	}
}

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];
}

void
efimain(EFI_HANDLE ih, EFI_SYSTEM_TABLE *st)
{
	u8 *k, *src, *dst;
	u32 magic, text, data, bss, entry, i;
	void (*kentry)(void);

	IH = ih; ST = st;
	eputs("\nPlan9 EFI loader (amd64)\n");
	eputs("parsing embedded a.out kernel...\n");

	k = kernel_blob;
	magic = be32(k + 0);                    /* S_MAGIC(amd64) = 0x8A97 */
	if(magic != 0x8A97){ eputs("bad magic, halt\n"); for(;;); }
	text  = be32(k + 4);
	data  = be32(k + 8);
	bss   = be32(k + 12);
	entry = be32(k + 36);                   /* 64-бит entry (мл. слово) на off 32; = 0x100000 */

	src = k + 40;                           /* сегменты идут за 40-байтным заголовком */
	dst = (u8*)(uintptr)entry;              /* грузим по адресу линковки (-T) */
	for(i = 0; i < text + data; i++)
		dst[i] = src[i];
	for(i = 0; i < bss; i++)
		dst[text + data + i] = 0;

	eputs("kernel loaded @0x100000, jumping...\n");
	kentry = (void(*)(void))(uintptr)entry;
	kentry();                               /* -> ядро пишет 0xB8000, назад не вернётся */
	for(;;);
}