2、gicv2_secure_spis_configure_props
前面的函数一是对于gicv2的spi中断的默认配置,这里是设置对于spi g0组的属性配置。
/*******************************************************************************
-
Helper function to configure properties of secure G0 SPIs.
******************************************************************************/
void gicv2_secure_spis_configure_props(uintptr_t gicd_base,
const interrupt_prop_t *interrupt_props,
unsigned int interrupt_props_num)
{
unsigned int i;
const interrupt_prop_t *prop_desc;typedef struct gicv2_driver_data { uintptr_t gicd_base; uintptr_t gicc_base; unsigned int *target_masks; unsigned int target_masks_num; const interrupt_prop_t *interrupt_props; unsigned int interrupt_props_num; } gicv2_driver_data_t; *此结构描述了GICv2 IP的一些实现定义属性。平台端口使用它来指定这些属性,以便初始化GICv2驱动程序。属性描述如下。 * *“gicd_base”字段包含分发器接口程序员视图的基地址。 * *“gicc_base”字段包含CPU接口程序员视图的基地址。 * *“target_mask”是指向包含“target_masks_num”元素的数组的指针。GIC驱动程序将使用每个PE目标掩码填充阵列,以便在确定中断目标时使用。 * *“interrupt_props”字段是指向枚举安全中断及其属性的数组的指针。如果此字段不为NULL,将忽略“g0_trupt_array”和“g1s_interrupt_aArray”字段。 * *“interrupt_props_num”字段包含“interrupt _props”数组中的条目数。如果此字段为非零,则忽略“g0_crupt_num”。 列出GIC驱动程序的中断属性。所有中断目标EL3 /* List interrupt properties for GIC driver. All interrupts target EL3 */ const interrupt_prop_t plat_interrupts[] = { /* Dispatcher 1 owns interrupts d1_0 and d1_1, so assigns priority DISP1_PRIO */ INTR_PROP_DESC(d1_0, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(d1_1, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), /* Dispatcher 2 owns interrupts d2_0 and d2_1, so assigns priority DISP2_PRIO */ INTR_PROP_DESC(d2_0, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(d2_1, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), /* Dispatcher 3 owns interrupts d3_0 and d3_1, so assigns priority DISP3_PRIO */ INTR_PROP_DESC(d3_0, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(d3_1, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), }; typedef struct interrupt_prop { unsigned int intr_num:10; unsigned int intr_pri:8; unsigned int intr_grp:2; unsigned int intr_cfg:2; } interrupt_prop_t; 这个数组是中断的属性,这个我们之前说过。通过这个INTR_PROP_DESC声明的。
/* Make sure there’s a valid property array */
if (interrupt_props_num != 0U)
assert(interrupt_props != NULL);
interrupt_props_num
*“interrupt_props_num”字段包含“interrupt _props”数组中的条目数。如果此字段为非零,则忽略“g0_crupt_num”。
interrupt_props这个是一个中断的属性,interrupt_props_num就是表明中断的数量。
for (i = 0; i < interrupt_props_num; i++) {
prop_desc = &interrupt_props[i];
if (prop_desc->intr_num < MIN_SPI_ID)
continue;
确定这个中断的中断号符合要求
1-根据中断group分组将该中断设置为secure中断
/* Configure this interrupt as a secure interrupt */
assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
gicd_clr_igroupr(gicd_base, prop_desc->intr_num);
设置成安全中断前,得先看一下是不是属于group0
gicd_clr_igroupr:将该中断设置为secure中断。
void gicd_clr_igroupr(uintptr_t base, unsigned int id)
{
unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U);
unsigned int reg_val = gicd_read_igroupr(base, id);
gicd_write_igroupr(base, id, reg_val & ~(1U << bit_num));
}
2-设置该中断的优先级
/* Set the priority of this interrupt */
gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
prop_desc->intr_pri);
设置该中断的优先级
void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
{
uint8_t val = pri & GIC_PRI_MASK;
mmio_write_8(base + GICD_IPRIORITYR + id, val);
}
3-将该中断设置绑定到primary cpu
/* Target the secure interrupts to primary CPU */ (类似于gicd_write_irouter,路由亲和)
gicd_set_itargetsr(gicd_base, prop_desc->intr_num,
gicv2_get_cpuif_id(gicd_base));
static inline void gicd_set_itargetsr(uintptr_t base, unsigned int id,
unsigned int target)
{
uint8_t val = target & GIC_TARGET_CPU_MASK;
mmio_write_8(base + GICD_ITARGETSR + id, val);
}
GICD_ITARGETSR
未启用关联路由时,保留中断的目标PE列表。也就是说,如果中断被断言并且具有足够的优先级,它将保存分发器转发中断的CPU接口列表
未启用关联路由时使用这些寄存器。**当为中断的安全状态启用关联路由时,中断的目标PE由GICD_IROUTER<n>定义**,GICD_ITARGETSR<n>中的关联字节为RES0。在这种情况下,允许实现字节RAZ/WI。
•这些寄存器可通过字节访问。
•未实现中断对应的寄存器字段为RAZ/WI。
•未实现CPU接口对应的字段位为RAZ/WI。
•GICD_ITARGETSR0-GICD_ITARGETSR7为只读。每个字段返回一个仅对应于读取寄存器的PE的值。
•它是由硬件静态配置的SPIs(如果有的话)定义的实现。此类SPI的字段是只读的,并返回一个值,**该值指示中断的PE目标。**
•如果GICD_CTLR.DS==0,**除非GICD_NSACR<n>寄存器允许非安全软件控制组0和安全组1中断**,否则与组0或安全组1的中断对应的任何位只能通过安全访问访问,并且是非安全访问的RAZ/WI。
在单连接PE实现中,所有中断都以一个PE为目标,这些寄存器是RAZ/WI。
笔记
实现必须确保在写入时挂起的中断使用旧值或新值,并且必须确保中断不会丢失或处理多次。变化的影响必须在有限的时间内可见。
配置
这些寄存器在GIC的所有配置中都可用。如果GIC实现支持两种安全状态,则这些寄存器是公共的。
实现的GICD_ITARGETSR<n>寄存器的数量为8*(GICD_TYPER.ITLinesNumber+1)。寄存器从0开始编号。
在多处理器实现中,GICD_ITARGETSR0到GICD_ITARGETSR7为每个连接的PE存储。这些寄存器为中断0-31提供PE目标字段。
4-设置该中断实际的触发方式
/* Set interrupt configuration */
gicd_set_icfgr(gicd_base, prop_desc->intr_num,
prop_desc->intr_cfg);
设置该中断实际的触发方式
void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg)
{
/* Interrupt configuration is a 2-bit field */
unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U);
unsigned int bit_shift = bit_num << 1;
//读取电平触发方式
uint32_t reg_val = gicd_read_icfgr(base, id);
/* Clear the field, and insert required configuration */
reg_val &= ~(GIC_CFG_MASK << bit_shift);
reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift);
//写电平触发方式
gicd_write_icfgr(base, id, reg_val);
}
5-使能该中断
/* Enable this interrupt */
允许将相应的中断转发到CPU接口。使能该中断
gicd_set_isenabler(gicd_base, prop_desc->intr_num);
}
}