Linux电源管理(3)_Generic PM之Reboot过程

作者:wowo 发布于:2014-5-19 15:44 分类:电源管理子系统

1. 前言

在使用计算机的过程中,关机和重启是最先学会的两个操作。同样,这两个操作在Linux中也存在,称作shutdown和restart。这就是本文要描述的对象。

在Linux Kernel中,主流的shutdown和restart都是通过“reboot”系统调用(具体可参考kernel/sys.c)来实现的,这也是本文使用“Generic PM之Reboot过程”作为标题的原因。另外,除了我们常用的shutdown和restart两类操作之外,该系统调用也提供了其它的reboot方式,也会在这里一一说明。

2. Kernel支持的reboot方式

也许你会奇怪,reboot是重启的意思,所以用它实现Restart是合理的,但怎么用它实现关机操作呢?答案是这样的:关机之后,早晚也会开机啊!所以关机是一种特殊的Restart过程,只不过持续的时间有点长而已。所以,内核根据不同的表现方式,将reboot分为如下的几种方式:

   1: /*      
   2:  * Commands accepted by the _reboot() system call.
   3:  *
   4:  * RESTART     Restart system using default command and mode.
   5:  * HALT        Stop OS and give system control to ROM monitor, if any.
   6:  * CAD_ON      Ctrl-Alt-Del sequence causes RESTART command.
   7:  * CAD_OFF     Ctrl-Alt-Del sequence sends SIGINT to init task.
   8:  * POWER_OFF   Stop OS and remove all power from system, if possible.
   9:  * RESTART2    Restart system using given command string.
  10:  * SW_SUSPEND  Suspend system using software suspend if compiled in.
  11:  * KEXEC       Restart system using a previously loaded Linux kernel
  12:  */
  13:         
  14: #define LINUX_REBOOT_CMD_RESTART        0x01234567
  15: #define LINUX_REBOOT_CMD_HALT           0xCDEF0123
  16: #define LINUX_REBOOT_CMD_CAD_ON         0x89ABCDEF
  17: #define LINUX_REBOOT_CMD_CAD_OFF        0x00000000
  18: #define LINUX_REBOOT_CMD_POWER_OFF      0x4321FEDC
  19: #define LINUX_REBOOT_CMD_RESTART2       0xA1B2C3D4
  20: #define LINUX_REBOOT_CMD_SW_SUSPEND     0xD000FCE2
  21: #define LINUX_REBOOT_CMD_KEXEC          0x4558454

RESTART,正常的重启,也是我们平时使用的重启。执行该动作后,系统会重新启动。

HALT,停止操作系统,然后把控制权交给其它代码(如果有的话)。具体的表现形式,依赖于系统的具体实现。

CAD_ON/CAD_OFF,允许/禁止通过Ctrl-Alt-Del组合按键触发重启(RESTART)动作。
注1:Ctrl-Alt-Del组合按键的响应是由具体的Driver(如Keypad)实现的。

POWER_OFF,正常的关机。执行该动作后,系统会停止操作系统,并去除所有的供电。

RESTART2,重启的另一种方式。可以在重启时,携带一个字符串类型的cmd,该cmd会在重启前,发送给任意一个关心重启事件的进程,同时会传递给最终执行重启动作的machine相关的代码。内核并没有规定该cmd的形式,完全由具体的machine自行定义。

SW_SUSPEND,即前一篇文章中描述的Hibernate操作,会在下一篇文章描述,这里就暂不涉及。

KEXEC,重启并执行已经加载好的其它Kernel Image(需要CONFIG_KEXEC的支持),暂不涉及。

3. Reboot相关的操作流程

在Linux操作系统中,可以通过reboot、halt、poweroff等命令,发起reboot,具体的操作流程如下:

