您的位置:首页 > 其它

十二、VESA

2015-11-21 00:00 281 查看
书里还用 320 * 200 图形模式,太老旧了。现在的显卡都是超级显卡,模拟器也支持超级显卡,得用 VBE 才行。把用得上的 VBE 的几个函数(就是中断)贴出来,关键信息翻译成中文了。
; VBE 函数
; 在实模式下通过 0x10 中断调用。
; VBE : VESA BIOS Extension
; VESA : Video Electronics Standards Association(视频电子标准协会)
;
; 1、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 不支持
;
; 2、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
;
; 3、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以后:开发商自由可定义
;
; 4、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   扇区总数 (FAT12、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 = 2、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     ┃
;  ┗━┻━┻━┻━┻━━━━━━━┻━┻━━━┻━┻━━━━━━━┛
;  11、G:Granularity,界限粒度位
;    G = 0 界限粒度为 1 字节;
;    G = 1 界限粒度为 4K 字节。
;    注意,界限粒度只对段界限有效,对段基地址无效,段基地址总是以字节为单位。
;
;  10、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。
;
;  09、R:Reserved,保留位
;    未定义,应该总是设置为 0。
;
;  08、AVL:Available,可用位
;    未定义,可供系统软件使用。
;
;  07、P:Present,段存在位
;    P = 1 该段在内存中,即该段存在,或者说描述符对地址转换是有效的;
;    P = 0 该段不在内存中,即该段不存在,或者说描述符对地址转换无效。
;          把指向这个段描述符的选择符加载进段寄存器将导致产生一个段不存在异常。
;          内存管理软件可以使用这个标志来控制在某一给定时间实际需要把那个段加载进内存中。
;          这个功能为虚拟存储提供了除分页机制以外的控制。
;          操作系统可以使用该描述符来保存其他数据,如不存在段实际在什么地方。
;
; 06 05、DPL:Descriptor Privilege level,特权级位
;    规定了所描述段的特权级,用于特权检查,以决定对该段能否访问。
;    特权级范围从 0 到 3,0 级特权级最高,3 级最低。
;
;  04、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

; ========================================================================================
; 电脑的启动过程:
; 1、80x86 CPU 启动后(加电或复位),CS : IP 被设置为 0xFFFF : 0x0,CPU 从此处读取指令
;    开始执行。该单元在基本输入输出系统(Basic Input/Output System,BIOS)的地址范围内,
;    这里是一条跳转到 BIOS 中真正启动代码处的指令。
; 2、BIOS 首先进行加电自检(Power-On Self-Test,POST),然后进行更完整的硬件检测,并加载
;    相关设备。
; 3、接下来按启动顺序(Boot Sequence)读取第一个设备的第一个扇区,如果该扇区最后两个字节
;    是 0x55 和 0xAA,表明这个设备可以用于引导;如果不是,表明这个设备不能用于引导,BIOS
;    继续读取启动顺序中的下一个设备……直到找到启动设备。BIOS 把第一个启动设备的第一个扇区
;    读到内存 0x7C00 处,然后把控制权交给该处。
; 4、操作系统通过改写启动设备的第一个扇区,被读入内存后,从内存 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
; ****************************************************************************************

运行效果就不贴了,就是一块大蓝屏。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: