操作系統課堂筆記二-操作系統運行環境

操作系統運行環境

操作系統主要工作

  • 程序的執行
  • 完成與體系結構相關的工作(重點: 操作系統必須瞭解和適配硬件)
  • 完成應用程序所需的共性任務, 提供各種基礎服務
  • 性能,安全,健壯性等問題

操作系統運行狀態

中央處理器(CPU)

  • 一般由運算器, 控制器, 一系列寄存器以及高速緩存構成
  • 兩類寄存器
    • 用戶可見寄存器: 高級語言通過優化算法, 分配並且使用, 目的是減少內存的訪問次數
    • 控制狀態寄存器: 用於控制處理器的操作, 通常是操作系統代碼使用

控制狀態寄存器

  • 用於控制處理器的操作
  • 在某種特權級別下可以訪問修改
  • 常見的幾種寄存器
    • 程序計數器(PC-Program Counter): 記錄要取出指令的地址
    • 指令寄存器(IR-Instruction Register): 記錄最近取出的指令
    • 程序狀態字寄存器(PSW-Program Status Word): 記錄了CPU運行的狀態, 如: 條件碼,模式,控制位等信息. 通常會在psw中專門設置一位, 根據運行程序對資源和指令使用權限而設置不同的CPU狀態。
  • 舉例
    • X86架構中 EFLAGS寄存器 (IOPL: IO的權限級別)

用戶態

  • 運行用戶程序
  • 用戶能夠使用的指令叫做 非特權指令

核心態

  • 運行操作系統程序
  • 操作系統能夠執行的指令叫做 特權指令

指令

  • 特權指令: 啓動I/O, 內存清零, 修改程序狀態字, 設置時鐘, 允許/禁止中斷, 停機
  • 非特權指令: 控制轉移, 算術運算, 訪管指令, 取數指令
  • 舉例X86系列處理器
    • 支持4個級別 R0-R3 R0代表內核態 R3是用戶態
    • 不同級別對應指令不同 包含關係
  • 陷入指令(訪管指令): 是一條特殊的指令, 通過這條指令, 可以使用戶程序向操作系統提出各種各樣的請求,例如: int, trap, syscall, sysenter/sysexit

狀態轉換

  • 用戶態->核心態
    • 唯一途徑: 中斷/異常/陷入機制
  • 內核態->用戶態
    • 修改程序狀態字psw

中斷/異常機制

  • 操作系統中的中斷/異常機制很重要, 可以比作汽車的發動機, 飛機的引擎. 也可以說操作系統由中斷驅動或者事件驅動
  • 主要作用:
    • 外部設備發來的中斷請求
    • 可使os捕獲用戶程序提出的服務請求
    • 防止用戶程序執行過程中的破壞性活動
  • 概念: CPU對系統發生某個事件的一種反應, CPU會主動中斷當前的任務, 保留現場, 切換到需要處理的事件, 然後回來繼續上次的任務.
  • 特點
    • 事件是隨機發生的
    • 自動處理
    • 可恢復
  • 爲什麼引入 中斷機制?
    • 爲了支持CPU和設備之間的並行操作。
    • 舉例: CPU負責啓動輸入/輸出設備去幹活,然後CPU去處理別的事情, 當設備完成任務之後會向CPU彙報結果, 以尋求後續要做的事情, 那麼彙報的過程就需要中斷的參與, 讓CPU先停下手頭的活, 決策一下後續的工作。
  • 爲什麼引入異常機制?
    • 表示CPU在執行過程中自身出現了問題
    • 舉例: 當出現算術溢出, 除零, 取數時的奇偶錯, 地址越界, 陷入指令等異常時, 硬件會改變當前CPU的執行流程, 轉到相應的錯誤處理程序或異常處理程序或執行系統調用。
  • 中斷和異常的不同點?
    • 舉例: 我們以小明看書爲例, 看書的中途來了個電話, 小明記錄好看到多少頁然後去接電話之後回來繼續看 這個叫 中斷。 小明突然口渴了, 記錄下看到哪一頁然後去喝水, 最後再繼續看書 這個叫異常,牛逼!