Reboot相关的操作流程

  • 一般的Linux操作系统,在用户空间都提供了一些工具集合(如常在嵌入式系统使用的Busybox),这些工具集合包含了reboot、halt和poweroff三个和Reboot相关的命令。读者可以参考man帮助文档,了解这些命令的解释和使用说明
  • 用户空间程序通过reboot系统调用,进入内核空间
  • 内核空间根据执行路径的不同,提供了kernel_restart、kernel_halt和kernel_power_off三个处理函数,响应用空间的reboot请求
  • 这三个处理函数的处理流程大致相同,主要包括:向关心reboot过程的进程发送Notify事件;调用drivers核心模块提供的接口,关闭所有的外部设备;调用drivers syscore模块提供的接口,关闭system core;调用Architecture相关的处理函数,进行后续的处理;最后,调用machine相关的接口,实现真正意义上的Reboot
  • 另外,借助TTY模块提供的Sysreq机制,内核提供了其它途径的关机方法,如某些按键组合、向/proc文件写入命令等,后面会详细介绍

4. Reboot过程的内部动作和代码分析

4.1 Reboot系统调用

Reboot系统调用的实现位于“kernel/sys.c”,其函数原型如下:

   1: SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
   2:                 void __user *, arg)

该函数的参数解释如下:

reboot,该系统调用的名称。

magic1、magic2,两个int类型的“魔力数”,用于防止误操作。具体在“include/uapi/linux/reboot.h”中定义,感兴趣的同学可以去看看(话说这些数字还是蛮有意思的,例如Linus同学及其家人的生日就在里面,猜出来的可以在文章下面留言)。

cmd,第2章所讲述的reboot方式。

arg,其它的额外参数。

reboot系统调用的内部动作比较简单:

1)判断调用者的用户权限,如果不是超级用户(superuser),则直接返回错误(这也是我们再用户空间执行reboot、halt、poweroff等命令时,必须是root用户的原因);

2)判断传入的magic number是否匹配,如果不匹配,直接返回错误。这样就可以尽可能的防止误动作发生;

3)调用reboot_pid_ns接口,检查是否需要由该接口处理reboot请求。这是一个有关pid namespaces的新特性,也是Linux内核重要的知识点,我们会在其它文章中描述,这里就不多说了;

4)如果是POWER_OFF命令,且没有注册power off的machine处理函数(pm_power_off),把该命令转换为HALT命令;

5)根据具体的cmd命令,执行具体的处理,包括,
      如果是RESTART或者RESTART2命令,调用kernel_restart。
      如果是CAD_ON或CAD_OFF命令,更新C_A_D的值,表示是否允许通过Ctrl+Alt+Del组合键重启系统。
      如果是HALT命令,调用kernel_halt。
      如果是POWER_OFF命令,调用kernel_power_off。
      如果是KEXEC命令,调用kernel_kexec接口(暂不在本文涉及)。
      如果是SW_SUSPEND,调用hibernate接口(会在下一章描述);

6)返回上述的处理结果,系统调用结束。

4.2 kernel_restart、kernel_halt和kernel_power_off

这三个接口也位于“kernel/sys.c”,实现比较类似,具体动作包括:

1)调用kernel_xxx_prepare函数,进行restart/halt/power_off前的准备工作,包括,
      调用blocking_notifier_call_chain接口,向关心reboot事件的进程,发送SYS_RESTART、SYS_HALT或者SYS_POWER_OFF事件。对RESTART来说,还好将cmd参数一并发送出去。
      将系统状态设置为相应的状态(SYS_RESTART、SYS_HALT或SYS_POWER_OFF)。
      调用usermodehelper_disable接口,禁止User mode helper(可参考“Linux设备模型(3)_Uevent”相关的描述)。
      调用device_shutdown,关闭所有的设备(具体内容会在下一节讲述);

2)如果是power_off,且存在PM相关的power off prepare函数(pm_power_off_prepare),则调用该回调函数;

