如何将第 9 扇区复制到第 1 扇区?

How to copy 9th sector to 1st sector?

我正在创建自定义 mbr,类似于 mbr-lovenote and i can't create code that will copy 9th sector - (there is located original mbr) to 1st sector, i already tried take some code from mbr-lovenote 并修改它,但我发现该代码仅加载内存中的扇区并跳转到它,但我必须复制它。我写我的代码,代码将从 PhysicalDrive0 上的第一个扇区加载,但我不知道为什么它不起作用。

;---create buffer
buffer db 512

;---read sector - 9th
mov ax, buffer              ;ES: BX must point to the buffer
mov es, ax                  ;
mov bx, buffer              ;
mov dl,0                    ;drive number
mov dh,0                    ;head number
mov ch,0                    ;track number
mov cl,9                    ;sector number 
mov al,1                    ;number of sectors to read
mov ah,2                    ;read function number
int 13h

;---write sector - 1th
mov ax, buffer              ;ES: BX must point to the buffer
mov es, ax                  ;
mov bx, buffer              ;
mov dl,0                    ;drive number
mov dh,0                    ;head number
mov ch,0                    ;track number
mov cl,1                    ;sector number
mov al,1                    ;number of sectors to write
mov ah,3                    ;write function number
int 13h

;---fake signature
times 510 - ($-$$) db 0
dw        0xaa55

您没有提供最小的完整示例,并且有迹象表明您可能不知道实模式 20-bit segment:offset addressing 是如何工作的。实模式下的每个内存位置都由一个 16 位段和一个 16 位偏移量组成。两者结合使用以下公式计算 20 位物理地址:PhysicalAddress = (Segment<<4)+Offset。左移4等于乘以16

引导加载程序加载到内存中的物理地址 0x07c00。您必须选择一个 ORG 并在引导加载程序中设置段,以便它们引用物理地址 0x07c00。一个以上的20位segment:offset地址可以指向同一个物理地址。引导加载程序的 2 个常见的是使用 ORG 0x7c00 段设置为 0x0000 ((0x0000<<4)+0x7c00=0x07c00),或使用 ORG 0x0000 和一段 0x07c0 ((0x07c0<<4 )+0x0000=0x07c00)).

我在这个 . If you are potentially writing your bootloader to run on a USB drive in FDD mode you will also want to read my 中有一些关于使用表示软盘的 BIOS 数据区 (BDA) 的一般引导加载程序提示。

此示例是一个简单的引导加载程序,带有基于您的代码的 BDA,用于将扇区 9 复制到扇区 1 (MBR),然后使用 int 0x19 重新启动。该代码还使用内存中引导加载程序之后的内存(@ 0x0000:0x7e00)作为临时存储来执行扇区复制。我还提供了一个测试引导加载程序,它被放置在扇区 9 中,当 运行ning 时显示一条消息。

boot.asm:

org 0x7c00
bits 16

boot:
    jmp main
    TIMES 3-($-$$) DB 0x90   ; Support 2 or 3 byte encoded JMPs before BPB.

    ; Use a BIOS Parameter Block if you intend to use this on USB in FDD mode

    ; Dos 4.0 EBPB 1.44MB floppy
    OEMname:           db    "mkfs.fat"  ; mkfs.fat is what OEMname mkdosfs uses
    bytesPerSector:    dw    512
    sectPerCluster:    db    1
    reservedSectors:   dw    1
    numFAT:            db    2
    numRootDirEntries: dw    224
    numSectors:        dw    2880
    mediaType:         db    0xf0
    numFATsectors:     dw    9
    sectorsPerTrack:   dw    18
    numHeads:          dw    2
    numHiddenSectors:  dd    0
    numSectorsHuge:    dd    0
    driveNum:          db    0
    reserved:          db    0
    signature:         db    0x29
    volumeID:          dd    0x2d7e5a1a
    volumeLabel:       db    "NO NAME    "
    fileSysType:       db    "FAT12   "

main:
    ; BIOS passes our boot drive number in DL

    ; Setup segments
    xor ax, ax                  ; AX=0
    mov ds, ax                  ; DS=ES=0 because we use an org of 0x7c00
                                ;    segment<<4+offset = 0x0000<<4+0x7c00 = 0x07c00
    mov es, ax
    mov ss, ax
    mov sp, 0x7c00              ; SS:SP= 0x0000:0x7c00 stack just below bootloader

    ;---read sector - 9th
    mov bx, buffer              ; ES: BX point to buffer (ES set to zero previously)
;    mov dl,0                   ; use boot drive passed to bootloader by BIOS in DL
    mov dh,0                    ; head number
    mov ch,0                    ; track number
    mov cl,9                    ; sector number
    mov al,1                    ; number of sectors to read
    mov ah,2                    ; read function number
    int 13h

    ;---write sector - 1th

; The following commented lines aren't required. Int AH=13h/AH=2 only
; destroys AX and the following registers remain unchanged from the
; read disk BIOS call

;    mov bx, buffer              ; ES: BX must point to the buffer
;    mov dl,0                    ; use boot drive passed to bootloader by BIOS in DL
;    mov dh,0                    ; head number
;    mov ch,0                    ; track number

    mov cl,1                    ; sector number
    mov al,1                    ; number of sectors to write
    mov ah,3                    ; write function number
    int 13h


    mov si, message
    call print_string           ; Print a banner to the console

    int 19h                     ; Warm reboot, should run bootloader that was in sector 9

; Function: print_string
;           Display a string to the console on display page 0
;
; Inputs:   SI = Offset of address to print
; Clobbers: AX, BX, SI

print_string:               ; Routine: output string in SI to screen
    mov ah, 0eh             ; BIOS tty Print
    xor bx, bx              ; Set display page to 0 (BL)
    jmp .getch
