Chinaunix首页 | 论坛 | 博客
  • 博客访问: 48401
  • 博文数量: 26
  • 博客积分: 59
  • 博客等级: 民兵
  • 技术积分: 145
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-17 14:45
文章分类

全部博文(26)

文章存档

2012年(1)

2011年(25)

我的朋友

分类: LINUX

2011-02-25 09:15:06

 
作了一年的Linux+ARM了,整理了一些东西上来,希望对大家能有点用,欢迎批评指正!

 

                                 uClinux的执行过程

 uCinux的启动主要经历三个阶段。首先,必须完成CPU和存储器的硬件初始化,在系统RAM中建立程序堆栈和数据段,建立程序的运行时的环境。初始化完成之后,uClinux内核就取得了CPU的控制权,开始操作系统自身的初始化,这包括建立RAM中断矢量表、加载设备驱动程序、内存管理模块等等。这一切完成后,uClinux启动一个最初的init线程,进入到第三阶段,这时内核已经正常运行,外围模块也都就绪,开始执行一些脚本文件(如/etc/rc脚本文件)。               

                       .kernel代码段之前的系统初始化

 

1. uClinux-dist/linux-2.4.x/arch/armnommu/boot/compressed/head.S

    开发板从上电开始,最开始执行的程序放在uClinux-dist/linux-2.4.x/arch/armnommu/boot/compressed/head.S.

   (1) 切换模式,关闭中断. (line 96 )

   (2) 首先程序要先给SYSCFG,EXTDBWTH,ROMCON0等一系列系统控制寄存器赋值,此时flash地址在   0X0,DRAM地址在0X1000000.(line 141 )

   (3) 点亮I/O口的指示灯. (line 152 )

   (4) 把在flash上的image复制到DRAM.(line 161 )

   (5) 执行remap,flash地址映射为0X1000000,DRAM地址映射为0.(line 172 )

   (6) 打开cachewrite buffer.(line 196 )

   (7) 设置好64K堆栈.(line 204 )

   (8) 跳转到decompress_kernel函数(line 217 ),此处的跳转为带返回的跳转,以便于执行完此函数跳转回来.

2. uClinux-dist/linux-2.4.x/arch/armnommu/boot/compressed/misc.c

     此时的函数decompress_kernel是用C语言写的,line 297 .

   (1) makecrc();进行crc校验.

   (2) puts("Uncompressing Linux..."); 输出linux起动后的第一句话.

   (3) gunzip();解压缩kernel.

   (4) puts(" done, booting the kernel. ");

3. uClinux-dist/linux-2.4.x/arch/armnommu/boot/compressed/head.S

   执行完decompress_kernel函数后,kernel又跳转回head.S,因为此时我们还要检验解压缩之后的kernel起始地址是否紧接着kernel image,如果是,beq call_kernel(line 220),执行解压后的kernel.

   如果解压缩之后的kernel起始地址不是紧接着kernel image,执行relocate(line 236),将其拷贝到紧接着kernel image的地方,然后跳转,执行解压后的kernel.

                          .kernel执行

