diff --git a/examples/simple/board/qemu_virt_riscv64/rootfs.cpio.gz b/examples/simple/board/qemu_virt_riscv64/rootfs.cpio.gz
index e689dd29..be24cf90 100644
Binary files a/examples/simple/board/qemu_virt_riscv64/rootfs.cpio.gz and b/examples/simple/board/qemu_virt_riscv64/rootfs.cpio.gz differ
diff --git a/examples/simple/board/qemu_virt_riscv64/simple.system b/examples/simple/board/qemu_virt_riscv64/simple.system
index 5cb481b3..90f6e99a 100644
--- a/examples/simple/board/qemu_virt_riscv64/simple.system
+++ b/examples/simple/board/qemu_virt_riscv64/simple.system
@@ -19,5 +19,6 @@
+
diff --git a/examples/simple/vmm.c b/examples/simple/vmm.c
index caae0fdc..9e7d1ab3 100644
--- a/examples/simple/vmm.c
+++ b/examples/simple/vmm.c
@@ -17,6 +17,7 @@
#if defined(CONFIG_ARCH_RISCV)
#include
#include
+#include
#endif
// @ivanv: ideally we would have none of these hardcoded values
@@ -59,6 +60,10 @@
* across platforms. */
#define SERIAL_IRQ_CH 1
+#if defined(BOARD_qemu_virt_riscv64)
+#define VTIMER_IRQ_CH 2
+#endif
+
#if defined(BOARD_qemu_virt_aarch64)
#define SERIAL_IRQ 33
#elif defined(BOARD_qemu_virt_riscv64)
@@ -133,10 +138,15 @@ void init(void) {
void notified(microkit_channel ch) {
switch (ch) {
case SERIAL_IRQ_CH: {
- // bool success = virq_inject(GUEST_VCPU_ID, SERIAL_IRQ);
- // if (!success) {
- // LOG_VMM_ERR("IRQ %d dropped on vCPU %d\n", SERIAL_IRQ, GUEST_VCPU_ID);
- // }
+ bool success = virq_inject(GUEST_VCPU_ID, SERIAL_IRQ);
+ if (!success) {
+ LOG_VMM_ERR("IRQ %d dropped on vCPU %d\n", SERIAL_IRQ, GUEST_VCPU_ID);
+ }
+ break;
+ }
+ case VTIMER_IRQ_CH: {
+ // TODO: handle vcpu id properly
+ plic_inject_timer_irq(0);
break;
}
default:
diff --git a/src/arch/riscv/fault.c b/src/arch/riscv/fault.c
index 4aa56967..025a202e 100644
--- a/src/arch/riscv/fault.c
+++ b/src/arch/riscv/fault.c
@@ -24,7 +24,10 @@
#define MACHINE_IMPL_ID 0
#define MACHINE_VENDOR_ID 0
-/* What SBI extensions we actually support */
+/*
+ * List of SBI extensions. Note that what extensions
+ * we actually support is a subset of this list.
+ */
// TODO: support system suspend
enum sbi_extensions {
SBI_EXTENSION_BASE = 0x10,
@@ -34,7 +37,7 @@ enum sbi_extensions {
SBI_EXTENSION_DEBUG_CONSOLE = 0x4442434e,
};
-enum sbi_ {
+enum sbi_debug_extension {
SBI_CONSOLE_PUTCHAR = 1,
};
@@ -155,10 +158,10 @@ extern uintptr_t guest_ram_vaddr;
#define FUNCT3_CLW 0b010
struct fault_instruction fault_decode_instruction(size_t vcpu_id, seL4_UserContext *regs, seL4_Word ip) {
- LOG_VMM("decoding at ip 0x%lx\n", ip);
+ // LOG_VMM("decoding at ip 0x%lx\n", ip);
seL4_Word guest_physical = guest_virtual_physical(ip, vcpu_id);
assert(guest_physical >= guest_ram_vaddr && guest_physical <= guest_ram_vaddr + 0x10000000);
- LOG_VMM("guest_physical: 0x%lx\n", guest_physical);
+ // LOG_VMM("guest_physical: 0x%lx\n", guest_physical);
/*
* For guest OSes that use the RISC-V 'C' extension we must read the instruction 16-bits at
* a time, in order to avoid UB since it is valid for *all* instructions, compressed or not,
@@ -167,7 +170,7 @@ struct fault_instruction fault_decode_instruction(size_t vcpu_id, seL4_UserConte
uint16_t instruction_lo = *((uint16_t *)guest_physical);
uint16_t instruction_hi = *(uint16_t *)(guest_physical + 16);
uint32_t instruction = ((uint32_t)instruction_hi << 16) | instruction_lo;
- LOG_VMM("guest_physical: 0x%lx, instruction: 0x%lx, instruction_lo: 0x%x, instruction_hi: 0x%x\n", guest_physical, instruction, instruction_lo, instruction_hi);
+ // LOG_VMM("guest_physical: 0x%lx, instruction: 0x%lx, instruction_lo: 0x%x, instruction_hi: 0x%x\n", guest_physical, instruction, instruction_lo, instruction_hi);
// TODO: check this.
uint8_t op_code = instruction & 0x7f;
/* funct3 is from bits 12:14. */
@@ -180,14 +183,12 @@ struct fault_instruction fault_decode_instruction(size_t vcpu_id, seL4_UserConte
/* If we are in here, we are dealing with a compressed instruction */
switch (instruction_lo >> 13) {
case FUNCT3_CSW:
- LOG_VMM("compressed store\n");
return (struct fault_instruction){
.op_code = OP_CODE_STORE,
.width = 2,
.rs2 = (instruction_lo >> 2) & (BIT(3) - 1),
};
case FUNCT3_CLW:
- LOG_VMM("compressed load\n");
return (struct fault_instruction){
.op_code = OP_CODE_LOAD,
.width = 2,
@@ -199,14 +200,12 @@ struct fault_instruction fault_decode_instruction(size_t vcpu_id, seL4_UserConte
switch (op_code) {
case OP_CODE_STORE:
- LOG_VMM("store\n");
return (struct fault_instruction){
.op_code = OP_CODE_STORE,
.width = 4,
.rs2 = (instruction >> 20) & (BIT(5) - 1),
};
case OP_CODE_LOAD:
- LOG_VMM("load\n");
return (struct fault_instruction){
.op_code = OP_CODE_LOAD,
.width = 4,
@@ -258,7 +257,7 @@ static bool fault_handle_sbi_timer(size_t vcpu_id, seL4_Word sbi_fid, seL4_UserC
seL4_Error err = seL4_RISCV_VCPU_WriteRegs(BASE_VCPU_CAP + vcpu_id, seL4_VCPUReg_TIMER, stime_value);
assert(!err);
}
- LOG_VMM("setting timer stime_value: 0x%lx, curr_time: 0x%lx\n", stime_value, curr_time);
+ // LOG_VMM("setting timer stime_value: 0x%lx, curr_time: 0x%lx\n", stime_value, curr_time);
regs->a0 = SBI_SUCCESS;
@@ -296,7 +295,7 @@ static bool fault_handle_sbi_base(size_t vcpu_id, seL4_Word sbi_fid, seL4_UserCo
seL4_Word probe_eid = regs->a0;
switch (probe_eid) {
case SBI_EXTENSION_BASE:
- // case SBI_EXTENSION_TIMER:
+ case SBI_EXTENSION_TIMER:
case SBI_EXTENSION_HART_STATE_MANAGEMENT:
case SBI_EXTENSION_SYSTEM_RESET:
case SBI_EXTENSION_DEBUG_CONSOLE:
@@ -304,6 +303,7 @@ static bool fault_handle_sbi_base(size_t vcpu_id, seL4_Word sbi_fid, seL4_UserCo
regs->a1 = 1;
return true;
default:
+ // TODO: print out string name of extension
LOG_VMM("guest probed for SBI EID 0x%lx that is not supported\n", probe_eid);
regs->a0 = SBI_ERR_NOT_SUPPORTED;
return true;
@@ -322,7 +322,7 @@ static bool fault_handle_sbi(size_t vcpu_id, seL4_UserContext *regs) {
seL4_Word sbi_eid = regs->a7;
/* SBI function ID for the given extension */
seL4_Word sbi_fid = regs->a6;
- LOG_VMM("SBI handle EID 0x%lx, FID: 0x%lx\n", sbi_eid, sbi_fid);
+ // LOG_VMM("SBI handle EID 0x%lx, FID: 0x%lx\n", sbi_eid, sbi_fid);
switch (sbi_eid) {
case SBI_EXTENSION_BASE:
// TODO: error handling
@@ -353,11 +353,11 @@ bool fault_handle(size_t vcpu_id, microkit_msginfo msginfo) {
seL4_UserContext regs;
seL4_TCB_ReadRegisters(BASE_VM_TCB_CAP + vcpu_id, false, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), ®s);
size_t label = microkit_msginfo_get_label(msginfo);
- LOG_VMM("handling fault '%s'\n", fault_to_string(label));
+ // LOG_VMM("handling fault '%s'\n", fault_to_string(label));
bool success = false;
switch (label) {
case seL4_Fault_VMFault: {
- LOG_VMM("fault on addr 0x%lx at pc 0x%lx\n", seL4_GetMR(seL4_VMFault_Addr), regs.pc);
+ // LOG_VMM("fault on addr 0x%lx at pc 0x%lx\n", seL4_GetMR(seL4_VMFault_Addr), regs.pc);
seL4_Word addr = seL4_GetMR(seL4_VMFault_Addr);
seL4_Word fsr = seL4_GetMR(seL4_VMFault_FSR);
if (addr >= PLIC_ADDR && addr < PLIC_ADDR + PLIC_SIZE) {
diff --git a/src/arch/riscv/plic.c b/src/arch/riscv/plic.c
index c8195f8a..485b941b 100644
--- a/src/arch/riscv/plic.c
+++ b/src/arch/riscv/plic.c
@@ -4,7 +4,7 @@
#include
#include
-#define DEBUG_PLIC
+// #define DEBUG_PLIC
#if defined(DEBUG_PLIC)
#define LOG_PLIC(...) do{ LOG_VMM("PLIC: "); printf(__VA_ARGS__); }while(0)
@@ -36,7 +36,7 @@ struct plic_regs plic_regs;
#define SIP_TIMER (1 << 5)
bool plic_inject_timer_irq(size_t vcpu_id) {
- LOG_VMM("injecting timer irq\n");
+ // LOG_VMM("injecting timer irq\n");
seL4_RISCV_VCPU_ReadRegs_t res = seL4_RISCV_VCPU_ReadRegs(BASE_VCPU_CAP + vcpu_id, seL4_VCPUReg_SIP);
assert(!res.error);
seL4_Word sip = res.value;
@@ -52,15 +52,22 @@ bool plic_inject_timer_irq(size_t vcpu_id) {
return true;
}
+#define SIP_EXTERNAL (1 << 9)
+
// TODO: this is for context 0
#define PLIC_IRQ_ENABLE_START 0x2000
#define PLIC_IRQ_ENABLE_END 0x1F1FFC
+// TODO: need to check whether the ENDs are correct, I think they might be off by one
#define PLIC_IRQ_PRIORITY_START 0x0
#define PLIC_IRQ_PRIORITY_END 0xFFC
#define PLIC_PRIOTIY_THRESHOLD_CONTEXT_1_START 0x201000
#define PLIC_PRIOTIY_THRESHOLD_CONTEXT_1_END 0x201004
+#define PLIC_CLAIM_COMPLETE_CONTEXT_1_START 0x201004
+#define PLIC_CLAIM_COMPLETE_CONTEXT_1_END 0x201008
+
+uint32_t plic_pending_irq = 0;
static bool plic_handle_fault_read(size_t vcpu_id, size_t offset, seL4_UserContext *regs, struct fault_instruction *instruction) {
LOG_PLIC("handling read at offset: 0x%lx\n", offset);
@@ -76,6 +83,17 @@ static bool plic_handle_fault_read(size_t vcpu_id, size_t offset, seL4_UserConte
data = plic_regs.enable_bits[context][enable_group];
break;
}
+ case PLIC_CLAIM_COMPLETE_CONTEXT_1_START: {
+ LOG_PLIC("read complete claim for pending IRQ %d\n", plic_pending_irq);
+ data = plic_pending_irq;
+ plic_pending_irq = 0;
+ seL4_RISCV_VCPU_ReadRegs_t sip = seL4_RISCV_VCPU_ReadRegs(BASE_VCPU_CAP + vcpu_id, seL4_VCPUReg_SIP);
+ assert(!sip.error);
+ sip.value &= ~SIP_EXTERNAL;
+ int err = seL4_RISCV_VCPU_WriteRegs(BASE_VCPU_CAP + vcpu_id, seL4_VCPUReg_SIP, sip.value);
+ assert(!err);
+ break;
+ }
default:
LOG_PLIC("invalid offset 0x%lx\n", offset);
return false;
@@ -136,11 +154,22 @@ static bool plic_handle_fault_write(size_t vcpu_id, size_t offset, seL4_UserCont
plic_regs.priority[irq_index] = data;
break;
}
- case PLIC_PRIOTIY_THRESHOLD_CONTEXT_1_START...PLIC_PRIOTIY_THRESHOLD_CONTEXT_1_END: {
+ case PLIC_PRIOTIY_THRESHOLD_CONTEXT_1_START: {
LOG_PLIC("write priority threshold for context %d: %d\n", 1, data);
plic_regs.priority_threshold[1] = data;
break;
}
+ case PLIC_CLAIM_COMPLETE_CONTEXT_1_START: {
+ LOG_PLIC("write complete claim for pending IRQ %d\n", plic_pending_irq);
+ /* TODO: we should be checking here, and probably in a lot of other places, that the
+ * IRQ attempting to be claimed is actually enabled. */
+ /* TODO: double check but when we get a claim we should be clearing the pending bit */
+ // size_t irq_pending_group = plic_pending_irq / 32;
+ plic_pending_irq = 0;
+ // plic_regs.pending_bits[irq_pending_group] = 0;
+ microkit_irq_ack(1);
+ break;
+ }
default:
LOG_PLIC("invalid offset 0x%lx\n", offset);
return false;
@@ -149,8 +178,6 @@ static bool plic_handle_fault_write(size_t vcpu_id, size_t offset, seL4_UserCont
return true;
}
-#define SIP_EXTERNAL (1 << 9)
-
#define PLIC_MAX_REGISTERED_IRQS 10
struct virq {
@@ -178,6 +205,12 @@ bool plic_register_irq(size_t vcpu_id, size_t irq, virq_ack_fn_t ack_fn, void *a
}
bool plic_inject_irq(size_t vcpu_id, int irq) {
+ // size_t context = irq / 128;
+ size_t enable_group = irq / 128;
+ if ((plic_regs.enable_bits[1][enable_group] & (1 << irq)) == 0) {
+ return true;
+ }
+
seL4_RISCV_VCPU_ReadRegs_t res = seL4_RISCV_VCPU_ReadRegs(BASE_VCPU_CAP + vcpu_id, seL4_VCPUReg_SIP);
assert(!res.error);
seL4_Word sip = res.value;
@@ -185,10 +218,13 @@ bool plic_inject_irq(size_t vcpu_id, int irq) {
size_t irq_pending_group = irq / 32;
size_t irq_bit = irq % 32;
- LOG_PLIC("injecting for IRQ %d (group: %d, bit: %d)\n", irq, irq_pending_group, irq_bit);
+ // LOG_PLIC("injecting for IRQ %d (group: %d, bit: %d)\n", irq, irq_pending_group, irq_bit);
// TODO: should we check if it's already pending?
+ // assert(plic_pending_irq == 0);
+ plic_pending_irq = irq;
+
plic_regs.pending_bits[irq_pending_group] |= 1 << irq_bit;
sip |= SIP_EXTERNAL;