自制操作系统日志——第二十九、三十天

自制操作系统日志——第二十九、三十天

其实,在昨天我们已经完成了我们这个纸娃娃操作系统的基本功能了。但是呢,我们今天还是要继续进一步的完善一下,那么今天呢,主要就是进行一下压缩与制作一些简单的小游戏。



一、压缩

这里呢,我们想要给操作系统添加上一个功能。即,我们可以支持文件压缩的功能。当然,这一个支持文件压缩的功能并不是说我们制作一个用于压缩的程序,而是说我们能够将压缩好的文件可以在操作系统内部进行解压缩,即对于压缩过的文件,我们一九可以做到像未经压缩的文件一样使用。

为什么要这样子做呢?其实主要还是因为,我们想要整个操作系统读入的文件大小更加小巧而已!! 那么接下来就让我们开始制作吧:

对于解压缩的文件tek.c 这里我不在赘述了,直接将源代码中的tek.c放进haribote文件夹里。以及在添加上tek的文件夹即可。然后,我们添加导入的函数:

  • file.c: file_loadfile2 ==> 函数的功能是,首先使用alloc申请必要的内存空间;然后用file_loadfile将文件内容导入内存空间; 如果文件大小超过17KB则有可能是tek的文件,则调用tek_getsize进行判断,如果判断该文件确实是tek文件,则为解压缩后的文件申请内存空间,并执行解压缩操作,并舍弃之前的文件内容,函数返回存放文件的内存地址:
char *file_loadfile2(int clustno, int *psize, int *fat)
{
	int size = *psize, size2;
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
	char *buf, *buf2;
	buf = (char *) memman_alloc_4k(memman, size);
	file_loadfile(clustno, size, buf, fat, (char *) (ADR_DISKIMG + 0x003e00));
	if (size >= 17) {
		size2 = tek_getsize(buf);
		if (size2 > 0) {	/* 使用tek格式进行解压缩 */
			buf2 = (char *) memman_alloc_4k(memman, size2);
			tek_decomp(buf, buf2, size2);
			memman_free_4k(memman, (int) buf, size);
			buf = buf2;
			*psize = size2;
		}
	}
	return buf;
}
  • graphic.c: 修改之前的导入字库文件:
void font_init(unsigned char mode)
{
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
	int *fat;
	int i;
	unsigned char *nihongo, *hzk;
	struct FILEINFO *finfo;
	extern char hankaku[4096];
    if( mode == 3)
	{
		//载入HZK16,中文字符集
		fat = (int *) memman_alloc_4k(memman, 4 * 2880);
		file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200));

		finfo = file_search("hzk16s.fnt", (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
		if (finfo != 0) {
			i = finfo->size;
			hzk = file_loadfile2(finfo->clustno, &i, fat);
		} else {
			hzk = (unsigned char *) memman_alloc_4k(memman, 0x5d5d * 32);
			for (i = 0; i < 16 * 256; i++) {
				hzk[i] = hankaku[i]; /* 没有字符库,则直接赋值前面的英文字符库 */
			}
			for (i = 16 * 256; i < 0x5d5d * 32; i++) {
				hzk[i] = 0xff; /* 剩下部分填充0xff*/
			}
		}
		*((int *) 0x0fe8) = (int) hzk; //用0xfe8存字库地址
		memman_free_4k(memman, (int) fat, 4 * 2880);
	}

	if( mode == 2)
	{
		fat = (int *) memman_alloc_4k(memman, 4 * 2880);
		file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200));

		finfo = file_search("nihongo.fnt", (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
		if (finfo != 0) {
			i = finfo->size;
			nihongo = file_loadfile2(finfo->clustno, &i, fat);
			} else {
			for (i = 0; i < 16 * 256; i++) {
				nihongo = (unsigned char *) memman_alloc_4k(memman, 16 * 256 + 32 * 94 * 47);
				nihongo[i] = hankaku[i]; /* 没有字符库,则直接赋值前面的英文字符库 */
			}
			for (i = 16 * 256; i < 16 * 256 + 32 * 94 * 47; i++) {
				nihongo[i] = 0xff; /* 剩下部分填充0xff*/
			}
		}
		*((int *) 0x0fd8) = (int) nihongo; //用0xfe8存字库地址
		memman_free_4k(memman, (int) fat, 4 * 2880);
	}
}

