>
首页 » 技术文章 » eCos操作系统针对并行S698P-SOC的启动初始化过程

eCos操作系统针对并行S698P-SOC的启动初始化过程

作者:颜军 许学艺  时间:2008-10-13 17:16  来源:
1 引言
SMP的全称是"对称多处理"(Symmetrical Multi-Processing)技术,是指在一个计算机上汇集了一组处理器(多CPU),各处理器之间共享同一个操作系统、内存子系统、总线结构和I/O系统等。它是相对非对称多处理技术而言的、应用十分广泛的并行技术。在这种架构中,一台计算机不再由单个处理器组成,而同时由多个处理器运行操作系统的单一复本,并共享内存和一台计算机的其他资源。虽然同时使用多个处理器,但是从管理的角度来看,它们的表现就像一台单机一样。系统将任务队列对称地分布于多个处理器之上,从而极大地提高了整个系统的数据处理能力。所有的处理器无主从之分,都可以平等地访问内存、I/O和外部中断。在对称多处理系统中,系统资源被系统中所有处理器共享,工作负载能够均匀地分配到所有可用处理器之上。并且因为结构共享存储器、统一地址空间,系统编程比较容易。
S698P-SOC处理器是欧比特(珠海)软件工程有限公司的S698系列的其中一款处理器,是一款高性能的、SPARC V8架构的、32-bit RISC嵌入式SMP微处理器。
S698P-SOC处理器内核结构如下:

S698P-SOC各处理器之间的通信是通过多核中断控制器(MP IRQCTRL)的中断来实现的,其结构如下:



S698P-SOC中的每个处理器都可以通过多核中断控制器向其它处理器发中断请求,每个处理器都可以响应其它处理器的中断请求,并且在多核中断控制器其中一个称为多处理器状态寄存(Multi-processor status register)的后16位(STATUS[15:0]),写入1,其相应的处理器启动。

 

31            28                                           16  15                                          0

 

 


NCPU

“000…0”

STATUS[15:0]

 


eCos(Embedded Configurable Operating System,嵌入式可配置操作系统)是一种针对16位、32位和64位处理器的可移植的开源嵌入式实时操作系统。eCos可在选定的处理器架构和平台上提供SMP支持。

eCos在它的SMP支持中加入了一些目标硬件限制,包括以下内容:

 最大支持处理器个数为8,典型是2或4;
 硬件必须提供测试并设置或者比较并交换指令同步机制。eCos内核使用这些硬件指令实现螺旋锁;
 不使用cache,或所有的处理器共享系统cache,或硬件维护cache的一致;
 所有的处理器共享的内存对所有的处理器的地址是一致的;
 每个处理器都可以访问任何外设;
 中断控制器必须将中断信号传送给指定的处理器;
 允许一个处理器上的事件导致另一个处理器的重新调度(需要允许系统中一个处理器中断另一个处理器的机制);
 在某个处理器上运行的软件必须能识别其所运行的处理器;

S698P-SOC满足eCos对SMP的硬件限制条件:

 S698P-SOC目前支持4核;
 S698P-SOC内有swapa指令,可以提供测试并设置同步机制,利用该条指令在eCos实现HAL_TAS_SET和HAL_TAS_CLEAR两个宏定义,eCos在HAL层以这两个宏来实现螺旋锁;
 在SMP系统中,各CPU通过Cache访问内存数据时,要求系统必须经常保持内存中的数据与Cache中的数据一致,若Cache的内容更新了,内存中的内容也应该相应更新,否则就会影响系统数据的一致性。S698P-SOC用总线侦听技术(snooping)维护了4个处理器的data cache的一致性;
 S698P-SOC所以的处理器共享系统sram和sdram,其编址是一致的,使编程容易;
 S698P-SOC中所有外设的寄存器,所有处理器都能访问到;所有外设的中断,都能引起所有处理器的中断处理,并且可以通过设置各处理器的中断屏蔽寄存器指明哪个外设的中断由哪个处理器处理;
 S698P-SOC各个处理器之间通过多核中断控制器(MP IRQCTRL)的中断来通信,允许将中断传递到系统中特定的处理器,该处理器执行中断处理函数,根据消息的内容执行优先级抢占重新调度或者时间片轮转调度;
   S698P-SOC各个处理器均有一个称为%asr17的寄存器,其31-28位(下图INDEX部分),指明当运运行的是哪个处理器,并由此实现CYG_KERNEL_CPU_THIS()宏定义,该宏定义得到当前是在哪个处理器上运行,程序可以根据这个宏定义作相应的处理。

SMP系统的启动顺序是不同的。其中定有一个处理器,称为主处理器(在S698P-SOC中,编号为0的是主处理器),处理启动初始化顺序;而其它处理器,称为附属处理器,或者被HAL置于待机状态,或者被HAL置于空闲循环。当应用程序调用cyg_sheduler_start函数,附属处理器启动运行。因此,S698P-SOC处理器上的启动初始化过程必然会根据%ars17寄存器分主从处理器分别初。,

