1. 程式人生 > >linux kernel 4.6 移植到imx280手札

linux kernel 4.6 移植到imx280手札

資源簡介

周立功過節發招,49元買了imx280核心板:

ARM926EJ-S 架構 arm v5TE 指令集,cpu最高能跑450M

預設光碟資料是 比較老的uboot-2009加linux-2.6核心。

因為本人電腦是ubuntu環境,周立功提供的燒寫環境都不適用與我的電腦。

不過眾裡尋他千百度,終於在開源專案rockbox裡面找到一個linux下面的usb燒寫工具.

外加一根串列埠線。我就是移植的全部外部環境。

自己的程式碼環境在github上面放了個倉庫,方面回老家的時候也能夠寫程式碼。

https://github.com/QtForQT/imx280_zlg.git

心酸史(一) 串列埠輸出

通過下載了最新的kernel(我移植時2016年5月)發現裡面預設支援了imx28這顆晶片。當時高興呀,以為只要make一下就能運行了。 通過make ARCH=arm CROSS_COMPILE=****  mxs_defconfig && make zImage然後替換周立功bootloader/imx-bootlets-src-10.12.01/ 裡面的zImage 發現只有  “Uncompressing Linux... done, booting the kernel.
” 然後喜憂參半,高興的是已經跳到kernel並且解壓完成的了,憂傷的是:WTF,只要一句話。 然後開始折騰列印,通過看原始碼,和google 發現這句話能列印的原因是:bootloader初始化好了串列埠。也就是arch/arm/boot/compressed/裡面能夠列印 通過加打印發現解壓完成跳進kernel裡面就沒有列印了。於是看arch/arm/kernel/head.S的程式碼 裡面呼叫了__error_p然後最終呼叫了printascii來列印。
__error_p:
#ifdef CONFIG_DEBUG_LL
        adr     r0, str_p1
        bl      printascii
        mov     r0, r9
        bl      printhex8
        adr     r0, str_p2
        bl      printascii
        b       __error
str_p1: .asciz  "\nError: unrecognized/unsupported processor variant (0x"
str_p2: .asciz  ").\n"
        .align
#endif
ENDPROC(__error_p)

注意兩點:一個是巨集:CONFIG_DEBUG_LL一個是printascii printascii的實現:
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  
                ret     lr  
ENDPROC(printascii)

然後打開了CONFIG_DEBUG_LL巨集,檢視.config 發現裡面會有CONFIG_DEBUG_LL_INCLUDE=“debug/pl01x.S” 然後在arch/arm/include/debug/pl01x.S裡面實現了 addruart,senduart,busyuart三個巨集。
當然這其中還有因為編譯的是mxs_defonfig它裡面及支援imx23和imx28需要把imx23 uart相關的去掉。 就這樣愉快的加列印直到有一天。。。。。。。。

__turn_mmu_on關了我的世界

當__turn_mmu_on過後串列埠就沒有輸出了。看這個貨,估計是開啟mmu了。更具常識猜測,可能: 1.uart相關的記憶體沒有對映上來 2.uart的虛擬地址不對。 瘋狂的看原始碼,找到了對映虛擬地址的地方:
__create_page_tables:
        pgtbl   r4, r8                          @ page table address
...................................
...................................
#ifdef CONFIG_DEBUG_LL
#if !defined(CONFIG_DEBUG_ICEDCC) && !defined(CONFIG_DEBUG_SEMIHOSTING)
        /*
         * Map in IO space for serial debugging.
         * This allows debug messages to be output
         * via a serial console before paging_init.
         */
        addruart r7, r3, r0

        mov     r3, r3, lsr #SECTION_SHIFT
        mov     r3, r3, lsl #PMD_ORDER

        add     r0, r4, r3
        mov     r3, r7, lsr #SECTION_SHIFT
        ldr     r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
        orr     r3, r7, r3, lsl #SECTION_SHIFT
..............................................................
..............................................................
#ifdef CONFIG_DEBUG_LL
#if !defined(CONFIG_DEBUG_ICEDCC) && !defined(CONFIG_DEBUG_SEMIHOSTING)
        /*
         * Map in IO space for serial debugging.
         * This allows debug messages to be output
         * via a serial console before paging_init.
         */
        addruart r7, r3, r0

        mov     r3, r3, lsr #SECTION_SHIFT
        mov     r3, r3, lsl #PMD_ORDER

        add     r0, r4, r3
        mov     r3, r7, lsr #SECTION_SHIFT
        ldr     r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
        orr     r3, r7, r3, lsl #SECTION_SHIFT

發現它是通過addruart來獲得uart的物理和虛擬地址,然後映射了的。也就是說,地址是映射了的,因為這個巨集我們第一步的時候打開了的。 在檢查虛擬地址:
#ifdef CONFIG_DEBUG_UART_PHYS
                .macro  addruart, rp, rv, tmp 
                ldr     \rp, =CONFIG_DEBUG_UART_PHYS
                ldr     \rv, =CONFIG_DEBUG_UART_VIRT
                .endm
#endif

在arch/arm/Kconfig.debug中找到了
default 0xfe100000 if DEBUG_IMX23_UART || DEBUG_IMX28_UART
但是怎樣得到虛擬地址呢?我google很久,但是還是沒有找到規則。最終取了個巧,從周立功的程式碼得到了正確的地址。
default 0xf0074000 if DEBUG_IMX23_UART || DEBUG_IMX28_UART

走到哪裡了?

然後安裝debug流程在lib/vsprintf.c裡面加上了printascii貼出來的程式碼是我後來註釋掉的:
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
        int i;

        i = vsnprintf(buf, size, fmt, args);

//#if defined(CONFIG_DEBUG_LL)
//extern void printascii(const char *);
//      printascii(buf);
//#endif
        if (likely(i < size))
                return i;
        if (size != 0)
                return size - 1; 
        return 0;
}
EXPORT_SYMBOL(vscnprintf);
然後在init/main.c中把 bool initcall_debug = 1; 這樣可以看在載入那個模組時失敗了的。 最終確定了是載入application uart卡住了。為了儘快啟動我直接去掉了這個驅動

開啟串列埠

為了能夠進入控制檯,和列印輸出。有把debug uart串列埠開啟。也就是前面的pl011
arm,primecell-periphid = <0x00041011>;