Skip to content

Commit 7578b2b

Browse files
D3boker1josecm
authored andcommitted
feat(riscv): add vimsic support
Co-authored-by: Jose Martins <[email protected]> Signed-off-by: Jose Martins <[email protected]>
1 parent 0ac3acd commit 7578b2b

File tree

7 files changed

+156
-23
lines changed

7 files changed

+156
-23
lines changed

src/arch/riscv/inc/arch/vm.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include <bao.h>
1010
#include <irqc.h>
1111
#include <arch/sbi.h>
12-
#include <arch/interrupts.h>
1312

1413
#define REG_RA (1)
1514
#define REG_SP (2)
@@ -52,6 +51,9 @@ struct arch_vm_platform {
5251
struct {
5352
paddr_t base;
5453
} aplic;
54+
struct {
55+
paddr_t base;
56+
} imsic;
5557
} aia;
5658
} irqc;
5759
};

src/arch/riscv/irqc/aia/inc/irqc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <arch/sbi.h>
1515
#elif (IRQC == AIA)
1616
#include <imsic.h>
17+
#include <vimsic.h>
1718
#endif
1819

1920
#define IRQC_TIMR_INT_ID (APLIC_MAX_INTERRUPTS + 1)

src/arch/riscv/irqc/aia/inc/vaplic.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,6 @@ void vaplic_inject(struct vcpu* vcpu, irqid_t id);
6363
*/
6464
void vaplic_set_hw(struct vm* vm, irqid_t id);
6565

66-
/**
67-
* @brief Wrapper for the virtual irqc initialization function
68-
*
69-
* @param vm Virtual Machine
70-
* @param vm_irqc_dscrp virtual irqc platform configuration
71-
*/
72-
static inline void virqc_init(struct vm* vm, const union vm_irqc_dscrp* vm_irqc_dscrp)
73-
{
74-
vaplic_init(vm, vm_irqc_dscrp);
75-
}
76-
7766
/**
7867
* @brief Injects a given interrupt into a virtual cpu
7968
*
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright (c) Bao Project and Contributors. All rights reserved.
4+
*/
5+
6+
#ifndef VIMSIC_H
7+
#define VIMSIC_H
8+
9+
#include <bao.h>
10+
11+
/**
12+
* @brief Maps the guest IMSIC addresses into the physical IMSIC adresses
13+
*
14+
* Guest's VCPUs assume no indexation order, e.g., VCPU 0 can map to CPU 2. This mapping
15+
* occurs at run-time (during bao initialization), therefore, also the IMSIC mapping needs to
16+
* be done at initialization time.
17+
* The vimsic_init function needs to be executed by every VM's virtual CPU. Then, it will
18+
* calculate the physical IMSIC address based on the physical CPU into which the VCPU is
19+
* mapped. Finally, it adds a new entry in the MMU.
20+
*
21+
* @param vm Virtual Machine
22+
* @param vm_irqc_dscrp Virtual Machine Description
23+
*/
24+
void vimsic_init(struct vm* vm, const union vm_irqc_dscrp* vm_irqc_dscrp);
25+
26+
#endif // VIMSIC_H

src/arch/riscv/irqc/aia/vaplic.c

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
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

4547
static uint32_t vaplic_get_domaincfg(struct vcpu* vcpu);
4648
static uint32_t vaplic_get_target(struct vcpu* vcpu, irqid_t intp_id);
49+
#if (IRQC == APLIC)
50+
#define APLIC_MIN_PRIO (0xFF)
51+
4752
static uint32_t vaplic_get_idelivery(struct vcpu* vcpu, idcid_t idc_id);
4853
static uint32_t vaplic_get_iforce(struct vcpu* vcpu, idcid_t idc_id);
4954
static uint32_t vaplic_get_ithreshold(struct vcpu* vcpu, idcid_t idc_id);
55+
#endif
5056

5157
void 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

12851371
void 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
}

src/arch/riscv/irqc/aia/vimsic.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright (c) Bao Project and Contributors. All rights reserved.
4+
*/
5+
6+
#include <vm.h>
7+
#include <arch/platform.h>
8+
#include <mem.h>
9+
#include <imsic.h>
10+
11+
/** We only support 1 guest per hart at the moment */
12+
#define VS_FILE_IDX 1
13+
14+
void vimsic_init(struct vm* vm, const union vm_irqc_dscrp* vm_irqc_dscrp)
15+
{
16+
struct vcpu* vcpu = cpu()->vcpu;
17+
cpuid_t pcpu_id = vcpu->phys_id;
18+
vcpuid_t vcpu_id = vcpu->id;
19+
paddr_t imsic_paddr;
20+
vaddr_t imsic_vaddr;
21+
22+
imsic_vaddr = vm_irqc_dscrp->aia.imsic.base + (PAGE_SIZE * vcpu_id);
23+
24+
imsic_paddr = platform.arch.irqc.aia.imsic.base +
25+
(PAGE_SIZE * ((IMSIC_NUM_FILES * pcpu_id) + VS_FILE_IDX));
26+
27+
if (imsic_vaddr != INVALID_VA) {
28+
mem_alloc_map_dev(&vm->as, SEC_VM_ANY, imsic_vaddr, imsic_paddr, 1);
29+
}
30+
}

src/arch/riscv/vm.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,7 @@ void vcpu_arch_reset(struct vcpu* vcpu, vaddr_t entry)
3838

3939
csrs_sscratch_write((uintptr_t)&vcpu->regs);
4040

41-
vcpu->regs.hstatus = HSTATUS_SPV;
42-
if (RV64) {
43-
vcpu->regs.hstatus |= HSTATUS_VSXL_64;
44-
}
41+
vcpu->regs.hstatus = HSTATUS_SPV | (1ULL << HSTATUS_VGEIN_OFF);
4542
vcpu->regs.sstatus = SSTATUS_SPP_BIT | SSTATUS_FS_DIRTY | SSTATUS_XS_DIRTY;
4643
vcpu->regs.sepc = entry;
4744
vcpu->regs.a0 = vcpu->arch.hart_id = vcpu->id;

0 commit comments

Comments
 (0)