本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接。内容可任意使用,但对因使用该内容引起的后果不做任何保证。
这里使用的单板是通过Qemu模拟的一块smdkc210单板,CPU类型为Samsung的Exynos4 (cortex-A9的核)。开发环境是Ubuntu 12.04。
2.1 Memory map
u-boot用于加载linux系统,因此需要提前规划好内存布局。下图中是目标smdkc210的的内存布局(可以在Qemu上使用info mtree命令查看)。内存占据了4G到8G这段空间。ARM系统默认的启动地址为0。smdkc210的这个位置上有一块ROM,通过x命令可以发现它会跳转到地址0x40010000,而u-boot.bin也会被加载到这个位置。通过info roms命令,可以查看Qemu加载ROM的位置。从这时起,内存如何使用就取决于我们如何设置u-boot了。
此时u-boot已经被放到RAM中了,但这只是Qemu为了执行后续操作。在真是的单板中,u-boot通常会被放到ROM中,而不是内存中。因此u-boot启动后会尽快把自己拷贝到RAM中(一般是RAM的最后)。这里我们也保留这一拷贝操作。同时为uImage与uRamDisk设定加载位置。加载位置选择的原则是不要与u-boot互相覆盖。
图 1:内存布局
2.2 设置Qemu虚拟机
a) $ apt-get install qemu.
该命令用于在ubuntu上安装Qemu。也可以下载Qemu源码,自己编译。
b) $ qemu-system-ARM -M ?
查看Qemu支持的单板类型:
Supported machines are: none empty machine smdkc210 Samsung SMDKC210 board (Exynos4210) realview-pbx-a9 ARM RealView Platform Baseboard Explore for Cortex-A9 |
可以看到Qemu支持smdkc210单板。
2.3 注册板类型
a) 设置编译器.
由于是交叉编译,需要设置要使用的编译器。编译器由变量CROSS_COMPILE指定,同时通过变量BUILD_DIR设置临时文件与目标文件的保存路径。默认的保存路径是与源文件根目录,这样会与源文件混在一起,不利于管理。
这两个变量可以通过make命令传入,但每次都要输入它们。更好的方式是直接把它们在Makefile中设置好:
export CROSS_COMPILE=arm-qhao-Linux-gnueabi- export BUILD_DIR=../obj/u-boot/tmp$(ARCH) $(shell mkdir -p $(BUILD_DIR)) |
b) 注册板类型
u-boot支持的板类型保存在boards.cfg中。其格式如下:
# Status, Arch, CPU:SPLCPU, SoC, Vendor, Board name, Target, Options, Maintainers
Active ARM ARMv7 exynos samsung smdkc210 smdkc210 - Marco Hao |
Target 名是该单板的唯一标示,不能重复。注册板类型命令如下:
$ make smdkc210_config
如果boards.cfg中找不到对应的单板,则需要自己增加新的板类型。
如果注册成功,则显示如下信息:
Configuring for smdkc210 board... |
板信息会被存储到“obj/u-boot/tmpARM/include/config.mk”中:
ARCH = ARM CPU = ARMv7 BOARD = smdkc210 VENDOR = samsung SOC = exynos |
2.4 编译 u-boot
$ make
如果u-boot已经支持该单板,执行这个命令就可以完成编译,生成u-boot与u-boot.bin。但如果不支持,则需要一些额外操作。
如果要加入新的单板类型,千万不要试着从头写。选择一个类似的单板类型,照着它进行改造。这里选择smdkv310,因为它与smdkc210都是三星的开发板,同样都是使用exynos4。相信他们的结构会非常类似。
对于新的板类型smdkc210,需要增加下面的几个文件:
1) include/configs/smdkc210.h
单板的配置文件,记录了单板的硬件信息。(拷贝自smdkv310.h).
2) board/samsung/smdkc210/smdkc210.c’
单板的一些独有的配置函数。(拷贝自smdkv310.c).
有时,新单板与参考单板的某些期间不一样,所以需要的驱动也不一样。比如,smkdc210与smkdv310使用的串口设备不一样,所以需要改变串口驱动类型。所有的串口驱动都在“drivers/serial”目录中。通过查看smdkv310.h得知smdkv310设置了宏CONFIG_S5P。打开“drivers/serial/Makefile”,信息如下:
COBJS-$(CONFIG_S5P) += serial_s5p.o COBJS-$(CONFIG_SYS_NS16550_SERIAL) += serial_ns16550.o COBJS-$(CONFIG_IMX_SERIAL) += serial_imx.o COBJS-$(CONFIG_IXP_SERIAL) += serial_ixp.o COBJS-$(CONFIG_KS8695_SERIAL) += serial_ks8695.o |
因此我们知道smdkv210选择的串口驱动是serial_s5p.c。假设smdkc210使用的是serial_ns16550.c,则需要在smdkc210.h中把CONFIG_S5P替换成CONFIG_SYS_NS16550_SERIAL。
2.5 在Qemu上加载u-boot
如下命令用于启动Qemu,指定的单板类型为smdkc210,加载的image为u-boot.bin:
$ my_tap=$(sudo /usr/sbin/tunctl -b) $ sudo ifconfig $my_tap 192.168.2.100 netmask 255.255.255.0 $ sudo qemu-system-ARM -machine smdkc210 -m 1024m -kernel u-boot.bin \ -monitor stdio -serial vc -net nic,vlan=0 -net tap,vlan=0,ifname=$my_tap,script=no $ sudo /usr/sbin/tunctl -d $my_tap |
2.6 设置tftp服务器
u-boot启动后,通常会通过tftp的方式加载linux影响与文件系统,下面的命令用于在Ubuntu上安装与启动tftp
a) 安装tftp
sudo apt-get install xinetd tftpd tftp
b) 创建并加入下面的信息,sserver_args指定了tftp的根路径。
service tftp { protocol = udp port = 69 socket_type = dgram wait = yes user = nobody server = /usr/sbin/in.tftpd server_args = /tftpboot disable = no } |
a) 设置根路径
从上面的配置中可以看到根路径的user是nobody,所以需要把根路径的所有者改成nobody,并且好设置根路径的读写权限:
$ sudo mkdir /tftpboot $ sudo chmod -R 777 /tftpboot $ sudo chown -R nobody /tftpboot |
b) Restart the xinetd service.
$ sudo /etc/init.d/xinetd restart
c) Additional command of tftp:
$ sudo /etc/init.d/xinetd start
$ sudo /etc/init.d/xinetd stop
2.7 下载 Linux kernel 与 uRamDisk
加载命令如下
$ Tftp 0x7c000000 uImage $ Tftp 0x7d000000 uRamDisk $ Bootm 0x7d000000 0x7c000000 |
u-boot要加载linux kernel,需要配置网卡、设置启动参数、下载与启动kernel等多个步骤,可以在启动u-boot后通过控制台命令进行设置,也可以在配置文件中写死,好处是启动后可以自动完成上述步骤。单板配置文件在include/configs目录下,与单板同名,我们这里的板子配置文件是smdkc210.h。
#define CONIFG_ETHADDR 00:e0:0c:bc:e5:61 #define CONFIG_IPADDR 192.168.2.102 #define CONFIG_NETMASK 255.255.255.0 #define CONFIG_SERVERIP 192.168.2.100 #define CONFIG_GATEWAYIP 192.168.2.100
#define CONFIG_RAMBOOT_COMMAND \ "setenv bootargs root=/dev/ram rw init=/linuxrc console=ttyAMA0;" \ "tftp 7f000000 uRamDisk;" \ "tftp 7e000000 uImage;" \ "bootm 7e000000 7f000000"
#define CONFIG_EXTRA_ENV_SETTINGS \ "bootargs=root=/dev/ram rw init=/linuxrc console=ttyAMA0\0" \ "netdev=eth0\0" \ "consoledev=ttyAMA0\0" \ "loadaddr=7e000000\0" \ "bootfile=uImage\0" \ "ramdiskaddr=7f000000\0" \ "ramdiskfile=uRamDisk\0" \ "" #define CONFIG_BOOTCOMMAND CONFIG_RAMBOOT_COMMAND |
本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接。内容可任意使用,但对因使用该内容引起的后果不做任何保证。