WobbyChip
WobbyChip

Reputation: 87

How to copy 9th sector to 1st sector?

I'm creating custom mbr, something like 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 and modify it, but i find out that code only load sector in memory and jump to it, but i have to copy it. I write my code, the code will be loaded from fist sector on PhysicalDrive0, but i don't know why it doesn't works.

;---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

Upvotes: 2

Views: 281

Answers (2)

Michael Petch
Michael Petch

Reputation: 47573

The OP (@WobbyChip) wrote this solution in an update to their question.


SectorCopy.asm -> Thanks to Michael Petch ---> Use this code to copy sectors.

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:

Upvotes: 0

Michael Petch
Michael Petch

Reputation: 47573

You don't provide a minimal complete example and there are indications you may not know how real mode 20-bit segment:offset addressing works. Every memory location in real mode is made up of a 16-bit segment and a 16-bit offset. Both are combined to compute a 20-bit physical address with the formula: PhysicalAddress = (Segment<<4)+Offset. Shifting left by 4 is the same as multiplying by 16.

A bootloader is loaded at physical address 0x07c00 in memory. You have to choose an ORG and set the segments in your bootloader so that they reference physical address 0x07c00. More than one 20-bit segment:offset address can point to the same physical address. The 2 common ones for bootloaders are using an ORG 0x7c00 with segments set to 0x0000 ((0x0000<<4)+0x7c00=0x07c00), or usingORG 0x0000 and a segment of 0x07c0 ((0x07c0<<4)+0x0000=0x07c00)).

I have some general bootloader tips in this Stackoverflow answer. If you are potentially writing your bootloader to run on a USB drive in FDD mode you will also want to read my Stackoverflow answer about using a BIOS Data Area (BDA) representing a floppy.

This example is a simple bootloader with a BDA based on your code to copy sector 9 onto sector 1 (MBR) and then reboots with int 0x19. The code also uses the memory right after the bootloader in memory (@ 0x0000:0x7e00) for temporary storage to do the sector copy. I also provide a test bootloader that is placed into sector 9 that displays a message when it is running.

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

To build a 1.44MiB floppy image and place the primary bootloader at sector 1 and the secondary bootloader in sector 9 you could use commands like this if you are running on a system that has the dd command:

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

You can use QEMU to run this code using:

qemu-system-i386 -fda disk.img

If you run this in an emulator or virtual machine like QEMU it should display something like:

enter image description here

What has happened is that sector 9 was copied to sector 1 by the original bootloader in boot.bin and then the machine rebooted. Upon reboot it ran the bootloader code in sector9.bin that was copied from sector 9 to the MBR. It should print:

Running original bootloader...

And at a later time should print:

Running sector 9 bootloader...


Note: you will need to make sure that your disk is not write protected and that any BIOS you are using isn't using MBR security. MBR security prevent BIOS calls from overwriting the MBR (sector 1) on the boot drive.

Upvotes: 2

Related Questions