1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Switch to non-secure mode 4 * 5 * Copyright (c) 2018 Heinrich Schuchardt 6 * 7 * This module contains the ARMv8 specific code required to adjust the exception 8 * level before booting an operating system. 9 */ 10 11 #include <bootm.h> 12 #include <cpu_func.h> 13 #include <log.h> 14 #include <setjmp.h> 15 #include <asm/cache.h> 16 17 /** 18 * entry_non_secure() - entry point when switching to non-secure mode 19 * 20 * When switching to non-secure mode switch_to_non_secure_mode() calls this 21 * function passing a jump buffer. We use this jump buffer to restore the 22 * original stack and register state. 23 * 24 * @non_secure_jmp: jump buffer for restoring stack and registers 25 */ entry_non_secure(jmp_buf non_secure_jmp)26static void entry_non_secure(jmp_buf non_secure_jmp) 27 { 28 dcache_enable(); 29 debug("Reached non-secure mode\n"); 30 31 /* Restore stack and registers saved in switch_to_non_secure_mode() */ 32 longjmp(non_secure_jmp, 1); 33 } 34 35 /** 36 * switch_to_non_secure_mode() - switch to non-secure mode 37 * 38 * Exception level EL3 is meant to be used by the secure monitor only (ARM 39 * trusted firmware being one embodiment). The operating system shall be 40 * started at exception level EL2. So here we check the exception level 41 * and switch it if necessary. 42 */ switch_to_non_secure_mode(void)43void switch_to_non_secure_mode(void) 44 { 45 jmp_buf non_secure_jmp; 46 47 /* On AArch64 we need to make sure we call our payload in < EL3 */ 48 if (current_el() == 3) { 49 if (setjmp(non_secure_jmp)) 50 return; 51 dcache_disable(); /* flush cache before switch to EL2 */ 52 53 /* Move into EL2 and keep running there */ 54 armv8_switch_to_el2((uintptr_t)&non_secure_jmp, 0, 0, 0, 55 (uintptr_t)entry_non_secure, ES_TO_AARCH64); 56 } 57 } 58