Boot loader 在不同的虚拟机中 lgdt 后产生不同的结果
Boot loader makes different results after lgdt in different virtual machines
我正在编写一个简单的引导加载程序。引导加载程序由两个汇编文件编译而成:boot.asm、protected_start.asm。 boot.asm 加载 protected_start 到 0x10000,设置 GDTR,进入保护模式并跳转到 0x10000。所以编码在boot.asm中设置为16位,在protected_start.asm中设置为32位。
我在 Windows 上使用 QEMU、VMware 和 NASM。两个虚拟机都有 128MB 的内存。进入保护模式后,QEMU 成功跳转到 0x10000 并打印给定的字符串,但 VMWare 重新启动。我用"jmp $"寻找错误发生的地方,发现"jmp dword 0x08:0x0000"在boot.asm中出错。
QEMU的版本是20180519,VMware是Workstation Player 14.1.2 build-8497320。
为什么LGDT出错后"jmp dword 0x08:0x0000"?我必须怎么做才能解决这个问题?
boot.asm:
[org 0x7c00]
[bits 16]
load:
mov ax, 0x1000
mov es, ax
mov bx, 0x0000;
mov ah, 0x02; Read sectors from drive
mov al, 0x08; Number of sectors to read
mov ch, 0x00; Cylinder index
mov cl, 0x02; Sector
mov dh, 0x00; Head
mov dl, 0x00; Drive
int 0x13
jc load
cli
lgdt [gdtr]
mov eax, cr0
or eax, 0x00000001
mov cr0, eax
jmp dword 0x08:0x0000
gdt_list:
dw 0
dw 0
db 0
db 0
db 0
db 0
.gdt_code:
dw 0xFFFF
dw 0x0000
db 0x01
db 0x9A
db 0xCF
db 0x00
.gdt_data:
dw 0xFFFF
dw 0x0000
db 0x00
db 0x92
db 0xCF
db 0x00
.gdt_video:
dw 0xFFFF
dw 0x8000
db 0x0B
db 0x92
db 0xCF
db 0x00
gdtr:
dw 4*8
dd gdt_list
times 510 - ($ - $$) db 0
dw 0xAA55
protected_start.asm:
[org 0x10000]
[bits 32]
protected:
mov ax, 0x10
mov ds, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0xFFFF
mov ebp, 0xFFFF
mov ax, 0x18
mov es, ax
mov edi, 0x0000
mov esi, my_str
call write
jmp $
write:
push eax
push ebx
mov ah, 0x0e
mov bx, 0x0007
.loop:
lodsb
or al, al
jz .end
mov byte [es:edi], al
inc di
mov byte [es:edi], 0x0f
inc di
jmp .loop
.end:
pop ebx
pop eax
ret
my_str:
db "Protected", 0x0
times 512 - ($ - $$) db 0
我用来在 PowerShell 中调用虚拟机的内容:
qemu-system-x86_64 -m 128 -smp 1 -fda ".\bin\os.img"
Invoke-Item ".\virtual\os.vmx"
在 lgdt 解决问题之前初始化 ds。因为lgdt[gdtr]其实就是lgdt[ds:gdtr],如果不设置ds,可能会出现这个错误。因为我使用了 [org 0x7c00],所以我将 ds 设置为 0x0000。它适用于 QEMU 和 VMware。
boot.asm的编辑版本:
[org 0x7c00]
[bits 16]
load:
; edited part: initialize ds
mov ax, 0x0000
mov ds, ax
mov ax, 0x1000
mov es, ax
mov bx, 0x0000;
mov ah, 0x02; Read sectors from drive
mov al, 0x08; Number of sectors to read
mov ch, 0x00; Cylinder index
mov cl, 0x02; Sector
mov dh, 0x00; Head
mov dl, 0x00; Drive
int 0x13
jc load
cli
lgdt [gdtr]
mov eax, cr0
or eax, 0x00000001
mov cr0, eax
jmp dword 0x08:0x0000
gdt_list:
dw 0
dw 0
db 0
db 0
db 0
db 0
.gdt_code:
dw 0xffff
dw 0x0000
db 0x01
db 0x9a
db 0xcf
db 0x00
.gdt_data:
dw 0xffff
dw 0x0000
db 0x00
db 0x92
db 0xcf
db 0x00
.gdt_video:
dw 0xffff
dw 0x8000
db 0x0b
db 0x92
db 0xcf
db 0x00
gdtr:
dw 4*8
dd gdt_list
times 510 - ($ - $$) db 0
dw 0xAA55
我正在编写一个简单的引导加载程序。引导加载程序由两个汇编文件编译而成:boot.asm、protected_start.asm。 boot.asm 加载 protected_start 到 0x10000,设置 GDTR,进入保护模式并跳转到 0x10000。所以编码在boot.asm中设置为16位,在protected_start.asm中设置为32位。
我在 Windows 上使用 QEMU、VMware 和 NASM。两个虚拟机都有 128MB 的内存。进入保护模式后,QEMU 成功跳转到 0x10000 并打印给定的字符串,但 VMWare 重新启动。我用"jmp $"寻找错误发生的地方,发现"jmp dword 0x08:0x0000"在boot.asm中出错。
QEMU的版本是20180519,VMware是Workstation Player 14.1.2 build-8497320。
为什么LGDT出错后"jmp dword 0x08:0x0000"?我必须怎么做才能解决这个问题?
boot.asm:
[org 0x7c00]
[bits 16]
load:
mov ax, 0x1000
mov es, ax
mov bx, 0x0000;
mov ah, 0x02; Read sectors from drive
mov al, 0x08; Number of sectors to read
mov ch, 0x00; Cylinder index
mov cl, 0x02; Sector
mov dh, 0x00; Head
mov dl, 0x00; Drive
int 0x13
jc load
cli
lgdt [gdtr]
mov eax, cr0
or eax, 0x00000001
mov cr0, eax
jmp dword 0x08:0x0000
gdt_list:
dw 0
dw 0
db 0
db 0
db 0
db 0
.gdt_code:
dw 0xFFFF
dw 0x0000
db 0x01
db 0x9A
db 0xCF
db 0x00
.gdt_data:
dw 0xFFFF
dw 0x0000
db 0x00
db 0x92
db 0xCF
db 0x00
.gdt_video:
dw 0xFFFF
dw 0x8000
db 0x0B
db 0x92
db 0xCF
db 0x00
gdtr:
dw 4*8
dd gdt_list
times 510 - ($ - $$) db 0
dw 0xAA55
protected_start.asm:
[org 0x10000]
[bits 32]
protected:
mov ax, 0x10
mov ds, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0xFFFF
mov ebp, 0xFFFF
mov ax, 0x18
mov es, ax
mov edi, 0x0000
mov esi, my_str
call write
jmp $
write:
push eax
push ebx
mov ah, 0x0e
mov bx, 0x0007
.loop:
lodsb
or al, al
jz .end
mov byte [es:edi], al
inc di
mov byte [es:edi], 0x0f
inc di
jmp .loop
.end:
pop ebx
pop eax
ret
my_str:
db "Protected", 0x0
times 512 - ($ - $$) db 0
我用来在 PowerShell 中调用虚拟机的内容:
qemu-system-x86_64 -m 128 -smp 1 -fda ".\bin\os.img"
Invoke-Item ".\virtual\os.vmx"
在 lgdt 解决问题之前初始化 ds。因为lgdt[gdtr]其实就是lgdt[ds:gdtr],如果不设置ds,可能会出现这个错误。因为我使用了 [org 0x7c00],所以我将 ds 设置为 0x0000。它适用于 QEMU 和 VMware。
boot.asm的编辑版本:
[org 0x7c00]
[bits 16]
load:
; edited part: initialize ds
mov ax, 0x0000
mov ds, ax
mov ax, 0x1000
mov es, ax
mov bx, 0x0000;
mov ah, 0x02; Read sectors from drive
mov al, 0x08; Number of sectors to read
mov ch, 0x00; Cylinder index
mov cl, 0x02; Sector
mov dh, 0x00; Head
mov dl, 0x00; Drive
int 0x13
jc load
cli
lgdt [gdtr]
mov eax, cr0
or eax, 0x00000001
mov cr0, eax
jmp dword 0x08:0x0000
gdt_list:
dw 0
dw 0
db 0
db 0
db 0
db 0
.gdt_code:
dw 0xffff
dw 0x0000
db 0x01
db 0x9a
db 0xcf
db 0x00
.gdt_data:
dw 0xffff
dw 0x0000
db 0x00
db 0x92
db 0xcf
db 0x00
.gdt_video:
dw 0xffff
dw 0x8000
db 0x0b
db 0x92
db 0xcf
db 0x00
gdtr:
dw 4*8
dd gdt_list
times 510 - ($ - $$) db 0
dw 0xAA55