Index: head/sys/boot/ofw/common/main.c =================================================================== --- head/sys/boot/ofw/common/main.c (revision 279798) +++ head/sys/boot/ofw/common/main.c (revision 279799) @@ -1,190 +1,190 @@ /*- * Copyright (c) 2000 Benno Rice * Copyright (c) 2000 Stephane Potvin * 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 AUTHORS 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 __FBSDID("$FreeBSD$"); #include #include "openfirm.h" #include "libofw.h" #include "bootstrap.h" struct arch_switch archsw; /* MI/MD interface boundary */ extern char end[]; extern char bootprog_name[]; extern char bootprog_rev[]; extern char bootprog_date[]; extern char bootprog_maker[]; u_int32_t acells, scells; static char bootargs[128]; -#define HEAP_SIZE 0x80000 +#define HEAP_SIZE 0x100000 #define OF_puts(fd, text) OF_write(fd, text, strlen(text)) void init_heap(void) { void *base; ihandle_t stdout; if ((base = ofw_alloc_heap(HEAP_SIZE)) == (void *)0xffffffff) { OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); OF_puts(stdout, "Heap memory claim failed!\n"); OF_enter(); } setheap(base, (void *)((int)base + HEAP_SIZE)); } uint64_t memsize(void) { phandle_t memoryp; cell_t reg[24]; int i, sz; u_int64_t memsz; memsz = 0; memoryp = OF_instance_to_package(memory); sz = OF_getprop(memoryp, "reg", ®, sizeof(reg)); sz /= sizeof(reg[0]); for (i = 0; i < sz; i += (acells + scells)) { if (scells > 1) memsz += (uint64_t)reg[i + acells] << 32; memsz += reg[i + acells + scells - 1]; } return (memsz); } int main(int (*openfirm)(void *)) { phandle_t root; int i; char bootpath[64]; char *ch; int bargc; char **bargv; /* * Initalise the Open Firmware routines by giving them the entry point. */ OF_init(openfirm); root = OF_finddevice("/"); scells = acells = 1; OF_getprop(root, "#address-cells", &acells, sizeof(acells)); OF_getprop(root, "#size-cells", &scells, sizeof(scells)); /* * Initialise the heap as early as possible. Once this is done, * alloc() is usable. The stack is buried inside us, so this is * safe. */ init_heap(); /* * Set up console. */ cons_probe(); /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); printf("\n"); printf("%s, Revision %s\n", bootprog_name, bootprog_rev); printf("(%s, %s)\n", bootprog_maker, bootprog_date); printf("Memory: %lldKB\n", memsize() / 1024); OF_getprop(chosen, "bootpath", bootpath, 64); ch = strchr(bootpath, ':'); *ch = '\0'; printf("Booted from: %s\n", bootpath); printf("\n"); /* * Only parse the first bootarg if present. It should * be simple to handle extra arguments */ OF_getprop(chosen, "bootargs", bootargs, sizeof(bootargs)); bargc = 0; parse(&bargc, &bargv, bootargs); if (bargc == 1) env_setenv("currdev", EV_VOLATILE, bargv[0], ofw_setcurrdev, env_nounset); else env_setenv("currdev", EV_VOLATILE, bootpath, ofw_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, bootpath, env_noset, env_nounset); setenv("LINES", "24", 1); /* optional */ archsw.arch_getdev = ofw_getdev; archsw.arch_copyin = ofw_copyin; archsw.arch_copyout = ofw_copyout; archsw.arch_readin = ofw_readin; archsw.arch_autoload = ofw_autoload; interact(NULL); /* doesn't return */ OF_exit(); return 0; } COMMAND_SET(halt, "halt", "halt the system", command_halt); static int command_halt(int argc, char *argv[]) { OF_exit(); return (CMD_OK); } COMMAND_SET(memmap, "memmap", "print memory map", command_memmap); int command_memmap(int argc, char **argv) { ofw_memmap(acells); return (CMD_OK); } Index: head/sys/boot/ofw/libofw/elf_freebsd.c =================================================================== --- head/sys/boot/ofw/libofw/elf_freebsd.c (revision 279798) +++ head/sys/boot/ofw/libofw/elf_freebsd.c (revision 279799) @@ -1,98 +1,104 @@ /*- * Copyright (c) 2001 Benno Rice * 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 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "bootstrap.h" #include "libofw.h" #include "openfirm.h" extern char end[]; extern vm_offset_t reloc; /* From /conf.c */ int __elfN(ofw_loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) { int r; r = __elfN(loadfile)(filename, dest, result); if (r != 0) return (r); #if defined(__powerpc__) /* * No need to sync the icache for modules: this will * be done by the kernel after relocation. */ if (!strcmp((*result)->f_type, "elf kernel")) __syncicache((void *) (*result)->f_addr, (*result)->f_size); #endif return (0); } int __elfN(ofw_exec)(struct preloaded_file *fp) { struct file_metadata *fmp; - vm_offset_t mdp; + vm_offset_t mdp, dtbp; Elf_Ehdr *e; int error; intptr_t entry; if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) { return(EFTYPE); } e = (Elf_Ehdr *)&fmp->md_data; entry = e->e_entry; - if ((error = md_load(fp->f_args, &mdp)) != 0) + if ((error = md_load(fp->f_args, &mdp, &dtbp)) != 0) return (error); printf("Kernel entry at 0x%lx ...\n", e->e_entry); dev_cleanup(); ofw_release_heap(); - OF_chain((void *)reloc, end - (char *)reloc, (void *)entry, - (void *)mdp, sizeof(mdp)); + if (dtbp != 0) { + OF_quiesce(); + ((int (*)(u_long, u_long, u_long, void *, u_long))entry)(dtbp, 0, 0, + mdp, sizeof(mdp)); + } else { + OF_chain((void *)reloc, end - (char *)reloc, (void *)entry, + (void *)mdp, sizeof(mdp)); + } panic("exec returned"); } struct file_format ofw_elf = { __elfN(ofw_loadfile), __elfN(ofw_exec) }; Index: head/sys/boot/ofw/libofw/openfirm.c =================================================================== --- head/sys/boot/ofw/libofw/openfirm.c (revision 279798) +++ head/sys/boot/ofw/libofw/openfirm.c (revision 279799) @@ -1,771 +1,785 @@ /* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */ /*- * Copyright (C) 1995, 1996 Wolfgang Solfrank. * Copyright (C) 1995, 1996 TooLs GmbH. * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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. */ /*- * Copyright (C) 2000 Benno Rice. * 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 Benno Rice ``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 "openfirm.h" int (*openfirmware)(void *); phandle_t chosen; ihandle_t mmu; ihandle_t memory; int real_mode = 0; /* Initialiser */ void OF_init(int (*openfirm)(void *)) { phandle_t options; char mode[sizeof("true")]; openfirmware = openfirm; if ((chosen = OF_finddevice("/chosen")) == -1) OF_exit(); if (OF_getprop(chosen, "memory", &memory, sizeof(memory)) == -1) { memory = OF_open("/memory"); if (memory == -1) memory = OF_open("/memory@0"); if (memory == -1) OF_exit(); } if (OF_getprop(chosen, "mmu", &mmu, sizeof(mmu)) == -1) OF_exit(); /* * Check if we run in real mode. If so, we do not need to map * memory later on. */ options = OF_finddevice("/options"); if (OF_getprop(options, "real-mode?", mode, sizeof(mode)) > 0 && strcmp(mode, "true") == 0) real_mode = 1; } /* * Generic functions */ /* Test to see if a service exists. */ int OF_test(char *name) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t service; cell_t missing; } args = { (cell_t)"test", 1, 1, }; args.service = (cell_t)name; if (openfirmware(&args) == -1) return (-1); return (args.missing); } /* Return firmware millisecond count. */ int OF_milliseconds() { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t ms; } args = { (cell_t)"milliseconds", 0, 1, }; openfirmware(&args); return (args.ms); } /* * Device tree functions */ /* Return the next sibling of this node or 0. */ phandle_t OF_peer(phandle_t node) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t node; cell_t next; } args = { (cell_t)"peer", 1, 1, }; args.node = node; if (openfirmware(&args) == -1) return (-1); return (args.next); } /* Return the first child of this node or 0. */ phandle_t OF_child(phandle_t node) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t node; cell_t child; } args = { (cell_t)"child", 1, 1, }; args.node = node; if (openfirmware(&args) == -1) return (-1); return (args.child); } /* Return the parent of this node or 0. */ phandle_t OF_parent(phandle_t node) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t node; cell_t parent; } args = { (cell_t)"parent", 1, 1, }; args.node = node; if (openfirmware(&args) == -1) return (-1); return (args.parent); } /* Return the package handle that corresponds to an instance handle. */ phandle_t OF_instance_to_package(ihandle_t instance) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t instance; cell_t package; } args = { (cell_t)"instance-to-package", 1, 1, }; args.instance = instance; if (openfirmware(&args) == -1) return (-1); return (args.package); } /* Get the length of a property of a package. */ int OF_getproplen(phandle_t package, char *propname) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t package; cell_t propname; cell_t proplen; } args = { (cell_t)"getproplen", 2, 1, }; args.package = package; args.propname = (cell_t)propname; if (openfirmware(&args) == -1) return (-1); return (args.proplen); } /* Get the value of a property of a package. */ int OF_getprop(phandle_t package, char *propname, void *buf, int buflen) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t package; cell_t propname; cell_t buf; cell_t buflen; cell_t size; } args = { (cell_t)"getprop", 4, 1, }; args.package = package; args.propname = (cell_t)propname; args.buf = (cell_t)buf; args.buflen = buflen; if (openfirmware(&args) == -1) return (-1); return (args.size); } /* Get the next property of a package. */ int OF_nextprop(phandle_t package, char *previous, char *buf) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t package; cell_t previous; cell_t buf; cell_t flag; } args = { (cell_t)"nextprop", 3, 1, }; args.package = package; args.previous = (cell_t)previous; args.buf = (cell_t)buf; if (openfirmware(&args) == -1) return (-1); return (args.flag); } /* Set the value of a property of a package. */ /* XXX Has a bug on FirePower */ int OF_setprop(phandle_t package, char *propname, void *buf, int len) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t package; cell_t propname; cell_t buf; cell_t len; cell_t size; } args = { (cell_t)"setprop", 4, 1, }; args.package = package; args.propname = (cell_t)propname; args.buf = (cell_t)buf; args.len = len; if (openfirmware(&args) == -1) return (-1); return (args.size); } /* Convert a device specifier to a fully qualified pathname. */ int OF_canon(const char *device, char *buf, int len) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t device; cell_t buf; cell_t len; cell_t size; } args = { (cell_t)"canon", 3, 1, }; args.device = (cell_t)device; args.buf = (cell_t)buf; args.len = len; if (openfirmware(&args) == -1) return (-1); return (args.size); } /* Return a package handle for the specified device. */ phandle_t OF_finddevice(const char *device) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t device; cell_t package; } args = { (cell_t)"finddevice", 1, 1, }; args.device = (cell_t)device; if (openfirmware(&args) == -1) return (-1); return (args.package); } /* Return the fully qualified pathname corresponding to an instance. */ int OF_instance_to_path(ihandle_t instance, char *buf, int len) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t instance; cell_t buf; cell_t len; cell_t size; } args = { (cell_t)"instance-to-path", 3, 1, }; args.instance = instance; args.buf = (cell_t)buf; args.len = len; if (openfirmware(&args) == -1) return (-1); return (args.size); } /* Return the fully qualified pathname corresponding to a package. */ int OF_package_to_path(phandle_t package, char *buf, int len) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t package; cell_t buf; cell_t len; cell_t size; } args = { (cell_t)"package-to-path", 3, 1, }; args.package = package; args.buf = (cell_t)buf; args.len = len; if (openfirmware(&args) == -1) return (-1); return (args.size); } /* Call the method in the scope of a given instance. */ int OF_call_method(char *method, ihandle_t instance, int nargs, int nreturns, ...) { va_list ap; static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t method; cell_t instance; cell_t args_n_results[12]; } args = { (cell_t)"call-method", 2, 1, }; cell_t *cp; int n; if (nargs > 6) return (-1); args.nargs = nargs + 2; args.nreturns = nreturns + 1; args.method = (cell_t)method; args.instance = instance; va_start(ap, nreturns); for (cp = (cell_t *)(args.args_n_results + (n = nargs)); --n >= 0;) *--cp = va_arg(ap, cell_t); if (openfirmware(&args) == -1) return (-1); if (args.args_n_results[nargs]) return (args.args_n_results[nargs]); for (cp = (cell_t *)(args.args_n_results + nargs + (n = args.nreturns)); --n > 0;) *va_arg(ap, cell_t *) = *--cp; va_end(ap); return (0); } /* * Device I/O functions */ /* Open an instance for a device. */ ihandle_t OF_open(char *device) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t device; cell_t instance; } args = { (cell_t)"open", 1, 1, }; args.device = (cell_t)device; if (openfirmware(&args) == -1 || args.instance == 0) { return (-1); } return (args.instance); } /* Close an instance. */ void OF_close(ihandle_t instance) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t instance; } args = { (cell_t)"close", 1, }; args.instance = instance; openfirmware(&args); } /* Read from an instance. */ int OF_read(ihandle_t instance, void *addr, int len) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t instance; cell_t addr; cell_t len; cell_t actual; } args = { (cell_t)"read", 3, 1, }; args.instance = instance; args.addr = (cell_t)addr; args.len = len; #if defined(OPENFIRM_DEBUG) printf("OF_read: called with instance=%08x, addr=%p, len=%d\n", args.instance, args.addr, args.len); #endif if (openfirmware(&args) == -1) return (-1); #if defined(OPENFIRM_DEBUG) printf("OF_read: returning instance=%d, addr=%p, len=%d, actual=%d\n", args.instance, args.addr, args.len, args.actual); #endif return (args.actual); } /* Write to an instance. */ int OF_write(ihandle_t instance, void *addr, int len) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t instance; cell_t addr; cell_t len; cell_t actual; } args = { (cell_t)"write", 3, 1, }; args.instance = instance; args.addr = (cell_t)addr; args.len = len; if (openfirmware(&args) == -1) return (-1); return (args.actual); } /* Seek to a position. */ int OF_seek(ihandle_t instance, u_int64_t pos) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t instance; cell_t poshi; cell_t poslo; cell_t status; } args = { (cell_t)"seek", 3, 1, }; args.instance = instance; args.poshi = pos >> 32; args.poslo = pos; if (openfirmware(&args) == -1) return (-1); return (args.status); } /* * Memory functions */ /* Claim an area of memory. */ void * OF_claim(void *virt, u_int size, u_int align) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t virt; cell_t size; cell_t align; cell_t baseaddr; } args = { (cell_t)"claim", 3, 1, }; args.virt = (cell_t)virt; args.size = size; args.align = align; if (openfirmware(&args) == -1) return ((void *)-1); return ((void *)args.baseaddr); } /* Release an area of memory. */ void OF_release(void *virt, u_int size) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t virt; cell_t size; } args = { (cell_t)"release", 2, }; args.virt = (cell_t)virt; args.size = size; openfirmware(&args); } /* * Control transfer functions */ /* Reset the system and call "boot ". */ void OF_boot(char *bootspec) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t bootspec; } args = { (cell_t)"boot", 1, }; args.bootspec = (cell_t)bootspec; openfirmware(&args); for (;;) /* just in case */ ; } /* Suspend and drop back to the Open Firmware interface. */ void OF_enter() { static struct { cell_t name; cell_t nargs; cell_t nreturns; } args = { (cell_t)"enter", }; openfirmware(&args); /* We may come back. */ } /* Shut down and drop back to the Open Firmware interface. */ void OF_exit() { static struct { cell_t name; cell_t nargs; cell_t nreturns; } args = { (cell_t)"exit", }; openfirmware(&args); for (;;) /* just in case */ ; } +void +OF_quiesce() +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + } args = { + (cell_t)"quiesce", + }; + + openfirmware(&args); +} + /* Free bytes starting at , then call with . */ #if 0 void OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len) { static struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t virt; cell_t size; cell_t entry; cell_t arg; cell_t len; } args = { (cell_t)"chain", 5, }; args.virt = (cell_t)virt; args.size = size; args.entry = (cell_t)entry; args.arg = (cell_t)arg; args.len = len; openfirmware(&args); } #else void OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len) { /* * This is a REALLY dirty hack till the firmware gets this going */ #if 0 if (size > 0) OF_release(virt, size); #endif entry(0, 0, openfirmware, arg, len); } #endif Index: head/sys/boot/ofw/libofw/openfirm.h =================================================================== --- head/sys/boot/ofw/libofw/openfirm.h (revision 279798) +++ head/sys/boot/ofw/libofw/openfirm.h (revision 279799) @@ -1,121 +1,122 @@ /* $NetBSD: openfirm.h,v 1.1 1998/05/15 10:16:00 tsubai Exp $ */ /*- * Copyright (C) 1995, 1996 Wolfgang Solfrank. * Copyright (C) 1995, 1996 TooLs GmbH. * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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. */ /*- * Copyright (C) 2000 Benno Rice. * 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 Benno Rice ``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. * * $FreeBSD$ */ #ifndef _OPENFIRM_H_ #define _OPENFIRM_H_ /* * Prototypes for Open Firmware Interface Routines */ #include #include typedef unsigned int ihandle_t; typedef unsigned int phandle_t; typedef unsigned long int cell_t; extern int (*openfirmware)(void *); extern phandle_t chosen; extern ihandle_t memory, mmu; extern int real_mode; /* * This isn't actually an Open Firmware function, but it seemed like the right * place for it to go. */ void OF_init(int (*openfirm)(void *)); /* Generic functions */ int OF_test(char *); +void OF_quiesce(); /* Disable firmware */ /* Device tree functions */ phandle_t OF_peer(phandle_t); phandle_t OF_child(phandle_t); phandle_t OF_parent(phandle_t); phandle_t OF_instance_to_package(ihandle_t); int OF_getproplen(phandle_t, char *); int OF_getprop(phandle_t, char *, void *, int); int OF_nextprop(phandle_t, char *, char *); int OF_setprop(phandle_t, char *, void *, int); int OF_canon(const char *, char *, int); phandle_t OF_finddevice(const char *); int OF_instance_to_path(ihandle_t, char *, int); int OF_package_to_path(phandle_t, char *, int); int OF_call_method(char *, ihandle_t, int, int, ...); /* Device I/O functions */ ihandle_t OF_open(char *); void OF_close(ihandle_t); int OF_read(ihandle_t, void *, int); int OF_write(ihandle_t, void *, int); int OF_seek(ihandle_t, u_quad_t); /* Memory functions */ void *OF_claim(void *, u_int, u_int); void OF_release(void *, u_int); /* Control transfer functions */ void OF_boot(char *); void OF_enter(void); void OF_exit(void) __attribute__((noreturn)); void OF_chain(void *, u_int, void (*)(), void *, u_int); /* Time function */ int OF_milliseconds(void); #endif /* _OPENFIRM_H_ */ Index: head/sys/boot/ofw/libofw/ppc64_elf_freebsd.c =================================================================== --- head/sys/boot/ofw/libofw/ppc64_elf_freebsd.c (revision 279798) +++ head/sys/boot/ofw/libofw/ppc64_elf_freebsd.c (revision 279799) @@ -1,101 +1,107 @@ /*- * Copyright (c) 2001 Benno Rice * 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 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 __FBSDID("$FreeBSD$"); #define __ELF_WORD_SIZE 64 #include #include #include #include #include #include "bootstrap.h" #include "libofw.h" #include "openfirm.h" extern char end[]; extern vm_offset_t reloc; /* From /conf.c */ int ppc64_ofw_elf_loadfile(char *filename, u_int64_t dest, struct preloaded_file **result) { int r; r = __elfN(loadfile)(filename, dest, result); if (r != 0) return (r); /* * No need to sync the icache for modules: this will * be done by the kernel after relocation. */ if (!strcmp((*result)->f_type, "elf kernel")) __syncicache((void *) (*result)->f_addr, (*result)->f_size); return (0); } int ppc64_ofw_elf_exec(struct preloaded_file *fp) { struct file_metadata *fmp; - vm_offset_t mdp; + vm_offset_t mdp, dtbp; Elf_Ehdr *e; int error; intptr_t entry; if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) { return(EFTYPE); } e = (Elf_Ehdr *)&fmp->md_data; /* Handle function descriptor */ entry = *(uint64_t *)e->e_entry; - if ((error = md_load64(fp->f_args, &mdp)) != 0) + if ((error = md_load64(fp->f_args, &mdp, &dtbp)) != 0) return (error); printf("Kernel entry at 0x%lx ...\n", entry); dev_cleanup(); ofw_release_heap(); - OF_chain((void *)reloc, end - (char *)reloc, (void *)entry, - (void *)mdp, sizeof(mdp)); + if (dtbp != 0) { + OF_quiesce(); + ((int (*)(u_long, u_long, u_long, void *, u_long))entry)(dtbp, 0, 0, + mdp, sizeof(mdp)); + } else { + OF_chain((void *)reloc, end - (char *)reloc, (void *)entry, + (void *)mdp, sizeof(mdp)); + } panic("exec returned"); } struct file_format ofw_elf64 = { ppc64_ofw_elf_loadfile, ppc64_ofw_elf_exec }; Index: head/sys/boot/powerpc/ofw/Makefile =================================================================== --- head/sys/boot/powerpc/ofw/Makefile (revision 279798) +++ head/sys/boot/powerpc/ofw/Makefile (revision 279799) @@ -1,117 +1,126 @@ # $FreeBSD$ .include MK_SSP= no PROG= loader NEWVERSWHAT= "Open Firmware loader" ${MACHINE_ARCH} BINDIR?= /boot INSTALLFLAGS= -b # Architecture-specific loader code SRCS= conf.c metadata.c vers.c start.c SRCS+= ucmpdi2.c LOADER_DISK_SUPPORT?= yes LOADER_UFS_SUPPORT?= yes LOADER_CD9660_SUPPORT?= yes LOADER_EXT2FS_SUPPORT?= no LOADER_NET_SUPPORT?= yes LOADER_NFS_SUPPORT?= yes LOADER_TFTP_SUPPORT?= no LOADER_GZIP_SUPPORT?= yes LOADER_BZIP2_SUPPORT?= no +LOADER_FDT_SUPPORT?= yes .if ${LOADER_DISK_SUPPORT} == "yes" CFLAGS+= -DLOADER_DISK_SUPPORT .endif .if ${LOADER_UFS_SUPPORT} == "yes" CFLAGS+= -DLOADER_UFS_SUPPORT .endif .if ${LOADER_CD9660_SUPPORT} == "yes" CFLAGS+= -DLOADER_CD9660_SUPPORT .endif .if ${LOADER_EXT2FS_SUPPORT} == "yes" CFLAGS+= -DLOADER_EXT2FS_SUPPORT .endif .if ${LOADER_GZIP_SUPPORT} == "yes" CFLAGS+= -DLOADER_GZIP_SUPPORT .endif .if ${LOADER_BZIP2_SUPPORT} == "yes" CFLAGS+= -DLOADER_BZIP2_SUPPORT .endif .if ${LOADER_NET_SUPPORT} == "yes" CFLAGS+= -DLOADER_NET_SUPPORT .endif .if ${LOADER_NFS_SUPPORT} == "yes" CFLAGS+= -DLOADER_NFS_SUPPORT .endif .if ${LOADER_TFTP_SUPPORT} == "yes" CFLAGS+= -DLOADER_TFTP_SUPPORT .endif +.if ${LOADER_FDT_SUPPORT} == "yes" +SRCS+= ofwfdt.c +CFLAGS+= -I${.CURDIR}/../../fdt +CFLAGS+= -I${.OBJDIR}/../../fdt +CFLAGS+= -I${.CURDIR}/../../../contrib/libfdt +CFLAGS+= -DLOADER_FDT_SUPPORT +LIBFDT= ${.OBJDIR}/../../fdt/libfdt.a +.endif .if ${MK_FORTH} != "no" # Enable BootForth BOOT_FORTH= yes CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/powerpc LIBFICL= ${.OBJDIR}/../../ficl/libficl.a .endif # Avoid the open-close-dance for every file access as some firmwares perform # an auto-negotiation on every open of the network interface and thus causes # netbooting to take horribly long. CFLAGS+= -DNETIF_OPEN_CLOSE_ONCE # Always add MI sources .PATH: ${.CURDIR}/../../common ${.CURDIR}/../../../libkern .include "${.CURDIR}/../../common/Makefile.inc" CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../../.. CFLAGS+= -I. CLEANFILES+= vers.c loader.help CFLAGS+= -ffreestanding -msoft-float # load address. set in linker script RELOC?= 0x1C00000 CFLAGS+= -DRELOC=${RELOC} LDFLAGS= -nostdlib -static -T ${.CURDIR}/ldscript.powerpc # Pull in common loader code .PATH: ${.CURDIR}/../../ofw/common .include "${.CURDIR}/../../ofw/common/Makefile.inc" # Open Firmware standalone support library LIBOFW= ${.OBJDIR}/../../ofw/libofw/libofw.a CFLAGS+= -I${.CURDIR}/../../ofw/libofw # where to get libstand from LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ -DPADD= ${LIBFICL} ${LIBOFW} ${LIBSTAND} -LDADD= ${LIBFICL} ${LIBOFW} ${LIBSTAND} +DPADD= ${LIBFICL} ${LIBOFW} ${LIBFDT} ${LIBSTAND} +LDADD= ${LIBFICL} ${LIBOFW} ${LIBFDT} ${LIBSTAND} vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} -loader.help: help.common help.ofw +loader.help: help.common help.ofw ${.CURDIR}/../../fdt/help.fdt cat ${.ALLSRC} | \ awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} .PATH: ${.CURDIR}/../../forth FILES= loader.help loader.4th support.4th loader.conf FILES+= screen.4th frames.4th FILES+= beastie.4th brand.4th check-password.4th color.4th delay.4th FILES+= menu.4th menu-commands.4th menusets.4th shortcuts.4th version.4th FILESDIR_loader.conf= /boot/defaults .if !exists(${DESTDIR}/boot/loader.rc) FILES+= loader.rc .endif .if !exists(${DESTDIR}/boot/menu.rc) FILES+= menu.rc .endif .include Index: head/sys/boot/powerpc/ofw/metadata.c =================================================================== --- head/sys/boot/powerpc/ofw/metadata.c (revision 279798) +++ head/sys/boot/powerpc/ofw/metadata.c (revision 279799) @@ -1,334 +1,349 @@ /*- * Copyright (c) 1998 Michael Smith * 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 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. * * from: FreeBSD: src/sys/boot/sparc64/loader/metadata.c,v 1.6 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include +#include #include #include "bootstrap.h" -#include "libofw.h" int md_getboothowto(char *kargs) { char *cp; int howto; int active; int i; /* Parse kargs */ howto = 0; if (kargs != NULL) { cp = kargs; active = 0; while (*cp != 0) { if (!active && (*cp == '-')) { active = 1; } else if (active) switch (*cp) { case 'a': howto |= RB_ASKNAME; break; case 'C': howto |= RB_CDROM; break; case 'd': howto |= RB_KDB; break; case 'D': howto |= RB_MULTIPLE; break; case 'm': howto |= RB_MUTE; break; case 'g': howto |= RB_GDB; break; case 'h': howto |= RB_SERIAL; break; case 'p': howto |= RB_PAUSE; break; case 'r': howto |= RB_DFLTROOT; break; case 's': howto |= RB_SINGLE; break; case 'v': howto |= RB_VERBOSE; break; default: active = 0; break; } cp++; } } /* get equivalents from the environment */ for (i = 0; howto_names[i].ev != NULL; i++) if (getenv(howto_names[i].ev) != NULL) howto |= howto_names[i].mask; if (!strcmp(getenv("console"), "comconsole")) howto |= RB_SERIAL; if (!strcmp(getenv("console"), "nullconsole")) howto |= RB_MUTE; return(howto); } /* * Copy the environment into the load area starting at (addr). * Each variable is formatted as =, with a single nul * separating each variable, and a double nul terminating the environment. */ vm_offset_t md_copyenv(vm_offset_t addr) { struct env_var *ep; /* traverse the environment */ for (ep = environ; ep != NULL; ep = ep->ev_next) { archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name)); addr += strlen(ep->ev_name); archsw.arch_copyin("=", addr, 1); addr++; if (ep->ev_value != NULL) { archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value)); addr += strlen(ep->ev_value); } archsw.arch_copyin("", addr, 1); addr++; } archsw.arch_copyin("", addr, 1); addr++; return(addr); } /* * Copy module-related data into the load area, where it can be * used as a directory for loaded modules. * * Module data is presented in a self-describing format. Each datum * is preceded by a 32-bit identifier and a 32-bit size field. * * Currently, the following data are saved: * * MOD_NAME (variable) module name (string) * MOD_TYPE (variable) module type (string) * MOD_ARGS (variable) module parameters (string) * MOD_ADDR sizeof(vm_offset_t) module load address * MOD_SIZE sizeof(size_t) module size * MOD_METADATA (variable) type-specific metadata */ static int align; #define COPY32(v, a, c) { \ u_int32_t x = (v); \ if (c) \ archsw.arch_copyin(&x, a, sizeof(x)); \ a += sizeof(x); \ } #define MOD_STR(t, a, s, c) { \ COPY32(t, a, c); \ COPY32(strlen(s) + 1, a, c) \ if (c) \ archsw.arch_copyin(s, a, strlen(s) + 1);\ a += roundup(strlen(s) + 1, align); \ } #define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) #define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) #define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) #define MOD_VAR(t, a, s, c) { \ COPY32(t, a, c); \ COPY32(sizeof(s), a, c); \ if (c) \ archsw.arch_copyin(&s, a, sizeof(s)); \ a += roundup(sizeof(s), align); \ } #define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) #define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) #define MOD_METADATA(a, mm, c) { \ COPY32(MODINFO_METADATA | mm->md_type, a, c);\ COPY32(mm->md_size, a, c); \ if (c) \ archsw.arch_copyin(mm->md_data, a, mm->md_size);\ a += roundup(mm->md_size, align); \ } #define MOD_END(a, c) { \ COPY32(MODINFO_END, a, c); \ COPY32(0, a, c); \ } vm_offset_t md_copymodules(vm_offset_t addr, int kern64) { struct preloaded_file *fp; struct file_metadata *md; uint64_t scratch64; int c; c = addr != 0; /* start with the first module on the list, should be the kernel */ for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { MOD_NAME(addr, fp->f_name, c); /* this field must come first */ MOD_TYPE(addr, fp->f_type, c); if (fp->f_args) MOD_ARGS(addr, fp->f_args, c); if (kern64) { scratch64 = fp->f_addr; MOD_ADDR(addr, scratch64, c); scratch64 = fp->f_size; MOD_SIZE(addr, scratch64, c); } else { MOD_ADDR(addr, fp->f_addr, c); MOD_SIZE(addr, fp->f_size, c); } for (md = fp->f_metadata; md != NULL; md = md->md_next) { if (!(md->md_type & MODINFOMD_NOCOPY)) { MOD_METADATA(addr, md, c); } } } MOD_END(addr, c); return(addr); } /* * Load the information expected by a powerpc kernel. * * - The 'boothowto' argument is constructed * - The 'bootdev' argument is constructed * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int -md_load_dual(char *args, vm_offset_t *modulep, int kern64) +md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64) { struct preloaded_file *kfp; struct preloaded_file *xp; struct file_metadata *md; vm_offset_t kernend; vm_offset_t addr; vm_offset_t envp; + vm_offset_t fdtp; vm_offset_t size; uint64_t scratch64; char *rootdevname; int howto; align = kern64 ? 8 : 4; howto = md_getboothowto(args); /* * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ rootdevname = getenv("rootdev"); if (rootdevname == NULL) rootdevname = getenv("currdev"); /* Try reading the /etc/fstab file to select the root device */ getrootmount(rootdevname); /* find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* copy our environment */ envp = addr; addr = md_copyenv(addr); /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); + /* Copy out FDT */ + *dtb = fdtp = 0; + if (getenv("usefdt") != NULL) { + size = fdt_copy(addr); + *dtb = fdtp = addr; + addr = roundup(addr + size, PAGE_SIZE); + } + kernend = 0; kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel"); if (kfp == NULL) kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) panic("can't find kernel file"); file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); if (kern64) { scratch64 = envp; file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64); + if (fdtp != 0) { + scratch64 = fdtp; + file_addmetadata(kfp, MODINFOMD_DTBP, sizeof scratch64, &scratch64); + } scratch64 = kernend; file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof scratch64, &scratch64); } else { file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); + if (fdtp != 0) + file_addmetadata(kfp, MODINFOMD_DTBP, sizeof fdtp, &fdtp); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); } *modulep = addr; size = md_copymodules(0, kern64); kernend = roundup(addr + size, PAGE_SIZE); md = file_findmetadata(kfp, MODINFOMD_KERNEND); if (kern64) { scratch64 = kernend; bcopy(&scratch64, md->md_data, sizeof scratch64); } else { bcopy(&kernend, md->md_data, sizeof kernend); } (void)md_copymodules(addr, kern64); return(0); } int -md_load(char *args, vm_offset_t *modulep) +md_load(char *args, vm_offset_t *modulep, vm_offset_t *dtb) { - return (md_load_dual(args, modulep, 0)); + return (md_load_dual(args, modulep, dtb, 0)); } int -md_load64(char *args, vm_offset_t *modulep) +md_load64(char *args, vm_offset_t *modulep, vm_offset_t *dtb) { - return (md_load_dual(args, modulep, 1)); + return (md_load_dual(args, modulep, dtb, 1)); } Index: head/sys/boot/powerpc/ofw/ofwfdt.c =================================================================== --- head/sys/boot/powerpc/ofw/ofwfdt.c (nonexistent) +++ head/sys/boot/powerpc/ofw/ofwfdt.c (revision 279799) @@ -0,0 +1,202 @@ +/*- + * Copyright (C) 2014-2015 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 "bootstrap.h" + +static int +OF_hasprop(phandle_t node, const char *prop) +{ + return (OF_getproplen(node, prop) > 0); +} + +static void +add_node_to_fdt(void *buffer, phandle_t node, int fdt_offset) +{ + int i, child_offset, error; + char name[2048], *lastprop, *subname; + void *propbuf; + size_t proplen; + + lastprop = NULL; + while (OF_nextprop(node, lastprop, name) > 0) { + proplen = OF_getproplen(node, name); + propbuf = malloc(proplen); + OF_getprop(node, name, propbuf, proplen); + error = fdt_setprop(buffer, fdt_offset, name, propbuf, proplen); + free(propbuf); + lastprop = name; + if (error) + printf("Error %d adding property %s to " + "node %d\n", error, name, fdt_offset); + } + + if (!OF_hasprop(node, "phandle") && !OF_hasprop(node, "linux,phandle") + && !OF_hasprop(node, "ibm,phandle")) + fdt_setprop(buffer, fdt_offset, "phandle", &node, sizeof(node)); + + for (node = OF_child(node); node > 0; node = OF_peer(node)) { + OF_package_to_path(node, name, sizeof(name)); + subname = strrchr(name, '/'); + subname++; + child_offset = fdt_add_subnode(buffer, fdt_offset, subname); + if (child_offset < 0) { + printf("Error %d adding node %s (%s), skipping\n", + child_offset, name, subname); + continue; + } + + add_node_to_fdt(buffer, node, child_offset); + } +} + +static void +ofwfdt_fixups(void *fdtp) +{ + int offset, len, i; + phandle_t node; + ihandle_t rtas; + const void *prop; + + /* + * Instantiate and add reservations for RTAS state if present + */ + + offset = fdt_path_offset(fdtp, "/rtas"); + if (offset > 0) { + uint32_t base; + void *rtasmem; + char path[255]; + + node = OF_finddevice("/rtas"); + OF_package_to_path(node, path, sizeof(path)); + OF_getprop(node, "rtas-size", &len, sizeof(len)); + + /* Allocate memory */ + rtasmem = OF_claim(0, len, 4096); + + /* Instantiate RTAS */ + rtas = OF_open(path); + base = 0; + OF_call_method("instantiate-rtas", rtas, 1, 1, (cell_t)rtas, + &base); + + /* Store info to FDT using Linux convention */ + base = cpu_to_fdt32(base); + fdt_setprop(fdtp, offset, "linux,rtas-entry", &base, + sizeof(base)); + base = cpu_to_fdt32((uint32_t)rtasmem); + offset = fdt_path_offset(fdtp, "/rtas"); + fdt_setprop(fdtp, offset, "linux,rtas-base", &base, + sizeof(base)); + + /* Mark RTAS private data area reserved */ + fdt_add_mem_rsv(fdtp, base, len); + } else { + /* + * Remove /memory/available properties, which reflect long-gone OF + * state. Note that this doesn't work if we need RTAS still, since + * that's part of the firmware. + */ + + offset = fdt_path_offset(fdtp, "/memory@0"); + if (offset > 0) + fdt_delprop(fdtp, offset, "available"); + } + + /* + + /* + * Convert stored ihandles under /chosen to xref phandles + */ + offset = fdt_path_offset(fdtp, "/chosen"); + if (offset > 0) { + const char *chosenprops[] = {"stdout", "stdin", "mmu", "cpu", + NULL}; + const uint32_t *ihand; + for (i = 0; chosenprops[i] != NULL; i++) { + ihand = fdt_getprop(fdtp, offset, chosenprops[i], &len); + if (ihand != NULL && len == sizeof(*ihand)) { + node = OF_instance_to_package( + fdt32_to_cpu(*ihand)); + if (OF_hasprop(node, "phandle")) + OF_getprop(node, "phandle", &node, + sizeof(node)); + else if (OF_hasprop(node, "linux,phandle")) + OF_getprop(node, "linux,phandle", &node, + sizeof(node)); + else if (OF_hasprop(node, "ibm,phandle")) + OF_getprop(node, "ibm,phandle", &node, + sizeof(node)); + node = cpu_to_fdt32(node); + fdt_setprop(fdtp, offset, chosenprops[i], &node, sizeof(node)); + } + + /* Refind node in case it moved */ + offset = fdt_path_offset(fdtp, "/chosen"); + } + } +} + +int +fdt_platform_load_dtb(void) +{ + void *buffer; + size_t buflen = 409600; + + buffer = malloc(buflen); + fdt_create_empty_tree(buffer, buflen); + add_node_to_fdt(buffer, OF_peer(0), fdt_path_offset(buffer, "/")); + ofwfdt_fixups(buffer); + fdt_pack(buffer); + + fdt_load_dtb_addr(buffer); + free(buffer); + + return (0); +} + +void +fdt_platform_fixups(void) +{ + +} + +static int +command_fdt(int argc, char *argv[]) +{ + + return (command_fdt_internal(argc, argv)); +} + +COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); + Property changes on: head/sys/boot/powerpc/ofw/ofwfdt.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/boot/sparc64/loader/metadata.c =================================================================== --- head/sys/boot/sparc64/loader/metadata.c (revision 279798) +++ head/sys/boot/sparc64/loader/metadata.c (revision 279799) @@ -1,344 +1,345 @@ /*- * Copyright (c) 1998 Michael Smith * 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 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. * * from: FreeBSD: src/sys/boot/i386/libi386/bootinfo.c,v 1.29 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "bootstrap.h" #include "libofw.h" extern struct tlb_entry *dtlb_store; extern struct tlb_entry *itlb_store; extern int dtlb_slot; extern int itlb_slot; static int md_bootserial(void); int md_getboothowto(char *kargs) { char *cp; int howto; int active; int i; /* Parse kargs */ howto = 0; if (kargs != NULL) { cp = kargs; active = 0; while (*cp != 0) { if (!active && (*cp == '-')) { active = 1; } else if (active) switch (*cp) { case 'a': howto |= RB_ASKNAME; break; case 'C': howto |= RB_CDROM; break; case 'd': howto |= RB_KDB; break; case 'D': howto |= RB_MULTIPLE; break; case 'm': howto |= RB_MUTE; break; case 'g': howto |= RB_GDB; break; case 'h': howto |= RB_SERIAL; break; case 'p': howto |= RB_PAUSE; break; case 'r': howto |= RB_DFLTROOT; break; case 's': howto |= RB_SINGLE; break; case 'v': howto |= RB_VERBOSE; break; default: active = 0; break; } cp++; } } /* get equivalents from the environment */ for (i = 0; howto_names[i].ev != NULL; i++) if (getenv(howto_names[i].ev) != NULL) howto |= howto_names[i].mask; if (md_bootserial() != -1) howto |= RB_SERIAL; return(howto); } static int md_bootserial(void) { char buf[64]; ihandle_t inst; phandle_t input; phandle_t node; phandle_t output; if ((node = OF_finddevice("/options")) == -1) return(-1); if (OF_getprop(node, "input-device", buf, sizeof(buf)) == -1) return(-1); input = OF_finddevice(buf); if (OF_getprop(node, "output-device", buf, sizeof(buf)) == -1) return(-1); output = OF_finddevice(buf); if (input == -1 || output == -1 || OF_getproplen(input, "keyboard") >= 0) { if ((node = OF_finddevice("/chosen")) == -1) return(-1); if (OF_getprop(node, "stdin", &inst, sizeof(inst)) == -1) return(-1); if ((input = OF_instance_to_package(inst)) == -1) return(-1); if (OF_getprop(node, "stdout", &inst, sizeof(inst)) == -1) return(-1); if ((output = OF_instance_to_package(inst)) == -1) return(-1); } if (input != output) return(-1); if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1) return(-1); if (strcmp(buf, "serial") != 0) return(-1); return(0); } /* * Copy the environment into the load area starting at (addr). * Each variable is formatted as =, with a single nul * separating each variable, and a double nul terminating the environment. */ vm_offset_t md_copyenv(vm_offset_t addr) { struct env_var *ep; /* traverse the environment */ for (ep = environ; ep != NULL; ep = ep->ev_next) { archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name)); addr += strlen(ep->ev_name); archsw.arch_copyin("=", addr, 1); addr++; if (ep->ev_value != NULL) { archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value)); addr += strlen(ep->ev_value); } archsw.arch_copyin("", addr, 1); addr++; } archsw.arch_copyin("", addr, 1); addr++; return(addr); } /* * Copy module-related data into the load area, where it can be * used as a directory for loaded modules. * * Module data is presented in a self-describing format. Each datum * is preceded by a 32-bit identifier and a 32-bit size field. * * Currently, the following data are saved: * * MOD_NAME (variable) module name (string) * MOD_TYPE (variable) module type (string) * MOD_ARGS (variable) module parameters (string) * MOD_ADDR sizeof(vm_offset_t) module load address * MOD_SIZE sizeof(size_t) module size * MOD_METADATA (variable) type-specific metadata */ #define COPY32(v, a, c) { \ u_int32_t x = (v); \ if (c) \ archsw.arch_copyin(&x, a, sizeof(x)); \ a += sizeof(x); \ } #define MOD_STR(t, a, s, c) { \ COPY32(t, a, c); \ COPY32(strlen(s) + 1, a, c) \ if (c) \ archsw.arch_copyin(s, a, strlen(s) + 1);\ a += roundup(strlen(s) + 1, sizeof(u_long));\ } #define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) #define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) #define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) #define MOD_VAR(t, a, s, c) { \ COPY32(t, a, c); \ COPY32(sizeof(s), a, c); \ if (c) \ archsw.arch_copyin(&s, a, sizeof(s)); \ a += roundup(sizeof(s), sizeof(u_long)); \ } #define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) #define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) #define MOD_METADATA(a, mm, c) { \ COPY32(MODINFO_METADATA | mm->md_type, a, c);\ COPY32(mm->md_size, a, c); \ if (c) \ archsw.arch_copyin(mm->md_data, a, mm->md_size);\ a += roundup(mm->md_size, sizeof(u_long)); \ } #define MOD_END(a, c) { \ COPY32(MODINFO_END, a, c); \ COPY32(0, a, c); \ } vm_offset_t md_copymodules(vm_offset_t addr) { struct preloaded_file *fp; struct file_metadata *md; int c; c = addr != 0; /* start with the first module on the list, should be the kernel */ for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { MOD_NAME(addr, fp->f_name, c); /* this field must come first */ MOD_TYPE(addr, fp->f_type, c); if (fp->f_args) MOD_ARGS(addr, fp->f_args, c); MOD_ADDR(addr, fp->f_addr, c); MOD_SIZE(addr, fp->f_size, c); for (md = fp->f_metadata; md != NULL; md = md->md_next) { if (!(md->md_type & MODINFOMD_NOCOPY)) { MOD_METADATA(addr, md, c); } } } MOD_END(addr, c); return(addr); } /* * Load the information expected by a sparc64 kernel. * * - The 'boothowto' argument is constructed * - The 'bootdev' argument is constructed * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int -md_load(char *args, vm_offset_t *modulep) +md_load(char *args, vm_offset_t *modulep, vm_offset_t *dtbp) { struct preloaded_file *kfp; struct preloaded_file *xp; struct file_metadata *md; vm_offset_t kernend; vm_offset_t addr; vm_offset_t envp; vm_offset_t size; char *rootdevname; int howto; howto = md_getboothowto(args); + *dtbp = 0; /* * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ if ((rootdevname = getenv("rootdev")) == NULL) rootdevname = getenv("currdev"); getrootmount(rootdevname); /* find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* copy our environment */ envp = addr; addr = md_copyenv(addr); /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); kernend = 0; kfp = file_findfile(NULL, "elf64 kernel"); if (kfp == NULL) kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) panic("can't find kernel file"); file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); file_addmetadata(kfp, MODINFOMD_DTLB_SLOTS, sizeof dtlb_slot, &dtlb_slot); file_addmetadata(kfp, MODINFOMD_ITLB_SLOTS, sizeof itlb_slot, &itlb_slot); file_addmetadata(kfp, MODINFOMD_DTLB, dtlb_slot * sizeof(*dtlb_store), dtlb_store); file_addmetadata(kfp, MODINFOMD_ITLB, itlb_slot * sizeof(*itlb_store), itlb_store); *modulep = addr; size = md_copymodules(0); kernend = roundup(addr + size, PAGE_SIZE); md = file_findmetadata(kfp, MODINFOMD_KERNEND); bcopy(&kernend, md->md_data, sizeof kernend); (void)md_copymodules(addr); return(0); }