30天自制操作系统:第三天:系统引导完成

对第二天代码进行了修改,只打印hello ,uos没一点意思。

读取磁盘上10个柱面的1-18个扇区,(目前ssd已经没有柱面这个概念了)。读出来的数据放入内存0x8200起始的地方。

启动区放在0x8000内存扇区中。为什么要放在0x8000以后的内存中的呢? 只是因为这块内存没有用而已。

为什么要将启动程序(img的0扇区)放在0x7c00处? 这是ibm规定的。

向一个空软盘保存文件时:

1.文件名会写在0x002600以后的地方。

2.文件内容会写在0x004200以后的地方。

所以若想启动位于0x004200的程序,就得让引导程序运行完成后跳转到0x8000+0x4200=0xc200处。

作者这一块写的很混乱啊,咱们整理一下为啥是0xc200地址,看下图:


30天自制操作系统:第三天:系统引导完成


bios会把磁盘0位置的内容拷贝到内存0x7c00这个位置然后跳过去执行, 也就是把A拷贝到了内存,然后执行A A会把磁盘后面的内容从内存0x8200开始拷贝 这样的话磁盘0x4200位置就会对应到内存0xC200 一个扇区512字节,十六进制表示就是0x200

程序的执行情况:

1.bios读取磁盘0扇区到0x7c00处。

2.bios跳转到0x7c00处开始执行,该处为ipl10.nas程序,该程序功能为加载磁盘[1-最后]扇区到内存的0x8200处。并跳转到0xc200处执行。

3.0xc200处为asmhead.nas程序,该程序功能为,调用显卡bios,设置画面模式,调用操作系统代码。

4.操作系统代码目前就一个功能就是让cpu睡眠,开始进入c程序。


下面根据功能修改代码:

修改ipl.nas


ipl10.nas:

; haribote-ipl
; TAB=4

CYLS    EQU     10              ; 声明CYLS=10

        ORG     0x7c00          ; 指明程序装载地址

; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code
​
        JMP     entry
        DB      0x90
        DB      "HARIBOTE"      ; 启动扇区名称(8字节)
        DW      512             ; 每个扇区(sector)大小(必须512字节)
        DB      1               ; 簇(cluster)大小(必须为1个扇区)
        DW      1               ; FAT起始位置(一般为第一个扇区)
        DB      2               ; FAT个数(必须为2)
        DW      224             ; 根目录大小(一般为224项)
        DW      2880            ; 该磁盘大小(必须为2880扇区1440*1024/512)
        DB      0xf0            ; 磁盘类型(必须为0xf0)
        DW      9               ; FAT的长度(必??9扇区)
        DW      18              ; 一个磁道(track)有几个扇区(必须为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            ; 初始化寄存器
        MOV     SS,AX
        MOV     SP,0x7c00
        MOV     DS,AX
​
; 读取磁盘
​
        MOV     AX,0x0820
        MOV     ES,AX
        MOV     CH,0            ; 柱面0
        MOV     DH,0            ; 磁头0
        MOV     CL,2            ; 扇区2
​
readloop:
        MOV     SI,0            ; 记录失败次数寄存器
​
retry:
        MOV     AH,0x02         ; AH=0x02 : 读入磁盘
        MOV     AL,1            ; 1个扇区
        MOV     BX,0
        MOV     DL,0x00         ; A驱动器
        INT     0x13            ; 调用磁盘BIOS
        JNC     next            ; 没出错则跳转到next
        ADD     SI,1            ; 往SI加1
        CMP     SI,5            ; 比较SI与5
        JAE     error           ; SI >= 5 跳转到error
        MOV     AH,0x00
        MOV     DL,0x00         ; A驱动器
        INT     0x13            ; 重置驱动器
        JMP     retry
next:
        MOV     AX,ES           ; 把内存地址后移0x200(512/16十六进制转换)
        ADD     AX,0x0020
        MOV     ES,AX           ; ADD ES,0x020因为没有ADD ES,只能通过AX进行
        ADD     CL,1            ; 往CL里面加1
        CMP     CL,18           ; 比较CL与18
        JBE     readloop        ; CL <= 18 跳转到readloop
        MOV     CL,1
        ADD     DH,1
        CMP     DH,2
        JB      readloop        ; DH < 2 跳转到readloop
        MOV     DH,0
        ADD     CH,1
        CMP     CH,CYLS
        JB      readloop        ; CH < CYLS 跳转到readloop
​
; 读取完毕,跳转到haribote.sys执行!
        MOV     [0x0ff0],CH     ; 记下IPL读到哪里了
        JMP     0xc200
​
error:
        MOV     SI,msg
​
putloop:
        MOV     AL,[SI]
        ADD     SI,1            ; 给SI加1
        CMP     AL,0
        JE      fin
        MOV     AH,0x0e         ; 显示一个文字
        MOV     BX,15           ; 指定字符颜色
        INT     0x10            ; 调用显卡BIOS
        JMP     putloop
​
fin:
        HLT                     ; 让CPU停止,等待指令
        JMP     fin             ; 无限循环
​
msg:
        DB      0x0a, 0x0a      ; 换行两次
        DB      "load error"
        DB      0x0a            ; 换行
        DB      0
​
        RESB    0x7dfe-$        ; 填写0x00直到0x001fe
​
        DB      0x55, 0xaa
​

我们在使用段寄存器时,以ES:BX这种方式表示地址,写成"MOV AL, [ES:BX]"它代表ES×16+BX内存地址。

2.修改asmhead.nas

; haribote-os boot asm
; TAB=4
​
;一些定义
BOTPAK  EQU     0x00280000      ; bootpack�̃��[�h��
DSKCAC  EQU     0x00100000      ; �f�B�X�N�L���b�V���̏ꏊ
DSKCAC0 EQU     0x00008000      ; �f�B�X�N�L���b�V���̏ꏊ�i���A�����[�h�j
​
; 有关BOOT_INFO
CYLS    EQU     0x0ff0          ; 设定启动区
LEDS    EQU     0x0ff1
VMODE   EQU     0x0ff2          ; 该位置保存颜色数目的信息,颜色的位数。
SCRNX   EQU     0x0ff4          ; 该位置保存 分辨率的x
SCRNY   EQU     0x0ff6          ; 该位置保存 分辨率的y
VRAM    EQU     0x0ff8          ; 图像缓冲区的开始地址。
​
        ORG     0xc200          ; 这个程序需要装载到内存的什么地方呢。
​
; 画面设定
​
        MOV     AL,0x13         ; VGA显卡,320*320*8位彩色,调色板模式。
        MOV     AH,0x00
        INT     0x10            ;调用显卡bios的函数,切换显示模式。
        MOV     BYTE [VMODE],8  ; 将画面模式信息保存到这些内存地址中。
        MOV     WORD [SCRNX],320
        MOV     WORD [SCRNY],200
        MOV     DWORD [VRAM],0x000a0000     
;VRAM指的时显卡内存,也就是用来显示画面的内存。这一块内存地址都对应着画面上的像素。
;VRAM在0xa0000~0xaffff之间的64kb。 VRAM分布在内存分布图中的好几个不同的地方。
​
; 用bios取得键盘上各种led灯的状态。
​
        MOV     AH,0x02
        INT     0x16            ; keyboard BIOS
        MOV     [LEDS],AL
​
;=====================================后边的留以后再看,这块时调用bootpack.c程序的======================
; 防止PIC接受所有中断
;   AT兼容机的规范、PIC初始化
;   然后之前在CLI不做任何事就挂起
;   PIC在同意后初始化
​
        MOV     AL,0xff
        OUT     0x21,AL
        NOP                     ; ; 不断执行OUT指令
        OUT     0xa1,AL
​
        CLI                     ;进一步中断CPU
​
; ; 让CPU支持1M以上内存、设置A20GATE
​
        CALL    waitkbdout
        MOV     AL,0xd1
        OUT     0x64,AL
        CALL    waitkbdout
        MOV     AL,0xdf         ; enable A20
        OUT     0x60,AL
        CALL    waitkbdout
​
; 保护模式转换
​
[INSTRSET "i486p"]              ; 说明使用486指令
​
        LGDT    [GDTR0]         ;设置临时GDT
        MOV     EAX,CR0
        AND     EAX,0x7fffffff  ; 使用bit31(禁用分页)
        OR      EAX,0x00000001  ; bit0到1转换(保护模式过渡)
        MOV     CR0,EAX
        JMP     pipelineflush
pipelineflush:
        MOV     AX,1*8          ;  写32bit的段
        MOV     DS,AX
        MOV     ES,AX
        MOV     FS,AX
        MOV     GS,AX
        MOV     SS,AX
​
;bootpack传递
​
        MOV     ESI,bootpack    ; 源
        MOV     EDI,BOTPAK      ; 目标
        MOV     ECX,512*1024/4
        CALL    memcpy
​
; 传输磁盘数据
​
; 从引导区开始
​
        MOV     ESI,0x7c00      ; 源
        MOV     EDI,DSKCAC      ; 目标
        MOV     ECX,512/4
        CALL    memcpy
​
; 剩余的全部
​
        MOV     ESI,DSKCAC0+512 ; 源
        MOV     EDI,DSKCAC+512  ; 目标
        MOV     ECX,0
        MOV     CL,BYTE [CYLS]
        IMUL    ECX,512*18*2/4  ; 除以4得到字节数
        SUB     ECX,512/4       ; IPL偏移量
        CALL    memcpy
​
; 由于还需要asmhead才能完成
; 完成其余的bootpack任务
​
; bootpack启动
​
        MOV     EBX,BOTPAK
        MOV     ECX,[EBX+16]
        ADD     ECX,3           ; ECX += 3;
        SHR     ECX,2           ; ECX /= 4;
        JZ      skip            ; 传输完成
        MOV     ESI,[EBX+20]    ; 源
        ADD     ESI,EBX
        MOV     EDI,[EBX+12]    ; 目标
        CALL    memcpy
skip:
        MOV     ESP,[EBX+12]    ; 堆栈的初始化
        JMP     DWORD 2*8:0x0000001b
​
waitkbdout:
        IN       AL,0x64
        AND      AL,0x02
        JNZ     waitkbdout      ; AND结果不为0跳转到waitkbdout
        RET
​
memcpy:
        MOV     EAX,[ESI]
        ADD     ESI,4
        MOV     [EDI],EAX
        ADD     EDI,4
        SUB     ECX,1
        JNZ     memcpy          ; 运算结果不为0跳转到memcpy
        RET
; memcpy地址前缀大小
​
        ALIGNB  16
GDT0:
        RESB    8               ; 初始值
        DW      0xffff,0x0000,0x9200,0x00cf ; 写32bit位段寄存器
        DW      0xffff,0x0000,0x9a28,0x0047 ; 可执行的文件的32bit寄存器(bootpack用)
​
        DW      0
GDTR0:
        DW      8*3-1
        DD      GDT0
​
        ALIGNB  16
bootpack:
​

3.加入bootpack.c操作系统代码

这个操作系统实现了一个最简单的功能:让cpu睡眠

void io_hlt(void);
​
​
void HariMain(void)
{
​
fin:
    io_hlt(); /* 执行naskfunc.nas里边的_io_hlt()函数。 */
    goto fin;
​
}
​

4.加入naskfunc.nas

加入这个文件是因为c程序不能调用HLT指令,所以使用c程序调用汇编程序,在汇编程序中用HLT让cpu睡眠。

; naskfunc
; TAB=4
​
[FORMAT "WCOFF"]                ; 制作目标文件的模式 
[BITS 32]                       ; 制作32位模式用的机器语言
​
​
; 制作目标文件的信息。
[FILE "naskfunc.nas"]           ; 源文件名信息
​
        GLOBAL  _io_hlt         ; 程序中包含的函数名
​
​
;实际的函数
​
[SECTION .text]     ;目标中间中写了这些之后再写程序
​
_io_hlt:    ; void io_hlt(void); 这个函数只执行了一个HLT命令,让cpu睡眠。
        HLT
        RET
​

5.运行结果


30天自制操作系统:第三天:系统引导完成

本地代码下载:https://download.csdn.net/download/u011164819/12981508

展开阅读全文

页面更新:2024-04-29

标签:寄存器   初始化   字节   磁盘   函数   显卡   画面   大小   操作系统   内存   位置   目标   模式   代码   地址   程序   系统   科技

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top