<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      從零開始制作 MyOS(一)

      從零開始制作 MyOS - 最簡單的操作系統內核

      開發環境

      1. 操作系統:ubuntu22 (windows10 + VMware15pro + ubunut22 + qemu)
      2. 編譯器:gcc-multilib
      3. 匯編器:nasm
      4. 模擬器: QEMU
      5. 版本控制: git

      安裝依賴

      ubuntu22 中:

      # 安裝必要的工具鏈
      sudo apt update
      sudo apt install -y build-essential
      sudo apt install -y qemu-system-x86 
      sudo apt install -y nasm    # x86架構匯編器
      sudo apt install -y gdb
      sudo apt install -y git
      sudo apt install -y mtools  # 用于制作磁盤鏡像
      
      # 安裝交叉編譯器(重要!避免使用宿主系統的libc)
      sudo apt install -y gcc-multilib
      

      前置知識

      1. x86 匯編語言:寄存器,實模式 vs 保護模式,中斷和異常,CPU 特權級
      2. C 語言編程
      3. 硬件基礎知識:
        • 引導過程:當你按下電源鍵時,發生了什么事
        • BIOS/UEFI:它們做了什么
        • 內存映射:硬件設備(如 VGA 顯存)在內存中的位置

      實模式 VS 保護模式

      實模式是處理器的初始狀態,能夠將內存視為連續的,無保護的物理空間,能夠通過簡單的算術運算擴展尋址范圍;而保護模式則是通過硬件強制實施內存訪問策略,將物理內存抽象成虛擬地址空間后的一種內存訪問模式。

      實模式下,程序能直接物理地址訪問,而內存訪問的范圍則是在 1MB,也就是 20 位地址線內,不支持多任務,也沒有內存保護。
      保護模式下,物理地址被抽象成虛擬內存,程序通過分段和分頁訪問,最高能訪問到 4GB 的內存范圍。

      保護模式是現代操作系統的基礎。

      計算機啟動過程

      當計算機上電后,位于 SPI Flash ROM 中的 BIOS 程序會被運行,該程序的任務是初始化計算的硬件,并且尋找可引導設備,這個可引導設備就是我們要開發的操作系統。

      BIOS 在扇區 0 中找到有效地可引導設備后,就會將 CPU 的控制權轉移過去,執行可引導設備程序。

      關于 BIOS 程序

      1. BIOS 引導程序物理存儲地址是在 SPI Flash ROM ,也就是 串行外設接口閃存只讀存儲器 ,這個存儲器是焊接在主板上,容量一般為 16 MB ~ 32 MB,斷電后不丟失數據。
      2. 在現代計算機中,傳統的 BIOS 被 UEFI,也叫做 統一可擴展固件接口替代,它的存儲位置也是在 SPI Flash 芯片中。
      3. 由硬件廠商開發,BIOS 廠商根據芯片廠商提供的規范來負責編寫 BIOS 代碼
      4. BIOS 的任務
        • 上電自檢:檢查關鍵硬件,包括 CPU,內存,芯片組等;然后初始化系統管理總線(SMBus),并且驗證硬件完整性和兼容性
        • 硬件初始化:設置 CPU 微代碼更新,配置內存控制器和時序參數,初始化 PCIe 設備枚舉,設置 USB,SATA 控制器
        • 運行時服務建立:創建中斷向量表,建立 BIOS 數據區,提供系統調用接口(INT,13h 磁盤服務等)

      第一步:制作一個最簡單的操作系統內核

      啟動電腦時,BIOS 會做自檢,然后找到第一個可以啟動的設備,讀取該設備的第一個扇區(512 字節),如果該扇區最后兩個字節是 0x55 和 0xAA,BIOS 會認為這是一個有效的引導扇區,并將其加載到內存 0x7c00 處執行。

      下面我們使用匯編程序編寫一個最簡單的引導程序,也就是一個 boot.asm :(必須使用匯編語言)

      ; boot.asm - simple BIOS boot sector (512 bytes)
      ; Assembled with: nasm -f bin -o boot.bin boot.asm
      
      org 0x7C00
      bits 16
      
      start:
          cli                 ; disable interrupts while setting up stack
          xor ax, ax
          mov ss, ax
          mov sp, 0x7C00      ; stack grows down from 0x7C00
          sti                 ; enable interrupts
      
          mov si, msg         ; pointer to message
      .print_char:
          lodsb               ; al = [si], si++
          cmp al, 0
          je .hang
          mov ah, 0x0E        ; BIOS teletype function
          mov bh, 0x00        ; page
          mov bl, 0x07        ; color/attribute (for teletype this selects fg color)
          int 0x10
          jmp .print_char
      
      .hang:
          cli
          hlt
          ; do not loop: single HLT to hang the CPU. If an interrupt occurs (shouldn't, because
          ; interrupts are disabled), execution could continue into the padding; we intentionally
          ; avoid an explicit jump here so the CPU remains halted instead of spinning.
      
      msg db "Hello, OS! Booted from boot.asm", 0
      
      ; pad to 510 bytes so that signature is at offset 510-511
      times 510 - ($ - $$) db 0
      dw 0xAA55
      
      
      # 編譯匯編文件
      nasm -f bin boot.asm -o boot.bin
      
      # 使用 QEMU 運行
      qemu-system-x86_64 boot.bin
      
      # vscode 終端 ssh 執行 QEMU 結果
      qemu-system-x86_64 -nographic -monitor none -serial mon:stdio -drive file=boot.bin,format=raw,index=0,if=floppy
      
      qemu-system-x86_64 -nographic -serial mon:stdio -drive format=raw,file=boot_serial.bin
      

      運行結果

      1. 會出現一個 QEMU 的黑屏窗口
      2. 打印出 “"Hello, OS! Booted from boot.asm"”

      qemu-system-x86_64 boot.bin

      代碼詳解

      boot.asm 文件都是匯編指令,下面對指令和它背后的意義做一個簡單介紹:

      1. boot.asm

      它是一個最小的 BIOS 引導扇區,做了以下工作:

      • 被 BIOS 加載到物理地址 0x0000:0x7C00(也就是線性地址 0x7C00)并從那里執行。
      • 在屏幕上打印一行文本(通過 BIOS int 0x10 teletype 服務)。
      • 進入 halt 循環停止執行。
      • 文件被填充到 512 字節并以 0x55AA 結尾(這是 BIOS 引導簽名)。

      代碼設計步驟:

      • org 0x7C00 + bits 16:引導扇區在實模式下,并且 BIOS 把第一個扇區加載到 0x0000:0x7C00,因此必須讓匯編器使用那個基址來生成正確的地址。
      • 填充到 512 字節并寫入 0x55AA:滿足 BIOS 的最小引導扇區約定。
      • 使用 BIOS int 服務(int 0x10)來打印:簡單、兼容且不需要直接操作視頻內存。
      • 設置棧:引導階段沒有默認可靠的棧,需要顯式設置以免后續調用/中斷出現問題。
      • 禁用/恢復中斷(cli/sti):在設置棧或初始化關鍵結構時防止中斷打斷(可以提高穩定性)。
      1. org 0x7C00
      • 告訴匯編器,代碼段在源代碼中被認為是從線性地址 0x7C00 開始的(即 BIOS 把扇區加載到內存 0x0000:0x7C00)
      1. bits 16
        指示 nasm 生成 16-bit 實模式編碼

      2. start
        程序入口點標簽(實際 BIOS 會跳轉到 0x7C00,所以這只是代碼中便于引用的標簽)

      3. xor ax, ax

      • ax 寄存器是
      • xor 是一個清零指令,
      • xor ax, ax 將 AX 清零(AX = 0),等同于指令 mov ax, 0,這里為接下來設 SS = 0 做準備
      1. mov ss, ax
      • mov 指令,匯編語言中的賦值指令,將后者的值賦值給前者
      • 為了設定棧使用的段,將 SS(棧段寄存器)設為 0x0000(因為 AX 清零)。
      • 注意:在實模式下修改 SS 要小心(最好在修改 SP 之前或配套操作)。
      1. mov sp, 0x7C00
      • 把棧指針 SP 設為 0x7C00(棧從 0x0000:0x7C00 向下增長)。
      • 必須設置棧,否則函數/中斷可能導致不可預期行為。
      • 把棧放在 0x7C00 是一種常見簡單做法(和引導扇區加載地址一致),但要確保不覆蓋自身代碼/數據
      • 如果后續會加載第二階段,可能選不同位置。
      1. sti
      • 允許中斷指令(Set Interrupt Flag)。
      • 一般和 cli 配套使用,在想要想讓 BIOS/硬件中斷產生的地方使用
      1. mov si, msg
      • 將 msg 值賦值給 si 寄存器,msg 本質是一個地址值,是一個存儲字符串區域的首地址。
      • 把 SI 指向數據標簽 msg,用于字符串讀取。
      1. .print_char
      • 一個循環標簽
      • jmp .print_char 配合該條指令實現循環功能
      1. lodsb
      • 從 [DS:SI] 處加載字節到 AL,然后 SI++(DS 默認是 0x0000,且 org 保證 msg 地址正確)。
      • 是一種簡潔的逐字節讀取方式。
      1. cmp al, 0
      • cmp 是一個比較指令;
      • 比較 al 寄存器的值是否為 0 .
      • 目的是檢查是否為字符串結束符(這里用 0 作為結束符)。
      • 用于結束循環。
      1. je .hang
      • 如果 AL==0,則跳到結束(hang)。
      1. mov ah, 0x0E
      • ah 寄存器是
      • 設置 BIOS int 0x10 的功能號為 teletype 輸出(TTY 輸出字符到當前光標并前進)。
      • 必須設 AH 才能讓 int 0x10 執行正確的子功能。
      1. mov bh, 0x00
      • 設置頁面號(page)。BIOS teletype 函數使用 BH 指定頁號(通常 0)。
      • 通常設為 0,是標準做法。
      1. mov bl, 0x07
      • BL 設置字體屬性/顏色
      • 盡管對于 teletype(0x0E)在傳統文本模式 BL 并非總必需,但設會更兼容某些 BIOS。
      1. int 0x10
      • int 指令為 BIOS 中斷指令
      • 調用 BIOS 視頻中斷,執行上面設置的 teletype 輸出(輸出 AL 中的字符)。
      • 必須使用 BIOS 中斷才能在實模式下不直接操作顯存也輸出字符(更簡單)。
      1. jmp .print_char
        作用:繼續循環輸出下一個字符。

      .hang:
          cli
          hlt
      
      • 進入禁中斷并執行 halt 指令,cpu 進入低功耗等待模式,然后跳回(確保 CPU 不會繼續向下執行垃圾代碼)。
      • 需要一個安全的結束點而不返回到隨機內存。hlt 比不停循環省電;
      • cli+hlt 防止來自中斷的喚醒(但會阻塞直到外部復位),加上 jump 可在某些環境下避免返回到可能是可執行的區域。
      1. msg db "Hello, OS! Booted from boot.asm", 0
      • 定義以 0 結尾的字符串數據,打印時 lodsb 逐字節讀取直到 0。
      times 510 - ($ - $$) db 0
      
      • 把文件填充到偏移 510(即文件前 510 個字節有效,接下來 2 字節用來放簽名)。
      • 必須讓整個扇區達到 512 字節,使得簽名位于正確偏移。
      1. dw 0xAA55
      • 寫入引導簽名 0x55AA(注意小端序寫入會在磁盤上以 55 AA 的順序保存)。
      • BIOS 在嘗試從介質引導時會檢查每個扇區末尾的 0x55AA 來判定該扇區是否為引導扇區;缺失此簽名通常導致 BIOS 忽略該鏡像作為引導設備。

      使用串口輸出(boot_serial.asm)

      在沒有圖形界面的環境下,推薦用串口輸出調試和顯示信息。下面詳細介紹串口初始化涉及的寄存器和每一步的作用。

      串口輸出代碼結構

      start:
          cli
          xor ax, ax
          mov ss, ax
          mov sp, 0x7C00
          sti
          call init_serial         ; 初始化串口
          mov si, msg
      .print_loop:
          lodsb
          cmp al, 0
          je .hang
          call serial_putchar      ; 發送 AL 到串口
          jmp .print_loop
      .hang:
          cli
          hlt
      
      ; 串口初始化例程 (COM1, 38400 8N1)
      init_serial:
          ; 設置 IER = 0 (禁用中斷)
          mov dx, 0x3F8      ; COM1 base port
          mov al, 0x00
          add dx, 1
          out dx, al
          sub dx, 1
          ; 設置 DLAB = 1,準備設置分頻器
          mov dx, 0x3F8
          add dx, 3
          mov al, 0x80       ; LCR: DLAB=1
          out dx, al
          sub dx, 3
          ; 設置波特率分頻器 (38400)
          mov dx, 0x3F8
          mov al, 3          ; divisor low byte
          out dx, al
          inc dx
          mov al, 0          ; divisor high byte
          out dx, al
          dec dx
          ; 設置 LCR = 8N1 (8位,無校驗,1停止位)
          mov dx, 0x3F8
          add dx, 3
          mov al, 0x03       ; LCR: DLAB=0, 8N1
          out dx, al
          sub dx, 3
          ; 啟用 FIFO
          mov dx, 0x3F8
          add dx, 2
          mov al, 0xC7       ; FCR: 啟用FIFO,清空,14字節閾值
          out dx, al
          sub dx, 2
          ; 設置 MCR (RTS/DSR/OUT2)
          mov dx, 0x3F8
          add dx, 4
          mov al, 0x0B       ; MCR: IRQs enabled, RTS/DSR set
          out dx, al
          sub dx, 4
          ret
      
      ; 串口發送單字符例程 (AL)
      serial_putchar:
          push dx
          push ax
          mov dx, 0x3F8
          add dx, 5           ; LSR port
      .wait_lsr:
          in al, dx
          test al, 0x20       ; 檢查 THRE (發送寄存器空)
          jz .wait_lsr
          pop ax              ; 恢復要發送的字符到 AL
          mov dx, 0x3F8       ; 數據端口
          out dx, al
          pop dx
          ret
      
      msg db "Hello, OS! Booted to serial from boot_serial.asm", 0
      

      串口初始化步驟與寄存器說明

      PC 的標準串口 COM1 基地址是 0x3F8,串口芯片(16550A)有多個寄存器,分別控制不同功能:

      1. 數據端口 (Data Register, 0x3F8)
        • 用于收發數據。寫入一個字節即可發送。
      2. 中斷使能寄存器 (IER, 0x3F9)
        • 控制串口中斷。我們設置為 0,禁用所有串口中斷。
      3. 分頻器鎖存寄存器 (DLL/DLM, 0x3F8/0x3F9, 需 DLAB=1)
        • 設置波特率。波特率 = 基準頻率 / 分頻值。常見基準頻率為 115200Hz,分頻值為 3,則波特率為 38400。
        • DLL (低字節) 寫入 3,DLM (高字節) 寫入 0。
      4. 線路控制寄存器 (LCR, 0x3FB)
        • 控制數據位、停止位、校驗位和 DLAB 位。
        • DLAB=1 時可設置分頻器,DLAB=0 時正常通信。
        • 設置為 0x03 表示 8位數據,無校驗,1停止位(8N1)。
      5. FIFO 控制寄存器 (FCR, 0x3FA)
        • 控制 FIFO 緩沖區。0xC7 啟用 FIFO,清空緩沖,設置 14字節閾值。
      6. 調制解調器控制寄存器 (MCR, 0x3FC)
        • 控制 RTS/DSR/OUT2 等信號。0x0B 啟用 IRQs,設置 RTS/DSR。
      7. 線路狀態寄存器 (LSR, 0x3FD)
        • 只讀。用于檢測發送寄存器是否空(THRE 位,0x20)。發送前需輪詢該位。

      串口發送字符流程

      • 發送字符前,先輪詢 LSR 的 THRE 位,確保發送寄存器空。
      • 然后將要發送的字符寫入數據端口 (0x3F8)。
      • 這樣可以保證數據不會丟失。

      編譯和運行

      nasm -f bin boot_serial.asm -o boot_serial.bin
      qemu-system-x86_64 -nographic -serial mon:stdio -drive format=raw,file=boot_serial.bin
      

      運行效果

      • 如果一切正常,你會在終端看到:

        Hello, OS! Booted to serial from boot_serial.asm

      • 如果沒有輸出,請檢查 boot_serial.asm 是否正確生成、QEMU 參數是否正確、串口初始化代碼是否有誤。


      總結:

      • 串口輸出適合無頭環境、遠程調試、嵌入式開發。
      • 代碼中每一步都對應串口芯片的硬件寄存器設置,理解這些寄存器有助于后續開發更復雜的 bootloader 和內核調試功能。
      posted @ 2025-10-22 16:33  王清河  閱讀(22)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 欧美精品高清在线观看| 中国china体内裑精亚洲日本| 一级女性全黄久久片免费 | 亚洲一区成人在线视频| 老熟妇老熟女老女人天堂| 精品久久久久中文字幕APP| 国产色悠悠在线免费观看| 国产亚洲人成网站在线观看 | 色午夜久久男人操女人| 无码视频一区二区三区| 成在线人永久免费视频播放| 亚洲最大激情中文字幕| www亚洲精品| 久久青草国产精品一区| 欧美疯狂xxxxbbbb喷潮| 1区2区3区4区产品不卡码网站| 久激情内射婷内射蜜桃| 国内精品久久久久电影院| 午夜无码免费福利视频网址| 久久综合色最新久久综合色| 熟女人妻视频| 亚洲国产综合性亚洲综合性| 久久99国产乱子伦精品免费| 亚洲永久精品日韩成人av| 平山县| 久久亚洲精品无码播放| 欧洲一区二区中文字幕| 女高中生强奷系列在线播放| 丰满的少妇一区二区三区| 国产99在线 | 免费| 免费天堂无码人妻成人av电影 | 久久精品国产蜜臀av| 成人国产精品一区二区网站公司| 四虎在线成人免费观看| 久久精品手机观看| 国产成人av免费观看| 在线日韩日本国产亚洲| 国精品午夜福利不卡视频| 亚洲国产一区二区三区久| 亚洲欧美日韩综合久久| 成人午夜国产内射主播|