事件

  • 中斷(外中斷)
    • I/O 中斷: 鍵盤上control+c,打印機結束了, 讀盤結束
    • 時鐘中斷: 設置定時器到點了, 時間片到了
    • 硬件故障: 筆記本電腦沒電了, 讀內存奇偶校驗錯誤
  • 異常(內中斷)
    • 系統調用
    • 頁故障/頁錯誤: 程序運行時候需要從磁盤load到內存(缺頁異常)
    • 保護性異常: 內存空間標記爲只讀(執行寫操作), 訪問內存空間越界
    • 斷點指令: 程序debug
    • 程序性異常: 算術溢出, 棧溢出, 除零
  • 所以中斷和異常又可以理解爲程序外部遇到的問題叫做中斷, 程序內部問題叫做異常中斷是正在運行的外部程序所不期望的, 異常是由正在執行的指令引發的。

中斷異常小結

類別 原因 異步/同步 返回行爲
中斷Interrupt 來自I/O設備,其他硬件 異步 返回下一條指令
陷入Trap 有意識安排的 同步 返回下一條指令
故障Fault 可恢復的錯誤 同步 返回當前指令
終止Abort 不可恢復的錯誤 同步 不返回

操作系統運行機制

操作系統需求-保護

  • 首先我們爲什麼需要保護, 我們知道, 操作系統四大特徵中併發和共享容易導致一些問題, 比如多個進程之間競爭資源, 那麼我們就需要操作系統給我們提供一個保護措施, 使得應用程序間相互不干擾, 應用程序和操作系統之間不干擾。

需要硬件提供的運行機制

  • 處理器具有特權級別, 能在不同特權級運行的不同指令集合
  • 硬件機制可將os和用戶程序隔離

中斷異常機制工作原理

  • 中斷和異常是現在計算機的核心機制之一, 軟硬件相互配合而使計算機系統得以發揮充分的作用。

硬件和軟件

  • 硬件做了什麼? --中斷/異常響應
    • 硬件捕獲發出的中斷/異常請求, 以一定的方式響應, 將處理器的控制權交給特定的程序。
  • 軟件做了什麼? --中斷/異常處理程序
    • 識別中斷/異常類型並完成相應處理

中斷響應

  • 發現中斷, 接收中斷的過程, 中斷硬件部件完成。
  • 處理器控制部件中設有中斷寄存器, CPU何時做響應中斷的工作?
    • CPU->取指令->執行下一條指令->掃描中斷寄存器, 看是否有中斷信號->有則往下看,否則繼續執行下一條指令
    • 當中斷信號發生時, 中斷硬件按照規定編碼將中斷觸發器內容送入PSW相應位, 稱爲中斷碼,通過查中斷向量表引出中斷處理程序。
  • 中斷向量表
    • 中斷向量: 一個內存單元, 存放中斷處理程序入口地址和程序運行時所需的處理機狀態字。
    • 若干個中斷向量構成了中斷向量表, 中斷向量表存儲的是各個中斷程序的入口地址以及出現中斷的原因(其實就是送入psw裏面的東西), 程序會按照中斷號或者異常類型把控制權轉移給對應的中斷處理程序
  • 下面通過一張圖我們瞭解一下Linux中的中斷向量表,轉自這裏
    在這裏插入圖片描述
  • 下面按照自己的理解總結下中斷響應的流程
    在這裏插入圖片描述
  • 中斷處理程序
    • 爲每一類中斷/異常事件編好相應的處理程序,並設置好中斷向量表
    • 系統運行是如果響應中斷, 中斷硬件部件將CPU控制權轉交給中斷處理程序,下面看下中斷處理程序做了哪些事:
      • 保存相關寄存器信息
      • 分析中斷/異常原因
      • 執行對應的處理功能
      • 恢復現場
  • 總的來說就是兩句話: 軟件提前設置好, 硬件部件來執行

相關案例

  • 我們以打印機輸入輸出中斷爲例描述一下

  • 硬件方面:

    • 打印機給CPU發出中斷信號
    • CPU處理完當前指令, 判斷中斷來源並向相關設備發送確認信號
    • 處理器狀態切換到核心態
    • 在系統中保存上下文, 主要是程序計數器PC和狀態字寄存器PSW
    • CPU根據中斷碼查中斷向量表, 查到程序入口地址, 將PC設置成該地址。當新的指令週期開始時,CPU轉移到中斷處理程序
  • 軟件方面

    • 在系統棧中保存現場信息
    • 檢查I/O設備狀態
  • 中斷處理結束後, CPU檢測到中斷返回指令,從系統堆棧中恢復被中斷程序的上下文, 也就是將psw和pc設置回原來的值, 等下一個指令週期繼續運行。(硬件完成)

系統調用機制

  • 操作系統向用戶程序提供的接口

系統調用

  • 系統調用是什麼?
    • 全稱操作系統功能調用, 指的是用戶在編程時可以調用操作系統的功能
  • 系統調用的作用?
    • 系統調用是操作系統和程序員交互的唯一入口
    • 將CPU狀態從用戶態切換到核心態
  • 典型的系統調用
    • 操作系統系統調用接口很多,舉幾個例子:
    • 進程控制
    • 進程通信
    • 文件使用
    • 目錄操作
    • 設備管理
    • 信息維護
  • 系統調用,庫函數,API,內核函數之間的區別
    • 應用程序->C庫函數/API->系統調用->內核函數處理(常見情況)
    • 應用程序->系統調用->內核函數處理
    • 所以,區別在於, 系統調用全是內核函數封裝起來形成的接口, 而C庫函數和API只有部分(個人理解)

系統調用機制設計與執行過程

  • 利用硬件提供的中斷/異常機制, 支持系統調用服務的實現
  • 選擇一條特殊的指令, 陷入指令(也叫做訪管指令), 引發異常, 完成用戶態->內核態的切換(所有的系統調用都是通過該指令進入內核)
  • 每個系統調用事先給好一個編號, 也叫功能號(訪管指令其實是通過傳參的方式進入系統)
  • 系統調用表: 存放系統調用服務的入口地址
  • 如何將參數傳遞給內核?
    • 由陷入指令自帶參數實現: 陷入指令能夠攜帶的參數有限, 還有攜帶功能號
    • 通過通用寄存器傳遞參數實現(最爲常用): 這些寄存器是操作系統和用戶都能訪問的,因此寄存器個數決定了傳參的個數
    • 內存中開闢專用堆棧來實現

系統調用實戰

  • 說了這麼多, 我們來一段代碼看下系統調用的過程
#代碼文件是helloworld.c
#include<unistd.h>
int main(int argc, char const *argv[])
{
    /* code */
    char hello[5] = {"1", "2", "3", "4", "5"};
    write(1, hello, 7);
    return 0;
}
  • 我們上面這段代碼應該會經過兩次系統調用, 一次在write函數,一次在於return
  • 執行如下命令查看彙編代碼:
$ gcc -S helloworld.c -o hello.s
$ cat hello.s
	.section	__TEXT,__text,regular,pure_instructions
	.build_version macos, 10, 14
	.globl	_main                   ## -- Begin function main
	.p2align	4, 0x90
_main:                                  ## @main
	.cfi_startproc
## %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$32, %rsp
	movl	$1, %eax // 主要看這一行開始 write(1...)就是代表功能號1 這一行就是給寄存器傳參
	movl	$7, %ecx
	movl	%ecx, %edx
	leaq	-21(%rbp), %r8
	movl	$0, -4(%rbp)
	movl	%edi, -8(%rbp)
	movq	%rsi, -16(%rbp)
	movl	l_main.hello(%rip), %ecx
	movl	%ecx, -21(%rbp)
	movb	l_main.hello+4(%rip), %r9b
	movb	%r9b, -17(%rbp)
	movl	%eax, %edi
	movq	%r8, %rsi
	callq	_write
	xorl	%ecx, %ecx
	movq	%rax, -32(%rbp)         ## 8-byte Spill
	movl	%ecx, %eax
	addq	$32, %rsp
	popq	%rbp
	retq
	.cfi_endproc
                                        ## -- End function
	.section	__TEXT,__const
l_main.hello:                           ## @main.hello
	.ascii	"Hello"

系統調用執行過程

  • CPU接到特殊的陷入指令將進行如下操作
  • 中斷/異常機制: 硬件保護現場; 通過查中斷向量表(也就是拿到中斷程序的入口地址) 將CPU控制權交給中斷處理程序
  • 系統調用總入口程序: 保存現場; 將(寄存器中的參數) 傳遞給內核中的堆棧, 然後查找系統調用表, 將控制權交給相關係統調用過程或者內核函數。
  • 執行系統調用過程
  • 恢復現場返回用戶程序

參考

[1] 操作系統

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章