基于tiny4412的Linux内核移植(支持device tree)(三)

发布时间:2023-06-20  

平台简介

开发板:tiny4412ADK + S700 + 4GB Flash

要移植的内核版本:Linux-4.4.0 (支持device tree)

u-boot版本:友善之臂自带的 U-Boot 2010.12 (为支持uImage启动,做了少许改动)

busybox版本:busybox 1.25

交叉编译工具链: arm-none-linux-gnueabi-gcc

      (gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29))


注意

继续上文。

到目前为止,板子已经可以起来了,接下来就可以针对板子的情况移植驱动程序了。这个放在以后再做,下面是我折腾过程中得到的一些知识,分享一下。


一、设备树反编译

在内核目录下当我们执行make dtbs后,就会在arch/arm/boot/dts下生成一些.dtb文件,那这个文件里是什么东西呢?我们可以用dtc命令反编译这些dtb文件,这里的可执行程序dtc在Linux内核源码中已经提供了,具体路径是:scripts/dtc/,可以使用下面的命令从Linux源码中编译出这个工具:

make CROSS_COMPILE=arm-none-linux-gnueabi- ARCH=arm scripts

 这样就会在scripts/dtc下生成可执行程序dtc。


当然,如果没有Linux源码,也可以使用apt-get命令安装这个工具,命令如下:


sudo apt-get install device-tree-compiler

 下面以exynos4412-tiny4412.dtb为例:


命令:


dtc -I dtb -O dts -o tiny4412.dts arch/arm/boot/dts/exynos4412-tiny4412.dtb

然后就会生成反编译后的文件 tiny4412.dts,部分内容如下:


/dts-v1/;


