@@ -489,20 +489,219 @@ SECTION_FUNC(TEXT, z_arm_svc)
489489 * r8 - saved link register
490490 * /
491491.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 * /
492555#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
496564#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
498577#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}
500590#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+
502636#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:
504694#endif
505695
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+
506705#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
507706 ldr r3 , =K_SYSCALL_LIMIT
508707 cmp r6 , r3
@@ -556,14 +755,12 @@ SECTION_FUNC(TEXT, z_arm_svc)
556755 isb
557756
558757#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
567764
568765 / * return from SVC to the modified LR - z_arm_do_syscall * /
569766 bx lr
0 commit comments