mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 09:34:18 +00:00
GIC: Add API to raise secure SGI
API documentation updated. Change-Id: I129725059299af6cc612bafa8d74817f779d7c4f Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
This commit is contained in:
parent
74dce7fa6e
commit
8db978b5a8
13 changed files with 178 additions and 0 deletions
|
@ -200,6 +200,23 @@ For GICv2:
|
|||
``INTR_TYPE_S_EL1`` maps to Group 0. Otherwise, ``INTR_TYPE_EL3`` maps to
|
||||
Group 0 interrupt.
|
||||
|
||||
Function: void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target); [optional]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
Argument : int
|
||||
Argument : u_register_t
|
||||
Return : void
|
||||
|
||||
This API should raise an EL3 SGI. The first parameter, ``sgi_num``, specifies
|
||||
the ID of the SGI. The second parameter, ``target``, must be the MPIDR of the
|
||||
target PE.
|
||||
|
||||
In case of ARM standard platforms using GIC, the implementation of the API
|
||||
inserts barrier to make memory updates visible before raising SGI, then writes
|
||||
to appropriate *SGI Register* in order to raise the EL3 SGI.
|
||||
|
||||
----
|
||||
|
||||
*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
|
||||
|
|
|
@ -368,3 +368,38 @@ void gicv2_set_interrupt_type(unsigned int id, unsigned int type)
|
|||
}
|
||||
spin_unlock(&gic_lock);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function raises the specified SGI to requested targets.
|
||||
*
|
||||
* The proc_num parameter must be the linear index of the target PE in the
|
||||
* system.
|
||||
******************************************************************************/
|
||||
void gicv2_raise_sgi(int sgi_num, int proc_num)
|
||||
{
|
||||
unsigned int sgir_val, target;
|
||||
|
||||
assert(driver_data);
|
||||
assert(proc_num < GICV2_MAX_TARGET_PE);
|
||||
assert(driver_data->gicd_base);
|
||||
|
||||
/*
|
||||
* Target masks array must have been supplied, and the core position
|
||||
* should be valid.
|
||||
*/
|
||||
assert(driver_data->target_masks);
|
||||
assert(proc_num < driver_data->target_masks_num);
|
||||
|
||||
/* Don't raise SGI if the mask hasn't been populated */
|
||||
target = driver_data->target_masks[proc_num];
|
||||
assert(target != 0);
|
||||
|
||||
sgir_val = GICV2_SGIR_VALUE(SGIR_TGT_SPECIFIC, target, sgi_num);
|
||||
|
||||
/*
|
||||
* Ensure that any shared variable updates depending on out of band
|
||||
* interrupt trigger are observed before raising SGI.
|
||||
*/
|
||||
dsbishst();
|
||||
gicd_write_sgir(driver_data->gicd_base, sgir_val);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,14 @@ static inline unsigned int gicd_read_pidr2(uintptr_t base)
|
|||
return mmio_read_32(base + GICD_PIDR2_GICV2);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Distributor interface accessors for writing entire registers
|
||||
******************************************************************************/
|
||||
static inline void gicd_write_sgir(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICD_SGIR, val);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC CPU interface accessors for reading entire registers
|
||||
******************************************************************************/
|
||||
|
|
|
@ -960,3 +960,42 @@ void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
|
|||
spin_unlock(&gic_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function raises the specified Secure Group 0 SGI.
|
||||
*
|
||||
* The target parameter must be a valid MPIDR in the system.
|
||||
******************************************************************************/
|
||||
void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target)
|
||||
{
|
||||
unsigned int tgt, aff3, aff2, aff1, aff0;
|
||||
uint64_t sgi_val;
|
||||
|
||||
/* Verify interrupt number is in the SGI range */
|
||||
assert((sgi_num >= MIN_SGI_ID) && (sgi_num < MIN_PPI_ID));
|
||||
|
||||
/* Extract affinity fields from target */
|
||||
aff0 = MPIDR_AFFLVL0_VAL(target);
|
||||
aff1 = MPIDR_AFFLVL1_VAL(target);
|
||||
aff2 = MPIDR_AFFLVL2_VAL(target);
|
||||
aff3 = MPIDR_AFFLVL3_VAL(target);
|
||||
|
||||
/*
|
||||
* Make target list from affinity 0, and ensure GICv3 SGI can target
|
||||
* this PE.
|
||||
*/
|
||||
assert(aff0 < GICV3_MAX_SGI_TARGETS);
|
||||
tgt = BIT(aff0);
|
||||
|
||||
/* Raise SGI to PE specified by its affinity */
|
||||
sgi_val = GICV3_SGIR_VALUE(aff3, aff2, aff1, sgi_num, SGIR_IRM_TO_AFF,
|
||||
tgt);
|
||||
|
||||
/*
|
||||
* Ensure that any shared variable updates depending on out of band
|
||||
* interrupt trigger are observed before raising SGI.
|
||||
*/
|
||||
dsbishst();
|
||||
write_icc_sgi0r_el1(sgi_val);
|
||||
isb();
|
||||
}
|
||||
|
|
|
@ -36,6 +36,19 @@
|
|||
#define CPENDSGIR_SHIFT 2
|
||||
#define SPENDSGIR_SHIFT CPENDSGIR_SHIFT
|
||||
|
||||
#define SGIR_TGTLSTFLT_SHIFT 24
|
||||
#define SGIR_TGTLSTFLT_MASK 0x3
|
||||
#define SGIR_TGTLST_SHIFT 16
|
||||
#define SGIR_TGTLST_MASK 0xff
|
||||
#define SGIR_INTID_MASK 0xf
|
||||
|
||||
#define SGIR_TGT_SPECIFIC 0
|
||||
|
||||
#define GICV2_SGIR_VALUE(tgt_lst_flt, tgt, intid) \
|
||||
((((tgt_lst_flt) & SGIR_TGTLSTFLT_MASK) << SGIR_TGTLSTFLT_SHIFT) | \
|
||||
(((tgt) & SGIR_TGTLST_MASK) << SGIR_TGTLST_SHIFT) | \
|
||||
((intid) & SGIR_INTID_MASK))
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv2 specific CPU interface register offsets and constants.
|
||||
******************************************************************************/
|
||||
|
@ -157,6 +170,7 @@ void gicv2_enable_interrupt(unsigned int id);
|
|||
void gicv2_disable_interrupt(unsigned int id);
|
||||
void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority);
|
||||
void gicv2_set_interrupt_type(unsigned int id, unsigned int type);
|
||||
void gicv2_raise_sgi(int sgi_num, int proc_num);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __GICV2_H__ */
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
/* Constant to categorize LPI interrupt */
|
||||
#define MIN_LPI_ID 8192
|
||||
|
||||
/* GICv3 can only target up to 16 PEs with SGI */
|
||||
#define GICV3_MAX_SGI_TARGETS 16
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv3 specific Distributor interface register offsets and constants.
|
||||
******************************************************************************/
|
||||
|
@ -165,6 +168,27 @@
|
|||
#define IAR1_EL1_INTID_SHIFT 0
|
||||
#define IAR1_EL1_INTID_MASK 0xffffff
|
||||
|
||||
/* ICC SGI macros */
|
||||
#define SGIR_TGT_MASK 0xffff
|
||||
#define SGIR_AFF1_SHIFT 16
|
||||
#define SGIR_INTID_SHIFT 24
|
||||
#define SGIR_INTID_MASK 0xf
|
||||
#define SGIR_AFF2_SHIFT 32
|
||||
#define SGIR_IRM_SHIFT 40
|
||||
#define SGIR_IRM_MASK 0x1
|
||||
#define SGIR_AFF3_SHIFT 48
|
||||
#define SGIR_AFF_MASK 0xf
|
||||
|
||||
#define SGIR_IRM_TO_AFF 0
|
||||
|
||||
#define GICV3_SGIR_VALUE(aff3, aff2, aff1, intid, irm, tgt) \
|
||||
((((uint64_t) (aff3) & SGIR_AFF_MASK) << SGIR_AFF3_SHIFT) | \
|
||||
(((uint64_t) (irm) & SGIR_IRM_MASK) << SGIR_IRM_SHIFT) | \
|
||||
(((uint64_t) (aff2) & SGIR_AFF_MASK) << SGIR_AFF2_SHIFT) | \
|
||||
(((intid) & SGIR_INTID_MASK) << SGIR_INTID_SHIFT) | \
|
||||
(((aff1) & SGIR_AFF_MASK) << SGIR_AFF1_SHIFT) | \
|
||||
((tgt) & SGIR_TGT_MASK))
|
||||
|
||||
/*****************************************************************************
|
||||
* GICv3 ITS registers and constants
|
||||
*****************************************************************************/
|
||||
|
@ -357,6 +381,7 @@ void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
|
|||
unsigned int priority);
|
||||
void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
|
||||
unsigned int group);
|
||||
void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __GICV3_H__ */
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
(((mpidr) >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK)
|
||||
#define MPIDR_AFFLVL2_VAL(mpidr) \
|
||||
(((mpidr) >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK)
|
||||
#define MPIDR_AFFLVL3_VAL(mpidr) 0
|
||||
|
||||
/*
|
||||
* The MPIDR_MAX_AFFLVL count starts from 0. Take care to
|
||||
|
|
|
@ -266,6 +266,7 @@ DEFINE_COPROCR_RW_FUNCS(icc_iar0_el1, ICC_IAR0)
|
|||
DEFINE_COPROCR_RW_FUNCS(icc_iar1_el1, ICC_IAR1)
|
||||
DEFINE_COPROCR_RW_FUNCS(icc_eoir0_el1, ICC_EOIR0)
|
||||
DEFINE_COPROCR_RW_FUNCS(icc_eoir1_el1, ICC_EOIR1)
|
||||
DEFINE_COPROCR_RW_FUNCS_64(icc_sgi0r_el1, ICC_SGI0R_EL1_64)
|
||||
|
||||
DEFINE_COPROCR_RW_FUNCS(hdcr, HDCR)
|
||||
DEFINE_COPROCR_RW_FUNCS(cnthp_ctl, CNTHP_CTL)
|
||||
|
@ -325,4 +326,7 @@ DEFINE_DCOP_PARAM_FUNC(cvac, DCCMVAC)
|
|||
|
||||
#define read_ctr_el0() read_ctr()
|
||||
|
||||
#define write_icc_sgi0r_el1(_v) \
|
||||
write64_icc_sgi0r_el1(_v)
|
||||
|
||||
#endif /* __ARCH_HELPERS_H__ */
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
#define ICC_IAR1_EL1 S3_0_c12_c12_0
|
||||
#define ICC_EOIR0_EL1 S3_0_c12_c8_1
|
||||
#define ICC_EOIR1_EL1 S3_0_c12_c12_1
|
||||
#define ICC_SGI0R_EL1 S3_0_c12_c11_7
|
||||
|
||||
/*******************************************************************************
|
||||
* Generic timer memory mapped registers & offsets
|
||||
|
|
|
@ -322,6 +322,7 @@ DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar0_el1, ICC_IAR0_EL1)
|
|||
DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar1_el1, ICC_IAR1_EL1)
|
||||
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir0_el1, ICC_EOIR0_EL1)
|
||||
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1)
|
||||
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_sgi0r_el1, ICC_SGI0R_EL1)
|
||||
|
||||
|
||||
#define IS_IN_EL(x) \
|
||||
|
|
|
@ -82,6 +82,7 @@ void plat_ic_enable_interrupt(unsigned int id);
|
|||
int plat_ic_has_interrupt_type(unsigned int type);
|
||||
void plat_ic_set_interrupt_type(unsigned int id, unsigned int type);
|
||||
void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority);
|
||||
void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target);
|
||||
|
||||
/*******************************************************************************
|
||||
* Optional common functions (may be overridden)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <gic_common.h>
|
||||
#include <gicv2.h>
|
||||
#include <interrupt_mgmt.h>
|
||||
#include <platform.h>
|
||||
|
||||
/*
|
||||
* The following platform GIC functions are weakly defined. They
|
||||
|
@ -29,6 +30,7 @@
|
|||
#pragma weak plat_ic_disable_interrupt
|
||||
#pragma weak plat_ic_set_interrupt_priority
|
||||
#pragma weak plat_ic_set_interrupt_type
|
||||
#pragma weak plat_ic_raise_el3_sgi
|
||||
|
||||
/*
|
||||
* This function returns the highest priority pending interrupt at
|
||||
|
@ -220,3 +222,21 @@ void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
|
|||
|
||||
gicv2_set_interrupt_type(id, gicv2_type);
|
||||
}
|
||||
|
||||
void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
|
||||
{
|
||||
#if GICV2_G0_FOR_EL3
|
||||
int id;
|
||||
|
||||
/* Target must be a valid MPIDR in the system */
|
||||
id = plat_core_pos_by_mpidr(target);
|
||||
assert(id >= 0);
|
||||
|
||||
/* Verify that this is a secure SGI */
|
||||
assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
|
||||
|
||||
gicv2_raise_sgi(sgi_num, id);
|
||||
#else
|
||||
assert(0);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#pragma weak plat_ic_disable_interrupt
|
||||
#pragma weak plat_ic_set_interrupt_priority
|
||||
#pragma weak plat_ic_set_interrupt_type
|
||||
#pragma weak plat_ic_raise_el3_sgi
|
||||
|
||||
CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
|
||||
(INTR_TYPE_NS == INTR_GROUP1NS) &&
|
||||
|
@ -217,6 +218,17 @@ void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
|
|||
{
|
||||
gicv3_set_interrupt_type(id, plat_my_core_pos(), type);
|
||||
}
|
||||
|
||||
void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
|
||||
{
|
||||
/* Target must be a valid MPIDR in the system */
|
||||
assert(plat_core_pos_by_mpidr(target) >= 0);
|
||||
|
||||
/* Verify that this is a secure EL3 SGI */
|
||||
assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
|
||||
|
||||
gicv3_raise_secure_g0_sgi(sgi_num, target);
|
||||
}
|
||||
#endif
|
||||
#ifdef IMAGE_BL32
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue