書裏還用 320 * 200 圖形模式,太老舊了。如今的顯卡都是超級顯卡,模擬器也支持超級顯卡,得用 VBE 才行。把用得上的 VBE 的幾個函數(就是中斷)貼出來,關鍵信息翻譯成中文了。數組
; VBE 函數 ; 在實模式下經過 0x10 中斷調用。 ; VBE : VESA BIOS Extension ; VESA : Video Electronics Standards Association(視頻電子標準協會) ; ; 一、Return VBE Controller Information(返回 VBE 控制器信息) ; Input: ; AX = 0x4F00 ; ES : DI = Pointer to buffer in which to place VbeInfoBlock structure ; (指向存放 VbeInfoBlock 結構體的緩衝區指針) ; VbeInfoBlock 結構體 ; 名稱 偏移 長度 內容 ; VbeSignature 0x00 4 VBE Signature(VESA 簽名,= "VESA") ; VbeVersion 0x04 2 VBE Version(VESA 版本,0x0200 = 2.00) ; OemStringPtr 0x06 4 VbeFarPtr to OEM String(指向 OEM 信息的遠指針, ; selector : offset 形式,用於識別圖形控制器芯片、驅動等) ; Capabilities 0x0A 4 Capabilities of graphics controller ; VideoModePtr 0x0E 4 VbeFarPtr to VideoModeList(指向圖形模式列表的 ; 遠指針,selector : offset 形式) ; TotalMemory 0x12 2 Number of 64kb memory blocks(V2.0+支持) ; OemSoftwareRev 0x14 2 VBE implementation Software revision ; OemVendorNamePtr 0x16 4 VbeFarPtr to Vendor Name String ; OemProductNamePtr 0x1A 4 VbeFarPtr to Product Name String ; OemProductRevPtr 0x1E 4 VbeFarPtr to Product Revision String ; Reserved 0x22 222 Reserved for VBE implementation scratch area ; OemData 0x100 256 Data Area for OEM Strings(V2.0+支持) ; ; Output: ; AX = VBE Return Status ; AH = 0:調用正常;其餘:調用失敗 ; AL = 0x4F:VESA 支持;其餘:VESA 不支持 ; ; 二、Return VBE mode information(返回 VBE 模式信息) ; Input: ; AX = 0x4F01 ; CX = Mode number(模式號) ; ES : DI = Return VBE mode information(指向 ModeInfoBlock 結構體的緩衝區指針) ; ModeInfoBlock 結構體 ; 名稱 偏移 長度 內容 ; ModeAttributes 0x00 2 mode attributes(模式屬性, ; 第 4 位爲模式位:1 = Graphics mode 圖形,0 = Text mode 文本。第 7 位爲緩衝模式位: ; 1 = Linear frame buffer mode 線性幀,0 = Nonlinear frame buffer mode 非線性幀。) ; WinAAttributes 0x02 1 window A attributes ; WinBAttributes 0x03 1 window B attributes ; WinGranularity 0x04 2 window granularity ; WinSize 0x06 2 window size ; WinASegment 0x08 2 window A start segment ; WinBSegment 0x0A 2 window B start segment ; WinFuncPtr 0x0C 4 real mode pointer to windowfunction ; BytesPerScanLine 0x10 2 bytes per scan line ; ; Mandatory information for VBE 1.2 and above ; XResolution 0x12 2 horizontal resolution in pixels or characters ; (X分辨率) ; YResolution 0x14 2 vertical resolution in pixels or characters ; (Y分辨率) ; XCharSize 0x16 1 character cell width in pixels ; YCharSize 0x17 1 character cell height in pixels ; NumberOfPlanes 0x18 1 number of memory planes ; BitsPerPixel 0x19 1 bits per pixel(每一個像素所佔的位數) ; NumberOfBanks 0x1A 1 number of banks ; MemoryModel 0x1B 1 memory model type ; BankSize 0x1C 1 bank size in KB ; NumberOfImagePages 0x1D 1 number of images ; Reserved 0x1E 1 reserved for page function ; ; direct Color fields (required for direct/6 and YUV/7 memory models) ; RedMaskSize 0x1F 1 size of direct color red mask in bits ; RedFieldPosition 0x20 1 bit position of lsb of red mask ; GreenMaskSize 0x21 1 size of direct color green mask in bits ; GreenFieldPosition 0x22 1 bit position of lsb of green mask ; BlueMaskSize 0x23 1 size of direct color blue mask in bits ; BlueFieldPosition 0x24 1 bit position of lsb of blue mask ; RsvdMaskSize 0x25 1 size of direct color reserved mask in bits ; RsvdFieldPosition 0x26 1 bit position of lsb of reserved mask ; DirectColorModeInfo 0x27 1 direct color mode attributes ; ; Mandatory information for VBE 2.0 and above ; PhysBasePtr 0x28 4 physical address for flat memory frame buffer ; 平坦內存幀緩衝區的物理地址,即顯存起始地址) ; Reserved 0x2C 4 Reserved - always set to 0 ; Reserved 0x30 2 Reserved - always set to 0 ; Mandatory information for VBE 3.0 and above ; LinBytesPerScanLine 0x32 2 bytes per scan line for linear modes ; BnkNumberOfImagePages 0x34 1 number of images for banked modes ; LinNumberOfImagePages 0x35 1 number of images for linear modes ; LinRedMaskSize 0x36 1 size of direct color red mask (linear modes) ; LinRedFieldPosition 0x37 1 bit position of lsb ofred mask (linear modes) ; LinGreenMaskSize 0x38 1 size of direct color green mask (linear modes) ; LinGreenFieldPosition 0x39 1 bit position of lsb of green mask (linear modes) ; LinBlueMaskSize 0x3A 1 size of direct color blue mask (linear modes) ; LinBlueFieldPosition 0x3B 1 bit position of lsb of blue mask (linear modes) ; LinRsvdMaskSize 0x3C 1 size of direct color reserved mask (linear modes) ; LinRsvdFieldPosition 0x3D 1 bit position of lsb of reserved mask (linear modes) ; MaxPixelClock 0x3E 4 maximum pixel clock (in Hz) for graphics mode ; Reserved 0x42 189 remainder of ModeInfoBlock ; ; Output: ; AX = VBE Return Status ; ; 三、Set VBE Mode(設置 VBE 模式) ; Input: ; AX = 0x4F02 ; BX = Desired Mode to set(須要設置的模式) ; D0 - D8 = Mode number (模式號) ; D9 - D10 = Reserved (must be 0)(保留,必須爲 0) ; D11 = 0 Use current default refresh rate(使用當前缺省刷新率) ; = 1 Use user specified CRTC values for refresh rate(使用用戶指定的 CRTC ; 值爲刷新率) ; D12 - 13 Reserved for VBE/AF (must be 0)(爲 VBE/AF 保留,必須爲 0) ; D14 = 0 Use windowed frame buffer model(使用窗口幀緩衝區模式) ; = 1 Use linear/flat frame buffer model(使用線性/平坦幀緩衝區模式) ; D15 = 0 Clear display memory(清除顯示內存) ; = 1 Don't clear display memory(不清除顯示內存) ; ES:DI = Pointer to CRTCInfoBlock structure(指向 CRTCInfoBlock 結構體的緩衝區指針) ; CRTCInfoBlock 結構體 ; 名稱 偏移 長度 內容 ; HorizontalTotal 0x00 2 Horizontal total in pixels ; HorizontalSyncStart 0x02 2 Horizontal sync start in pixels ; HorizontalSyncEnd 0x04 2 Horizontal sync end in pixels ; VerticalTotal 0x06 2 Vertical total in lines ; VerticalSyncStart 0x08 2 Vertical sync start in lines ; VerticalSyncEnd 0x0A 2 Vertical sync end in lines ; Flags 0x0C 1 Flags (Interlaced, Double Scan etc) ; PixelClock 0x0D 4 Pixel clock in units of Hz ; RefreshRate 0x21 2 Refresh rate in units of 0.01 Hz ; Reserved 0x23 40 remainder of ModeInfoBlock ; ; Output: ; AX = VBE Return Status ; ; 附:標準模式號列表 ; 文本模式 ; 分辨率 模式 ; 80x60 0x108 ; 132x132 0x109 ; 132x50 0x10b ; 132x60 0x10c ; ; 圖形模式 ; 分辨率 4位 8位 15位 16位 32位(24位有效) ; 320x200 0x10d 0x10e 0x10f ; 640x400 0x100 ; 640×480 0x101 0x110 0x111 0x112 ; 800x600 0x102 0x103 0x113 0x114 0x115 ; 1024×768 0x104 0x105 0x116 0x117 0x118 ; 1280×1024 0x106 0x107 0x119 0x11a 0x11b ; 1600x1200 0x11c 0x11d 0x11e 0x11f ; ; 8 位:調色板模式 ; 15 位:R5 / G5 / B5(15 位的支持的是小型的,因此不能期望。) ; 16 位:R5 / G6 / B5 ; 32 位:I8 / R8 / G8 / B8(I = ignore) ; ; 0x140之後:開發商自由可定義 ; ; 四、Return current VBE Mode(返回當前 VBE 模式) ; Input: ; AX = 0x4F03 ; Output: ; AX = VBE Return Status ; BX = Current VBE mode ; D0 - D13 = Mode number ; D14 = 0 Windowed frame buffer model ; = 1 Linear/flat frame buffer model ; D15 = 0 Memory cleared at last mode set ; = 1 Memory not cleared at last mode set ;
而後就能夠打開圖形模式了,順便把 Bootsector 和 Loader 整理下:數據結構
; Constant.inc ; 常量 ; 四彩 ; 2015-11-21 %ifndef _CONSTANT_INC %define _CONSTANT_INC ; ======================================================================================== ; 內存中 0x0500 ~ 0x7BFF(29.75 KB) 段和 0x7E00 ~ 0xFFFF(32.5KB)段、 ; 0x10000 ~ 0x9FBFF(575 KB)段可自由使用。引導扇區段在加載完 Loader 也可以使用。 ; SEGMENTOFGPARAM equ 0x50 ; 全局變量保存段基址 SEGMENTOFTEMP equ 0x7E0 ; 臨時數據被加載到內存的段基址(最多 2 個扇區) SEGMENTOFLOADER equ 0x4000 ; LOADER.SYS 被加載到內存的段基址(最大 63KB) OFFSETOFLOADER equ 0x400 ; 堆棧大小 ; **************************************************************************************** %endif
; FAT12.inc ; FAT12 文件系統常量、宏及子函數定義 ; 四彩 ; 2015-11-17 %ifndef _FAT12_INC %define _FAT12_INC ; ======================================================================================== BYTESPERSECTOR equ 512 ; 每扇區字節數 IFATFIRSTSECTOR equ 1 ; FAT 表的起始邏輯扇區號 IROOTDIRECTORYFIRSTSECTOR equ 19 ; 根目錄區的起始邏輯扇區號 IDATAFIRSTSECTOR equ 33 ; 數據區的起始邏輯扇區號 ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系統的引導扇區頭部格式宏 ; 調用格式:FAT12Head RealEntry, OEMName, VolLab ; RealEntry : 入口地址標籤 ; OEMName : 廠商名稱(8 字節長,不夠的填空格) ; VolLab : 卷標(11 字節長,不夠的填空格) %macro FAT12Head 3 ; 名稱 偏移 長度 說明 3.5英寸軟盤內容 jmp %1 ; 0x00 3 跳轉指令,指向程序入口 jmp RealEntry nop BS_OEMName db %2 ; 0x03 8 廠商名稱 自行定義 BPB_BytsPerSec dw 512 ; 0x0B 2 每扇區字節數 512 BPB_SecPerClus db 1 ; 0x0D 1 每簇扇區數 1 BPB_RsvdSecCnt dw 1 ; 0x0E 2 保留扇區數 1 BPB_NumFATs db 2 ; 0x10 1 FAT表份數 2 BPB_RootEntCnt dw 224 ; 0x11 2 根目錄中最多容納的文件數 224 BPB_TotSec16 dw 2880 ; 0x13 2 扇區總數 (FAT十二、16) 2880 BPB_Media db 0xF0 ; 0x15 1 介質描述符 0xF0 BPB_FATSz16 dw 9 ; 0x16 2 每一個FAT表所佔的扇區數 9 BPB_SecPerTrk dw 18 ; 0x18 2 每磁道扇區數 18 BPB_NumHeads dw 2 ; 0x1A 2 磁頭數 2 BPB_HiddSec dd 0 ; 0x1C 4 隱藏扇區數 0 BPB_TotSec32 dd 2880 ; 0x20 4 扇區總數(FAT32) 2880 BS_DrvNum db 0 ; 0x24 1 磁盤驅動器號 0 BS_Reserved1 db 0 ; 0x25 1 保留(供NT使用) 0 BS_BootSig db 0x29 ; 0x26 1 擴展引導標記 0x29 BS_VolD dd 0 ; 0x27 4 卷標序列號 0 BS_VolLab db %3 ; 0x2B 11 卷標 自行定義 BS_FileSysType db 'FAT12' ; 0x36 8 文件系統類型名 FAT12 ; 0x3E 448 引導代碼及其餘填充字符 ; 0x1FE 2 結束標誌 0xAA55 ; ; BPB:BIOS Parameter Block,BIOS 參數塊 ; BS:Boot Sector,引導扇區 %endmacro ; **************************************************************************************** ; ======================================================================================== ; 目錄表項結構 struc DirectoryItem ; 字段名 偏移 長度 說明 .DIR_Name resb 11 ; 0x00 11 文件名 8 + 3(大寫,不夠長度末尾填空格) .DIR_Attr resb 1 ; 0x0B 1 文件屬性 resb 10 ; 0x0C 10 保留 .DIR_WrtTime resw 1 ; 0x16 2 最後修改時間 .DIR_WrtDate resw 1 ; 0x18 2 最後修改日期 .DIR_FstClus resw 1 ; 0x1A 2 此條目對應的開始簇號(即 FAT 表項序號) .DIR_FileSize resd 1 ; 0x1C 4 文件大小 endstruc ; **************************************************************************************** ; ======================================================================================== ; 從軟盤A(FAT12 格式)裝載文件到內存用到的子函數 %macro IncludeFAT12Function 1 ; 調用格式 :IncludeFAT12Function SEGMENTOFTEMP ; 參數 :SEGMENTOFTEMP = 暫存臨時數據的段基址 ; ; ---------------------------------------------------------------------------------------- ; 函數功能:查找文件位置 ; 入口參數:ds : si = 文件名(字符串)地址 ; 出口參數:ax = 起始 FAT 表項序號 SearchFile: push bp mov bp, sp sub sp , 2 * 2 ; 爲局部變量分配空間 push es push di push dx push cx push bx ; 待讀取的根目錄區邏輯扇區號 mov word[bp - 2], IROOTDIRECTORYFIRSTSECTOR ; 待查找的根目錄區扇區數 mov word[bp - 2 * 2], IDATAFIRSTSECTOR - IROOTDIRECTORYFIRSTSECTOR mov di, si ; 逐個扇區尋找 push %1 ; Read1Sector 要用到 es pop es .Search_NextSector: mov ax, [bp - 2] xor bx, bx call Read1Sector ; cx 統計一個扇區內未匹配的表項數 mov cx, 16 ; = [BPB_BytsPerSec] / DirectoryItem_size .Search_ThisSector: ; 匹配文件名 mov si, di mov dx, 11 ; dx 統計未匹配的文件名字符數 .Match_FileName: lodsb cmp al, byte[es : bx] jnz .Match_NextItem dec dx jz .Found inc bx jmp .Match_FileName .Match_NextItem: and bx, 0b1111111111100000 ; 回當前表項的開始處 add bx, 32 ; 指向下一個表項(一個表項 32 字節,佔用 5 位) loop .Search_ThisSector ; 判斷是否讀完根目錄區全部扇區:讀完說明沒找到,沒讀完就繼續下一個 dec word[bp - 2 * 2] jz .NotFound inc word[bp - 2] jmp .Search_NextSector .NotFound: xor ax, ax jmp .Return .Found: mov ax, word[es : bx + 0x1A - 11 + 1] ; 指向當前表項中的 .DIR_FstClus .Return: mov si, di pop bx pop cx pop dx pop di pop es mov sp, bp pop bp ret ; ---------------------------------------------------------------------------------------- ; 函數功能:複製文件到內存 ; 入口參數:ax = 起始 FAT 表項序號 ; es : bx = 起始內存地址 ; 出口參數:無 LoadFile: push bp mov bp, sp push bx push ax .Load: push bx push ax add ax, IDATAFIRSTSECTOR - 2 ; FAT 表項序號轉換爲邏輯扇區號 call Read1Sector mov ax, 0x0E2E ; 在光標後面顯示一個"." int 0x10 pop ax call GetEntryValue pop bx cmp ax, 0xFF8 ; FAT 表項的值大於等於 0xFF8,表示文件結束 jae .Return ; 未檢查壞扇區 —— 虛擬的不會壞的 add bx, BYTESPERSECTOR jmp .Load .Return: POP ax pop bx mov sp, bp pop bp ret ; ---------------------------------------------------------------------------------------- ; 函數功能:取得 FAT 表中指定序號表項的值(即下一個扇區的 FAT 表項序號) ; 入口參數:ax = FAT 表項序號 ; 出口參數:ax = 對應的 FAT 表項值 GetEntryValue: push bp mov bp, sp push es ; 讀取 FAT 表時要使用 es 暫存數據 push dx push cx push bx ; 計算該表項序號所在的邏輯扇區號和在該扇區的偏移量 xor dx, dx ; 字節號(ax * 12 / 8) mov bx, 3 mul bx mov bx, 2 div bx mov cx, dx ; 保存表項序號的奇偶性(0 = 偶數,1 = 奇數) xor dx, dx mov bx, BYTESPERSECTOR div bx add ax, IFATFIRSTSECTOR ; 邏輯扇區號 push dx ; 保存在該扇區的偏移量 ; 讀取連續 2 個扇區(表項可能跨扇區) push cx ; Read1Sector 函數改變了 cx、ax push ax push %1 pop es xor bx, bx call Read1Sector pop ax inc ax mov bx, BYTESPERSECTOR call Read1Sector pop cx ; 讀出 16 位,奇數項取高 12 位、偶數項取低 12 位(低低高高存放原則),獲得項值 pop bx ; 偏移量(上面壓進去的 dx 值) mov ax, [es : bx] jcxz .Even shr ax, 4 .Even: and ax, 0b0000111111111111 ; 奇數項高 4 位已爲 0,執行此操做值也不變 pop bx pop cx pop dx pop es mov sp, bp pop bp ret ; ---------------------------------------------------------------------------------------- ; 函數功能:讀取一個邏輯扇區到內存 ; 入口參數:ax = 邏輯扇區號 ; es : bx = 起始內存地址 ; 出口參數:ax = 同 ah = 二、int 0x13 Read1Sector: push bp mov bp, sp push dx push cx ; 由 LBA 計算 CHS mov dl, 18 div dl mov ch, al mov dh, al mov cl, ah shr ch, 1 inc cl and dh, 1 ; 讀一個扇區 mov ax, 0x0201 xor dl, dl int 0x13 ; 未檢讀取失敗 —— 虛擬的不會失敗 pop cx pop dx mov sp, bp pop bp ret ; ---------------------------------------------------------------------------------------- ; 函數功能:在光標當前顯示字符串,光標跟隨移動 ; 入口參數:ds : si = 字符串地址 ; 出口參數:無 PrintStr: push bp mov bp, sp push si push ax mov ah, 0x0E ; 功能號,0x0E:顯示一個字符,光標跟隨字符移動 .Print: lodsb cmp al, 0 ; 字符串以 0 結尾 je .Return int 0x10 jmp .Print .Return: pop ax pop si mov sp, bp pop bp ret %endmacro ; **************************************************************************************** %endif
; PM.inc ; 分段管理機制的說明、宏及常量定義 ; 四彩 ; 2015-11-16 %ifndef _DESCRIPTOR_INC %define _DESCRIPTOR_INC ; ======================================================================================== ; ---------------------------------------------------------------------------------------- ; 存儲器(Storage):存放程序和數據的器件,是用於保存信息的記憶設備。 ; 存儲元(Storage Unit):也稱存儲位、記憶單元,是存放一個二進制位的單元。 ; 是存儲器內部儲存數據的最小單位。 ; 任何具備雙穩態(兩個穩定狀態)的物理器件均可以來作存儲元。 ; 存儲單元(Storage Cell):存儲器中有大量的存儲元,把它們按相同的位劃分爲組,組內全部的 ; 存儲元同時進行讀出或寫入操做,這樣的一組存儲元稱爲一個存儲單元。 ; 一個存儲單元一般能夠存放一個字節;存儲單元是 CPU 訪問存儲器的基本單位。 ; 存儲單元地址(Storage Cell Address):存儲單元的惟一的固定編號。 ; 物理存儲器(Physical Storage):實際存在的、具備實物形式的存儲器。 ; 內存(Memory):即內部存儲器,也叫主存。是 CPU 的地址線能夠直接進行尋址的存儲器。 ; 用於暫時存放 CPU 中的運算數據,以及與硬盤等外部存儲器交換的數據。 ; 分爲兩種: ; 物理內存(Physical Memory):經過物理上真實存在的內存條得到的內存。 ; 虛擬內存(Virtual Memory):在硬盤上開出一個區域或文件模擬的物理內存。 ; ; ; 內存地址(Address):內存中每一個用於數據存取的基本單位(字節),都被賦予的一個惟一的序號。 ; 邏輯地址(Logical Address):機器語言指令中,用來指定一個操做數或一條指令的相對地址。 ; 也叫虛擬地址(Virtual Address),是與段相關的偏移地址部分。 ; 線性地址(Linear Address):邏輯地址(段中的偏移地址)加上相應段基地址生成的地址。 ; 是邏輯地址到物理地址變換之間的中間層。 ; 物理地址(Physical Address):內存單元的真實地址。 ; 實際是出如今 CPU 外部地址總線上尋址物理內存的地址信號。能夠理解成把插在機器上的 ; 物理內存看作一個從 0 到最大容量、逐字節編號的大數組,這個數組的下標就叫作物理地址。 ; ; ; 物理存儲空間:物理地址的集合,就是硬件的存儲空間。也稱爲物理空間。 ; 地址空間:是指編碼地址(對每個存儲單元分配一個號碼)的範圍。 ; 存儲器地址空間:對存儲器編碼地址的範圍。 ; 內存地址空間(Address Space):CPU 在操控物理存儲器的時候,把物理存儲器都看成內存來對待, ; 把它們總的看做一個由若干存儲單元組成的邏輯存儲器,這個邏輯存儲器就是內存地址空間。 ; 內存地址空間是爲了不物理地址暴露給進程帶來的嚴重問題,創造的一種內存抽象。 ; 是一個進程可用於尋址所有內存的地址的集合,是一段表示內存位置的地址範圍。 ; 內存地址空間的大小受 CPU 地址總線寬度的限制。32 位地址總線寬度的內存地址空間最大 4GB。 ; 邏輯地址空間(Logical Address Space):也稱虛擬地址空間,是指程序中指令和數據所用的 ; 全部相對地址的編碼的範圍。 ; 線性地址空間(Linear Address Space):線性地址的編碼範圍。 ; CPU 將一個虛擬內存空間中的地址轉換爲物理地址,須要進行兩步:首先將給定一個邏輯地址( ; 段內偏移量),CPU 利用其段式內存管理單元,先將爲個邏輯地址轉換成一個線程地址,再利用其 ; 頁式內存管理單元,轉換爲最終物理地址。 ; ; ; 內核空間:操做系統內核運行的線性地址空間。 ; 內核線性地址空間由全部進程共享,但只有運行在內核態的進程才能訪問,用戶進程能夠經過 ; 系統調用切換到內核態訪問內核空間,進程運行在內核態時所產生的地址都屬於內核空間。 ; 用戶空間:普通應用程序運行的線性地址空間。 ; 每一個進程都有一個獨立的用戶空間,用戶空間由每一個進程獨有。 ; 可是內核線程沒有用戶空間,由於它不產生用戶空間地址。另外子進程共享(繼承)父進程的 ; 用戶空間,只是使用與父進程相同的用戶線性地址到物理內存地址的映射關係,而不是共享 ; 父進程用戶空間。 ; ; ; 尋址(Addressing):由地址尋找數據,從地址對應的存儲單元中訪存數據。 ; 物理上就是磁頭在盤片上定位數據的過程。 ; 尋址方式(Addressing Mode):在存儲器中,指令、操做數寫入或讀出的方式,分爲地址指定方式、 ; 相聯存儲方式和堆棧存取方式。計算機內存都採用地址指定方式。當採用地址指定方式時,處理器 ; 根據指令中給出的地址信息來尋找物理地址的方式稱爲尋址方式。 ; 指令尋址方式:造成指令的有效地址的方法。分爲兩類: ; 順序尋址方式:指令地址在內存中按順序安排,執行程序時,指令一條一條地順序執行。 ; 跳躍尋址方式:下條指令的地址碼不是由程序計數器給出,而是由本條指令給出,程序 ; 轉移執行的順序的過程。 ; 操做數尋址方式:造成操做數的有效地址的方法。分不少種,常見的有: ; 隱含尋址:不明顯地給出操做數的地址。而是在指令中隱含着操做數的地址。 ; 當即尋址:指令的地址字段指出的不是操做數的地址,而是操做數自己。 ; 直接尋址(Direct Addressing):在指令中直接給出參與運算的操做數及運算結果所 ; 存放的有效地址、不須要通過某種變換的尋址方式。 ; 間接尋址:指令地址字段中的形式地址不是操做數的真正地址,而是操做數地址的指示器, ; 或者說此形式地址單元的內容纔是操做數的有效地址。 ; 相對尋址方式:把當前指令的地址加上指令格式中的形式地址而造成操做數的有效地址。 ; 基址尋址方式:將基址寄存器的內容,加上變址寄存器的內容而造成操做數的有效地址。 ; 變址尋址方式:把變址寄存器的內容與偏移量相加來造成操做數有效地址。 ; 塊尋址方式(Block Addressing):在指令中指出數據塊的起始地址(首地址)和數據塊 ; 的長度(字數或字節數)。 ; ; ; 段(Segment):將用戶做業的邏輯地址空間依照相應的邏輯信息組的長度劃分紅若干個連續的段。 ; 由三個參數定義: ; 段基地址(Segment Base Address):線性地址空間中段的起始地址。 ; 段界限(Segment Limit):段的大小。 ; 段屬性(Segment Attributes):段的主要特性。 ; 分 2 類: ; 存儲段(Memory Segment):存放可由程序直接進行訪問的代碼和數據。分 2 類: ; 代碼段(Code Segment): ; 數據段(Data Segment): ; 系統段(System Segment):分 2 類: ; 任務狀態段(Task State Segment):保存任務的重要信息,經過它實現任務的掛起和恢復。 ; 任務:能夠理解成線程,每一個線程須要一個描述符來描述。 ; 局部描述符表段:保存局部描述符表的段。 ; !!用分段機制隔離 OS 核心和應用程序,用分頁機制隔離進程。只須要兩個代碼段和兩個數據段。 ; ———用分段把整個系統空間分爲系統空間和用戶空間,再用分頁將用戶空間劃分爲不一樣的進程空間。 ; ; 描述符(Descriptor):描述一個段所須要的三個參數(B、L、A)組成的數據結構。分 3 類: ; 存儲段描述符:段寄存器使用的描述符。分 2 類:代碼段描述符、數據段描述符。 ; 系統段描述符,分 2 類:TSS 段描述符、LDT 段描述符。 ; 門描述符(Gate Descriptor):描述控制轉移的入口點。 ; 經過門實現任務內特權級的變換和任務間的切換。 ; 分 4 類: ; 調用門(Call Gate):描述子程序的人口。 ; 任務門(Task Gate):指示任務。 ; 中斷門(Interrupt Gate):描述中斷處理程序的入口。 ; 陷阱門(Trap Gate):描述異常處理程序的入口。 ; ; 描述符表(Descriptor Table):由描述符組成的線性表。分 3 類: ; 全局描述符表(Global Descriptor Table): ; 中斷描述符表(Interrupt Descriptor Table): ; 局部描述符表(Local Descriptor Table):。 ; LDT 只是一個可選的數據結構,徹底能夠不用它。使用它帶來方便性,也帶來複雜性。 ; 若是你想讓你的 OS 內核保持簡潔性、可移植性,則最好不要使用它。 ; ; ---------------------------------------------------------------------------------------- ; 存儲段(代碼段和數據段)描述符格式(8 字節 64 位) ; ; ------ ┏━━┳━━┓內存高地址 ; ┃ 7 ┃ 段 ┃ ; ┣━━┫ 基 ┃ ; ┆ ┆ 址 ┆ ; 字節 ┆ ┆ 高 ┆ ; 7 ┣━━┫ 8 ┃ ; ┃ 0 ┃ 位 ┃ ; ------ ┣━━╋━━┫ ; ┃ 7 ┃ G ┃ ; ┣━━╉━━┨ ; ┃ 6 ┃D/B ┃ ; ┣━━╉━━┨ ; ┃ 5 ┃ 未 ┃ ; ┣━━┫ 定 ┃ ; ┃ 4 ┃ 義 ┃ ; 字節 ┣━━╉━━┨ ; 6 ┃ 3 ┃ ┃ ; ┣━━┫ 段 ┃ ; ┃ 2 ┃ 界 ┃ ; ┣━━┫ 限 ┃ ; ┃ 1 ┃ 高 ┃ ; ┣━━┫ 4 ┃ ; ┃ 0 ┃ 位 ┃ ; ------ ┣━━╋━━┫ ; ┃ 7 ┃ P ┃ ; ┣━━╉━━┨ ; ┃ 6 ┃ D ┃ ; ┣━━┫ P ┃ ; ┃ 5 ┃ L ┃ ; ┣━━╉━━┨ ; ┃ 4 ┃ S ┃ ; 字節 ┣━━╉━━┨ ; 5 ┃ 3 ┃ ┃ ; ┣━━┫ T ┃ ; ┃ 2 ┃ Y ┃ ; ┣━━┫ P ┃ ; ┃ 1 ┃ E ┃ ; ┣━━┫ ┃ ; ┃ 0 ┃ ┃ ; ------ ┣━━╋━━┫ ; ┃ 23 ┃ ┃ ; ┣━━┫ ┃ ; ┃ 22 ┃ 段 ┃ ; ┣━━┫ 基 ┃ ; ┆ ┆ 址 ┆ ; 字節 ┆ ┆ 低 ┆ ; 2,3,4 ┣━━┫ 24 ┃ ; ┃ 1 ┃ 位 ┃ ; ┣━━┫ ┃ ; ┃ 0 ┃ ┃ ; ------ ┣━━╋━━┫ ; ┃ 15 ┃ ┃ ; ┣━━┫ ┃ ; ┃ 14 ┃ 段 ┃ ; ┣━━┫ 界 ┃ ; ┆ ┆ 限 ┆ ; 字節 ┆ ┆ 低 ┆ ; 0,1 ┣━━┫ 16 ┃ ; ┃ 1 ┃ 位 ┃ ; ┣━━┫ ┃ ; ┃ 0 ┃ ┃ ; ------ ┗━━┻━━┛內存低地址 ; ; 存儲段描述符定義宏:(看不明白的話,把 16 進制換成 2 進制就很清楚了) ; 調用格式:Descriptor Base, Limit, Attribute ; Base : dd ; 基址,32 位 ; Limit : dd ; 界限,32 位,低 20 位有效 ; Attribute : dw ; 屬性,16 位,高 4 位和低 8 位有效,中間 4 位無效。 %macro Descriptor 3 dw %2 & 0xFFFF ; 界限低 16 位 dw %1 & 0xFFFF ; 基址低 16 位 db (%1 >> 16) & 0xFF ; 基址中間 8 位(高字節的低字) dw ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 屬性低 8 位 + 界限高 4 位 + 屬性高 4 位 = ; %2 的高字的低字節的低 4 位替換 %3 高字中的低 4 位 db (%1 >> 24) & 0xFF ; 基址高 8 位 %endmacro ; 共佔用 8 個字節(64 位) ; **************************************************************************************** ; ; ; ======================================================================================== ; 描述符屬性: ; 描述符屬性是一個字型數值,可是隻有高 4 位和低 8 位有效,中間 4 位無效。 ; ┏━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┓ ; ┃15┃14┃13┃12┃11┃10┃09┃08┃07┃06┃05┃04┃03┃02┃01┃ 0┃ ; ┣━┻━┻━┻━╋━┻━┻━┻━╋━╋━┻━╋━╋━┻━┻━┻━┫ ; ┃G ┃DB┃R AVL┃ 無效位 ┃P ┃ DPL ┃S ┃ TYPE ┃ ; ┗━┻━┻━┻━┻━━━━━━━┻━┻━━━┻━┻━━━━━━━┛ ; 十一、G:Granularity,界限粒度位 ; G = 0 界限粒度爲 1 字節; ; G = 1 界限粒度爲 4K 字節。 ; 注意,界限粒度只對段界限有效,對段基地址無效,段基地址老是以字節爲單位。 ; ; 十、DB:Default operation size / default stack pointer size and/or upper bound ; 默認操做大小/默認棧指針大小和/或上界限位,根據描述的段不一樣,功能不一樣。 ; 對於 32 位代碼和數據段,應該老是設置爲 1;對於 16 位代碼和數據段,應該老是設置爲 0。 ; ⑴ 可執行代碼段(D):指明指令引用有效地址和操做數的默認長度。 ; ① D = 1 默認爲 32 位代碼段,指令使用 32 位地址及 32 或 8 位操做數; ; ② D = 0 默認爲 16 位代碼段,指令使用 16 位地址及 16 或 8 位操做數。 ; 可使用指令前綴 0x66 來選擇非默認值的操做數大小、0x67 來選擇非默認值的地址大小。 ; ⑵由 SS 寄存器指向的數據段,一般爲堆棧段(B):指明堆棧操做指令默認棧指針大小。 ; ① D = 1 使用 32 位堆棧指針寄存器 ESP; ; ② D = 0 使用 16 位堆棧指針寄存器 SP。 ; ⑶ 向下擴展數據段(B):指明段的上界限。 ; ① D = 1 段的上界限爲 4G; ; ② D = 0 段的上界限爲 64K。 ; ; 0九、R:Reserved,保留位 ; 未定義,應該老是設置爲 0。 ; ; 0八、AVL:Available,可用位 ; 未定義,可供系統軟件使用。 ; ; 0七、P:Present,段存在位 ; P = 1 該段在內存中,即該段存在,或者說描述符對地址轉換是有效的; ; P = 0 該段不在內存中,即該段不存在,或者說描述符對地址轉換無效。 ; 把指向這個段描述符的選擇符加載進段寄存器將致使產生一個段不存在異常。 ; 內存管理軟件可使用這個標誌來控制在某一給定時間實際須要把那個段加載進內存中。 ; 這個功能爲虛擬存儲提供了除分頁機制之外的控制。 ; 操做系統可使用該描述符來保存其餘數據,如不存在段實際在什麼地方。 ; ; 06 0五、DPL:Descriptor Privilege level,特權級位 ; 規定了所描述段的特權級,用於特權檢查,以決定對該段可否訪問。 ; 特權級範圍從 0 到 3,0 級特權級最高,3 級最低。 ; ; 0四、S:Descriptor type flag,描述符類型位 ; S = 1 存儲段 ; S = 0 系統段和門 ; ; 03 02 01 00、TYPE:說明存儲段描述符所描述的存儲段的具體屬性。 ; 值 說明 ; ------------------------------------------ ; 系 0 未定義 ; 1 可用 286TSS ; 2 局部描述符表 ; 3 忙的 286TSS ; 4 286 調用門 ; 5 任務門 ; 6 286 中斷門 ; 統 7 286 陷阱門 ; 8 未定義 ; 9 可用 386TSS ; A 未定義 ; B 忙的 386TSS ; C 386 調用門 ; D 未定義 ; E 386 中斷門 ; 段 F 386 陷阱門 ; ------------------------------------------ ; 數據段均可讀、非一致 ; 數 0 只讀 ; 1 只讀、已訪問 ; 2 讀/寫 ; 據 3 讀/寫、已訪問 ; 4 只讀、向下擴展 ; 5 只讀、向下擴展、已訪問 ; 6 讀/寫、向下擴展 ; 段 7 讀/寫、向下擴展、已訪問 ; ------------------------------------------ ; 代碼段均可執行 ; 代 8 只執行 ; 9 只執行、已訪問 ; A 執行/讀 ; 碼 B 執行/讀、已訪問 ; C 只執行、一致 ; D 只執行、一致、已訪問 ; E 執行/讀、一致 ; 段 F 執行/讀、一致、已訪問 ; ; 關於一致(Conforming)、非一致(Non-conforming): ; 同級間代碼、數據均可互相訪問。 ; 特權級高的不容許訪問特權級低的代碼:系統不會調用用戶代碼。 ; 特權級高的能夠訪問特權級低的數據,特權級低的不容許訪問特權級高的數據: ; 系統能夠訪問用戶數據,用戶不能訪問系統數據。 ; 一致代碼段,特權級低的能夠訪問特權級高的代碼(特權級不會改變): ; 用戶能夠調用系統共享的代碼。 ; 非一致代段(普通的代碼段)不一樣級間不能訪問: ; 防止用戶調用受保護的系統代碼。 ; ; ---------------------------------------------------------------------------------------- ; 描述符屬性常量定義: ; G 位,默認 1 字節粒度 DA_4K equ 0x8000 ; 4K 字節粒度,0b 1 000 0000 0000 0000 ; ; DB 位,默認 16 位 DA_32 equ 0x4000 ; 32 位,0b 1 00 0000 0000 0000 ; ; DPL 位,默認特權級 0 DA_DPL_1 equ 0x20 ; DPL = 1,0b 01 0 0000 DA_DPL_2 equ 0x40 ; DPL = 2,0b 10 0 0000 DA_DPL_3 equ 0x60 ; DPL = 3,0b 11 0 0000 ; ;P + S + TYPE 位,存在:+ 0x80(0b 1 000 0000) ; 系統段 DA_SS_LDT equ 0x82 ; 局部描述符表 DA_SS_TSKG equ 0x85 ; 任務門 DA_SS_TSKSS equ 0x89 ; 可用 386 TSS(任務狀態)段 DA_SS_CALLG equ 0x8C ; 386 調用門 DA_SS_INTG equ 0x8E ; 386 中斷門 DA_SS_TRPG equ 0x8F ; 386 陷阱門 ; 存儲段:+ 0x10(0b 1 0000) DA_DS_R equ 0x90 ; 只讀數據段 DA_DS_RW equ 0x92 ; 可讀寫數據段 DA_DS_RWA equ 0x93 ; 可讀寫、已訪問數據段 ; DA_CS_E equ 0x98 ; 只執行代碼段 DA_CS_ER equ 0x9A ; 可執行、可讀代碼段 DA_CS_EC equ 0x9C ; 可執行、一致代碼段 DA_CS_ERC equ 0x9E ; 可執行、可讀、一致代碼段 ; ; **************************************************************************************** ; ======================================================================================== ; 選擇子: ; ---------------------------------------------------------------------------------------- ; ┏━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┓ ; ┃15┃14┃13┃12┃11┃10┃09┃08┃07┃06┃05┃04┃03┃02┃01┃0 ┃ ; ┣━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━╋━╋━┻━┫ ; ┃ 描述符索引 ┃TI┃ RPL ┃ ; ┗━━━━━━━━━━━━━━━━━━━━━━━━━┻━┻━━━┛ ; TI:Table Indicator,引用描述符表位 ; TI = 0 從全局描述符表(GDT)中讀取描述符; ; TI = 1 從局部描述符表(LDT)中讀取描述符。 ; ; RPL:Requested Privilege Level,請求特權級位 ; 用於特權檢查。 ; ; ---------------------------------------------------------------------------------------- ; 選擇子屬性常量定義: ; TI 位,默認爲全局描述符表 SA_LDT equ 4 ; 局部描述符表,0b 1 00 ; ; RPL 位,默認請求特權級 0 SA_RPL_1 equ 1 SA_RPL_2 equ 2 SA_RPL_3 equ 3 ; ; **************************************************************************************** %endif
; BootSector.asm ; 引導扇區 ; 四彩 ; 2015-11-17 ; ======================================================================================== ; 電腦的啓動過程: ; 一、80x86 CPU 啓動後(加電或復位),CS : IP 被設置爲 0xFFFF : 0x0,CPU 今後處讀取指令 ; 開始執行。該單元在基本輸入輸出系統(Basic Input/Output System,BIOS)的地址範圍內, ; 這裏是一條跳轉到 BIOS 中真正啓動代碼處的指令。 ; 二、BIOS 首先進行加電自檢(Power-On Self-Test,POST),而後進行更完整的硬件檢測,並加載 ; 相關設備。 ; 三、接下來按啓動順序(Boot Sequence)讀取第一個設備的第一個扇區,若是該扇區最後兩個字節 ; 是 0x55 和 0xAA,代表這個設備能夠用於引導;若是不是,代表這個設備不能用於引導,BIOS ; 繼續讀取啓動順序中的下一個設備……直到找到啓動設備。BIOS 把第一個啓動設備的第一個扇區 ; 讀到內存 0x7C00 處,而後把控制權交給該處。 ; 四、操做系統經過改寫啓動設備的第一個扇區,被讀入內存後,從內存 0x7C00 處開始接管電腦。 ; **************************************************************************************** ; ======================================================================================== ; 頭文件及常量定義 ; ---------------------------------------------------------------------------------------- %include "./INC/Constant.inc" %include "./INC/FAT12.inc" ; ---------------------------------------------------------------------------------------- org 0x7C00 ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系統引導扇區的頭部(前 62 字節) FAT12Head main, "NASM+GCC", "TestX_v0.01" ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系統引導扇區的引導代碼(從第 62 字節開始) ; ---------------------------------------------------------------------------------------- ; 程序入口 main: cli cld xor eax, eax ; 初始化寄存器 mov ax, cs mov ds, ax mov ss, ax mov ax, 0x7C00 mov bp, ax mov sp, ax mov si, strBootMsg call PrintStr ; 尋找 Loader mov si, FileNameOfLoader call SearchFile cmp ax, 0 jnz .Found mov si, strNotFoundLoader call PrintStr jmp $ .Found: ; 加載 Loader push SEGMENTOFLOADER pop es mov bx, OFFSETOFLOADER call LoadFile ; 控制權交給已加載到內存的 Loader mov si, strLoaded call PrintStr jmp SEGMENTOFLOADER : OFFSETOFLOADER ; ---------------------------------------------------------------------------------------- ; 包含 FAT12 子函數 IncludeFAT12Function SEGMENTOFTEMP ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系統引導扇區引導數據部分(提示信息字符串) strBootMsg db "TestX is booting ...", `\r\n`, "Loading loader ...", 0 strNotFoundLoader db `\r\n`, "Not Found Loader.sys !", 0 strLoaded db `\r\n`, "Loader is loaded !", 0 ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系統引導扇區引導代碼的剩餘部分用 0 填滿,最後兩個字節置結束標誌(0xAA55) times 497 - ($ - $$) db 0 FileNameOfLoader db "LOADER SYS", 0, 0 ; Loader 文件名,8 + 3格式 dw 0xAA55 ; ****************************************************************************************
; Loader.asm ; 加載程序 ; 四彩 ; 2015-11-21 ; ======================================================================================== ; 頭文件及常量定義 ; ---------------------------------------------------------------------------------------- %include "./INC/Constant.inc" %include "./INC/FAT12.inc" %include "./INC/PM.inc" ; ---------------------------------------------------------------------------------------- org OFFSETOFLOADER jmp RM_main ; **************************************************************************************** [SECTION .gdt] ; ======================================================================================== ; Loader 把所有 4G 內存都做爲一個段使用,分爲兩類:代碼段、數據段 ; ---------------------------------------------------------------------------------------- ; GDT ; 基址 界限 屬性 Desc_Begin : Descriptor 0, 0, 0 ; 空描述符 Desc_Code : Descriptor 0, 0xFFFFF, DA_CS_ER + DA_32 + DA_4K ; 代碼段 Desc_Data : Descriptor 0, 0xFFFFF, DA_DS_RW + DA_32 + DA_4K ; 數據段 Desc_Video : Descriptor 0, 0xFFFFF, DA_DS_RW + DA_32 + DA_4K ; 顯存段 Desc_End : ; ; ---------------------------------------------------------------------------------------- ; GDTPtr GDTPtr dw Desc_End - Desc_Begin - 1 ; 界限 dd SEGMENTOFLOADER * 0x10 + Desc_Begin ; 基址 ; ; ---------------------------------------------------------------------------------------- ; 選擇子 SelectorCode equ Desc_Code - Desc_Begin SelectorData equ Desc_Data - Desc_Begin SelectorVideo equ Desc_Video - Desc_Begin ; **************************************************************************************** [SECTION .16] [BITS 16] ; ======================================================================================== ; 實模式下複製 kernle 到內存,並開啓保護模式 ; ---------------------------------------------------------------------------------------- ; 程序入口,實模式代碼段 RM_main: ; 初始化寄存器 mov ax, cs mov ds, ax mov ss, ax mov ax, OFFSETOFLOADER mov bp, ax mov sp, ax ; 切換圖形模式 push SEGMENTOFGPARAM ; 取得 VBE 信息 pop es xor di, di mov ax, 0x4F00 int 0x10 mov di, 0x200 mov ax, 0x4F01 ; 取得 800*600*16 模式信息 mov cx, 0x114 int 0x10 cmp ax, 0x004F jz .Support mov si, strNotSupportVESA call PrintStr jmp $ .Support: mov ax, 0x4F02 ; 設置畫面模式 mov bx, 0x4114 ; 800*600*16,線性幀緩衝區 int 0x10 mov eax, [es : 0x200 + 0x28] ; 圖形模式顯存基址 mov word[Desc_Video + 2], ax ; 顯存基址拆分紅 3 部分存入段描述符相應位置 shr eax, 16 mov byte[Desc_Video + 4], al mov byte[Desc_Video + 7], ah ; 開啓保護模式 lgdt [GDTPtr] ; 加載 GDT in al, 0x92 ; 打開地址線 A20 or al, 0b10 out 0x92, al mov eax, cr0 ; 置保護模式標誌位 or eax, 1 mov cr0, eax jmp dword SelectorCode : (SEGMENTOFLOADER * 0x10 + PM_main) ; 修改 CS : EIP ; ---------------------------------------------------------------------------------------- ; 包含 FAT12 子函數 IncludeFAT12Function SEGMENTOFTEMP ; ---------------------------------------------------------------------------------------- strNotSupportVESA db `\r\n`, "Not Support VESA !", 0 ; **************************************************************************************** [SECTION .32] [BITS 32] ; ======================================================================================== ; 保護模式代碼段,由實模式跳入 PM_main: push SelectorData pop fs push SelectorVideo pop gs mov cx, 0b0000000000011111 call ClearScreen16 jmp $ ; ---------------------------------------------------------------------------------------- ; 函數功能:用指定的顏色清除屏幕 ; 入口參數:cx = 顏色(VBX 模擬器只支持 16 位色) ; 出口參數:無 ClearScreen16: push ebp mov ebp, esp push esi push edx push ebx push eax xor eax, eax xor ebx, ebx xor edx, edx mov esi, SEGMENTOFGPARAM * 0x10 + 0x200 ; 只處理 16 位色 mov al, [fs : esi + 0x19] ; 從全局參數段取每一個像素所佔的位數 cmp al, 16 jnz .Return ; 計算顯存大小 mov bl, 8 div bl push ax mov bx, [fs : esi + 0x12] ; 從全局參數段取 X 分辨率 mul ebx mov bx, [fs : esi + 0x14] ; 從全局參數段取 Y 分辨率 mul ebx xor ebx, ebx pop bx ; 上面壓入的 ax(即每一個像素所佔字節數) ; 逐個像素點填色 .CLS16: mov [gs : eax], cx sub eax, ebx jnz .CLS16 .Return: pop eax pop ebx pop edx pop esi mov esp, ebp pop ebp ret ; ****************************************************************************************
運行效果就不貼了,就是一塊大藍屏。ide