亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

lguest 三步曲之三 (源碼分析)

系統(tǒng) 1539 0

lguest上的guest os啟動的過程


根據(jù)linux啟動流程的分析,在執(zhí)行到j(luò)mp *0xc0100000時,系統(tǒng)將會根據(jù)是壓縮內(nèi)核還是未壓縮的內(nèi)核來決定跳轉(zhuǎn)的方向:
(1)如果是未壓縮的內(nèi)核,就直接跳到/kernel/head_32.S的入口開始執(zhí)行
(2)如果是壓縮的內(nèi)核,就要先解壓,整個解壓的過程在/boot/compressed/head_32.S中,解壓完成后跳到解壓內(nèi)核的起始地址開始執(zhí)行其實解壓后的起始地址,也是/kernel/head_32.S的入口。

因此不管是壓縮的內(nèi)核還是未壓縮的內(nèi)核,都會執(zhí)行/kernel/head_32.S中的代碼。這是可以確定0xc0100000處的第一條代碼就是startup_32.
現(xiàn)在我們就從/kernel/head_32.S開始分析。
(1)重新加載boot_gdt_desc和段寄存器的值
(2)清空bss段
(3)把實模式下的boot_params,拷貝到保護模式下的boot_params結(jié)構(gòu)體中
(4)movl pa(boot_params) + NEW_CL_POINTER,%esi // %esi指向了 setup_header.cmd_line_ptr
判斷一下命令行參數(shù)指針是否為空,如果不為空,就要把命令行的參數(shù)拷貝過來,拷貝到boot_command_line數(shù)組中。
下面就開始判斷,如果定義了CONFIG_PARAVIRT的話,即支持虛擬化對的話,就要選擇到底執(zhí)行哪條內(nèi)核路徑,這里有三條路徑:
1 default_entry:這是默認的系統(tǒng)啟動路徑
2 bad_subarch: 當前內(nèi)核不支持的啟動路徑
3當前內(nèi)核支持的兩種虛擬化啟動路徑:lguest_entry 和 xen_entry

相當于定義了一個內(nèi)核路徑數(shù)組,數(shù)組名是subarch_entries,元素個數(shù)是num_subarch_entries,然后在尋址的時候是這樣的:

eax = 0 + eax*4 + pa(subarch_entries)。因為我們分析的是lguest , 因此這里的跳到lguest_entry。

有個很重要的數(shù)據(jù)結(jié)構(gòu),在這里必須要介紹一下: boot_params 結(jié)構(gòu)體,它就是傳說中的"zero page".


這個數(shù)據(jù)結(jié)構(gòu)幾乎保存了啟動過程中所需要的所有的信息,比如屏幕顯示信息,hdr,e820返回的內(nèi)存信息等等,在后面的啟動程序中,很多地方都用到了這個數(shù)據(jù)結(jié)構(gòu)中的參數(shù),

很明顯這是個循環(huán)復制的一組指令,目的地址就是boot_params, 那么源地址是哪里呢?其實,當跳到startup_32時,%esi還是執(zhí)行實模式下的數(shù)據(jù)boot_params。應該豁然開朗了,

實模式下的數(shù)據(jù)在保護模式下是不可用的,因此要拷貝過來。為了驗證esi到底是不是指向boot_params,看下面的代碼:

但是,boot_params到底是什么時候被初始化的呢?這也是我們比較關(guān)心的一個問題。

大部分的初始化的代碼包含在arch/x86/boot/Main.c中
(1)copy_boot_params(); 初始化的boot_params.hdr
(2)detect_memory(void);
初始化了boot_params.e820_map 和boot_params.e820_entries
(3)query_apm_bios(); 初始化了apm_bios_info
(4)query_apm_bios(); 初始化了screen_info

到此,boot_params這個數(shù)據(jù)結(jié)構(gòu)介紹完了,后面很多代碼都會從這個結(jié)構(gòu)體里面取數(shù)據(jù)。繼續(xù)分析lguest執(zhí)行流程lguest_entry.

在arch/x86/lguest/i386_head.S中找到了ENTRY(lguest_entry)

我們把這段代碼總整體上來看,就是實現(xiàn)了這么一個操作,%eax = $LHCALL_LGUEST_INIT %ebx=lguest_data 數(shù)據(jù)結(jié)構(gòu)的物理地址
后面又創(chuàng)建了一個堆棧,然后又調(diào)用了一個c函數(shù)lguest_init .把以上的信息串聯(lián)起來,豈不就相當于在匯編里調(diào)用c函數(shù)的整個準備過程,

先設(shè)置好參數(shù)(%eax,%ebx),然后設(shè)置好堆棧。

LHCALL_LGUEST_INIT是 lguest實現(xiàn)的hypercall 調(diào)用號,就想我們熟悉的linux的其他的系統(tǒng)調(diào)用,只不過是lguest的系統(tǒng)調(diào)用而已。在調(diào)用

系統(tǒng)調(diào)用前,要把系統(tǒng)調(diào)用號保存在eax中,把參數(shù)保存在ebx等其他的幾個寄存器中。然后.byte 0×0f ,0×01,0xc1就是執(zhí)行系統(tǒng)調(diào)用,相當于

