Lec 03 系統指令集架構
(參考來源:上海交通大學並行與分散式系統研究所+作業系統課程ppt)
Creative Commons Attribution 4.0 License
Contents
3.1 回顧:特權級的必要性
- 一臺計算機上同時執行多個應用程式,如何保證不同應用間的隔離?
- 如果所有的應用均能完全控制硬體計算資源,則會導致混亂
例如:某個應用希望關機,某個應用希望格式化硬碟 - 因此必須先讓應用降權,不允許直接改變全域性的系統狀態
例如:中斷是否開啟
- 方案:必須要有不同的許可權級——至少兩種許可權
- 低許可權:不允許改變全域性系統狀態,用來執行應用
- 高許可權:集中執行能改變全域性系統狀態的操作,形成了作業系統
- 特權操作:操作裝置(讀取檔案、傳送網路包…)、調整CPU頻率、提供程序間通訊…
3.2 ARM v8.4特權級別(Exception Level)
3.2.1 系統狀態暫存器:PSTATE
- 抽象程序狀態資訊(PSTATE)
- 條件碼 (Condition flags)
e.g. NZCV - 執行狀態 (Execution state controls)
e.g. CurrentEL:CPU當前特權級別 - 異常掩碼 (Exception mask bits)
e.g. DAIF - 訪問控制(Access control bits)
例如PAN(Privileged Access Never)
3.2.2 使用者ISA和系統ISA
- 使用者ISA
- 通用暫存器
- (使用者)棧暫存器
- 條件碼暫存器
- 運算指令等
- 系統ISA
- 系統暫存器
- 系統指令
3.2.3 使用者態(EL0)與核心態(EL1)
- 使用者態(User-mode)
1.只能使用使用者 ISA - 核心態(Kernel-mode)
2.可以同時使用系統 ISA 和使用者ISA - 作業系統往往同時包含核心態與使用者態的程式碼
3.如:Unix包含核心態的kernel 與 使用者態的 shell - aarch64中常見暫存器在不同特權級中的可見情況:
3.3 特權級切換(EL0與EL1)
3.3.1 使用者態與核心態之間的控制流跳轉
- 初始時CPU處於使用者態(EL0)執行應用程式,如何改變CPU控制流從使用者態進入核心態?
- 已知的兩種改變控制流的方式:
(1) 跳轉指令,如 b
(2) 過程呼叫與返回指令,如 bl 和 ret - 這兩種方式只能在同一種模式之間跳轉
- 需要新的指令(在控制流跳轉的同時進行特權級切換):
例如:svc
或eret
3.3.2 進行特權級切換的必要性
- 作業系統的職責之一:
- 服務應用、管理應用
- 特權級切換的必要性:
- 將CPU控制權移交給核心
- 服務:應用程式向作業系統請求服務
- 管理:作業系統能夠切換不同應用程式執行
否則,錯誤/惡意程式死迴圈怎麼辦(作業系統終止惡意程式(故意/無意))
3.3.3 異常處理特權級切換
- 同步異常: 執行當前指令觸發異常
- 第一類:使用者程式主動發起:svc指令(OS利用eret指令返回)
- 第二類:非主動,例如使用者程式意外訪問空指標:普通ldr指令(OS“殺死”出錯程式)
- 非同步異常: CPU收到中斷訊號
- 從外設發來的中斷,例如螢幕點選、滑鼠、收到網路包
- CPU時鐘中斷,例如定時器超時
OS處理完異常後一定返回到被打斷執行的使用者程式嗎?
不一定。原因如下。
3.3.4 異常處理函式
- 異常處理函式屬於作業系統的一部分
- 執行在核心態的程式碼
- 異常處理函式完成異常處理後,將透過下述操作之一轉移控制權:
- 回到發生異常時正在執行的指令
- 回到發生異常時的下一條指令
- 切換到其它程序執行
3.3.5 CPU尋找異常處理函式:異常向量表
- 作業系統核心預先在一張表中準備好不同型別異常的處理函式
- 基地址儲存在VBAR_EL1暫存器中
- 系統暫存器
- CPU在異常發生時自動跳轉到相應處理函式
- 同步異常:主動下陷svc、指令執行出錯
- 非同步異常:中斷(IRQ、FIQ)、SError
3.3.6 CPU執行邏輯
- CPU的執行邏輯很簡單
- 以PC的值為地址從記憶體中獲取一條指令並執行
- PC+=4,goto 1(簡化,表示跳轉/函式呼叫)
- 執行過程中可能發生兩種情況
- 指令執行出現異常,比如svc、缺頁(同步異常)
- 外部裝置觸發中斷(非同步異常)
- 這兩種情況在ARM平臺均稱為「異常」
- 均會導致CPU陷入核心態,並根據異常向量表找到對應的處理函式執行
- 處理函式執行完後,執行流需要恢復到之前被打斷的地方繼續執行
3.3.7 作業系統關於異常處理的任務
一、實現對異常向量表的設定
- 該設定是系統初始化的重要工作之一:在開啟中斷和啟動第一個應用之前
msr vbar_el1, x0
(是核心態才能使用的指令,核心才能訪問的暫存器)
二、實現對不同異常(中斷)的處理函式
- 處理應用程式出錯的情況:如訪問空指標
Q:核心如果自己執行出錯怎麼辦?
A:同樣核心異常處理,但無需下陷(已經處於核心態)。有些平臺在三次遞迴後會丟擲triple-fault
- 一類特殊的同步異常:系統呼叫,由應用主動觸發
Q:核心如何識別出是系統呼叫(而不是其他異常)?
A:執行mrs x1, esr_el1
,核心透過 ESR_EL1 暫存器讀取陷入核心的原因 - 處理來自外部裝置的中斷:如收取網路包、獲取鍵盤輸入等
3.4 使用者態和核心態的切換
3.4.1 處理器狀態變化
3.4.2 處理器的任務
- 將發生異常事件的指令地址儲存在ELR_EL1中
- 將異常事件的原因儲存在ESR_EL1
例如,是執行svc指令導致的,還是訪存缺頁導致的 - 將處理器的當前狀態(即PSTATE)儲存在SPSR_EL1
- 棧暫存器不再使用SP_EL0(使用者態棧暫存器),開始使用SP_EL1
核心態棧暫存器,需要由作業系統提前設定 - 修改PSTATE暫存器中的特權級標誌位,設定為核心態
- 找到異常處理函式的入口地址,並將該地址寫入PC,開始執行作業系統
根據VBAR_EL1暫存器儲存的異常向量表基地址,以及發生異常事件的型別確定
? 為什麼作業系統不能直接使用應用程式在使用者態的棧呢?
- 安全問題。當作業系統的棧和使用者態程式棧混合時,會使得作業系統的棧被使用者態程式訪問,導致核心級操作可以被應用操作。
? 處理器的這些操作都是必要的麼?
- PC暫存器的值必須由處理器儲存
否則當作業系統開始執行時,PC將被覆蓋 - 棧的切換也必須由硬體完成
否則作業系統有可能使用使用者態的棧,導致安全問題
3.4.3 eret:從核心態返回到使用者態
- 將SPSR_EL1中的處理器狀態寫入PSTATE中
處理器狀態也從 EL1 切換到 EL0 - 棧暫存器不再使用SP_EL1,開始使用SP_EL0
注意:SP_EL1的值並沒有改變
下一次下陷時,作業系統依然會使用這個核心棧 - 將ELR_EL1中的地址寫入PC,並執行應用程式程式碼
3.4.4 作業系統在切換過程中的任務
- 主要任務:將屬於應用程式的 CPU 狀態儲存到記憶體中
用於之後恢復應用程式繼續執行 - 應用程式需要儲存的執行狀態稱為處理器上下文
(1) 處理器上下文(Processor Context):應用程式在完成切換後恢復執行所需的最小處理器狀態集合
(2) 處理器上下文中的暫存器具體包括:
1.通用暫存器 X0-X30
2.特殊暫存器,主要包括PC、SP和PSTATE
3.系統暫存器,包括頁表基地址暫存器等