aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv64/kernel/vmem.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-11-01 04:44:50 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2024-11-01 10:28:11 +0200
commit9914b44878ca52cc615d2f4e47fec400dd55ab76 (patch)
tree7678216d4049fa5d2a4a9e381daa4d34dc317c22 /arch/riscv64/kernel/vmem.c
parent89e162f3916de5a4faef5bd626590d004bdcdc39 (diff)
downloadkmi-9914b44878ca52cc615d2f4e47fec400dd55ab76.tar.gz
kmi-9914b44878ca52cc615d2f4e47fec400dd55ab76.zip
test all ipc variants more-or-less properly
Diffstat (limited to 'arch/riscv64/kernel/vmem.c')
-rw-r--r--arch/riscv64/kernel/vmem.c71
1 files changed, 47 insertions, 24 deletions
diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c
index fa3c1c2..4986c1f 100644
--- a/arch/riscv64/kernel/vmem.c
+++ b/arch/riscv64/kernel/vmem.c
@@ -623,7 +623,7 @@ stat_t setup_rpc_stack(struct tcb *t)
NULL);
/* we count downward in base pages, the top page is *always* reserved */
t->arch.rpc_idx = rpc_pages - 1;
-
+ /** @todo we could mark the first stack page accessible here already */
/* point registers to stack */
t->regs = t->rpc_stack - sizeof(struct call_ctx);
@@ -672,62 +672,85 @@ bool in_rpc_stack(struct tcb *t, vm_t addr)
&& addr < RPC_STACK_BASE + BASE_PAGE_SIZE * t->arch.rpc_idx;
}
-void close_rpc(struct tcb *t)
+void reuse_rpc(struct tcb *t)
{
struct vmem *b = t->arch.rpc_leaf;
int top_idx = t->arch.rpc_idx;
- /* absolute max iter count */
- for (; top_idx < (int)rpc_pages; --top_idx) {
- /* mark inaccessible until we reach the first inaccessible
- * region */
+ const int max = rpc_pages - 1;
+ for (; top_idx < max; --top_idx) {
pm_t *pte = (pm_t *)&b->leaf[top_idx];
if (!(pte_flags(*pte) & VM_U))
break;
- /* make page not accessible from userspace */
clear_bits(*pte, vp_flags(VM_U));
}
- /* make page following closed region accessible so we can avoid an
- * unnecessary page fault */
- pm_t *pte = (pm_t *)&b->leaf[top_idx];
+ /* top_idx is our 'current' kernel region, so mark page following it
+ * user accessible to avoid page fault on entry */
+ t->arch.rpc_idx = top_idx + 1;
+ pm_t *pte = (pm_t *)&b->leaf[t->arch.rpc_idx];
set_bits(*pte, vp_flags(VM_U));
- t->arch.rpc_idx = top_idx;
}
-void shrink_rpc(struct tcb *t)
+void new_rpc(struct tcb *t)
{
struct vmem *b = t->arch.rpc_leaf;
int top_idx = t->arch.rpc_idx;
- for (; top_idx > 0; ++top_idx) {
+ int max = rpc_pages - 1;
+ for (; top_idx < max; --top_idx) {
+ /* mark inaccessible until we reach the first inaccessible
+ * region, which must be our previous kernel data region */
pm_t *pte = (pm_t *)&b->leaf[top_idx];
if (!(pte_flags(*pte) & VM_U))
break;
+ /* make page not accessible from userspace */
clear_bits(*pte, vp_flags(VM_U));
}
- t->arch.rpc_idx = top_idx;
+ /* kernel region, skip */
+ t->arch.rpc_idx--;
+
+ /* user stack start, mark accessible to avoid pagefault on entry */
+ t->arch.rpc_idx--;
+ pm_t *pte = (pm_t *)&b->leaf[t->arch.rpc_idx];
+ set_bits(*pte, vp_flags(VM_U));
}
-void open_rpc(struct tcb *t, vm_t top)
+void destroy_rpc(struct tcb *t)
{
- assert(is_aligned(top, BASE_PAGE_SIZE));
struct vmem *b = t->arch.rpc_leaf;
- int old_idx = t->arch.rpc_idx;
- int new_idx = (top - RPC_STACK_BASE) / BASE_PAGE_SIZE;
- assert(new_idx >= old_idx);
+ int top_idx = t->arch.rpc_idx;
- /* always stop one before the page index indicated, might be kind of
- * easy to mess up */
- for (int i = old_idx; i < new_idx - 1; ++i) {
- pm_t *pte = (pm_t *)&b->leaf[i];
+ /* first, mark all 'current' accessible pages unaccessible */
+ int max = rpc_pages - 1;
+ for (; top_idx < max; ++top_idx) {
+ /* mark inaccessible until we reach the first inaccessible
+ * region, which must be our previous kernel data region */
+ pm_t *pte = (pm_t *)&b->leaf[top_idx];
+ if (!(pte_flags(*pte) & VM_U))
+ break;
+
+ /* make page not accessible from userspace */
+ clear_bits(*pte, vp_flags(VM_U));
+ }
+
+ /* current kernel data region, skip */
+ top_idx++;
+
+ int ctx = (t->rpc_stack - RPC_STACK_BASE) / BASE_PAGE_SIZE;
+
+ /* now mark previous rpc user region accessible again */
+ /* prev_ctx is page where our kernel context is, so we need to stop one
+ * before it */
+ for (; top_idx < ctx - 1; ++top_idx) {
+ pm_t *pte = (pm_t *)&b->leaf[top_idx];
set_bits(*pte, vp_flags(VM_U));
}
- t->arch.rpc_idx = new_idx - 1;
+ t->arch.rpc_idx = ctx - 1;
}
void grow_rpc(struct tcb *t, vm_t top)