linux 编程 wordpress mysql centos Python php 微软 apache 程序员 Firefox Windows google 开源 Ubuntu 云计算 java Android shell nginx

《嵌入式Linux基礎教程(第2版)》——2.2 剖析嵌入式系統

2.2 剖析嵌入式系統

圖2-1是一個典型嵌入式系統的框圖。這個例子很簡單,描述了一個系統的高層硬件架構,無線接入點設備可能就是采用這種硬件構架。這個系統架構以一個32位的RISC處理器為中心,系統中的閃存用於存儲非易失性程序和數據,主存儲器是SDRAM(同步動態隨機存儲器),其容量可以從幾兆至幾百兆字節,視應用而定。一個通常由電池供電的實時時鐘模塊記錄著當前時間(包括日期)。這個例子裏面包含以太網和USB接口,也包含串行端口,利用串行端口可基於RS-232標準訪問控制臺。802.11芯片組或模塊實現了無線調制解調器的功能。

screenshot

通常,嵌入式系統的處理器完成很多功能,不僅僅是處理傳統的核心指令流。圖2-1中的假想處理器包含集成的串行接口UART、集成的USB和以太網控制器。很多處理器都包含集成在處理器中的外設,有時這些處理器被稱為片上系統(SOC,System On Chip)。第3章會考察幾個集成處理器的例子。

2.2.1 典型的嵌入式Linux開發環境
嵌入式Linux開發新手經常提出的一個問題,就是開發之前需要準備些什麽。為了回答這個問題,圖2-2展示了一個典型的嵌入式Linux開發環境。

圖中展示了一個主機開發系統,其中運行你最喜歡的桌面Linux發行版,比如Red Hat、SUSE或Ubuntu Linux。嵌入式Linux目標板通過一根RS-232串行端口線與開發主機相連。目標板的以太網接口插接到本地以太網集線器或交換機上,開發主機也通過以太網連接到上面。開發主機包含開發工具和程序以及目標文件,通常這些都可從一個嵌入式Linux發行版中獲得。

screenshot

在這個例子中,主機和嵌入式Linux目標板主要通過一個遵循RS-232標準的串行端口連接。主機上運行的串行端口終端程序用於和目標板通信。minicom是最常用的串行端口通信應用程序之一,幾乎所有的桌面Linux發行版中都有這個應用程序[2]。本書使用screen作為串行端口通信程序,這個程序可以取代minicom的功能,而且更靈活,特別是在trace捕捉方面。對於系統啟動或解決故障時串行端口線上的垃圾信息,screen也更加寬容。為了在USB轉串行端口線上使用screen,可以在主機終端調用它並指定速率:

screenshot

2.2.2 啟動目標板
第一次加電時,目標板上的引導加載程序立即獲得處理器的控制權。該程序執行一些非常底層的硬件初始化,包括處理器和內存的設置,初始化UART用於控制串行端口,以及初始化以太網控制器。代碼清單2-1顯示了目標板加電後從串行端口接收到的字符。在這個例子中,我們選擇了飛思卡爾半導體公司的目標板PowerQUICC III MPC8548 可配置開發系統(Configurable Development System,CDS)。這個開發系統包含了PowerQUICC III MPC8548處理器。這個目標板從飛思卡爾出廠時就預裝了U-Boot引導加載程序。

代碼清單2-1引導加載程序從串行端口輸出的初始信息

screenshot

當MPC8548CDS目標板加電時,U-Boot執行一些底層的硬件初始化,包括配置串行端口,然後打印標題行,見代碼清單2-1中顯示的第一行。接著顯示了CPU和核心(Core)的型號及版本,接下來是描述時鐘配置和緩存配置的數據,再後面是一串文字描述了這個目標板。

初始的硬件配置完成後,U-Boot根據其靜態設置來配置其他硬件子系統。這裏,我們看到U-Boot配置了I2C、DRAM、閃存(FLASH)、2級緩存(L2 cache)、PCI和網絡子系統。最後U-Boot等待來自串行端口控制臺的輸入,顯示為命令行提示符“=>”。

2.2.3 引導內核
現在U-Boot已經初始化了硬件、串行端口和以太網接口,在其短暫但有益的生命中還剩一件工作:加載並引導Linux內核。所有的引導加載程序都提供了命令用於加載和執行操作系統鏡像。代碼清單2-2顯示了使用U-Boot手動加載並引導Linux內核的一種常用方法。

代碼清單2-2 加載Linux內核

screenshot

代碼清單2-2開頭的tftp命令指示U-Boot使用TFTP[3]協議將內核鏡像uImage通過網絡加載到內存。在這個例子中,內核鏡像存放於開發工作站(通常,這個開發工作站就是通過串行端口與目標板相連的那臺主機)。執行tftp命令時,需要傳入一個地址參數,這個地址用於指定內核鏡像將要被加載到的目標板內存的物理地址。讀者現在不用擔心這些細節,第7章將會詳細介紹U-Boot。

