assembly 程序集 Boot 扇区在VirtualBox上工作,但在真实的硬件上不工作[重复]

p5fdfcr1  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(111)

此问题在此处已有答案

Boot loader doesn't jump to kernel code(1个答案)
Custom bootloader booted via USB drive produces incorrect output on some computers(2个答案)
24天前关闭。
我正在尝试用汇编语言编写一个简单的引导程序。我正在尝试打印一些字符串,然后等待按键。这是我的代码:

[org 0x7c00]
mov al, 0
mov ah, 0
mov ax, 0
mov bx, 0
mov bp , 0x8000 ; Set the base of the stack a little above where BIOS
mov sp , bp ; loads our boot sector - so it won ’t overwrite us.
jmp main
message:
    db 0x0a,0x0d,'Enderbyte Programs',0x0a,0x0d,0
bmessage:
    db 0x0a,0x0d,'Booting...',0x0a,0x0d,0
cmessage:
    db 0x0a,0x0d,'Just kidding this does nothing ',0
kmessage:
    db 'Or does it?',0
print_string:
    mov al, [bx]
    inc bx
    cmp al, 0 
    jne print_char
    mov bx, 0
    ret
print_char: 
    int 0x10; Print AL register
    jmp print_string
main:
    mov ah, 0x0e ; int 10/ ah = 0 eh -> scrolling teletype BIOS routine
    mov bx, message
    call print_string
    mov bx, bmessage
    call print_string
    mov bx, cmessage,
    call print_string
    mov ah, 00h
    int 16h; Wait for keypress?
    mov ah, 0x0e
    mov bx, kmessage
    call print_string
    ;jmp $

这段代码在VirtualBox上运行得很好,但是当我尝试在PC上运行它时(通过将其复制到闪存驱动器中并从其启动),发生了非常奇怪的事情。光标移动到屏幕的右下角区域,并打印出一个奇怪的字符(一个O,但是在NE角有一个箭头)。按下一个键会导致它清除屏幕,光标在打印出另一个字符之前跳来跳去。这是怎么回事?
我已经试着遵循Assembly boot loader working on virtual PC, not on real PC中的建议(将所有寄存器设置为零,验证堆栈),但它在真实的硬件上仍然不起作用。(在Virtualbox上仍然工作正常)。

B0 00 B4 00 B8 00 00 BB 00 00 BD 00 80 89 EC EB
63 0A 0D 45 6E 64 65 72 62 79 74 65 20 50 72 6F
67 72 61 6D 73 0A 0D 00 0A 0D 42 6F 6F 74 69 6E
67 2E 2E 2E 0A 0D 00 0A 0D 4A 75 73 74 20 6B 69
64 64 69 6E 67 20 74 68 69 73 20 64 6F 65 73 20
6E 6F 74 68 69 6E 67 20 00 4F 72 20 64 6F 65 73
20 69 74 3F 00 8A 07 43 3C 00 75 04 BB 00 00 C3
CD 10 EB F1 B4 0E BB 11 7C E8 E9 FF BB 28 7C E8
E3 FF BB 37 7C E8 DD FF B4 00 CD 16 B4 0E BB 59
7C E8 D1 FF 25 00 00 00 00 00 00 00 00 00 00 00
*
00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA
6ie5vjzr

6ie5vjzr1#

你应该做一个更好的设置,也许是一个有效的MBR。你不能假设BIOS为你设置了段和寄存器。你必须从一开始就初始化最重要的东西。也许可以尝试这样的东西:
此代码假定您的print_string工作正常。

[ORG 0x7c00]
[BITS 16]

global boot

boot:
    jmp _start
    nop

    ; Here is a example BPB
    OEMname:           db    "mkfs.fat"  
    bytesPerSector:    dw    512
    sectPerCluster:    db    0
    reservedSectors:   dw    0
    numFAT:            db    0
    numRootDirEntries: dw    0
    numSectors:        dw    0
    mediaType:         db    0
    numFATsectors:     dw    0
    sectorsPerTrack:   dw    0
    numHeads:          dw    0
    numHiddenSectors:  dd    0
    numSectorsHuge:    dd    0
    driveNum:          db    0
    reserved:          db    0
    signature:         db    0
    volumeID:          dd    0
    volumeLabel:       db    "NO NAME    "
    fileSysType:       db    "FAT12   "

