Repository: chipsalliance/caliptra-sw
Pull request #496 (2023-07-17 17:54:28)

Libcaliptra
Starting over for a new PR due to changes.

Derived from the api example in hw-model/c-binding/examples/api, this is the initial skeleton of a more generic client API for Caliptra, intended to abstract away the details of the implementation. Client applications will include caliptra_api.h and implementations will provide definitions to the functions declared in caliptra_if.h, check the README.md for more information.

Included in this PR are:

* The API
* A test that demonstrates a minimum interface.
* A test that demonstrates integration into a larger implementation, in this case the hardware model.


Patch:
diff --git a/hw-model/c-binding/examples/Makefile b/hw-model/c-binding/examples/Makefile
index 24d0b01d..a4a1928d 100644
--- a/hw-model/c-binding/examples/Makefile
+++ b/hw-model/c-binding/examples/Makefile
@@ -34,7 +34,7 @@ $(OUT)/caliptra_model.h:
 
 $(OUT)/%.o: $(SOURCE)
 	$(MKDIR)
-	$(CC) ${CFLAGS} -c $< -o $@
+	$(CC) ${CFLAGS} -g -c $< -o $@
 
 $(TARGET): $(OUT)/caliptra_model.h $(OBJS)
 	$(CC) -o $(TARGET) $(OBJS) $(CFLAGS) -Wl,-L$(OUT)/debug -lcaliptra_hw_model_c_binding -lpthread -lstdc++ -ldl -lm
