Skip to content

Commit

Permalink
Implement Real time counter to prevent mtime overflow
Browse files Browse the repository at this point in the history
Make 64-bit unsigned integer `mtime` with Real time counter (RTC)
to prevent mtime overflow.

Take 16-bit unsigned integer for example:

mtime    mtimecmp   delta

0xFFF8    0x0004    0x000c
0xFFFC    0x0004    0x0008
0x0000    0x0004    0x0004
0x0004    0x0004    0x0000    <- trigger interrupt
0x0008    0x0004    0xfffc

Trigger timer interrupt when `delta` is zero or negative (highest bit set).
  • Loading branch information
chiangkd committed Jun 2, 2024
1 parent 60db9e2 commit 5ee9e9c
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 27 deletions.
24 changes: 10 additions & 14 deletions aclint.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@

void aclint_timer_interrupts(vm_t *vm, aclint_state_t *aclint)
{
if ((vm->mtimeh > aclint->mtimecmp_hi) ||
((vm->mtimeh == aclint->mtimecmp_hi) &&
(vm->mtime >= aclint->mtimecmp_lo)))
uint64_t time_delta = aclint->mtimecmp - vm->mtime;
if ((time_delta & 0x8000000000000000) || time_delta == 0)
vm->sip |= RV_INT_STI_BIT;
else
vm->sip &= ~RV_INT_STI_BIT;
return;
}

void aclint_update_interrupts(vm_t *vm, aclint_state_t *aclint)
Expand All @@ -19,8 +17,6 @@ void aclint_update_interrupts(vm_t *vm, aclint_state_t *aclint)
vm->sip |= RV_INT_SSI_BIT;
else
vm->sip &= ~RV_INT_SSI_BIT;

return;
}

static bool aclint_reg_read(aclint_state_t *aclint,
Expand All @@ -35,19 +31,19 @@ static bool aclint_reg_read(aclint_state_t *aclint,
return true;
case _(MTIMECMP_LO):
/* mtimecmp */
*value = aclint->mtimecmp_lo;
*value = aclint->mtimecmp & 0xFFFFFFFF;
return true;
case _(MTIMECMP_HI):
/* mtimecmph */
*value = aclint->mtimecmp_hi;
*value = (aclint->mtimecmp >> 32) & 0xFFFFFFFF;
return true;
case _(MTIME_LO):
/* mtime */
*value = aclint->vm->mtime;
*value = aclint->vm->mtime & 0xFFFFFFFF;
return true;
case _(MTIME_HI):
/* mtimeh */
*value = aclint->vm->mtimeh;
*value = (aclint->vm->mtime >> 32) & 0xFFFFFFFF;
return true;
default:
return false;
Expand All @@ -67,19 +63,19 @@ static bool aclint_reg_write(aclint_state_t *aclint,
return true;
case _(MTIMECMP_LO):
/* mtimecmp */
aclint->mtimecmp_lo = value;
aclint->mtimecmp |= value;
return true;
case _(MTIMECMP_HI):
/* mtimecmph */
aclint->mtimecmp_hi = value;
aclint->mtimecmp |= ((uint64_t) value) << 32;
return true;
case _(MTIME_LO):
/* mtime */
aclint->vm->mtime = value;
aclint->vm->mtime |= value;
return true;
case _(MTIME_HI):
/* mtimeh */
aclint->vm->mtimeh = value;
aclint->vm->mtime |= ((uint64_t) value) << 32;
return true;
default:
return false;
Expand Down
3 changes: 1 addition & 2 deletions device.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ enum {

typedef struct {
vm_t *vm;
uint32_t mtimecmp_lo;
uint32_t mtimecmp_hi;
uint64_t mtimecmp;
uint32_t setssip;
} aclint_state_t;

Expand Down
9 changes: 4 additions & 5 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ static inline sbi_ret_t handle_sbi_ecall_TIMER(vm_t *vm, int32_t fid)
emu_state_t *data = PRIV(vm);
switch (fid) {
case SBI_TIMER__SET_TIMER:
data->aclint.mtimecmp_lo = vm->x_regs[RV_R_A0];
data->aclint.mtimecmp_hi = vm->x_regs[RV_R_A1];
data->aclint.mtimecmp = (((uint64_t) vm->x_regs[RV_R_A1])) << 32 |
(uint64_t) vm->x_regs[RV_R_A0];
return (sbi_ret_t){SBI_SUCCESS, 0};
default:
return (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0};
Expand Down Expand Up @@ -453,12 +453,11 @@ static int semu_start(int argc, char **argv)
#endif
}

if (!++vm.mtime)
vm.mtimeh++;

aclint_timer_interrupts(&vm, &emu.aclint);
aclint_update_interrupts(&vm, &emu.aclint);

vm.mtime++;

vm_step(&vm);
if (likely(!vm.error))
continue;
Expand Down
8 changes: 4 additions & 4 deletions riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -488,10 +488,10 @@ static void csr_read(vm_t *vm, uint16_t addr, uint32_t *value)
*value = vm->stval;
break;
case RV_CSR_TIME:
*value = vm->mtime;
*value = vm->mtime & 0xFFFFFFFF;
break;
case RV_CSR_TIMEH:
*value = vm->mtimeh;
*value = (vm->mtime >> 32) & 0xFFFFFFFF;
break;
default:
vm_set_exception(vm, RV_EXC_ILLEGAL_INSN, 0);
Expand Down Expand Up @@ -546,10 +546,10 @@ static void csr_write(vm_t *vm, uint16_t addr, uint32_t value)
vm->stval = value;
break;
case RV_CSR_TIME:
vm->mtime = value;
vm->mtime |= value;
break;
case RV_CSR_TIMEH:
vm->mtimeh = value;
vm->mtime |= ((uint64_t) value) << 32;
break;
default:
vm_set_exception(vm, RV_EXC_ILLEGAL_INSN, 0);
Expand Down
3 changes: 1 addition & 2 deletions riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@ struct __vm_internal {
uint32_t *page_table;

/* Timer */
uint32_t mtime;
uint32_t mtimeh;
uint64_t mtime;

void *priv; /**< environment supplied */

Expand Down

0 comments on commit 5ee9e9c

Please sign in to comment.