rtems初始化过程分析

上电后一般执行引导加载程序,这个程序可以初始化硬件设备,建立吸引的内存空间映射图,对于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

大致流程:屏蔽中断-读取grub传递的info信息-跳转到load_srgments处,加载全局描述符-跳转到establish_stack处,建立rtems内核栈空间-清除BSS-调用initvideo函数进行视频显示器初始化-调用checkcpu函数查找cpu类型-调用第一个c函数boot_card


系统初始化第二阶段:

初始化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空间太小而不够设定初始化内容

指定的中断栈太小

没有配置用户初始化任务

有一个用户初始化任务但不能够被成功创建或启动。



你可能感兴趣的:(RTEMS,rtems开发)