Skip to content

Commit

Permalink
Libcaliptra piecewise FW load (#1651)
Browse files Browse the repository at this point in the history
* Libcaliptra: Adding function headers for piecewise FW LOAD

* Libcaliptra: Adding piecewise FW load for loading FW chunks at a time
  • Loading branch information
nquarton committed Sep 10, 2024
1 parent 593c9bd commit 8d6f8d7
Show file tree
Hide file tree
Showing 4 changed files with 299 additions and 60 deletions.
99 changes: 99 additions & 0 deletions libcaliptra/examples/generic/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,104 @@ int rom_test_devid_csr(const test_info* info)
return failure;
}

// Issue FW load commands repeatedly
// Coverage for piecewise FW load and runtime FW updates
int upload_fw_piecewise(const test_info* info)
{
int failure = 0;
int status = boot_to_ready_for_fw(info, false);

if (status){
printf("Failed to boot to ready for FW: 0x%x\n", status);
failure = 1;
}

// Some "random" size to split up the FW load into chunks
// These represent the first two chunks, the third chunk is the remainder of the image
// Sizes of 0 are ignored (meaning one fewer chunk is sent)
uint32_t chunk_sizes[][2] = {
{0x4, 0},
{0x1000, 0},
{0x1234, 0},
{0xe924, 0},
{0x8, 0x2000},
{0x2340, 0x4},
{0x388, 0x1844},
};

// Load FW in a loop, using the offsets above as points to split chunks
for (int i = 0; i < CALIPTRA_ARRAY_SIZE(chunk_sizes); i++) {
// Start the FW load
uint32_t total_fw_size = info->image_bundle.len;
status = caliptra_upload_fw_start_req(total_fw_size);

if (status)
{
printf("FW Load %d Start Failed: 0x%x\n", i, status);
dump_caliptra_error_codes();
failure = 1;
} else {
printf("FW Load %d Start: OK\n", i);
}

// Ensure other commands report busy during this process
struct caliptra_fips_version_resp version_resp;
status = caliptra_fips_version(&version_resp, false);
if (status != MBX_BUSY) {
printf("Command during piecewise FW load should report MBX_BUSY. Result was: 0x%x\n", status);
failure = 1;
}

uint32_t sent_bytes = 0;
uint8_t chunk_count = 0;
// Upload each of up to 3 chunks
// The size of the first two chunks comes from the table above
// The final chunk is the remainder
// Some chunks may be skipped if their size is 0 in the table
for (int j = 0; j < 3; j++){
uint32_t chunk_size;
if (j == 2) {
// Final chunk
chunk_size = total_fw_size - sent_bytes;
} else {
chunk_size = chunk_sizes[i][j];
}

if (chunk_size != 0){
// Set up the caliptra_buffer for the chunk and send it
struct caliptra_buffer fw_chunk = {.data = info->image_bundle.data + sent_bytes, .len = chunk_size};
status = caliptra_upload_fw_send_data(&fw_chunk);

if (status)
{
printf("FW Load %d Send Data chunk %d (%d bytes) Failed: 0x%x\n", i, chunk_count, status, chunk_size);
dump_caliptra_error_codes();
failure = 1;
} else {
printf("FW Load %d Send Data chunk %d (%d bytes): OK\n", i, chunk_count, chunk_size);
}

// Track what has been sent
sent_bytes += chunk_size;
chunk_count++;
}
}

// Finish the FW load
status = caliptra_upload_fw_end_req(false);

if (status)
{
printf("FW Load %d End Failed: 0x%x\n", i, status);
dump_caliptra_error_codes();
failure = 1;
} else {
printf("FW Load %d End: OK\n", i);
}
}

return failure;
}

// Test infrastructure

Expand Down Expand Up @@ -699,6 +797,7 @@ int run_tests(const test_info* info)
run_test(rom_test_all_commands, info, "Test all ROM commands");
run_test(rt_test_all_commands, info, "Test all Runtime commmands");
run_test(rom_test_devid_csr, info, "Test IDEV CSR GEN");
run_test(upload_fw_piecewise, info, "Test Piecewise FW Load");

if (global_test_result) {
printf("\t\tlibcaliptra test failures reported\n");
Expand Down
25 changes: 22 additions & 3 deletions libcaliptra/inc/caliptra_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,27 @@ int caliptra_mailbox_execute(uint32_t cmd, const struct caliptra_buffer *mbox_tx
// For full command details, please refer to the Caliptra Runtime Readme file at runtime\README.md

// Upload Caliptra Firmware
// Requires entire FW as fw_buffer
// For loading chunks of data at a time, use start/send/end functions below
int caliptra_upload_fw(const struct caliptra_buffer *fw_buffer, bool async);

// If the SoC cannot buffer the entire FW, the following 3 functions can be used to write chunks at a time
// Upload Caliptra Firmware Start Request
// Begin a FW_LOAD command to caliptra. Total FW size is needed at the start per mailbox protocol
int caliptra_upload_fw_start_req(uint32_t fw_size_in_bytes);

// Upload Caliptra Firmware Send Data
// Load a chunk of the FW data to Caliptra
// Intended to be called multiple times
// MUST follow caliptra_upload_fw_start_req and precede caliptra_upload_fw_end_request
// Size MUST be dword aligned for any chunks except the final chunk
int caliptra_upload_fw_send_data(const struct caliptra_buffer *fw_buffer);

// Upload Caliptra Firmware End Request
// End the FW_LOAD request after sending all the FW data
// Waits for Caliptra completion and response if async is false
int caliptra_upload_fw_end_req(bool async);

// Get IDEV cert
int caliptra_get_idev_cert(struct caliptra_get_idev_cert_req *req, struct caliptra_get_idev_cert_resp *resp, bool async);

Expand Down Expand Up @@ -176,12 +195,12 @@ int caliptra_capabilities(struct caliptra_capabilities_resp *resp, bool async);
// Query if IDevID CSR is ready.
bool caliptra_is_idevid_csr_ready();

int caliptra_retrieve_idevid_csr(struct caliptra_buffer* caliptra_idevid_csr);
int caliptra_retrieve_idevid_csr(struct caliptra_buffer* caliptra_idevid_csr);

void caliptra_req_idev_csr_start();

// Clear IDEV CSR request.
void caliptra_req_idev_csr_complete();
// Clear IDEV CSR request.
void caliptra_req_idev_csr_complete();

#ifdef __cplusplus
}
Expand Down
13 changes: 12 additions & 1 deletion libcaliptra/inc/caliptra_enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
*/
enum libcaliptra_error {
NO_ERROR = 0,
// General
// General API
INVALID_PARAMS = 0x100,
API_INTERNAL_ERROR = 0x101,
REG_ACCESS_ERROR = 0x102,
PAUSER_LOCKED = 0x103,
FW_LOAD_NOT_IN_PROGRESS = 0x104,
// Fuse
NOT_READY_FOR_FUSES = 0x200,
STILL_READY_FOR_FUSES = 0x201,
Expand All @@ -34,6 +35,16 @@ enum libcaliptra_error {
IDEV_CSR_NOT_READY = 0x400,
};

/**
* fw_load_piecewise_state
*
* Tracks state for piecewise FW loading to enforce correct flow
*/
enum fw_load_piecewise_state {
FW_LOAD_PIECEWISE_IDLE = 0,
FW_LOAD_PIECEWISE_IN_PROGRESS = 1,
};

/**
* device_lifecycle
*
Expand Down
Loading

0 comments on commit 8d6f8d7

Please sign in to comment.