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/types.h> 27#include <fdt_platform.h> 28#include <libfdt.h> 29#include "bootstrap.h" 30#include "host_syscall.h" 31#include "kboot.h" 32 33static void 34add_node_to_fdt(void *buffer, const char *path, int fdt_offset) 35{ 36 int child_offset, fd, pfd, error, dentsize; 37 char subpath[512]; 38 void *propbuf; 39 ssize_t proplen; 40 41 char dents[2048]; 42 struct host_dirent64 *dent; 43 int d_type; 44 45 fd = host_open(path, O_RDONLY, 0); 46 while (1) { 47 dentsize = host_getdents64(fd, dents, sizeof(dents)); 48 if (dentsize <= 0) 49 break; 50 for (dent = (struct host_dirent64 *)dents; 51 (char *)dent < dents + dentsize; 52 dent = (struct host_dirent64 *)((void *)dent + dent->d_reclen)) { 53 sprintf(subpath, "%s/%s", path, dent->d_name); 54 if (strcmp(dent->d_name, ".") == 0 || 55 strcmp(dent->d_name, "..") == 0) 56 continue; 57 d_type = dent->d_type; 58 if (d_type == HOST_DT_DIR) { 59 child_offset = fdt_add_subnode(buffer, fdt_offset, 60 dent->d_name); 61 if (child_offset < 0) { 62 printf("Error %d adding node %s/%s, skipping\n", 63 child_offset, path, dent->d_name); 64 continue; 65 } 66 add_node_to_fdt(buffer, subpath, child_offset); 67 } else { 68 propbuf = malloc(1024); 69 proplen = 0; 70 pfd = host_open(subpath, O_RDONLY, 0); 71 if (pfd > 0) { 72 proplen = host_read(pfd, propbuf, 1024); 73 host_close(pfd); 74 } 75 error = fdt_setprop(buffer, fdt_offset, dent->d_name, 76 propbuf, proplen); 77 free(propbuf); 78 if (error) 79 printf("Error %d adding property %s to " 80 "node %d\n", error, dent->d_name, 81 fdt_offset); 82 } 83 } 84 } 85 86 host_close(fd); 87} 88 89int 90fdt_platform_load_dtb(void) 91{ 92 void *buffer; 93 size_t buflen = 409600; 94 int fd, err = 0; 95 96 /* 97 * Should load /sys/firmware/fdt if it exists, otherwise we walk the 98 * tree from /proc/device-tree. The former is much easier than the 99 * latter and also the newer interface. But as long as we support the 100 * PS3 boot, we'll need the latter due to that kernel's age. 101 */ 102 buffer = malloc(buflen); 103 fd = host_open("/sys/firmware/fdt", O_RDONLY, 0); 104 if (fd >= 0) { 105 err = host_read(fd, buffer, buflen); 106 close(fd); 107 } 108 if (fd < 0 || err < 0) { 109 fdt_create_empty_tree(buffer, buflen); 110 add_node_to_fdt(buffer, "/proc/device-tree", 111 fdt_path_offset(buffer, "/")); 112 } 113 fdt_arch_fixups(buffer); 114 115 fdt_pack(buffer); 116 117 fdt_load_dtb_addr(buffer); 118 free(buffer); 119 120 return (0); 121} 122 123void 124fdt_platform_load_overlays(void) 125{ 126 fdt_load_dtb_overlays(NULL); 127} 128 129void 130fdt_platform_fixups(void) 131{ 132 fdt_apply_overlays(); 133} 134