第2次執行tftp命令加載了一個目標板配置文件,稱為設備樹(device tree),這個文件還有其他的名字,包括扁平設備樹(flat device tree)和設備樹二進制文件(device tree binary)或dtb。你將在第7章了解到這個文件的更多信息。現在,你只要知道這個文件與具體目標板相關,包含了內核所需的用於引導目標板的信息就足夠了。這些信息包括內存大小、時鐘速率、板載設備、總線和閃存布局。

接著,執行bootm(從內存鏡像引導)命令來讓U-Boot引導剛才加載至內存的內核,起始地址就是在tftp命令中指定的地址。在這個使用bootm命令的例子中,我們讓U-Boot加載放在地址0x600000處的內核,並將加載到地址0xc00000處的設備樹二進制文件(dtb)傳給內核。bootm命令會將控制權移交給Linux內核。假設內核配置正確,這個命令的結果是引導Linux內核直至在目標板上出現控制臺命令行提示符,如同登錄提示符所示。

註意bootm命令為U-Boot敲響了喪鐘。這是一個重要的概念。與桌面PC的BIOS不同,大多數的嵌入式系統都采用這樣一種架構:當Linux內核掌握控制權時,引導加載程序就不復存在了。Linux內核會要求收回那些之前被引導加載程序所占用的內存和系統資源。將控制權交回給引導加載程序的唯一方法就是重啟目標板。

最後還需要註意一點。在代碼清單2-2的串行端口輸出中,下面這行之前的信息(包含這一行)都是由U-Boot引導加載程序產生的:

其余引導信息是由Linux內核產生的。對於這一點,我們在後續章節還要詳細說明,但我們需要註意U-Boot是在哪兒離開的以及Linux內核是在哪兒取得控制權的。

2.2.4 內核初始化:概述
當Linux內核開始執行時,它會在其相當復雜的引導過程中輸出大量狀態消息。在當前討論的這個例子中,在顯示登錄提示符之前,Linux內核大約顯示了200行printk[4]打印信息(代碼清單中省略了這些打印行以便討論的重點更加清晰)。代碼清單2-3再現了登錄提示符之前的最後幾行輸出。這個練習的目的不是要深入到內核初始化的細節中去(第5章會講述這方面的內容),而是要對正在發生的事情,以及對嵌入式系統中引導Linux內核需要哪些組件有一個概覽。

代碼清單2-3Linux內核加載的最後幾行引導消息

screenshot

Linux在串行端口終端上顯示登錄提示符之前,會掛載一個根文件系統。在代碼清單2-3中,Linux通過一系列必要步驟,從一個NFS[5] 服務器來遠程(通過以太網)掛載其根文件系統,這個NFS服務器程序運行於ip地址為192.168.0.9的主機之上。通常這個主機就是你的開發工作站。根文件系統包含構成整個Linux系統的應用程序、系統庫和工具軟件。

重申一下這裏討論的重點:Linux必須有一個文件系統。很多老式的嵌入式操作系統不需要文件系統,因此那些從老式嵌入式操作系統遷移到嵌入式Linux系統的工程師往往會感到驚訝。一個文件系統由一組預定義的系統目錄和文件組成,這些目錄和文件按照特定的布局存儲在硬盤或其他存儲介質上,而Linux內核可以掛載這些介質作為其根文件系統。

註意Linux也可以從其他設備掛載根文件系統。最常見的情況當然是掛載一個硬盤分區作為根文件系統,就像筆記本或工作站中的Linux系統所做的那樣。實際上,當你將嵌入式Linux小玩意帶出房門或遠離開發環境時,NFS就沒什麽用處了。然而,在讀這本書的過程中,你會逐漸體會到在開發環境中掛載NFS根文件系統帶來的威力和靈活性。

2.2.5 第一個用戶空間進程:init
繼續探討其他內容之前,還有一個重點需要強調一下。請註意代碼清單2-3中的這一行:

screenshot

直到這時,內核都是自己在執行代碼,它在一個稱為內核上下文(kernel context)的環境中完成大量的初始化工作。在這個運行狀態下,內核擁有所有的系統內存並且全權控制所有的系統資源。內核能夠訪問所有的物理內存和所有的I/O子系統。它在內核虛擬地址空間中執行代碼,使用一個由內核自己創建和支配的棧。

當內核完成其內部初始化並掛載了根文件系統後,默認會執行一個名為init的應用程序。內核一啟動init,它隨即進入用戶空間(user space)或用戶空間上下文運行。在這個運行狀態下,用戶空間進程對系統的訪問是受限的,必須使用內核系統調用(system call)來請求內核服務,比如設備和文件I/O。這些用戶空間進程或程序,運行在一個由內核隨機[6]選擇和管理的虛擬內存空間中。在處理器中專門的內存管理硬件的協助下,內核為用戶空間進程完成虛擬地址到物理地址的轉換。這種架構的最大好處是某個進程中的錯誤不會破壞其他進程的內存空間。這是老式嵌入式系統的一個普遍缺陷,會產生那些最難查找的故障。

對這些概念不熟悉也不用驚慌。本節的目標只是提綱挈領地作個介紹,在此基礎上,你會在閱讀本書的過程中逐步獲得更加深入的理解。後續章節將詳細解釋這些概念。

延伸阅读

    评论