1 /*- 2 * Copyright (C) 2014-2015 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <stand.h> 30 #include <sys/param.h> 31 #include <fdt_platform.h> 32 #include <openfirm.h> 33 #include <libfdt.h> 34 #include "bootstrap.h" 35 36 extern int command_fdt_internal(int argc, char *argv[]); 37 38 static int 39 OF_hasprop(phandle_t node, const char *prop) 40 { 41 return (OF_getproplen(node, (char *)prop) > 0); 42 } 43 44 static void 45 add_node_to_fdt(void *buffer, phandle_t node, int fdt_offset) 46 { 47 int i, child_offset, error; 48 char name[255], *lastprop, *subname; 49 void *propbuf; 50 ssize_t proplen; 51 52 lastprop = NULL; 53 while (OF_nextprop(node, lastprop, name) > 0) { 54 proplen = OF_getproplen(node, name); 55 56 /* Detect and correct for errors and strangeness */ 57 if (proplen < 0) 58 proplen = 0; 59 if (proplen > 1024) 60 proplen = 1024; 61 62 propbuf = malloc(proplen); 63 if (propbuf == NULL) { 64 printf("Cannot allocate memory for prop %s\n", name); 65 return; 66 } 67 OF_getprop(node, name, propbuf, proplen); 68 error = fdt_setprop(buffer, fdt_offset, name, propbuf, proplen); 69 free(propbuf); 70 lastprop = name; 71 if (error) 72 printf("Error %d adding property %s to " 73 "node %d\n", error, name, fdt_offset); 74 } 75 76 if (!OF_hasprop(node, "phandle") && !OF_hasprop(node, "linux,phandle") 77 && !OF_hasprop(node, "ibm,phandle")) 78 fdt_setprop(buffer, fdt_offset, "phandle", &node, sizeof(node)); 79 80 for (node = OF_child(node); node > 0; node = OF_peer(node)) { 81 OF_package_to_path(node, name, sizeof(name)); 82 subname = strrchr(name, '/'); 83 subname++; 84 child_offset = fdt_add_subnode(buffer, fdt_offset, subname); 85 if (child_offset < 0) { 86 printf("Error %d adding node %s (%s), skipping\n", 87 child_offset, name, subname); 88 continue; 89 } 90 91 add_node_to_fdt(buffer, node, child_offset); 92 } 93 } 94 95 static void 96 ofwfdt_fixups(void *fdtp) 97 { 98 int offset, len, i; 99 phandle_t node; 100 ihandle_t rtas; 101 const void *prop; 102 103 /* 104 * Instantiate and add reservations for RTAS state if present 105 */ 106 107 offset = fdt_path_offset(fdtp, "/rtas"); 108 if (offset > 0) { 109 uint32_t base; 110 void *rtasmem; 111 char path[255]; 112 113 node = OF_finddevice("/rtas"); 114 OF_package_to_path(node, path, sizeof(path)); 115 OF_getprop(node, "rtas-size", &len, sizeof(len)); 116 117 /* Allocate memory */ 118 rtasmem = OF_claim(0, len, 4096); 119 120 /* Instantiate RTAS */ 121 rtas = OF_open(path); 122 base = 0; 123 OF_call_method("instantiate-rtas", rtas, 1, 1, (cell_t)rtas, 124 &base); 125 126 /* Store info to FDT using Linux convention */ 127 base = cpu_to_fdt32(base); 128 fdt_setprop(fdtp, offset, "linux,rtas-entry", &base, 129 sizeof(base)); 130 base = cpu_to_fdt32((uint32_t)rtasmem); 131 offset = fdt_path_offset(fdtp, "/rtas"); 132 fdt_setprop(fdtp, offset, "linux,rtas-base", &base, 133 sizeof(base)); 134 135 /* Mark RTAS private data area reserved */ 136 fdt_add_mem_rsv(fdtp, base, len); 137 } else { 138 /* 139 * Remove /memory/available properties, which reflect long-gone 140 * OF state. Note that this doesn't work if we need RTAS still, 141 * since that's part of the firmware. 142 */ 143 offset = fdt_path_offset(fdtp, "/memory@0"); 144 if (offset > 0) 145 fdt_delprop(fdtp, offset, "available"); 146 } 147 148 149 /* 150 * Convert stored ihandles under /chosen to xref phandles 151 */ 152 offset = fdt_path_offset(fdtp, "/chosen"); 153 if (offset > 0) { 154 const char *chosenprops[] = {"stdout", "stdin", "mmu", "cpu", 155 NULL}; 156 const uint32_t *ihand; 157 for (i = 0; chosenprops[i] != NULL; i++) { 158 ihand = fdt_getprop(fdtp, offset, chosenprops[i], &len); 159 if (ihand != NULL && len == sizeof(*ihand)) { 160 node = OF_instance_to_package( 161 fdt32_to_cpu(*ihand)); 162 if (OF_hasprop(node, "phandle")) 163 OF_getprop(node, "phandle", &node, 164 sizeof(node)); 165 else if (OF_hasprop(node, "linux,phandle")) 166 OF_getprop(node, "linux,phandle", &node, 167 sizeof(node)); 168 else if (OF_hasprop(node, "ibm,phandle")) 169 OF_getprop(node, "ibm,phandle", &node, 170 sizeof(node)); 171 node = cpu_to_fdt32(node); 172 fdt_setprop(fdtp, offset, chosenprops[i], &node, 173 sizeof(node)); 174 } 175 176 /* Refind node in case it moved */ 177 offset = fdt_path_offset(fdtp, "/chosen"); 178 } 179 } 180 } 181 182 int 183 fdt_platform_load_dtb(void) 184 { 185 void *buffer; 186 size_t buflen = 409600; 187 188 buffer = malloc(buflen); 189 fdt_create_empty_tree(buffer, buflen); 190 add_node_to_fdt(buffer, OF_peer(0), fdt_path_offset(buffer, "/")); 191 ofwfdt_fixups(buffer); 192 fdt_pack(buffer); 193 194 fdt_load_dtb_addr(buffer); 195 free(buffer); 196 197 return (0); 198 } 199 200 void 201 fdt_platform_fixups(void) 202 { 203 204 } 205 206 static int 207 command_fdt(int argc, char *argv[]) 208 { 209 210 return (command_fdt_internal(argc, argv)); 211 } 212 213 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); 214 215