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驱动。