remove useless boot code

This commit is contained in:
catfood 2023-11-22 21:06:03 +08:00
parent 175b9e7da3
commit af16e1508a
12 changed files with 0 additions and 3650 deletions

View File

@ -1,288 +0,0 @@
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; boot.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;%define _BOOT_DEBUG_ ; 做 Boot Sector 时一定将此行注释掉!将此行打开后用 nasm Boot.asm -o Boot.com 做成一个.COM文件易于调试
%ifdef _BOOT_DEBUG_
org 0100h ; 调试状态, 做成 .COM 文件, 可调试
%else
org 07c00h ; Boot 状态, Bios 将把 Boot Sector 加载到 0:7C00 处并开始执行
%endif
;================================================================================================
%ifdef _BOOT_DEBUG_
BaseOfStack equ 0100h ; 调试状态下堆栈基地址(栈底, 从这个位置向低地址生长)
%else
BaseOfStack equ 07c00h ; Boot状态下堆栈基地址(栈底, 从这个位置向低地址生长)
%endif
%include "load.inc"
;================================================================================================
jmp short LABEL_START ; Start to boot.
nop ; 这个 nop 不可少
; 下面是 FAT12 磁盘的头, 之所以包含它是因为下面用到了磁盘的一些信息
%include "fat12hdr.inc"
LABEL_START:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack
; 清屏
mov ax, 0600h ; AH = 6, AL = 0h
mov bx, 0700h ; 黑底白字(BL = 07h)
mov cx, 0 ; 左上角: (0, 0)
mov dx, 0184fh ; 右下角: (80, 50)
int 10h ; int 10h
mov dh, 0 ; "Booting "
call DispStr ; 显示字符串
xor ah, ah ; ┓
xor dl, dl ; ┣ 软驱复位
int 13h ; ┛
; 下面在 A 盘的根目录寻找 LOADER.BIN
mov word [wSectorNo], SectorNoOfRootDirectory
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
cmp word [wRootDirSizeForLoop], 0 ; ┓
jz LABEL_NO_LOADERBIN ; ┣ 判断根目录区是不是已经读完
dec word [wRootDirSizeForLoop] ; ┛ 如果读完表示没有找到 LOADER.BIN
mov ax, BaseOfLoader
mov es, ax ; es <- BaseOfLoader
mov bx, OffsetOfLoader ; bx <- OffsetOfLoader 于是, es:bx = BaseOfLoader:OffsetOfLoader
mov ax, [wSectorNo] ; ax <- Root Directory 中的某 Sector 号
mov cl, 1
call ReadSector
mov si, LoaderFileName ; ds:si -> "LOADER BIN"
mov di, OffsetOfLoader ; es:di -> BaseOfLoader:0100 = BaseOfLoader*10h+100
cld
mov dx, 10h
LABEL_SEARCH_FOR_LOADERBIN:
cmp dx, 0 ; ┓循环次数控制,
jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR ; ┣如果已经读完了一个 Sector,
dec dx ; ┛就跳到下一个 Sector
mov cx, 11
LABEL_CMP_FILENAME:
cmp cx, 0
jz LABEL_FILENAME_FOUND ; 如果比较了 11 个字符都相等, 表示找到
dec cx
lodsb ; ds:si -> al
cmp al, byte [es:di]
jz LABEL_GO_ON
jmp LABEL_DIFFERENT ; 只要发现不一样的字符就表明本 DirectoryEntry 不是
; 我们要找的 LOADER.BIN
LABEL_GO_ON:
inc di
jmp LABEL_CMP_FILENAME ; 继续循环
LABEL_DIFFERENT:
and di, 0FFE0h ; else ┓ di &= E0 为了让它指向本条目开头
add di, 20h ; ┃
mov si, LoaderFileName ; ┣ di += 20h 下一个目录条目
jmp LABEL_SEARCH_FOR_LOADERBIN; ┛
LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
add word [wSectorNo], 1
jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN
LABEL_NO_LOADERBIN:
mov dh, 2 ; "No LOADER."
call DispStr ; 显示字符串
%ifdef _BOOT_DEBUG_
mov ax, 4c00h ; ┓
int 21h ; ┛没有找到 LOADER.BIN, 回到 DOS
%else
jmp $ ; 没有找到 LOADER.BIN, 死循环在这里
%endif
LABEL_FILENAME_FOUND: ; 找到 LOADER.BIN 后便来到这里继续
mov ax, RootDirSectors
and di, 0FFE0h ; di -> 当前条目的开始
add di, 01Ah ; di -> 首 Sector
mov cx, word [es:di]
push cx ; 保存此 Sector 在 FAT 中的序号
add cx, ax
add cx, DeltaSectorNo ; 这句完成时 cl 里面变成 LOADER.BIN 的起始扇区号 (从 0 开始数的序号)
mov ax, BaseOfLoader
mov es, ax ; es <- BaseOfLoader
mov bx, OffsetOfLoader ; bx <- OffsetOfLoader 于是, es:bx = BaseOfLoader:OffsetOfLoader = BaseOfLoader * 10h + OffsetOfLoader
mov ax, cx ; ax <- Sector 号
LABEL_GOON_LOADING_FILE:
push ax ; ┓
push bx ; ┃
mov ah, 0Eh ; ┃ 每读一个扇区就在 "Booting " 后面打一个点, 形成这样的效果:
mov al, '.' ; ┃
mov bl, 0Fh ; ┃ Booting ......
int 10h ; ┃
pop bx ; ┃
pop ax ; ┛
mov cl, 1
call ReadSector
pop ax ; 取出此 Sector 在 FAT 中的序号
call GetFATEntry
cmp ax, 0FFFh
jz LABEL_FILE_LOADED
push ax ; 保存 Sector 在 FAT 中的序号
mov dx, RootDirSectors
add ax, dx
add ax, DeltaSectorNo
add bx, [BPB_BytsPerSec]
jmp LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED:
mov dh, 1 ; "Ready."
call DispStr ; 显示字符串
; *****************************************************************************************************
jmp BaseOfLoader:OffsetOfLoader ; 这一句正式跳转到已加载到内存中的 LOADER.BIN 的开始处
; 开始执行 LOADER.BIN 的代码
; Boot Sector 的使命到此结束
; *****************************************************************************************************
;============================================================================
;变量
;----------------------------------------------------------------------------
wRootDirSizeForLoop dw RootDirSectors ; Root Directory 占用的扇区数, 在循环中会递减至零.
wSectorNo dw 0 ; 要读取的扇区号
bOdd db 0 ; 奇数还是偶数
;============================================================================
;字符串
;----------------------------------------------------------------------------
LoaderFileName db "LOADER BIN", 0 ; LOADER.BIN 之文件名
; 为简化代码, 下面每个字符串的长度均为 MessageLength
MessageLength equ 9
BootMessage: db "Booting "; 9字节, 不够则用空格补齐. 序号 0
Message1 db "Ready. "; 9字节, 不够则用空格补齐. 序号 1
Message2 db "No LOADER"; 9字节, 不够则用空格补齐. 序号 2
;============================================================================
;----------------------------------------------------------------------------
; 函数名: DispStr
;----------------------------------------------------------------------------
; 作用:
; 显示一个字符串, 函数开始时 dh 中应该是字符串序号(0-based)
DispStr:
mov ax, MessageLength
mul dh
add ax, BootMessage
mov bp, ax ; ┓
mov ax, ds ; ┣ ES:BP = 串地址
mov es, ax ; ┛
mov cx, MessageLength ; CX = 串长度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 0007h ; 页号为0(BH = 0) 黑底白字(BL = 07h)
mov dl, 0
int 10h ; int 10h
ret
;----------------------------------------------------------------------------
; 函数名: ReadSector
;----------------------------------------------------------------------------
; 作用:
; 从第 ax 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中
ReadSector:
; -----------------------------------------------------------------------
; 怎样由扇区号求扇区在磁盘中的位置 (扇区号 -> 柱面号, 起始扇区, 磁头号)
; -----------------------------------------------------------------------
; 设扇区号为 x
; ┌ 柱面号 = y >> 1
; x ┌ 商 y ┤
; -------------- => ┤ └ 磁头号 = y & 1
; 每磁道扇区数 │
; └ 余 z => 起始扇区号 = z + 1
push bp
mov bp, sp
sub esp, 2 ; 辟出两个字节的堆栈区域保存要读的扇区数: byte [bp-2]
mov byte [bp-2], cl
push bx ; 保存 bx
mov bl, [BPB_SecPerTrk] ; bl: 除数
div bl ; y 在 al 中, z 在 ah 中
inc ah ; z ++
mov cl, ah ; cl <- 起始扇区号
mov dh, al ; dh <- y
shr al, 1 ; y >> 1 (其实是 y/BPB_NumHeads, 这里BPB_NumHeads=2)
mov ch, al ; ch <- 柱面号
and dh, 1 ; dh & 1 = 磁头号
pop bx ; 恢复 bx
; 至此, "柱面号, 起始扇区, 磁头号" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^
mov dl, [BS_DrvNum] ; 驱动器号 (0 表示 A 盘)
.GoOnReading:
mov ah, 2 ; 读
mov al, byte [bp-2] ; 读 al 个扇区
int 13h
jc .GoOnReading ; 如果读取错误 CF 会被置为 1, 这时就不停地读, 直到正确为止
add esp, 2
pop bp
ret
;----------------------------------------------------------------------------
; 函数名: GetFATEntry
;----------------------------------------------------------------------------
; 作用:
; 找到序号为 ax 的 Sector 在 FAT 中的条目, 结果放在 ax 中
; 需要注意的是, 中间需要读 FAT 的扇区到 es:bx 处, 所以函数一开始保存了 es 和 bx
GetFATEntry:
push es
push bx
push ax
mov ax, BaseOfLoader ; ┓
sub ax, 0100h ; ┣ 在 BaseOfLoader 后面留出 4K 空间用于存放 FAT
mov es, ax ; ┛
pop ax
mov byte [bOdd], 0
mov bx, 3
mul bx ; dx:ax = ax * 3
mov bx, 2
div bx ; dx:ax / 2 ==> ax <- 商, dx <- 余数
cmp dx, 0
jz LABEL_EVEN
mov byte [bOdd], 1
LABEL_EVEN:;偶数
xor dx, dx ; 现在 ax 中是 FATEntry 在 FAT 中的偏移量. 下面来计算 FATEntry 在哪个扇区中(FAT占用不止一个扇区)
mov bx, [BPB_BytsPerSec]
div bx ; dx:ax / BPB_BytsPerSec ==> ax <- 商 (FATEntry 所在的扇区相对于 FAT 来说的扇区号)
; dx <- 余数 (FATEntry 在扇区内的偏移)。
push dx
mov bx, 0 ; bx <- 0 于是, es:bx = (BaseOfLoader - 100):00 = (BaseOfLoader - 100) * 10h
add ax, SectorNoOfFAT1 ; 此句执行之后的 ax 就是 FATEntry 所在的扇区号
mov cl, 2
call ReadSector ; 读取 FATEntry 所在的扇区, 一次读两个, 避免在边界发生错误, 因为一个 FATEntry 可能跨越两个扇区
pop dx
add bx, dx
mov ax, [es:bx]
cmp byte [bOdd], 1
jnz LABEL_EVEN_2
shr ax, 4
LABEL_EVEN_2:
and ax, 0FFFh
LABEL_GET_FAT_ENRY_OK:
pop bx
pop es
ret
;----------------------------------------------------------------------------
times 510-($-$$) db 0 ; 填充剩下的空间使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志

