目录

1.制作真正的IPL

IPL:启动区,启动程序装载器

完整代码:

; 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

这里有个JC指令,是有条件跳转指令
注意到上面有个INT 0x13,这是调用BIOS的0x13号函数
常用的有:



这个进位标志位是存储在标志寄存器里面。
为了明白今天新加的代码,需要了解磁盘的工作方式

一定记得,磁盘他是实体的,是三维立体的物体,这样就好理解了

IPL启动区就在C0-H0-S1(柱面0-磁头0-扇区1)
接下来,为了介绍缓冲区(cache)的概念,需要再次复习一下,CPU寻址方式:段基址+段内地址

上面的说法比较老,最新的指令格式是AT&T格式,但是,基本思想是一致的,可百度。
这次的运行结果将会一闪而过,大家获取源码之后可以自行体验。
这里有一个报错:

解决方式如下:
16位不兼容解决方案
最好重启一下!!!!!!!!!!
运行结果解释漆黑一片:

2.试错

软盘不可靠,读取失败的情况下,需要多次读取,考虑极端情况,需要限制读取次数


这里两个新的指令:
JNC:进位标志为0时跳转
JAE:大于等于时跳转
INT 0x13,功能是系统复位

3.读到18扇区



新的指令:
JBE:小于等于跳转

4.读入10个柱面


代码如下:

; 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

新加指令:
JB:如果小于,跳转
EQU:等价与#define

5.着手开发操作系统

上面已经完成了启动区的制作
下面,写一个最简单的操作系统






6.从启动区执行操作系统


7.确认操作系统的执行情况





全黑画面:

8.32位模式前期准备

接下来就要以C语言作为开发语言,汇编语言暂时不用了。
32位模式就不能调用BIOS函数了(16位编写的)

所以需要使用BIOS的地方,我们需要首先放到前面去加载,在asmhead.nas文件中

; haribote-os boot asm
; TAB=4 BOTPAK EQU 0x00280000 ; 加载bootpack
DSKCAC EQU 0x00100000 ; 磁盘缓存的位置
DSKCAC0 EQU 0x00008000 ; 磁盘缓存的位置(实模式) ; 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显卡,320x200x8bit
MOV AH,0x00
INT 0x10
MOV BYTE [VMODE],8 ; 屏幕的模式(参考C语言的引用)
MOV WORD [SCRNX],320
MOV WORD [SCRNY],200
MOV DWORD [VRAM],0x000a0000 ; 通过BIOS获取指示灯状态 MOV AH,0x02
INT 0x16 ; keyboard BIOS
MOV [LEDS],AL ; 防止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:


9.开始导入C语言

bootpack.c

/* 告诉C编译器,有一个函数在别的文件里 */

void io_hlt(void);

/* 是函数声明却不用{},而用;,这表示的意思是:
函数在别的文件中,你自己找一下 */ void HariMain(void)
{ fin:
io_hlt(); /* 执行naskfunc.nas中的_io_hlt函数 */
goto fin; }

这里goto最终将会被编译成JMP指令
函数io_hlt()在naskfunc.nas中

; naskfunc
; TAB=4 [FORMAT "WCOFF"] ; 制作目标文件的模式
[BITS 32] ; 制作32位模式用的机器语言 ; 制作目标文件的信息 [FILE "naskfunc.nas"] ; 源文件名信息 GLOBAL _io_hlt ; 程序中包含的函数名 ; 以下是实际的函数 [SECTION .text] ; 目标文件中写了这些后再写程序 _io_hlt: ; void io_hlt(void);
HLT
RET


下面讲解汇编语言做目标文件的方法

10.实现HLT(harib00j)



RET:等价与return

11.微信关注公众号获取源码和电子书籍

挑战30天写操作系统-day3-进入32位模式并导入C语言的更多相关文章

  1. 30天自制操作系统(三)进入32位模式并导入C语言

    1 制作真正的IPL IPL(Initial Program Loader),启动程序装载器,但是之前并没有实质性的装载任何程序,这次作者要开始装载程序了. 虽然现在开发的操作系统啥功能也没有,作者说 ...

  2. 挑战30天写操作系统-day4-C语言与画面显示的练习

    目录 获取源码关注公众号<猿小龙> 1.用C语言实现内存写入(harib01a) C语言中如果使用了write_mem8函数,就会跳转到_write_mem8,此时参数指定的数字就存放在内 ...

  3. 挑战30天写操作系统-day1-从计算机结构到汇编程序入门

    先动手操作 软盘映像文件制作:先采用二进制编辑器编辑我们所需要的映像文件helloos.img 二进制编辑器下载链接:Bz - c.mos (vcraft.jp) 制作好之后,可以选择写入软盘,通过软 ...

  4. 挑战30天写操作系统-day2-汇编语言学习与Makefile入门

    1.介绍文本编辑器 这里,我们直接采用自己windows电脑自带的文本编辑器即可以完成制作要求 2.继续开发 下面先是对昨天使用的helloos.nas文件内容进行详细解释 ; hello-os ; ...

  5. 《30天自制操作系统》笔记(06)——CPU的32位模式

    <30天自制操作系统>笔记(06)——CPU的32位模式 进度回顾 上一篇中实现了启用鼠标.键盘的功能.屏幕上会显示出用户按键.点击鼠标的情况.这是通过设置硬件的中断函数实现的,可以说硬件 ...

  6. 30天自制操作系统-day3

    30天自制操作系统-day3 前2天我们分别使用了直接使用二进制编辑器和简单的汇编指令生成了img文件,今天我们尝试一下使用稍微复杂一点的汇编指令 os.asm文件内容如下: ; hello-os ; ...

  7. 微软的操作系统中让 32 位支持大于 4GB 的内存。

    先给一个参考文献:The RAM reported by the System Properties dialog box and the System Information tool is les ...

  8. 16位模式/32位模式下PUSH指令探究——《x86汇编语言:从实模式到保护模式》读书笔记16

    一.Intel 32 位处理器的工作模式 如上图所示,Intel 32 位处理器有3种工作模式. (1)实模式:工作方式相当于一个8086 (2)保护模式:提供支持多任务环境的工作方式,建立保护机制 ...

  9. 呃,如何使 .NET 程序,在 64位 系统 中,以 32位 模式运行。

    其实最简单的方法就是在解决方案中,把平台设为 x86 就好了哈~   但是今天遇到一个第三方的软件,它调用的一个 dll 是 32位 的,可能它没有测试过在 64位 系统下运行的情况,它在编译时是按默 ...

随机推荐

  1. XCTF练习题---MISC---2017_Dating_in_Singapore

    XCTF练习题---MISC---2017_Dating_in_Singapore flag:HITB{CTFFUN} 解题步骤: 1.观察题目,下载附件 2.打开附件后发现是一张日历,还是新加坡的, ...

  2. XCTF练习题---MISC---something_in_image

    XCTF练习题---MISC---something_in_image flag:Flag{yc4pl0fvjs2k1t7T} 解题步骤: 1.观察题目,下载附件,这是一道2019湖湘杯的题目 2.下 ...

  3. CTO 说了,如果发现谁用 kill -9 关闭程序就开除

    关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ 来源:blog.csdn.net/qq_33220089          正文    kil ...

  4. 一文详解 Ansible 自动化运维

    开源Linux 一个执着于技术的公众号 一.Ansible 概述 Ansible 是近年来越来越火的一款开源运维自动化工具,通过Ansible可以实现运维自动化,提高运维工程师的工作效率,减少人为失误 ...

  5. linux项目部署(非前后端分离crm)

    参考博客 参考博客2---部署过程 导论:看参考博客1 WSGI是Web服务器网关接口.它是一个规范,描述了Web服务器如何与Web应用程序通信,以及Web应用程序如何链接在一起以处理一个请求,(接收 ...

  6. os模块,sys模块,json模块,subprocess模块

    os模块 一·什么是os模块 os模块提供了多数操作系统的功能接口函数.当os模块被导入后,它会自适应于不同的操作系统平台,根据不同 的平台进行相应的操作,在python编程时,经常和文件.目录打交道 ...

  7. 为什么 io 包一般以 byte 数组做为处理单位?

    为什么 io 包一般以 byte 数组做为处理单位? 本文写于 2021 年 9 月 7 日 编程语言中时常会出现 []byte 作为类型的操作.特别是在网络传输或是 io 操作中,例如 socket ...

  8. vue项目引入TinyMCE

    1.安装 npm install @tinymce/tinymce-vue@3.0.1 -S 2.配置 <template> <!-- 富文本 --> <div> ...

  9. 好客租房49-组件的props(特点)

    特点 1可以给组件传递任意类型的数据 2props是只读的对象 只能读取属性的值 无法修改对象 3注意:使用类组件时 如果写了构造函数 应该将props传递给super() 否则 无法在构造函数 中获 ...

  10. Android源码环境生成Android SDK并导入Adnroid Studio

    1.发现问题 之前使用Repo同步Android源码使用的是下面这条指令,即同步的是分支android-7.1.2_r18的代码 repo init -u https://mirrors.tuna.t ...