微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM学习笔记之——MiniOS

ARM学习笔记之——MiniOS

时间:11-20 来源:互联网 点击:

1. 概述

最近,我花了大量的时间学习了杨铸老师写的《深入浅出嵌入式底层软件开发》,看完了ARM体系结构与编程这一章。在这章节的最后,作者做了一个用于总结前面所学内容的操作系统MiniOS,并附带了其中的源代码。我认真学习了其中的所有代码,悟到了其中非常巧妙的构思。

读这个MiniOS源代码我遇到了最大的几个问题如下:

(1)系统是怎么启动的?

(2)开启了MMU后,虚拟地址是怎么映射上物理地址上的?

(3)系统是怎么开启MMU的,为什么开启了MMU内存地址重映射之后程序还能正常运行?

(4)main( ) 函数是怎么变成task0的?

(5)任务之间是怎么切换的?

(6)任务中怎么被创建,并运行起来的?

上述这几个问题都是很细微,但又很难搞清楚的核心知识。笔者在此把自己悟到的东西分享出来,供大家参考。

其它,如:系统函数调用、任务调度机制、LED、UART、按键怎么实现,不做过多研究。

2. 详细内容

2.1 系统是怎么启动的?

首先说明,书上提供的MiniOS工程编译后的运行地址为0x33FF0000,不是 0x00000000,这点很重要。

-info totals -ro-base 0x33ff0000 -first start.o

而程序编译完成后,生成了bin文件将被烧录到NorFlash的0x00000000地址上,也就很重要!

ARM复位后,PC从NorFlash的0x00000000地址上取提,也就是”b Reset“,之后跳到Reset标号上继续执行。代码如下:

  1. AREAStart,CODE,READONLY
  2. ENTRY;代码段开始
  3. bReset
  4. ……
  5. Reset;Reset异常处理符号
  6. blclock_init;跳往时钟初始化处理
  7. blmem_init;跳往内存初始化处理
  8. ldrsp,=SVC_STACK;设置管理模式栈指针,common_asm.h中定义
  9. bldisable_watch_dog;关闭看门狗

之后所有的跳转都是用到b或bl,进行相对跳转。再跳转也是以PC为起始,相对位置跳转,不会受运行地址的影响。

初始化了时钟、SDRAM、关闭看门狗、设置sp。有人可能会问:为什么在进行了bl之后再设置栈指针?其实,哪里设置都无所谓,因为bl指令返回地址只保存在LR寄存器中,不放在栈里。SP被设置成了0x33FF0000,向下扩展,将来还会提及。

然后初始化SDRAM(如果不初始化,SDRAM是不能使用的),将程序自己从0x00000000地址复制一份到0x33FF0000地址上。然后再来一个绝对地址跳转,转到0x33FF0000地址域上的xmain地址处继续执行。如下:

  1. copy_code;代码拷贝开始符号
  2. movr0,#0x0;R0中为数据开始地址(ROM数据保存在0地址开始处)
  3. ldrr1,=|Image

    RO

    Base|;R1中存放RO输出域运行地址,
  4. ldrr2,=|Image

    ZI

    Limit|;R2中存放ZI输出域结束地址,
  5. subr2,r2,r1;R2=R2-R1,得出待拷贝数据长度
  6. blCopyCode2Ram;将R0,R1,R2三个参数传递给CopyCode2Ram函数执行拷贝
  7. ldrr0,=|Image

    ZI

    Base|
  8. ldrr1,=|Image

    ZI

    Limit|
  9. blclear_bss_region
  10. blstack_init;跳往栈初始化代码处
  11. msrcpsr_c,#0x5f;开启系统中断,进入系统模式
  12. ldrlr,=halt_loop;设置返回地址
  13. ldrpc,=xmain;跳往main函数,进入OS启动处理
  14. halt_loop
  15. bhalt_loop;死循环

在执行了”ldr pc, =xmain“这条指令之后,PC就指向了SDRAM的0x33FF0000地址区域上了,不再是NorFlash上了,从此达到了运行地址与加载地址的统一。谨记!

xmain()函数定议在main.c文件中。

  1. intxmain(void)
  2. {
  3. pgtb_init();//建立页表
  4. mmu_init();//mmu初始化
  5. uart_init();//串口初始化
  6. irq_init();//中断初始化
  7. Timer0_init();//定时器0初始化
  8. key_init();//按键初始化
  9. led_init();//led灯初始化
  10. }


2.2 开启了MMU后,虚拟地址是怎么映射上物理地址上的?

在xmain函数中,pgtb_init() 函数的功能就是构建页表,TTB=0x300F0000。

  1. voidpgtb_init()
  2. {
  3. unsignedlongentry_index,SFR_base;
  4. /*建立到Norflash的2MB的地址空间的映射*/
  5. /*0xA0000000映射到0开始的1MB地址空间*/
  6. *(mmu_tlb_base+(0xA0000000>>20))=0x0|SEC_DESC;
  7. /*0xA0100000映射到0x100000~0x1FFFFF的1MB地址空间*/
  8. *(mmu_tlb_base+(0xA0100000>>20))=0x100000|SEC_DESC;
  9. /*令0x30000000~0x34000000的64MB虚拟地址等于物理地址空间,方便miniOS内部进程管理*/
  10. for(entry_index=0x30000000;entry_index<0x34000000;entry_index+=0x100000){
  11. *(mmu_tlb_base+(entry_index>>20))=entry_index|SEC_DESC;
  12. }
  13. /*特殊功能寄存器0x48000000~0x60000000地址空间映射到0xC8000000~0xE0000000虚拟地址空间*/
  14. for(entry_index=0x48000000+0x80000000,SFR_base=0x48000000;
  15. SFR_base<0x60000000;entry_index+=0x100000,SFR_base+=0x100000){
  16. *(mmu_tlb_base+(entry_index>>20))=SFR_base|SEC_DESC;
  17. }
  18. /*
  19. *进程1-23号进程地址空间,每个进程32MB,miniOS允许进程使用32MB虚拟地址空间,

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top