diff --git a/libcaliptra/.gitignore b/libcaliptra/.gitignore
new file mode 100644
index 00000000..417d1e2e
--- /dev/null
+++ b/libcaliptra/.gitignore
@@ -0,0 +1,5 @@
+inc/caliptra_model.h
+src/caliptra_api.o
+libcaliptra/examples/generic/main.o
+libcaliptra/examples/hwmodel/hwmodel
+libcaliptra/examples/hwmodel/interface.o
diff --git a/libcaliptra/Makefile b/libcaliptra/Makefile
new file mode 100644
index 00000000..8b5b5bdc
--- /dev/null
+++ b/libcaliptra/Makefile
@@ -0,0 +1,27 @@
+Q=@
+
+ifneq ($(MAKECMDGOALS),clean)
+ifndef RTL_SOC_IFC_INCLUDE_PATH
+$(error RTL_SOC_IFC_INCLUDE_PATH must be defined and point to a location where caliptra_top_reg.h can be found)
+endif
+endif
+
+LIBCALIPTRA = libcaliptra.a
+
+SOURCE += src/caliptra_api.c
+OBJS := $(patsubst %.c,%.o, $(filter %.c,$(SOURCE)))
+
+INCLUDES  = -I$(RTL_SOC_IFC_INCLUDE_PATH)
+INCLUDES += -Iinc
+
+$(LIBCALIPTRA): $(OBJS)
+	@echo [AR] $@
+	$(Q)ar -cq $@ $(OBJS)
+
+%.o: %.c
+	@echo [CC] $< \-\> $@
+	$(Q)$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -g -c $< -o $@
+
+clean:
+	@echo [CLEAN] $(OBJS) $(LIBCALIPTRA)
+	$(Q)rm -f $(OBJS) $(LIBCALIPTRA)
diff --git a/libcaliptra/README.md b/libcaliptra/README.md
new file mode 100644
index 00000000..b1a66ac4
--- /dev/null
+++ b/libcaliptra/README.md
@@ -0,0 +1,41 @@
+# libcaliptra
+
+## Purpose
+
+libcaliptra is an abstraction layer between SoC applications and the Caliptra implementation in hardware.
+
+## Structure
+
+libcaliptra exists in two parts, the API and the Interface.
+
+### API
+
+Specified in caliptra_api.h and defined in caliptra_api.c
+
+Provides abstract APIs and functionality to SoC applications, independent of hardware details.
+
+### IF
+
+Specified in caliptra_if.h and used by caliptra_api.c
+
+The caliptra implementation must supply the definitions for the functions named in caliptra_if.h
+
+## Build
+
+To compile the API, the following must be provided:
+
+* Standard C headers
+* Access to the caliptra_top_reg.h header
+
+Run `make RTL_SOC_IFC_INCLUDE_PATH=<path>` to generate libcaliptra.a
+
+## Link
+
+To link the API, the following must be provided:
+
+* A main application utilizing these functions
+* An interface implementation
+
+## Implementation and consumer examples
+
+See examples/README.md for details on specific examples.
diff --git a/libcaliptra/examples/README.md b/libcaliptra/examples/README.md
new file mode 100644
index 00000000..1c889be0
--- /dev/null
+++ b/libcaliptra/examples/README.md
@@ -0,0 +1,23 @@
+# Caliptra C API Examples
+
+In this directory you will find a basic example on how to interact with the
+Caliptra C API and adapt it to your target platform.
+
+## Generic
+
+`generic/`
+
+The generic example contains the main() function, basic Caliptra startup, and firmware interaction.
+
+> NOTE: The current test executes a command that is ignored by ROM and not yet implemented by firmware.
+
+## hwmodel
+
+`hwmodel/`
+
+This is an implementation of the Caliptra C API Interface functions that target the hardware model. It abstracts out model specific details including:
+* ROM and Firmware image file opening
+** The paths are set at compile time, see the Makefile for details
+* Model-specific behavior (loading of ROM)
+* Model object management
+
diff --git a/libcaliptra/examples/generic/main.c b/libcaliptra/examples/generic/main.c
new file mode 100644
index 00000000..844db4aa
--- /dev/null
+++ b/libcaliptra/examples/generic/main.c
@@ -0,0 +1,63 @@
+// Licensed under the Apache-2.0 license
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "caliptra_api.h"
+
+// Interface defined values
+extern struct caliptra_fuses  fuses;        // Device-specific location of Caliptra fuse data
+extern struct caliptra_buffer image_bundle; // Device-specific location of Caliptra firmware
+
+int main(int argc, char *argv[])
+{
+    int status;
+
+    fuses = (struct caliptra_fuses){0};
+
+    if ((status = caliptra_init_fuses(&fuses)) != 0)
+    {
+        printf("Failed to init fuses: %d\n", status);
+        return status;
+    }
+
+    // Initialize FSM GO
+    caliptra_bootfsm_go();
+    
+    // Wait until ready for FW
+    caliptra_ready_for_firmware();
+
+    // Load Image Bundle
+    // FW_PATH is defined on the compiler command line
+    caliptra_upload_fw(&image_bundle);
+
+    uint32_t FIPS_VERSION = 0x46505652;
+
+    int mb_result;
+    uint32_t fips_ver;
+    struct caliptra_buffer buf = {
+        .data = (uint8_t*)&fips_ver,
+        .len = sizeof(fips_ver),
+    };
+
+    // Run Until RT is ready to receive commands
+    while(1) {
+        caliptra_wait();
+        mb_result = caliptra_mailbox_execute(FIPS_VERSION, &buf, NULL);
+
+        if (mb_result != -EIO)
+        {
+            printf("Caliptra C API Integration Test Failed: %x\n", mb_result);
+            return -1;
+        }
+
+        break;
+    }
+    printf("Caliptra C API Integration Test Passed \n");
+    return 0;
+}
+
+
diff --git a/libcaliptra/examples/generic/main.mk b/libcaliptra/examples/generic/main.mk
new file mode 100644
index 00000000..6a775de8
--- /dev/null
+++ b/libcaliptra/examples/generic/main.mk
@@ -0,0 +1,31 @@
+Q=@
+
+SOURCE += ../generic/main.c ../../src/caliptra_api.c
+
+LIBCALIPTRA_ROOT = ../..
+LIBCALIPTRA_INC  = $(LIBCALIPTRA_ROOT)/inc
+
+OBJS := $(patsubst %.c,%.o, $(filter %.c,$(SOURCE)))
+
+# SOC REFERENCE
+RTL_SOC_IFC_INCLUDE_PATH = ../../../hw-latest/caliptra-rtl/src/soc_ifc/rtl
+
+# INCLUDES
+INCLUDES += -I$(RTL_SOC_IFC_INCLUDE_PATH) -I$(LIBCALIPTRA_INC)
+
+.PHONY = run clean
+
+$(TARGET): $(OBJS) $(DEPS)
+	@echo [LINK] $(TARGET)
+	$(Q)$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)
+
+$(CALIPTRA_API):
+	$(Q)make -C ../../
+
+%.o: %.c $(DEPS)
+	@echo [CC] $< \-\> $@
+	$(Q)$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -g -c $< -o $@
+
+clean:
+	@echo [CLEAN] $(OBJS) $(TARGET)
+	$(Q)rm -f $(OBJS) $(TARGET)
diff --git a/libcaliptra/examples/hwmodel/Makefile b/libcaliptra/examples/hwmodel/Makefile
new file mode 100644
index 00000000..e437d989
--- /dev/null
+++ b/libcaliptra/examples/hwmodel/Makefile
@@ -0,0 +1,68 @@
+TARGET = hwmodel
+
+.DEFAULT_GOAL = $(TARGET)
+
+LIBCALIPTRA_ROOT = ../../
+LIBCALIPTRA_INC  = 
+
+OUTPUT_DIR = ../../../target/debug
+
+# ROM AND FW DIR
+ROM_FW_DIR = $(OUTPUT_DIR)
+
+ROM_FILE = $(ROM_FW_DIR)/caliptra_rom.bin
+FW_FILE  = $(ROM_FW_DIR)/image_bundle.bin
+
+BUILDER_PATH = ../../../builder
+
+# ROM AND FW FILES
+#
+# These paths are encoded into the binary so the generic
+# main sources don't need a command line.
+DEFINES  = -DROM_PATH=\"$(ROM_FILE)\"
+DEFINES += -DFW_PATH=\"$(FW_FILE)\"
+
+# HW MODEL
+HWMODEL_DIR = $(OUTPUT_DIR)
+HWMODEL_HEADER_DIR = ../../../hw-model/c-binding/out
+HWMODEL_INCLUDE = -I$(HWMODEL_HEADER_DIR)
+HWMODEL_LIB = -Wl,-L$(HWMODEL_DIR) -lcaliptra_hw_model_c_binding
+HWMODEL_FLAGS = -lpthread -lstdc++ -ldl -lm
+HWMODEL_HEADER = $(HWMODEL_HEADER_DIR)/caliptra_model.h
+HWMODEL_BINDING_LIB_OBJ = $(HWMODEL_DIR)/libcaliptra_hw_model_c_binding.a
+
+# DEPENDENCIES
+DEPS += $(HWMODEL_BINDING_LIB_OBJ) $(HWMODEL_HEADER) $(ROM_FILE) $(FW_FILE)
+
+# INCLUDES
+INCLUDES += $(HWMODEL_INCLUDE)
+
+SOURCE += interface.c
+
+CFLAGS += $(HWMODEL_INCLUDE) $(HWMODEL_LIB) $(HWMODEL_FLAGS)
+
+$(ROM_FILE) $(FW_FILE):
+	@echo [IMAGE] caliptra_rom.bin image_bundle.bin
+	$(Q)make -C ../../../rom/dev
+	$(Q)cd ../../../runtime && ./build.sh
+	$(Q)cargo --config="$(EXTRA_CARGO_CONFIG)" run --manifest-path=$(BUILDER_PATH)/Cargo.toml --bin image -- --rom $(ROM_FW_DIR)/caliptra_rom.bin --fw $(ROM_FW_DIR)/image_bundle.bin
+
+$(HWMODEL_BINDING_LIB_OBJ):
+	@echo "[CARGO] c-binding"
+	$(Q)cd ../../../hw-model/c-binding
+	$(Q)cargo build
+
+EXTRA_CARGO_CONFIG = target.'cfg(all())'.rustflags = [\"-Dwarnings\"]
+
+$(TARGET): $(ROM_FILE) $(FW_FILE)
+
+$(HWMODEL_HEADER):
+	@echo "[CARGO] hw-model"
+	$(Q)cd ../../../hw-model
+	$(Q)cargo --config="$(EXTRA_CARGO_CONFIG)" build
+
+run: $(TARGET)
+	@echo [RUN] $(TARGET)
+	$(Q)./$(TARGET)
+
+include ../generic/main.mk
diff --git a/libcaliptra/examples/hwmodel/README.md b/libcaliptra/examples/hwmodel/README.md
new file mode 100644
index 00000000..41442a5e
--- /dev/null
+++ b/libcaliptra/examples/hwmodel/README.md
@@ -0,0 +1,11 @@
+# hwmodel
+
+This example defines the Caliptra interface functions, allowing the generic application to communicate with the hardware model without having to directly manage model-specific details.
+
+# Prerequisites
+
+The c-binding, rom, and firmware must all be built.
+
+# Build
+
+Running "make" will compile the Caliptra C API, the interface, and link the application against the C binding.
diff --git a/libcaliptra/examples/hwmodel/interface.c b/libcaliptra/examples/hwmodel/interface.c
new file mode 100644
index 00000000..edc83896
--- /dev/null
+++ b/libcaliptra/examples/hwmodel/interface.c
@@ -0,0 +1,125 @@
+//Licensed under the Apache-2.0 license
+
+#define HWMODEL 1
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "caliptra_model.h"
+#include "caliptra_api.h"
+
+#define CALIPTRA_STATUS_OK 0
+
+// Implementation specifics
+
+struct caliptra_model_init_params init_params;
+struct caliptra_fuses fuses = {0};
+struct caliptra_buffer image_bundle;
+
+static bool caliptra_model_init_complete = false;
+
+static struct caliptra_buffer read_file_or_exit(const char* path)
+{
+    // Open File in Read Only Mode
+    FILE *fp = fopen(path, "r");
+    if (!fp) {
+        printf("Cannot find file %s \n", path);
+        exit(-ENOENT);
+    }
+
+    struct caliptra_buffer buffer = {0};
+
+    // Get File Size
+    fseek(fp, 0L, SEEK_END);
+    buffer.len = ftell(fp);
+    fseek(fp, 0L, SEEK_SET);
+
+    // Allocate Buffer Memory
+    buffer.data = malloc(buffer.len);
+    if (!buffer.data) {
+        printf("Cannot allocate memory for buffer->data \n");
+        exit(-ENOMEM);
+    }
+
+    // Read Data in Buffer
+    fread((char *)buffer.data, buffer.len, 1, fp);
+
+    return buffer;
+}
+
+struct caliptra_model* hwmod_get_or_init(void)
+{
+    const char *rom_path = ROM_PATH;
+    const char *fw_path = FW_PATH;
+    static struct caliptra_model *model = NULL;
+
+    if (model == NULL)
+    {
+        // Initialize Params
+        // HW model only
+        // ROM_PATH is defined on the compiler command line
+        struct caliptra_model_init_params init_params = {
+          .rom = read_file_or_exit(rom_path),
+          .dccm = {.data = NULL, .len = 0},
+          .iccm = {.data = NULL, .len = 0},
+        };
+
+        image_bundle = (struct caliptra_buffer)read_file_or_exit(fw_path);
+
+        int status = caliptra_model_init_default(init_params, &model);
+    }
+
+    return model;
+}
+
+// Memory
+
+/**
+ * caliptra_write_u32
+ *
+ * Writes a uint32_t value to the specified address.
+ *
+ * @param[in] address Memory address to write
+ * @param[in] data Data to write at address
+ *
+ * @return 0 if successful, other if error (TBD)
+ */
+int caliptra_write_u32(uint32_t address, uint32_t data)
+{
+    struct caliptra_model *m = hwmod_get_or_init();
+
+    int result = caliptra_model_apb_write_u32(m, address, (int)data);
+
+    caliptra_model_step(m);
+
+    return result; 
+}
+
+/**
+ * caliptra_read_u32
+ *
+ * Reads a uint32_t value from the specified address.
+ *
+ * @param[in] address Memory address to read
+ * @param[in] data Pointer to a uint32_t to store the data
+ *
+ * @return 0 if successful, other if error (TBD)
+ */
+int caliptra_read_u32(uint32_t address, uint32_t *data)
+{
+    return caliptra_model_apb_read_u32(hwmod_get_or_init(), address, (int*)data);
+}
+
+/**
+ * caliptra_wait
+ *
+ * Pend the current operation.
+ */
+void caliptra_wait(void)
+{
+    caliptra_model_step(hwmod_get_or_init());
+}
diff --git a/libcaliptra/inc/caliptra_api.h b/libcaliptra/inc/caliptra_api.h
new file mode 100644
index 00000000..d64a3467
--- /dev/null
+++ b/libcaliptra/inc/caliptra_api.h
@@ -0,0 +1,69 @@
+// Licensed under the Apache-2.0 license
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "caliptra_if.h"
+
+/**
+ * caliptra_buffer
+ *
+ * Transfer buffer for Caliptra mailbox commands
+ */
+#if !defined(HWMODEL)
+typedef struct caliptra_buffer {
+  const uint8_t *data; //< Pointer to a buffer with data to send/space to receive
+  uintptr_t len;       //< Size of the buffer
+} caliptra_buffer;
+#endif
+
+/**
+ * DeviceLifecycle
+ *
+ * Device life cycle states
+ */
+enum DeviceLifecycle {
+    Unprovisioned = 0,
+    Manufacturing = 1,
+    Reserved2 = 2,
+    Production = 3,
+};
+
+/**
+ * caliptra_fuses
+ *
+ * Fuse data to be written to Caliptra registers
+ */
+struct caliptra_fuses {
+    uint32_t uds_seed[12];
+    uint32_t field_entropy[8];
+    uint32_t key_manifest_pk_hash[12];
+    uint32_t key_manifest_pk_hash_mask : 4;
+    uint32_t rsvd : 28;
+    uint32_t owner_pk_hash[12];
+    uint32_t fmc_key_manifest_svn;
+    uint32_t runtime_svn[4];
+    bool anti_rollback_disable;
+    uint32_t idevid_cert_attr[24];
+    uint32_t idevid_manuf_hsm_id[4];
+    enum DeviceLifecycle life_cycle;
+};
+
+// Query if ROM is ready for fuses
+bool caliptra_ready_for_fuses(void);
+
+// Initialize Caliptra fuses prior to boot
+int caliptra_init_fuses(struct caliptra_fuses *fuses);
+
+// Write into Caliptra BootFSM Go Register
+int caliptra_bootfsm_go();
+
+// Query if ROM is ready for firmware
+bool caliptra_ready_for_firmware(void);
+
+// Upload Caliptra Firmware
+int caliptra_upload_fw(struct caliptra_buffer *fw_buffer);
+
+// Execute Mailbox Command
+int caliptra_mailbox_execute(uint32_t cmd, struct caliptra_buffer *mbox_tx_buffer, struct caliptra_buffer *mbox_rx_buffer);
diff --git a/libcaliptra/inc/caliptra_if.h b/libcaliptra/inc/caliptra_if.h
new file mode 100644
index 00000000..e32e1c4b
--- /dev/null
+++ b/libcaliptra/inc/caliptra_if.h
@@ -0,0 +1,40 @@
+//Licensed under the Apache-2.0 license
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define CALIPTRA_STATUS_OK 0
+
+// Memory
+
+/**
+ * caliptra_write_u32
+ *
+ * Writes a uint32_t value to the specified address.
+ *
+ * @param[in] address Memory address to write
+ * @param[in] data   Data to write at address
+ *
+ * @return 0 if successful, other if error (TBD)
+ */
+int caliptra_write_u32(uint32_t address, uint32_t data);
+
+/**
+ * caliptra_read_u32
+ *
+ * Reads a uint32_t value from the specified address.
+ *
+ * @param[in] address Memory address to read
+ * @param[in] data   Pointer to a uint32_t to store the data
+ *
+ * @return 0 if successful, other if error (TBD)
+ */
+int caliptra_read_u32(uint32_t address, uint32_t *data);
+
+/**
+ * caliptra_wait
+ *
+ * Pend the current operation.
+ */
+void caliptra_wait(void);
diff --git a/libcaliptra/src/caliptra_api.c b/libcaliptra/src/caliptra_api.c
new file mode 100644
index 00000000..3ca015cd
--- /dev/null
+++ b/libcaliptra/src/caliptra_api.c
@@ -0,0 +1,280 @@
+// Licensed under the Apache-2.0 license
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <caliptra_top_reg.h>
+#include "caliptra_if.h"
+#include "caliptra_api.h"
+#include "caliptra_fuses.h"
+#include "caliptra_mbox.h"
+
+#define CALIPTRA_STATUS_NOT_READY 0
+
+static inline uint32_t caliptra_read_status(void)
+{
+    uint32_t status;
+
+    caliptra_read_u32(CALIPTRA_TOP_REG_GENERIC_AND_FUSE_REG_CPTRA_FLOW_STATUS, &status);
+   
+    return status;
+}
+
+/**
+ * caliptra_ready_for_fuses
+ *
+ * Reports if the Caliptra hardware is ready for fuse data
+ *
+ * @return bool True if ready, false otherwise
+ */
+bool caliptra_ready_for_fuses(void)
+{
+    uint32_t status;
+
+    status = caliptra_read_status();
+
+    if ((status & CALIPTRA_TOP_REG_GENERIC_AND_FUSE_REG_CPTRA_FLOW_STATUS)
+                == GENERIC_AND_FUSE_REG_CPTRA_FLOW_STATUS_READY_FOR_FUSES_MASK)
+    {
+        return true;
+    }
+
+    return false;
+ }
+
+/**
+ * caliptra_init_fuses
+ *
+ * Initialize fuses based on contents of "fuses" argument
+ *
+ * @param[in] fuses Valid caliptra_fuses structure
+ *
+ * @return int 0 if successful, -EINVAL if fuses is null, -EPERM if caliptra is not ready for fuses, -EIO if still ready after fuses are written
+ */
+int caliptra_init_fuses(struct caliptra_fuses *fuses)
+{
+    // Parameter check
+    if (!fuses) {
+        return -EINVAL;
+    }
+
+    // Check whether caliptra is ready for fuses
+    // 
+    // This check is disabled until the below ticket is resolved.
+    // https://github.com/chipsalliance/caliptra-sw/issues/508
+    //
+    //if (!caliptra_ready_for_fuses())
+    //    return -EPERM;
+
+    // Write Fuses
+    caliptra_fuse_array_write(GENERIC_AND_FUSE_REG_FUSE_UDS_SEED_0, fuses->uds_seed, sizeof(fuses->uds_seed));
+    caliptra_fuse_array_write(GENERIC_AND_FUSE_REG_FUSE_FIELD_ENTROPY_0, fuses->field_entropy, sizeof(fuses->field_entropy));
+    caliptra_fuse_array_write(GENERIC_AND_FUSE_REG_FUSE_KEY_MANIFEST_PK_HASH_0, fuses->key_manifest_pk_hash, sizeof(fuses->key_manifest_pk_hash));
+    caliptra_fuse_write(GENERIC_AND_FUSE_REG_FUSE_KEY_MANIFEST_PK_HASH_MASK, fuses->key_manifest_pk_hash_mask);
+    caliptra_fuse_array_write(GENERIC_AND_FUSE_REG_FUSE_OWNER_PK_HASH_0, fuses->owner_pk_hash, sizeof(fuses->owner_pk_hash));
+    caliptra_fuse_write(GENERIC_AND_FUSE_REG_FUSE_FMC_KEY_MANIFEST_SVN, fuses->fmc_key_manifest_svn);
+    caliptra_fuse_array_write(GENERIC_AND_FUSE_REG_FUSE_FMC_KEY_MANIFEST_SVN, fuses->runtime_svn, sizeof(fuses->runtime_svn)); // https://github.com/chipsalliance/caliptra-sw/issues/529 
+    caliptra_fuse_write(GENERIC_AND_FUSE_REG_FUSE_ANTI_ROLLBACK_DISABLE, (uint32_t)fuses->anti_rollback_disable);
+    caliptra_fuse_array_write(GENERIC_AND_FUSE_REG_FUSE_IDEVID_CERT_ATTR_0, fuses->idevid_cert_attr, sizeof(fuses->idevid_cert_attr));
+    caliptra_fuse_array_write(GENERIC_AND_FUSE_REG_FUSE_IDEVID_MANUF_HSM_ID_0, fuses->idevid_manuf_hsm_id, sizeof(fuses->idevid_manuf_hsm_id));
+    caliptra_fuse_write(GENERIC_AND_FUSE_REG_FUSE_LIFE_CYCLE, (uint32_t)fuses->life_cycle);
+
+    // Write to Caliptra Fuse Done
+    caliptra_write_u32(CALIPTRA_TOP_REG_GENERIC_AND_FUSE_REG_CPTRA_FUSE_WR_DONE, 1);
+
+    // No longer ready for fuses
+    if (caliptra_ready_for_fuses())
+        return -EIO;
+
+    return 0;
+}
+
+/**
+ * caliptra_bootfsm_go
+ *
+ * Initiate caliptra hw startup
+ *
+ * @return 0 if successful
+ */
+int caliptra_bootfsm_go()
+{
+    // Write BOOTFSM_GO Register
+    caliptra_write_u32(CALIPTRA_TOP_REG_GENERIC_AND_FUSE_REG_CPTRA_BOOTFSM_GO, 1);
+
+    //TODO: Check registers/provide async completion mechanism
+
+    return 0;
+}
+
+/**
+ * caliptra_mailbox_write_fifo
+ *
+ * Transfer contents of buffer into the mailbox FIFO
+ *
+ * @param[in] buffer Pointer to a valid caliptra_buffer struct
+ *
+ * @return int -EINVAL if the buffer is too large.
+ */
+static int caliptra_mailbox_write_fifo(struct caliptra_buffer *buffer)
+{
+    // Check against max size
+    const uint32_t MBOX_SIZE = (128u * 1024u);
+
+    if (buffer->len > MBOX_SIZE) {
+        return -EINVAL;
+    }
+
+    // Write DLEN
+    caliptra_mbox_write_dlen(buffer->len);
+
+    uint32_t remaining_len = buffer->len;
+    uint32_t *data_dw = (uint32_t *)buffer->data;
+
+    // Copy DWord multiples
+    while (remaining_len > sizeof(uint32_t)) {
+        caliptra_mbox_write(MBOX_CSR_MBOX_DATAIN, *data_dw++);
+        remaining_len -= sizeof(uint32_t);
+    }
+
+    // if un-aligned dword remainder...
+    if (remaining_len) {
+        uint32_t data = 0;
+        memcpy(&data, data_dw, remaining_len);
+        caliptra_mbox_write(MBOX_CSR_MBOX_DATAIN, data);
+    }
+
+    return 0;
+}
+
+/**
+ * caliptra_mailbox_read_buffer
+ *
+ * Read a mailbxo FIFO into a buffer
+ *
+ * @param[in] buffer A pointer to a valid caliptra_buffer struct
+ *
+ * @return int 0 if successful, -EINVAL if the buffer is too small or the buffer pointer is invalid.
+ */
+static int caliptra_mailbox_read_buffer(struct caliptra_buffer *buffer)
+{
+    uint32_t remaining_len = caliptra_mbox_read_dlen();
+
+    // Check that the buffer is not null
+    if (buffer == NULL)
+        return -EINVAL;
+
+    // Check we have enough room in the buffer
+    if (buffer->len < remaining_len || !buffer->data)
+       return -EINVAL;
+
+    uint32_t *data_dw = (uint32_t *)buffer->data;
+
+    // Copy DWord multiples
+    while (remaining_len > sizeof(uint32_t)) {
+        *data_dw++ = caliptra_mbox_read(MBOX_CSR_MBOX_DATAOUT);
+        remaining_len -= sizeof(uint32_t);
+    }
+
+    // if un-aligned dword reminder...
+    if (remaining_len) {
+        uint32_t data = caliptra_mbox_read(MBOX_CSR_MBOX_DATAOUT);
+        memcpy(data_dw, &data, remaining_len);
+    }
+
+    return 0;
+}
+
+/**
+ * caliptra_mailbox_execute
+ *
+ * Execute a mailbox command and send/retrieve a buffer
+ *
+ * @param[in] cmd Caliptra command opcode
+ * @param[in] mbox_tx_buffer Transmit buffer
+ * @param[in] mbox_rx_buffer Receive buffer
+ *
+ * @return 0 if successful, -EBUSY if the mailbox is locked, -EIO if the command has failed or data is not available or the FSM is not include
+ */
+int caliptra_mailbox_execute(uint32_t cmd, struct caliptra_buffer *mbox_tx_buffer, struct caliptra_buffer *mbox_rx_buffer)
+{
+    // If mbox already locked return
+    if (caliptra_mbox_is_lock()) {
+        return -EBUSY;
+    }
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
+    // Write Cmd and Tx Buffer
+    caliptra_mbox_write_cmd(cmd);
+    caliptra_mailbox_write_fifo(mbox_tx_buffer);
+
+    // Set Execute bit and wait
+    caliptra_mbox_write_execute_wait(true);
+
+    // Check the Mailbox Status
+    uint32_t status = caliptra_mbox_read_status();
+    if (status == CALIPTRA_MBOX_STATUS_CMD_FAILURE) {
+        caliptra_mbox_write_execute(false);
+        return -EIO;
+    } else if(status == CALIPTRA_MBOX_STATUS_CMD_COMPLETE) {
+        caliptra_mbox_write_execute(false);
+        return 0;
+    } else if (status != CALIPTRA_MBOX_STATUS_DATA_READY) {
+        return -EIO;
+    }
+
+    // Read Buffer
+    caliptra_mailbox_read_buffer(mbox_rx_buffer);
+
+    // Execute False and wait
+    caliptra_mbox_write_execute_wait(false);
+
+    if (caliptra_mbox_read_status_fsm() != CALIPTRA_MBOX_STATUS_FSM_IDLE)
+        return -EIO;
+
+    return 0;
+}
+
+/**
+ * caliptra_ready_for_firmware
+ *
+ * Reports if the Caliptra hardware is ready for firmware upload 
+ *
+ * @return bool True if ready, false otherwise
+ */
+bool caliptra_ready_for_firmware(void)
+{
+    uint32_t status;
+    bool     ready;
+
+    do
+    {
+        status = caliptra_read_status();
+
+        if ((status & GENERIC_AND_FUSE_REG_CPTRA_FLOW_STATUS_READY_FOR_FW_MASK) 
+                == GENERIC_AND_FUSE_REG_CPTRA_FLOW_STATUS_READY_FOR_FW_MASK)
+        {
+            ready = true;
+        }
+        else
+        {
+            caliptra_wait();
+        }
+    } while(ready == false);
+
+    return true;
+}
+
+/**
+ * caliptra_upload_fw
+ *
+ * Upload firmware to the Caliptra device
+ * 
+ * @param[in] fw_buffer Buffer containing Caliptra firmware
+ *
+ * @return See caliptra_mailbo, mb_resultx_execute for possible results.
+ */
+int caliptra_upload_fw(struct caliptra_buffer *fw_buffer)
+{
+    const uint32_t FW_LOAD_CMD_OPCODE = 0x46574C44u;
+    return caliptra_mailbox_execute(FW_LOAD_CMD_OPCODE, fw_buffer, NULL);
+}
diff --git a/libcaliptra/src/caliptra_fuses.h b/libcaliptra/src/caliptra_fuses.h
new file mode 100644
index 00000000..ee5ddea5
--- /dev/null
+++ b/libcaliptra/src/caliptra_fuses.h
@@ -0,0 +1,20 @@
+// Licensed under the Apache-2.0 license
+
+#pragma once
+
+#include "caliptra_api.h"
+
+// WARNING: THESE APIS ARE INTENDED FOR SIMULATION ONLY.
+//          SOC FW MUST HAVE NO ACCESS TO THOSE APIS.
+//          A HW STATE MACHINE SHOULD BE USED TO SEND FUSE VALUES TO CALIPTRA OVER APB BUS
+
+static inline void caliptra_fuse_write(uint32_t offset, uint32_t data)
+{
+    caliptra_write_u32((offset + CALIPTRA_TOP_REG_GENERIC_AND_FUSE_REG_BASE_ADDR), data);
+}
+
+static inline void caliptra_fuse_array_write(uint32_t offset, uint32_t *data, uint32_t size)
+{
+    for (uint32_t idx= 0; idx < size; idx +=sizeof(uint32_t))
+        caliptra_fuse_write((offset + idx ), data[idx]);
+}
diff --git a/libcaliptra/src/caliptra_mbox.h b/libcaliptra/src/caliptra_mbox.h
new file mode 100644
index 00000000..69f09ff8
--- /dev/null
+++ b/libcaliptra/src/caliptra_mbox.h
@@ -0,0 +1,82 @@
+// Licensed under the Apache-2.0 license
+#pragma once
+
+/**
+ * Mailbox helper functions
+ *
+ * All of the below functions map to register reads and writes.
+ *
+ * TODO: Investigate interrupts for notification on mailbox
+ *       command completion.
+ */
+
+#define CALIPTRA_MBOX_STATUS_BUSY               0
+#define CALIPTRA_MBOX_STATUS_DATA_READY         1
+#define CALIPTRA_MBOX_STATUS_CMD_COMPLETE       2
+#define CALIPTRA_MBOX_STATUS_CMD_FAILURE        3
+
+#define CALIPTRA_MBOX_STATUS_FSM_IDLE           0
+#define CALIPTRA_MBOX_STATUS_FSM_READY_FOR_CMD  1
+#define CALIPTRA_MBOX_STATUS_FSM_READY_FOR_DATA 2
+#define CALIPTRA_MBOX_STATUS_FSM_READY_FOR_DLEN 3
+#define CALIPTRA_MBOX_STATUS_FSM_EXECUTE_SOC    4
+#define CALIPTRA_MBOX_STATUS_FSM_EXECUTE_UC     6
+
+static inline void caliptra_mbox_write(uint32_t offset, uint32_t data)
+{
+    caliptra_write_u32((offset + CALIPTRA_TOP_REG_MBOX_CSR_BASE_ADDR), data);
+}
+
+static inline uint32_t caliptra_mbox_read(uint32_t offset)
+{
+    uint32_t data;
+    caliptra_read_u32((offset + CALIPTRA_TOP_REG_MBOX_CSR_BASE_ADDR), &data);
+    return data;
+}
+
+static inline bool caliptra_mbox_is_lock()
+{
+    return (caliptra_mbox_read(MBOX_CSR_MBOX_LOCK) & MBOX_CSR_MBOX_LOCK_LOCK_MASK);
+}
+
+static inline void caliptra_mbox_write_cmd(uint32_t cmd)
+{
+    caliptra_mbox_write(MBOX_CSR_MBOX_CMD, cmd);
+}
+
+static inline void caliptra_mbox_write_execute(bool ex)
+{
+    caliptra_mbox_write(MBOX_CSR_MBOX_EXECUTE, ex);
+}
+
+static inline uint8_t caliptra_mbox_write_execute_wait(bool ex)
+{
+    caliptra_mbox_write(MBOX_CSR_MBOX_EXECUTE, ex);
+    uint8_t status;
+    while((status = (uint8_t)(caliptra_mbox_read(MBOX_CSR_MBOX_STATUS) & MBOX_CSR_MBOX_STATUS_STATUS_MASK)) == CALIPTRA_MBOX_STATUS_BUSY)
+    {
+        caliptra_wait();
+    }
+
+    return status;
+}
+
+static inline uint8_t caliptra_mbox_read_status(void)
+{
+    return (uint8_t)(caliptra_mbox_read(MBOX_CSR_MBOX_STATUS) & MBOX_CSR_MBOX_STATUS_STATUS_MASK);
+}
+
+static inline uint8_t caliptra_mbox_read_status_fsm(void)
+{
+    return (uint8_t)(caliptra_mbox_read(MBOX_CSR_MBOX_STATUS) >> 16 & MBOX_CSR_MBOX_STATUS_STATUS_MASK);
+}
+
+static inline uint32_t caliptra_mbox_read_dlen(void)
+{
+    return caliptra_mbox_read(MBOX_CSR_MBOX_DLEN);
+}
+
+static inline void caliptra_mbox_write_dlen(uint32_t dlen)
+{
+    caliptra_mbox_write(MBOX_CSR_MBOX_DLEN, dlen);
+}


Test patch:
diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml
index 6e9303ee..be1fcf09 100644
--- a/.github/workflows/build-test.yml
+++ b/.github/workflows/build-test.yml
@@ -125,3 +125,6 @@ jobs:
           git submodule update --init
           (cd hw-model/c-binding/examples && make run)
 
+      - name: Caliptra C API Hwmodel Integration Test
+        run: |
+          (cd libcaliptra/examples/hwmodel && make && ./hwmodel)