2008年12月25日星期四

ARM Linux 启动过程 (1)

此系列记录了ARM Linux从Bootloader部分到Linux初始化,然后进入C环境的一段坎坷历程 。作为第一部分,我将从RedBoot开开始。RedBoot是嵌入式中应用广泛的Bootloader,他将作为此系列的序章。

RedBoot (bootloader)

  • 概述
  • RedBoot所作的工作

概述

(本示例讲解基于ARM9的Cirrus EP9302) Bootloader 在 ARM 中依然是加电后的第一道程序,其作用简单,相当于 PC 机器上的 BIOS 固件程序。Bootloader 负责完成系统初始化,它将非易失性储存器中的 Linux 内核 拷贝到 RAM 中去,然后跳转到内核的第一道指令,将控制权交给内核。从这个意义上讲, 嵌入式 Bootloader 要做的事情比 x86 等机器多很多。

一般ARM Linux的第一条指令地址是0x0000_0000,而通常嵌入式系统会将FLASH等存储寄存 器映射到这个地址,而Bootloader就位于该存储器顶端,这保证了Bootloader的顺利执行。

以 RedBoot for EP93xx 为例,EP93xx 采用 NAND Flash 作为存储介质,在 RedBoot 中可 以罗列存储器的根目录如下:

RedBoot> fis init
Name FLASH addr Mem addr Length Entry point
RedBoot 0x60000000 0x60000000 0x00040000 0x00000000
RedBoot config 0x60FC0000 0x60FC0000 0x00001000 0x00000000
FIS directory 0x60FE0000 0x60FE0000 0x00020000 0x00000000
zImage 0x60040000 0x00080000 0x00120000 0x00080000
ramdisk 0x60140000 0x00800000 0x00800000 0x00800000

这里可以看出在 Flash 文件系统中存储了他的系统文件 RedBoot(内核)、RedBoot config(设置信息)、FIS directory(系统目录),另外就是 Linux 的内核 zImage 和内 存盘 ramdisk.gz。

RedBoot做的工作

  1. SDRAM初始化,没有内存,啥东西也玩不转 (cyg/hal/hal_platform_setup.h)
  2. 初始化串口 (hal/arch/ARCH/src/hal_diag.c)
  3. 检测处理器类型 (宏指定,cdl/hal_ARCH_MACHINE.cdl)
  4. 设置Linux启动参数 (hal/ARCH/arch/src/redboot_linux_exec.c)
  5. 将Linux内核装载到内存中,跳转执行

启动内核

启动内核函数do_exec的这段代码在 hal/ARCH/arch/src/redboot_linux_exec.c,最重要的 就是末尾处的内联汇编语句:

    asm volatile (
CYGARC_HAL_MMU_OFF(%5)
"__tramp_start__:\n"
" cmp %1,%4;\n" // Default kernel load address. Relocate
" beq 2f;\n" // kernel image there if necessary, and
" cmp %2,#0;\n" // if size is non-zero
" beq 2f;\n"
"1:\n"
" ldr r0,[%1],#4;\n"
" str r0,[%4],#4;\n"
" subs %2,%2,#4;\n"
" bne 1b;\n"
"2:\n"
" mov r0,#0;\n" // Set board type
" mov r1,%3;\n" // Machine type
" mov r2,%6;\n" // Kernel parameters
" mov pc,%0;\n" // Jump to kernel
"__tramp_end__:\n"
: :
"r"(entry),
"r"(CYGARC_PHYSICAL_ADDRESS(base_addr)),
"r"(length),
"r"(CYGHWR_REDBOOT_ARM_MACHINE_TYPE),
#ifdef CYGHWR_HAL_ARM_EDB93XX_VARIANT
"r"((CYGHWR_REDBOOT_ARM_LINUX_EXEC_ADDRESS & 0x3ffffff) +
ConfigInfo[3]),
#else
"r"(CYGHWR_REDBOOT_ARM_LINUX_EXEC_ADDRESS),
#endif
"r"(CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_TRAMPOLINE_ADDRESS)),
"r"(CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_LINUX_TAGS_ADDRESS))
: "r0", "r1"
);
首先关闭MMU,保证代码跳转位置是绝对的物理地址,然后重置内核(如果需要)到entry处, 执行跳转,跳转前保证了:r0置0,r1装载机器类型,r2装载struct tag数组地址。

这样RedBoot结束了其短暂而又伟大的一生,我们进入Linux的世界。

2008年12月12日星期五

优化代码显示的另一个方法


int main(void)
{
printf("Hello, everybody!\n");
}
/* 为啥空出那么多呢?*/



参考:
http://klcintw4.blogspot.com/2006/11/blog-post_03.html

2008年12月10日星期三

Linux SCSI子系统

scsi历史

scsi-1::1979年由SHugart Associates创建,它定义了一种具有5MHz数据时钟的8-bit并行接口。

scsi-2::1985年,10MHz,16位总线。

scsi-3::1993年,已经成为了一种标准集,它包含一种命名为Ultra的并行scsi标准和基于 串行scsi和基于串行scsi的协议,这些标准通过引入存储网络技术将数据速率拓展到了 1Gb/s。

scsi架构基础

如果你是一位设计师,那么需要从scsi spec下手。而对于软件开发人员来说,你只需要关 注scsi的架构。在深入之前,将scsi架构图牢记于心,对于理解代码是非常重要的。linux scsi位于系统的底层 —

linux scsi本身是一种三层架构,upper, mid, lower,upper层最为接近内核,包括一组驱 动器(比如块设备SCSI 磁盘和字符设备SCSI generic);mid实现了common services layer, 接受upper的请求并将其转化为scsi请求,scsi lower层则是紧附硬件之上的硬件驱动。

索引

从ibm developerworks大致了解三层架构:

从这里获得scsi标准的细节:

我们的目标在于linux的实现(pdf, 321KB):

出发


本着记录和总结的目的,深入求实的精神,我开始在日志上记录scsi的看书笔记。scsi的设 备是典型的层次架构,经历过风雨变迁的scsi标准也散发着蓬勃的活力,因此看懂这段代码 很有意义。

笔记目标将会从sd_mod.o起步,清晰中间层(mid),上层(upper)和底层(lower)的大 致架构,最后深入到公司最近正在移植的sata_sil驱动。

2008年11月28日星期五

使用muse来发布日志

使用Emacs是一件实在幸福的事情,它提供了一个又一个强大的拓展,让你的上机活动变的
轻松惬意。很多Linux用户都是以Emacs为中心的。而我现在使用ECB阅读代码,diary-mode
来撰写笔记,org-mode来组织日程规划……这次说到使用muse模式。

muse允许通过简单的样式控制,制作出非常漂亮的网页。

  1. 控制基本样式
  2. 高亮代码

控制基本样式

很简单的,我先给出几个例子。

#title 第一个Wiki页面
* 一级标题
** 二级标题
*** 三级标题
#anchor
段落需要空行两个(至少)
居中字前只少空四格
----

这是 *着重* 的文字,这是进一步 **着重** 的文字,这是 ***更进一步的着重*** 的文字

这是 _下划线_ 文字,这是 =等宽verbatim and monospace= 的文字
*** 列表:
- 无序列表需要以空格和“-”开头
1. 有序列表需要以空格和数字序号开头
字典 :: 名词定义需要以“::”分隔名词和所定义文字
- 列表也可以嵌套
1. 列表嵌套深度按照开头空格的多少来控制
2. 可以继续嵌套不同类型的列表
- 比如这样
*** 表格:
Double bars || Separate header fields
Single bars | Separate body fields
Here are more | body fields
Triple bars ||| Separate footer fields

生成的页面:


高亮代码

