U-boot网口问题解决后,uImage和ramdisk终于可以上传到单板上去验证了。脚本为:
MINI6410 # setenv serverip 192.168.1.200
MINI6410 # setenv bootargs root=/dev/ram rootfstype=ext2 init=/linuxrc console=ttySAC0,115200 mem=256
MINI6410 # tftp 0x51800000 ramdisk.bin
MINI6410 # tftp 0x50800000 uImage
MINI6410 # bootm 0x50800000 0x51800000
————————————————————————————————————————————————————————
————————————————————————————————————————————————————————
执行bootm命令后打印:
## Booting image at 50800000 ...
Image Name: Linux-2.6.38
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1902992 Bytes = 1.8 MB
Load Address: 50008000
Entry Point: 50008000
Verifying Checksum ... OK
OK
## Loading Ramdisk Image at 51800000 ...
Image Name: ramdisk1.0
Image Type: ARM Linux RAMDisk Image (gzip compressed)
Data Size: 1040870 Bytes = 1016.5 kB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Starting kernel ...
Uncompressing Linux... done, booting the kernel.
就无任何反应了!!!!网上查资料主要怀疑方向有:
1、machine ID uboot与内核定义不一致。
2、内核参数console传递的不对。
问题确认:
1、machine ID uboot与内核定义不一致。
uboot传递的machine ID参数:
board\samsung\mini6410\Mini6410.c
gd->bd->bi_arch_number = MACH_TYPE;
include/configs/Mini6410.h
#define MACH_TYPE 2520
内核的machine ID参数:
include/generated/mach-types.h
#define MACH_TYPE_MINI6410 2520
所以不是这个问题。
2、内核参数console传递的不对。
console=ttySAC0,115200 这个也确认是没有问题。
所以也不是这个问题。
————————————————————————————————————————————————————————
————————————————————————————————————————————————————————
没办法,只能自己动手调试了。
1、首先尝试low-level debug调试方法
Kernel hacking-->Kernel low-level debugging functions
Kernel hacking-->S3C UART to use for low-level debug 为UART 0。
可是问题依旧,还是无任何打印。
2、直接使用printascii/printhex8 打印kernel启动过程。
printascii其实就是1个字符1个字符往串口里写,addruart_current 就是返回当前uart的寄存器基地址,这个与我们前面的S3C UART to use for low-level debug 配置有关。
ENTRY(printascii)
addruart_current r3, r1, r2
b 2f
1: waituart r2, r3
senduart r1, r3
busyuart r2, r3
teq r1, #'\n'
moveq r1, #'\r'
beq 1b
2: teq r0, #0
ldrneb r1, [r0], #1
teqne r1, #0
bne 1b
mov pc, lr
ENDPROC(printascii)
printhex8 其实就是将16进制数,每4个bit为1个字符,填写到buffer里,即转为 ASCII字符串,然后调用printascii打印出来。
我写的定位函数,r0为入参,打印具体到了哪一步:
__right_p:
adr r13,spbuf1
STMIA r13, {R1-R4,R7}
mov r7,lr
mov r4, r0
adr r0, str_p3
bl printascii
mov r0 ,r4
bl printhex8
adr r0,str_p4
bl printascii
mov lr,r7
ldmia r13,{R1-R4,R7}
mov pc,lr
str_p3: .asciz "\nkernel boot step 0x"
str_p4: .asciz "\n"
.align
ENDPROC(__right_p)
spbuf1: .space 20
例如:
/*step 0*/
mov r0,#0
bl __right_p
写汇编函数要注意几点:
A、破坏的寄存器一定要保存
B、多层调用(a-->b-->c)一定要记得保存/恢复lr寄存器,因为b调用c是会破坏a的返回地址。
加了定位信息后:
Starting kernel ...
Uncompressing Linux... done, booting the kernel.
kernel boot step 0x00000000
000009d8
7f005000
c0008358
50025288
500252c0
000009d8
kernel boot step 0x00000001
kernel boot step 0x00000002
kernel boot step 0x00000003
kernel boot step 0x00000004
确认了:
machine ID确实是对的。
异常不是在汇编阶段而是出在start_kernel函数之后。
继续在start_kernel里加打印,终于确定是在 setup_arch(&command_line);之后就出现异常了。但是还是无法精确定位,由于在 console_init();初始化之前printk是打印在__log_buf里,而且在软复位或者按键复位后,内存的值还能保留,所以尝试按键复位后,在uboot里使用md命令查看__log_buf里的值来确认内核初始化的打印。
__log_buf=503c9598
MINI6410 # md 0x503c9598
503c9598: 4c3e353c 78756e69 72657620 6e6f6973 <5>Linux version
503c95a8: 362e3220 2038332e 6f6f7228 6f6c4074 2.6.38 (root@lo
503c95b8: 686c6163 2e74736f 61636f6c 6d6f646c calhost.localdom
503c95c8: 296e6961 63672820 65762063 6f697372 ain) (gcc versio
503c95d8: 2e34206e 20332e34 6e746328 2e312d67 n 4.4.3 (ctng-1.
503c95e8: 29312e36 23202920 53203432 4a206e75 6.1) ) #24 Sun J
503c95f8: 32206c75 32322034 3a35343a 43203333 ul 24 22:45:33 C
503c9608: 32205453 0a313130 433e343c 203a5550 ST 2011.<4>CPU:
503c9618: 764d5241 6f632d36 7461706d 656c6269 ARMv6-compatible
503c9628: 6f727020 73736563 5b20726f 66303134 processor [410f
503c9638: 36363762 6572205d 69736976 36206e6f b766] revision 6
503c9648: 52412820 2937764d 7263202c 6330303d (ARMv7), cr=00c
503c9658: 37383335 343c0a66 5550433e 4956203a 5387f.<4>CPU: VI
503c9668: 6e205450 6c616e6f 69736169 6420676e PT nonaliasing d
503c9678: 20617461 68636163 56202c65 20545049 ata cache, VIPT
503c9688: 616e6f6e 7361696c 20676e69 74736e69 nonaliasing inst
MINI6410 #
503c9698: 74637572 206e6f69 68636163 00000a65 ruction cache...
503c96a8: 00000000 00000000 00000000 00000000 ................
503c96b8: 00000000 00000000 79726f6d 6c6f7020 ........mory pol
503c96c8: 3a796369 43434520 73696420 656c6261 icy: ECC disable
503c96d8: 44202c64 20617461 68636163 72772065 d, Data cache wr
503c96e8: 62657469 0a6b6361 4b3e303c 656e7265 iteback.<0>Kerne
503c96f8: 6170206c 2063696e 6f6e202d 79732074 l panic - not sy
503c9708: 6e69636e 45203a67 524f5252 6146203a ncing: ERROR: Fa
503c9718: 64656c69 206f7420 6f6c6c61 65746163 iled to allocate
503c9728: 31783020 20303030 65747962 65622073 0x1000 bytes be
503c9738: 20776f6c 2e307830 3e303c0a 3e343c0a low 0x0..<0>.<4>
503c9748: 6b636142 63617274 0a203a65 5b3e343c Backtrace: .<4>[
503c9758: 3030633c 37363133 205d3e63 6d756428 <c003167c>] (dum
503c9768: 61625f70 72746b63 2b656361 2f307830 p_backtrace+0x0/
503c9778: 31317830 66202934 206d6f72 30633c5b 0x114) from [<c0
503c9788: 61306332 5d3e3436 75642820 735f706d 2c0a64>] (dump_s
MINI6410 # md 0x503c9598
503c9798: 6b636174 3178302b 78302f38 0a296331 tack+0x18/0x1c).
503c97a8: 00000000 00000000 00000000 00000000 ................
503c97b8: 00000000 00000000 00346163 00000000 ........ca4.....
503c97c8: 00000000 00000000 00000000 00000000 ................
503c97d8: 00000000 00000000 6d756428 74735f70 ........(dump_st
503c97e8: 2b6b6361 2f307830 63317830 72662029 ack+0x0/0x1c) fr
503c97f8: 5b206d6f 3230633c 63613063 205d3e63 om [<c02c0acc>]
503c9808: 6e617028 302b6369 2f343678 38317830 (panic+0x64/0x18
503c9818: 000a2930 00000000 63323063 38366130 0)......c02c0a68
503c9828: 28205d3e 696e6170 78302b63 78302f30 >] (panic+0x0/0x
503c9838: 29303831 6f726620 3c5b206d 31303063 180) from [<c001
503c9848: 38653936 28205d3e 626d656d 6b636f6c 69e8>] (memblock
503c9858: 6c6c615f 625f636f 2b657361 63337830 _alloc_base+0x3c
503c9868: 3478302f 000a2930 00000000 00000000 /0x40)..........
503c9878: 00000000 00000000 30303a32 30303030 ........2:000000
503c9888: 00003030 00000000 00000000 00000000 00..............
MINI6410 #
503c9898: 00000000 00000000 00006232 00000000 ........2b......
503c98a8: 00000000 00000000 00000000 00000000 ................
503c98b8: 00000000 00000000 625f636f 2b657361 ........oc_base+
503c98c8: 2f307830 30347830 72662029 5b206d6f 0x0/0x40) from [
503c98d8: 3030633c 33613631 205d3e34 6d656d28 <c0016a34>] (mem
503c98e8: 636f6c62 6c615f6b 2b636f6c 34317830 block_alloc+0x14
503c98f8: 3178302f 000a2938 72203e34 30633a35 /0x18)..4> r5:c0
503c9908: 31353134 00006338 00000000 00000000 41518c..........
503c9918: 00000000 00000000 31303063 30326136 ........c0016a20
503c9928: 28205d3e 626d656d 6b636f6c 6c6c615f >] (memblock_all
503c9938: 302b636f 302f3078 29383178 6f726620 oc+0x0/0x18) fro
503c9948: 3c5b206d 30303063 63306464 28205d3e m [<c000dd0c>] (
503c9958: 39332e54 78302b31 302f3831 29303378 T.391+0x18/0x30)
503c9968: 0000000a 00000000 00000000 00000000 ................
503c9978: 00000000 00000000 2f307830 30337830 ........0x0/0x30
503c9988: 72662029 5b206d6f 3030633c 32376530 ) from [<c000e72
发现一条异常打印:
Kerne panic - not syncing: ERROR: Failed to allocate 0x1000 bytes be low 0x0..
搜索代码中的打印,确认是这个函数里打印的:
start_kernel-->setup_arch-->paging_init-->bootmem_init-->arm_bootmem_init-->memblock_alloc_base
phys_addr_t __init memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
{
phys_addr_t alloc;
alloc = __memblock_alloc_base(size, align, max_addr);
if (alloc == 0)
panic("ERROR: Failed to allocate 0x%llx bytes below 0x%llx.\n",
(unsigned long long) size, (unsigned long long) max_addr);
return alloc;
}
这里分配出了问题,怀疑是struct meminfo meminfo;的初始化出问题了,所以继续使用printascii/printhex8在各个阶段打印这个结构
u.mem.start=50000000
u.mem.size=10000000
1
r_banks=00000001
start=50000000
u.mem.size=10000000
root=/dev/ram rootfstype=ext2 init=/linuxrc console=ttySAC0,115200 mem=256
2
r_banks=00000000
start=50000000
u.mem.size=00000000
3
r_banks=00000000
start=50000000
u.mem.size=00000000
OK
发现是 parse_early_param();之后就r_banks=00000000确认内存解析函数
early_mem-->memparse
unsigned long long memparse(const char *ptr, char **retptr)
{
char *endptr; /* local pointer to end of parsed string */
unsigned long long ret = simple_strtoull(ptr, &endptr, 0);
switch (*endptr) {
case 'G':
case 'g':
ret <<= 10;
case 'M':
case 'm':
ret <<= 10;
case 'K':
case 'k':
ret <<= 10;
endptr++;
default:
break;
}
if (retptr)
*retptr = endptr;
return ret;
}
size返回是0,终于发现竟然是我的boot args里的mem=256少了个M,悲剧!!!!!
————————————————————————————————————————————————————————
————————————————————————————————————————————————————————
总结一下console_init终端初始化前的定位方法:
1、使用low_level debug的printascii/printhex8做调试打印。
内核配置:
Kernel hacking-->Kernel low-level debugging functions
Kernel hacking-->S3C UART to use for low-level debug 选择UART num。
2、打印出来printk的__log_buf的物理地址的值,软复位或者按键复位后在uboot里使用md 这个物理地址查看打印内容。
printklogbuf = __pa(__log_buf);
printascii("\n__log_buf=");
printhex8(printklogbuf);
printascii("\n");
内存参数传递:
ATAG_MEM
uboot里在armlinux.c的setup_memory_tags里处理,bd->bi_dram[i].start和bd->bi_dram[i].size通常在自己单板的board文件里的dram_init来赋值:
#ifdef CONFIG_SETUP_MEMORY_TAGS
static void setup_memory_tags (bd_t *bd)
{
int i;
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = bd->bi_dram[i].start;
params->u.mem.size = bd->bi_dram[i].size;
params = tag_next (params);
}
}
#endif /* CONFIG_SETUP_MEMORY_TAGS */
内核在这里解析:setup_arch-->parse_tags-->parse_tag_mem32
parse_tags就是根据传递参数里的tags标记,然后选择各种解析函数进行解析,内存解析就是添加内存分区,即修改struct meminfo meminfo的内容
static int __init parse_tag_mem32(const struct tag *tag)
{
return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
}
bootargs:
mem=xM或者其它单位,bootargs是在parse_tags-->parse_tag_cmdline拷贝到内核default_command_line里的,然后在setup_arch--> parse_early_param();解析里面的各个参数,内存就是通过这个early_mem函数来解析的。
优先级:
bootargs>ATAG_MEM。也就是如果在bootargs里面定义了mem=就以bootargs里面为准,因为这个用户定义的。内核启动不起来,往往和这个还有关系。