上电后一般执行引导加载程序,这个程序可以初始化硬件设备,建立吸引的内存空间映射图,对于PC386体系,就是BIOS,嵌入式一般没有这个固化软件,直接由boot loader完成,bios进行完自检后,选择一个启动设备(软盘、硬盘、cd等),取得该设备的第一扇区(启动扇区)到内存的一个特定地址,至此BIOS完成,然后进行boot loader,嵌入式一般是grub。
以hello world rtems为例,grub如何加载rtems并把控制权交给rtems的,首先grub根据加载配置文件menu.lst找到rtems(hello.exe)的磁盘地址并加载到内存的特定地址。
系统初始化的第一阶段:
这部分代码一般是用汇编写的,属于bsp的一部分,然后进入基于c代码的初始化第二阶段,第一阶段的工作有:
屏蔽中断
初始化cpu工作模式
建立内核堆栈
对bss段清零
建立基本内存布局
代码位于rtems/c/src/lib/libbsp/i386/pc386/start/start.s
/*-------------------------------------------------------------------------+
| start.s v1.1 - PC386 BSP - 1997/08/07
+--------------------------------------------------------------------------+
| This file contains the entry point for the application.
| The name of this entry point is compiler dependent.
| It jumps to the BSP which is responsible for performing all initialization.
+--------------------------------------------------------------------------+
| (C) Copyright 1997 -
| - NavIST Group - Real-Time Distributed Systems and Industrial Automation
|
| http://pandora.ist.utl.pt
|
| Instituto Superior Tecnico * Lisboa * PORTUGAL
+--------------------------------------------------------------------------+
| Modified the 20/05/1998 by [email protected] in order to give a working
| example of eraly stage debugging via the DEBUG_EARLY_START define.
+--------------------------------------------------------------------------+
| Disclaimer:
|
| This file is provided "AS IS" without warranty of any kind, either
| expressed or implied.
+--------------------------------------------------------------------------+
| This code is based on an earlier generation RTEMS i386 start.s and the
| following copyright applies:
|
| **************************************************************************
| * COPYRIGHT (c) 1989-2012.
| * On-Line Applications Research Corporation (OAR).
| *
| * The license and distribution terms for this file may be
| * found in the file LICENSE in this distribution or at
| * http://www.rtems.org/license/LICENSE.
| **************************************************************************
+--------------------------------------------------------------------------*/
/*
* The most trivial start.s possible. It does not know anything
* about system it is running on, so it will jump to appropriate
* place in BSP specific place to do things it knows nothing about
*/
#include
#include
#include
/*----------------------------------------------------------------------------+
| Size of heap and stack:
+----------------------------------------------------------------------------*/
#ifndef CPU_STACK_ALIGNMENT
#error "Missing header ? CPU_STACK_ALIGNMENT NOT DEFINED"
#endif
.set STACK_SIZE, 0x1000
/*----------------------------------------------------------------------------+
| CODE section
+----------------------------------------------------------------------------*/
BEGIN_CODE
PUBLIC (start) # GNU default entry point
EXTERN (boot_card)
#if USE_VBE_RM
EXTERN (vesa_realmode_bootup_init)
#endif
EXTERN (_load_segments)
EXTERN (_return_to_monitor)
EXTERN (_IBMPC_initVideo)
EXTERN (debugPollingGetChar)
EXTERN (checkCPUtypeSetCr0)
EXTERN (printk)
#ifdef __SSE__
EXTERN (x86_capability)
#ifdef __SSE3__
EXTERN (x86_capability_x)
#endif
#endif
/*
* In case this crashes on your machine and this is not due
* to video mode set by the loader, you may try to define
* the following variable:
*/
/* #define DEBUG_EARLY_START */
SYM (start):
/*
* When things are really, REALLY!, bad -- turn on the speaker and
* lock up. This shows whether or not we make it to a certain
* location.
*/
#if 0
inb $0x61, al
orb $0x03, al
outb al, $0x61 # enable the speaker
speakl: jmp speakl # and SPIN!!!
#endif
nop
cli # DISABLE INTERRUPTS!!!
cld
/* Save multiboot info if we detect a multiboot loader */
cmp $0x2badb002,eax
jne 2f
/* We have multiboot info; let's hope DS and ES are OK... */
movl ebx, SYM(_boot_multiboot_info_p)
/* Check for memory size info and save */
movl ebx, esi
movl (esi), eax
movl eax, ebx
movl $SYM(_boot_multiboot_info), edi
/* save flags, always present */
movsd
/* flag 1 is memory */
and $1, eax
je 1f
movl $2, ecx
rep movsd
/* flag 2 is the command line */
1: movl ebx, eax
and $4, eax
je 3f
movl (_boot_multiboot_info_p), eax
movl 16(eax), esi
movl $255, ecx
2: movzbl (esi), eax
test al, al
je 3f
movb al, (edi)
inc edi
inc esi
dec ecx
je 3f
jmp 2b
3: xor al, al
movb al, (edi)
#ifdef DEBUG_EARLY_START
/*
* Must get video attribute to have a working printk.
* Note that the following code assume we already have
* valid segments and a stack. It should be true for
* any loader starting RTEMS in protected mode (or
* at least I hope so : -)).
*/
call _IBMPC_initVideo
/*
* try printk and a getchar in polling mode ASAP
*/
movl $welcome_msg, 0(esp)
call printk
addl $4, esp
/* call debugPollingGetChar */
#endif
/*----------------------------------------------------------------------------+
| Load the segment registers (this is done by the board's BSP) and perform any
| other board specific initialization procedures, this piece of code
| does not know anything about
|
| NOTE: Upon return, gs will contain the segment descriptor for a segment which
| maps directly to all of physical memory.
+----------------------------------------------------------------------------*/
jmp SYM (_load_segments) # load board dependent segments
/*----------------------------------------------------------------------------+
| Set up the stack
+----------------------------------------------------------------------------*/
PUBLIC (_establish_stack)
SYM (_establish_stack):
movl $_end, eax # eax = end of bss/start of heap
addl $STACK_SIZE, eax # make room for stack
subl $4, eax # reserve room for arg to 'boot_card'
andl $ - CPU_STACK_ALIGNMENT, eax # align SP on CPU_STACK_ALIGNMENT boundary
movl eax, esp # set stack pointer
movl eax, ebp # set base pointer
/*----------------------------------------------------------------------------+
| Zero out the BSS segment
+----------------------------------------------------------------------------*/
SYM (zero_bss):
cld # make direction flag count up
movl $ SYM (_end), ecx # find end of .bss
movl $ SYM (__bss_start), edi # edi = beginning of .bss
subl edi, ecx # ecx = size of .bss in bytes
shrl ecx # size of .bss in longs
shrl ecx
xorl eax, eax # value to clear out memory
repne # while ecx != 0
stosl # clear a long in the bss
#if BSP_ENABLE_VGA
/*-------------------------------------------------------------------+
| Initialize the video because zero_bss has cleared initVideo parameters
| if it was called earlier
| So from now we can use printk
+-------------------------------------------------------------------*/
call _IBMPC_initVideo
#if USE_VBE_RM
call vesa_realmode_bootup_init
#endif
#endif
/*---------------------------------------------------------------------+
| Check CPU type. Enable Cache and init coprocessor if needed.
+---------------------------------------------------------------------*/
call checkCPUtypeSetCr0
#ifdef __SSE__
call SYM(enable_sse)
#endif
/*---------------------------------------------------------------------+
| Transfer control to User's Board Support Package
| Note: at the top we reserved space for the argument
| so that
| initial_esp = ( TOS - 4 ) & ~(CPU_STACK_ALIGNMENT-1)
| this ensures that
| 1) esp is now aligned
| 2) there is space for the cmdline pointer which we just
| may store at *(esp)
+---------------------------------------------------------------------*/
movl $SYM(_boot_multiboot_cmdline), (esp)
call SYM (boot_card)
cli # stops interrupts from being processed after hlt!
hlt # shutdown
#ifdef __SSE__
/*--------------------------------------------------------------------+
| Enable SSE; we really only care about fxsave/fxrstor and leave
| The only feature *we* (as an OS) use is fxsave/fxrstor.
| But as a courtesy we make sure we don't execute on hardware
| that doesn't support features possibly used by the compiler.
+---------------------------------------------------------------------*/
PUBLIC (enable_sse)
SYM(enable_sse):
movl SYM (x86_capability), eax
testl $0x01000000, eax
jne 1f
movl $SYM (no_fxsave_msg), 0(esp)
jmp SYM(_sse_panic)
1:
testl $0x02000000, eax
jne 1f
movl $SYM (no_sse_msg), 0(esp)
jmp SYM(_sse_panic)
1:
#ifdef __SSE2__
testl $0x04000000, eax
jne 1f
movl $SYM (no_sse2_msg), 0(esp)
jmp SYM(_sse_panic)
1:
#endif
#ifdef __SSE3__
movl SYM (x86_capability_x), eax
testl $1, eax
jne 1f
movl $SYM (no_sse3_msg), 0(esp)
jmp SYM(_sse_panic)
1:
#endif
mov cr4, eax # OK to enable now
or $0x600, eax
mov eax, cr4
ret
SYM(_sse_panic):
call SYM(printk)
1: hlt
jmp 1b
#endif
END_CODE
BEGIN_DATA
PUBLIC(_boot_multiboot_info_p)
SYM(_boot_multiboot_info_p):
.long 0
PUBLIC(_boot_multiboot_info)
PUBLIC(_boot_multiboot_flags)
PUBLIC(_boot_multiboot_memory)
PUBLIC(_boot_multiboot_cmdline)
SYM(_boot_multiboot_info):
SYM(_boot_multiboot_flags):
.long 0 /* flags */
SYM(_boot_multiboot_memory):
.long 0 /* mem_lower */
.long 0 /* mem_upper */
SYM(_boot_multiboot_cmdline):
.rept 256 /* cmd line */
.byte 0
.endr
PUBLIC(_stack_size)
SYM(_stack_size):
.long STACK_SIZE
#ifdef DEBUG_EARLY_START
PUBLIC (welcome_msg)
SYM (welcome_msg) :
.string "Ready to debug RTEMS ?\nEnter \n"
PUBLIC (hex_msg)
SYM (hex_msg) :
.string "0x%x\n"
PUBLIC (made_it_msg)
SYM (made_it_msg) :
.string "made it to %d\n"
#endif
#ifdef __SSE__
SYM (no_fxsave_msg) :
.string "PANIC: compiled for SSE but CPU seems to have no FXSAVE/FXRSTOR support (which I need)\n"
SYM (no_sse_msg) :
.string "PANIC: compiled for SSE but your CPU seems to have no SSE support\n"
#ifdef __SSE2__
SYM (no_sse2_msg) :
.string "PANIC: compiled for SSE2 but your CPU seems to have no SSE2 support\n"
#endif
#ifdef __SSE3__
SYM (no_sse3_msg) :
.string "PANIC: compiled for SSE3 but your CPU seems to have no SSE3 support\n"
#endif
#endif
END_DATA
END
系统初始化第二阶段:
初始化rtems_cpu_table结构的cpu_table全局变量
初始化rtems_configuration_table结构体的configuration全局变量
设置rtems workspace区域
初始化中断和异常处理
初始化pci bios interface
其中cpu_table主要提供了一组bsp包中的关键函数指针,例如pretasking_hook、predriver_hook等。
执行流程:从boot_Card函数开始,大致的调用关系如下:bsp_cleanup-rtems_initialize_executive_late-rtems_initialize_executive_early-bsp_start
boot-card首先要更新cpu配置表和rtems配置表,因为下面的初始化工作很大程度上都是基于这两个配置表进行的,然后调用bsp_start函数,主要完成以下工作:
计算1ms时间指令loop值
进一步更新rtems的cpu配置表
根据rtems配置表,指定rtems的workspace的起始地址并分配空间
进一步初始化中断和异常管理
初始化pci bios interface
执行玩bsp_start函数后,进入系统初始化第三个阶段,开始执行rtems_initialize_early函数。
第三阶段:
最终目标,完成多任务切换,并切换到用户提供的任务,具体有:
初始化rtems核心层和系统服务层的功能组件
初始化驱动程序
进行任务初始化,切换到用户提供的任务
当bsp完成后,交给初始化管理器,其工作是负责启动和关闭rtems。启动rtems包括创建并启动所有的配置好的初始化任务,初始化设备驱动,然后将cpu控制移交给应用程序,应用程序退出后,初始化管理器完成对rtems的关闭。
在rtems的初始化管理器中,管理了三种用于初始化管理的任务:系统初始化任务、用户初始化、空闲任务。
其中系统初始化任务需要有足够的栈空间,否则无法初始化所有的设备驱动
用户初始化任务:定义在用户初始化任务表中,由应用程序具体实现,为了保证在其他应用任务启动前初始化任务能先启动,必须分配一个高的优先级。
init函数是一个典型的例子,该函数的内容就是用户初始化任务的主要工作。
空闲任务:由任务初始化任务创建并启动,只有当没有其他任务准备好运行的时候,空闲任务是一个优先级最低的任务,当其他任务就绪时,空闲任务使用处理器的权利就会被抢占,空闲任务一般的工作是让cpu休息。可以看看cpu pc386 bsp 的空闲任务是什么:
void_cpu_thread_idle_body()
{
while(1)
{
asm volatile("hlt");
}
}
初始化管理器运行失败的情况:
没有被提供cpu配置表或rtems配置表
rtems配置表中提供的rtems在workspace中入口地址是NULL
rtems中的workspace空间太小而不够设定初始化内容
指定的中断栈太小
没有配置用户初始化任务
有一个用户初始化任务但不能够被成功创建或启动。