struct data data_append_re(struct data d, const struct fdt_reserve_entry *re) { struct fdt_reserve_entry bere; bere.address = cpu_to_fdt64(re->address); bere.size = cpu_to_fdt64(re->size); return data_append_data(d, &bere, sizeof(bere)); }
static int ft_hs_fixup_dram(void *fdt, bd_t *bd) { const char *path, *subpath; int offs; u32 sec_mem_start = CONFIG_TI_SECURE_EMIF_REGION_START; u32 sec_mem_size = CONFIG_TI_SECURE_EMIF_TOTAL_REGION_SIZE; fdt64_t temp[2]; /* If start address is zero, place at end of DRAM */ if (0 == sec_mem_start) sec_mem_start = (CONFIG_SYS_SDRAM_BASE + (omap_sdram_size() - sec_mem_size)); /* Delete any original secure_reserved node */ path = "/reserved-memory/secure_reserved"; offs = fdt_path_offset(fdt, path); if (offs >= 0) fdt_del_node(fdt, offs); /* Add new secure_reserved node */ path = "/reserved-memory"; offs = fdt_path_offset(fdt, path); if (offs < 0) { debug("Node %s not found\n", path); path = "/"; subpath = "reserved-memory"; fdt_path_offset(fdt, path); offs = fdt_add_subnode(fdt, offs, subpath); if (offs < 0) { printf("Could not create %s%s node.\n", path, subpath); return 1; } path = "/reserved-memory"; offs = fdt_path_offset(fdt, path); } subpath = "secure_reserved"; offs = fdt_add_subnode(fdt, offs, subpath); if (offs < 0) { printf("Could not create %s%s node.\n", path, subpath); return 1; } temp[0] = cpu_to_fdt64(((u64)sec_mem_start)); temp[1] = cpu_to_fdt64(((u64)sec_mem_size)); fdt_setprop_string(fdt, offs, "compatible", "ti,dra7-secure-memory"); fdt_setprop_string(fdt, offs, "status", "okay"); fdt_setprop(fdt, offs, "no-map", NULL, 0); fdt_setprop(fdt, offs, "reg", temp, sizeof(temp)); return 0; }
struct data data_append_integer(struct data d, uint64_t value, int bits) { uint8_t value_8; uint16_t value_16; uint32_t value_32; uint64_t value_64; switch (bits) { case 8: value_8 = value; return data_append_data(d, &value_8, 1); case 16: value_16 = cpu_to_fdt16(value); return data_append_data(d, &value_16, 2); case 32: value_32 = cpu_to_fdt32(value); return data_append_data(d, &value_32, 4); case 64: value_64 = cpu_to_fdt64(value); return data_append_data(d, &value_64, 8); default: die("Invalid literal size (%d)\n", bits); } }
static void trace_add_dt_props(void) { unsigned int i; u64 *prop, tmask; prop = malloc(sizeof(u64) * 2 * debug_descriptor.num_traces); for (i = 0; i < debug_descriptor.num_traces; i++) { prop[i * 2] = cpu_to_fdt64(debug_descriptor.trace_phys[i]); prop[i * 2 + 1] = cpu_to_fdt64(debug_descriptor.trace_size[i]); } dt_add_property(opal_node, "ibm,opal-traces", prop, sizeof(u64) * 2 * i); free(prop); tmask = (uint64_t)&debug_descriptor.trace_mask; dt_add_property_cells(opal_node, "ibm,opal-trace-mask", hi32(tmask), lo32(tmask)); }
/* * Replace a reserve map entry in the nth slot. */ int fdt_replace_reservemap_entry(void *fdt, int n, uint64_t addr, uint64_t size) { struct fdt_reserve_entry *re; int used; int total; int err; err = fdt_num_reservemap(fdt, &used, &total); if (err != 0) return err; if (n >= total) return -FDT_ERR_NOSPACE; re = (struct fdt_reserve_entry *) (fdt + fdt_off_mem_rsvmap(fdt) + (n * sizeof(struct fdt_reserve_entry))); re->address = cpu_to_fdt64(addr); re->size = cpu_to_fdt64(size); return 0; }
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) { struct fdt_reserve_entry *re; unsigned int offset; FDT_SW_CHECK_HEADER(fdt); if (fdt_size_dt_struct(fdt)) return -FDT_ERR_BADSTATE; offset = fdt_off_dt_struct(fdt); if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) return -FDT_ERR_NOSPACE; re = (struct fdt_reserve_entry *)((char *)fdt + offset); re->address = cpu_to_fdt64(addr); re->size = cpu_to_fdt64(size); fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); return 0; }
static void generate_virtio_mmio_node(void *fdt, struct virtio_mmio *vmmio) { char dev_name[DEVICE_NAME_MAX_LEN]; u64 addr = vmmio->addr; u64 reg_prop[] = { cpu_to_fdt64(addr), cpu_to_fdt64(VIRTIO_MMIO_IO_SIZE) }; u32 irq_prop[] = { cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI), cpu_to_fdt32(vmmio->irq - GIC_SPI_IRQ_BASE), cpu_to_fdt32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI), }; snprintf(dev_name, DEVICE_NAME_MAX_LEN, "virtio@%llx", addr); _FDT(fdt_begin_node(fdt, dev_name)); _FDT(fdt_property_string(fdt, "compatible", "virtio,mmio")); _FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop))); _FDT(fdt_property(fdt, "interrupts", irq_prop, sizeof(irq_prop))); _FDT(fdt_end_node(fdt)); }
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) { struct fdt_reserve_entry *re; int err = check_header_sw(fdt); int offset; if (err) return err; if (fdt_size_dt_struct(fdt)) return -FDT_ERR_BADSTATE; offset = fdt_off_dt_struct(fdt); if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) return -FDT_ERR_NOSPACE; re = (struct fdt_reserve_entry *)(fdt + offset); re->address = cpu_to_fdt64(addr); re->size = cpu_to_fdt64(size); fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); return 0; }
/* * fdt_pack_reg - pack address and size array into the "reg"-suitable stream */ static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size, int n) { int i; int address_cells = fdt_address_cells(fdt, 0); int size_cells = fdt_size_cells(fdt, 0); char *p = buf; for (i = 0; i < n; i++) { if (address_cells == 2) *(fdt64_t *)p = cpu_to_fdt64(address[i]); else *(fdt32_t *)p = cpu_to_fdt32(address[i]); p += 4 * address_cells; if (size_cells == 2) *(fdt64_t *)p = cpu_to_fdt64(size[i]); else *(fdt32_t *)p = cpu_to_fdt32(size[i]); p += 4 * size_cells; } return p - (char *)buf; }
void ft_fixup_cpu(void *blob) { int off; __maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr(); fdt32_t *reg; int addr_cells; u64 val, core_id; size_t *boot_code_size = &(__secondary_boot_code_size); off = fdt_path_offset(blob, "/cpus"); if (off < 0) { puts("couldn't find /cpus node\n"); return; } of_bus_default_count_cells(blob, off, &addr_cells, NULL); off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); while (off != -FDT_ERR_NOTFOUND) { reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0); core_id = of_read_number(reg, addr_cells); if (reg) { if (core_id == 0 || (is_core_online(core_id))) { val = spin_tbl_addr; val += id_to_core(core_id) * SPIN_TABLE_ELEM_SIZE; val = cpu_to_fdt64(val); fdt_setprop_string(blob, off, "enable-method", "spin-table"); fdt_setprop(blob, off, "cpu-release-addr", &val, sizeof(val)); } else { debug("skipping offline core\n"); } } else { puts("Warning: found cpu node without reg property\n"); } off = fdt_node_offset_by_prop_value(blob, off, "device_type", "cpu", 4); } fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code, *boot_code_size); }
/* * Convert and fold provided ATAGs into the provided FDT. * * REturn values: * = 0 -> pretend success * = 1 -> bad ATAG (may retry with another possible ATAG pointer) * < 0 -> error from libfdt */ int atags_to_fdt(void *atag_list, void *fdt, int total_space) { struct tag *atag = atag_list; /* In the case of 64 bits memory size, need to reserve 2 cells for * address and size for each bank */ uint32_t mem_reg_property[2 * 2 * NR_BANKS]; int memcount = 0; int ret, memsize; /* make sure we've got an aligned pointer */ if ((u32)atag_list & 0x3) return 1; /* if we get a DTB here we're done already */ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) return 0; /* validate the ATAG */ if (atag->hdr.tag != ATAG_CORE || (atag->hdr.size != tag_size(tag_core) && atag->hdr.size != 2)) return 1; /* let's give it all the room it could need */ ret = fdt_open_into(fdt, fdt, total_space); if (ret < 0) return ret; for_each_tag(atag, atag_list) { if (atag->hdr.tag == ATAG_CMDLINE) { /* Append the ATAGS command line to the device tree * command line. * NB: This means that if the same parameter is set in * the device tree and in the tags, the one from the * tags will be chosen. */ if (do_extend_cmdline) merge_fdt_bootargs(fdt, atag->u.cmdline.cmdline); else setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/4) continue; if (!atag->u.mem.size) continue; memsize = get_cell_size(fdt); if (memsize == 2) { /* if memsize is 2, that means that * each data needs 2 cells of 32 bits, * so the data are 64 bits */ uint64_t *mem_reg_prop64 = (uint64_t *)mem_reg_property; mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.start); mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.size); } else { mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); } } else if (atag->hdr.tag == ATAG_INITRD2) { uint32_t initrd_start, initrd_size; initrd_start = atag->u.initrd.start; initrd_size = atag->u.initrd.size; setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); } } if (memcount) { setprop(fdt, "/memory", "reg", mem_reg_property, 4 * memcount * memsize); } return fdt_pack(fdt); }
static void fdt_fixup_gic(void *blob) { int offset, err; u64 reg[8]; struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); unsigned int val; struct ccsr_scfg __iomem *scfg = (void *)CONFIG_SYS_FSL_SCFG_ADDR; int align_64k = 0; val = gur_in32(&gur->svr); if (!IS_SVR_DEV(val, SVR_DEV(SVR_LS1043A))) { align_64k = 1; } else if (SVR_REV(val) != REV1_0) { val = scfg_in32(&scfg->gic_align) & (0x01 << GIC_ADDR_BIT); if (!val) align_64k = 1; } offset = fdt_subnode_offset(blob, 0, "interrupt-controller@1400000"); if (offset < 0) { printf("WARNING: fdt_subnode_offset can't find node %s: %s\n", "interrupt-controller@1400000", fdt_strerror(offset)); return; } /* Fixup gic node align with 64K */ if (align_64k) { reg[0] = cpu_to_fdt64(GICD_BASE_64K); reg[1] = cpu_to_fdt64(GICD_SIZE_64K); reg[2] = cpu_to_fdt64(GICC_BASE_64K); reg[3] = cpu_to_fdt64(GICC_SIZE_64K); reg[4] = cpu_to_fdt64(GICH_BASE_64K); reg[5] = cpu_to_fdt64(GICH_SIZE_64K); reg[6] = cpu_to_fdt64(GICV_BASE_64K); reg[7] = cpu_to_fdt64(GICV_SIZE_64K); } else { /* Fixup gic node align with default */ reg[0] = cpu_to_fdt64(GICD_BASE); reg[1] = cpu_to_fdt64(GICD_SIZE); reg[2] = cpu_to_fdt64(GICC_BASE); reg[3] = cpu_to_fdt64(GICC_SIZE); reg[4] = cpu_to_fdt64(GICH_BASE); reg[5] = cpu_to_fdt64(GICH_SIZE); reg[6] = cpu_to_fdt64(GICV_BASE); reg[7] = cpu_to_fdt64(GICV_SIZE); } err = fdt_setprop(blob, offset, "reg", reg, sizeof(reg)); if (err < 0) { printf("WARNING: fdt_setprop can't set %s from node %s: %s\n", "reg", "interrupt-controller@1400000", fdt_strerror(err)); return; } return; }
void ft_fixup_cpu(void *blob) { int off; __maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr(); fdt32_t *reg; int addr_cells; u64 val, core_id; size_t *boot_code_size = &(__secondary_boot_code_size); u32 mask = cpu_pos_mask(); int off_prev = -1; off = fdt_path_offset(blob, "/cpus"); if (off < 0) { puts("couldn't find /cpus node\n"); return; } fdt_support_default_count_cells(blob, off, &addr_cells, NULL); off = fdt_node_offset_by_prop_value(blob, off_prev, "device_type", "cpu", 4); while (off != -FDT_ERR_NOTFOUND) { reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0); if (reg) { core_id = fdt_read_number(reg, addr_cells); if (!test_bit(id_to_core(core_id), &mask)) { fdt_del_node(blob, off); off = off_prev; } } off_prev = off; off = fdt_node_offset_by_prop_value(blob, off_prev, "device_type", "cpu", 4); } #if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT) && \ defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI) int node; u32 psci_ver; /* Check the psci version to determine if the psci is supported */ psci_ver = sec_firmware_support_psci_version(); if (psci_ver == 0xffffffff) { /* remove psci DT node */ node = fdt_path_offset(blob, "/psci"); if (node >= 0) goto remove_psci_node; node = fdt_node_offset_by_compatible(blob, -1, "arm,psci"); if (node >= 0) goto remove_psci_node; node = fdt_node_offset_by_compatible(blob, -1, "arm,psci-0.2"); if (node >= 0) goto remove_psci_node; node = fdt_node_offset_by_compatible(blob, -1, "arm,psci-1.0"); if (node >= 0) goto remove_psci_node; remove_psci_node: if (node >= 0) fdt_del_node(blob, node); } else { return; } #endif off = fdt_path_offset(blob, "/cpus"); if (off < 0) { puts("couldn't find /cpus node\n"); return; } fdt_support_default_count_cells(blob, off, &addr_cells, NULL); off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); while (off != -FDT_ERR_NOTFOUND) { reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0); if (reg) { core_id = fdt_read_number(reg, addr_cells); if (core_id == 0 || (is_core_online(core_id))) { val = spin_tbl_addr; val += id_to_core(core_id) * SPIN_TABLE_ELEM_SIZE; val = cpu_to_fdt64(val); fdt_setprop_string(blob, off, "enable-method", "spin-table"); fdt_setprop(blob, off, "cpu-release-addr", &val, sizeof(val)); } else { debug("skipping offline core\n"); } } else { puts("Warning: found cpu node without reg property\n"); } off = fdt_node_offset_by_prop_value(blob, off, "device_type", "cpu", 4); } fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code, *boot_code_size); #if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD) efi_add_memory_map((uintptr_t)&secondary_boot_code, ALIGN(*boot_code_size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT, EFI_RESERVED_MEMORY_TYPE, false); #endif }
efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long orig_fdt_size, void *fdt, int new_fdt_size, char *cmdline_ptr, u64 initrd_addr, u64 initrd_size, efi_memory_desc_t *memory_map, unsigned long map_size, unsigned long desc_size, u32 desc_ver) { int node, prev, num_rsv; int status; u32 fdt_val32; u64 fdt_val64; /* Do some checks on provided FDT, if it exists*/ if (orig_fdt) { if (fdt_check_header(orig_fdt)) { pr_efi_err(sys_table, "Device Tree header not valid!\n"); return EFI_LOAD_ERROR; } /* * We don't get the size of the FDT if we get if from a * configuration table. */ if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) { pr_efi_err(sys_table, "Truncated device tree! foo!\n"); return EFI_LOAD_ERROR; } } if (orig_fdt) status = fdt_open_into(orig_fdt, fdt, new_fdt_size); else status = fdt_create_empty_tree(fdt, new_fdt_size); if (status != 0) goto fdt_set_fail; /* * Delete any memory nodes present. We must delete nodes which * early_init_dt_scan_memory may try to use. */ prev = 0; for (;;) { const char *type; int len; node = fdt_next_node(fdt, prev, NULL); if (node < 0) break; type = fdt_getprop(fdt, node, "device_type", &len); if (type && strncmp(type, "memory", len) == 0) { fdt_del_node(fdt, node); continue; } prev = node; } /* * Delete all memory reserve map entries. When booting via UEFI, * kernel will use the UEFI memory map to find reserved regions. */ num_rsv = fdt_num_mem_rsv(fdt); while (num_rsv-- > 0) fdt_del_mem_rsv(fdt, num_rsv); node = fdt_subnode_offset(fdt, 0, "chosen"); if (node < 0) { node = fdt_add_subnode(fdt, 0, "chosen"); if (node < 0) { status = node; /* node is error code when negative */ goto fdt_set_fail; } } if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) { status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr, strlen(cmdline_ptr) + 1); if (status) goto fdt_set_fail; } /* Set initrd address/end in device tree, if present */ if (initrd_size != 0) { u64 initrd_image_end; u64 initrd_image_start = cpu_to_fdt64(initrd_addr); status = fdt_setprop(fdt, node, "linux,initrd-start", &initrd_image_start, sizeof(u64)); if (status) goto fdt_set_fail; initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size); status = fdt_setprop(fdt, node, "linux,initrd-end", &initrd_image_end, sizeof(u64)); if (status) goto fdt_set_fail; } /* Add FDT entries for EFI runtime services in chosen node. */ node = fdt_subnode_offset(fdt, 0, "chosen"); fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table); status = fdt_setprop(fdt, node, "linux,uefi-system-table", &fdt_val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map); status = fdt_setprop(fdt, node, "linux,uefi-mmap-start", &fdt_val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(map_size); status = fdt_setprop(fdt, node, "linux,uefi-mmap-size", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(desc_size); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(desc_ver); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; /* * Add kernel version banner so stub/kernel match can be * verified. */ status = fdt_setprop_string(fdt, node, "linux,uefi-stub-kern-ver", linux_banner); if (status) goto fdt_set_fail; return EFI_SUCCESS; fdt_set_fail: if (status == -FDT_ERR_NOSPACE) return EFI_BUFFER_TOO_SMALL; return EFI_LOAD_ERROR; }
/* * Convert and fold provided ATAGs into the provided FDT. * * REturn values: * = 0 -> pretend success * = 1 -> bad ATAG (may retry with another possible ATAG pointer) * < 0 -> error from libfdt */ int atags_to_fdt(void *atag_list, void *fdt, int total_space) { struct tag *atag = atag_list; /* In the case of 64 bits memory size, need to reserve 2 cells for * address and size for each bank */ uint32_t mem_reg_property[2 * 2 * NR_BANKS]; int memcount = 0; int ret, memsize; /* make sure we've got an aligned pointer */ if ((u32)atag_list & 0x3) return 1; /* if we get a DTB here we're done already */ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) return 0; /* validate the ATAG */ if (atag->hdr.tag != ATAG_CORE || (atag->hdr.size != tag_size(tag_core) && atag->hdr.size != 2)) return 1; /* let's give it all the room it could need */ ret = fdt_open_into(fdt, fdt, total_space); if (ret < 0) return ret; for_each_tag(atag, atag_list) { if (atag->hdr.tag == ATAG_CMDLINE) { /* Append the ATAGS command line to the device tree * command line. * NB: This means that if the same parameter is set in * the device tree and in the tags, the one from the * tags will be chosen. */ if (do_extend_cmdline) merge_fdt_bootargs(fdt, atag->u.cmdline.cmdline); else setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/4) continue; if (!atag->u.mem.size) continue; memsize = get_cell_size(fdt); if (memsize == 2) { /* if memsize is 2, that means that * each data needs 2 cells of 32 bits, * so the data are 64 bits */ uint64_t *mem_reg_prop64 = (uint64_t *)mem_reg_property; mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.start); mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.size); } else { mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); } } else if (atag->hdr.tag == ATAG_INITRD2) { uint32_t initrd_start, initrd_size; initrd_start = atag->u.initrd.start; initrd_size = atag->u.initrd.size; setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); } else if (atag->hdr.tag == ATAG_BLUETOOTH) { setprop_values(fdt, "/chosen", "linux,bt_mac", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MSM_WIFI) { #define NVS_MAX_SIZE 0x800U #define NVS_LEN_OFFSET 0x0C #define NVS_DATA_OFFSET 0x40 char append[] = "\nsd_oobonly=1\nbtc_params80=0\nbtc_params6=30\n"; __u32 len = 0; __u32 full_len = (atag->hdr.size-2)*sizeof(__u32); // check that we have enought space for get len if (full_len > NVS_LEN_OFFSET) memcpy(&len, (unsigned char *)(&atag->u) + NVS_LEN_OFFSET, sizeof(len)); // len is less than full block size if (len > (NVS_MAX_SIZE - NVS_DATA_OFFSET)) len = (NVS_MAX_SIZE - NVS_DATA_OFFSET); // len is less than atag block size if (len > full_len) len = full_len; // we have enought space for add additional params if ((len + strlen(append) + 1) <= full_len) { // block is finished by zero if (((unsigned char *)(&atag->u))[NVS_DATA_OFFSET + len] == 0) len --; //copy additional params memcpy( (unsigned char *)(&atag->u) + NVS_DATA_OFFSET + len, append, strlen(append) + 1 ); len += strlen(append); len ++; } // finaly save new wifi calibration setprop_values(fdt, "/chosen", "linux,wifi-calibration", (unsigned char *)(&atag->u) + NVS_DATA_OFFSET, len); } else if (atag->hdr.tag == ATAG_MSM_AWB_CAL) { setprop_values(fdt, "/chosen", "linux,awb_cal", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MFG_GPIO_TABLE) { setprop_values(fdt, "/chosen", "linux,gpio_table", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MSM_PARTITION) { setprop_values(fdt, "/chosen", "linux,msm_partitions", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MEMSIZE) { setprop_cell(fdt, "/chosen", "linux,memsize", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_ALS) { setprop_cell(fdt, "/chosen", "linux,als_calibration", atag->u.als_kadc.kadc); } else if (atag->hdr.tag == ATAG_ENGINEERID) { setprop_cell(fdt, "/chosen", "linux,engineerid", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_SMI) { setprop_cell(fdt, "/chosen", "linux,smi", atag->u.mem.size); } else if (atag->hdr.tag == ATAG_HWID) { setprop_cell(fdt, "/chosen", "linux,hwid", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_SKUID) { setprop_cell(fdt, "/chosen", "linux,skuid", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_HERO_PANEL_TYPE) { setprop_cell(fdt, "/chosen", "linux,panel_type", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_GS) { setprop_cell(fdt, "/chosen", "linux,gs_calibration", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_REVISION) { __u32 revision[2]; revision[0] = cpu_to_fdt32(atag->u.revision.rev); revision[1] = cpu_to_fdt32(atag->u.revision.rev); if (atag->hdr.size > 3) { revision[1] = cpu_to_fdt32(atag->u.revision.rev2); } setprop_values(fdt, "/chosen", "linux,revision", revision, sizeof(revision)); } else if (atag->hdr.tag == ATAG_PS) { __u32 ps_settings[2]; ps_settings[0] = cpu_to_fdt32(atag->u.serialnr.low); ps_settings[1] = cpu_to_fdt32(atag->u.serialnr.high); setprop_values(fdt, "/chosen", "linux,ps_calibration", ps_settings, sizeof(ps_settings)); } else if (atag->hdr.tag == ATAG_PS_TYPE) { setprop_cell(fdt, "/chosen", "linux,ps_type", atag->u.revision.rev); } } if (memcount) { setprop(fdt, "/memory", "reg", mem_reg_property, 4 * memcount * memsize); } return fdt_pack(fdt); }
void fixup_memory(struct sys_info *si) { struct mem_region *curmr; uint32_t addr_cells, size_cells; uint32_t *addr_cellsp, *reg, *size_cellsp; int err, i, len, memory, realmrno, root; uint8_t *buf, *sb; root = fdt_path_offset(fdtp, "/"); if (root < 0) { sprintf(command_errbuf, "Could not find root node !"); return; } memory = fdt_path_offset(fdtp, "/memory"); if (memory <= 0) { /* Create proper '/memory' node. */ memory = fdt_add_subnode(fdtp, root, "memory"); if (memory <= 0) { sprintf(command_errbuf, "Could not fixup '/memory' " "node, error code : %d!\n", memory); return; } err = fdt_setprop(fdtp, memory, "device_type", "memory", sizeof("memory")); if (err < 0) return; } addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", NULL); size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); if (addr_cellsp == NULL || size_cellsp == NULL) { sprintf(command_errbuf, "Could not fixup '/memory' node : " "%s %s property not found in root node!\n", (!addr_cellsp) ? "#address-cells" : "", (!size_cellsp) ? "#size-cells" : ""); return; } addr_cells = fdt32_to_cpu(*addr_cellsp); size_cells = fdt32_to_cpu(*size_cellsp); /* Count valid memory regions entries in sysinfo. */ realmrno = si->mr_no; for (i = 0; i < si->mr_no; i++) if (si->mr[i].start == 0 && si->mr[i].size == 0) realmrno--; if (realmrno == 0) { sprintf(command_errbuf, "Could not fixup '/memory' node : " "sysinfo doesn't contain valid memory regions info!\n"); return; } if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg", &len)) != NULL) { if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0) /* * Do not apply fixup if existing 'reg' property * seems to be valid. */ return; } len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); sb = buf = (uint8_t *)malloc(len); if (!buf) return; bzero(buf, len); for (i = 0; i < si->mr_no; i++) { curmr = &si->mr[i]; if (curmr->size != 0) { /* Ensure endianess, and put cells into a buffer */ if (addr_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(curmr->start); else *(uint32_t *)buf = cpu_to_fdt32(curmr->start); buf += sizeof(uint32_t) * addr_cells; if (size_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(curmr->size); else *(uint32_t *)buf = cpu_to_fdt32(curmr->size); buf += sizeof(uint32_t) * size_cells; } } /* Set property */ if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); }
STATIC EFI_STATUS PrepareFdt ( IN OUT VOID *Fdt, IN UINTN FdtSize ) { EFI_STATUS Status; INT32 Node; INT32 CpuNode; UINTN Index; ARM_CORE_INFO *ArmCoreInfoTable; UINTN ArmCoreCount; INT32 MapNode; INT32 ClusterNode; INT32 PmuNode; PMU_INTERRUPT PmuInt; INT32 Phandle[NUM_CORES]; UINT32 ClusterIndex; UINT32 CoreIndex; UINT32 ClusterCount; UINT32 CoresInCluster; UINT32 ClusterId; UINTN MpId; CHAR8 Name[10]; AMD_MP_CORE_INFO_PROTOCOL *AmdMpCoreInfoProtocol; // // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms. // // For 'cpus' and 'cpu' device tree nodes bindings, refer to this file // in the kernel documentation: // Documentation/devicetree/bindings/arm/cpus.txt // Status = gBS->LocateProtocol ( &gAmdMpCoreInfoProtocolGuid, NULL, (VOID **)&AmdMpCoreInfoProtocol ); ASSERT_EFI_ERROR (Status); // Get pointer to ARM core info table ArmCoreInfoTable = AmdMpCoreInfoProtocol->GetArmCoreInfoTable (&ArmCoreCount); ASSERT (ArmCoreInfoTable != NULL); ASSERT (ArmCoreCount <= NUM_CORES); // Get Id from primary CPU MpId = (UINTN)ArmReadMpidr (); // Create /pmu node PmuNode = fdt_add_subnode(Fdt, 0, "pmu"); if (PmuNode >= 0) { fdt_setprop_string (Fdt, PmuNode, "compatible", "arm,armv8-pmuv3"); // append PMU interrupts for (Index = 0; Index < ArmCoreCount; Index++) { MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId, ArmCoreInfoTable[Index].CoreId); Status = AmdMpCoreInfoProtocol->GetPmuSpiFromMpId (MpId, &PmuInt.IntId); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "FDT: Error getting PMU interrupt for MpId '0x%x'\n", MpId)); return Status; } PmuInt.Flag = cpu_to_fdt32 (PMU_INT_FLAG_SPI); PmuInt.IntId = cpu_to_fdt32 (PmuInt.IntId); PmuInt.Type = cpu_to_fdt32 (PMU_INT_TYPE_HIGH_LEVEL); fdt_appendprop (Fdt, PmuNode, "interrupts", &PmuInt, sizeof(PmuInt)); } } else { DEBUG ((DEBUG_ERROR, "FDT: Error creating 'pmu' node\n")); return EFI_INVALID_PARAMETER; } // Create /cpus noide Node = fdt_add_subnode (Fdt, 0, "cpus"); if (Node >= 0) { // Configure the 'cpus' node fdt_setprop_string (Fdt, Node, "name", "cpus"); fdt_setprop_cell (Fdt, Node, "#address-cells", sizeof (UINTN) / 4); fdt_setprop_cell (Fdt, Node, "#size-cells", 0); } else { DEBUG ((DEBUG_ERROR, "FDT: Error creating 'cpus' node\n")); return EFI_INVALID_PARAMETER; } // // Walk the processor table in reverse order for proper listing in FDT // Index = ArmCoreCount; while (Index--) { // Create 'cpu' node AsciiSPrint (Name, sizeof (Name), "CPU%d", Index); CpuNode = fdt_add_subnode (Fdt, Node, Name); if (CpuNode < 0) { DEBUG ((DEBUG_ERROR, "FDT: Error on creating '%a' node\n", Name)); return EFI_INVALID_PARAMETER; } Phandle[Index] = fdt_alloc_phandle (Fdt); fdt_setprop_cell (Fdt, CpuNode, "phandle", Phandle[Index]); fdt_setprop_cell (Fdt, CpuNode, "linux,phandle", Phandle[Index]); fdt_setprop_string (Fdt, CpuNode, "enable-method", "psci"); MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId, ArmCoreInfoTable[Index].CoreId); MpId = cpu_to_fdt64 (MpId); fdt_setprop (Fdt, CpuNode, "reg", &MpId, sizeof (MpId)); fdt_setprop_string (Fdt, CpuNode, "compatible", "arm,armv8"); fdt_setprop_string (Fdt, CpuNode, "device_type", "cpu"); } // Create /cpu-map node MapNode = fdt_add_subnode (Fdt, Node, "cpu-map"); if (MapNode >= 0) { ClusterIndex = ArmCoreCount - 1; ClusterCount = NumberOfClustersInTable (ArmCoreInfoTable, ArmCoreCount); while (ClusterCount--) { // Create 'cluster' node AsciiSPrint (Name, sizeof (Name), "cluster%d", ClusterCount); ClusterNode = fdt_add_subnode (Fdt, MapNode, Name); if (ClusterNode < 0) { DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name)); return EFI_INVALID_PARAMETER; } ClusterId = ArmCoreInfoTable[ClusterIndex].ClusterId; CoreIndex = ClusterIndex; CoresInCluster = NumberOfCoresInCluster (ArmCoreInfoTable, ArmCoreCount, ClusterId); while (CoresInCluster--) { // Create 'core' node AsciiSPrint (Name, sizeof (Name), "core%d", CoresInCluster); CpuNode = fdt_add_subnode (Fdt, ClusterNode, Name); if (CpuNode < 0) { DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name)); return EFI_INVALID_PARAMETER; } fdt_setprop_cell (Fdt, CpuNode, "cpu", Phandle[CoreIndex]); // iterate to next core in cluster if (CoresInCluster) { do { --CoreIndex; } while (ClusterId != ArmCoreInfoTable[CoreIndex].ClusterId); } } // iterate to next cluster if (ClusterCount) { do { --ClusterIndex; } while (ClusterInRange (ArmCoreInfoTable, ArmCoreInfoTable[ClusterIndex].ClusterId, ClusterIndex + 1, ArmCoreCount - 1)); } } } else { DEBUG ((DEBUG_ERROR,"FDT: Error creating 'cpu-map' node\n")); return EFI_INVALID_PARAMETER; } SetSocIdStatus (Fdt); SetXgbeStatus (Fdt); // Update the real size of the Device Tree fdt_pack (Fdt); return EFI_SUCCESS; }
static int setup_fdt(struct kvm *kvm) { struct device_header *dev_hdr; u8 staging_fdt[FDT_MAX_SIZE]; u32 gic_phandle = fdt__alloc_phandle(); u64 mem_reg_prop[] = { cpu_to_fdt64(kvm->arch.memory_guest_start), cpu_to_fdt64(kvm->ram_size), }; void *fdt = staging_fdt; void *fdt_dest = guest_flat_to_host(kvm, kvm->arch.dtb_guest_start); void (*generate_mmio_fdt_nodes)(void *, struct device_header *, void (*)(void *, u8)); void (*generate_cpu_peripheral_fdt_nodes)(void *, struct kvm *, u32) = kvm->cpus[0]->generate_fdt_nodes; /* Create new tree without a reserve map */ _FDT(fdt_create(fdt, FDT_MAX_SIZE)); _FDT(fdt_finish_reservemap(fdt)); /* Header */ _FDT(fdt_begin_node(fdt, "")); _FDT(fdt_property_cell(fdt, "interrupt-parent", gic_phandle)); _FDT(fdt_property_string(fdt, "compatible", "linux,dummy-virt")); _FDT(fdt_property_cell(fdt, "#address-cells", 0x2)); _FDT(fdt_property_cell(fdt, "#size-cells", 0x2)); /* /chosen */ _FDT(fdt_begin_node(fdt, "chosen")); _FDT(fdt_property_cell(fdt, "linux,pci-probe-only", 1)); _FDT(fdt_property_string(fdt, "bootargs", kern_cmdline)); /* Initrd */ if (kvm->arch.initrd_size != 0) { u32 ird_st_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start); u32 ird_end_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start + kvm->arch.initrd_size); _FDT(fdt_property(fdt, "linux,initrd-start", &ird_st_prop, sizeof(ird_st_prop))); _FDT(fdt_property(fdt, "linux,initrd-end", &ird_end_prop, sizeof(ird_end_prop))); } _FDT(fdt_end_node(fdt)); /* Memory */ _FDT(fdt_begin_node(fdt, "memory")); _FDT(fdt_property_string(fdt, "device_type", "memory")); _FDT(fdt_property(fdt, "reg", mem_reg_prop, sizeof(mem_reg_prop))); _FDT(fdt_end_node(fdt)); /* CPU and peripherals (interrupt controller, timers, etc) */ generate_cpu_nodes(fdt, kvm); if (generate_cpu_peripheral_fdt_nodes) generate_cpu_peripheral_fdt_nodes(fdt, kvm, gic_phandle); /* Virtio MMIO devices */ dev_hdr = device__first_dev(DEVICE_BUS_MMIO); while (dev_hdr) { generate_mmio_fdt_nodes = dev_hdr->data; generate_mmio_fdt_nodes(fdt, dev_hdr, generate_irq_prop); dev_hdr = device__next_dev(dev_hdr); } /* IOPORT devices (!) */ dev_hdr = device__first_dev(DEVICE_BUS_IOPORT); while (dev_hdr) { generate_mmio_fdt_nodes = dev_hdr->data; generate_mmio_fdt_nodes(fdt, dev_hdr, generate_irq_prop); dev_hdr = device__next_dev(dev_hdr); } /* PCI host controller */ pci__generate_fdt_nodes(fdt, gic_phandle); /* PSCI firmware */ _FDT(fdt_begin_node(fdt, "psci")); _FDT(fdt_property_string(fdt, "compatible", "arm,psci")); _FDT(fdt_property_string(fdt, "method", "hvc")); _FDT(fdt_property_cell(fdt, "cpu_suspend", KVM_PSCI_FN_CPU_SUSPEND)); _FDT(fdt_property_cell(fdt, "cpu_off", KVM_PSCI_FN_CPU_OFF)); _FDT(fdt_property_cell(fdt, "cpu_on", KVM_PSCI_FN_CPU_ON)); _FDT(fdt_property_cell(fdt, "migrate", KVM_PSCI_FN_MIGRATE)); _FDT(fdt_end_node(fdt)); /* Finalise. */ _FDT(fdt_end_node(fdt)); _FDT(fdt_finish(fdt)); _FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE)); _FDT(fdt_pack(fdt_dest)); if (kvm->cfg.arch.dump_dtb_filename) dump_fdt(kvm->cfg.arch.dump_dtb_filename, fdt_dest); return 0; }
/** * elf_exec_load - load ELF executable image * @lowest_load_addr: On return, will be the address where the first PT_LOAD * section will be loaded in memory. * * Return: * 0 on success, negative value on failure. */ static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr, struct elf_info *elf_info, unsigned long *lowest_load_addr) { unsigned long base = 0, lowest_addr = UINT_MAX; int ret; size_t i; struct kexec_buf kbuf = { .image = image, .buf_max = ppc64_rma_size, .top_down = false }; /* Read in the PT_LOAD segments. */ for (i = 0; i < ehdr->e_phnum; i++) { unsigned long load_addr; size_t size; const struct elf_phdr *phdr; phdr = &elf_info->proghdrs[i]; if (phdr->p_type != PT_LOAD) continue; size = phdr->p_filesz; if (size > phdr->p_memsz) size = phdr->p_memsz; kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset; kbuf.bufsz = size; kbuf.memsz = phdr->p_memsz; kbuf.buf_align = phdr->p_align; kbuf.buf_min = phdr->p_paddr + base; ret = kexec_add_buffer(&kbuf); if (ret) goto out; load_addr = kbuf.mem; if (load_addr < lowest_addr) lowest_addr = load_addr; } /* Update entry point to reflect new load address. */ ehdr->e_entry += base; *lowest_load_addr = lowest_addr; ret = 0; out: return ret; } void *elf64_load(struct kimage *image, char *kernel_buf, unsigned long kernel_len, char *initrd, unsigned long initrd_len, char *cmdline, unsigned long cmdline_len) { int i, ret; unsigned int fdt_size; unsigned long kernel_load_addr, purgatory_load_addr; unsigned long initrd_load_addr, fdt_load_addr, stack_top; void *fdt; const void *slave_code; struct elfhdr ehdr; struct elf_info elf_info; struct fdt_reserve_entry *rsvmap; struct kexec_buf kbuf = { .image = image, .buf_min = 0, .buf_max = ppc64_rma_size }; ret = build_elf_exec_info(kernel_buf, kernel_len, &ehdr, &elf_info); if (ret) goto out; ret = elf_exec_load(image, &ehdr, &elf_info, &kernel_load_addr); if (ret) goto out; pr_debug("Loaded the kernel at 0x%lx\n", kernel_load_addr); ret = kexec_load_purgatory(image, 0, ppc64_rma_size, true, &purgatory_load_addr); if (ret) { pr_err("Loading purgatory failed.\n"); goto out; } pr_debug("Loaded purgatory at 0x%lx\n", purgatory_load_addr); if (initrd != NULL) { kbuf.buffer = initrd; kbuf.bufsz = kbuf.memsz = initrd_len; kbuf.buf_align = PAGE_SIZE; kbuf.top_down = false; ret = kexec_add_buffer(&kbuf); if (ret) goto out; initrd_load_addr = kbuf.mem; pr_debug("Loaded initrd at 0x%lx\n", initrd_load_addr); } fdt_size = fdt_totalsize(initial_boot_params) * 2; fdt = kmalloc(fdt_size, GFP_KERNEL); if (!fdt) { pr_err("Not enough memory for the device tree.\n"); ret = -ENOMEM; goto out; } ret = fdt_open_into(initial_boot_params, fdt, fdt_size); if (ret < 0) { pr_err("Error setting up the new device tree.\n"); ret = -EINVAL; goto out; } ret = setup_new_fdt(image, fdt, initrd_load_addr, initrd_len, cmdline); if (ret) goto out; /* * Documentation/devicetree/booting-without-of.txt says we need to * add a reservation entry for the device tree block, but * early_init_fdt_reserve_self reserves the memory even if there's no * such entry. We'll add a reservation entry anyway, to be safe and * compliant. * * Use dummy values, we will correct them in a moment. */ ret = fdt_add_mem_rsv(fdt, 1, 1); if (ret) { pr_err("Error reserving device tree memory: %s\n", fdt_strerror(ret)); ret = -EINVAL; goto out; } fdt_pack(fdt); kbuf.buffer = fdt; kbuf.bufsz = kbuf.memsz = fdt_size; kbuf.buf_align = PAGE_SIZE; kbuf.top_down = true; ret = kexec_add_buffer(&kbuf); if (ret) goto out; fdt_load_addr = kbuf.mem; /* * Fix fdt reservation, now that we now where it will be loaded * and how big it is. */ rsvmap = fdt + fdt_off_mem_rsvmap(fdt); i = fdt_num_mem_rsv(fdt) - 1; rsvmap[i].address = cpu_to_fdt64(fdt_load_addr); rsvmap[i].size = cpu_to_fdt64(fdt_totalsize(fdt)); pr_debug("Loaded device tree at 0x%lx\n", fdt_load_addr); kbuf.memsz = PURGATORY_STACK_SIZE; kbuf.buf_align = PAGE_SIZE; kbuf.top_down = true; ret = kexec_locate_mem_hole(&kbuf); if (ret) { pr_err("Couldn't find free memory for the purgatory stack.\n"); ret = -ENOMEM; goto out; } stack_top = kbuf.mem + PURGATORY_STACK_SIZE - 1; pr_debug("Purgatory stack is at 0x%lx\n", stack_top); slave_code = elf_info.buffer + elf_info.proghdrs[0].p_offset; ret = setup_purgatory(image, slave_code, fdt, kernel_load_addr, fdt_load_addr, stack_top, find_debug_console(fdt)); if (ret) pr_err("Error setting up the purgatory.\n"); out: elf_free_info(&elf_info); /* Make kimage_file_post_load_cleanup free the fdt buffer for us. */ return ret ? ERR_PTR(ret) : fdt; } struct kexec_file_ops kexec_elf64_ops = { .probe = elf64_probe, .load = elf64_load, };
efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long orig_fdt_size, void *fdt, int new_fdt_size, char *cmdline_ptr, u64 initrd_addr, u64 initrd_size, efi_memory_desc_t *memory_map, unsigned long map_size, unsigned long desc_size, u32 desc_ver) { int node, num_rsv; int status; u32 fdt_val32; u64 fdt_val64; /* Do some checks on provided FDT, if it exists*/ if (orig_fdt) { if (fdt_check_header(orig_fdt)) { pr_efi_err(sys_table, "Device Tree header not valid!\n"); return EFI_LOAD_ERROR; } /* * We don't get the size of the FDT if we get if from a * configuration table. */ if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) { pr_efi_err(sys_table, "Truncated device tree! foo!\n"); return EFI_LOAD_ERROR; } } if (orig_fdt) status = fdt_open_into(orig_fdt, fdt, new_fdt_size); else status = fdt_create_empty_tree(fdt, new_fdt_size); if (status != 0) goto fdt_set_fail; /* * Delete all memory reserve map entries. When booting via UEFI, * kernel will use the UEFI memory map to find reserved regions. */ num_rsv = fdt_num_mem_rsv(fdt); while (num_rsv-- > 0) fdt_del_mem_rsv(fdt, num_rsv); node = fdt_subnode_offset(fdt, 0, "chosen"); if (node < 0) { node = fdt_add_subnode(fdt, 0, "chosen"); if (node < 0) { status = node; /* node is error code when negative */ goto fdt_set_fail; } } if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) { status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr, strlen(cmdline_ptr) + 1); if (status) goto fdt_set_fail; } /* Set initrd address/end in device tree, if present */ if (initrd_size != 0) { u64 initrd_image_end; u64 initrd_image_start = cpu_to_fdt64(initrd_addr); status = fdt_setprop(fdt, node, "linux,initrd-start", &initrd_image_start, sizeof(u64)); if (status) goto fdt_set_fail; initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size); status = fdt_setprop(fdt, node, "linux,initrd-end", &initrd_image_end, sizeof(u64)); if (status) goto fdt_set_fail; } /* Add FDT entries for EFI runtime services in chosen node. */ node = fdt_subnode_offset(fdt, 0, "chosen"); fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table); status = fdt_setprop(fdt, node, "linux,uefi-system-table", &fdt_val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map); status = fdt_setprop(fdt, node, "linux,uefi-mmap-start", &fdt_val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(map_size); status = fdt_setprop(fdt, node, "linux,uefi-mmap-size", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(desc_size); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(desc_ver); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { efi_status_t efi_status; efi_status = efi_get_random_bytes(sys_table, sizeof(fdt_val64), (u8 *)&fdt_val64); if (efi_status == EFI_SUCCESS) { status = fdt_setprop(fdt, node, "kaslr-seed", &fdt_val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; } else if (efi_status != EFI_NOT_FOUND) { return efi_status; } } return EFI_SUCCESS; fdt_set_fail: if (status == -FDT_ERR_NOSPACE) return EFI_BUFFER_TOO_SMALL; return EFI_LOAD_ERROR; }
int atags_to_fdt(void *atag_list, void *fdt, int total_space) { struct tag *atag = atag_list; /* In the case of 64 bits memory size, need to reserve 2 cells for * address and size for each bank */ /* IAMROOT-12A: * ------------ * 64비트 시스템의 경우 한 개 뱅크당 주소와 사이즈((2 + 2) x sizeof(int32)) */ uint32_t mem_reg_property[2 * 2 * NR_BANKS]; int memcount = 0; int ret, memsize; /* make sure we've got an aligned pointer */ if ((u32)atag_list & 0x3) return 1; /* IAMROOT-12A: * ------------ * atag/DTB 포인터에서 DTB 매직넘버를 발견하면 이미 DTB가 존재하는 것으로 파악이되어 * ATAG를 컨버전할 필요 없으므로 성공으로 리턴 */ /* if we get a DTB here we're done already */ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) return 0; /* IAMROOT-12A: * ------------ * 처음에 오는 태크가 ATAG_CORE가 아니거나 사이즈가 맞지않으면 실패(1)로 리턴 */ /* validate the ATAG */ if (atag->hdr.tag != ATAG_CORE || (atag->hdr.size != tag_size(tag_core) && atag->hdr.size != 2)) return 1; /* let's give it all the room it could need */ ret = fdt_open_into(fdt, fdt, total_space); if (ret < 0) return ret; /* IAMROOT-12A: * ------------ * atag_list는 atag 개채의 묶음. * for_each_tag()를 수행 시 atag에 하나의 ATAG를 가리키는 포인터가 담김 * 태그는 3개(ATAG_CMDLINE, ATAG_MEM, ATAG_INITRD2)만 디바이스트리로 컨버전 * - ATAG_CMDLINE(cmdline) ---> DTB:/chosen 노드 -> bootargs 프로퍼티 * - ATAG_MEM(u.mem.start & u.mem.size x N뱅크) ---> DTB:/memory 노드 -> reg 프로퍼티 * - ATAG_INITRD2(u.initrd.start & u.initrd.size) ---> DTB:/chosen 노드 -> linux,initrd-start * ---> DTB:/chosen 노드 -> linux,initrd-end */ for_each_tag(atag, atag_list) { if (atag->hdr.tag == ATAG_CMDLINE) { /* Append the ATAGS command line to the device tree * command line. * NB: This means that if the same parameter is set in * the device tree and in the tags, the one from the * tags will be chosen. */ if (do_extend_cmdline) merge_fdt_bootargs(fdt, atag->u.cmdline.cmdline); else setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/4) continue; if (!atag->u.mem.size) continue; memsize = get_cell_size(fdt); /* IAMROOT-12A: * ------------ * memsize=2인 경우 64비트 * ATAG_MEM은 여러 개가 존재할 수 있다. */ if (memsize == 2) { /* if memsize is 2, that means that * each data needs 2 cells of 32 bits, * so the data are 64 bits */ uint64_t *mem_reg_prop64 = (uint64_t *)mem_reg_property; mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.start); mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.size); } else { mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); } } else if (atag->hdr.tag == ATAG_INITRD2) { uint32_t initrd_start, initrd_size; initrd_start = atag->u.initrd.start; initrd_size = atag->u.initrd.size; setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); } } if (memcount) { setprop(fdt, "/memory", "reg", mem_reg_property, 4 * memcount * memsize); } return fdt_pack(fdt); }
EFI_STATUS PrepareFdt ( IN CONST CHAR8* CommandLineArguments, IN EFI_PHYSICAL_ADDRESS InitrdImage, IN UINTN InitrdImageSize, IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase, IN OUT UINTN *FdtBlobSize ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS NewFdtBlobBase; EFI_PHYSICAL_ADDRESS NewFdtBlobAllocation; UINTN NewFdtBlobSize; VOID* fdt; INTN err; INTN node; INT32 lenp; CONST VOID* BootArg; EFI_PHYSICAL_ADDRESS InitrdImageStart; EFI_PHYSICAL_ADDRESS InitrdImageEnd; UINTN Index; UINTN MemoryMapSize; EFI_MEMORY_DESCRIPTOR *MemoryMap; EFI_MEMORY_DESCRIPTOR *MemoryMapPtr; UINTN MapKey; UINTN DescriptorSize; UINT32 DescriptorVersion; UINTN Pages; UINTN OriginalFdtSize; NewFdtBlobAllocation = 0; // // Sanity checks on the original FDT blob. // err = fdt_check_header ((VOID*)(UINTN)(*FdtBlobBase)); if (err != 0) { Print (L"ERROR: Device Tree header not valid (err:%d)\n", err); return EFI_INVALID_PARAMETER; } // The original FDT blob might have been loaded partially. // Check that it is not the case. OriginalFdtSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase)); if (OriginalFdtSize > *FdtBlobSize) { Print (L"ERROR: Incomplete FDT. Only %d/%d bytes have been loaded.\n", *FdtBlobSize, OriginalFdtSize); return EFI_INVALID_PARAMETER; } // // Relocate the FDT to its final location. // Status = RelocateFdt (*FdtBlobBase, OriginalFdtSize, &NewFdtBlobBase, &NewFdtBlobSize, &NewFdtBlobAllocation); if (EFI_ERROR (Status)) { goto FAIL_RELOCATE_FDT; } fdt = (VOID*)(UINTN)NewFdtBlobBase; node = fdt_subnode_offset (fdt, 0, "chosen"); if (node < 0) { // The 'chosen' node does not exist, create it node = fdt_add_subnode (fdt, 0, "chosen"); if (node < 0) { DEBUG ((EFI_D_ERROR, "Error on finding 'chosen' node\n")); Status = EFI_INVALID_PARAMETER; goto FAIL_COMPLETE_FDT; } } DEBUG_CODE_BEGIN (); BootArg = fdt_getprop (fdt, node, "bootargs", &lenp); if (BootArg != NULL) { DEBUG ((EFI_D_ERROR, "BootArg: %a\n", BootArg)); } DEBUG_CODE_END (); // // Set Linux CmdLine // if ((CommandLineArguments != NULL) && (AsciiStrLen (CommandLineArguments) > 0)) { err = fdt_setprop (fdt, node, "bootargs", CommandLineArguments, AsciiStrSize (CommandLineArguments)); if (err) { DEBUG ((EFI_D_ERROR, "Fail to set new 'bootarg' (err:%d)\n", err)); } } // // Set Linux Initrd // if (InitrdImageSize != 0) { InitrdImageStart = cpu_to_fdt64 (InitrdImage); err = fdt_setprop (fdt, node, "linux,initrd-start", &InitrdImageStart, sizeof (EFI_PHYSICAL_ADDRESS)); if (err) { DEBUG ((EFI_D_ERROR, "Fail to set new 'linux,initrd-start' (err:%d)\n", err)); } InitrdImageEnd = cpu_to_fdt64 (InitrdImage + InitrdImageSize); err = fdt_setprop (fdt, node, "linux,initrd-end", &InitrdImageEnd, sizeof (EFI_PHYSICAL_ADDRESS)); if (err) { DEBUG ((EFI_D_ERROR, "Fail to set new 'linux,initrd-start' (err:%d)\n", err)); } } // // Add the memory regions reserved by the UEFI Firmware // // Retrieve the UEFI Memory Map MemoryMap = NULL; MemoryMapSize = 0; Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion); if (Status == EFI_BUFFER_TOO_SMALL) { // The UEFI specification advises to allocate more memory for the MemoryMap buffer between successive // calls to GetMemoryMap(), since allocation of the new buffer may potentially increase memory map size. Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1; MemoryMap = AllocatePages (Pages); if (MemoryMap == NULL) { Status = EFI_OUT_OF_RESOURCES; goto FAIL_COMPLETE_FDT; } Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion); } // Go through the list and add the reserved region to the Device Tree if (!EFI_ERROR (Status)) { MemoryMapPtr = MemoryMap; for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) { if (IsLinuxReservedRegion ((EFI_MEMORY_TYPE)MemoryMapPtr->Type)) { DEBUG ((DEBUG_VERBOSE, "Reserved region of type %d [0x%lX, 0x%lX]\n", MemoryMapPtr->Type, (UINTN)MemoryMapPtr->PhysicalStart, (UINTN)(MemoryMapPtr->PhysicalStart + MemoryMapPtr->NumberOfPages * EFI_PAGE_SIZE))); err = fdt_add_mem_rsv (fdt, MemoryMapPtr->PhysicalStart, MemoryMapPtr->NumberOfPages * EFI_PAGE_SIZE); if (err != 0) { Print (L"Warning: Fail to add 'memreserve' (err:%d)\n", err); } } MemoryMapPtr = (EFI_MEMORY_DESCRIPTOR*)((UINTN)MemoryMapPtr + DescriptorSize); } } // Update the real size of the Device Tree fdt_pack ((VOID*)(UINTN)(NewFdtBlobBase)); *FdtBlobBase = NewFdtBlobBase; *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(NewFdtBlobBase)); return EFI_SUCCESS; FAIL_COMPLETE_FDT: gBS->FreePages (NewFdtBlobAllocation, EFI_SIZE_TO_PAGES (NewFdtBlobSize)); FAIL_RELOCATE_FDT: *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase)); // Return success even if we failed to update the FDT blob. // The original one is still valid. return EFI_SUCCESS; }
struct data data_append_addr(struct data d, uint64_t addr) { uint64_t beaddr = cpu_to_fdt64(addr); return data_append_data(d, &beaddr, sizeof(beaddr)); }
void fdt_fixup_memory(struct fdt_mem_region *region, size_t num) { struct fdt_mem_region *curmr; uint32_t addr_cells, size_cells; uint32_t *addr_cellsp, *size_cellsp; int err, i, len, memory, root; size_t realmrno; uint8_t *buf, *sb; uint64_t rstart, rsize; int reserved; root = fdt_path_offset(fdtp, "/"); if (root < 0) { sprintf(command_errbuf, "Could not find root node !"); return; } memory = fdt_path_offset(fdtp, "/memory"); if (memory <= 0) { /* Create proper '/memory' node. */ memory = fdt_add_subnode(fdtp, root, "memory"); if (memory <= 0) { sprintf(command_errbuf, "Could not fixup '/memory' " "node, error code : %d!\n", memory); return; } err = fdt_setprop(fdtp, memory, "device_type", "memory", sizeof("memory")); if (err < 0) return; } addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", NULL); size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); if (addr_cellsp == NULL || size_cellsp == NULL) { sprintf(command_errbuf, "Could not fixup '/memory' node : " "%s %s property not found in root node!\n", (!addr_cellsp) ? "#address-cells" : "", (!size_cellsp) ? "#size-cells" : ""); return; } addr_cells = fdt32_to_cpu(*addr_cellsp); size_cells = fdt32_to_cpu(*size_cellsp); /* * Convert memreserve data to memreserve property * Check if property already exists */ reserved = fdt_num_mem_rsv(fdtp); if (reserved && (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) { len = (addr_cells + size_cells) * reserved * sizeof(uint32_t); sb = buf = (uint8_t *)malloc(len); if (!buf) return; bzero(buf, len); for (i = 0; i < reserved; i++) { if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize)) break; if (rsize) { /* Ensure endianess, and put cells into a buffer */ if (addr_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(rstart); else *(uint32_t *)buf = cpu_to_fdt32(rstart); buf += sizeof(uint32_t) * addr_cells; if (size_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(rsize); else *(uint32_t *)buf = cpu_to_fdt32(rsize); buf += sizeof(uint32_t) * size_cells; } } /* Set property */ if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0) printf("Could not fixup 'memreserve' property.\n"); free(sb); } /* Count valid memory regions entries in sysinfo. */ realmrno = num; for (i = 0; i < num; i++) if (region[i].start == 0 && region[i].size == 0) realmrno--; if (realmrno == 0) { sprintf(command_errbuf, "Could not fixup '/memory' node : " "sysinfo doesn't contain valid memory regions info!\n"); return; } len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); sb = buf = (uint8_t *)malloc(len); if (!buf) return; bzero(buf, len); for (i = 0; i < num; i++) { curmr = ®ion[i]; if (curmr->size != 0) { /* Ensure endianess, and put cells into a buffer */ if (addr_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(curmr->start); else *(uint32_t *)buf = cpu_to_fdt32(curmr->start); buf += sizeof(uint32_t) * addr_cells; if (size_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(curmr->size); else *(uint32_t *)buf = cpu_to_fdt32(curmr->size); buf += sizeof(uint32_t) * size_cells; } } /* Set property */ if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); free(sb); }