Chinaunix首页 | 论坛 | 博客
  • 博客访问: 48063
  • 博文数量: 13
  • 博客积分: 1415
  • 博客等级: 上尉
  • 技术积分: 220
  • 用 户 组: 普通用户
  • 注册时间: 2006-12-24 14:46
文章分类

全部博文(13)

文章存档

2009年(4)

2008年(9)

我的朋友
最近访客

分类: BSD

2008-05-18 11:12:25

NetBSD上电启动到内核运行之前流程的简单介绍


作者:gvim@chinaunix.net/bsd


BSD License版权发布

 
 
作为内核分析的前期工作,本文介绍了NetBSD arm port中的smdk2410板从芯片加电到内核被调用之前的前期准备活动。大家不用担心,这些概念很大程度上是和i386是类似的,因此对体系结构有所了解的朋友会发现下面的章节不难理解。选择arm芯片的理由在于我们可以清楚地认识到一个操作系统所需要的底层支持。比如cache[1,2,3],虚拟地址影射的安装[1,2],存储管理器控制[1,2]等有关硬件体系的问题[3]。NetBSD执行流程进入kernel之后,可以很大程度上脱离对硬件平台的考虑。因此,对于内核分析过程来说,将平台有关操作首先在这里以功能介绍的形式予以说明是一个不错的开端。

一 介绍
本文着重的是对功能/流程的描述而不打算深入到实际的具体代码,因此这里简单的说明下smdk2410开发板的情况。具体说明书可以在Samsung网站上找到。

由于我们不关心指令细节,对该介绍不感兴趣的可以简单略过。仅仅知其然就足够明白下面章节的文字。

处理器使用的是arm9系列的芯片。有7种不同的处理器模式,分别是FIQ(快速中断响应),IRQ(中断响应),SVC(管理模式),ABT(异常模式),UND(未定义模式),SYS(系统模式)和大家熟悉的USR(用户模式)。USR具有普通权限,其他模式具有特殊权限。每种模式有16个寄存器,其中R0-R7供所有模式公用,R15固定坐位程序计数器(PC)使用,其他寄存器依据处理器当前所在模式的不同而定。当然,必然还有状态寄存器。开发板的物理地址从0x00000000开始,到0x2FFFFFFF用作ROM空间,0x30000000以上是用作RAM,并且各种处理器的控制寄存器也被影射到不同的物理地址上(一般可以是硬件直接搭线)。该处理器有一个协处理器(称作CPx  即coprocessor)CP15来控制有关控制MMU,控制cache,取得处理器信息等的情况。下面在叙述的时候会适当的提及。

NetBSD就不多介绍了。这里只说一些有关port的问题。NetBSD的平台相关代码放在arch/xxx目录之下。其中有boot代码(一般在arch/xxx/stand/),有启动代码(xxx_start.S),有内核环境初始化代码locore.S,有内存分页相关代码(pmap.c),体系相关代码(xxx_machdep.c)。可以从这里开始对一个port进行移植。

以我们的平台为例,port文件在arch/arm/evbarm下面(对于i386是arch/i386)。在这里我们可以看到我们关心的平台smdk2xx0,进去以后可以找到一个名为smdk2410_start.S的文件。我们就从这里开始。

内核配置文件是/arch/evbarm/conf/SMDK2410 ,ld链接文件是arch/evbarm/conf/ldscript.evbarm
生成方法:

get sys.tgz syssrc.tgz等相关代码

cd /usr/src ./build -m evbarm tools // 这里,交叉编译arm的编译器,-m指定平台。(或许需要你手工建立一个/usr/obj目录)

./build -m evbarm kernel=SMDK2410 // 见上面几行的说明

现在你就有了一个可以实际在某arm板上运行的BSD内核了。存放在/usr/obj/sys/.../.../SMDK2410下面。

二 bootloader (boot stage1)
对于嵌入式芯片来说,我们需要比x86更多的知识和系统支撑。在这个过程中,我们需要设置系统启动之前所需要进行的所有活动:比如设置时钟频率,设置MMU的页面影射等。

1 首先我们关闭中断。在系统引导的时候,我们不希望外部中断的发生,因为这个时候我们还没有安装中断的处理句柄,如果发生中断而跳转到中断地址的话,会发生什么呢?这个动作是通过往芯片的控制寄存器写入掩码完成的(类比i386上的EFLAGS寄存器)。

