<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.jackslab.org/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-cn">
		<id>http://wiki.jackslab.org/index.php?action=history&amp;feed=atom&amp;title=MIPS_Linux_SMP_%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B</id>
		<title>MIPS Linux SMP 启动流程 - 版本历史</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.jackslab.org/index.php?action=history&amp;feed=atom&amp;title=MIPS_Linux_SMP_%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B"/>
		<link rel="alternate" type="text/html" href="http://wiki.jackslab.org/index.php?title=MIPS_Linux_SMP_%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B&amp;action=history"/>
		<updated>2026-09-11T05:15:57Z</updated>
		<subtitle>本wiki的该页面的版本历史</subtitle>
		<generator>MediaWiki 1.19.2</generator>

	<entry>
		<id>http://wiki.jackslab.org/index.php?title=MIPS_Linux_SMP_%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B&amp;diff=204&amp;oldid=prev</id>
		<title>2013年1月17日 (四) 10:39 Comcat</title>
		<link rel="alternate" type="text/html" href="http://wiki.jackslab.org/index.php?title=MIPS_Linux_SMP_%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B&amp;diff=204&amp;oldid=prev"/>
				<updated>2013-01-17T10:39:27Z</updated>
		
		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table class='diff diff-contentalign-left'&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
			&lt;tr valign='top'&gt;
			&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←上一版本&lt;/td&gt;
			&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;2013年1月17日 (四) 10:39的版本&lt;/td&gt;
			&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第1行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第1行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&amp;#160;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;&amp;lt;br&amp;gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;1. 以 Cavium Octeon 多核 MIPS 为例，启动时所有的core的入口一起指向kernel_entry，然后在kernel_entry_setup宏里分叉，boot core 继续往下，其它的则不停的判断循环，直到boot core 唤醒之：&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;1. 以 Cavium Octeon 多核 MIPS 为例，启动时所有的core的入口一起指向kernel_entry，然后在kernel_entry_setup宏里分叉，boot core 继续往下，其它的则不停的判断循环，直到boot core 唤醒之：&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Comcat</name></author>	</entry>

	<entry>
		<id>http://wiki.jackslab.org/index.php?title=MIPS_Linux_SMP_%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B&amp;diff=203&amp;oldid=prev</id>
		<title>Comcat：以“1. 以 Cavium Octeon 多核 MIPS 为例，启动时所有的core的入口一起指向kernel_entry，然后在kernel_entry_setup宏里分叉，boot core 继续往下...”为内容创建页面</title>
		<link rel="alternate" type="text/html" href="http://wiki.jackslab.org/index.php?title=MIPS_Linux_SMP_%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B&amp;diff=203&amp;oldid=prev"/>
				<updated>2013-01-17T10:39:10Z</updated>
		
		<summary type="html">&lt;p&gt;以“1. 以 Cavium Octeon 多核 MIPS 为例，启动时所有的core的入口一起指向kernel_entry，然后在kernel_entry_setup宏里分叉，boot core 继续往下...”为内容创建页面&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;1. 以 Cavium Octeon 多核 MIPS 为例，启动时所有的core的入口一起指向kernel_entry，然后在kernel_entry_setup宏里分叉，boot core 继续往下，其它的则不停的判断循环，直到boot core 唤醒之：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef CONFIG_SMP&lt;br /&gt;
    rdhwr   v0, $0                                                            # 当前core 的 id 入 v0&lt;br /&gt;
&lt;br /&gt;
    bne     a2, zero, octeon_main_processor              # boot core 的 a2 会被bootloader 设为 1&lt;br /&gt;
    nop&lt;br /&gt;
    #&lt;br /&gt;
    # All cores other than the master need to wait here for SMP bootstrap&lt;br /&gt;
    # to begin&lt;br /&gt;
    #&lt;br /&gt;
    PTR_LA t0, octeon_processor_boot          # 全局变量，当boot core 完成必要的初始化，挨个 up 其它&lt;br /&gt;
                                                                       core 时，通过向该变量写入下一个要 up 的 core 的 number&lt;br /&gt;
                                                                       来up 下一个core&lt;br /&gt;
octeon_spin_wait_boot:&lt;br /&gt;
    LONG_L t1, (t0)                                                  # 读取 octeon_processor_boot 的值&lt;br /&gt;
    bne t1, v0, octeon_spin_wait_boot            # Keep looping if it isn't me :)&lt;br /&gt;
    nop&lt;br /&gt;
    PTR_LA t0, octeon_processor_cycle                # 如果是我，则同步一下 cycle counter，与其它core 一致&lt;br /&gt;
    LONG_L t0, (t0)&lt;br /&gt;
    daddu   t0, 122                                              # Aproximately how many cycles we will be off&lt;br /&gt;
    dmtc0   t0, CP0_CYCLE_COUNTER&lt;br /&gt;
    PTR_LA t0, octeon_processor_gp               # boot core cpu_up() 一个core 时，会先fork 一个 idle&lt;br /&gt;
                                                                 内核线程，尔后将 octeon_processor_gp 指向 idle 的 thread_info 结构&lt;br /&gt;
    LONG_L gp, (t0)&lt;br /&gt;
    PTR_LA t0, octeon_processor_sp               # octeon_processor_sp 指向 idle 的kernel stack&lt;br /&gt;
    LONG_L sp, (t0)&lt;br /&gt;
    LONG_S zero, (t0)                               # boot core 会通过不停的读取 octeon_processor_sp 的值来&lt;br /&gt;
                                                           判断被 cpu_up() 的core 是否已经boot 完。其值设为 0 时，表示我&lt;br /&gt;
                                                           已起来 :)&lt;br /&gt;
#ifdef __OCTEON__&lt;br /&gt;
    syncw&lt;br /&gt;
#else&lt;br /&gt;
    sync&lt;br /&gt;
#endif&lt;br /&gt;
    b   smp_bootstrap                                        # Jump to the normal Linux SMP entry point&lt;br /&gt;
    nop&lt;br /&gt;
&lt;br /&gt;
octeon_main_processor:&lt;br /&gt;
#endif&lt;br /&gt;
.endm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
注意 Linux 下， SMP 的通用入口是 smp_bootstrap，其定义于[arch/mips/head.S]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#ifdef CONFIG_SMP&lt;br /&gt;
/*&lt;br /&gt;
* SMP slave cpus entry point. Board specific code for bootstrap calls this&lt;br /&gt;
* function after setting up the stack and gp registers.&lt;br /&gt;
*/&lt;br /&gt;
NESTED(smp_bootstrap, 16, sp)&lt;br /&gt;
#ifdef CONFIG_MIPS_MT_SMTC&lt;br /&gt;
    /*&lt;br /&gt;
     * Read-modify-writes of Status must be atomic, and this&lt;br /&gt;
     * is one case where CLI is invoked without EXL being&lt;br /&gt;
     * necessarily set. The CLI and setup_c0_status will&lt;br /&gt;
     * in fact be redundant for all but the first TC of&lt;br /&gt;
     * each VPE being booted.&lt;br /&gt;
     */&lt;br /&gt;
    DMT 10 # dmt t2 /* t0, t1 are used by CLI and setup_c0_status() */&lt;br /&gt;
    jal mips_ihb&lt;br /&gt;
#endif /* CONFIG_MIPS_MT_SMTC */&lt;br /&gt;
    setup_c0_status_sec&lt;br /&gt;
    smp_slave_setup                                                      # slave core 额外的操作，一般为空&lt;br /&gt;
#ifdef CONFIG_MIPS_MT_SMTC&lt;br /&gt;
    andi    t2, t2, VPECONTROL_TE&lt;br /&gt;
    beqz    t2, 2f&lt;br /&gt;
    EMT     # emt&lt;br /&gt;
2:&lt;br /&gt;
#endif /* CONFIG_MIPS_MT_SMTC */&lt;br /&gt;
    j   start_secondary&lt;br /&gt;
&lt;br /&gt;
    END(smp_bootstrap)&lt;br /&gt;
#endif /* CONFIG_SMP */&lt;br /&gt;
&lt;br /&gt;
    .macro setup_c0_status_sec&lt;br /&gt;
#ifdef CONFIG_64BIT&lt;br /&gt;
    setup_c0_status ST0_KX ST0_BEV&lt;br /&gt;
#else&lt;br /&gt;
    setup_c0_status 0 ST0_BEV&lt;br /&gt;
#endif&lt;br /&gt;
    .endm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
