2 * Copyright (C) 2010-2014 Nathan Whitehorn
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <fdt_platform.h>
34 #include <machine/cpufunc.h>
35 #include "bootstrap.h"
36 #include "host_syscall.h"
38 struct arch_switch archsw;
41 extern char bootprog_name[];
42 extern char bootprog_rev[];
43 extern char bootprog_date[];
44 extern char bootprog_maker[];
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);
54 extern int command_fdt_internal(int argc, char *argv[]);
57 kboot_getdev(void **vdev, const char *devspec, const char **path)
60 const char *devpath, *filepath;
64 if (strchr(devspec, ':') != NULL) {
66 filepath = strchr(devspec, ':') + 1;
68 devpath = getenv("currdev");
72 for (i = 0; (dv = devsw[i]) != NULL; i++) {
73 if (strncmp(dv->dv_name, devpath, strlen(dv->dv_name)) == 0)
79 if (path != NULL && filepath != NULL)
81 else if (path != NULL)
82 *path = strchr(devspec, ':') + 1;
85 desc = malloc(sizeof(*desc));
88 desc->d_opendata = strdup(devpath);
96 main(int argc, const char **argv)
99 const size_t heapsize = 15*1024*1024;
100 const char *bootdev = argv[1];
103 * Set the heap to one page after the end of the loader.
105 heapbase = host_getmem(heapsize);
106 setheap(heapbase, heapbase + heapsize);
113 printf("Boot device: %s\n", bootdev);
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;
123 printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
124 printf("(%s, %s)\n", bootprog_maker, bootprog_date);
126 setenv("currdev", bootdev, 1);
127 setenv("loaddev", bootdev, 1);
128 setenv("LINES", "24", 1);
130 interact(NULL); /* doesn't return */
144 struct host_timeval tvi, tv;
146 host_gettimeofday(&tvi, NULL);
147 ti = tvi.tv_sec*1000000 + tvi.tv_usec;
149 host_gettimeofday(&tv, NULL);
150 t = tv.tv_sec*1000000 + tv.tv_usec;
151 } while (t < ti + usecs);
157 struct host_timeval tv;
158 host_gettimeofday(&tv, NULL);
174 struct kexec_segment {
181 struct kexec_segment loaded_segments[128];
182 int nkexec_segments = 0;
185 get_phys_buffer(vm_offset_t dest, const size_t len, void **buf)
188 const size_t segsize = 2*1024*1024;
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)
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;
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)));
212 kboot_copyin(const void *src, vm_offset_t dest, const size_t len)
214 ssize_t segsize, remainder;
219 segsize = get_phys_buffer(dest, remainder, &destbuf);
220 bcopy(src, destbuf, segsize);
221 remainder -= segsize;
224 } while (remainder > 0);
230 kboot_copyout(vm_offset_t src, void *dest, const size_t len)
232 ssize_t segsize, remainder;
237 segsize = get_phys_buffer(src, remainder, &srcbuf);
238 bcopy(srcbuf, dest, segsize);
239 remainder -= segsize;
242 } while (remainder > 0);
248 kboot_readin(const int fd, vm_offset_t dest, const size_t len)
251 size_t resid, chunk, get;
257 chunk = min(PAGE_SIZE, len);
260 printf("kboot_readin: buf malloc failed\n");
264 for (resid = len; resid > 0; resid -= got, p += got) {
265 get = min(chunk, resid);
266 got = read(fd, buf, get);
269 printf("kboot_readin: read failed\n");
273 kboot_copyin(buf, p, got);
277 return (len - resid);
288 kboot_loadaddr(u_int type, void *data, uint64_t addr)
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.
295 if (type == LOAD_ELF)
296 addr = roundup(addr, PAGE_SIZE);
298 addr += 64*1024*1024; /* Stay out of the way of Linux */
304 _start(int argc, const char **argv, char **env)
306 register volatile void **sp asm("r1");
307 main((int)sp[0], (const char **)&sp[1]);
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.
317 command_fdt(int argc, char *argv[])
320 return (command_fdt_internal(argc, argv));
323 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);