Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
rt-smart
rt-smart启动流程分析
1.00
发布于 2025-01-11 16:01:42 浏览:19
订阅该版
[tocm] # 从0分析RTT内核aarch64启动流程 分析前先看下面这个函数: ~~~asm .macro get_phy, reg, symbol adrp \reg, \symbol add \reg, \reg, #:lo12:\symbol .endm ~~~ + `adrp \reg, \symbol` 计算symbol相较于pc寄存器的页基地址,可以看成: ~~~c reg = (symbol & ~(0xFFF)) - (pc & ~(0xFFF)) + (pc & ~(0xFFF)) ~~~ + 再通过add \reg, \reg, #:lo12:\symbol将symbol的低12位与reg相加存放回reg中 这么使用是为了解除直接使用`ldr reg,=symbol`的限制 ### step1 首先从内核的入口_start进行分析: ~~~asm /* Variable registers: x21~x28 */ dtb_paddr .req x21 boot_arg0 .req x22 boot_arg1 .req x23 boot_arg2 .req x24 stack_top .req x25 _start: /* * Boot CPU general-purpose register settings: * x0 = physical address of device tree blob (dtb) in system RAM. * x1 = 0 (reserved for future use) * x2 = 0 (reserved for future use) * x3 = 0 (reserved for future use) */ mov dtb_paddr, x0 mov boot_arg0, x1 mov boot_arg1, x2 mov boot_arg2, x3 /* Save cpu stack */ get_phy stack_top, .boot_cpu_stack_top /* Save cpu id temp */ #ifdef ARCH_USING_HW_THREAD_SELF msr tpidrro_el0, xzr /* Save thread self */ #endif /* ARCH_USING_HW_THREAD_SELF */ msr tpidr_el1, xzr bl init_cpu_el bl init_kernel_bss bl init_cpu_stack_early #ifdef RT_USING_OFW /* Save devicetree info */ mov x0, dtb_paddr bl rt_hw_fdt_install_early #endif /* Now we are in the end of boot cpu process */ ldr x8, =rtthread_startup b init_mmu_early ~~~ + 首先通过`mov dtb_paddr, x0`将设备树的物理地址从x0中取出(由uboot放入x0中)放入dtb_paddr中,由`dtb_paddr .req x21`可知dtb_paddr 是寄存器x21的别名,同理,x1-x3中的值会被放入x23-x24中。 + 再通过`get_phy stack_top, .boot_cpu_stack_top`将CPU得栈顶地址保存在X25中 + 再将tpidr_el1&&tpidrro_el0清0 + 执行cpu的一些初始化,如init_cpu_el是对el3的一下初始化,init_kernel_bss将bss段清0,init_cpu_stack_early初始化CPU栈 + 通过`mov x0, dtb_paddr`将设备树的物理地址放入x0寄存器 + 在rt_hw_fdt_install_early将设备树的地址,size信息存放在全局变量中 + 将rtthread_startup的地址存入x8寄存器中后跳转到init_mmu_early ### step2 我们进入init_mmu_early中查看: ~~~asm init_mmu_early: get_phy x0, .early_page_array bl set_free_page get_phy x0, .early_tbl0_page get_phy x1, .early_tbl1_page get_pvoff x2 x3 ldr x2, =ARCH_EARLY_MAP_SIZE /* Map 1G memory for kernel space */ bl rt_hw_mem_setup_early b enable_mmu_early ~~~ 1. 首先获得了early_page_array的物理地址,通过源码可知,early_page_array是预留出来的一片24*4096的地址空间: ~~~c .early_page_array: .space 24 * ARCH_PAGE_SIZE ~~~ 再通过 `bl set_free_page`将这个地址存入全局变量`__init_page_array`中: ~~~c void set_free_page(void *page_array) { __init_page_array = page_array; } ~~~ 2. 将`early_tbl0_page` `early_tbl1_page`存入x0,x1寄存器中。`early_tbl0_page` `early_tbl1_page`描述如下: ~~~c .early_tbl0_page: .space ARCH_PAGE_SIZE .early_tbl1_page: /* Map 4G -> 2M * 512 entries */ .space 4 * ARCH_PAGE_SIZE ~~~ 3. 再通过get_pvoff x2 x3计算物理地址与虚拟地址的差值并存入x3寄存器: ~~~asm .macro get_pvoff, tmp, out ldr \tmp, =.boot_cpu_stack_top get_phy \out, .boot_cpu_stack_top sub \out, \out, \tmp .endm ~~~ 该函数先将符号boot_cpu_stack_top的地址(在链接阶段已经确定是虚拟地址)存入tmp寄存器,再将boot_cpu_stack_top的物理地址存入out寄存器,最后相减存回out寄存器 4. 将ARCH_EARLY_MAP_SIZE的值存入x2寄存器 5. 跳转到`rt_hw_mem_setup_early`函数,此时x0-3寄存去的值分别为: + early_tbl0_page + early_tbl1_page + ARCH_EARLY_MAP_SIZE + pvoff 将early_tbl0_page和early_tbl1_page映射为2M的页表,分别用于内核态和用户态,而`early_tbl0_page`和`early_tbl0_page`分别为内核态和用户态l0页表的首地址 6. 再跳转到`enable_mmu_early`函数中 ### step3 `enable_mmu_early`: ~~~c enable_mmu_early: get_phy x0, .early_tbl0_page get_phy x1, .early_tbl1_page msr ttbr0_el1, x0 msr ttbr1_el1, x1 dsb sy bl mmu_tcr_init /* * OK, now, we don't use sp before jump to kernel, set sp to current cpu's * stack top to visual address */ get_pvoff x1 x0 mov x1, stack_top sub x1, x1, x0 mov sp, x1 ldr x30, =kernel_start /* Set LR to kernel_start function, it's virtual addresses */ /* Enable page table translation */ mrs x1, sctlr_el1 orr x1, x1, #(1 << 12) /* Stage 1 instruction access Cacheability control */ orr x1, x1, #(1 << 2) /* Cacheable Normal memory in stage1 */ orr x1, x1, #(1 << 0) /* MMU Enable */ msr sctlr_el1, x1 dsb ish isb ic ialluis /* Invalidate all instruction caches in Inner Shareable domain to Point of Unification */ dsb ish isb tlbi vmalle1 /* Invalidate all stage 1 translations used at EL1 with the current VMID */ dsb ish isb ret ~~~ 1. 再获得刚刚分配的页表的首地址给x0与x1并将地址存放在`ttbr0_el1`和`ttbr1_el1`中 2. 设置内存屏障 3. 跳转到mmu_tcr_init函数 4. 获取pv_off到x0中并将sp设置为cpu栈顶指针的虚拟地址 5. 将x30寄存器设置为`kernel_start`的地址 6. 设置sctlr_el1寄存器,启动mmu和缓存,并失效前面的所有缓存 7. 返回 返回后由于x30寄存器中存放的是`kernel_start`地址所以会跳转到`kernel_start`中执行 ### step4 ~~~asm kernel_start: /* jump to the PE's system entry */ mov x29, xzr mov x30, x8 br x8 ~~~ 1. 将x29寄存器清0,再跳转到x8中执行。x8寄存器在step1中`ldr x8, =rtthread_startup`被存放了`rtthread_startup`的地址,所以会跳转到`rtthread_startup`中执行,接下来就是c的代码的阅读啦~
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
zhuzhuzhu
这家伙很懒,什么也没写!
文章
3
回答
1
被采纳
0
关注TA
发私信
相关文章
1
rt-smart发布时间
2
rt-smart qemu-vexpress-a9 编译报错
3
rt-smart分支编译rasp4-32bsp报错
4
rt-smart qemu-vexpress-a9 win10编译脚本问题
5
rt-smart qemu-vexpress-a9 linux 下crtl+c
6
rt-smart + pthread 编译报错
7
rt-smart的rt_channel实现问题
8
关于rt-smart的musl-libc
9
RT-Smart Windows 编译 qemu-vexpress-a9 出错
10
用户程序在RT-Smart存在的方式
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
cubemx
PWM
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
812
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
149
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部