前置:這里使用的linux版本是4.8,x86體系。
local_irq_disable();
這個函數是做了關閉中斷操作。和后面的local_irq_enable相對應。說明啟動的下面函數是不允許被中斷搶占的。這個函數追下去會發現下面的代碼:
static inline void native_irq_disable(void)
{
asm volatile("cli": : :"memory");
}
這個寫法是linux的內聯匯編寫法。在C語言中寫匯編語言。實際上調用的是匯編cli命令。cli命令是禁用中斷功能。http://rock3.info/blog/2013/11/24/linux-c中調用匯編用法/
接着start_kernel,linux關閉完中斷之后,還使用了一個變量early_boot_irqs_disabled來標記已經關閉irq了。
這里稍微說說irq的概念,我們把中斷分為兩個概念,一個是上半部,一個是下半部,上半部指的是硬件直接要求立即響應的中斷。下半部指的是可以在某個特定時間之后執行的。這里的IRQ就是一個上半部概念。每個硬件設備都有一個irq線,通過這個線把中斷描述符傳遞給CPU,CPU獲取中斷之后立即執行對應已經注冊的操作。
boot_cpu_init()
這個函數功能是初始化第一個CPU。
void __init boot_cpu_init(void)
{
int cpu = smp_processor_id();
/* Mark the boot cpu "present", "online" etc for SMP and UP case */
set_cpu_online(cpu, true);
set_cpu_active(cpu, true);
set_cpu_present(cpu, true);
set_cpu_possible(cpu, true);
}
先獲取cpu的id,在smp下,獲取第一個處理器ip,非smp,第一個cpu的id為0。后面就是設置cpu的四個標志位。
page_address_init()
這個是頁地址初始化操作。
我們先要了解下段式管理和頁式管理。我們會有三個地址,邏輯地址,虛擬地址,物理地址。CPU要將一個邏輯地址轉換為物理地址,需要兩步:首先CPU利用段式內存管理單元,先將邏輯地址轉換為線性地址(虛擬地址)。再利用頁式管理單元,把虛擬地址,轉化為物理地址。
形象理解,段式管理就是一個大大的內存按照目的分為幾段,有的段比較大,有的段比較小。但是呢,每個段的最低地址位都是0,實際的地址位是段的偏移量。所以,這里就存在邏輯地址和虛擬地址的轉換了。為什么要進行分段管理呢?進行分段管理,能使得我們有可能對不同的內存段賦予不同的權限管理。
頁式管理是一段內存,按照指定大小划分,每4k為一頁。這里就有一個虛擬地址和物理地址的映射關系了。比如在一個三級的頁式管理中,一個虛擬地址32位按照10,10,12分為3段,前10位是頁目錄地址,后10位是頁表地址,最后12位是偏移量地址。這里其實有個奇怪的地方了。
為什么要進行頁式管理呢?不管是否有分頁管理,一個32位的地址,最多指向的也就是4G內存空間。頁式管理其實是為了更好地利用內存。比如假設內存是連續分配的,進程A獲取了1~100的內存空間,進程B獲取了100~104的內存空間,進程C獲取了104~200的內存空間。現在進程B釋放空間了,但是只有很小的4。這個時候,如果后續的進程要申請的空間都是大於4的,那么100~104這個內存空間段就永遠沒有辦法被分配。而使用頁式管理就有辦法避免這個問題。它可以讓程序使用的內存在邏輯上是連續的,在物理上是離散的。
回到linux中,由於僅有一部分體系支持段式管理,基於兼容的原因吧,linux並沒有支持段式管理。換句話說,linux把內存塊當作是一個段。所以實際上,在linux中,邏輯地址和虛擬地址是一樣的。但是linux把頁式管理是全盤接受了。
回到這個函數,page_address_init()
查找這個函數的定義,你可以看到根據宏不同有兩種定義,一種是
#if !defined(HASHED_PAGE_VIRTUAL) && !defined(WANT_PAGE_VIRTUAL)
#define page_address(page) lowmem_page_address(page)
#define set_page_address(page, address) do { } while(0)
#define page_address_init() do { } while(0)
#endif
一種是
void __init page_address_init(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(page_address_htable); i++) {
INIT_LIST_HEAD(&page_address_htable[i].lh);
spin_lock_init(&page_address_htable[i].lock);
}
}
#endif /* defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL) */
首先,這里分配的頁地址空間指的是內核的頁地址空間。linux把4G的虛擬地址空間分為3G用戶地址空間+1G內核地址空間。基本上是使用物理地址+3G的方式進行直接映射的。所以一般初始化內核地址空間的時候並不需要做任何操作。但是,當有些系統自身需要的內存大於896M的時候,就出現問題了。首先1G的內核空間,linux內核會把它分為896M的操作系統使用的空間,和128M的IO映射空間。當有些操作系統自身需要的內存大於896M,那么就難免有一些操作系統空間需要使用虛擬地址的形式,實際上是占用了原本用戶的系統空間,這一部分空間就叫做high memory。(那么想對,原本已經有的896M的空間叫做low memory)。這一部分的空間映射,是保存在128M的IO映射空間里面的。http://blog.sina.com.cn/s/blog_6488248f0100wu6v.html