2 接着设置处理器时钟,分频器等有关处理器实际运行的参数。由于涉及其他硬件设计方面的问题,我们忽略它而不会影响下面的分析。

3 由于嵌入式中没有普通PC的二级存储设备(一般是硬盘)。而所有内核代码必须保存在某个地方,这个地方只有是ROM(刚才我们说了在0x00000000 – 0x2FFFFFFF地址空间被影射为ROM的地址)。由于在ROM中读取、运行系统代码的速度很慢,我们需要把系统代码拷贝到RAM里面去。现在,我们拷贝内核到0x30200000(这不是硬性规定,0x30000000 之后的空间被影射为RAM)。

4 内核已经在RAM中了,但是内核还不能运行。为什么呢?因为我们还没有设置存储控制器的行为,也就是说我们不能使用虚拟地址,也不能使用MMU提供的内存保护,权限检查等机制(类比于i386的MMU)。这对于操作系统来说(而不是实时系统)是很不合适的。

细节就不详细讲述了,我们假设我们确实现在可以使用MMU提供的虚拟地址到物理地址的影射。并且,我们有如下的影射图(va表示虚拟地址virtual,pa表示物理地址physical):

va(0x30000000-0x33FFFFFF)影射到pa(0x30000000 - 0x33FFFFFF)中去,va(0xC0000000 - 0xC3FFFFFF)也影射到pa(0x30000000 - 0x33FFFFFF)中去。其余没有提及的虚拟地址和物理地址一一影射,也就是说MMU(va(0x00000000))  ==  pa(0x00000000),MMU(va(0x20000000)) == pa(0x20000000)。 (该写法表示va(0x00000000)经过MMU变换之后影射到pa(0x00000000)上)。

到这里,我们的虚拟地址变换可以这样进行:处理器发出地址va的时候,MMU在接收到va,首先在物理地址0x30000000(这个地址是记录在协处理器CP15的寄存器里,可以被读取和修改)处取得我们的影射表,查找va对应的pa进行访问(虚地址转换的概念和i386上很类似,这个转换表是存放在内存的某个地方,这里我们放在0x30000000处)。

5 好了,为了减少MMU的访村操作(回忆刚才说的转换表是放在内存里的,要转换虚拟地址首先要访问至少一次内存)。因此我们设置好最初的虚拟/物理地址影射之后,可以使用TLB,也就是转换表的高速缓存,这个在i386上也很常用。接着设置一些附属内存的属性。到这里,我们只完成了内核的加载和最初的硬件环境设置,下面可以进入boot stage2,进行内核运行环境的设置。

三 内核环境的初始化 (boot stage2)

前面讲过port的代码集中在locore.S、xxx_machdep.c(我们的例子中是smdk2410_machdep.c)和pmap.c中。其中locore.S利用xxx_machdep.c和pmap.c中的C函数设置内核运行环境。第二部分最后我们打开了MMU支持,因此下面所涉及的地址,除非特殊说明,均指的虚拟地址。

下面就功能模块进行说明。

1 由于locore.S是用汇编语言写的,smdk2410_machdep.c和pmap.c是用C语言写的,大家都知道C函数的调用需要堆栈的支持。所以,我们首先设置好调用smdk2410_machdep.c中函数的堆栈。

2 在smdk2410_machdep.c中,我们需要设置内存属性,取得处理器信息供后面使用,对开发版上的物理寄存器进行影射,安装中断处理,安装页表等操作。

为什么我们还需要对内存,页表等再一次操作呢?因为boot stage1中的设置只是为了可以运行接下来的boot stage2。为了让kernel可以运行,所以我们需要设置kernel的运行环境。

这部分如果要写的话就太多了,简单起见,我用一张图表示了。



四 进入内核

之后我们可以看到熟悉的/kern/init_main.c中的main()了。

五 小结

BSD?我才刚上路呢。(发哥广告词)

参考:
最重要的 /usr/src/sys/*
用google搜索吧,我也不知道从哪里下下来的了
[1] um_s3c2410s_rev12_030428.pdf
[2] Addison Wesley - ARM Architecture Reference Manual (2nd Edition).pdf
[3] 计算机体系结构 --- 量化研究方法


欢迎大家提出指导意见
阅读(733) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:NetBSD LKM简单分析

给主人留下些什么吧!~~