diff --git a/boot/floppy/boot.asm b/boot/floppy/boot.asm deleted file mode 100644 index 789912c..0000000 --- a/boot/floppy/boot.asm +++ /dev/null @@ -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 ; 结束标志 diff --git a/boot/floppy/include/fat12hdr.inc b/boot/floppy/include/fat12hdr.inc deleted file mode 100644 index b199a1b..0000000 --- a/boot/floppy/include/fat12hdr.inc +++ /dev/null @@ -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 diff --git a/boot/floppy/include/load.inc b/boot/floppy/include/load.inc deleted file mode 100644 index 5a57c98..0000000 --- a/boot/floppy/include/load.inc +++ /dev/null @@ -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 \ No newline at end of file diff --git a/boot/floppy/include/pm.inc b/boot/floppy/include/pm.inc deleted file mode 100644 index ee4c012..0000000 --- a/boot/floppy/include/pm.inc +++ /dev/null @@ -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 字节 -; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/boot/floppy/loader.asm b/boot/floppy/loader.asm deleted file mode 100644 index f25167c..0000000 --- a/boot/floppy/loader.asm +++ /dev/null @@ -1,1061 +0,0 @@ - -; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -; loader.asm -; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -; Forrest Yu, 2005 -; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - -org 0100h - - jmp LABEL_START ; Start - -; 下面是 FAT12 磁盘的头, 之所以包含它是因为下面用到了磁盘的一些信息 -%include "fat12hdr.inc" -%include "load.inc" -%include "pm.inc" - - -; GDT ------------------------------------------------------------------------------------------------------------------------------------------------------------ -; 段基址 段界限 , 属性 -LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符 -LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR | DA_32 | DA_LIMIT_4K ; 0 ~ 4G -LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW | DA_32 | DA_LIMIT_4K ; 0 ~ 4G -LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW | DA_DPL3 ; 显存首地址 -; GDT ------------------------------------------------------------------------------------------------------------------------------------------------------------ - -GdtLen equ $ - LABEL_GDT -GdtPtr dw GdtLen - 1 ; 段界限 - dd BaseOfLoaderPhyAddr + LABEL_GDT ; 基地址 - -; GDT 选择子 ---------------------------------------------------------------------------------- -SelectorFlatC equ LABEL_DESC_FLAT_C - LABEL_GDT -SelectorFlatRW equ LABEL_DESC_FLAT_RW - LABEL_GDT -SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT + SA_RPL3 -; GDT 选择子 ---------------------------------------------------------------------------------- - - -BaseOfStack equ 0100h - - -LABEL_START: ; <--- 从这里开始 ************* - mov ax, cs - mov ds, ax - mov es, ax - mov ss, ax - mov sp, BaseOfStack - - mov dh, 0 ; "Loading " - call DispStrRealMode ; 显示字符串 - - ; 得到内存数 - mov ebx, 0 ; ebx = 后续值, 开始时需为 0 - mov di, _MemChkBuf ; es:di 指向一个地址范围描述符结构(Address Range Descriptor Structure) -.MemChkLoop: - mov eax, 0E820h ; eax = 0000E820h - mov ecx, 20 ; ecx = 地址范围描述符结构的大小 - mov edx, 0534D4150h ; edx = 'SMAP' - int 15h ; int 15h - jc .MemChkFail - add di, 20 - inc dword [_dwMCRNumber] ; dwMCRNumber = ARDS 的个数 - cmp ebx, 0 - jne .MemChkLoop - jmp .MemChkOK -.MemChkFail: - mov dword [_dwMCRNumber], 0 -.MemChkOK: - - ; 下面在 A 盘的根目录寻找 KERNEL.BIN - mov word [wSectorNo], SectorNoOfRootDirectory - xor ah, ah ; ┓ - xor dl, dl ; ┣ 软驱复位 - int 13h ; ┛ -LABEL_SEARCH_IN_ROOT_DIR_BEGIN: - cmp word [wRootDirSizeForLoop], 0 ; ┓ - jz LABEL_NO_KERNELBIN ; ┣ 判断根目录区是不是已经读完, 如果读完表示没有找到 KERNEL.BIN - dec word [wRootDirSizeForLoop] ; ┛ - mov ax, BaseOfKernelFile - mov es, ax ; es <- BaseOfKernelFile - mov bx, OffsetOfKernelFile ; bx <- OffsetOfKernelFile 于是, es:bx = BaseOfKernelFile:OffsetOfKernelFile = BaseOfKernelFile * 10h + OffsetOfKernelFile - mov ax, [wSectorNo] ; ax <- Root Directory 中的某 Sector 号 - mov cl, 1 - call ReadSector - - mov si, KernelFileName ; ds:si -> "KERNEL BIN" - mov di, OffsetOfKernelFile ; es:di -> BaseOfKernelFile:???? = BaseOfKernelFile*10h+???? - cld - mov dx, 10h -LABEL_SEARCH_FOR_KERNELBIN: - cmp dx, 0 ; ┓ - jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR ; ┣ 循环次数控制, 如果已经读完了一个 Sector, 就跳到下一个 Sector - dec dx ; ┛ - 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] ; if al == es:di - jz LABEL_GO_ON - jmp LABEL_DIFFERENT -LABEL_GO_ON: - inc di - jmp LABEL_CMP_FILENAME ; 继续循环 - -LABEL_DIFFERENT: - and di, 0FFE0h ; else┓ 这时di的值不知道是什么, di &= e0 为了让它是 20h 的倍数 - add di, 20h ; ┃ - mov si, KernelFileName ; ┣ di += 20h 下一个目录条目 - jmp LABEL_SEARCH_FOR_KERNELBIN; ┛ - -LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR: - add word [wSectorNo], 1 - jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN - -LABEL_NO_KERNELBIN: - mov dh, 2 ; "No KERNEL." - call DispStrRealMode ; 显示字符串 - jmp $ ; 没有找到 KERNEL.BIN, 死循环在这里 - -LABEL_FILENAME_FOUND: ; 找到 KERNEL.BIN 后便来到这里继续 - mov ax, RootDirSectors - and di, 0FFF0h ; di -> 当前条目的开始 - - push eax - mov eax, [es : di + 01Ch] ; ┓ - mov dword [dwKernelSize], eax ; ┛保存 KERNEL.BIN 文件大小 - pop eax - - 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, BaseOfKernelFile - mov es, ax ; es <- BaseOfKernelFile - mov bx, OffsetOfKernelFile ; bx <- OffsetOfKernelFile 于是, es:bx = BaseOfKernelFile:OffsetOfKernelFile = BaseOfKernelFile * 10h + OffsetOfKernelFile - mov ax, cx ; ax <- Sector 号 - -LABEL_GOON_LOADING_FILE: - push ax ; ┓ - push bx ; ┃ - mov ah, 0Eh ; ┃ 每读一个扇区就在 "Loading " 后面打一个点, 形成这样的效果: - mov al, '.' ; ┃ - mov bl, 0Fh ; ┃ Loading ...... - 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] -;to support the kernel.bin larger than 64KB -;copied from Orange's_9_h, xw, 18/6/12 - jc .1 ;if bx becomes 0, indicates that the kernel is larger than 64KB - jmp .2 -.1: - push ax ;es += 0x1000, points to next segment - mov ax, es - add ax, 1000h - mov es, ax - pop ax -.2: -;~xw - jmp LABEL_GOON_LOADING_FILE -LABEL_FILE_LOADED: - - call KillMotor ; 关闭软驱马达 - - mov dh, 1 ; "Ready." - call DispStrRealMode ; 显示字符串 - -;;add begin add by liang 2016.04.20 -EXE_LABEL_START: ; <--- 从这里开始 ************* - mov ax, cs - mov ds, ax - mov es, ax - mov ss, ax - mov sp, BaseOfStack - - mov dh, 3 ; "exLoading" - call DispStrRealMode ; 显示字符串 - - - ; 下面在 A 盘的根目录寻找 ECHO - mov word [wSectorNo], SectorNoOfRootDirectory - xor ah, ah ; ┓ - xor dl, dl ; ┣ 软驱复位 - int 13h ; ┛ -EXE_LABEL_SEARCH_IN_ROOT_DIR_BEGIN: - cmp word [wRootDirSizeForLoop], 0 ; ┓ - jz EXE_LABEL_NO_ECHO ; ┣ 判断根目录区是不是已经读完, 如果读完表示没有找到 ECHO - dec word [wRootDirSizeForLoop] ; ┛ - mov ax, BaseOfEchoFile - mov es, ax ; es <- BaseOfEchoFile - mov bx, OffsetOfEchoFile ; bx <- OffsetOfEchoFile 于是, es:bx = BaseOfEchoFile:OffsetOfEchoFile = BaseOfEchoFile * 10h + OffsetOfEchoFile - mov ax, [wSectorNo] ; ax <- Root Directory 中的某 Sector 号 - mov cl, 1 - call ReadSector - - mov si, EchoFileName ; ds:si -> "echo bin" - mov di, OffsetOfEchoFile ; es:di -> BaseOfEchoFile:???? = BaseOfEchoFile*10h+???? - cld - mov dx, 10h -EXE_LABEL_SEARCH_FOR_ECHO: - cmp dx, 0 ; ┓ - jz EXE_LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR ; ┣ 循环次数控制, 如果已经读完了一个 Sector, 就跳到下一个 Sector - dec dx ; ┛ - mov cx, 11 -EXE_LABEL_CMP_FILENAME: - cmp cx, 0 ; ┓ - jz EXE_LABEL_FILENAME_FOUND; ┣ 循环次数控制, 如果比较了 11 个字符都相等, 表示找到 - dec cx ; ┛ - lodsb ; ds:si -> al - cmp al, byte [es:di] ; if al == es:di - jz EXE_LABEL_GO_ON - jmp EXE_LABEL_DIFFERENT -EXE_LABEL_GO_ON: - inc di - jmp EXE_LABEL_CMP_FILENAME ; 继续循环 - -EXE_LABEL_DIFFERENT: - and di, 0FFE0h ; else┓ 这时di的值不知道是什么, di &= e0 为了让它是 20h 的倍数 - add di, 20h ; ┃ - mov si, EchoFileName ; ┣ di += 20h 下一个目录条目 - jmp EXE_LABEL_SEARCH_FOR_ECHO ; ┛ - -EXE_LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR: - add word [wSectorNo], 1 - jmp EXE_LABEL_SEARCH_IN_ROOT_DIR_BEGIN - -EXE_LABEL_NO_ECHO: - mov dh, 5 ; "No ECHO " - call DispStrRealMode ; 显示字符串 - jmp $ ; 没有找到 echo, 死循环在这里 - -EXE_LABEL_FILENAME_FOUND: ; 找到 echo 后便来到这里继续 - mov ax, RootDirSectors - and di, 0FFF0h ; di -> 当前条目的开始 - - push eax - mov eax, [es : di + 01Ch] ; ┓ - mov dword [_dwEchoSize], eax ; ┛保存 echo 文件大小 - pop eax - - add di, 01Ah ; di -> 首 Sector - mov cx, word [es:di] - push cx ; 保存此 Sector 在 FAT 中的序号 - add cx, ax - add cx, DeltaSectorNo ; 这时 cl 里面是 echo 的起始扇区号 (从 0 开始数的序号) - mov ax, BaseOfEchoFile - mov es, ax ; es <- BaseOfEchoFile - mov bx, OffsetOfEchoFile ; bx <- OffsetOfEchoFile 于是, es:bx = BaseOfEchoFile:OffsetOfEchoFile = BaseOfEchoFile * 10h + OffsetOfEchoFile - mov ax, cx ; ax <- Sector 号 - -EXE_LABEL_GOON_LOADING_FILE: - push ax ; ┓ - push bx ; ┃ - mov ah, 0Eh ; ┃ 每读一个扇区就在 "exLoading" 后面打一个点, 形成这样的效果: - mov al, '.' ; ┃ - mov bl, 0Fh ; ┃ exLoading...... - int 10h ; ┃ - pop bx ; ┃ - pop ax ; ┛ - - mov cl, 1 - call ReadSector - pop ax ; 取出此 Sector 在 FAT 中的序号 - call GetFATEntry - cmp ax, 0FFFh - jz EXE_LABEL_FILE_LOADED - push ax ; 保存 Sector 在 FAT 中的序号 - mov dx, RootDirSectors - add ax, dx - add ax, DeltaSectorNo - add bx, [BPB_BytsPerSec] - jmp EXE_LABEL_GOON_LOADING_FILE -EXE_LABEL_FILE_LOADED: - - call KillMotor ; 关闭软驱马达 - mov dh, 4 ; "exReady." - call DispStrRealMode ; 显示字符串 - -;;add end add by liang 2016.04.20 -; 下面准备跳入保护模式 ------------------------------------------- - -; 加载 GDTR - lgdt [GdtPtr] - -; 关中断 - cli - -; 打开地址线A20 - in al, 92h - or al, 00000010b - out 92h, al - -; 准备切换到保护模式 - mov eax, cr0 - or eax, 1 - mov cr0, eax - -; 真正进入保护模式 - jmp dword SelectorFlatC:(BaseOfLoaderPhyAddr+LABEL_PM_START) - - -;============================================================================ -;变量 -;---------------------------------------------------------------------------- -wRootDirSizeForLoop dw RootDirSectors ; Root Directory 占用的扇区数 -wSectorNo dw 0 ; 要读取的扇区号 -bOdd db 0 ; 奇数还是偶数 -dwKernelSize dd 0 ; KERNEL.BIN 文件大小 -_dwEchoSize dd 0 ;echo size add by liang 2016.04.20 -;============================================================================ -;字符串 -;---------------------------------------------------------------------------- -KernelFileName db "KERNEL BIN", 0 ; KERNEL.BIN 之文件名 -EchoFileName db "INIT BIN", 0 ;add by liang 2016.04.20 ;edit by visual 2016.5.16 -; 为简化代码, 下面每个字符串的长度均为 MessageLength -MessageLength equ 9 -LoadMessage: db "Loading " -Message1 db "Ready. " -Message2 db "No KERNEL" -Message3 db "exLoading" ;add by liang 2016.04.20 -Message4 db "exReady. " ;add by liang 2016.04.20 -Message5 db "No ECHO " ;add by liang 2016.04.20 -;============================================================================ - -;---------------------------------------------------------------------------- -; 函数名: DispStrRealMode -;---------------------------------------------------------------------------- -; 运行环境: -; 实模式(保护模式下显示字符串由函数 DispStr 完成) -; 作用: -; 显示一个字符串, 函数开始时 dh 中应该是字符串序号(0-based) -DispStrRealMode: - mov ax, MessageLength - mul dh - add ax, LoadMessage - 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 - add dh, 3 ; 从第 3 行往下显示 - int 10h ; int 10h - ret -;---------------------------------------------------------------------------- -; 函数名: ReadSector -;---------------------------------------------------------------------------- -; 作用: -; 从序号(Directory Entry 中的 Sector 号)为 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, BaseOfKernelFile ; ┓ - sub ax, 0100h ; ┣ 在 BaseOfKernelFile 后面留出 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 = (BaseOfKernelFile - 100):00 = (BaseOfKernelFile - 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 -;---------------------------------------------------------------------------- - - -;---------------------------------------------------------------------------- -; 函数名: KillMotor -;---------------------------------------------------------------------------- -; 作用: -; 关闭软驱马达 -KillMotor: - push dx - mov dx, 03F2h - mov al, 0 - out dx, al - pop dx - ret -;---------------------------------------------------------------------------- - - -; 从此以后的代码在保护模式下执行 ---------------------------------------------------- -; 32 位代码段. 由实模式跳入 --------------------------------------------------------- -[SECTION .s32] - -ALIGN 32 - -[BITS 32] - -LABEL_PM_START: - mov ax, SelectorVideo - mov gs, ax - mov ax, SelectorFlatRW - mov ds, ax - mov es, ax - mov fs, ax - mov ss, ax - mov esp, TopOfStack - - push szMemChkTitle - call DispStr - add esp, 4 - - call DispMemInfo - call getFreeMemInfo ;add by liang 2016.04.13 - call DispEchoSize ;add by liang 2016.04.21 - call SetupPaging - - ;mov ah, 0Fh ; 0000: 黑底 1111: 白字 - ;mov al, 'P' - ;mov [gs:((80 * 0 + 39) * 2)], ax ; 屏幕第 0 行, 第 39 列。 - - call InitKernel - - ;jmp $ - - ;*************************************************************** - jmp SelectorFlatC:KernelEntryPointPhyAddr ; 正式进入内核 * - ;*************************************************************** - ; 内存看上去是这样的: - ; ┃ ┃ - ; ┃ . ┃ - ; ┃ . ┃ - ; ┃ . ┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; ┃■■■■■■Page Tables■■■■■■■■■■■■■■■■■■┃ - ; ┃■■■■■(大小由LOADER决定)■■■■■■■■■■■■■┃ - ; 00101000h ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ PageTblBase - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; 00100000h ┃■■■■Page Directory Table■■■■■■■■■■■■┃ PageDirBase <- 1M - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ - ; F0000h ┃□□□□□□□System ROM□□□□□□□□□□□□□□□□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ - ; E0000h ┃□□□□Expansion of system ROM □□□□□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ - ; C0000h ┃□□□Reserved for ROM expansion□□□□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ B8000h ← gs - ; A0000h ┃□□□Display adapter reserved□□□□□□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ - ; 9FC00h ┃□□extended BIOS data area (EBDA)□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; 90000h ┃■■■■■■■LOADER.BIN■■■■■■■■■■■■■■■■■■■┃ somewhere in LOADER ← esp - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; 80000h ┃■■■■■■■KERNEL.BIN■■■■■■■■■■■■■■■■■■■┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; 30000h ┃■■■■■■■■KERNEL■■■■■■■■■■■■■■■■■■■■■■┃ 30400h ← KERNEL 入口 (KernelEntryPointPhyAddr) - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃ ┃ - ; 7E00h ┃ F R E E ┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; 7C00h ┃■■■■■■BOOT SECTOR■■■■■■■■■■■■■■■■■■┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃ ┃ - ; 500h ┃ F R E E ┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ - ; 400h ┃□□□□ROM BIOS parameter area □□□□□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇┃ - ; 0h ┃◇◇◇◇◇◇Int Vectors◇◇◇◇◇◇┃ - ; ┗━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss - ; - ; - ; ┏━━━┓ ┏━━━┓ - ; ┃■■■■■■┃ 我们使用 ┃□□□□□□┃ 不能使用的内存 - ; ┗━━━┛ ┗━━━┛ - ; ┏━━━┓ ┏━━━┓ - ; ┃ ┃ 未使用空间 ┃◇◇◇┃ 可以覆盖的内存 - ; ┗━━━┛ ┗━━━┛ - ; - ; 注:KERNEL 的位置实际上是很灵活的,可以通过同时改变 LOAD.INC 中的 KernelEntryPointPhyAddr 和 MAKEFILE 中参数 -Ttext 的值来改变。 - ; 比如,如果把 KernelEntryPointPhyAddr 和 -Ttext 的值都改为 0x400400,则 KERNEL 就会被加载到内存 0x400000(4M) 处,入口在 0x400400。 - ; - - - - -; ------------------------------------------------------------------------ -; 显示 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 结束------------------------------------------------------------- - -;;;;;;;;;;;;;;;;;add begin add by liang 2016.04.13;;;;;;;;;;;;;;;;;;;;; - -memtest: - push edi - push esi - - mov esi,0xaa55aa55 - mov edi,0x55aa55aa - mov eax,[esp+8+4] ;start -.mt_loop: - mov ebx,eax - add ebx,0xffc ;检查每4KB最后4B - mov ecx,[ebx] ;保存原值 - mov [ebx],esi ;写入 - xor dword [ebx],0xffffffff ;反转 - cmp edi,[ebx] ;检查反转结果是否正确 - jne .mt_fin - xor dword [ebx],0xffffffff ;再次反转 - cmp esi,[ebx] ;检查是否恢复初始值 - jne .mt_fin - mov [ebx],ecx ;恢复为修改前的值 - add eax,0x1000 ;每循环一次加0x1000 - cmp eax,[esp+8+8] ;未到end,循环 - jbe .mt_loop - pop esi - pop edi - ret - -.mt_fin: - mov [ebx],ecx ;恢复为修改前的值 - pop esi - pop edi - ret - -getFreeMemInfo: - push eax - push ebx - push ecx - push edx - - mov eax,cr0 - or eax,0x60000000 ;禁止缓存 - mov cr0,eax - - mov ebx,0x00000000 ;检查0到32M - mov ecx,0x02000000 - mov edx,FMIBuff ;存于0x007ff000处 - -.fmi_loop: - push ecx - push ebx - call memtest - pop ebx - pop ecx - mov [edx+4],eax ;留出前4B存放dwFMINumber - add edx,4 - add eax,0x1000 - mov ebx,eax - inc dword [dwFMINumber] ;循环次数,即返回值个数 - cmp ebx,ecx - jb .fmi_loop - - mov ebx,[dwFMINumber] - mov edx,FMIBuff - mov [edx],ebx ;前4B存放返回值个数 - mov ebx,[FMIBuff] - push ebx - call DispInt ;打印返回值个数 - add esp,4 - - mov eax,cr0 - and eax,0x9fffffff ;恢复缓存 - mov cr0,eax - - pop edx - pop ecx - pop ebx - pop eax - ret - - -;;;;;;;;;;;;;;;;;;;;;;;;;;add end add by liang 2016.04.13;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;add begin add by liang 2016.04.21 -DispEchoSize: - push eax - mov eax,[dwEchoSize] - push eax - call DispInt - add esp,4 - pop eax - ret -;;add end add by liang 2016.04.21 - -; 显示内存信息 -------------------------------------------------------------- -DispMemInfo: - push esi - push edi - push ecx - - mov esi, MemChkBuf - mov ecx, [dwMCRNumber] ;for(int i=0;i<[MCRNumber];i++) // 每次得到一个ARDS(Address Range Descriptor Structure)结构 -.loop: ;{ - mov edx, 5 ; for(int j=0;j<5;j++) // 每次得到一个ARDS中的成员,共5个成员 - mov edi, ARDStruct ; { // 依次显示:BaseAddrLow,BaseAddrHigh,LengthLow,LengthHigh,Type -.1: ; - push dword [esi] ; - call DispInt ; DispInt(MemChkBuf[j*4]); // 显示一个成员 - pop eax ; - stosd ; ARDStruct[j*4] = MemChkBuf[j*4]; - add esi, 4 ; - dec edx ; - cmp edx, 0 ; - jnz .1 ; } - call DispReturn ; printf("\n"); - cmp dword [dwType], 1 ; if(Type == AddressRangeMemory) // AddressRangeMemory : 1, AddressRangeReserved : 2 - jne .2 ; { - mov eax, [dwBaseAddrLow] ; - add eax, [dwLengthLow] ; - cmp eax, [dwMemSize] ; if(BaseAddrLow + LengthLow > MemSize) - jb .2 ; - mov [dwMemSize], eax ; MemSize = BaseAddrLow + LengthLow; -.2: ; } - loop .loop ;} - ; - call DispReturn ;printf("\n"); - push szRAMSize ; - call DispStr ;printf("RAM size:"); - add esp, 4 ; - ; - push dword [dwMemSize] ; - call DispInt ;DispInt(MemSize); - add esp, 4 ; - - pop ecx - pop edi - pop esi - ret -; --------------------------------------------------------------------------- - -; 启动分页机制 -------------------------------------------------------------- -SetupPaging: - ; 根据内存大小计算应初始化多少PDE以及多少页表 - xor edx, edx - mov eax, [dwMemSize] - mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小 - div ebx - mov ecx, eax ; 此时 ecx 为页表的个数,也即 PDE 应该的个数 - test edx, edx - jz .no_remainder - inc ecx ; 如果余数不为 0 就需增加一个页表 -.no_remainder: - push ecx ; 暂存页表个数 - mov dword[PageTblNumAddr],ecx ;将页表数写进这个物理地址 - - ; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞. - - ; 首先初始化页目录 - mov ax, SelectorFlatRW - mov es, ax - mov edi, PageDirBase ; 此段首地址为 PageDirBase - xor eax, eax - mov eax, PageTblBase | PG_P | PG_USU | PG_RWW -.1: - stosd - add eax, 4096 ; 为了简化, 所有页表在内存中是连续的. - loop .1 - -;;;;初始化3G处的页目录;;;;;;;;;;;;;;;; //add by visual 2016.5.10 - pop eax ;页表个数 - mov ecx,eax ;重新放到ecx里 - push ecx ;暂存页表个数 - mov ax, SelectorFlatRW - mov es, ax - mov eax, 3072 ;768*4 - add eax, PageDirBase ; - mov edi, eax ; 应该往页目录这个位置写: PageDirBase+768*4,即线性地址3G处 - - xor eax, eax ; 清0 - mov eax, ecx ; - mov ebx, 4096 ; - mul ebx ;跳过前ecx个页表,即PageTblBase+页表数*4096 - add eax, PageTblBase | PG_P | PG_USU | PG_RWW; -.1k: - stosd - add eax, 4096 ; 为了简化, 所有页表在内存中是连续的. - loop .1k -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - ; 再初始化所有页表(最开始处,一一映射的) - pop eax ; 页表个数 - push eax ;暂存页表个数 - mov ebx, 1024 ; 每个页表 1024 个 PTE - mul ebx - mov ecx, eax ; PTE个数 = 页表个数 * 1024 - mov edi, PageTblBase ; 此段首地址为 PageTblBase - xor eax, eax - mov eax, PG_P | PG_USU | PG_RWW -.2: - stosd - add eax, 4096 ; 每一页指向 4K 的空间 - loop .2 - -;;;;初始化3G处的页表;;;;;;;;;;;;;;;; //add by visual 2016.5.10 - ; 再初始化3G后的页表 - pop eax ; 页表个数 - mov ebx, 1024 ; 每个页表 1024 个 PTE - mul ebx - mov ecx, eax ; PTE个数 = 页表个数 * 1024 - - xor eax, eax ; 清0 - mov eax, ecx ; - mov ebx, 4 - mul ebx ;跳过前ecx个页表,即PageTblBase+页表数*4096 - add eax, PageTblBase ; 后面3G对应页表的起始位置为 PageTblBase+页表数*4096 - mov edi, eax - xor eax, eax - mov eax, PG_P | PG_USU | PG_RWW ;从0开始 -.2k: - stosd - add eax, 4096 ; 每一页指向 4K 的空间 - loop .2k -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - ;mov ah, 0Fh ; 0000: 黑底 1111: 白字 - ;mov al, 'P' - ;mov [gs:((80 * 0 + 39) * 2)], ax ; 屏幕第 0 行, 第 39 列。 - - ;启动页表机制 - mov eax, PageDirBase - mov cr3, eax - mov eax, cr0 - or eax, 80000000h - mov cr0, eax - jmp short .3 -.3: - nop - - ret -; 分页机制启动完毕 ---------------------------------------------------------- - - - -; InitKernel --------------------------------------------------------------------------------- -; 将 KERNEL.BIN 的内容经过整理对齐后放到新的位置 -; -------------------------------------------------------------------------------------------- -InitKernel: ; 遍历每一个 Program Header,根据 Program Header 中的信息来确定把什么放进内存,放到什么位置,以及放多少。 - xor esi, esi - mov cx, word [BaseOfKernelFilePhyAddr + 2Ch]; ┓ ecx <- pELFHdr->e_phnum - movzx ecx, cx ; ┛ - mov esi, [BaseOfKernelFilePhyAddr + 1Ch] ; esi <- pELFHdr->e_phoff - add esi, BaseOfKernelFilePhyAddr ; esi <- OffsetOfKernel + pELFHdr->e_phoff -.Begin: - mov eax, [esi + 0] - cmp eax, 0 ; PT_NULL - jz .NoAction - push dword [esi + 010h] ; size ┓ - mov eax, [esi + 04h] ; ┃ - add eax, BaseOfKernelFilePhyAddr ; ┣ ::memcpy( (void*)(pPHdr->p_vaddr), - push eax ; src ┃ uchCode + pPHdr->p_offset, - push dword [esi + 08h] ; dst ┃ pPHdr->p_filesz; - call MemCpy ; ┃ - add esp, 12 ; ┛ -.NoAction: - add esi, 020h ; esi += pELFHdr->e_phentsize - dec ecx - jnz .Begin - - ret -; InitKernel ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - -; SECTION .data1 之开始 --------------------------------------------------------------------------------------------- -[SECTION .data1] - -ALIGN 32 - -LABEL_DATA: -; 实模式下使用这些符号 -; 字符串 -_szMemChkTitle: db "BaseAddrL BaseAddrH LengthLow LengthHigh Type", 0Ah, 0 -_szRAMSize: db "RAM size:", 0 -_szReturn: db 0Ah, 0 -;; 变量 -_dwMCRNumber: dd 0 ; Memory Check Result -_dwDispPos: dd (80 * 6 + 0) * 2 ; 屏幕第 6 行, 第 0 列。 -_dwMemSize: dd 0 -_ARDStruct: ; Address Range Descriptor Structure - _dwBaseAddrLow: dd 0 - _dwBaseAddrHigh: dd 0 - _dwLengthLow: dd 0 - _dwLengthHigh: dd 0 - _dwType: dd 0 -_MemChkBuf: times 256 db 0 -_dwFMINumber: dd 0 ;add by liang 2016.04.13 - - -; -;; 保护模式下使用这些符号 -szMemChkTitle equ BaseOfLoaderPhyAddr + _szMemChkTitle -szRAMSize equ BaseOfLoaderPhyAddr + _szRAMSize -szReturn equ BaseOfLoaderPhyAddr + _szReturn -dwDispPos equ BaseOfLoaderPhyAddr + _dwDispPos -dwMemSize equ BaseOfLoaderPhyAddr + _dwMemSize -dwMCRNumber equ BaseOfLoaderPhyAddr + _dwMCRNumber -ARDStruct equ BaseOfLoaderPhyAddr + _ARDStruct - dwBaseAddrLow equ BaseOfLoaderPhyAddr + _dwBaseAddrLow - dwBaseAddrHigh equ BaseOfLoaderPhyAddr + _dwBaseAddrHigh - dwLengthLow equ BaseOfLoaderPhyAddr + _dwLengthLow - dwLengthHigh equ BaseOfLoaderPhyAddr + _dwLengthHigh - dwType equ BaseOfLoaderPhyAddr + _dwType -MemChkBuf equ BaseOfLoaderPhyAddr + _MemChkBuf -dwFMINumber equ BaseOfLoaderPhyAddr + _dwFMINumber ;add by liang 2016.04.13 -dwEchoSize equ BaseOfLoaderPhyAddr + _dwEchoSize ;add by liang 2016.04.21 - -; 堆栈就在数据段的末尾 -StackSpace: times 1000h db 0 -TopOfStack equ BaseOfLoaderPhyAddr + $ ; 栈顶 -; SECTION .data1 之结束 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - diff --git a/boot/grub/boot.asm b/boot/grub/boot.asm deleted file mode 100644 index 09f8fdb..0000000 --- a/boot/grub/boot.asm +++ /dev/null @@ -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 ; 结束标志 diff --git a/boot/grub/grub.cfg b/boot/grub/grub.cfg deleted file mode 100644 index 1c27541..0000000 --- a/boot/grub/grub.cfg +++ /dev/null @@ -1,8 +0,0 @@ -set default=0 -set timeout=5 - -menuentry "myboot" { - set root=(hd0,msdos1) - chainloader +1 - boot -} diff --git a/boot/grub/include/fat32.inc b/boot/grub/include/fat32.inc deleted file mode 100644 index 5ac98d9..0000000 --- a/boot/grub/include/fat32.inc +++ /dev/null @@ -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' - diff --git a/boot/grub/include/lib.inc b/boot/grub/include/lib.inc deleted file mode 100644 index 1faceea..0000000 --- a/boot/grub/include/lib.inc +++ /dev/null @@ -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 结束------------------------------------------------------------- - diff --git a/boot/grub/include/loader.inc b/boot/grub/include/loader.inc deleted file mode 100644 index 8050550..0000000 --- a/boot/grub/include/loader.inc +++ /dev/null @@ -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 - -;============================================================================================================================== - diff --git a/boot/grub/include/pm.inc b/boot/grub/include/pm.inc deleted file mode 100644 index 6d4c94c..0000000 --- a/boot/grub/include/pm.inc +++ /dev/null @@ -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 字节 -; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/boot/grub/loader.asm b/boot/grub/loader.asm deleted file mode 100644 index 08cc938..0000000 --- a/boot/grub/loader.asm +++ /dev/null @@ -1,1064 +0,0 @@ - -; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -; loader.asm -; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -; Forrest Yu, 2005 -; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - -org 0100h - - jmp LABEL_START ; Start - -; 下面是 FAT12 磁盘的头, 之所以包含它是因为下面用到了磁盘的一些信息 -%include "fat32.inc" -%include "loader.inc" -%include "pm.inc" - - -; GDT ------------------------------------------------------------------------------------------------------------------------------------------------------------ -; 段基址 段界限 , 属性 -LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符 -LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR | DA_32 | DA_LIMIT_4K ; 0 ~ 4G -LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW | DA_32 | DA_LIMIT_4K ; 0 ~ 4G -LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW | DA_DPL3 ; 显存首地址 -; GDT ------------------------------------------------------------------------------------------------------------------------------------------------------------ - -GdtLen equ $ - LABEL_GDT -GdtPtr dw GdtLen - 1 ; 段界限 - dd BaseOfLoaderPhyAddr + LABEL_GDT ; 基地址 - -; GDT 选择子 ---------------------------------------------------------------------------------- -SelectorFlatC equ LABEL_DESC_FLAT_C - LABEL_GDT -SelectorFlatRW equ LABEL_DESC_FLAT_RW - LABEL_GDT -SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT + SA_RPL3 -; GDT 选择子 ---------------------------------------------------------------------------------- - -LABEL_START: ; <--- 从这里开始 ************* - cld - mov ax, cs - 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 word [bp - DAP_BUFFER_SEG ], 0x09000 - - ; 得到内存数 - mov ebx, 0 ; ebx = 后续值, 开始时需为 0 - mov di, _MemChkBuf ; es:di 指向一个地址范围描述符结构(Address Range Descriptor Structure) -.MemChkLoop: - mov eax, 0E820h ; eax = 0000E820h - mov ecx, 20 ; ecx = 地址范围描述符结构的大小 - mov edx, 0534D4150h ; edx = 'SMAP' - int 15h ; int 15h - jc .MemChkFail - add di, 20 - inc dword [_dwMCRNumber] ; dwMCRNumber = ARDS 的个数 - cmp ebx, 0 - jne .MemChkLoop - jmp .MemChkOK -.MemChkFail: - mov dword [_dwMCRNumber], 0 -.MemChkOK: - - 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, KernelFileName - 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, BaseOfKernelFile ; 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 ], OffsetOfKernelFile - -_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 ], 0x09000 - 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 - - jmp EXE_SEARCH_LOADER - -EXE_MISSING_LOADER: -EXE_DISK_ERROR: - jmp $ - -EXE_SEARCH_LOADER: - mov word [bp - DAP_BUFFER_OFF], DATA_BUF_OFF - mov eax, dword [BS_RootClus] - mov dword [bp - CURRENT_CLUSTER], eax - -EXE_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] - -EXE_NEXT_ROOT_SECTOR: - call ReadSector - - mov di, DATA_BUF_OFF - mov bl, DIR_PER_SECTOR - -EXE_NEXT_ROOT_ENTRY: - cmp byte [di], DIR_NAME_FREE - jz EXE_MISSING_LOADER - - push di; - mov si, EchoFileName - mov cx, 10 - repe cmpsb - jcxz EXE_FOUND_LOADER - - pop di - add di, DIR_ENTRY_SIZE - dec bl - jnz EXE_NEXT_ROOT_ENTRY - - dec dl - jz EXE_CHECK_NEXT_ROOT_CLUSTER - inc dword [bp - DAP_SECTOR_LOW] - jmp EXE_NEXT_ROOT_SECTOR - -EXE_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 EXE_NEXT_ROOT_CLUSTER - JMP EXE_MISSING_LOADER - -EXE_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, BaseOfEchoFile ; CX = 缓冲区段地址 - -EXE_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 ], OffsetOfEchoFile - -EXE_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 EXE_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 ], 0x09000 - 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 EXE_NEXT_DATA_CLUSTER - -EXE_RUN_LOADER: - mov dl, [BS_DriveNum] - -;;add end add by liang 2016.04.20 -; 下面准备跳入保护模式 ------------------------------------------- - -; 加载 GDTR - lgdt [GdtPtr] - -; 关中断 - cli - -; 打开地址线A20 - in al, 92h - or al, 00000010b - out 92h, al - -; 准备切换到保护模式 - mov eax, cr0 - or eax, 1 - mov cr0, eax - -; 真正进入保护模式 - jmp dword SelectorFlatC:(BaseOfLoaderPhyAddr+LABEL_PM_START) - - -;============================================================================ -;变量 -;---------------------------------------------------------------------------- -wSectorNo dw 0 ; 要读取的扇区号 -bOdd db 0 ; 奇数还是偶数 -dwKernelSize dd 0 ; KERNEL.BIN 文件大小 -_dwEchoSize dd 0 ;echo size add by liang 2016.04.20 -;============================================================================ -;字符串 -;---------------------------------------------------------------------------- -KernelFileName db "KERNEL BIN", 0 ; KERNEL.BIN 之文件名 -EchoFileName db "INIT BIN", 0 ;add by liang 2016.04.20 ;edit by visual 2016.5.16 -; 为简化代码, 下面每个字符串的长度均为 MessageLength -MessageLength equ 9 -LoadMessage: db "Loading " -Message1 db "Ready. " -Message2 db "No KERNEL" -Message3 db "exLoading" ;add by liang 2016.04.20 -Message4 db "exReady. " ;add by liang 2016.04.20 -Message5 db "No ECHO " ;add by liang 2016.04.20 -;============================================================================ - -;---------------------------------------------------------------------------- -; 函数名: DispStrRealMode -;---------------------------------------------------------------------------- -; 运行环境: -; 实模式(保护模式下显示字符串由函数 DispStr 完成) -; 作用: -; 显示一个字符串, 函数开始时 dh 中应该是字符串序号(0-based) -DispStrRealMode: - mov ax, MessageLength - mul dh - add ax, LoadMessage - 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 - add dh, 3 ; 从第 3 行往下显示 - int 10h ; int 10h - ret -;---------------------------------------------------------------------------- - - -;---------------------------------------------------------------------------- -; 函数名: KillMotor -;---------------------------------------------------------------------------- -; 作用: -; 关闭软驱马达 -KillMotor: - push dx - mov dx, 03F2h - mov al, 0 - out dx, al - pop dx - ret -;---------------------------------------------------------------------------- - -; 从此以后的代码在保护模式下执行 ---------------------------------------------------- -; 32 位代码段. 由实模式跳入 --------------------------------------------------------- -[SECTION .s32] - -ALIGN 32 - -[BITS 32] - -LABEL_PM_START: - mov ax, SelectorVideo - mov gs, ax - mov ax, SelectorFlatRW - mov ds, ax - mov es, ax - mov fs, ax - mov ss, ax - mov esp, TopOfStack - - push szMemChkTitle - call DispStr - add esp, 4 - - call DispMemInfo - call getFreeMemInfo ;add by liang 2016.04.13 - call DispEchoSize ;add by liang 2016.04.21 - call SetupPaging - - ;mov ah, 0Fh ; 0000: 黑底 1111: 白字 - ;mov al, 'P' - ;mov [gs:((80 * 0 + 39) * 2)], ax ; 屏幕第 0 行, 第 39 列。 - - call InitKernel - - ;jmp $ - - ;*************************************************************** - jmp SelectorFlatC:KernelEntryPointPhyAddr ; 正式进入内核 * - ;*************************************************************** - ; 内存看上去是这样的: - ; ┃ ┃ - ; ┃ . ┃ - ; ┃ . ┃ - ; ┃ . ┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; ┃■■■■■■Page Tables■■■■■■■■■■■■■■■■■■┃ - ; ┃■■■■■(大小由LOADER决定)■■■■■■■■■■■■■┃ - ; 00101000h ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ PageTblBase - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; 00100000h ┃■■■■Page Directory Table■■■■■■■■■■■■┃ PageDirBase <- 1M - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ - ; F0000h ┃□□□□□□□System ROM□□□□□□□□□□□□□□□□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ - ; E0000h ┃□□□□Expansion of system ROM □□□□□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ - ; C0000h ┃□□□Reserved for ROM expansion□□□□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ B8000h ← gs - ; A0000h ┃□□□Display adapter reserved□□□□□□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ - ; 9FC00h ┃□□extended BIOS data area (EBDA)□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; 90000h ┃■■■■■■■LOADER.BIN■■■■■■■■■■■■■■■■■■■┃ somewhere in LOADER ← esp - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; 80000h ┃■■■■■■■KERNEL.BIN■■■■■■■■■■■■■■■■■■■┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; 30000h ┃■■■■■■■■KERNEL■■■■■■■■■■■■■■■■■■■■■■┃ 30400h ← KERNEL 入口 (KernelEntryPointPhyAddr) - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃ ┃ - ; 7E00h ┃ F R E E ┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■┃ - ; 7C00h ┃■■■■■■BOOT SECTOR■■■■■■■■■■■■■■■■■■┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃ ┃ - ; 500h ┃ F R E E ┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□┃ - ; 400h ┃□□□□ROM BIOS parameter area □□□□□□□□┃ - ; ┣━━━━━━━━━━━━━━━━━━┫ - ; ┃◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇┃ - ; 0h ┃◇◇◇◇◇◇Int Vectors◇◇◇◇◇◇┃ - ; ┗━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss - ; - ; - ; ┏━━━┓ ┏━━━┓ - ; ┃■■■■■■┃ 我们使用 ┃□□□□□□┃ 不能使用的内存 - ; ┗━━━┛ ┗━━━┛ - ; ┏━━━┓ ┏━━━┓ - ; ┃ ┃ 未使用空间 ┃◇◇◇┃ 可以覆盖的内存 - ; ┗━━━┛ ┗━━━┛ - ; - ; 注:KERNEL 的位置实际上是很灵活的,可以通过同时改变 LOAD.INC 中的 KernelEntryPointPhyAddr 和 MAKEFILE 中参数 -Ttext 的值来改变。 - ; 比如,如果把 KernelEntryPointPhyAddr 和 -Ttext 的值都改为 0x400400,则 KERNEL 就会被加载到内存 0x400000(4M) 处,入口在 0x400400。 - ; - - - - -; ------------------------------------------------------------------------ -; 显示 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 结束------------------------------------------------------------- - -;;;;;;;;;;;;;;;;;add begin add by liang 2016.04.13;;;;;;;;;;;;;;;;;;;;; - -memtest: - push edi - push esi - - mov esi,0xaa55aa55 - mov edi,0x55aa55aa - mov eax,[esp+8+4] ;start -.mt_loop: - mov ebx,eax - add ebx,0xffc ;检查每4KB最后4B - mov ecx,[ebx] ;保存原值 - mov [ebx],esi ;写入 - xor dword [ebx],0xffffffff ;反转 - cmp edi,[ebx] ;检查反转结果是否正确 - jne .mt_fin - xor dword [ebx],0xffffffff ;再次反转 - cmp esi,[ebx] ;检查是否恢复初始值 - jne .mt_fin - mov [ebx],ecx ;恢复为修改前的值 - add eax,0x1000 ;每循环一次加0x1000 - cmp eax,[esp+8+8] ;未到end,循环 - jbe .mt_loop - pop esi - pop edi - ret - -.mt_fin: - mov [ebx],ecx ;恢复为修改前的值 - pop esi - pop edi - ret - -getFreeMemInfo: - push eax - push ebx - push ecx - push edx - - mov eax,cr0 - or eax,0x60000000 ;禁止缓存 - mov cr0,eax - - mov ebx,0x00000000 ;检查0到32M - mov ecx,0x02000000 - mov edx,FMIBuff ;存于0x007ff000处 - -.fmi_loop: - push ecx - push ebx - call memtest - pop ebx - pop ecx - mov [edx+4],eax ;留出前4B存放dwFMINumber - add edx,4 - add eax,0x1000 - mov ebx,eax - inc dword [dwFMINumber] ;循环次数,即返回值个数 - cmp ebx,ecx - jb .fmi_loop - - mov ebx,[dwFMINumber] - mov edx,FMIBuff - mov [edx],ebx ;前4B存放返回值个数 - mov ebx,[FMIBuff] - push ebx - call DispInt ;打印返回值个数 - add esp,4 - - mov eax,cr0 - and eax,0x9fffffff ;恢复缓存 - mov cr0,eax - - pop edx - pop ecx - pop ebx - pop eax - ret - - -;;;;;;;;;;;;;;;;;;;;;;;;;;add end add by liang 2016.04.13;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;add begin add by liang 2016.04.21 -DispEchoSize: - push eax - mov eax,[dwEchoSize] - push eax - call DispInt - add esp,4 - pop eax - ret -;;add end add by liang 2016.04.21 - -; 显示内存信息 -------------------------------------------------------------- -DispMemInfo: - push esi - push edi - push ecx - - mov esi, MemChkBuf - mov ecx, [dwMCRNumber] ;for(int i=0;i<[MCRNumber];i++) // 每次得到一个ARDS(Address Range Descriptor Structure)结构 -.loop: ;{ - mov edx, 5 ; for(int j=0;j<5;j++) // 每次得到一个ARDS中的成员,共5个成员 - mov edi, ARDStruct ; { // 依次显示:BaseAddrLow,BaseAddrHigh,LengthLow,LengthHigh,Type -.1: ; - push dword [esi] ; - call DispInt ; DispInt(MemChkBuf[j*4]); // 显示一个成员 - pop eax ; - stosd ; ARDStruct[j*4] = MemChkBuf[j*4]; - add esi, 4 ; - dec edx ; - cmp edx, 0 ; - jnz .1 ; } - call DispReturn ; printf("\n"); - cmp dword [dwType], 1 ; if(Type == AddressRangeMemory) // AddressRangeMemory : 1, AddressRangeReserved : 2 - jne .2 ; { - mov eax, [dwBaseAddrLow] ; - add eax, [dwLengthLow] ; - cmp eax, [dwMemSize] ; if(BaseAddrLow + LengthLow > MemSize) - jb .2 ; - mov [dwMemSize], eax ; MemSize = BaseAddrLow + LengthLow; -.2: ; } - loop .loop ;} - ; - call DispReturn ;printf("\n"); - push szRAMSize ; - call DispStr ;printf("RAM size:"); - add esp, 4 ; - ; - push dword [dwMemSize] ; - call DispInt ;DispInt(MemSize); - add esp, 4 ; - - pop ecx - pop edi - pop esi - ret -; --------------------------------------------------------------------------- - -; 启动分页机制 -------------------------------------------------------------- -SetupPaging: - ; 根据内存大小计算应初始化多少PDE以及多少页表 - xor edx, edx - mov eax, [dwMemSize] - mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小 - div ebx - mov ecx, eax ; 此时 ecx 为页表的个数,也即 PDE 应该的个数 - test edx, edx - jz .no_remainder - inc ecx ; 如果余数不为 0 就需增加一个页表 -.no_remainder: - push ecx ; 暂存页表个数 - mov dword[PageTblNumAddr],ecx ;将页表数写进这个物理地址 - - ; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞. - - ; 首先初始化页目录 - mov ax, SelectorFlatRW - mov es, ax - mov edi, PageDirBase ; 此段首地址为 PageDirBase - xor eax, eax - mov eax, PageTblBase | PG_P | PG_USU | PG_RWW -.1: - stosd - add eax, 4096 ; 为了简化, 所有页表在内存中是连续的. - loop .1 - -;;;;初始化3G处的页目录;;;;;;;;;;;;;;;; //add by visual 2016.5.10 - pop eax ;页表个数 - mov ecx,eax ;重新放到ecx里 - push ecx ;暂存页表个数 - mov ax, SelectorFlatRW - mov es, ax - mov eax, 3072 ;768*4 - add eax, PageDirBase ; - mov edi, eax ; 应该往页目录这个位置写: PageDirBase+768*4,即线性地址3G处 - - xor eax, eax ; 清0 - mov eax, ecx ; - mov ebx, 4096 ; - mul ebx ;跳过前ecx个页表,即PageTblBase+页表数*4096 - add eax, PageTblBase | PG_P | PG_USU | PG_RWW; -.1k: - stosd - add eax, 4096 ; 为了简化, 所有页表在内存中是连续的. - loop .1k -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - ; 再初始化所有页表(最开始处,一一映射的) - pop eax ; 页表个数 - push eax ;暂存页表个数 - mov ebx, 1024 ; 每个页表 1024 个 PTE - mul ebx - mov ecx, eax ; PTE个数 = 页表个数 * 1024 - mov edi, PageTblBase ; 此段首地址为 PageTblBase - xor eax, eax - mov eax, PG_P | PG_USU | PG_RWW -.2: - stosd - add eax, 4096 ; 每一页指向 4K 的空间 - loop .2 - -;;;;初始化3G处的页表;;;;;;;;;;;;;;;; //add by visual 2016.5.10 - ; 再初始化3G后的页表 - pop eax ; 页表个数 - mov ebx, 1024 ; 每个页表 1024 个 PTE - mul ebx - mov ecx, eax ; PTE个数 = 页表个数 * 1024 - - xor eax, eax ; 清0 - mov eax, ecx ; - mov ebx, 4 - mul ebx ;跳过前ecx个页表,即PageTblBase+页表数*4096 - add eax, PageTblBase ; 后面3G对应页表的起始位置为 PageTblBase+页表数*4096 - mov edi, eax - xor eax, eax - mov eax, PG_P | PG_USU | PG_RWW ;从0开始 -.2k: - stosd - add eax, 4096 ; 每一页指向 4K 的空间 - loop .2k -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - ;mov ah, 0Fh ; 0000: 黑底 1111: 白字 - ;mov al, 'P' - ;mov [gs:((80 * 0 + 39) * 2)], ax ; 屏幕第 0 行, 第 39 列。 - - ;启动页表机制 - mov eax, PageDirBase - mov cr3, eax - mov eax, cr0 - or eax, 80000000h - mov cr0, eax - jmp short .3 -.3: - nop - - ret -; 分页机制启动完毕 ---------------------------------------------------------- - - - -; InitKernel --------------------------------------------------------------------------------- -; 将 KERNEL.BIN 的内容经过整理对齐后放到新的位置 -; -------------------------------------------------------------------------------------------- -InitKernel: ; 遍历每一个 Program Header,根据 Program Header 中的信息来确定把什么放进内存,放到什么位置,以及放多少。 - xor esi, esi - mov cx, word [BaseOfKernelFilePhyAddr + 2Ch]; ┓ ecx <- pELFHdr->e_phnum - movzx ecx, cx ; ┛ - mov esi, [BaseOfKernelFilePhyAddr + 1Ch] ; esi <- pELFHdr->e_phoff - add esi, BaseOfKernelFilePhyAddr ; esi <- OffsetOfKernel + pELFHdr->e_phoff -.Begin: - mov eax, [esi + 0] - cmp eax, 0 ; PT_NULL - jz .NoAction - push dword [esi + 010h] ; size ┓ - mov eax, [esi + 04h] ; ┃ - add eax, BaseOfKernelFilePhyAddr ; ┣ ::memcpy( (void*)(pPHdr->p_vaddr), - push eax ; src ┃ uchCode + pPHdr->p_offset, - push dword [esi + 08h] ; dst ┃ pPHdr->p_filesz; - call MemCpy ; ┃ - add esp, 12 ; ┛ -.NoAction: - add esi, 020h ; esi += pELFHdr->e_phentsize - dec ecx - jnz .Begin - - ret -; InitKernel ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - -; SECTION .data1 之开始 --------------------------------------------------------------------------------------------- -[SECTION .data1] - -ALIGN 32 - -LABEL_DATA: -; 实模式下使用这些符号 -; 字符串 -_szMemChkTitle: db "BaseAddrL BaseAddrH LengthLow LengthHigh Type", 0Ah, 0 -_szRAMSize: db "RAM size:", 0 -_szReturn: db 0Ah, 0 -;; 变量 -_dwMCRNumber: dd 0 ; Memory Check Result -_dwDispPos: dd (80 * 6 + 0) * 2 ; 屏幕第 6 行, 第 0 列。 -_dwMemSize: dd 0 -_ARDStruct: ; Address Range Descriptor Structure - _dwBaseAddrLow: dd 0 - _dwBaseAddrHigh: dd 0 - _dwLengthLow: dd 0 - _dwLengthHigh: dd 0 - _dwType: dd 0 -_MemChkBuf: times 256 db 0 -_dwFMINumber: dd 0 ;add by liang 2016.04.13 - - -; -;; 保护模式下使用这些符号 -szMemChkTitle equ BaseOfLoaderPhyAddr + _szMemChkTitle -szRAMSize equ BaseOfLoaderPhyAddr + _szRAMSize -szReturn equ BaseOfLoaderPhyAddr + _szReturn -dwDispPos equ BaseOfLoaderPhyAddr + _dwDispPos -dwMemSize equ BaseOfLoaderPhyAddr + _dwMemSize -dwMCRNumber equ BaseOfLoaderPhyAddr + _dwMCRNumber -ARDStruct equ BaseOfLoaderPhyAddr + _ARDStruct - dwBaseAddrLow equ BaseOfLoaderPhyAddr + _dwBaseAddrLow - dwBaseAddrHigh equ BaseOfLoaderPhyAddr + _dwBaseAddrHigh - dwLengthLow equ BaseOfLoaderPhyAddr + _dwLengthLow - dwLengthHigh equ BaseOfLoaderPhyAddr + _dwLengthHigh - dwType equ BaseOfLoaderPhyAddr + _dwType -MemChkBuf equ BaseOfLoaderPhyAddr + _MemChkBuf -dwFMINumber equ BaseOfLoaderPhyAddr + _dwFMINumber ;add by liang 2016.04.13 -dwEchoSize equ BaseOfLoaderPhyAddr + _dwEchoSize ;add by liang 2016.04.21 - -; 堆栈就在数据段的末尾 -StackSpace: times 1000h db 0 -TopOfStack equ BaseOfLoaderPhyAddr + $ ; 栈顶 -; SECTION .data1 之结束 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -