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