3)调用migrate_to_reboot_cpu接口,将当前的进程(task)移到一个CPU上;
注2:对于多CPU的机器,无论哪个CPU触发了当前的系统调用,代码都可以运行在任意的CPU上。这个接口将代码分派到一个特定的CPU上,并禁止调度器分派代码到其它CPU上。也就是说,这个接口被执行后,只有一个CPU在运行,用于完成后续的reboot动作。

4)调用syscore_shutdown接口,将系统核心器件关闭(例如中断等);

5)调用printk以及kmsg_dump,向这个世界发出最后的声音(打印日志);

6)最后,由machine-core的代码,接管后续的处理。

4.3 device_shutdown

在理解device_shutdown之前,我们需要回忆一下前几篇有关Linux设备模型的文章。同时,借助对电源管理的解析,我们会把在Linux设备模型系列文章中没有描述的部分补回来。设备模型中和device_shutdown有关的逻辑包括:

  • 每个设备(struct device)都会保存该设备的驱动(struct device_driver)指针,以及该设备所在总线(struct bus_type)的指针(具体参考“Linux设备模型(5)_device和device driver”)
  • 设备驱动中有一个名称为“shutdown”的回调函数,用于在device_shutdown时,关闭该设备(具体参考“Linux设备模型(5)_device和device driver”)
  • 总线中也有一个名称为“shutdown”的回调函数,用于在device_shutdown时,关闭该设备(具体参考“Linux设备模型(6)_Bus”)
  • 系统的所有设备,都存在于“/sys/devices/”目录下,而该目录由名称为“devices_kset”的kset表示。而由“Linux设备模型(2)_Kobject”的描述可知,kset中会使用一个链表保存其下所有的kobject(也即“/sys/devices/”目录下的所有设备)。最终的结果就是,以“devices_kset”为root节点,将内核中所有的设备(以相应的kobject为代表),组织成一个树状结构

介绍完以上的背景知识,我们来看device_shutdown的实现,就非常容易了。该接口位于“drivers/base/core.c”中,执行逻辑如下。

   1: /**
   2:  * device_shutdown - call ->shutdown() on each device to shutdown.
   3:  */
   4: void device_shutdown(void)
   5: {
   6:         struct device *dev, *parent;
   7:         
   8:         spin_lock(&devices_kset->list_lock);
   9:         /*
  10:          * Walk the devices list backward, shutting down each in turn.
  11:          * Beware that device unplug events may also start pulling
  12:          * devices offline, even as the system is shutting down.
  13:          */
  14:         while (!list_empty(&devices_kset->list)) {
  15:                 dev = list_entry(devices_kset->list.prev, struct device,
  16:                                 kobj.entry);
  17:  
  18:                 /*
  19:                  * hold reference count of device's parent to
  20:                  * prevent it from being freed because parent's
  21:                  * lock is to be held
  22:                  */
  23:                 parent = get_device(dev->parent);
  24:                 get_device(dev);
  25:                 /*
  26:                  * Make sure the device is off the kset list, in the
  27:                  * event that dev->*->shutdown() doesn't remove it.
  28:                  */
  29:                 list_del_init(&dev->kobj.entry);
  30:                 spin_unlock(&devices_kset->list_lock);
  31:  
  32:                 /* hold lock to avoid race with probe/release */
  33:                 if (parent)
  34:                         device_lock(parent);
  35:                 device_lock(dev);
  36:  
  37:                 /* Don't allow any more runtime suspends */
  38:                 pm_runtime_get_noresume(dev);
  39:                 pm_runtime_barrier(dev);
  40:  
  41:                 if (dev->bus && dev->bus->shutdown) {
  42:                         if (initcall_debug)
  43:                                 dev_info(dev, "shutdown\n");
  44:                         dev->bus->shutdown(dev);
  45:                 } else if (dev->driver && dev->driver->shutdown) {
  46:                         if (initcall_debug)
  47:                                 dev_info(dev, "shutdown\n");
  48:                         dev->driver->shutdown(dev);
  49:                 }
  50:  
  51:                 device_unlock(dev);
  52:                 if (parent)
  53:                         device_unlock(parent);
  54:  
  55:                 put_device(dev);
  56:                 put_device(parent);
  57:  
  58:                 spin_lock(&devices_kset->list_lock);
  59:         }
  60:         spin_unlock(&devices_kset->list_lock);
  61:         async_synchronize_full();
  62: }

