`

(第4章 2)突破512字节的限制

 
阅读更多

 

一、代码

     启动的过程中,引导扇区boot sector(boot.asm,07c00h开始,最多512bytes)负责把加载器Loader(loader.asm,长度不受限制)载入内存并且把控制权交给她。Loader再加载操作系统内核之前,还要作准备保护模式等一系列工作,就很可能超过512bytes了。

 

     loader.asm代码在这里只是虚晃一枪,其具体功能编写放在“第五章 内核雏形”,不再赘述。

 

     boot.asm中灰色部分为代码“主线”,基本思路为:

(1)LABEL_SEARCH_IN_ROOT_DIR_BEGIN~~~LABEL_FILENAME_FOUND:在FAT12文件系统的“根目录区”中找到"loader.bin"对应的条目。

   执行后[es:di]指向该条目内部的一个字节,而非条目的开始,根据P105“根目录分区的条目格式”可知,[es:di]指向条目中的位置如下图所示:

                                    [DIR_NAME] [DIR_ATTR] [保         留]  [DIR_WrtTime] [DIR_WrtDate] [DIR_FstClus] [DIR_FileSize]

长度(单位:byte):         8+3                 1                10                        2                          2                           2                      4                  

                                 LOADER_ _BIN      *               **********             **                         **                        **                     ****

                                                                    |

                                                                   di: 是字符'N'后面的那个字节

 

(2)LABEL_FILENAME_FOUND子程序:后面ReadSector中会用到int 13中断读磁盘,故在此准备3个寄存器内容——

ax <-- (全局)扇区号

es <--  BaseOfLoader (09000h)

bx <--  OffsetOfLoader (0100h)

   在ReadSector中,会将(全局)扇区号ax 转换成 “柱面号ch”,“磁头号(即盘面号)dh”,“起始扇区号cl”,从而定位到磁盘上的一个扇区。另外,在ReadSector中另行指定“cl为待读扇区数”。int 13h的2号功能(ah=2)会将磁盘上的这若干个扇区读到[es:bx]开始的内存中。

 

(3)LABEL_GOON_LOADING_FILE~~~jmp BaseOfLoader:OffsetOfLoader之前:注意到根据“根目录区条目”只能找到“loader.bin”在磁盘上的“第一个扇区”,因此本部分在FAT表中顺藤摸瓜地找到loader.bin在磁盘上的“后续所有扇区号(这里也是簇号)”,并通过call ReadSector载入内存。

 

(4)jmp BaseOfLoader:OffsetOfLoader这条指令:(前面已经将磁盘中若干个扇区上的loader.bin文件载入BaseOfLoader:OffsetOfLoader开始的连续内存中了,这里)跳转到loader.bin,将控制权交给loader.bin。在下一章中将分析loader完成的功能——加载OS内核+跳入保护模式。

 

loader.asm

org	0100h

	mov	ax, 0B800h
	mov	gs, ax
	mov	ah, 0Fh				; 0000: 黑底    1111: 白字
	mov	al, 'L'
	mov	[gs:((80 * 0 + 39) * 2)], ax	; 屏幕第 0 行, 第 39 列。

	jmp	$		; Start

   

 

boot.asm

 

;%define_BOOT_DEBUG_; 做 Boot Sector 时一定将此行注释掉!将此行打开后用 nasm Boot.asm -o Boot.com 做成一个.COM文件易于调试

 

%ifdef_BOOT_DEBUG_

org  0100h; 调试状态, 做成 .COM 文件, 可调试

%else

org  07c00h; Boot 状态, Bios 将把 Boot Sector 加载到 0:7C00 处并开始执行

%endif

 

;================================================================================================

%ifdef_BOOT_DEBUG_

BaseOfStackequ0100h; 调试状态下堆栈基地址(栈底, 从这个位置向低地址生长)

%else

BaseOfStackequ07c00h; Boot状态下堆栈基地址(栈底, 从这个位置向低地址生长)

%endif

 

BaseOfLoaderequ09000h; LOADER.BIN 被加载到的位置 ----  段地址

OffsetOfLoaderequ0100h; LOADER.BIN 被加载到的位置 ---- 偏移地址

 

RootDirSectorsequ14; 根目录占用空间

SectorNoOfRootDirectoryequ19; Root Directory 的第一个扇区号

SectorNoOfFAT1equ1; FAT1 的第一个扇区号 = BPB_RsvdSecCnt

DeltaSectorNoequ17; DeltaSectorNo = BPB_RsvdSecCnt + (BPB_NumFATs * FATSz) - 2

; 文件的开始Sector号 = DirEntry中的开始Sector号 + 根目录占用Sector数目 + DeltaSectorNo

;================================================================================================

 

jmp short LABEL_START; Start to boot.

nop; 这个 nop 不可少 ???1为何

 

; 下面是 FAT12 磁盘的头

BS_OEMNameDB 'ForrestY'; OEM String, 必须 8 个字节

BPB_BytsPerSecDW 512; 每扇区字节数

BPB_SecPerClusDB 1; 每簇多少扇区

BPB_RsvdSecCntDW 1; Boot 记录占用多少扇区

BPB_NumFATsDB 2; 共有多少 FAT 表

BPB_RootEntCntDW 224; 根目录文件数最大值(  14扇区 * 512字节/扇区 / 32字节/根目录区条目  )

BPB_TotSec16DW 2880; 逻辑扇区总数 (2880扇区 * 512字节/扇区 = 1.4M 字节 = 一个软盘的容量)

BPB_Media  DB 0xF0; 媒体描述符

BPB_FATSz16  DW 9; 每FAT扇区数

BPB_SecPerTrk  DW 18; 每磁道扇区数

BPB_NumHeads  DW 2; 磁头数(面数)

BPB_HiddSec  DD 0; 隐藏扇区数

BPB_TotSec32  DD 0; 如果 wTotalSectorCount 是 0 由这个值记录扇区数

BS_DrvNum  DB 0; 中断 13 的驱动器号

BS_Reserved1  DB 0; 未使用

BS_BootSig  DB 29h; 扩展引导标记 (29h)

BS_VolID  DD 0; 卷序列号

BS_VolLab  DB 'OrangeS0.02'; 卷标, 必须 11 个字节

BS_FileSysType  DB 'FAT12   '; 文件系统类型, 必须 8个字节  

 

LABEL_START:

mov  ax, cs

mov  ds, ax

mov  es, ax

mov  ss, ax

mov  sp, BaseOfStack

 

; 清屏

mov  ax, 0600h

mov  bx, 0700h

mov  cx, 0

mov  dx, 0184fh

int  10h

 

; 上面清屏用到了BIOS中断  int 10h

; int 10h是BIOS对屏幕及显示器提供的服务程序,
; 功能号AH=6:屏幕初始化或上卷,
; 参数AL=0:屏幕为空白,
; 背景和前景颜色BH = Background Color and Foreground color.
; 矩形区域:左上角(行ch,列cl)=(0,0), 右下角(行dh,列dl)=(0x18,0x4f)=(24, 79)

 

mov  dh, 0          ; "Booting  "

call  DispStr        ; 显示字符串

 

        ;  int 13h is a shorthand for BIOS interrupt call 13h, the 20th interrupt vector in an x86-based computer system. The BIOS typically sets up a real mode interrupt handler at this vector that provides sector-based hard disk and floppy disk read and write services using cylinder-head-sector(CHS) addressing.

        ; Drive Table:

        ;                           DL=00h,  1st floppy disk ("drive A:")

        ;                           DL=01h,  2st floppy disk ("drive B:")

        ;                           DL=80h,  1st hard disk 

        ;                           DL=80h,  2st hard disk

        ; Function Table:

        ;                           AH=00h, Reset Disk Drives

        ;                           AH=01h, Get Status of Last Drive Operation

        ;                           AH=02h, Read Sectors From Drive

        ;                           AH=03h, Write Sectors To Drive

        ; Parameters ...

        ; An interrupt handler, also known as an interrupt service routine (ISR), is a callback subroutine in microcontroller firmware, operating system or device driver whose execution is triggered by the reception of an interrupt.

xor  ah, ah; ┓

xor  dl, dl; ┣ 软驱复位

int  13h; ┛

 

; 下面在 A 盘的根目录寻找 LOADER.BIN

mov  word [wSectorNo], SectorNoOfRootDirectory;根目录分区的第一个扇区号SectorNoOfRootDirectory=19

LABEL_SEARCH_IN_ROOT_DIR_BEGIN:

cmp  word [wRootDirSizeForLoop], 0        ; ┓;根目录分区占用的扇区数wRootDirSizeForLoop

jz  LABEL_NO_LOADERBIN                      ; ┣ 判断根目录区是不是已经读完

dec  word [wRootDirSizeForLoop]             ; ┛ 如果读完表示没有找到 LOADER.BIN

 

 

        ; 从第 ax 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中

        ; call ReadSector后,[BaseOfLoader:OffsetOfLoader] (即[es:bx]),开始存放根目录分区的一个扇区的数据

mov  ax, BaseOfLoader

mov  es, ax                        ; es <- BaseOfLoader

mov  bx, OffsetOfLoader   ; bx <- OffsetOfLoader于是, es:bx = BaseOfLoader:OffsetOfLoader

 

mov  ax, [wSectorNo]         ; ax <- Root Directory 中的某 Sector 号

mov  cl, 1

call   ReadSector

 

; 比较[ds:si] (即"LOADER BIN")和 [es:di](即根目录区中每个条目中 文件的名称)

mov  si, LoaderFileName; ds:si -> "LOADER  BIN"

mov  di, OffsetOfLoader; es:di -> BaseOfLoader:0100 = BaseOfLoader*10h+100

 

cld

mov  dx, 10h    ; 一个扇区大小/根目录区一个条目大小=512byte/32byte=10h 个 ==> 一个扇区有多少条目

 

LABEL_SEARCH_FOR_LOADERBIN:

cmp  dx, 0                                                                    ; ┓循环次数控制,

jz  LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR    ; ┣如果已经读完了一个 Sector,

dec  dx                                                                         ; ┛就跳到下一个 Sector

 

; 下面(粗体斜体部分)实际上是在检查“一个扇区”中的“一个根目录区条目”中是否有loader.bin这个名称出现

; ∴在这里有两个循环,外层循环挨个读取根目录区的每个扇区,内层循环在指定扇区中挨个读取每个条目。

mov  cx, 11

LABEL_CMP_FILENAME:

cmp  cx, 0

jz  LABEL_FILENAME_FOUND; 如果比较了 11 个字符都相等, 表示找到

dec  cx

lodsb                       ; ds:si -> al

cmp  al, byte [es:di]

jz  LABEL_GO_ON

jmp  LABEL_DIFFERENT; 只要发现不一样的字符就表明本 DirectoryEntry 不是

; 我们要找的 LOADER.BIN

LABEL_GO_ON:

inc  di

jmp  LABEL_CMP_FILENAME;继续循环

 

LABEL_DIFFERENT:             ; 一个根目录区中的条目长20h (bytes),详见P105

and  di, 0FFE0h                                                                   ; else ┓di &= E0 为了让它指向本条目开头

add  di, 20h                                                                          ;        ┃

mov  si, LoaderFileName                                                      ;        ┣ di += 20h  下一个目录条目

jmp  LABEL_SEARCH_FOR_LOADERBIN                            ;        ┛

 

LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:

addword [wSectorNo], 1

jmpLABEL_SEARCH_IN_ROOT_DIR_BEGIN

 

LABEL_NO_LOADERBIN:

mov  dh, 2                                       ; "No LOADER."

call  DispStr                                     ; 显示字符串

 

; 由于上面有这样一句:“jz  LABEL_FILENAME_FOUND”,所以程序不会执行如下的预编译,而直接跳到LABEL_FILENAME_FOUND去 !

%ifdef  _BOOT_DEBUG_

mov  ax, 4c00h                                      ; ┓

int     21h                                               ; ┛没有找到 LOADER.BIN, 回到 DOS

%else

jmp  $                                                     ; 没有找到 LOADER.BIN, 死循环在这里

%endif

 

在找到文件的这一刻[es : di] 指向根目录区中相应条目的DIR_NAME中'N'字母后的那个字符,注意到一个“根目录区的条目”的结构如下:(总共长度为0x20h 即32个字节)

;  名称                             偏移

;  DIR_NAME                    0x0

;  DIR_ATTR                    0xB

;  保留位                           0xC

;  DIR_WrtTime                0x16

;  DIR_WrtDate                0x18

;  DIR_FstClus                  0x1A

;  DIR_FileSize                  0x1C

LABEL_FILENAME_FOUND:                                 ; 找到 LOADER.BIN 后便来到这里继续

mov  ax, RootDirSectors

 

and  di, 0FFE0h                                                    ; di -> 当前条目的开始

add  di, 01Ah                                                         ; di -> 首 Sector

; 此时 [es:di] 指向根目录区条目中LOADER.BIN对应的那个条目的开头(一个条目32字节长度)

 

mov  cx, word [es:di]

push  cx                                                                 ; 保存此 Sector 在 FAT 中的序号

add  cx, ax

add  cx, DeltaSectorNo                                          ; cl <- LOADER.BIN的起始扇区号(0-based)

; 此时的cx = word [es:di] + RootDirSectors + DeltaSectorNo

; word [es:di] ==> LOADER.BIN这个文件在FAT12格式数据区中对应的簇号/扇区号

; RootDirSectors ==> 14, 即根目录区占据的扇区数

; DeltaSectorNo  ==>  19-2, 其中19是根目录区之前的扇区数

 

mov  ax, BaseOfLoader

mov  es, ax                                                             ; es <- BaseOfLoader

mov  bx, OffsetOfLoader                                        ; bx <- OffsetOfLoader

mov  ax, cx                                                             ; ax <- Sector 号

 

LABEL_GOON_LOADING_FILE:

push  ax                                       ; `.

push  bx                                       ;  |

mov  ah, 0Eh                                       ;  | 每读一个扇区就在 "Booting  " 后面

mov  al, '.'                                            ;  | 打一个点, 形成这样的效果:

mov  bl, 0Fh                                        ;  | Booting ......

int  10h;  |

pop  bx                                       ;  |

pop  ax                                       ; /

 

mov  cl, 1

call  ReadSector     ; 从第 ax(相对整个磁盘起始的扇区号) 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中

 

;  此时,ax为当前在FAT中的扇区号/簇号

pop  ax                    ; 取出此 Sector 在 FAT 中的序号

call  GetFATEntry

cmp  ax, 0FFFh

;  此时,ax为下一个要读扇区在FAT中的扇区号/簇号

 

; 下面需要将“FAT中的扇区号/簇号“ax 转换为“在整个磁盘中的扇区号”ax

jz  LABEL_FILE_LOADED

push  ax; 保存 Sector 在 FAT 中的序号

mov  dx, RootDirSectors

add  ax, dx

add  ax, DeltaSectorNo

add  bx, [BPB_BytsPerSec]

jmp  LABEL_GOON_LOADING_FILE

LABEL_FILE_LOADED:

 

mov  dh, 1; "Ready."

call  DispStr; 显示字符串

 