本文将具体介绍eCos在S698P-SOC处理器上的启动初始化过程,使开发人员对eCos在S698P-SOC多核处理器运行有一个全局的了解。

2 启动初始化过程


下面详细说明上图所示的HAL启动过程中的每个操作:

1. eCos上电或者软复位后,S698P-SOC只启动cpu0,其它CPU处于power down状态。系统的程序指针会自动指向地址0。后程序搬移到0x40000000地址开始的内存区。运行的第一个程序是位于体系结构抽象层arch子目录中的vector.S文件。

2. vector.S执行代码一开始是定义了4K字节的中trap_table,该表包括256组trap。其中比较重要的有0号trap:硬件复位中断向量;5号和6号trap;寄存器窗口上溢和下溢处理中断向量;17-31号trap:外设中断1-15;128号:操作系统软件软中断处理向量。S698P-SOC所有的处理器的中断向量表是一样的。只是能够通过设置中断相关寄存器,指定哪个处理器响应哪个外设中断,而其它处理器不响应。

3.S698P-SOC的处理器0(其它处理器也一样)根据0号trap,跳转到genuine_reset:设置%tbr寄存器指定中断向量表的位置为 0x40000000 开始的 4K BYTE;设置%wim指明处理器的寄存器窗口数为8;清指令cache和数据cache;设置总线侦听使能(snoop enable),使各个处理器的数据cache能一致。

4. S698P-SOC的所有处理器根据%asr17(处理器配置寄存器)的31-28位,得到处理器的索引号,指明当前是运行在哪个处理器。执行代码如下:

rd     %asr17,%g2
srl    %g2,28,%g2

%g2为当前运行处理器的索引号,主处理器为0,其它处理器为大于0的数字。

5. 如果是处理器0,跳转到mastergo;
15.如果是S698P-SOC中的其它处理器(其它的处理器是由cpu0在mpstatus(多处理器状态寄存器寄存器)写入相应的位启动),程序执行cyg_hal_smp_start,设置%tbr,设置中断堆栈;设置%psr;

16 S698P-SOC中的其它处理器调用cyg_hal_smp_startup函数,设置该处理器已运行标志(在变量cyg_hal_smp_cpu_running相应位置位);检查是否内核设置了总线侦听使用,否则打印告警信息;系统运行处理器数量加1,指明多启动了一个核,以后系统调度可以使用该核;

17 S698P-SOC中的其它处理器调用cyg_kernel_smp_startup函数。在该函数内先用Cyg_Scheduler::lock()锁调度器,再调用Cyg_Scheduler::start_cpu(),该函数如下:

void Cyg_Scheduler::start_cpu()
{

#ifdef CYGPKG_KERNEL_SMP_SUPPORT
    Cyg_Interrupt * intr = new( (void *)&cyg_sched_cpu_interrupt[HAL_SMP_CPU_THIS()] )
    Cyg_Interrupt( CYGNUM_HAL_SMP_CPU_INTERRUPT_VECTOR( HAL_SMP_CPU_THIS() ),
                 0,
                 0,
                 cyg_hal_cpu_message_isr,
                 cyg_hal_cpu_message_dsr
                 );

    intr->set_cpu( intr->get_vector(), HAL_SMP_CPU_THIS() );
    intr->attach();
intr->unmask_interrupt( intr->get_vector() );
 #endif 
  register Cyg_Thread *next = scheduler.schedule();
  clear_need_reschedule();            // finished rescheduling
set_current_thread(next);           // restore current thread pointer
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
    CYG_REFERENCE_OBJECT( Cyg_Clock::real_time_clock );
#endif
    HAL_THREAD_LOAD_CONTEXT( &next->stack_ptr );   
}
该函数先生成Cyg_Interrupt中断处理类的一个实例,设置该中断在指定的处理器处理,再用attach()函数在指定的处理器通信中断(目前为14号中断)挂中断处理函数isr和dsr;再开放指定的中断。最后从调度器得到应该调度的一个任务,用HAL_THREAD_LOAD_CONTEXT载入该任务的上下文环境。从此,该处理器进入了多核运行调度环境;

6. S698P-SOC中的处理器0调用hal_sparc_leon_init函数,在该函数调用ahbslv_scan函数扫描IP核在AHB总线上的slave设备。调用apbslv_scan函数扫描IP核在APB总线上的slave设备。初始化中断控制器、定时器、串口。设置处理器0栈地址、%wim、%psr。如果不使用DSU,则设置内存配制寄存器1、内存配制寄存器2、sdram 控制寄存器;

7.S698P-SOC中的处理器0调用cyg_hal_start函数,该函数作S698P-SOC系统的硬件初始化操作。

8.S698P-SOC中的处理器0在cyg_hal_start函数中调用hal_board_prestart函数,执行板子开始运行前的处理动作;

9.S698P-SOC中的处理器0在 cyg_hal_start函数调用hal_zero_bss函数,清bbs段;