然后,我们继续加把劲,压缩一下其他的应用程序:
console.c:

int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
{int i, segsiz, datsiz, esp, dathrb, appsiz;if (finfo != 0) {
		/*找到文件的情况*/
		appsiz = finfo->size;
		p = file_loadfile2(finfo->clustno, &appsiz, fat);
		if (appsiz >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) {}memman_free_4k(memman, (int) p, appsiz);
		cons_newline(cons);
		return 1;
	}

int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{else if (edx == 21){//打开文件
		for(i = 0; i < 8; i++){
			if(task->fhandle[i].buf == 0){
				break;
			}
		}
		fh = &task->fhandle[i];
		reg[7] = 0;
		if(i < 8){
			finfo = file_search((char *) ebx + ds_base,
			        (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
			if(finfo != 0){
				reg[7] = (int) fh;//返回文件句柄
				fh->buf = (char *) memman_alloc_4k (memman, finfo->size);
				fh->size = finfo->size;
				fh->pos = 0;
				fh->buf = file_loadfile2(finfo->clustno, &fh->size, task->fat);
			}
		}
	}}

然后,我们还需要修改一下,app_make.txt:

%.org : %.bim Makefile ../app_make.txt
	$(BIM2HRB) $*.bim $*.org $(MALLOC)

%.hrb : %.org Makefile ../app_make.txt
	$(BIM2BIN) -osacmp in:$*.org out:$*.hrb

然后,运行一下:
在这里插入图片描述

可以看出,大小确实小了很多!! oh,对了我忘记说字符库的压缩了:
我们将需要载入的字符库进行压缩一下,主要使用如下命令:

bim2bin -osacmp in:hzk16s.org out:hzk16s.fnt

这里,我们先将原本的hzk16s 重命名为了hzk16s.org 然后再使用bim2bin.exe文件进行了压缩:
在这里插入图片描述
而且系统没啥问题:
在这里插入图片描述
不过呢,这里不知道是qemu的问题还是压缩器的问题,如果压缩了中文字符库可能会出bug,因此啊大家自行尝试了。

软件

软件部分,我就不详述了,毕竟我们主要是为了了解操作系统的。这里直接看书以及参考本文的源代码即可。不过对于文本阅读器这里,我们要增加一段:

if (lang == 3 ) {	/* EUC */
			if (*p == 0x09) {
				x = puttab(x, w, xskip, s, tab);
				p++;
			} else if (0xa1 <= *p && *p <= 0xfe) {
				/* ‘SŠp•¶Žš */
				if (x == -1) {
					s[0] = ' ';
				}
				if (0 <= x && x < w - 1) {
					s[x]     = *p;
					s[x + 1] = p[1];
				}
				if (x == w - 1) {
					s[x] = ' ';
				} 
				x += 2;
				p += 2;
			} else {
				if (0 <= x && x < w) {
					s[x] = *p;
				}
				x++;
				p++;
			}
		}

这样子就可以支持中文的文字显示了!!!

二、ipl的改良

由于这里我的中文字符库并未压缩,因此这里我们虽然使用了快速读入,但是我读取的柱区依旧很多:

; haribote-ipl
; TAB=4

CYLS	EQU		30				; 声明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
		MOV		BX,18*2*CYLS-1	; 要读取的合计扇区数
		CALL	readfast		; 告诉读取

; 读取完毕,跳转到haribote.sys执行!
		MOV		[0x0ff0],CH		; 记录IPL实际读取了多少内容
		JMP		0xc200

error:
		MOV		AX,0
		MOV		ES,AX
		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

readfast:	; 使用AL尽量一次性读取数据 从此开始
; ES:读取地址, CH:柱面, DH:磁头, CL:扇区, BX:读取扇区数

		MOV		AX,ES			; < 通过ES计算AL的最大值 >
		SHL		AX,3			; 将AX除以32,将结果存入AH(SHL是左移位指令)
		AND		AH,0x7f		; AH是AH除以128所得的余数(512*128=64K)
		MOV		AL,128		; AL = 128 - AH; AH是AH除以128所得的余数(512*128=64K)
		SUB		AL,AH

		MOV		AH,BL			; < 通过BX计算AL的最大值并存入AH >
		CMP		BH,0			; if (BH != 0) { AH = 18; }
		JE		.skip1
		MOV		AH,18
.skip1:
		CMP		AL,AH			; if (AL > AH) { AL = AH; }
		JBE		.skip2
		MOV		AL,AH
.skip2:

		MOV		AH,19			; < 通过CL计算AL的最大值并存入AH >
		SUB		AH,CL			; AH = 19 - CL;
		CMP		AL,AH			; if (AL > AH) { AL = AH; }
		JBE		.skip3
		MOV		AL,AH
.skip3:

		PUSH	BX
		MOV		SI,0			; 计算失败次数的寄存器
retry:
		MOV		AH,0x02			; AH=0x02 : 读取磁盘
		MOV		BX,0
		MOV		DL,0x00			; A盘
		PUSH	ES
		PUSH	DX
		PUSH	CX
		PUSH	AX
		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			; 驱动器重置
		POP		AX
		POP		CX
		POP		DX
		POP		ES
		JMP		retry
next:
		POP		AX
		POP		CX
		POP		DX
		POP		BX				; 将ES的内容存入BX
		SHR		BX,5			; 将BX由16字节为单位转换为512字节为单位
		MOV		AH,0
		ADD		BX,AX			; BX += AL;
		SHL		BX,5			; 将BX由512字节为单位转换为16字节为单位
		MOV		ES,BX			; 相当于EX += AL * 0x20;
		POP		BX
		SUB		BX,AX
		JZ		.ret
		ADD		CL,AL			; 将CL加上AL
		CMP		CL,18			; 将CL与18比较
		JBE		readfast	; CL <= 18则跳转至readfast
		MOV		CL,1
		ADD		DH,1
		CMP		DH,2
		JB		readfast	; DH < 2则跳转至readfast
		MOV		DH,0
		ADD		CH,1
		JMP		readfast
.ret:
		RET

		RESB	0x7dfe-$	;0x7dfe为止用0x00填充的指令

		DB		0x55, 0xaa

使用了快速读入!!

三、制作ISO映像

点击打开fdtoiso.exe这个软件,然后按下图步骤进行即可:

在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、

下载地址:https://sourceforge.net/projects/cdrtfe/

点击这个软件:
在这里插入图片描述

选择中文模式:
在这里插入图片描述
点击文件系统
在这里插入图片描述
点击【制作引导光盘】,然后点击下方的【浏览】,选择对应的软盘 img文件。

在这里插入图片描述

然后还需要点击【光盘选项】后,设置:
在这里插入图片描述

点击确定后,我们就可以把想载入的一些其他文件拖到软件的窗口里,并点击【开始】的按钮就可以进行刻录了。
在这里插入图片描述

然后就会看到下面有生成的信息了!!

在这里插入图片描述


总结

Yuan - OS
历经接近一个月的磨练,最终实现了一个操作系统的雏形。
我制作的YuanOS一共 39.8 KB,主要实现了以下的功能:
1、开启了32位的保护模式;
2、能够实现1024 x 768 x 8的画面模式;
3、实现了GDT(全局段号记录表)、IDT(内存中断管理表)与LDT(程序段管理表);
4、实现了内存的动态管理与分配;
5、实现了利用图层技术显示窗口与画面;
6、实现了定时器的功能;
7、实现了内存保护机制(并利用程序进行了越权访问的测试);
8、实现了多任务;
9、实现了API的制作以及应用程序的制作;
10、实现了命令行窗口;
11、实现了中文和日文的显示,并可以无缝切换;
12、能够看图片,听音乐、打游戏等等。

虽然有可能会有大佬不屑一顾这个雏形,但对于我这个初学者来说,我已经从中学到许多了。收获颇丰,虽然中间过程蛮辛苦的,也曾想过放弃,但是咬咬牙努力的坚持了下来,最终有这个收获我还是非常开心的!!!

最后来张全家福,嘿嘿嘿!
在这里插入图片描述

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值