DIY操作系统(一)

原创 2016年08月30日 09:56:09
引文:构想根据《30天自制操作系统》以及《ORANGE’S:一个操作系统的实现》初步实现一个操作系统。

先开个头,以后的棋一步一步下。

先说几句题外话:
  回想第一次看到《30天自制操作系统》这本书时,就被这快餐般的标题深深吸引了,我无法想象如此复杂有内涵的内容能在30天就弄出来,直到我花了一个多月看到这本书的第9天时,我放弃了。
  然而这次。
  对不起,我是认真的!

以下开始正文,都是个人浅见,如有错误,欢迎斧正。
  操作系统如何自己运行起来?
  首先,机器自动读取磁盘的第一个扇区(512字节),并载入到内存的0x7c00位置,然后执行第一个扇区的代码,这段代码会读取磁盘后续的扇区到内存,接着跳转到引导文件,由引导文件继续启动操作系统。
  这里有几点说明,并不是所有的第一个扇区都是引导扇区,因为他有个特殊的标记,以0x55aa结尾,为什么是0x55aa?还是让我们先看下为什么要载入到内存的0x7c00位置,因为答案都是一样的,龟腚!

下面是《30天自制操作系统》引导扇区的代码,略作修改,并且加了大量注释,让我们RTFSC!

CYLS    EQU        10                ; 定义变量,将要读取的柱面数量

        ORG        0x7c00            ; 指明程序载入到内存的地址,7c00是魔法数字,人为规定的,没什么道理好讲

        
; 以下这段是标准的FAT12格式软盘用的代码

        JMP       entry           ; 跳到下面执行入口entry
        DB        0x90            ; 写一个字节,DW是写2个字节,DD是写4个字节
        DB        "HARIBOTE"        ; 启动区的名称,必须8字节
        DW        512                ; 每个扇区的大小,必须512字节
        DB        1                ; 簇的大小,必须1个扇区
        DW        1                ; FAT的起始位置,通常从第一个扇区开始
        DB        2                ; FAT的个数,必须为2
        DW        224                ; 根目录大小,通常为224
        DW        2880            ; 该磁盘的大小,必须为2880扇区
        DB        0xf0            ; 磁盘的种类,必须是0Xf0
        DW        9                ; FAT的长度,必须是9扇区
        DW        18                ; 一个磁道有几个扇区,必须是18
        DW        2                ; 磁头数,必须是2
        DD        0                ; 不使用分区,必须是0
        DD        2880            ; 重写一次磁盘大小
        DB        0,0,0x29        ; 意义不明
        DD        0xffffffff        ; 可能是卷标号码
        DB        "HARIBOTEOS "    ; 磁盘的名字(必须11字节) 
        DB        "FAT12   "        ; 格式化格式的名字(8字节)
        RESB      18                ; 将后面的18个字节置空

; 程序核心

entry:
        MOV        AX,0            ; 将0赋值给AX寄存器,目的其实是初始化后面的SS和DS寄存器
                                ; 为什么要初始化DS寄存器?因为使用内存时默认都要使用DS段寄存器作为基址,比如MOV AX,[0xFF](表示将内存地址0xFF存储的数据赋值给AX)实际是MOV AX,[DS:0xFF],DS默认省略了。
                                ; [DS:0xFF]表示DS*16+0xFF所指地址存储的数据
                                ; 段寄存器不能通过MOV DS, 0这种形式(没有这种机器码),为了初始化段寄存器,不得不通过AX间接来初始化,以后赋值也必须通过寄存器间接赋值
        MOV        SS,AX            ; 初始化SS寄存器
        MOV        SP,0x7c00       ; 栈指针初始化为与内存起始位置一致,为什么?我也不知道。
        MOV        DS,AX            ; 初始化DS寄存器