View File

@ -1,43 +0,0 @@
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; fat12hdr.inc
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; FAT12 磁盘的头
; ----------------------------------------------------------------------
BS_OEMName DB 'ForrestY' ; OEM String, 必须 8 个字节
BPB_BytsPerSec DW 512 ; 每扇区字节数
BPB_SecPerClus DB 1 ; 每簇多少扇区
BPB_RsvdSecCnt DW 1 ; Boot 记录占用多少扇区
BPB_NumFATs DB 2 ; 共有多少 FAT
BPB_RootEntCnt DW 224 ; 根目录文件数最大值
BPB_TotSec16 DW 2880 ; 逻辑扇区总数
BPB_Media DB 0xF0 ; 媒体描述符
BPB_FATSz16 DW 9 ; 每FAT扇区数
BPB_SecPerTrk DW 18 ; 每磁道扇区数
BPB_NumHeads DW 2 ; 磁头数(面数)
BPB_HiddSec DD 0 ; 隐藏扇区数
BPB_TotSec32 DD 0 ; 如果 wTotalSectorCount 0 由这个值记录扇区数
BS_DrvNum DB 0 ; 中断 13 的驱动器号
BS_Reserved1 DB 0 ; 未使用
BS_BootSig DB 29h ; 扩展引导标记 (29h)
BS_VolID DD 0 ; 卷序列号
BS_VolLab DB 'OrangeS0.02'; 卷标, 必须 11 个字节
BS_FileSysType DB 'FAT12 ' ; 文件系统类型, 必须 8个字节
;------------------------------------------------------------------------
; -------------------------------------------------------------------------
; 基于 FAT12 头的一些常量定义,如果头信息改变,下面的常量可能也要做相应改变
; -------------------------------------------------------------------------
FATSz equ 9 ; BPB_FATSz16
RootDirSectors equ 14 ; 根目录占用空间: RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec 1)) / BPB_BytsPerSec; 但如果按照此公式代码过长
SectorNoOfRootDirectory equ 19 ; Root Directory 的第一个扇区号 = BPB_RsvdSecCnt + (BPB_NumFATs * FATSz)
SectorNoOfFAT1 equ 1 ; FAT1 的第一个扇区号 = BPB_RsvdSecCnt
DeltaSectorNo equ 17 ; DeltaSectorNo = BPB_RsvdSecCnt + (BPB_NumFATs * FATSz) - 2
; 文件的开始Sector号 = DirEntry中的开始Sector号 + 根目录占用Sector数目 + DeltaSectorNo

View File

@ -1,34 +0,0 @@
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; load.inc
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BaseOfLoader equ 09000h ; LOADER.BIN 被加载到的位置 ---- 段地址
OffsetOfLoader equ 0100h ; LOADER.BIN 被加载到的位置 ---- 偏移地址
BaseOfLoaderPhyAddr equ BaseOfLoader * 10h ; LOADER.BIN 被加载到的位置 ---- 物理地址 (= BaseOfLoader * 10h)
;modified by xw, 18/6/12
; BaseOfKernelFile equ 08000h ; KERNEL.BIN 被加载到的位置 ---- 段地址
BaseOfKernelFile equ 07000h ;
OffsetOfKernelFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址
BaseOfEchoFile equ 07E0h ; KERNEL.BIN 被加载到的位置 ---- 段地址
OffsetOfEchoFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址
BaseOfKernelFilePhyAddr equ BaseOfKernelFile * 10h
BaseOfEchoFilePhyAddr equ BaseOfKernelFile * 10h
KernelEntryPointPhyAddr equ 0C0030400h ; 注意1、必须与 MAKEFILE 中参数 -Ttext 的值相等!! edit by visual 2016.5.10
; 2、这是个地址而非仅仅是个偏移,如果 -Ttext 的值为 0x400400,则它的值也应该是 0x400400
PageDirBase equ 200000h ; 页目录开始地址: 2M
PageTblBase equ 201000h ; 页表开始地址: 2M + 4K
PageTblNumAddr equ 500h;页表数量放在这个位置 delete by visual 2016.4.28
FMIBuff equ 007ff000h

View File