_start:
    cli
    xor ax, ax ; clear your segments
    mov es, ax
    mov ds, ax

    jmp 0x00:main ; clear code segment

main:
    sti
    mov bp , 0x8000 ; Set the base of the stack a little above where BIOS
    mov ss,  ax ; Setup Stack SS (AX=0) followed immediately by SP
    mov sp , bp 

    mov ah, 0x0e ; int 10/ ah = 0 eh -> scrolling teletype BIOS routine
    mov bx, message
    call print_string
    mov bx, bmessage
    call print_string
    mov bx, cmessage,
    call print_string
    mov ah, 00h
    int 16h; Wait for keypress?
    mov ah, 0x0e

    jmp $

print_string:
    mov al, [bx]
    inc bx
    cmp al, 0 
    jne print_char
    mov bx, 0
    ret
print_char: 
    int 0x10; Print AL register
    jmp print_string

message:
    db 0x0a,0x0d,"Enderbyte Programs",0x0a,0x0d,0
bmessage:
    db 0x0a,0x0d,"Booting...",0x0a,0x0d,0
cmessage:
    db 0x0a,0x0d,"Just kidding this does nothing ",0
kmessage:
    db "Or does it?",0

times 446 - ($ - $$) db 0x00 ; Padding to 512 bytes

; Partitions table for a MBR

partition_table_1:
    db 0x80 ; Status, 0x80 means active
    db 0x00 ; First Absolute Sector CHS
    db 0x00 ; 
    db 0x00 ;  
    db 0x00 ; Partition Type
    db 0x00 ; Last Absolute Sector CHS
    db 0x00 ; 
    db 0x00 ; 
    dd 0x00000001 ; First Absolute Sector LBA
    dd 0x00000200 ; Number of Sectors
    
partition_table_2:
    db 0x00 ; Status, 0x80 means active
    db 0x00 ; First Absolute Sector CHS
    db 0x00 ; 
    db 0x00 ;  
    db 0x00 ; Partition Type
    db 0x00 ; Last Absolute Sector CHS
    db 0x00 ; 
    db 0x00 ; 
    dd 0x00000000 ; First Absolute Sector LBA
    dd 0x00000000 ; Number of Sectors
    
partition_table_3:
    db 0x00 ; Status, 0x80 means active
    db 0x00 ; First Absolute Sector CHS
    db 0x00 ; 
    db 0x00 ;  
    db 0x00 ; Partition Type
    db 0x00 ; Last Absolute Sector CHS
    db 0x00 ; 
    db 0x00 ; 
    dd 0x00000000 ; First Absolute Sector LBA
    dd 0x00000000 ; Number of Sectors
    
partition_table_4:
    db 0x00 ; Status, 0x80 means active
    db 0x00 ; First Absolute Sector CHS
    db 0x00 ; 
    db 0x00 ;  
    db 0x00 ; Partition Type
    db 0x00 ; Last Absolute Sector CHS
    db 0x00 ; 
    db 0x00 ; 
    dd 0x00000000 ; First Absolute Sector LBA
    dd 0x00000000 ; Number of Sectors

dw 0xAA55 ; Boot signature required to boot

首先,我们清除了代码段,以确保BIOS不会给予我们垃圾值,这将导致以后的麻烦。我们还清除了代码段,以确保我们在地址0x 0000:0x 7 c 00,而不是它的等价物,如0x 07 c 0:0x 0000。我格式化了代码,并将数据向下移动,以便您可以更容易地操作它们。您的代码还缺少填充和签名,这是添加的。我还添加了一些MBR分区表,以防您从硬盘或等效系统启动。您还可以添加一个BPB,您可以在这里找到它的结构:
https://wiki.osdev.org/FAT#BPB_.28BIOS_Parameter_Block.29
上面的代码可以用

nasm -fbin bootloader.asm -o bootloader.bin

将其写入硬盘/USB/CD或等效设备的第一个扇区。
还可以查看以下内容:
https://wiki.osdev.org/Bootloader
https://wiki.osdev.org/Rolling_Your_Own_Bootloader
https://wiki.osdev.org/MBR_(x86)
编辑:
上面的代码编译无误,并在QEMU上运行。
编辑:
还添加了一个BPB

相关问题