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

时间:2018-07-20 05:38:45

标签: assembly x86 nasm x86-16 bootloader

我正在创建自定义mbr,类似mbr-lovenote,但是我无法创建将复制第9个扇区的代码 -(位于原始mbr) 到第一扇区,我已经尝试从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

2 个答案:

答案 0 :(得分:2)

您没有提供一个完整的示例,有迹象表明您可能不知道实模式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))。

在此Stackoverflow answer中,我有一些常规的引导程序提示。如果您可能正在编写引导加载程序以在FDD模式下的USB驱动器上运行,则您还需要阅读我的Stackoverflow answer,有关使用代表软盘的BIOS数据区(BDA)。

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

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)中运行此程序,则应显示以下内容:

enter image description here

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

  

正在运行原始的引导程序...

然后应打印:

  

正在运行扇区9引导加载程序...


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

答案 1 :(得分:0)

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: