博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

马二进三名人传记

yjx2003---linux
  yjx2003.cublog.cn

关于作者
mail: xjybook7###yahoo.com.cn
把3个# 换成 @ ,就是邮件地址
|| << >> ||
我的分类


转载--Redboot(i386)启动流程

 

Redbooti386)启动流程(一) - [源码分析]

原始出处   http://redboot.blogbus.com/logs/21270390.html

现在将通过阅读代码,看看redboot是如何启动的,这是每个系统执行的第一步,也是不可缺少的一步。这部分会分几篇完成,这是第一部分,主要是一个概要介绍。

 

由于系统启动跟硬件的紧密关系,所以在不同的硬件平台下,这部分都会有相应不同的处理。

 

下面这幅图来自《EMBEDDED SOFTWARE DEVELOPMENT WITH ECOS》书中,介绍了一款PowerPC的设备启动流程。

 

 

而这里,仍将介绍PC下的启动流程,通过阅读代码可以了解其具体的执行步骤,也可以通过修改代码重新编译、运行前面介绍的实验,查看结果。在阅读代码的过程中,最好结合实验,这样能够证实系统是否象我们理解的那样运行。

 

在今后,会进一步分析eCos操作系统的其他部分代码结构,比如:调度,驱动等等。

也会对其他不同体系架构(如 mips arm)下的代码进行分析阅读。

 

Redboot最先执行的文件通常命名为 vectors.S

 

因为我们是i386架构下,所以可以在下面目录下找到相应文件:

package/hal/i386/arch/v2_0/src/vectors.S

 

 

程序执行的入口是 _start

_start 处开始执行,至   call cyg_start 完成启动部分。

 

i386 体系 

#==============================================================================

 

//    .file   "vectors.S"

 

#==============================================================================

# Real startup code. We jump here from the various reset vectors to set up the

# world.

 

       .text

       .globl      _start

 

_start:

       hal_cpu_init

       hal_smp_init

       hal_diag_init

       hal_mmu_init

       hal_memc_init

       hal_intc_init

       hal_cache_init

       hal_timer_init

 

       # Loading the stack pointer seems appropriate now.

       # In SMP systems, this may not be the interrupt stack we

       # actually need to use for this CPU. We fix that up later.

      

       movl       $__interrupt_stack, %esp

 

#if defined(CYG_HAL_STARTUP_FLOPPY) \

    || defined(CYG_HAL_STARTUP_ROM) \

    || defined(CYG_HAL_STARTUP_GRUB)

       # If we are here first, initialize the IDT. RAM startup

       # configurations can assume that Redboot has already set

       # the IDT up.

       hal_idt_init

#endif    

                                         

       hal_mon_init

 

       # Init FPU

       # Do this after the monitor init so that we can plant our

       # own FPU unavailable VSR.

      

       hal_fpu_init            # WARNING: may adjust stack pointer

      

       # Zero the BSS. If the BSS is not a whole number of words

       # long we will write up to 3 extra bytes at the end.

       # (This should not be a problem usually).

       movl       $__bss_end,%ecx         # ECX = end of BSS

       movl       $__bss_start,%edi  # EDI = base of BSS

       subl %edi,%ecx            # ECX = size of BSS

       addl $3,%ecx                # ECX += sizeof(long)-1

       shrl  $2,%ecx                # ECX >>= 2 = number of words to fill

       xorl  %eax,%eax            # EAX = 0 = fill value

       rep     stosl               # Fill it in

 

#ifdef CYG_HAL_STARTUP_ROM

 

       # In a ROM booted system, we also need to copy the data section

       # out to the RAM.

       movl       $__rom_data_start,%esi # ESI = base of ROM data area

       movl       $__ram_data_start,%edi # EDI = base of RAM data area

       movl       $__ram_data_end,%ecx # ECX = end of data

       subl %edi,%ecx            # ECX = size of data in bytes

       shrl  $2,%ecx                # ECX >>= 2 = number of words to copy

       rep     movsl                    # Copy it over

 

#endif    

      

       .extern hal_variant_init

       call  hal_variant_init

 

       .extern hal_platform_init

       call  hal_platform_init

 

#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS

       // This is here so we can debug the constructors.

       .extern initialize_stub

       call  initialize_stub

#endif

 

       .extern cyg_hal_invoke_constructors

       call  cyg_hal_invoke_constructors

 

#ifdef CYGPKG_HAL_SMP_SUPPORT

      

       # Now move SP to actual interrupt stack we will use for this

       # processor.

       hal_init_istack %esp

 

