一般性保护错误上运行ISO
OS时,我有以下bootloader代码似乎运行在硬盘上完美的罚款:一般性保护错误上运行ISO
[bits 16]
[org 0x7c00]
bootld_start:
KERNEL_OFFSET equ 0x2000
xor ax, ax ; Explicitly set ES = DS = 0
mov ds, ax
mov es, ax
mov bx, 0x8C00 ; Set SS:SP to 0x8C00:0x0000 . The stack will exist
; between 0x8C00:0x0000 and 0x8C00:0xFFFF
mov ss, bx
mov sp, ax
mov [BOOT_DRIVE], dl
mov bx, boot_msg
call print_string
mov dl, [BOOT_DRIVE]
call disk_load
jmp pm_setup
jmp $
BOOT_DRIVE:
db 0
disk_load:
mov si, dap
mov ah, 0x42
int 0x13
;cmp al, 4
;jne disk_error_132
ret
dap:
db 0x10 ; Size of DAP
db 0
; You can only read 46 sectors into memory between 0x2000 and
; 0x7C00. Don't read anymore or we overwrite the bootloader we are
; executing from. (0x7c00-0x2000)/512 = 46
dw 46 ; Number of sectors to read
dw KERNEL_OFFSET ; Offset
dw 0 ; Segment
dd 1
dd 0
disk_error_132:
mov bx, disk_error_132_msg
call print_string
jmp $
disk_error_132_msg:
db 'Error! Error! Something is VERY wrong! (0x132)', 0
gdt_start:
gdt_null:
dd 0x0
dd 0x0
gdt_code:
dw 0xffff
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
boot_msg:
db 'OS is booting files... ', 0
done_msg:
db 'Done! ', 0
%include "boot/print_string.asm"
pm_setup:
mov bx, done_msg
call print_string
mov ax, 0
mov ss, ax
mov sp, 0xFFFC
mov ax, 0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
cli
lgdt[gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:b32
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
print32:
pusha
mov edx, VIDEO_MEMORY
.loop:
mov al, [ebx]
mov ah, WHITE_ON_BLACK
cmp al, 0
je .done
mov [edx], ax
add ebx, 1
add edx, 2
jmp .loop
.done:
popa
ret
b32:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Place stack below EBDA in lower memory
mov ebp, 0x9c000
mov esp, ebp
mov ebx, pmode_msg
call print32
call KERNEL_OFFSET
jmp $
pmode_msg:
db 'Protected mode enabled!', 0
kernel:
mov ebx, pmode_msg
call print32
jmp $
pmode_tst:
db 'Testing...'
times 510-($-$$) db 0
db 0x55
db 0xAA
的问题是,当我将其转换为使用这些命令的ISO:
mkdir iso
mkdir iso/boot
cp image.flp iso/boot/boot
xorriso -as mkisofs -R -J -c boot/bootcat \
-b boot/boot -no-emul-boot -boot-load-size 4 \
-o image.iso iso
...它失败并出现三重故障。当我与qemu-system-i386 -boot d -cdrom os-image.iso -m 512 -d int -no-reboot -no-shutdown
运行它,它输出(不含无用SMM例外):
check_exception old: 0xffffffff new 0xd
0: v=0d e=0000 i=0 cpl=0 IP=0008:0000000000006616
pc=0000000000006616
SP=0010:000000000009bff8 env->regs[R_EAX]=0000000000000000
EAX=00000000 EBX=00007d72 ECX=00000000 EDX=000000e0
ESI=00007cb0 EDI=00000010 EBP=0009c000 ESP=0009bff8
EIP=00006616 EFL=00000083 [--S---C] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 00007c73 00000018
IDT= 00000000 000003ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=000000e0 CCD=000001b3 CCO=ADDB
EFER=0000000000000000
check_exception old: 0xd new 0xd
1: v=08 e=0000 i=0 cpl=0 IP=0008:0000000000006616 pc=0000000000006616 SP=0010:000000000009bff8 env- >regs[R_EAX]=0000000000000000
EAX=00000000 EBX=00007d72 ECX=00000000 EDX=000000e0
ESI=00007cb0 EDI=00000010 EBP=0009c000 ESP=0009bff8
EIP=00006616 EFL=00000083 [--S---C] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 00007c73 00000018
IDT= 00000000 000003ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=000000e0 CCD=000001b3 CCO=ADDB
EFER=0000000000000000
check_exception old: 0x8 new 0xd
这意味着我得到了一个0X0D(一般性保护错误),然后0x08的(双重故障),则三重故障。这是为什么发生?
编辑:我已经改变了命令:
xorriso -as mkisofs -R -J -c boot/bootcat -b boot/boot.flp -o nmos.iso nmos.flp
但现在我收到以下错误:
xorriso : FAILURE : Cannot find in ISO image: -boot_image ... bin_path='/boot/boot.flp'
xorriso : NOTE : -return_with SORRY 32 triggered by problem severity FAILURE
有谁知道这是什么意思?
编辑2:
我已经改变了代码中使用啊= 0×02像这样写着:
mov bx, KERNEL_OFFSET
mov ah, 0x02
mov al, 46
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
mov dl, [BOOT_DRIVE]
int 0x13
,但它仍然是三重断裂。为什么?
问题中的所有三重故障的主要原因,真正归因于你的内核没有被正确加载到0x0000:0x2000的内存中。当您使用JMP将控制转移到此位置时,最终运行内存区域中发生的情况,并执行CPU直到它遇到导致故障的指令。
引导光盘是具有多种不同的模式的奇兽,并且有引导这样的CD,但他们也可能有自己的怪癖很多的BIOS。当您使用-no-emul-boot
和XORRISO您正在请求磁盘既不被视为软盘也不被视为硬盘。你可以删除-no-emul-boot -boot-load-size 4
,它应该生成一个被视为软盘的ISO。问题在于许多真正的BIOS,仿真器(BOCH和QEMU)和虚拟机在使用软盘模拟引导CD时不支持Int 13h/AH=42h扩展磁盘读取。您可能会*通过Int 13h/AH=02h使用常规磁盘读取。
如果您使用-no-emul-boot -boot-load-size 4
,则应该可以通过Int 13h/AH = 42h使用扩展磁盘读取,但它需要对引导加载程序进行一些更改。当使用-no-emul-boot -boot-load-size 4
时,CDROM的扇区大小为2048字节,而不是512.这需要对引导加载程序和内核进行一些修改。 -boot-load-size 4
将信息写入ISO,通知BIOS从ISO内的磁盘映像的起始处读取4
512字节的块。不再需要0xaa55
引导签名。
如果您使用-no-emul-boot
还有一个需要处理的障碍。在CD-ROM上,LBA 0不是放置在最终ISO中的磁盘映像的位置。问题是,如何获得磁盘镜像在ISO中的LBA?您可以使用XORRISO将此信息写入您创建的引导加载程序的特殊部分,然后使用-boot-info-table
启用此功能。
在引导加载程序开始时创建特殊部分相对比较容易。在El Torito Specification Supplement他们提到这一点:
EL TORITO BOOT INFORMATION TABLE ... The format of this table is as follows; all integers are in sec- tion 7.3.1 ("little endian") format. Offset Name Size Meaning 8 bi_pvd 4 bytes LBA of primary volume descriptor 12 bi_file 4 bytes LBA of boot file 16 bi_length 4 bytes Boot file length in bytes 20 bi_csum 4 bytes 32-bit checksum 24 bi_reserved 40 bytes Reserved The 32-bit checksum is the sum of all the 32-bit words in the boot file starting at byte offset 64. All linear block addresses (LBAs) are given in CD sectors (normally 2048 bytes).
这是在谈论56个字节,我们创建拿着我们的bootloader虚拟磁盘的偏移量为8。如果我们修改你的引导代码的顶部看起来像这样,我们有效地创建一个空的引导信息表:
start:
jmp bootld_start
times 8-($-$$) db 0 ; Pad out first 8 bytes
; Boot info table
bi_pvd dd 0
bi_file dd 0
bi_kength dd 0
bi_csum dd 0
bi_reserved times 40 db 0 ; 40 bytes reserved
当使用XORRISO与-boot-info-table
一旦ISO生成此表将被填充。 bi_file
是我们需要的重要信息,因为它是我们的磁盘镜像放置在ISO内部的LBA。我们可以使用它来填充扩展磁盘读取使用的磁盘访问包,以便从ISO的正确位置读取。
为了使DAP有点更具可读性,并考虑到我已经修改它看起来像2048字节扇区:
dap:
dap_size: db 0x10 ; Size of DAP
dap_zero db 0
; You can only read 11 2048 byte sectors into memory between 0x2000 and
; 0x7C00. Don't read anymore or we overwrite the bootloader we are
; executing from. (0x7c00-0x2000)/2048 = 11 (rounded down)
dap_numsec: dw 11 ; Number of sectors to read
dap_offset: dw KERNEL_OFFSET ; Offset
dap_segment: dw 0 ; Segment
dap_lba_low: dd 0
dap_lba_high:dd 0
一个问题是,放入启动信息表中的LBA是从磁盘映像的启动(使用我们的引导程序的扇区)。我们需要将该LBA增加1,并将其放入DAP中,以便我们在内核启动时使用LBA。使用32位指令,我们可以从引导信息表读取32位值,加1并保存到DAP中。如果使用严格的16位指令,则向32位值添加一个更复杂。由于我们将进入386保护模式,因此我们可以假设在实模式下支持32位操作数的指令。代码更新与内核的LBA的DAP可能看起来像:
mov ebx, [bi_file] ; Get LBA of our disk image in ISO
inc ebx ; Add sector to get LBA for start of kernel
mov [dap_lba_low], ebx ; Update DAP with LBA of kernel in the ISO
其他唯一的问题是引导程序部门需要对其进行填充到2048(一个CD-ROM部门的规模),而超过512,我们可以删除启动签名。变化:
times 510-($-$$) db 0
db 0x55
db 0xAA
要:
times 2048-($-$$) db 0
修改后的Bootloader代码可能看起来像:
[bits 16]
[org 0x7c00]
KERNEL_OFFSET equ 0x2000
start:
jmp bootld_start
times 8-($-$$) db 0 ; Pad out first 8 bytes
; Boot info table
bi_pvd dd 0
bi_file dd 0
bi_kength dd 0
bi_csum dd 0
bi_reserved times 40 db 0 ; 40 bytes reserved
bootld_start:
xor ax, ax ; Explicitly set ES = DS = 0
mov ds, ax
mov es, ax
mov bx, 0x8C00 ; Set SS:SP to 0x8C00:0x0000 . The stack will exist
; between 0x8C00:0x0000 and 0x8C00:0xFFFF
mov ss, bx
mov sp, ax
mov ebx, [bi_file] ; Get LBA of our disk image in ISO
inc ebx ; Add sector to get LBA for start of kernel
mov [dap_lba_low], ebx ; Update DAP with LBA of kernel in the ISO
mov [BOOT_DRIVE], dl
mov bx, boot_msg
call print_string
mov dl, [BOOT_DRIVE]
call disk_load
jmp pm_setup
jmp $
BOOT_DRIVE:
db 0
disk_load:
mov si, dap
mov ah, 0x42
int 0x13
;cmp al, 4
;jne disk_error_132
ret
dap:
dap_size: db 0x10 ; Size of DAP
dap_zero db 0
; You can only read 11 2048 byte sectors into memory between 0x2000 and
; 0x7C00. Don't read anymore or we overwrite the bootloader we are
; executing from. (0x7c00-0x2000)/2048 = 11 (rounded down)
dap_numsec: dw 11 ; Number of sectors to read
dap_offset: dw KERNEL_OFFSET ; Offset
dap_segment: dw 0 ; Segment
dap_lba_low: dd 0
dap_lba_high:dd 0
disk_error_132:
mov bx, disk_error_132_msg
call print_string
jmp $
disk_error_132_msg:
db 'Error! Error! Something is VERY wrong! (0x132)', 0
gdt_start:
gdt_null:
dd 0x0
dd 0x0
gdt_code:
dw 0xffff
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
boot_msg:
db 'OS is booting files... ', 0
done_msg:
db 'Done! ', 0
%include "boot/print_string.asm"
pm_setup:
mov bx, done_msg
call print_string
mov ax, 0
mov ss, ax
mov sp, 0xFFFC
mov ax, 0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
cli
lgdt[gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:b32
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
print32:
pusha
mov edx, VIDEO_MEMORY
.loop:
mov al, [ebx]
mov ah, WHITE_ON_BLACK
cmp al, 0
je .done
mov [edx], ax
add ebx, 1
add edx, 2
jmp .loop
.done:
popa
ret
b32:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Place stack below EBDA in lower memory
mov ebp, 0x9c000
mov esp, ebp
mov ebx, pmode_msg
call print32
call KERNEL_OFFSET
jmp $
pmode_msg:
db 'Protected mode enabled!', 0
kernel:
mov ebx, pmode_msg
call print32
jmp $
pmode_tst:
db 'Testing...'
times 2048-($-$$) db 0
然后,您可以修改原来的XORRISO命令是:
xorriso -as mkisofs -R -J -c boot/bootcat \
-b boot/boot -no-emul-boot -boot-load-size 4 \
-boot-info-table -o image.iso iso
我是xorriso的开发者。如果image.flp是带有MBR的软盘映像 ,可能是分区表和文件系统,则Michael的提示 会朝着正确的方向前进。 El Torito指定了模拟 ,它允许引导映像文件在BIOS中显示为软盘或硬盘。
选项-no-emul-boot -boot-load-size 4会导致BIOS加载 文件image.flp的第一个2048字节并将它们作为x86程序执行。 显然,软盘映像不适合作为普通程序。
根据mkisofs的传统软盘模拟是 选项-b的默认值。因此,您只需从xorriso命令行中删除选项-no-emul-boot 即可将El Torito启动映像 设置为软盘。 (-boot-load-size 4也已过时)。 软盘映像必须具有512 字节的2400或2880或5760扇区,否则它将被xorriso拒绝。
其他大小的图像可能会模拟为硬盘,其中MBR分区表中的第一个 (且仅限)分区条目指示磁盘的大小为 。 xorriso -as mkisofs选项-hard-disk-boot选择此仿真。
关于引导映像内容 和BIOS问题的唯一知识是: http:// git.zytor.com/syslinux/syslinux.git/tree/core/isolinux.asm 是一个经过测试的-no-emul-boot引导程序示例。 我唯一的软盘模拟ISO示例是名为MooseDT-SD1A-2D-8-16-32MB.iso的Seagate固件升级程序 。 –
El Torito,4.1“INT 13 Function 08”给出了仿真的十六进制软盘几何结构。 轨道x头x扇区:1.44 Meg = 0x50 x 2 x 0x12, 2.88 Meg = 0x50 x 2 x 0x24,1.2 Meg = 0x50 x 2 x 0x0F。 –
I'我不是ISO的专家,但看起来你正在使用xorriso来创建一个ISO,但已经关闭了软盘模拟。由于ISO不是模拟软盘,所以您的DAP读取可能会执行2048字节的扇区读取,而读取扇区1是相对于CD的开始。可能你并没有将你的内核读入内存,当你跳到KERNEL_OFFSET(0x2000)时,你正在执行内存,直到它在EIP 0x6616发生故障。我怀疑你的内核只是没有被正确读取。 –
'xorriso -as mkisofs -R -J -c boot/bootcat -b boot/boot.flp -o nmos.iso nmos.flp'应该是'xorriso -as mkisofs -R -J -c boot/bootcat -b boot /boot.flp -o nmos.iso'。允许软盘模拟的ISO生成是'nmos.iso'。你可能会发现这个**可能不适用于BOCHS,QEMU和一些真正的硬件,因为int 13h/ah = 42h可能甚至不能用作模拟软盘的CD-ROM。 –
查看我之前评论的最后一句。 –