前回の続きとしてacpi_parse_madt_lapic_entries()内で acpi_table_parse_madt()の2番目の引数で渡している関数を見ていこう。
見るのはうちの環境に関係ありそうなところでこの辺を。
- acpi_parse_x2apic()
- acpi_parse_lapic()
- acpi_parse_x2apic_nmi()
- acpi_parse_lapic_nmi()
4つあるけどx2apicとlapicの違いくらいで終わってくれれば良いんだけど。あとACPIの仕様書は今日も必要か。
最初に4関数共通なところでいくと、これらはacpi_table_parse_madt()に関数ポインタとして渡してhandlerという名前になり、実際に使われるのはacpi_table_parse_entries()の以下の部分。
while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < 240 table_end) { 241 if (entry->type == entry_id 242 && (!max_entries || count++ < max_entries)) 243 if (handler(entry, table_end)) 244 goto err;
ではまずはacpi_parse_x2apic()から。
この関数はProcessor Local x2APIC Structureのデータを見ていく。
213 acpi_parse_x2apic(struct acpi_subtable_header *header, const unsigned long end) 214 { 215 struct acpi_madt_local_x2apic *processor = NULL; 216 int apic_id; 217 u8 enabled; 218 219 processor = (struct acpi_madt_local_x2apic *)header; 220 221 if (BAD_MADT_ENTRY(processor, end)) 222 return -EINVAL; 223
最初にするのが引数で渡ってきたデータのアドレス範囲のチェック。
テーブル内容の表示。
224 acpi_table_print_madt_entry(header); 225
次にIDとフラグを見ている部分。
226 apic_id = processor->local_apic_id; 227 enabled = processor->lapic_flags & ACPI_MADT_ENABLED;
Processor Local x2APIC Structureの構造は「5.2.12.12 Processor Local x2APIC Structure」にあって以下の通り。
Filed | Byte Length | Byte Offset | Description |
Type | 1 | 0 | typeは9 |
Length | 1 | 1 | このテーブルの長さで16バイト |
Reserved | 2 | 2 | 予約領域で0埋め |
X2APIC ID | 4 | 4 | プロセッサローカルなAPIC ID |
Flags | 4 | 8 | Local APIC Flagsと同じ |
ACPI Processor UID | 4 | 12 |
Flagsは「Local APIC Flags」と同じというのでここで見てしまう。「Table 5-47 Local APIC Flags」を見ると至って単純で、32bit中、先頭の1bitをフラグとして使っているだけ。
LocalAPIC Flags | Bit Length | Bit Offset | Description |
Enabled | 1 | 0 | 0: disabled 1:enabled |
Reserved | 31 | 1 | 0埋め |
「rocessor->local_apic_id」で見ているのはテーブルの「X2APIC ID」で、processor->lapic_flagsは「Flags」の部分。
最後の処理はacpi_register_lapic()の呼び出し。
228 #ifdef CONFIG_X86_X2APIC 229 /* 230 * We need to register disabled CPU as well to permit 231 * counting disabled CPUs. This allows us to size 232 * cpus_possible_map more accurately, to permit 233 * to not preallocating memory for all NR_CPUS 234 * when we use CPU hotplug. 235 */ 236 if (!apic->apic_id_valid(apic_id) && enabled) 237 printk(KERN_WARNING PREFIX "x2apic entry ignored\n"); 238 else 239 acpi_register_lapic(apic_id, enabled); 240 #else 241 printk(KERN_WARNING PREFIX "x2apic entry ignored\n"); 242 #endif 243 244 return 0; 245 }
acpi_register_lapic()はacpi_register_lapic()も使っていて、この関数の中ではgeneric_processor_info()というまた重要そうな関数を読んでいたりするので後で読む。
と言う訳でacpi_parse_lapic()を。これは短い!
248 acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end) 249 { 250 struct acpi_madt_local_apic *processor = NULL; 251 252 processor = (struct acpi_madt_local_apic *)header; 253 254 if (BAD_MADT_ENTRY(processor, end)) 255 return -EINVAL; 256 257 acpi_table_print_madt_entry(header); 258 259 /* 260 * We need to register disabled CPU as well to permit 261 * counting disabled CPUs. This allows us to size 262 * cpus_possible_map more accurately, to permit 263 * to not preallocating memory for all NR_CPUS 264 * when we use CPU hotplug. 265 */ 266 acpi_register_lapic(processor->id, /* APIC ID */ 267 processor->lapic_flags & ACPI_MADT_ENABLED); 268 269 return 0; 270 }
テーブルの表示とacpi_register_lapic()を呼ぶだけというシンプルさ。
ここで見ているデータは
Filed | Byte Length | Byte Offset | Description |
Type | 1 | 0 | typeは0 |
Length | 1 | 1 | このテーブルの長さで8バイト |
ACPI Processor ID | 1 | 2 | プロセッサ ID |
APIC ID | 1 | 3 | プロセッサローカルなAPICID |
Flags | 4 | 4 | Local APIC Flagsと同じ |
processor->idはACPI Processor IDを見ている。
acpi_table_print_madt_entry()で表示しているのはdmesgしたときの↓の部分。acpi_parse_lapic()ではループ処理は無いけど呼び出し元のacpi_table_parse_madt()ではwhileループで処理しているので複数回呼び出されてる。
[ 0.000000] ACPI: LAPIC (acpi_id[0x01] lapic_id[0x00] enabled) [ 0.000000] ACPI: LAPIC (acpi_id[0x02] lapic_id[0x02] enabled) [ 0.000000] ACPI: LAPIC (acpi_id[0x03] lapic_id[0x04] enabled) [ 0.000000] ACPI: LAPIC (acpi_id[0x04] lapic_id[0x06] enabled) [ 0.000000] ACPI: LAPIC (acpi_id[0x05] lapic_id[0x01] enabled) [ 0.000000] ACPI: LAPIC (acpi_id[0x06] lapic_id[0x03] enabled) [ 0.000000] ACPI: LAPIC (acpi_id[0x07] lapic_id[0x05] enabled) [ 0.000000] ACPI: LAPIC (acpi_id[0x08] lapic_id[0x07] enabled)
データは8回表示されているので8スレッド分ということですな。
次はacpi_parse_x2apic_nmi()をば。処理は短い。
306 static int __init 307 acpi_parse_x2apic_nmi(struct acpi_subtable_header *header, 308 const unsigned long end) 309 { 310 struct acpi_madt_local_x2apic_nmi *x2apic_nmi = NULL; 311 312 x2apic_nmi = (struct acpi_madt_local_x2apic_nmi *)header; 313 314 if (BAD_MADT_ENTRY(x2apic_nmi, end)) 315 return -EINVAL; 316 317 acpi_table_print_madt_entry(header); 318 319 if (x2apic_nmi->lint != 1) 320 printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n"); 321 322 return 0; 323 }
見たままで特筆すべきことはなさそうですね。じゃあ、acpi_parse_lapic_nmi()はどうかな?
325 static int __init 326 acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end) 327 { 328 struct acpi_madt_local_apic_nmi *lapic_nmi = NULL; 329 330 lapic_nmi = (struct acpi_madt_local_apic_nmi *)header; 331 332 if (BAD_MADT_ENTRY(lapic_nmi, end)) 333 return -EINVAL; 334 335 acpi_table_print_madt_entry(header); 336 337 if (lapic_nmi->lint != 1) 338 printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n"); 339 340 return 0; 341 }
これも特に処理といった処理はない。
うちの環境だとacpi_table_print_madt_entry()では↓が出ている。
[ 0.000000] ACPI: LAPIC_NMI (acpi_id[0xff] high edge lint[0x1])
さて、さっき後で読むとしたacpi_register_lapic()なんだけど、関数は以下の通り。
192 static void acpi_register_lapic(int id, u8 enabled) 193 { 194 unsigned int ver = 0; 195 196 if (id >= MAX_LOCAL_APIC) { 197 printk(KERN_INFO PREFIX "skipped apicid that is too big\n"); 198 return; 199 } 200 201 if (!enabled) { 202 ++disabled_cpus; 203 return; 204 } 205 206 if (boot_cpu_physical_apicid != -1U) 207 ver = apic_version[boot_cpu_physical_apicid]; 208 209 generic_processor_info(id, ver); 210 } 211
generic_processor_info()が名前からして重要そうな感じ。
そんな訳で次はgeneric_processor_info()を読むφ( ̄ー ̄ )メモメモ
はじめてのOSコードリーディング ~UNIX V6で学ぶカーネルのしくみ (Software Design plus)
- 作者: 青柳隆宏
- 出版社/メーカー: 技術評論社
- 発売日: 2013/01/09
- メディア: 単行本(ソフトカバー)
- 購入: 56人 クリック: 1,959回
- この商品を含むブログ (23件) を見る