X86 Linux的SMP

SMP是对称多处理器的意思。Intel为SMP特地出台了一个MultiProcessor Specification,现在使用最多的就是1997年5月的1.4版。里面规范了如何设置中断控制器,BSP如何启动其他的AP,达到SMP。

X86多核系统启动的时候,硬件会选出一个BSP专门完成系统的引导工作,因此说BIOS是一般是运行在单核状态,grub也是。这个BSP在引导阶段要做的很重要的工作就是检查和配置系统的设备(特别是磁盘相关的HBA硬件),扫描并且初始化PCI树,初始化内存。因此当系统变得非常庞大、资源很多的时候,例如高端的服务器平台,这个初始化的时间就非常长了。

具体有多长呢?举一个EMC DD9XXX产品的例子吧,在512GB RAM,12个PCIe Gen2的卡全配的情况下,系统从按下power button到开到grub菜单,大约需要15-20分钟!也就是差不多1/4个小时就用来开机了。这也是为什么服务器平台通常不建议重启的原因,因为开关一次的代价实在是太大太大了。

上面提到的是硬件的SMP,就是系统当中存在同质的多个处理器。

在Intel的平台下,BSP在工作的时候,其他处理器(AP)处于wait startup IPI状态。BSP在初始化了基本硬件资源之后,通过APIC首先发送INIT IPI给其他的AP,然后等待10ms;接下来发送一个STARTUP IPI,再等待200us;最后再发送一个STARTUP IPI,再等待200us。之所以会有第二个STARTUP IPI,据说是为了fix一些CPU的bug。大部分情况下,第一个STARTUP IPI就足够了。BSP需要告知AP从哪里开始运行。

接下来说软件。Linux在2.6就开始支持多处理器SMP。那么这里说的软件的SMP,就是说同样的操作系统内核(Image)并发跑在多个物理处理器上。

Linux支持SMP是follow Intel的规范,包括上面提到的IPI中断。Linux的启动SMP的过程总结下来就是下面的过程。

do_boot_cpu() [ setup start_secondary() as entry point ]

|-> wakeup_xxxx_via_init_nmi() [ runs start_secondary in APs ]

  |-> cpu_init() [ initializes AP ]

    |-> wait_for_master_cpu() [ set xxx_initialized_mask, then pends on xxx_callout_mask ]

|-> BSP set xxx_callout_mask, to continue AP's cpu_init(), pends on xxx_callin_mask ]

也就是说这里定义了三个bitmap,其中每一位代表一个逻辑CPU(HT,或者core)。

BSP发送STARTUP IPI之后会等待AP置位cpu_initialized_mask。

AP启动之后会把自己对应的bit置为1,然后等待BSP设置cpu_callout_mask。

此时BSP知道该AP已经启动,然后设置cpu_callout_mask的相应位,之后等待AP设置cpu_callin_mask。

AP发现cpu_callout_mask被设置,于是进行剩余的启动工作。然后设置cpu_callin_mask的相应位。

BSP检测到cpu_callin_mask被设置之后,完成该AP的初始化,开始下一个AP的初始化操作。

这里面其实有个地方没有详细展开,那就是AP的启动的entry point。这个是由BSP设置的一段代码,由STARTUP IPI发送给AP。AP运行这段代码,完成从实模式开始的启动过程直到32bit保护模式/64bit长模式。这段代码在Linux里面叫做trampoline,中文是蹦床的意思。

(其实在前一篇IoT产品架构设计当中提到了一个独创性的在线升级,把代码从ROM搬移并跳转到RAM中运行,也可以说使用了一种特殊的蹦床的技术)。

关于Linux SMP的具体流程可以参考代码。trampoline是纯汇编,有兴趣的也可以去看看它的原理。

刚才讨论的是SMP的引导部分。在Linux运行过程中,有些时候也需要让某一个或者几个CPU完成一些特定的操作,这个时候也需要通过IPI。Linux内核为此做了封装,例如

/*

* Call a function on all other processors

*/

void smp_call_function(smp_call_func_t func, void *info, int wait);

void smp_call_function_many(const struct cpumask *mask,

    smp_call_func_t func, void *info, bool wait);

int smp_call_function_any(const struct cpumask *mask,

  smp_call_func_t func, void *info, int wait);

具体的用法网上大把大把的,这里不举例了。

但是需要注意的是,刚才提到了这些实际上是通过IPI来实现的,所以接收的CPU是在中断上下文运行的特定函数(Linux-4.4.30, Ubuntu-16.04 X86_64 server),例如。

void print_cpu_id(void * cpuid)

{

      int cpu=smp_processor_id();

        printk("Called: myid %d\n",cpu);

        printk("Called: myid %d\n",cpu);

        printk("Called: in_int=%d, in_irq=%d, in_softirq=%d\n",

                in_interrupt(), in_irq(), in_softirq());

        return;

}

static int __init hello_world_init(void)

{

        int cpu=0;

        flag=0;

        printk("hello_world_init\n");

        cpu=smp_processor_id();

        printk("Caller: myid is %d\n",cpu);

        smp_call_function(print_cpu_id, &cpu, 0);

。。。

}

[447099.229034] Called: myid 0

[447099.229037] Called: in_int=65536, in_irq=65536, in_softirq=0

因此需要记住中断上下文里的一些使用禁忌。

如果不能避免这样的禁忌,那就需要用别的方法来做,例如可以参考Linux中断处理的路子(top half和bottom half,softirq, tasklet, workqueue)。

我自己实现了类似的操作。

总结一下,硬件和操作系统(Linux)都为SMP的支持做了必要的准备,不管是boot up还是run-time。

仔细想想,好像还有一个什么地方有些奇怪。为什么SMP的初始化是由Linux完成的?服务器平台开机15-20分钟难道就没有什么好办法加速?

其实,这就是问为什么BIOS不用SMP来开机,而是UP。这个我也不知道确切的答案,或许是因为复杂性,或许是因为灵活性。这些有待专家给出来吧。

下一篇讲讲Linux X86的中断吧,应该会很短小。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,869评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,716评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,223评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,047评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,089评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,839评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,516评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,410评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,920评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,052评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,179评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,868评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,522评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,070评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,186评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,487评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,162评论 2 356