/** * \brief Function to raise the privilege, used by the assemble code */ static void _RaisePrivilege(void) { /* As this function is called in privilege mode, we don't need to set the privilege mode*/ printf("\n\r-I- Raise to Privilege mode\n\r"); __set_CONTROL(PRIVILEGE_MODE); }
/** * @brief Port-related initialization code. */ void _port_init(void) { /* Initialization of the vector table and priority related settings.*/ SCB_VTOR = CORTEX_VTOR_INIT; SCB_AIRCR = AIRCR_VECTKEY | AIRCR_PRIGROUP(CORTEX_PRIGROUP_INIT); #if CORTEX_USE_FPU { /* Initializing the FPU context save in lazy mode.*/ SCB_FPCCR = FPCCR_ASPEN | FPCCR_LSPEN; /* CP10 and CP11 set to full access.*/ SCB_CPACR |= 0x00F00000; /* Enables FPU context save/restore on exception entry/exit (FPCA bit).*/ __set_CONTROL(__get_CONTROL() | 4); /* FPSCR and FPDSCR initially zero.*/ __set_FPSCR(0); SCB_FPDSCR = 0; } #endif /* Initialization of the system vectors used by the port.*/ nvicSetSystemHandlerPriority(HANDLER_SVCALL, CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_SVCALL)); nvicSetSystemHandlerPriority(HANDLER_PENDSV, CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_PENDSV)); nvicSetSystemHandlerPriority(HANDLER_SYSTICK, CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_SYSTICK)); }
/** * @brief This function handles SVCall exception. * @param None * @retval None */ void SVC_Handler(void) { /* Switch back Thread mode to privileged */ __set_CONTROL(THREAD_MODE_PRIVILEGED | SP_PROCESS); /* Execute ISB instruction to flush pipeline as recommended by Arm */ __ISB(); }
/** * \brief Default SVC interrupt handler. */ void SVC_Handler(void) { /* Set to privilege mode */ __set_CONTROL(PRIVILEGE_MODE); /* Set flag */ dwRaisePriDone = 1; }
/** * @brief This function handles SVCall exception. * @param None * @retval None */ void SVC_Handler(void) { /* Switch back Thread mode to privileged */ __set_CONTROL(2); /* Execute ISB instruction to flush pipeline as recommended by Arm */ __ISB(); }
/*! \brief C part of the SVC exception handler SVC 0 is initializing the OS and starting the scheduler. Each thread stack frame is initialized. \param svc_args Used to extract the SVC number */ void SVC_Handler_C(unsigned int * svc_args) { uint8_t svc_number; svc_number = ((char *) svc_args[6])[-2]; // Memory[(Stacked PC)-2] // marking kernel as busy kernel_busy = 1; switch(svc_number) { //************* SVC( 0 ) OS Start case (0): // OS start // Starting the task scheduler //TWP playing a trick here!? by making curr = next, will make next's stack and current's stack the same stack! // will save (garbage) current register values, and then immediately restore them as next's initial values :-) curr_task = rtr_q_h; // Switch to head ready-to-run task (Current task) // when current task was put in RTRQ its state was set to RUNNING svc_exc_return = HW32_REG(( curr_task->stack_p )); // Return to thread with PSP __set_PSP(( (uint32_t) curr_task->stack_p + 10*4)); // Set PSP to @R0 of task 0 exception stack frame NVIC_SetPriority(PendSV_IRQn, 0xFF); // Set PendSV to lowest possible priority if (SysTick_Config(os_sysTickTicks) != 0) // 1000 Hz SysTick interrupt on 16MHz core clock { stop_cpu2; // Impossible SysTick_Config number of ticks } __set_CONTROL(0x3); // Switch to use Process Stack, unprivileged state __ISB(); // Execute ISB after changing CONTROL (architectural recommendation) break; //************* SVC( 1 ) Thread Yield case (1): // Thread Yield if (curr_task != rtr_q_h) { // Context switching needed ScheduleContextSwitch(); } __ISB(); break; //************* SVC( 2 ) Stack Frame Allocation for First Launch //TWPV6: no longer used! Functionality moved to osThreadCreate ... case left here (for now) case (2): // Stack Allocation __ISB(); break; default: #if ((ENABLE_KERNEL_PRINTF) && (ENABLE_KERNEL_PRINTF == 1)) printf("ERROR: Unknown SVC service number\n\r"); printf("- SVC number 0x%x\n\r", svc_number); #endif stop_cpu2; break; } // end switch // marking kernel as normal kernel_busy = 0; }
static inline void switch_sp_to_psp(void) { __set_CONTROL(__get_CONTROL() | CONTROL_SPSEL_Msk); /* * When changing the stack pointer, software must use an ISB instruction * immediately after the MSR instruction. This ensures that instructions * after the ISB instruction execute using the new stack pointer. */ __ISB(); }
void Init_Cpu(void) { __set_PSP((uint32_t)msp_top); __set_PRIMASK(1); __set_FAULTMASK(1); __set_CONTROL(0); switch(pg_scb_reg->CPUID) { case cn_revision_r0p0: break; //市场没有版本0的芯片 case cn_revision_r1p0: pg_scb_reg->CCR |= 1<<bo_scb_ccr_stkalign; break; case cn_revision_r1p1: pg_scb_reg->CCR |= 1<<bo_scb_ccr_stkalign; break; case cn_revision_r2p0:break; //好像没什么要做的 } pg_inflash_fpec_reg->ACR &= ~(u32)0x1f; pg_inflash_fpec_reg->ACR |= (CN_CFG_MCLK-1)/24000000; //设置等待周期。 pg_inflash_fpec_reg->ACR |= 0x10; //开启预取 if(((pg_rcc_reg->CR & cn_cr_check_mask) != cn_cr_check) || ((pg_rcc_reg->CFGR & cn_cfgr_check_mask) != cn_cfgr_check)) { //开始初始化时钟 //step1:复位时钟控制寄存器 pg_rcc_reg->CR |= (uint32_t)0x00000001; // 复位 SW[1:0], HPRE[3:0], PPRE1[2:0], PPRE2[2:0], ADCPRE[1:0] MCO[2:0] 位 pg_rcc_reg->CFGR &= (uint32_t)0xF8FF0000; // 复位 HSEON, CSSON and PLLON 位 pg_rcc_reg->CR &= (uint32_t)0xFEF6FFFF; // 复位 HSEBYP 位 pg_rcc_reg->CR &= (uint32_t)0xFFFBFFFF; // 复位 PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE 位 pg_rcc_reg->CFGR &= (uint32_t)0xFF80FFFF; // 禁止所有中断 pg_rcc_reg->CIR = 0x00000000; //step2:设置各时钟控制位以及倍频、分频值 pg_rcc_reg->CFGR = cn_cfgr_set+(7<<24); // set clock configuration register pg_rcc_reg->CR = cn_cr_set; // set clock control register while(bb_rcc_cr_hserdy ==0); while(bb_rcc_cr_pllrdy ==0); } SRAM_Init(); Load_Preload(); }
/** \brief Test case: TC_CoreFunc_MSP \details - Check if __get_MSP and __set_MSP intrinsic can be used to manipulate main stack pointer. */ void TC_CoreFunc_MSP (void) { // don't use stack for this variables static uint32_t orig; static uint32_t msp; static uint32_t result; static uint32_t ctrl; ctrl = __get_CONTROL(); __set_CONTROL(ctrl | CONTROL_SPSEL_Msk); // switch to PSP orig = __get_MSP(); msp = orig + 0x12345678U; __set_MSP(msp); result = __get_MSP(); __set_MSP(orig); __set_CONTROL(ctrl); ASSERT_TRUE(result == msp); }
void jump_to_ns_code(void) { #if TFM_LVL != 1 /* Initialization is done, set thread mode to unprivileged. */ CONTROL_Type ctrl; ctrl.w = __get_CONTROL(); ctrl.b.nPRIV = 1; __set_CONTROL(ctrl.w); #endif /* All changes made to memory will be effective after this point */ __DSB(); __ISB(); /* Calls the non-secure Reset_Handler to jump to the non-secure binary */ ns_entry(); }
FUNC (void, OS_CODE) tpl_init_machine_specific (void) { nested_kernel_entrance_counter = 0; tpl_set_systick_timer(); tpl_init_external_interrupts(); /* * Switch to use PSP, unprivileged state */ __set_CONTROL(0x3); /* * Instruction SynchronizationBarrier * Execute ISB after changing CONTROL (architectural recommendation) */ __ISB(); /* Set SVCall priority to 2 */ // NVIC_SetPriority(SVCall_IRQn, 2); }
/* call scheduler so active_thread points to the next task */ void sched_task_return(void) { /* switch to user mode use PSP insteat of MSP in ISR Mode*/ CONTROL_Type mode; mode.w = __get_CONTROL(); mode.b.SPSEL = 1; // select PSP mode.b.nPRIV = 0; // privilege __set_CONTROL(mode.w); /* load pdc->stackpointer in r0 */ asm("ldr r0, =active_thread"); /* r0 = &active_thread */ asm("ldr r0, [r0]"); /* r0 = *r0 = active_thread */ asm("ldr sp, [r0]"); /* sp = r0 restore stack pointer*/ asm("pop {r4}"); /* skip exception return */ asm("pop {r4-r11}"); asm("pop {r0-r3,r12,lr}"); /* simulate register restor from stack */ asm("pop {pc}"); }
void Reset_Handler( void ) { #if main_stack_size + proc_stack_size > 0 /* Initialize the process stack pointer */ __set_PSP((unsigned)__initial_sp); __set_CONTROL(CONTROL_SPSEL_Msk); #endif #if __FPU_USED /* Set CP10 and CP11 Full Access */ SCB->CPACR = 0x00F00000U; #endif #ifndef __NO_SYSTEM_INIT /* Call the system clock intitialization function */ SystemInit(); #endif /* Call the application's entry point */ __main(); }
void nOS_InitSpecific(void) { #if (NOS_CONFIG_DEBUG > 0) size_t i; for (i = 0; i < NOS_CONFIG_ISR_STACK_SIZE; i++) { _isrStack[i] = 0xFFFFFFFFUL; } #endif /* Copy MSP to PSP */ __set_PSP(__get_MSP()); /* Set MSP to local ISR stack */ __set_MSP((uint32_t)&_isrStack[NOS_CONFIG_ISR_STACK_SIZE] & 0xFFFFFFF8UL); /* Set current stack to PSP and privileged mode */ __set_CONTROL(__get_CONTROL() | 0x00000002UL); /* Set PendSV exception to lowest priority */ *(volatile uint32_t *)0xE000ED20UL |= 0x00FF0000UL; }
/**************************************************************************//** * @brief Memory protection fault second level exception handler. *****************************************************************************/ void MemManage_HandlerC( uint32_t *stack ) { static char text[ 80 ], s[ 5 ]; uint32_t pc; pc = stack[6]; /* Get stacked return address */ strcpy( text, " MPU FAULT AT PC 0x" ); s[ 0 ] = Hex2Char( pc >> 12 ); s[ 1 ] = Hex2Char( pc >> 8 ); s[ 2 ] = Hex2Char( pc >> 4 ); s[ 3 ] = Hex2Char( pc ); s[ 4 ] = '\0'; strcat( text, s ); strcat( text, " " ); ScrollText( text ); SCB->CFSR |= 0xFF; /* Clear all status bits in the */ /* MMFSR part of CFSR */ __set_CONTROL( 0 ); /* Enter Priviledged state before exit */ }
/**************************************************************************//** * @brief Memory protection fault second level exception handler. *****************************************************************************/ void MemManage_HandlerC( uint32_t *stack ) { static uint32_t mmfar, pc, shcsr, cfsr; mmfar = SCB->MMFAR; /* Memory Management Fault Address Register */ cfsr = SCB->CFSR; /* Configurable Fault Status Register */ shcsr = SCB->SHCSR; /* System Handler Control and State Register */ pc = stack[6]; /* Get stacked return address */ printf( "\nMPU fault !\n" " Violation memory address : 0x%"PRIX32"\n" " Violation program counter : 0x%"PRIX32"\n" " System Control Block (SCB) registers: \n" " SCB->SHCSR = 0x%"PRIX32"\n" " SCB->CFSR = 0x%"PRIX32"\n" " SCB->MMFAR = 0x%"PRIX32"\n", mmfar, pc, shcsr, cfsr, mmfar ); SCB->CFSR |= 0xFF; /* Clear all status bits in the */ /* MMFSR part of CFSR */ __set_CONTROL( 0 ); /* Enter Priviledged state before exit */ }
// ============================================================================= // 功能:CORTEX M3内核启动函数,系统复位启动后,从汇编向量表跳转到C的第一个函数。函数 // 会初始化主堆栈和用户堆栈,配置内核寄存器,然后初始化时钟模块。 // 参数:无 // 返回:无 // ============================================================================= void Init_Cpu(void) { __set_PSP((uint32_t)msp_top); __set_PRIMASK(1); __set_FAULTMASK(1); __set_CONTROL(0); switch(pg_scb_reg->CPUID) { case cn_revision_r0p0: break; //市场没有版本0的芯片 case cn_revision_r1p0: pg_scb_reg->CCR |= 1<<bo_scb_ccr_stkalign; break; case cn_revision_r1p1: pg_scb_reg->CCR |= 1<<bo_scb_ccr_stkalign; break; case cn_revision_r2p0:break; //好像没什么要做的 } SystemInit(); Load_Preload(); return; }
/** * \brief Update MPU regions. * * \return Unused (ANSI-C compatibility). */ static void _UpdateMPU( uint32_t dwRegionNum, uint32_t dwRegionBaseAddr, uint32_t dwRegionAttr) { /* Raise privilege, the MPU register could be set only in privilege mode */ __ASM volatile(" svc 0x00 "); while (!dwRaisePriDone); dwRaisePriDone = 0; /* Disable interrupt */ __disable_irq(); /* Clean up data and instruction buffer */ __DSB(); __ISB(); /* Set active region */ MPU_SetRegionNum(dwRegionNum); /* Disable region */ MPU_DisableRegion(); /* Update region attribute */ MPU_SetRegion( dwRegionBaseAddr, dwRegionAttr); /* Clean up data and instruction buffer to make the new region taking effect at once */ __DSB(); __ISB(); /* Enable the interrupt */ __enable_irq(); /* Reset to thread mode */ __set_CONTROL(USER_MODE); }
/** * @brief Main program. * @param None * @retval None */ int main(void) { /*!< At this stage the microcontroller clock setting is already configured, this is done through SystemInit() function which is called from startup file (startup_stm32f10x_xx.s) before to branch to application main. To reconfigure the default setting of SystemInit() function, refer to system_stm32f10x.c file */ /* Switch Thread mode Stack from Main to Process -----------------------------*/ /* Initialize memory reserved for Process Stack */ for(Index = 0; Index < SP_PROCESS_SIZE; Index++) { PSPMemAlloc[Index] = 0x00; } /* Set Process stack value */ __set_PSP((uint32_t)PSPMemAlloc + SP_PROCESS_SIZE); /* Select Process Stack as Thread mode Stack */ __set_CONTROL(SP_PROCESS); /* Get the Thread mode stack used */ if((__get_CONTROL() & 0x02) == SP_MAIN) { /* Main stack is used as the current stack */ CurrentStack = SP_MAIN; } else { /* Process stack is used as the current stack */ CurrentStack = SP_PROCESS; /* Get process stack pointer value */ PSPValue = __get_PSP(); } /* Switch Thread mode from privileged to unprivileged ------------------------*/ /* Thread mode has unprivileged access */ __set_CONTROL(THREAD_MODE_UNPRIVILEGED | SP_PROCESS); /* Unprivileged access mainly affect ability to: - Use or not use certain instructions such as MSR fields - Access System Control Space (SCS) registers such as NVIC and SysTick */ /* Check Thread mode privilege status */ if((__get_CONTROL() & 0x01) == THREAD_MODE_PRIVILEGED) { /* Thread mode has privileged access */ ThreadMode = THREAD_MODE_PRIVILEGED; } else { /* Thread mode has unprivileged access*/ ThreadMode = THREAD_MODE_UNPRIVILEGED; } /* Switch back Thread mode from unprivileged to privileged -------------------*/ /* Try to switch back Thread mode to privileged (Not possible, this can be done only in Handler mode) */ __set_CONTROL(THREAD_MODE_PRIVILEGED | SP_PROCESS); /* Generate a system call exception, and in the ISR switch back Thread mode to privileged */ __SVC(); /* Check Thread mode privilege status */ if((__get_CONTROL() & 0x01) == THREAD_MODE_PRIVILEGED) { /* Thread mode has privileged access */ ThreadMode = THREAD_MODE_PRIVILEGED; } else { /* Thread mode has unprivileged access*/ ThreadMode = THREAD_MODE_UNPRIVILEGED; } while (1) { } }
/**************************************************************************//** * @brief Main function *****************************************************************************/ int main(void) { int c; MPU_RegionInit_TypeDef flashInit = MPU_INIT_FLASH_DEFAULT; MPU_RegionInit_TypeDef sramInit = MPU_INIT_SRAM_DEFAULT; MPU_RegionInit_TypeDef peripheralInit = MPU_INIT_PERIPHERAL_DEFAULT; /* Chip revision alignment and errata fixes */ CHIP_Init(); /* Initialize DK board register access */ BSP_Init(BSP_INIT_DK_SPI); /* If first word of user data page is non-zero, enable eA Profiler trace */ BSP_TraceProfilerSetup(); /* Enable printf on RS232 port - this example only supports LEUART */ RETARGET_SerialInit(); RETARGET_SerialCrLf(1); printf("\nEFM32 MPU access violation example.\n" "Hit lowercase 'x' to force access violations.\n"); MPU_Disable(); /* Flash memory */ MPU_ConfigureRegion( &flashInit ); /* SRAM */ MPU_ConfigureRegion( &sramInit ); /* SRAM, a 4k part with priviledged only access, this regions settings */ /* will override those of the previous region */ sramInit.regionNo = 2; sramInit.baseAddress = RAM_MEM_BASE + 0x2000; sramInit.size = mpuRegionSize4Kb; sramInit.accessPermission = mpuRegionApPRw; MPU_ConfigureRegion( &sramInit ); /* LEUART, priviledged only access */ peripheralInit.regionNo = 3; peripheralInit.baseAddress = LEUART1_BASE; peripheralInit.size = mpuRegionSize128b; peripheralInit.accessPermission = mpuRegionApPRw; MPU_ConfigureRegion( &peripheralInit ); MPU_Enable( MPU_CTRL_PRIVDEFENA ); /* Full access to default memory map */ /* in priviledged state */ while (1) { EMU_EnterEM2(true); /* Retrieve new character */ c = getchar(); if (c > 0) { if ( c == 'x' ) { /* Generate an access violation in LEUART1 peripheral */ __set_CONTROL( 1 ); /* Enter User (unpriviledged) state */ putchar( c ); /* MemManage_Handler() will set back to priviledged state */ /* Generate an access violation in internal SRAM */ __set_CONTROL( 1 ); /* Enter User (unpriviledged) state */ *(volatile uint32_t *)(RAM_MEM_BASE + 0x2000) = 1; /* MemManage_Handler() will set back to priviledged state */ } else { /* Echo character */ putchar(c); } } /* Most terminals issue CR when pressing enter, add LF */ if (c == '\r') { putchar('\n'); } } }
/*! \brief C part of the SVC exception handler SVC 0 is initializing the OS and starting the scheduler. Each thread stack frame is initialized. \param svc_args Used to extract the SVC number */ void SVC_Handler_C(unsigned int * svc_args) { uint8_t svc_number, i; svc_number = ((char *) svc_args[6])[-2]; // Memory[(Stacked PC)-2] // marking kernel as busy kernel_busy = 1; switch(svc_number) { case (0): // OS start // Starting the task scheduler // Update thread to be run based on priority scheduler(); curr_task = next_task; // Switch to head ready-to-run task (Current task) th_q_h = curr_task; th_q[curr_task]->status = TH_RUNNING; if (PSP_array[curr_task] == NULL) { // Stack not allocated for current task, allocating i = curr_task; th_q[i]->stack_p = (uint32_t) task_stack[i]; PSP_array[i] = ((unsigned int) th_q[i]->stack_p) + (th_q[i]->stack_size) - 18*4; HW32_REG((PSP_array[i] + (16<<2))) = (unsigned long) th_q[i]->start_p; // initial Program Counter HW32_REG((PSP_array[i] + (17<<2))) = 0x01000000; // initial xPSR HW32_REG((PSP_array[i] )) = 0xFFFFFFFDUL; // initial EXC_RETURN HW32_REG((PSP_array[i] + ( 1<<2))) = 0x3;// initial CONTROL : unprivileged, PSP th_q[i]->stack_p = PSP_array[i]; } svc_exc_return = HW32_REG((PSP_array[curr_task])); // Return to thread with PSP __set_PSP((PSP_array[curr_task] + 10*4)); // Set PSP to @R0 of task 0 exception stack frame NVIC_SetPriority(PendSV_IRQn, 0xFF); // Set PendSV to lowest possible priority if (SysTick_Config(os_sysTickTicks) != 0) // 1000 Hz SysTick interrupt on 16MHz core clock { stop_cpu2; // Impossible SysTick_Config number of ticks } __set_CONTROL(0x3); // Switch to use Process Stack, unprivileged state __ISB(); // Execute ISB after changing CONTROL (architectural recommendation) break; case (1): // Thread Yield // Run scheduler to determine if a context switch is needed scheduler(); if (curr_task != next_task) { // Context switching needed ScheduleContextSwitch(); } __ISB(); break; case (2): // Stack Allocation // Create stack frame for thread i = svc_args[0]; th_q[i]->stack_p = (uint32_t) task_stack[i]; PSP_array[i] = ((unsigned int) th_q[i]->stack_p) + (th_q[i]->stack_size) - 18*4; HW32_REG((PSP_array[i] + (16<<2))) = (unsigned long) th_q[i]->start_p; // initial Program Counter HW32_REG((PSP_array[i] + (17<<2))) = 0x01000000; // initial xPSR HW32_REG((PSP_array[i] )) = 0xFFFFFFFDUL; // initial EXC_RETURN HW32_REG((PSP_array[i] + ( 1<<2))) = 0x3;// initial CONTROL : unprivileged, PSP th_q[i]->stack_p = PSP_array[i]; __ISB(); break; default: #if ((ENABLE_KERNEL_PRINTF) && (ENABLE_KERNEL_PRINTF == 1)) printf("ERROR: Unknown SVC service number\n\r"); printf("- SVC number 0x%x\n\r", svc_number); #endif stop_cpu2; break; } // end switch // marking kernel as normal kernel_busy = 0; }
/** * @brief This function handles SVCall exception. * @param None * @retval None */ void SVC_Handler(void) { /* Switch back Thread mode to privileged */ __set_CONTROL(2); }
void SVC_Handler(void) { __set_CONTROL(2); // Control 레지스터에 0x02를 대입한다. 즉, 스택포인터를 PSP로 설정하고, Privileged 모드로 설정 }
/** * @brief Change the mode privilege to unprivilege */ void BSP_Set_UnprivilegeMode(void) { __set_CONTROL((priviledge_status & THREAD_PRIVILEDGED_MASK)|THREAD_UNPRIVILEGED); }
static int32_t tfm_start_partition(const struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn) { uint32_t caller_partition_idx = desc_ptr->caller_part_idx; const struct spm_partition_runtime_data_t *curr_part_data; uint32_t caller_flags; register uint32_t partition_idx; uint32_t psp = __get_PSP(); uint32_t partition_psp, partition_psplim; uint32_t partition_state; uint32_t partition_flags; struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp; uint32_t caller_partition_id; int32_t client_id; struct iovec_args_t *iovec_args; caller_flags = tfm_spm_partition_get_flags(caller_partition_idx); /* Check partition state consistency */ if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0) != (!desc_ptr->ns_caller)) { /* Partition state inconsistency detected */ return TFM_SECURE_LOCK_FAILED; } if((caller_flags & SPM_PART_FLAG_APP_ROT) == 0) { /* Disable NS exception handling while secure service is running. * FixMe: * This restriction is applied to limit the number of possible attack * vectors. * To be removed when pre-emption and context management issues have * been analysed and resolved. */ TFM_NS_EXC_DISABLE(); } partition_idx = get_partition_idx(desc_ptr->sp_id); curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx); partition_state = curr_part_data->partition_state; partition_flags = tfm_spm_partition_get_flags(partition_idx); caller_partition_id = tfm_spm_partition_get_partition_id( caller_partition_idx); if (tfm_secure_api_initializing) { #if TFM_LVL != 1 /* Make thread mode unprivileged while untrusted partition init is * executed */ if ((partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) { CONTROL_Type ctrl; ctrl.w = __get_CONTROL(); ctrl.b.nPRIV = 1; __set_CONTROL(ctrl.w); __DSB(); __ISB(); } #endif } else if (partition_state == SPM_PARTITION_STATE_RUNNING || partition_state == SPM_PARTITION_STATE_SUSPENDED || partition_state == SPM_PARTITION_STATE_BLOCKED) { /* Recursion is not permitted! */ return TFM_ERROR_PARTITION_NON_REENTRANT; } else if (partition_state != SPM_PARTITION_STATE_IDLE) { /* The partition to be called is not in a proper state */ return TFM_SECURE_LOCK_FAILED; } #if TFM_LVL == 1 /* Prepare switch to shared secure partition stack */ /* In case the call is coming from the non-secure world, we save the iovecs * on the stop of the stack. So the memory area, that can actually be used * as stack by the partitions starts at a lower address */ partition_psp = (uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)- sizeof(struct iovec_args_t); partition_psplim = (uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base); #else partition_psp = curr_part_data->stack_ptr; partition_psplim = tfm_spm_partition_get_stack_bottom(partition_idx); #endif /* Store the context for the partition call */ tfm_spm_partition_set_caller_partition_idx(partition_idx, caller_partition_idx); tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn); if ((caller_flags & SPM_PART_FLAG_APP_ROT)) { tfm_spm_partition_set_caller_client_id(partition_idx, caller_partition_id); } else { client_id = tfm_nspm_get_current_client_id(); if (client_id >= 0) { return TFM_SECURE_LOCK_FAILED; } tfm_spm_partition_set_caller_client_id(partition_idx, client_id); } #if (TFM_LVL != 1) && (TFM_LVL != 2) /* Dynamic partitioning is only done is TFM level 3 */ tfm_spm_partition_sandbox_deconfig(caller_partition_idx); /* Configure partition execution environment */ if (tfm_spm_partition_sandbox_config(partition_idx) != SPM_ERR_OK) { ERROR_MSG("Failed to configure sandbox for partition!"); tfm_secure_api_error_handler(); } #endif /* Default share to scratch area in case of partition to partition calls * this way partitions always get default access to input buffers */ /* FixMe: return value/error handling TBD */ tfm_spm_partition_set_share(partition_idx, desc_ptr->ns_caller ? TFM_BUFFER_SHARE_NS_CODE : TFM_BUFFER_SHARE_SCRATCH); #if TFM_LVL == 1 /* In level one, only switch context and return from exception if in * handler mode */ if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) { if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) { /* Save the iovecs on the common stack. The vectors had been sanity * checked already, and since then the interrupts have been kept * disabled. So we can be sure that the vectors haven't been * tampered with since the check. */ iovec_args = (struct iovec_args_t *) ((uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)- sizeof(struct iovec_args_t)); if (tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args) != SPM_ERR_OK) { return TFM_ERROR_GENERIC; } tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args)); /* Prepare the partition context, update stack ptr */ psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr, iovec_args, (uint32_t *)partition_psp); } else { /* Prepare the partition context, update stack ptr */ psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr, (uint32_t *)partition_psp); } __set_PSP(psp); __set_PSPLIM(partition_psplim); } #else if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) { /* Save the iovecs on the stack of the partition. The vectors had been * sanity checked already, and since then the interrupts have been kept * disabled. So we can be sure that the vectors haven't been tampered * with since the check. */ iovec_args = (struct iovec_args_t *)(tfm_spm_partition_get_stack_top(partition_idx) - sizeof(struct iovec_args_t)); if (tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args) != SPM_ERR_OK) { return TFM_ERROR_GENERIC; } tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args)); /* Prepare the partition context, update stack ptr */ psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr, iovec_args, (uint32_t *)partition_psp); } else { /* Prepare the partition context, update stack ptr */ psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr, (uint32_t *)partition_psp); } __set_PSP(psp); __set_PSPLIM(partition_psplim); #endif tfm_spm_partition_set_state(caller_partition_idx, SPM_PARTITION_STATE_BLOCKED); tfm_spm_partition_set_state(partition_idx, SPM_PARTITION_STATE_RUNNING); tfm_secure_lock++; return TFM_SUCCESS; }
/** * @brief Main program. * @param None * @retval None */ int main(void) { /* STM32F4xx HAL library initialization: - Configure the Flash prefetch - Systick timer is configured by default as source of time base, but user can eventually implement his proper time base source (a general purpose timer for example or other time source), keeping in mind that Time base duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and handled in milliseconds basis. - Set NVIC Group Priority to 4 - Low Level Initialization */ HAL_Init(); /* Configure the system clock to have a system clock = 180 MHz */ SystemClock_Config(); /* Configure LED1*/ BSP_LED_Init(LED1); /* Switch Thread mode Stack from Main to Process -----------------------------*/ /* Initialize memory reserved for Process Stack */ for(Index = 0; Index < SP_PROCESS_SIZE; Index++) { PSPMemAlloc[Index] = 0x00; } /* Set Process stack value */ __set_PSP((uint32_t)PSPMemAlloc + SP_PROCESS_SIZE); /* Select Process Stack as Thread mode Stack */ __set_CONTROL(SP_PROCESS); /* Execute ISB instruction to flush pipeline as recommended by Arm */ __ISB(); /* Get the Thread mode stack used */ if((__get_CONTROL() & 0x02) == SP_MAIN) { /* Main stack is used as the current stack */ CurrentStack = SP_MAIN; } else { /* Process stack is used as the current stack */ CurrentStack = SP_PROCESS; /* Get process stack pointer value */ PSPValue = __get_PSP(); } /* Switch Thread mode from privileged to unprivileged ------------------------*/ /* Thread mode has unprivileged access */ __set_CONTROL(THREAD_MODE_UNPRIVILEGED | SP_PROCESS); /* Execute ISB instruction to flush pipeline as recommended by Arm */ __ISB(); /* Unprivileged access mainly affect ability to: - Use or not use certain instructions such as MSR fields - Access System Control Space (SCS) registers such as NVIC and SysTick */ /* Check Thread mode privilege status */ if((__get_CONTROL() & 0x01) == THREAD_MODE_PRIVILEGED) { /* Thread mode has privileged access */ ThreadMode = THREAD_MODE_PRIVILEGED; } else { /* Thread mode has unprivileged access*/ ThreadMode = THREAD_MODE_UNPRIVILEGED; } /* Switch back Thread mode from unprivileged to privileged -------------------*/ /* Try to switch back Thread mode to privileged (Not possible, this can be done only in Handler mode) */ __set_CONTROL(THREAD_MODE_PRIVILEGED | SP_PROCESS); /* Execute ISB instruction to flush pipeline as recommended by Arm */ __ISB(); /* Generate a system call exception, and in the ISR switch back Thread mode to privileged */ __SVC(); /* Check Thread mode privilege status */ if((__get_CONTROL() & 0x01) == THREAD_MODE_PRIVILEGED) { /* Thread mode has privileged access */ ThreadMode = THREAD_MODE_PRIVILEGED; } else { /* Thread mode has unprivileged access*/ ThreadMode = THREAD_MODE_UNPRIVILEGED; } /* Infinite loop */ while (1) { /* Turn ON LED once test finished */ BSP_LED_On(LED1); } }
static int32_t tfm_return_from_partition(uint32_t *excReturn) { uint32_t current_partition_idx = tfm_spm_partition_get_running_partition_idx(); const struct spm_partition_runtime_data_t *curr_part_data, *ret_part_data; uint32_t current_partition_flags; uint32_t return_partition_idx; uint32_t return_partition_flags; uint32_t psp = __get_PSP(); size_t i; struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp; struct iovec_args_t *iovec_args; if (current_partition_idx == SPM_INVALID_PARTITION_IDX) { return TFM_SECURE_UNLOCK_FAILED; } curr_part_data = tfm_spm_partition_get_runtime_data(current_partition_idx); return_partition_idx = curr_part_data->caller_partition_idx; if (return_partition_idx == SPM_INVALID_PARTITION_IDX) { return TFM_SECURE_UNLOCK_FAILED; } ret_part_data = tfm_spm_partition_get_runtime_data(return_partition_idx); return_partition_flags = tfm_spm_partition_get_flags(return_partition_idx); current_partition_flags = tfm_spm_partition_get_flags( current_partition_idx); tfm_secure_lock--; if((return_partition_flags & SPM_PART_FLAG_APP_ROT) == 0) { /* Re-enable NS exceptions when secure service returns to NS client. * FixMe: * To be removed when pre-emption and context management issues have * been analysed and resolved. */ TFM_NS_EXC_ENABLE(); } #if (TFM_LVL != 1) && (TFM_LVL != 2) /* Deconfigure completed partition environment */ tfm_spm_partition_sandbox_deconfig(current_partition_idx); if (tfm_secure_api_initializing) { /* Restore privilege for thread mode during TF-M init. This is only * have to be done if the partition is not trusted. */ if ((current_partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) { CONTROL_Type ctrl; ctrl.w = __get_CONTROL(); ctrl.b.nPRIV = 0; __set_CONTROL(ctrl.w); __DSB(); __ISB(); } } else { /* Configure the caller partition environment in case this was a * partition to partition call and returning to untrusted partition */ if (tfm_spm_partition_sandbox_config(return_partition_idx) != SPM_ERR_OK) { ERROR_MSG("Failed to configure sandbox for partition!"); tfm_secure_api_error_handler(); } if (return_partition_flags & SPM_PART_FLAG_APP_ROT) { /* Restore share status */ tfm_spm_partition_set_share( return_partition_idx, tfm_spm_partition_get_runtime_data( return_partition_idx)->share); } } #endif #if TFM_LVL == 1 if (!(return_partition_flags & SPM_PART_FLAG_APP_ROT) || (tfm_secure_api_initializing)) { /* In TFM level 1 context restore is only done when * returning to NS or after initialization */ /* Restore caller context */ restore_caller_ctx(svc_ctx, (struct tfm_exc_stack_t *)ret_part_data->stack_ptr); *excReturn = ret_part_data->lr; __set_PSP(ret_part_data->stack_ptr); extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[]; uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base; __set_PSPLIM(psp_stack_bottom); /* FIXME: The condition should be removed once all the secure service * calls are done via the iovec veneers */ if (curr_part_data->iovec_api) { iovec_args = (struct iovec_args_t *) ((uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)- sizeof(struct iovec_args_t)); for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) { curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len; } tfm_clear_iovec_parameters(iovec_args); } } #else /* Restore caller context */ restore_caller_ctx(svc_ctx, (struct tfm_exc_stack_t *)ret_part_data->stack_ptr); *excReturn = ret_part_data->lr; __set_PSP(ret_part_data->stack_ptr); __set_PSPLIM(tfm_spm_partition_get_stack_bottom(return_partition_idx)); /* Clear the context entry before returning */ tfm_spm_partition_set_stack( current_partition_idx, psp + sizeof(struct tfm_exc_stack_t)); /* FIXME: The condition should be removed once all the secure service * calls are done via the iovec veneers */ if (curr_part_data->iovec_api) { iovec_args = (struct iovec_args_t *) (tfm_spm_partition_get_stack_top(current_partition_idx) - sizeof(struct iovec_args_t)); for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) { curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len; } tfm_clear_iovec_parameters(iovec_args); } #endif tfm_spm_partition_cleanup_context(current_partition_idx); tfm_spm_partition_set_state(current_partition_idx, SPM_PARTITION_STATE_IDLE); tfm_spm_partition_set_state(return_partition_idx, SPM_PARTITION_STATE_RUNNING); return TFM_SUCCESS; }
/** * @brief Change mode to privilege handler */ void SVC_Handler(void) { /* Change Thread mode to privileged */ __set_CONTROL(2); }
/**************************************************************************//** * @brief Main function. *****************************************************************************/ int main( void ) { int i; MPU_RegionInit_TypeDef flashInit = MPU_INIT_FLASH_DEFAULT; MPU_RegionInit_TypeDef sramInit = MPU_INIT_SRAM_DEFAULT; MPU_RegionInit_TypeDef peripheralInit = MPU_INIT_PERIPHERAL_DEFAULT; /* Chip alignment */ CHIP_Init(); /* If first word of user data page is non-zero, enable eA Profiler trace */ BSP_TraceProfilerSetup(); /* Enable LCD without voltage boost */ SegmentLCD_Init( false ); SegmentLCD_AllOff(); SegmentLCD_Symbol(LCD_SYMBOL_GECKO, 1); SegmentLCD_Symbol(LCD_SYMBOL_EFM32, 1); GpioInit(); RTCDRV_Setup( cmuSelect_LFXO, cmuClkDiv_32); ScrollText( " MPU DEMO PRESS Pb0 OR Pb1 " "TO GENERATE MPU EXCEPTIONS " ); MPU_Disable(); /* Flash memory */ MPU_ConfigureRegion( &flashInit ); /* SRAM */ MPU_ConfigureRegion( &sramInit ); /* SRAM, a 4k part with priviledged only access, this regions settings */ /* will override those of the previous region */ sramInit.regionNo = 2; sramInit.baseAddress = RAM_MEM_BASE + 0x2000; sramInit.size = mpuRegionSize4Kb; sramInit.accessPermission = mpuRegionApPRw; MPU_ConfigureRegion( &sramInit ); /* LCD, priviledged only access */ peripheralInit.regionNo = 3; peripheralInit.baseAddress = LCD_BASE; peripheralInit.size = mpuRegionSize128b; peripheralInit.accessPermission = mpuRegionApPRw; MPU_ConfigureRegion( &peripheralInit ); MPU_Enable( MPU_CTRL_PRIVDEFENA ); /* Full access to default memory map */ /* in priviledged state */ i = 0; while ( 1 ) { SegmentLCD_Number( i ); /* Count on numeric diplay */ i = ( i + 1 ) % 101; RTCDRV_Delay( 150 , false); if ( PB0_PUSHED() ) { BullsEye( 1 ); /* Generate an access violation in internal SRAM */ __set_CONTROL( 1 ); /* Enter User (unpriviledged) state */ *(volatile uint32_t *)(RAM_MEM_BASE + 0x2000) = 1; BullsEye( 0 ); } if ( PB1_PUSHED() ) { BullsEye( 1 ); /* Generate an access violation in LCD peripheral */ __set_CONTROL( 1 ); /* Enter User (unpriviledged) state */ BullsEye( 0 ); } } }
/** * @brief Main program * @param None * @retval None */ int main(void) { /* STM32F4xx HAL library initialization: - Configure the Flash prefetch, instruction and Data caches - Configure the Systick to generate an interrupt each 1 msec - Set NVIC Group Priority to 4 - Global MSP (MCU Support Package) initialization */ HAL_Init(); /* Configure the system clock to 180 MHz */ SystemClock_Config(); /* Switch Thread mode Stack from Main to Process ###########################*/ /* Initialize memory reserved for Process Stack */ for(Index = 0; Index < SP_PROCESS_SIZE; Index++) { PSPMemAlloc[Index] = 0x00; } /* Set Process stack value */ __set_PSP((uint32_t)PSPMemAlloc + SP_PROCESS_SIZE); /* Select Process Stack as Thread mode Stack */ __set_CONTROL(SP_PROCESS); /* Execute ISB instruction to flush pipeline as recommended by Arm */ __ISB(); /* Get the Thread mode stack used */ if((__get_CONTROL() & 0x02) == SP_MAIN) { /* Main stack is used as the current stack */ CurrentStack = SP_MAIN; } else { /* Process stack is used as the current stack */ CurrentStack = SP_PROCESS; /* Get process stack pointer value */ PSPValue = __get_PSP(); } /* Switch Thread mode from privileged to unprivileged ######################*/ /* Thread mode has unprivileged access */ __set_CONTROL(THREAD_MODE_UNPRIVILEGED | SP_PROCESS); /* Execute ISB instruction to flush pipeline as recommended by Arm */ __ISB(); /* Unprivileged access mainly affect ability to: - Use or not use certain instructions such as MSR fields - Access System Control Space (SCS) registers such as NVIC and SysTick */ /* Check Thread mode privilege status */ if((__get_CONTROL() & 0x01) == THREAD_MODE_PRIVILEGED) { /* Thread mode has privileged access */ ThreadMode = THREAD_MODE_PRIVILEGED; } else { /* Thread mode has unprivileged access*/ ThreadMode = THREAD_MODE_UNPRIVILEGED; } /* Switch back Thread mode from unprivileged to privileged #################*/ /* Try to switch back Thread mode to privileged (Not possible, this can be done only in Handler mode) */ __set_CONTROL(THREAD_MODE_PRIVILEGED | SP_PROCESS); /* Execute ISB instruction to flush pipeline as recommended by Arm */ __ISB(); /* Generate a system call exception, and in the ISR switch back Thread mode to privileged */ __SVC(); /* Check Thread mode privilege status */ if((__get_CONTROL() & 0x01) == THREAD_MODE_PRIVILEGED) { /* Thread mode has privileged access */ ThreadMode = THREAD_MODE_PRIVILEGED; } else { /* Thread mode has unprivileged access */ ThreadMode = THREAD_MODE_UNPRIVILEGED; } /* Infinite loop */ while (1) { } }