2020-12-29

RT-Thread smart 混内核操作系统启动流程分析一

下面以 qemu-Vexpress-a9 该虚拟平台为例,该工程,启动引导文件为
 

rt-smart\kernel\libcpu\arm\cortex-a\start_gcc.S

芯片跑起来的,第一步,是初始化mmu,对应代码如下

    ldr r5, =PV_OFFSET

    mov r7, #0x100000
    sub r7, #1
    mvn r8, r7

    ldr r9, =KERNEL_VADDR_START

    ldr r6, =__bss_end
    add r6, r7
    and r6, r8 //r6 end vaddr align up to 1M
    sub r6, r9 //r6 is size

    ldr sp, =stack_top
    add sp, r5 //use paddr

    ldr r0, =init_mtbl
    add r0, r5
    mov r1, r6
    mov r2, r5
    bl init_mm_setup

    ldr lr, =after_enable_mmu
    ldr r0, =init_mtbl
    add r0, r5
    b enable_mmu

在这个初始化mmu的过程中做了什么呢,下面咱们一步步分析

    ldr r5, =PV_OFFSET      //将PV_OFFSET这个立即数放入r5, PV_OFFSET 由宏定义得知其值为 0xa000 0000

 

    mov r7, #0x100000      //将0x10 0000 立即数放入r7, 

    sub r7, #1                    //0x10 0000 减1 为0xF FFFF

    mvn r8, r7                   //将r7的值赋给r8,此时 r8的值为 0xF FFFF

 

    ldr r9, =KERNEL_VADDR_START   //将KERNEL_VADDR_START 这个立即数放入r9, KERNEL_VADDR_START由宏定义得知其为 0xC000 0000

    ldr r6, =__bss_end           //将代码区 bss 区的结束的地址值放入 r6

    add r6, r7                         // r6+r7 放入r6 此时r6的值为  __bss_end + 0xF FFFF

    and r6, r8 //r6 end vaddr align up to 1M  r6 | r8 放入 r6 将r6的值1 M对其

    sub r6, r9 //r6 is size    r6 - r9 为 整个内核镜像大小 + 1MB + 64KB   为何为这个值呢,首先看镜像的链接脚本,该文件在 rt-smart\kernel\bsp\qemu-vexpress-a9\link.lds,在该链接脚本的开头,定义了镜像的代码段开始位置为 . = 0xc0010000

经过上述步骤,我们计算出了整个内核镜像大小,同时多加出了一部分区域

OK,接着看第二段

    ldr sp, =stack_top         //将栈顶地址赋值给sp,这个是为后续执行C代码做准备,

    add sp, r5 //use paddr  // sp的值为  stack_top + PV_OFFSET   stack_top的地址为 0xC001 0000 + 实际链接的偏移,这个可以在.map文件中找到,例如我的为 0xC015 5804 ,那个这个值 + PV_OFFSET是多少呢?通过计算,因为这个平台为32位平台,则最终值是 0x6015 5804

那么 0x6015 5804 这个值有什么意义呢?看下面这个平台的地址map图

可以看到物理RAM对应的地址有两个一个由 0x6000 0000 ~ 0x8000 0000 第二个域为 0x8400 0000 ~ 0xA000 0000

因为此时mmu还未使能,则此时,CPU访问地址均为实际物理地址,所以,在此,SP + PV_OFFSET是将SP加载的地址转换为实际的物理内存的地址

好了,至此,系统已可以调用C语言的接口,下面咱们接着分析

    ldr r0, =init_mtbl         //将init_mtbl数据的地址赋值给r0

    add r0, r5                  //将 r0 + r5, 联系上文,r5的值为PV_OFFSET, 则在此处,则计算出了init_mtbl在物理内存中地址

    mov r1, r6                //将r6 赋值给 r1, r6的值是什么呢,r6中当前存储的值 完整的内核镜像大小+ 1MB + 64KB

    mov r2, r5              //将 PV_OFFSET 赋值给r2

    bl init_mm_setup  //在此处调用C函数 init_mm_setup   上述的对r0 r1 r2的赋值相当与对C函数传参

下面是init_mm_setup函数的代码

void init_mm_setup(unsigned int *mtbl, unsigned int size, unsigned int pv_off) {
    unsigned int va;

    for (va = 0; va < 0x1000; va++) {              //vaddr range 10 0000 ~ 1 0000 0000
        unsigned int vaddr = (va << 20);
        if (vaddr >= KERNEL_VADDR_START && vaddr - KERNEL_VADDR_START < size) { /*将内核地址开始之上的地址,映射到 0x6000 0000 之后*/
            mtbl[va] = ((va << 20) + pv_off) | NORMAL_MEM;
        } else if (vaddr >= (KERNEL_VADDR_START + pv_off) && vaddr - (KERNEL_VADDR_START + pv_off) < size) { /*虚拟地址与物理内存重合的地映射为和物理地址一样*/
            mtbl[va] = (va << 20) | NORMAL_MEM;
        } else {
            mtbl[va] = 0; /*赋值为0,未映射*/
        }
    }
}

继续分析init_mm_setup 函数的代码

va 取的值 是0x00 ~0x1000 这个范围是 0~4096

vaddr 的取值范围是 0x00 ~ (0x1000 << 20) 这个范围是 0~4G的空间,数值全部以 1MB 对齐,为何在此取1MB呢,下节继续

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值