當前位置:首頁 » 操作系統 » linux內核初始化

linux內核初始化

發布時間: 2022-04-02 04:33:24

linux系統開機時啟動內核步驟是什麼

實模式,並開始執行位於地址0xFFFF0處
的代碼,也就是ROM-BIOS起始位置的代碼。BIOS先進行一系列的系統自檢,然後初始化位
於地址0的中斷向量表。最後BIOS將啟動盤的第一個扇區裝入到0x7C00,並開始執行此處
的代碼。這就是對內核初始化過程的一個最簡單的描述。
最初,linux核心的最開始部分是用8086匯編語言編寫的。當開始運行時,核心將自
己裝入到絕對地址0x90000,再將其後的2k位元組裝入到地址0x90200處,最後將核心的其餘
部分裝入到0x10000。
當系統裝入時,會顯示Loading...信息。裝入完成後,控制轉向另一個實模式下的匯
編語言代碼boot/Setup.S。Setup部分首先設置一些系統的硬體設備,然後將核心從
0x10000處移至0x1000處。這時系統轉入保護模式,開始執行位於0x1000處的代碼。
接下來是內核的解壓縮。0x1000處的代碼來自於文件Boot/head.S,它用來初始化寄
存器和調用decompress_kernel( )程序。decompress_kernel( )程序由Boot/inflate.c,
Boot/unzip.c和Boot../misc.c組成。解壓縮後的數據被裝入到了0x100000處,這也是
linux不能在內存小於2M的環境下運行的主要原因。
解壓後的代碼在0x1010000處開始執行,緊接著所有的32位的設置都將完成: IDT、
GDT和LDT將被裝入,處理器初始化完畢,設置好內存頁面,最終調用start_kernel過程。
這大概是整個內核中最為復雜的部分。
[系統開始運行]
linux kernel 最早的C代碼從匯編標記startup_32開始執行
startup_32:
start_kernel
lock_kernel
trap_init
init_IRQ
sched_init
softirq_init
time_init
console_init
#ifdef CONFIG_MODULES
init_moles
#endif
kmem_cache_init
sti
calibrate_delay
mem_init
kmem_cache_sizes_init
pgtable_cache_init
fork_init
proc_caches_init
vfs_caches_init
buffer_init
page_cache_init
signals_init
#ifdef CONFIG_PROC_FS
proc_root_init
#endif
#if defined(CONFIG_SYSVIPC)
ipc_init
#endif
check_bugs
smp_init
rest_init
kernel_thread
unlock_kernel
cpu_idle
・startup_32 [arch/i386/kernel/head.S]
・start_kernel [init/main.c]
・lock_kernel [include/asm/smplock.h]
・trap_init [arch/i386/kernel/traps.c]
・init_IRQ [arch/i386/kernel/i8259.c]
・sched_init [kernel/sched.c]
・softirq_init [kernel/softirq.c]
・time_init [arch/i386/kernel/time.c]
・console_init [drivers/char/tty_io.c]
・init_moles [kernel/mole.c]
・kmem_cache_init [mm/slab.c]
・sti [include/asm/system.h]
・calibrate_delay [init/main.c]
・mem_init [arch/i386/mm/init.c]
・kmem_cache_sizes_init [mm/slab.c]
・pgtable_cache_init [arch/i386/mm/init.c]
・fork_init [kernel/fork.c]
・proc_caches_init
・vfs_caches_init [fs/dcache.c]
・buffer_init [fs/buffer.c]
・page_cache_init [mm/filemap.c]
・signals_init [kernel/signal.c]
・proc_root_init [fs/proc/root.c]
・ipc_init [ipc/util.c]
・check_bugs [include/asm/bugs.h]
・smp_init [init/main.c]
・rest_init
・kernel_thread [arch/i386/kernel/process.c]
・unlock_kernel [include/asm/smplock.h]
・cpu_idle [arch/i386/kernel/process.c]
start_kernel( )程序用於初始化系統內核的各個部分,包括:
*設置內存邊界,調用paging_init( )初始化內存頁面。
*初始化陷阱,中斷通道和調度。
*對命令行進行語法分析。
*初始化設備驅動程序和磁碟緩沖區。
*校對延遲循環。
最後的function'rest_init' 作了以下工作:
・開辟內核線程'init'
・調用unlock_kernel
・建立內核運行的cpu_idle環, 如果沒有調度,就一直死循環
實際上start_kernel永遠不能終止.它會無窮地循環執行cpu_idle.
最後,系統核心轉向move_to_user_mode( ),以便創建初始化進程(init)。此後,進程0開始進入無限循環。
初始化進程開始執行/etc/init、/bin/init 或/sbin /init中的一個之後,系統內核就不再對程序進行直接控制了。之後系統內核的作用主要是給進程提供系統調用,以及提供非同步中斷事件的處理。多任務機制已經建立起來,並開始處理多個用戶的登錄和fork( )創建的進程。
[init]
init是第一個進程,或者說內核線程
init
lock_kernel
do_basic_setup
mtrr_init
sysctl_init
pci_init
sock_init
start_context_thread
do_init_calls
(*call())-> kswapd_init
prepare_namespace
free_initmem
unlock_kernel
execve
[目錄]
--------------------------------------------------------------------------------
啟動步驟
系統引導:
涉及的文件
./arch/$ARCH/boot/bootsect.s
./arch/$ARCH/boot/setup.s
bootsect.S
這個程序是linux kernel的第一個程序,包括了linux自己的bootstrap程序,
但是在說明這個程序前,必須先說明一般IBM PC開機時的動作(此處的開機是指
"打開PC的電源"):
一般PC在電源一開時,是由內存中地址FFFF:0000開始執行(這個地址一定
在ROM BIOS中,ROM BIOS一般是在FEOOOh到FFFFFh中),而此處的內容則是一個
jump指令,jump到另一個位於ROM BIOS中的位置,開始執行一系列的動作,包
括了檢查RAM,keyboard,顯示器,軟硬磁碟等等,這些動作是由系統測試代碼
(system test code)來執行的,隨著製作BIOS廠商的不同而會有些許差異,但都
是大同小異,讀者可自行觀察自家機器開機時,螢幕上所顯示的檢查訊息。
緊接著系統測試碼之後,控制權會轉移給ROM中的啟動程序
(ROM bootstrap routine),這個程序會將磁碟上的第零軌第零扇區讀入
內存中(這就是一般所謂的boot sector,如果你曾接觸過電腦病
毒,就大概聽過它的大名),至於被讀到內存的哪裡呢? --絕對
位置07C0:0000(即07C00h處),這是IBM系列PC的特性。而位在linux開機
磁碟的boot sector上的正是linux的bootsect程序,也就是說,bootsect是
第一個被讀入內存中並執行的程序。現在,我們可以開始來
看看到底bootsect做了什麼。
第一步
首先,bootsect將它"自己"從被ROM BIOS載入的絕對地址0x7C00處搬到
0x90000處,然後利用一個jmpi(jump indirectly)的指令,跳到新位置的
jmpi的下一行去執行,
第二步
接著,將其他segment registers包括DS,ES,SS都指向0x9000這個位置,
與CS看齊。另外將SP及DX指向一任意位移地址( offset ),這個地址等一下
會用來存放磁碟參數表(disk para- meter table )
第三步
接著利用BIOS中斷服務int 13h的第0號功能,重置磁碟控制器,使得剛才
的設定發揮功能。
第四步
完成重置磁碟控制器之後,bootsect就從磁碟上讀入緊鄰著bootsect的setup
程序,也就是setup.S,此讀入動作是利用BIOS中斷服務int 13h的第2號功能。
setup的image將會讀入至程序所指定的內存絕對地址0x90200處,也就是在內存
中緊鄰著bootsect 所在的位置。待setup的image讀入內存後,利用BIOS中斷服
務int 13h的第8號功能讀取目前磁碟的參數。
第五步
再來,就要讀入真正linux的kernel了,也就是你可以在linux的根目錄下看
到的"vmlinuz" 。在讀入前,將會先呼叫BIOS中斷服務int 10h 的第3號功能,
讀取游標位置,之後再呼叫BIOS 中斷服務int 10h的第13h號功能,在螢幕上輸
出字串"Loading",這個字串在boot linux時都會首先被看到,相信大家應該覺
得很眼熟吧。
第六步
接下來做的事是檢查root device,之後就仿照一開始的方法,利用indirect
jump 跳至剛剛已讀入的setup部份
第七步
setup.S完成在實模式下版本檢查,並將硬碟,滑鼠,內存參數寫入到 INITSEG
中,並負責進入保護模式。
第八步
操作系統的初始化。

❷ 如何調整Linux內核啟動中的驅動初始化順序late

單獨定義一個優先順序,把afe相關的初始化都放到那裡面去,這樣,就可以保證,其他沒什麼相關的沖突了。最後證實,這樣是可以實現目的的。具體添加一個新的優先順序的步驟如下:1.定義新的優先順序include\linux\init.h中:#define pure_initcall(fn) __define_initcall("0",fn,1)#define core_initcall(fn) __define_initcall("1",fn,1)#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)#define postcore_initcall(fn) __define_initcall("2",fn,2)#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)#define arch_initcall(fn) __define_initcall("3",fn,3)#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)#define subsys_initcall(fn) __define_initcall("4",fn,4)#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)#define fs_initcall(fn) __define_initcall("5",fn,5)#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)#if 1#define prev_device_initcall(fn) __define_initcall("6",fn,6)#define prev_device_initcall_sync(fn) __define_initcall("6s",fn,6s)#define device_initcall(fn) __define_initcall("7",fn,7)#define device_initcall_sync(fn) __define_initcall("7s",fn,7s)#define late_initcall(fn) __define_initcall("8",fn,8)#define late_initcall_sync(fn) __define_initcall("8s",fn,8s)#else#define device_initcall(fn) __define_initcall("6",fn,6)#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)#define late_initcall(fn) __define_initcall("7",fn,7)#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)#endif復制代碼2.用對應新的宏,定義我們的驅動:prev_device_initcall(i2c_dev_init);prev_device_initcall(as352x_afe_i2c_init);prev_device_initcall(as352x_afe_init);

❸ linux 內核對象初始化是什麼意思

Linux內核對象管理 內核中很多地方都需要跟蹤記錄C語言中結構的實例。

❹ linux內核會初始化lcd嗎

不會,得自己移植的。
了解更多開源相關,去LUPA社區看看吧。

❺ linux2.6內核中cpu_init堆棧初始化疑惑

你去查查內聯匯編,"r"代表將輸入變數放入通用寄存器,也就是eax ,ebx,ecx,edx,esi,edi中的一個

❻ Linux 內核啟動

那麼linux內核和android什麼關系?linux內核是怎樣引導起android呢?本文進行簡單的描述。
android雖然建立在linux內核之上,但是他對內核進行了一些擴展,增加了一些驅動。比如binder,loger等等驅動。可以拿android內核代碼和其baseline版本進行對比。可以看到android對linux內核的所有擴展。
熟悉linux啟動的朋友知道,首先linux引導完成之後,會啟動用戶態的init進程(pid為0),這個進程在整個系統運行過程中起著非常重要的作用,如果你對init進程不了解請查相關資料。init完成系統的初始化工作,然後進入shell,接收用戶的輸入。
android啟動也沒有什麼神秘的,就是用自己的init進程替換了linux內核的init進程,完成自己初始化工作(設備,文件系統等等初始化)。然後啟動自己的虛擬機,程序等等的東西。android的init進程的代碼位於system/core/init/init.c下面,可以去查看其源碼,來了解android啟動詳細流程。android啟動流程的資料網上已經比較多,這里就不贅述了。
可以看到移植android過程中,調試init非常重要。因為所有和硬體平台相關的東西都這里初始化,所以init進程有可能需要移植或者配置。其他的進程都是和硬體無關的,理論上不需要修改就應該能夠運行起來。
經過上面的描述可以看出,android的init進程起著一個承上啟下的作用。

❼ Linux系統初始化設備的過程主要有哪些

1.自檢:依賴於CPU,ROM中的程序
2.載入BIOS,Boot Sequence確定啟動順序
3.MBR:
硬碟0磁軌0扇區的MBR文件,共512位元組
446:BootLoader
64:分區表,每16位元組一個分區
2:5A(一個特殊標記)
4.kernel文件vmlinuz+initrd:只能放在基本磁碟分區,BootLoader會把vmlinuz當做根來使用,即/vmlinuz
將vmlinuz載入到內存中使用。vmlinuz分為兩段,前半部分未壓縮段,是為了解壓第二段。
至此BootLoader任務完成,退場。
操作系統安裝時會執行一個命令,安裝程序完成後自動運行腳本,收集操作系統運行需要的腳本,將所需要的模塊打包成initrd,幫助內核完成初始化
initrd: ram disk,內核將之作為根來使用,將硬碟模擬成磁碟
5.initrd將所需文件復制到/下,內核完成初始化後進行根切換
6.啟動/sbin/init,由內核空間進入用戶空間
/lib/moles
/sbin/init:
/etc/inittab
id:3:initdefault:
/etc/rc.d/rc.sysinit腳本

