一.内核结构
/arch 所有硬件结构特定的kernel代码。多平台设计所用,如i386,alpha,arm(与体系结构相关的代码都存放在arch//和include/asm-/目录下。如arm体系则是arch/arm和include/asm-arm.);
/drivers 内核中所有的设备驱动程序,如usb和sound;
/fs 所有的文件系统的代码,如ntfs,ext3,jffs2等;
/include 建立内核代码时所需要的大部分库文件,这个模块利用其他模块重建内核。该目录也包括了不同平台需要的库文件,如asm-arm是arm平台需要的库文件;
/init 内核的初始化代码,内核从此处开始工作;
/ipc 进程间通信代码;
/kernel 主内核代码;
/mm 所有内存管理代码;
/net 和网络相关的代码,如atm,ipv6等;
一般在每个目录下都有一个.depend文件和一个Makefile文件。这两个文件都是编译时使用的辅助文件。
1./arch
linux系统能支持如此多平台的部分原因是因为内核把sourcecode清晰地划分为与体系结构无关部分和体系结构相关部分。/arch包含与体系结构相关的代码.其中每一个目录代表一种硬件平台,such as arm,i386.对任何平台,都必须包括以下几个目录:
/boot:启动内核所使用的部分或全部平台特有代码;
/kernel:存放支持体系结构特有的(如信号处理和SMP)特征的实现;
/lib:存放告诉的体系结构特有的(如strlen和memcpy)通用的函数的实现;
/mm:存放体系结构特有的内存管理程序的实现;
/math-emu:模拟FPU的代码。对于arm处理器来说,此目录用mach-xxx代替。
So,移植工作的重点就是 /arch目录下的文件。
2./dirvers
所有的设备驱动程序。它占整个内核发行版本代码的一半以上,非常庞大。有些驱动程序是与硬件平台无关的而有些是相关的。
3./fs
所有的文件系统的代码。如ntfs,ext3,jffs2等。一般来说,文件系统也与硬件平台无关。
4./include
建立编译内核代码时所需要的大部分头文件,例如与平台无关的头文件在/include/linux下。不同的平台需要的头文件会有所不同,因此该目录和/arch一样,按平台划分了多个sub-dir,such as asm-arm.
5./init
内核的初始化代码(不是系统的引导代码),有main.c和version.c两个文件。这是研究核心如何工作的好起点。
6./ipc
进程间通信代码.
7./kernel
内核管理的核心代码。与处理器相关的代码都放在archmm下。
10./net
和网络相关的代码,如atm,ipv6等.其每一个子目录对应网络的一个方面。
11./其他
还有两个dir.:/documentation including many docs和/scripts主要在配置内核时用到,存放了配置内核的一些脚本文件,如make menuconfig.
-----------------------------------------
二、下载核心以及相应补丁:
Linux核心:linux-2.4.18.tar.bz2
下载地址:
下载补丁:
patch-2.4.18-rmk7.gz
patch-2.4.18-rmk7-swl8.gz
patch-2.4.18-rmk7-swl8-cy2.gz
patch-2.4.18-rmk7-swl8-cy2-lc3.gz
(补丁下载地址一:
下载地址二:)
然后解压缩:
# tar xzvf linux-2.4.18.tar.gz
# gunzip patch-2.4.18-rmk7.gz
# gunzip patch-2.4.18-rmk7-swl8.gz
# gunzip patch-2.4.18-rmk7-swl8-cy2.gz
# gunzip patch-2.4.18-rmk7-swl8-cy2-lc3.gz
打补丁:
# cd linux-2.4.18
# patch -p1 < ../patch-2.4.18-rmk7
# patch -p1 < ../patch-2.4.18-rmk7-swl8
# patch -p1 < ../patch-2.4.18-rmk7-swl8-cy2
# patch -p1 < ../patch-2.4.18-rmk7-swl8-cy2-lc3
在移植之前,先说下自己在移植时发生的错误,像我这种菜鸟级的初学者,也难免会发生。我最开始的内核是linux-2.4.20,因为随便下的一个内核, 就照着步骤移植,结果配置好后,发现不能用make menuconfig,其它的像make xconfig也不能用,都进不去界面,总是说有段错误。在网上也没查出什么原因来,当时以为配置错了,重搞了好几遍都不行,又用排除法,发现在改了 ARCH := arm后,就不能用。找到原因有了关键字百度就方便了,在网上找了半天,才搞明白需要一个ARM的补丁,目前最高的是2.4.19-rmk7,所以大家别 和我一样用2.4.20编译ARM内核。所有的补丁打上后,几乎不需要再做下面的工作了,就可以直接移植到开发板上了。这几个补丁实在是太好了,之前只用 了第一个补丁,搞了半个月也没能移植成功,后来找到后面的几个补丁,几分钟就搞定了。
三、 Linux操作系统的移植
假定内核代码存放在/usr/src/linux-2.4.18下,并设置环境变量$KERNELCODE=/usr/src/linux-2.4.18
1.根目录
只需要修改Makefile文件。这里Makefile的任务是:产生vmlinux文件和产生内核模块.
它将递归进入到内核的各个子目录中,分别调用位于这些子目录中的Makefile.起到组织内核的各模块,记录各模块的相互联系和以来关系。(建议一定读懂Makefile文件。)
对最上层的Makefile的修改:
a:指定目标平台
移植前: ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
移植后: ARCH := arm
b:指定交叉编译器
移植前: CROSS_COMPILE =
移植后: CROSS_COMPILE = arm-linux- //反正是指定交叉编译程序的目录.
2.arch目录
这里存放着和体系结构相关部分的内核代码。
2.1 修改arch/arm目录下的Makefile
手动添加:
ifeq ($(CONFIG_ARCH_S3C2410),y)
TEXTADDR = 0xC0008000
MACHINE = s3c2410
endif
TEXTADDR决定内核起始运行地址,即image.ram应下载的地址。
要点:根据自己的电路设置TEXTADDR变量。
这里我们的电路地址是0xC0008000:从地址0xC0000000开始,总共32MB的空间。
2.2 修改arch/arm目录下的config.in
配置文件,运行make menuconfig命令时出现的菜单就是config配置的。
a.在System Type菜单中添加S3C2410-based选项。
mainmenu_option next_comment
comment 'System Type'
choice 'ARM system type' \
"Anakin CONFIG_ARCH_ANAKIN \
Archimedes/A5000 CONFIG_ARCH_ARCA5K \
Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \
CLPS711x/EP721x-based CONFIG_ARCH_CLPS711X \
Co-EBSA285 CONFIG_ARCH_CO285 \
EBSA-110 CONFIG_ARCH_EBSA110 \
Epxa10db CONFIG_ARCH_CAMELOT \
FootBridge CONFIG_ARCH_FOOTBRIDGE \
Integrator CONFIG_ARCH_INTEGRATOR \
LinkUp-L7200 CONFIG_ARCH_L7200 \
RiscPC CONFIG_ARCH_RPC \
SA1100-based CONFIG_ARCH_SA1100 \
S3C2410-based CONFIG_ARCH_S3C2410 \
Shark CONFIG_ARCH_SHARK" RiscPC \
b.添加CONFIG_ARCH_S3C2410子选项
if [ "$CONFIG_ARCH_S3C2410" = "y" ]; then
comment 'S3C2410 Implementation'
dep_bool ' SMDK (MERI TECH BOARD)' CONFIG_S3C2410_SMDK $CONFIG_ARCH_S3C2410
fi
c. 其他选项:
添加"$CONFIG_ARCH_S3C2410" = "y" -o \
if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \
"$CONFIG_ARCH_SHARK" = "y" -o \
"$CONFIG_ARCH_CLPS7500" = "y" -o \
"$CONFIG_ARCH_EBSA110" = "y" -o \
"$CONFIG_ARCH_CDB89712" = "y" -o \
"$CONFIG_ARCH_EDB7211" = "y" -o \
"$CONFIG_ARCH_S3C2410" = "y" -o \
"$CONFIG_ARCH_SA1100" = "y" ]; then
define_bool CONFIG_ISA y
else
define_bool CONFIG_ISA n
fi
类似的添加项不只一处,读者可以根据需要在需要的地方加入。
d.还有一处需添加,不然后面的make zImage会错误
# we use the PC-type keyboard map?
if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \
"$CONFIG_ARCH_SHARK" = "y" -o \
"$CONFIG_ARCH_SA1100" = "y" -o \
"$CONFIG_ARCH_INTEGRATOR" = "y" -o \
"$CONFIG_ARCH_TBOX" = "y" -o \
"$CONFIG_ARCH_CLPS7500" = "y" -o \
"$CONFIG_ARCH_P720T" = "y" -o \
"$CONFIG_S3C2410_SMDK" = "y" -o \
"$CONFIG_ARCH_ANAKIN" = "y" ]; then
define_bool CONFIG_PC_KEYMAP y
fi
移植要点:config文件决定了menuconfig菜单的内容。把使用的平台加在需要的地方,这样在配置linux内核时就能够选择是否支持你的平台了。
3 arch/arm/boot目录
编译出来的内核是存放在这个目录中。这里将指定内核解压到目标板的地址,所以如果内核无法正常启动,很有可能是这里的地址指定错误。
3.1 Makefile
ifeq ($(CONFIG_ARCH_S3C2410),y)
ZTEXTADDR = 0x30008000
ZRELADDR = 0x30008000
endif
------
ZRELADDR决定内核解压后数据输出的地址。
ZTEXTADDR为bootloader的压缩内核文件烧入flash的起始地址,即从哪个位置开始执行bootloader,若启动时直接运行,则将其设为0;若自带bios可以跳到想要的地址,则可改为所要的位置。
移植要点:要根据自己的电路设置ZTEXTADDR和ZRELADDR变量。
3.2 compressed/Makefile
通过这个文件将从vmlinux创建一个压缩的vmlinuz镜像。此文件中用到的SYSTEM,ZTEXTADDR,ZBSSADDR和ZRELADDR是从arch/arm/boot/Makefile获得的。
ifeq ($(CONFIG_ARCH_S3C2410),y)
OBJS = head-s3c2410.o
endif
移植要点:加入head-s3c2410.S
3.3 arch/arm/boot/compressed/head-s3c2410.S
主要用来init处理器。好好研究下汇编代码//如何进行初始化需要仔细研究处理器的手册。
#include
#include
#include
.section ".start", #alloc, #execinstr
__S3C2410_start:
bic r2, pc, #0x1f @清除pc中的相关位,存放在寄存器r2中
add r3, r2, #0x4000 @ r3
1: ldr r0, [r2], #32 @r0
teq r2, r3 @compare contents of two regs
bne 1b
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c7, c7, 0 @ flush I & D caches
#if 0
@ 禁用mmu和caches
mrc p15, 0, r0, c1, c0, 0 @ read control register
bic r0, r0, #0x05 @ disable D cache and MMU
bic r0, r0, #1000 @ disable I cache
mcr p15, 0, r0, c1, c0, 0 @使前面的设置生效
#endif
mov r0, #0x00200000
1: subs r0, r0, #1
bne 1b
-------------------
Note that:arm的D cache必须和MMU一起打开,而I cache可以单独打开。
3.4 arch/arm/def-configs目录
定义了一些平台的config文件,比如lart和assert等.把配置好的文件复制到这里就可以了。
3.5 arch/arm/kernel目录
与硬件平台相关的内核代码
3.5.1 Makefile
a.add the support for s3c2410x
no-irq-arch := $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \
$(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \
$(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT) \
$(CONFIG_ARCH_S3C2410) $(CONFIG_ARCH_MX1ADS) \
$(CONFIG_ARCH_PXA)
b.add other function
obj-$(CONFIG_MIZI) = event.o
obj-$(CONFIG_APM) = apm2.o
移植要点:有任何新加的功能都要告知Makefile文件。上述两条语句的目的是编译event.c和apm2.c,当然需要将这两个文件拷贝到当前目录,不需要的话可省略这步.
3.5.2 debug-armv.S
在适当的地方加入如下代码,目的是关闭全部外围设备的时钟,从而保证系统正确运行.
#elif defined(CONFIG_ARCH_S3C2410)
.macro addruart,rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled 查看是否运行mmu?
moveq \rx, #0x50000000 @ physical base address
movne \rx, #0xf0000000 @ virtual address
.endm
.macro senduart,rd,rx
str \rd, [\rx, #0x20] @ UTXH
.endm
.macro waituart,rd,rx
.endm
.macro busyuart,rd,rx
1001: ldr \rd, [\rx, #0x10] @ read UTRSTAT
tst \rd, #1 @ TX_EMPTY ?
beq 1001b
.endm
3.5.3 entry-armv.S
加入cpu的中断部分。
#elif defined(CONFIG_ARCH_S3C2410)
#include
.macro disable_fiq
.endm
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
mov r4, #INTBASE @ virtual address of IRQ registers
ldr \irqnr, [r4, #0x8] @ read INTMSK
ldr \irqstat, [r4, #0x10] @ read INTPND
bics \irqstat, \irqstat, \irqnr
bics \irqstat, \irqstat, \irqnr
beq 1002f
mov \irqnr, #0
1001: tst \irqstat, #1
bne 1002f @ jump if found IRQ
add \irqnr, \irqnr, #1
mov \irqstat, \irqstat, lsr #1
cmp \irqnr, #32
bcc 1001b
1002:
.endm
.macro irq_prio_table
.endm
---
移植要点:了解cpu初始化时是如何处理中断的。寄存器在s3c2410.h中定义。
3.5.4 setup.c
这个文件中有一个非常重要的函数setup_arch。这个函数用来完成和体系相关的初始化工作,比如对物理内存结构meminfo的初始化。这个结构将 在后面的内存初始化中起到很重要的作用。其中,nr_banks指定了内存块的数量,bank指定了每块内存的范围。用来指定块开始及长度的 PAGE_OFFSET和MEM——SIZE都在include/asm-arm/arch-s3c2410/memory.h中定 义,PAGE_OFFSET是内存的开始地址,这块板子设置该值为0x00000000UL,就是前面介绍的init和data的开始地址,结束地址自然 就是内存的结束地址。后文介绍的函数就将根据meminfo进行内存结构初始化。
3.6 arch/arm/mm目录
此目录下的文件是和arm平台相关的内存管理内容,只有mm-armv.c文件需要移植。
把init_maps->bufferable = 0;
改为:
init_maps->bufferable = 1;
3.7 arch/arm/mach-s3c2410目录
这里只是对处理器的基本信息提供了支持,有关开发板的外设,如usb,powermanage等都需要用户自己添加。(可参考相应开发板配套cd).
三、 编译linux内核
之前要配置内核:
make config;
make oldconfig;
make menuconfig;
make xconfig.
无论哪个命令都产生一个.config文件,并在每个.c文件中加上,使define的宏CONFIG_XXX起全局性作用。
查看内核的配置:
make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig
执行make dep
make zImage
make modules
make modules_install
安装内核需要copy 4个文件:没压缩的内核镜像zImage,压缩的内核镜像vmlinux,内核符号映射文件System.map以及配置文件.config.
zImage文件是和平台无关的,它在Makefile文件中设置。这里使用arm平台,so生成的镜像文件在/arch/arm/boot/zImage下。其他三个文件在内核代码的根目录/usr/src/linux-2.4.18下.
对创建的内核进行backup的好处是能通过配置文件知道内核的功能。比如是否lcd的驱动,是否有bluetooth等。代码如下:
cp arch/arm/boot/zImage $(YOURBAKPATH)/image/zImage-2.4.18-rmk7
cp System.map $(YOURBAKPATH)/image/System.map-2.4.18-rmk7
cp vmlinux $(YOURBAKPATH)/image/vmlinux-2.4.18-rmk7
cp .config $(YOURBAKPATH)/image/2.4.18-rmk7.config