| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| |
| #include <arch/exception.h> |
| #include <types.h> |
| #include <console/console.h> |
| #include <device/mmio.h> |
| #include <ramdetect.h> |
| #include <arch/smp/spinlock.h> |
| #include <vm.h> |
| |
| static enum { |
| ABORT_CHECKER_NOT_TRIGGERED, |
| ABORT_CHECKER_TRIGGERED, |
| } abort_state = ABORT_CHECKER_NOT_TRIGGERED; |
| |
| extern void (*trap_handler)(struct trapframe *tf); |
| |
| static int get_instruction_len(uintptr_t addr) |
| { |
| uint16_t ins = read16p(addr); |
| |
| /* |
| * 16-bit or 32-bit instructions supported |
| */ |
| if ((ins & 0x3) != 3) { |
| return 2; |
| } else if ((ins & 0x1f) != 0x1f) { |
| return 4; |
| } |
| |
| die("Not a 16bit or 32bit instruction 0x%x\n", ins); |
| } |
| |
| static void ramcheck_trap_handler(struct trapframe *tf) |
| { |
| abort_state = ABORT_CHECKER_TRIGGERED; |
| |
| /* |
| * skip read instruction. |
| */ |
| int insn_size = get_instruction_len(tf->epc); |
| |
| write_csr(mepc, read_csr(mepc) + insn_size); |
| } |
| |
| 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; |
| trap_handler = ramcheck_trap_handler; |
| barrier(); |
| read32(ptr); |
| trap_handler = default_trap_handler; |
| barrier(); |
| printk(BIOS_DEBUG, "%lx is %s DRAM\n", dram_start + size * MiB, |
| abort_state == ABORT_CHECKER_NOT_TRIGGERED ? "" : "not"); |
| |
| return abort_state == ABORT_CHECKER_NOT_TRIGGERED; |
| } |