自制操作系统01

这是一个系列文章。为什么要写这些文章,因为我作为一名程序员,想搞明白我们一天到晚玩的这些java,c到底基于一个什么环境。本来想把软硬件环境都搞清楚,于是尝试了编译openjdk,准备编译一个arduino的bootloader时,遇到了问题,c语言环境被搞乱了。于是想起多年前的这本书,当时没搞下去,笔记也记得不多。那么现在继续搞下去,笔记记清楚点。


记录了学习《30天自制操作系统》的笔记 ,今天是第一天:
1.准备好环境,我这是在win7安装了一个VMware
准备好随书光盘文件。
今天要用的是光盘里的helloos.img文件
2.VMware新建一个虚拟机,
关键点

a.新建时系统与其版本都选Other


b.软驱(Floppy)选上面的这个helloos.img文件,并把Connect at power on选上。


3.启动虚拟机,出现以下界面。



下面我们用作者推荐的bz打开这个helloos.img文件,可以观察到,这个文件就是开头与01F0这个位置左右不是0,其他都是0。即然这么简单,那我用java生成一个这样的文件。

先分析下,查看这个文件简介可知道总共有1474560个字节。而显示出来每两个十六进制数,实际上是一个字节(256)。

所以,如下图,状态栏把字节下标告诉我们了。


即有用的字节数是[0x0-0x82]与[0x1FE-0x202]这两段。那么我可以写程序了:
public class CreateOSImg {

	
	public static void main(String[] args) throws Exception {
		FileInputStream fis=new FileInputStream(new File("E:/30_workspace/helloos.img"));
		FileOutputStream fos=new FileOutputStream(new File("E:/30_workspace/javaos.img"));
		int totalLen=1474560;
		byte src[]=new byte[totalLen];
		fis.read(src);
		
		
		//总共有1474560个字节,
		for(int i=0;i<totalLen;i++){
			if((i>=0&&i<=0x82)||(i>=0x1FE&&i<=0x202)){
				fos.write(src[i]);
			}else{
				fos.write(0);
			}
		}
		fis.close();
		fos.close();

	}

}


完事把软驱文件选为生成的javaos.img文件。是不是看到相同的结果了。
即然这样,我们就把hello,word改一下,改成welcome to my os,当然也可改成自己的名字。
我们通过bz软件可以看到hello的开始位置是0x76,那么计算下:
[0x00-0x75]复制
[0x76-?]使用我们定制的。
[?-0x1FE]使用0。
[0x1FE-0x202]复制

[剩下的]使用0。

代码:

public class CreateOSImg {

	
	public static void main(String[] args) throws Exception {
		FileInputStream fis=new FileInputStream(new File("E:/30_workspace/helloos.img"));
		FileOutputStream fos=new FileOutputStream(new File("E:/30_workspace/javaos.img"));
		int totalLen=1474560;
		byte src[]=new byte[totalLen];
		fis.read(src);
		
		String welcome="welcome to my os";
		int welComeLen=welcome.getBytes().length;
		//总共有1474560个字节,
		for(int i=0;i<totalLen;i++){
			/*
			if((i>=0&&i<=0x82)||(i>=0x1FE&&i<=0x202)){
				fos.write(src[i]);
			}else{
				fos.write(0);
			}
			*/
			if(i>=0&&i<=0x75){
				fos.write(src[i]);
			}else if(i>=0x76&&i<(0x76+welComeLen)){
				fos.write(welcome.getBytes()[i-0x76]);
			}else if(i>=(0x76+welComeLen)&&i<0x1fe){
				fos.write(0);
			}else if(i>=0x1fe&&i<=0x202){
				fos.write(src[i]);
			}else{
				fos.write(0);
			}
			
			
		}
		fis.close();
		fos.close();

	}

}

这样也就能写程序了。执行后看一下效果:

汇编入门:
作者写了一个nask工具,上来就是汇编命令,不懂,查了下资料.
DB就是Define Byte的缩写,另外DW(2字节),DD(4字节),DQ(8字节),DF(6字节),DT(16字节),都是定义字节,不过越来越大。当然这里的Define就是写,类似java里的out.print。
nask工具基于nasm,那我还是用nasm吧,毕竟nasm有源码。
我在windows下没能安装nasm,外网太慢了。于是我在centos下执行nasm命令,下载nasm.
https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/nasm-2.14.02.tar.gz
然后
./configure
make
就会在本目录下生成nasm可执行文件。
然后执行nasm helloos.nas 这个文件也在光盘里。就生成了一个helloos的文件,这就是镜像软盘文件,拿到虚拟机里去执行是一样的效果。
好了下面我们按作者的最初做法,只用DB命令生成整个汇编程序。java代码如下:

package day1;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class CreateOSASM {

	
	public static void main(String[] args) throws Exception {
		FileInputStream fis=new FileInputStream(new File("E:/30_workspace/helloos.img"));
		PrintWriter pw=new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File("E:/30_workspace/javaos.asm")),"UTF-8"));
		int totalLen=1474560;
		byte src[]=new byte[totalLen];
		fis.read(src);
		//总共有1474560个字节,
		for(int i=0;i<totalLen;i++){
			
			if((i>=0&&i<=0x82)||(i>=0x1FE&&i<=0x202)){
				pw.println("DB 0x"+bytesToHexString(src[i]));
			}else{
				pw.println("DB 0x00");
			}
			
			
			
		}
		fis.close();
		pw.close();

	}
	
	public static String bytesToHexString(byte src){ 
	    StringBuilder stringBuilder = new StringBuilder(""); 
	     
	     
        int v = src & 0xFF; 
        String hv = Integer.toHexString(v); 
        if (hv.length() < 2) { 
            stringBuilder.append(0); 
        } 
        stringBuilder.append(hv); 
	     
	    return stringBuilder.toString(); 
	}  

}

这样生成的汇编代码比作者的更简陋和庞大。
哈哈,居然也可以nasm编译,且生成了同样的镜像文件。

明白了DB指令,现在再来尝试RESB指令。这个指令是reserve byte的缩写,0x1FE-0x82=0x17C=380
1474560-0x202=1474046
在中间两处分别写RESB 380与RESB 1474046来填充0x00。其实1474046多计算了一个字节,但我惊奇的发现,这也不影响结果。
最后粘一下正常的写出的汇编程序,光盘里是日文的,需要看请看翻译的书或自行翻译:

; hello-os
; TAB=4

; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述

		DB		0xeb, 0x4e, 0x90
		DB		"HELLOIPL"		; ブートセクタの名前を自由に書いてよい(8バイト)
		DW		512				; 1セクタの大きさ(512にしなければいけない)
		DB		1				; クラスタの大きさ(1セクタにしなければいけない)
		DW		1				; FATがどこから始まるか(普通は1セクタ目からにする)
		DB		2				; FATの個数(2にしなければいけない)
		DW		224				; ルートディレクトリ領域の大きさ(普通は224エントリにする)
		DW		2880			; このドライブの大きさ(2880セクタにしなければいけない)
		DB		0xf0			; メディアのタイプ(0xf0にしなければいけない)
		DW		9				; FAT領域の長さ(9セクタにしなければいけない)
		DW		18				; 1トラックにいくつのセクタがあるか(18にしなければいけない)
		DW		2				; ヘッドの数(2にしなければいけない)
		DD		0				; パーティションを使ってないのでここは必ず0
		DD		2880			; このドライブ大きさをもう一度書く
		DB		0,0,0x29		; よくわからないけどこの値にしておくといいらしい
		DD		0xffffffff		; たぶんボリュームシリアル番号
		DB		"HELLO-OS   "	; ディスクの名前(11バイト)
		DB		"FAT12   "		; フォーマットの名前(8バイト)
		RESB	18				; とりあえず18バイトあけておく

; プログラム本体

		DB		0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
		DB		0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
		DB		0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
		DB		0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
		DB		0xee, 0xf4, 0xeb, 0xfd

; メッセージ部分

		DB		0x0a, 0x0a		; 改行を2つ
		DB		"hello, world"
		DB		0x0a			; 改行
		DB		0

		RESB	0x1fe-$			; 0x001feまでを0x00で埋める命令

		DB		0x55, 0xaa

; 以下はブートセクタ以外の部分の記述

		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	4600
		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	1469432


文/中中 浏览次数:0次   2020-04-03 17:03:42

相关阅读


评论: