• <div id="0yoao"><tr id="0yoao"></tr></div>
    <dl id="0yoao"></dl>
  • <sup id="0yoao"></sup>
    <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>
  • ?

    Device Tree(一):背景介绍

    作者:linuxer 发布于:2014-5-22 16:46 分类:统一设备模型

    一、前言

    作为一个多年耕耘在linux 2.6.23内核的开发者,各个不同项目中各种不同周边外设驱动的开发以及各种琐碎的、扯皮的俗务占据了大部分的时间。当有机会下载3.14的内核并准备学习的时候,突然发现linux kernel对于我似乎变得非常的陌生了,各?#20013;?#30340;机制,各种framework、各?#20013;?#30340;概念让我感到阅读内核代码变得举步维艰。 还好,剖析内核的热情还在,剩下的就交给时间的。首先进入视线的是Device Tree机制,这是和porting内核非常相关的机制,如果想让将我们的?#24067;?#24179;台迁移到高版本的内核上,Device Tree是一个必须要扫清的?#20064;?

    我想从下面三个方面来了解Device Tree:

    1、为?#25105;?#24341;入Device Tree,这个机制是用来解决什么问题的?(这是本文的主题)

    2、Device Tree的基础概念(请参考DT基础概念

    3、ARM linux中和Device Tree相关的代码分析(请参考DT代码分析

    阅读linux内核代码就像欣赏冰山,有看得到的美景(各种内核机制及其代码),也有埋在水面之下看不到的基础(机制背后的?#20174;?#21644;目的)。沉醉于各种内核机制的代码固然有无限乐趣,但更重要的是注入更多的思考,思考其背后的机理,真正理解软件抽象。这样才能举一反三,并应用在具体的工作和生活中。

    本文主要从下面几个方面阐述为何ARM linux会引入Device Tree:

    1、没有Device Tree的ARM linux是如何?#20439;?#30340;?

    2、混乱的ARM architecture代码和存在的问题

    3、新内核的解决之道

     

    二、没有Device Tree的ARM linux是如何?#20439;?#30340;?

    ?#20197;?#32463;porting内核到两个ARM-based的平台上。一个是小的芯片公司的应用处理器,公司自己购买了CPU core,该CPU core使用ARM兼容的指令集(但不是ARM)加上各种公司自行设计的多媒体外设整合成公司的产品进行销售。而我的任务就是porting 2.4.18内核到该平台上。在黑白屏幕的手机时代,那颗AP(application process)支持了彩屏、camera、JPEG?#24067;?#21152;速、2D/3D加速、MMC/SD卡、各种音频加速(内置DSP)等等特性,功能强大到无法直视。另外一?#25105;?#26893;经历是让2.6.23内核跑在一个大公司的冷门BP(baseband processor)上。具体porting的方法是很简单的:

    1、自己撰写一个bootloader并传递适当的?#38382;?#32473;kernel。除了传统的command line以及tag list之类的,最重要的是申请一个machine type,当拿到属于自己项目的machine type ID的时候,当时心情雀跃,似乎自己已经是开源社区的一份子了(其实当时是有意愿,或者说有目标是想将大家的代码并入到linux kernel main line的)。

    2、在内核的arch/arm目录下建立mach-xxx目录,这个目录下,放入该SOC的相关代码,例如中断controller的代码,时间相关的代码,内存?#25104;洌?#30561;眠相关的代码等等。此外,最重要的是建立一个board specific文件,定义一个machine的宏:

    MACHINE_START(project name, "xxx公司的xxx?#24067;?#24179;台")
        .phys_io    = 0x40000000,
        .boot_params    = 0xa0000100,  
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io        = xxx_map_io,
        .init_irq    = xxx_init_irq,
        .timer        = &xxx_timer,
        .init_machine    = xxx_init,
    MACHINE_END

    在xxx_init函数中,一般会加入很多的platform device。因此,伴随这个board specific文件中是大量的静态table,描述了各种?#24067;?#35774;备信息。

    3、调通了system level的driver(timer,中断处理,clock等)以及串口terminal之后,linux kernel基本是可以起来了,后续各种driver不断的添加,直到系统软件支持所有的?#24067;?

    综上所述,在linux kernel中支持一个SOC平台其实是非常简单的,让linux kernel在一个特定的平台上“跑”起来也是非常简单的,问题的重点是如何优雅的”跑”。

     

    三、混乱的ARM architecture代码和存在的问题

    ?#30475;?#27491;式的linux kernel release之后都会有两周的merge window,在这个窗口期间,kernel各个部分的维护者都会提交各自的patch,将自己测试稳定的代码请求并入kernel main line。每到这个时候,Linus就会比较繁忙,他需要从各个内核维护者的?#31181;先?#24471;最新代码并merge到自己的kernel source tree中。Tony Lindgren,内核OMAP development tree的维护者,发送了一个邮件给Linus,请求提交OMAP平台代码修?#27169;?#24182;给出了一些细节描述:

    1、简单介绍本次改动

    2、关于如何解决merge conficts。有些git mergetool就可以处理,不能处理的,给出了详细介绍和解决方案

    一切?#24049;?#24179;常,也给出?#20439;?#22815;的信息,然而,正是这个pull request引发了一场针对ARM linux的内核代码的争论。我相信Linus一定?#23884;訟RM相关的代码早就不爽了,ARM的merge工作量较大倒在其次,主要是他认为ARM很多的代码都是垃圾,代码里面有若干愚蠢的table,而多个人在维护这个table,从而导致了冲突。因此,在处理完OMAP的pull request之后(Linus并非针对OMAP平台,只是Tony Lindgren撞在枪口上了),他发出了怒吼:

    Gaah. Guys, this whole ARM thing is a f*cking pain in the ass.

    负责ARM linux开发的Russell King脸上挂不住,进行了反驳:事情没有那么?#29616;兀?#36825;次的merge conficts就是OMAP和IMX/MXC之间一点协调的问题,不能抹杀整个ARM linux团队的努力。其他的各个ARM平台维护者?#24067;?#20837;讨论:ARM平台如何复杂,如何庞大,对于arm linux code我们已经有一些思考,正在进行中……一时间,讨论的气氛有些尖锐,但总体是坦诚和友好的。

    对于一件事情,不同层次的人有不同层次的思考。这次争论涉及的人包括:

    1、内核维护者(CPU体系结构无关的代码)

    2、维护ARM系统结构代码的人

    3、维护ARM sub architecture的人(来自各个ARM SOC vendor)

    维护ARM sub architecture的人并没有强烈的使命感,作为公司的一员,他们最大的目标是以最快的速度支持自己公司的SOC,尽快的占领市场。这些人的软件功力未必强,对linux kernel的理解未必深入(有些人可能很强,但是人在江湖身不由己)。在这样的情况下,很多SOC specific的代码都是通过copy and paste,然后稍?#26377;?#25913;代码就提交了。此外,各个ARM vendor的SOC family是一长串的CPU list,每个CPU多多少少有些不同,这时候#ifdef?#32479;?#26021;了各个源代码中,让ARM mach-和plat-目录下的代码有些不?#35752;?#35270;。

    作为维护ARM体系结构的人,其能力不容置疑。以Russell King为首的team很好的维护了ARM体系结构的代码。基本上,除了mach-和plat-目录,其他的目录中的代码和目录组织是很好的。作为ARM linux的维护者,维护一个不断有新的SOC加入的CPU architecture code的确是一个挑战。在Intel X86的架构一统天下的时候,任?#34583;?#27491;面攻击Intel的对手?#21450;?#19979;阵来。想要击倒巨人(或者说想要和巨人并存)必须另辟蹊径。ARM的策略有两个,一个是focus在嵌入式应用上,也就意味着要求低功?#27169;?#21516;时也避免了和Intel的正面对抗。另外一个就是博采众家之长,采用license IP的方式,让更多的厂商加入ARM建立的生态系统。毫无疑?#21097;珹RM公司是成功的,但是这种模式也给ARM linux的维护者带来了噩梦。越来越多的芯片厂商加入ARM阵营,越来越多的ARM platform相关的代码被加入到内核,不同厂商的周边HW block设计又各不相同……

    内核维护者是真正对操作系统内核软件有深入理解的人,他们往往能站在更高的层次?#20808;?#35266;察问题,发现问题。Linus注意到?#30475;蝝erge window中,ARM的代码变化大约占整个ARCH目录的60%,他认为这是一个很明显的符号,意味着ARM linux的代码可能存在问题。其实,60%这个比率的确很夸张,因为unicore32是在2.6.39 merge window中第一次全新提交,它的代码是全新的,但是其代码变化大约占整个ARCH目录的9.6%(需要提及的是unicore32是一个中国芯)。有些维护ARM linux的人认为这是CPU市场占用率的体现,不是问题,直到内核维护者贴出实际的代码并指出问题所在。内核维护者当然想linux kernel支持更多的?#24067;?#24179;台,但是他们更愿意为linux kernel制定更长远的规划。例如:对于各种繁杂的ARM平台,用一个kernel image来支持。

    经过争论,确定的问题如下:

    1、ARM linux缺少platform(各个ARM sub architecture,或者说各个SOC)之间的协调,导致arm linux的代码有重?#30784;?#20540;得一提的是在本次争论之前,ARM维护者已经进行了不少相关的工作(例如PM和clock tree)来抽象相同的功能模块。

    2、ARM linux中大量的board specific的源代码应该踢出kernel,否则这些垃圾代码和table会影响linux kernel的长期目标。

    3、各个sub architecture的维护者直接提交给Linux并入主线的机制缺乏层次。

     

    四、新内核的解决之道

    针对ARM linux的现状,最需要解决的是人员问题,也就是如何整合ARM sub architecture(各个ARM Vendor)的?#35797;础?#22240;此,内核社区成立了一个ARM sub architecture的team,该team主要负责协调各个ARM厂商的代码(not ARM core part),Russell King继续负责ARM core part的代码。此外,建立一个ARM platform consolidation tree。ARM sub architecture team负责review各个sub architecture维护者提交的代码,并在ARM platform consolidation tree上维护。在下一个merge window到来的时候,将patch发送给Linus。

    针对重复的代码问题,如果不同的SOC使用了相同的IP block(例如I2C controller),那么这个driver的code要从各个arch/arm/mach-xxx中独立出来,变成一个通用的模块供各个SOC specific的模块使用。移动到哪个目录呢?对于I2C或者USB OTG而言,这些HW block的驱动当然应该移动到kernel/drivers目录。因为,对于这些外设,可能是in-chip,?#37096;?#33021;是off-chip的,但?#23884;?#20110;软件而言,它们是没有差别的(或者说好的软件抽象应该掩盖?#25758;閿布?#30340;不同)。对于那些system level的code呢?例如clock control、interrupt control。其实这些也不是ARM-specific,应该属于linux kernel的核心代码,应该放到linux/kernel目录下,属于core-Linux-kernel frameworks。当然对于ARM平台,也需要保存一些和framework交互的code,这些code叫做ARM SoC core architecture code。OK,总结一下:

    1、ARM的核心代码仍然保存在arch/arm目录下

    2、ARM SoC core architecture code保存在arch/arm目录下

    3、ARM SOC的周边外设模块的驱动保存在drivers目录下

    4、ARM SOC的特定代码在arch/arm/mach-xxx目录下

    5、ARM SOC board specific的代码被移除,由Device Tree机制来负责传递?#24067;?#25299;扑和?#24067;?#36164;源信息。

    OK,终于来到了Device Tree了。本质上,Device Tree改变了原来用hardcode方式将HW 配置信息嵌入到内核代码的方法,改用bootloader传递一个DB的形式。对于基于ARM CPU的嵌入式系统,我们习惯于针对每一个platform进行内核的编译。但是随着ARM在消费类电子上的广泛应用(甚至桌面系统、服务器系统),我们期望ARM能够象X86那样用一个kernel image来支持多个platform。在这种情况下,如果我们认为kernel是一个black box,那么其输入?#38382;?#24212;该包括:

    1、识别platform的信息

    2、runtime的配置?#38382;?

    3、设备的拓扑结构以及特性

    对于嵌入式系统,在系统启动阶段,bootloader会加载内核并将控制权转交给内核,此外,还需要把上述的三个?#38382;?#20449;息传递给kernel,以便kernel可以有较大的灵活性。在linux kernel中,Device Tree的设计目标就是如此。


    原创文章,转发请注明出处。蜗窝科技www.71402172.com

    标签: Device tree

    评论:

    Jack
    2019-02-25 16:06
    請教蝸窩兩幾個問題:
    1. 目前再?#33455;?#22914;何將新的Kernel 移植到前人所交接的版子,原先是可以動作。(版本為Kernel 4.15左右)
    但我去下載kernel 4.19版本來?#24190;g後,根據其他網站及論壇所講解的方式及步驟,有成功將zImage所?#24190;g出來。
    放入燒錄後,但始終卡住在Starting kernel位置,不知蝸窩是否有什麼方向或是建議可提供。謝謝蝸窩。
    2. 而我?#24190;g的步驟為
       a. 下載源碼
       b. 設定環境變數export ARCH=arm;export CROSS_COMPILE=arm-linux-gnueabihf-;
       c. 開始?#24190;g make menuconfig;make;之後就會出現zImage
    不知蝸窩有沒有什麼方向可以提供。謝謝。
    Downey
    2019-07-11 16:39
    @Jack:可能是image地址的问题
    bigbigtree
    2018-04-16 07:34
    wowo大哥,您好!请问一下您上面讲的移植内核“调通了system level的driver(timer,中断处理,clock等)以及串口terminal之后,linux kernel基本是可以起来了?#20445;?#36825;个是怎么做的呢?有没有一些文章介绍呢?就是让linux最小系统跑起来,可以进入终端,谢谢您
    wowo
    2018-04-16 08:47
    @bigbigtree?#32791;?#21487;以看看这个专题(不知道能否帮到你):
    http://www.71402172.com/sort/x_project
    wason
    2018-02-27 10:48
    你好,看了你的文章,感到非常惊讶,请问你是如何对linux设备树的历史背景了解得那么清楚呢?
    black
    2017-12-28 14:04
    逻辑上flat device tree实现了adv cfg & pwr management(acpi)中的cfg部分,但是power management部分怎么办?
    风露
    2017-12-21 23:05
    请教蜗窝两个问题:
    1、对于platform匹配,我的理解是这样的:
    过去采用的方式是,Linux静态定义板级信息,通过bootloader传递的machine type ID 进?#33455;?#24577;匹配,匹配?#29616;?#21518;得到相关?#24067;?#36164;源和定义的初始化接口。
    dt采用的方式是,Linux同样定义一些静态信息(DT_MACHINE_START和MACHINE_END),然后根据dts根目录中的“compatible”来进行匹配。
    这样理解对吗?如果是这样,在platform匹配上面,这两种方式好像换汤不换药啊。
    2、对于?#24067;?#20449;息的初始化。我的理解是这样的:
    过去的方式是?#21644;?#36807;静态配置的方式,把各种控制器相关的信息(如寄存器)写死,内核中配置上要使用的驱动,并给驱动传入这些寄存器等?#38382;?#23436;成?#24067;?#30340;初始化。
    dt的方式是,片上的?#24067;?#20449;息都写到dts中,内核配置上可能用到的驱动(会产生冗余?),然后Linux启动时会解析dtb,根据node来进行?#24067;?#35774;备的注册。这种理解对吗?另外,这是否就是dt引入的根本原因?
    linuxer
    2017-12-22 16:36
    @风露:基本上我是认同你的看法的。
    DTS之前,bootloader可以通过tag list传递?#38382;?#20197;便实现内核的动态配置,但是,这时候设备往往是通过静态定义的xxx_device hardcode在代码中,DTS主要解决这个问题,顺便接管了原理tag list的功能,使之统一在dts的框架中。
    风露
    2017-12-22 17:35
    @linuxer:关于tag list,bootargs可以通过在 chosen node中指定,但对于一些自定义tag在哪里进行传递
    Isara
    2017-10-27 10:59
    字里行间体现出的风采,和背后沉淀的?#33258;蹋?#36825;都是装不出来的
    zin
    2017-07-17 18:29
    写的真好,学习了
    光阴的事故
    2017-02-08 10:21
    感谢,我是新手,有空就过来学习哈
    edison.jiang
    2017-01-24 17:34
    博总弄过unicore?
    wowo
    2017-01-25 09:13
    @edison.jiang?#22909;?#26377;哦。
    iamhuskar
    2017-01-18 11:27
    新的板子上,关于上层文件系统构建。如果要构建一个定制的rootfs,。一般采用什么样的形式做呢?自己一个个包编译安装构建太麻烦了。linuxfromscratch或者是busybox。不知道博主用什么形式
    wowo
    2017-01-18 12:27
    @iamhuskar:嵌入式的小系统可以用busybox,具体可参考http://www.71402172.com/x_project/simple_busybox.html。

    发表评论:

    Copyright @ 2013-2015 蜗窝科技 All rights reserved. Powered by emlog
    连码三全中是什么
  • <div id="0yoao"><tr id="0yoao"></tr></div>
    <dl id="0yoao"></dl>
  • <sup id="0yoao"></sup>
    <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>
    <dl id="0yoao"></dl>
  • <sup id="0yoao"></sup>
    <div id="0yoao"><tr id="0yoao"></tr></div>
  • <div id="0yoao"><tr id="0yoao"></tr></div>
  • 北京pk10有官方网站吗 河北20选5最新开奖查询 p3试机号体彩 天津快乐十分现场直播 河南快赢481最近30期 新浪爱彩竟彩足球比分直播 彩票七星彩开奖直播 网球王子图片 香港六合彩期 千禧3d试机号金码今天一 双色球基本走势图表图中彩网 吉林快三和值图表 澳洲幸运5软件下载 网络棋牌游戏大全21点 湖南彩票网站