上一篇说到了下面这个函数,接着说。前面已经建立了内存页面管理所需的数据结构,现在进一步完善页面映射机制。
paging_init();
此函数源码如下:
/*
* paging_init() sets up the page tables - note that the first 8MB are
* already mapped by head.S.
*
* This routines also unmaps the page at virtual kernel address 0, so
* that we can trap those pesky NULL-reference errors in the kernel.
*/
void __init paging_init(void)
{
#ifdef CONFIG_X86_PAE
.....
#endif
pagetable_init();通过此函数扩充在系统初始化(那些汇编代码)创建的页面映射目录和页面映射表。看上面那行红色的注释。
load_cr3(swapper_pg_dir);装载页面目录到cr3
#ifdef CONFIG_X86_PAE
.........
#endif
.........
}
* NOTE: at this point the bootmem allocator is fully available.
*/
#ifdef CONFIG_EARLY_PRINTK
{
........
}
#endif
dmi_scan_machine();
此函数的作用
SMBIOS/DMI : System Management BIOS/Desktop Management Interface. PC的BIOS规范。(摘于网络)
#ifdef CONFIG_X86_GENERICARCH
.......
#endif
register_memory(max_low_pfn);物理页面是一种资源,从另外一个角度,地址空间本身也是一种资源吗,所以要加以管理,分配。 对系统I/O资源生成资源树 ,源码如下:
/*
* Request address space for all standard resources
*/
这里涉及到一个很重要的数据结构,它描述了一片可以通过访问内存操作或I/O操作加以访问的连续空间。每个resource结构通过struct resource *parent, *sibling, *child;等指针联系在一起,形成树状结构。内核中有两颗这样的树,分别代表着两类不同性质的地址资源。
/* PC/ISA/whatever - the normal PC address spaces: IO and memory */
struct resource ioport_resource = {
.name = "PCI IO",
.start = 0x0000,
.end = IO_SPACE_LIMIT,
.flags = IORESOURCE_IO,
};
struct resource iomem_resource = {
.name = "PCI mem",
.start = 0UL,
.end = ~0UL,
.flags = IORESOURCE_MEM,
};
/*
* Resources are tree-like, allowing
* nesting etc..
*/
struct resource {
const char *name;
unsigned long start, end;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
static void __init register_memory(unsigned long max_low_pfn)
{
unsigned long low_mem_size;
int i;
if (efi_enabled)
efi_initialize_iomem_resources(&code_resource, &data_resource);
前几篇对这个EFI都没说什么,因为实在不知道他是什么?后来查了下资料,EFI是可扩展固件接口(英文名Extensible Firmware Interface 或EFI)是由英特尔,一个主导个人电脑技术研发的公司推出的一种在未来的类PC的电脑系统中替代BIOS的升级方案。BIOS技术的兴起源于IBM PC/AT机器的流行以及第一台由康柏公司研制生产的“克隆”PC。在PC启动的过程中,BIOS担负着初始化硬件,检测硬件功能,以及引导操作系统的责任,在早期,BIOS还提供一套运行时的服务程序给操作系统及应用程序使用。BIOS程序存放于一个掉电后内容不会丢失的只读存储器中,系统加电时处理器的第一条指令的地址会被定位到BIOS的存储器中,便于使初始化程序得到执行。
else
legacy_init_iomem_resources(&code_resource, &data_resource);
这些是内核代码段和数据段中的地址信息。
......
/* request I/O space for devices used on all i[345]86 PCs */
for (i = 0; i < STANDARD_IO_RESOURCES; i++)
request_resource(&ioport_resource, &standard_io_resources[i]);
看一下它的参数standard_io_resources[i],是系统的固有I/O资源。只列出几个
static struct resource standard_io_resources[] = { {
.name = "dma1",
.start = 0x0000,
.end = 0x001f,
.flags = IORESOURCE_BUSY | IORESOURCE_IO
}, {
.name = "pic1",
.start = 0x0020,
.end = 0x0021,
.flags = IORESOURCE_BUSY | IORESOURCE_IO
}, {
.name = "timer0",
.start = 0x0040,
.end = 0x0043,
.flags = IORESOURCE_BUSY | IORESOURCE_IO
}
最重要的就是这个函数,我们先列出其源码:
int request_resource(struct resource *root, struct resource *new)
{
struct resource *conflict;
write_lock(&resource_lock);
conflict = __request_resource(root, new);
继续
/* Return the conflict entry if you can't request it */对资源的合理性加以判定,不能冲突。
static struct resource * __request_resource(struct resource *root, struct resource *new)
{
unsigned long start = new->start;
unsigned long end = new->end;
struct resource *tmp, **p;
if (end < start)
return root;
if (start < root->start)
return root;
if (end > root->end)
return root;
p = &root->child;
for (;;) {
tmp = *p;
if (!tmp || tmp->start > end) {
new->sibling = tmp;
*p = new;
new->parent = root;
return NULL;
}
p = &tmp->sibling;
if (tmp->end < start)
continue;
return tmp;
}
}
write_unlock(&resource_lock);
return conflict ? -EBUSY : 0;
}
.........
}
#ifdef CONFIG_VT
.......
#endif
}
}
setup_arch函数终于完了。