第三章第三节 加载地址和入口地址
在上一节中,无法启动内核,导致的原因可能是加载地址、入口地址等导致的。执行./mkimage之后如下:
zhuzhaoqi@zhuzhaoqi-desktop:~/u-boot/u-boot-2013.04/u-boot-2013.04/tools$ ./mkimage
./mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
其中-a addr指的就是镜像在内存中的加载地址,镜像下载到内存中时,要按照用mkimage制作镜像时,这个参数所指定的地址值来下载。
而-e ep 是指定镜像运行的入口点地址。
还有两个概念需要明白,即是bootm address和kernel运行地址。bootm address:通过uboot的bootm命令,从address启动kernel。kernel运行地址:在具体mach目录中的Makefile.boot中指定,是kernel启动后实际运行的物理地址。
如果bootm address和Load Address相等,在这种情况下,bootm不会对uImage header后的zImage进行memory move的动作,而会直接go到Entry Point开始执行。因此此时的Entry Point必须设置为Load Address+ 0x40。如果kernel boot过程没有到uncompressing the kernel,就可能是这里设置不对。它们之间的关系为:boom address == Load Address == Entry Point - 0x40。
如果bootm address和Load Address不相等(但需要避免出现memory move时出现覆盖导致zImage被破坏的情况)。此种情况下,bootm会把uImage header后的zImage文件move到Load Address,然后go到entry point开始执行。这段代码在common/cmd_bootm.c中bootm_load_os函数中,如下程序所示。由此知道此时的Load Address必须等于Entry Point。它们之间的关系则为:boom address != Load Address == Entry Point。
case IH_COMP_NONE:
if (load == blob_start || load == image_start)
{
printf(" XIP %s ... ", type_name);
no_overlap = 1;
}
else
{
printf(" Loading %s ... ", type_name);
memmove_wd((void *)load, (void *)image_start,
image_len, CHUNKSZ);
}
*load_end = load + image_len;
puts("OK\n");
break;
zImage的头部有地址无关的自解压程序,因此刚开始执行的时候,zImage所在的内存地址(Entry Point)不需要同编译kernel的地址相同。自解压程序会把kernel解压到编译时指定的物理地址,然后开始地址相关代码的执行。在开启MMU之前,kernel都是直接使用物理地址(可参看内核符号映射表System.map)。
通过上面的分析,大概找出了问题的根源,由于bootm address和Load Address都为50008000,属于相等情况,也就是说Entry Point: 50008000,这个地址需要修改,替换成50008040。
找到Load Address和Entry Point这两个地址的定义,存在于scripts/makefile.lib中,
zhuzhaoqi@zhuzhaoqi-desktop:~/Linux/linux-3.8.3/scripts$ gedit Makefile.lib
打开之后可以找到如下:
318 UIMAGE_LOADADDR ?= arch_must_set_this
319 UIMAGE_ENTRYADDR ?= $(UIMAGE_LOADADDR)
这里就是说Entry Point等于Load Address,那么应该修改成为Entry Point=Load Address+0x40,在GNU make中,有sed –e替换操作,如sed -e "s/..$$/40/",就是把输出的字符串的最后两个字符删掉,并且用40来补充,也就是说把字符串最后两个字符用40来替换。
那么作如下修改:
318 UIMAGE_LOADADDR ?= arch_must_set_this
319 #UIMAGE_ENTRYADDR ?= $(UIMAGE_LOADADDR)
320 UIMAGE_ENTRYADDR ?=$(shell echo $(UIMAGE_LOADADDR) |
sed -e "s/..$$/40/")
修改完成之后,回到linux-3.8.3根目录下进行编译,如下操作:
zhuzhaoqi@zhuzhaoqi-desktop:~/Linux/linux-3.8.3$ make uImage
如果有如下报错:
zhuzhaoqi@zhuzhaoqi-desktop:~/Linux/linux-3.8.3$ make uImage
scripts/kconfig/conf --silentoldconfig Kconfig
*** Error during update of the configuration.
make[2]: *** [silentoldconfig] 错误 1
make[1]: *** [silentoldconfig] 错误 2
make: *** 没有规则可以创建“include/config/kernel.release”需要的目标“include/config/auto.conf”。停止。
那就是权限的问题,要么修改文件权限,要么在root下编译。这样即可:
zhuzhaoqi@zhuzhaoqi-desktop:~/Linux/linux-3.8.3$ sudo make uImage
编译成功之后输出如下信息:
······
Image Name: Linux-3.8.3
Created: Sat Mar 16 10:38:47 2013
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1664080 Bytes = 1625.08 kB = 1.59 MB
Load Address: 50008000
Entry Point: 50008040
Image arch/arm/boot/uImage is ready
从串口输出可知,Entry Point=Load Address+0x40,依旧按照SD烧写方式进行测试,如果bootdelay延时过长,可以修改bootdelay时间,如下操作:
Hit any key to stop autoboot: 0
zzq6410 >>> set bootdelay 3
zzq6410 >>> sav
Saving Environment to NAND...
Erasing Nand...
Erasing at 0x80000 -- 100% complete.
Writing to Nand... done
zzq6410 >>>
重启OK6410开发平台,测试结果如下:
NAND read: device 0 offset 0x100000, size 0x500000
5242880 bytes read: OK
## Booting kernel from Legacy Image at 50008000 ...
Image Name: Linux-3.8.3
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1664080 Bytes = 1.6 MiB
Load Address: 50008000
Entry Point: 50008040
Verifying Checksum ... OK
XIP Kernel Image ... OK
OK
Starting kernel ...
Starting kernel ...
Uncompressing Linux... done, booting the kernel.
Booting Linux on physical CPU 0x0
Linux version 3.8.3 (zhuzhaoqi@zhuzhaoqi-desktop) (gcc version 4.4.1 (Sourcery G++ Lite 2009q3-67) ) #1 Fri Mar 15 12:56:52 CST 2013
CPU: ARMv6-compatible processor [410fb766] revision 6 (ARMv7), cr=00c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
Machine: OK6410
Memory policy: ECC disabled, Data cache writeback
CPU S3C6410 (id 0x36410101)
S3C24XX Clocks, Copyright 2004 Simtec Electronics
S3C64XX: PLL settings, A=533000000, M=533000000, E=24000000
S3C64XX: HCLK2=266500000, HCLK=133250000, PCLK=66625000
mout_apll: source is fout_apll (1), rate is 533000000
mout_epll: source is epll (1), rate is 24000000
mout_mpll: source is mpll (1), rate is 533000000
usb-bus-host: source is clk_48m (0), rate is 48000000
irda-bus: source is mout_epll (0), rate is 24000000
CPU: found DTCM0 8k @ 00000000, not enabled
CPU: moved DTCM0 8k to fffe8000, enabled
CPU: found DTCM1 8k @ 00000000, not enabled
CPU: moved DTCM1 8k to fffea000, enabled
CPU: found ITCM0 8k @ 00000000, not enabled
CPU: moved ITCM0 8k to fffe0000, enabled
CPU: found ITCM1 8k @ 00000000, not enabled
CPU: moved ITCM1 8k to fffe2000, enabled
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 65024
Kernel command line: root=/dev/mtdblock2 rootfstype=cramfs console=ttySAC0,115200
PID hash table entries: 1024 (order: 0, 4096 bytes)
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
__ex_table already sorted, skipping sort
Memory: 256MB = 256MB total
Memory: 256532k/256532k available, 5612k reserved, 0K highmem
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
DTCM : 0xfffe8000 - 0xfffec000 ( 16 kB)
ITCM : 0xfffe0000 - 0xfffe4000 ( 16 kB)
fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
vmalloc : 0xd0800000 - 0xff000000 ( 744 MB)
lowmem : 0xc0000000 - 0xd0000000 ( 256 MB)
modules : 0xbf000000 - 0xc0000000 ( 16 MB)
.text : 0xc0008000 - 0xc02bed88 (2780 kB)
.init : 0xc02bf000 - 0xc02da7a4 ( 110 kB)
.data : 0xc02dc000 - 0xc03076a0 ( 174 kB)
.bss : 0xc0308000 - 0xc0338ef8 ( 196 kB)
SLUB: Genslabs=13, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
NR_IRQS:246
VIC @f6000000: id 0x00041192, vendor 0x41
VIC @f6010000: id 0x00041192, vendor 0x41
sched_clock: 32 bits at 100 Hz, resolution 10000000ns, wraps every 4294967286ms
Console: colour dummy device 80x30
Calibrating delay loop... 353.89 BogoMIPS (lpj=1769472)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
Setting up static identity map for 0x502149a8 - 0x50214a04
DMA: preallocated 256 KiB pool for atomic coherent allocations
OK6410: Option string ok6410=0
OK6410: selected LCD display is 480x272
s3c64xx_dma_init: Registering DMA channels
PL080: IRQ 73, at d0846000, channels 0..8
PL080: IRQ 74, at d0848000, channels 8..16
S3C6410: Initialising architecture
bio: create slab at 0
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
ROMFS MTD (C) 2007 Red Hat, Inc.
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
s3c-fb s3c-fb: window 0: fb
Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
s3c6400-uart.0: ttySAC0 at MMIO 0x7f005000 (irq = 69) is a S3C6400/10
console [ttySAC0] enabled
s3c6400-uart.1: ttySAC1 at MMIO 0x7f005400 (irq = 70) is a S3C6400/10
s3c6400-uart.2: ttySAC2 at MMIO 0x7f005800 (irq = 71) is a S3C6400/10
s3c6400-uart.3: ttySAC3 at MMIO 0x7f005c00 (irq = 72) is a S3C6400/10
brd: module loaded
loop: module loaded
s3c24xx-nand s3c6400-nand: Tacls=4, 30ns Twrph0=8 60ns, Twrph1=6 45ns
s3c24xx-nand s3c6400-nand: System booted from NAND
s3c24xx-nand s3c6400-nand: NAND soft ECC
NAND device: Manufacturer ID: 0xec, Chip ID: 0xd5 (Samsung NAND 2GiB 3,3V 8-bit), 2048MiB, page size: 4096, OOB size: 218
No oob scheme defined for oobsize 218
……
Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
中间作者省去了很多信息,因为这些信息暂时对我们是没有太大关系,但是也给出了很多信息,因为可以很好地和接下来的每一步移植作对比。从串口的输出,可以得知内核是启动了。也就是说,此时u-boot已经成功将相关参数传递给linux3.8.3内核,完成了u-boot到内核的交接。并且内核已经识别了是OK6410开发平台,控制CPU是s3c6410等信息。
当然,读者不仅仅可以通过修改Entry Point使得内核启动,还可以修改启动内核的地址使得bootm address和Load Address不相等,也就是修改U-Boot源码中include/configs/目录下的s3c6410.h文件中:
#ifdef CONFIG_ENABLE_MMU
#define CONFIG_SYS_MAPPED_RAM_BASE 0xc0000000
#define CONFIG_BOOTCOMMAND"nand read 0xc0018000 0x600000x1c0000;\"bootm 0xc0018000"
#else
#define CONFIG_SYS_MAPPED_RAM_BASE CONFIG_SYS_SDRAM_BASE
#define CONFIG_BOOTCOMMAND"nand read 0x50018000 0x100000 0x500000;"\"bootm 0x50018000"
#endif