#ifndef CYG_HAL_STARTUP_RAM

       # Only start other CPUs when we are the original boot executable.

       # RAM executables are loaded via RedBoot, so only FLOPPY, GRUB

        # and ROM startups count here.

      

       .extern cyg_hal_smp_cpu_start_all

       call cyg_hal_smp_cpu_start_all

#endif

             

#endif

 

#ifdef CYGDBG_HAL_DEBUG_GDB_INITIAL_BREAK

        .extern breakpoint

        call breakpoint

#endif       

       .extern cyg_start

       call  cyg_start

 

       # Hmm.  Not expecting to return from 0.

1:     hlt

       jmp  1b

 

在函数 cyg_start 中,将进入 Redboot的执行流程。

 

这并不是很长的一段代码,却完成了整个PC的启动和初始化的部分。其中相当部分代码为汇编,所以要阅读这些代码必须首先对i386体系结构有基本的了解。

 

待续

 

 

 

 

Redbooti386)启动流程(二) - [源码分析]

接上篇

 

虽然 Redboot的启动过程已经相对简单,它没有使用分页机制,也没有区分内核态和用户态。

所有的代码都被放在一个段中统一编址。只使用了两个段(selector)一个为code,另一个为data。这个对于redbootsize(大概在100k左右吧)已经足够了。

 

如果对于一个操作系统来讲,这是一个相当程度简化的操作系统。即便如此,启动过程也不是一目了然的清晰。所以,这里仍然会忽略掉一些不太必要的内容,比如对SMPFPUGDB的支持等等。

 

整个启动过程中大概分为以下几个部分:

 

1. boot-loader: 这部分的工作就是将代码加载(load)到内存中,对于不同的设备,代码会装在不同的地方,通常PC会放在硬盘里面,某些嵌入式设备会把代码放在ROM(一般是flash)里面,而这里是放在软盘里面。boot-loader就是把软盘的代码load至内存,然后运行它们。

 

2. 进入保护模式,对于i386体系架构的cpu上电后缺省时实模式,内存访问空间也只有1M,这只是为了跟最初的8086兼容,所以要进入保护模式。

 

3. 初始化中断向量和异常。

 

4. 初始化基本的输入输出设备,如显示器,键盘,串行口等等。

 

5. 其他还有一些零散的初始化工作。

 

从下次开始将按运行次序对启动过程进行介绍。

 

待续

 

 

 

Redbooti386)启动流程(三) - [源码分析]

接上篇继续

 

 

_start之后的第一行是一个宏 hal_cpu_init 该宏定义在package/hal/i386/pcmb/v2_0/include/pcmb.inc 文件中。   由于从软盘引导,所以 hal_cpu_init分为两部分: 一部分是引导分区部分(以0xAA55结束),另一部分的功能是使CPU进入保护模式。

 

解释:PC上电后会进入BIOS, BIOS会检测磁盘(软盘和硬盘),如果软盘(或硬盘)的第一个分区是引导分区(以 0xAA55结束为标志)则将软盘的第一个分区内容加载到内存 0x7c00处,并运行它。

 

引导分区被运行之后,将整个redboot逐个分区地加载到0x3000为起始地址的内存空间。

 

注意:这个过程,引导分区内容会再次被加载到0x3000处,且马上会跳转到0x3000处执行引导分区的代码。而0x7c00处的内容会在后面被覆盖掉。

 

在执行加载工作前,会先执行两个小任务:

   1. 设置栈,栈顶为0x3000

   2. 通过BIOS提供的中断,得到扩展内存和标准内存大小,压入栈中

  

 

引导分区代码结束后,程序将进入保护模式。大概次序如下:

  1. 关中断

  2. 初始化GDTIDT

  3. 进入保护模式

  4. 设置数据段

  5. 重新设置栈段(因为保护模式和实模式,内存编址方式不同)

 

GDT主要用两个Selector分别是 0x08 (code) 0x10 (data)

 

寻址空间都是从0x00000000 - 0xFFFFFFFF

 

特权级(DPL) 0

 

IDT的地址为:0x1000

 

这部分比较复杂,这里不在详细说明,如果有时间,会在讨论i386架构的文章里,详细说明。而有关这部分的资料也相当丰富,可以在网上搜寻。

 

