让系统内核突破512字节的限制

栏目: Java · 发布时间: 6年前

内容简介:之前做的系统内核,放在虚拟软盘的第一扇区,由于一个扇区只有512字节,因此系统内核的大小无法超过512字节。但是,一个拥有完整功能的内核不可能只有512字节,因此要想越过512字节的限制,具体做法就是做一个内核加载器(大小小于512字节),放入第一扇区,加载器加载入内存后,再将内核从软盘加载到系统内存,最后跳转到内核的加载地址假设把编译好的内核代码写入软盘的第一柱面,第2扇区,那么加载器的代码如下(boot.asm)

之前做的系统内核,放在虚拟软盘的第一扇区,由于一个扇区只有512字节,因此系统内核的大小无法超过512字节。但是,一个拥有完整功能的内核不可能只有512字节,因此要想越过512字节的限制,具体做法就是做一个内核加载器(大小小于512字节),放入第一扇区,加载器加载入内存后,再将内核从软盘加载到系统内存,最后跳转到内核的加载地址

假设把编译好的内核代码写入软盘的第一柱面,第2扇区,那么加载器的代码如下(boot.asm)

org  0x7c00;

LOAD_ADDR  EQU  0X8000

entry:
    mov  ax, 0
    mov  ss, ax
    mov  ds, ax
    mov  es, ax
    mov  si, ax

readFloppy:
    mov  CH, 1  ;CH 用来存储柱面号
    mov  DH, 0  ;DH 用来存储磁头号
    mov  CL, 2  ;CL 用来存储扇区号

    mov  BX, LOAD_ADDR  ;ES:BX 数据存储缓冲区

    mov  AH, 0x02  ;AH = 02 表示要做的是读盘操作
    mov  AL, 1  ;AL表示要练习读取几个扇区
    mov  DL, 0  ;驱动器编号,一般我们只有一个软盘驱动器,所以写死为0
    INT  0x13 ;调用BIOS中断实现磁盘读取功能

    JC  fin

    jmp  LOAD_ADDR

fin:
    HLT
    jmp  fin

readFloppy 这段代码的作用是从软盘的1柱面2扇区,将内核读取到系统内存的0x8000处,读取成功后,通过一个 jmp 跳转到内核的加载地址,将机器的控制权转交给内核。内核代码如下(kernel.asm)

org 0x8000

entry:
    mov ax,0
    mov ss,ax
    mov ds,ax
    mov es,ax
    mov es,ax
    mov si,msg
    
putloop:
    mov al,[si]
    add si,1
    cmp al,0
    je fin
    mov ah,0x0e
    mov bx,15
    int 0x10
    jmp putloop

fin:
    HLT
    jmp fin
    
msg:
    DB "This is Hello World from kernel"

下载 nasm软件 对汇编语言进行编译。使用命令分别编译加载器和内核:

nasm boot.asm -o boot.bat 
nasm kernel.asm -o kernel.bat

编译好以后,通过 java 代码将编译好的内核写入虚拟软盘

Floppy.java

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;

public class Floppy {
    enum MAGNETIC_HEAD {
        MAGNETIC_HEAD_0, MAGETIC_HEAD_1
    };

    public int SECTOR_SIZE = 512;
    private int CYLINDER_COUNT = 80; // 80个柱面
    private int SECTORS_COUNT = 18;
    private MAGNETIC_HEAD magneticHead = MAGNETIC_HEAD.MAGNETIC_HEAD_0;
    private int current_cylinder = 0;
    private int current_sector = 0;

    private HashMap<Integer, ArrayList<ArrayList<byte[]>>> floppy = new HashMap<Integer, ArrayList<ArrayList<byte[]>>>(); // 一个磁盘两个面

    public Floppy() {
        initFloppy();
    }

    private void initFloppy() {
        // 一个磁盘有两个盘面
        floppy.put(MAGNETIC_HEAD.MAGNETIC_HEAD_0.ordinal(), initFloppyDisk());
        floppy.put(MAGNETIC_HEAD.MAGETIC_HEAD_1.ordinal(), initFloppyDisk());
    }

    private ArrayList<ArrayList<byte[]>> initFloppyDisk() {
        ArrayList<ArrayList<byte[]>> floppyDisk = new ArrayList<ArrayList<byte[]>>(); // 磁盘的一个面
        // 一个磁盘面有80个柱面
        for (int i = 0; i < CYLINDER_COUNT; i++)
            floppyDisk.add(initCylinder());
        return floppyDisk;
    }

