自制操作系统:MBR读盘并写入RAM中执行(着手开发操作系统)

计算机开机后,BIOS能自动装载MBR,但MBR大小限制在512B(\frac{1}{2}MB)内,这根本装不下我们做的操作系统。所以我们只能自己装载程序,让CPU继续执行我们的程序,为后面开发庞大的操作系统做准备。

一、核心功能

使用BIOS13号磁盘中断功能读盘

寄存器参数含义
AH不同磁盘功能(0x02写磁盘)
AL读取扇区数
BX读取磁盘内容后,存放在RAM的地址
DL        驱动器号(0表示第一个软盘,硬盘C:80H,硬盘D:81H)
返回值寄存器含义
EFLAGS:CF出错误为1

二、完整代码实现

mbr.asm

%define         ENDSTR  0
%define         UNKNOWN 1

%macro          PUTS 1
        MOV     SI,     %1
        CALL    putloop
%endmacro

MBRSeg          EQU     07C0h
LoaderSeg       EQU     0800h
KernelSeg       EQU     0800h

RetryTimes      EQU     5               ; 重读5次
SectorNum       EQU     5               ; 18个扇区
HeaderNum       EQU     0
CylindNum       EQU     0               ; 10个柱面

; 以下的记述用于标准FAT12格式的软盘
jumper:
        JMP     short   jumper_between_data

floppy_info:
        DB      0x90
        DB      "PILLARLD"              ; 启动区的名称可以是任意字符串(8字节)
        DW      512                     ; 每个扇区(sector)的大小必须为512字节
        DB      1                       ; 簇(cluster)的大小必须为1个扇区
        DW      1                       ; FAT的起始位置(一般从第一个扇区开始)
        DB      2                       ; FAT的个数(必须为2)
        DW      224                     ; 根目录的大小(一般设为244项)
        DW      2880                    ; 该磁盘的的大小(必须为2880扇区)
        DB      0xf0                    ; 磁盘的种类(必须为0xfd)
        DW      9                       ; FAT的长度(必须为9扇区)
        DW      18                      ; 一个磁道(track)有几个扇区(必须为18)
        DW      2                       ; 磁头数(必须为2)
        DD      0                       ; 不使用分区(必须为0)
        DD      2880                    ; 重写一次磁盘大小
        DB      0,0,0x29                ; 意义不明,固定
        DD      0xffffffff              ; (可能是)卷标号码
        DB      "PillarFrame"           ; 磁盘名称(11字节)
        DB      "FAT12   "              ; 磁盘格式名称(8字节)
        TIMES   18      DB      0       ; 先腾出18字
;===========================二次跳转=================================
jumper_between_data:
        JMP     entry
;===========================数据区域=================================
line:
        DB      0X0A,   0X0D
        DB      ENDSTR
cylindmsg:
        DB      "Cylind:"
        DB      UNKNOWN,        UNKNOWN
        DB      " "
        DB      ENDSTR
headermsg:
        DB      "Header:"
        DB      UNKNOWN,        UNKNOWN
        DB      " "
        DB      ENDSTR
sectormsg:
        DB      "Sector:"
        DB      UNKNOWN,        UNKNOWN
        DB      " "
        DB      ENDSTR
normalfymsg:
        DB      "--Read Normally!"
        DB      ENDSTR
errorfymsg:
        DB      "--Read Exceptionally!"
        DB      ENDSTR
sucessfullymsg:
        DB      "CELEBRATE!"
        DB      0X0A,   0X0D
        DB      "MBR Loaded Sucessfully!"
        DB      ENDSTR

cylindct:
        DB      0
headerct:
        DB      0
sectorct:
        DB      2

;===========================主要代码=================================
entry:
        CALL    ready

        PUTS    line

        CALL    fyloader

        PUTS    line
        PUTS    line

        PUTS    sucessfullymsg
        
        JMP     800h:0

ready:
        MOV     AX,     MBRSeg          ;为显示各种提示信息做准备 
        MOV     DS,     AX
        MOV     AX,     LoaderSeg       ;为读软盘数据到内存做准备,因为读软盘需地址控制---ES:BX
        MOV     ES,     AX
        RET
