dustland

dustball in dustland

x86汇编语言 chapter 4 虚拟磁盘

虚拟硬盘vhd

virtual hard disk

用virtualbox新建的没有操作系统的虚拟电脑,选择VHD格式虚拟硬盘,固定大小2G.

刚建立的vhd虚拟硬盘文件的最后512字节是有意义的,前面其他字节都是空的

这最后512个字节是啥呢?

image-20220825094005879

结构体定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct hd_ftr { //harddisk_footer
  char   cookie[8];       /* Identifies original creator of the disk      */ //魔数
  u32    features;        /* Feature Support -- see below                 */ 
  u32    ff_version;      /* (major,minor) version of disk file           */ 
  u64    data_offset;     /* Abs. offset from SOF to next structure       */ 
  u32    timestamp;       /* Creation time.  secs since 1/1/2000GMT       */ 
  char   crtr_app[4];     /* Creator application                          */ 
  u32    crtr_ver;        /* Creator version (major,minor)                */ 
  u32    crtr_os;         /* Creator host OS                              */ 
  u64    orig_size;       /* Size at creation (bytes)                     */ 
  u64    curr_size;       /* Current size of disk (bytes)                 */ 
  u32    geometry;        /* Disk geometry                                */ 
  u32    type;            /* Disk type                                    */ 
  u32    checksum;        /* 1's comp sum of this struct.                 */ 
  vhd_uuid_t uuid;        /* Unique disk ID, used for naming parents      */ 
  char   saved;           /* one-bit -- is this disk/VM in a saved state? */ 
  char   hidden;          /* tapdisk-specific field: is this vdi hidden?  */ 
  char   reserved[426];   /* padding                                      */ 
}; 

可以理解为文件魔数,通过检查cookie值是否是"conectix",判断该VHD是否有效

conectix是connectix公司的名称缩写,这个技术是connectix发明的

features

1
2
3
#define HD_NO_FEATURES     0x00000000 
#define HD_TEMPORARY       0x00000001 /* disk can be deleted on shutdown */ //只要关机就删除硬盘
#define HD_RESERVED        0x00000002 /* NOTE: must always be set        */ 

ff_version

VHD版本

data_offset

对固定磁盘来说,该值总是0xFFFFFFFF,不重要

对于动态磁盘来说,该值是dd_hdr的文件偏移量

timestamp

VHD文件的创建时间,不重要

crtr_app

创建该VHD文件使用的应用程序,如果是virtualbox创建的则为"vbox"

crtr_ver

创建版本,不同磁盘版本管理方法不同

crtr_os

操作系统枚举值

image-20220825094803757

orig_size

创建时该虚拟磁盘的可用寻址空间,大小等于整个vhd文件大小减去该尾部扇区512字节

该nobody.vhd文件在创建时我们选择的大小是整2G,用010editor打开观察,发现除了最后一个扇区正好2G,全空.

加上最后一个扇区则为2GB+512B

curr_size

当前大小,可能是扩容后的可用寻址空间

geometry

几何参数,即柱面数C,磁头数H,扇区数S

image-20220825102119209

VHD规范中,每个扇区sector大小是512B

刚建立的2G的虚拟硬盘,有4161个柱面

16个磁头,即16个盘面

每个柱面上有63个扇区

VHD文件最开始的512字节,就对磁盘的0面0道1扇区,也就是主引导扇区

接下来是0面0道2扇区

0面0道3扇区

...

0面0道63扇区

1面0道1扇区

1面0道2扇区

...

1面0道63扇区

...

15面0道0扇区

15面0道1扇区

15面0道63扇区

0面1道0扇区

type

VHD类型

1
2
3
4
#define HD_TYPE_NONE       0 //无类型
#define HD_TYPE_FIXED      2 //固定大小 
#define HD_TYPE_DYNAMIC    3 //动态大小
#define HD_TYPE_DIFF       4 //差分磁盘

前三个容易理解,第四个差分磁盘是什么呢?

差分盘分成母盘和子盘,一个母盘可以带好几个子盘,母盘存放这几个子盘共有的东西,比如操作系统代码,就跟so动态库似的可以复用

每个子盘中单独存放自己的数据

假如原来要装四个虚拟机,每个虚拟机操作系统在磁盘中占8g,剩下2g磁盘存放数据.

如果不使用差分磁盘,则四个虚拟机就实打实地需要40G的物理磁盘

然而每个虚拟机中占据8G磁盘的操作系统实际上是搞重复建设

因此可以用母盘放8G的操作系统,四个子盘每个2G存放各自的数据.

这样总共占用物理磁盘16G

checksum

检校和

最后这个扇区的所有字节相加得到的32位数按位取反

uuid

VHD识别号,决定VHD主从关系

saved

动态磁盘才会使用,不重要

reserved

保留关键字,尚未使用

物理磁盘

磁盘结构

结构总览

img
image-20220825105415000