; 下面这段的功能是读磁盘,读磁盘需要调用BIOS的中断来实现,中断相当于一个系列的函数,都是围绕某个功能,比如下面这个13中断,都是与磁盘相关,具体是度还是写,就要看传什么参数。
; BIOS的中断的调用方式跟函数相似,传参数,调用,取返回值。中断的参数和返回值一般都放在特定寄存器中,所以调用中断之前,先要向特定寄存器传递值。
; 下面要用到INT13中断,这个中断的说明如下:

; 直接磁盘服务(Direct Disk Service——INT 13H) 

; 功能00H
; 功能描述:磁盘系统复位
; 入口参数:AH=00H 
; DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘
; 出口参数:CF=0——操作成功,AH=00H,否则,AH=状态代码,参见功能号01H中的说明

; 功能02H 
; 功能描述:读扇区
; 入口参数:AH=02H
; AL=扇区数
; CH=柱面
; CL=扇区
; DH=磁头
; DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘
; ES:BX=缓冲区(内存)的地址
; 出口参数:CF=0——操作成功,AH=00H,AL=传输的扇区数,否则,AH=状态代码,


; 初始化BIOS的参数
        MOV        AX,0x0800
        MOV        ES,AX           ; 初始化ES段为0800,而作为基址ES要*16,所以实际上0x0800*16=0x8000,为什么要放到内存0x8000的位置?因为这段是空的。。
        MOV        CH,0            ; 柱面从0开始读
        MOV        DH,0            ; 磁头从0开始读
        MOV        CL,1            ; 扇区从1开始读。。。因为第一个就是1而不是0
readloop:
        MOV        SI,0            ; 初始化SI,SI用作记录失败次数
retry:
        MOV        AH,0x02            ; AH=0x02 : AH设置为0x02表示读取磁盘
        MOV        AL,1            ; 要读取的扇区数
        MOV        BX,0            ; ES:BX表示读到内存的地址 0x0800*16 + 0 = 0x8000
        MOV        DL,0x00            ; 驱动器号,0表示第一个软盘,是的,软盘。。
        INT        0x13            ; 调用BIOS 13号中断,磁盘相关功能
        JNC        next            ; 未出错则跳转到next,出错的话则会使EFLAGS寄存器的CF位置1
        ADD        SI,1            ; SI加1,表示出错次数加1
        CMP        SI,5            ; SI与5比较
        JAE        error            ; SI >= 5 则跳转到error
        MOV        AH,0x00         ; AH=0x00 表示磁盘系统复位
        MOV        DL,0x00            ; 复位第一个软盘,我们也就一块软盘
        INT        0x13            ; 调用BIOS 13号中断,磁盘相关功能
        JMP        retry
next:
        MOV        AX,ES            
        ADD        AX,0x0020
        MOV        ES,AX            ; 上面三个指令的目的就是 ADD ES,0x020,但是没有这种指令,所以只能通过AX间接操作
                                ; ES+0x020 那么ES:BX=ES*16+BX=0x020*16+BX=0X200+BX=512+BX 相当于放到内存的位置往后移了一个扇区的大小
                                
        ADD        CL,1            ; 扇区位置加1
        CMP        CL,18            ; 与18比较,意思就是读到第18个扇区,为什么是18个扇区?请看文后图
        JBE        readloop        ; CL <= 18 跳到readloop
        MOV        CL,1            ; 重读第一个扇区
        ADD        DH,1            ; 磁头加1,表示读完第一个磁头的18个扇区读第二个磁头的18个扇区
        CMP        DH,2
        JB         readloop        ; 
        MOV        DH,0            ; 重读第一个磁头
        ADD        CH,1            ; 柱面加1
        CMP        CH,CYLS         ; 按照读完扇面换磁头,读完磁头再换柱面的顺序循环读取
        JB         readloop        ; 

