7
7
#include <zephyr/ztest.h>
8
8
#include <zephyr/kernel.h>
9
9
#include <zephyr/arch/arm64/lib_helpers.h>
10
+ #include <zephyr/app_memory/app_memdomain.h>
10
11
#include <stdint.h>
11
12
12
13
/* Helper function for SVE vector length */
@@ -47,7 +48,7 @@ ZTEST(arm64_sve_ctx, test_sve_basic_instructions)
47
48
}
48
49
}
49
50
50
- #define STACK_SIZE 1024
51
+ #define STACK_SIZE 4096
51
52
#define THREAD_PRIORITY 1
52
53
53
54
K_THREAD_STACK_DEFINE (thread1_stack , STACK_SIZE );
@@ -60,9 +61,10 @@ static struct k_thread thread2_data;
60
61
static struct k_sem sync_sem ;
61
62
static struct k_sem done_sem ;
62
63
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 ;
66
68
67
69
/* Set unique patterns in SVE Z registers for thread identification */
68
70
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)
121
123
/* Verify SVE Z register patterns */
122
124
static inline bool sve_verify_z_pattern (uint32_t thread_id )
123
125
{
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 );
126
128
uint32_t * actual_p = actual_buffer ;
127
129
uint32_t vl = sve_get_vl ();
128
130
uint32_t expected_base = 0x12340000 | (thread_id & 0xFFF );
@@ -283,29 +285,121 @@ static void sve_test_thread2(void *arg1, void *arg2, void *arg3)
283
285
/*
284
286
* Test suite setup and tests
285
287
*/
288
+ static struct k_mem_domain sve_test_domain ;
289
+
286
290
static void * sve_ctx_setup (void )
287
291
{
288
292
k_sem_init (& sync_sem , 0 , 1 );
289
293
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
+
290
300
return NULL ;
291
301
}
292
302
293
- ZTEST ( arm64_sve_ctx , test_sve_context_switching )
303
+ static void sve_ctx_before ( void * fixture )
294
304
{
295
- /* Reset test results */
305
+ /* Reset test results and semaphores before each test */
296
306
thread1_sve_ok = false;
297
307
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" );
298
315
299
- /* Create threads that will use SVE */
316
+ /* Create privileged kernel threads that will use SVE */
300
317
k_thread_create (& thread1_data , thread1_stack , STACK_SIZE ,
301
318
sve_test_thread1 , NULL , NULL , NULL ,
302
319
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 " );
304
321
305
322
k_thread_create (& thread2_data , thread2_stack , STACK_SIZE ,
306
323
sve_test_thread2 , NULL , NULL , NULL ,
307
324
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 */
309
403
310
404
/* Wait for both threads to complete */
311
405
k_sem_take (& done_sem , K_FOREVER );
@@ -315,8 +409,8 @@ ZTEST(arm64_sve_ctx, test_sve_context_switching)
315
409
k_thread_join (& thread2_data , K_FOREVER );
316
410
317
411
/* 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" );
320
414
}
321
415
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