-
Notifications
You must be signed in to change notification settings - Fork 85
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
Preliminary support for MMU emulation #438
base: master
Are you sure you want to change the base?
Conversation
This PR is not fully ready to be merged since testing is not yet fully designed. PR earlier to get some feedbacks for further design. |
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.
Benchmarks
Benchmark suite | Current: 66c2b9d | Previous: 05cfc40 | Ratio |
---|---|---|---|
Dhrystone |
1755.22 Average DMIPS over 10 runs |
1596.88 Average DMIPS over 10 runs |
0.91 |
Coremark |
1502.888 Average iterations/sec over 10 runs |
1474.188 Average iterations/sec over 10 runs |
0.98 |
This comment was automatically generated by workflow using github-action-benchmark.
The initial design mentioned in here does not fully consider the CSR such as satp CSR needs to be accessed during MMU translation. During implementation, the interface shall be changed to adapt MMU translation. |
The purpose of this commit is to boot 32-bit RISC-V Linux in the future. The virtual memory scheme to support is Sv32. There are one change to original code base to adapt the MMU: The prototype of riscv_io_t interface needs to be changed. Particularly, add a RISC-V instance(riscv_t) as the first parameter. MMU related callbacks require to access the satp CSR to perform a page table walk during virtual memory translation but satp CSR is stored in RISC-V instance(riscv_t), thus it should have a way to access the satp CSR. The trivial solution is adding RISC-V instance(riscv_t) to the prototype of riscv_io_t interface. After this change, we can reuse riscv_io_t for system emulation afterward. The rest of changes are implementing the Sv32 virtual memory scheme. For every memory access, it has to walk through the page table to get the corresponding PTE. Depends on the retrieval of PTE, there are several page faults to be handled if necessary, so there are three exceptions handlers have been introduced which are insn_pgfault, load_pgfault, and store_pgfault and they are used in MMU_CHECK_FAULT. In this commit, the access fault are not handled well since they are related to PMA and PMP and they might not the must to boot 32-bit RISC-V Linux (tested on semu). Some S-mode CSRs are added to riscv_internal to support S-mode. PTE, S-mode and M-mode CSR helper macro are introduced as well. Related: sysprog21#310
@@ -25,6 +25,8 @@ | |||
|
|||
#define ARRAYS_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) | |||
|
|||
#define MASK(n) (~(1 << n)) |
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.
Perhaps replacing "1" with "1U" to avoid unexpected signed integer overflow would be better?
@@ -604,16 +619,18 @@ static void block_translate(riscv_t *rv, block_t *block) | |||
block->pc_start = block->pc_end = rv->PC; | |||
|
|||
rv_insn_t *prev_ir = NULL; | |||
rv_insn_t *ir = mpool_calloc(rv->block_ir_mp); | |||
rv_insn_t *ir = mpool_alloc(rv->block_ir_mp); |
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.
Why should mpool_calloc() be replaced with mpool_alloc() and then execute memset()?
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.
It seems like a rebase problem for #437.
block->ir_head = ir; | ||
|
||
/* translate the basic block */ | ||
while (true) { | ||
memset(ir, 0, sizeof(rv_insn_t)); |
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.
Ditto.
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.
It seems like a rebase problem for #437.
@@ -644,7 +661,7 @@ static void block_translate(riscv_t *rv, block_t *block) | |||
break; | |||
} | |||
|
|||
ir = mpool_calloc(rv->block_ir_mp); | |||
ir = mpool_alloc(rv->block_ir_mp); |
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.
Ditto.
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.
It seems like a rebase problem for #437.
@@ -51,7 +52,10 @@ extern struct target_ops gdbstub_ops; | |||
_(breakpoint, 3) /* Breakpoint */ \ | |||
_(load_misaligned, 4) /* Load address misaligned */ \ | |||
_(store_misaligned, 6) /* Store/AMO address misaligned */ \ | |||
_(ecall_M, 11) /* Environment call from M-mode */ | |||
_(ecall_M, 11) /* Environment call from M-mode */ \ | |||
_(insn_pgfault, 12) /* Instruction page fault */ \ |
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.
Rename to pagefault_insn
, pagefault_load
, and pagefault_store
.
if (!pte && rv->csr_satp) { /* not found */ \ | ||
rv_except_##pgfault(rv, addr); \ | ||
return false; \ | ||
} else if (pte && \ |
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.
Replace else if
with if
statement.
(!(*pte & PTE_V) || (!(*pte & PTE_R) && (*pte & PTE_W)))) { \ | ||
rv_except_##pgfault(rv, addr); \ | ||
return false; \ | ||
} else if (pte && (!(*pte & PTE_X) && (access_bits & PTE_X))) { \ |
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.
Ditto. No else
is required for the sake of previous return.
How can we test the MMU specific operations? |
The testing idea can be break down to following steps:
If I am at the wrong path, please correct me. It take times to design this testing. So, I would try to support other peripherals emulation at the same time such as PLIC. |
The above sound great. I expect the lean and reasonably straightforward approach as following: |
sret instruction is used for returning from a trap when trap occurs in S-mode level. Thus, the execution flow will not be sequential. During basic block translation, the sret instruction should be considered as can_branch instruction. Moreover, the existing system instruction decoder does not support decoding the sret instruction. Thus, the ir->opcode should be set correctly to support decoding the sret instruction. The implementation of sret instruction is simply returning false for now, the improved implementation will be completed and tested in sysprog21#438.
sret instruction is used for returning from a trap when trap occurs in S-mode level. Thus, the execution flow will not be sequential. During basic block translation, the sret instruction should be considered as can_branch instruction. Moreover, the existing system instruction decoder does not support decoding the sret instruction. Thus, the ir->opcode should be set correctly to support decoding the sret instruction. The implementation of sret instruction is simply returning false for now, the improved implementation will be completed and tested in sysprog21#438 since the sret instruction involves privilege mode changing.
sret instruction is used for returning from a trap when trap occurs in S-mode level. Thus, the execution flow will not be sequential. During basic block translation, the sret instruction should be considered as can_branch instruction. Moreover, the existing system instruction decoder does not support decoding the sret instruction. Thus, the ir->opcode should be set correctly to support decoding the sret instruction. The implementation of sret instruction is simply returning false for now, the improved implementation will be completed and tested in sysprog21#438 since the sret instruction involves privilege mode changing.
The purpose of this commit is to boot 32-bit RISC-V Linux in the future. The virtual memory scheme to support is Sv32. There are one change to original code base to adapt the MMU:
After this change, we can reuse riscv_io_t for system emulation afterward.
The rest of changes are implementing the Sv32 virtual memory scheme. For every memory access, it has to walk through the page table to get the corresponding PTE. Depends on the retrieval of PTE, there are several page faults to be handled if necessary, so there are three exceptions handlers have been introduced which are insn_pgfault, load_pgfault, and store_pgfault and they are used in MMU_CHECK_FAULT. In this commit, the access fault are not handled well since they are related to PMA and PMP and they might not the must to boot 32-bit RISC-V Linux (tested on semu). More PTE, S-mode, M-mode CSR helper macro are introduced as well.
Related: #310