; 

        MOV        [0x0ff0],CH        ; 将读取的柱面数保存到内存地址0x0ff0处
        JMP        0xc200          ; 跳转到内存的0xc200,0xc200是从哪来的?0xc200是0x8000+0x4200,0x8000是软盘读取到内存的起始地址,那么0x4200就是指软盘的0x4200位置
                                ; 因为软盘是FAT12格式,通过找资料,知道软盘中保存的第一个文件的起始地址(也就是数据区)的位置
                                ; 是隐藏扇区+保留扇区+FAT表数*FAT表所占扇区+根目录所占扇区=0+1+2*9+14=33,每个扇区是512字节,33*512=16896,换算成16进制正好是0x4200。
                                ; 所以这里的跳转就是跳到软盘里保存的第一个文件的位置。

; 下面这段是用来在屏幕上显示错误信息的
; 显示服务(Video Service——INT 10H) 

; 功能0EH 
; 功能描述:在Teletype模式下显示字符
; 入口参数:AH=0EH
; AL=字符
; BH=页码
; BL=前景色(图形模式)
; 出口参数:无

error:
        MOV        SI,msg          ; 将错误信息地址赋值给SI寄存器
putloop:
        MOV        AL,[SI]         ; 根据地址取出一个字节数据
        ADD        SI,1            ; SI加1
        CMP        AL,0            ; 如果数据为0则结束
        JE         fin
        MOV        AH,0x0e            ; 
        MOV        BX,15            ; 设置颜色
        INT        0x10            ; 上面三行为调用BIOS第10号中断,AH为0x0e时为显示字符功能,BH为页码,BL为前景色
        JMP        putloop
fin:
        HLT                        ; CPU待机
        JMP        fin                ; 无限循环
msg:
        DB        0x0a, 0x0a        ; 换两行
        DB        "load error"
        DB        0x0a            ; 换行
        DB        0

        RESB      0x7dfe-$        ; 0x7dfe 是0x7c00+510
        DB        0x55, 0xaa      ; 最后两位55aa表示这个扇区是启动区


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

NAS DIY的设计和实施过程-8-打造属于我的NAS操作系统3-SERVER和WEB配置工具的调试 --ISCSI篇

存储部分的功能我一开始就打算实现这3种功能:SMB/FTP/ISCSI 不是说其它的存储协议不好,而是我认为这3种最有用,第一个版本不要给自己这么大的压力呵呵。 FTP和SMB很容易实现,Cent...
  • wwwlh
  • wwwlh
  • 2011-04-24 22:32
  • 3567

NAS DIY的设计和实施过程-7-打造属于我的NAS操作系统1-精简centos

NAS DIY的设计和实施过程-7-打造属于我的NAS操作系统1-精简centos的过程
  • wwwlh
  • wwwlh
  • 2011-02-16 13:00
  • 10763

中关村-DIY操作系统之不分区安装Ubuntu系统

上个月收到了Ubuntu的光盘,先是直接在光盘上运行体验了一下,觉得不错就在硬盘安装了,因为时间关系,加上最近做设计,就一直放那里没去管。分区安装过程不是很复杂,但空出分区和想删除的时候还是有点麻烦的...

NAS DIY的设计和实施过程-6-打造属于我的NAS操作系统

打造属于我的NAS操作系统,你没看错,我决定自己自起炉灶,定制一个完全的满足我要求的操作系统,要玩就玩大一点哈哈。       首先我选择一个集础的操作系统,我选择了CENTOS5.5 X86-64...
  • wwwlh
  • wwwlh
  • 2011-01-17 11:36
  • 12200

中关村-DIY操作系统之替换DV2804恢复分区中的wim镜像

DV2804自带HomeBsc版,很不爽,经过十几次的Ghost和系统恢复盘的恢复(确保测试成功),终于确认成功把f11恢复分区里的wim镜像替换为U版的没问题,哈哈,以后按f11恢复的是我自己装的U...

Diy操作系统注册表

  • 2009-05-11 10:47
  • 2.18MB
  • 下载

5+ Best Examples of How to Build a DIY Self-Balancing Robot

TwitterFacebookGoogle+RSS Feed A blog about autonomous, outdoor and Internet connected robots. ...

安卓手机otg线 diy

  • 2017-03-10 21:22
  • 21KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)