面0,面1,实际上就是磁头0,磁头1

因为每个面上都会有一个磁头负责读写该面的数据

扇区和磁道的关系

img

一个盘面从里向外有多个同心圆磁道,每个磁道上有多个扇区,但是任意两个磁道的扇区数是相同的,

可以想象,越往外的磁道,一个扇区约长,数据约稀疏

磁头和柱面

img

柱面和磁头都是从0开始编号,但是扇区是从1开始编号的

一个盘片就像一个烧饼一样有两面,每面上都有磁道,一个柱面就是所有等半径的磁道集合

比如有三个盘片就有6个盘面,那么半径为2厘米的磁道就有6条,半径为2厘米的柱面就包含了这6条磁道

有多少个盘面就得有多少个磁头,每个磁头负责一个盘面的读写

所有磁头的动作都是同步的,就算是要读写最顶上这个盘的上面,所有的磁头都得跟着最上面这个磁头动,从顶向下看所有磁头是重叠的.但是只有上面这个磁头可以读写数据.控制哪个磁头也是硬盘控制器要做的工作

读写速度

磁盘的读写速度有三个方面组成

寻道时间,旋转时间,传送时间

寻道时间

假如一开始磁头都趴在最外环上,现在需要往最内环的扇区读写数据,那么传动臂就得跟个塔吊一样把磁头吊过去

这是肉眼可见的,显然速度非常慢

旋转时间

现在磁头已经到达了最内环,要读写该环上的第一个扇区,但是不巧,磁头刚过来时,第一个扇区刚转过去,磁头就得等到盘子转一整圈才能盼来第一个扇区,而CPU早已望眼欲穿了

传送时间

扇区也到位了,磁头赶紧趴下看看扇区上写了啥

这个过程肉眼几乎不可见,是最快的

这三个过程前面两个都是毫秒量级的,并且差不多.最后的传送时间稀松了了,相对于前面俩可以忽略

访问模式

访问模式有两种,老古董CHS模式,即通过指定柱面,磁头,扇区三个坐标访问一个扇区

现代LBA(logical block address)模式,不考虑柱面,磁头数了,所有扇区统一编号,将逻辑扇区号翻译成CHS的工作交给硬盘控制器干

LBA和CHS的映射关系

image-20220825111708551

逻辑扇区从0开始编号

假设某个硬盘有h个磁头,c个柱面,每个磁道上有s个扇区,给定一个逻辑扇区号g,求改扇区落在哪个盘子的哪个磁道上

这三个单位的权重是c>h>s

因为寻道时间>旋转时间>传送时间,因此最忌讳动传动臂,磁头最好老实在固定的一环上趴着,等这个柱面上的所有磁道都满了,才迫不得已动一下传动臂换个圈转

这就是为啥权重c>h

每个柱面上有h*s个扇区,每个磁道上有s个扇区

n*h*s<=g<(n+1)*h*s

n就是第几个柱面,也就是哪个磁道,至于哪个盘子

1
k*s<=(g-n*h*s)<(k+1)*s

k就是哪个盘子

瞎写主引导记录

程序来自教材x86汇编语言从实模式到保护模式

image-20220825113210639

他这段程序用nasm编会报错,因为mov [0x00],'a'只指定了目的地址,但是没有说明大小

我是把'a'搬到0x00这个位置上一个字节?还是0x00~0x01这个字还是0x00~0x03这个双字?没有说清.

假:'a'不是一个字节吗?自然搬过去还是一个字节喽!

这里'a'实际上就是一个立即数,就是'a'的ASCII码.而一个立即数是不能决定占用几个字节的

如果写mov [0x00],al这样就可以,把al这个字节寄存器的东西搬到内存0x00位置上,这时候就不用指定多大的内存了,因为al自己隐含就是一个字节寄存器了

并且这一点儿代码根本凑不够一个扇区,需要写一些废话填满一个扇区才有效

应该这样写:

1
2
3
4
5
6
7
8
9
10
11
; 4-2.asm
mov ax,0xb800
mov ds,ax

mov byte [0x00],'a'
mov byte [0x02],'s'
mov byte [0x04],'m'

jmp $
times 510-($-$$) db 0
db 0x55,0xaa

编译:

1
nasm main.asm -o main.bin

然后使用fixvhdw2把main.bin写到虚拟磁盘nobody.vhd中

image-20220825115728499

现在就可以开启虚拟机了

image-20220825115716225

asm三个字已经打印在最左上角

如果不够512字节

如果main.asm没写废话

1
2
3
4
5
6
mov ax,0xb800                 
mov ds,ax

mov byte [0x00],'a'
mov byte [0x02],'s'
mov byte [0x04],'m'

编译成main.bin之后是远没有512个字节的

image-20220825115945064

不够512个字节的主引导记录作废了,写到磁盘里然后尝试启动会说找不到靴子

至于怎么凑够的512字节,以及为啥可以在屏幕上输出asm,那是后话了