❽ linux 內核啟動完如何到init

Linux內核為不同驅動的載入順序對應不同的優先順序,定義了一些宏:
include\linux\init.h

#define pure_initcall(fn) __define_initcall("0",fn,1)

#define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
#define arch_initcall(fn) __define_initcall("3",fn,3)
#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall("7",fn,7)
#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)

#define __initcall(fn) device_initcall(fn)

把自己的驅動的函數名用這些宏去定義之後,
就會對應不同的載入時候的優先順序。

其中,我們寫驅動中所用到的mole_init對應的是
#define mole_init(x) __initcall(x);

#define __initcall(fn) device_initcall(fn)
所以,驅動對應的載入的優先順序為6

在上面的不同的優先順序中,
數字越小,優先順序越高。
同一等級的優先順序的驅動,載入順序是鏈接過程決定的,結果是不確定的,我們無法去手動設置誰先誰後。
不同等級的驅動載入的順序是先優先順序高,後優先順序低,這是可以確定的。

所以,像我們之前在驅動中用:
mole_init(i2c_dev_init);
mole_init(as352x_afe_init);
mole_init(as352x_afe_i2c_init);

mole_init(enc28j60_init);

所以,大家都是同一個優先順序去初始化,
最後這些驅動載入的順序,可以查看在根目錄下,
生成的system.map:

。。。
c00197d8 t __initcall_alignment_init5
。。。。。
c00197f4 t __initcall_default_rootfsrootfs
c00197f8 t __initcall_timer_init_sysfs6
c00197fc t __initcall_clock_dev_init6
。。。
c00198d8 t __initcall_loop_init6
c00198dc t __initcall_net_olddevs_init6
c00198e0 t __initcall_loopback_init6
c00198e4 t __initcall_enc28j60_init6
。。。
c0019900 t __initcall_as352x_spi_init6
c0019904 t __initcall_spidev_init6
。。。
c0019920 t __initcall_i2c_dev_init6
c0019924 t __initcall_as352x_afe_i2c_init6
c0019928 t __initcall_as352x_afe_init6
。。。
c0019970 t __initcall_random32_reseed7
c0019974 t __initcall_seqgen_init7
c0019978 t __initcall_rtc_hctosys7
c001997c T __con_initcall_start
c001997c t __initcall_con_init
c001997c T __initcall_end
。。。

此處就是由於
c0019920 t __initcall_i2c_dev_init6
c0019924 t __initcall_as352x_afe_i2c_init6
c0019928 t __initcall_as352x_afe_init6

c00198e4 t __initcall_enc28j60_init6
之前,所以我這里才要去改。。。

知道原理,能想到的,就是
要麼把
as352x_afe_init
改到
enc28j60_init
之前一級,即優先順序為5。
即在驅動中,調用:
fs_initcall(as352x_afe_init);

要麼把
enc28j60_init
改到
as352x_afe_init
之後,即優先順序為7
即在驅動中,調用:
late_initcall(enc28j60_init);

但是,此處麻煩就麻煩在,
如果把
as352x_afe_init
改到
enc28j60_init
之前一級,
發現後面網卡初始化enc28j60_init中,雖然讀取晶元ID對了,
但是後面的IP-auto configure 有問題。
所以放棄。

如果把
enc28j60_init
改到
as352x_afe_init
之後,
但是,從system.map中看到的是,優先順序為7的驅動中,明顯有幾個驅動,
也是和網卡初始化相關的,所以,這樣改,嘗試後,還是失敗了。

所以,沒法簡單的通過調整現有的驅動的順序,去實現順序的調整。

最後,被逼無奈,想到了一個可以實現我們需求的辦法,
那就是,單獨定義一個優先順序,把afe相關的初始化都放到那裡面去,
這樣,就可以保證,其他沒什麼相關的沖突了。
最後證實,這樣是可以實現目的的。

具體添加一個新的優先順序的步驟如下:

1.定義新的優先順序

include\linux\init.h中:

#define pure_initcall(fn) __define_initcall("0",fn,1)

#define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
#define arch_initcall(fn) __define_initcall("3",fn,3)
#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#if 1
#define prev_device_initcall(fn) __define_initcall("6",fn,6)
#define prev_device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define device_initcall(fn) __define_initcall("7",fn,7)
#define device_initcall_sync(fn) __define_initcall("7s",fn,7s)
#define late_initcall(fn) __define_initcall("8",fn,8)
#define late_initcall_sync(fn) __define_initcall("8s",fn,8s)

