一直想写写APIC这个玩意,可惜一直没时间。不多说了,直接入正题。
从start_kernel(void)开始,这个函数中,跟APIC有关的函数包括以下几个
setup_arch(&command_line);
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
trap_init();
init_IRQ();
rest_init();
这五个函数涉及到了所有的APIC初始化的代码,包含LAPIC和IOAPIC。
从第一个函数开始看起
setup_arch(&command_line);
其实,这个函数里的APIC相关的代码,主要是对于MP table进行分析,从BIOS中读取MP表,然后用表中的值初始化一些相关的数据结构。
在这个函数中,调用的与APIC有关的函数如下
setup_memory() -> setup_bootmem_allocator() -> find_smp_config();
acpi_boot_table_init();
acpi_boot_init();
get_smp_config();
看第一个函数
void __init find_smp_config (void)
{
unsigned int address;
/*
* FIXME: Linux assumes you have 640K of base ram..
* this continues the error...
*
* 1) Scan the bottom 1K for a signature
* 2) Scan the top 1K of base RAM
* 3) Scan the 64K of bios
*/
if (smp_scan_config(0x0,0x400) ||
smp_scan_config(639*0x400,0x400) ||
smp_scan_config(0xF0000,0x10000))
return;
/*
* If it is an SMP machine we should know now, unless the
* configuration is in an EISA/MCA bus machine with an
* extended bios data area.
*
* there is a real-mode segmented pointer pointing to the
* 4K EBDA area at 0x40E, calculate and scan it here.
*
* NOTE! There are Linux loaders that will corrupt the EBDA
* area, and as such this kind of SMP config may be less
* trustworthy, simply because the SMP table may have been
* stomped on during early boot. These loaders are buggy and
* should be fixed.
*
* MP1.4 SPEC states to only scan first 1K of 4K EBDA.
*/
address = get_bios_ebda();
if (address)
smp_scan_config(address, 0x400);
}
关键就是找到MP table所在的地址,这里还是实模式
/*
* there is a real-mode segmented pointer pointing to the
* 4K EBDA area at 0x40E.这个表的地址是0x40E
*/
static inline unsigned long get_bios_ebda(void)
{
unsigned long address = *(unsigned short *)phys_to_virt(0x40EUL);
address <<= 4;
return address;
}
而smp_scan_config()这个函数的作用是,以address为基地址,搜索0x400的范围内,希望能够找到一个MP table。而MP table的主要标志,就是以“_MP_”开头,于是,在函数中
mpf = (struct intel_mp_floating *)bp;
if ((*bp == SMP_MAGIC_IDENT) &&
(mpf->mpf_length == 1) &&
!mpf_checksum((unsigned char *)bp, 16) &&
((mpf->mpf_specification == 1)
|| (mpf->mpf_specification == 4)) ) {
smp_found_config = 1;
其中,这个SMP_MAGIC_IDENT宏是
#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')
没错,就是“_MP_”。
如果条件都符合,那么全局变量smp_found_config = 1;就被设置成了1,表示找到了MP table。并且后面把这个MP table的地址mpf_found = mpf;
找到MP table之后,我们就要以此表为依据,初始化一些变量结构体等,以备将来的需要。
阅读(1989) | 评论(0) | 转发(0) |