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