uclinux表示micro-control linux.即“微控制器領域中的Linux系統”,是Lineo公司的主打產品,同時也是開放源碼的嵌入式Linux的典范之作。uCLinux主要是針對目標處理器沒有存儲管理單元MMU(Memory Management Unit)的嵌入式系統而設計的。它已經被成功地移植到了很多平臺上。由于沒有MMU,其多任務的實現需要一定技巧。
uClinux啟動過程
uCinux的啟動主要經歷三個階段。首先,必須完成CPU和存儲器的硬件初始化,在系統RAM中建立程序堆棧和數據段,建立程序的運行時的環境。初始化完成之后,uClinux內核就取得了CPU的控制權,開始操作系統自身的初始化,這包括建立RAM中斷矢量表、加載設備驅動程序、內存管理模塊等等。這一切完成后,uClinux啟動一個最初的init線程,進入到第三階段,這時內核已經正常運行,外圍模塊也都就緒,開始執行一些腳本文件(如/etc/rc腳本文件)。
一.kernel代碼段之前的系統初始化
1. uClinux-dist/linux-2.4.x/arch/armnommu/boot/compressed/head.S
開發板從上電開始,最開始執行的程序放在uClinux-dist/linux-2.4.x/arch/armnommu/boot/compressed/head.S中。
(1) 切換模式,關閉中斷。 (line 96 )
(2) 首先程序要先給SYSCFG,EXTDBWTH,ROMCON0等一系列系統控制寄存器賦值,此時flash地址在 0X0,DRAM地址在0X1000000.(line 141 )
(3) 點亮I/O口的指示燈。 (line 152 )
(4) 把在flash上的image復制到DRAM上。(line 161 )
(5) 執行remap,把flash地址映射為0X1000000,DRAM地址映射為0.(line 172 )
(6) 打開cache和write buffer.(line 196 )
(7) 設置好64K堆棧。(line 204 )
(8) 跳轉到decompress_kernel函數(line 217 ),此處的跳轉為帶返回的跳轉,以便于執行完此函數跳轉回來。
2. uClinux-dist/linux-2.4.x/arch/armnommu/boot/compressed/misc.c
此時的函數decompress_kernel是用C語言寫的,line 297 。
(1) makecrc();進行crc校驗。
(2) puts(“Uncompressing Linux.。.”); 輸出linux起動后的第一句話。
(3) gunzip();解壓縮kernel.
(4) puts(“ done, booting the kernel./n”);
3. uClinux-dist/linux-2.4.x/arch/armnommu/boot/compressed/head.S
執行完decompress_kernel函數后,kernel又跳轉回head.S中,因為此時我們還要檢驗解壓縮之后的kernel起始地址是否緊接著kernel image,如果是,beq call_kernel(line 220),執行解壓后的kernel.
如果解壓縮之后的kernel起始地址不是緊接著kernel image,執行relocate(line 236),將其拷貝到緊接著kernel image的地方,然后跳轉,執行解壓后的kernel.
二.kernel執行
1.uClinux-dist/linux-2.4.x/init/main.c中的start_kernel() (line 352)
系統啟動過程到此,轉入體系結構無關的通用C代碼中,start_kernel() 中調用了一系列初始化函數,以完成kernel本身的設置。這些動作有的是公共的,有的則是需要配置的才會執行的。
(1) 輸出Linux版本信息(printk(linux_banner))
(2) 設置與體系結構相關的環境(setup_arch())
(3) parse_options(command_line);解析command_line,將其轉化為環境變量。
(4) 初始化系統IRQ(init_IRQ())
(5) 核心進程調度器初始化(sched_init())
(6) 軟中段初始化softirq_init();
(7) 時間、定時器初始化(包括估測主頻、初始化定時器中斷等,time_init())
(8) 控制臺初始化console_init();
(9) 核心CACHE初始化kmem_cache_init();
(10)延遲校準calibrate_delay();
(11)內存初始化(設置內存上下界和頁表項初始值,mem_init())
(12)文件,目錄,塊設備讀寫緩沖區初始化
(13)檢查體系結構漏洞(check_bugs())
(14)啟動init過程(創建第一個核心線程,調用init()函數,原執行序列調用cpu_idle() 等待調度,init())
至此start_kernel()結束,基本的核心環境已經建立起來了。
2.uClinux-dist/linux-2.4.x/init/main.c中的init() (line 548)
現在我們進入內核引導第二部分,init()函數作為核心線程,首先鎖定內核(僅對SMP機器有效,我們為空函數),然后調用 do_basic_setup() (line 551)完成外設及其驅動程序的加載初始化。
過程如下:
* 網絡初始化(初始化網絡數據結構,包括sk_init()、skb_init()和proto_init()三部分,在proto_init()中,將調用protocols結構中包含的所有協議的初始化過程,sock_init())
* 創建事件管理核心線程(start_context_thread()函數,這是系統創建的第二個內核線程,名叫“keventd”。其代碼context_thread()也在kernel/context.c中,)
啟動任何使用__initcall標識的函數(方便核心開發者添加啟動函數,此時由do_initcalls()函數啟動)。
此時系統開始加載外部設備的初始化程序,如:在linux-2.4.x/driver/block/genhd.c中的device_init()函數,在genhd.c中由__initcall(device_init)標識在此時調用,device_init()函數是所有外部設備初始化的總入口,包括了塊設備的初始化blk_dev_init,網絡設備的初始化net_dev_init()和atmdev_init()等。
至此do_basic_setup()函數返回init(),在釋放啟動內存段(free_initmem())并給內核解鎖以后,init()打開/dev/console設備,重定向stdin、stdout和stderr到控制臺,最后,搜索文件系統中的init程序(或者由init=命令行參數指定的程序),并使用 execve()系統調用加載執行init程序。(line 576) 。
init()函數到此結束,內核的引導部分也到此結束了,
3. uClinux-dist/linux-2.4.x/init/main.c中的execve(“/etc/init”,argv_init,envp_init); (line 579)
init進程是系統所有進程的起點,內核在完成核內引導以后,即在本線程(進程)空間內加載init程序,它的進程號是1。
init程序需要讀取/vendors/SAMSUNG/4510B/inittab文件作為其行為指針,然后執行。
4.系統執行rc腳本。
hostname Samsung
/bin/expand /etc/ramfs.img /dev/ram0
/bin/expand /etc/ramfs2048.img /dev/ram1
mount -t proc proc /proc
mount -t ext2 /dev/ram0 /var
mount -t ext2 /dev/ram1 /ramdisk
chmod 777 /ramdisk
mkdir /var/config
mkdir /var/tmp
mkdir /var/log
mkdir /var/run
mkdir /var/lock
ifconfig lo 127.0.0.1
route add -net 127.0.0.0 netmask 255.255.255.0 lo
dhcpcd &
cat /etc/motd
rc程序執行完畢后,系統環境已經設置好了,下面就該用戶登錄系統了。
5.運行Sash command shell
uclinux啟動的詳細過程有著諸多的信息可以給我們巨大的啟發,我們在這里討論的就是要對這些信息做一個具體細致的分析,通過我們的討論,大家會對uclinux啟動過程中出現的、以前感覺熟悉的、但卻又似是而非的東西有一個確切的了解,并且能了解到這些輸出信息的來龍去脈。
uclinux的啟動過程,它是一幅縮影圖,對它有了一個詳細的了解后,有助于指導我們更加深入地了解uclinux的核心。
大家對uclinux的啟動應該都比較熟悉,作為一名嵌入系統開發者,你一定遇到過下面的情景:在某論壇上看到一篇帖子,上面貼著uclinux開發板啟動時的一堆信息,然后大家在帖子里討論著這個啟動過程中出現的問題,隨機舉例如下:
Linux version 2.4.20-uc1 (root@Local) (gcc version 2.95.3
20010315 (release)(ColdFire patches - 20010318 from http://f
(uClinux XIP and shared lib patches from http://www.snapgear.com/)) #20 三 6月 1
8 00:58:31 CST 2003
Processor: Samsung S3C4510B revision 6
Architecture: SNDS100
On node 0 totalpages: 4096
zone(0): 0 pages.
zone(1): 4096 pages.
zone(2): 0 pages.
Kernel command line: root=/dev/rom0
Calibrating delay loop.。. 49.76 BogoMIPS
Memory: 16MB = 16MB total
Memory: 14348KB available (1615K code, 156K data, 40K init)
Dentry cache hash table entries: 2048 (order: 2, 16384 bytes)
Inode cache hash table entries: 1024 (order: 1,
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes)
Page-cache hash table entries: 4096 (order: 2, 16384 bytes)
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
Starting kswapd
Samsung S3C4510 Serial driver version 0.9 (2001-12-27) with no serial options en
abled
ttyS00 at 0x3ffd000 (irq = 5) is a S3C4510B
ttyS01 at 0x3ffe000 (irq = 7) is a S3C451
Blkmem copyright 1998,1999 D. Jeff Dionne
Blkmem copyright 1998 Kenneth Albanowski
Blkmem 1 disk images:
0: BE558-1A5D57 [VIRTUAL BE558-1A5D57] (RO)
RAMDISK driver initialized: 16 RAM disks of 1024K size 1024 blocksize
Samsung S3C4510 Ethernet driver version 0.1 (2002-02-20) 《mac@os.nctu.edu.tw》
eth0: 00:40:95:36:35:34
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 1024 bind 1024)
VFS: Mounted root (romfs
Freeing init memory: 40K
評論
查看更多