@ -1,322 +0,0 @@
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; pm.inc
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; 描述符图示
; 图示一
;
; ------ ┏━━┳━━┓高地址
; 7
; ┣━━┫
;
; 字节 7
;
; ┣━━┫
; 0
; ------ ┣━━╋━━┫
; 7 G
; ┣━━╉──┨
; 6 D
; ┣━━╉──┨
; 5 0
; ┣━━╉──┨
; 4 AVL┃
; 字节 6 ┣━━╉──┨
; 3
; ┣━━┫
; 2
; ┣━━┫
; 1
; ┣━━┫
; 0
; ------ ┣━━╋━━┫
; 7 P
; ┣━━╉──┨
; 6
; ┣━━┫ DPL┃
; 5
; ┣━━╉──┨
; 4 S
; 字节 5 ┣━━╉──┨
; 3
; ┣━━┫ T
; 2 Y
; ┣━━┫ P
; 1 E
; ┣━━┫
; 0
; ------ ┣━━╋━━┫
; 23
; ┣━━┫
; 22
; ┣━━┫
;
; 字节
; 2, 3, 4
; ┣━━┫
; 1
; ┣━━┫
; 0
; ------ ┣━━╋━━┫
; 15
; ┣━━┫
; 14
; ┣━━┫
;
; 字节 0,1
;
; ┣━━┫
; 1
; ┣━━┫
; 0
; ------ ┗━━┻━━┛低地址
;
; 图示二
; 高地址………………………………………………………………………低地址
; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
; |7654321076543210765432107654321076543210765432107654321076543210| <- 8 字节
; |--------========--------========--------========--------========|
; ┏━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┓
; ┃31..24 (见下图) 段基址(23..0) 段界限(15..0)
;
; 基址2┃③│②│ ①┃基址1b│ 基址1a 段界限1
; ┣━━━╋━━━┳━━━╋━━━━━━━━━━━╋━━━━━━━┫
; %6 %5 %4 %3 %2 %1
; ┗━━━┻━━━┻━━━┻━━━┻━━━━━━━┻━━━━━━━┛
; \_________
; \__________________
; \________________________________________________
; \
; ┏━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┓
; 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
; ┣━━╋━━╋━━╋━━╋━━┻━━┻━━┻━━╋━━╋━━┻━━╋━━╋━━┻━━┻━━┻━━┫
; G D 0 AVL┃ 段界限 2 (19..16) P DPL S TYPE
; ┣━━┻━━┻━━┻━━╋━━━━━━━━━━━╋━━┻━━━━━┻━━┻━━━━━━━━━━━┫
; : 属性 2 : 段界限 2 : 属性1
; ┗━━━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━┛
; 高地址 低地址
;
;
; 说明:
;
; (1) P: 存在(Present)位。
; P=1 表示描述符对地址转换是有效的,或者说该描述符所描述的段存在,即在内存中;
; P=0 表示描述符对地址转换无效,即该段不存在。使用该描述符进行内存访问时会引起异常。
;
; (2) DPL: 表示描述符特权级(Descriptor Privilege level)共2位。它规定了所描述段的特权级用于特权检查以决定对该段能否访问。
;
; (3) S: 说明描述符的类型。
; 对于存储段描述符而言S=1,以区别与系统段描述符和门描述符(S=0)
;
; (4) TYPE: 说明存储段描述符所描述的存储段的具体属性。
;
;
; 数据段类型 类型值 说明
; ----------------------------------
; 0 只读
; 1 只读、已访问
; 2 /
; 3 /写、已访问
; 4 只读、向下扩展
; 5 只读、向下扩展、已访问
; 6 /写、向下扩展
; 7 /写、向下扩展、已访问
;
;
; 类型值 说明
; 代码段类型 ----------------------------------
; 8 只执行
; 9 只执行、已访问
; A 执行/
; B 执行/读、已访问
; C 只执行、一致码段
; D 只执行、一致码段、已访问
; E 执行/读、一致码段
; F 执行/读、一致码段、已访问
;
;
; 系统段类型 类型编码 说明
; ----------------------------------
; 0 <未定义>
; 1 可用286TSS
; 2 LDT
; 3 忙的286TSS
; 4 286调用门
; 5 任务门
; 6 286中断门
; 7 286陷阱门
; 8 未定义
; 9 可用386TSS
; A <未定义>
; B 忙的386TSS
; C 386调用门
; D <未定义>
; E 386中断门
; F 386陷阱门
;
; (5) G: 段界限粒度(Granularity)位。
; G=0 表示界限粒度为字节;
; G=1 表示界限粒度为4K 字节。
; 注意,界限粒度只对段界限有效,对段基地址无效,段基地址总是以字节为单位。
;
; (6) D: D位是一个很特殊的位在描述可执行段、向下扩展数据段或由SS寄存器寻址的段(通常是堆栈段)的三种描述符中的意义各不相同。
; 在描述可执行段的描述符中D位决定了指令使用的地址及操作数所默认的大小。
; D=1表示默认情况下指令使用32位地址及32位或8位操作数这样的代码段也称为32位代码段
; D=0 表示默认情况下使用16位地址及16位或8位操作数这样的代码段也称为16位代码段它与80286兼容。可以使用地址大小前缀和操作数大小前缀分别改变默认的地址或操作数的大小。
; 在向下扩展数据段的描述符中D位决定段的上部边界。
; D=1表示段的上部界限为4G
; D=0表示段的上部界限为64K这是为了与80286兼容。
; 在描述由SS寄存器寻址的段描述符中D位决定隐式的堆栈访问指令(如PUSH和POP指令)使用何种堆栈指针寄存器。
; D=1表示使用32位堆栈指针寄存器ESP
; D=0表示使用16位堆栈指针寄存器SP这与80286兼容。
;
; (7) AVL: 软件可利用位。80386对该位的使用未左规定Intel公司也保证今后开发生产的处理器只要与80386兼容就不会对该位的使用做任何定义或规定。
;
;----------------------------------------------------------------------------
; 描述符类型值说明
; 其中:
; DA_ : Descriptor Attribute
; D : 数据段
; C : 代码段
; S : 系统段
; R : 只读
; RW : 读写
; A : 已访问
; 其它 : 可按照字面意思理解
;----------------------------------------------------------------------------
DA_32 EQU 4000h ; 32 位段
DA_LIMIT_4K EQU 8000h ; 段界限粒度为 4K 字节
DA_DPL0 EQU 00h ; DPL = 0
DA_DPL1 EQU 20h ; DPL = 1
DA_DPL2 EQU 40h ; DPL = 2
DA_DPL3 EQU 60h ; DPL = 3
;----------------------------------------------------------------------------
; 存储段描述符类型值说明
;----------------------------------------------------------------------------
DA_DR EQU 90h ; 存在的只读数据段类型值
DA_DRW EQU 92h ; 存在的可读写数据段属性值
DA_DRWA EQU 93h ; 存在的已访问可读写数据段类型值
DA_C EQU 98h ; 存在的只执行代码段属性值
DA_CR EQU 9Ah ; 存在的可执行可读代码段属性值
DA_CCO EQU 9Ch ; 存在的只执行一致代码段属性值
DA_CCOR EQU 9Eh ; 存在的可执行可读一致代码段属性值
;----------------------------------------------------------------------------
; 系统段描述符类型值说明
;----------------------------------------------------------------------------
DA_LDT EQU 82h ; 局部描述符表段类型值
DA_TaskGate EQU 85h ; 任务门类型值
DA_386TSS EQU 89h ; 可用 386 任务状态段类型值
DA_386CGate EQU 8Ch ; 386 调用门类型值
DA_386IGate EQU 8Eh ; 386 中断门类型值
DA_386TGate EQU 8Fh ; 386 陷阱门类型值
;----------------------------------------------------------------------------
; 选择子图示:
; ┏━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┓
; 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
; ┣━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━╋━━╋━━┻━━┫
; 描述符索引 TI RPL
; ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━┻━━━━━┛
;
; RPL(Requested Privilege Level): 请求特权级,用于特权检查。
;
; TI(Table Indicator): 引用描述符表指示位
; TI=0 指示从全局描述符表GDT中读取描述符
; TI=1 指示从局部描述符表LDT中读取描述符。
;
;----------------------------------------------------------------------------
; 选择子类型值说明
; 其中:
; SA_ : Selector Attribute
SA_RPL0 EQU 0 ;
SA_RPL1 EQU 1 ; RPL
SA_RPL2 EQU 2 ;
SA_RPL3 EQU 3 ;
SA_TIG EQU 0 ; ┓TI
SA_TIL EQU 4 ;
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
; 分页机制使用的常量说明
;----------------------------------------------------------------------------
PG_P EQU 1 ; 页存在属性位
PG_RWR EQU 0 ; R/W 属性位值, /执行
PG_RWW EQU 2 ; R/W 属性位值, //执行
PG_USS EQU 0 ; U/S 属性位值, 系统级
PG_USU EQU 4 ; U/S 属性位值, 用户级
;----------------------------------------------------------------------------
; =========================================
; FLAGS - Intel 8086 Family Flags Register
; =========================================
;
; |11|10|F|E|D|C|B|A|9|8|7|6|5|4|3|2|1|0|
; | | | | | | | | | | | | | | | | | '--- CF……Carry Flag
; | | | | | | | | | | | | | | | | '--- 1
; | | | | | | | | | | | | | | | '--- PF……Parity Flag
; | | | | | | | | | | | | | | '--- 0
; | | | | | | | | | | | | | '--- AF……Auxiliary Flag
; | | | | | | | | | | | | '--- 0
; | | | | | | | | | | | '--- ZF……Zero Flag
; | | | | | | | | | | '--- SF……Sign Flag
; | | | | | | | | | '--- TF……Trap Flag (Single Step)
; | | | | | | | | '--- IF……Interrupt Flag
; | | | | | | | '--- DF……Direction Flag
; | | | | | | '--- OF……Overflow flag
; | | | | '----- IOPL……I/O Privilege Level (286+ only)
; | | | '----- NT……Nested Task Flag (286+ only)
; | | '----- 0
; | '----- RF……Resume Flag (386+ only)
; '------ VM……Virtual Mode Flag (386+ only)
;
; : see PUSHF POPF STI CLI STD CLD
;
; ------------------------------------------------------------------------------------------------------
;
; 描述符
; usage: Descriptor Base, Limit, Attr
; Base: dd
; Limit: dd (low 20 bits available)
; Attr: dw (lower 4 bits of higher byte are always 0)
%macro Descriptor 3
dw %2 & 0FFFFh ; 段界限 1 (2 字节)
dw %1 & 0FFFFh ; 段基址 1 (2 字节)
db (%1 >> 16) & 0FFh ; 段基址 2 (1 字节)
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性 1 + 段界限 2 + 属性 2 (2 字节)
db (%1 >> 24) & 0FFh ; 段基址 3 (1 字节)
%endmacro ; 8 字节
;
;
; usage: Gate Selector, Offset, DCount, Attr
; Selector: dw
; Offset: dd
; DCount: db
; Attr: db
%macro Gate 4
dw (%2 & 0FFFFh) ; 偏移 1 (2 字节)
dw %1 ; 选择子 (2 字节)
dw (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性 (2 字节)
dw ((%2 >> 16) & 0FFFFh) ; 偏移 2 (2 字节)
%endmacro ; 8 字节
; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File diff suppressed because it is too large Load Diff

View File

@ -1,253 +0,0 @@
;==============================================================================================================================
BaseOfStack equ 0x07c00 ; Boot状态下堆栈基地址
DATA_BUF_OFF equ 0x2000 ; 目录被加载的缓冲区地址
STACK_ADDR equ 0x7bea ; 堆栈栈顶
OSLOADER_SEG equ 0x09000 ; 起始段地址
OSLOADER_SEG_OFF equ 0x0100
FAT_START_SECTOR equ 0x820 ; FAT表的起始扇区号 DWORD
DATA_START_SECTOR equ 0xd6a ; 数据区起始扇区号 DWORD
DIR_PER_SECTOR equ 0x10 ; 每个扇区所容纳的目录 BYTE
; 扩展磁盘服务所使用的地址包
DAP_SECTOR_HIGH equ 4 ; 起始扇区号的高32位 ( 每次调用需要重置 ) DWORD
DAP_SECTOR_LOW equ 8 ; 起始扇区号的低32位 ( 每次调用需要重置 ) DWORD
DAP_BUFFER_SEG equ 10 ; 缓冲区段地址 ( 每次调用需要重置 ) WORD
DAP_BUFFER_OFF equ 12 ; 缓冲区偏移 ( 每次调用需要重置 ) WORD
DAP_RESERVED2 equ 13 ; 保留字节
DAP_READ_SECTORS equ 14 ; 要处理的扇区数(1 - 127 )
DAP_RESERVED1 equ 15 ; 保留字节
DAP_PACKET_SIZE equ 16 ; 包的大小为16字节
CURRENT_CLUSTER equ 20 ; 当前正在处理的簇号 DWORD
; 目录项结构
OFF_START_CLUSTER_HIGH equ 20 ; 起始簇号高位 WORD
OFF_START_CLUSTER_LOW equ 26 ; 起始簇号低位 WORD
; 相关常量
DIR_NAME_FREE equ 0x00 ; 该项是空闲的
DIR_ENTRY_SIZE equ 32 ; 每个目录项的尺寸
; 簇属性
CLUSTER_MASK equ 0FFFFFFFH ; 簇号掩码
CLUSTER_LAST equ 0FFFFFF8H ;0xFFFFFFF8-0xFFFFFFFF表示文件的最后一个簇
;==============================================================================================================================
org 07c00h
jmp START
nop
BS_OEM DB 'mkfs.fat' ;文件系统标志
BPB_BytesPerSec DW 0x200 ;每扇区字节数
BPB_SecPerClu DB 1 ;每簇扇区数
BPB_RsvdSecCnt DW 0x20 ;保留扇区数
BPB_NumFATs DB 2 ;FAT表数
BPB_RootEntCnt DW 0 ;FAT32不使用
BPB_TotSec16 DW 0 ;扇区总数
BPB_Media DB 0xf8 ;介质描述符
BPB_FATSz16 DW 0 ;每个FAT表的大小扇区数
BPB_SecPerTrk DW 0x3f ;每磁道扇区数
BPB_NumHeads DW 0xff ;磁头数
BPB_HiddSec DD 0 ;分区已使用扇区数
BPB_TotSec32 DD 0x015791 ;文件系统大小扇区数
BS_SecPerFAT DD 0x02a5 ;每个FAT表大小扇区数
BS_Flag DW 0 ;标记
BS_Version DW 0 ;版本号
BS_RootClus DD 2 ;根目录簇号
BS_FsInfoSec DW 1 ;FSINFO扇区号
BS_BackBootSec DW 6 ;备份引导扇区位置
BS_Unuse1 DD 0 ;未使用
BS_Unuse2 DD 0 ;未使用
BS_Unuse3 DD 0 ;未使用
BS_DriveNum DB 0x80 ;设备号
BS_Unuse4 DB 0x01 ;未使用
BS_ExtBootFlag DB 0x29 ;扩展引导标志
BS_VolNum DD 0xbe3a8ff5 ;卷序列号
BS_VolName DB 'MZY hd boot' ;卷标
START:
cld
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, STACK_ADDR
mov bp, BaseOfStack
mov dword [bp - DAP_SECTOR_HIGH ], 00h
mov byte [bp - DAP_RESERVED1 ], 00h
mov byte [bp - DAP_RESERVED2 ], 00h
mov byte [bp - DAP_PACKET_SIZE ], 10h
mov byte [bp - DAP_READ_SECTORS], 01h
mov byte [bp - DAP_BUFFER_SEG ], 00h
jmp _SEARCH_LOADER
_MISSING_LOADER: ; 显示没有装载程序
_DISK_ERROR: ; 显示磁盘错误信息
JMP $
ReadSector:
pusha
mov ah, 42h
lea si, [BP - DAP_PACKET_SIZE]
mov dl, [BS_DriveNum]
int 13h
jc _DISK_ERROR
popa
ret
_SEARCH_LOADER:
mov word [bp - DAP_BUFFER_OFF], DATA_BUF_OFF
mov eax, dword [BS_RootClus]
mov dword [bp - CURRENT_CLUSTER], eax
_NEXT_ROOT_CLUSTER:
dec eax
dec eax
xor ebx, ebx
mov bl, byte [BPB_SecPerClu]
mul ebx
add eax, DATA_START_SECTOR
mov dword [BP - DAP_SECTOR_LOW], eax
mov dl, [BPB_SecPerClu]
_NEXT_ROOT_SECTOR:
call ReadSector
mov di, DATA_BUF_OFF
mov bl, DIR_PER_SECTOR
_NEXT_ROOT_ENTRY:
cmp byte [di], DIR_NAME_FREE
jz _MISSING_LOADER
push di;
mov si, LoaderName
mov cx, 10
repe cmpsb
jcxz _FOUND_LOADER
pop di
add di, DIR_ENTRY_SIZE
dec bl
jnz _NEXT_ROOT_ENTRY
dec dl
jz _CHECK_NEXT_ROOT_CLUSTER
inc dword [bp - DAP_SECTOR_LOW]
jmp _NEXT_ROOT_SECTOR
_CHECK_NEXT_ROOT_CLUSTER:
; 计算FAT所在的簇号和偏移
; FatOffset = ClusterNum*4
XOR EDX,EDX
MOV EAX,DWORD[BP - CURRENT_CLUSTER]
SHL EAX,2
XOR ECX,ECX
MOV CX,WORD [ BPB_BytesPerSec ]
DIV ECX ; EAX = Sector EDX = OFFSET
ADD EAX, FAT_START_SECTOR
MOV DWORD [ BP - DAP_SECTOR_LOW ], EAX
call ReadSector
; 检查下一个簇
MOV DI,DX
ADD DI,DATA_BUF_OFF
MOV EAX,DWORD[DI] ; EAX = 下一个要读的簇号
AND EAX,CLUSTER_MASK
MOV DWORD[ BP - CURRENT_CLUSTER ],EAX
CMP EAX,CLUSTER_LAST ; CX >= 0FFFFFF8H则意味着没有更多的簇了
JB _NEXT_ROOT_CLUSTER
JMP _MISSING_LOADER
_FOUND_LOADER:
; 目录结构地址放在DI中
pop di
xor eax, eax
mov ax, [di + OFF_START_CLUSTER_HIGH] ; 起始簇号高32位
shl ax, 16
mov ax, [di + OFF_START_CLUSTER_LOW] ; 起始簇号低32位
mov dword [ bp - CURRENT_CLUSTER ], eax
mov cx, OSLOADER_SEG ; CX = 缓冲区段地址
_NEXT_DATA_CLUSTER:
; 根据簇号计算扇区号
DEC EAX
DEC EAX
XOR EBX,EBX
MOV BL, BYTE [ BPB_SecPerClu ]
MUL EBX
ADD EAX, DATA_START_SECTOR
MOV DWORD[ BP - DAP_SECTOR_LOW ], EAX
MOV BL , BYTE [BPB_SecPerClu]
; 设置缓冲区
MOV WORD [ BP - DAP_BUFFER_SEG ], CX
MOV WORD [ BP - DAP_BUFFER_OFF ], OSLOADER_SEG_OFF
_NEXT_DATA_SECTOR:
; 读取簇中的每个扇区(内层循环)
; 注意 : 通过检查文件大小,可以避免读取最后一个不满簇的所有大小
call ReadSector
; 更新地址,继续读取
MOV AX, WORD [BPB_BytesPerSec]
ADD WORD [BP - DAP_BUFFER_OFF], ax
INC DWORD [BP - DAP_SECTOR_LOW] ; 递增扇区号
DEC BL ; 内层循环计数
JNZ _NEXT_DATA_SECTOR
; 更新读取下一个簇的缓冲区地址
MOV CL, BYTE [ BPB_SecPerClu ]
MOV AX, WORD [BPB_BytesPerSec]
SHR AX, 4
MUL CL
ADD AX, WORD [ BP - DAP_BUFFER_SEG ]
MOV CX, AX ; 保存下一个簇的缓冲区段地址
;====================================================================
; 检查是否还有下一个簇(读取FAT表的相关信息)
; LET N = 数据簇号
; THUS FAT_BYTES = N*4 (FAT32)
; FAT_SECTOR = FAT_BYTES / BPB_BytesPerSec
; FAT_OFFSET = FAT_BYTES % BPB_BytesPerSec
;====================================================================
; 计算FAT所在的簇号和偏移
MOV EAX,DWORD [BP - CURRENT_CLUSTER]
XOR EDX,EDX
SHL EAX,2
XOR EBX,EBX
MOV BX,WORD [ BPB_BytesPerSec ]
DIV EBX ; EAX = Sector EDX = Offset
; 设置缓冲区地址
ADD EAX, FAT_START_SECTOR
MOV DWORD [ BP - DAP_SECTOR_LOW ], EAX
MOV WORD [BP - DAP_BUFFER_SEG ], 00H
MOV WORD [BP - DAP_BUFFER_OFF ], DATA_BUF_OFF
; 读取扇区
CALL ReadSector
; 检查下一个簇
MOV DI,DX
ADD DI,DATA_BUF_OFF
MOV EAX,DWORD[DI] ; EAX = 下一个要读的簇号
AND EAX,CLUSTER_MASK
MOV DWORD[ BP - CURRENT_CLUSTER ],EAX
CMP EAX,CLUSTER_LAST ; CX >= 0FFFFFF8H则意味着没有更多的簇了
JB _NEXT_DATA_CLUSTER
_RUN_LOADER:
mov dl, [BS_DriveNum]
jmp OSLOADER_SEG:OSLOADER_SEG_OFF
LoaderName db "LOADER BIN" ; 第二阶段启动程序 FDOSLDR.BIN
times 510-($-$$) db 0 ; 填充剩下的空间使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志

View File

@ -1,8 +0,0 @@
set default=0
set timeout=5
menuentry "myboot" {
set root=(hd0,msdos1)
chainloader +1
boot
}

View File

@ -1,28 +0,0 @@
BS_OEM DB 'mkfs.fat'
BPB_BytesPerSec DW 0x200
BPB_SecPerClu DB 1
BPB_RsvdSecCnt DW 0x20
BPB_NumFATs DB 2
BPB_RootEntCnt DW 0
BPB_TotSec16 DW 0
BPB_Media DB 0xf8
BPB_FATSz16 DW 0
BPB_SecPerTrk DW 0x20
BPB_NumHeads DW 0x40
BPB_HiddSec DD 0
BPB_TotSec32 DD 0x015791
BS_SecPerFAT DD 0x02a5
BS_Flag DW 0
BS_Version DW 0
BS_RootClus DD 2
BS_FsInfoSec DW 1
BS_BackBootSec DW 6
BS_Unuse1 DD 0
BS_Unuse2 DD 0
BS_Unuse3 DD 0
BS_DriveNum DB 0x80
BS_Unuse4 DB 0
BS_ExtBootFlag DB 0x29
BS_VolNum DD 0xbe3a8ff5
BS_VolName DB 'MZY hd boot'

View File

@ -1,170 +0,0 @@
; ------------------------------------------------------------------------
; 显示 AL 中的数字
; ------------------------------------------------------------------------
DispAL:
push ecx
push edx
push edi
mov edi, [dwDispPos]
mov ah, 0Fh ; 0000b: 黑底 1111b: 白字
mov dl, al
shr al, 4
mov ecx, 2
.begin:
and al, 01111b
cmp al, 9
ja .1
add al, '0'
jmp .2
.1:
sub al, 0Ah
add al, 'A'
.2:
mov [gs:edi], ax
add edi, 2
mov al, dl
loop .begin
;add edi, 2
mov [dwDispPos], edi
pop edi
pop edx
pop ecx
ret
; DispAL 结束-------------------------------------------------------------
; ------------------------------------------------------------------------
; 显示一个整形数
; ------------------------------------------------------------------------
DispInt:
mov eax, [esp + 4]
shr eax, 24
call DispAL
mov eax, [esp + 4]
shr eax, 16
call DispAL
mov eax, [esp + 4]
shr eax, 8
call DispAL
mov eax, [esp + 4]
call DispAL
mov ah, 07h ; 0000b: 黑底 0111b: 灰字
mov al, 'h'
push edi
mov edi, [dwDispPos]
mov [gs:edi], ax
add edi, 4
mov [dwDispPos], edi
pop edi
ret
; DispInt 结束------------------------------------------------------------
; ------------------------------------------------------------------------
; 显示一个字符串
; ------------------------------------------------------------------------
DispStr:
push ebp
mov ebp, esp
push ebx
push esi
push edi
mov esi, [ebp + 8] ; pszInfo
mov edi, [dwDispPos]
mov ah, 0Fh
.1:
lodsb
test al, al
jz .2
cmp al, 0Ah ; 是回车吗?
jnz .3
push eax
mov eax, edi
mov bl, 160
div bl
and eax, 0FFh
inc eax
mov bl, 160
mul bl
mov edi, eax
pop eax
jmp .1
.3:
mov [gs:edi], ax
add edi, 2
jmp .1
.2:
mov [dwDispPos], edi
pop edi
pop esi
pop ebx
pop ebp
ret
; DispStr 结束------------------------------------------------------------
; ------------------------------------------------------------------------
; 换行
; ------------------------------------------------------------------------
DispReturn:
push szReturn
call DispStr ;printf("\n");
add esp, 4
ret
; DispReturn 结束---------------------------------------------------------
; ------------------------------------------------------------------------
; 内存拷贝,仿 memcpy
; ------------------------------------------------------------------------
; void* MemCpy(void* es:pDest, void* ds:pSrc, int iSize);
; ------------------------------------------------------------------------
MemCpy:
push ebp
mov ebp, esp
push esi
push edi
push ecx
mov edi, [ebp + 8] ; Destination
mov esi, [ebp + 12] ; Source
mov ecx, [ebp + 16] ; Counter
.1:
cmp ecx, 0 ; 判断计数器
jz .2 ; 计数器为零时跳出
mov al, [ds:esi] ;
inc esi ;
; 逐字节移动
mov byte [es:edi], al ;
inc edi ;
dec ecx ; 计数器减一
jmp .1 ; 循环
.2:
mov eax, [ebp + 8] ; 返回值
pop ecx
pop edi
pop esi
mov esp, ebp
pop ebp
ret ; 函数结束,返回
; MemCpy 结束-------------------------------------------------------------

View File

@ -1,61 +0,0 @@
;==============================================================================================================================
BaseOfStack equ 0x0100
STACK_ADDR equ 0x0ea
SEG_ADDR equ 0x09000
DATA_BUF_OFF equ 0x09000
FAT_START_SECTOR equ 0x820 ; FAT表的起始扇区号 DWORD
DATA_START_SECTOR equ 0xd6a ; 数据区起始扇区号 DWORD
DIR_PER_SECTOR equ 0x10 ; 每个扇区所容纳的目录 BYTE
; 扩展磁盘服务所使用的地址包
DAP_SECTOR_HIGH equ 4 ; 起始扇区号的高32位 ( 每次调用需要重置 ) DWORD
DAP_SECTOR_LOW equ 8 ; 起始扇区号的低32位 ( 每次调用需要重置 ) DWORD
DAP_BUFFER_SEG equ 10 ; 缓冲区段地址 ( 每次调用需要重置 ) WORD
DAP_BUFFER_OFF equ 12 ; 缓冲区偏移 ( 每次调用需要重置 ) WORD
DAP_RESERVED2 equ 13 ; 保留字节
DAP_READ_SECTORS equ 14 ; 要处理的扇区数(1 - 127 )
DAP_RESERVED1 equ 15 ; 保留字节
DAP_PACKET_SIZE equ 16 ; 包的大小为16字节
CURRENT_CLUSTER equ 20 ; 当前正在处理的簇号 DWORD
; 目录项结构
OFF_START_CLUSTER_HIGH equ 20 ; 起始簇号高位 WORD
OFF_START_CLUSTER_LOW equ 26 ; 起始簇号低位 WORD
; 相关常量
DIR_NAME_FREE equ 0x00 ; 该项是空闲的
DIR_ENTRY_SIZE equ 32 ; 每个目录项的尺寸
; 簇属性
CLUSTER_MASK equ 0FFFFFFFH ; 簇号掩码
CLUSTER_LAST equ 0FFFFFF8H ;0xFFFFFFF8-0xFFFFFFFF表示文件的最后一个簇
BaseOfLoader equ 09000h ; LOADER.BIN 被加载到的位置 ---- 段地址
OffsetOfLoader equ 0100h ; LOADER.BIN 被加载到的位置 ---- 偏移地址
BaseOfLoaderPhyAddr equ BaseOfLoader * 10h ; LOADER.BIN 被加载到的位置 ---- 物理地址 (= BaseOfLoader * 10h)
BaseOfKernelFile equ 06000h ; KERNEL.BIN 被加载到的位置 ---- 段地址
OffsetOfKernelFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址
BaseOfKernelFilePhyAddr equ BaseOfKernelFile * 10h
BaseOfEchoFile equ 07E0h ; KERNEL.BIN 被加载到的位置 ---- 段地址
OffsetOfEchoFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址
BaseOfEchoFilePhyAddr equ BaseOfKernelFile * 10h
KernelEntryPointPhyAddr equ 0xC0030400 ; 注意1、必须与 MAKEFILE 中参数 -Ttext 的值相等!!
; 2、这是个地址而非仅仅是个偏移
PageDirBase equ 200000h ; 页目录开始地址: 2M
PageTblBase equ 201000h ; 页表开始地址: 2M + 4K
PageTblNumAddr equ 500h;页表数量放在这个位置 delete by visual 2016.4.28
FMIBuff equ 007ff000h
;==============================================================================================================================

View File

@ -1,318 +0,0 @@
; 描述符图示
; 图示一
;
; ------ ┏━━┳━━┓高地址
; 7
; ┣━━┫
;
; 字节 7
;
; ┣━━┫
; 0
; ------ ┣━━╋━━┫
; 7 G
; ┣━━╉──┨
; 6 D
; ┣━━╉──┨
; 5 0
; ┣━━╉──┨
; 4 AVL┃
; 字节 6 ┣━━╉──┨
; 3
; ┣━━┫
; 2
; ┣━━┫
; 1
; ┣━━┫
; 0
; ------ ┣━━╋━━┫
; 7 P
; ┣━━╉──┨
; 6
; ┣━━┫ DPL┃
; 5
; ┣━━╉──┨
; 4 S
; 字节 5 ┣━━╉──┨
; 3
; ┣━━┫ T
; 2 Y
; ┣━━┫ P
; 1 E
; ┣━━┫
; 0
; ------ ┣━━╋━━┫
; 23
; ┣━━┫
; 22
; ┣━━┫
;
; 字节
; 2, 3, 4
; ┣━━┫
; 1
; ┣━━┫
; 0
; ------ ┣━━╋━━┫
; 15
; ┣━━┫
; 14
; ┣━━┫
;
; 字节 0,1
;
; ┣━━┫
; 1
; ┣━━┫
; 0
; ------ ┗━━┻━━┛低地址
;
; 图示二
; 高地址………………………………………………………………………低地址
; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
; |7654321076543210765432107654321076543210765432107654321076543210| <- 8 字节
; |--------========--------========--------========--------========|
; ┏━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┓
; ┃31..24 (见下图) 段基址(23..0) 段界限(15..0)
;
; 基址2┃③│②│ ①┃基址1b│ 基址1a 段界限1
; ┣━━━╋━━━┳━━━╋━━━━━━━━━━━╋━━━━━━━┫
; %6 %5 %4 %3 %2 %1
; ┗━━━┻━━━┻━━━┻━━━┻━━━━━━━┻━━━━━━━┛
; \_________
; \__________________
; \________________________________________________
; \
; ┏━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┓
; 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
; ┣━━╋━━╋━━╋━━╋━━┻━━┻━━┻━━╋━━╋━━┻━━╋━━╋━━┻━━┻━━┻━━┫
; G D 0 AVL┃ 段界限 2 (19..16) P DPL S TYPE
; ┣━━┻━━┻━━┻━━╋━━━━━━━━━━━╋━━┻━━━━━┻━━┻━━━━━━━━━━━┫
; : 属性 2 : 段界限 2 : 属性1
; ┗━━━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━┛
; 高地址 低地址
;
;
; 说明:
;
; (1) P: 存在(Present)位。
; P=1 表示描述符对地址转换是有效的,或者说该描述符所描述的段存在,即在内存中;
; P=0 表示描述符对地址转换无效,即该段不存在。使用该描述符进行内存访问时会引起异常。
;
; (2) DPL: 表示描述符特权级(Descriptor Privilege level)共2位。它规定了所描述段的特权级用于特权检查以决定对该段能否访问。
;
; (3) S: 说明描述符的类型。
; 对于存储段描述符而言S=1,以区别与系统段描述符和门描述符(S=0)
;
; (4) TYPE: 说明存储段描述符所描述的存储段的具体属性。
;
;
; 数据段类型 类型值 说明
; ----------------------------------
; 0 只读
; 1 只读、已访问
; 2 /
; 3 /写、已访问
; 4 只读、向下扩展
; 5 只读、向下扩展、已访问
; 6 /写、向下扩展
; 7 /写、向下扩展、已访问
;
;
; 类型值 说明
; 代码段类型 ----------------------------------
; 8 只执行
; 9 只执行、已访问
; A 执行/
; B 执行/读、已访问
; C 只执行、一致码段
; D 只执行、一致码段、已访问
; E 执行/读、一致码段
; F 执行/读、一致码段、已访问
;
;
; 系统段类型 类型编码 说明
; ----------------------------------
; 0 <未定义>
; 1 可用286TSS
; 2 LDT
; 3 忙的286TSS
; 4 286调用门
; 5 任务门
; 6 286中断门
; 7 286陷阱门
; 8 未定义
; 9 可用386TSS
; A <未定义>
; B 忙的386TSS
; C 386调用门
; D <未定义>
; E 386中断门
; F 386陷阱门
;
; (5) G: 段界限粒度(Granularity)位。
; G=0 表示界限粒度为字节;
; G=1 表示界限粒度为4K 字节。
; 注意,界限粒度只对段界限有效,对段基地址无效,段基地址总是以字节为单位。
;
; (6) D: D位是一个很特殊的位在描述可执行段、向下扩展数据段或由SS寄存器寻址的段(通常是堆栈段)的三种描述符中的意义各不相同。
; 在描述可执行段的描述符中D位决定了指令使用的地址及操作数所默认的大小。
; D=1表示默认情况下指令使用32位地址及32位或8位操作数这样的代码段也称为32位代码段
; D=0 表示默认情况下使用16位地址及16位或8位操作数这样的代码段也称为16位代码段它与80286兼容。可以使用地址大小前缀和操作数大小前缀分别改变默认的地址或操作数的大小。
; 在向下扩展数据段的描述符中D位决定段的上部边界。
; D=1表示段的上部界限为4G
; D=0表示段的上部界限为64K这是为了与80286兼容。
; 在描述由SS寄存器寻址的段描述符中D位决定隐式的堆栈访问指令(如PUSH和POP指令)使用何种堆栈指针寄存器。
; D=1表示使用32位堆栈指针寄存器ESP
; D=0表示使用16位堆栈指针寄存器SP这与80286兼容。
;
; (7) AVL: 软件可利用位。80386对该位的使用未左规定Intel公司也保证今后开发生产的处理器只要与80386兼容就不会对该位的使用做任何定义或规定。
;
;----------------------------------------------------------------------------
; 描述符类型值说明
; 其中:
; DA_ : Descriptor Attribute
; D : 数据段
; C : 代码段
; S : 系统段
; R : 只读
; RW : 读写
; A : 已访问
; 其它 : 可按照字面意思理解
;----------------------------------------------------------------------------
DA_32 EQU 4000h ; 32 位段
DA_LIMIT_4K EQU 8000h ; 段界限粒度为 4K 字节
DA_DPL0 EQU 00h ; DPL = 0
DA_DPL1 EQU 20h ; DPL = 1
DA_DPL2 EQU 40h ; DPL = 2
DA_DPL3 EQU 60h ; DPL = 3
;----------------------------------------------------------------------------
; 存储段描述符类型值说明
;----------------------------------------------------------------------------
DA_DR EQU 90h ; 存在的只读数据段类型值
DA_DRW EQU 92h ; 存在的可读写数据段属性值
DA_DRWA EQU 93h ; 存在的已访问可读写数据段类型值
DA_C EQU 98h ; 存在的只执行代码段属性值
DA_CR EQU 9Ah ; 存在的可执行可读代码段属性值
DA_CCO EQU 9Ch ; 存在的只执行一致代码段属性值
DA_CCOR EQU 9Eh ; 存在的可执行可读一致代码段属性值
;----------------------------------------------------------------------------
; 系统段描述符类型值说明
;----------------------------------------------------------------------------
DA_LDT EQU 82h ; 局部描述符表段类型值
DA_TaskGate EQU 85h ; 任务门类型值
DA_386TSS EQU 89h ; 可用 386 任务状态段类型值
DA_386CGate EQU 8Ch ; 386 调用门类型值
DA_386IGate EQU 8Eh ; 386 中断门类型值
DA_386TGate EQU 8Fh ; 386 陷阱门类型值
;----------------------------------------------------------------------------
; 选择子图示:
; ┏━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┓
; 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
; ┣━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━╋━━╋━━┻━━┫
; 描述符索引 TI RPL
; ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━┻━━━━━┛
;
; RPL(Requested Privilege Level): 请求特权级,用于特权检查。
;
; TI(Table Indicator): 引用描述符表指示位
; TI=0 指示从全局描述符表GDT中读取描述符
; TI=1 指示从局部描述符表LDT中读取描述符。
;
;----------------------------------------------------------------------------
; 选择子类型值说明
; 其中:
; SA_ : Selector Attribute
SA_RPL0 EQU 0 ;
SA_RPL1 EQU 1 ; RPL
SA_RPL2 EQU 2 ;
SA_RPL3 EQU 3 ;
SA_TIG EQU 0 ; ┓TI
SA_TIL EQU 4 ;
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
; 分页机制使用的常量说明
;----------------------------------------------------------------------------
PG_P EQU 1 ; 页存在属性位
PG_RWR EQU 0 ; R/W 属性位值, /执行
PG_RWW EQU 2 ; R/W 属性位值, //执行
PG_USS EQU 0 ; U/S 属性位值, 系统级
PG_USU EQU 4 ; U/S 属性位值, 用户级
;----------------------------------------------------------------------------
; =========================================
; FLAGS - Intel 8086 Family Flags Register
; =========================================
;
; |11|10|F|E|D|C|B|A|9|8|7|6|5|4|3|2|1|0|
; | | | | | | | | | | | | | | | | | '--- CF……Carry Flag
; | | | | | | | | | | | | | | | | '--- 1
; | | | | | | | | | | | | | | | '--- PF……Parity Flag
; | | | | | | | | | | | | | | '--- 0
; | | | | | | | | | | | | | '--- AF……Auxiliary Flag
; | | | | | | | | | | | | '--- 0
; | | | | | | | | | | | '--- ZF……Zero Flag
; | | | | | | | | | | '--- SF……Sign Flag
; | | | | | | | | | '--- TF……Trap Flag (Single Step)
; | | | | | | | | '--- IF……Interrupt Flag
; | | | | | | | '--- DF……Direction Flag
; | | | | | | '--- OF……Overflow flag
; | | | | '----- IOPL……I/O Privilege Level (286+ only)
; | | | '----- NT……Nested Task Flag (286+ only)
; | | '----- 0
; | '----- RF……Resume Flag (386+ only)
; '------ VM……Virtual Mode Flag (386+ only)
;
; : see PUSHF POPF STI CLI STD CLD
;
; ------------------------------------------------------------------------------------------------------
;
; 描述符
; usage: Descriptor Base, Limit, Attr
; Base: dd
; Limit: dd (low 20 bits available)
; Attr: dw (lower 4 bits of higher byte are always 0)
%macro Descriptor 3
dw %2 & 0FFFFh ; 段界限 1 (2 字节)
dw %1 & 0FFFFh ; 段基址 1 (2 字节)
db (%1 >> 16) & 0FFh ; 段基址 2 (1 字节)
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性 1 + 段界限 2 + 属性 2 (2 字节)
db (%1 >> 24) & 0FFh ; 段基址 3 (1 字节)
%endmacro ; 8 字节
;
;
; usage: Gate Selector, Offset, DCount, Attr
; Selector: dw
; Offset: dd
; DCount: db
; Attr: db
%macro Gate 4
dw (%2 & 0FFFFh) ; 偏移 1 (2 字节)
dw %1 ; 选择子 (2 字节)
dw (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性 (2 字节)
dw ((%2 >> 16) & 0FFFFh) ; 偏移 2 (2 字节)
%endmacro ; 8 字节
; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File diff suppressed because it is too large Load Diff