int $0×80,這么做的目的無非就是通知host os,當前運行的是一個guest os.

這里也涉及到一個非常重要的數(shù)據(jù)結(jié)構(gòu)lguest_data, 分析下這個結(jié)構(gòu)體。

這個數(shù)據(jù)結(jié)構(gòu)實現(xiàn)了Host和Guest之間進行交流的一種方法
/*G:032 The second method of communicating with the Host is to via "struct
* lguest_data". Once the Guest's initialization hypercall tells the Host where
* this is, the Guest and Host both publish information in it. :*/
詳細分析一下每一個數(shù)據(jù)成員的含義:
(1)irq_enabled
/* 512 == enabled (same as eflags in normal hardware). The Guest
* changes interrupts so often that a hypercall is too slow. */
相當于Host里面的eflags, 512=2^9,即第10位置1,就表示開中斷。這么做的原因是:如果通過hypercall 來實現(xiàn)中斷的使能的話,太慢了!

(2)DECLARE_BITMAP(blocked_interrupts, LGUEST_IRQS);

定義了一個bitmap,用來做中斷屏蔽的???
(3)CR2 :Guest缺頁中斷時會在CR2中保存一個hypercall,Host在這里寫上一次page fault的虛擬地址
(4)time : Host設(shè)置的時間
(5)hcall_status[LHCALL_RING_SIZE] LHCALL_RING_SIZE=64
/* Async hypercall ring. Instead of directly making hypercalls, we can
* place them in here for processing the next time the Host wants.
* This batching can be quite efficient. */
/* 0xFF == done (set by Host), 0 == pending (set by Guest). */
并不是每產(chǎn)生一個hypercall,Host就對它進行處理,可以先讓這些hypercall 排隊,主機在某一個時間來對他們進行處理。0xFF表示Host處理完了所有的pending的hypercall, 0表示有Guest的hypercall在pending.
(6)reserve_mem: 指明給switcher保留的空間的大小(主機初始化)
(7)設(shè)置TSC的 頻率(Host初始化)
(以下變量guest 在初始化時設(shè)置)
(8)noirq_start,noirq_end: 不允許中斷的一段指令的范圍,即使此時是開中斷的;
(9)kernel_address = PAGE_OFFSET
(10)syscall_vec: 系統(tǒng)調(diào)用號0×80

下面我們就跳到arch/x86/lguest/boot.c 中的lguest_init()函數(shù)來執(zhí)行。
這個函數(shù)主要是對內(nèi)核的一些敏感操作進行的封裝或這說是替換,主要有一下幾個方面的封裝:
(1)中斷相關(guān)的操作
(2)cpu指令的封裝
(3)頁表管理
(4)apic的讀寫操作
(5)時間相關(guān)操作
對以上部分封裝之后,接著又執(zhí)行了下面一系列的操作:
(1)reserve_top_address(lguest_data.reserve_mem);
為Host<->Guest Switcher 保留一段內(nèi)存空間,這段內(nèi)存空間的大小由lguest_data.reserve_mem 指定。
(2)lockdep_init()
這個函數(shù)分別申請4096個classhash_table和8192個chainhash_table.這兩個hashtable到底是用來he干什么的,現(xiàn)在還不清楚?
(3)para_virt_disable_iospace()
禁止所有的非虛擬驅(qū)動程序去掃描它所支持的硬件設(shè)備,減少啟動時間
(4)cpu_detect(&new_cpu_data)
(5)add_preferred_console(“hvc”,0,NULL);
注冊hvc這個虛擬終端的驅(qū)動
(6)virtio_cons_early_init(early_put_chars);
(7)pm_power_off = lguest_power_off
machine_ops.restart=lguest_restart
(9)i386_start_kernel

lguest 三步曲之三 (源碼分析)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久久精品亚洲乱码伦伦中文 | 欧美日韩国产另类一区二区三区 | 国产成+人+亚洲+欧美综合 | 欧美综合精品一区二区三区 | 久青草国产在视频在线观看 | 国产一级毛片视频在线! | 日韩 欧美 亚洲国产 | 中文字幕日韩精品在线 | 亚洲精品天堂自在久久77 | 亚洲成人毛片 | 久久99亚洲综合精品首页 | 中文字幕视频一区二区 | 四虎影院在线播放 | 亚洲色中文字幕在线播放 | 国产免费久久精品久久久 | 久久精品国产一区二区三区不卡 | 久久一区精品 | 国产在线视频www色 国产在线视频凹凸分类 | 一区一区三区产品乱码 | 欧美一区二区在线观看免费网站 | 日日夜夜精品 | 99久久99热久久精品免费看 | 老妇色 | 亚洲欧美日韩在线一区 | 成人高清视频在线观看大全 | 免费国产一区二区三区 | 久久久久综合中文字幕 | 久久久久在线 | 亚洲综合成人网 | 亚洲在线视频免费 | 精品无人区乱码一区二区 | 国产成人性毛片aaww | 国产精品一 | 日韩精品一区二区在线观看 | 天天透天天狠 | 国产精品久久久久久久 | 九九热欧美 | 手机看片欧美日韩 | 5060网午夜一级毛片在线看 | 四虎在线永久免费观看 | 日韩成人免费aa在线看 |