2

現在、ブートローダーを開発していますが、問題があります。

私はBochsを使用してブートローダーをテストし、ブートローダーをコンパイルしてディスクイメージを作成します。

rm disk.bin
rm boot.bin
rm post.bin
nasm bootloader.asm -o boot.bin
nasm postmbr.asm -o post.bin
cat boot.bin post.bin > disk.bin

これはbootloader.asmです:

[BITS 16]       ;Tells the assembler that its a 16 bit code
[ORG 0x7C00]    ;Origin, tell the assembler that where the code will

MOV SI, HelloString ;Store string pointer to SI
MOV AH, 02h          ; read sector command
MOV AL, 01h
MOV CX, 0001h
MOV DH, 00h
MOV DL, 80h ;disk
MOV AX, 7E00h
MOV ES, AX ;buffer
MOV BX, 00h ;offset
CALL PrintString
JMP 0x7E00              ;Infinite loop, hang it here.


PrintCharacter: ;Procedure to print character on screen
        ;Assume that ASCII value is in register AL
MOV AH, 0Eh     ;Tell BIOS that we need to print one charater on screen.
MOV BH, 00h     ;Page no.
MOV BL, 07h     ;Text attribute 0x07 is lightgrey font on black background

INT 10h ;Call video interrupt
RET             ;Return to calling procedure



PrintString:    ;Procedure to print string on screen
        ;Assume that string starting pointer is in register SI

next_character: ;Lable to fetch next character from string
MOV AL, [SI]    ;Get a byte from string and store in AL register
INC SI          ;Increment SI pointer
OR AL, AL       ;Check if value in AL is zero (end of string)
JZ exit_function ;If end then return
CALL PrintCharacter ;Else print the character which is in AL register
JMP next_character      ;Fetch next character from string
exit_function:  ;End label
RET             ;Return from procedure


;Data
HelloString db 'Loading OS demo...', 0  ;HelloWorld string ending with 0

TIMES 510 - ($ - $$) db 0       ;Fill the rest of sector with 0
DW 0xAA55                       ;Add boot signature at the end of bootloader

そしてpostmbr.asm:

[BITS 16]       ;Tells the assembler that its a 16 bit code

MOV SI, HelloString ;Store string pointer to SI
CALL PrintString        ;Call print string procedure
JMP $           ;Infinite loop, hang it here.


PrintCharacter: ;Procedure to print character on screen
        ;Assume that ASCII value is in register AL
MOV AH, 0x0E    ;Tell BIOS that we need to print one charater on screen.
MOV BH, 0x00    ;Page no.
MOV BL, 0x07    ;Text attribute 0x07 is lightgrey font on black background

INT 0x10        ;Call video interrupt
RET             ;Return to calling procedure



PrintString:    ;Procedure to print string on screen
        ;Assume that string starting pointer is in register SI

next_character: ;Lable to fetch next character from string
MOV AL, [SI]    ;Get a byte from string and store in AL register
INC SI          ;Increment SI pointer
OR AL, AL       ;Check if value in AL is zero (end of string)
JZ exit_function ;If end then return
CALL PrintCharacter ;Else print the character which is in AL register
JMP next_character      ;Fetch next character from string
exit_function:  ;End label
RET             ;Return from procedure


;Data
HelloString db 'Hello World', 0 ;HelloWorld string ending with 0

TIMES 512 - ($ - $$) db 0       ;Fill the rest of sector with 0

これはBochsのクラッシュログです。

00000004661i[BIOS ] $Revision: 11318 $ $Date: 2012-08-06 19:59:54 +0200 (Mo, 06. Aug 2012) $
00000319074i[KBD  ] reset-disable command received
00000321808i[BIOS ] Starting rombios32
00000322242i[BIOS ] Shutdown flag 0
00000322837i[BIOS ] ram_size=0x02000000
00000323258i[BIOS ] ram_end=32MB
00000363787i[BIOS ] Found 1 cpu(s)
00000377969i[BIOS ] bios_table_addr: 0x000fa438 end=0x000fcc00
00000396429i[BIOS ] bios_table_cur_addr: 0x000fa438
00000524046i[VBIOS] VGABios $Id: vgabios.c,v 1.75 2011/10/15 14:07:21 vruppert Exp $
00000524117i[BXVGA] VBE known Display Interface b0c0
00000524149i[BXVGA] VBE known Display Interface b0c5
00000527074i[VBIOS] VBE Bios $Id: vbe.c,v 1.64 2011/07/19 18:25:05 vruppert Exp $
00000800003i[XGUI ] charmap update. Font Height is 16
00000866078i[BIOS ] ata0-0: PCHS=1/1/2 translation=none LCHS=1/1/2
00004743252i[BIOS ] IDE time out
00016726470i[BIOS ] Booting from 0000:7c00
00016755553e[CPU0 ] write_virtual_word_32(): segment limit violation
00016755553e[CPU0 ] write_virtual_word_32(): segment limit violation
00016755553e[CPU0 ] write_virtual_word_32(): segment limit violation
00016755553i[CPU0 ] CPU is in real mode (active)
00016755553i[CPU0 ] CS.mode = 16 bit
00016755553i[CPU0 ] SS.mode = 16 bit
00016755553i[CPU0 ] EFER   = 0x00000000
00016755553i[CPU0 ] | EAX=000000aa  EBX=00000007  ECX=00090001  EDX=00000080
00016755553i[CPU0 ] | ESP=00000001  EBP=00000000  ESI=000e7c45  EDI=0000ffac
00016755553i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of DF if tf SF zf af PF cf
00016755553i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00016755553i[CPU0 ] |  CS:0000( 0004| 0|  0) 00000000 0000ffff 0 0
00016755553i[CPU0 ] |  DS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00016755553i[CPU0 ] |  SS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00016755553i[CPU0 ] |  ES:7e00( 0005| 0|  0) 0007e000 0000ffff 0 0
00016755553i[CPU0 ] |  FS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00016755553i[CPU0 ] |  GS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00016755553i[CPU0 ] | EIP=0000fd34 (0000fd34)
00016755553i[CPU0 ] | CR0=0x60000010 CR2=0x00000000
00016755553i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00016755553i[CPU0 ] 0x0000fd34>> pusha  : 60
00016755553e[CPU0 ] exception(): 3rd (12) exception with no resolution, shutdown status is 00h, resetting
00016755553i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00016755553i[CPU0 ] cpu hardware reset
00016755553i[APIC0] allocate APIC id=0 (MMIO enabled) to 0x00000000fee00000
00016755553i[CPU0 ] CPUID[0x00000000]: 00000002 68747541 444d4163 69746e65
00016755553i[CPU0 ] CPUID[0x00000001]: 00000633 00010800 00000008 17cbfbff
00016755553i[CPU0 ] CPUID[0x00000002]: 00000000 00000000 00000000 00000000
00016755553i[CPU0 ] CPUID[0x80000000]: 80000008 68747541 444d4163 69746e65
00016755553i[CPU0 ] CPUID[0x80000001]: 00000633 00000000 00000000 c1c3f3ff
00016755553i[CPU0 ] CPUID[0x80000002]: 20444d41 6c687441 74286e6f 7020296d
00016755553i[CPU0 ] CPUID[0x80000003]: 65636f72 726f7373 00000000 00000000
00016755553i[CPU0 ] CPUID[0x80000004]: 00000000 00000000 00000000 00000000
00016755553i[CPU0 ] CPUID[0x80000005]: 01ff01ff 01ff01ff 40020140 40020140
00016755553i[CPU0 ] CPUID[0x80000006]: 00000000 42004200 02008140 00000000
00016755553i[CPU0 ] CPUID[0x80000007]: 00000000 00000000 00000000 00000000
00016755553i[CPU0 ] CPUID[0x80000008]: 00002028 00000000 00000000 00000000
00016755553i[     ] reset of 'cmos' plugin device by virtual method
00016755553i[     ] reset of 'dma' plugin device by virtual method
00016755553i[     ] reset of 'pic' plugin device by virtual method
00016755553i[     ] reset of 'pit' plugin device by virtual method
00016755553i[     ] reset of 'floppy' plugin device by virtual method
00016755553i[     ] reset of 'vga' plugin device by virtual method
00016755553i[     ] reset of 'ioapic' plugin device by virtual method
00016755553i[     ] reset of 'keyboard' plugin device by virtual method
00016755553i[     ] reset of 'harddrv' plugin device by virtual method
00016755553i[     ] reset of 'unmapped' plugin device by virtual method
00016755553i[     ] reset of 'biosdev' plugin device by virtual method
00016755553i[     ] reset of 'speaker' plugin device by virtual method
00016755553i[     ] reset of 'extfpuirq' plugin device by virtual method
00016755553i[     ] reset of 'parallel' plugin device by virtual method
00016755553i[     ] reset of 'serial' plugin device by virtual method

そしてこれはBochsの設定ファイルです:

# configuration file generated by Bochs
plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1
config_interface: textconfig
display_library: x
memory: host=32, guest=32
romimage: file="/usr/share/bochs/BIOS-bochs-latest"
vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
boot: disk
floppy_bootsig_check: disabled=0
# no floppya
# no floppyb
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, mode=flat, translation=auto, path="disk.bin", cylinders=1, heads=1, spt=2, biosdetect=auto, model="Generic 1234"
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata2: enabled=0
ata3: enabled=0
pci: enabled=0
vga: extension=vbe, update_freq=5
cpu: count=1, ips=4000000, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
cpuid: family=6, model=0x03, stepping=3, mmx=1, apic=xapic, sse=sse2, sse4a=0, sep=1, aes=0, xsave=0, xsaveopt=0, movbe=0, adx=0, smep=0, mwait=1
cpuid: vendor_string="AuthenticAMD"
cpuid: brand_string="AMD Athlon(tm) processor"

print_timestamps: enabled=0
port_e9_hack: enabled=0
private_colormap: enabled=0
clock: sync=none, time0=local, rtc_sync=0
# no cmosimage
# no loader
log: -
logprefix: %t%e%d
panic: action=ask
error: action=report
info: action=report
debug: action=ignore
keyboard: type=mf, serial_delay=250, paste_delay=100000, keymap=
user_shortcut: keys=none
mouse: enabled=0, type=ps2, toggle=ctrl+mbutton
parport1: enabled=1, file=""
parport2: enabled=0
com1: enabled=1, mode=null, dev=""
com2: enabled=0
com3: enabled=0
com4: enabled=0

何が悪いのかわかりません。他のプラットフォームでブートローダーをテストしていません。

4

3 に答える 3

4

クラッシュダンプはpusha、破壊されたスタックにレジスタをプッシュしようとしている命令を明確に示しています。

関連ビット:

00016755553e [CPU0] write_virtual_word_32():セグメント制限違反
00016755553e [CPU0] write_virtual_word_32():セグメント制限違反
00016755553e [CPU0] write_virtual_word_32():セグメント制限違反
00016755553i [CPU0] | EAX = 000000aa EBX = 00000007 ECX = 00090001 EDX = 00000080
00016755553i [CPU0] | ESP = 00000000EBP = 00000000 ESI = 000e7c45 EDI = 0000ffac
00016755553i [CPU0] | SEG sltr(index | ti | rpl)ベース制限GD
00016755553i [CPU0] | CS:0000(0004 | 0 | 0)00000000 0000ffff 0 0
00016755553i [CPU0] | SS:0000(0005 | 0 | 0)00000000 0000ffff 0 0
00016755553i [CPU0] | EIP = 0000fd34(0000fd34)
00016755553i [CPU0] 0x0000fd34 >> pusha:60
00016755553e [CPU0]例外():解決なしの3番目(12)の例外、シャットダウンステータスは00h、リセット

その命令は、スタックにデータを書き込むときに、オフセット0でセグメントの下限を超えようとしています。そして、それは回復不能な例外とそれに続くリセットを引き起こします。

最も可能性の高い原因は、間違った場所へのジャンプとそこでのランダムなもの、おそらくデータの実行です。

この指示を見てください:

JMP 0x7E00              ;Infinite loop, hang it here.

CPUがそれを実行した後、CS:IP0:0x7E00になります。

次に、postmbr.asmを見てください。

[BITS 16]       ;Tells the assembler that its a 16 bit code

MOV SI, HelloString ;Store string pointer to SI
...

そこorgには何もありません。その場合org 0は暗示されます。

したがって、コードのこの部分は、開始時に= 0であり、すべてのオフセットがコードのこの部分の先頭からカウントされるという仮定でコンパイルされIPます。論理的には、これはCS== DS0も間違っていることを意味します。しかし、レジスターに間違った予期しない値が含まれていることにジャンプしています。

そのため、このコードは期待どおりに実行されません。IOW、それはほとんど何でもすることができます、そして、私は確かに、それはスタックの破壊とクラッシュにつながります。

ここでの重要な教訓:x86コードは位置に依存しません。

org適切な( )を挿入するか、org 0x7E00それに応じてレジスタを設定し、コードのこの部分にジャンプします(egを使用jmp 0x7e0:0)。

更新:そして今が私にとってのレッスンの時間です...上記の問題は確かに存在します。ただし、 @ ughoavgfhwが指摘しているように、ほぼ同じ場所にもう1つありますが、少し前に発生しています。2番目の512バイトはロードされません。うん。BIOS自体は最初のセクターのみをロードします。この最初のセクターは、BIOS int 13hを明示的に呼び出すことにより、2番目のセクターをロードする必要があります。

于 2012-10-22T17:40:20.260 に答える
1
JMP 0x7E00

この時点で0x7E00にジャンプすると、予期しない動作が発生します。0x7E00でロードされると予想されるpost.binにジャンプしたいようです。そうではありません。BIOSは、0x7C00で1つのセクターboot.binのみをロードしました。追加のセクターを手動でロードする必要があります。

于 2012-10-22T17:43:46.153 に答える
-1

ブートローダーの実行が開始されると、ほとんどのレジスタの値は何でもかまいません。これにはスタックポインタが含まれます。クラッシュレポートはそれespが1であることを示しており、クラッシュは命令のトリプルフォールトが原因で発生しpushaます。これは、基本的に、存在しないスタックにデータをプッシュしようとしていることを意味します。これは、スタックポインタを設定したことがないため、スタックポインタがどこにあるかわからないためです。最初に行うことの1つとして、スタックポインタを設定する必要があります。コードのすぐ下に配置されるように、0x7c00に設定することをお勧めします。これをブートローダーの先頭近くに配置します。

mov  sp, 0x7C00
于 2012-10-22T17:37:47.077 に答える