Skip to content

Commit daff7ed

Browse files
author
Nicolas Pitre
committed
tests: arm64: SVE: context switching test across different privileges
Expand the SVE context switching test to cover all thread privilege combinations with validation of SVE state preservation across different contexts. Test Coverage: - Privileged vs Privileged threads (kernel mode) - User vs User threads (userspace with memory domains) - User vs Privileged threads (mixed privilege levels) Signed-off-by: Nicolas Pitre <[email protected]>
1 parent e726a50 commit daff7ed

File tree

2 files changed

+113
-14
lines changed

2 files changed

+113
-14
lines changed

tests/arch/arm64/arm64_sve_ctx/prj.conf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,8 @@ CONFIG_FPU=y
33
CONFIG_FPU_SHARING=y
44
CONFIG_ARM64_SVE=y
55
CONFIG_ARM64_SVE_VL_MAX=256
6+
7+
# Enable userspace for SVE context switching test
8+
CONFIG_USERSPACE=y
9+
CONFIG_MAX_THREAD_BYTES=3
10+
CONFIG_TEST_USERSPACE=y

tests/arch/arm64/arm64_sve_ctx/src/main.c

Lines changed: 108 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <zephyr/ztest.h>
88
#include <zephyr/kernel.h>
99
#include <zephyr/arch/arm64/lib_helpers.h>
10+
#include <zephyr/app_memory/app_memdomain.h>
1011
#include <stdint.h>
1112

1213
/* Helper function for SVE vector length */
@@ -47,7 +48,7 @@ ZTEST(arm64_sve_ctx, test_sve_basic_instructions)
4748
}
4849
}
4950

50-
#define STACK_SIZE 1024
51+
#define STACK_SIZE 4096
5152
#define THREAD_PRIORITY 1
5253

5354
K_THREAD_STACK_DEFINE(thread1_stack, STACK_SIZE);
@@ -60,9 +61,10 @@ static struct k_thread thread2_data;
6061
static struct k_sem sync_sem;
6162
static struct k_sem done_sem;
6263

63-
/* Test data for validation */
64-
static volatile bool thread1_sve_ok;
65-
static volatile bool thread2_sve_ok;
64+
/* User space memory partition for test results */
65+
K_APPMEM_PARTITION_DEFINE(sve_test_partition);
66+
K_APP_DMEM(sve_test_partition) static volatile bool thread1_sve_ok;
67+
K_APP_DMEM(sve_test_partition) static volatile bool thread2_sve_ok;
6668

