summaryrefslogtreecommitdiffstats
path: root/src/arch/arm64/ramdetect.c
blob: 2f6a1cd50c05a2c25243a8855059539049e85bb2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/* SPDX-License-Identifier: GPL-2.0-or-later */

#include <types.h>
#include <device/mmio.h>
#include <ramdetect.h>
#include <arch/exception.h>
#include <arch/transition.h>

static enum {
	ABORT_CHECKER_NOT_TRIGGERED,
	ABORT_CHECKER_TRIGGERED,
} abort_state = ABORT_CHECKER_NOT_TRIGGERED;

static int abort_checker(struct exc_state *state, uint64_t vector_id)
{
	if (raw_read_esr_el3() >> 26 != 0x25)
		return EXC_RET_IGNORED; /* Not a data abort. */

	abort_state = ABORT_CHECKER_TRIGGERED;
	state->elx.elr += sizeof(uint32_t); /* Jump over faulting instruction. */
	raw_write_elr_el3(state->elx.elr);
	return EXC_RET_HANDLED;
}

static struct exception_handler sync_el0 = {.handler = &abort_checker};

int probe_mb(const uintptr_t dram_start, const uintptr_t size)
{
	uintptr_t addr = dram_start + (size * MiB) - sizeof(uint32_t);
	void *ptr = (void *)addr;

	abort_state = ABORT_CHECKER_NOT_TRIGGERED;
	exception_handler_register(EXC_VID_CUR_SP_EL0_SYNC, &sync_el0);
	read32(ptr);
	exception_handler_unregister(EXC_VID_CUR_SP_EL0_SYNC, &sync_el0);
	return abort_state == ABORT_CHECKER_NOT_TRIGGERED;
}