Lec 03 系統指令集架構

木木ちゃん發表於2024-11-12

Lec 03 系統指令集架構

(參考來源:上海交通大學並行與分散式系統研究所+作業系統課程ppt)
Creative Commons Attribution 4.0 License

Contents

3.1 回顧:特權級的必要性

  • 一臺計算機上同時執行多個應用程式,如何保證不同應用間的隔離?
  1. 如果所有的應用均能完全控制硬體計算資源,則會導致混亂
    例如:某個應用希望關機,某個應用希望格式化硬碟
  2. 因此必須先讓應用降權,不允許直接改變全域性的系統狀態
    例如:中斷是否開啟
  • 方案:必須要有不同的許可權級——至少兩種許可權
  1. 低許可權:不允許改變全域性系統狀態,用來執行應用
  2. 高許可權:集中執行能改變全域性系統狀態的操作,形成了作業系統
  3. 特權操作:操作裝置(讀取檔案、傳送網路包…)、調整CPU頻率、提供程序間通訊…

alt

3.2 ARM v8.4特權級別(Exception Level)

alt

3.2.1 系統狀態暫存器:PSTATE

  • 抽象程序狀態資訊(PSTATE)
  1. 條件碼 (Condition flags)
    e.g. NZCV
  2. 執行狀態 (Execution state controls)
    e.g. CurrentEL:CPU當前特權級別
  3. 異常掩碼 (Exception mask bits)
    e.g. DAIF
  4. 訪問控制(Access control bits)
    例如PAN(Privileged Access Never)

alt

3.2.2 使用者ISA和系統ISA

  • 使用者ISA
  1. 通用暫存器
  2. (使用者)棧暫存器
  3. 條件碼暫存器
  4. 運算指令等
  • 系統ISA
  1. 系統暫存器
  2. 系統指令

alt

3.2.3 使用者態(EL0)與核心態(EL1)

  • 使用者態(User-mode)
    1.只能使用使用者 ISA
  • 核心態(Kernel-mode)
    2.可以同時使用系統 ISA 和使用者ISA
  • 作業系統往往同時包含核心態與使用者態的程式碼
    3.如:Unix包含核心態的kernel 與 使用者態的 shell
  • aarch64中常見暫存器在不同特權級中的可見情況:

alt

3.3 特權級切換(EL0與EL1)

3.3.1 使用者態與核心態之間的控制流跳轉

  • 初始時CPU處於使用者態(EL0)執行應用程式,如何改變CPU控制流從使用者態進入核心態?
  1. 已知的兩種改變控制流的方式:
    (1) 跳轉指令,如 b
    (2) 過程呼叫與返回指令,如 bl 和 ret
  2. 這兩種方式只能在同一種模式之間跳轉
  3. 需要新的指令(在控制流跳轉的同時進行特權級切換):
    例如:svceret

3.3.2 進行特權級切換的必要性

  • 作業系統的職責之一:
  1. 服務應用、管理應用
  • 特權級切換的必要性:
  1. 將CPU控制權移交給核心
  2. 服務:應用程式向作業系統請求服務
  3. 管理:作業系統能夠切換不同應用程式執行
    否則,錯誤/惡意程式死迴圈怎麼辦(作業系統終止惡意程式(故意/無意))

3.3.3 異常處理特權級切換

  • 同步異常: 執行當前指令觸發異常
  1. 第一類:使用者程式主動發起:svc指令(OS利用eret指令返回)
  2. 第二類:非主動,例如使用者程式意外訪問空指標:普通ldr指令(OS“殺死”出錯程式)
  • 非同步異常: CPU收到中斷訊號
  1. 從外設發來的中斷,例如螢幕點選、滑鼠、收到網路包
  2. CPU時鐘中斷,例如定時器超時

alt

OS處理完異常後一定返回到被打斷執行的使用者程式嗎?
不一定。原因如下。

3.3.4 異常處理函式

  • 異常處理函式屬於作業系統的一部分
  1. 執行在核心態的程式碼
  • 異常處理函式完成異常處理後,將透過下述操作之一轉移控制權:
  1. 回到發生異常時正在執行的指令
  2. 回到發生異常時的下一條指令
  3. 切換到其它程序執行

3.3.5 CPU尋找異常處理函式:異常向量表

  • 作業系統核心預先在一張表中準備好不同型別異常的處理函式
  1. 基地址儲存在VBAR_EL1暫存器中
  2. 系統暫存器
  • CPU在異常發生時自動跳轉到相應處理函式
  1. 同步異常:主動下陷svc、指令執行出錯
  2. 非同步異常:中斷(IRQ、FIQ)、SError

alt

3.3.6 CPU執行邏輯

  • CPU的執行邏輯很簡單
  1. 以PC的值為地址從記憶體中獲取一條指令並執行
  2. PC+=4,goto 1(簡化,表示跳轉/函式呼叫)
  • 執行過程中可能發生兩種情況
  1. 指令執行出現異常,比如svc、缺頁(同步異常)
  2. 外部裝置觸發中斷(非同步異常)
  • 這兩種情況在ARM平臺均稱為「異常」
  1. 均會導致CPU陷入核心態,並根據異常向量表找到對應的處理函式執行
  2. 處理函式執行完後,執行流需要恢復到之前被打斷的地方繼續執行

3.3.7 作業系統關於異常處理的任務

一、實現對異常向量表的設定

  1. 該設定是系統初始化的重要工作之一:在開啟中斷和啟動第一個應用之前
  2. msr vbar_el1, x0 (是核心態才能使用的指令,核心才能訪問的暫存器)

二、實現對不同異常(中斷)的處理函式

  1. 處理應用程式出錯的情況:如訪問空指標
    Q:核心如果自己執行出錯怎麼辦?
    A:同樣核心異常處理,但無需下陷(已經處於核心態)。有些平臺在三次遞迴後會丟擲triple-fault
  2. 一類特殊的同步異常:系統呼叫,由應用主動觸發
    Q:核心如何識別出是系統呼叫(而不是其他異常)?
    A:執行mrs x1, esr_el1,核心透過 ESR_EL1 暫存器讀取陷入核心的原因
  3. 處理來自外部裝置的中斷:如收取網路包、獲取鍵盤輸入等

alt

3.4 使用者態和核心態的切換

3.4.1 處理器狀態變化

alt

3.4.2 處理器的任務

  1. 將發生異常事件的指令地址儲存在ELR_EL1中
  2. 將異常事件的原因儲存在ESR_EL1
    例如,是執行svc指令導致的,還是訪存缺頁導致的
  3. 將處理器的當前狀態(即PSTATE)儲存在SPSR_EL1
  4. 棧暫存器不再使用SP_EL0(使用者態棧暫存器),開始使用SP_EL1
    核心態棧暫存器,需要由作業系統提前設定
  5. 修改PSTATE暫存器中的特權級標誌位,設定為核心態
  6. 找到異常處理函式的入口地址,並將該地址寫入PC,開始執行作業系統
    根據VBAR_EL1暫存器儲存的異常向量表基地址,以及發生異常事件的型別確定

為什麼作業系統不能直接使用應用程式在使用者態的棧呢?

  • 安全問題。當作業系統的棧和使用者態程式棧混合時,會使得作業系統的棧被使用者態程式訪問,導致核心級操作可以被應用操作。

處理器的這些操作都是必要的麼?

  1. PC暫存器的值必須由處理器儲存
    否則當作業系統開始執行時,PC將被覆蓋
  2. 棧的切換也必須由硬體完成
    否則作業系統有可能使用使用者態的棧,導致安全問題

3.4.3 eret:從核心態返回到使用者態

  1. 將SPSR_EL1中的處理器狀態寫入PSTATE中
    處理器狀態也從 EL1 切換到 EL0
  2. 棧暫存器不再使用SP_EL1,開始使用SP_EL0
    注意:SP_EL1的值並沒有改變
    下一次下陷時,作業系統依然會使用這個核心棧
  3. 將ELR_EL1中的地址寫入PC,並執行應用程式程式碼

3.4.4 作業系統在切換過程中的任務

  1. 主要任務:將屬於應用程式的 CPU 狀態儲存到記憶體中
    用於之後恢復應用程式繼續執行
  2. 應用程式需要儲存的執行狀態稱為處理器上下文
    (1) 處理器上下文(Processor Context):應用程式在完成切換後恢復執行所需的最小處理器狀態集合
    (2) 處理器上下文中的暫存器具體包括:
    1.通用暫存器 X0-X30
    2.特殊暫存器,主要包括PC、SP和PSTATE
    3.系統暫存器,包括頁表基地址暫存器等

相關文章