@@ -489,20 +489,219 @@ SECTION_FUNC(TEXT, z_arm_svc)
489
489
* r8 - saved link register
490
490
* /
491
491
.L_do_syscall:
492
+ / *
493
+ * Build a privilege stack frame from the user stack frame , then switch PSP
494
+ * to it. This ensures return from SVC does not rely on the user stack.
495
+ *
496
+ * Layout of privilege stack created from user stack:
497
+ *
498
+ * +------+-------------------------+------+-------------------------+--------------------------+
499
+ * | User stack | Privilege stack | Notes |
500
+ * +------+-------------------------+------+-------------------------+--------------------------+
501
+ * |Offset| contents |Offset| contents | |
502
+ * +------+-------------------------+------+-------------------------+--------------------------+
503
+ * | 0 | R0 - > | 0 | R0 | PSP switches from 0th |
504
+ * | | | | | offset of user stack to |
505
+ * | | | | | 0th offset of priv stack |
506
+ * | 4 | R1 - > | 4 | R1 | |
507
+ * | 8 | R2 - > | 8 | R2 | |
508
+ * | 12 | R3 - > | 12 | R3 | |
509
+ * | 16 | R12 - > | 16 | R12 | |
510
+ * | 20 | LR - > | 20 | LR | |
511
+ * | 24 | Return Address - x> | 24 | z_arm_do_syscall |return address from user |
512
+ * | | | | |sf is not copied. Instead , |
513
+ * | | | | |it is replaced so th at |
514
+ * | | | | |z_arm_svc returns to |
515
+ * | | | | |z_arm_do_syscall. |
516
+ * | | | | | |
517
+ * | 28 | xPSR (w/ or w/o pad) - > | 28 | xPSR (pad bit cleared) |This completes the basic |
518
+ * | | | | |exception sf w/ or w/o pad|
519
+ * | | | | | |
520
+ * | -- | FP regs + FPSCR - > | -- | FP regs + FPSCR |For arch supporting fp |
521
+ * | | (w/ or w/o pad) | | |context an additional |
522
+ * | | | | |extended sf is copied. |
523
+ * |________________________________|______|_________________________|__________________________|
524
+ * | | | | |On returning to |
525
+ * | | | | |z_arm_do_syscall , the |
526
+ * | | | | |above sf has already been |
527
+ * | | | | |unstacked and 8B from the |
528
+ * | | | | |then sf are used to pass |
529
+ * | | | | |original pre - svc sp & the |
530
+ * | | | | |return address. |
531
+ * | | | | |Note: at the moment |
532
+ * | | | | |z_arm_do_syscall also |
533
+ * | | | | |expects the return address|
534
+ * | | | | |to be set in r8 . |
535
+ * | | | | | |
536
+ * | | | 0 | address th at |z_arm_do_syscall expects |
537
+ * | | | | z_arm_do_syscall should |the original pre - svc sp at |
538
+ * | | | | set as PSP before |0th offset i.e. new sp [ 0 ] |
539
+ * | | | | returning from svc. | and , |
540
+ * | | | | | |
541
+ * | | | 4 | Address th at |the return address at |
542
+ * | | | | z_arm_do_syscall should | sp [ 4 ] . Note th at this is |
543
+ * | | | | return to after handling|the return address copied |
544
+ * | | | | svc |from user exception sf [ 24 ] |
545
+ * | | | | |which was not copied in |
546
+ * | | | | |the previous sf. |
547
+ * +------+-------------------------+------+-------------------------+--------------------------+
548
+ * "sf" in this function is used as abbreviation for "stack frame" .
549
+ * Note th at the "FP regs + FPSCR" are only present if CONFIG_FPU_SHARING=y , and the optional pad
550
+ * is only present if PSP was not 8 - byte aligned when SVC was executed.
551
+ * Also note th at FPU cannot be present in ARMv6 - M or ARMv8 - M Baseline implementations
552
+ * (i.e. , it may only be present when CONFIG_ARMV7_M_ARMV8_M_MAINLINE is enabled).
553
+ * /
554
+ / * Start by fetching the top of privileged stack * /
492
555
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
493
- movs r3 , # 24
494
- ldr r1 , [ r0 , r3 ] / * grab address of PC from stack frame * /
495
- mov r8 , r1
556
+ ldr r1 , =_kernel
557
+ ldr r1 , [ r1 , #_kernel_offset_to_current ]
558
+ adds r1 , r1 , #_thread_offset_to_priv_stack_start
559
+ ldr r1 , [ r1 ] / * bottom of priv stack * /
560
+ ldr r3 , =CONFIG_PRIVILEGED_STACK_SIZE
561
+ subs r3 , #(_EXC_HW_SAVED_BASIC_SF_SIZE + 8 ) / * 8 for original sp and pc * /
562
+ add r1 , r3
563
+ mov ip , r1
496
564
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
497
- ldr r8 , [ r0 , # 24 ] / * grab address of PC from stack frame * /
565
+ ldr ip , =_kernel
566
+ ldr ip , [ ip , #_kernel_offset_to_current ]
567
+ ldr ip , [ ip , #_thread_offset_to_priv_stack_start ] / * bottom of priv stack * /
568
+ add ip , #CONFIG_PRIVILEGED_STACK_SIZE
569
+ #ifdef CONFIG_FPU_SHARING
570
+ / * Assess whether svc calling thread had been using the FP registers. * /
571
+ tst lr , #_EXC_RETURN_FTYPE_Msk
572
+ ite eq
573
+ moveq r8 , #_EXC_HW_SAVED_EXTENDED_SF_SIZE
574
+ movne r8 , #_EXC_HW_SAVED_BASIC_SF_SIZE
575
+ #else
576
+ mov r8 , #_EXC_HW_SAVED_BASIC_SF_SIZE
498
577
#endif
499
- ldr r1 , =z_arm_do_syscall
578
+ sub ip , # 8 / * z_arm_do_syscall will use this to get original sp and pc * /
579
+ sub ip , r8 / * 32 for basic sf + 72 for the optional esf * /
580
+ #endif
581
+
582
+ / *
583
+ * At this point:
584
+ * r0 has PSP i.e. top of user stack
585
+ * ip has top of privilege stack
586
+ * r8 has hardware - saved stack frame size (only in case of mainline)
587
+ * /
588
+ push {r4 - r7}
589
+ push {r2}
500
590
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
501
- str r1 , [ r0 , r3 ] / * overwrite the PC to point to z_arm_do_syscall * /
591
+ mov r2 , r0 / * safe to use r2 since it is saved on MSP * /
592
+
593
+ / * Check for padding in the sf * /
594
+ ldr r1 , [ r0 , #_EXC_HW_SAVED_BASIC_SF_XPSR_OFFSET ] / * grab xPSR from sf which has the pad bit * /
595
+ movs r3 , # 1
596
+ / * Check if pad bit 9 is set * /
597
+ lsls r3 , r3 , # 9
598
+ tst r1 , r3
599
+ beq .L_no_padding
600
+ / * special handling for padded sf * /
601
+ bics r1 , r3 / * clear the pad bit (priv stack is aligned and doesn't need it) * /
602
+ adds r2 , # 4
603
+ .L_no_padding:
604
+ / * Calculate original pre - svc user sp which is psp + sf size ( + 4B if pad bit was set) * /
605
+ adds r2 , #_EXC_HW_SAVED_BASIC_SF_SIZE
606
+ mov r3 , ip
607
+ str r2 ,[ r3 , # 0 ]
608
+
609
+ / * Store the pre - SVC user SP at the offset expected by z_arm_do_syscall ,
610
+ * as detailed in the table above.
611
+ * /
612
+ str r2 ,[ r3 , #_EXC_HW_SAVED_BASIC_SF_SIZE ]
613
+ / * sf of priv stack has the same xPSR as user stack but with 9th bit reset * /
614
+ str r1 ,[ r3 , #_EXC_HW_SAVED_BASIC_SF_XPSR_OFFSET ]
615
+
616
+ / * r0 - r3 , r12 , LR from user stack sf are copied to sf of priv stack * /
617
+ mov r1 , r0
618
+ mov r2 , r3
619
+ ldmia r1! , {r4 - r7}
620
+ stmia r2! , {r4 - r7}
621
+ ldmia r1! , {r4 - r5}
622
+ stmia r2! , {r4 - r5}
623
+
624
+ / * Store the svc return address at the offset expected by z_arm_do_syscall ,
625
+ * as detailed in the table above.
626
+ * /
627
+ str r5 , [ r3 , #(_EXC_HW_SAVED_BASIC_SF_SIZE + 4 ) ]
628
+
629
+ ldr r1 , =z_arm_do_syscall
630
+ str r1 , [ r3 , #_EXC_HW_SAVED_BASIC_SF_RETADDR_OFFSET ] / * Execution return to z_arm_do_syscall * /
631
+ ldr r1 , [ r0 , #_EXC_HW_SAVED_BASIC_SF_RETADDR_OFFSET ] / * grab address of PC from stack frame * /
632
+ / * Store the svc return address (i.e. next instr to svc) in r8 as expected by z_arm_do_syscall.
633
+ * /
634
+ mov r8 , r1
635
+
502
636
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
503
- str r1 , [ r0 , # 24 ] / * overwrite the PC to point to z_arm_do_syscall * /
637
+ mov r2 , r0 / * safe to use r2 since it is saved on MSP * /
638
+
639
+ / * Calculate original pre - svc user sp without pad which is psp + sf size * /
640
+ add r2 , r8
641
+
642
+ / * Also , check for padding in the sf * /
643
+ ldr r1 , [ r0 , #_EXC_HW_SAVED_BASIC_SF_XPSR_OFFSET ] / * grab xPSR from sf which has the pad bit * /
644
+ tst r1 , #( 1 << 9 ) / * Check if pad bit 9 is set * /
645
+ beq .L_no_padding
646
+ bics r1 , #( 1 << 9 ) / * clear the pad bit (priv stack is aligned and doesn't need it) * /
647
+ / * Calculate original pre - svc user sp with pad * /
648
+ add r2 , # 4
649
+ .L_no_padding:
650
+ str r2 ,[ ip , # 0 ]
651
+ / * Store the pre - SVC user SP at the offset expected by z_arm_do_syscall ,
652
+ * as detailed in the table above.
653
+ * /
654
+ str r2 ,[ ip , r8 ]
655
+ str r1 ,[ ip , #_EXC_HW_SAVED_BASIC_SF_XPSR_OFFSET ] / * priv sf get user sf xPSR with bit9 reset * /
656
+
657
+ / * r0 - r3 , r12 , LR from user stack sf are copied to sf of priv stack * /
658
+ mov r1 , r0
659
+ mov r2 , ip
660
+ ldmia r1! , {r4 - r7}
661
+ stmia r2! , {r4 - r7}
662
+ ldmia r1! , {r4 - r5}
663
+ stmia r2! , {r4 - r5}
664
+
665
+ / * Store the svc return address at the offset expected by z_arm_do_syscall ,
666
+ * as detailed in the table above.
667
+ * /
668
+ add r8 , # 4
669
+ str r5 , [ ip , r8 ]
670
+
671
+ ldr r1 , =z_arm_do_syscall
672
+ str r1 , [ ip , #_EXC_HW_SAVED_BASIC_SF_RETADDR_OFFSET ] / * Execution return to z_arm_do_syscall * /
673
+ ldr r1 , [ r0 , #_EXC_HW_SAVED_BASIC_SF_RETADDR_OFFSET ] / * grab address of PC from stack frame * /
674
+ / * Store the svc return address (i.e. next instr to svc) in r8 as expected by z_arm_do_syscall.
675
+ * /
676
+ mov r8 , r1
677
+
678
+ / * basic stack frame is copied at this point to privilege stack ,
679
+ * now time to copy the fp context
680
+ * /
681
+ #ifdef CONFIG_FPU_SHARING
682
+ tst lr , #_EXC_RETURN_FTYPE_Msk
683
+ bne .L_skip_fp_copy
684
+ add r1 , r0 , # 32
685
+ add r2 , ip , # 32
686
+
687
+ vldmia r1! , {s0 - s15}
688
+ vstmia r2! , {s0 - s15}
689
+
690
+ / * copy FPSCR + reserved ( 8 bytes) * /
691
+ ldmia r1! , {r4 , r5}
692
+ stmia r2! , {r4 , r5}
693
+ .L_skip_fp_copy:
504
694
#endif
505
695
696
+ #endif
697
+ pop {r2} / * restore CONTROL value * /
698
+ pop {r4 - r7}
699
+
700
+ / * Point PSP to privilege stack ,
701
+ * note th at r0 still has the old PSP
702
+ * /
703
+ msr PSP , ip
704
+
506
705
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
507
706
ldr r3 , =K_SYSCALL_LIMIT
508
707
cmp r6 , r3
@@ -556,14 +755,12 @@ SECTION_FUNC(TEXT, z_arm_svc)
556
755
isb
557
756
558
757
#if defined(CONFIG_BUILTIN_STACK_GUARD)
559
- / * Thread is now in privileged mode ; after returning from SCVall it
560
- * will use the default (user) stack before switching to the privileged
561
- * stack to execute the system call . We need to protect the user stack
562
- * against stack overflows until this stack transition.
563
- * /
564
- ldr r1 , [ r0 , #_thread_offset_to_stack_info_start ] / * stack_info.start * /
565
- msr PSPLIM , r1
566
- #endif / * CONFIG_BUILTIN_STACK_GUARD * /
758
+ / * Set stack pointer limit (needed in privileged mode) * /
759
+ ldr ip , =_kernel
760
+ ldr ip , [ ip , #_kernel_offset_to_current ]
761
+ ldr ip , [ ip , #_thread_offset_to_priv_stack_start ] / * priv stack ptr * /
762
+ msr PSPLIM , ip
763
+ #endif
567
764
568
765
/ * return from SVC to the modified LR - z_arm_do_syscall * /
569
766
bx lr
0 commit comments