10.接下来在 cyg_hal_start函数调用cyg_hal_invoke_constructors函数,执行各个内嵌的构造函数;
11. cyg_hal_start函数调用hal_board_poststart函数,执行板子开始运行后的处理动作,在应该函数内调用amba_init函数和开放系统中断。其中,在amba_init函数中执行的amba总线的扫描,找出中断控制寄存器和定时器的起始地址;操作系统以后可以根据中断控制寄存器和定时器的起始地址对两者的寄存器进行配置。目前操作系统所需要的系统实时时钟由第一个定时器Timer1,中断编号为8。定时器的初始化函数如下:

void hal_sparc_leon3_clock_init(cyg_uint32 period) {
  cyg_hal_sparc_clock_period = (period);                      
 
  if (LEON3_GpTimer_Regs) {
    //设置定时器周期长度
    LEON3_BYPASS_STORE_PA(&LEON3_GpTimer_Regs ->e[0].val,(period));
    LEON3_BYPASS_STORE_PA(&LEON3_GpTimer_Regs ->e[0].rld,(period));
    LEON3_BYPASS_STORE_PA(&LEON3_GpTimer_Regs ->e[0].ctrl,0);
    //设置定时器使能并自动重启动
LEON3_BYPASS_STORE_PA(&LEON3_GpTimer_Regs ->e[0].ctrl,
LEON3_GPTIMER_EN |
LEON3_GPTIMER_RL |
LEON3_GPTIMER_IRQEN |
 LEON3_GPTIMER_LD);
  } else {
    diag_printf("Clock init failed");
  }
}

12. S698P-SOC中的处理器0调用cyg_hal_smp_init函数,检查处理器0是否打开了总线侦听机制,计算系统所有处理器的中断堆栈地址,设置变量cyg_hal_smp_cpu_running第0位为1,表明处理器0已经启动,变量cyg_hal_smp_cpu_running_count加1,表示系统中启动的处理器加了一个。
检查打开总线侦听的代码如下:
   
    if (cfg & ASI_LEON3_SYSCTRL_CFG_SNOOPING) {
      sparc_leon3_enable_snooping();
    }
    else {
      leon3smp_diag_printf("Caches disabled due to lack snooping\n");    
      sparc_leon3_disable_cache();
}

代码首先检查是否IP核配置了snooping,有则打开。没有则告警并关闭data cache;

13. S698P-SOC中的处理器0调用cyg_start函数,该函数是ecos的用户程序入口函数。用户程序至少要在这个函数内生成一个任务,并且这个任务处于可运行状态;

14.用户程序在cyg_start内调用cyg_scheduler_start函数,该函数调用调度器类的start()函数。在start函数内,处理器0调用cyg_hal_cpu_reset函数启动其它从处理器,并且调用Cyg_Scheduler 调度器类的start_cpu函数,如上述17所示,处理器0也加载了处理器之间通信的中断处理函数,并执行第一个任务;
  总之,主处理器执行1->2->3->4->5->6->7->8->9->10->11->12->13->14后,再启动其它三个从处理器;从处理器启动后,执行1->2->3->4->15->16->17->18。两者都完成后,系统进入了多核运行调度环境,eCos操作系统开始根据用户程序生成的任务以及之间的相互关系进行调度。至此,eCos操作系统针对S698P-SOC的启动初始化过程结束。


3 结束语
本文主要研究了eCos操作系统在S698P-SOC的启动初始化过程,并移植代码已在处理器上经过实际测试,系统稳定可靠,可运行多任务应用程序。本文所具体讨论的启动过程不仅有助于开发人员了解eCos操作系统的运行,而且有助于了解S698P-SOC多核处理器的工作原理,方便开发人员使用S698P-SOC多核处理器进行军用民用领域项目开发。

参考文献:
[1] S698P-SOC eCos Reference Manual, 欧比特(珠海)软件工程有限公司, 2006
[2] eCos使用说明, 欧比特(珠海)软件工程有限公司, 2006
[3] 嵌入式操作系统eCos在S698系列处理器上的移植,欧比特(珠海)软件工程有限公司,2006
[4] Anthony J.Massa,嵌入式可配置实时操作系统eCos软件开发(Embedded Software Development with eCos),北京航空航天大学出版社,2006
[5] John D, Carpinelli,计算机系统组成与体系结构 (Computer Systems Organization & Architecture),人民邮电出版社,2003

相关推荐

祝宁华:支撑光网络发展的光电子器件研究

光纤  通信  2013-12-05

物联网建立在通信应用之上 “链接”传统产业

物联网  通信  2013-10-11

高速关键器件和芯片技术列入优先发展

芯片  通信  2013-09-26

从物联网三层构建看现代信息技术的地位

物联网  通信  2013-09-10

统一通信必须要回归本质

IP  通信  2013-08-23

通信产业的“芯”痛:高通独大 国产遭难

高通  通信  2013-08-20
在线研讨会
焦点