1)遍历devices_kset的链表,取出所有的设备(struct device);

2)将该设备从链表中删除;

3)调用pm_runtime_get_noresume和pm_runtime_barrier接口,停止所有的Runtime相关的电源管理动作(后续的文章会详细描述有关Runtime PM的逻辑);

4)如果该设备的bus提供了shutdown函数,优先调用bus的shutdown,关闭设备;

5)如果bus没有提供shutdown函数,检测设备driver是否提供,如果提供,调用设备driver的shutdown,关闭设备;

6)直至处理完毕所有的设备。

4.4 system_core_shutdown

system core的shutdown和设备的shutdown类似,也是从一个链表中,遍历所有的system core,并调用它的shutdown接口。后续蜗蜗会专门写一篇文章介绍syscore,这里暂不描述。

4.5 machine_restart、machine_halt和machine_power_off

虽然以machine_为前缀命名,这三个接口却是属于Architecture相关的处理函数,如ARM。以ARM为例,它们在“arch/arm/kernel/process.c”中实现,具体如下。

4.5.1 machine_restart
   1: /*
   2:  * Restart requires that the secondary CPUs stop performing any activity
   3:  * while the primary CPU resets the system. Systems with a single CPU can
   4:  * use soft_restart() as their machine descriptor's .restart hook, since that
   5:  * will cause the only available CPU to reset. Systems with multiple CPUs must
   6:  * provide a HW restart implementation, to ensure that all CPUs reset at once.
   7:  * This is required so that any code running after reset on the primary CPU
   8:  * doesn't have to co-ordinate with other CPUs to ensure they aren't still
   9:  * executing pre-reset code, and using RAM that the primary CPU's code wishes
  10:  * to use. Implementing such co-ordination would be essentially impossible.
  11:  */
  12: void machine_restart(char *cmd)
  13: {
  14:         smp_send_stop();
  15:  
  16:         arm_pm_restart(reboot_mode, cmd);
  17:  
  18:         /* Give a grace period for failure to restart of 1s */
  19:         mdelay(1000);
  20:  
  21:         /* Whoops - the platform was unable to reboot. Tell the user! */
  22:         printk("Reboot failed -- System halted\n");
  23:         local_irq_disable();
  24:         while (1);
  25: }

0)先转述一下该接口的注释;
对于多CPU的机器来说,Restart之前必须保证其它的CPU处于非活动状态,由其中的一个主CPU负责Restart动作。并且,必须实现一个基于硬件的Restart操作,以保证所有CPU同步Restart,这是设计的重点
对于单CPU机器来说,就相对简单了,可以直接用软件reset的方式实现Restart。

1)调用smp_send_stop接口,确保其它CPU处于非活动状态;

2)调用machine-dependent的restart接口,实现真正的restart。该接口是一个回调函数,由“arch/arm/kernel/process.c”声明,由具体的machine代码实现。格式如下:
      void (*arm_pm_restart)(char str, const char *cmd) = null_restart;
      EXPORT_SYMBOL_GPL(arm_pm_restart);

3)等待1s;

4)如果没有返回,则restart成功,否则失败,打印错误信息。

4.5.2 machine_halt

ARM的halt很简单,就是将其它CPU停下来,并禁止当前CPU的中断后,死循环!确实,中断被禁止了,又死循环了,不halt才怪。代码如下:

   1: /*
   2:  * Halting simply requires that the secondary CPUs stop performing any
   3:  * activity (executing tasks, handling interrupts). smp_send_stop()
   4:  * achieves this.
   5:  */
   6: void machine_halt(void)
   7: {
   8:         smp_send_stop();
   9:  
  10:         local_irq_disable();
  11:         while (1);
  12: }
