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