xref: /plan9/sys/src/9/port/rebootcmd.c (revision 15bfe97de97771872f389e30cbf1ae2973fc2dfe)
19a747e4fSDavid du Colombier #include	"u.h"
29a747e4fSDavid du Colombier #include	"../port/lib.h"
39a747e4fSDavid du Colombier #include	"mem.h"
49a747e4fSDavid du Colombier #include	"dat.h"
59a747e4fSDavid du Colombier #include	"fns.h"
69a747e4fSDavid du Colombier #include	"../port/error.h"
75482313dSDavid du Colombier #include	<a.out.h>
8*15bfe97dSDavid du Colombier #include 	"/sys/src/libmach/elf.h"
9*15bfe97dSDavid du Colombier 
10*15bfe97dSDavid du Colombier enum {
11*15bfe97dSDavid du Colombier 	Ehdr32sz	= 52,
12*15bfe97dSDavid du Colombier 	Phdr32sz	= 32,
13*15bfe97dSDavid du Colombier 	Shdr32sz	= 40,
14*15bfe97dSDavid du Colombier 
15*15bfe97dSDavid du Colombier 	Ehdr64sz	= 64,
16*15bfe97dSDavid du Colombier 	Phdr64sz	= 56,
17*15bfe97dSDavid du Colombier 	Shdr64sz	= 64,
18*15bfe97dSDavid du Colombier };
19*15bfe97dSDavid du Colombier 
20*15bfe97dSDavid du Colombier static uchar elfident[] = {
21*15bfe97dSDavid du Colombier 	'\177', 'E', 'L', 'F',
22*15bfe97dSDavid du Colombier };
239a747e4fSDavid du Colombier 
245482313dSDavid du Colombier void
readn(Chan * c,void * vp,long n)259a747e4fSDavid du Colombier readn(Chan *c, void *vp, long n)
269a747e4fSDavid du Colombier {
279a747e4fSDavid du Colombier 	char *p = vp;
289a747e4fSDavid du Colombier 	long nn;
299a747e4fSDavid du Colombier 
309a747e4fSDavid du Colombier 	while(n > 0) {
319a747e4fSDavid du Colombier 		nn = devtab[c->type]->read(c, p, n, c->offset);
329a747e4fSDavid du Colombier 		if(nn == 0)
339a747e4fSDavid du Colombier 			error(Eshort);
349a747e4fSDavid du Colombier 		c->offset += nn;
359a747e4fSDavid du Colombier 		p += nn;
369a747e4fSDavid du Colombier 		n -= nn;
379a747e4fSDavid du Colombier 	}
389a747e4fSDavid du Colombier }
399a747e4fSDavid du Colombier 
40*15bfe97dSDavid du Colombier /* assume the elf header is in the byte order of this machine */
41*15bfe97dSDavid du Colombier int
readelfhdr(Chan * c,ulong,Execvals * evp)42*15bfe97dSDavid du Colombier readelfhdr(Chan *c, ulong, Execvals *evp)
43*15bfe97dSDavid du Colombier {
44*15bfe97dSDavid du Colombier 	Ehdr ehdr;
45*15bfe97dSDavid du Colombier 	Phdr phdrs[3];
46*15bfe97dSDavid du Colombier 
47*15bfe97dSDavid du Colombier 	c->offset = 0;			/* back up */
48*15bfe97dSDavid du Colombier 	readn(c, &ehdr, sizeof ehdr);
49*15bfe97dSDavid du Colombier 	if(memcmp(&ehdr.ident[MAG0], elfident, sizeof elfident) != 0 ||
50*15bfe97dSDavid du Colombier 	    ehdr.ident[CLASS] != ELFCLASS32)
51*15bfe97dSDavid du Colombier 		return -1;
52*15bfe97dSDavid du Colombier 
53*15bfe97dSDavid du Colombier 	/* get textsize and datasize from Phdrs */
54*15bfe97dSDavid du Colombier 	readn(c, phdrs, sizeof phdrs);
55*15bfe97dSDavid du Colombier 	evp->entry = ehdr.elfentry;
56*15bfe97dSDavid du Colombier 	evp->textsize = phdrs[0].filesz;
57*15bfe97dSDavid du Colombier 	evp->datasize = phdrs[1].filesz;
58*15bfe97dSDavid du Colombier 	c->offset = ROUNDUP(Ehdr32sz + 3*Phdr32sz, 16);	/* position for text */
59*15bfe97dSDavid du Colombier 	return 0;
60*15bfe97dSDavid du Colombier }
61*15bfe97dSDavid du Colombier 
62*15bfe97dSDavid du Colombier static int
readelf64hdr(Chan * c,ulong,Execvals * evp)63*15bfe97dSDavid du Colombier readelf64hdr(Chan *c, ulong, Execvals *evp)
64*15bfe97dSDavid du Colombier {
65*15bfe97dSDavid du Colombier 	E64hdr ehdr;
66*15bfe97dSDavid du Colombier 	P64hdr phdrs[3];
67*15bfe97dSDavid du Colombier 
68*15bfe97dSDavid du Colombier 	c->offset = 0;			/* back up */
69*15bfe97dSDavid du Colombier 	readn(c, &ehdr, sizeof ehdr);
70*15bfe97dSDavid du Colombier 	if(memcmp(&ehdr.ident[MAG0], elfident, sizeof elfident) != 0 ||
71*15bfe97dSDavid du Colombier 	    ehdr.ident[CLASS] != ELFCLASS64)
72*15bfe97dSDavid du Colombier 		return -1;
73*15bfe97dSDavid du Colombier 
74*15bfe97dSDavid du Colombier 	/* get textsize and datasize from Phdrs */
75*15bfe97dSDavid du Colombier 	readn(c, phdrs, sizeof phdrs);
76*15bfe97dSDavid du Colombier 	evp->entry = ehdr.elfentry;
77*15bfe97dSDavid du Colombier 	evp->textsize = phdrs[0].filesz;
78*15bfe97dSDavid du Colombier 	evp->datasize = phdrs[1].filesz;
79*15bfe97dSDavid du Colombier 	c->offset = ROUNDUP(Ehdr64sz + 3*Phdr64sz, 16);	/* position for text */
80*15bfe97dSDavid du Colombier 	return 0;
81*15bfe97dSDavid du Colombier }
82*15bfe97dSDavid du Colombier 
839a747e4fSDavid du Colombier static void
setbootcmd(int argc,char * argv[])849a747e4fSDavid du Colombier setbootcmd(int argc, char *argv[])
859a747e4fSDavid du Colombier {
869a747e4fSDavid du Colombier 	char *buf, *p, *ep;
879a747e4fSDavid du Colombier 	int i;
889a747e4fSDavid du Colombier 
899a747e4fSDavid du Colombier 	buf = malloc(1024);
909a747e4fSDavid du Colombier 	if(buf == nil)
919a747e4fSDavid du Colombier 		error(Enomem);
929a747e4fSDavid du Colombier 	p = buf;
939a747e4fSDavid du Colombier 	ep = buf + 1024;
949a747e4fSDavid du Colombier 	for(i=0; i<argc; i++)
959a747e4fSDavid du Colombier 		p = seprint(p, ep, "%q ", argv[i]);
969a747e4fSDavid du Colombier 	*p = 0;
979a747e4fSDavid du Colombier 	ksetenv("bootcmd", buf, 1);
989a747e4fSDavid du Colombier 	free(buf);
999a747e4fSDavid du Colombier }
1009a747e4fSDavid du Colombier 
1019a747e4fSDavid du Colombier void
rebootcmd(int argc,char * argv[])1029a747e4fSDavid du Colombier rebootcmd(int argc, char *argv[])
1039a747e4fSDavid du Colombier {
1049a747e4fSDavid du Colombier 	Chan *c;
1059a747e4fSDavid du Colombier 	Exec exec;
106*15bfe97dSDavid du Colombier 	Execvals ev;
1079a747e4fSDavid du Colombier 	ulong magic, text, rtext, entry, data, size;
1089a747e4fSDavid du Colombier 	uchar *p;
1099a747e4fSDavid du Colombier 
1109a747e4fSDavid du Colombier 	if(argc == 0)
1119a747e4fSDavid du Colombier 		exit(0);
1129a747e4fSDavid du Colombier 
1139a747e4fSDavid du Colombier 	c = namec(argv[0], Aopen, OEXEC, 0);
1149a747e4fSDavid du Colombier 	if(waserror()){
1159a747e4fSDavid du Colombier 		cclose(c);
1169a747e4fSDavid du Colombier 		nexterror();
1179a747e4fSDavid du Colombier 	}
1189a747e4fSDavid du Colombier 
1199a747e4fSDavid du Colombier 	readn(c, &exec, sizeof(Exec));
1209a747e4fSDavid du Colombier 	magic = l2be(exec.magic);
1214e3613abSDavid du Colombier 	/*
1224e3613abSDavid du Colombier 	 * AOUT_MAGIC is sometimes defined like this:
1234e3613abSDavid du Colombier 	 * #define AOUT_MAGIC	V_MAGIC || magic==M_MAGIC
1244e3613abSDavid du Colombier 	 * so we can only use it in a fairly stylized manner.
1254e3613abSDavid du Colombier 	 */
1264e3613abSDavid du Colombier 	if(magic == AOUT_MAGIC) {
1275482313dSDavid du Colombier 		entry = l2be(exec.entry);
1285482313dSDavid du Colombier 		text = l2be(exec.text);
1295482313dSDavid du Colombier 		data = l2be(exec.data);
130*15bfe97dSDavid du Colombier 	} else if(parseboothdr && (*parseboothdr)(c, magic, &ev) >= 0 ||
131*15bfe97dSDavid du Colombier 	    readelfhdr(c, magic, &ev) >= 0 ||
132*15bfe97dSDavid du Colombier 	    readelf64hdr(c, magic, &ev) >= 0){
133*15bfe97dSDavid du Colombier 		entry = ev.entry;
134*15bfe97dSDavid du Colombier 		text = ev.textsize;
135*15bfe97dSDavid du Colombier 		data = ev.datasize;
1365482313dSDavid du Colombier 	} else {
1379a747e4fSDavid du Colombier 		error(Ebadexec);
1385482313dSDavid du Colombier 		return;				/* for the compiler */
1395482313dSDavid du Colombier 	}
1409a747e4fSDavid du Colombier 
1419a747e4fSDavid du Colombier 	/* round text out to page boundary */
142a826b788SDavid du Colombier 	rtext = ROUNDUP(entry+text, BY2PG) - entry;
1439a747e4fSDavid du Colombier 	size = rtext + data;
1449a747e4fSDavid du Colombier 	p = malloc(size);
1459a747e4fSDavid du Colombier 	if(p == nil)
1469a747e4fSDavid du Colombier 		error(Enomem);
1479a747e4fSDavid du Colombier 
1489a747e4fSDavid du Colombier 	if(waserror()){
1499a747e4fSDavid du Colombier 		free(p);
1509a747e4fSDavid du Colombier 		nexterror();
1519a747e4fSDavid du Colombier 	}
1529a747e4fSDavid du Colombier 
1539a747e4fSDavid du Colombier 	memset(p, 0, size);
1549a747e4fSDavid du Colombier 	readn(c, p, text);
1559a747e4fSDavid du Colombier 	readn(c, p + rtext, data);
1569a747e4fSDavid du Colombier 
1579a747e4fSDavid du Colombier 	ksetenv("bootfile", argv[0], 1);
1589a747e4fSDavid du Colombier 	setbootcmd(argc-1, argv+1);
1599a747e4fSDavid du Colombier 
1609a747e4fSDavid du Colombier 	reboot((void*)entry, p, size);
1619a747e4fSDavid du Colombier 
1629a747e4fSDavid du Colombier 	panic("return from reboot!");
1639a747e4fSDavid du Colombier }
164