#else
#define device_initcall(fn) __define_initcall("6",fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall("7",fn,7)
#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
#endif

2.用對應新的宏,定義我們的驅動:
prev_device_initcall(i2c_dev_init);
prev_device_initcall(as352x_afe_i2c_init);
prev_device_initcall(as352x_afe_init);

做到這里,本以為可以了,但是編譯後,在system.map中,發現之前優先順序為7的那幾個函數,
被放到system.map最後了,而不是預想的,
在優先順序7之後,在
c001997c T __con_initcall_start
c001997c t __initcall_con_init
c001997c T __initcall_end
之前。

最後,發現時沒有把對應的鏈接文件中的宏加進去:

3.

include\asm-generic\vmlinux.lds.h

#if 1
#define INITCALLS \
*(.initcall0.init) \
*(.initcall0s.init) \
*(.initcall1.init) \
*(.initcall1s.init) \
*(.initcall2.init) \
*(.initcall2s.init) \
*(.initcall3.init) \
*(.initcall3s.init) \
*(.initcall4.init) \
*(.initcall4s.init) \
*(.initcall5.init) \
*(.initcall5s.init) \
*(.initcallrootfs.init) \
*(.initcall6.init) \
*(.initcall6s.init) \
*(.initcall7.init) \
*(.initcall7s.init) \
*(.initcall8.init) \
*(.initcall8s.init)

#else

#define INITCALLS \
*(.initcall0.init) \
*(.initcall0s.init) \
*(.initcall1.init) \
*(.initcall1s.init) \
*(.initcall2.init) \
*(.initcall2s.init) \
*(.initcall3.init) \
*(.initcall3s.init) \
*(.initcall4.init) \
*(.initcall4s.init) \
*(.initcall5.init) \
*(.initcall5s.init) \
*(.initcallrootfs.init) \
*(.initcall6.init) \
*(.initcall6s.init) \
*(.initcall7.init) \
*(.initcall7s.init)

#endif
最後,再重新編譯,就可以實現我們要的,
和afe相關的驅動初始化,都在網卡enc28j60_init之前了。
也就可以在網卡裡面讀晶元ID了。
當然,對應編譯生成的system.map文件中,
對應的通過mole_init定義的驅動,優先順序也都變成7了。
而late_initcall對應優先順序8了。

註:當前開發板arm的板子,所以,對應的load 腳本在:

linux-2.6.28.4\arch\arm\kernel\vmlinux.lds

看起來,應該是這個文件:

linux-2.6.28.4\arch\arm\kernel\vmlinux.lds.S

生成上面那個腳本的。

vmlinux.lds中的這一行:

__initcall_start = .;
*(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)
就是將之前那些對應的init類型的函數,展開,放到這對應的位置。

❾ 嵌入式linux內核啟動時gpio初始化在什麼位置

gpio初始化是你自己要完成的工作,內核不會幫你完成,你可以在初始化函數中添加功能

❿ 如何調整Linux內核啟動中的驅動初始化順序

最簡單想到的,是內核裡面的
arch/arm/mach-as352x/core.c
中,去改devices設備列表中的順序。
enc28j60_init對應的是ssp_device,因為網卡初始化用到的是SPI驅動去進行和通訊的。
as352x_afe_init對應的是afe_device。

熱點內容
電腦主機買什麼配置內存大 發布:2024-09-27 15:04:06 瀏覽:266
華為技術有限公司c語言 發布:2024-09-27 14:50:42 瀏覽:919
雪種壓縮機 發布:2024-09-27 14:50:38 瀏覽:323
怎樣調用c編譯器 發布:2024-09-27 14:19:38 瀏覽:265
導頁源碼模板 發布:2024-09-27 14:03:34 瀏覽:268
配置文件的元素有哪些 發布:2024-09-27 14:02:47 瀏覽:264
qq等級的密碼是什麼 發布:2024-09-27 13:54:05 瀏覽:143
怎麼復制安卓應用雙開 發布:2024-09-27 13:53:53 瀏覽:573
電腦運行什麼查看配置 發布:2024-09-27 13:53:53 瀏覽:637
excel導入資料庫oracle 發布:2024-09-27 13:53:51 瀏覽:503