1.1 可以参考此工程移植:
https://github.com/FreeRTOS/FreeRTOS/tree/main/FreeRTOS/Demo/CORTEX_A53_64-bit_UltraScale_MPSoC
1.2 链接脚本
MEMORY
{
ddr_0_MEM_0 : ORIGIN = 0x88000000, LENGTH = 0x40000000
}
/* Specify the default entry point to the program */
ENTRY(_vector_table) //入口
1.3 汇编入口
_vector_table
-》b _boot //此时位于EL2
-》mrs x0, currentEL //获取当前的EL级别
-》cmp x0, #0x8 //如果为8,表明当前是EL2
-》beq switch_to_el1_from_el2 //从EL2切换到EL1
-》el1_entry
-》b _boot //进入EL1
-》bl invalidate_dcaches //无效cache
-》Enable MMU //使能MMU
-》b _startup //jump to start
-》bl __libc_init_array
-》bl main //进入main函数
-》prvSetupHardware()
-》XScuGic_LookupConfig( XPAR_SCUGIC_SINGLE_DEVICE_ID )
-》XScuGic_CfgInitialize( &xInterruptController, pxGICConfig, pxGICConfig->CpuBaseAddress )
-》vTaskStartScheduler(); //开启调度
-》prvCreateIdleTasks()
-》xTimerCreateTimerTask() //创建调度用的timer
-》xPortStartScheduler() //配置调用用的 timer 硬件
-》configSETUP_TICK_INTERRUPT()
-》vConfigureTickInterrupt()
-》enable_generic_timer(TICK_INIT_VALUE); //初始化arm v8 generic timer
-》Register_Irq(29, FreeRTOS_Tick_Handler, NULL, portLOWEST_USABLE_INTERRUPT_PRIORITY, ucLevelSensitive);
XScuGic_SetPriorityTriggerType( &xInterruptController, Int_Id, Priority << portPRIORITY_SHIFT, ucLevelSensitive ) //配置GIC-400的优先级寄存器
XScuGic_Connect( &xInterruptController, Int_Id, (Xil_ExceptionHandler) Handler, ( void * ) CallBackRef ) //配置中断处理函数
XScuGic_Enable( &xInterruptController, Int_Id) //使能该中断呈
-》while(1) {} //死循环
1.4 初始化armv8 generic timer
/*******************************************************************/
#define ARCH_TIMER_PHYS_ACCESS 0
#define ARCH_TIMER_VIRT_ACCESS 1
#define ARCH_TIMER_MEM_PHYS_ACCESS 2
#define ARCH_TIMER_MEM_VIRT_ACCESS 3
#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
enum arch_timer_reg {
ARCH_TIMER_REG_CTRL,
ARCH_TIMER_REG_TVAL,
};
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)
/*
* Unlike read_cpuid, calls to read_sysreg are never expected to be
* optimized away or replaced with synthetic values.
*/
#define read_sysreg(r) ({ \
u64 __val; \
asm volatile("mrs %0, " __stringify(r) : "=r" (__val)); \
__val; \
})
/*
* The "Z" constraint normally means a zero immediate, but when combined with
* the "%x0" template means XZR.
*/
#define write_sysreg(v, r) do { \
u64 __val = (u64)(v); \
asm volatile("msr " __stringify(r) ", %x0" \
: : "rZ" (__val)); \
} while (0)
static void arch_timer_reg_write_cp15(enum arch_timer_reg reg, u32 val)
{
switch (reg) {
case ARCH_TIMER_REG_CTRL:
write_sysreg(val, cntp_ctl_el0);
break;
case ARCH_TIMER_REG_TVAL:
write_sysreg(val, cntp_tval_el0);
break;
}
}
static u32 arch_timer_reg_read_cp15(enum arch_timer_reg reg)
{
switch (reg) {
case ARCH_TIMER_REG_CTRL:
return read_sysreg(cntp_ctl_el0);
case ARCH_TIMER_REG_TVAL:
return read_sysreg(cntp_tval_el0);
}
}
static u32 arch_timer_reg_read(enum arch_timer_reg reg)
{
u32 val;
val = arch_timer_reg_read_cp15(reg);
return val;
}
static void arch_timer_reg_write(enum arch_timer_reg reg, u32 val)
{
arch_timer_reg_write_cp15(reg, val);
}
static __always_inline void enable_generic_timer(unsigned long evt)
{
unsigned long ctrl;
ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
ctrl |= ARCH_TIMER_CTRL_ENABLE;
ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt);
arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
}
1.5 Freertos中断处理过程
FreeRTOS_IRQ_Handler
-》BL vApplicationIRQHandler
-》pxVectorEntry->Handler( pxVectorEntry->CallBackRef ) // Handler ()由XScuGic_Connect()注册进来
-》portSAVE_CONTEXT //保存当前任务上下文
-》BL vTaskSwitchContext
-》vTaskSwitchContext
-》taskSELECT_HIGHEST_PRIORITY_TASK()
-》listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ) //找到当前要执行的TCB
-》portRESTORE_CONTEXT //真正进行任务切换
1.6 注册CLI命令行
void vUARTCommandConsoleStart( uint16_t usStackSize, unsigned portBASE_TYPE uxPriority )
{
vRegisterSampleCLICommands();
/* Create that task that handles the console itself. */
xTaskCreate( prvUARTCommandConsoleTask, /* The task that implements the command console. */
"CLI", /* Text name assigned to the task. This is just to assist debugging. The kernel does not use this name itself. */
usStackSize, /* The size of the stack allocated to the task. */
NULL, /* The parameter is not used, so NULL is passed. */
uxPriority, /* The priority allocated to the task. */
NULL ); /* A handle is not required, so just pass NULL. */
}