assembly - 系统在 QEMU 上启动,但在真实硬件上出现恐慌(重新启动)
问题描述
我在引导加载程序中从 CBS 切换到 LBA,在 ata_lba_read 之后以 32 位模式加载内核 在此之前,我总是用 QEMU 测试我的系统,它在那里工作(并且工作)完美。现在我决定尝试在真实硬件上启动系统。它打印一条引导消息并永远重新启动(内核未加载)我搜索了一段时间的答案,但只有那些已经在我的引导加载程序中实现。
这是引导加载程序代码:
ORG 7C00h
[BITS 16]
CODE_SEG equ GDT_CODE - GDT_START
DATA_SEG equ GDT_DATA - GDT_START
jmp short start
nop
;FAT16 Header
OEM_Identifier db 'FAT16OEM'
BytesPerSector dw 0x200
SectorsPerCluster db 0x80
ReservedSectors dw 200
FATCopies db 0x02
RootDirEntries dw 0x40
NumberOfSectors dw 0
MediaType db 0xF8
SectorsPerFAT dw 0x100
SectorsPerTrack dw 0x20
NumberOfHeads dw 0x40
HiddenSectors dd 0x00
SectorsBig dd 0x773594
;Extended BPB
DriveNumber db 0x80
WinNTBit db 0x00
Signature db 0x29
VolumeID dd 0xD105
VolumeIDString db 'MYSTOS_BOOT'
SystemIDString db 'MOSFAT16'
start:
jmp 0x0:load
load:
cli
mov ax, 0x00
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x00
sti
mov cx, bootmsg
call print
mov cx, newline
call print
mov ax, 0xFFFF
mov cx, 0x2000
call sleep
.load_protected:
cli
lgdt[GDT_DESCRIPTOR]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:load32
print:
push si
push bx
push ax
mov si, cx
mov bx, 0
print_loop:
lodsb
cmp al, 0
jz finish_print
call PrintChar
jmp print_loop
finish_print:
pop ax
pop bx
pop si
ret
PrintChar:
mov ah, 0Eh
int 10h
ret
sleep:
push ax
push cx
sleep_loop:
cmp cx, 0
jz dec_ax
dec cx
jmp sleep_loop
dec_ax:
cmp ax, 0
jz finish_sleep
dec ax
pop cx
push cx
jmp sleep_loop
finish_sleep:
pop cx
pop ax
ret
GDT_START:
GDT_NULL: ;64 bits of zeros
dd 0x0
dd 0x0
; offset 0x8
GDT_CODE: ;CS SHOULD POINT TO THIS
dw 0xFFFF ;Segment limit first 0-15 bits
dw 0 ;Base first 0-15 bits
db 0 ;Base 16-23 bits
db 0x9a ;Access byte
db 11001111b ;High and low 4 bit flags
db 0 ;Base 24-31 bits
; offset 0x10
GDT_DATA: ;DS, SS, ES, FS, GS
dw 0xFFFF ;Segment limit first 0-15 bits
dw 0 ;Base first 0-15 bits
db 0 ;Base 16-23 bits
db 0x92 ;Access byte
db 11001111b ;High and low 4 bit flags
db 0 ;Base 24-31 bits
GDT_END:
GDT_DESCRIPTOR:
dw GDT_END - GDT_START - 1
dd GDT_START
[BITS 32]
load32:
mov eax, 1
mov ecx, 128
mov edi, 0x0100000
call ata_lba_read
jmp CODE_SEG:0x0100000
ata_lba_read:
mov ebx, eax ;Backup the LBA
;Send the highest 8 bits of the LBA to harddisk controller
shr eax, 24 ;Shift 24 bits so eax now contain only the highest 8 bits of the LBA
or eax, 0xE0 ;Select the master drive
mov dx, 0x1F6
out dx, al ;Send
;Send the total sectors to read
mov eax, ecx
mov dx, 0x1F2
out dx, al
;Send more bits of the LBA
mov eax, ebx ;Restore LBA
mov dx, 0x1F3
out dx, al
;Send more bits of the LBA
mov eax, ebx ;Restore LBA
mov dx, 0x1F4
shr eax, 8 ;Shift 8 bits that were sent
out dx, al
;Send upper 16 bits of the LBA
mov eax, ebx ;Restore LBA
mov dx, 0x1F5
shr eax, 16 ;Shift 16 bits
out dx, al
;Finished sending
mov dx, 0x1F7
mov al, 0x20
out dx, al
;Read all sectors
.next_sector:
push ecx
;Checking the need to read
.try_again:
mov dx, 0x1F7
in al, dx
test al, 8
jz .try_again
;We need to read 256 words at a time
mov ecx, 256
mov dx, 0x1F0
rep insw
pop ecx
loop .next_sector
;End of reading
ret
bootmsg db 'www.https://stackoverflow.com/', 0
newline db 0Ah, 0Dh, 0
times 510-($-$$) db 0
dw 0xAA55
UPD:32 位打印例程代码(基于 0xB8000 的 VGA 显存)将我的工作 C 打印功能转换为汇编之一。引导加载程序停止并阻止在 QEMU 中加载内核
makechar32: ;eax - chr, edx - color
shl edx, 8
or edx, eax
mov eax, edx
ret
putchar32: ;eax - chr, edx - color, ebx - x, ecx - y
call makechar32
mov esi, 0xB8000
;video_mem_saddr + y*80 + x
add esi, ebx
mov ebx, eax
mov eax, 80
mul ecx
mov ecx, eax
add esi, ecx
mov [esi], ebx
ret
printchar32: ;eax - chr, edx - color
pushad
mov ebx, [col]
mov ecx, [row]
call putchar32
inc ebx
cmp ebx, 80
jge newrow
newcol:
inc ebx
mov [col], ebx
popad
ret
newrow:
xor ebx, ebx
mov [col], ebx
inc ecx
mov [row], ecx
popad
ret
print32: ;ecx - *str
pushad
mov esi, ecx
print32_loop:
lodsb
cmp eax, 0
jz finish_print32
mov edx, 7
call printchar32
jmp print32_loop
finish_print32:
popad
ret
解决方案
推荐阅读
- python - 不必一遍又一遍地加载数据集
- javascript - 自动化使用 JavaScript 功能的网页
- ruby-on-rails-4 - 使用 Redis 缓存对 Rails 工作者进行功能测试的最佳实践是什么?
- matlab - 绘制两个函数的卷积时出错
- python - 可视化 TensorFlow 优化图
- json - 如何在 Ubuntu webhook commad 上设置 webhook 密码?
- identityserver4 - 在另一个应用程序中列出来自 IdentityServer 的注册用户
- angular - Angular FormControl 检查是否需要
- java - Netty 服务器中 Dropwizard 指标和 JMeter 之间的延迟值不一致
- php - 获取类别中显示的所有产品的 WooCommerce 产品条款