Chapter 03-1:Privilege Level Switching === :::info GDT 遠比我們想的更加複雜,為了能更加深刻理解 GDT 的運作,我們另外設計測試程式來幫助我們更好理解 GDT 的運作。 &emsp; 1. GDT Basic。 &emsp; 2. Ring 0 to Ring 3: retf。 &emsp; 3. Call Gate。 &emsp; 4. Ring 3 to Ring 0: Call Gate and TSS。 ::: >[time=Tue, Sep 2, 2025 5:43 PM] --- https://youtu.be/zVd-MjakdEI <iframe width="560" height="315" src="https://www.youtube.com/embed/zVd-MjakdEI?si=UEEnLkdblOv7rluZ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> >Reference: [利用Call Gate與TSS (Task-State Segment)實現特權等級的轉換](https://jasonblog.github.io/note/os/1417.html) >這個參考文件寫得相當好,而且也有搭配清晰的圖作為輔助。 # GDT Basic >Reference:[Segment-Level Protection](https://pdos.csail.mit.edu/6.828/2004/readings/i386/s06_03.htm) 主要會做以下保護以及確認: * Type checking:Code segment or data segment。 * Limit checking * Privilege Levels * Accessing Data in Data Segments ![截圖 2025-09-06 凌晨1.30.47](https://hackmd.io/_uploads/rkvDAqdqll.png) * Restricting Control Transfers ![截圖 2025-09-06 凌晨1.33.23](https://hackmd.io/_uploads/S1GWyjdcxg.png) :::warning CPL: 特指 CS 當前的特權級。 RPL: Selector 裡面 RPL 欄位的特權級。 DPL: 在 GDT descriptor 裡面描述 segment 的特權級。 ::: >[!Note] Memory Layout >![截圖 2025-09-06 凌晨1.20.11](https://hackmd.io/_uploads/BJlZhqOclg.png) >[!Note] Code Flow >![截圖 2025-09-06 凌晨1.24.58](https://hackmd.io/_uploads/BJ176cO9gx.png) ## Source Code https://github.com/srhuang/a-os/commit/c548634472f9af6958f309103a59d263809ba580 ## Compile ```sh nasm boot/loader.s -I boot/ -o out/loader.bin ``` ## Put on hard disk ```sh dd if=../code/out/loader.bin of=./60mb.img bs=512 count=4 seek=1 conv=notrunc ``` ## Checkpoint ![截圖 2025-09-04 凌晨1.18.11](https://hackmd.io/_uploads/BkGOOgIcee.png) ![截圖 2025-09-04 凌晨4.42.00](https://hackmd.io/_uploads/HyjnOQ8ceg.png) # Ring 0 to Ring 3 >[!Caution] CPU 原生設計是不允許高特權往低特權跳轉,唯一的方式就是使用 retf 的方式跳轉。 在 x86 的 inter-privilege-level far return (retf 但 RPL ≠ CPL) 的情況下,處理器會從 堆疊中依序 pop 這些東西: * IP / EIP → return address (指令指標) * CS → return code segment * SP / ESP → 呼叫者的 stack pointer * SS → 呼叫者的 stack segment 👉 所以會 pop 4 個項目(IP、CS、SP、SS),而不是一般情況下的 2 個(IP、CS)。 ```asm=171 push SELECTOR_B_STACK ; stack segment push B_STACK_TOP ; top of stack push SELECTOR_B_CODE ; code segment push 0 ; EIP retf ``` >[!Note] Memory Layout >![截圖 2025-09-06 凌晨1.11.48](https://hackmd.io/_uploads/r1mG99d5le.png) >[!Note] Code Flow >![截圖 2025-09-06 凌晨1.16.08](https://hackmd.io/_uploads/HJDli5_5lx.png) ## Source Code https://github.com/srhuang/a-os/commit/a4d7ff54c13b819f533eff0a51c376d5511f57db ## Compile ```sh nasm boot/loader.s -I boot/ -o out/loader.bin ``` ## Put on hard disk ```sh dd if=../code/out/loader.bin of=./60mb.img bs=512 count=4 seek=1 conv=notrunc ``` ## Checkpoint ![截圖 2025-09-04 晚上10.26.52](https://hackmd.io/_uploads/rkRpZQD5gx.png) ![截圖 2025-09-04 晚上10.31.47](https://hackmd.io/_uploads/S14iXQvqxg.png) # Call Gate >[!Tip] 這邊展示的是沒有特權級轉換的 call gate,下部分才會展示有特權級轉換的 call gate。 >[!Note] Call Gate Descriptor >![截圖 2025-09-05 凌晨2.20.27](https://hackmd.io/_uploads/SyqKOIv5gg.png) >DWORD COUNT: This field specifies the number of doublewords (DWORDs) to copy from the caller's stack to the new stack associated with the higher privilege level. >在特權等級轉換的情況下,主要是用做參數的傳遞。 >[!Note] Memory Layout >![截圖 2025-09-06 凌晨12.58.08](https://hackmd.io/_uploads/SygaL9_9gl.png) >[!Note] Code Flow >![截圖 2025-09-06 凌晨1.01.25](https://hackmd.io/_uploads/BkqFPc_5xx.png) ## Source Code https://github.com/srhuang/a-os/commit/4ad72ddab1af6db2d6b421406c4407565a33b66c ## Compile ```sh nasm boot/loader.s -I boot/ -o out/loader.bin ``` ## Put on hard disk ```sh dd if=../code/out/loader.bin of=./60mb.img bs=512 count=4 seek=1 conv=notrunc ``` ## Checkpoint ![截圖 2025-09-05 凌晨2.24.24](https://hackmd.io/_uploads/SJhtYLvqeg.png) ![截圖 2025-09-05 凌晨2.28.30](https://hackmd.io/_uploads/S1XZiIPcgg.png) # Ring 3 to Ring 0 >[!Tip] 我們會使用 call gate 來進行低特權往高特權跳轉,低特權跳轉高特權還需要 TSS 的協助。 >Reference: >[利用Call Gate與TSS (Task-State Segment)實現特權等級的轉換](https://jasonblog.github.io/note/os/1417.html) >[Task State Segment](https://pdos.csail.mit.edu/6.828/2004/readings/i386/s07_01.htm) >[!Note] TSS data structure >![截圖 2025-09-05 凌晨4.09.22](https://hackmd.io/_uploads/rk1Qz_v9gl.png) >[!Note] TSS Descriptor >![截圖 2025-09-05 凌晨4.27.09](https://hackmd.io/_uploads/Hy3EU_D9ee.png) >[!Note] LTR: load Task Register >![截圖 2025-09-06 下午5.03.16](https://hackmd.io/_uploads/HkKZF_tceg.png) >[!Note] Memory Layout >![截圖 2025-09-06 凌晨12.17.43](https://hackmd.io/_uploads/ByuHpK_9el.png) >[!Note] Code Flow >![截圖 2025-09-06 下午5.01.12](https://hackmd.io/_uploads/SJ29__F9xx.png) ## Source Code https://github.com/srhuang/a-os/commit/461fe96aaa305dd2707922cd39dd45f7fb3fca97 ## Compile ```sh nasm boot/loader.s -I boot/ -o out/loader.bin ``` ## Put on hard disk ```sh dd if=../code/out/loader.bin of=./60mb.img bs=512 count=4 seek=1 conv=notrunc ``` ## Checkpoint ![截圖 2025-09-05 下午4.39.15](https://hackmd.io/_uploads/rk7AWmO9xg.png) ![截圖 2025-09-05 下午4.34.00](https://hackmd.io/_uploads/SJp8b7Ocle.png) 觀察 stack pointer(SP) 的變化。 ![截圖 2025-09-15 下午3.09.59](https://hackmd.io/_uploads/rJmZhVBjll.png)