Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	"u.h"
2
#include	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"../port/error.h"
7
#include	<a.out.h>
8
#include 	"/sys/src/libmach/elf.h"
9
 
10
enum {
11
	Ehdr32sz	= 52,
12
	Phdr32sz	= 32,
13
	Shdr32sz	= 40,
14
 
15
	Ehdr64sz	= 64,
16
	Phdr64sz	= 56,
17
	Shdr64sz	= 64,
18
};
19
 
20
static uchar elfident[] = {
21
	'\177', 'E', 'L', 'F',
22
};
23
 
24
void
25
readn(Chan *c, void *vp, long n)
26
{
27
	char *p = vp;
28
	long nn;
29
 
30
	while(n > 0) {
31
		nn = devtab[c->type]->read(c, p, n, c->offset);
32
		if(nn == 0)
33
			error(Eshort);
34
		c->offset += nn;
35
		p += nn;
36
		n -= nn;
37
	}
38
}
39
 
40
/* assume the elf header is in the byte order of this machine */
41
int
42
readelfhdr(Chan *c, ulong, Execvals *evp)
43
{
44
	Ehdr ehdr;
45
	Phdr phdrs[3];
46
 
47
	c->offset = 0;			/* back up */
48
	readn(c, &ehdr, sizeof ehdr);
49
	if(memcmp(&ehdr.ident[MAG0], elfident, sizeof elfident) != 0 ||
50
	    ehdr.ident[CLASS] != ELFCLASS32)
51
		return -1;
52
 
53
	/* get textsize and datasize from Phdrs */
54
	readn(c, phdrs, sizeof phdrs);
55
	evp->entry = ehdr.elfentry;
56
	evp->textsize = phdrs[0].filesz;
57
	evp->datasize = phdrs[1].filesz;
58
	c->offset = ROUNDUP(Ehdr32sz + 3*Phdr32sz, 16);	/* position for text */
59
	return 0;
60
}
61
 
62
static int
63
readelf64hdr(Chan *c, ulong, Execvals *evp)
64
{
65
	E64hdr ehdr;
66
	P64hdr phdrs[3];
67
 
68
	c->offset = 0;			/* back up */
69
	readn(c, &ehdr, sizeof ehdr);
70
	if(memcmp(&ehdr.ident[MAG0], elfident, sizeof elfident) != 0 ||
71
	    ehdr.ident[CLASS] != ELFCLASS64)
72
		return -1;
73
 
74
	/* get textsize and datasize from Phdrs */
75
	readn(c, phdrs, sizeof phdrs);
76
	evp->entry = ehdr.elfentry;
77
	evp->textsize = phdrs[0].filesz;
78
	evp->datasize = phdrs[1].filesz;
79
	c->offset = ROUNDUP(Ehdr64sz + 3*Phdr64sz, 16);	/* position for text */
80
	return 0;
81
}
82
 
83
static void
84
setbootcmd(int argc, char *argv[])
85
{
86
	char *buf, *p, *ep;
87
	int i;
88
 
89
	buf = malloc(1024);
90
	if(buf == nil)
91
		error(Enomem);
92
	p = buf;
93
	ep = buf + 1024;
94
	for(i=0; i<argc; i++)
95
		p = seprint(p, ep, "%q ", argv[i]);
96
	*p = 0;
97
	ksetenv("bootcmd", buf, 1);
98
	free(buf);
99
}
100
 
101
void
102
rebootcmd(int argc, char *argv[])
103
{
104
	Chan *c;
105
	Exec exec;
106
	Execvals ev;
107
	ulong magic, text, rtext, entry, data, size;
108
	uchar *p;
109
 
110
	if(argc == 0)
111
		exit(0);
112
 
113
	c = namec(argv[0], Aopen, OEXEC, 0);
114
	if(waserror()){
115
		cclose(c);
116
		nexterror();
117
	}
118
 
119
	readn(c, &exec, sizeof(Exec));
120
	magic = l2be(exec.magic);
121
	/*
122
	 * AOUT_MAGIC is sometimes defined like this:
123
	 * #define AOUT_MAGIC	V_MAGIC || magic==M_MAGIC
124
	 * so we can only use it in a fairly stylized manner.
125
	 */
126
	if(magic == AOUT_MAGIC) {
127
		entry = l2be(exec.entry);
128
		text = l2be(exec.text);
129
		data = l2be(exec.data);
130
	} else if(parseboothdr && (*parseboothdr)(c, magic, &ev) >= 0 ||
131
	    readelfhdr(c, magic, &ev) >= 0 ||
132
	    readelf64hdr(c, magic, &ev) >= 0){
133
		entry = ev.entry;
134
		text = ev.textsize;
135
		data = ev.datasize;
136
	} else {
137
		error(Ebadexec);
138
		return;				/* for the compiler */
139
	}
140
 
141
	/* round text out to page boundary */
142
	rtext = ROUNDUP(entry+text, BY2PG) - entry;
143
	size = rtext + data;
144
	p = malloc(size);
145
	if(p == nil)
146
		error(Enomem);
147
 
148
	if(waserror()){
149
		free(p);
150
		nexterror();
151
	}
152
 
153
	memset(p, 0, size);
154
	readn(c, p, text);
155
	readn(c, p + rtext, data);
156
 
157
	ksetenv("bootfile", argv[0], 1);
158
	setbootcmd(argc-1, argv+1);
159
 
160
	reboot((void*)entry, p, size);
161
 
162
	panic("return from reboot!");
163
}