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