4.5.3 machine_power_off

power off动作和restart类似,即停止其它CPU,调用回调函数。power off的回调函数和restart类似,就不再说明了。

5. 总结与思考

5.1 Architecture和Machine的概念

本文是我们在分析Linux内核时第一次遇到Architecture和Machine的概念,顺便解释一下。内核代码中最常见的目录结构就是:arch/xxx/mach-xxx/(例如arch/arm/mach-bcm/)。由该目录结构可知,Architecture(简称arch)是指具体的体系结构,如ARM、X86等等。Machine呢,是指具体体系结构下的一个或一系列的SOC,如bcm等。

5.2 电源管理驱动(和reboot有关的部分)需要实现内容

由上面的分析可知,在Reboot的过程中,大部分的逻辑是否内核处理的,具体的driver需要关注2点即可:

1)实现各自的shutdown接口,以正确关闭对应的设备

2)实现machine-dependent的接口,以确保底层的Machine可以正确restart或者power off

看来还是很简单的。

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

标签: Linux PM 电源管理 reboot power_off

评论:

maze
2017-01-11 15:45
看了一遍又一遍,螺旋上升的感觉还是不错的
窝窝加油
wowo
2017-01-12 13:31
@maze:加油~!
lamaboy
2016-08-14 17:22
你好,,
我在 追踪 pm_power_off 的时候,如下发现,在关机之前把所有的设备都关闭,或者 put_device(dev)了,可是下面部分的挂机是通过i2c 写寄存器,让pmic 断电,, 这里还有什么特殊的设置存在吧

具体看如下代码;

pm_power_off = act8865_power_off;

static void act8865_power_off(void)
{
    struct act8865 *act8865;

    act8865 = i2c_get_clientdata(act8865_i2c_client);
    regmap_write(act8865->regmap, act8865->off_reg, act8865->off_mask);
    while (1);
}
wowo
2016-08-15 12:26
@lamaboy:你可以检查一下,i2c有关的Shutdown接口应该没有实现(或者没有真的Shutdown),或者这里就不会起作用了。
lamaboy
2016-08-15 20:36
@wowo:谢谢,, 你一说我就明白是怎么回事了,,谢谢啊1
swingboard
2015-12-15 11:04
个人认为do_exit(0)还是会调用的,这个函数的最后调用:
for (;;)
    cpu_relax();    /* For when BUG is null */
不就是傻等着掉点吗?
请指教。
wowo
2015-12-15 17:20
@swingboard:是不是能走到这里,是取决于pm_power_off中做了什么事情的。举2个极端的例子:
如果pm_power_off直接断电,肯定无法到这里;
如果pm_power_off什么都不做,肯定能到这里。
wowo
2015-05-02 21:14
@shoujixiaodao:在手机的做法一般如下……感谢分享,总结很清楚。
Tekkaman Ninja
2015-04-15 12:55
Reboot系统调用的实现位于“kernel/sys.c”  --> 现在在 kernel/reboot.c 了
Tekkaman Ninja
2015-04-15 13:11
@Tekkaman Ninja:kernel_restart、kernel_halt和kernel_power_off 这三个接口也位于“kernel/reboot.c”
wowo
2015-04-15 14:24
@Tekkaman Ninja:多谢提醒~~
这个世界变化真快啊,呵呵~~
perr
2014-09-27 10:23
#define LINUX_REBOOT_MAGIC1     0xfee1dead
#define LINUX_REBOOT_MAGIC2     672274793 //0x28121969 Linus Torvalds
#define LINUX_REBOOT_MAGIC2A    85072278  //0x05121996
#define LINUX_REBOOT_MAGIC2B    369367448 //0x16041998
#define LINUX_REBOOT_MAGIC2C    537993216 //0x20112000

