在运行linux的时候有所有的调试信息可以分为三个部分
1、 bootloader输出信息
U-Boot 1.3.2(Nov 19 2016 - 22:02:08) DRAM: 64 MB Flash: 512 kB NAND: 64 MiB In: serial Out: serial Err: serial Hit any key to stop autoboot: 0 [yqliu2410 #] tftp Found DM9000 ID:90000a46 at address 10000000 ! DM9000 work in 16 bus width bd->bi_entaddr: 08:00:3e:26:0a:5b [eth_init]MAC:8:0:3e:26:a:5b: TFTP from server 192.168.1.152; ourIP address is 192.168.1.155 Filename 'uImage'. Load address: 0x30008000 Loading: T T#######################################################done Bytes transferred = 1617316 (18ada4 hex) [up-tech2410 #] bootm ## Booting image at 30008000 ... Image Name: Linux-2.6.24.4 Created: 2016-11-19 14:05:29 UTC Image Type: ARM Linux Kernel Image(uncompressed) Data Size: 1617252 Bytes= 1.5 MB Load Address: 30008000 Entry Point: 30008040 Verifying Checksum ... OK Starting kernel ... |
2、 linux低级调试信息输出
Uncompressing Linux............................................................. done, booting the kernel. |
3、 linux调试信息输出
Linux version 2.6.24.4(root@vm-dev)(gcc version 3.4.6) #100 Sat Nov 19 07:47:35 CST 2016 CPU: ARM920T [41129200] revision 0(ARMv4T), cr=00007177 Machine: SMDK2410 Memory policy: ECC disabled, Data cache writeback CPU S3C2410A (id 0x32410002) S3C2410: core 202.800 MHz, memory 101.400 MHz, peripheral 50.700 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, 32byte lines, 8sets CPU0: D cache: 16384 bytes, associativity 64, 32byte lines, 8sets Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256 Kernel command line: root=/dev/mtdblock2 noinitrd console=ttySAC1,115200 irq: clearing subpending status 00000010 PID hash table entries: 256 (order: 8, 1024 bytes) timer tcon=00500000, tcnt a509, tcfg 00000200,00000000, usec 00001e4c Console: colour dummy device 80x30 console [ttySAC1] enabled
............................ |
现在要将所有的调试信息输出到别的串口。以com1为例(从com0开始计算)!
一、将bootloader的输出信息输出到com1
这里以u-boot1.3.2为例:很简单只需要修改一个宏定义就ok
Vi inlcude/configs/xxxconfig.h(xxx为你定义的开发板的名字)
更改原有的宏
/* * select serial console configuration */ //#define CONFIG_SERIAL1 1 /* we use SERIAL 1 on SMDK2410*/ //modify for xxx2410 //by lyj_uptech #define CONFIG_SERIAL2 1 /* we use SERIAL 2 on SMDK2410*/ |
二、将low_level的调试信息输出到com1
在改之前我们先分析一下在linux启动之前它是如何使用串口的(以linux-2.6.24为例)。
1、 在arch/arm/boot/compressed/misc.c文件中有定义
staticvoid putstr(constchar *ptr) { char c; while ((c= *ptr++)!= '\0') { if (c =='\n') putc('\r'); putc(c); } flush(); } |
2、 arch/arm/boot/compressed/misc.中的函数decompress_kernel就是使用的putstr来打印的如下输出信息:
Uncompressing Linux............................................................. done, booting the kernel |
3、 追根溯源,putstr函数最终调用的是putc(请注意这里的putc不是在misc.c函数中定义的icedcc_putc,因为没有CONFIG_CPU_V6宏定义),真正的底层操作在文件include/asm-arm/plat-s3c/uncompress.h
4、 解析该文件
/* we can deal with the case the UARTs are being run * in FIFO mode, so that we don't hold up our execution * waiting for tx to happen... */ static voidputc(int ch) { if (uart_rd(S3C2410_UFCON)& S3C2410_UFCON_FIFOMODE){ int level; while (1) { level = uart_rd(S3C2410_UFSTAT); level &= fifo_mask;
if (level < fifo_max) break; } } else{ /* not using fifos */ while ((uart_rd(S3C2410_UTRSTAT)& S3C2410_UTRSTAT_TXE)!= S3C2410_UTRSTAT_TXE) barrier(); } /* write byte to transmission register */ uart_wr(S3C2410_UTXH, ch); } |
该函数中调用的两个函数,uart_rd uart_wr在同一个文件中定义
#define uart_base S3C24XX_PA_UART+ (0x4000*CONFIG_S3C_LOWLEVEL_UART_PORT) static __inline__void uart_wr(unsignedint reg, unsigned int val) { volatile unsignedint *ptr; ptr = (volatileunsigned int*)(reg+ uart_base); *ptr = val; } static __inline__unsigned int uart_rd(unsignedint reg) { volatile unsignedint *ptr; ptr = (volatileunsigned int*)(reg+ uart_base); return *ptr; } |
从宏定义uart_base中就可以清楚的看到,当CONFIG_S3C_LOWLEVEL_UART_PORT为0时,uart_base的值为0x50000000,也就是uart0的控制寄存器基地址。如果要使用uart1的话就把CONFIG_S3C_LOWLEVEL_UART_PORT赋值为1就可以了。
5、真正更改的地方只有一个
下级目录
修改为1就ok!
6、 需要注意的地方(你使用的串口初始化了么)
我在整个内核中找遍了解压内核之前运行的代码,都找不到关于串口初始化的代码。所以说,linux在启动之前的串口初始化是依赖bootloader的,要想正常的输出,就必须使用你的bootloader使用的串口,因为在bootloader中进行了对要使用的串口进行了初始化。要保证你的bootloader兼容性很好,那就在bootloader中把所有的串口都初始化一遍。
如果你没有初始化串口,一旦调用putstr,程序就死掉了!
三、将linux的信息输出到com1
将linux运行的信息输出到com1就太简单了,直接到bootloader里面改linux的传递参数就可以了。
setenv bootargs root=/dev/mtdblock2 noinitrd console=ttySAC1,115200 saveenv |
现在启动一切ok!
感谢yqliu29的支持,没有他的调试程序,我始终的无法知道linux的内核是否正确调用,也无法定位问题!
这里附上他给我的程序(这里的三个灯分别对应的io管脚是GPF5/6/7)
#if 0 asm volatile( "ldr r6, =0x5400\n\r" "ldr r7, =0x56000020\n\r" "str r6, [r7]\n\r" "ldr r6, =0xC0\n\r" "ldr r7, =0x56000024\n\r" "str r6, [r7]"); #endif |
include/s3c6410.h 里
#define ELFIN_UART_BASE 0x7F005000 // Assembly 阶段吃这里
#define ELFIN_UART0_OFFSET 0x0000
#define ELFIN_UART1_OFFSET 0x0400
#define ELFIN_UART2_OFFSET 0x0800
#ifdef CONFIG_SERIAL1 // 这一句在 include/config/smdk6410.h
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART0_OFFSET)
#elif defined(CONFIG_SERIAL2)
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART1_OFFSET)
#else
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART0_OFFSET)
#endif
文章来自:http://blog.csdn.net/longtian635241/article/details/7867730