]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/boot/powerpc/kboot/main.c
Update llvm, clang, lld and lldb to release_39 branch r288513.
[FreeBSD/FreeBSD.git] / sys / boot / powerpc / kboot / main.c
1 /*-
2  * Copyright (C) 2010-2014 Nathan Whitehorn
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <stand.h>
30 #include <sys/param.h>
31 #include <fdt_platform.h>
32
33 #define _KERNEL
34 #include <machine/cpufunc.h>
35 #include "bootstrap.h"
36 #include "host_syscall.h"
37
38 struct arch_switch      archsw;
39 extern void *_end;
40
41 extern char bootprog_name[];
42 extern char bootprog_rev[];
43 extern char bootprog_date[];
44 extern char bootprog_maker[];
45
46 int kboot_getdev(void **vdev, const char *devspec, const char **path);
47 ssize_t kboot_copyin(const void *src, vm_offset_t dest, const size_t len);
48 ssize_t kboot_copyout(vm_offset_t src, void *dest, const size_t len);
49 ssize_t kboot_readin(const int fd, vm_offset_t dest, const size_t len);
50 int kboot_autoload(void);
51 uint64_t kboot_loadaddr(u_int type, void *data, uint64_t addr);
52 int kboot_setcurrdev(struct env_var *ev, int flags, const void *value);
53
54 extern int command_fdt_internal(int argc, char *argv[]);
55
56 int
57 kboot_getdev(void **vdev, const char *devspec, const char **path)
58 {
59         int i;
60         const char *devpath, *filepath;
61         struct devsw *dv;
62         struct devdesc *desc;
63
64         if (strchr(devspec, ':') != NULL) {
65                 devpath = devspec;
66                 filepath = strchr(devspec, ':') + 1;
67         } else {
68                 devpath = getenv("currdev");
69                 filepath = devspec;
70         }
71
72         for (i = 0; (dv = devsw[i]) != NULL; i++) {
73                 if (strncmp(dv->dv_name, devpath, strlen(dv->dv_name)) == 0)
74                         goto found;
75         }
76         return (ENOENT);
77
78 found:
79         if (path != NULL && filepath != NULL)
80                 *path = filepath;
81         else if (path != NULL)
82                 *path = strchr(devspec, ':') + 1;
83
84         if (vdev != NULL) {
85                 desc = malloc(sizeof(*desc));
86                 desc->d_dev = dv;
87                 desc->d_unit = 0;
88                 desc->d_opendata = strdup(devpath);
89                 *vdev = desc;
90         }
91
92         return (0);
93 }
94
95 int
96 main(int argc, const char **argv)
97 {
98         void *heapbase;
99         const size_t heapsize = 15*1024*1024;
100         const char *bootdev = argv[1];
101
102         /*
103          * Set the heap to one page after the end of the loader.
104          */
105         heapbase = host_getmem(heapsize);
106         setheap(heapbase, heapbase + heapsize);
107
108         /*
109          * Set up console.
110          */
111         cons_probe();
112
113         printf("Boot device: %s\n", bootdev);
114
115         archsw.arch_getdev = kboot_getdev;
116         archsw.arch_copyin = kboot_copyin;
117         archsw.arch_copyout = kboot_copyout;
118         archsw.arch_readin = kboot_readin;
119         archsw.arch_autoload = kboot_autoload;
120         archsw.arch_loadaddr = kboot_loadaddr;
121
122         printf("\n");
123         printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
124         printf("(%s, %s)\n", bootprog_maker, bootprog_date);
125
126         setenv("currdev", bootdev, 1);
127         setenv("loaddev", bootdev, 1);
128         setenv("LINES", "24", 1);
129
130         interact(NULL);                 /* doesn't return */
131
132         return (0);
133 }
134
135 void
136 exit(int code)
137 {
138         /* XXX: host_exit */
139 }
140
141 void
142 delay(int usecs)
143 {
144         struct host_timeval tvi, tv;
145         uint64_t ti, t;
146         host_gettimeofday(&tvi, NULL);
147         ti = tvi.tv_sec*1000000 + tvi.tv_usec;
148         do {
149                 host_gettimeofday(&tv, NULL);
150                 t = tv.tv_sec*1000000 + tv.tv_usec;
151         } while (t < ti + usecs);
152 }
153
154 time_t
155 getsecs(void)
156 {
157         struct host_timeval tv;
158         host_gettimeofday(&tv, NULL);
159         return (tv.tv_sec);
160 }
161
162 time_t
163 time(time_t *tloc)
164 {
165         time_t rv;
166         
167         rv = getsecs();
168         if (tloc != NULL)
169                 *tloc = rv;
170
171         return (rv);
172 }
173
174 struct kexec_segment {
175         void *buf;
176         int bufsz;
177         void *mem;
178         int memsz;
179 };
180
181 struct kexec_segment loaded_segments[128];
182 int nkexec_segments = 0;
183
184 static ssize_t
185 get_phys_buffer(vm_offset_t dest, const size_t len, void **buf)
186 {
187         int i = 0;
188         const size_t segsize = 2*1024*1024;
189
190         for (i = 0; i < nkexec_segments; i++) {
191                 if (dest >= (vm_offset_t)loaded_segments[i].mem &&
192                     dest < (vm_offset_t)loaded_segments[i].mem +
193                     loaded_segments[i].memsz)
194                         goto out;
195         }
196
197         loaded_segments[nkexec_segments].buf = host_getmem(segsize);
198         loaded_segments[nkexec_segments].bufsz = segsize;
199         loaded_segments[nkexec_segments].mem = (void *)rounddown2(dest,segsize);
200         loaded_segments[nkexec_segments].memsz = segsize;
201         i = nkexec_segments;
202         nkexec_segments++;
203
204 out:
205         *buf = loaded_segments[i].buf + (dest -
206             (vm_offset_t)loaded_segments[i].mem);
207         return (min(len,loaded_segments[i].bufsz - (dest -
208             (vm_offset_t)loaded_segments[i].mem)));
209 }
210
211 ssize_t
212 kboot_copyin(const void *src, vm_offset_t dest, const size_t len)
213 {
214         ssize_t segsize, remainder;
215         void *destbuf;
216
217         remainder = len;
218         do {
219                 segsize = get_phys_buffer(dest, remainder, &destbuf);
220                 bcopy(src, destbuf, segsize);
221                 remainder -= segsize;
222                 src += segsize;
223                 dest += segsize;
224         } while (remainder > 0);
225
226         return (len);
227 }
228
229 ssize_t
230 kboot_copyout(vm_offset_t src, void *dest, const size_t len)
231 {
232         ssize_t segsize, remainder;
233         void *srcbuf;
234
235         remainder = len;
236         do {
237                 segsize = get_phys_buffer(src, remainder, &srcbuf);
238                 bcopy(srcbuf, dest, segsize);
239                 remainder -= segsize;
240                 src += segsize;
241                 dest += segsize;
242         } while (remainder > 0);
243
244         return (len);
245 }
246
247 ssize_t
248 kboot_readin(const int fd, vm_offset_t dest, const size_t len)
249 {
250         void            *buf;
251         size_t          resid, chunk, get;
252         ssize_t         got;
253         vm_offset_t     p;
254
255         p = dest;
256
257         chunk = min(PAGE_SIZE, len);
258         buf = malloc(chunk);
259         if (buf == NULL) {
260                 printf("kboot_readin: buf malloc failed\n");
261                 return (0);
262         }
263
264         for (resid = len; resid > 0; resid -= got, p += got) {
265                 get = min(chunk, resid);
266                 got = read(fd, buf, get);
267                 if (got <= 0) {
268                         if (got < 0)
269                                 printf("kboot_readin: read failed\n");
270                         break;
271                 }
272
273                 kboot_copyin(buf, p, got);
274         }
275
276         free (buf);
277         return (len - resid);
278 }
279
280 int
281 kboot_autoload(void)
282 {
283
284         return (0);
285 }
286
287 uint64_t
288 kboot_loadaddr(u_int type, void *data, uint64_t addr)
289 {
290         /*
291          * Need to stay out of the way of Linux. /chosen/linux,kernel-end does
292          * a better job here, but use a fixed offset for now.
293          */
294
295         if (type == LOAD_ELF)
296                 addr = roundup(addr, PAGE_SIZE);
297         else
298                 addr += 64*1024*1024; /* Stay out of the way of Linux */
299
300         return (addr);
301 }
302
303 void
304 _start(int argc, const char **argv, char **env)
305 {
306         register volatile void **sp asm("r1");
307         main((int)sp[0], (const char **)&sp[1]);
308 }
309
310 /*
311  * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
312  * and declaring it as extern is in contradiction with COMMAND_SET() macro
313  * (which uses static pointer), we're defining wrapper function, which
314  * calls the proper fdt handling routine.
315  */
316 static int
317 command_fdt(int argc, char *argv[])
318 {
319
320         return (command_fdt_internal(argc, argv));
321 }
322         
323 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
324