summaryrefslogtreecommitdiff
path: root/kernel/loader.c
blob: 0246628a7d03fba2b85f86f5b864776a71b8225e (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
/*
 * Загрузчик ядра в формате 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();
}