xref: /plan9/sys/src/9/port/rebootcmd.c (revision 15bfe97de97771872f389e30cbf1ae2973fc2dfe)
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
readn(Chan * c,void * vp,long n)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
readelfhdr(Chan * c,ulong,Execvals * evp)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
readelf64hdr(Chan * c,ulong,Execvals * evp)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
setbootcmd(int argc,char * argv[])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
rebootcmd(int argc,char * argv[])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 }
164