diff options
| -rw-r--r-- | arch/riscv64/kernel/vmem.c | 71 | ||||
| -rw-r--r-- | include/arch/tcb.h | 52 | ||||
| -rw-r--r-- | src/uapi/ipc.c | 57 | ||||
| -rw-r--r-- | tests/ipc-fwd/init.c | 63 | ||||
| -rw-r--r-- | tests/ipc-fwd/source.mk | 1 | ||||
| -rw-r--r-- | tests/ipc-kick/init.c | 54 | ||||
| -rw-r--r-- | tests/ipc-kick/source.mk | 1 | ||||
| -rw-r--r-- | tests/ipc-req-exhaustion/init.c | 27 | ||||
| -rw-r--r-- | tests/ipc-req-exhaustion/source.mk | 1 | ||||
| -rw-r--r-- | tests/ipc-root/init.c | 51 | ||||
| -rw-r--r-- | tests/ipc-root/source.mk | 1 | ||||
| -rw-r--r-- | tests/ipc-tail/init.c | 54 | ||||
| -rw-r--r-- | tests/ipc-tail/source.mk | 1 | ||||
| -rwxr-xr-x | tests/scripts/gen-tests | 4 |
14 files changed, 358 insertions, 80 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) diff --git a/include/arch/tcb.h b/include/arch/tcb.h index b04dc56..3f99ae9 100644 --- a/include/arch/tcb.h +++ b/include/arch/tcb.h @@ -89,33 +89,31 @@ vm_t rpc_position(struct tcb *t); bool in_rpc_stack(struct tcb *t, vm_t addr); /** - * Shrinks rpc stack down to where the previous reserved area is, so stack looks - * something like this: + * Reuse current rpc activation. + * Effectively marks all stack pages except the first in the 'new' stack + * activation inaccessible. * - * ``` - * ctx | user | < - * v - * ctx | < - * ``` - * - * Implementation note: t->arch.rpc_idx now points to ctx. + * @param t Current tcb. + */ +void reuse_rpc(struct tcb *t); + +/** + * Create new rpc activation. + * Marks all current stack pages inaccessible, marks the first in the new stack + * accessible. * - * @param t tcb to shrink. + * @param t Current tcb. */ -void shrink_rpc(struct tcb *t); +void new_rpc(struct tcb *t); /** - * Opens back up a previous stack frame, so - * ``` - * ctx | user | ctx | < - * v - * ctx | user | < - * ``` + * Destroy a stack activation. + * Marks all current stack pages inaccessible, and marks all user stack pages in + * the previous activation accessible again. * - * @param t tcb to open up again. - * @param top Address to where previous ctx is. + * @param t Current tcb. */ -void open_rpc(struct tcb *t, vm_t top); +void destroy_rpc(struct tcb *t); /** * Adds more accessible space on the stack, so @@ -134,18 +132,4 @@ void open_rpc(struct tcb *t, vm_t top); */ void grow_rpc(struct tcb *t, vm_t top); -/** - * Marks all user accessible areas inaccessible, so - * ``` - * ctx | user | < - * ctx | ---- | < - * ``` - * - * Used by \ref do_ipc to make sure different processes can't mess with - * eachother's stacks. - * - * @param t tcb whose stack should be closed. - */ -void close_rpc(struct tcb *t); - #endif /* KMI_ARCH_TCB_H */ diff --git a/src/uapi/ipc.c b/src/uapi/ipc.c index 3e9c04a..e380e1f 100644 --- a/src/uapi/ipc.c +++ b/src/uapi/ipc.c @@ -44,16 +44,22 @@ enum ipc_flags { * @param t Thread to migrate. * @param r Process to migrate to. * @param s RPC stack regions to mark inaccessible. + * @param flags What kind of IPC we're doing. */ -static inline void finalize_rpc(struct tcb *t, struct tcb *r, vm_t s) +static inline void finalize_rpc(struct tcb *t, struct tcb *r, vm_t s, + enum ipc_flags flags) { clone_uvmem(r->proc.vmem, t->rpc.vmem); set_return(t, r->callback); reference_thread(r); t->pid = r->rid; - /* make sure updates are visible when swapping to the new virtual memory */ - close_rpc(t); + if (is_set(flags, IPC_TAIL)) + reuse_rpc(t); + else + new_rpc(t); + + flush_tlb_all(); set_stack(t, s); } @@ -72,8 +78,10 @@ static inline vm_t enter_rpc(struct tcb *t, struct sys_ret a, { /* reuse current rpc stack location if we're being kicked */ vm_t rpc_stack = (is_set(flags, IPC_TAIL) && is_rpc(t)) - ? t->rpc_stack : rpc_position(t); + ? t->rpc_stack + : rpc_position(t); + /* rpc_stack points to the top of the region */ struct call_ctx *ctx = (struct call_ctx *)(rpc_stack) - 1; t->regs = (vm_t)ctx; @@ -81,12 +89,17 @@ static inline vm_t enter_rpc(struct tcb *t, struct sys_ret a, * later use */ set_ret(t, 6, a); - ctx->exec = t->exec; - ctx->pid = t->pid; - ctx->eid = t->eid; - ctx->notify = flags & IPC_NOTIFY; - ctx->rpc_stack = t->rpc_stack; - t->rpc_stack = rpc_stack; + if (!is_set(flags, IPC_TAIL)) { + /* if we're doing a tail call, we don't need to update any of + * these things */ + ctx->rpc_stack = t->rpc_stack; + t->rpc_stack = rpc_stack; + ctx->exec = t->exec; + ctx->pid = t->pid; + ctx->eid = t->eid; + ctx->notify = flags & IPC_NOTIFY; + } + return rpc_stack - BASE_PAGE_SIZE; } @@ -141,7 +154,7 @@ static __noreturn void __run_notify(struct tcb *t, struct tcb *r) SYS_RET5(0, t->tid, code, flags, t->eid), IPC_NOTIFY); - finalize_rpc(t, r, s); + finalize_rpc(t, r, s, 0); clear_bits(t->notify_flags, flags); @@ -234,11 +247,10 @@ static void leave_rpc(struct tcb *t, struct sys_ret a) set_return(t, ctx->exec); /* if we're returning from a failed rpc, this should essentially be a * no-op */ - shrink_rpc(t); - open_rpc(t, ctx->rpc_stack); + t->rpc_stack = ctx->rpc_stack; + destroy_rpc(t); flush_tlb_all(); - t->rpc_stack = ctx->rpc_stack; t->pid = ctx->pid; t->eid = ctx->eid; @@ -282,10 +294,11 @@ static void do_ipc(struct tcb *t, sys_arg_t d3, enum ipc_flags flags) { - if (unlikely(!__enough_rpc_stack(t))) + if (!is_set(flags, IPC_TAIL) && !__enough_rpc_stack(t)) return_args1(t, ERR_OOMEM); - vm_t s = enter_rpc(t, SYS_RET6(t->eid, t->tid, d0, d1, d2, d3), flags); + id_t id = is_set(flags, IPC_FORWARD) ? t->eid : t->pid; + vm_t s = enter_rpc(t, SYS_RET6(id, t->tid, d0, d1, d2, d3), flags); struct tcb *r = get_tcb(pid); if (unlikely(!r || !is_proc(r))) { @@ -306,7 +319,7 @@ static void do_ipc(struct tcb *t, if (!is_set(flags, IPC_FORWARD)) t->eid = t->pid; - finalize_rpc(t, r, s); + finalize_rpc(t, r, s, flags); /* I tested out passing the return values as arguments to * ret_userspace_fast, but apparently that causes enough stack shuffling * to be slower overall. */ @@ -345,7 +358,11 @@ SYSCALL_DEFINE5(ipc_req)(struct tcb *t, sys_arg_t pid, SYSCALL_DEFINE5(ipc_fwd)(struct tcb *t, sys_arg_t pid, sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, sys_arg_t d3) { - do_ipc(t, pid, d0, d1, d2, d3, IPC_FORWARD); + /* I guess it's fine to check our rpc status and choose flags based on + * that, though the path is starting to get a bit convoluted with a + * bunch of conditionals that I might want to have a look at getting rid + * of at some point, to speed things up a little bit. */ + do_ipc(t, pid, d0, d1, d2, d3, is_rpc(t) ? IPC_FORWARD : 0); } /** @@ -363,7 +380,7 @@ SYSCALL_DEFINE5(ipc_tail)(struct tcb *t, sys_arg_t pid, sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, sys_arg_t d3) { - do_ipc(t, pid, d0, d1, d2, d3, IPC_TAIL); + do_ipc(t, pid, d0, d1, d2, d3, is_rpc(t) ? IPC_TAIL : 0); } /** @@ -381,7 +398,7 @@ SYSCALL_DEFINE5(ipc_kick)(struct tcb *t, sys_arg_t pid, sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, sys_arg_t d3) { - do_ipc(t, pid, d0, d1, d2, d3, IPC_FORWARD | IPC_TAIL); + do_ipc(t, pid, d0, d1, d2, d3, is_rpc(t) ? IPC_FORWARD | IPC_TAIL : 0); } /** diff --git a/tests/ipc-fwd/init.c b/tests/ipc-fwd/init.c new file mode 100644 index 0000000..2f04f3f --- /dev/null +++ b/tests/ipc-fwd/init.c @@ -0,0 +1,63 @@ +#include <common/test.h> + +START(pid, tid, d0, d1, d2, d3) +{ + check(pid == 0 || pid == 1, "illegal pid for init"); + if (pid == 0) { + printf("creating pid 2\n"); + id_t id1 = sys_fork(NULL); + check(id1 == 2, "unexpected pid?\n"); + + printf("creating pid 3\n"); + id_t id2 = sys_fork(NULL); + check(id2 == 3, "unexpected pid?\n"); + + struct sys_ret r = sys_ipc_req4(2, 1, 2, 3, 4); + check(r.s == 0, "failed request?\n"); + check(r.id == 2, "wrong responder?\n"); + check(r.a0 == 1, "wrong a0?\n"); + check(r.a1 == 2, "wrong a1?\n"); + check(r.a2 == 3, "wrong a2?\n"); + check(r.a3 == 4, "wrong a3?\n"); + } + else if (pid == 1 && d0 == 1) { + printf("pid 2 caught ipc req\n"); + check(pid == 1, "illegal pid source\n"); + check(tid == 1, "illegal tid source\n"); + check(d0 == 1, "illegal d0\n"); + check(d1 == 2, "illegal d1\n"); + check(d2 == 3, "illegal d2\n"); + check(d3 == 4, "illegal d3\n"); + + printf("pid 2 forwarding\n"); + struct sys_ret r = sys_ipc_fwd4(3, 5, 6, 7, 8); + check(r.s == 0, "failed request?\n"); + check(r.id == 3, "wrong responder?\n"); + check(r.a0 == 5, "wrong a0?\n"); + check(r.a1 == 6, "wrong a1?\n"); + check(r.a2 == 7, "wrong a2?\n"); + check(r.a3 == 8, "wrong a3?\n"); + + printf("pid 2 responding\n"); + sys_ipc_resp4(1, 2, 3, 4); + error("pid 2 ipc_resp failed\n"); + } + else if (pid == 1 && d0 == 5) { + printf("pid 3 caught ipc fwd\n"); + check(pid == 1, "illegal pid source\n"); + check(tid == 1, "illegal tid source\n"); + check(d0 == 5, "illegal d0\n"); + check(d1 == 6, "illegal d1\n"); + check(d2 == 7, "illegal d2\n"); + check(d3 == 8, "illegal d3\n"); + + printf("pid 3 responding\n"); + sys_ipc_resp4(5, 6, 7, 8); + error("pid 3 ipc_resp failed\n"); + } + else { + error("weird pid: %ld\n", pid); + } + + ok(); +} diff --git a/tests/ipc-fwd/source.mk b/tests/ipc-fwd/source.mk new file mode 100644 index 0000000..ed0078f --- /dev/null +++ b/tests/ipc-fwd/source.mk @@ -0,0 +1 @@ +TESTS += ipc-fwd diff --git a/tests/ipc-kick/init.c b/tests/ipc-kick/init.c new file mode 100644 index 0000000..3be4dee --- /dev/null +++ b/tests/ipc-kick/init.c @@ -0,0 +1,54 @@ +#include <common/test.h> + +START(pid, tid, d0, d1, d2, d3) +{ + check(pid == 0 || pid == 1, "illegal pid for init\n"); + if (pid == 0) { + printf("creating pid 2\n"); + id_t id1 = sys_fork(NULL); + check(id1 == 2, "unexpected pid?\n"); + + printf("creating pid 3\n"); + id_t id2 = sys_fork(NULL); + check(id2 == 3, "unexpected pid?\n"); + + struct sys_ret r = sys_ipc_req4(2, 1, 2, 3, 4); + check(r.s == 0, "failed request?\n"); + check(r.id == 3, "wrong responder?\n"); + check(r.a0 == 5, "wrong a0?\n"); + check(r.a1 == 6, "wrong a1?\n"); + check(r.a2 == 7, "wrong a2?\n"); + check(r.a3 == 8, "wrong a3?\n"); + } + else if (pid == 1 && d0 == 1) { + printf("pid 2 caught ipc req\n"); + check(pid == 1, "illegal pid source\n"); + check(tid == 1, "illegal tid source\n"); + check(d0 == 1, "illegal d0\n"); + check(d1 == 2, "illegal d1\n"); + check(d2 == 3, "illegal d2\n"); + check(d3 == 4, "illegal d3\n"); + + printf("pid 2 kicking\n"); + sys_ipc_kick4(3, 5, 6, 7, 8); + error("pid 2 ipc_tail failed\n"); + } + else if (pid == 1 && d0 == 5) { + printf("pid 3 caught ipc kick\n"); + check(pid == 1, "illegal pid source\n"); + check(tid == 1, "illegal tid source\n"); + check(d0 == 5, "illegal d0\n"); + check(d1 == 6, "illegal d1\n"); + check(d2 == 7, "illegal d2\n"); + check(d3 == 8, "illegal d3\n"); + + printf("pid 3 responding\n"); + sys_ipc_resp4(5, 6, 7, 8); + error("pid 3 ipc_resp failed\n"); + } + else { + error("weird pid: %ld\n", pid); + } + + ok(); +} diff --git a/tests/ipc-kick/source.mk b/tests/ipc-kick/source.mk new file mode 100644 index 0000000..838a651 --- /dev/null +++ b/tests/ipc-kick/source.mk @@ -0,0 +1 @@ +TESTS += ipc-kick diff --git a/tests/ipc-req-exhaustion/init.c b/tests/ipc-req-exhaustion/init.c new file mode 100644 index 0000000..6dd1a04 --- /dev/null +++ b/tests/ipc-req-exhaustion/init.c @@ -0,0 +1,27 @@ +#include <common/test.h> + +long counter = 0; + +START(pid, tid, d0, d1, d2, d3) +{ + (void)tid; + (void)d0; + (void)d1; + (void)d2; + (void)d3; + + check(pid == 0 || pid == 1, "illegal pid for init"); + printf("sending ipc req %zd to ourselves\n", counter++); + struct sys_ret r = sys_ipc_req4(1, 1, 2, 3, 4); + if (r.s) { + printf("ran out of stack space at %ld\n", counter); + printf("starting to unwind\n"); + } + + printf("unwinding at %ld\n", counter--); + + /* the final resp0 should fail, since we're back in our root process */ + sys_ipc_resp0(); + + ok(); +} diff --git a/tests/ipc-req-exhaustion/source.mk b/tests/ipc-req-exhaustion/source.mk new file mode 100644 index 0000000..3dc2ff3 --- /dev/null +++ b/tests/ipc-req-exhaustion/source.mk @@ -0,0 +1 @@ +TESTS += ipc-req-exhaustion diff --git a/tests/ipc-root/init.c b/tests/ipc-root/init.c new file mode 100644 index 0000000..8b43b4f --- /dev/null +++ b/tests/ipc-root/init.c @@ -0,0 +1,51 @@ +#include <common/test.h> + +START(pid, tid, d0, d1, d2, d3) +{ + check(pid == 0 || pid == 1, "illegal pid for init"); + if (pid == 0) { + printf("sending ipc fwd from root\n"); + struct sys_ret r = sys_ipc_fwd4(1, 1, 2, 3, 4); + check(r.s == OK, "not OK return\n"); + check(r.id == 1, "not OK response ID\n"); + check(r.a0 == 1, "not OK d0 response\n"); + check(r.a1 == 2, "not OK d1 response\n"); + check(r.a2 == 3, "not OK d2 response\n"); + check(r.a3 == 4, "not OK d3 response\n"); + + printf("sending ipc tail from root\n"); + r = sys_ipc_tail4(1, 1, 2, 3, 4); + printf("returned ipc req to ourselves\n"); + check(r.s == OK, "not OK return\n"); + check(r.id == 1, "not OK response ID\n"); + check(r.a0 == 1, "not OK d0 response\n"); + check(r.a1 == 2, "not OK d1 response\n"); + check(r.a2 == 3, "not OK d2 response\n"); + check(r.a3 == 4, "not OK d3 response\n"); + + printf("sending ipc kick from root\n"); + r = sys_ipc_kick4(1, 1, 2, 3, 4); + printf("returned ipc req to ourselves\n"); + check(r.s == OK, "not OK return\n"); + check(r.id == 1, "not OK response ID\n"); + check(r.a0 == 1, "not OK d0 response\n"); + check(r.a1 == 2, "not OK d1 response\n"); + check(r.a2 == 3, "not OK d2 response\n"); + check(r.a3 == 4, "not OK d3 response\n"); + } + else if (pid == 1) { + printf("caught ipc\n"); + check(pid == 1, "illegal pid source\n"); + check(tid == 1, "illegal tid source\n"); + check(d0 == 1, "illegal d0\n"); + check(d1 == 2, "illegal d1\n"); + check(d2 == 3, "illegal d2\n"); + check(d3 == 4, "illegal d3\n"); + + printf("sending response\n"); + sys_ipc_resp4(1, 2, 3, 4); + error("ipc resp failed\n"); + } + + ok(); +} diff --git a/tests/ipc-root/source.mk b/tests/ipc-root/source.mk new file mode 100644 index 0000000..fe98f64 --- /dev/null +++ b/tests/ipc-root/source.mk @@ -0,0 +1 @@ +TESTS += ipc-root diff --git a/tests/ipc-tail/init.c b/tests/ipc-tail/init.c new file mode 100644 index 0000000..8f3efdd --- /dev/null +++ b/tests/ipc-tail/init.c @@ -0,0 +1,54 @@ +#include <common/test.h> + +START(pid, tid, d0, d1, d2, d3) +{ + check(pid == 0 || pid == 1 || pid == 2, "illegal pid for init\n"); + if (pid == 0) { + printf("creating pid 2\n"); + id_t id1 = sys_fork(NULL); + check(id1 == 2, "unexpected pid?\n"); + + printf("creating pid 3\n"); + id_t id2 = sys_fork(NULL); + check(id2 == 3, "unexpected pid?\n"); + + struct sys_ret r = sys_ipc_req4(2, 1, 2, 3, 4); + check(r.s == 0, "failed request?\n"); + check(r.id == 3, "wrong responder?\n"); + check(r.a0 == 5, "wrong a0?\n"); + check(r.a1 == 6, "wrong a1?\n"); + check(r.a2 == 7, "wrong a2?\n"); + check(r.a3 == 8, "wrong a3?\n"); + } + else if (pid == 1) { + printf("pid 2 caught ipc req\n"); + check(pid == 1, "illegal pid source\n"); + check(tid == 1, "illegal tid source\n"); + check(d0 == 1, "illegal d0\n"); + check(d1 == 2, "illegal d1\n"); + check(d2 == 3, "illegal d2\n"); + check(d3 == 4, "illegal d3\n"); + + printf("pid 2 tailing\n"); + sys_ipc_tail4(3, 5, 6, 7, 8); + error("pid 2 ipc_tail failed\n"); + } + else if (pid == 2) { + printf("pid 3 caught ipc tail\n"); + check(pid == 2, "illegal pid source\n"); + check(tid == 1, "illegal tid source\n"); + check(d0 == 5, "illegal d0\n"); + check(d1 == 6, "illegal d1\n"); + check(d2 == 7, "illegal d2\n"); + check(d3 == 8, "illegal d3\n"); + + printf("pid 3 responding\n"); + sys_ipc_resp4(5, 6, 7, 8); + error("pid 3 ipc_resp failed\n"); + } + else { + error("weird pid: %ld\n", pid); + } + + ok(); +} diff --git a/tests/ipc-tail/source.mk b/tests/ipc-tail/source.mk new file mode 100644 index 0000000..e91a864 --- /dev/null +++ b/tests/ipc-tail/source.mk @@ -0,0 +1 @@ +TESTS += ipc-tail diff --git a/tests/scripts/gen-tests b/tests/scripts/gen-tests index 7095e30..3be204d 100755 --- a/tests/scripts/gen-tests +++ b/tests/scripts/gen-tests @@ -18,8 +18,8 @@ for NAME in "${@}"; do build/$NAME/initrd > reports/$NAME/log" >> tests.mk echo "reports/$NAME/OK: reports/$NAME/log" >> tests.mk - echo " grep 'BUG' reports/$NAME/log \\" >> tests.mk - echo " && echo 'BUG' > reports/$NAME/log \\" >> tests.mk + echo " grep 'BUG|ERROR' reports/$NAME/log \\" >> tests.mk + echo " && echo 'NOTOK' > reports/$NAME/log \\" >> tests.mk echo " || tail -n1 reports/$NAME/log | tr -d '\\\\r' \\" >> tests.mk echo " > reports/$NAME/OK" >> tests.mk |
