王海峰 蔣曉華
1.廣東科學技術職業學院,珠海 519090 2.珠海歐比特控制工程股份有限公司,珠海 519080
基于SPARC多核SOC的Linux操作系統研究
王海峰1蔣曉華2
1.廣東科學技術職業學院,珠海 519090 2.珠海歐比特控制工程股份有限公司,珠海 519080

通過移植啟動代碼,實現了Linux在SPARC多核處理器上的運行,重點剖析Linux針對SMP多核系統的進程管理機制、同步機制、進程調度和負載平衡等,在S698PM多核處理器平臺進行了驗證。 關鍵詞 多核系統;SPARC SOC;Linux;進程調度;S698PM
Linux作為一種開源操作系統,具有內核精簡、應用程序豐富、開發成本低廉和組件可配置等特點,廣泛運用在桌面端和嵌入式領域。
目前在嵌入式領域,多核處理器已經大量應用,而多核處理器中又以SMP架構最為常見。所謂SMP 架構,即是2個或多個同樣的處理器通過一塊共享內存彼此連接,每個處理器可同等地訪問共享內存(具有相同的內存空間訪問延遲)。SMP技術提升了系統的性能,但同時也增加了操作系統內核的復雜度和協同開銷,如何更好的支持SMP硬件系統是每個操作系統都面臨的棘手問題[1]。
SPARC是國際上流行的RISC處理器體系架構
之一, SPARC V7/V8 是目前嵌入式控制系統常用的處理器標準版本,并在航天設備的電子系統中得到廣泛應用。基于SPARC SMP的多核處理器應用前景較好,由于SPARC嵌入式處理器主要應用在航天軍工領域,Linux系統本身對SPARC架構的支持有限,對SPARC SMP的支持更是空白,一般需要進行平臺移植[2-3]。本文以此為出發點,研究SMP系統中的幾個關鍵技術,闡述了Linux 2.6系統針對SPARC多核處理器中的移植過程,并詳細分析研究了在Linux操作系統下如何更好地解決多個CPU之間的同步機制、負載平衡和進程調度問題。
以多核處理器S698PM為硬件實驗平臺。S698PM是基于SPARC V8架構的高性能的32位RISC嵌入式4核SOC處理器,其內部采用SMP“對稱多處理”技術,各CPU之間共享內存子系統以及總線結構,總線競爭和仲裁由硬件自動完成,為了支持SMP,硬件上還集成了APIC中斷控制系統[4]。
在Linux2.6 SMP結構中,CPU平等是建立在系
統中有多個進程或者多個執行上下文的前提下,由于在系統的引導和初始化階段只有一個上下文,而同一時間,一個上下文只能有1個CPU來處理,所以在CPU系統初始化階段只能有1個引導處理器CPU0工作,而其余的應用處理器CPU1,CPU2和CPU3處于暫停狀態。CPU0完成系統的引導和初始化,并創建1號進程kernel_init和3個idle進程,在kernel_init中通過LOCAL APIC發送IPI消息控制CPU1,CPU2和CPU3從指定的起始地址運行,實現逐個啟動CPU1,CPU2和CPU3的功能,達到SMP并行處理的要求。
在操作系統中,可能會隨機分配某個CPU為啟動CPU,因此,為確保CPU0為啟動CPU,必須修改head.s文件中的trapbase為CPU0,如下所示。

圖1 S698PM功能結構

start:trapbase:#ifdefCONFIG_SMPtrapbase_cpu0:#endif
此外引導部分還需要針對SPARC架構進行內存管理單元、中斷控制器和時鐘的設置,并進行內存清空和內存讀寫測試等操作,只有部分工作統一由CPU0來完成。添加及修改的幾個主要文件包括:
1)device.c和init.c:完成處理器信息和驅動信息的掃描。如果掃描符合要求,系統才允許進入引導程序,并做出下一步的初始化;
2)prom.c:在rootnode中建立驅動樹,為后續開發驅動應用程序提供幫助,使驅動設備和其相應的驅動程序以及設備號能很好地對應起來;
3)leon_irq.c:實現對SPARC系統中斷的管理,用來對中斷初始化、中斷設置和中斷錯誤報告相關信息的跟蹤等。
移植完成后Linux對SMP的引導過程如下:
(1)加載Linux內核映像到內存
Linux內核映像存貯在Flash中,當系統加電時,利用Bootloader將初始化信息傳遞給Linux內核,Bootloader把Linux內核復制到0開始的物理內存處開始執行。
(2)執行Linux系統初始化
成功加載內核映像之后,Boot Loader將指引CPU0跳轉到Linux內核映像的入口地址_start函數處執行。這時,由于MMU地址映射還沒啟用,因此需要將鏈接地址轉換成物理地址來實現CPU中Cache,TLB以及寄存器的初始化。
初始化后,臨時MMU地址映射開啟,CPU0跳轉到 start_kernel()繼續執行,并構造0號進程rest_init運行上下文,rest_init完成初始化部分并調用kernel_thread()函數創建第一個核心進程kernel_init。kernel_init函數代碼如下:

Statickernel_init(void){smp_prepare_cpus(max_cpus);smp_boot_cpus(max_cpus);connect_bsp_APIC();setup_local_APIC();map_cpu_to_logical_apicid();do_boot_cpu(apicid,cpu)}
do_boot_cpu會完成應用處理器的初始化,并通過中斷方式通知主CPU,次CPU可以啟動。
(3)應用程序初始化
init完成Linux的各項配置后,會在/sbin,/etc和/bin中尋找init程序來運行。該init程序會替換kernel_init()進程,此時處于內核態的1號進程kernel_init()將轉換為用戶空間內的1號進程init,開始系統的正常運行。
在Linux中,SMP系統的多核引導是一個分階段的過程,這中間需要主CPU和次CPU在幾個地方進行同步,最終基本在同一時間進入SMP的進程調度。

圖2 Linux SMP多核引導流程圖
3.1 同步機制
在Linux SMP中,多個CPU可以并行運行內核代碼,當內核數據被多個內核控制路徑共享存取時,就會產生資源競爭。根據資源競爭產生的原因及所保護的數據不同,Linux操作系統為內核代碼提供了多種同步與互斥機制,如原子操作、信號量、讀寫、大內核鎖、讀寫鎖和自旋鎖等方法,來保護內核數據的安全共享。操作系統鎖機制的基本原理是在某個鎖操作過程中不能與其他鎖操作交織執行,以免多個執行路徑對內核中某些重要的數據及數據結構進行同時操作而造成混亂,本文主要利用自旋鎖來確保CPU的同步互斥操作。
自旋鎖(spinlock)是使用忙等待鎖來確保互斥的一種特殊方法。每個自旋鎖都是用1個spinlock_t數據結構來表示。只有spinlock_t的最低位被使用,如果鎖可用,則它是0;如果被取走,則它是1。
在可搶占內核和SMP情況下,如果2個任務競爭1個共享的資源,沒有得到資源的任務將自旋以等待另一個任務使用完該共享資源,自旋鎖的實現如下:自旋鎖在使用前必須先初始化,自旋鎖有完全鎖和讀寫鎖2種形式。在SMP系統中主要用的是完全鎖。
首先創建一個新的自旋鎖,

spinlock_tpm_spinlock=SPIN_LOCK_UNLOCKED;SPINLOCK(pm_spinlock);spin_lock_init(&pm_spinlock);
自旋鎖被初始化為值SPIN_LOCK_UNLOCKED,它也可以用spin_lock_init函數來初始化。這兩者都把spinlock_t的lock成員設置成0,也就是未鎖狀態。定義自旋鎖后,就可以使用鎖變量,每個變量用于不同的上下文。
實際運行時通過函數spin_lock_irqsave和spin_unlock_irqrestore來實現自旋鎖的獲取和釋放。當進程在某個CPU上運行時,需要通過spin_lock_irqsave獲取自旋鎖,并在本地處理器上禁用中斷。運行完成之后,需要通過spin_unlock_irqrestore釋放自旋鎖,并且(通過flags參數)恢復中斷,實現CPU之間的互斥功能。
3.2 進程調度
Linux 操作系統在處理進程調度時,Task起關鍵作用。任務的基本數據結構為task_struct,包涵了任務的當前狀態、優先級、剩余時間片、進程號、正在使用的CPU和上一次使用的CPU以及內核鎖的深度等參數。
Linux 操作系統內核中負責進程調度的具體函數是Schedule,當已經不在運行隊列里的進程被喚醒時,Wake up process( ) 函數將調用Reschedule idle( ) 函數,嘗試在一個空閑的CPU 上運行被喚醒的進程,它使高優先級的進程得到占用CPU 的機會。此時函數Reschedule idle 被調用, 嘗試在別的CPU 上調度該進程。
函數Reschedule idle首先檢查進程上次運行的CPU,如果該CPU處于忙狀態,則找其它合適的CPU,查看SMP中的每個CPU上運行的進程,并與現有進程相比優先權,把具有最高的搶先權值的進程記錄在target_task中。 如target_task為空,說明沒有找到合適的CPU;如果target_task不為空,則說明找到了合適的CPU,將target_task->need_resched置為1。如果運行target_task的CPU不是當前運行的CPU,則向運行target_task的CPU發送一個IPI中斷,讓它重新調度,實現對進程的調度功能。
3.3 負載均衡
在SMP多核系統中,每個處理器都有獨立的運行隊列runqueue,當存在多個就緒進程隊列runqueue,CPU會一直處于忙狀態。相反,當runqueue較少時,相應的CPU可能會經常處于空轉狀態,這會導致CPU負載不均衡。Linux對負載均衡的實現重點體現在何時檢查負載,如何調整負載。
檢查負載有2種方法:1)在進程的啟動、睡眠時進行檢查;2)定時檢查。
當進程調用了sleep,pause等操作時,schedule()函數會調用idle_balance(),從其他CPU挪用進程過來。定時檢查利用函數rebalance_tick()來實現,在每個CPU上的每個定時器的tick時刻調用rebalance_tick(),檢查每個調度域,在一定的時間間隔內調用函數load_balance()進行負載平衡。
Linux系統中,在load_balance函數及idle_balance函數中調用pull_task函數以從重載CPU上將進程“搬運”到輕載CPU上,實現負載平衡。函數load_balance根據當前CPU是否空閑分為“忙平衡”和“空閑平衡”。每tick時鐘中斷會啟動一次函數rebalance_tick來計算合適的時間間隔,啟動函數load_balance平衡負載。另外,在調度器schedule中,如果本CPU的就緒隊列為空也會調用idle_balance函數進行“空閑平衡”。函數pull_task實現任務的搬運工作,更新進程的timestamp屬性,如果搬運過來的進程優先級比本CPU正運行的進程高,則當前進程被搶占。

staticvoidrebalance_tick(){……if(idle!=SCHED_IDLE)interval?=sd->busy_factor;……}
移植完成后,Linux可以在S698PM平臺正確運行,本文以S698PM處理器的1553B應用為例,驗證Linux SMP系統的運行過程。
應用程序中使片內1553B為RT模式,同時打開1553B的2路接收,相當于在Linux操作系統中開啟了2個進程來實現RT的接收功能,在RT接收過程中,Linux操作系統還需要處理其他的進程,如:sshd守護進程、shell進程等,觀察程序的運行過程可以大概了解Linux的進程管理方法。
執行user/custom/Makefile腳本文件編譯應用并生成image.dsu文件,下載到S698PM板卡中運行,并連續向這2路1553B接口發送數據,程序運行如圖3所示。
從圖4 可以看出,當2路1553B同時接收時,Linux會根據SMP調度機制將2路接收進程分配在CPU0和CPU1上同時運行,實現了資源合理分配和負載平衡。并且2路之間沒有出現延時和漏數的現象,證明系統的進程調度和同步機制工作正常。
通過修改Linux的啟動代碼,實現了對基于SPARC的SMP對稱多核SOC處理器的支持,通過在S698PM處理器平臺上運行Linux,驗證了Linux針對SMP系統的同步機制、進程調度和負載平衡這3個重要特性。
[1] [美]ScottMaxwell. Linux 內核源代碼分析[M]. 馮銳, 等. 譯.北京: 機械工業出版社, 2000.
[2] Bovet, Cesati .深入理解Linux 內核[M]. 陳莉君, 等. 譯.北京:中國電力出版社, 2001.
[3] [美]李(Li,Q),等.嵌入式系統的實時概念[M].王安生.譯.北京:北京航空航天大學出版社,2004.
[4] S698PM用戶手冊[Z].珠海歐比特控制工程股份有限公司,2014,6.
Study on Linux Application Based on Multi-Core SPARC SOC
Wang Haifeng1, Jiang Xiaohua2
1. Guangdong Institute of Science and Technology, Zhuhai 519090, China 2.Orbita Control Engineering Co.,Ltd., Zhuhai 519080, China
Firstly,bythetransplantationofthestartupcode, LinuxcanrunontheSPARCmulti-coreprocessor.Then,theLinuxprocessmanagementfortheSMPmulti-coresystemisfocused,includingsynchronizationmechanism,processschedulingandloadbalance.Finally,theactualverificationisimplementedinS698PMmulti-coreprocessorplatform.
Multi-coresystem;SPARC SOC;Linux;Dispatchprocessing;S698PM

圖3 Linux在S698PM運行

圖4 Linux 1553B RT運行截圖
TP316
A
1006-3242(2017)03-0049-05
2015-06-10
王海峰(1974-),男,山西永濟人,碩士,副教授,主要研究方向為電子與信息系統;蔣曉華(1978-),男,湖南衡陽人,碩士,高級工程師,主要研究方向為集成電路設計。