diff --git a/stand/kboot/arch/amd64/Makefile.inc b/stand/kboot/arch/amd64/Makefile.inc index 79ddbd67f5b6..e2f5b9038ee6 100644 --- a/stand/kboot/arch/amd64/Makefile.inc +++ b/stand/kboot/arch/amd64/Makefile.inc @@ -1,5 +1,5 @@ -SRCS+= host_syscall.S amd64_tramp.S elf64_freebsd.c +SRCS+= host_syscall.S amd64_tramp.S elf64_freebsd.c load_addr.c CFLAGS+= -I${SYSDIR}/contrib/dev/acpica/include LDFLAGS= -nostdlib -static -T ${.CURDIR}/arch/${MACHINE_ARCH}/ldscript.amd64 diff --git a/stand/kboot/arch/amd64/load_addr.c b/stand/kboot/arch/amd64/load_addr.c new file mode 100644 index 000000000000..cbe066d02d40 --- /dev/null +++ b/stand/kboot/arch/amd64/load_addr.c @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2022 Netflix, Inc + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "stand.h" +#include "host_syscall.h" +#include "kboot.h" + +uint64_t +kboot_get_phys_load_segment(void) +{ + return (~0ULL); +} diff --git a/stand/kboot/arch/powerpc64/Makefile.inc b/stand/kboot/arch/powerpc64/Makefile.inc index b62a12506969..4c863553397c 100644 --- a/stand/kboot/arch/powerpc64/Makefile.inc +++ b/stand/kboot/arch/powerpc64/Makefile.inc @@ -1,8 +1,8 @@ CFLAGS+= -mcpu=powerpc64 -SRCS+= ppc64_elf_freebsd.c host_syscall.S kerneltramp.S +SRCS+= ppc64_elf_freebsd.c host_syscall.S kerneltramp.S load_addr.c SRCS+= ucmpdi2.c LDFLAGS= -nostdlib -static -T ${.CURDIR}/arch/${MACHINE_ARCH}/ldscript.powerpc MK_PIE= no diff --git a/stand/kboot/arch/powerpc64/load_addr.c b/stand/kboot/arch/powerpc64/load_addr.c new file mode 100644 index 000000000000..81b5d0d50581 --- /dev/null +++ b/stand/kboot/arch/powerpc64/load_addr.c @@ -0,0 +1,210 @@ +/*- + * Copyright (C) 2010-2014 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "stand.h" +#include "host_syscall.h" +#include "kboot.h" + +struct region_desc { + uint64_t start; + uint64_t end; +}; + +/* + * Find a good place to load the kernel, subject to the PowerPC's constraints + * + * This excludes ranges that are marked as reserved. + * And 0..end of kernel + * + * It then tries to find the memory exposed from the DTB, which it assumes is one + * contiguous range. It adds everything not in that list to the excluded list. + * + * Sort, dedup, and it finds the first region and uses that as the load_segment + * and returns that. All addresses are offset by this amount. + */ +uint64_t +kboot_get_phys_load_segment(void) +{ + int fd; + uint64_t entry[2]; + static uint64_t load_segment = ~(0UL); + uint64_t val_64; + uint32_t val_32; + struct region_desc rsvd_reg[32]; + int rsvd_reg_cnt = 0; + int ret, a, b; + uint64_t start, end; + + if (load_segment == ~(0UL)) { + + /* Default load address is 0x00000000 */ + load_segment = 0UL; + + /* Read reserved regions */ + fd = host_open("/proc/device-tree/reserved-ranges", O_RDONLY, 0); + if (fd >= 0) { + while (host_read(fd, &entry[0], sizeof(entry)) == sizeof(entry)) { + rsvd_reg[rsvd_reg_cnt].start = be64toh(entry[0]); + rsvd_reg[rsvd_reg_cnt].end = + be64toh(entry[1]) + rsvd_reg[rsvd_reg_cnt].start - 1; + rsvd_reg_cnt++; + } + host_close(fd); + } + /* Read where the kernel ends */ + fd = host_open("/proc/device-tree/chosen/linux,kernel-end", O_RDONLY, 0); + if (fd >= 0) { + ret = host_read(fd, &val_64, sizeof(val_64)); + + if (ret == sizeof(uint64_t)) { + rsvd_reg[rsvd_reg_cnt].start = 0; + rsvd_reg[rsvd_reg_cnt].end = be64toh(val_64) - 1; + } else { + memcpy(&val_32, &val_64, sizeof(val_32)); + rsvd_reg[rsvd_reg_cnt].start = 0; + rsvd_reg[rsvd_reg_cnt].end = be32toh(val_32) - 1; + } + rsvd_reg_cnt++; + + host_close(fd); + } + /* Read memory size (SOCKET0 only) */ + fd = host_open("/proc/device-tree/memory@0/reg", O_RDONLY, 0); + if (fd < 0) + fd = host_open("/proc/device-tree/memory/reg", O_RDONLY, 0); + if (fd >= 0) { + ret = host_read(fd, &entry, sizeof(entry)); + + /* Memory range in start:length format */ + entry[0] = be64toh(entry[0]); + entry[1] = be64toh(entry[1]); + + /* Reserve everything what is before start */ + if (entry[0] != 0) { + rsvd_reg[rsvd_reg_cnt].start = 0; + rsvd_reg[rsvd_reg_cnt].end = entry[0] - 1; + rsvd_reg_cnt++; + } + /* Reserve everything what is after end */ + if (entry[1] != 0xffffffffffffffffUL) { + rsvd_reg[rsvd_reg_cnt].start = entry[0] + entry[1]; + rsvd_reg[rsvd_reg_cnt].end = 0xffffffffffffffffUL; + rsvd_reg_cnt++; + } + + host_close(fd); + } + + /* Sort entries in ascending order (bubble) */ + for (a = rsvd_reg_cnt - 1; a > 0; a--) { + for (b = 0; b < a; b++) { + if (rsvd_reg[b].start > rsvd_reg[b + 1].start) { + struct region_desc tmp; + tmp = rsvd_reg[b]; + rsvd_reg[b] = rsvd_reg[b + 1]; + rsvd_reg[b + 1] = tmp; + } + } + } + + /* Join overlapping/adjacent regions */ + for (a = 0; a < rsvd_reg_cnt - 1; ) { + + if ((rsvd_reg[a + 1].start >= rsvd_reg[a].start) && + ((rsvd_reg[a + 1].start - 1) <= rsvd_reg[a].end)) { + /* We have overlapping/adjacent regions! */ + rsvd_reg[a].end = + MAX(rsvd_reg[a].end, rsvd_reg[a + a].end); + + for (b = a + 1; b < rsvd_reg_cnt - 1; b++) + rsvd_reg[b] = rsvd_reg[b + 1]; + rsvd_reg_cnt--; + } else + a++; + } + + /* Find the first free region */ + if (rsvd_reg_cnt > 0) { + start = 0; + end = rsvd_reg[0].start; + for (a = 0; a < rsvd_reg_cnt - 1; a++) { + if ((start >= rsvd_reg[a].start) && + (start <= rsvd_reg[a].end)) { + start = rsvd_reg[a].end + 1; + end = rsvd_reg[a + 1].start; + } else + break; + } + + if (start != end) { + uint64_t align = 64UL*1024UL*1024UL; + + /* Align both to 64MB boundary */ + start = (start + align - 1UL) & ~(align - 1UL); + end = ((end + 1UL) & ~(align - 1UL)) - 1UL; + + if (start < end) + load_segment = start; + } + } + } + + return (load_segment); +} + +#if 0 +/* + * XXX this appears to be unused, but may have been for selecting the allowed + * kernels ABIs. It's been unused since the first commit, which suggests an + * error in bringing this into the tree. + */ +uint8_t +kboot_get_kernel_machine_bits(void) +{ + static uint8_t bits = 0; + struct old_utsname utsname; + int ret; + + if (bits == 0) { + /* Default is 32-bit kernel */ + bits = 32; + + /* Try to get system type */ + memset(&utsname, 0, sizeof(utsname)); + ret = host_uname(&utsname); + if (ret == 0) { + if (strcmp(utsname.machine, "ppc64") == 0) + bits = 64; + else if (strcmp(utsname.machine, "ppc64le") == 0) + bits = 64; + } + } + + return (bits); +} +#endif diff --git a/stand/kboot/kboot.h b/stand/kboot/kboot.h index 01de346234f3..13c9f9ad3032 100644 --- a/stand/kboot/kboot.h +++ b/stand/kboot/kboot.h @@ -1,12 +1,14 @@ /*- * Copyright (c) 2022, Netflix, Inc. * * SPDX-License-Identifier: BSD-2-Clause */ #ifndef KBOOT_H #define KBOOT_H void do_init(void); +uint64_t kboot_get_phys_load_segment(void); +uint8_t kboot_get_kernel_machine_bits(void); #endif /* KBOOT_H */ diff --git a/stand/kboot/main.c b/stand/kboot/main.c index be08528049e6..10dd6b05194b 100644 --- a/stand/kboot/main.c +++ b/stand/kboot/main.c @@ -1,499 +1,339 @@ /*- * Copyright (C) 2010-2014 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "host_syscall.h" #include "kboot.h" struct arch_switch archsw; extern void *_end; int kboot_getdev(void **vdev, const char *devspec, const char **path); ssize_t kboot_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t kboot_copyout(vm_offset_t src, void *dest, const size_t len); ssize_t kboot_readin(readin_handle_t fd, vm_offset_t dest, const size_t len); int kboot_autoload(void); uint64_t kboot_loadaddr(u_int type, void *data, uint64_t addr); static void kboot_kseg_get(int *nseg, void **ptr); extern int command_fdt_internal(int argc, char *argv[]); -struct region_desc { - uint64_t start; - uint64_t end; -}; - -static uint64_t -kboot_get_phys_load_segment(void) -{ - int fd; - uint64_t entry[2]; - static uint64_t load_segment = ~(0UL); - uint64_t val_64; - uint32_t val_32; - struct region_desc rsvd_reg[32]; - int rsvd_reg_cnt = 0; - int ret, a, b; - uint64_t start, end; - - if (load_segment == ~(0UL)) { - - /* Default load address is 0x00000000 */ - load_segment = 0UL; - - /* Read reserved regions */ - fd = host_open("/proc/device-tree/reserved-ranges", O_RDONLY, 0); - if (fd >= 0) { - while (host_read(fd, &entry[0], sizeof(entry)) == sizeof(entry)) { - rsvd_reg[rsvd_reg_cnt].start = be64toh(entry[0]); - rsvd_reg[rsvd_reg_cnt].end = - be64toh(entry[1]) + rsvd_reg[rsvd_reg_cnt].start - 1; - rsvd_reg_cnt++; - } - host_close(fd); - } - /* Read where the kernel ends */ - fd = host_open("/proc/device-tree/chosen/linux,kernel-end", O_RDONLY, 0); - if (fd >= 0) { - ret = host_read(fd, &val_64, sizeof(val_64)); - - if (ret == sizeof(uint64_t)) { - rsvd_reg[rsvd_reg_cnt].start = 0; - rsvd_reg[rsvd_reg_cnt].end = be64toh(val_64) - 1; - } else { - memcpy(&val_32, &val_64, sizeof(val_32)); - rsvd_reg[rsvd_reg_cnt].start = 0; - rsvd_reg[rsvd_reg_cnt].end = be32toh(val_32) - 1; - } - rsvd_reg_cnt++; - - host_close(fd); - } - /* Read memory size (SOCKET0 only) */ - fd = host_open("/proc/device-tree/memory@0/reg", O_RDONLY, 0); - if (fd < 0) - fd = host_open("/proc/device-tree/memory/reg", O_RDONLY, 0); - if (fd >= 0) { - ret = host_read(fd, &entry, sizeof(entry)); - - /* Memory range in start:length format */ - entry[0] = be64toh(entry[0]); - entry[1] = be64toh(entry[1]); - - /* Reserve everything what is before start */ - if (entry[0] != 0) { - rsvd_reg[rsvd_reg_cnt].start = 0; - rsvd_reg[rsvd_reg_cnt].end = entry[0] - 1; - rsvd_reg_cnt++; - } - /* Reserve everything what is after end */ - if (entry[1] != 0xffffffffffffffffUL) { - rsvd_reg[rsvd_reg_cnt].start = entry[0] + entry[1]; - rsvd_reg[rsvd_reg_cnt].end = 0xffffffffffffffffUL; - rsvd_reg_cnt++; - } - - host_close(fd); - } - - /* Sort entries in ascending order (bubble) */ - for (a = rsvd_reg_cnt - 1; a > 0; a--) { - for (b = 0; b < a; b++) { - if (rsvd_reg[b].start > rsvd_reg[b + 1].start) { - struct region_desc tmp; - tmp = rsvd_reg[b]; - rsvd_reg[b] = rsvd_reg[b + 1]; - rsvd_reg[b + 1] = tmp; - } - } - } - - /* Join overlapping/adjacent regions */ - for (a = 0; a < rsvd_reg_cnt - 1; ) { - - if ((rsvd_reg[a + 1].start >= rsvd_reg[a].start) && - ((rsvd_reg[a + 1].start - 1) <= rsvd_reg[a].end)) { - /* We have overlapping/adjacent regions! */ - rsvd_reg[a].end = - MAX(rsvd_reg[a].end, rsvd_reg[a + a].end); - - for (b = a + 1; b < rsvd_reg_cnt - 1; b++) - rsvd_reg[b] = rsvd_reg[b + 1]; - rsvd_reg_cnt--; - } else - a++; - } - - /* Find the first free region */ - if (rsvd_reg_cnt > 0) { - start = 0; - end = rsvd_reg[0].start; - for (a = 0; a < rsvd_reg_cnt - 1; a++) { - if ((start >= rsvd_reg[a].start) && - (start <= rsvd_reg[a].end)) { - start = rsvd_reg[a].end + 1; - end = rsvd_reg[a + 1].start; - } else - break; - } - - if (start != end) { - uint64_t align = 64UL*1024UL*1024UL; - - /* Align both to 64MB boundary */ - start = (start + align - 1UL) & ~(align - 1UL); - end = ((end + 1UL) & ~(align - 1UL)) - 1UL; - - if (start < end) - load_segment = start; - } - } - } - - return (load_segment); -} - -uint8_t -kboot_get_kernel_machine_bits(void) -{ - static uint8_t bits = 0; - struct old_utsname utsname; - int ret; - - if (bits == 0) { - /* Default is 32-bit kernel */ - bits = 32; - - /* Try to get system type */ - memset(&utsname, 0, sizeof(utsname)); - ret = host_uname(&utsname); - if (ret == 0) { - if (strcmp(utsname.machine, "ppc64") == 0) - bits = 64; - else if (strcmp(utsname.machine, "ppc64le") == 0) - bits = 64; - } - } - - return (bits); -} - int kboot_getdev(void **vdev, const char *devspec, const char **path) { int i, rv; const char *devpath, *filepath; struct devsw *dv; struct devdesc *desc; if (devspec == NULL) { rv = kboot_getdev(vdev, getenv("currdev"), NULL); if (rv == 0 && path != NULL) *path = devspec; return (rv); } if (strchr(devspec, ':') != NULL) { devpath = devspec; filepath = strchr(devspec, ':') + 1; } else { devpath = getenv("currdev"); filepath = devspec; } for (i = 0; (dv = devsw[i]) != NULL; i++) { if (strncmp(dv->dv_name, devpath, strlen(dv->dv_name)) == 0) goto found; } return (ENOENT); found: if (path != NULL && filepath != NULL) *path = filepath; else if (path != NULL) *path = strchr(devspec, ':') + 1; if (vdev != NULL) { desc = malloc(sizeof(*desc)); desc->d_dev = dv; desc->d_unit = 0; desc->d_opendata = strdup(devpath); *vdev = desc; } return (0); } int main(int argc, const char **argv) { void *heapbase; const size_t heapsize = 15*1024*1024; const char *bootdev; /* Give us a sane world if we're running as init */ do_init(); /* * Setup the heap 15MB should be plenty */ heapbase = host_getmem(heapsize); setheap(heapbase, heapbase + heapsize); /* * Set up console. */ cons_probe(); /* Choose bootdev if provided */ if (argc > 1) bootdev = argv[1]; else bootdev = ""; printf("Boot device: %s\n", bootdev); archsw.arch_getdev = kboot_getdev; archsw.arch_copyin = kboot_copyin; archsw.arch_copyout = kboot_copyout; archsw.arch_readin = kboot_readin; archsw.arch_autoload = kboot_autoload; archsw.arch_loadaddr = kboot_loadaddr; archsw.arch_kexec_kseg_get = kboot_kseg_get; printf("\n%s", bootprog_info); setenv("currdev", bootdev, 1); setenv("loaddev", bootdev, 1); setenv("LINES", "24", 1); setenv("usefdt", "1", 1); interact(); /* doesn't return */ return (0); } void exit(int code) { host_exit(code); __unreachable(); } void delay(int usecs) { struct host_timeval tvi, tv; uint64_t ti, t; host_gettimeofday(&tvi, NULL); ti = tvi.tv_sec*1000000 + tvi.tv_usec; do { host_gettimeofday(&tv, NULL); t = tv.tv_sec*1000000 + tv.tv_usec; } while (t < ti + usecs); } time_t getsecs(void) { struct host_timeval tv; host_gettimeofday(&tv, NULL); return (tv.tv_sec); } time_t time(time_t *tloc) { time_t rv; rv = getsecs(); if (tloc != NULL) *tloc = rv; return (rv); } struct host_kexec_segment loaded_segments[HOST_KEXEC_SEGMENT_MAX]; int nkexec_segments = 0; static ssize_t get_phys_buffer(vm_offset_t dest, const size_t len, void **buf) { int i = 0; const size_t segsize = 8*1024*1024; if (nkexec_segments == HOST_KEXEC_SEGMENT_MAX) panic("Tried to load too many kexec segments"); for (i = 0; i < nkexec_segments; i++) { if (dest >= (vm_offset_t)loaded_segments[i].mem && dest < (vm_offset_t)loaded_segments[i].mem + loaded_segments[i].memsz) goto out; } loaded_segments[nkexec_segments].buf = host_getmem(segsize); loaded_segments[nkexec_segments].bufsz = segsize; loaded_segments[nkexec_segments].mem = (void *)rounddown2(dest,segsize); loaded_segments[nkexec_segments].memsz = segsize; i = nkexec_segments; nkexec_segments++; out: *buf = loaded_segments[i].buf + (dest - (vm_offset_t)loaded_segments[i].mem); return (min(len,loaded_segments[i].bufsz - (dest - (vm_offset_t)loaded_segments[i].mem))); } ssize_t kboot_copyin(const void *src, vm_offset_t dest, const size_t len) { ssize_t segsize, remainder; void *destbuf; remainder = len; do { segsize = get_phys_buffer(dest, remainder, &destbuf); bcopy(src, destbuf, segsize); remainder -= segsize; src += segsize; dest += segsize; } while (remainder > 0); return (len); } ssize_t kboot_copyout(vm_offset_t src, void *dest, const size_t len) { ssize_t segsize, remainder; void *srcbuf; remainder = len; do { segsize = get_phys_buffer(src, remainder, &srcbuf); bcopy(srcbuf, dest, segsize); remainder -= segsize; src += segsize; dest += segsize; } while (remainder > 0); return (len); } ssize_t kboot_readin(readin_handle_t fd, vm_offset_t dest, const size_t len) { void *buf; size_t resid, chunk, get; ssize_t got; vm_offset_t p; p = dest; chunk = min(PAGE_SIZE, len); buf = malloc(chunk); if (buf == NULL) { printf("kboot_readin: buf malloc failed\n"); return (0); } for (resid = len; resid > 0; resid -= got, p += got) { get = min(chunk, resid); got = VECTX_READ(fd, buf, get); if (got <= 0) { if (got < 0) printf("kboot_readin: read failed\n"); break; } kboot_copyin(buf, p, got); } free (buf); return (len - resid); } int kboot_autoload(void) { return (0); } uint64_t kboot_loadaddr(u_int type, void *data, uint64_t addr) { if (type == LOAD_ELF) addr = roundup(addr, PAGE_SIZE); else addr += kboot_get_phys_load_segment(); return (addr); } static void kboot_kseg_get(int *nseg, void **ptr) { #if 0 int a; for (a = 0; a < nkexec_segments; a++) { printf("kseg_get: %jx %jx %jx %jx\n", (uintmax_t)loaded_segments[a].buf, (uintmax_t)loaded_segments[a].bufsz, (uintmax_t)loaded_segments[a].mem, (uintmax_t)loaded_segments[a].memsz); } #endif *nseg = nkexec_segments; *ptr = &loaded_segments[0]; } /* * Since proper fdt command handling function is defined in fdt_loader_cmd.c, * and declaring it as extern is in contradiction with COMMAND_SET() macro * (which uses static pointer), we're defining wrapper function, which * calls the proper fdt handling routine. */ static int command_fdt(int argc, char *argv[]) { return (command_fdt_internal(argc, argv)); } COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);