]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/powerpc/kboot/main.c
Re-sync loader.mk and ficl.mk to where they should be
[FreeBSD/FreeBSD.git] / stand / 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_info[];
42
43 int kboot_getdev(void **vdev, const char *devspec, const char **path);
44 ssize_t kboot_copyin(const void *src, vm_offset_t dest, const size_t len);
45 ssize_t kboot_copyout(vm_offset_t src, void *dest, const size_t len);
46 ssize_t kboot_readin(const int fd, vm_offset_t dest, const size_t len);
47 int kboot_autoload(void);
48 uint64_t kboot_loadaddr(u_int type, void *data, uint64_t addr);
49 int kboot_setcurrdev(struct env_var *ev, int flags, const void *value);
50
51 extern int command_fdt_internal(int argc, char *argv[]);
52
53 int
54 kboot_getdev(void **vdev, const char *devspec, const char **path)
55 {
56         int i;
57         const char *devpath, *filepath;
58         struct devsw *dv;
59         struct devdesc *desc;
60
61         if (strchr(devspec, ':') != NULL) {
62                 devpath = devspec;
63                 filepath = strchr(devspec, ':') + 1;
64         } else {
65                 devpath = getenv("currdev");
66                 filepath = devspec;
67         }
68
69         for (i = 0; (dv = devsw[i]) != NULL; i++) {
70                 if (strncmp(dv->dv_name, devpath, strlen(dv->dv_name)) == 0)
71                         goto found;
72         }
73         return (ENOENT);
74
75 found:
76         if (path != NULL && filepath != NULL)
77                 *path = filepath;
78         else if (path != NULL)
79                 *path = strchr(devspec, ':') + 1;
80
81         if (vdev != NULL) {
82                 desc = malloc(sizeof(*desc));
83                 desc->d_dev = dv;
84                 desc->d_unit = 0;
85                 desc->d_opendata = strdup(devpath);
86                 *vdev = desc;
87         }
88
89         return (0);
90 }
91
92 int
93 main(int argc, const char **argv)
94 {
95         void *heapbase;
96         const size_t heapsize = 15*1024*1024;
97         const char *bootdev = argv[1];
98
99         /*
100          * Set the heap to one page after the end of the loader.
101          */
102         heapbase = host_getmem(heapsize);
103         setheap(heapbase, heapbase + heapsize);
104
105         /*
106          * Set up console.
107          */
108         cons_probe();
109
110         printf("Boot device: %s\n", bootdev);
111
112         archsw.arch_getdev = kboot_getdev;
113         archsw.arch_copyin = kboot_copyin;
114         archsw.arch_copyout = kboot_copyout;
115         archsw.arch_readin = kboot_readin;
116         archsw.arch_autoload = kboot_autoload;
117         archsw.arch_loadaddr = kboot_loadaddr;
118
119         printf("\n%s", bootprog_info);
120
121         setenv("currdev", bootdev, 1);
122         setenv("loaddev", bootdev, 1);
123         setenv("LINES", "24", 1);
124
125         interact(NULL);                 /* doesn't return */
126
127         return (0);
128 }
129
130 void
131 exit(int code)
132 {
133         /* XXX: host_exit */
134 }
135
136 void
137 delay(int usecs)
138 {
139         struct host_timeval tvi, tv;
140         uint64_t ti, t;
141         host_gettimeofday(&tvi, NULL);
142         ti = tvi.tv_sec*1000000 + tvi.tv_usec;
143         do {
144                 host_gettimeofday(&tv, NULL);
145                 t = tv.tv_sec*1000000 + tv.tv_usec;
146         } while (t < ti + usecs);
147 }
148
149 time_t
150 getsecs(void)
151 {
152         struct host_timeval tv;
153         host_gettimeofday(&tv, NULL);
154         return (tv.tv_sec);
155 }
156
157 time_t
158 time(time_t *tloc)
159 {
160         time_t rv;
161         
162         rv = getsecs();
163         if (tloc != NULL)
164                 *tloc = rv;
165
166         return (rv);
167 }
168
169 struct kexec_segment {
170         void *buf;
171         int bufsz;
172         void *mem;
173         int memsz;
174 };
175
176 struct kexec_segment loaded_segments[128];
177 int nkexec_segments = 0;
178
179 static ssize_t
180 get_phys_buffer(vm_offset_t dest, const size_t len, void **buf)
181 {
182         int i = 0;
183         const size_t segsize = 2*1024*1024;
184
185         for (i = 0; i < nkexec_segments; i++) {
186                 if (dest >= (vm_offset_t)loaded_segments[i].mem &&
187                     dest < (vm_offset_t)loaded_segments[i].mem +
188                     loaded_segments[i].memsz)
189                         goto out;
190         }
191
192         loaded_segments[nkexec_segments].buf = host_getmem(segsize);
193         loaded_segments[nkexec_segments].bufsz = segsize;
194         loaded_segments[nkexec_segments].mem = (void *)rounddown2(dest,segsize);
195         loaded_segments[nkexec_segments].memsz = segsize;
196         i = nkexec_segments;
197         nkexec_segments++;
198
199 out:
200         *buf = loaded_segments[i].buf + (dest -
201             (vm_offset_t)loaded_segments[i].mem);
202         return (min(len,loaded_segments[i].bufsz - (dest -
203             (vm_offset_t)loaded_segments[i].mem)));
204 }
205
206 ssize_t
207 kboot_copyin(const void *src, vm_offset_t dest, const size_t len)
208 {
209         ssize_t segsize, remainder;
210         void *destbuf;
211
212         remainder = len;
213         do {
214                 segsize = get_phys_buffer(dest, remainder, &destbuf);
215                 bcopy(src, destbuf, segsize);
216                 remainder -= segsize;
217                 src += segsize;
218                 dest += segsize;
219         } while (remainder > 0);
220
221         return (len);
222 }
223
224 ssize_t
225 kboot_copyout(vm_offset_t src, void *dest, const size_t len)
226 {
227         ssize_t segsize, remainder;
228         void *srcbuf;
229
230         remainder = len;
231         do {
232                 segsize = get_phys_buffer(src, remainder, &srcbuf);
233                 bcopy(srcbuf, dest, segsize);
234                 remainder -= segsize;
235                 src += segsize;
236                 dest += segsize;
237         } while (remainder > 0);
238
239         return (len);
240 }
241
242 ssize_t
243 kboot_readin(const int fd, vm_offset_t dest, const size_t len)
244 {
245         void            *buf;
246         size_t          resid, chunk, get;
247         ssize_t         got;
248         vm_offset_t     p;
249
250         p = dest;
251
252         chunk = min(PAGE_SIZE, len);
253         buf = malloc(chunk);
254         if (buf == NULL) {
255                 printf("kboot_readin: buf malloc failed\n");
256                 return (0);
257         }
258
259         for (resid = len; resid > 0; resid -= got, p += got) {
260                 get = min(chunk, resid);
261                 got = read(fd, buf, get);
262                 if (got <= 0) {
263                         if (got < 0)
264                                 printf("kboot_readin: read failed\n");
265                         break;
266                 }
267
268                 kboot_copyin(buf, p, got);
269         }
270
271         free (buf);
272         return (len - resid);
273 }
274
275 int
276 kboot_autoload(void)
277 {
278
279         return (0);
280 }
281
282 uint64_t
283 kboot_loadaddr(u_int type, void *data, uint64_t addr)
284 {
285         /*
286          * Need to stay out of the way of Linux. /chosen/linux,kernel-end does
287          * a better job here, but use a fixed offset for now.
288          */
289
290         if (type == LOAD_ELF)
291                 addr = roundup(addr, PAGE_SIZE);
292         else
293                 addr += 64*1024*1024; /* Stay out of the way of Linux */
294
295         return (addr);
296 }
297
298 void
299 _start(int argc, const char **argv, char **env)
300 {
301         register volatile void **sp asm("r1");
302         main((int)sp[0], (const char **)&sp[1]);
303 }
304
305 /*
306  * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
307  * and declaring it as extern is in contradiction with COMMAND_SET() macro
308  * (which uses static pointer), we're defining wrapper function, which
309  * calls the proper fdt handling routine.
310  */
311 static int
312 command_fdt(int argc, char *argv[])
313 {
314
315         return (command_fdt_internal(argc, argv));
316 }
317         
318 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
319