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