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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
#include <elf.h>
#include <stddef.h>
#include "bootloader.h"
static int cmp(const char *a, const char *b, size_t len)
{
while (len--) if (*a++ != *b++) return 1;
return 0;
}
static void load_segment(char *dst, const char *src, size_t outlen, size_t inlen)
{
outlen -= inlen;
while (inlen--) *dst++ = *src++;
while (outlen--) *dst++ = 0;
}
static const char e_ident[] = {
0x7f, 'E', 'L', 'F', /* magic number */
ELFCLASS32, /* 32-bit */
ELFDATA2MSB, /* big endian */
1, /* ELF version 1 */
};
_Noreturn void bootloader(struct systemid *boot)
{
if (!boot->load_addr || boot->load_addr & 3) fail();
if (boot->stack_master & 3) fail();
char *base = (void*) boot->load_addr;
long *stack = (long*)(boot->stack_master ? boot->stack_master : 0x06002000);
Elf32_Ehdr *ehdr = (void*)base;
if (cmp(ehdr->e_ident, e_ident, sizeof e_ident)
|| ehdr->e_type != ET_EXEC
|| ehdr->e_machine != EM_SH
|| ehdr->e_version != EV_CURRENT
|| !ehdr->e_entry)
fail();
void *entry = (void*)ehdr->e_entry;
char *phdrs = base + ehdr->e_phoff;
size_t phentsize = ehdr->e_phentsize;
size_t phnum = ehdr->e_phnum;
/* find load address for program headers, immediately before first segment */
char *phdr_out = NULL, *p;
size_t n;
for (p = phdrs, n = phnum; n--; p += phentsize) {
Elf32_Phdr *ph = (void*)p;
if (ph->p_type == PT_LOAD) {
phdr_out = (char*)ph->p_vaddr - phentsize * phnum;
break;
}
}
if (!phdr_out) fail();
/* fixup PT_PHDR program header (if present) to point to where we're loading it */
for (p = phdrs, n = phnum; n--; p += phentsize) {
Elf32_Phdr *ph = (void*)p;
if (ph->p_type == PT_PHDR) {
ph->p_vaddr = (Elf32_Word)phdr_out;
break;
}
}
/* load program headers */
load_segment(phdr_out, phdrs, phentsize * phnum, phentsize * phnum);
/* load all the PT_LOAD segments */
for (p = phdrs, n = phnum; n--; p += phentsize) {
Elf32_Phdr *ph = (void*)p;
if (ph->p_type != PT_LOAD) continue;
load_segment((void*)ph->p_vaddr, base + ph->p_offset, ph->p_memsz, ph->p_filesz);
}
#define PUSH(v) do { *--stack = (long)(v); } while(0)
#define PUSH_AUX(a,v) do { PUSH(v); PUSH(a); } while(0)
/* push aux vector onto target process stack */
long *emptystr = stack - 1;
PUSH_AUX(AT_NULL, 0);
PUSH_AUX(AT_PHDR, phdr_out);
PUSH_AUX(AT_PHENT, phentsize);
PUSH_AUX(AT_PHNUM, phnum);
PUSH_AUX(AT_ENTRY, entry);
/* push environment and arguments */
PUSH(0); /* envp[0] */
PUSH(0); /* argv[1] */
PUSH(emptystr); /* argv[0] */
PUSH(1); /* argc */
jump(entry, stack);
fail();
}
|