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 #include <stand.h> 28 #include <sys/param.h> 29 #include <fdt_platform.h> 30 #include <openfirm.h> 31 #include <libfdt.h> 32 #include "bootstrap.h" 33 34 extern int command_fdt_internal(int argc, char *argv[]); 35 36 static int 37 OF_hasprop(phandle_t node, const char *prop) 38 { 39 return (OF_getproplen(node, (char *)prop) > 0); 40 } 41 42 static void 43 add_node_to_fdt(void *buffer, phandle_t node, int fdt_offset) 44 { 45 int i, child_offset, error; 46 char name[255], *lastprop, *subname; 47 void *propbuf; 48 ssize_t proplen; 49 50 lastprop = NULL; 51 while (OF_nextprop(node, lastprop, name) > 0) { 52 proplen = OF_getproplen(node, name); 53 54 /* Detect and correct for errors and strangeness */ 55 if (proplen < 0) 56 proplen = 0; 57 if (proplen > 1024) 58 proplen = 1024; 59 60 propbuf = malloc(proplen); 61 if (propbuf == NULL) { 62 printf("Cannot allocate memory for prop %s\n", name); 63 return; 64 } 65 OF_getprop(node, name, propbuf, proplen); 66 error = fdt_setprop(buffer, fdt_offset, name, propbuf, proplen); 67 free(propbuf); 68 lastprop = name; 69 if (error) 70 printf("Error %d adding property %s to " 71 "node %d\n", error, name, fdt_offset); 72 } 73 74 if (!OF_hasprop(node, "phandle") && !OF_hasprop(node, "linux,phandle") 75 && !OF_hasprop(node, "ibm,phandle")) 76 fdt_setprop(buffer, fdt_offset, "phandle", &node, sizeof(node)); 77 78 for (node = OF_child(node); node > 0; node = OF_peer(node)) { 79 OF_package_to_path(node, name, sizeof(name)); 80 subname = strrchr(name, '/'); 81 subname++; 82 child_offset = fdt_add_subnode(buffer, fdt_offset, subname); 83 if (child_offset < 0) { 84 printf("Error %d adding node %s (%s), skipping\n", 85 child_offset, name, subname); 86 continue; 87 } 88 89 add_node_to_fdt(buffer, node, child_offset); 90 } 91 } 92 93 static void 94 ofwfdt_fixups(void *fdtp) 95 { 96 int offset, len, i; 97 phandle_t node; 98 ihandle_t rtas; 99 const void *prop; 100 101 /* 102 * Instantiate and add reservations for RTAS state if present 103 */ 104 105 offset = fdt_path_offset(fdtp, "/rtas"); 106 if (offset > 0) { 107 uint32_t base; 108 void *rtasmem; 109 char path[255]; 110 111 node = OF_finddevice("/rtas"); 112 OF_package_to_path(node, path, sizeof(path)); 113 OF_getencprop(node, "rtas-size", &len, sizeof(len)); 114 115 /* Allocate memory */ 116 rtasmem = OF_claim(0, len, 4096); 117 118 /* Instantiate RTAS */ 119 rtas = OF_open(path); 120 base = 0; 121 OF_call_method("instantiate-rtas", rtas, 1, 1, (cell_t)rtasmem, 122 &base); 123 124 /* Store info to FDT using Linux convention */ 125 base = cpu_to_fdt32(base); 126 fdt_setprop(fdtp, offset, "linux,rtas-entry", &base, 127 sizeof(base)); 128 base = cpu_to_fdt32((uint32_t)rtasmem); 129 offset = fdt_path_offset(fdtp, "/rtas"); 130 fdt_setprop(fdtp, offset, "linux,rtas-base", &base, 131 sizeof(base)); 132 133 /* Mark RTAS private data area reserved */ 134 base = fdt32_to_cpu(base); 135 fdt_add_mem_rsv(fdtp, base, len); 136 } else { 137 /* 138 * Remove /memory/available properties, which reflect long-gone 139 * OF state. Note that this doesn't work if we need RTAS still, 140 * since that's part of the firmware. 141 */ 142 offset = fdt_path_offset(fdtp, "/memory@0"); 143 if (offset > 0) 144 fdt_delprop(fdtp, offset, "available"); 145 } 146 147 148 /* 149 * Convert stored ihandles under /chosen to xref phandles 150 */ 151 offset = fdt_path_offset(fdtp, "/chosen"); 152 if (offset > 0) { 153 const char *chosenprops[] = {"stdout", "stdin", "mmu", "cpu", 154 NULL}; 155 const uint32_t *ihand; 156 for (i = 0; chosenprops[i] != NULL; i++) { 157 ihand = fdt_getprop(fdtp, offset, chosenprops[i], &len); 158 if (ihand != NULL && len == sizeof(*ihand)) { 159 node = OF_instance_to_package(*ihand); 160 if (OF_hasprop(node, "phandle")) 161 OF_getprop(node, "phandle", &node, 162 sizeof(node)); 163 else if (OF_hasprop(node, "linux,phandle")) 164 OF_getprop(node, "linux,phandle", &node, 165 sizeof(node)); 166 else if (OF_hasprop(node, "ibm,phandle")) 167 OF_getprop(node, "ibm,phandle", &node, 168 sizeof(node)); 169 fdt_setprop(fdtp, offset, chosenprops[i], &node, 170 sizeof(node)); 171 } 172 173 /* Refind node in case it moved */ 174 offset = fdt_path_offset(fdtp, "/chosen"); 175 } 176 } 177 } 178 179 int 180 fdt_platform_load_dtb(void) 181 { 182 void *buffer; 183 size_t buflen = 409600; 184 185 buffer = malloc(buflen); 186 fdt_create_empty_tree(buffer, buflen); 187 add_node_to_fdt(buffer, OF_peer(0), fdt_path_offset(buffer, "/")); 188 ofwfdt_fixups(buffer); 189 fdt_pack(buffer); 190 191 fdt_load_dtb_addr(buffer); 192 free(buffer); 193 194 return (0); 195 } 196 197 void 198 fdt_platform_load_overlays(void) 199 { 200 201 } 202 203 void 204 fdt_platform_fixups(void) 205 { 206 207 } 208 209 static int 210 command_fdt(int argc, char *argv[]) 211 { 212 213 return (command_fdt_internal(argc, argv)); 214 } 215 216 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); 217 218