setup_c0_status ST0_KX ST0_BEV 完成的操作为：&lt;br /&gt;
&lt;br /&gt;
将 cp0_status 低5位清0，另加 CU0 | KX 位，清 BEV 位，注意与setup_c0_status_pri 的差别，setup_c0_status_pri 是不清BEV 位，因为 boot core 用它时尚未初始化好异常入口，这个要到 trap_init()中才会被清掉。而此时 slave core 起时系统异常入口已经初始化好了，可以清 BEV 位了。&lt;br /&gt;
&lt;br /&gt;
尔后直接跳到 start_secondary() 这是 slave core 执行的第一个C 代码函数，一个新时代开始了:)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 有些 Multi-core 的实现是，最先进入kernel_entry 的只有一个 core (boot core)（此时，其它core的状态，要不没上电，要不就是在死循环），尔后由boot core 在依次 cpu_up() 的时候，通过调用prom_boot_secondary() ，在其中将 slave core 的入口指向 smp_bootstrap，当然还要设置好 slave core 的 sp, gp。&lt;br /&gt;
&lt;br /&gt;
具体的实现有所不一，broadcom 的实现是借助CFE (common firmware envirment)，来设置 sp, gp, 入口地址(smp_bootstrap)，然后start slave core：&lt;br /&gt;
&lt;br /&gt;
[arch/mips/sibyte/cfe/smp.c]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
* Setup the PC, SP, and GP of a secondary processor and start it&lt;br /&gt;
* running!&lt;br /&gt;
*/&lt;br /&gt;
void __cpuinit prom_boot_secondary(int cpu, struct task_struct *idle)&lt;br /&gt;
{&lt;br /&gt;
    int retval;&lt;br /&gt;
&lt;br /&gt;
    retval = cfe_cpu_start(cpu_logical_map(cpu), &amp;amp;smp_bootstrap,&lt;br /&gt;
                   __KSTK_TOS(idle),&lt;br /&gt;
                   (unsigned long)task_thread_info(idle), 0);&lt;br /&gt;
    if (retval != 0)&lt;br /&gt;
        printk(&amp;quot;cfe_start_cpu(%i) returned %i\n&amp;quot; , cpu, retval);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[arch/mips/sibyte/cfe/cfe_api.c]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#if defined(CFE_API_cpu_start) || defined(CFE_API_ALL)&lt;br /&gt;
int cfe_cpu_start(int cpu, void (*fn) (void), long sp, long gp, long a1)&lt;br /&gt;
{&lt;br /&gt;
    cfe_xiocb_t xiocb;&lt;br /&gt;
&lt;br /&gt;
    xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL;&lt;br /&gt;
    xiocb.xiocb_status = 0;&lt;br /&gt;
    xiocb.xiocb_handle = 0;&lt;br /&gt;
    xiocb.xiocb_flags = 0;&lt;br /&gt;
    xiocb.xiocb_psize = sizeof(xiocb_cpuctl_t);&lt;br /&gt;
    xiocb.plist.xiocb_cpuctl.cpu_number = cpu;&lt;br /&gt;
    xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_START;&lt;br /&gt;
    xiocb.plist.xiocb_cpuctl.gp_val = gp;&lt;br /&gt;
    xiocb.plist.xiocb_cpuctl.sp_val = sp;&lt;br /&gt;
    xiocb.plist.xiocb_cpuctl.a1_val = a1;&lt;br /&gt;
    xiocb.plist.xiocb_cpuctl.start_addr = (long) fn;&lt;br /&gt;
&lt;br /&gt;
    cfe_iocb_dispatch(&amp;amp;xiocb);&lt;br /&gt;
&lt;br /&gt;
    return xiocb.xiocb_status;&lt;br /&gt;
}&lt;br /&gt;
#endif              /* CFE_API_cpu_start || CFE_API_ALL */&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
这个在kernel 里也容易实现，只要在一个内存区域实现一段代码，然后将这些值写入，最后将slave core 的异常入口指向这断代码（当然这段代码最终是跳往 smp_bootstrap 的），然后写一下相应 slave core 的 reset 控制寄存器即可，这个一般的多核平台都有，cavium octeon 也有，只是它的默认实现没用这个机制而已。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Append: octeon 是从octeon_boot_desc_ptr-&amp;gt;core_mask 拿到bootloader传过来的 coremask，然后设置相应的bitmap 位。这个与内核参数 numcores= 没有直接的联系，应该是bootloader根据numcores 的值，计算相应的coremask&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Comcat</name></author>	</entry>

	</feed>