分类: 嵌入式
2009-09-07 23:22:39
1. 为vmware 添加新的硬盘
fdisk 用法就算了
mkfs -t ext3 -c /dev/sdb1 (我看就不用 -c 参数了吧, check bad block 就不用了, 俺的E4500真快阿,郁闷为啥叫sdx了呢)
df 看看
vim /etc/fstab 添加到系统fstab
/dev/sdb1 /cross ext3 default 1 2
(man fstab,mount) 不备份 fsck检查顺序
2. cross build principle
--------------------------------------------------------------------------------
1) 准备source code (host:linux targe:arm-linux)
binutils-2.18
gcc-core-4.1.2
gcc-g++4.1.2
glibc-2.6.1
linux-2.6.24.4
--------------------------------------------------------------------------------
2) 定义环境变量 (然后解压缩...)
export PREFIX=/cross/cross-arm cross gcc的bin会放到这个目录
export TARGET=arm-linux arm 上的linux
cd /cross/src 假设你下载的gcc 和binutil在这个目录(你当然要解压缩了)
mkdir build-binutils build-gcc build-glibc
--------------------------------------------------------------------------------
3) binutils (要分清host和target啊...)
cd /cross/src/build-binutils
../binutils-x.xx/configure --target=$TARGET --prefix=$PREFIX --disable-nls
make all
make install
--disable-nls :不要使用汉语吧, 用英语就行了. 这个选项让gcc不输出汉语的提示...
--------------------------------------------------------------------------------
4) bootstrap gcc
cd /cross/src/build-gcc
export PATH=$PATH:$PREFIX/bin
../gcc-x.x.x/configure --target=$TARGET --prefix=$PREFIX --disable-nls
--enable-languages=c --without-headers --disable-shared --disable-threads --disable-libmudflap --disable-libssp
make all-gcc
make install-gcc
-without-headers :这个选项使你编译出的GCC不能使用标准库.(host cpu和target cpu一样的话,基本不用cross toolchain系统通过编译选项也能实现这个功能).
--with-newlib 这只是个bug的work around,和newlib没有关系的.
This is only necessary if you are compiling GCC <= 3.3.x. That version has a known bug that keeps --without-headers from working correctly. Additionally setting --with-newlib is a workaround for that bug.
--enable-languages :tell gcc需要哪些语言支持:font end, bootstrap gcc only surppot C
tells GCC not to compile all the other language frontends it supports, but only C。
--disable-shared : 没有这个选项,会有 crti.o: No such file: No such file or directory collect2: ld returned 1 exit status
--disable-thread : 没有这个选项的话会有, posix_thread.h can't not found 的问题 .
--disable-libmudflap --disable-libssp :两个边界检查使用的库,有问题,禁止
无libc的时候这几个库是不能编译通过的 :ssp,mudflap,gomp
这个线索是这个问题的补丁
还有官方的 bug :
--------------------------------------------------------------------------------
5) prepare linux kernel heads
make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig 配置内核,记着选arm哦
make ARCH=arm CROSS_COMPILE=arm-linux- 随意运行下,就能产生version.h autoconf.h
cd linux-2.4.21
cp -dR include/asm-arm $PREFIX/$TARGET/include/asm
cp -dR include/linux $PREFIX/$TARGET/include/linux
在$TARGET/PREFIX/目录中建立下面的符号连接:
cd $PREFIX/$TARGET
ln -s include sys-linux 相当于configure gcc --with-heads=
在$TARGET_PREFIX/目录中建立下面的符号连接:
cd $PREFIX/$TARGET/include/asm
ln -s arch-s3c2410 arch 其实arch 已经建立了 (make了下,建立好了)
ln -s proc-armv proc 这个版本没proc这个连接了
--------------------------------------------------------------------------------
6) build glibc
搞了半天,原来glibc 2.6.1 是不支持arm的, 需要打上一系列的补丁
glibc-2.6.1-alpha_ioperm_fix-1.patch
glibc-2.6.1-cross_hacks-1.patch
glibc-2.6.1-hppa_nptl-1.patch
glibc-2.6.1-libgcc_eh-1.patch
glibc-2.6.1-localedef_segfault-1.patch
glibc-2.6.1-mawk_fix-1.patch
glibc-2.6.1-RTLD_SINGLE_THREAD_P-1.patch
glibc-2.6.1-sysdep_cancel-1.patch
推荐补丁下载地址 :
推荐文章: http://blog.chinaunix.net/u/26710/showart_394113.html
RTLD_SINGLE_THREAD_P 的fix(上面的patch已经包含了,参考下):
用 patch -Np1 -i 猛打把,少了那个都编译不过去 ,详细步骤如下
tar xvf glibc-2.6.1.tar.bz2
cd glibc-2.6.1/
tar xvf ../glibc-ports-2.6.1.tar.bz2
mv -v glibc-ports-2.6.1 ports
patch -Np1 -i ../glibc-2.6.1-libgcc_eh-1.patch
patch -Np1 -i ../glibc-2.6.1-localedef_segfault-1.patch
patch -Np1 -i ../glibc-2.6.1-cross_hacks-1.patch
patch -Np1 -i ../glibc-2.6.1-RTLD_SINGLE_THREAD_P-1.patch
NPTL problem fix:
patch for glibc2.4: http://www.devfiles.jlime.com/parted/glibc/nptl-crosscompile.patch
The following lines need to be added to config.cache for Glibc to support NPTL:
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache
最后使用参数--cache-file=config.cache
还不行,需要把asm-generic copy 到 $PREFIX/$TARGET/include .... (为啥经验这么重要呢。。)
$ tar -xvzf glibc-2.2.3.tar.gz
$ tar -xzvf glibc-linuxthreads-2.2.3.tar.gz --directory=glibc-2.2.3
$ cd build-glibc
$ CC=arm-linux-gcc ../glibc-2.2.3/configure --host=$TARGET --prefix=/usr
--with-headers=$PREFIX/$TARGET/include --cache-file=config.cache
CC=arm-linux-gcc 把 CC 变量设成你刚编译完的boostrap gcc, 用它来编译你的glibc.
--host=$TARGET 告诉该链接库在目标系统上执行, 而非在本地主机.
--prefix="/usr" 告诉配置脚本在目标板的根文件系统中glibc的位置.
--with-headers 告诉glibc 我们的linux 内核头文件的目录位置.
--enable-add-ons 告诉配置脚本使用我们下载的附加包. 已经将glibc-linuxthreads-2.2.3放入了glibc 源码目录中.
由于我们只添加了一个附加包, 这里--enable-add-ons等价于 --enable-add-ons=linuxthreads.
(如果使用glibc-2.1.x, 需要使用glibc-crypt附加包, 就得使用: --enable-add-ons= linuxthreads, crypt选项). (NPTL 了 )
$ make
$ make install_root=$PREFIX/$TARGET prefix="" install
install_root 指定了安装链接库组件的目录, 将glibc安装到与我们项目相关的目录, 而非/usr目录.如果不指定prefix="", 那么glibc会被安装到$/PREFIX/$TARGET/usr/lib目录中. 指定prefix使glibc被安装到 $TARGET_PREFIX/lib目录.
--------------------------------------------------------------------------------
7.)修改$PREFIX$TARGET/lib目录中的libc.so
$ cd $PREFIX/$TARGET/lib
$ cat libc.so
libc.so的内容:
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a )
将/lib/绝对目录去掉, 既将"GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a )"改为: GROUP ( libc.so.6 libc_nonshared.a )
--------------------------------------------------------------------------------
8) completed GCC
cd build-4.1.2
../gcc-4.1.2/configure --target=arm-linux --prefix=/cross/cross-arm --enable-languages=c
make
make install
(出鬼的顺利,不支持c++,gcc 相关补丁也没有打, 凑合先用吧)
--------------------------------------------------------------------------------
9) simple check
arm-linux-gcc --print-libgcc-file-name
arm-linux-gcc -print-search-dirs
arm-linux-gcc -o test test.c
arm-linux-objdump -D test
--------------------------------------------------------------------------------
10 build kernel for arm
为了配置方便,copy 一个default config 到linux2.6.24.4 的根目录. 然后就剪辑吧能去的都去掉.嘿嘿.
cp arch/arm/configs/s3c2410_defconfig .
mv s3c2410_defconfig .config
menuconfig:
make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig
zImage 出来了, download 到S3C2440 看看吧. 任意键进入boot menu. 选2 downfrom uart,用DNW下载代码,完成 选4,写入nand flash. (不同系统不一样,看monitor 咋写了) 选boot os............. 操蛋,啥都没看到,
只是在串口上看到monitor输出如下:
Set boot params = root=/dev/ram init=/linuxrc initrd=0x00000000,0x00000000 console=ttyS1,115200 mem=65536K devfs=mount
Load Kernel...
Load Ramdisk...
遇到的问题请继续看下一节...
--------------------------------------------------------------------------------
11 调整解压缩参数
到底啥是最重要的啊, 如果连个printf都不能用,运气未免太差. 参数中的ttyS1 (第10节的输出),俺没有注意到(么经验啊). 于是上ADS 的AXD调试:
先连接上目标板,然后选run, 这样就可以reboot 系统,选5, boot os, 然后用ADX stop,就会看到一段汇编了. 仔细查看发现arm 确实在运行一段程序,经过查询system.map,发现是panic( 我猜想是root fs没有...,但是没有显示内容到我的串口啊,串口接在uart1上).
随意看看那个2440 mon程序, linux的加载方式如下:
将zImage从nand flash copy到 0x3040 0000 然后就jump过去. 内核参数放在0x3000 0100.
goto_start = 0x3040 0000;
(*goto_start)(0, 193);
不过对为啥不能启动还是没有线索啊...
有几个比较可疑的内核配置选项可能引起问题比如
boot option->
compressed rom boot loader base address #
default kernel command string #
所以俺又试了几个选项, 把 # 的地址改成0x3040 0000...... 不幸还是不可以, 因为没有信息出现也不知道运行到了哪里,不过根据调试的结果,应该是过了解压缩阶段的....
事后俺查上面两个选项的含义( 就是按 ? 了), # 是说ROM able 的zImage, 就是zImage直接在rom中运行时, 才有效所以犯了错误啊. 也不行, 因为如果没有办法传递kernel 的command line时才有效, 而s32440下无效. 帮助里列举有几个平台需要这个选项.
先把参数地址为啥在0x3000 0100 和runaddr为啥在0x3040 0000跳过不谈,为啥没有任何信息? 连解压内核的信息都没有? 看了几遍config, 找到了如下的选项:
system type->
[0] S3C UART to use for low-level messages
嘿嘿,进去把0改成1, 看看arm的相关启动代码,印证了通过这个选项选择内核解压缩信息的输出端口. 选成1, 再试,果然有内核解压缩信息打印出来,呵呵. 相关代码在内核的位置:
decompress_kernel ->
putstr("Uncompressing Linux...");
gunzip();
putstr(" done, booting the kernel. ");
-> include/asm-arm/plat-s3c
static void putc(int ch)
{
if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) {
.....
}
uart_rd(unsigned int reg)
{
volatile unsigned int *ptr;
ptr = (volatile unsigned int *)(reg + uart_base);
return *ptr;
}
#define uart_base S3C24XX_PA_UART + (0x4000*CONFIG_S3C_LOWLEVEL_UART_PORT)
--------------------------------------------------------------------------------
12. 内核控制台
就是命令行里的console参数. 这里不打算讨论console到底是啥, 仅指出,俺没有看到内核正常的启动信息和这个选项大大的相关.我们分析下monitor给出的信息:
Set boot params = root=/dev/ram init=/linuxrc initrd=0x00000000,0x00000000 console=ttyS1,115200 mem=65536K devfs=
Load Ramdisk...
这里console设置成了 ttyS1, 而linux2.6.24.4 要求(不知道具体从啥时候开始,2.6?) 名字是ttySAC1,指定串口1. 看monitor的代码就能知道了, monitor需要升级的. ...走了冤枉路了,明白了monitor和内核这里的一点纠缠.
升级monitor之后... 嘿嘿,终于有东西了...呵呵
Uncompressing Linux...................................................... done
, booting the kernel.
Linux version 2.6.24.4 (root@localhost.localdomain) (gcc version 4.1.2) #7
Tue Apr 15 07:50:25 CST 2008
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
Machine: SMDK2410
ATAG_INITRD is deprecated; please update your bootloader.
Memory policy: ECC disabled, Data cache writeback
CPU S3C2440A (id 0x32440001)
S3C244X: core 400.000 MHz, memory 100.000 MHz, peripheral 50.000 MHz
S3C24XX Clocks, (c) 2004 Simtec Electronics
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
CPU0: D VIVT write-back cache
CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256
Kernel command line: root=/dev/ram init=/linuxrc initrd=0x00000000,0x00000000
console=ttySAC1,115200 mem=65536K devfs=mount
irq: clearing pending ext status 000dff00
irq: clearing pending ext status 00001000
irq: clearing subpending status 000000ba
irq: clearing subpending status 00000092
PID hash table entries: 256 (order: 8, 1024 bytes)
timer tcon=00090000, tcnt a2c1, tcfg 00000200,00000000, usec 00001eb8
Console: colour dummy device 80x30
console [ttySAC1] enabled
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 64MB = 64MB total
Memory: 63128KB available (1428K code, 223K data, 92K init)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
S3C2440: Initialising architecture
S3C2440: IRQ Support
S3C2440: Clock Support, DVS off
S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics
DMA channel 0 at c4800000, irq 33
DMA channel 1 at c4800040, irq 34
DMA channel 2 at c4800080, irq 35
DMA channel 3 at c48000c0, irq 36
JFFS2 version 2.2. (NAND) 漏 2001-2006 Red Hat, Inc.
io scheduler noop registered
io scheduler anticipatory registered (default)
io scheduler deadline registered
io scheduler cfq registered
Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing enabled
s3c2440-uart.0: s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2440
s3c2440-uart.1: s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2440
s3c2440-uart.2: s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2440
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
loop: module loaded
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=3 30ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-
bit)
Scanning device for bad blocks
Creating 8 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x00000000-0x00004000 : "Boot Agent"
0x00000000-0x00200000 : "S3C2410 flash partition 1"
0x00400000-0x00800000 : "S3C2410 flash partition 2"
0x00800000-0x00a00000 : "S3C2410 flash partition 3"
0x00a00000-0x00e00000 : "S3C2410 flash partition 4"
0x00e00000-0x01800000 : "S3C2410 flash partition 5"
0x01800000-0x03000000 : "S3C2410 flash partition 6"
0x03000000-0x04000000 : "S3C2410 flash partition 7"
mice: PS/2 mouse device common for all mice
S3C24XX RTC, (c) 2004,2006 Simtec Electronics
s3c2440-i2c s3c2440-i2c: slave address 0x10
s3c2440-i2c s3c2440-i2c: bus frequency set to 390 KHz
s3c2440-i2c s3c2440-i2c: i2c-0: S3C I2C adapter
S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics
s3c2410-wdt s3c2410-wdt: watchdog inactive, reset disabled, irq enabled
drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
List of all partitions:
1f00 16 mtdblock0 (driver?)
1f01 2048 mtdblock1 (driver?)
1f02 4096 mtdblock2 (driver?)
1f03 2048 mtdblock3 (driver?)
1f04 4096 mtdblock4 (driver?)
1f05 10240 mtdblock5 (driver?)
1f06 24576 mtdblock6 (driver?)
1f07 16384 mtdblock7 (driver?)
No filesystem could mount root, tried: cramfs romfs
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0)
--------------------------------------------------------------------------------
13. 内核参数的传递方式
前边说过monitor吧内核参数放到了地址 0x3000 0100 这个地址. 这个道理何在呢. 先看内核打印内核命令行的地方: init/main.c
asmlinkage void __init start_kernel(void)
-->printk(KERN_NOTICE "Kernel command line: %s ", boot_command_line);
是个全局变量,搜索下,在arch/arm/kernel/setup.c:
void __init setup_arch(char **cmdline_p)
{
char *from = default_command_line; /*.config 中指定的命令行*/
...
mdesc = setup_machine(machine_arch_type); /*从上面串口输出知道是 "Machine: SMDK2410", 由.config决定*/
/*里边引用的lookup_machine_type 在arch/arm/kernel/head_common.S*/
......
if (__atags_pointer)
tags = phys_to_virt(__atags_pointer);
else if (mdesc->boot_params)
tags = phys_to_virt(mdesc->boot_params);
...
/*
* If we have the old style parameters, convert them to
* a tag list.
*/
if (tags->hdr.tag != ATAG_CORE)
convert_to_tag_list(tags); /*把boot loader传递的参数, arch/arm/kernel/compat.c struct param_struct {
..} 转换成tag list, 其中包括 ATAG_CMDLINE */
if (tags->hdr.tag != ATAG_CORE)
tags = (struct tag *)&init_tags;
if (mdesc->fixup) /*s3c2410 是NULL*/
mdesc->fixup(mdesc, tags, &from, &meminfo);
if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
squash_mem_tags(tags);
parse_tags(tags); /*ATAG_CMDLINE 的parser 把相应命令行copy 到default_command_line, 也在这个文件内*/
}
....
memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
parse_cmdline(cmdline_p, from);
}
这里先忽略下mdesc是怎么被找到的,先直接搜索 mdesc的类型,可以找到 #define MACHINE_START(_type,_name) 这个宏,然后console的"SMDK2410"这个宏定义, 可以在arch/arm/mach-s3c2410下找到:
MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
* to SMDK2410 */
/* Maintainer: Jonas Dietsche */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = smdk2410_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = smdk2410_init,
.timer = &s3c24xx_timer,
MACHINE_END
#define S3C2410_SDRAM_PA (S3C2410_CS6)
#define S3C2410_CS6 (0x30000000)
这下子就知道内核参数传递的方式了: (arm)
把 arch/arm/kernel/compat.c 中定义的struct param_struct { } 放到0x3000 0100 处即可....
至于去求证 monitor 的 runAddr 和参数地址, 请看 : (这个是monitor用到的参数,决定了runAddrs)
BootParams boot_params = {
{"bootpara", 1}, //0=boot without parameters,1=boot with parameters
{"cpuclk", 2}, //0=200M, 1=300M, 2=400M, 3=440M
{"rundelay", 0}, //0 seconds
{"serial", 1}, //0=serial port 0, 1=serial port 1
{"baudrate", 115200},
{"machine", 193},
{"runAddr", 0x30400000},
{"rootfs", 0},
{"tty", 1},
{"initrdA", 0},
{"initrdL", 0},
{"memsize", 0x04000000},
{"devfs", 1},
{"ostore", 0}, //0=nand, 1=nor
{"userpara", sizeof(DEFAULT_USER_PARAMS)},
DEFAULT_USER_PARAMS
};
从这个参数加载linux的代码在nand.c LoadRun .