《30天自制操作系统》第三课学习笔记

标签: 学习30天自制操作系统笔记

今天作者写了一个真正载入内存的IPL,用来讲磁盘上的数据载入内存当中
载入的程序节选是

		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			; 没出错则跳转到fin
		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			; 把内存地址后移0x200512/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		;
		JMP		0xc200

这段程序就就通过读取磁盘上的文件,载入到0x8200往后的地址上面,最后跳转掉0xC200去执行。
上面虽然写的是0x820,这个数据是存在段寄存器上面的,在进行解析的时候是要默认*16,也就是0x8200。在书中有提到要将程序载入到内存0x8000哪里去,但现在的程序确实0x8200,开始满懵逼的,原来仔细看程序它是从第二个扇区开始读取数据,所以地址要写0x8200。如果上面是从第一个扇区读取数据的话,也就是语句MOV CL,2 ; 扇区2改成
MOV CL,1 ; 扇区1,那么MOV AX,0x0820就要改成0x800。
上面的INT 0x13就是调用BIOS的中段函数,他的格式如下:
BIOS中断INT 0x13中,
ah=0x02,即为读磁盘扇区到内存。
al=需要读出的扇区数;
ch=磁道号的低八位;
cl=开始扇区(位0—5),磁道号高二位(位6—7)
dh=磁头号
dl=驱动器号(若是硬盘则要置位7)
es:dx—>指向数据缓冲区
若出错则CF示志置位


上面的程序只是将磁盘载入内存,载入内存之后,执行JMP 0xc200跳转到磁盘里面的程序进行运行,执行asmhead.nas里面的程序

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:

INT 0x10
AH = 00H --设置显示的格式
调用参数:
AL = 00H  40 × 25  黑白文本,16级灰度
AL = 01H  40 × 25  16色文本
AL = 02H  80 × 25  黑白文本,16级灰度
AL = 03H  80 × 25  16色文本
AL = 04H  320 × 200 4色图形
AL = 05H  320 × 200 黑白图形,4色灰度
AL = 06H  640 × 200 黑白图形
AL = 07H  80 × 25  黑白文本
AL = 08H  160 × 200 16色图形(MCGA)
AL = 09H  320 × 200 16色图形(MCGA)
AL = 0AH  640 × 200 4色图形(MCGA)
AL = 0DH  320 × 200 16色图形(EGA/VGA)
AL = 0EH  640 × 200 16色图形(EGA/VGA)
AL = 0FH  640 × 350 单色图形(EGA/VGA)
AL = 0DH  320 × 200 16色图形(EGA/VGA)
AL = 0DH  320 × 200 16色图形(EGA/VGA)
AL = 0E  640 × 200 16色图形(EGA/VGA)H
AL = 0F  640 × 350 单色图形(EGA/VGA)H
AL = 11H  640 × 480 单色图形(VGA)
AL = 12H  640 × 480 16色图形(VGA)
AL = 13H  320 × 200 256色图形(VGA)
屏幕的显存地址是0x000a0000


对上面程序的小笔记

1)PIC:可编程中断控制器,是微处器与外设之间的中断处理的桥梁,用于处理由外设发出的中断请求。一般用的是8259芯片

在这里插入图片描述
在这里插入图片描述
初始化的时候为了防止芯片处理中断函数,所以要先屏蔽掉中断。

2)GDT:
关于GDT和IDT这里写的很好
http://www.techbulo.com/708.html

3)设置A20GATE
又是实模式下,芯片寻址只有20根,也就是1M的寻址能力,如果要想超过1M那就需要时能第21根地址先,也就是A20
MOV AL,0xdf ; enable A20
OUT 0x60,AL
这两个语句就是用来使能A20的

4)要进入保护模式,只要设置CR0寄存器的最高位为0,最低位为1,则可以进入保护模式。

5)作者将引导程序赋值到了0X10000的地址上面去了

; 从引导区开始

		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

6)对于bootpac.c的复制

    MOV		ESI,bootpack	; 源
	MOV		EDI,BOTPAK		; 目标
	MOV		ECX,512*1024/4
	CALL	memcpy

这里作者将这个.c文件生成的程序复制到了0x280000哪里去了。

这个bootpack是在末尾哪里定义的符号,它就是在asmhead.nas最后面定义的。而在makefile里面我们看到

bootpack.hrb : bootpack.bim Makefile
	$(BIM2HRB) bootpack.bim bootpack.hrb 0

haribote.sys : asmhead.bin bootpack.hrb Makefile
	copy /B asmhead.bin+bootpack.hrb haribote.sys

bootpack.hrb就是挨着asmhead.bin进行连接的,所以在asmhead.nas中定义的符号bootpack就是指向bootpack.hrb

7)程序最后跳转到 JMP DWORD 28:0x0000001b去执行程序了。
为什么跳转到这个地址,刚开始我也不解,看了好久才有点明白,上面的2
8其实就是选择GDT的第二个引索。

GDT0:
		RESB	8				; 这个是0个GDT引索
		DW		0xffff,0x0000,0x9200,0x00cf	; 这个是第1个
		DW		0xffff,0x0000,0x9a28,0x0047	; 这个是2个
		DW		0
GDTR0:
		DW		8*3-1   
		DD		GDT0
		ALIGNB	16

现在来看看GDT的64位段信息,并将第二段信息带入
0~15 --限制长度的低16位 --0xffff
16~31 --基地址低16位 --0000
32~39 -基地址中间8位 --28(因为是小端存储,所以28在前面)
40~47 --权限 --9a
48~55 --限制长度高8位 --cf
56~63 --基地址最高8位 --00

根据上面所得,基地址是0x280000,限制长度是0xcfffff,权限是9a,查资料是可执行的意思
至于为什么要跳转到0x1b的话,得看二进制文件可得
在这里插入图片描述
这样系统就进入bootpac.c程序里面去跑了。

版权声明:本文为LiJinGang6原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/LiJinGang6/article/details/108176605

智能推荐

CentOS 7配置南大docker镜像

文章目录 CentOS 7配置南大docker镜像 0.帮助页面 1.系统要求 2.卸载旧版本(没有旧版本可跳过) 3.安装方式 4.准备工作 5.可选操作 Stable Test Nightly 6.安装docker引擎 7. (可选)修改配置文件防止与xshell连接冲突 8.启动docker CentOS 7配置南大docker镜像 0.帮助页面 南大docker源:https://mirr...

Qcon演讲纪实:详解如何在实时视频通话中实现AR功能

2018年4月20日-22日,由 infoQ 主办的 Qcon 2018全球软件开发大会在北京如期举行。声网首席 iOS 研发工程师,iOS 端移动应用产品设计和技术架构负责人龚宇华,受邀分享了《基于 ARkit 和 ARcore,在实时视频通话中实现 AR 功能》,在演讲中剖析了 AR 与 VR 差异,ARKit 的工作原理,以及逐步讲解如何基于 ARKit 与声网Agora SDK 创建 AR...

POJ2348 UVa10368 HDU1525 Euclid's Game【博弈】

Euclid's GameTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4106    Accepted Submission(s): 1947 Probl...

使用Breeze.js编写更好的查询

这篇文章是由同行评审Agbonghama柯林斯 。 感谢所有SitePoint的审稿作出SitePoint内容也可以是最好的! 数据量正在迅速发展,他们正在变得越来越复杂,维护。 许多开发人员希望避免由数据问题他们的工作过程中造成的问题和头痛。 一个使我们的工作更轻松的图书馆是Breeze.js 。 在这篇文章中,我们将讨论我们如何能够写出更好的查询与Breeze.js。 但是首先,我们应该知道什...

Netty框架构建Nio编程

~~~ 随手点赞,养成习惯 ~~~ 为什么选择Netty框架 Netty是业界最流行的NIO框架之一,它的健壮性、功能、性能、可定制性和可扩展性在同类框架中都是首屈一指的。 优点: ① API使用简单,开发门槛低 ②功能强大,预置了多种编解码功能,支持多种主流协议 ③ 定制能力强,可以通过ChannelHandler对通信框架进行灵活地扩展; ④性能高,通过与其他业界主流的NIO框架对比,Nett...

猜你喜欢

【JZOJ5262】【GDOI2018模拟8.12】树(DP,性质题)

Description Solution 首先我们可以知道两个性质:1、路径u-v和路径v-w可以合并为路径u-w;2、路径u1-v1加路径u2-v2和路径u1-v2加路径u2-v1是等价的(就是起始点和终点可以互换) 那么知道这些性质之后就很好做了。我们只用知道每个点多少次做起点和多少次做终点。 我们设f[i]表示满足i子树的需求i上的值要是多少。 那么枚举i的所有儿子,判断a[i]-f[i],...

【String-easy】541. Reverse String II 反转的元素,有反转个数和间隔

1. 题目原址 https://leetcode.com/problems/reverse-string-ii/ 2. 题目描述 3. 题目大意 给定一个字符串,和字符串的间隔k, 这个k表示每k个数反转一次,然后再间隔k个元素再反转k个元素。 4. 解题思路 只要按照间隔去反转就可以了。然后间隔k个元素不反转是通过让i每次递增 2*k完成的。 5. AC代码 6. 相似题型 【1】344. Re...

【C语言笔记结构体】

我们都知道C语言中变量的类型决定了变量存储占用的空间。当我们要使用一个变量保存年龄时可以将其声明为int类型,当我们要使用一个变量保存某一科目的考试成绩时可以将其声明为float。 那么,当我们要做一个学生信息管理系统时,需要保存学生的姓名、学号、年龄等信息,该怎么做呢? 如当要保存三个学生的信息时, 方法一是: 方法二是: 显然,方法二跟更清晰,因为它把name、num、age都集成在一个模板,...

39. Combination Sum 回溯算法简析

LeetCode传送门     这道题要求给你一组正数 C,然后给你一个目标数 T,让你从那组C中找到加在一起等于 T 的那些组合。     例如:给你 [2,3,6,7] 和 7,则返回 [[2,2,3],[7] ] 。      想解决这个问题前,我们首先引入一个新问题,图(树)的遍历问题。  ...

git安装|Linux系统安装 git|Linux如何安装git?Linux通过远程安装git|

Git是一个开源的分布式版本控制系统,可以有效、高速地处理项目版本管理。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。 开发者需要一个GIT账号,通过这个查看项目的提交记录,可以更加清楚项目的开发情况,便于版本控制。 以下介绍在CentOS8操作系统搭建GIT服务器。   一、安装GIT服务器流程   安装GIT...