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