;-------------------MOUDLE:FLOPPY LOAD-----------------------
fyloader:
        call    sectorreading
        MOV     AX,     ES
        ADD     AX,     0X0020
        MOV     ES,     AX                      ;ES+=0X0020
                                                ;一个扇区占512B=200H,刚好能被整除成完整的段,因此只需改变ES值,无需改变BP即可。
        
        INC     BYTE[sectorct]                  ;sectorct++
        CMP     BYTE[sectorct], SectorNum       ;if(sectorct<=sectornum)
        JBE     fyloader                        ;jmp fyloader

        MOV     BYTE[sectorct],1                ;reset


        INC     BYTE[headerct]
        CMP     BYTE[headerct], HeaderNum
        JBE     fyloader

        MOV     BYTE[headerct],0

        INC     BYTE[cylindct]
        CMP     BYTE[cylindct], CylindNum
        JBE     fyloader

        RET

sectorreading:
        MOV     CL,     [sectorct]
        CALL    num2char
        MOV     [sectormsg+7],  AL
        MOV     [sectormsg+8],  AH

        MOV     CL,     [headerct]
        CALL    num2char
        MOV     [headermsg+7],  AL
        MOV     [headermsg+8],  AH

        MOV     CL,     [cylindct]
        CALL    num2char
        MOV     [cylindmsg+7],  AL
        MOV     [cylindmsg+8],  AH

        MOV     CH,     [cylindct]
        MOV     DH,     [headerct]
        MOV     CL,     [sectorct]

        CALL    readinginfo
        MOV     DI,     0
readsector:
        MOV     AH,     02H     ; AH=0x02 : AH设置为0x02表示读取磁盘
        MOV     AL,     1       ; 要读取的扇区数
        MOV     BX,     0       ; ES:BX表示读到内存的地址 0x0800*16 + 0 = 0x8000
        MOV     DL,     00H     ; 驱动器号,0表示第一个软盘,是的,软盘。。硬盘C:80H C 硬盘D:81H
        INT     13H             ; 调用BIOS 13号中断,磁盘相关功能
        JNC     normallyread; 未出错则跳转,出错的话则会使EFLAGS寄存器的CF位置1

        INC     DI
        MOV     AH,     0x00
        MOV     DL,     0x00    ; A驱动器
        INT     0x13            ; 重置驱动器
        CMP     DI,     5       ; 软盘很脆弱,同一扇区如果重读5次都失败就放弃 
        JNE     readsector
        
        PUTS    errorfymsg
        PUTS    line
        JMP     exitread

exceptionallyread:
        PUTS    errorfymsg
        PUTS    line
normallyread:
        PUTS    normalfymsg
        PUTS    line
exitread:
        RET
readinginfo:
        PUTS    cylindmsg
        PUTS    headermsg
        PUTS    sectormsg
        RET
;----------------MOUDLE:DATA-TOOLS------------------
num2char:     ;将2位数的10进制数分解成ASII码才能正常显示。如柱面56 分解成出口ascii: al:35,ah:36
        MOV        AX,     0
        MOV        AL,     CL
        MOV        BL,     10
        DIV        BL
        ADD        AX,     3030H
        RET

;----------------MOUDLE:PUTSTRING-------------------
putloop:
        MOV     AL,     [SI]            ;显示字符
        CMP     AL,     ENDSTR
        JE      endprocedure
        MOV     AH,     0eh  ;显示字符的颜色
        INT     10H
        INC     SI
        JMP     putloop

endprocedure:
        RET
;===========================尾部填充=================================
tail:
        TIMES   510-($-$$)              DB      0
        DB      0X55,   0XAA

kernel.asm 

%define         ENDSTR  0

start:
        MOV     AX, 800H          ;跳转后,CS为新的地址
        MOV     DS, AX
        MOV     ES, AX          ;将DS=CS,ES=CS,直接执行后续程序
        JMP     entry

kernelmsg:
        DB      "Message from Kernel Program."
        DB      0
entry:
        MOV     SI, kernelmsg
        CALL    putloop
        JMP     end
putloop:
        MOV     AL, [SI]    ;显示字符
        CMP     AL, ENDSTR
        JE      endprocedure
        MOV     AH, 0eh     ;显示字符的颜色
        INT     10H
        INC     SI
        JMP     putloop

endprocedure:
        RET

end:
        JMP     $

make.bat

cls
mkdir dist
mkdir log
nasm -o dist/mbr.plr -l log/mbr.lst mbr.asm
nasm -o dist/kernel.plr -l log/kernel.lst kernel.asm
cd dist
copy /b mbr.plr+kernel.plr pillar.plr
copy /b pillar.plr pillar.img
python ../../tools/bf.py pillar.img 1474560
cd ../

三、制作效果

运行make.bat,将dist/pillar.img装入虚拟机中运行

B站视频:自制操作系统 MBR装在内核 为开发庞大的操作系统做准备_哔哩哔哩_bilibili

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值