用java和汇编开发一个Hello World系统内核
生活随笔
收集整理的这篇文章主要介绍了
用java和汇编开发一个Hello World系统内核
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
文章目录
- 1 汇编实现
- 1.1 汇编实现
- 1.2 使用nasm编译器进行编译
- 2 利用java生成软盘文件
- 2.1 利用java生成软盘文件的代码如下
1 汇编实现
1.1 汇编实现
汇编代码如下:
org 0x7c00;entry:mov ax, 0mov ss, axmov ds, axmov es, axmov si, msgputloop:mov al, [si]add si, 1cmp al, 0je finmov ah, 0x0emov bx, 15int 0x10jmp putloopfin:HLTjmp finmsg:DB 0x0a, 0x0adb "hello, world"db 0x0adb 0上面的汇编代码主要是设置了一些初始化数据,然后调用bios中断,将某个缓冲区中的字符打印到屏幕上,然后进入一个死循环。代码段的详细解释如下:
/* org 的意思是origin, 中文意思是“起始,起源,” org 后面的7c00 是物理内存地址,假设物理内存是一个byte类型 的大数组,例如byte[] memory, 如果你有2 G内容,换算成字节就是2097152, 也就相当于memory数组有2097152字 节,于是当虚拟机上电,然后new一块内存 byte[] memory = new byte[2097152]. org 0x7c00 的意思是将本汇编 编译后的二进制数据从memory[0x7c00]处写入memory. */ org 0x7c00;/* jmp entry 中的jmp 其实就是c语言中的语句goto, jmp entry 其实是让cpu跳转到entry 处,执行entry下面的代 码,如果entry是一个函数名字的话,jmp entry 相当于调用entry函数,类比于java就是函数调用:entry(); */ jmp entry// 下面的代码一直到RESB 18这行代码是可以直接删除的,我这里之所以放在这里是为了记录一下汇编知识点 /* jmp entry 对应的机器代码,长度是3字节,那么db 0x90 的意思就是 memory[0x7c00+3] = 0x90, 也就是说db 0x90 实际上做的是赋值操作,db 0x90 表示将给定位置处的一个字节赋予数值0x90, 赋值的内存位置就在0x7c00+3处。 */ db 0x90 /* DB 和 db 是同一个意思, 那么DB “OSKERNEL” 意思是,strcpy(memory + 0x7c00 + 3 + 1, “OSKERNEL”); 也就 是把”OSKERNEL”这个字符串拷贝到内存0x7c00 + 3 + 1 处, 3是什么意思呢,3就是jmp entry 编译成二进制代码后 的数据长度, 1 就是db 0x90 所所赋值的那个字节的长度。DW 跟DB是一个意思, DB 是将数据赋值给一个字节,由于 一个字节只有8位,那么赋值给这个字节的数据大小不能超过256, 512大于256,所以需要两个字节才能存储512这个数 据,DD 0xFFFFFFFF 就是把0xFFFFFFFF存储到四个字节长的内存中, 语句RESB 18 表示把接下来的18个字节的内存全 部初始化为0,转换为java代码就类似于: byte[] block = new byte[18]; for (int i = 0; i < 18; i++) { block[i] = 0; } */ DB "OSKERNEL" DW 512 DB 1 DW 1 DB 2 DW 224 DW 2880 DB 0xf0 DW 9 DW 18 DW 2 DD 0 DD 2880 DB 0,0,0x29 DD 0xFFFFFFFF DB "MYFIRSTOS " DB "FAT12 " RESB 18entry: /* 先做的是初始化一系列寄存器,寄存器其实相当于java程序中,我们定义的变量,ax 是一个2字节长的寄存器, mov ax, 0是把数值0放入到ax寄存器中,类比于java 就是: char ax = 0; char类型的数据在java中是两个字节长,跟寄存器ax的长度一样,类似的,语句: mov ss, ax 相当于java的 char ss = ax; 后面的语句意思类推。 */mov ax, 0mov ss, axmov ds, axmov es, ax /* 我们要注意看语句 mov si, msg. msg 相当于一段内存, msg: DB 0x0a, 0x0a db “hello, world” db 0x0a 就类似于 C 语言中的char* msg = “\n\nhello,world\n”. 字符’\n’的ascii值就是0xa.mov si, msg 就相当于把msg内存的起始地址放入到寄存器si里。如果用C语言做类比,那么就相当于: char* si = msg; */mov si, msgputloop: /* mov al, [si] [si]表示读取si存储的内存地址处的一个字节长度的信息, mov al, [si] ,把该字节的数据存储到寄存器al 中,ax是两个字节长度的寄存器,这样ax就可以分解成两部分,第一 部分就对应于al, 第二部分就对应于ah, 也就是al, ah合起来就是ax, 对应于C语言就相当于 char ax[2], al 表示的是ax[0], ah 表示的就是 ax[1], mov al, [si], 转换成C语言就是 char al = *si; */mov al, [si] /* add si, 1 表示将寄存器si中的数值加1,也就相当于C语言的 si++; */add si, 1 /* cmp al, 0 表示将al寄存器中的数据跟0比较,看al中的值是否等于0 */cmp al, 0 /* je fin 中的 je 表示 jump if equal, 也就是如果al 的值确实等于0,那么就跳转到fin所表示的代码处去执行,转 换成C语言就是 : if (al == 0) { goto fin } */je fin/* mov ah, 0xe 就是把0xe赋值给寄存器 ah, mov bx ,15 同理。接下来要调用一个中断,中断其实就是一个函数调用, 我们在写c语言或java程序时,往往需要调用一些系统库函数,例如printf, 或java的System.out.print. 中断就是 bios提供给汇编语言的库函数,这些库函数都放入到一个数组里,int 0x10 意思是在库函数数组中取出第0x10个库函 数,然后执行该库函数的代码。我们知道,函数调用时需要传递参数,那么调用bios提供的函数时,怎么传递参数呢,做法是,把需要传递的参数放入到 指定的寄存器中,例如想要在屏幕上输出字符,那么bios提供的编号为0x10的库函数可以实现这个功能,同时按规定, 要把寄存器ah设置为0x0e, 把要输出的字符的ascii值放入到寄存器al, 同时要把寄存器设bh的值设置成0,字符的颜色 可以通过寄存器bl的值来设定。看起来相当麻烦,这是由于我们做的是非常底层的编程,所以麻烦也就不可避免。 */mov ah, 0x0emov bx, 15int 0x10jmp putloop /* 于是代码片段: putloop: mov al, [si] add si, 1 cmp al, 0 je fin mov ah, 0x0e mov bx, 15 int 0x10 jmp putloop就相当于C语言: do { char al = *si; si++; if (al == 0) { goto fin }printf(“%c”, al); } while(true); *//* hlt 表示 halt, 也就是让cpu进入休眠状态,如果此时我们点击一下键盘,或动一下鼠标,那么cpu就被唤醒,然后执行hlt后面的语句: jmp fin 也就是跳转到fin开始处去执行,也就是进入了死循环。 */ fin:HLTjmp finmsg:DB 0x0a, 0x0adb "hello, world"db 0x0adb 01.2 使用nasm编译器进行编译
nasm boot.asm -o boot.bat 。
2 利用java生成软盘文件
2.1 利用java生成软盘文件的代码如下
import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList;public class OperatingSystem {private ArrayList<Integer> imgByteToWrite = new ArrayList<Integer>();private void readKernelFormatFile(String fileName){File file = new File(fileName);FileInputStream in = null;try{in = new FileInputStream(file);int val = 0;while ((val = in.read()) != -1){imgByteToWrite.add(val);}in.close();}catch (IOException e){e.printStackTrace();return;}// 当前代码之后至510字节全部写0int len = 510;int curlen = imgByteToWrite.size();for (int i=curlen; i<len; i++){imgByteToWrite.add(0);}// 第511、512字节为磁盘主引导扇区的有效标志,必须为0x55、0xaaimgByteToWrite.add(0x55);imgByteToWrite.add(0xaa);//imgByteToWrite.add(0xf0);//imgByteToWrite.add(0xff);//imgByteToWrite.add(0xff);}public OperatingSystem(String fileName) {readKernelFormatFile(fileName);// 1.44MB大小的软盘int len = 0x168000;int curSize = imgByteToWrite.size();for (int i=curSize; i<len; i++) {imgByteToWrite.add(0);}}public void makeFllopy() {try {DataOutputStream out = new DataOutputStream(new FileOutputStream("system.img"));for (int i = 0; i < imgByteToWrite.size(); i++) {out.writeByte(imgByteToWrite.get(i).byteValue());}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static void main(String[] args) {OperatingSystem op = new OperatingSystem("boot.bat");op.makeFllopy();} }参考资料:
总结
以上是生活随笔为你收集整理的用java和汇编开发一个Hello World系统内核的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 深州装修公司排名前十口碑推荐有哪些?
- 下一篇: 数据库与数据库管理系统的基本概念