前言
本篇的内容进入了rt-smart内核的C语言世界,因此会同时涉及到较多的.c文件,需要读者对rt-smart内核有基本的认识,至少需要大致了解内核的文件结构。
在上一章节中,我们从启动汇编start_gcc.S
进入了内核入口rtthread_startup
,该内核入口函数位于./kernel/src/components.c
文件中;一般而言,为了保证内核的代码统一和可移植性,通常不会直接修改rtthread_startup
里面的内容,而是根据主板硬件和用户实际需求将自身特定的代码实现在函数rt_hw_board_init
中;跳转到components.c
中就可以看到以下内容:
int rtthread_startup(void)
{
rt_hw_interrupt_disable();
/* board level initialization
* NOTE: please initialize heap inside board initialization.
*/
rt_hw_board_init();
/* show RT-Thread version */
rt_show_version();
/* timer system initialization */
rt_system_timer_init();
/* scheduler system initialization */
rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
/* signal system initialization */
rt_system_signal_init();
#endif
/* create init_thread */
rt_application_init();
/* timer thread initialization */
rt_system_timer_thread_init();
/* idle thread initialization */
rt_thread_idle_init();
#ifdef RT_USING_SMP
rt_hw_spin_lock(&_cpus_lock);
#endif /*RT_USING_SMP*/
/* start scheduler */
rt_system_scheduler_start();
/* never reach here */
return 0;
}
关闭中断
rtthread_startup
进来第一步便是关闭中断rt_hw_interrupt_disable
,屏蔽中断FIQ和IRQ;由于我们在start_gcc.S
启动代码中已经关闭了中断控制器(INTC),这里实际上运行到此处是不会有外部中断产生的。'rt_hw_interrupt_disable'函数实现位于context_gcc.S中,由于后面开启调度器会强行使能中断,因此这里可以不接收返回的CPSR寄存器值。
板级初始化
第二步调用的函数rt_hw_board_init
,在rtthread标准版中主要执行芯片相关的初始化操作,例如获取CPU主频,开启systick定时器,执行BOARD_EXPORT
宏导出的初始化函数。在rt-smart系统中,除了上述工作还新增了二级页表配置,ioremap配置,LWP用户态初始化等,板级初始化函数也是rt-smart适配到不同芯片时比较重要的步骤。
rt_hw_board_init
函数的实现通常实现在bsp目录下,例如./kernel/bsp/allwinner_tina/driver/board.c
中,下面代码中已经定义的宏:RT_USING_USERSPACE
RT_USING_HEAP
RT_USING_CONSOLE
RT_USING_COMPONENTS_INIT
// 以下全局变量、宏定义、结构体定义是从其它文件复制而来,
// 在真实内核文件结构中并不在一起,这里放在一起是为了便于说明
#define HEAP_END (void*)(KERNEL_VADDR_START + 8 * 1024 * 1024)
#define PAGE_START HEAP_END
#define PAGE_END (void*)(KERNEL_VADDR_START + 32 * 1024 * 1024)
#ifdef RT_USING_USERSPACE
rt_region_t init_page_region = {
(size_t)PAGE_START,
(size_t)PAGE_END,
};
#endif
typedef struct
{
size_t *vtable;
size_t vstart;
size_t vend;
size_t pv_off;
} rt_mmu_info;
rt_mmu_info mmu_info;
void rt_hw_board_init(void)
{
#ifdef RT_USING_USERSPACE
// 0xf0000000 ~ 0xffffffff - 1 高256MB保留作为动态设备映射地址空间
rt_hw_mmu_map_init(&mmu_info, (void*)0xf0000000, 0x10000000, (size_t *)MMUTable, PV_OFFSET);
rt_page_init(init_page_region);
rt_hw_mmu_ioremap_init(&mmu_info, (void*)0xf0000000, 0x10000000);
arch_kuser_init(&mmu_info, (void*)0xffff0000);
#else
rt_hw_mmu_map_init(&mmu_info, (void*)0x80000000, 0x10000000, MMUTable, 0);
rt_hw_mmu_ioremap_init(&mmu_info, (void*)0x80000000, 0x10000000);
#endif
#ifdef RT_USING_HEAP
/* initialize system heap */
rt_system_heap_init(HEAP_BEGIN, HEAP_END);
#endif
rt_hw_interrupt_init();
ccu_init();
rt_hw_gpio_init();
/* init hardware interrupt */
rt_hw_uart_init();
#ifdef RT_USING_CONSOLE
/* set console device */
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif /* RT_USING_CONSOLE */
os_clock_init();
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
}
rt_hw_mmu_map_init
rt_hw_mmu_map_init主要是预留0xf0000000 ~ 0xffffffff
高256M地址空间作为外设地址空间,其中的实现也并不复杂,只是配置下mmu_info
这个结构体,在后面使用虚拟地址映射实际的物理外设时配合mmu_info
里面的信息进行检查和分配。
其函数原型如下
/**
* @param mmu_info 用于存储地址信息的mmu_info结构体
* @param v_address 起始虚拟地址
* @param size 空间大小 unit:byte
* @param vtable 当前使用的MMU页表(内核页表)
* @param pv_off 内核起始虚拟地址和DRAM物理起始地址的差值 0xC0000000
* */
int rt_hw_mmu_map_init(rt_mmu_info *mmu_info, void* v_address, size_t size, size_t *vtable, size_t pv_off)
rt_hw_mmu_map_init
的初始化操作还是比较简单的,该函数的返回值上层也没有处理,事实上这里不应该出错,这是内核移植者应当保证的。(因为此时串口都还没初始化,在这之前即使发生错误也无法告知用户了。)
rt_page_init
待完成...
标签:rt,F1C100S,mmu,hw,init,info,RT,smart From: https://www.cnblogs.com/yanye0xff/p/16615735.html