blob: bb37c63c25ae10508f93b5ba216e5dae48fcbfc1 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "updater.h"
#include <assert.h>
namespace opentitan {
namespace spiflash {
namespace {
// Populates frame |f| with |frame_number|, |code_offset|, and frame data
// starting at |code_offset| from |code| buffer. Calculates SHA256 hash of
// frame payload and it stores it in the frame header. Returns the number of
// bytes loaded into the frame.
uint32_t Populate(uint32_t frame_number, uint32_t code_offset,
const std::string &code, Frame *f) {
assert(f);
assert(code_offset < code.size());
// Populate payload data. Initialize buffer to 0xff to minimize flash
// writes.
size_t copy_size =
std::min<size_t>(f->PayloadSize(), code.size() - code_offset);
memset(f->data, 0xff, f->PayloadSize());
memcpy(f->data, code.data() + code_offset, copy_size);
// Populate header number, offset and hash.
f->hdr.frame_num = frame_number;
f->hdr.offset = code_offset;
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, &f->hdr.frame_num, sizeof(f->hdr.frame_num));
SHA256_Update(&sha256, &f->hdr.offset, sizeof(f->hdr.offset));
SHA256_Update(&sha256, f->data, f->PayloadSize());
SHA256_Final(f->hdr.hash, &sha256);
return copy_size;
}
} // namespace
bool Updater::Run() {
std::cout << "Running SPI flash update." << std::endl;
std::vector<Frame> frames;
if (!GenerateFrames(options_.code, &frames)) {
std::cerr << "Unable to process flash image." << std::endl;
return false;
}
std::cout << "Image divided into " << frames.size() << " frames."
<< std::endl;
for (const Frame &f : frames) {
std::cout << "frame: 0x" << std::setfill('0') << std::setw(8) << std::hex
<< f.hdr.frame_num << " to offset: 0x" << std::setfill('0')
<< std::setw(8) << std::hex << f.hdr.offset << std::endl;
uint8_t rx[sizeof(Frame)];
if (!spi_->TransmitFrame(reinterpret_cast<const uint8_t *>(&f), rx,
sizeof(Frame))) {
std::cerr << "Failed to transmit frame no: 0x" << std::setfill('0')
<< std::setw(8) << std::hex << f.hdr.frame_num << std::endl;
}
}
return true;
}
bool Updater::GenerateFrames(const std::string &code,
std::vector<Frame> *frames) {
if (frames == nullptr) {
return false;
}
uint32_t frame_number = 0;
uint32_t code_offset = 0;
while (code_offset < code.size()) {
Frame frame;
uint32_t bytes_copied = Populate(frame_number, code_offset, code, &frame);
code_offset += bytes_copied;
frame_number++;
frames->emplace_back(frame);
}
// Update last frame to sentinel EOF value.
Frame &last_frame = frames->back();
last_frame.hdr.frame_num = 0x80000000 | last_frame.hdr.frame_num;
return true;
}
} // namespace spiflash
} // namespace opentitan