static int dt_add_psci_node(void *fdt) { int offs; if (fdt_path_offset(fdt, "/psci") >= 0) { DMSG("PSCI Device Tree node already exists!\n"); return 0; } offs = fdt_path_offset(fdt, "/"); if (offs < 0) return -1; offs = fdt_add_subnode(fdt, offs, "psci"); if (offs < 0) return -1; if (append_psci_compatible(fdt, offs, "arm,psci-1.0")) return -1; if (append_psci_compatible(fdt, offs, "arm,psci-0.2")) return -1; if (append_psci_compatible(fdt, offs, "arm,psci")) return -1; if (fdt_setprop_string(fdt, offs, "method", "smc")) return -1; if (fdt_setprop_u32(fdt, offs, "cpu_suspend", PSCI_CPU_SUSPEND)) return -1; if (fdt_setprop_u32(fdt, offs, "cpu_off", PSCI_CPU_OFF)) return -1; if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON)) return -1; if (fdt_setprop_u32(fdt, offs, "sys_poweroff", PSCI_SYSTEM_OFF)) return -1; if (fdt_setprop_u32(fdt, offs, "sys_reset", PSCI_SYSTEM_RESET)) return -1; return 0; }
/* Function to add the subsequent RAM partition info to the device tree. */ int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint32_t addr, uint32_t size) { static int mem_info_cnt = 0; int ret; if (!mem_info_cnt) { /* Replace any other reg prop in the memory node. */ ret = fdt_setprop_u32(fdt, offset, "reg", addr); mem_info_cnt = 1; } else { /* Append the mem info to the reg prop for subsequent nodes. */ ret = fdt_appendprop_u32(fdt, offset, "reg", addr); } if (ret) { dprintf(CRITICAL, "Failed to add the memory information addr: %d\n", ret); } ret = fdt_appendprop_u32(fdt, offset, "reg", size); if (ret) { dprintf(CRITICAL, "Failed to add the memory information size: %d\n", ret); } return ret; }
static inline int fdt_setprop_uxx(void *fdt, int nodeoffset, const char *name, uint64_t val, int is_u64) { if (is_u64) return fdt_setprop_u64(fdt, nodeoffset, name, val); else return fdt_setprop_u32(fdt, nodeoffset, name, (uint32_t)val); }
static int ft_fixup_clocks(void *fdt, const char **names, u32 *rates, int num) { int offs, node_offs, ret, i; uint32_t phandle; offs = fdt_path_offset(fdt, "/ocp/l4@4a000000/cm_core_aon@5000/clocks"); if (offs < 0) { debug("Could not find cm_core_aon clocks node path offset : %s\n", fdt_strerror(offs)); return offs; } for (i = 0; i < num; i++) { node_offs = fdt_subnode_offset(fdt, offs, names[i]); if (node_offs < 0) { debug("Could not find clock sub-node %s: %s\n", names[i], fdt_strerror(node_offs)); return offs; } phandle = fdt_get_phandle(fdt, node_offs); if (!phandle) { debug("Could not find phandle for clock %s\n", names[i]); return -1; } ret = fdt_setprop_u32(fdt, node_offs, "assigned-clocks", phandle); if (ret < 0) { debug("Could not add assigned-clocks property to clock node %s: %s\n", names[i], fdt_strerror(ret)); return ret; } ret = fdt_setprop_u32(fdt, node_offs, "assigned-clock-rates", rates[i]); if (ret < 0) { debug("Could not add assigned-clock-rates property to clock node %s: %s\n", names[i], fdt_strerror(ret)); return ret; } } return 0; }
/** * cros_ec_write_state() - Write out our state to the state file * * The caller will ensure that there is a node ready for the state. The node * may already contain the old state, in which case it is overridden. * * @param blob: Device tree blob holding state * @param node: Node to write our state into */ static int cros_ec_write_state(void *blob, int node) { struct ec_state *ec = g_state; /* We are guaranteed enough space to write basic properties */ fdt_setprop_u32(blob, node, "current-image", ec->current_image); fdt_setprop(blob, node, "vbnv-context", ec->vbnv_context, sizeof(ec->vbnv_context)); return state_setprop(node, "flash-data", ec->flash_data, ec->ec_config.flash.length); }
int fdt_record_loadable(void *blob, u32 index, const char *name, uintptr_t load_addr, u32 size, uintptr_t entry_point, const char *type, const char *os) { int err, node; err = fdt_check_header(blob); if (err < 0) { printf("%s: %s\n", __func__, fdt_strerror(err)); return err; } /* find or create "/fit-images" node */ node = fdt_find_or_add_subnode(blob, 0, "fit-images"); if (node < 0) return node; /* find or create "/fit-images/<name>" node */ node = fdt_find_or_add_subnode(blob, node, name); if (node < 0) return node; /* * We record these as 32bit entities, possibly truncating addresses. * However, spl_fit.c is not 64bit safe either: i.e. we should not * have an issue here. */ fdt_setprop_u32(blob, node, "load-addr", load_addr); if (entry_point != -1) fdt_setprop_u32(blob, node, "entry-point", entry_point); fdt_setprop_u32(blob, node, "size", size); if (type) fdt_setprop_string(blob, node, "type", type); if (os) fdt_setprop_string(blob, node, "os", os); return node; }
/* * This function updates the mmu-masters property on the SMMU * node as per the SMMU binding-- phandle and list of stream IDs * for each MMU master. */ void append_mmu_masters(void *blob, const char *smmu_path, const char *master_name, u32 *stream_ids, int count) { u32 phandle; int smmu_nodeoffset; int master_nodeoffset; int i; /* get phandle of mmu master device */ master_nodeoffset = fdt_path_offset(blob, master_name); if (master_nodeoffset < 0) { printf("\n%s: ERROR: master not found\n", __func__); return; } phandle = fdt_get_phandle(blob, master_nodeoffset); if (!phandle) { /* if master has no phandle, create one */ phandle = fdt_create_phandle(blob, master_nodeoffset); if (!phandle) { printf("\n%s: ERROR: unable to create phandle\n", __func__); return; } } /* append it to mmu-masters */ smmu_nodeoffset = fdt_path_offset(blob, smmu_path); if (fdt_appendprop_u32(blob, smmu_nodeoffset, "mmu-masters", phandle) < 0) { printf("\n%s: ERROR: unable to update SMMU node\n", __func__); return; } /* for each stream ID, append to mmu-masters */ for (i = 0; i < count; i++) { fdt_appendprop_u32(blob, smmu_nodeoffset, "mmu-masters", stream_ids[i]); } /* fix up #stream-id-cells with stream ID count */ if (fdt_setprop_u32(blob, master_nodeoffset, "#stream-id-cells", count) < 0) printf("\n%s: ERROR: unable to update #stream-id-cells\n", __func__); }
int dev_tree_setprop_u32(void *fdt, char *node, const char *property, uint32_t value) { int ret = 0; int offset; offset = fdt_path_offset(fdt, node); if (offset < 0) { dprintf(CRITICAL, "Could not found %s node.\n" , node); return offset; } ret = fdt_setprop_u32(fdt, offset, property, value); if (ret < 0) { dprintf(CRITICAL, "Could not set %d value to %s property in %s node.\n", value, property, node); return ret; } return ret; }
/* Function to add the first RAM partition info to the device tree. * Note: The function replaces the reg property in the "/memory" node * with the addr and size provided. */ int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size) { int ret; ret = fdt_setprop_u32(fdt, offset, "reg", addr); if (ret) { dprintf(CRITICAL, "Failed to add the memory information addr: %d\n", ret); } ret = fdt_appendprop_u32(fdt, offset, "reg", size); if (ret) { dprintf(CRITICAL, "Failed to add the memory information size: %d\n", ret); } return ret; }
} static int fdtloader_add_single_meminfo(meminfo_pdata_t *pdata, boot_uint64_t addr, boot_uint64_t size) { int rc = 0; // set first addr if (!pdata->do_append) { if (pdata->addr_cell_size == 2) { rc = fdt_setprop_u32(pdata->fdt, pdata->memoffset, "reg", addr >> 32); if (rc) return -1; rc = fdt_appendprop_u32(pdata->fdt, pdata->memoffset, "reg", (boot_uint32_t)addr); if (rc) return -1; } else { rc = fdt_setprop_u32(pdata->fdt, pdata->memoffset, "reg", (boot_uint32_t)addr); if (rc) if (rc) return -1; } pdata->do_append = 1; } // append addr else { if (pdata->addr_cell_size == 2) { rc = fdt_appendprop_u32(pdata->fdt, pdata->memoffset, "reg", addr >> 32); if (rc) return -1; } rc = fdt_appendprop_u32(pdata->fdt, pdata->memoffset, "reg", (boot_uint32_t)addr); if (rc) return -1; }
static __init int remove_gic(void *fdt) { const unsigned int cpu_ehci_int = 2; const unsigned int cpu_uart_int = 4; const unsigned int cpu_eth_int = 6; int gic_off, cpu_off, uart_off, eth_off, ehci_off, err; uint32_t cfg, cpu_phandle; /* leave the GIC node intact if a GIC is present */ cfg = __raw_readl((uint32_t *)SEAD_CONFIG); if (cfg & SEAD_CONFIG_GIC_PRESENT) return 0; gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic"); if (gic_off < 0) { pr_err("unable to find DT GIC node: %d\n", gic_off); return gic_off; } err = fdt_nop_node(fdt, gic_off); if (err) { pr_err("unable to nop GIC node\n"); return err; } cpu_off = fdt_node_offset_by_compatible(fdt, -1, "mti,cpu-interrupt-controller"); if (cpu_off < 0) { pr_err("unable to find CPU intc node: %d\n", cpu_off); return cpu_off; } cpu_phandle = fdt_get_phandle(fdt, cpu_off); if (!cpu_phandle) { pr_err("unable to get CPU intc phandle\n"); return -EINVAL; } uart_off = fdt_node_offset_by_compatible(fdt, -1, "ns16550a"); while (uart_off >= 0) { err = fdt_setprop_u32(fdt, uart_off, "interrupt-parent", cpu_phandle); if (err) { pr_warn("unable to set UART interrupt-parent: %d\n", err); return err; } err = fdt_setprop_u32(fdt, uart_off, "interrupts", cpu_uart_int); if (err) { pr_err("unable to set UART interrupts property: %d\n", err); return err; } uart_off = fdt_node_offset_by_compatible(fdt, uart_off, "ns16550a"); } if (uart_off != -FDT_ERR_NOTFOUND) { pr_err("error searching for UART DT node: %d\n", uart_off); return uart_off; } eth_off = fdt_node_offset_by_compatible(fdt, -1, "smsc,lan9115"); if (eth_off < 0) { pr_err("unable to find ethernet DT node: %d\n", eth_off); return eth_off; } err = fdt_setprop_u32(fdt, eth_off, "interrupt-parent", cpu_phandle); if (err) { pr_err("unable to set ethernet interrupt-parent: %d\n", err); return err; } err = fdt_setprop_u32(fdt, eth_off, "interrupts", cpu_eth_int); if (err) { pr_err("unable to set ethernet interrupts property: %d\n", err); return err; } ehci_off = fdt_node_offset_by_compatible(fdt, -1, "generic-ehci"); if (ehci_off < 0) { pr_err("unable to find EHCI DT node: %d\n", ehci_off); return ehci_off; } err = fdt_setprop_u32(fdt, ehci_off, "interrupt-parent", cpu_phandle); if (err) { pr_err("unable to set EHCI interrupt-parent: %d\n", err); return err; } err = fdt_setprop_u32(fdt, ehci_off, "interrupts", cpu_ehci_int); if (err) { pr_err("unable to set EHCI interrupts property: %d\n", err); return err; } return 0; }
int main(int argc, char *argv[]) { void *fdt; void *buf; const uint32_t *intp; const char *strp; int err; test_init(argc, argv); fdt = load_blob_arg(argc, argv); buf = xmalloc(SPACE); err = fdt_open_into(fdt, buf, SPACE); if (err) FAIL("fdt_open_into(): %s", fdt_strerror(err)); fdt = buf; intp = check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1); verbose_printf("Old int value was 0x%08x\n", *intp); err = fdt_setprop_string(fdt, 0, "prop-int", NEW_STRING); if (err) FAIL("Failed to set \"prop-int\" to \"%s\": %s", NEW_STRING, fdt_strerror(err)); strp = check_getprop_string(fdt, 0, "prop-int", NEW_STRING); verbose_printf("New value is \"%s\"\n", strp); strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, TEST_STRING_1); verbose_printf("Old string value was \"%s\"\n", strp); err = fdt_setprop(fdt, 0, "prop-str", NULL, 0); if (err) FAIL("Failed to empty \"prop-str\": %s", fdt_strerror(err)); check_getprop(fdt, 0, "prop-str", 0, NULL); err = fdt_setprop_u32(fdt, 0, "prop-u32", TEST_VALUE_2); if (err) FAIL("Failed to set \"prop-u32\" to 0x%08x: %s", TEST_VALUE_2, fdt_strerror(err)); check_getprop_cell(fdt, 0, "prop-u32", TEST_VALUE_2); err = fdt_setprop_cell(fdt, 0, "prop-cell", TEST_VALUE_2); if (err) FAIL("Failed to set \"prop-cell\" to 0x%08x: %s", TEST_VALUE_2, fdt_strerror(err)); check_getprop_cell(fdt, 0, "prop-cell", TEST_VALUE_2); err = fdt_setprop_u64(fdt, 0, "prop-u64", TEST_VALUE64_1); if (err) FAIL("Failed to set \"prop-u64\" to 0x%016llx: %s", TEST_VALUE64_1, fdt_strerror(err)); check_getprop_64(fdt, 0, "prop-u64", TEST_VALUE64_1); PASS(); }
/* Top level function that updates the device tree. */ int update_device_tree(void *fdt, const char *cmdline, void *ramdisk, uint32_t ramdisk_size) { int ret = 0; uint32_t offset; /* Check the device tree header */ ret = fdt_check_header(fdt); if (ret) { dprintf(CRITICAL, "Invalid device tree header \n"); return ret; } /* Add padding to make space for new nodes and properties. */ ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE); if (ret!= 0) { dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret); return ret; } /* Get offset of the memory node */ ret = fdt_path_offset(fdt, "/memory"); if (ret < 0) { dprintf(CRITICAL, "Could not find memory node.\n"); return ret; } offset = ret; ret = target_dev_tree_mem(fdt, offset); if(ret) { dprintf(CRITICAL, "ERROR: Cannot update memory node\n"); return ret; } /* Get offset of the chosen node */ ret = fdt_path_offset(fdt, "/chosen"); if (ret < 0) { dprintf(CRITICAL, "Could not find chosen node.\n"); return ret; } offset = ret; /* Adding the cmdline to the chosen node */ ret = fdt_setprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline); if (ret) { dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n"); return ret; } /* Adding the initrd-start to the chosen node */ ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start", (uint32_t)ramdisk); if (ret) { dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n"); return ret; } /* Adding the initrd-end to the chosen node */ ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end", ((uint32_t)ramdisk + ramdisk_size)); if (ret) { dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n"); return ret; } fdt_pack(fdt); return ret; }
int rsa_add_verify_data(struct image_sign_info *info, void *keydest) { BIGNUM *modulus, *r_squared; uint64_t exponent; uint32_t n0_inv; int parent, node; char name[100]; int ret; int bits; RSA *rsa; debug("%s: Getting verification data\n", __func__); ret = rsa_get_pub_key(info->keydir, info->keyname, &rsa); if (ret) return ret; ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared); if (ret) return ret; bits = BN_num_bits(modulus); parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME); if (parent == -FDT_ERR_NOTFOUND) { parent = fdt_add_subnode(keydest, 0, FIT_SIG_NODENAME); if (parent < 0) { ret = parent; if (ret != -FDT_ERR_NOSPACE) { fprintf(stderr, "Couldn't create signature node: %s\n", fdt_strerror(parent)); } } } if (ret) goto done; /* Either create or overwrite the named key node */ snprintf(name, sizeof(name), "key-%s", info->keyname); node = fdt_subnode_offset(keydest, parent, name); if (node == -FDT_ERR_NOTFOUND) { node = fdt_add_subnode(keydest, parent, name); if (node < 0) { ret = node; if (ret != -FDT_ERR_NOSPACE) { fprintf(stderr, "Could not create key subnode: %s\n", fdt_strerror(node)); } } } else if (node < 0) { fprintf(stderr, "Cannot select keys parent: %s\n", fdt_strerror(node)); ret = node; } if (!ret) { ret = fdt_setprop_string(keydest, node, "key-name-hint", info->keyname); } if (!ret) ret = fdt_setprop_u32(keydest, node, "rsa,num-bits", bits); if (!ret) ret = fdt_setprop_u32(keydest, node, "rsa,n0-inverse", n0_inv); if (!ret) { ret = fdt_setprop_u64(keydest, node, "rsa,exponent", exponent); } if (!ret) { ret = fdt_add_bignum(keydest, node, "rsa,modulus", modulus, bits); } if (!ret) { ret = fdt_add_bignum(keydest, node, "rsa,r-squared", r_squared, bits); } if (!ret) { ret = fdt_setprop_string(keydest, node, FIT_ALGO_PROP, info->name); } if (!ret && info->require_keys) { ret = fdt_setprop_string(keydest, node, "required", info->require_keys); } done: BN_free(modulus); BN_free(r_squared); if (ret) return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; return 0; }
/* Top level function that updates the device tree. */ int update_device_tree(void *fdt, const char *cmdline, void *ramdisk, uint32_t ramdisk_size) { int ret = 0; uint32_t offset; /* Check the device tree header */ ret = fdt_check_header(fdt); if (ret) { dprintf(CRITICAL, "Invalid device tree header \n"); return ret; } /* Get offset of the memory node */ ret = fdt_path_offset(fdt, "/memory"); if (ret < 0) { dprintf(CRITICAL, "Could not find memory node.\n"); return ret; } offset = ret; ret = target_dev_tree_mem(fdt, offset); if(ret) { dprintf(CRITICAL, "ERROR: Cannot update memory node\n"); return ret; } /* Get offset of the chosen node */ ret = fdt_path_offset(fdt, "/chosen"); if (ret < 0) { dprintf(CRITICAL, "Could not find chosen node.\n"); return ret; } offset = ret; /* Adding the cmdline to the chosen node */ ret = fdt_setprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline); if (ret) { dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n"); return ret; } /* Adding the initrd-start to the chosen node */ ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start", (uint32_t)ramdisk); if (ret) { dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n"); return ret; } /* Adding the initrd-end to the chosen node */ ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end", ((uint32_t)ramdisk + ramdisk_size)); if (ret) { dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n"); return ret; } fdt_pack(fdt); return ret; }
int fdt_psci(void *fdt) { #if defined(CONFIG_ARMV7_PSCI) || defined(CONFIG_ARMV8_PSCI) || \ defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI) int nodeoff; unsigned int psci_ver = 0; int tmp; nodeoff = fdt_path_offset(fdt, "/cpus"); if (nodeoff < 0) { printf("couldn't find /cpus\n"); return nodeoff; } /* add 'enable-method = "psci"' to each cpu node */ for (tmp = fdt_first_subnode(fdt, nodeoff); tmp >= 0; tmp = fdt_next_subnode(fdt, tmp)) { const struct fdt_property *prop; int len; prop = fdt_get_property(fdt, tmp, "device_type", &len); if (!prop) continue; if (len < 4) continue; if (strcmp(prop->data, "cpu")) continue; /* * Not checking rv here, our approach is to skip over errors in * individual cpu nodes, hopefully some of the nodes are * processed correctly and those will boot */ fdt_setprop_string(fdt, tmp, "enable-method", "psci"); } nodeoff = fdt_path_offset(fdt, "/psci"); if (nodeoff >= 0) goto init_psci_node; nodeoff = fdt_path_offset(fdt, "/"); if (nodeoff < 0) return nodeoff; nodeoff = fdt_add_subnode(fdt, nodeoff, "psci"); if (nodeoff < 0) return nodeoff; init_psci_node: #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT psci_ver = sec_firmware_support_psci_version(); #elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI) psci_ver = ARM_PSCI_VER_1_0; #endif if (psci_ver >= ARM_PSCI_VER_1_0) { tmp = fdt_setprop_string(fdt, nodeoff, "compatible", "arm,psci-1.0"); if (tmp) return tmp; } if (psci_ver >= ARM_PSCI_VER_0_2) { tmp = fdt_appendprop_string(fdt, nodeoff, "compatible", "arm,psci-0.2"); if (tmp) return tmp; } #ifndef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT /* * The Secure firmware framework isn't able to support PSCI version 0.1. */ if (psci_ver < ARM_PSCI_VER_0_2) { tmp = fdt_appendprop_string(fdt, nodeoff, "compatible", "arm,psci"); if (tmp) return tmp; tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_suspend", ARM_PSCI_FN_CPU_SUSPEND); if (tmp) return tmp; tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_off", ARM_PSCI_FN_CPU_OFF); if (tmp) return tmp; tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_on", ARM_PSCI_FN_CPU_ON); if (tmp) return tmp; tmp = fdt_setprop_u32(fdt, nodeoff, "migrate", ARM_PSCI_FN_MIGRATE); if (tmp) return tmp; } #endif tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc"); if (tmp) return tmp; #endif return 0; }