简介
虚拟机是利用软件来模拟完整的计算机系统,无需添加任何新的设备,而且与主计算机是隔离的,在虚拟机上的任何操作都不会影响到物理计算机上的操作系统和软件,还可以在装好系统的虚拟机下再克隆多个系统。虚拟机在测试病毒、频繁重启之类的软件中非常方便。
主流虚拟机
VMWare、Virtual PC 和VirtualBox 等,但是只有VirtualBox 是开源和免费的
软盘结构
一张3.5寸软盘有80个柱面(从0开始编号),2个磁头(从0开始编号),18个扇区(从1开始编号),每个扇区512字节。所以一张软盘容量 80x2x18x512 = 1474560B = 1440KB。
软盘读写顺序:0柱面0磁头1扇区 -> 0柱面0磁头2扇区 -> … ->0柱面0磁头18扇区 -> 0柱面1磁头1扇区 -> 0柱面1磁头2扇区 -> … 0柱面1磁头18扇区 -> 1柱面0磁头1扇区…
硬盘结构
硬盘结构和软盘结构非常相似。软盘采用塑料作为基片,表面涂有磁性物质用来记录2进制位。硬盘是多盘片、密封、高转速,采用铝合金作为基片表面涂有磁性物质用来记录2进制位。
每个盘片都有2个磁头,上面一个,下面一个,所以常用磁头表示盘面。第一个盘片上面磁头编号0,下面磁头编号为1;第2个盘片上面磁头编号2,下面磁头编号3,依次类推。
知道了硬盘的访问原理,完全可以使用如C语言制作一个虚拟硬盘,让虚拟机加载该文件。硬盘是一个典型的块(block)设备。采用磁道、磁头、扇区的模式访问硬盘称为CHS模式,但是很不方便,尤其是在制作虚拟硬盘文件时定位特定的磁道、磁头、扇区时。把原来的物理扇区访问方式映射为逻辑扇区(假设一个磁道共18个扇区):
逻辑0扇区对应0面0道1扇区;
逻辑1扇区对应0面0道2扇区;
…
逻辑17扇区对应0面0道18扇区;
逻辑18扇区对应1面0道1扇区;
逻辑19扇区对应1面0道2扇区;
…
故逻辑块地址(logical block address,LBA)计算方式如下:
LBA = cx磁头总数x每磁道扇区数+hx每磁道扇区数+扇区数-1
据此可以根据LBA 使用C 语言实现虚拟软盘文件如下:
floppy.c
//
// floppy.c
// os-test
//
// Created by vincent on 2018/10/29.
// Copyright © 2018年 vincent. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE* initFloppy(char *fileName){
FILE *fp = fopen(fileName, "w");
char buf[512];
memset(buf, 0, 512);
for(int c=0;c<80;c++){//磁道
for(int h=0;h<2;h++){//磁头
for(int s=1;s<=18;s++){//扇区
fwrite(buf, 512, 1, fp);
}
}
}
return fp;
}
void readFloppy(int c,int h,int s,FILE *fp,char *buf){
//把虚拟软盘映射成线性偏移
int index = 18*2*512*c + h*18*512 + (s-1)*512;
int tmp = (int)ftell(fp);
fseek(fp, index, SEEK_SET);
fread(buf,512,1,fp);
fseek(fp, tmp, SEEK_SET);
}
void writeFloppy(int c,int h,int s,FILE *fp,char *buf){
//把虚拟软盘映射成线性偏移
int index = 18*2*512*c + h*18*512 + (s-1)*512;
int tmp = (int)ftell(fp);
fseek(fp, index, SEEK_SET);
fwrite(buf, 512, 1, fp);
fseek(fp, tmp, SEEK_SET);
}
虚拟软盘文件共1.44M 足够学习相关原理,虚拟机虚拟硬盘文件的实现原理与虚拟软盘类似,但是每个厂商虚拟机的虚拟软盘可能有相关的规范,会在硬盘末尾或开头写入特定数据,但是我们使用2进制查看器分析后依然可以制作虚拟硬盘文件。
引导扇区
0磁道、0磁头、1扇区就是引导扇区,电脑开机后cpu会将引导扇区的数据读取到0x0:0x7c00处,然后从该位置执行代码。
有了虚拟软盘制作工具floppy.c 后我们可以简单实现一个简单开机过程体验。引导扇区字符输出boot.s 汇编文件如下:
mov ax,0xb800
mov ds,ax
mov byte [0],'a'
mov byte [2],'s'
mov byte [4],'m'
jmp $
使用nasm 编译boot.s
nasm boot.s -o boot.bin
使用main.c 虚拟软盘制作工具把boot.bin 写入虚拟软盘
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "floppy.h"
int main(int argc,char **argv){
FILE *fp = initFloppy("floppy.img");
if(fp == NULL) {
printf("初始化磁盘失败");
exit(0);
}
FILE *src = fopen("boot.bin", "r");
if(src == NULL) {
printf("文件打开失败:%s\n","boot.bin");
exit(0);
}
char buf[512];
memset(buf, 0, 512);
fread(buf, 512, 1, src);
writeFloppy(0, 0, 1, fp, buf);
fclose(src);
fclose(fp);
return 0;
}
gcc 或 clang 编译器生成软盘工具mf,笔者使用clang 编译器
clang main.c floppy.c -o mf
运行./mf
将会在当前目录下生成floppy.img 虚拟软盘文件。
VirtualBox创建虚拟机加载虚拟软盘文件floppy.img,由于我们使用的是虚拟软盘文件所以要添加虚拟软盘控制器,如下图:
虚拟软盘控制器添加成功后如下图
我们使用的是虚拟软盘控制器,所以IDE控制器可以直接删除。删除IDE控制器后选中虚拟软盘控制器添加虚拟软盘文件floppy.img
虚拟机启动时会像真实的计算机一样加载硬盘上的引导扇区代码,运行显示字符效果如下: