操作系統慕課ucore lab1筆記

来源:https://www.cnblogs.com/SilenceWell/archive/2020/07/13/13282111.html
-Advertisement-
Play Games

#知識點 操作系統的啟動知識和中斷的建立與初始化 涉及到Intel 806386寄存器,AT&T彙編,gcc內聯彙編,C函數堆棧,Makefile等知識 筆記主要按照操作系統的啟動和中斷的建立兩個部分來記錄 ##理論課的介紹 ###系統啟動 當CPU剛加電初始化時,CS:IP寄存器根據設定的初始值跳 ...


知識點

  • 操作系統的啟動知識和中斷的建立與初始化
  • 涉及到Intel 806386寄存器,AT&T彙編,gcc內聯彙編,C函數堆棧,Makefile等知識
    筆記主要按照操作系統的啟動和中斷的建立兩個部分來記錄

理論課的介紹


系統啟動

當CPU剛加電初始化時,CS:IP寄存器根據設定的初始值跳轉到BIOS固件處執行第一條指令,根據指令跳轉到BIOS數據區執行BIOS代碼。BIOS在完成硬體的自檢後,會將操作系統的啟動代碼載入到記憶體。此時CPU還處於實模式,只能定址20位,也就是1MB的記憶體空間(通常處於記憶體空間的低位地址),所以操作系統的啟動代碼需要載入在這1MB的定址空間內。實驗環境下,啟動代碼需載入到記憶體地址0x7C00處,啟動代碼再將CPU從實模式轉成保護模式,得以獲得32位的定址空間(4GB),去載入代碼量龐大的操作系統。理論課視頻截圖較為系統地展示了這個過程,如下圖所示

為什麼不利用BIOS直接載入操作系統?原因是不同操作系統可能擁有不同的文件系統,BIOS無法編寫所有文件系統的解析代碼,所以將載入程式作為操作系統的一部分,讓操作系統可以“定製化”實現自己的載入程式。主引導記錄和活動分區的存在主要是硬碟分區的原因。

中斷建立

中斷源的類型

  • 系統調用(system call):應用程式主動向操作系統發出的服務請求
  • 異常(exception):非法指令或者其它原因導致指令執行失敗(如:記憶體出錯)後的處理請求
  • 中斷(hardware interrupt):來自硬體設備的處理請求

    如上圖所示,中斷向量表可以建立起中斷源和服務常式之間的聯繫,在實操課程中中斷向量表的建立也是一項重要的內容。

實驗課的一些知識


在Lab1中,代碼主要分為bootblockkernel兩個部分。bootblock完成了主引導記錄、活動分區文件系統識別以及載入程式的功能,kernel則是完成系統內核的功能。


bootblock

從make和makefile來看,bootblock主要涉及到的源文件有bootmain.c,bootasm.S,sign.c,其中,bootmain.c,bootasm.S實現了bootblock的大部分功能,而sign.c從代碼上看來,只是將第二個命令行參數(argv[1])的文件指針指向內容拷貝到argv[2]指向的文件,併在文件結尾加入主引導記錄標誌0x55, 0xAA,控制拷貝完的文件大小為512位元組。在make編譯鏈接的過程中,傳入bin/sign(sign.c生成)的文件為obj/bootblock.out,輸出的文件為bin/bootblock,bootblock.outbootmain.cbootasm.S生成。

bootasm.S

在實模式下,段寄存器和ip寄存器只提供16位的操作空間。為了定址1MB的記憶體空間,此時段寄存器存儲的基值(16位,base)會左移四位,加上偏移量(IP寄存器,offset)作為邏輯地址。
一開始CPU還處於實模式,段機制還未啟動,但是將CPU轉成保護模式之前需要將重要的段寄存器設置好,轉換前段寄存器DS,ES,SS需置0

xorw %ax, %ax                                   
movw %ax, %ds                                   
movw %ax, %es                                   
movw %ax, %ss 

在進入保護模式之前,需要開啟A20地址線https://chyyuu.gitbooks.io/ucore_os_docs/content/lab1/lab1_appendix_a20.html,開啟步驟為

  1. 等待8042 Input buffer為空;
  2. 發送Write 8042 Output Port (P2)命令到8042 Input buffer;
  3. 等待8042 Input buffer為空;
  4. 將8042 Output Port(P2)得到位元組的第2位置1,然後寫入8042 Input buffer;
    對應代碼為
seta20.1:
    inb $0x64, %al                                  # Wait for not busy(8042 input buffer empty).
    testb $0x2, %al
    jnz seta20.1

    movb $0xd1, %al                                 # 0xd1 -> port 0x64
    outb %al, $0x64                                 # 0xd1 means: write data to 8042's P2 port

seta20.2:
    inb $0x64, %al                                  # Wait for not busy(8042 input buffer empty).
    testb $0x2, %al
    jnz seta20.2

    movb $0xdf, %al                                 # 0xdf -> port 0x60
    outb %al, $0x60                                 # 0xdf = 11011111, means set P2's A20 bit(the 1 bit) to 1

接下來載入GDT,

lgdt gdtdesc
...
# Bootstrap GDT
.p2align 2                                          # force 4 byte alignment
gdt:
    SEG_NULLASM                                     # null seg
    SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)           # code seg for bootloader and kernel
    SEG_ASM(STA_W, 0x0, 0xffffffff)                 # data seg for bootloader and kernel

gdtdesc:
    .word 0x17                                      # sizeof(gdt) - 1
    .long gdt                                       # address gdt

從代碼上看,CPU會先讀取GDT的描述信息,確定GDT的大小(24位元組),再跳轉到gdt的所在地址,執行記憶體分段。實驗環境中,記憶體被分為代碼段和數據段,大小都為4G(0x0~0xffffffff).設置完成之後,進入32位的保護模式,進行相應的準備工作。

.code32                                             # Assemble for 32-bit mode
protcseg:
    # Set up the protected-mode data segment registers
    movw $PROT_MODE_DSEG, %ax                       # Our data segment selector, $PROT_MODE_DSEG=0x10,ax最高位為1,使ds等段寄存器相應位置1,以支持保護模式
    movw %ax, %ds                                   # -> DS: Data Segment
    movw %ax, %es                                   # -> ES: Extra Segment
    movw %ax, %fs                                   # -> FS
    movw %ax, %gs                                   # -> GS
    movw %ax, %ss                                   # -> SS: Stack Segment

    # Set up the stack pointer and call into C. The stack region is from 0--start(0x7c00)
    movl $0x0, %ebp                                 
    movl $start, %esp                               # start為bootasm.S入口地址

一切準備工作就緒後,調用C函數bootmain.c繼續執行以至可以載入操作系統內核call bootmain,bootmain負責將內核載入到記憶體0x10000處,並檢查是否為合法的ELF文件。


kernel


在Lab1中,提及最多的知識是關於C函數堆棧的內容。見https://chyyuu.gitbooks.io/ucore_os_docs/content/lab1/lab1_3_3_1_function_stack.html,調試的編程參考於此
Lab1關於中斷的內容主要是實現LDT的初始化。線索從kern/trap/vector.S開始,其中以彙編的形式記錄了__vectors[].從功能上看,__vectors像是一個函數指針數組,每個數組成員對應某個函數操作的入口。不同類型的中斷向量被觸發之後都會跳轉到kern/trap/trapentry.S的__alltraps處。目前來講,這些功能使用C語言都能實現類似的效果,但是操作系統在這裡使用了彙編的原因據推斷是這裡需要獲取段寄存器的值,使用彙編會直接很多。__alltraps的目的是輔助C函數trap()的實現。trap的代碼如下:

void
trap(struct trapframe *tf) {
    trap_dispatch(tf);
}
# trapframe的結構如下
struct trapframe {
    struct pushregs tf_regs;
    uint16_t tf_gs;
    uint16_t tf_padding0;
    uint16_t tf_fs;
    uint16_t tf_padding1;
    uint16_t tf_es;
    uint16_t tf_padding2;
    uint16_t tf_ds;
    uint16_t tf_padding3;
    uint32_t tf_trapno;
    /* below here defined by x86 hardware */
    uint32_t tf_err;
    uintptr_t tf_eip;
    uint16_t tf_cs;
    uint16_t tf_padding4;
    uint32_t tf_eflags;
    /* below here only when crossing rings, such as from user to kernel */
    uintptr_t tf_esp;
    uint16_t tf_ss;
    uint16_t tf_padding5;
} __attribute__((packed));

彙編代碼

.text
.globl __alltraps
__alltraps:
  
    pushl %ds
    pushl %es
    pushl %fs
    pushl %gs
    pushal

    # load GD_KDATA into %ds and %es to set up data segments for kernel
    movl $GD_KDATA, %eax
    movw %ax, %ds
    movw %ax, %es

    pushl %esp

    call trap

push語句主要是為了模擬C函數的堆棧形式。最先入棧的是C函數的實際參數,該參數為指向trapframe的指針,但在此之前需要將指針指向內容壓棧,可以看到彙編壓棧順序和結構成員聲明相反(說明:結構成員tf_paddingx是作為填充消除編譯器的記憶體對齊問題)。之後調用trap_dispatch,根據中斷號執行不同的中斷常式。
回到LDT的初始化,現在已經大概清楚從中斷向量到觸發中斷常式的過程,但是怎麼聯繫起中斷向量__vectors[]和中斷源呢?這是idt_init需要實現的東西。中斷源用結構體gatedesc描述,再將數組idt[256]對應不同的中斷源。idt_init做的很重要的一件事是怎麼將__vectors[]和idt[]相同下標的gatedesc成員賦值好。最後利用彙編命令lidt載入LDT.


結尾

筆記寫的不是非常嚴謹,此筆記主要功能是提供自己能夠快速回憶操作系統知識。有其他重要知識點就等以後意識到再補充吧


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 引言 1.1. 背景 隨著時代的進步,社會的發展,人們的生活形式與習慣也越來越多樣化,出行成為了人們生活中的一個重要組成部分,而客車成為許多人出行選擇的交通工具。面對巨大數量的乘客的購票需要,客車站就要選擇使用先進的管理方法來實現方便、快捷的售票、退票等方面的票務管理。隨著電腦的普及,信息處 ...
  • 動畫是將靜止的畫面變為動態的藝術.實現由靜止到動態,主要是靠人眼的視覺殘留效應。視覺殘留也叫視覺暫留現象,物體在快速運動時, 當人眼所看到的影像消失後,人眼仍能繼續保留其影像0.1~0.4秒左右的圖像,這種現象被稱為視覺暫留現象。利用人的這種視覺生理特性可製作出具有高度想象力和表現力的動畫影片。 電 ...
  • 一、 引言 對於一個多人團隊來說,制定一個統一的規範是必要的,因為個性化的東西無法產生良好的聚合效果,規範化可以提高編碼工作效率,使代碼保持統一的風格,以便於代碼整合和後期維護。 二、 HTML/CSS規範 2.1 瀏覽器相容 根據公司業務要求而定,一般:主流程測試:Chrome 30+、IE9+; ...
  • 結構型模式 適配器模式 類適配器和對象適配器 結構型模式 結構型模式的重點在於如何通過靈活的體系組織不同的對象,併在此基礎上完成更為複雜的類型(或者類型系統),而參與組合的各類型之間始終保持儘量鬆散的結構關係。 結構型模式包括以下幾種: 適配器模式 橋接模式 組合模式 裝飾模式 外觀模式 享元模式 ...
  • 前段時間做了個node全棧項目,服務端技術棧是 nginx + koa + postgresql。其中在centos上搭建環境和部署都挺費周折,部署測試伺服器,接著上線的時候又部署生產環境伺服器。這中間就有很多既無聊又費精力,吃力不討好的"體力活"。所以就開始思考怎麼自動化這部分搭建部署的工作,也就 ...
  • 1 #include <emscripten/bind.h> 2 #include <string> 3 4 using namespace std; 5 using namespace emscripten; 6 7 class xClass { 8 public: 9 // 構造方法; 10 x ...
  • 繼golang第一天後,今天學習下golang的變數、常量、數據類型和控制流語句。 做過其他編程語言(比如JavaScript,java,python)項目的話,其實很好理解變數、常量、數據類型和控制流。 變數也被稱為“變數”,是反映事物運動變化狀態的量,比如匯率、房貸利率、貸款利率。 常量也被稱“ ...
  • 一、函數名的應用 ​ 函數名的定義和變數的定義幾乎一致,在變數的角度,函數名其實就是一個變數,具有變數的功能:可以賦值;但是作為函數名他也有特殊的功能就是加上()就會執行對應的函數,所以我們可以把函數名當做一個特殊的變數 1、函數名指向的是函數的記憶體地址 ​ 函數名 + ()就可以執行次函數 def ...
一周排行
    -Advertisement-
    Play Games
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...