    private ArrayList<byte[]> initCylinder() {
        // 构造一个柱面,一个柱面有18个扇区
        ArrayList<byte[]> cylinder = new ArrayList<byte[]>();
        for (int i = 0; i < SECTORS_COUNT; i++) {
            byte[] sector = new byte[SECTOR_SIZE];
            cylinder.add(sector);
        }
        return cylinder;
    }

    public void setMagneticHead(MAGNETIC_HEAD head) {
        magneticHead = head;
    }

    public void setCylinder(int cylinder) {
        if (cylinder < 0)
            this.current_cylinder = 0;
        else if (cylinder >= 80)
            this.current_cylinder = 79;
        else
            this.current_cylinder = cylinder;
    }

    public void setSector(int sector) {
        // sector 编号从1到18
        if (sector < 0)
            this.current_sector = 0;
        else if (sector > 18)
            this.current_sector = 18 - 1;
        else
            this.current_sector = sector - 1;
    }

    public byte[] readFloppy(MAGNETIC_HEAD head, int cylinder_num, int sector_num) {
        setMagneticHead(head);
        setCylinder(cylinder_num);
        setSector(sector_num);

        ArrayList<ArrayList<byte[]>> disk = floppy.get(this.magneticHead.ordinal());
        ArrayList<byte[]> cylinder = disk.get(this.current_cylinder);

        byte[] sector = cylinder.get(this.current_sector);

        return sector;
    }

    public void writeFloppy(MAGNETIC_HEAD head, int cylinder_num, int sector_num, byte[] buf) {
        setMagneticHead(head);
        setCylinder(cylinder_num);
        setSector(sector_num);

        ArrayList<ArrayList<byte[]>> disk = floppy.get(this.magneticHead.ordinal());
        ArrayList<byte[]> cylinder = disk.get(this.current_cylinder);

        byte[] buffer = cylinder.get(this.current_sector);
        System.arraycopy(buf, 0, buffer, 0, buf.length);
    }

    public void makeFloppy(String fileName) {
        try {
            DataOutputStream out = new DataOutputStream(new FileOutputStream(fileName));
            for (int cylinder = 0; cylinder < CYLINDER_COUNT; cylinder++)
                for (int head = 0; head <= MAGNETIC_HEAD.MAGETIC_HEAD_1.ordinal(); head++)
                    for (int sector = 1; sector <= SECTORS_COUNT; sector++) {
                        byte[] buf = readFloppy(MAGNETIC_HEAD.values()[head], cylinder, sector);
                        out.write(buf);
                    }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

OPeratingSystem.java

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class OperatingSystem {

    private Floppy floppyDisk = new Floppy();
    private int MAX_SECTOR_NUM = 18;

    private void writeFileToFloppy(String fileName, boolean bootable, int cylinder, int beginSec) {
        File file = new File(fileName);
        InputStream in = null;

        try {
            in = new FileInputStream(file);
            byte[] buf = new byte[512];
            if (bootable) {
                buf[510] = 0x55;
                buf[511] = (byte) 0xaa;
            }

            while (in.read(buf) > 0) {
                // 将内核读入到磁盘第0面,第0柱面,第1个扇区
                floppyDisk.writeFloppy(Floppy.MAGNETIC_HEAD.MAGNETIC_HEAD_0, cylinder, beginSec, buf);
                beginSec++;

                if (beginSec > MAX_SECTOR_NUM) {
                    beginSec = 1;
                    cylinder++;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
    }

    public OperatingSystem(String s) {
        writeFileToFloppy(s, true, 0, 1);
    }

    public void makeFllopy() {
        writeFileToFloppy("kernel.bat", false, 1, 2);
        floppyDisk.makeFloppy("system.img");
    }

    public static void main(String[] args) {
        OperatingSystem op = new OperatingSystem("boot.bat");
        op.makeFllopy();
    }
}

运行的是 OperatingSystem.java 代码。将生成的虚拟软盘文件system.img加载到虚拟机中启动,就可以看到如下效果

让系统内核突破512字节的限制

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法竞赛入门经典

算法竞赛入门经典

刘汝佳 / 清华大学出版社 / 2009-11 / 24.00元

《算法竞赛入门经典》是一本算法竞赛的入门教材,把C/C++语言、算法和解题有机地结合在了一起,淡化理论,注重学习方法和实践技巧。全书内容分为11章,包括程序设计入门、循环结构程序设计、数组和字符串、函数和递归、基础题目选解、数据结构基础、暴力求解法、高效算法设计、动态规划初步、数学概念与方法、图论模型与算法,覆盖了算法竞赛入门所需的主要知识点,并附有大量习题。书中的代码规范、简洁、易懂,不仅能帮助......一起来看看 《算法竞赛入门经典》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具