Oracle VM VirtualBoxでMINIX 1.1のブートストラップを見る

書籍の記載を確認するために、VirtualBoxのデバッグ機能を使って、MINIX 1.1のブートストラップ(bootblok.s)を見てみました。
・MINIXオペレーティングシステム (ISBN4-7561-0000-7)
 ⇒「APPENDIX D MINIX再構築ガイド」/「D.1 はじめに」
・MINIXリファレンスマニュアル (ISBN4-535-60004-X-C3055)
 ⇒「Chapter 3 MINIX インプリメンターガイド」/「3.1 イントロダクション」
 ⇒「Chapter 3 MINIX インプリメンターガイド」/「3.5 ブートディスケットの構築」/「3.5.1 導入」

1.準備①VirtualBoxの設定

理由はわからないが、VirtualBoxのブレークポイントを利用するために、[設定]-[システム]-[アクセラレーション]-[仮想化支援機能]のチェックボックス[VT-x/AMD-Vを有効化]のチェックを外しておく。

2.準備②MINIX起動ディスクのファイル名を変更

拡張子が無いとVirtualBoxでイメージの選択ができないため、拡張子を付与する。

オリジナルファイル名変更後ファイル名内容(“README_1.1″より)
floppy_disk1floppy_disk1.imgBoot Disk
floppy_disk2floppy_disk2.imgRoot File System
floppy_disk3floppy_disk3.img/usr
floppy_disk4floppy_disk4.img/user
floppy_disk5floppy_disk5.imgKernel, H and Include Sources
floppy_disk6floppy_disk6.imgFS and Lib Sources
floppy_disk7floppy_disk7.imgMM and Tools Sources
floppy_disk8floppy_disk8.imgCommands Sources

3.VirtualBoxでイメージを選択しデバッグ起動

VirtualBoxのフロッピーデバイス0に「floppy_disk1.img」を選択し、下記コマンドを用いて起動する。
“C:\Program Files\Oracle\VirtualBox\VBoxManage.exe” startvm “Minix_v1.1” -E VBOX_GUI_DBG_AUTO_SHOW=true -E VBOX_GUI_DBG_ENABLED=true
※”Minix_v1.1″は仮想マシン名。
※起動すると一時停止状態になる。


(他の起動方法)
“C:\Program Files\Oracle\VirtualBox\VirtualBoxVM.exe” –startvm “Minix_v1.1” –dbg
※一時停止状態ではなく、動作する。

4.使用するデバッグコマンドを確認

ウィンドウ「VBox Dbg – Console」のテキストボックス「Command」へ、「help commands」と入力し[Enter]キーを押下。

※一部抜粋。

br          <address> [passes [max passes]] [cmds]
               Sets a recompiler specific breakpoint.
db          [addr]
               Dump memory in bytes.
g              Continue execution.
p           [count] [cmds]
               Step over.
r           [reg [[=] newval]]
               Show or set register(s) - active reg set.
t           [count] [cmds]
               Trace .
u           [addr]
               Unassemble.
stop           Stop execution.

※ウィンドウ「VBox Dbg – Console」が表示されていない場合、仮想マシンのウィンドウのメニュー[デバッグ]-[コマンドライン]で、表示できる。

※参考 – 「help commands」の結果。

Welcome to the VirtualBox Debugger!
Current VM is 09a80000, CPU #0
VBoxDbg> help commands
Commands for CodeView/WinDbg emulation:
ba          <access> <size> <address> [passes [max passes]] [cmds]
                                           Sets a data access breakpoint.
bc          all | <bp#> [bp# []]           Deletes a set of breakpoints.
bd          all | <bp#> [bp# []]           Disables a set of breakpoints.
be          all | <bp#> [bp# []]           Enables a set of breakpoints.
bl                                         Lists all the breakpoints.
bp          <address> [passes [max passes]] [cmds]
                                           Sets a breakpoint (int 3).
br          <address> [passes [max passes]] [cmds]
                                           Sets a recompiler specific breakpoint.
