-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement basic ACLINT support for the MTIMER register #45
Conversation
I would like to ask @ranvd for reviewing and collaborating. |
Could you provide some information on the approach used to validate ACLINT/MTIMER? |
I'll take a look soon and maybe verify with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The patch works with virtio-gpu
without side effects.
main.c
Outdated
@@ -143,6 +147,10 @@ static void mem_store(vm_t *vm, uint32_t addr, uint8_t width, uint32_t value) | |||
emu_update_vblk_interrupts(vm); | |||
return; | |||
#endif | |||
case 0x43: /* CLINT */ |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I don't mind using 0x44 for CLINT since 0x43 is used by virtio-gpu
. Thank you for pointing that out.
main.c
Outdated
data->timer = (((uint64_t) vm->x_regs[RV_R_A1]) << 32) | | ||
(uint64_t) (vm->x_regs[RV_R_A0]); | ||
data->aclint.mtimecmp = vm->x_regs[RV_R_A0]; | ||
data->aclint.mtimecmph = vm->x_regs[RV_R_A1]; |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
aclint.c
Outdated
uint32_t *value) | ||
{ | ||
switch (addr) { | ||
case 0x0: |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
main.c
Outdated
else | ||
vm.sip &= ~RV_INT_STI_BIT; | ||
if (!++vm.mtime) | ||
vm.mtimeh++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jserv:
mtimeh
variable increases whenever mtime
overflows to zero, is this a good way?
Also, mtimeh
is reset to zero via overflowing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need something more elegant. See https://luckyresistor.me/2019/07/10/real-time-counter-and-integer-overflow/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement mtime
as a Real-time counter (RTC) in #5ee9e9c and check interrupt with delta
(difference between mtimecmp
and mtime
) is zero or negative (highest bit set)
Replacing Clarify that the MTIMER peripheral can also trigger timer interrupts within a scheduled period by monitoring
|
riscv.c
Outdated
break; | ||
case RV_CSR_TIMEH: | ||
*value = vm->mtimeh; | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code from lines 432 to 445 should be removed, or the code here may not be used while simulating.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for pointing that out.
The above should appear in git commit messages for future reference purpose. |
riscv_private.h
Outdated
@@ -56,6 +56,10 @@ enum { | |||
|
|||
/* S-mode (Supervisor Protection and Translation) */ | |||
RV_CSR_SATP = 0x180, /**< Supervisor address translation and protection */ | |||
|
|||
/* Unprivileged Timers */ | |||
RV_CSR_TIME = 0xC01, /**< Timer for RDTIME instruction */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RDTIME is a pseudo-instruction. Quote from The RISC-V Instruction Set Manual : Volume I: User-Level ISA:
The RDTIME pseudo-instruction reads the low XLEN bits of the time CSR, which counts wall-clock real time that has passed from an arbitrary start time in the past. RDTIMEH is an RV32I-only instruction that reads bits 63–32 of the same real-time counter. The underlying 64-bit counter should never overflow in practice. The execution environment should provide a means of determining the period of the real-time counter (seconds/tick). The period must be constant. The real-time clocks of all hardware threads in a single user application should be synchronized to within one tick of the real-time clock. The environment should provide a means to determine the accuracy of the clock.
If this pull request is ready for reviewing, use |
In this commit, replace the `timer` defined in the `emu_state_t` structure, which originally compared with the instruction counter and triggered software timer interrupts. Further, make 64-bit unsigned integer `mtime` with Real time counter (RTC) to prevent mtime overflow. Replacing timer with MTIMER perpheral also triggers timer interrupts normally. Clarify that the MTIMER peripheral can also trigger timer interrupts within a scheduled period by monitoring `/proc/interrupts` reveals an increase in timer interrupts triggered by `riscv-timer`: ``` 1: 595 SiFive PLIC 1 Edge ttyS0 2: 19 SiFive PLIC 3 Edge virtio1 3: 0 SiFive PLIC 2 Edge virtio0 5: 58985 RISC-V INTC 5 Edge riscv-timer ... 1: 610 SiFive PLIC 1 Edge ttyS0 2: 19 SiFive PLIC 3 Edge virtio1 3: 0 SiFive PLIC 2 Edge virtio0 5: 59196 RISC-V INTC 5 Edge riscv-timer ... 1: 625 SiFive PLIC 1 Edge ttyS0 2: 19 SiFive PLIC 3 Edge virtio1 3: 0 SiFive PLIC 2 Edge virtio0 5: 59296 RISC-V INTC 5 Edge riscv-timer ``` Additionally, the `vm_timer_t` structure is use to retrieve system-wide clock through `clock_gettime()`. The clock frequency is configured to 65MHz, which matches the `timebase-frequency` specified in `minimal.dts`.
I defer @ranvd for confirmation. |
vm.sip &= ~RV_INT_STI_BIT; | ||
aclint_timer_interrupts(&vm, &emu.aclint); | ||
aclint_update_interrupts(&vm, &emu.aclint); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this blank line.
*/ | ||
*value = vm->insn_count >> ((addr & (1 << 7)) ? 32 : 0); | ||
switch (addr) { | ||
case RV_CSR_INSTRET: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add some comments here. E.g., denote the types.
_(MTIME_LO, 0x7FF8) \ | ||
_(MTIME_HI, 0x7FFC) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After enable the clint driver for Linux kernel, the "load access fault" show up. Maybe this is caused by the wrong address map here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After correcting the error above, the kernel gets stuck after logging out [ 0.010981] clint: registering percpu irq failed [-16].
This error may occur in my implementation as well. I'm still figuring out the reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for pointing out my mistake!
Related pull request: #46 |
If
To resolve this, directly set CLINT IRQ number with 1 and 5 for supervior software and timer interrupt:
However, this setup triggers the following warning:
This indicates that both Does it make sense to prioritize adding M-mode privilege levels support for semu first? |
Thank you for providing this information! I reviewed some Since we are running the Linux kernel in supervisor mode,
So, according to the clues above, I suggest not implementing M-mode for semu since semu already support SBI for the Linux kernel. |
I agree with the previous discussion. The
Additionally,
As this PR overlaps with PR #46, it should be closed. I will create a new PR to implement time CSR for generating software timer interrupts, originally triggered by instruction count:
This new feature can be integrated after PR #46 is complete. |
Replace the
timer
defined in theemu_state_t
structure, which originally compared with the instruction counter and triggered software timer interrupts, with the MTIMER memory-mapped peripheral. For each HART (currently only one), there is an MTIMECMP register connected to the MTIMER device.Additionally, use the TIMER Extension to program the clock for scheduling the next timer event.
Replacing timer with MTIMER perpheral also triggers timer interrupts normally.
Clarify that the MTIMER peripheral can also trigger timer interrupts within a scheduled period by monitoring
/proc/interrupts
reveals an increase in timer interrupts triggered byriscv-timer
: