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