/ {

    #address-cells = ;

    #size-cells = ;

    interrupt-parent = ;

    compatible = "friendlyarm,tiny4412", "samsung,exynos4412", "samsung,exynos4";

    model = "FriendlyARM TINY4412 board based on Exynos4412";


    chosen {

        stdout-path = "/serial@13800000";

        bootargs = "root=/dev/ram0 rw rootfstype=ext4 console=ttySAC0,115200 init=/linuxrc earlyprintk";

    };


    aliases {

        spi0 = "/spi@13920000";

        spi1 = "/spi@13930000";

        spi2 = "/spi@13940000";

        i2c0 = "/i2c@13860000";

        i2c1 = "/i2c@13870000";

        i2c2 = "/i2c@13880000";

        i2c3 = "/i2c@13890000";

        i2c4 = "/i2c@138A0000";

        i2c5 = "/i2c@138B0000";

        i2c6 = "/i2c@138C0000";

        i2c7 = "/i2c@138D0000";

        i2c8 = "/i2c@138E0000";

        csis0 = "/camera/csis@11880000";

        csis1 = "/camera/csis@11890000";

        fimc0 = "/camera/fimc@11800000";

        fimc1 = "/camera/fimc@11810000";

        fimc2 = "/camera/fimc@11820000";

        fimc3 = "/camera/fimc@11830000";

        serial0 = "/serial@13800000";

        serial1 = "/serial@13810000";

        serial2 = "/serial@13820000";

        serial3 = "/serial@13830000";

        pinctrl0 = "/pinctrl@11400000";

        pinctrl1 = "/pinctrl@11000000";

        pinctrl2 = "/pinctrl@03860000";

        pinctrl3 = "/pinctrl@106E0000";

        fimc-lite0 = "/camera/fimc-lite@12390000";

        fimc-lite1 = "/camera/fimc-lite@123A0000";

        mshc0 = "/mmc@12550000";

    };


    memory {

        device_type = "memory";

        reg = <0x40000000 0x40000000>;

    };


    clock-controller@03810000 {

        compatible = "samsung,exynos4210-audss-clock";

        reg = <0x3810000 0xc>;

        #clock-cells = ;

        linux,phandle = ;

        phandle = ;

    };

    i2s@03830000 {

这个方法对于学习设备树很有帮助。

二、在u-boot打印信息

在u-boot中很多文件中是通过debug(… …)来打印信息,默认情况下这些log是打印不出来的。这个函数的定义是在include/common.h中:


#ifdef DEBUG

#define debug(fmt,args...)    printf (fmt ,##args)

#define debugX(level,fmt,args...) if (DEBUG>=level) printf(fmt,##args);

#else

#define debug(fmt,args...)

#define debugX(level,fmt,args...)

#endif /* DEBUG */

所以可以在调用debug函数的C文件的最上面添加  #define DEBUG  即可。这个方法在Linux内核以及Android当中也很常用。


三、打开Linux内核启动早期的log

有时会遇到当在u-boot中执行完bootm后,打印出start kernel后串口就没有再输出任何信息了。此时就需要打开内核早期的log:


make menuconfig


  Kernel hacking  --->


      [*] Kernel low-level debugging functions (read help!)


             Kernel low-level debugging port (Use Samsung S3C UART 0 for low-level debug)


      [*] Early printk


对于earlyprintk,还需要在bootargs中添加参数earlyprintk才能生效,有了上面这几个配置,会有下面几个宏生效:


CONFIG_DEBUG_LL=y


CONFIG_DEBUG_S3C_UART0=y


CONFIG_DEBUG_LL_INCLUDE="debug/exynos.S"


CONFIG_DEBUG_UNCOMPRESS=y

CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"

CONFIG_EARLY_PRINTK=y


关于earlyprintk的解析在文件arch/arm/kernel/early_printk.c中:


   1: extern void printch(int);

   2: 

   3: static void early_write(const char *s, unsigned n)

   4: {

   5:     while (n-- >; 0) {

   6:         if (*s == 'n')

   7:             printch('r');

   8:         printch(*s);

   9:         s++;

  10:     }

  11: }

  12:  

  13: static void early_console_write(struct console *con, const char *s, unsigned n)

  14: {

  15:     early_write(s, n);

  16: }

  17:  

  18: static struct console early_console_dev = {

  19:     .name =        "earlycon",

  20:     .write =    early_console_write,

  21:     .flags =    CON_PRINTBUFFER | CON_BOOT,

  22:     .index =    -1,

  23: };

  24: 

  25: static int __init setup_early_printk(char *buf)

  26: {

  27:     early_console = &;early_console_dev;

  28:     register_console(&;early_console_dev);

  29:     return 0;

  30: }

  31:  

  32: early_param("earlyprintk", setup_early_printk);

其中printch都是通过汇编语言实现的。


在arch/arm/Kconfig.debug中可以看到:


config DEBUG_LL

    bool "Kernel low-level debugging functions (read help!)"

    depends on DEBUG_KERNEL

    help

      Say Y here to include definitions of printascii, printch, printhex

      in the kernel.  This is helpful if you are debugging code that

      executes before the console is initialized.


 


config DEBUG_S3C_UART0

    depends on PLAT_SAMSUNG

    select DEBUG_EXYNOS_UART if ARCH_EXYNOS

    select DEBUG_S3C24XX_UART if ARCH_S3C24XX

    select DEBUG_S5PV210_UART if ARCH_S5PV210

    bool "Use Samsung S3C UART 0 for low-level debug"

    help

      Say Y here if you want the debug print routines to direct

      their output to UART 0. The port must have been initialised

      by the boot-loader before use.


 


config DEBUG_LL_INCLUDE

    string

    ……

    default "debug/exynos.S" if DEBUG_EXYNOS_UART


 


config EARLY_PRINTK

    bool "Early printk"

    depends on DEBUG_LL

    help

      Say Y here if you want to have an early console using the

      kernel low-level debugging functions. Add earlyprintk to your

      kernel parameters to enable this console.


从上面的信息我们可以知道:


在串口终端尚未注册时,内核定义了printascii、printch以及printhex用于调试;

early console使用的也是上面定义的函数,需要在传递给内核的参数中添加earlyprintk参数

Linux内核早期的print函数的输出串口要跟u-boot下使用的一致,即内核不再负责初始化了,让u-boot来做,所以二者一定要一致,否则那些print函数以及earlyprintk都没法输出信息;

可以参考arch/arm/kernel/debug.S,printascii、printch以及printhex都是在这里定义的;

在kernel进入C函数(start_kernel)后可以调用early_print来打印信息,它是在arch/arm/kernel/setup.c中定义的:

   1: void __init early_print(const char *str, ...)

   2: {

   3:     extern void printascii(const char *);

   4:     char buf[256];

   5:     va_list ap;

   6: 

   7:     va_start(ap, str);

   8:     vsnprintf(buf, sizeof(buf), str, ap);

   9:     va_end(ap);

  10:  

  11: #ifdef CONFIG_DEBUG_LL

  12:     printascii(buf);

  13: #endif

  14:     printk("%s", buf);

  15: }

可以看到,early_print也会调用printascii和printk,意思是用early_print打印的信息可能会重复出现在终端上(printk会缓冲一部分,当bootconsole注册后,会将printk缓冲区中的内容输出)。


上面所说的打印函数只能在内核自解压后的函数中才能使用,那么内核自解压过程中的信息是不是也可以打印呢?可以,内核自解压相关的文件在arch/arm/boot/compressed/下面,我们所熟知的:


Uncompressing Linux... done, booting the kernel.


就是这个目录下的代码打印出来的,具体代码如下:


arch/arm/boot/compressed/misc.c


   1: void

   2: decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,

   3:         unsigned long free_mem_ptr_end_p,

   4:         int arch_id)

   5: {

   6:     ......

   7:     putstr("Uncompressing Linux...");

   8:     ret = do_decompress(input_data, input_data_end - input_data,

   9:                 output_data, error);

  10:     ......

  11:     putstr(" done, booting the kernel.n");

  12: }

 其中,putstr的定义如下:


   1: static void putstr(const char *ptr)

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>