Skip to content

Commit 0c53d48

Browse files
committed
tests: expand sdk_suite coverage for IPC, IRQ, mem, and faults
- Add black-box QEMU cases for PI, destroy/kill waiters, pool exhaust, races, IRQ stress, cap/mem/fault - Allow sdk_spawn_priv for USER-privileged negative tests
1 parent 3744405 commit 0c53d48

19 files changed

Lines changed: 1610 additions & 4 deletions

File tree

tests/sdk_suite/_common/sdk_test_util.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ static inline void sdk_msleep_yield(uint32_t ms)
5353
ulmk_thread_yield();
5454
}
5555

56-
static inline ulmk_tid_t sdk_spawn(const char *name, void (*entry)(void *),
57-
void *arg, uint8_t prio, size_t stack,
58-
size_t heap)
56+
static inline ulmk_tid_t sdk_spawn_priv(const char *name, void (*entry)(void *),
57+
void *arg, uint8_t prio, size_t stack,
58+
size_t heap, ulmk_privilege_t priv)
5959
{
6060
ulmk_thread_attr_t a;
6161

@@ -64,9 +64,17 @@ static inline ulmk_tid_t sdk_spawn(const char *name, void (*entry)(void *),
6464
a.arg = arg;
6565
a.priority = prio;
6666
a.stack_size = stack;
67-
a.privilege = ULMK_PRIV_DRIVER;
67+
a.privilege = priv;
6868
a.heap_size = heap;
6969
return ulmk_thread_create(&a);
7070
}
7171

72+
static inline ulmk_tid_t sdk_spawn(const char *name, void (*entry)(void *),
73+
void *arg, uint8_t prio, size_t stack,
74+
size_t heap)
75+
{
76+
return sdk_spawn_priv(name, entry, arg, prio, stack, heap,
77+
ULMK_PRIV_DRIVER);
78+
}
79+
7280
#endif /* SDK_TEST_UTIL_H */

tests/sdk_suite/cap_neg/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CASE_NAME := cap_neg
2+
CASE_SRCS := root_thread.c
3+
SENTINELS := "cap_neg: PASS"
4+
FAIL_SENTINEL := "cap_neg: FAIL"
5+
QEMU_TIMEOUT := 40
6+
7+
include ../sdk_case.mk
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/* SPDX-License-Identifier: MIT */
2+
/*
3+
* cap_neg — CAP/privilege EPERM matrix (sdk_suite promotion of silicon_cap_neg).
4+
*/
5+
#include "sdk_test_util.h"
6+
#include "board_config.h"
7+
8+
#ifndef ULMK_BOARD_PERIPH_BASE
9+
#define ULMK_BOARD_PERIPH_BASE 0xF0000000u
10+
#endif
11+
12+
static int g_pass;
13+
static int g_fail;
14+
static ulmk_notif_t g_done;
15+
static volatile int g_user_spawn_eperm;
16+
static volatile int g_user_kill_eperm;
17+
static volatile int g_user_sus_eperm;
18+
static volatile int g_user_irq_eperm;
19+
static volatile int g_user_heap_eperm;
20+
static volatile int g_user_mmap_eperm;
21+
static volatile int g_user_cap_eperm;
22+
static volatile int g_drv_spawn_eperm;
23+
static volatile int g_drv_kill_eperm;
24+
static volatile int g_drv_cap_eperm;
25+
static volatile int g_drv_irq_ok;
26+
static volatile int g_drv_mmap_ok;
27+
static ulmk_tid_t g_victim;
28+
29+
static void check(const char *name, int ok)
30+
{
31+
sdk_puts(ok ? ".ok " : ".FAIL ");
32+
sdk_puts(name);
33+
sdk_puts("\n");
34+
if (ok)
35+
g_pass++;
36+
else
37+
g_fail++;
38+
}
39+
40+
#define CHECK(name, cond) check((name), (cond) ? 1 : 0)
41+
42+
static int is_eperm(int rc)
43+
{
44+
return rc == ULMK_EPERM;
45+
}
46+
47+
static int tid_is_eperm(ulmk_tid_t tid)
48+
{
49+
return (int32_t)(uintptr_t)tid == ULMK_EPERM;
50+
}
51+
52+
static void idle_victim(void *arg)
53+
{
54+
(void)arg;
55+
for (;;)
56+
ulmk_thread_yield();
57+
}
58+
59+
static void user_probe(void *arg)
60+
{
61+
ulmk_thread_attr_t a;
62+
ulmk_notif_t n;
63+
void *p;
64+
ulmk_tid_t tid;
65+
66+
(void)arg;
67+
a.name = "x";
68+
a.entry = idle_victim;
69+
a.arg = NULL;
70+
a.priority = 200u;
71+
a.stack_size = 512u;
72+
a.privilege = ULMK_PRIV_USER;
73+
a.heap_size = 0u;
74+
tid = ulmk_thread_create(&a);
75+
g_user_spawn_eperm = tid_is_eperm(tid);
76+
g_user_kill_eperm = is_eperm(ulmk_thread_kill(g_victim));
77+
g_user_sus_eperm = is_eperm(ulmk_thread_suspend(g_victim));
78+
n = ulmk_notif_create();
79+
g_user_irq_eperm = is_eperm(ulmk_irq_bind(5u, n, 0u));
80+
if (n != ULMK_NOTIF_INVALID)
81+
ulmk_notif_destroy(n);
82+
g_user_heap_eperm = is_eperm(ulmk_heap_extend(64u));
83+
p = ulmk_mem_map((void *)(uintptr_t)ULMK_BOARD_PERIPH_BASE, 64u,
84+
ULMK_PERM_READ | ULMK_PERM_WRITE, ULMK_MMAP_PERIPH);
85+
g_user_mmap_eperm = (p == NULL);
86+
g_user_cap_eperm = is_eperm(ulmk_cap_grant(g_victim, ULMK_CAP_SPAWN));
87+
ulmk_notif_signal(g_done, 0x1u);
88+
ulmk_thread_exit();
89+
}
90+
91+
static void driver_probe(void *arg)
92+
{
93+
ulmk_thread_attr_t a;
94+
ulmk_notif_t n;
95+
void *p;
96+
ulmk_tid_t tid;
97+
98+
(void)arg;
99+
a.name = "y";
100+
a.entry = idle_victim;
101+
a.arg = NULL;
102+
a.priority = 200u;
103+
a.stack_size = 512u;
104+
a.privilege = ULMK_PRIV_USER;
105+
a.heap_size = 0u;
106+
tid = ulmk_thread_create(&a);
107+
g_drv_spawn_eperm = tid_is_eperm(tid);
108+
g_drv_kill_eperm = is_eperm(ulmk_thread_kill(g_victim));
109+
g_drv_cap_eperm = is_eperm(ulmk_cap_grant(g_victim, ULMK_CAP_SPAWN));
110+
n = ulmk_notif_create();
111+
g_drv_irq_ok = (n != ULMK_NOTIF_INVALID) &&
112+
(ulmk_irq_bind(6u, n, 0u) == ULMK_OK);
113+
if (n != ULMK_NOTIF_INVALID)
114+
ulmk_notif_destroy(n);
115+
p = ulmk_mem_map((void *)(uintptr_t)ULMK_BOARD_PERIPH_BASE, 64u,
116+
ULMK_PERM_READ | ULMK_PERM_WRITE, ULMK_MMAP_PERIPH);
117+
g_drv_mmap_ok = sdk_map_ok(p);
118+
if (g_drv_mmap_ok)
119+
(void)ulmk_mem_unmap(p, 64u);
120+
ulmk_notif_signal(g_done, 0x2u);
121+
ulmk_thread_exit();
122+
}
123+
124+
void ulmk_root_thread(const ulmk_boot_info_t *info)
125+
{
126+
uint32_t bits = 0u;
127+
128+
board_services_init(info);
129+
sdk_puts("cap_neg: begin\n");
130+
g_pass = 0;
131+
g_fail = 0;
132+
g_done = ulmk_notif_create();
133+
g_victim = sdk_spawn_priv("victim", idle_victim, NULL, 200u, 1024u, 0u,
134+
ULMK_PRIV_USER);
135+
CHECK("victim", g_victim != ULMK_TID_INVALID);
136+
137+
sdk_spawn_priv("uprobe", user_probe, NULL, 10u, 1024u, 512u,
138+
ULMK_PRIV_USER);
139+
bits = 0u;
140+
ulmk_notif_wait(g_done, 0x1u, &bits);
141+
CHECK("u_spawn", g_user_spawn_eperm);
142+
CHECK("u_kill", g_user_kill_eperm);
143+
CHECK("u_sus", g_user_sus_eperm);
144+
CHECK("u_irq", g_user_irq_eperm);
145+
CHECK("u_heap", g_user_heap_eperm);
146+
CHECK("u_mmap", g_user_mmap_eperm);
147+
CHECK("u_cap", g_user_cap_eperm);
148+
149+
sdk_spawn_priv("dprobe", driver_probe, NULL, 10u, 1024u, 0u,
150+
ULMK_PRIV_DRIVER);
151+
bits = 0u;
152+
ulmk_notif_wait(g_done, 0x2u, &bits);
153+
CHECK("d_spawn", g_drv_spawn_eperm);
154+
CHECK("d_kill", g_drv_kill_eperm);
155+
CHECK("d_cap", g_drv_cap_eperm);
156+
CHECK("d_irq_ok", g_drv_irq_ok);
157+
CHECK("d_mmap_ok", g_drv_mmap_ok);
158+
159+
CHECK("r_spawn",
160+
sdk_spawn_priv("ok", idle_victim, NULL, 200u, 1024u, 0u,
161+
ULMK_PRIV_USER) != ULMK_TID_INVALID);
162+
CHECK("r_cap", ulmk_cap_grant(g_victim, ULMK_CAP_SPAWN) == ULMK_OK);
163+
164+
sdk_puts("cap_neg: pass=");
165+
sdk_put_u32((uint32_t)g_pass);
166+
sdk_puts(" fail=");
167+
sdk_put_u32((uint32_t)g_fail);
168+
sdk_puts("\n");
169+
sdk_puts(g_fail == 0 ? "cap_neg: PASS\n" : "cap_neg: FAIL\n");
170+
ulmk_thread_exit();
171+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CASE_NAME := destroy_waiters
2+
CASE_SRCS := root_thread.c
3+
SENTINELS := "destroy_waiters: PASS"
4+
FAIL_SENTINEL := "destroy_waiters: FAIL"
5+
QEMU_TIMEOUT := 40
6+
7+
include ../sdk_case.mk
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/* SPDX-License-Identifier: MIT */
2+
/*
3+
* destroy_waiters — ep/notif destroy unblocks waiters with ULMK_EINVAL.
4+
*/
5+
#include "sdk_test_util.h"
6+
7+
#define BIT_DONE (1u << 0)
8+
9+
static int g_pass;
10+
static int g_fail;
11+
static ulmk_ep_t g_ep;
12+
static ulmk_notif_t g_sync;
13+
static ulmk_notif_t g_target;
14+
static volatile int g_recv_rc;
15+
static volatile int g_call_rc;
16+
static volatile int g_wait_rc;
17+
18+
static void check(const char *name, int ok)
19+
{
20+
sdk_puts(ok ? ".ok " : ".FAIL ");
21+
sdk_puts(name);
22+
sdk_puts("\n");
23+
if (ok)
24+
g_pass++;
25+
else
26+
g_fail++;
27+
}
28+
29+
#define CHECK(name, cond) check((name), (cond) ? 1 : 0)
30+
31+
static void recv_waiter(void *arg)
32+
{
33+
ulmk_msg_t m;
34+
ulmk_tid_t sender;
35+
36+
(void)arg;
37+
g_recv_rc = ulmk_ep_recv(g_ep, &m, &sender);
38+
ulmk_notif_signal(g_sync, BIT_DONE);
39+
ulmk_thread_exit();
40+
}
41+
42+
static void call_waiter(void *arg)
43+
{
44+
ulmk_msg_t m;
45+
46+
(void)arg;
47+
m.label = 1u;
48+
g_call_rc = ulmk_ep_call(g_ep, &m);
49+
ulmk_notif_signal(g_sync, BIT_DONE);
50+
ulmk_thread_exit();
51+
}
52+
53+
static void notif_waiter(void *arg)
54+
{
55+
uint32_t bits = 0u;
56+
57+
(void)arg;
58+
g_wait_rc = ulmk_notif_wait(g_target, 0x1u, &bits);
59+
ulmk_notif_signal(g_sync, BIT_DONE);
60+
ulmk_thread_exit();
61+
}
62+
63+
void ulmk_root_thread(const ulmk_boot_info_t *info)
64+
{
65+
ulmk_tid_t tid;
66+
uint32_t bits = 0u;
67+
int i;
68+
int rc;
69+
70+
board_services_init(info);
71+
sdk_puts("destroy_waiters: begin\n");
72+
g_pass = 0;
73+
g_fail = 0;
74+
g_recv_rc = 0;
75+
g_call_rc = 0;
76+
g_wait_rc = 0;
77+
78+
g_sync = ulmk_notif_create();
79+
CHECK("sync", g_sync != ULMK_NOTIF_INVALID);
80+
81+
/* --- ep_recv waiter --- */
82+
g_ep = ulmk_ep_create();
83+
CHECK("ep_recv_create", g_ep != ULMK_EP_INVALID);
84+
tid = sdk_spawn("recv_w", recv_waiter, NULL, 10u, 1024u, 0u);
85+
CHECK("spawn_recv", tid != ULMK_TID_INVALID);
86+
(void)ulmk_ep_grant(g_ep, tid);
87+
88+
(void)ulmk_thread_priority_set(ulmk_thread_self(), 200u);
89+
for (i = 0; i < 8; i++)
90+
ulmk_thread_yield();
91+
92+
rc = ulmk_ep_destroy(g_ep);
93+
CHECK("ep_destroy_recv", rc == ULMK_OK);
94+
bits = 0u;
95+
ulmk_notif_wait(g_sync, BIT_DONE, &bits);
96+
CHECK("recv_einval", g_recv_rc == ULMK_EINVAL);
97+
98+
/* --- ep_call waiter (no server) --- */
99+
g_ep = ulmk_ep_create();
100+
CHECK("ep_call_create", g_ep != ULMK_EP_INVALID);
101+
tid = sdk_spawn("call_w", call_waiter, NULL, 10u, 1024u, 0u);
102+
CHECK("spawn_call", tid != ULMK_TID_INVALID);
103+
(void)ulmk_ep_grant(g_ep, tid);
104+
105+
for (i = 0; i < 8; i++)
106+
ulmk_thread_yield();
107+
108+
rc = ulmk_ep_destroy(g_ep);
109+
CHECK("ep_destroy_call", rc == ULMK_OK);
110+
bits = 0u;
111+
ulmk_notif_wait(g_sync, BIT_DONE, &bits);
112+
CHECK("call_einval", g_call_rc == ULMK_EINVAL);
113+
114+
/* --- notif_wait waiter --- */
115+
g_target = ulmk_notif_create();
116+
CHECK("notif_create", g_target != ULMK_NOTIF_INVALID);
117+
tid = sdk_spawn("notif_w", notif_waiter, NULL, 10u, 1024u, 0u);
118+
CHECK("spawn_notif", tid != ULMK_TID_INVALID);
119+
120+
for (i = 0; i < 8; i++)
121+
ulmk_thread_yield();
122+
123+
rc = ulmk_notif_destroy(g_target);
124+
CHECK("notif_destroy", rc == ULMK_OK);
125+
bits = 0u;
126+
ulmk_notif_wait(g_sync, BIT_DONE, &bits);
127+
CHECK("wait_einval", g_wait_rc == ULMK_EINVAL);
128+
129+
sdk_puts("destroy_waiters: pass=");
130+
sdk_put_u32((uint32_t)g_pass);
131+
sdk_puts(" fail=");
132+
sdk_put_u32((uint32_t)g_fail);
133+
sdk_puts("\n");
134+
sdk_puts(g_fail == 0 ? "destroy_waiters: PASS\n" : "destroy_waiters: FAIL\n");
135+
ulmk_thread_exit();
136+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CASE_NAME := fault_policy
2+
CASE_SRCS := root_thread.c
3+
SENTINELS := "fault_policy: PASS"
4+
FAIL_SENTINEL := "fault_policy: FAIL"
5+
QEMU_TIMEOUT := 40
6+
7+
include ../sdk_case.mk

0 commit comments

Comments
 (0)