/* * Verifying the Golden Image is idealistic. It will be evaluated * against the currently programmed image and thus may fail - due to * either rollback protection (if its an older version than that in use) * or if the version is the same as that of the in-use image. * Extracting the information as to why a failure occurred is not * currently possible due to limitations of the system controller * driver. If those are fixed, verification of the Golden Image should * be added here.
*/
priv->flash = mpfs_sys_controller_get_flash(priv->sys_controller); if (!priv->flash) return FW_UPLOAD_ERR_HW_ERROR;
/* * We need to calculate if we have enough space in the flash for the * new image. * First, chop off the first 1 KiB as it's reserved for the directory. * The 1 MiB reserved for design info needs to be ignored also. * All that remains is carved into 3 & rounded down to the erasesize. * If this is smaller than the image size, we abort. * There's also no need to consume more than 20 MiB per image.
*/
priv->size_per_bitstream = priv->flash->size - SZ_1K - SZ_1M;
priv->size_per_bitstream = round_down(priv->size_per_bitstream / 3, erase_size); if (priv->size_per_bitstream > 20 * SZ_1M)
priv->size_per_bitstream = 20 * SZ_1M;
if (priv->size_per_bitstream < size) {
dev_err(priv->dev, "flash device has insufficient capacity to store this bitstream\n"); return FW_UPLOAD_ERR_INVALID_SIZE;
}
if (!response_msg || !response || !message) return -ENOMEM;
/* * The system controller can verify that an image in the flash is valid. * Rather than duplicate the check in this driver, call the relevant * service from the system controller instead. * This service has no command data and no response data. It overloads * mbox_offset with the image index in the flash's SPI directory where * the bitstream is located.
*/
response->resp_msg = response_msg;
response->resp_size = AUTO_UPDATE_AUTHENTICATE_RESP_SIZE;
message->cmd_opcode = AUTO_UPDATE_AUTHENTICATE_CMD_OPCODE;
message->cmd_data_size = AUTO_UPDATE_AUTHENTICATE_CMD_DATA_SIZE;
message->response = response;
message->cmd_data = AUTO_UPDATE_AUTHENTICATE_CMD_DATA;
message->mbox_offset = AUTO_UPDATE_UPGRADE_INDEX;
message->resp_offset = AUTO_UPDATE_DEFAULT_RESP_OFFSET;
dev_info(priv->dev, "Running verification of Upgrade Image\n");
ret = mpfs_blocking_transaction(priv->sys_controller, message); if (ret | response->resp_status) {
dev_warn(priv->dev, "Verification of Upgrade Image failed!\n"); return ret ? ret : -EBADMSG;
}
dev_info(priv->dev, "Verification of Upgrade Image passed!\n");
/* * We need to write the "SPI DIRECTORY" to the first 1 KiB, telling * the system controller where to find the actual bitstream. Since * this is spi-nor, we have to read the first eraseblock, erase that * portion of the flash, modify the data and then write it back. * There's no need to do this though if things are already the way they * should be, so check and save the write in that case.
*/
ret = mtd_read(priv->flash, AUTO_UPDATE_DIRECTORY_BASE, erase_size, &bytes_read,
(u_char *)buffer); if (ret) return ret;
ret = mtd_erase(priv->flash, &erase); if (ret) return ret;
/* * Populate the image address and then zero out the next directory so * that the system controller doesn't complain if in "Single Image" * mode.
*/
memcpy(buffer + AUTO_UPDATE_UPGRADE_DIRECTORY, &image_address,
AUTO_UPDATE_DIRECTORY_WIDTH);
memset(buffer + AUTO_UPDATE_BLANK_DIRECTORY, 0x0, AUTO_UPDATE_DIRECTORY_WIDTH);
dev_info(priv->dev, "Writing the image address (0x%x) to the flash directory (0x%llx)\n",
image_address, directory_address);
ret = mtd_write(priv->flash, 0x0, erase_size, &bytes_written, (u_char *)buffer); if (ret) return ret;
/* * For bitstream info, the descriptor is written to a fixed offset, * so there is no need to set the image address.
*/ if (!is_info) {
ret = mpfs_auto_update_set_image_address(priv, image_address, directory_address); if (ret) {
dev_err(priv->dev, "failed to set image address in the SPI directory: %d\n", ret); return ret;
}
} else { if (size > AUTO_UPDATE_INFO_SIZE) {
dev_err(priv->dev, "bitstream info exceeds permitted size\n"); return -ENOSPC;
}
}
/* * Now the .spi image itself can be written to the flash. Preservation * of contents here is not important here, unlike the spi "directory" * which must be RMWed.
*/
erase.len = round_up(size, (size_t)priv->flash->erasesize);
erase.addr = image_address;
dev_info(priv->dev, "Erasing the flash at address (0x%x)\n", image_address);
ret = mtd_erase(priv->flash, &erase); if (ret) return ret;
/* * No parsing etc of the bitstream is required. The system controller * will do all of that itself - including verifying that the bitstream * is valid.
*/
dev_info(priv->dev, "Writing the image to the flash at address (0x%x)\n", image_address);
ret = mtd_write(priv->flash, (loff_t)image_address, size, &bytes_written, data); if (ret) return ret;
if (bytes_written != size) return -EIO;
*written = bytes_written;
dev_info(priv->dev, "Wrote 0x%zx bytes to the flash\n", bytes_written);
if (!response_msg || !response || !message) return -ENOMEM;
/* * To verify that Auto Update is possible, the "Query Security Service * Request" is performed. * This service has no command data & does not overload mbox_offset.
*/
response->resp_msg = response_msg;
response->resp_size = AUTO_UPDATE_FEATURE_RESP_SIZE;
message->cmd_opcode = AUTO_UPDATE_FEATURE_CMD_OPCODE;
message->cmd_data_size = AUTO_UPDATE_FEATURE_CMD_DATA_SIZE;
message->response = response;
message->cmd_data = AUTO_UPDATE_FEATURE_CMD_DATA;
message->mbox_offset = AUTO_UPDATE_DEFAULT_MBOX_OFFSET;
message->resp_offset = AUTO_UPDATE_DEFAULT_RESP_OFFSET;
ret = mpfs_blocking_transaction(priv->sys_controller, message); if (ret) return ret;
/* * Currently, the system controller's firmware does not generate any * interrupts for failed services, so mpfs_blocking_transaction() should * time out & therefore return an error. * Hitting this check is highly unlikely at present, but if the system * controller's behaviour changes so that it does generate interrupts * for failed services, it will be required.
*/ if (response->resp_status) return -EIO;
/* * Bit 5 of byte 1 is "UL_IAP" & if it is set, Auto Update is * not possible.
*/ if ((((u8 *)response_msg)[1] & AUTO_UPDATE_FEATURE_ENABLED)) return -EPERM;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
priv->sys_controller = mpfs_sys_controller_get(dev); if (IS_ERR(priv->sys_controller)) return dev_err_probe(dev, PTR_ERR(priv->sys_controller), "Could not register as a sub device of the system controller\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.