前回の続きとしてgeneric_processor_info()を読む。
まずはgeneric_processor_info()が呼ばれる流れを。これはacpi_register_lapic()から呼ばれていて、acpi_register_lapic()は以下の関数などから呼ばれる。
- acpi_parse_x2apic()
- acpi_parse_lapic()
- acpi_parse_x2apic_nmi()
- acpi_parse_lapic_nmi()
フロートしてはだいたいこんなもの。
acpi_parse_madt_lapic_entries() <- acpi_parse_x2apic()などはacpi_table_parse_madt()の引数として関数ポインタで渡す
-> acpi_table_parse_madt()
-> acpi_table_parse_entries() handler(entry, table_end)という形でacpi_parse_x2apic()などの呼び出し
-> acpi_parse_x2apic()
-> acpi_register_lapic()
-> generic_processor_info()
では、generic_processor_info()を見ていく。
2110 void generic_processor_info(int apicid, int version) 2111 { 2112 int cpu, max = nr_cpu_ids; 2113 bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid, 2114 phys_cpu_present_map); 2115 2116 /* 2117 * If boot cpu has not been detected yet, then only allow upto 2118 * nr_cpu_ids - 1 processors and keep one slot free for boot cpu 2119 */ 2120 if (!boot_cpu_detected && num_processors >= nr_cpu_ids - 1 && 2121 apicid != boot_cpu_physical_apicid) { 2122 int thiscpu = max + disabled_cpus - 1; 2123 2124 pr_warning( 2125 "ACPI: NR_CPUS/possible_cpus limit of %i almost" 2126 " reached. Keeping one slot for boot cpu." 2127 " Processor %d/0x%x ignored.\n", max, thiscpu, apicid); 2128 2129 disabled_cpus++; 2130 return; 2131 } 2132
ここまではBSP(Boot Strap Processorはコンピューターの起動時に動いたcpu。カーネルが別途起動させるのはApplication Processorで略称はAP)が検出済みかをチェックして、もし未検出ならAPのほうはdisableにしておくということか。
num_processors、nr_cpu_idsはグローバル変数。
2133 if (num_processors >= nr_cpu_ids) { 2134 int thiscpu = max + disabled_cpus; 2135 2136 pr_warning( 2137 "ACPI: NR_CPUS/possible_cpus limit of %i reached." 2138 " Processor %d/0x%x ignored.\n", max, thiscpu, apicid); 2139 2140 disabled_cpus++; 2141 return; 2142 } 2143
ここも整合性のチェックでcpuの検出数があってないようならそのcpuはdisableになる。
2144 num_processors++; 2145 if (apicid == boot_cpu_physical_apicid) { 2146 /* 2147 * x86_bios_cpu_apicid is required to have processors listed 2148 * in same order as logical cpu numbers. Hence the first 2149 * entry is BSP, and so on. 2150 * boot_cpu_init() already hold bit 0 in cpu_present_mask 2151 * for BSP. 2152 */ 2153 cpu = 0; 2154 } else 2155 cpu = cpumask_next_zero(-1, cpu_present_mask); 2156
今見ているcpuがBSPの場合の処理だけど、ここはBIOSのバグ対策なのね。
2157 /* 2158 * Validate version 2159 */ 2160 if (version == 0x0) { 2161 pr_warning("BIOS bug: APIC version is 0 for CPU %d/0x%x, fixing up to 0x10\n", 2162 cpu, apicid); 2163 version = 0x10; 2164 } 2165 apic_version[apicid] = version; 2166
バージョンについてはさらにもう一個チェックがある。
2167 if (version != apic_version[boot_cpu_physical_apicid]) { 2168 pr_warning("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n", 2169 apic_version[boot_cpu_physical_apicid], cpu, version); 2170 } 2171
次は今処理してきたcpuをカーネルのほうで覚えておく(という言い方は微妙だけど)。
2172 physid_set(apicid, phys_cpu_present_map); 2173 if (apicid > max_physical_apicid) 2174 max_physical_apicid = apicid; 2175 2176 #if defined(CONFIG_SMP) || defined(CONFIG_X86_64) 2177 early_per_cpu(x86_cpu_to_apicid, cpu) = apicid; 2178 early_per_cpu(x86_bios_cpu_apicid, cpu) = apicid; 2179 #endif 2180 #ifdef CONFIG_X86_32 2181 early_per_cpu(x86_cpu_to_logical_apicid, cpu) = 2182 apic->x86_32_early_logical_apicid(cpu); 2183 #endif
ここの処理で登録したcpuはnum_possible_cpus()、num_present_cpus() で見れるようになるはず。
2184 set_cpu_possible(cpu, true); 2185 set_cpu_present(cpu, true); 2186 }
generic_processor_info()はループの中で呼ばれてくるので、1cpu毎に処理が行われて最終的にすべての(CPUコア、HT)がcpuとして登録されるということかな。
ブート時のcpu数の認識に関してはdmesgの以下の部分が出た時点で確定できているので今度はここをちょっと見てみる。
[ 0.000000] smpboot: Allowing 8 CPUs, 0 hotplug CPUs
Linuxカーネル Hacks ―パフォーマンス改善、開発効率向上、省電力化のためのテクニック
- 作者: 池田宗広,大岩尚宏,島本裕志,竹部晶雄,平松雅巳,高橋浩和
- 出版社/メーカー: オライリージャパン
- 発売日: 2011/07/26
- メディア: 単行本(ソフトカバー)
- 購入: 4人 クリック: 50回
- この商品を含むブログ (4件) を見る