; *****************************************************************************************************

; 这一句正式跳转到已加载到内存中的 LOADER.BIN 的开始处,

; 开始执行 LOADER.BIN 的代码。

; Boot Sector 的使命到此结束

jmpBaseOfLoader:OffsetOfLoader

; *****************************************************************************************************

 

 

 

;============================================================================

;变量

;----------------------------------------------------------------------------

wRootDirSizeForLoopdwRootDirSectors; Root Directory 占用的扇区数, 在循环中会递减至零.

wSectorNodw0; 要读取的扇区号

bOdddb0; 奇数还是偶数

 

;============================================================================

;字符串

;----------------------------------------------------------------------------

LoaderFileNamedb"LOADER  BIN", 0; LOADER.BIN 之文件名

; 为简化代码, 下面每个字符串的长度均为 MessageLength

MessageLengthequ9

BootMessage:db"Booting  "; 9字节, 不够则用空格补齐. 序号 0

Message1db"Ready.   "; 9字节, 不够则用空格补齐. 序号 1

Message2db"No LOADER"; 9字节, 不够则用空格补齐. 序号 2

;============================================================================

 

 

;----------------------------------------------------------------------------

; 函数名: DispStr

;----------------------------------------------------------------------------

; 作用:

;显示一个字符串, 函数开始时 dh 中应该是字符串序号(0-based)

