Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 26 additions & 12 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -437,28 +437,42 @@ static inline sbi_ret_t handle_sbi_ecall_RFENCE(hart_t *hart, int32_t fid)
* completely.
*/
uint64_t hart_mask, hart_mask_base;
uint32_t start_addr, size;
switch (fid) {
case 0:
case SBI_RFENCE__I:
/* Instruction cache flush - ignored in interpreter mode */
return (sbi_ret_t){SBI_SUCCESS, 0};
case 1:
case SBI_RFENCE__VMA:
case SBI_RFENCE__VMA_ASID:
/* RFENCE.VMA and RFENCE.VMA.ASID both use the same parameters:
* a0: hart_mask (low bits)
* a1: hart_mask_base (high bits)
* a2: start_addr
* a3: size
* For VMA_ASID, a4 contains asid (currently ignored)
*/
hart_mask = (uint64_t) hart->x_regs[RV_R_A0];
hart_mask_base = (uint64_t) hart->x_regs[RV_R_A1];
start_addr = hart->x_regs[RV_R_A2];
size = hart->x_regs[RV_R_A3];

if (hart_mask_base == 0xFFFFFFFFFFFFFFFF) {
for (uint32_t i = 0; i < hart->vm->n_hart; i++) {
mmu_invalidate(hart->vm->hart[i]);
}
/* Flush all harts */
for (uint32_t i = 0; i < hart->vm->n_hart; i++)
mmu_invalidate_range(hart->vm->hart[i], start_addr, size);
} else {
/* Flush specified harts based on mask */
for (int i = hart_mask_base; hart_mask; hart_mask >>= 1, i++) {
mmu_invalidate(hart->vm->hart[i]);
if (hart_mask & 1)
mmu_invalidate_range(hart->vm->hart[i], start_addr, size);
}
}
return (sbi_ret_t){SBI_SUCCESS, 0};
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case SBI_RFENCE__GVMA_VMID:
case SBI_RFENCE__GVMA:
case SBI_RFENCE__VVMA_ASID:
case SBI_RFENCE__VVMA:
/* Hypervisor-related RFENCE operations - not implemented */
return (sbi_ret_t){SBI_SUCCESS, 0};
default:
return (sbi_ret_t){SBI_ERR_FAILED, 0};
Expand Down
48 changes: 48 additions & 0 deletions riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,54 @@ void mmu_invalidate(hart_t *vm)
vm->cache_store.n_pages = 0xFFFFFFFF;
}

/* Invalidate MMU caches for a specific virtual address range.
* If size is 0 or -1, invalidate all caches (equivalent to mmu_invalidate()).
* Otherwise, only invalidate cache entries whose VPN falls within
* [start_addr >> PAGE_SHIFT, (start_addr + size - 1) >> PAGE_SHIFT].
*/
void mmu_invalidate_range(hart_t *vm, uint32_t start_addr, uint32_t size)
{
/* SBI spec: size == 0 or size == -1 means flush entire address space */
if (size == 0 || size == (uint32_t) -1) {
mmu_invalidate(vm);
return;
}

/* Calculate VPN range: [start_vpn, end_vpn] inclusive.
* Use 64-bit arithmetic to prevent overflow when (start_addr + size - 1)
* exceeds UINT32_MAX. For example:
* start_addr = 0xFFF00000, size = 0x00200000
* 32-bit: 0xFFF00000 + 0x00200000 - 1 = 0x000FFFFF (wraps)
* 64-bit: 0xFFF00000 + 0x00200000 - 1 = 0x100FFFFF (correct)
* Clamp to RV32 address space maximum before calculating end_vpn.
*/
uint32_t start_vpn = start_addr >> RV_PAGE_SHIFT;
uint64_t end_addr = (uint64_t) start_addr + size - 1;
if (end_addr > UINT32_MAX)
end_addr = UINT32_MAX;
uint32_t end_vpn = (uint32_t) end_addr >> RV_PAGE_SHIFT;

/* Check each cache entry and invalidate if in range.
* Since we only have 4 cache entries total (fetch: 1, load: 2, store: 1),
* simple sequential checks are sufficient.
*/
if (vm->cache_fetch.n_pages >= start_vpn &&
vm->cache_fetch.n_pages <= end_vpn)
vm->cache_fetch.n_pages = 0xFFFFFFFF;

if (vm->cache_load[0].n_pages >= start_vpn &&
vm->cache_load[0].n_pages <= end_vpn)
vm->cache_load[0].n_pages = 0xFFFFFFFF;

if (vm->cache_load[1].n_pages >= start_vpn &&
vm->cache_load[1].n_pages <= end_vpn)
vm->cache_load[1].n_pages = 0xFFFFFFFF;

if (vm->cache_store.n_pages >= start_vpn &&
vm->cache_store.n_pages <= end_vpn)
vm->cache_store.n_pages = 0xFFFFFFFF;
}

/* Pre-verify the root page table to minimize page table access during
* translation time.
*/
Expand Down
3 changes: 3 additions & 0 deletions riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,6 @@ void vm_error_report(const hart_t *vm);

/* Invalidate all MMU translation caches (fetch, load, store) */
void mmu_invalidate(hart_t *vm);

/* Invalidate MMU caches for a specific virtual address range */
void mmu_invalidate_range(hart_t *vm, uint32_t start_addr, uint32_t size);
Loading