static int imx_bbu_check_prereq(struct imx_internal_bbu_handler *imx_handler, const char *devicefile, struct bbu_data *data, enum filetype expected_type) { int ret; const void *blob; size_t len; enum filetype type; type = file_detect_type(data->image, data->len); switch (type) { case filetype_arm_barebox: /* * Specifying expected_type as unknown will disable the * inner image type check. * * The only user of this code is * imx_bbu_external_nor_register_handler() used by * i.MX27. */ if (expected_type == filetype_unknown) break; blob = data->image + imx_handler->flash_header_offset; len = data->len - imx_handler->flash_header_offset; type = file_detect_type(blob, len); if (type != expected_type) { pr_err("Expected image type: %s, " "detected image type: %s\n", file_type_to_string(expected_type), file_type_to_string(type)); return -EINVAL; } break; default: if (!bbu_force(data, "Not an ARM barebox image")) return -EINVAL; } ret = bbu_confirm(data); if (ret) return ret; device_detect_by_name(devpath_to_name(devicefile)); return 0; }
static int tegra_bbu_emmc_handler(struct bbu_handler *handler, struct bbu_data *data) { int fd, ret; if (file_detect_type(data->image + 0x4000, data->len) != filetype_arm_barebox && !bbu_force(data, "Not an ARM barebox image")) return -EINVAL; ret = bbu_confirm(data); if (ret) return ret; fd = open(data->devicefile, O_WRONLY); if (fd < 0) return fd; ret = write(fd, data->image, data->len); if (ret < 0) { pr_err("writing update to %s failed with %s\n", data->devicefile, strerror(-ret)); goto err_close; } ret = 0; err_close: close(fd); return ret; }
static int do_bootz_linux_fdt(int fd, struct image_data *data) { struct fdt_header __header, *header; void *oftree; int ret; u32 end; if (data->oftree) return -ENXIO; header = &__header; ret = read(fd, header, sizeof(*header)); if (ret < sizeof(*header)) return ret; if (file_detect_type(header, sizeof(*header)) != filetype_oftree) return -ENXIO; end = be32_to_cpu(header->totalsize); oftree = malloc(end + 0x8000); if (!oftree) { perror("zImage: oftree malloc"); return -ENOMEM; } memcpy(oftree, header, sizeof(*header)); end -= sizeof(*header); ret = read_full(fd, oftree + sizeof(*header), end); if (ret < 0) goto err_free; if (ret < end) { printf("premature end of image\n"); ret = -EIO; goto err_free; } if (IS_BUILTIN(CONFIG_OFTREE)) { data->of_root_node = of_unflatten_dtb(NULL, oftree); if (!data->of_root_node) { pr_err("unable to unflatten devicetree\n"); ret = -EINVAL; goto err_free; } } else { data->oftree = oftree; } pr_info("zImage: concatenated oftree detected\n"); return 0; err_free: free(oftree); return ret; }
/* * Update barebox on a v1 type internal boot (i.MX25, i.MX35, i.MX51) * * This constructs a DCD header, adds the specific DCD data and writes * the resulting image to the device. Currently this handles MMC/SD * devices. */ static int imx_bbu_internal_v1_update(struct bbu_handler *handler, struct bbu_data *data) { struct imx_internal_bbu_handler *imx_handler = container_of(handler, struct imx_internal_bbu_handler, handler); struct imx_flash_header *flash_header; unsigned long flash_header_offset = imx_handler->flash_header_offset; u32 *dcd_image_size; void *imx_pre_image; int imx_pre_image_size = 0x2000; int ret, image_len; void *buf; if (file_detect_type(data->image, data->len) != filetype_arm_barebox) { if (!bbu_force(data, "Not an ARM barebox image")) return -EINVAL; } ret = bbu_confirm(data); if (ret) return ret; printf("updating to %s\n", data->devicefile); imx_pre_image = xzalloc(imx_pre_image_size); flash_header = imx_pre_image + flash_header_offset; flash_header->app_code_jump_vector = imx_handler->app_dest + 0x1000; flash_header->app_code_barker = APP_CODE_BARKER; flash_header->app_code_csf = 0; flash_header->dcd_ptr_ptr = imx_handler->app_dest + flash_header_offset + offsetof(struct imx_flash_header, dcd); flash_header->super_root_key = 0; flash_header->dcd = imx_handler->app_dest + flash_header_offset + offsetof(struct imx_flash_header, dcd_barker); flash_header->app_dest = imx_handler->app_dest; flash_header->dcd_barker = DCD_BARKER; flash_header->dcd_block_len = imx_handler->dcdsize; memcpy((void *)flash_header + sizeof(*flash_header), imx_handler->dcd, imx_handler->dcdsize); dcd_image_size = (imx_pre_image + flash_header_offset + sizeof(*flash_header) + imx_handler->dcdsize); *dcd_image_size = ALIGN(imx_pre_image_size + data->len, 4096); /* Create a buffer containing header and image data */ image_len = data->len + imx_pre_image_size; buf = xzalloc(image_len); memcpy(buf, imx_pre_image, imx_pre_image_size); memcpy(buf + imx_pre_image_size, data->image, data->len); ret = imx_bbu_write_device(imx_handler, data, buf, image_len); free(buf); free(imx_pre_image); return ret; }
static int imx_bbu_check_prereq(struct bbu_data *data) { int ret; if (file_detect_type(data->image, data->len) != filetype_arm_barebox) { if (!bbu_force(data, "Not an ARM barebox image")) return -EINVAL; } ret = bbu_confirm(data); if (ret) return ret; return 0; }
enum filetype file_name_detect_type(const char *filename) { int fd, ret; void *buf; enum filetype type = filetype_unknown; unsigned long bootsec; fd = open(filename, O_RDONLY); if (fd < 0) return fd; buf = xzalloc(512); ret = read(fd, buf, 512); if (ret < 0) goto err_out; type = file_detect_type(buf); if (type == filetype_mbr) { /* * Get the first partition start sector * and check for FAT in it */ is_fat_or_mbr(buf, &bootsec); ret = lseek(fd, (bootsec) * 512, SEEK_SET); if (ret < 0) goto err_out; ret = read(fd, buf, 512); if (ret < 0) goto err_out; type = is_fat_or_mbr((u8 *)buf, NULL); } err_out: close(fd); free(buf); return type; }
enum filetype file_name_detect_type(const char *filename) { int fd, ret; void *buf; enum filetype type = filetype_unknown; fd = open(filename, O_RDONLY); if (fd < 0) return fd; buf = xmalloc(512); ret = read(fd, buf, 512); if (ret != 512) goto err_out; type = file_detect_type(buf); err_out: close(fd); free(buf); return type; }
void *uimage_load_to_buf(struct uimage_handle *handle, int image_no, size_t *outsize) { u32 size; int ret; struct uimage_handle_data *ihd; char ftbuf[128]; enum filetype ft; void *buf; if (image_no >= handle->nb_data_entries) return NULL; ihd = &handle->ihd[image_no]; ret = lseek(handle->fd, ihd->offset + handle->data_offset, SEEK_SET); if (ret < 0) return NULL; if (handle->header.ih_comp == IH_COMP_NONE) { buf = malloc(ihd->len); if (!buf) return NULL; ret = read_full(handle->fd, buf, ihd->len); if (ret < ihd->len) { free(buf); return NULL; } size = ihd->len; goto out; } ret = read(handle->fd, ftbuf, 128); if (ret < 0) return NULL; ft = file_detect_type(ftbuf, 128); if ((int)ft < 0) return NULL; if (ft != filetype_gzip) return NULL; ret = lseek(handle->fd, ihd->offset + handle->data_offset + ihd->len - 4, SEEK_SET); if (ret < 0) return NULL; ret = read(handle->fd, &size, 4); if (ret < 0) return NULL; size = le32_to_cpu(size); ret = lseek(handle->fd, ihd->offset + handle->data_offset, SEEK_SET); if (ret < 0) return NULL; buf = malloc(size); ret = uncompress_fd_to_buf(handle->fd, buf, uncompress_err_stdout); if (ret) { free(buf); return NULL; } out: if (outsize) *outsize = size; return buf; }
static int do_bootz_linux_fdt(int fd, struct image_data *data) { struct fdt_header __header, *header; struct resource *r = data->os_res; struct resource *of_res = data->os_res; void *oftree; int ret; u32 end; header = &__header; ret = read(fd, header, sizeof(*header)); if (ret < sizeof(*header)) return ret; if (file_detect_type(header) != filetype_oftree) return -ENXIO; end = be32_to_cpu(header->totalsize); if (IS_BUILTIN(CONFIG_OFTREE)) { oftree = malloc(end + 0x8000); if (!oftree) { perror("zImage: oftree malloc"); return -ENOMEM; } } else { of_res = request_sdram_region("oftree", r->start + resource_size(r), end); if (!of_res) { perror("zImage: oftree request_sdram_region"); return -ENOMEM; } oftree = (void*)of_res->start; } memcpy(oftree, header, sizeof(*header)); end -= sizeof(*header); ret = read_full(fd, oftree + sizeof(*header), end); if (ret < 0) return ret; if (ret < end) { printf("premature end of image\n"); return -EIO; } if (IS_BUILTIN(CONFIG_OFTREE)) { fdt_open_into(oftree, oftree, end + 0x8000); ret = of_fix_tree(oftree); if (ret) return ret; data->oftree = oftree; } pr_info("zImage: concatenated oftree detected\n"); return 0; }
int save_file(Computer* comp, const char* name, int id, int drv) { QString path = QDialog::trUtf8(name); QString flt; QString ext; xFileTypeInfo* inf = NULL; xFileTypeInfo* tin; xFileGroupInfo* grp; int i; int flg; if (id == FG_DISK) id = disk_id[drv & 3]; if (id == FG_ALL) id = detect_hw_id(comp->hw->id); int err = ERR_OK; if (path.isEmpty()) { flt = file_get_hw_filter(comp, id, 1); if (flt.isEmpty()) { flt = file_get_group_filter(comp, id, 1); if (flt.isEmpty()) flt = file_get_type_filter(id, 1); } if (!flt.isEmpty()) { filer->setWindowTitle("Save file"); filer->setNameFilter(flt); filer->setAcceptMode(QFileDialog::AcceptSave); filer->setDirectory(conf.path.lastDir); filer->setHistory(QStringList()); if (filer->exec()) { path = filer->selectedFiles().first(); flt = filer->selectedNameFilter(); grp = file_detect_grp(flt); if (grp->id != FL_NONE) { drv = grp->drv; i = 0; flg = 1; // scan group file types and check if path extension is the same while ((grp->child[i] != FL_NONE) && flg) { tin = file_find_type(grp->child[i]); if (tin) { if (path.endsWith(tin->ext, Qt::CaseInsensitive)) { flg = 0; inf = tin; } } i++; } // if no filetypes found, add default extension if (flg) { path.append(grp->defext); } } else { tin = file_detect_type(flt); if (tin->id != FL_NONE) { path.append(tin->ext); } } } strcpy(conf.path.lastDir, filer->directory().absolutePath().toLocal8Bit().data()); } } if (path.isEmpty()) return err; if (drv < 0) drv = 0; if (!inf) inf = file_ext_type(path); if (inf) { if (inf->save) { err = inf->save(comp, path.toLocal8Bit().data(), drv); } else { shitHappens("Can't save that"); } } else { shitHappens("Don't know such extension"); } file_errors(err); return err; }
static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *data) { struct imx_nand_fcb_bbu_handler *imx_handler = container_of(handler, struct imx_nand_fcb_bbu_handler, handler); struct cdev *bcb_cdev; struct mtd_info *mtd; int ret, i; struct fcb_block *fcb = NULL; void *fw = NULL, *fw_orig = NULL; unsigned fw_size, partition_size; enum filetype filetype; unsigned num_blocks_fw; int pages_per_block; int used = 0; int fw_orig_len; int used_refresh = 0, unused_refresh = 0; if (data->image) { filetype = file_detect_type(data->image, data->len); if (filetype != imx_handler->filetype && !bbu_force(data, "Image is not of type %s but of type %s", file_type_to_string(imx_handler->filetype), file_type_to_string(filetype))) return -EINVAL; } bcb_cdev = cdev_by_name(handler->devicefile); if (!bcb_cdev) { pr_err("%s: No FCB device!\n", __func__); return -ENODEV; } mtd = bcb_cdev->mtd; partition_size = mtd->size; pages_per_block = mtd->erasesize / mtd->writesize; for (i = 0; i < 4; i++) { read_fcb(mtd, i, &fcb); if (fcb) break; } /* * This code uses the following layout in the Nand flash: * * fwmaxsize = (n_blocks - 4) / 2 * * block * * 0 ---------------------- * | FCB/DBBT 0 | * 1 ---------------------- * | FCB/DBBT 1 | * 2 ---------------------- * | FCB/DBBT 2 | * 3 ---------------------- * | FCB/DBBT 3 | * 4 ---------------------- * | Firmware slot 0 | * 4 + fwmaxsize ---------------------- * | Firmware slot 1 | * ---------------------- * * We want a robust update in which a power failure may occur * everytime without bricking the board, so here's the strategy: * * The FCBs contain pointers to the firmware slots in the * Firmware1_startingPage and Firmware2_startingPage fields. Note that * Firmware1_startingPage doesn't necessarily point to slot 0. We * exchange the pointers during update to atomically switch between the * old and the new firmware. * * - We read the first valid FCB and the firmware slots. * - We check which firmware slot is currently used by the ROM: * - if no FCB is found or its layout differs from the above layout, * continue without robust update * - if only one firmware slot is readable, the ROM uses it * - if both slots are readable, the ROM will use slot 0 * - Step 1: erase/update the slot currently unused by the ROM * - Step 2: Update FCBs/DBBTs, thereby letting Firmware1_startingPage * point to the slot we just updated. From this moment * on the new firmware will be used and running a * refresh/repair after a power failure after this * step will complete the update. * - Step 3: erase/update the other firmwre slot * - Step 4: Eventually write FCBs/DBBTs again. This may become * necessary when step 3 revealed new bad blocks. * * This robust update only works when the original FCBs on the device * uses the same layout as this code does. In other cases update will * also work, but it won't be robust against power failures. * * Refreshing the firmware which is needed when blocks become unreadable * due to read disturbance works the same way, only that the new firmware * is the same as the old firmware and that it will only be written when * reading from the device returns -EUCLEAN indicating that a block needs * to be rewritten. */ if (fcb) read_firmware_all(mtd, fcb, &fw_orig, &fw_orig_len, &used_refresh, &unused_refresh, &used); if (data->image) { /* * We have to write one additional page to make the ROM happy. * Maybe the PagesInFirmwarex fields are really the number of pages - 1. * kobs-ng has the same. */ fw_size = ALIGN(data->len + mtd->writesize, mtd->writesize); fw = xzalloc(fw_size); memcpy(fw, data->image, data->len); free(fw_orig); used_refresh = 1; unused_refresh = 1; free(fcb); fcb = xzalloc(sizeof(*fcb)); fcb->Firmware1_startingPage = imx_bbu_firmware_start_block(mtd, !used) * pages_per_block; fcb->Firmware2_startingPage = imx_bbu_firmware_start_block(mtd, used) * pages_per_block; fcb->PagesInFirmware1 = fw_size / mtd->writesize; fcb->PagesInFirmware2 = fcb->PagesInFirmware1; fcb_create(imx_handler, fcb, mtd); } else { if (!fcb) { pr_err("No FCB found on device, cannot refresh\n"); ret = -EINVAL; goto out; } if (!fw_orig) { pr_err("No firmware found on device, cannot refresh\n"); ret = -EINVAL; goto out; } fw = fw_orig; fw_size = fw_orig_len; pr_info("Refreshing existing firmware\n"); } num_blocks_fw = imx_bbu_firmware_max_blocks(mtd); if (num_blocks_fw * mtd->erasesize < fw_size) { pr_err("Not enough space for update\n"); return -ENOSPC; } ret = bbu_confirm(data); if (ret) goto out; /* Step 1: write firmware which is currently unused by the ROM */ if (unused_refresh) { pr_info("%sing slot %d\n", data->image ? "updat" : "refresh", !used); ret = imx_bbu_write_firmware(mtd, !used, fw, fw_size); if (ret < 0) goto out; } else { pr_info("firmware slot %d still ok, nothing to do\n", !used); } /* * Step 2: Write FCBs/DBBTs. This will use the firmware we have * just written as primary firmware. From now on the new * firmware will be booted. */ ret = imx_bbu_write_fcbs_dbbts(mtd, fcb); if (ret < 0) goto out; /* Step 3: Write the secondary firmware */ if (used_refresh) { pr_info("%sing slot %d\n", data->image ? "updat" : "refresh", used); ret = imx_bbu_write_firmware(mtd, used, fw, fw_size); if (ret < 0) goto out; } else { pr_info("firmware slot %d still ok, nothing to do\n", used); } /* * Step 4: If writing the secondary firmware discovered new bad * blocks, write the FCBs/DBBTs again with updated bad block * information. */ if (ret > 0) { pr_info("New bad blocks detected, writing FCBs/DBBTs again\n"); ret = imx_bbu_write_fcbs_dbbts(mtd, fcb); if (ret < 0) goto out; } out: free(fw); free(fcb); return ret; }
/* * Update barebox on a v2 type internal boot (i.MX53) * * This constructs a DCD header, adds the specific DCD data and writes * the resulting image to the device. Currently this handles MMC/SD * and NAND devices. */ static int imx_bbu_internal_v2_update(struct bbu_handler *handler, struct bbu_data *data) { struct imx_internal_bbu_handler *imx_handler = container_of(handler, struct imx_internal_bbu_handler, handler); struct imx_flash_header_v2 *flash_header; unsigned long flash_header_offset = imx_handler->flash_header_offset; void *imx_pre_image; int imx_pre_image_size; int ret, image_len; void *buf; if (file_detect_type(data->image, data->len) != filetype_arm_barebox) { if (!bbu_force(data, "Not an ARM barebox image")) return -EINVAL; } ret = bbu_confirm(data); if (ret) return ret; printf("updating to %s\n", data->devicefile); if (imx_handler->flags & IMX_INTERNAL_FLAG_NAND) /* NAND needs additional space for the DBBT */ imx_pre_image_size = 0x8000; else imx_pre_image_size = 0x2000; imx_pre_image = xzalloc(imx_pre_image_size); flash_header = imx_pre_image + flash_header_offset; flash_header->header.tag = IVT_HEADER_TAG; flash_header->header.length = cpu_to_be16(32); flash_header->header.version = IVT_VERSION; flash_header->entry = imx_handler->app_dest + imx_pre_image_size; if (imx_handler->dcdsize) flash_header->dcd_ptr = imx_handler->app_dest + flash_header_offset + offsetof(struct imx_flash_header_v2, dcd); flash_header->boot_data_ptr = imx_handler->app_dest + flash_header_offset + offsetof(struct imx_flash_header_v2, boot_data); flash_header->self = imx_handler->app_dest + flash_header_offset; flash_header->boot_data.start = imx_handler->app_dest; flash_header->boot_data.size = ALIGN(imx_pre_image_size + data->len, 4096);; if (imx_handler->dcdsize) { flash_header->dcd.header.tag = DCD_HEADER_TAG; flash_header->dcd.header.length = cpu_to_be16(sizeof(struct imx_dcd) + imx_handler->dcdsize); flash_header->dcd.header.version = DCD_VERSION; } /* Add dcd data */ memcpy((void *)flash_header + sizeof(*flash_header), imx_handler->dcd, imx_handler->dcdsize); /* Create a buffer containing header and image data */ image_len = data->len + imx_pre_image_size; buf = xzalloc(image_len); memcpy(buf, imx_pre_image, imx_pre_image_size); memcpy(buf + imx_pre_image_size, data->image, data->len); if (imx_handler->flags & IMX_INTERNAL_FLAG_NAND) { ret = imx_bbu_internal_v2_write_nand_dbbt(imx_handler, data, buf, image_len); goto out_free_buf; } ret = imx_bbu_write_device(imx_handler, data, buf, image_len); out_free_buf: free(buf); free(imx_pre_image); return ret; }