d           [addr]                         Dump memory using last element size and type.
dF          [addr]                         Dump memory as far 16:16.
dFs         [addr]                         Dump memory as far 16:16 with near symbols.
da          [addr]                         Dump memory as ascii string.
db          [addr]                         Dump memory in bytes.
dd          [addr]                         Dump memory in double words.
dds         [addr]                         Dump memory as double words with near symbols.
da          [addr]                         Dump memory as ascii string.
dg          [sel [..]]                     Dump the global descriptor table (GDT).
dga         [sel [..]]                     Dump the global descriptor table (GDT) including
                                           not-present entries.
di          [int [..]]                     Dump the interrupt descriptor table (IDT).
dia         [int [..]]                     Dump the interrupt descriptor table (IDT) including
                                           not-present entries.
dl          [sel [..]]                     Dump the local descriptor table (LDT).
dla         [sel [..]]                     Dump the local descriptor table (LDT) including
                                           not-present entries.
dpd         [addr|index]                   Dumps page directory entries of the default context.
dpda        [addr]                         Dumps memory at given address as a page directory.
dpdb        [addr|index]                   Dumps page directory entries of the guest and the
                                           hypervisor. 
dpdg        [addr|index]                   Dumps page directory entries of the guest.
dpdh        [addr|index]                   Dumps page directory entries of the hypervisor. 
dph         [addr [cr3 [mode]]             Dumps the paging hierarchy at for specfied address range.
                                           Default context.
dphg        [addr [cr3 [mode]]             Dumps the paging hierarchy at for specfied address range.
                                           Guest context.
dphh        [addr [cr3 [mode]]             Dumps the paging hierarchy at for specfied address range.
                                           Hypervisor context.
dp          [addr]                         Dump memory in mode sized words.
dps         [addr]                         Dump memory in mode sized words with near symbols.
dpt         <addr>                         Dumps page table entries of the default context.
dpta        <addr>                         Dumps memory at given address as a page table.
dptb        <addr>                         Dumps page table entries of the guest and the hypervisor.
dptg        <addr>                         Dumps page table entries of the guest.
dpth        <addr>                         Dumps page table entries of the hypervisor.
dq          [addr]                         Dump memory in quad words.
dqs         [addr]                         Dump memory as quad words with near symbols.
dt          [tss|tss:ign|addr]             Dump the task state segment (TSS).
dt16        [tss|tss:ign|addr]             Dump the 16-bit task state segment (TSS).
dt32        [tss|tss:ign|addr]             Dump the 32-bit task state segment (TSS).
dt64        [tss|tss:ign|addr]             Dump the 64-bit task state segment (TSS).
dti         <type> [levels]                Dump type information.
dtv         <type> <addr> [levels]         Dump a memory buffer using the information in the given
                                           type.
du          [addr]                         Dump memory as unicode string (little endian).
dw          [addr]                         Dump memory in words.
eb          <addr> <value>                 Write a 1-byte value to memory.
ew          <addr> <value>                 Write a 2-byte value to memory.
ed          <addr> <value>                 Write a 4-byte value to memory.
eq          <addr> <value>                 Write a 8-byte value to memory.
g                                          Continue execution.
gu                                         Go up - continue execution till after return.
k                                          Callstack.
kv                                         Verbose callstack.
kg                                         Callstack - guest.
kgv                                        Verbose callstack - guest.
kh                                         Callstack - hypervisor.
lm          [module [..]]                  List modules.
lmv         [module [..]]                  List modules, verbose.
lmo         [module [..]]                  List modules and their segments.
lmov        [module [..]]                  List modules and their segments, verbose.
ln          [addr/sym [..]]                List symbols near to the address. Default address is
                                           CS:EIP.
ls          [addr]                         Source.
m           <addr>                         Display information about that piece of memory.
p           [count] [cmds]                 Step over.
pr                                         Toggle displaying registers for tracing & stepping (no
                                           code executed).
pa          <addr> [count] [cmds]          Step to the given address.
pc          [count] [cmds]                 Step to the next call instruction.
pt          [count] [cmds]                 Step to the next return instruction.
r           [reg [[=] newval]]             Show or set register(s) - active reg set.
rg          [reg [[=] newval]]             Show or set register(s) - guest reg set.
rg32                                       Show 32-bit guest registers.
rg64                                       Show 64-bit guest registers.
rh          [reg [[=] newval]]             Show or set register(s) - hypervisor reg set.
rt                                         Toggles terse / verbose register info.
s           [options] <range> <pattern>    Continue last search.
sa          <range> <pattern>              Search memory for an ascii string.
sb          <range> <pattern>              Search memory for one or more bytes.
sd          <range> <pattern>              Search memory for one or more double words.
sq          <range> <pattern>              Search memory for one or more quad words.
su          <range> <pattern>              Search memory for an unicode string.
sw          <range> <pattern>              Search memory for one or more words.
sx          [<event> [..]]                 Lists settings for exceptions, exits and other events.
                                           All if no filter is specified.
sx-         -c <cmd> <event> [..]          Modifies the command for one or more exceptions, exits or
                                           other event.  'all' addresses all.
sxe         [-c <cmd>] <event> [..]        Enable: Break into the debugger on the specified
                                           exceptions, exits and other events.  'all' addresses all.
sxn         [-c <cmd>] <event> [..]        Notify: Display info in the debugger and continue on the
                                           specified exceptions, exits and other events. 'all'
                                           addresses all.
sxi         [-c <cmd>] <event> [..]        Ignore: Ignore the specified exceptions, exits and other
                                           events ('all' = all of them).  Without the -c option, the
                                           guest runs like normal.
sxr                                        Reset the settings to default for exceptions, exits and
                                           other events. All if no filter is specified.
t           [count] [cmds]                 Trace .
tr                                         Toggle displaying registers for tracing & stepping (no
                                           code executed).
ta          <addr> [count] [cmds]          Trace to the given address.
tc          [count] [cmds]                 Trace to the next call instruction.
tt          [count] [cmds]                 Trace to the next return instruction.
u           [addr]                         Unassemble.
u64         [addr]                         Unassemble 64-bit code.
u32         [addr]                         Unassemble 32-bit code.
u16         [addr]                         Unassemble 16-bit code.
uv86        [addr]                         Unassemble 16-bit code with v8086/real mode addressing.
ucfg        [addr]                         Unassemble creating a control flow graph.
ucfgc       [addr]                         Unassemble creating a control flow graph with colors.

Common Commands:
bye                                        Exits the debugger.
cpu         [idCpu]                        If no argument, display the current CPU, else change to
                                           the specified CPU.
echo        <str1> [str2..[strN]]          Displays the strings separated by one blank space and the
                                           last one followed by a newline.
exit                                       Exits the debugger.
format                                     Evaluates an expression and formats it.
detect                                     Detects or re-detects the guest os and starts the OS
                                           specific digger.
dmesg       [N last messages]              Displays the guest os kernel messages, if available.
dumpimage   <addr1> [addr2..[addrN]]       Dumps executable images.
harakiri                                   Kills debugger process.
help        [cmd/op [..]]                  Display help. For help about info items try 'info help'.
info        <info> [args]                  Display info register in the DBGF. For a list of info
                                           items try 'info help'.
loadimage   <filename> <address> [name]    Loads the symbols of an executable image at the specified
                                           address. 
loadimage32 <filename> <address> [name]    loadimage variant for selecting 32-bit images (mach-o).
loadimage64 <filename> <address> [name]    loadimage variant for selecting 64-bit images (mach-o).
loadinmem   <address> [name]               Tries to load a image mapped at the given address.
loadmap     <filename> <address> [name] [subtrahend] [seg]
                                           Loads the symbols from a map file, usually at a specified
                                           address. 
loadplugin  <plugin1> [plugin2..N]         Loads one or more plugins
loadseg     <filename> <address> <seg> [name]
                                           Loads the symbols of a segment in the executable image at
                                           the specified address. 
loadvars    <filename>                     Load variables from file. One per line, same as the args
                                           to the set command.
log         [group string]                 Displays or modifies the logging group settings
                                           (VBOX_LOG)
logdest     [dest string]                  Displays or modifies the logging destination
                                           (VBOX_LOG_DEST).
logflags    [flags string]                 Displays or modifies the logging flags (VBOX_LOG_FLAGS).
logflush                                   Flushes the log buffers.
quit                                       Exits the debugger.
runscript   <filename>                     Runs the command listed in the script. Lines starting
                                           with '#' (after removing blanks) are comment. blank lines
                                           are ignored. Stops on failure.
set         <var> <value>                  Sets a global variable.
showvars                                   List all the defined variables.
stop                                       Stop execution.
unload      <modname1> [modname2..N]       Unloads one or more modules in the current address space.
unloadplugin <plugin1> [plugin2..N]        Unloads one or more plugins.
unset       <var1> [var1..[varN]]          Unsets (delete) one or more global variables.
writecore   <filename>                     Write core to file.

External Commands:
injecterror                                Inject error into I/O subsystem.
alliem      [boolean]                      Enables or disabled executing ALL code in IEM, if no
                                           arguments are given it displays the current status.
patmon                                     Enable patching.
patmoff                                    Disable patching.
csamon                                     Enable CSAM code scanning.
csamoff                                    Disable CSAM code scanning.
remstep     [on/off]                       Enable or disable the single stepping with logged
                                           disassembly. If no arguments show the current state.
pgmsync                                    Sync the CR3 page.
pgmerror                                   Enables inject runtime of errors into parts of PGM.
pgmerroroff                                Disables inject runtime errors into parts of PGM.
pgmsyncalways                              Toggle permanent CR3 syncing.
pgmphystofile                              Save the physical memory to file.
pgmpoolcheck                               Check the pgm pool pages.
stats       [pattern]                      Display statistics.
statsreset  [pattern]                      Resets statistics.
VBoxDbg> 

5.ブレークポイントへブートプログラムの開始番地(0x7c00)を追加

ウィンドウ「VBox Dbg – Console」のテキストボックス「Command」へ、「br 0x7c00」と入力し[Enter]キーを押下。

6.仮想マシンを再開

再開し暫くすると、設定したブレークポイントで、中断し、ウィンドウ「VBox Dbg – Console」へ、アドレス「0000:00007c00」で、中断した旨が、表示される。

Welcome to the VirtualBox Debugger!
Current VM is 099d0000, CPU #0
VBoxDbg> br 0x7c00
Set REM breakpoint 28 at 0000000000007c00
VBoxDbg> 
dbgf event: Breakpoint 28! (rem)
eax=0000aa55 ebx=00000000 ecx=00000001 edx=00000000 esi=00000000 edi=0000fff0
eip=00007c00 esp=00007800 ebp=00000000 iopl=0 nv up ei pl zr na po nc
cs=0000 ds=0000 es=0000 fs=0000 gs=0000 ss=0000               eflags=00200246
Looking for 'F:\tinderbox\win-6.0\out\win.amd64\release\obj\VMMRC\VMMRC.pdb' w/ cache subdir 'B21A97ADD3DE42519576F8C1C0BD39EE1' and 0xd4000014 flags...
Path list entry: 'C:\Program Files\Oracle\VirtualBox\VBoxDbgSyms/'
Dir does not exist: 'C:/Program Files/Oracle/VirtualBox/VBoxDbgSyms/'
Path list entry: 'C:\Program Files\Oracle\VirtualBox'
Path list entry: 'C:\■■■■■■■■■■■■■■■■■\Minix_v1.1/debug/'
Dir does not exist: 'C:/■■■■■■■■■■■■■■■■■/Minix_v1.1/debug/'
Path list entry: 'C:\■■■■■■■■■■■■■■■■■\Minix_v1.1/'
Path list entry: 'C:\■■■■■■■■■\'
Looking for 'F:\tinderbox\win-6.0\out\win.amd64\release\obj\VBoxDDRC\VBoxDDRC.pdb' w/ cache subdir '29F5E12563A749D78778B99DBE9A084A1' and 0xd4000014 flags...
Path list entry: 'C:\Program Files\Oracle\VirtualBox\VBoxDbgSyms/'
Dir does not exist: 'C:/Program Files/Oracle/VirtualBox/VBoxDbgSyms/'
Path list entry: 'C:\Program Files\Oracle\VirtualBox'
Path list entry: 'C:\■■■■■■■■■■■■■■■■■\Minix_v1.1/debug/'
Dir does not exist: 'C:/■■■■■■■■■■■■■■■■■/Minix_v1.1/debug/'
Path list entry: 'C:\■■■■■■■■■■■■■■■■■\Minix_v1.1/'
Path list entry: 'C:\■■■■■■■■■\'
0000:00007c00 b8 c0 07                mov ax, 007c0h
VBoxDbg> 

7.0x7c00へロードされているプログラムとブートストラップ(bootblok.s)を比較

0x7c00へロードされているプログラムを表示するために、ウィンドウ「VBox Dbg – Console」のテキストボックス「Command」へ、「u」と入力し[Enter]キーを押下。

VBoxDbg> u
0000:00007c00 b8 c0 07                mov ax, 007c0h
0000:00007c03 8e d8                   mov ds, ax
0000:00007c05 33 f6                   xor si, si
0000:00007c07 b8 e0 2f                mov ax, 02fe0h
0000:00007c0a 8e c0                   mov es, ax
0000:00007c0c 33 ff                   xor di, di
0000:00007c0e b9 00 01                mov cx, 00100h
0000:00007c11 f3 a5                   rep movsw
0000:00007c13 ea 18 00 e0 2f          jmp far 02fe0h:00018h
0000:00007c18 8c ca                   mov dx, cs
VBoxDbg> 

[ブートストラップ(bootblok.s)の抜粋]

…省略…
| Summary of the words patched into the boot block by build:
| Word at 504: # sectors to load
| Word at 506: # DS value for fsck
| Word at 508: # PC value for fsck
| Word at 510: # CS value for fsck
|
| This version of the boot block must be assembled without separate I & D
| space.  

        LOADSEG = 0x0060         | here the boot block will start loading
        BIOSSEG = 0x07C0         | here the boot block itself is loaded
        BOOTSEG = 0x2FE0         | here it will copy itself (192K-512b)
        DSKBASE = 120            | 120 = 4 * 0x1E = ptr to disk parameters

final   = 504
fsck_ds = 506
fsck_pc = 508
fsck_cs = 510


.globl begtext, begdata, begbss, endtext, enddata, endbss  | asld needs these
.text
begtext:
.data
begdata:
.bss
begbss:
.text

| copy bootblock to bootseg
        mov     ax,#BIOSSEG
        mov     ds,ax
        xor     si,si           | ds:si - original block
        mov     ax,#BOOTSEG
        mov     es,ax
        xor     di,di           | es:di - new block
        mov     cx,#256         | #  words to move
        rep     
        movw                    | copy loop

| start boot procedure
        jmpi    start,BOOTSEG   | set cs to bootseg

start:
        mov     dx,cs
        mov     ds,dx           | set ds to cs
        xor     ax,ax
        mov     es,ax           | set es to 0
        mov     ss,ax           | set ss to 0
        mov     sp,#1024        | initialize sp (top of vector table)
…省略…

8.最後に、ブートストラップ処理を見るためにステップ実行

※「t」、「p」、「br」、「g」などを使用する。
※理由はわからないが、「g」コマンドは、「t」コマンドなどのステップ実行後でないと動作しない。
※「0000:00007c11 rep movsw」は、繰り返しのため、下記は、「0000:00007c13 jmp far 02fe0h:00018h」へブレークポイントを設定した例である。

VBoxDbg> t
VBoxDbg> 
dbgf event: Single step! (rem)
eax=000007c0 ebx=00000000 ecx=00000001 edx=00000000 esi=00000000 edi=0000fff0
eip=00007c03 esp=00007800 ebp=00000000 iopl=0 nv up ei pl zr na po nc
cs=0000 ds=0000 es=0000 fs=0000 gs=0000 ss=0000               eflags=00200246
0000:00007c03 8e d8                   mov ds, ax
VBoxDbg> br 0000:00007c13
Set REM breakpoint 29 at 0000000000007c13
VBoxDbg> g
VBoxDbg> 
dbgf event: Breakpoint 29! (rem)
eax=00002fe0 ebx=00000000 ecx=00000000 edx=00000000 esi=00000200 edi=00000200
eip=00007c13 esp=00007800 ebp=00000000 iopl=0 nv up ei pl zr na po nc
cs=0000 ds=07c0 es=2fe0 fs=0000 gs=0000 ss=0000               eflags=00200246
0000:00007c13 ea 18 00 e0 2f          jmp far 02fe0h:00018h
VBoxDbg>