1010#include <mem.h>
1111#include <interrupts.h>
1212#include <arch/csrs.h>
13+ #if (IRQC == AIA )
14+ #include <imsic.h>
15+ #endif
1316
14- #define APLIC_MIN_PRIO (0xFF)
1517#define UPDATE_ALL_HARTS (~0U)
1618
1719#define SET_INTP_REG (reg , intp_id ) (reg[intp_id / 32] = bit32_set(reg[intp_id / 32], intp_id % 32))
@@ -44,9 +46,13 @@ static inline cpuid_t vaplic_vcpuid_to_pcpuid(struct vcpu* vcpu, vcpuid_t vhart)
4446
4547static uint32_t vaplic_get_domaincfg (struct vcpu * vcpu );
4648static uint32_t vaplic_get_target (struct vcpu * vcpu , irqid_t intp_id );
49+ #if (IRQC == APLIC )
50+ #define APLIC_MIN_PRIO (0xFF)
51+
4752static uint32_t vaplic_get_idelivery (struct vcpu * vcpu , idcid_t idc_id );
4853static uint32_t vaplic_get_iforce (struct vcpu * vcpu , idcid_t idc_id );
4954static uint32_t vaplic_get_ithreshold (struct vcpu * vcpu , idcid_t idc_id );
55+ #endif
5056
5157void vaplic_set_hw (struct vm * vm , irqid_t intp_id )
5258{
@@ -55,6 +61,21 @@ void vaplic_set_hw(struct vm* vm, irqid_t intp_id)
5561 }
5662}
5763
64+ #if (IRQC == AIA )
65+ /**
66+ * @brief Returns the target guest index of a given interrupt
67+ *
68+ * @param vcpu virtual cpu
69+ * @param intp_id interrupt ID
70+ * @return uint8_t guest hart index of the given interrupt
71+ */
72+ static inline uint8_t vaplic_get_target_guest (struct vcpu * vcpu , irqid_t intp_id )
73+ {
74+ return (vaplic_get_target (vcpu , intp_id ) >> APLIC_TARGET_GUEST_IDX_SHIFT ) &
75+ APLIC_TARGET_GUEST_INDEX_MASK ;
76+ }
77+ #endif
78+
5879/**
5980 * @brief Returns the target hart index of a given interrupt
6081 *
@@ -163,6 +184,11 @@ static bool vaplic_set_pend(struct vcpu* vcpu, irqid_t intp_id)
163184 return ret ;
164185}
165186
187+ enum { UPDATE_HART_LINE };
188+ static void vaplic_ipi_handler (uint32_t event , uint64_t data );
189+ CPU_MSG_HANDLER (vaplic_ipi_handler , VPLIC_IPI_ID )
190+
191+ #if (IRQC == APLIC )
166192/**
167193 * @brief Updates the topi register with with the highest pend & en interrupt id
168194 *
@@ -213,10 +239,6 @@ static bool vaplic_update_topi(struct vcpu* vcpu)
213239 return ret ;
214240}
215241
216- enum { UPDATE_HART_LINE };
217- static void vaplic_ipi_handler (uint32_t event , uint64_t data );
218- CPU_MSG_HANDLER (vaplic_ipi_handler , VPLIC_IPI_ID )
219-
220242/**
221243 * @brief Updates the interrupt line for a single hart
222244 *
@@ -243,6 +265,30 @@ static void vaplic_update_hart_line(struct vcpu* vcpu, vcpuid_t vhart_index)
243265 }
244266}
245267
268+ #elif (IRQC == AIA )
269+ static void vaplic_update_hart_imsic (struct vcpu * vcpu , vcpuid_t vhart_index )
270+ {
271+ struct vaplic * vaplic = & vcpu -> vm -> arch .vaplic ;
272+ cpuid_t pcpu_id = vaplic_vcpuid_to_pcpuid (vcpu , vhart_index );
273+ bool domain_enbl = !!(vaplic_get_domaincfg (vcpu ) & APLIC_DOMAINCFG_IE );
274+ size_t target_guest = 0 ;
275+
276+ if (pcpu_id == cpu ()-> id ) {
277+ for (irqid_t i = 1 ; i < APLIC_MAX_INTERRUPTS ; i ++ ) {
278+ if ((vaplic_get_hart_index (vcpu , i ) == vcpu -> id ) && vaplic_get_pend (vcpu , i ) &&
279+ vaplic_get_enbl (vcpu , i ) && domain_enbl ) {
280+ target_guest = vaplic_get_target_guest (vcpu , i );
281+ imsic_inject_pend (target_guest , i );
282+ CLR_INTP_REG (vaplic -> ip , i );
283+ }
284+ }
285+ } else {
286+ struct cpu_msg msg = { (uint32_t )VPLIC_IPI_ID , UPDATE_HART_LINE , vhart_index };
287+ cpu_send_msg (pcpu_id , & msg );
288+ }
289+ }
290+ #endif
291+
246292/**
247293 * @brief Triggers the hart/harts interrupt line update.
248294 *
@@ -257,10 +303,18 @@ static void vaplic_update_hart(struct vcpu* vcpu, size_t vhart_index)
257303
258304 if (vhart_index == UPDATE_ALL_HARTS ) {
259305 for (size_t i = 0 ; i < vaplic -> idc_num ; i ++ ) {
306+ #if (IRQC == APLIC )
260307 vaplic_update_hart_line (vcpu , (vcpuid_t )i );
308+ #elif (IRQC == AIA )
309+ vaplic_update_hart_imsic (vcpu , (vcpuid_t )i );
310+ #endif
261311 }
262312 } else if ((uint16_t )vhart_index < vaplic -> idc_num ) {
313+ #if (IRQC == APLIC )
263314 vaplic_update_hart_line (vcpu , (vcpuid_t )vhart_index );
315+ #elif (IRQC == AIA )
316+ vaplic_update_hart_imsic (vcpu , (vcpuid_t )vhart_index );
317+ #endif
264318 }
265319}
266320
@@ -295,7 +349,11 @@ static void vaplic_set_domaincfg(struct vcpu* vcpu, uint32_t new_val)
295349 /** Update only the virtual domaincfg */
296350 /** Only Interrupt Enable is configurable */
297351 new_val &= APLIC_DOMAINCFG_IE ;
352+ #if (IRQC == APLIC )
298353 new_val &= ~APLIC_DOMAINCFG_DM ;
354+ #elif (IRQC == AIA )
355+ new_val |= APLIC_DOMAINCFG_DM ;
356+ #endif
299357 vaplic -> domaincfg = new_val | APLIC_DOMAINCFG_RO80 ;
300358 vaplic_update_hart (vcpu , UPDATE_ALL_HARTS );
301359 spin_unlock (& vaplic -> lock );
@@ -645,7 +703,12 @@ static void vaplic_set_target(struct vcpu* vcpu, irqid_t intp_id, uint32_t new_v
645703{
646704 struct vaplic * vaplic = & vcpu -> vm -> arch .vaplic ;
647705 vcpuid_t hart_index = (new_val >> APLIC_TARGET_HART_IDX_SHIFT ) & APLIC_TARGET_HART_IDX_MASK ;
706+ #if (IRQC == APLIC )
648707 uint8_t priority = (uint8_t )(new_val & APLIC_IPRIO_MASK );
708+ #elif (IRQC == AIA )
709+ uint8_t guest_index = (new_val >> APLIC_TARGET_GUEST_IDX_SHIFT ) & APLIC_TARGET_GUEST_INDEX_MASK ;
710+ irqid_t eiid = new_val & APLIC_TARGET_EEID_MASK ;
711+ #endif
649712 cpuid_t pcpu_id = vm_translate_to_pcpuid (vcpu -> vm , hart_index );
650713 vcpuid_t prev_hart_index = 0 ;
651714
@@ -657,20 +720,37 @@ static void vaplic_set_target(struct vcpu* vcpu, irqid_t intp_id, uint32_t new_v
657720 pcpu_id = vm_translate_to_pcpuid (vcpu -> vm , hart_index );
658721 }
659722
723+ #if (IRQC == APLIC )
660724 new_val &= APLIC_TARGET_DIRECT_MASK ;
661725 if (priority == 0 ) {
662726 new_val |= APLIC_TARGET_MAX_PRIO ;
663727 priority = APLIC_TARGET_MAX_PRIO ;
664728 }
729+ #elif (IRQC == AIA )
730+ new_val &= APLIC_TARGET_MSI_MASK ;
731+ #endif
732+
665733 if (vaplic_get_active (vcpu , intp_id ) && vaplic_get_target (vcpu , intp_id ) != new_val ) {
666734 prev_hart_index = vaplic_get_hart_index (vcpu , intp_id );
667735 if (vaplic_get_hw (vcpu , intp_id )) {
668736 aplic_set_target_hart (intp_id , pcpu_id );
737+ #if (IRQC == APLIC )
669738 aplic_set_target_prio (intp_id , priority );
670739 priority = aplic_get_target_prio (intp_id );
740+ #elif (IRQC == AIA )
741+ aplic_set_target_guest (intp_id , 1 );
742+ aplic_set_target_eiid (intp_id , eiid );
743+ eiid = aplic_get_target_eiid (intp_id );
744+ #endif
671745 }
672- vaplic -> target [intp_id ] =
673- (uint32_t )((hart_index << APLIC_TARGET_HART_IDX_SHIFT ) | priority );
746+
747+ #if (IRQC == APLIC )
748+ vaplic -> target [intp_id ] = (uint32_t )(hart_index << APLIC_TARGET_HART_IDX_SHIFT ) | priority ;
749+ #elif (IRQC == AIA )
750+ vaplic -> target [intp_id ] = (uint32_t )(hart_index << APLIC_TARGET_HART_IDX_SHIFT ) |
751+ (uint32_t )(guest_index << APLIC_TARGET_GUEST_IDX_SHIFT ) | eiid ;
752+ #endif
753+
674754 if (prev_hart_index != hart_index ) {
675755 vaplic_update_hart (vcpu , prev_hart_index );
676756 }
@@ -697,6 +777,7 @@ static uint32_t vaplic_get_target(struct vcpu* vcpu, irqid_t intp_id)
697777 return ret ;
698778}
699779
780+ #if (IRQC == APLIC )
700781/**
701782 * @brief Set idelivery register for a given idc.
702783 *
@@ -854,6 +935,7 @@ static uint32_t vaplic_get_claimi(struct vcpu* vcpu, idcid_t idc_id)
854935 spin_unlock (& vaplic -> lock );
855936 return ret ;
856937}
938+ #endif
857939
858940/**
859941 * @brief domaincfg register access emulation function
@@ -1028,6 +1110,7 @@ static void vaplic_emul_target_access(struct emul_access* acc)
10281110 }
10291111}
10301112
1113+ #if (IRQC == APLIC )
10311114/**
10321115 * @brief idelivery register access emulation function
10331116 *
@@ -1103,6 +1186,7 @@ static void vaplic_emul_claimi_access(struct emul_access* acc, idcid_t idc_id)
11031186 vcpu_writereg (cpu ()-> vcpu , acc -> reg , vaplic_get_claimi (cpu ()-> vcpu , idc_id ));
11041187 }
11051188}
1189+ #endif
11061190
11071191/**
11081192 * @brief Injects a given interrupt into a given vcpu
@@ -1239,6 +1323,7 @@ static bool vaplic_domain_emul_handler(struct emul_access* acc)
12391323 return true;
12401324}
12411325
1326+ #if (IRQC == APLIC )
12421327/**
12431328 * @brief Function to handle writes (or reads) to (from) IDC structure.
12441329 *
@@ -1281,6 +1366,7 @@ static bool vaplic_idc_emul_handler(struct emul_access* acc)
12811366 }
12821367 return true;
12831368}
1369+ #endif
12841370
12851371void vaplic_init (struct vm * vm , const union vm_irqc_dscrp * vm_irqc_dscrp )
12861372{
@@ -1295,11 +1381,13 @@ void vaplic_init(struct vm* vm, const union vm_irqc_dscrp* vm_irqc_dscrp)
12951381
12961382 vm_emul_add_mem (vm , & vm -> arch .vaplic .aplic_domain_emul );
12971383
1384+ #if (IRQC == APLIC )
12981385 vm -> arch .vaplic .aplic_idc_emul =
12991386 (struct emul_mem ){ .va_base = vm_irqc_dscrp -> aia .aplic .base + APLIC_IDC_OFF ,
13001387 .size = sizeof (struct aplic_idc_hw ) * vm -> arch .vaplic .idc_num ,
13011388 .handler = vaplic_idc_emul_handler };
13021389
13031390 vm_emul_add_mem (vm , & vm -> arch .vaplic .aplic_idc_emul );
1391+ #endif
13041392 }
13051393}
0 commit comments