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
5354K_THREAD_STACK_DEFINE (thread1_stack , STACK_SIZE );
@@ -60,9 +61,10 @@ static struct k_thread thread2_data;
6061static struct k_sem sync_sem ;
6162static 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 */
6870static 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 */
122124static 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+
286290static 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