高亮代码是一个比较头疼的问题,大家给出的方案也不一样。在blogger中,你可以使用
Google的prettyprint方法来实现高亮,但是它支持代码样式很少;同样2maomao也写了一个
高亮语法的工具,相对来说总是麻烦点;其实使用emacs高度的拓展性完全可以做到这点。

这里给出了一个使用muse来实现语法高亮的模式,这个方法非常的cool。它将emacs强大的
高亮特性报留下来,嵌入到了html中。

阅读上面的例子就可以看到,通过很少的字符,就可以实现工整的格式控制,这对于编写繁
杂冗长的标志语言和记住大批的标记来说,是一种极好的替代。muse编写的脚本可以简单的
声称很多种文档发布,包括HTML,Latex,PDF等等,多多使用,也自然可以可以极大提高工
作效率。

参考资料

  1. Emacs Wiki
  2. Emacs muse官方网站

2008年11月27日星期四

eCos HAL分析

HAL架构

HAL在eCos中是一个多层次的架构,层级封装了不同的功能,它包括:

  • the architecture HAL

    架构抽象包含基本的CPU架构,比如interrupt,上下文切换,CPU启动等

  • the variant HAL

    变体抽象层专注某一CPU的特性,比如caches,MMU和FPU等,他通常也处理内存和中断 控制器等外设。

  • the platform HAL

    平台抽象层专注于现任的平台特性,比如平台启动,定时器,I/O寄存器访问和中断控 制器等等。

HAL接口

这里讲究HAL实现了哪些接口。

architecture characterization

这里包含了CPU基础架构的定义。包括了CPU段文存储格式,上下文切换,bit twiddling, 断点,堆栈大小和地址转换。这些定义位于:

  1. cyg/hal/hal_arch.h (arch HAL)
  2. cyg/hal/var_arch.h (var HAL)
  3. cyg/hal/plf_arch.h (plf HAL)

以下为议题细节

  • register save format
  • thread context initialization
  • thread context switching
  • bit indexing
  • idle thread activity
  • reorder barrier
  • breakpoint support
  • GDB support
  • setjmp and longjmp support
  • stack sizes
  • address translation
  • global pointer

interrupt handling

这些接口定义了中断处理相关的定义,包括了异常和中断号,中断允许和屏蔽和实时时钟操 作。这些定义可以位于:

cyg/hal/hal_intr.h (arch HAL)

而变体和平台抽象层定义位于:

  1. cyg/hal/var_intr.h (var HAL)
  2. cyg/hal/plf_intr.h (plf HAL)
  3. cyg/hal/hal_platform_ints.h (?)

议题细节:

  • vector numbers
  • interrupt state control
  • ISR and VSR management
  • interrupt controller management
  • clock control
  • microsecond delay

HAL I/O

此接口定义了对设备控制寄存器的访问支持。

  1. cyg/hal/hal_io.h
  2. cyg/hal/var_io.h
  3. cyg/hal/plf_io.h

议题细节有:

  • register address
  • register read
  • register write

cache control

此接口定义了CPU caches的控制支持。

  1. cyg/hal/hal_cache.h
  2. cyg/hal/var_cache.h
  3. cyg/hal/plf_cache.h

详细议题:

  • cache dimensions
  • global cache control
  • cache line control

Linker scripts(连接器脚本,lds)

连接器脚本对于eCos程序来说是必须的,他定义了内存区域,地址和尺寸,代码段和数据段 的放置位置,还有分配不同的编译器声称的段。

一般lds位于install/lib/target.ld,它事实上是由其他两类文件声称,一个基本的lds和 ldi文件声称的。

基本lds由arch HAL或者var HAL提供,它由一组lds段组成。ldi由plf HAL提供哦你,它包 含目标平台的的内存布局信息,位于

pkgconf/mlt____.ldi

这些ldi文件都是由相应的mlt(memory layout tool)脚本生成的。

诊断支持

SMP支持


参考资料

  1. eCos component writer's guide
  2. eCos HAL porting guide
  3. 如何构建eCos嵌入式系统