// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2022 Sean Anderson * Copyright 2014 Broadcom Corporation */ #include /* * Macro to force the compiler to *populate* memory (for an array or struct) * before passing the pointer to an inline assembly call. */ #define USE_PTR(ptr) *(const char (*)[]) (ptr) #if defined(CONFIG_ARM64) #define SMH_TRAP "hlt #0xf000" #elif defined(CONFIG_CPU_V7M) #define SMH_TRAP "bkpt #0xAB" #elif defined(CONFIG_SYS_THUMB_BUILD) #define SMH_TRAP "svc #0xab" #else #define SMH_TRAP "svc #0x123456" #endif /* * Call the handler */ long smh_trap(unsigned int sysnum, void *addr) { register long result asm("r0"); register void *_addr asm("r1") = addr; /* * We need a memory clobber (aka compiler barrier) for two reasons: * - The compiler needs to populate any data structures pointed to * by "addr" *before* the trap instruction is called. * - At least the SYSREAD function puts the result into memory pointed * to by "addr", so the compiler must not use a cached version of * the previous content, after the call has finished. */ asm volatile (SMH_TRAP : "=r" (result) : "0"(sysnum), "r"(USE_PTR(_addr)) : "memory"); return result; }