DispStr:

movax, MessageLength

muldh

addax, BootMessage

movbp, ax; ┓

movax, ds; ┣ ES:BP = 串地址

moves, ax; ┛

movcx, MessageLength; CX = 串长度

movax, 01301h; AH = 13,  AL = 01h

movbx, 0007h; 页号为0(BH = 0) 黑底白字(BL = 07h)

movdl, 0

int10h; int 10h

ret

 

 

;----------------------------------------------------------------------------

; 函数名: ReadSector

;----------------------------------------------------------------------------

; 作用:

;从第 ax 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中

ReadSector:

; -----------------------------------------------------------------------

; 怎样由扇区号求扇区在磁盘中的位置 (扇区号 -> 柱面号, 起始扇区, 磁头号)

; -----------------------------------------------------------------------

; 设扇区号为 x

;                           ┌ 柱面号 = y >> 1

;       x           ┌ 商 y ┤

; -------------- => ┤      └ 磁头号 = y & 1

;  每磁道扇区数     │

;                   └ 余 z => 起始扇区号 = z + 1

pushbp

movbp, sp

subesp, 2; 辟出两个字节的堆栈区域保存要读的扇区数: byte [bp-2]

 

movbyte [bp-2], cl

pushbx; 保存 bx

movbl, [BPB_SecPerTrk]; bl: 除数