6769
/* Set unique patterns in SVE Z registers for thread identification */
6870
static inline void sve_set_thread_pattern(uint32_t thread_id)
@@ -121,8 +123,8 @@ static inline void sve_set_predicate_pattern(uint32_t thread_id)
121123
/* Verify SVE Z register patterns */
122124
static inline bool sve_verify_z_pattern(uint32_t thread_id)
123125
{
124-
/* because of "static" this can be used by only one thread at a time */
125-
static uint32_t actual_buffer[8 * 256/4] __aligned(8);
126+
/* Use stack-allocated buffer for user threads */
127+
uint32_t actual_buffer[8 * 256/4] __aligned(8);
126128
uint32_t *actual_p = actual_buffer;
127129
uint32_t vl = sve_get_vl();
128130
uint32_t expected_base = 0x12340000 | (thread_id & 0xFFF);
@@ -283,29 +285,121 @@ static void sve_test_thread2(void *arg1, void *arg2, void *arg3)
283285
/*
284286
* Test suite setup and tests
285287
*/
288+
static struct k_mem_domain sve_test_domain;
289+
286290
static void *sve_ctx_setup(void)
287291
{
288292
k_sem_init(&sync_sem, 0, 1);
289293
k_sem_init(&done_sem, 0, 1);
294+
295+
/* Initialize memory domain for user threads */
296+
struct k_mem_partition *parts[] = { &sve_test_partition };
297+
298+
k_mem_domain_init(&sve_test_domain, 1, parts);
299+
290300
return NULL;
291301
}
292302

293-
ZTEST(arm64_sve_ctx, test_sve_context_switching)
303+
static void sve_ctx_before(void *fixture)
294304
{
295-
/* Reset test results */
305+
/* Reset test results and semaphores before each test */
296306
thread1_sve_ok = false;
297307
thread2_sve_ok = false;
308+
k_sem_reset(&sync_sem);
309+
k_sem_reset(&done_sem);
310+
}
311+
312+
ZTEST(arm64_sve_ctx, test_sve_context_switching_privileged)
313+
{
314+
TC_PRINT("=== Testing SVE Context Switching: Privileged vs Privileged ===\n");
298315

299-
/* Create threads that will use SVE */
316+
/* Create privileged kernel threads that will use SVE */
300317
k_thread_create(&thread1_data, thread1_stack, STACK_SIZE,
301318
sve_test_thread1, NULL, NULL, NULL,
302319
THREAD_PRIORITY, 0, K_NO_WAIT);
303-
k_thread_name_set(&thread1_data, "sve_thread1");
320+
k_thread_name_set(&thread1_data, "sve_priv_thread1");
304321

305322
k_thread_create(&thread2_data, thread2_stack, STACK_SIZE,
306323
sve_test_thread2, NULL, NULL, NULL,
307324
THREAD_PRIORITY, 0, K_NO_WAIT);
308-
k_thread_name_set(&thread2_data, "sve_thread2");
325+
k_thread_name_set(&thread2_data, "sve_priv_thread2");
326+
327+
/* Wait for both threads to complete */
328+
k_sem_take(&done_sem, K_FOREVER);
329+
330+
/* Clean up */
331+
k_thread_join(&thread1_data, K_FOREVER);
332+
k_thread_join(&thread2_data, K_FOREVER);
333+
334+
/* Verify both threads maintained their SVE context */
335+
zassert_true(thread1_sve_ok, "Privileged Thread 1 SVE context was corrupted");
336+
zassert_true(thread2_sve_ok, "Privileged Thread 2 SVE context was corrupted");
337+
}
338+
339+
ZTEST(arm64_sve_ctx, test_sve_context_switching_user)
340+
{
341+
TC_PRINT("=== Testing SVE Context Switching: User vs User ===\n");
342+
343+
/* Create user threads that will use SVE */
344+
k_thread_create(&thread1_data, thread1_stack, STACK_SIZE,
345+
sve_test_thread1, NULL, NULL, NULL,
346+
THREAD_PRIORITY, K_USER, K_NO_WAIT);
347+
k_thread_name_set(&thread1_data, "sve_user_thread1");
348+
349+
/* Grant permission to semaphores for user thread 1 */
350+
k_object_access_grant(&sync_sem, &thread1_data);
351+
k_object_access_grant(&done_sem, &thread1_data);
352+
353+
/* Add thread 1 to memory domain for accessing result variables */
354+
k_mem_domain_add_thread(&sve_test_domain, &thread1_data);
355+
356+
k_thread_create(&thread2_data, thread2_stack, STACK_SIZE,
357+
sve_test_thread2, NULL, NULL, NULL,
358+
THREAD_PRIORITY, K_USER, K_NO_WAIT);
359+
k_thread_name_set(&thread2_data, "sve_user_thread2");
360+
361+
/* Grant permission to semaphores for user thread 2 */
362+
k_object_access_grant(&sync_sem, &thread2_data);
363+
k_object_access_grant(&done_sem, &thread2_data);
364+
365+
/* Add thread 2 to memory domain for accessing result variables */
366+
k_mem_domain_add_thread(&sve_test_domain, &thread2_data);
367+
368+
/* Wait for both threads to complete */
369+
k_sem_take(&done_sem, K_FOREVER);
370+
371+
/* Clean up */
372+
k_thread_join(&thread1_data, K_FOREVER);
373+
k_thread_join(&thread2_data, K_FOREVER);
374+
375+
/* Verify both threads maintained their SVE context */
376+
zassert_true(thread1_sve_ok, "User Thread 1 SVE context was corrupted");
377+
zassert_true(thread2_sve_ok, "User Thread 2 SVE context was corrupted");
378+
}
379+
380+
ZTEST(arm64_sve_ctx, test_sve_context_switching_mixed)
381+
{
382+
TC_PRINT("=== Testing SVE Context Switching: User vs Privileged ===\n");
383+
384+
/* Create mixed privilege threads: thread 1 = user, thread 2 = privileged */
385+
k_thread_create(&thread1_data, thread1_stack, STACK_SIZE,
386+
sve_test_thread1, NULL, NULL, NULL,
387+
THREAD_PRIORITY, K_USER, K_NO_WAIT);
388+
k_thread_name_set(&thread1_data, "sve_user_thread1");
389+
390+
/* Grant permission to semaphores for user thread 1 */
391+
k_object_access_grant(&sync_sem, &thread1_data);
392+
k_object_access_grant(&done_sem, &thread1_data);
393+
394+
/* Add thread 1 to memory domain for accessing result variables */
395+
k_mem_domain_add_thread(&sve_test_domain, &thread1_data);
396+
397+
k_thread_create(&thread2_data, thread2_stack, STACK_SIZE,
398+
sve_test_thread2, NULL, NULL, NULL,
399+
THREAD_PRIORITY, 0, K_NO_WAIT);
400+
k_thread_name_set(&thread2_data, "sve_priv_thread2");
401+
402+
/* Privileged thread doesn't need special permissions */
309403

310404
/* Wait for both threads to complete */
311405
k_sem_take(&done_sem, K_FOREVER);
@@ -315,8 +409,8 @@ ZTEST(arm64_sve_ctx, test_sve_context_switching)
315409
k_thread_join(&thread2_data, K_FOREVER);
316410

317411
/* Verify both threads maintained their SVE context */
318-
zassert_true(thread1_sve_ok, "Thread 1 SVE context was corrupted");
319-
zassert_true(thread2_sve_ok, "Thread 2 SVE context was corrupted");
412+
zassert_true(thread1_sve_ok, "User Thread 1 SVE context was corrupted");
413+
zassert_true(thread2_sve_ok, "Privileged Thread 2 SVE context was corrupted");
320414
}
321415

322-
ZTEST_SUITE(arm64_sve_ctx, NULL, sve_ctx_setup, NULL, NULL, NULL);
416+
ZTEST_SUITE(arm64_sve_ctx, NULL, sve_ctx_setup, sve_ctx_before, NULL, NULL);

0 commit comments

Comments
 (0)