自制x86玩具操作系统 week2

2019-05-01 | OSDev | #操作系统 #DIY

DAY 0x03

Makefile

汇编

例如

		MOV		AX,0x0820
		MOV		ES,AX			; 缓冲区段地址
		MOV		CH,0			; 柱面号为0
		MOV		DH,0			; 磁头号0
		MOV		CL,2			; 扇区号2

		MOV		AH,0x02			; AH=0x02 : 从磁盘读入
		MOV		AL,1			; 1读取一个扇区
		MOV		BX,0			; 缓冲区地址
		MOV		DL,0x00			; 0号驱动器
		INT		0x13			; 磁盘BIOS调用
		JC		error

该1.44Md的3.5寸软盘共有80个柱面(cylinder)(0-79),2个磁头(0-1),18个扇区(1-18) 启动区位于C0-H0-S1,扇区序号按扇区→磁头→柱面的顺序进位

内存区域(x86)

低地址区域

|-------------------------------------------------------|0x00000000
|	1 KiB 	RAM - partially unusable (see above) 		|
|	Real Mode IVT (Interrupt Vector Table)			 	|0x000003FF
|-------------------------------------------------------|0x00000400
|	256 bytes 	RAM - partially unusable (see above)	|
|	BDA (BIOS data area)								|0x000004FF
|-------------------------------------------------------|0x00000500
|	almost 30 KiB 	RAM (guaranteed free for use)		|
|	Conventional memory									|0x00007BFF
|-------------------------------------------------------|0x00007C00 ←
|	512 bytes 	RAM - partially unusable (see above)	|
|	Your OS BootSector									|0x00007DFF
|-------------------------------------------------------|0x00007E00
|	480.5 KiB 	RAM (guaranteed free for use)			|
|	Conventional memory									|0x0007FFFF
|-------------------------------------------------------|0x00080000
|	128 KiB 	RAM - partially unusable (see above)	|
|	EBDA (Extended BIOS Data Area)						|0x0009FFFF
|-------------------------------------------------------|0x000A0000
|	384 KiB 	various (unusable)						|
|	Video memory, ROM Area								|0x000FFFFF
|-------------------------------------------------------|

参考

关于作者开发的edimg.exe工具

edimg imgin:../z_tools/fdimg0at.tek \ #读取映像文件
		wbinimg src:ipl.bin len:512 from:0 to:0 \ #将指定文件的内容写入映像的指定位置,一般用于写入引导扇区
		copy from:haribote.sys to:@: \ #将文件写入磁盘映像中或从中取出文件,@:表示盘符,类似于C:和D:等
		imgout:haribote.img #输出文件名

ipl.nas启动后从C0-H0-S2开始加载,加载到0x08200地址处,略过了启动区。 haribote.nas开头设置ORG 0xc200,其中0xc200=0x08200-0x00200+0x04200,意味着这段程序将被加载到0xc200这个地址 作者书中说整个磁盘上的内容被加载到0x08000号地址,但实际上代码只加载了第二扇区开始的内容到0x08000,调试查看0x08000-0x08200并没有找到启动区的数据,发现该系统采用小端字节序,不知道和我用的是bochs还是qemu也没有关系

参考

启动程序加载器完成磁盘数据的加载以后,跳转到第一个文件的位置开始执行,确认无误以后make run但是究竟程序有没有出错呢,屏幕一片黑啥也看不出,于是在切换显卡模式以后,往屏幕上输出一段信息确定启动没有问题。

然后是加了一堆预定义的地址,记录一堆数据,其中有一个图像缓冲区的初始地址0xa0000,于是尝试直接debug往这个地址以及后面的那块区域里面写东西,但是并没有像预想的那样在屏幕上出现图案。emmm先留着。

查看网页发现0xa0000到0xaffff是VRAM的空间,一个像素点是一个字节,分辨率是320*200,试试循环画点?

尝试了如下代码,

		MOV		DX,0xf0
		MOV		CX,0
		MOV		BX,0
		MOV		AX,0xa000
		MOV		ES,AX
		JMP		write_VRAM

write_VRAM:
		MOV		BX,CX
		ADD		CX,1
		CMP		CX,320*200
		MOV		[ES:BX],DX
		JBE		write_VRAM

结果整个屏幕果然呈现了棕绿色,吧DX改为0x0f,结果屏幕变成了全白色 最后选定了0x08,深灰色

证实了,确实能直接在显示内存区域直接写数据然后显示出来

接下来在asmhead.nas里加上一堆汇编代码,然后最终调用了bootpack.cHariMain(),然后用汇编编写了一个输出模式为WCOFFnaskfunc.nas文件,其中编写了执行HLT指令的函数io_hlt(),然后编译成目标文件让bootpack.c链接,暴露的函数名称要声明为GLOBAL。 在

将目标文件用作者的工具链接起来以后就会得到bim文件

总之这样超长的第三天过去了,还剩下asmhead里面加的100行代码作者没有解释 不如先试着看看吧,能看多少是多少

汇编

DAY 0x04

因为自带的cc1不支持最高只支持c99,用着很不爽,改成了电脑上装的gcc输出汇编指令,发现也能运行,只是gas2nask的时候程序状态值为1,但是不影响运行,修改makefile在该条指令前加上-就能避免整个make进程的中断

汇编

Makefile

作者第四天一开始在c程序里面进行了绘制操作,但是我在第三天的时候已经用汇编指令对图像内存缓存地址区域进行了写值,因此,这里验证了write_mem8以后注释这一段了 在第三天的时候我也用汇编的形式在asmhead.nas里做了作者第四天做的第二件事情,写入条纹图案,只不过我写入的条纹时写入的是i而不是i&0x0f,不过也看到了一些奇怪的条纹

之后作者长篇叙述了指针的概念及其实现,这些已经懂了的知识就草草看完进入第四天的第6小节了

VGA8位色号

作者定义的调色板:

 0:#000000:黑	 6:#00ffff:浅亮蓝	12:#000084:暗蓝
 1:#ff0000:亮红	 7:#ffffff:白		13:#840084:暗紫
 2:#00ff00:亮绿	 8:#c6c6c6:亮灰		14:#008484:浅暗蓝
 3:#ffff00:亮黄	 9:#840000:暗红		15:#848484:暗灰
 4:#0000ff:亮藍	10:#008400:暗绿
 5:#ff00ff:亮紫	11:#848400:暗黄

VGA/EGA调色板技术

调色板是当初为了节约宝贵的内存空间而设计的一种解决方案,屏幕上最多可以显示16种颜色,在EGA的16个颜色寄存器存储颜色的。每个颜色存储器有3*6=18位,其中R、G、B各用6位表示,即R、G、B各有64种取值,从0到63代表颜色的程度,所以一种颜色用18位表示。这样机器能够显示的颜色总共有64*64*64=256k种,但是同一时刻在屏幕上显示的颜色只有16种,图像缓存区域中每个像素点只需用一个字节(实际上是0-15的值)来表示这16种颜色的索引号。

EFLAGS寄存器(32位,由FLAGS扩展而来),FLAGS的各个位含义

-------------------------------------------------
|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
|  |NT| IOPL|OF|DF|IF|TF|SF|ZF|  |AF|  |PF|  |CF|
-------------------------------------------------

中断标志位在第9位

汇编

参考

DAY 0x05

由hankaku.txt生成的obj文件中,.data段存的是连续的字符数据,该obj文件导出了一个符号_hankaku 要使用该外部obj导出的符号,只要在c文件里用extern char hankaku[4096]即可

第五天的实验开始出现了问题,因为之前由于忍受不了只允许使用c99标准,我改成了用gcc -S 输出代码,但是现在似乎问题更大了,gcc输出的汇编中包含一个叫.section .rdata的段,这个段不能被gas2nask识别,而函数调用参数中的字符串字面量就在这个段里存着 比如

putfonts8_asc(vram, xsize, ysize, 0, 0, COL8_FFFFFF, "test it!");

这条里面的"test it!"就在这个段里,被gas2nask忽略掉了以后,导致生成的nas文件里头缺失了这部分内容,nask编译出错。 上网意外找到了作者的github,clone下来编译不过关,缺少个文件,遂放弃。 有意外找到OSASK项目的项目中文首页,从中下载了2010年的版本,没想到这个作者依然没有注意到这个bug,我绝望了,删光了下载的东西,决心不用nask了,另外想办法整一下

回忆编译流程,发现bootpack.c最终是为了生成.obj目标文件,而这个作者偏偏要先生成.gas,再生成.nas,再用他那个nask编译成.obj,其实这其中的步骤完全就可以省略嘛,我之前就用了gcc,现在,直接可以gcc -c生成目标文件,于是乎改写Makefile,直接通过编译!(坑爹的作者)

既然改了这么多,代码也越来越乱,干脆一改到底,就用c++,反正c++也是兼容c的问题不大。

但是用c++编译,链接时出现问题

Warning : can't link _HariMain

原因是c++编译的名字修饰规则和c的不匹配,入口函数被编译成了__Z8HariMainv,这下我大概明白它的原理了,我们在写的bootpack.cpp是要被作为类库一样被链接的,而另外一边是已经写好了的,所以只能让我们这边做妥协,到解决办法是定义处套上extern "C"就好了

在引入了c++的基础上,我新建了几个文件,还增加了Cursor类和Mouse类,Cursor对象相当于一个隐形的光标,封装的函数,可以方便地进行定位,比如,下一格,换行等操作,这样代码也更加清晰。

分段

段的有关信息(CPU用8个字节,即64位的数据来表示这些信息)
GDT 全局段号记录表(global segment descriptor table)
IDT 中断记录表(interrupt descriptor table)

数据的组织形式应该是和机器是小端模式有关系,因为GDT的数据结构中base字段的低24位被储存到16位的base_low和base_mid的低八位中了,但是base剩下的最高8位为什么被存储到与前面两个字段不相邻的base_high字段我就不清楚了。