linux啟動流程 二

2021-09-28 10:42:18 字數 4788 閱讀 7944

想要了解核心的啟動過程,就需要檢視linux原始碼了(此文是基於linux 5.2)。檢視原始碼的過程中我們發現,核心的啟動是start_kernel()函式,它是位於init包下main.c檔案中的方法。

我們在此方法裡發現很多***_init的方法,也就是做一些初始化操作。

asmlinkage __visible void __init start_kernel

(void

)

初始化第乙個程序

我們知道linux系統中的所有程序都是通過父程序fork來的,那麼核心啟動時需要乙個祖先程序,這個程序我們稱之為0號程序,它是由set_task_stack_end_magic方法設定而來,set_task_stack_end_magic方法位於fock.c檔案中。

void

set_task_stack_end_magic

(struct task_struct *tsk)

引數init_task是乙個結構體,其定義在init_task.c檔案中,做一些結構體的填充。

struct task_struct init_task

#ifdef config_arch_task_struct_on_stack

__init_task_data

#endif

=

smp_processor_id是乙個巨集,在smp的情況下獲取cpu_id ,如果不是smp,那麼返回0。

vfs_caches_init()位於fs/dcache.c檔案中,用來初始化基於記憶體的檔案系統rootfs。

void __init vfs_caches_init

(void

)

vfs_caches_init()內 會呼叫mnt_init()方法, mnt方法位於namespace.c中

void __init mnt_init

(void

)

mnt_init() 呼叫了 init_rootfs() 方法,此方法中會在vfs中註冊一種 struct file_system_type rootfs_fs_type 的型別。vfs (virtual file system) 存放著核心對外提供的介面。

此時0號程序初始化完成了

初始化第二個程序

start_kernel() 方法中的注釋我們發現,有乙個名叫 arch_call_rest_init() 的方法來做其餘初始化的事,實際呼叫的是rest_init()方法

noinline void __ref rest_init

(void

)

發現第12行pid = kernel_thread(kernel_init, null, clone_fs);此時會建立乙個程序,我們稱之為1號程序,此程序裡執行的是使用者程序 即所有使用者態程序的祖先程序,當此程序進入使用者態後,會開枝散葉 建立出很多子程序,形成一棵程序樹。

從核心態到使用者態

kernel_thread() 會呼叫 kernel_init 引數

static

int __ref kernel_init

(void

*unused)..

.if(!

try_to_run_init_process

("/sbin/init")||

!try_to_run_init_process

("/etc/init")||

!try_to_run_init_process

("/bin/init")||

!try_to_run_init_process

("/bin/sh"))

return0;

...}

///執行ramdisk

static noinline void __init kernel_init_freeable

(void

)///執行系統呼叫

static

intrun_init_process

(const

char

*init_filename)

從以上**可以看出,1號程序執行的是乙個檔案。run_init_process() 中執行了 do_execve() 。 此方法會嘗試執行remdisk的』 /init '或普通檔案系統上的"sbin/init"、"/etc/init"、 「/bin/init」、"/bin/sh"。不同版本的linux會選擇不同的檔案啟動,但是只要有乙個起來了就可以了。

那麼具體的執行流程是什麼?

//呼叫do_execve方法

intdo_execve

(struct filename *filename,

const

char __user *

const __user *__ar**,

const

char __user *

const __user *__envp)

;struct user_arg_ptr envp =

;return

do_execveat_common

(at_fdcwd, filename, ar**, envp,0)

;}//呼叫do_execveat_common

static

intdo_execveat_common

(int fd,

struct filename *filename,

struct user_arg_ptr ar**,

struct user_arg_ptr envp,

int flags)

//__do_execve_file 方法中 我們會發現執行了乙個二進位制檔案exec_binprm()

static

int__do_execve_file

(int fd,

struct filename *filename,

struct user_arg_ptr ar**,

struct user_arg_ptr envp,

int flags,

struct file *file)

//呼叫exec_binprm,此時又呼叫了search_binary_handler方法

static

intexec_binprm

(struct linux_binprm *bprm)

return ret;

}//檢視search_binary_handler,我們會發現有乙個名為linux_binfmt的結構體

intsearch_binary_handler

(struct linux_binprm *bprm)

return retval;

}//結構體linux_binfmt,定義了二進位制檔案

struct linux_binfmt __randomize_layout;

static

struct linux_binfmt elf_format =

;//load_elf_binary 載入elf檔案

static

intload_elf_binary

(struct linux_binprm *bprm)

//開啟位於/arch/x86/kernel/process_32.c檔案

void

start_thread

(struct pt_regs *regs,

unsigned

long new_ip,

unsigned

long new_sp)

export_symbol_gpl

(start_thread)

;

tip:

elf(executable and linkable format,可執行與可鏈結格式)是linux中的常用格式

最後我們會發現 start_thread把所有暫存器狀態都設定成了_user_xx, 也就是將**段cs設定成了_user_cs 將資料段的ds設定成了__user_ds, 指令指標暫存器ip和棧指標暫存器sp都做了重置,即此函式的作用 是儲存暫存器

force_iret是從系統呼叫中返回,即下一條指令是從使用者態開始執行了。

進入到使用者態之後 就需要執行 remdisk 上的/init 載入儲存裝置的驅動,有了驅動就可以設定真正的根檔案系統了。接下來remdisk 上的/init 會啟動檔案系統上的init

初始化2號程序

當系統進入使用者態之後,就也就是有了所有程序的祖程序,接下來就需要乙個核心態的程序來統一管理核心態了 這個程序我們稱之為2號程序

在main.c 檔案中

noinline void __ref rest_init

(void

)

上述**中,我們知道kernel_thread()是用來建立程序的,那麼引數kthreadd 就是用來建立2號程序的了。

kthreadd負責所有核心態的執行緒的排程和管理,是核心態所有執行緒執行的祖先。

ok,啟動流程大體上就是這樣了。

linux啟動流程

linux系統主要通過以下步驟啟動 讀取mbr的資訊,啟動boot manager windows使用ntldr作為boot manager,如果您的系統中安裝多個版本的windows,您就需要在ntldr中選擇您要進入的系統。linux通常使用功能強大,配置靈活的grub作為boot manage...

linux啟動流程

bios basic input output system mbr main boot record kernel kernel自解壓 核心初始化 核心啟動 start kernel 自身為0 程序,建立1 程序執行,直接執行在物理記憶體空間上,沒有虛位址。1 程序裝入並執行程式 sbin ini...

Linux啟動流程

下面簡單介紹下啟動,詳細的後續再補。1.載入bios的硬體資訊並進行自我測試,並依據設定取得第乙個可以啟動的裝置 2.讀取並執行第乙個裝置內的mbr master boot record,硬碟的主引導記錄 的boot loader 即是grub,spfdisk等程式 3.依據boot loader的...