divbl; y 在 al 中, z 在 ah 中

incah; z ++

movcl, ah; cl <- 起始扇区号

movdh, al; dh <- y

shral, 1; y >> 1 (其实是 y/BPB_NumHeads, 这里BPB_NumHeads=2)

movch, al; ch <- 柱面号

anddh, 1; dh & 1 = 磁头号

popbx; 恢复 bx

; 至此, "柱面号, 起始扇区, 磁头号" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^

movdl, [BS_DrvNum]; 驱动器号 (0 表示 A 盘)

.GoOnReading:

movah, 2; 读

moval, byte [bp-2]; 读 al 个扇区

int13h

jc.GoOnReading; 如果读取错误 CF 会被置为 1, 这时就不停地读, 直到正确为止

 

addesp, 2

popbp

 

ret

 

;----------------------------------------------------------------------------

; 函数名: GetFATEntry

;----------------------------------------------------------------------------

; 作用:

;找到序号为 ax 的 Sector 在 FAT 中的条目, 结果放在 ax 中

;需要注意的是, 中间需要读 FAT 的扇区到 es:bx 处, 所以函数一开始保存了 es 和 bx

GetFATEntry:

pushes

pushbx

pushax

movax, BaseOfLoader; `.

subax, 0100h;  | 在 BaseOfLoader 后面留出 4K 空间用于存放 FAT

moves, ax; /

popax

movbyte [bOdd], 0

movbx, 3

mulbx; dx:ax = ax * 3

movbx, 2

divbx; dx:ax / 2  ==>  ax <- 商, dx <- 余数

cmpdx, 0

jzLABEL_EVEN

movbyte [bOdd], 1

LABEL_EVEN:;偶数

; 现在 ax 中是 FATEntry 在 FAT 中的偏移量,下面来

; 计算 FATEntry 在哪个扇区中(FAT占用不止一个扇区)

xordx, dx

movbx, [BPB_BytsPerSec]

divbx ; dx:ax / BPB_BytsPerSec

  ;  ax <- 商 (FATEntry 所在的扇区相对于 FAT 的扇区号)

  ;  dx <- 余数 (FATEntry 在扇区内的偏移)

pushdx

movbx, 0 ; bx <- 0 于是, es:bx = (BaseOfLoader - 100):00

addax, SectorNoOfFAT1 ; 此句之后的 ax 就是 FATEntry 所在的扇区号

movcl, 2

callReadSector ; 读取 FATEntry 所在的扇区, 一次读两个, 避免在边界

  ; 发生错误, 因为一个 FATEntry 可能跨越两个扇区

popdx

addbx, dx

movax, [es:bx]

cmpbyte [bOdd], 1

jnzLABEL_EVEN_2

shrax, 4

LABEL_EVEN_2:

andax, 0FFFh

 

LABEL_GET_FAT_ENRY_OK:

 

popbx

popes

ret

;----------------------------------------------------------------------------

 

times 510-($-$$)db0; 填充剩下的空间,使生成的二进制代码恰好为512字节

dw 0xaa55; 结束标志

 

 

 

 

二、运行方法

方法一:Linux上装bochs虚拟机,然后在bochs虚拟机中运行(由于有时候bochs很难在Linux上安装成功,因此推荐用方法二)

1. 编译boot.asm和loader.asm

[hadoop@sam1 c]$ pwd

/home/hadoop/Desktop/OSImpl/一个操作系统的实现/chapter4/c

[hadoop@sam1 c]$ ls

a.img  bochsrc  boot.asm  loader.asm  Makefile

[hadoop@sam1 c]$ nasm boot.asm -o boot.bin

[hadoop@sam1 c]$ nasm loader.asm -o loader.bin

 

2. 创建a.img软盘镜像,并将boot.asm写入软盘第一个扇区作为“引导扇区”:

[hadoop@sam1 bochs-2.6]$ bximage

...

Do you want to create a floppy disk image or a hard disk image?

Please type hd or fd. [hd] fd

...

Please type 0.16, 0.18, 0.32, 0.36, 0.72, 1.2, 1.44, 1.68, 1.72, or 2.88.

 [1.44]

...

What should I name the image?

[a.img] 

...

[hadoop@sam1 bochs-2.6]$ dd if=/home/hadoop/Desktop/OSImpl/一个操作系统的实现/chapter4/c/boot.bin of=/home/hadoop/Desktop/OSImpl/bochs-2.6/a.img bs=512 count=1 conv=notrunc

 

 

注:必须要设置从软盘a.img启动,因此修改$bochs_home/.bochsrc为如下:

megs:32

romimage:file=/usr/share/bochs/BIOS-bochs-latest

vgaromimage:file=/usr/share/vgabios/VGABIOS-lgpl-latest.bin

 

#floppya: 1_44=freedos.img, status=inserted

#floppyb: 1_44=pm.img,status=inserted

floppya: 1_44=a.img, status=inserted

 

boot: a

 

#disable the mouse

 

#enable key mapping, using US layout as default.

keyboard_mapping: enabled=1, map=gui/keymaps/x11-pc-us.map

 

mouse: enabled=0

 

log:bochsout.txt

 

3. 把loader.bin作为一个普通的文件写入软盘a.img(当然也可以是其他盘)

[hadoop@sam1 bochs-2.6]$ sudo mount -o loop /home/hadoop/Desktop/OSImpl/bochs-2.6/a.img /mnt/floppy/

[sudo] password for hadoop: 

[hadoop@sam1 bochs-2.6]$ sudo cp /home/hadoop/Desktop/OSImpl/一个操作系统的实现/chapter4/c/loader.bin /mnt/floppy -v

`/home/hadoop/Desktop/OSImpl/一个操作系统的实现/chapter4/c/loader.bin' -> `/mnt/floppy/loader.bin'