.repeat:
    int 10h                 ; print character
.getch:
    lodsb                   ; Get character from string
    test al,al              ; Have we reached end of string?
    jnz .repeat             ;     if not process next character
.end:
    ret

message: db "Running original bootloader...", 0x0a, 0x0d, 0

times 510 - ($-$$) db 0
dw        0xaa55               ; Boot signature

; This buffer is right after the bootloader and will be at offset 0x7e00.
; 0x0000:0x7e00 is the memory location starting right after the 512 byte
; bootloader loaded into memory by the BIOS
buffer:

sector9.asm:

org 0x7c00
bits 16

boot:
    jmp main
    TIMES 3-($-$$) DB 0x90   ; Support 2 or 3 byte encoded JMPs before BPB.

    ; Use a BIOS Parameter Block if you intend to use this on USB in FDD mode

    ; Dos 4.0 EBPB 1.44MB floppy
    OEMname:           db    "mkfs.fat"  ; mkfs.fat is what OEMname mkdosfs uses
    bytesPerSector:    dw    512
    sectPerCluster:    db    1
    reservedSectors:   dw    1
    numFAT:            db    2
    numRootDirEntries: dw    224
    numSectors:        dw    2880
    mediaType:         db    0xf0
    numFATsectors:     dw    9
    sectorsPerTrack:   dw    18
    numHeads:          dw    2
    numHiddenSectors:  dd    0
    numSectorsHuge:    dd    0
    driveNum:          db    0
    reserved:          db    0
    signature:         db    0x29
    volumeID:          dd    0x2d7e5a1a
    volumeLabel:       db    "NO NAME    "
    fileSysType:       db    "FAT12   "

main:
    ; Setup segments
    xor ax, ax                  ; AX=0
    mov ds, ax                  ; DS=ES=0 because we use an org of 0x7c00
                                ;    segment<<4+offset = 0x0000<<4+0x7c00 = 0x07c00
    mov ss, ax
    mov sp, 0x7c00              ; SS:SP= 0x0000:0x7c00 stack just below bootloader

    mov si, message
    call print_string           ; Print a banner to the console

    cli
.endloop:                       ; Infinite loop to end bootloader
    hlt
    jmp .endloop

; Function: print_string
;           Display a string to the console on display page 0
;
; Inputs:   SI = Offset of address to print
; Clobbers: AX, BX, SI

print_string:               ; Routine: output string in SI to screen
    mov ah, 0eh             ; BIOS tty Print
    xor bx, bx              ; Set display page to 0 (BL)
    jmp .getch
.repeat:
    int 10h                 ; print character
.getch:
    lodsb                   ; Get character from string
    test al,al              ; Have we reached end of string?
    jnz .repeat             ;     if not process next character
.end:
    ret

message: db "Running sector 9 bootloader...", 0x0a, 0x0d, 0

times 510 - ($-$$) db 0
dw        0xaa55               ; boot signature

要构建 1.44MiB 软盘映像并将主引导加载程序放置在扇区 1 中,将辅助引导加载程序放置在扇区 9 中,如果您 运行 在具有 dd命令:

nasm -f bin boot.asm -o boot.bin
nasm -f bin sector9.asm -o sector9.bin

dd if=/dev/zero of=disk.img bs=1024 count=1440
dd if=boot.bin of=disk.img conv=notrunc seek=0
dd if=sector9.bin of=disk.img conv=notrunc seek=8

您可以使用 QEMU 运行 此代码使用:

qemu-system-i386 -fda disk.img

如果你 运行 在模拟器或像 QEMU 这样的虚拟机中,它应该显示如下内容:

发生的事情是扇区 9 被 boot.bin 中的原始引导加载程序复制到扇区 1,然后机器重新启动。重新启动后,运行 sector9.bin 中的引导加载程序代码已从扇区 9 复制到 MBR。它应该打印:

Running original bootloader...

稍后应该打印:

Running sector 9 bootloader...


注意:您需要确保您的磁盘没有写保护,并且您使用的任何 BIOS 都没有使用 MBR 安全性MBR 安全性 防止 BIOS 调用覆盖引导驱动器上的 MBR(扇区 1)。

OP (@WobbyChip) 在他们的问题的更新中写了这个解决方案。


SectorCopy.asm -> 感谢 Michael Petch --->使用此代码复制扇区。

org 0x7c00
bits 16

SectorCopy: 
    ; Setup segments
    xor ax, ax                  ; AX=0
    mov ds, ax                  ; DS=ES=0 because we use an org of 0x7c00 - Segment<<4+offset = 0x0000<<4+0x7c00 = 0x07c00
    mov es, ax
    mov ss, ax
    mov sp, 0x7c00              ; SS:SP= 0x0000:0x7c00 stack just below bootloader

    ;---read sector - 9th
    mov bx, buffer              ; ES: BX must point to the buffer
;   mov dl,0                    ; use boot drive passed to bootloader by BIOS in DL
    mov dh,0                    ; head number
    mov ch,0                    ; track number
    mov cl,9                    ; sector number - (9th)
    mov al,1                    ; number of sectors to read
    mov ah,2                    ; read function number
    int 13h

    ;---write sector - 1th
    mov bx, buffer              ; ES: BX must point to the buffer
;   mov dl,0                    ; use boot drive passed to bootloader by BIOS in DL
    mov dh,0                    ; head number
    mov ch,0                    ; track number
    mov cl,1                    ; sector number - (1th)
    mov al,1                    ; number of sectors to write
    mov ah,3                    ; write function number
    int 13h

times 510 - ($-$$) db 0
dw        0xaa55                ; Boot signature

buffer: