OS架構整理

OS架構整理

  • 引導啟動部分
    • bios bootloader區別
    • 啟動流程(x86 BIOS 啟動):
    • bios
    • boot_loader
      • 3.切換進保護模式
        • 實模式的限制
        • 如何切換進保護模式
      • 加載kernel到內存地址1M
      • 加載內核映像文件
      • elf
  • 一些基礎知識
    • 鏈接腳本與代碼數據段
      • 創建GDT表
        • 段頁式內存管理
    • 顯示字符串
    • bios中斷向量表中來顯示
    • 內聯匯編來顯示

引導啟動部分

bios bootloader區別

[BIOS] (硬件開機,里面有寫好的固件,上電自檢)↓ 讀取硬盤第0扇區 → 加載到內存地址 0x7C00
[boot] (512字節以內的 MBR/bootloader階段1)(因為只有512字節,太小了所以用了二級引導)↓ 加載并跳轉到更復雜的 loader(通常是 2階)
[loader] (多段程序,支持文件系統、內核加載等)↓ 加載操作系統內核(kernel)
[OS內核] (操作系統正式啟動)

在這里插入圖片描述
前三步是我們自己控制不了的
我的代碼是從磁盤加載
在這里插入圖片描述

啟動流程(x86 BIOS 啟動):

在這里插入圖片描述
這個第0扇區的代碼需要自己去寫
首先Bios上電自檢,然后將磁盤的第一個扇區512字節放入到內存地址0x7c00,檢查是否以0x55 0xaa結束,從而判斷這是否是有效的MBR
,如果是的話就進行引導

bios

  1. 加電啟動(Power On)
  2. BIOS 執行 POST(Power-On Self-Test)
  3. 搜索可啟動設備(硬盤、U盤、光盤…)
  4. 找到啟動設備后:
    • 讀取該設備的 第 1 個扇區(LBA 0,大小 = 512 字節)
    • 把它加載到內存地址 0x0000:0x7C00(實地址 = 0x7C00
  5. 檢查最后兩個字節是否為 0x55AA(有效的引導扇區簽名)
  6. 如果正確 → 跳轉到 0x7C00 執行

在 BIOS 啟動模式中,BIOS 會將硬盤的 第 0 扇區(MBR)加載到 0x7C00,并從那里開始執行。

讀取磁盤又兩種方式
一種是int13(bios)
一種是LAB(復雜一點,在loader中實現)

x86在上電后自動進入實模式,1m內存 無分頁機制 寄存器也只能用16位
但是1m內存的話要訪問完需要20位地址,我們就是將段基址<<4+偏移構成20位
段基址的值是存在CS/DS/SS/ES/FS/GS(段寄存器)中
這個實模式下1M大小的內存映射情況:
在這里插入圖片描述
我的boot是在start.s中寫的
boot的初始化: 主要就是將段寄存器先賦初值0,簡化代碼,棧頂指針賦值0x7c00,表示我的boot在0x7c00地址以下的棧區,大概30kb左右是滿足這個大小的
boot跳轉到loader二級引導
在這里插入圖片描述
在這里插入圖片描述

讀取多個磁盤加載到內存地址上:用了bios中斷向量表 0x13 從第一個扇區開始 分配64個扇區(大概32kb) 如果讀取磁盤正確后進入C環境并跳轉到loader(jmp或者call)
在這里插入圖片描述
.extern C函數名字(boot的一個跳轉函數)

boot_loader

在這里插入圖片描述

cmake的鏈接器表示我loader 加載到0x8000的地址,start.s放在cmake加入的工程文件的最開頭,這樣就可以保證加載到0x8000時在start.s
在這里插入圖片描述

因為512字節顯然比較小,沒辦法完成這么多功能,所以我做了一個二級引導
1.內聯匯編顯示字符串
2.檢測內存容量 0x15(boot_info)
在這里插入圖片描述
檢測10塊可用內存區域

3.切換進保護模式

實模式的限制

1.只能訪問1MB內存,內核寄存器最大為16位寬
2.所有的操作數最大為16位寬
3.沒有任何保護機制
4.沒有特權級支持
5.沒有分頁機制和虛擬內存的支持

如何切換進保護模式

在這里插入圖片描述

首先保證過程原子性,禁用中斷,然后打開A20地址線讓其訪問1m以上的內存地址,然后初始化加載GDT表保證開啟保護模式寄存器值正常,再設置CR0 PE位,開啟保護模式。

這個禁用中斷的函數我也寫了一個函數,保存關中斷前的各個寄存器的狀態(eflags等),完成實模式到保護模式切換后恢復到原來的狀態,這個函數再后面的也可以用到。函數中我也用到了內聯匯編函數 sti cli進行開關中斷.

加載kernel到內存地址1M

在loader中實現LAB讀取磁盤,(一次兩字節讀取)(通常512字節一次性讀取)

#define SYS_KERNEL_LOAD_ADDR		(1024*1024)		// 內核加載的起始地址(此時打開了A20地址線和保護模式,可以訪問1M以上空間
static void read_disk(int sector, int sector_count, uint8_t * buf)
名稱含義單位
sector起始扇區號(LBA)扇區(512 字節)
sector_count連續讀取的扇區數量扇區(512 字節)

創建kernel文件夾,同樣cmake設置起始位置1M
在這里插入圖片描述
在這里插入圖片描述
棧的作用:C的局部變量,函數調用中的參數
在保護模式下 push pop的一個棧都是4個字節
esp是棧頂指針 ebp相對比較固定。ESP 指向當前棧頂,EBP 保存的是上一個調用幀的基地址(上一個函數的棧底基準)

我在loader32.c中寫了 ((void (*)(boot_info_t *))kernel_entry)(&boot_info); 然后進入kernel1M地址,

		push %ebpmov %esp, %ebpmov 0x8(%ebp), %eaxpush %eaxcall kernel_init

取出boot_info參數傳給kernel_init函數void kernel_init (boot_info_t * boot_info)(函數指針) 我沒用全局變量不依賴任何外部狀態,bootloader 和 kernel解耦,可移植性強。

我再講解下這個loader的這個函數指針:(為了跳到kernel_entry(裸地址0x100000)并傳入參數boot_info

部分解釋
void (*)(boot_info_t *)一個函數指針類型,指向接受一個 boot_info_t * 參數、返回 void 的函數
(void (*)(boot_info_t *))kernel_entrykernel_entry 強制轉換為這種函數指針類型
((...))(&boot_info)把這個函數指針當成函數調用,傳入參數 &boot_info

加載內核映像文件

在這里插入圖片描述
改一下kernel.lds和loader32.c中跳轉到kernel的函數指針的裸地址改一下0x100000 改為0x1000

elf

elf更小,并且可以進行權限設置。
elf是一種通用的可執行文件格式,操作系統內核是程序邏輯,elf是其封裝形式,方便bootloader加載執行。
這個elf文件是我的c、匯編寫的內核編譯出來的最終可執行映像。
在這里插入圖片描述
查看手冊把elf_header和program_header的結構放在elf.h中
在loader32.c中寫了一個加載elf的函數,首先要進行魔術驗證,0x7F ‘E’ ‘L’ 'F’開頭,判斷其是否合法。將elf里面的內容提取到指定的物理地址,做好初始化(比如bss通常是未初始化的參數,初始化為0),最后跳轉到elf的入口地址(return elf_hdr->e_entry;)。然后將e_entry這個elf入口地址作為loader的跳轉地址(剛剛我們改的裸地址就可以改成e_entry)
從而跳轉到kernel內核。
在這里插入圖片描述

一些基礎知識

鏈接腳本與代碼數據段

先看一個具體的
在這里插入圖片描述
有下面的一個順序
在這里插入圖片描述
為什么會這么放呢?
下面是一個測試
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
當我們建立了kernel.lds就不用在每個文件夾下的cmake -text進行設置 告訴編譯器這些分別放在哪
在這里插入圖片描述

創建GDT表

段描述符 結構的主要是和cpu有關,就放在kernel的include文件下cpu.h里面。
GDT表就放在cpu.c中

段頁式內存管理

在這里插入圖片描述
在這里插入圖片描述

我們先關注分段存儲
在這里插入圖片描述
段頁式內存管理第一部分:邏輯地址 → 線性地址
我采用的是平坦模型(base address = 0,offset的limit可以覆蓋整個4GB空間),選擇子在GDT查表得到基地址,然后和偏移量相加得到線性地址。
換而言之:線性地址 = offset (因為 base = 0)
在這里插入圖片描述
但是我仍需要設置GDT表:

gdt:(參考下面段描述符).quad 0                       ; 空描述符.quad 0x00CF9A000000FFFF      ; 代碼段:base=0, limit=4GB.quad 0x00CF92000000FFFF      ; 數據段:base=0, limit=4GB

其中limit有20位(高 4 + 低 16),雖然 limit 字段最大只能表示 0xFFFFF(1MB),但段描述符中還有一個 “粒度位(G bit)”,它決定 limit 的單位是字節還是 4KB。如果是4KB*1MB=4GB 因此段限長可以設置為4GB,從而實現平坦系統。

總結一下內存訪問整體流程:
在這里插入圖片描述

下面是對段描述符,GDT結構 處理上的詳細介紹:

段描述符:
在這里插入圖片描述
在這里插入圖片描述

/*** GDT描述符(其實就是段描述符)*/
typedef struct _segment_desc_t {uint16_t limit15_0;uint16_t base15_0;uint8_t base23_16;uint16_t attr;uint8_t base31_24;
}segment_desc_t;

主要分成三個部分limit base attr

/*** 設置段描述符*/
void segment_desc_set(int selector, uint32_t base, uint32_t limit, uint16_t attr) {segment_desc_t * desc = gdt_table + (selector >> 3);// 如果界限比較長,將長度單位換成4KBif (limit > 0xfffff) {attr |= 0x8000;limit /= 0x1000;}desc->limit15_0 = limit & 0xffff;desc->base15_0 = base & 0xffff;desc->base23_16 = (base >> 16) & 0xff;desc->attr = attr | (((limit >> 16) & 0xf) << 8);desc->base31_24 = (base >> 24) & 0xff;
}/*** 然后利用set函數初始化GDT*/
void init_gdt(void) {// 全部清空for (int i = 0; i < GDT_TABLE_SIZE; i++) {segment_desc_set(i << 3, 0, 0, 0);}//數據段segment_desc_set(KERNEL_SELECTOR_DS, 0x00000000, 0xFFFFFFFF,SEG_P_PRESENT | SEG_DPL0 | SEG_S_NORMAL | SEG_TYPE_DATA| SEG_TYPE_RW | SEG_D | SEG_G);// 只能用非一致代碼段,以便通過調用門更改當前任務的CPL執行關鍵的資源訪問操作segment_desc_set(KERNEL_SELECTOR_CS, 0x00000000, 0xFFFFFFFF,SEG_P_PRESENT | SEG_DPL0 | SEG_S_NORMAL | SEG_TYPE_CODE| SEG_TYPE_RW | SEG_D | SEG_G);// 調用門gate_desc_set((gate_desc_t *)(gdt_table + (SELECTOR_SYSCALL >> 3)),KERNEL_SELECTOR_CS,(uint32_t)exception_handler_syscall,GATE_P_PRESENT | GATE_DPL3 | GATE_TYPE_SYSCALL | SYSCALL_PARAM_COUNT);// 加載gdtlgdt((uint32_t)gdt_table, sizeof(gdt_table));
}

其中selector >> 3才能表示GDT的索引,因為選擇子selector 是16位,結構包括 Index(段描述符索引)、TI(表選擇標志1位)和 RPL(請求者特權級2位),所以通過選擇子查找GDT中的索引需要右移3位。

有的同學可能會疑惑,進入保護模式CS/DS/SS等端寄存器不是從16位變成32位了嗎?
事實上每個段寄存器(如CS、DS、SS、ES、FS、GS)在保護模式下實際上分為兩部分,其中“隱藏部分”,保存了段基址、限長、權限等完整段描述符信息,這部分可能是32 位甚至 64 位。

部分說明
可見部分16 位選擇子(selector)
隱藏部分段描述符緩存(base、limit、access rights)

顯示字符串

bios中斷向量表中來顯示

0x10

內聯匯編來顯示

也是用的bios中斷進行顯示的

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917107.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917107.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917107.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【WRF-Chem第二期】WRF-Chem有關 namelist 詳解

目錄namelist 選項&#xff1a;chem_opt 的選擇其他化學相關的 namelist 選項氣溶膠光學屬性與輸出邊界與初始條件配置&#xff08;氣體&#xff09;參考本博客詳細介紹 WRF-Chem有關 namelist 選項。 namelist 選項&#xff1a;chem_opt 的選擇 chem_opt 是什么&#xff1f;…

STM32-USART串口實現接收數據三種方法(1.根據\r\n標志符、2.空閑幀中斷、3.根據定時器輔助接收)

本章概述思維導圖&#xff1a;USART串口初始化配置串口初始化配置在&#xff08;STM32-USART串口初始化章節有詳細教程配置&#xff09;&#xff0c;本章不做講解直接代碼示例&#xff0c;本章重點在于串口實現接收數據三種方法&#xff1b;配置USART1串口接收初始化函數步驟&a…

【NLP輿情分析】基于python微博輿情分析可視化系統(flask+pandas+echarts) 視頻教程 - 微博評論數據可視化分析-點贊區間折線圖實現

大家好&#xff0c;我是java1234_小鋒老師&#xff0c;最近寫了一套【NLP輿情分析】基于python微博輿情分析可視化系統(flaskpandasecharts)視頻教程&#xff0c;持續更新中&#xff0c;計劃月底更新完&#xff0c;感謝支持。今天講解微博評論數據可視化分析-點贊區間折線圖實現…

Unity_SRP Batcher

SRP Batcher 全面解析&#xff1a;原理、啟用、優化與調試一、什么是 SRP Batcher&#xff1f;SRP Batcher 是 Unity Scriptable Render Pipeline&#xff08;URP、HDRP 或自定義 SRP&#xff09; 專屬的 CPU 渲染性能優化技術&#xff0c;核心目標是 減少材質切換時的 CPU 開銷…

詳解Vite 配置中的代理功能

在前端開發過程中&#xff0c;你可能經常會遇到一個頭疼的問題&#xff1a;當你在本地啟動的前端項目中調用后端接口時&#xff0c;瀏覽器控制臺會報出類似 “Access to fetch at ‘http://xxx’ from origin ‘http://localhost:3000’ has been blocked by CORS policy” 的錯…

理解梯度在神經網絡中的應用

梯度&#xff08;Gradient&#xff09;是微積分中的一個重要概念&#xff0c;廣泛應用于機器學習和深度學習中&#xff0c;尤其是在神經網絡的訓練過程中。下面將從梯度的基本概念、其在神經網絡中的應用兩個方面進行詳細介紹。一、梯度的基本概念 1.1 什么是梯度&#xff1f; …

WPF,按鈕透明背景實現MouseEnter

在幫手程序&#xff08;assister.exe&#xff09;中&#xff0c;可以點擊錄制按鈕&#xff0c;實現錄制用戶操作直接生成操作列表。而在彈出錄制按鈕的懸浮窗中&#xff0c;需要能夠拖動錄制按鈕放置在任意的位置&#xff0c;以免阻擋正常的窗口。具體功能是&#xff0c;當鼠標…

【抄襲】思科交換機DAI(動態ARP監控)配置測試

一.概述 1.DAI作用 ①.使用DAI&#xff0c;管理員可以指定交換機的端口為信任和非信任端口&#xff1a; 信任端口可以轉發任何ARP信息 非信任端口的ARP消息要進行ARP檢測驗證 ②.交換機執行如下的ARP驗證&#xff1a; 靜態ARP監控&#xff1a;為一個靜態的IP地址配置一個靜態AR…

在嵌入式系統或 STM32 平臺中常見的外設芯片和接口

在嵌入式系統或 STM32 平臺中常見的 外設芯片 或 模塊名稱&#xff0c;包括&#xff1a; &#x1f4fa; 顯示驅動&#xff08;如 ST7735、OTM8009A、NT35510&#xff09;&#x1f4f7; 攝像頭模組&#xff08;如 OV5640、OV9655、S5K5CAG&#xff09;&#x1f4be; Flash 存儲器…

AI 類型的 IDE

指集成了 AI 輔助編程能力的集成開發環境 一、代碼輔助生成 ? 自動補全&#xff08;更智能&#xff09; 比傳統 IDE 更智能&#xff0c;理解上下文&#xff0c;生成整個函數/模塊 示例&#xff1a;根據函數名 calculateTax 自動生成稅務計算邏輯 ? 函數 / 類自動生成 給…

JP3-3-MyClub后臺后端(一)

Java道經 - 項目 - MyClub - 后臺后端&#xff08;一&#xff09; 傳送門&#xff1a;JP3-1-MyClub項目簡介 傳送門&#xff1a;JP3-2-MyClub公共服務 傳送門&#xff1a;JP3-3-MyClub后臺后端&#xff08;一&#xff09; 傳送門&#xff1a;JP3-3-MyClub后臺后端&#xff08;…

架構實戰——互聯網架構模板(“存儲層”技術)

目錄 一、SQL 二、NoSQL 三、小文件存儲 四、大文件存儲 本文來源:極客時間vip課程筆記 一、SQL SQL 即我們通常所說的關系數據。前幾年 NoSQL 火了一陣子,很多人都理解為 NoSQL 是完全拋棄關系數據,全部采用非關系型數據。但經過幾年的試驗后,大家發現關系數據不可能完全被…

CentOS7.9在線部署Dify

一、CentOS7.9安裝dify 二、檢查是否安裝dcoker docker --version2.1下載后將安裝包上傳至服務器對應文件夾下,我選在放在了 /root文件夾下 cd /root2.2 上傳至服務器 cd /root #對應目錄下tar -xvf docker-26.1.4.tgz # 解壓安裝包:chmod 755 -R docker # 賦予可執…

深入淺出C語言指針:從數組到函數指針的進階之路(中)

指針是C語言的靈魂&#xff0c;也是初學者最頭疼的知識點。它像一把鋒利的刀&#xff0c;用得好能大幅提升代碼效率&#xff0c;用不好則會讓程序漏洞百出。今天這篇文章&#xff0c;我們從數組與指針的基礎關系講起&#xff0c;一步步揭開指針進階類型的神秘面紗&#xff0c;最…

java web Cookie處理

java web 設置cookie更改啟動端口// Directory tree (5 levels) ├── src\ │ ├── a.txt │ └── com\ │ └── zhang\ │ └── ServletContext\ │ ├── cookie\ │ └── servletContext.java └── web\├─…

機器學習—線性回歸

一線性回歸線性回歸是利用數理統計中回歸分析&#xff0c;來確定兩種或兩種以上變量間相互依賴的定量關系的一種統計分析方法。相關關系&#xff1a;包含因果關系和平行關系因果關系&#xff1a;回歸分析【原因引起結果&#xff0c;需要明確自變量和因變量】平行關系&#xff1…

Spring Boot Admin 監控模塊筆記-實現全鏈路追蹤

一、概述Spring Boot Admin&#xff08;SBA&#xff09;是一個用于監控和管理 Spring Boot 應用程序的工具。它提供了一個 Web 界面&#xff0c;可以集中管理多個 Spring Boot 應用程序的健康狀態、指標、日志、配置等信息。通過 SBA&#xff0c;你可以輕松地監控和管理你的微服…

容器化與Docker核心原理

目錄 專欄介紹 作者與平臺 您將學到什么&#xff1f; 學習特色 容器化與Docker核心原理 引言&#xff1a;為什么容器化成為云計算時代的基石&#xff1f; 容器化技術全景與Docker核心原理&#xff1a;從概念到實踐 文章摘要 1. 引言&#xff1a;為什么容器化成為云計算…

掌握Python三大語句:順序、條件與循環

PS不好意思各位&#xff0c;由于最近筆者在參加全國大學生電子設計大賽&#xff0c;所以最近會出現停更的情況&#xff0c;望大家諒解&#xff0c;比賽結束后我會加大力度&#xff0c;火速講Python的知識給大家寫完&#x1f396;?&#x1f396;?&#x1f396;?&#x1f396;…

JAVA結合AI

Java 與人工智能&#xff08;AI&#xff09;的結合正經歷從技術探索到深度融合的關鍵階段。以下從技術生態、應用場景、工具創新、行業實踐及未來趨勢五個維度展開分析&#xff0c;結合最新技術動態與企業級案例&#xff0c;揭示 Java 在 AI 時代的獨特價值與發展路徑。一、技術…