[hadoop@sam1 bochs-2.6]$ sudo umount /mnt/floppy/

 

注:mount -o loop —— 

        -o: option

        loop: loop device. loop device is a pseudo('fake') device (actually just a file) that acts as a block-based device.

        (1)loop device 区别于loopback device. Sometimes, the loop device if erroneously referred to as 'loopback' device, but this term is reserved for a networking device in the Linux kernel (cf. loopback). The concept of the 'loop' device is distinct from 'loopback', although similar in name.

        (2)为什么命名为loop呢:在使用之前,一个loop设备必须要和一个文件进行连接,这种结合方式给用户提供了一个代替块特殊文件的接口。如果一个文件包含一个完整的文件系统,那么这个文件就可以像一个磁盘设备一样被mount起来。

             对于第一层文件系统,它直接安装(环绕)在我们的计算机物理设备上;而对于这种被mount起来的镜像文件(它也包含有文件系统),则建立在第一层文件系统上,就好像是在第一层文件系统上再环绕一层文件系统似的,所以称为loop.

 

 

4. 开始模拟

[hadoop@sam1 bochs-2.6]$ ./bochs 

 

结果截图:

 

 

方法二:直接在VMware添加一块硬盘,将boot.bin和loader.bin写到这块盘中,然后从这块盘启动

1. 在VMWare中添加一块硬盘后,给他分区、格式化为FAT12

    ***添加过程如图(注意:新添加的硬盘大小最大为32MB(FAT12格式限制)





 
我在添加新硬盘时,虚拟机是启动着的,需要
#reboot

#fdisk -l                             看到新硬盘没有分区的提示:Disk /dev/sdb doesn't contain a valid partition table
#mkfs.vfat -I -F 12 /dev/sdb      不分区(-I)直接把整块硬盘格式化为FAT12格式

2. 将boot.bin和loader.bin写到这块盘中
#cd /home/hadoop/osimpl/OSImplCode/chapter4/c/
#dd if=boot.bin of=/dev/sdb bs=512 count=1        

#cp loader.bin /dev/sdb

3. 然后从从新添加的硬盘/dev/sdb启动
#reboot

//重启时马上按F2,进入BIOS设置界面

 

效果图:

 

 

 

 

  • 大小: 13.4 KB
  • 大小: 39 KB
  • 大小: 38.6 KB
  • 大小: 37.9 KB
  • 大小: 40.4 KB
  • 大小: 34.5 KB
  • 大小: 25.1 KB
  • 大小: 17.6 KB
分享到:
评论

相关推荐

    自己动手写操作系统

    4.1 突破512字节的限制125 4.1.1 FAT12126 4.1.2 DOS可以识别的引导盘131 4.1.3 一个最简单的Loader132 4.1.4 加载Loader入内存133 4.1.5 向Loader交出控制权142 4.1.6 整理boot.asm142 4.2 保护模式下的...

    自己动手写操作系统 电子工业出版社 pdf

    4.1 突破512字节的限制125 4.1.1 FAT12126 4.1.2 DOS可以识别的引导盘131 4.1.3 一个最简单的Loader132 4.1.4 加载Loader入内存133 4.1.5 向Loader交出控制权142 4.1.6 整理boot.asm142 4.2 保护模式下的“操作系统...

    自己动手写操作系统 pdf

    4.1 突破512字节的限制125 4.1.1 FAT12126 4.1.2 DOS可以识别的引导盘131 4.1.3 一个最简单的Loader132 4.1.4 加载Loader入内存133 4.1.5 向Loader交出控制权142 4.1.6 整理boot.asm142 4.2 保护模式下的“操作系统...

    自己动手写操作系统(含源代码).part2

    经过四年的磨练成长,于渊又拿出第二版的书稿《Orange'S:一个操作系统的实现》,这本书是属于真正 Hacker的。我虽然已经有多年不写代码了,但看这本书的时候,让我又重新感受到做程序员的乐趣:用代码建设属于自己...

    自己动手写操作系统(含源代码).part1

    经过四年的磨练成长,于渊又拿出第二版的书稿《Orange'S:一个操作系统的实现》,这本书是属于真正 Hacker的。我虽然已经有多年不写代码了,但看这本书的时候,让我又重新感受到做程序员的乐趣:用代码建设属于自己...

    evm:超轻量级物联网虚拟机

    EVM全称Embedded Virtural Machine ,本质上是一种通用,精简的嵌入式虚拟机,由语法解析框架和字节码运行组成,可运行在资源受限制的单片机上。 2. EVM技术架构 3. EVM优势 纯C开发,零依赖,跨平台,内置REPL; ...

    大数据处理的基本流程:数据抽取与集成+数据分析+数据解释.pdf

    图 1 ⼤数据时代的 10 个重⼤变化 对研究范式的新认识:从第三范式到第四范式 对研究范式的新认识:从第三范式到第四范式 2007 年 1 ⽉,图灵奖得主、关系型数据库⿐祖 JimGray 发表演讲,他凭着⾃⼰对于⼈类科学...

    AES加密与解密软件_最新版(2.2.2与2.2.3版 速度与性能上有较大提高).rar

    4、本软件突破了原2.1版本软件只能加密与解密文件大小为小于等于4GB(吉字节)的限制。 5、使用了内存映射文件技术与多线程技术相结合的方式进行文件的读写,对加密与解密在速度上都有一定的提高。(注:2.2.2 版的...

    RouterOS2.9.6.with.crack及配置动画

     系统提供基于HTB (Hierarchical Token Bucket)算法的流量管理功能,可有效提高带宽利用率和限制P2P等海量下载软件的使用:对于正常上网的内网主机,系统将允许它偶然突破最大限速;相反,对于长期使用P2P等软件的...

    易语言程序免安装版下载

    4) 修改静态编译后“读配置项”命令在第三个参数“配置项名称”为空文本时导致程序崩溃的BUG 5) 修改高级选择夹中的组件在窗口载入后强制得到焦点的BUG 6) 修改MYSQL支持库跨静态编译的EXE和DLL传递连接句柄和...

    cmd操作命令和linux命令大全收集

    4. explorer-------打开资源管理器 5. logoff---------注销命令 6. shutdown-------60秒倒计时关机命令 7. lusrmgr.msc----本机用户和组 8. services.msc---本地服务设置 9. oobe/msoobe /a----检查XP是否激活 ...

Global site tag (gtag.js) - Google Analytics