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