FROM wikipedia:
Tove and Linus were later married and have three daughters, Patricia Miranda (born 1996), Daniela Yolanda (born 1998), and Celeste Amanda (born 2000), two of whom were born in the United States.

life is a interesting thing. isn't it?
汉字
蜗蜗~
2014-09-27 18:52
@perr:呵呵,是啊,Linus一家4口的生日都在里面了。
forion
2014-08-27 16:15
hi 蜗蜗
有一个问题
case LINUX_REBOOT_CMD_POWER_OFF:
    kernel_power_off();
    do_exit(0);
    break;
是不是正常情况下,do_exit(0),应该不会执行是不是这样?
wowo
2014-08-27 17:15
@forion:我个人的看法是这样的:
linux的reboot指令包括shutdown、halt、power off和restart,这些指令中,只有power off可能不被底层的平台支持(特别是早期的基于ARM的嵌入式平台),以ARM为例,可以参见arch/arm/kernel/process.c中machine_xxx的实现。
因此,很有可能,kernel_power_off()的调用会直接返回,do_exit会被执行。

下面是arm平台power off的实现,可以佐证这一点:
void machine_power_off(void)
{
    local_irq_disable();
    smp_send_stop();

    if (pm_power_off)
        pm_power_off();
}
linuxer
2014-08-27 19:12
@wowo:pm_power_off()这个函数应该是machine或者是board specific的,有的板子还是支持这个函数的,在这个函数中,可以shutdown整个系统的电源。在这种情况下,do_exit(0)还是有可能不执行的。
forion
2014-08-27 20:13
@linuxer:我现在就是这样的,因为我看到pm_power_off()把所有的电都关了,按照道理,do_exit(0)应该不会执行到,如果执行到了那就有可能走到panic里面
wowo
2014-08-27 20:20
@forion:关电的动作可能会有延迟,CPU可以挣扎一会儿。所以一般会在pm_power_off中加一些延时。
linuxer
2014-08-27 23:09
@wowo:延时有点困难吧,中断已经关闭了。其他的CPU已经停下来,只剩下一个boot CPU做最后的清理工作。
对于X86平台,我估计kernel_power_off之后程序已经跑到BIOS里面去了,应该是会不来了。
shoujixiaodao
2015-05-01 22:38
@linuxer:在手机的做法一般如下
1,pm_power_off()这个函数最终machine 都会实现的。
2,machine的实现方式大都一样。即控制PMIC。让PMIC给soc断电
3,下完如上第二点的命令后。虽然控制pmic掉电。但是一般pmic的输出电源都有滤波电容。所以电源是慢慢掉下去的。即下电后cpu还能挣扎执行一些命令
4,如上第3点。所以一般加一些delay
5.有的做法还会做一些判断。比如我插入充电器。执行了关机命令。一般充电器插入pmic的时候,即使cpu发命令让pmic下电。pmic也不会掉电。所以如果延时过后会check是否插入充电器。如果插入则重启手机,以便进入关机充电模式。
动漫情报站
2014-05-22 12:05
这个确实可以看看哈
蜗蜗
2014-05-22 12:32
@动漫情报站:谢谢~~
linuxer
2014-05-20 17:09
有点歪楼哦,本文的主题是电源管理,呵呵~~~不过我喜欢这个话题
-------------------------------------
实际上,按照arch/SOC/board这样的代码组织是否OK?对于很多的ARM soc,其实它的很多controller都是购买的,例如USB OTG controller,可能都是购买自同一家公司。而目前的ARM的代码组织导致很多的代码重复。
也许确实应该从功能角度进行目录规划......
linux_fans
2014-05-21 08:53
@linuxer:这里的SOC具体是什么含义呢?目前按照arch/arm来分,也有一定的合理性,因为有很多ARM相关的很新代码,是共用的。
linuxer
2014-05-22 09:06
@linux_fans:抱歉,我写的太快了,没有检查,arch/arm是必须的,应该是这样的:
arch/SOC/board  ---修改成---》 arch/arm/platform-SOC/board specific
Note:当引入Device Tree之后,board specific的文件不应该存在了。

