Date: Mon, 9 Mar 2015 02:57:35 +0000 (UTC) From: Nathan Whitehorn <nwhitehorn@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r279799 - in head/sys/boot: ofw/common ofw/libofw powerpc/ofw sparc64/loader Message-ID: <201503090257.t292vZfn019820@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: nwhitehorn Date: Mon Mar 9 02:57:34 2015 New Revision: 279799 URL: https://svnweb.freebsd.org/changeset/base/279799 Log: Provide a shim layer in loader to condense the Open Firmware device tree to an FDT. This is how Linux and OS X boot and can avoid some issues with using Open Firmware at runtime. The code is highly experimental and disabled by default; it can be turned on by setting the loader environment variable "usefdt" to a non-NULL value. Added: head/sys/boot/powerpc/ofw/ofwfdt.c (contents, props changed) Modified: head/sys/boot/ofw/common/main.c head/sys/boot/ofw/libofw/elf_freebsd.c head/sys/boot/ofw/libofw/openfirm.c head/sys/boot/ofw/libofw/openfirm.h head/sys/boot/ofw/libofw/ppc64_elf_freebsd.c head/sys/boot/powerpc/ofw/Makefile head/sys/boot/powerpc/ofw/metadata.c head/sys/boot/sparc64/loader/metadata.c Modified: head/sys/boot/ofw/common/main.c ============================================================================== --- head/sys/boot/ofw/common/main.c Mon Mar 9 02:19:44 2015 (r279798) +++ head/sys/boot/ofw/common/main.c Mon Mar 9 02:57:34 2015 (r279799) @@ -45,7 +45,7 @@ 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)) Modified: head/sys/boot/ofw/libofw/elf_freebsd.c ============================================================================== --- head/sys/boot/ofw/libofw/elf_freebsd.c Mon Mar 9 02:19:44 2015 (r279798) +++ head/sys/boot/ofw/libofw/elf_freebsd.c Mon Mar 9 02:57:34 2015 (r279799) @@ -67,7 +67,7 @@ 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; @@ -78,15 +78,21 @@ __elfN(ofw_exec)(struct preloaded_file * 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"); } Modified: head/sys/boot/ofw/libofw/openfirm.c ============================================================================== --- head/sys/boot/ofw/libofw/openfirm.c Mon Mar 9 02:19:44 2015 (r279798) +++ head/sys/boot/ofw/libofw/openfirm.c Mon Mar 9 02:57:34 2015 (r279799) @@ -729,6 +729,20 @@ OF_exit() ; } +void +OF_quiesce() +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + } args = { + (cell_t)"quiesce", + }; + + openfirmware(&args); +} + /* Free <size> bytes starting at <virt>, then call <entry> with <arg>. */ #if 0 void Modified: head/sys/boot/ofw/libofw/openfirm.h ============================================================================== --- head/sys/boot/ofw/libofw/openfirm.h Mon Mar 9 02:19:44 2015 (r279798) +++ head/sys/boot/ofw/libofw/openfirm.h Mon Mar 9 02:57:34 2015 (r279799) @@ -82,6 +82,7 @@ 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); Modified: head/sys/boot/ofw/libofw/ppc64_elf_freebsd.c ============================================================================== --- head/sys/boot/ofw/libofw/ppc64_elf_freebsd.c Mon Mar 9 02:19:44 2015 (r279798) +++ head/sys/boot/ofw/libofw/ppc64_elf_freebsd.c Mon Mar 9 02:57:34 2015 (r279799) @@ -67,7 +67,7 @@ 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; @@ -80,7 +80,7 @@ ppc64_ofw_elf_exec(struct preloaded_file /* 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); @@ -88,8 +88,14 @@ ppc64_ofw_elf_exec(struct preloaded_file 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"); } Modified: head/sys/boot/powerpc/ofw/Makefile ============================================================================== --- head/sys/boot/powerpc/ofw/Makefile Mon Mar 9 02:19:44 2015 (r279798) +++ head/sys/boot/powerpc/ofw/Makefile Mon Mar 9 02:57:34 2015 (r279799) @@ -21,6 +21,7 @@ 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 @@ -49,6 +50,14 @@ CFLAGS+= -DLOADER_NFS_SUPPORT .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 @@ -89,13 +98,13 @@ CFLAGS+= -I${.CURDIR}/../../ofw/libofw 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} Modified: head/sys/boot/powerpc/ofw/metadata.c ============================================================================== --- head/sys/boot/powerpc/ofw/metadata.c Mon Mar 9 02:19:44 2015 (r279798) +++ head/sys/boot/powerpc/ofw/metadata.c Mon Mar 9 02:57:34 2015 (r279799) @@ -34,11 +34,11 @@ __FBSDID("$FreeBSD$"); #include <sys/reboot.h> #include <sys/linker.h> #include <sys/boot.h> +#include <fdt_platform.h> #include <machine/metadata.h> #include "bootstrap.h" -#include "libofw.h" int md_getboothowto(char *kargs) @@ -243,7 +243,7 @@ md_copymodules(vm_offset_t addr, int ker * - 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; @@ -251,6 +251,7 @@ md_load_dual(char *args, vm_offset_t *mo 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; @@ -286,6 +287,14 @@ md_load_dual(char *args, vm_offset_t *mo /* 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) @@ -296,10 +305,16 @@ md_load_dual(char *args, vm_offset_t *mo 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); } @@ -321,14 +336,14 @@ md_load_dual(char *args, vm_offset_t *mo } 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)); } Added: head/sys/boot/powerpc/ofw/ofwfdt.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/boot/powerpc/ofw/ofwfdt.c Mon Mar 9 02:57:34 2015 (r279799) @@ -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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <sys/param.h> +#include <fdt_platform.h> +#include <openfirm.h> +#include <libfdt.h> +#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); + Modified: head/sys/boot/sparc64/loader/metadata.c ============================================================================== --- head/sys/boot/sparc64/loader/metadata.c Mon Mar 9 02:19:44 2015 (r279798) +++ head/sys/boot/sparc64/loader/metadata.c Mon Mar 9 02:57:34 2015 (r279799) @@ -276,7 +276,7 @@ md_copymodules(vm_offset_t addr) * - 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; @@ -289,6 +289,7 @@ md_load(char *args, vm_offset_t *modulep int howto; howto = md_getboothowto(args); + *dtbp = 0; /* * Allow the environment variable 'rootdev' to override the supplied device
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201503090257.t292vZfn019820>