/*! * \brief This function sets up the stack frame of a new task descriptor. * * \param[in] td_ptr the address of the task descriptor * \param[in] stack_ptr the address of the stack memory block * \param[in] stack_size the size of the stack * \param[in] template_ptr the task's template * \param[in] status_register the status register to use in creating the task * \param[in] create_parameter the task creation parameter */ bool _psp_build_stack_frame ( /* [IN] the address of the task descriptor */ TD_STRUCT_PTR td_ptr, /* [IN] the address of the stack memory block */ void *stack_ptr, /* [IN] the size of the stack */ _mem_size stack_size, /* [IN] the task's template */ TASK_TEMPLATE_STRUCT_PTR template_ptr, /* [IN] the status register to use in creating the task */ _mqx_uint status_register, /* [IN] the task creation parameter */ uint32_t create_parameter ) { unsigned char *stack_base_ptr; PSP_STACK_START_STRUCT_PTR stack_start_ptr; bool res = TRUE; stack_base_ptr = (unsigned char *)_GET_STACK_BASE(stack_ptr, stack_size); stack_start_ptr = (PSP_STACK_START_STRUCT_PTR)(stack_base_ptr - sizeof(PSP_STACK_START_STRUCT)); td_ptr->STACK_BASE = (void *)stack_base_ptr; td_ptr->STACK_LIMIT = _GET_STACK_LIMIT(stack_ptr, stack_size); td_ptr->STACK_PTR = stack_start_ptr; /* ** Build the task's initial stack frame. This contains the initialized ** registers, and an exception frame which will cause the task to ** "return" to the start of the task when it is dispatched. */ _mem_zero(stack_start_ptr, (_mem_size)sizeof(PSP_STACK_START_STRUCT)); stack_start_ptr->INITIAL_CONTEXT.LR = (uint32_t)_task_exit_function_internal; stack_start_ptr->INITIAL_CONTEXT.R0 = (uint32_t)create_parameter; stack_start_ptr->INITIAL_CONTEXT.PC = (uint32_t)(template_ptr->TASK_ADDRESS) | 1; stack_start_ptr->INITIAL_CONTEXT.PSR = 0x01000000; stack_start_ptr->PARAMETER = create_parameter; #if PSP_MQX_CPU_IS_ARM_CORTEX_M4 stack_start_ptr->INITIAL_CONTEXT.PENDSVPRIOR = 0; stack_start_ptr->INITIAL_CONTEXT.BASEPRI = status_register; stack_start_ptr->INITIAL_CONTEXT.LR2 = 0xfffffffd; #endif #if MQXCFG_ENABLE_FP && PSP_HAS_FPU if (td_ptr->FLAGS & MQX_FLOATING_POINT_TASK) { res = _psp_build_float_context(td_ptr); } #endif /* MQXCFG_ENABLE_FP && PSP_HAS_FPU */ return res; }
boolean _psp_build_stack_frame ( /* [IN] the address of the task descriptor */ TD_STRUCT_PTR td_ptr, /* [IN] the address of the stack memory block */ pointer stack_ptr, /* [IN] the size of the stack */ uint_32 stack_size, /* [IN] the task template address */ TASK_TEMPLATE_STRUCT_PTR template_ptr, /* [IN] the status register to use in creating the task */ uint_32 status_register, /* [IN] the task creation parameter */ uint_32 create_parameter ) { /* Body */ uchar_ptr stack_base_ptr; PSP_STACK_START_STRUCT_PTR stack_start_ptr; uint_32 reg_val; boolean res = TRUE; stack_base_ptr = (uchar_ptr)_GET_STACK_BASE(stack_ptr, stack_size); stack_start_ptr = (pointer)(stack_base_ptr - sizeof(PSP_STACK_START_STRUCT)); td_ptr->STACK_BASE = (pointer)stack_base_ptr; #if MQX_TD_HAS_STACK_LIMIT td_ptr->STACK_LIMIT = _GET_STACK_LIMIT(stack_ptr, stack_size); #endif td_ptr->STACK_PTR = stack_start_ptr; /* ** Build the task's initial stack frame. This contains the initialized ** registers, and an exception frame which will cause the task to ** "return" to the start of the task when it is dispatched. */ _mem_zero(stack_start_ptr, (uint_32)sizeof(PSP_STACK_START_STRUCT)); stack_start_ptr->INITIAL_CONTEXT.FRAME.STATUS_REGISTER = (uint_16)status_register; stack_start_ptr->INITIAL_CONTEXT.FRAME.FORMAT_AND_VECTOR = (uint_16)PSP_NORMAL_STACK_FRAME; stack_start_ptr->INITIAL_CONTEXT.FRAME.RETURN_ADDRESS = (void (_CODE_PTR_)(void)) template_ptr->TASK_ADDRESS; stack_start_ptr->EXIT_ADDRESS = _task_exit_function_internal; #if PSP_ABI == PSP_ABI_REG stack_start_ptr->INITIAL_CONTEXT.REGISTERS.D0 = create_parameter; #endif stack_start_ptr->PARAMETER = create_parameter; _PSP_GET_A5(reg_val); stack_start_ptr->INITIAL_CONTEXT.REGISTERS.A5 = (pointer)reg_val; /* Mark the bottom of the stack for debuggers*/ stack_start_ptr->INITIAL_CONTEXT.REGISTERS.A6 = &stack_start_ptr->ZERO_LINK_ADDRESS; #if PSP_HAS_FPU if ((td_ptr->FLAGS & MQX_FLOATING_POINT_TASK) != 0) { res = _psp_build_float_context(td_ptr); } /* Endif */ #endif return res; } /* Endbody */
/*! * \brief Initializes and starts MQX on the processor. * * The function does the following: * \li Initializes the default memory pool and memory components. * \li Initializes kernel data. * \li Performs BSP-specific initialization, which includes installing the * periodic timer. * \li Performs PSP-specific initialization. * \li Creates the interrupt stack. * \li Creates the ready queues. * \li Starts MQX tasks. * \li Starts autostart application tasks. * * \param[in] mqx_init Pointer to the MQX initialization structure for the * processor. * * \return Does not return (Success.) * \return If application called _mqx_exit(), error code that it passed to * _mqx_exit() (Success.) * \return Errors from _int_install_isr() (MQX cannot install the interrupt * subsystem.) * \return Errors from _io_init() (MQX cannot install the I/O subsystem.) * \return Errors from _mem_alloc_system() (There is not enough memory to * allocate either the interrupt stack or the interrupt table.) * \return Errors from _mem_alloc_zero() (There is not enough memory to allocate * the ready queues.) * \return MQX_KERNEL_MEMORY_TOO_SMALL (Init_struct_ptr does not specify enough * kernel memory.) * \return MQX_OUT_OF_MEMORY (There is not enough memory to allocate either the * ready queues, the interrupt stack, or the interrupt table.) * \return MQX_TIMER_ISR_INSTALL_FAIL (MQX cannot install the periodic timer ISR.) * * \warning Must be called exactly once per processor. * * \see _mqx_exit * \see _int_install_isr * \see _mem_alloc() * \see _mem_alloc_from() * \see _mem_alloc_system() * \see _mem_alloc_system_from() * \see _mem_alloc_system_zero() * \see _mem_alloc_system_zero_from() * \see _mem_alloc_zero() * \see _mem_alloc_zero_from() * \see _mem_alloc_align() * \see _mem_alloc_align_from() * \see _mem_alloc_at() * \see MQX_INITIALIZATION_STRUCT * \see TASK_TEMPLATE_STRUCT */ _mqx_uint _mqx ( register MQX_INITIALIZATION_STRUCT_PTR mqx_init ) { /* Body */ KERNEL_DATA_STRUCT_PTR kernel_data; TASK_TEMPLATE_STRUCT_PTR template_ptr; TD_STRUCT_PTR td_ptr; _mqx_uint result; pointer stack_ptr; pointer sys_td_stack_ptr; uchar_ptr sys_stack_base_ptr; #if MQX_EXIT_ENABLED || MQX_CRIPPLED_EVALUATION /* Setup a longjmp buffer using setjmp, so that if an error occurs * in mqx initialization, we can perform a longjmp to this location. * * Also _mqx_exit will use this jumpbuffer to longjmp to here in order * to cleanly exit MQX. */ if ( MQX_SETJMP( _mqx_exit_jump_buffer_internal ) ) { _GET_KERNEL_DATA(kernel_data); _int_set_vector_table(kernel_data->USERS_VBR); return kernel_data->USERS_ERROR; } /* Endif */ #endif /* * The kernel data structure starts at the start of kernel memory, * as specified in the initialization structure. Make sure address * specified is aligned */ kernel_data = (KERNEL_DATA_STRUCT_PTR) _ALIGN_ADDR_TO_HIGHER_MEM(mqx_init->START_OF_KERNEL_MEMORY); /* Set the global pointer to the kernel data structure */ _SET_KERNEL_DATA(kernel_data); /* The following assignments are done to force the linker to include * the symbols, which are required by TAD. * Note that we should use address of the variable so it is not optimized * as direct constant assignment when optimization level is high. * Note that counter will be immediately reset to zero on the subsequent * _mem_zero call. */ *(volatile pointer*) kernel_data = (pointer) & _mqx_version_number; *(volatile pointer*) kernel_data = (pointer) & _mqx_vendor; /* Initialize the kernel data to zero. */ _mem_zero((pointer) kernel_data, (_mem_size) sizeof(KERNEL_DATA_STRUCT)); #if MQX_CHECK_ERRORS && MQX_VERIFY_KERNEL_DATA /* Verify that kernel data can be read and written correcly without * errors. This is necessary during BSP development to validate the * DRAM controller is initialized properly. */ #ifndef PSP_KERNEL_DATA_VERIFY_ENABLE #define PSP_KERNEL_DATA_VERIFY_ENABLE 0 #endif /* PSP_KERNEL_DATA_VERIFY_ENABLE */ if (PSP_KERNEL_DATA_VERIFY_ENABLE) { /* This memory check is dangerous, because can destroy boot stack * stack which is used !!! -> MQX will failed ! * Set PSP_KERNEL_DATA_VERIFY_ENABLE to 1 * only if your boot stack is out of MQX memory heap */ result = _mem_verify((uchar_ptr)kernel_data + sizeof(KERNEL_DATA_STRUCT), mqx_init->END_OF_KERNEL_MEMORY); if ( result != MQX_OK ) { _mqx_exit(result); /* RETURN TO USER */ } } #endif /* MQX_CHECK_ERRORS && MQX_VERIFY_KERNEL_DATA */ /* Copy the MQX initialization structure into kernel data. */ kernel_data->INIT = *mqx_init; kernel_data->INIT.START_OF_KERNEL_MEMORY = (pointer) kernel_data; kernel_data->INIT.END_OF_KERNEL_MEMORY = (pointer) _ALIGN_ADDR_TO_LOWER_MEM(kernel_data->INIT.END_OF_KERNEL_MEMORY); /* init kernel data structures */ _mqx_init_kernel_data_internal(); /* Initialize the memory resource manager for the kernel */ result = _mem_init_internal(); #if MQX_CHECK_ERRORS if ( result != MQX_OK ) { _mqx_exit(result); /* RETURN TO USER */ } /* Endif */ #endif #if MQX_USE_INTERRUPTS /* Now obtain the interrupt stack */ if (kernel_data->INIT.INTERRUPT_STACK_LOCATION) { stack_ptr = kernel_data->INIT.INTERRUPT_STACK_LOCATION; result = kernel_data->INIT.INTERRUPT_STACK_SIZE; } else { if ( kernel_data->INIT.INTERRUPT_STACK_SIZE < PSP_MINSTACKSIZE ) { kernel_data->INIT.INTERRUPT_STACK_SIZE = PSP_MINSTACKSIZE; } /* Endif */ #if PSP_STACK_ALIGNMENT result = kernel_data->INIT.INTERRUPT_STACK_SIZE + PSP_STACK_ALIGNMENT + 1; #else result = kernel_data->INIT.INTERRUPT_STACK_SIZE; #endif stack_ptr = _mem_alloc_system((_mem_size)result); #if MQX_CHECK_MEMORY_ALLOCATION_ERRORS if (stack_ptr == NULL) { _mqx_exit(MQX_OUT_OF_MEMORY); /* RETURN TO USER */ } /* Endif */ #endif _mem_set_type(stack_ptr, MEM_TYPE_INTERRUPT_STACK); } /* Endif */ #if MQX_MONITOR_STACK _task_fill_stack_internal((_mqx_uint_ptr)stack_ptr, result); #endif kernel_data->INTERRUPT_STACK_PTR = _GET_STACK_BASE(stack_ptr, result); #endif /* * Set the stack for the system TD, in case the idle task gets blocked * by an exception or if idle task is not used. */ result = PSP_MINSTACKSIZE; sys_td_stack_ptr = _mem_alloc_system((_mem_size) result); #if MQX_CHECK_MEMORY_ALLOCATION_ERRORS if (sys_td_stack_ptr == NULL) { _mqx_exit(MQX_OUT_OF_MEMORY); /* RETURN TO USER */ } /* Endif */ #endif _mem_set_type(sys_td_stack_ptr, MEM_TYPE_SYSTEM_STACK); sys_stack_base_ptr = (uchar_ptr) _GET_STACK_BASE(sys_td_stack_ptr, result); td_ptr = SYSTEM_TD_PTR(kernel_data); td_ptr->STACK_PTR = (pointer)(sys_stack_base_ptr - sizeof(PSP_STACK_START_STRUCT)); td_ptr->STACK_BASE = sys_stack_base_ptr; #if MQX_TD_HAS_STACK_LIMIT td_ptr->STACK_LIMIT = _GET_STACK_LIMIT(sys_td_stack_ptr, result); #endif _mqx_system_stack = td_ptr->STACK_PTR; /* Build the MQX ready to run queues */ result = _psp_init_readyqs(); #if MQX_CHECK_MEMORY_ALLOCATION_ERRORS if ( result != MQX_OK ) { _mqx_exit(result); /* RETURN TO USER */ } /* Endif */ #endif #if MQX_USE_COMPONENTS /* Create a light wait semaphore for component creation */ _lwsem_create((LWSEM_STRUCT_PTR)&kernel_data->COMPONENT_CREATE_LWSEM, 1); #endif /* Create a light wait semaphore for task creation/destruction creation */ _lwsem_create((LWSEM_STRUCT_PTR) & kernel_data->TASK_CREATE_LWSEM, 1); /* Call bsp to enable timers and other devices */ result = _bsp_enable_card(); #if MQX_CHECK_ERRORS if ( result != MQX_OK ) { _mqx_exit(result); /* RETURN TO USER */ } /* Endif */ #endif #if MQX_HAS_TIME_SLICE /* Set the kernel default time slice value */ PSP_ADD_TICKS_TO_TICK_STRUCT(&kernel_data->SCHED_TIME_SLICE, MQX_DEFAULT_TIME_SLICE, &kernel_data->SCHED_TIME_SLICE); #endif /* Create the idle task */ #if MQX_USE_IDLE_TASK td_ptr = _task_init_internal( (TASK_TEMPLATE_STRUCT_PTR)&kernel_data->IDLE_TASK_TEMPLATE, kernel_data->ACTIVE_PTR->TASK_ID, MQX_IDLE_TASK_PARAMETER, TRUE, NULL, 0); #if MQX_CHECK_MEMORY_ALLOCATION_ERRORS if (td_ptr == NULL) { _mqx_exit(MQX_OUT_OF_MEMORY); } /* Endif */ #endif _task_ready_internal(td_ptr); #endif /* Check here for auto-create tasks, and create them here */ template_ptr = kernel_data->INIT.TASK_TEMPLATE_LIST; while (template_ptr->TASK_TEMPLATE_INDEX) { if (template_ptr->TASK_ATTRIBUTES & MQX_AUTO_START_TASK) { td_ptr = _task_init_internal(template_ptr, kernel_data->ACTIVE_PTR->TASK_ID, template_ptr->CREATION_PARAMETER, FALSE, NULL, 0); #if MQX_CHECK_MEMORY_ALLOCATION_ERRORS if (td_ptr == NULL) { _mqx_exit(MQX_OUT_OF_MEMORY); } /* Endif */ #endif _task_ready_internal(td_ptr); } /* Endif */ ++template_ptr; } /* Endwhile */ _sched_start_internal(); /* WILL NEVER RETURN FROM HERE */ return MQX_OK; /* To satisfy lint */ } /* Endbody */
/*! * \brief Initializes MQXLite on the processor. * * The function does the following: * \n - Initializes kernel data. * \n - Creates the interrupt stack. * \n - Creates the ready queues. * \n - Creates a lightweight semaphore for task creation/destruction. * \n - Initializes interrupts. * \n - Initializes system timer. * * \param[in] mqx_init Pointer to the MQXLITE initialization structure for the * processor. * * \return MQX_OK * \return Initialization error code * * \warning Must be called exactly once per processor. * * \see _mqxlite * \see _mqx_exit * \see MQXLITE_INITIALIZATION_STRUCT */ _mqx_uint _mqxlite_init ( MQXLITE_INITIALIZATION_STRUCT const * mqx_init ) { /* Body */ KERNEL_DATA_STRUCT_PTR kernel_data; pointer stack_ptr; _mqx_uint result = MQX_OK; /* * The kernel data structure starts at the start of kernel memory, * as specified in the initialization structure. Make sure address * specified is aligned */ kernel_data = (KERNEL_DATA_STRUCT_PTR) (mqx_init->START_OF_KERNEL_MEMORY); /* Set the global pointer to the kernel data structure */ _SET_KERNEL_DATA(kernel_data); /* The following assignments are done to force the linker to include * the symbols, which are required by TAD. * Note that we should use address of the variable so it is not optimized * as direct constant assignment when optimization level is high. * Note that counter will be immediately reset to zero on the subsequent * _mem_zero call. */ { MQX_INITIALIZATION_STRUCT * MQX_init_struct_ptr; *(volatile pointer*) kernel_data = (pointer) & _mqx_version_number; *(volatile pointer*) kernel_data = (pointer) & _mqx_vendor; *(volatile pointer*) kernel_data = (pointer) & _mqx_path; *(volatile pointer*) kernel_data = (pointer) & _mqxlite_version_number; *(volatile pointer*) kernel_data = (pointer) & MQX_init_struct_ptr; } /* Initialize the kernel data to zero. */ _mem_zero((pointer) kernel_data, (_mem_size) sizeof(KERNEL_DATA_STRUCT)); #if MQX_CHECK_ERRORS && MQX_VERIFY_KERNEL_DATA /* Verify that kernel data can be read and written correctly without * errors. This is necessary during BSP development to validate the * DRAM controller is initialized properly. */ if (PSP_KERNEL_DATA_VERIFY_ENABLE) { /* This memory check is dangerous, because can destroy boot stack * stack which is used !!! -> MQX will failed ! * Set PSP_KERNEL_DATA_VERIFY_ENABLE to 1 * only if your boot stack is out of MQX memory heap */ result = _mem_verify((uchar_ptr)kernel_data + sizeof(KERNEL_DATA_STRUCT), mqx_init->END_OF_KERNEL_MEMORY); if ( result != MQX_OK ) { return (result); /* RETURN TO USER */ } } #endif /* MQX_CHECK_ERRORS && MQX_VERIFY_KERNEL_DATA */ /* Copy the MQX initialization structure into kernel data. */ kernel_data->INIT = *mqx_init; /* init kernel data structures */ _mqx_init_kernel_data_internal(); #if MQX_USE_LWMEM == 1 /** * Initialize lightweight memory pool for dynamic memory allocation */ { /* Extern symbols defined in linker command file */ extern char __heap_addr[]; extern char __heap_size[]; KERNEL_DATA_STRUCT * kernel_data; LWMEM_POOL_STRUCT * pool_ptr; void * start_addr; _GET_KERNEL_DATA(kernel_data); pool_ptr = (LWMEM_POOL_STRUCT *) __heap_addr; kernel_data->KERNEL_LWMEM_POOL = pool_ptr; start_addr = (void *)((char *) __heap_addr + sizeof(LWMEM_POOL_STRUCT)); _lwmem_create_pool(pool_ptr, start_addr, (_mem_size)__heap_size); } #endif #if MQX_USE_INTERRUPTS /* Now obtain the interrupt stack */ if (kernel_data->INIT.INTERRUPT_STACK_LOCATION) { stack_ptr = kernel_data->INIT.INTERRUPT_STACK_LOCATION; result = kernel_data->INIT.INTERRUPT_STACK_SIZE; } else { return (MQX_INVALID_PARAMETER); } /* Endif */ #if MQX_MONITOR_STACK _task_fill_stack_internal((_mqx_uint_ptr)stack_ptr, result); #endif kernel_data->INTERRUPT_STACK_PTR = _GET_STACK_BASE(stack_ptr, result); #endif /* MQX_USE_INTERRUPTS */ #if MQX_USE_IDLE_TASK == 0 { /* * Set the stack for the system TD, in case the idle task gets blocked * by an exception or if idle task is not used. */ TD_STRUCT_PTR td_ptr; uchar_ptr stack_base_ptr; stack_base_ptr = (uchar_ptr) _GET_STACK_BASE(mqx_system_stack, PSP_MINSTACKSIZE); td_ptr = SYSTEM_TD_PTR(kernel_data); td_ptr->STACK_PTR = (pointer)(stack_base_ptr - sizeof(PSP_STACK_START_STRUCT)); td_ptr->STACK_BASE = stack_base_ptr; #if MQX_TD_HAS_STACK_LIMIT td_ptr->STACK_LIMIT = _GET_STACK_LIMIT(mqx_system_stack, PSP_MINSTACKSIZE); #endif _mqx_system_stack = td_ptr->STACK_PTR; } #endif /* MQX_USE_IDLE_TASK */ /* Build the MQX ready to run queues */ result = _psp_init_readyqs(); #if MQX_CHECK_MEMORY_ALLOCATION_ERRORS if ( result != MQX_OK ) { return (result); /* RETURN TO USER */ } /* Endif */ #endif #if MQX_USE_COMPONENTS /* Create a light wait semaphore for component creation */ _lwsem_create((LWSEM_STRUCT_PTR)&kernel_data->COMPONENT_CREATE_LWSEM, 1); #endif /* Create a light wait semaphore for task creation/destruction creation */ _lwsem_create((LWSEM_STRUCT_PTR) & kernel_data->TASK_CREATE_LWSEM, 1); /* Set the CPU type */ _mqx_set_cpu_type(MQX_CPU); result = _psp_int_init(FIRST_INTERRUPT_VECTOR_USED, LAST_INTERRUPT_VECTOR_USED); if (result != MQX_OK) { return(result); /* RETURN TO USER */ } /* set possible new interrupt vector table * if MQX_ROM_VECTORS = 0 switch to ram interrupt table which * was initialized in _psp_int_init) */ _int_set_vector_table((uint32_t)(&__vect_table)); /* * Initialize System Timer and Ticks parameters in kernel_data structure */ system_timer_init(NULL); return MQX_OK; /* To satisfy lint */ } /* Endbody */