挑战30天写操作系统-day3-进入32位模式并导入C语言
目录
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语言的更多相关文章
- 30天自制操作系统(三)进入32位模式并导入C语言
1 制作真正的IPL IPL(Initial Program Loader),启动程序装载器,但是之前并没有实质性的装载任何程序,这次作者要开始装载程序了. 虽然现在开发的操作系统啥功能也没有,作者说 ...
- 挑战30天写操作系统-day4-C语言与画面显示的练习
目录 获取源码关注公众号<猿小龙> 1.用C语言实现内存写入(harib01a) C语言中如果使用了write_mem8函数,就会跳转到_write_mem8,此时参数指定的数字就存放在内 ...
- 挑战30天写操作系统-day1-从计算机结构到汇编程序入门
先动手操作 软盘映像文件制作:先采用二进制编辑器编辑我们所需要的映像文件helloos.img 二进制编辑器下载链接:Bz - c.mos (vcraft.jp) 制作好之后,可以选择写入软盘,通过软 ...
- 挑战30天写操作系统-day2-汇编语言学习与Makefile入门
1.介绍文本编辑器 这里,我们直接采用自己windows电脑自带的文本编辑器即可以完成制作要求 2.继续开发 下面先是对昨天使用的helloos.nas文件内容进行详细解释 ; hello-os ; ...
- 《30天自制操作系统》笔记(06)——CPU的32位模式
<30天自制操作系统>笔记(06)——CPU的32位模式 进度回顾 上一篇中实现了启用鼠标.键盘的功能.屏幕上会显示出用户按键.点击鼠标的情况.这是通过设置硬件的中断函数实现的,可以说硬件 ...
- 30天自制操作系统-day3
30天自制操作系统-day3 前2天我们分别使用了直接使用二进制编辑器和简单的汇编指令生成了img文件,今天我们尝试一下使用稍微复杂一点的汇编指令 os.asm文件内容如下: ; hello-os ; ...
- 微软的操作系统中让 32 位支持大于 4GB 的内存。
先给一个参考文献:The RAM reported by the System Properties dialog box and the System Information tool is les ...
- 16位模式/32位模式下PUSH指令探究——《x86汇编语言:从实模式到保护模式》读书笔记16
一.Intel 32 位处理器的工作模式 如上图所示,Intel 32 位处理器有3种工作模式. (1)实模式:工作方式相当于一个8086 (2)保护模式:提供支持多任务环境的工作方式,建立保护机制 ...
- 呃,如何使 .NET 程序,在 64位 系统 中,以 32位 模式运行。
其实最简单的方法就是在解决方案中,把平台设为 x86 就好了哈~ 但是今天遇到一个第三方的软件,它调用的一个 dll 是 32位 的,可能它没有测试过在 64位 系统下运行的情况,它在编译时是按默 ...
随机推荐
- XCTF练习题---MISC---Erik-Baleog-and-Olaf
XCTF练习题---MISC---Erik-Baleog-and-Olaf flag:flag{#justdiffit} 解题步骤: 1.观察题目,下载附件 2.拿到手以后发现是一个没有后缀名的文件, ...
- [cf]Codeforces Round #784(Div 4)
由于一次比赛被虐得太惨,,生发开始写blog的想法,于是便有了这篇随笔(找了个近期的cf比赛练练手(bushi))第一次写blog,多多包涵. 第二场cf比赛,第一场打的Div2,被虐太惨,所以第二场 ...
- 变量命名 函数命名 方法 Naming cheatsheet
Naming things is hard. This sheet attempts to make it easier. Although these suggestions can be appl ...
- Linux 运维请务必收藏~ Nginx 五大常见应用场景
关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ Nginx 是一个很强大的高性能 Web 和反向代理服务,它具有很多非常优越的特性,在连接高并 ...
- 【hexo博客搭建】将搭建好的hexo博客部署到阿里云服务器上面(下)
一.部署到阿里云服务器 既然博客也已经成功在本地部署,然后主题也成功安装,接下来就可以部署到服务器上面了,如果你也想要魔改matery主题,可以去各种博客上面找一找大佬的教程,或者联系我,也可以让你少 ...
- 关闭BottomSheetDialogFragment从后台返回后的动画
问题 显示BottomSheetDialogFragment后.将当前应用放于后台,切换到其他APP,然后再返回当前应用.此时会看到BottomSheetDialogFragment从下而上的动画再次 ...
- C#/VB.NET 创建图片超链接
超链接(Hyperlink)可以看做是一个"热点",它可以从当前Web页定义的位置跳转到其他位置,包括当前页的某个位置.Internet.本地硬盘或局域网上的其他文件,甚至跳转到声 ...
- TS 自学笔记(一)
TS 自学笔记(一) 本文写于 2020 年 5 月 6 日 日常废话两句 有几天没有更新了,最近学的比较乱,休息了两天感觉好一些了.这两天玩了几个设计软件,过几天也写篇文章分享分享. 为啥要学 TS ...
- c# SendInput模拟输入字符和按键
介绍: 该程序本意是为了在彩六里打中文用的,现整理出来供大家复制粘贴.(源程序已开源至GitHub - 彩六中文输入) 主要使用SendInput函数,与c语言中用法一致.(部分代码来自网络) 命名空 ...
- Flask框架实现登录注册功能(mysql数据库)
前言: 本例使用Flask框架完成登录和注册操作,包括前端(index.html,regist.html)和后端(app.py)两部分,前端页面不过多介绍,直接进入后端部分: 逻辑思路: 登录部分:运 ...