1.uClinux-dist/linux-2.4.x/init/main.c中的start_kernel()  (line 352)

   

   系统启动过程到此,转入体系结构无关的通用C代码中,start_kernel() 中调用了一系列初始化函数,以完成kernel本身的设置。这些动作有的是公共的,有的则是需要配置的才会执行的。

    (1) 输出Linux版本信息(printk(linux_banner)

    (2) 设置与体系结构相关的环境(setup_arch()

    (3) parse_options(command_line);解析command_line,将其转化为环境变量.

    (4) 初始化系统IRQinit_IRQ()

    (5) 核心进程调度器初始化(sched_init()

    (6) 软中段初始化softirq_init();

    (7) 时间、定时器初始化(包括估测主频、初始化定时器中断等,time_init()

    (8) 控制台初始化console_init();

    (9) 核心CACHE初始化kmem_cache_init(); 

    (10)延迟校准calibrate_delay();

    (11)内存初始化(设置内存上下界和页表项初始值,mem_init() 

    (12)文件,目录,块设备读写缓冲区初始化

    (13)检查体系结构漏洞(check_bugs()

    (14)启动init过程(创建第一个核心线程,调用init()函数,原执行序列调用cpu_idle() 等待调度,init()

   至此start_kernel()结束,基本的核心环境已经建立起来了。

2.uClinux-dist/linux-2.4.x/init/main.c中的init() (line 548)

现在我们进入内核引导第二部分,init()函数作为核心线程,首先锁定内核(仅对SMP机器有效,我们为空函数),然后调用 do_basic_setup() (line 551)完成外设及其驱动程序的加载初始化。

过程如下:

    * 网络初始化(初始化网络数据结构,包括sk_init()skb_init()proto_init()三部分,在proto_init()中,将调用protocols结构中包含的所有协议的初始化过程,sock_init()

    * 创建事件管理核心线程(start_context_thread()函数,这是系统创建的第二个内核线程,名叫“keventd”。其代码context_thread()也在kernel/context.c中,)

启动任何使用__initcall标识的函数(方便核心开发者添加启动函数,此时由do_initcalls()函数启动)。

    此时系统开始加载外部设备的初始化程序,如:在linux-2.4.xdriverlockgenhd.c中的device_init()函数,在genhd.c中由__initcall(device_init)标识在此时调用,device_init()函数是所有外部设备初始化的总入口,包括了块设备的初始化blk_dev_init,网络设备的初始化net_dev_init()atmdev_init()等。

   至此do_basic_setup()函数返回init(),在释放启动内存段(free_initmem())并给内核解锁以后,init()打开/dev/console设备,重定向stdinstdoutstderr到控制台,最后,搜索文件系统中的init程序(或者由init=命令行参数指定的程序),并使用 execve()系统调用加载执行init程序。(line 576) .

   init()函数到此结束,内核的引导部分也到此结束了,

3. uClinux-dist/linux-2.4.x/init/main.c中的execve("/etc/init",argv_init,envp_init); (line 579)

  

    init进程是系统所有进程的起点,内核在完成核内引导以后,即在本线程(进程)空间内加载init程序,它的进程号是1

   init程序需要读取/vendors/SAMSUNG/4510B/inittab文件作为其行为指针,然后执行.

4.系统执行rc脚本.

hostname Samsung

/bin/expand /etc/ramfs.img /dev/ram0

/bin/expand /etc/ramfs2048.img /dev/ram1

mount -t proc proc /proc

mount -t ext2 /dev/ram0 /var

mount -t ext2 /dev/ram1 /ramdisk

chmod 777 /ramdisk

mkdir /var/config

mkdir /var/tmp

mkdir /var/log

mkdir /var/run

mkdir /var/lock

ifconfig lo 127.0.0.1

route add -net 127.0.0.0 netmask 255.255.255.0 lo

dhcpcd &

cat /etc/motd

rc程序执行完毕后,系统环境已经设置好了,下面就该用户登录系统了。

5.运行Sash command shell

uclinux 的代码行数统计

uclinux 2.4内核总共:

程序总行数:4837046行,

代码行:    3385356

注释行:    824721

空行:      642779

s3c4510使用的文件

程序总行数:308363

代码行总数:2066773

注释行总数:58706

空白行总数:43131

在配置uclinux是添加菜单:

一.

linux 2.4menuconfig,添加驱动程序菜单,需要修改两个文件

config.in(也可能为Config.in)Makefile

:把程序mydriver.c放在drivers/char目录下

1.修改drivers/char/Config.in,在合适的位置加上一行:

tristate 'XXXXXXXX' CONFIG_XXXX

2. 然后需要修改drivers/char/Makefile,在合适的位置,加上

obj-$(CONFIG_XXXX) += mydriver.o

这样,就可以在make menuconfig时选择配置自己的驱动程序了

二.在menuconfig中加入菜单:

要想添加自己的选项,可以在uClinux-distlinux-2.4.xarcharmnommuconfig文件中加入:比如要添加一个xxxxx菜单:

mainmenu_option next_comment

comment xxxxxx’

tristate 'xxxxxx?' CONFIG_xxxx

if [ "$CONFIG_xxxx" != "n" ]; then 

 //如果选择该选项,则调用相应目录的config.in显示下一级菜单,原理与这个相同

   source drivers/xxxx/Config.in

fi

endmenu

此菜单出现在自定义内核的 第一级菜单,要显示下一级菜单,则在相应目录的config.in开头,添加:(比如添加一个MTD驱动,则在drivers/MTD/Config,in

mainmenu_option next_comment

Comment 'Memory Technology Devices (MTD)'

tristate 'Memory Technology Device (MTD) support' CONFIG_MTD

Comment引号里面的为显示的内容,tristate后面表示选择此选项,则CONFIG_MTD为真,为后面的程序进行条件编译

比如选中此选项后要出现相应的选项进行选择,则可以如下面所示:

if [ "$CONFIG_MTD" = "y" -o "$CONFIG_MTD" = "m" ]; then

   bool 'Debugging' CONFIG_MTD_DEBUG

   if [ "$CONFIG_MTD_DEBUG" = "y" ]; then

      int '  Debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_MTD_DEBUG_VERBOSE 0

   fi

   dep_tristate '  MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD

   dep_tristate '  MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD

   dep_tristate '  RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS

   dep_tristate '  Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS $CONFIG_MTD_PARTITIONS

   if [ "$CONFIG_ARM" = "y" ]; then

      dep_tristate '  Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS

      dep_tristate '  ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS

   fi

fi

fi用来表示一个if条件的结束。

dep_tristate后面引号内的内容就是选择时出现的菜单内容,dep_tristate用于tristate的下一级菜单显示,后面的选项意义同上。

与平台相关的代码:

需要修改的系统源码主要有如下几处:

(1) bootloader相关代码。此代码位于uClinuxlinux-2.4.xarcharmnommuootcompressed目录下名为head.s的文件中。此处程序用汇编语言实现,需要修改的地方主要是设置memory map的代码,与memory controller的硬件实现相关。

(2) drivers li mian UART deng相关代码。UART相关代码位于uClinuxlinux-2.4.xdriverschar目录下的serial.c,并修改uClinux-2.4.x/drivers/Makefile,添加相应的驱动

(3) 定时器相关代码。uClinux中有如下函数调用star_kernel()->time_init()->setup_timer(),需要修改uClinux-2.4.x/include/asm-armnommu/arch-s3c44b0/time.h setup_timer()函数中的相关代码,hardware.h

uClinux-2.4.x/arch/armnommu/mach-s3c44b0/time.c

(4) 中断控制器相关。uClinuxlinux-2.4.xarcharmnommumach-s3c44b0irq.c

(5)

修改uClinux-2.4.x/arch/armnommu/kernel/entry-armv.S

修改uClinux-2.4.x/arch/armnommu/kernel/head-armv.S

修改 uClinux-2.4.x/arch/armnommu/mm/proc-arm6,7.S

uClinux-distlinux-2.4.xarcharmnommu目录下添加相应CPU的文件夹

并修改armnommu下面的config.inMakefile.

修改uClinux-distlinux-2.4.xarcharmnommuootcompressed目录下的Makefile

修改uClinux-distlinux-2.4.xarcharmnommuoot下的Makefile

修改uClinux-2.4.x/arch/armnommu/kernel/entry-armv.S

修改uClinux-2.4.x/arch/armnommu/kernel/head-armv.S

修改 uClinux-2.4.x/arch/armnommu/mm/proc-arm6,7.S

修改uClinux-2.4.x/drivers/Makefile

在修改源代码时,可按照uclinux启动和执行顺序依次修改整个平台。

uclinux的移植大致可以分为:

·结构层次的移植,如果待移植处理器的结构不同于任何已经支持的处理器结构,

则需要修改linux/arch目录下相关处理器结构的文件。虽然uclinux内核代码的

大部分是独立于处理器和其体系结构的,但是其最低级的代码也是特定于各个系

统的。这主要表现在它们的中断处理上下文、内存映射的维护、任务上下文和初

始化过程都是独特的。这些例行程序位于linux/arch/目录下。由于linux所支持

体系结构的种类繁多,所以对一个新型的体系,其低级例程可以模仿与其相似的

体系例程编写。

·平台层次的移植,如果待移植处理器是某种uclinux已支持体系的分支处理器,

则需要在相关体系结构目录下建立相应目录并编写相应代码。如mc68ez328

是基于无mmum68k内核的。此时的移植需要创建

linux/arch/m68knommu/platform/ mc68ez328目录并在其下编写跟踪程序(实现

用户程序到内核函数的接口等功能)、中断控制调度程序和向量初始化程序等。

下面以添加 s3c44b0为例:

一、加入S3C44B0的在make menuconfig时的厂商/产品选项。

    uClinux-distvendorsSamsung下新建S3C44B0目录,将uClinux-distvendorsSamsung4510B下的内容全部复制到S3C44B0目录下。这里有几个文件较为重要:

    config.linux-2.4.x”这个是linux内核编译配置选项文件。现在针对S3C44B0我们要修改的是# System Type# General setup之间的内容。修改如下:

#

# System Type

#

# CONFIG_ARCH_DSC21 is not set

# CONFIG_ARCH_CNXT is not set

# CONFIG_ARCH_SWARM is not set

CONFIG_ARCH_S3C44B0=y            #指明是处理器类型是S3C44B0

# CONFIG_ARCH_ATMEL is not set

CONFIG_NO_PGT_CACHE=y

CONFIG_CPU_32=y

# CONFIG_CPU_26 is not set

CONFIG_CPU_ARM710=y

CONFIG_CPU_WITH_CACHE=y

# CONFIG_CPU_WITH_MCR_INSTRUCTION is not set

CONFIG_SERIAL_S3C44B0=y          #使用S3C44B0的串口

DRAM_BASE=0x0c000000             #SDRAM起始是地址

DRAM_SIZE=0x00800000             #SDRAM大小

FLASH_MEM_BASE=0x00000000        #FLASH起始地址

FLASH_SIZE=0x00200000            #FLASH大小

#

# General setup  

以后的make都以CONFIG_ARCH_S3C44B0=y这选项来解决是编译和S3C44B0相关的其他选项。

    make config后在Vendor/Product下可以看到有Samsung/S3C44B0的选项了

二、在linux内核加入对44B0处理器的支持。

    上面讲了如何在uClinux中加入S3C44B0的在make config时的厂商/产品选项。现在主要讲述如何在在uClinux的内核加入对44B0处理器的支持。

因为三星的S3C44B0X处理器无MMU。这里主要修改uClinux-distlinux-2.4.xarcharmnommu下的config.inMakefileconfig.in是我们在make config时选择Customiae Kernel Settings(自定义内核)时的编译项配置文件。

config.in里找有关4510的编译选项“CONFIG_ARCH_SAMSUNG”:

#--------------------------------------------------------------------

#                               S y s t e m

#--------------------------------------------------------------------

mainmenu_option next_comment

comment 'System Type'

choice 'ARM system type'   

     "TI-DSC21        CONFIG_ARCH_DSC21

      Conexant        CONFIG_ARCH_CNXT

      SWARM            CONFIG_ARCH_SWARM

      Samsung        CONFIG_ARCH_SAMSUNG

      S3C44B0           CONFIG_ARCH_S3C44B0

      Atmel            CONFIG_ARCH_ATMEL" TI-DSC21

其中“S3C44B0           CONFIG_ARCH_S3C44B0 ”是要加入的。另外还有一处:

管理员在2009年8月13日编辑了该文章文章。

-->
阅读(1181) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~