mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-24 05:54:08 +00:00

This ensures that probe_data starts with a reasonable default, as opposed to whatever was left on the stack. Change-Id: I5550efea5e2bec7717f9fa063cb11e6a7005cce5 Signed-off-by: Justin Chadwell <justin.chadwell@arm.com>
142 lines
3.3 KiB
C
142 lines
3.3 KiB
C
/*
|
|
* Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <arch_helpers.h>
|
|
#include <bl31/ea_handle.h>
|
|
#include <bl31/ehf.h>
|
|
#include <common/debug.h>
|
|
#include <lib/extensions/ras.h>
|
|
#include <lib/extensions/ras_arch.h>
|
|
#include <plat/common/platform.h>
|
|
|
|
#ifndef PLAT_RAS_PRI
|
|
# error Platform must define RAS priority value
|
|
#endif
|
|
|
|
/* Handler that receives External Aborts on RAS-capable systems */
|
|
int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
|
|
void *handle, uint64_t flags)
|
|
{
|
|
unsigned int i, n_handled = 0;
|
|
int probe_data, ret;
|
|
struct err_record_info *info;
|
|
|
|
const struct err_handler_data err_data = {
|
|
.version = ERR_HANDLER_VERSION,
|
|
.ea_reason = ea_reason,
|
|
.interrupt = 0,
|
|
.syndrome = (uint32_t) syndrome,
|
|
.flags = flags,
|
|
.cookie = cookie,
|
|
.handle = handle
|
|
};
|
|
|
|
for_each_err_record_info(i, info) {
|
|
assert(info->probe != NULL);
|
|
assert(info->handler != NULL);
|
|
|
|
/* Continue probing until the record group signals no error */
|
|
while (true) {
|
|
if (info->probe(info, &probe_data) == 0)
|
|
break;
|
|
|
|
/* Handle error */
|
|
ret = info->handler(info, probe_data, &err_data);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
n_handled++;
|
|
}
|
|
}
|
|
|
|
return (n_handled != 0U) ? 1 : 0;
|
|
}
|
|
|
|
#if ENABLE_ASSERTIONS
|
|
static void assert_interrupts_sorted(void)
|
|
{
|
|
unsigned int i, last;
|
|
struct ras_interrupt *start = ras_interrupt_mappings.intrs;
|
|
|
|
if (ras_interrupt_mappings.num_intrs == 0UL)
|
|
return;
|
|
|
|
last = start[0].intr_number;
|
|
for (i = 1; i < ras_interrupt_mappings.num_intrs; i++) {
|
|
assert(start[i].intr_number > last);
|
|
last = start[i].intr_number;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Given an RAS interrupt number, locate the registered handler and call it. If
|
|
* no handler was found for the interrupt number, this function panics.
|
|
*/
|
|
static int ras_interrupt_handler(uint32_t intr_raw, uint32_t flags,
|
|
void *handle, void *cookie)
|
|
{
|
|
struct ras_interrupt *ras_inrs = ras_interrupt_mappings.intrs;
|
|
struct ras_interrupt *selected = NULL;
|
|
int probe_data = 0;
|
|
int start, end, mid, ret __unused;
|
|
|
|
const struct err_handler_data err_data = {
|
|
.version = ERR_HANDLER_VERSION,
|
|
.interrupt = intr_raw,
|
|
.flags = flags,
|
|
.cookie = cookie,
|
|
.handle = handle
|
|
};
|
|
|
|
assert(ras_interrupt_mappings.num_intrs > 0UL);
|
|
|
|
start = 0;
|
|
end = (int) ras_interrupt_mappings.num_intrs;
|
|
while (start <= end) {
|
|
mid = ((end + start) / 2);
|
|
if (intr_raw == ras_inrs[mid].intr_number) {
|
|
selected = &ras_inrs[mid];
|
|
break;
|
|
} else if (intr_raw < ras_inrs[mid].intr_number) {
|
|
/* Move left */
|
|
end = mid - 1;
|
|
} else {
|
|
/* Move right */
|
|
start = mid + 1;
|
|
}
|
|
}
|
|
|
|
if (selected == NULL) {
|
|
ERROR("RAS interrupt %u has no handler!\n", intr_raw);
|
|
panic();
|
|
}
|
|
|
|
if (selected->err_record->probe != NULL) {
|
|
ret = selected->err_record->probe(selected->err_record, &probe_data);
|
|
assert(ret != 0);
|
|
}
|
|
|
|
/* Call error handler for the record group */
|
|
assert(selected->err_record->handler != NULL);
|
|
(void) selected->err_record->handler(selected->err_record, probe_data,
|
|
&err_data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __init ras_init(void)
|
|
{
|
|
#if ENABLE_ASSERTIONS
|
|
/* Check RAS interrupts are sorted */
|
|
assert_interrupts_sorted();
|
|
#endif
|
|
|
|
/* Register RAS priority handler */
|
|
ehf_register_priority_handler(PLAT_RAS_PRI, ras_interrupt_handler);
|
|
}
|