也就是说:
1、arm目录保存所有的ARM cpu体系结构的东西以及platform cross的代码。这里的platform是指SOC family,每个公司可能出若干个SOC family以便适应不同的市场。当前的plat-pxa、plat-omap等不是我想要的。每个ARM vendor都是以自己为中心,只是考虑自己平台的通用性,而不是ARM platform的通用性。一个简单的例子就是不同的ARM vendor公司会购买同样的IP block,毫无疑问,这些代码应该是被复用的,不过有些无节操的厂商会copy and paste,然后稍加修改。当然,厂商这么做也情有可原,毕竟他们的目标只是让linux kernel在他们的平台上跑起来,不关心整个ARM LINUX code是否优雅。
2、platform-SOC目录包含了各个ARM SOC family的代码,这些代码必须是platform specific的,如果有共用性,那么需要抽取出来,并入到上级目录。例如GPIO driver,各个ARM SOC平台都有自己的GPIO driver,但也不过是copy and paste的产物,为何不进一步抽象?(新的内核已经这么做了,不过我还没有去深入了解),更进一步,是否所有的arch都要同样的问题?基于MIPS的SOC也是一样的需要GPIO,那么是否GPIO变成driver目录的一个block?(写完上面的文字,我去瞄了一眼3.14的内核,其实现在已经是这么做的了,呵呵~~)
3、ARM已经引入了device tree来解决hardcode board specific的问题
有理想的咸鱼
2014-05-20 12:30
针对5.1 section,我的看法如下:
实际上,硬件是分三个层次:
1、用的哪一类型CPU,是X86的还是ARM的(对应linux kernel中的arch/XXX目录)
2、如果使用的是X86的CPU,那么具体使用哪一种CPU,是AMD的Geode 处理器还是intel的mid处理器。如果是ARM,那么使用的是S3C2410还是OMAP3530(在ARM中,我看不出什么对应关系。对与X86平台,对应linux kernel中的arch/platform/XXX目录)
3、具体的target board。这个是和具体的项目相关,和CPU以及周边的外设相关。具体的target board必须要选择一个CPU platform以及外设芯片(对应linux kernel中的driver目录)。而描述board相关的信息对应对应linux kernel中的arch/platform/XXX/board-xxx.c文件。

对于arch/arm目录下的东西,非常凌乱,希望近期的kernel release能够改善。我理想的目录结构是:
1、arch保持不变,映射CPU architecture的概念
2、建立platform目录,映射CPU platform的概念。
3、选择了某个CPU platform的target board代码应该尽量的少(和CPU platform相关的代码是公共代码,并非board specific,和外设相关的代码在driver目录)并集中在一个文件(我看不出来这个board specific文件存在的必要性,可能有些board fixup吧)。

Machine的概念在ARM上比较模糊。在定义每一个SOC的时候,使用了ARCH这个术语,例如对于Marvell的PXA2xx/PXA3xx-based的CPU platform,arm kernel使用了ARCH_PXA这样的定义,而在board specific文件,例如mainstone.c中,我们需要定义一个MAINSTONE相关的MACHINE。linus大骂ARM linux的代码“this whole ARM thing is a f*cking pain in the ass”也是有些道理的。
linux_fans
2014-05-20 15:58
@有理想的咸鱼:确实,arch/arm目录是很凌乱的。所以那些概念性的东西,如Architecture,如Machine,其定义也不是很清晰。我们看内核的时候,不要太纠结这些词汇就是了。

发表评论:

Copyright @ 2013-2015 蜗窝科技 All rights reserved. Powered by emlog