天天看點

tiny4412 序列槽驅動分析三 --- log列印的幾個階段之核心自解壓

開發闆:tiny4412ADK+S700 4GB Flash

主機:Wind7 64位

虛拟機:Vmware+Ubuntu12_04

u-boot:U-Boot 2010.12

Linux核心版本:linux-3.0.31

Android版本:android-4.1.2

核心自解壓時期的序列槽列印

在zImage格式的核心啟動時會自解壓核心,此時列印資訊如下:

Uncompressing Linux...

這句話是在arch/arm/boot/compressed/misc.c中:

void decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, unsigned long free_mem_ptr_end_p, int arch_id)
{
         ……
         putstr("Uncompressing Linux...");
         ……
}      
static void putstr(const char *ptr)
{
         char c;

         while ((c = *ptr++) != '\0') {
                   if (c == '\n')
                            putc('\r');
                   putc(c);  // 根據APCS規則,c中的值會傳給寄存器r0
         }

         flush();
}      

在arch/arm/boot/compressed/.misc.o.cmd中列出了編譯misc.c需要依賴那些檔案,其中

deps_arch/arm/boot/compressed/misc.o := \
...
  arch/arm/mach-exynos/include/mach/uncompress.h \
...
  arch/arm/plat-samsung/include/plat/uncompress.h \
...      

在misc.c中有#include <mach/uncompress.h> 指的就是 arch/arm/mach-exynos/include/mach/uncompress.h

在mach/uncompress.h中有:#include <plat/uncompress.h>,指的就是:

arch/arm/plat-samsung/include/plat/uncompress.h

在arch/arm/plat-samsung/include/plat/uncompress.h中有putc的實作:

static void putc(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的實作

static __inline__ void
uart_wr(unsigned int reg, unsigned int val)
{
         volatile unsigned int *ptr;
         ptr = (volatile unsigned int *)(reg + uart_base);
         *ptr = val;
}

static __inline__ unsigned int
uart_rd(unsigned int reg)
{
         volatile unsigned int *ptr;
         ptr = (volatile unsigned int *)(reg + uart_base);
         return *ptr;
}      

可以看到,使用的是内聯函數,并且直接操作的是底層的寄存器,那麼到底操作的是哪個uart呢?我們知道,tiny4412有兩個可以直接使用的序列槽,分别對應的是uart0和uart3。想知道這個問題,就需要看uart_base這個變量是什麼值?

還是在這個檔案中:

#define uart_base S3C_PA_UART + (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT)

其中S3C_PA_UART是uart控制器的基位址0x13800000,exynos4412一共有5個uart,每個uart占S3C_UART_OFFSET (0x10000)個位元組,還有一個關鍵的宏CONFIG_S3C_LOWLEVEL_UART_PORT,它就指定了使用哪一個uart,這個宏可以在make menuconfig的時候配置,這裡我們設定的是

CONFIG_S3C_LOWLEVEL_UART_PORT=0

繼續閱讀