到这里hal_cpu_init已经执行结束了 ,不过进入保护模式还需要 激活A20地址线 。不激活A20地址线只能访问1M空间内的内存,激活A20才能访问所有内存。这个任务在另外一个宏 hal_memc_init 中实现,它位于文件 packages/hal/i386/arch/v2_0/include/arch.inc

 

这样,就完成了加载和进入保护模式的任务。

 

Redbooti386)启动流程(四) - [源码分析]

接上篇继续

进入保护模式之后做以下工作:

 

 设置中断栈空间,在之前栈定义在小于0x3000的内存空间中。通过

 movl $__interrupt_stack, %esp

 将栈重新设置在__interrupt_stack处,并分配了4096kB的栈空间。

 栈大小也可以通过改变cdl文件进行调整。

 

 

hal_idt_initpackages/hal/i386/pc/v2_0/include/platform.inc

  设置idt向量, 回头会在介绍中断的文章中介绍这部分。

 

BSS段初始化(清零)

解释: BSSBlock Started by Symbol)用来存放程序中未初始化的全局变量的一块內存区域,属于静态內存分配。

 

 

hal_platform_initpackages/hal/i386/pc/v2_0/src/plf_misc.c

  这部分是内容比较多,也比较重要。主要为 初始化 中断,异常 以及虚拟向量表。

  初始化虚拟向量表的工作通过调用函数 hal_if_init 来完成

eCos中设置了3张向量表,idt, hal_vsr_table, hal_virtual_vector_table

内存地址如下:

idtStart = 0x00001000;

hal_vsr_table = 0x00001800;

hal_virtual_vector_table = 0x00001c00;

idt 是硬件实际设置的中断区域,当中断发生后进入调用idt的中断向量。而eCosidt的中断向量有指向 hal_vsr_table

(猜测是为了隔离不同的cpu中断机制不同,专门设置了hal_vsr_table,使其中断处理方式一致)

 

hal_platform_init 函数中,初始化所有中断(和异常),设定为缺省的中断处理例程,以防止有中断意外发生,造成程序进入未知状态。

 

有关中断,异常,虚拟向量等相关处理机制内容比较多,会在以后的文章具体介绍。

 

cyg_hal_invoke_constructors

这个函数主要执行相关的构造函数,因为ecos一部分代码是用c++写的,所以有些类具有构造函数,需要在首先执行,这里面做这部分的处理。

 

 

 

cyg_start

最后则进入主函数 cyg_start 这个函数中,首先执行外围设备的初始化,之后就开始轮询处理用户输入的命令。

以上就是Redboot启动的全过程。由于篇幅有限,对很多部分没有深入讨论。在之后计划对以下部分进行讨论:

 

1 eCos设备驱动结构和编写

 

2 PCI设备的初始化过程

 

3 中断和异常处理过程

 

4 虚拟向量(hal_virtual_vector_table)介绍

 

5 Redboot 命令介绍

 

等等……

 
卓越网上书城 eCos & linux 及计算机 相关图书
 
嵌入式可配置实时操作系统 eCos 软件开发
市场价: ¥39
卓越价: ¥29.1
VIP价: ¥29.4
从卓越亚马逊购买

 

嵌入式实时操作系统μC\OS-Ⅱ原理及应用(高等院校通用教材)
市场价: ¥22
卓越价: ¥16.4
VIP价: ¥16.8
从卓越亚马逊购买

 

嵌入式操作系统基础μC/OS-Ⅱ和Linux
市场价: ¥35
卓越价: ¥26.2
VIP价: ¥26.4
从卓越亚马逊购买

 

基于VxWorks的嵌入式系统及实验
市场价: ¥35
卓越价: ¥27.2
VIP价: ¥26.5
从卓越亚马逊购买

 

源码开放的嵌入式实时操作系统T-Kernel(附光盘改订新版)/T-Engine论坛嵌入式系统技术系列丛书
市场价: ¥45
卓越价: ¥33.7
VIP价: ¥33.1
从卓越亚马逊购买

 

源码开放的嵌入式实时操作系统T-Kernel(附光盘改订新版)/T-Engine论坛嵌入式系统技术系列丛书
市场价: ¥45
卓越价: ¥33.7
VIP价: ¥33.1
从卓越亚马逊购买

 

鸟哥的Linux私房菜基础学习篇(第二版)
市场价: ¥65
卓越价: ¥48.3
VIP价: ¥47.4
从卓越亚马逊购买

 
Linux程序设计(第3版)
市场价: ¥89
卓越价: ¥64.9
VIP价: ¥64.9