1. CPU信息初始化函数调用
start_kernelàsetup_archàearly_cpu_initàearly_identify_cpuàcpu_detect等;
early_identify_cpu函数主要功能是记录内核所支持的CPU设备,并调用early_identify_cpu函数来完成CPU信息的初始化。
在early_identify_cpu函数中,有如下循环语句:
for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) {
const struct cpu_dev *cpudev = *cdev;
if (count >= X86_VENDOR_NUM)
break;
cpu_devs[count] = cpudev;
count++;
}
__x86_cpu_dev_start、__x86_cpu_dev_end变量定义在哪个文件呢?各个厂家的CPU信息又如何组合在一起的呢?
2. CPU信息组合
在arch/x86/kernel/目录下有编译链接脚本文件vmlinux.lds.S,在此文件中,包含了如下的代码段:
.x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
__x86_cpu_dev_start = .;
*(.x86_cpu_dev.init)
__x86_cpu_dev_end = .;
}
在arch/x86/kernel/cpu/目录下,有描述AMD CPU信息的amd.c文件,有描述Intel CPU信息的Intel.c文件,有描述Centaur CPU信息的Centaur.c文件,有描述Cyrix CPU信息和NSC CPU的Cyrix.c文件,有描述Transmeta CPU信息的Transmeta.c文件,有描述UMC CPU信息的Umc.c文件。我以前真不知道,除了AMD和Intel,还有这么多厂家也在生产和使用X86 CPU呀。
在这些文件中,都调用了相同的一个宏定义cpu_dev_register。此宏定义在arch\x86\kernel\cpu\cpu.h文件中,如下所示:
#define cpu_dev_register(cpu_devX) \
static const struct cpu_dev *const __cpu_dev_##cpu_devX __used \
__attribute__((__section__(".x86_cpu_dev.init"))) = \
&cpu_devX;
此宏定义通过使用__attribute__((__section__(".x86_cpu_dev.init")))将这些文件中包含的CPU设备变量组合在以__x86_cpu_dev_start开头的数组中。例如,AMD和Intel的CPU设备变量如下所示:
static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
.c_vendor = "AMD",
.c_ident = { "AuthenticAMD" },
#ifdef CONFIG_X86_32
.c_models = {
{ .vendor = X86_VENDOR_AMD, .family = 4, .model_names =
{
[3] = "486 DX/2",
[7] = "486 DX/2-WB",
[8] = "486 DX/4",
[9] = "486 DX/4-WB",
[14] = "Am5x86-WT",
[15] = "Am5x86-WB"
}
},
},
.c_size_cache = amd_size_cache,
#endif
.c_early_init = early_init_amd,
.c_init = init_amd,
.c_x86_vendor = X86_VENDOR_AMD,
};
cpu_dev_register(amd_cpu_dev);
static const struct cpu_dev __cpuinitconst intel_cpu_dev = {
.c_vendor = "Intel",
.c_ident = { "GenuineIntel" },
#ifdef CONFIG_X86_32
.c_models = {
{ .vendor = X86_VENDOR_INTEL, .family = 4, .model_names =
{
[0] = "486 DX-25/33",
[1] = "486 DX-50",
[2] = "486 SX",
[3] = "486 DX/2",
[4] = "486 SL",
[5] = "486 SX/2",
[7] = "486 DX/2-WB",
[8] = "486 DX/4",
[9] = "486 DX/4-WB"
}
},
{ .vendor = X86_VENDOR_INTEL, .family = 5, .model_names =
{
[0] = "Pentium 60/66 A-step",
[1] = "Pentium 60/66",
[2] = "Pentium 75 - 200",
[3] = "OverDrive PODP5V83",
[4] = "Pentium MMX",
[7] = "Mobile Pentium 75 - 200",
[8] = "Mobile Pentium MMX"
}
},
{ .vendor = X86_VENDOR_INTEL, .family = 6, .model_names =
{
[0] = "Pentium Pro A-step",
[1] = "Pentium Pro",
[3] = "Pentium II (Klamath)",
[4] = "Pentium II (Deschutes)",
[5] = "Pentium II (Deschutes)",
[6] = "Mobile Pentium II",
[7] = "Pentium III (Katmai)",
[8] = "Pentium III (Coppermine)",
[10] = "Pentium III (Cascades)",
[11] = "Pentium III (Tualatin)",
}
},
{ .vendor = X86_VENDOR_INTEL, .family = 15, .model_names =
{
[0] = "Pentium 4 (Unknown)",
[1] = "Pentium 4 (Willamette)",
[2] = "Pentium 4 (Northwood)",
[4] = "Pentium 4 (Foster)",
[5] = "Pentium 4 (Foster)",
}
},
},
.c_size_cache = intel_size_cache,
#endif
.c_early_init = early_init_intel,
.c_init = init_intel,
.c_x86_vendor = X86_VENDOR_INTEL,
};
cpu_dev_register(intel_cpu_dev);
在结构体变量cpu_dev中提供了回调函数。这样,CPU信息初始化代码可以调用这些回调函数得到更加详细的CPU信息。