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