kbootfdt.c revision 329175
1/*- 2 * Copyright (C) 2014 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: stable/11/stand/powerpc/kboot/kbootfdt.c 329175 2018-02-12 17:44:35Z kevans $"); 28 29#include <sys/types.h> 30#include <fdt_platform.h> 31#include <libfdt.h> 32#include "bootstrap.h" 33#include "host_syscall.h" 34 35static void 36add_node_to_fdt(void *buffer, const char *path, int fdt_offset) 37{ 38 int child_offset, fd, pfd, error, dentsize; 39 char subpath[512]; 40 void *propbuf; 41 ssize_t proplen; 42 43 struct host_dent { 44 unsigned long d_fileno; 45 unsigned long d_off; 46 unsigned short d_reclen; 47 char d_name[]; 48 /* uint8_t d_type; */ 49 }; 50 char dents[2048]; 51 struct host_dent *dent; 52 int d_type; 53 54 fd = host_open(path, O_RDONLY, 0); 55 while (1) { 56 dentsize = host_getdents(fd, dents, sizeof(dents)); 57 if (dentsize <= 0) 58 break; 59 for (dent = (struct host_dent *)dents; 60 (char *)dent < dents + dentsize; 61 dent = (struct host_dent *)((void *)dent + dent->d_reclen)) { 62 sprintf(subpath, "%s/%s", path, dent->d_name); 63 if (strcmp(dent->d_name, ".") == 0 || 64 strcmp(dent->d_name, "..") == 0) 65 continue; 66 d_type = *((char *)(dent) + dent->d_reclen - 1); 67 if (d_type == 4 /* DT_DIR */) { 68 child_offset = fdt_add_subnode(buffer, fdt_offset, 69 dent->d_name); 70 if (child_offset < 0) { 71 printf("Error %d adding node %s/%s, skipping\n", 72 child_offset, path, dent->d_name); 73 continue; 74 } 75 76 add_node_to_fdt(buffer, subpath, child_offset); 77 } else { 78 propbuf = malloc(1024); 79 proplen = 0; 80 pfd = host_open(subpath, O_RDONLY, 0); 81 if (pfd > 0) { 82 proplen = host_read(pfd, propbuf, 1024); 83 host_close(pfd); 84 } 85 error = fdt_setprop(buffer, fdt_offset, dent->d_name, 86 propbuf, proplen); 87 free(propbuf); 88 if (error) 89 printf("Error %d adding property %s to " 90 "node %d\n", error, dent->d_name, 91 fdt_offset); 92 } 93 } 94 } 95 96 host_close(fd); 97} 98 99/* Fix up wrong values added to the device tree by prom_init() in Linux */ 100 101static void 102fdt_linux_fixups(void *fdtp) 103{ 104 int offset, len; 105 const void *prop; 106 107 /* 108 * Remove /memory/available properties, which reflect long-gone OF 109 * state 110 */ 111 112 offset = fdt_path_offset(fdtp, "/memory@0"); 113 if (offset > 0) 114 fdt_delprop(fdtp, offset, "available"); 115 116 /* 117 * Add reservations for OPAL and RTAS state if present 118 */ 119 120 offset = fdt_path_offset(fdtp, "/ibm,opal"); 121 if (offset > 0) { 122 const uint64_t *base, *size; 123 base = fdt_getprop(fdtp, offset, "opal-base-address", 124 &len); 125 size = fdt_getprop(fdtp, offset, "opal-runtime-size", 126 &len); 127 if (base != NULL && size != NULL) 128 fdt_add_mem_rsv(fdtp, fdt64_to_cpu(*base), 129 fdt64_to_cpu(*size)); 130 } 131 offset = fdt_path_offset(fdtp, "/rtas"); 132 if (offset > 0) { 133 const uint32_t *base, *size; 134 base = fdt_getprop(fdtp, offset, "linux,rtas-base", &len); 135 size = fdt_getprop(fdtp, offset, "rtas-size", &len); 136 if (base != NULL && size != NULL) 137 fdt_add_mem_rsv(fdtp, fdt32_to_cpu(*base), 138 fdt32_to_cpu(*size)); 139 } 140 141 /* 142 * Patch up /chosen nodes so that the stored handles mean something, 143 * where possible. 144 */ 145 offset = fdt_path_offset(fdtp, "/chosen"); 146 if (offset > 0) { 147 fdt_delprop(fdtp, offset, "cpu"); /* This node not meaningful */ 148 149 offset = fdt_path_offset(fdtp, "/chosen"); 150 prop = fdt_getprop(fdtp, offset, "linux,stdout-package", &len); 151 if (prop != NULL) { 152 fdt_setprop(fdtp, offset, "stdout", prop, len); 153 offset = fdt_path_offset(fdtp, "/chosen"); 154 fdt_setprop(fdtp, offset, "stdin", prop, len); 155 } 156 } 157} 158 159int 160fdt_platform_load_dtb(void) 161{ 162 void *buffer; 163 size_t buflen = 409600; 164 165 buffer = malloc(buflen); 166 fdt_create_empty_tree(buffer, buflen); 167 add_node_to_fdt(buffer, "/proc/device-tree", 168 fdt_path_offset(buffer, "/")); 169 fdt_linux_fixups(buffer); 170 171 fdt_pack(buffer); 172 173 fdt_load_dtb_addr(buffer); 174 free(buffer); 175 176 return (0); 177} 178 179void 180fdt_platform_fixups(void) 181{ 182 183} 184 185