Hello,
I am currently developing TF-M on the RDV3R1 S/W platform, and I would like to report a potential issue observed during runtime with the integrity_checker_compute_value() function in BL2.
Problem Description:
Inside the integrity_checker_compute_value() function, the iccva register is set to the address of either the value or temp_val variable, as shown in the example below.
enum integrity_checker_error_t integrity_checker_compute_value(struct integrity_checker_dev_t *dev,
                                                               enum integrity_checker_mode_t mode,
                                                               const uint32_t *data, size_t size,
                                                               uint32_t *value, size_t value_size,
                                                               size_t *value_len)
{
    volatile uint32_t __ALIGNED(INTEGRITY_CHECKER_REQUIRED_ALIGNMENT)
        temp_val[INTEGRITY_CHECKER_OUTPUT_SIZE_SHA256 / sizeof(uint32_t)] = {0};
    volatile uint32_t *value_ptr = value;
    struct _integrity_checker_reg_map_t* p_integrity_checker =
        (struct _integrity_checker_reg_map_t*)dev->cfg->base;
    enum integrity_checker_error_t err;
    uint32_t iccval = 0;
    err = check_mode_is_supported(dev, mode, true);
    if (err != INTEGRITY_CHECKER_ERROR_NONE) {
        return err;
    }
    if (value_size < mode_sizes[mode]) {
        FATAL_ERR(INTEGRITY_CHECKER_ERROR_COMPUTE_VALUE_BUFFER_TOO_SMALL);
        return INTEGRITY_CHECKER_ERROR_COMPUTE_VALUE_BUFFER_TOO_SMALL;
    }
    if (((uintptr_t)data % INTEGRITY_CHECKER_REQUIRED_ALIGNMENT) != 0) {
        FATAL_ERR(INTEGRITY_CHECKER_ERROR_COMPUTE_VALUE_INVALID_ALIGNMENT);
        return INTEGRITY_CHECKER_ERROR_COMPUTE_VALUE_INVALID_ALIGNMENT;
    }
    if ((size % INTEGRITY_CHECKER_REQUIRED_ALIGNMENT) != 0) {
        FATAL_ERR(INTEGRITY_CHECKER_ERROR_COMPUTE_VALUE_INVALID_LENGTH);
        return INTEGRITY_CHECKER_ERROR_COMPUTE_VALUE_INVALID_LENGTH;
    }
    if (((uintptr_t)value % INTEGRITY_CHECKER_REQUIRED_ALIGNMENT) != 0) {
        value_ptr = temp_val;
    }
    init_integrity_checker(dev, &iccval);
    /* Set algorithm */
    iccval |= (mode & 0b111) << 1;
    /* Set to compute mode */
    iccval |= 1 << 4;
    /* Configure input data. Size is in words */
    p_integrity_checker->icda = remap_addr(dev, (uintptr_t)data);
    p_integrity_checker->icdl = size / INTEGRITY_CHECKER_REQUIRED_ALIGNMENT;
    /* Set output address */
    p_integrity_checker->iccva = remap_addr(dev, (uintptr_t)value_ptr);
    /* Start integrity checker */
    iccval |= 1;
    p_integrity_checker->icc = iccval;
    /* Poll for any interrupts */
    while(!p_integrity_checker->icis) {}
    /* Check for any unusual error interrupts */
    if (p_integrity_checker->icis & (~0b11)) {
        FATAL_ERR(INTEGRITY_CHECKER_ERROR_COMPUTE_VALUE_OPERATION_FAILED);
        return INTEGRITY_CHECKER_ERROR_COMPUTE_VALUE_OPERATION_FAILED;
    }
    if (value_ptr != value) {
        for (int idx = 0; idx < mode_sizes[mode] / sizeof(uint32_t); idx++) {
            value[idx] = value_ptr[idx];
        }
    }
    if (value_len != NULL) {
        *value_len = mode_sizes[mode];
    }
    return INTEGRITY_CHECKER_ERROR_NONE;
}
static void init_integrity_checker(struct integrity_checker_dev_t *dev,
                                   uint32_t *iccval)
{
    struct _integrity_checker_reg_map_t* p_integrity_checker =
        (struct _integrity_checker_reg_map_t*)dev->cfg->base;
    /* Set MatchTriggerDisable, as it is mandatory. */
    *iccval |= 1 << 5;
    /* Set EncompvalOut so the integrity checker writes the value pointer in
     * compute mode.
     */
    *iccval |= 1 << 6;
    *iccval |= (IC_APROT_SECURE_PRIVILEGED & 0b11) << 7;
    *iccval |= (IC_APROT_SECURE_PRIVILEGED & 0b11) << 9;
    /* Disable all alarms */
    p_integrity_checker->icae = 0;
    /* Enable and clear all interrupts */
    p_integrity_checker->icie = 0xFF;
    p_integrity_checker->icic = 0xFF;
}
The issue arises because the memory areas pointed to by value and temp_val are cacheable (e.g., located in the vm0 memory region, which is configured as cacheable).
As a result, even though the integrity checker writes the output data to the physical address of value or temp_val, the CPU cache is not updated, and this leads to stale data being read later in software, resulting in runtime errors.
Expected Behavior:
Ideally, the memory region used for integrity checker output should either be:
Non-cacheable, or
Explicitly synchronized (e.g., cache invalidated or cleaned) after the integrity checker operation.
Could you please confirm whether this is a known issue, and advise on the recommended way to handle integrity checker outputs with respect to cache settings?
Thank you.
JK Park