Reputation: 87
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
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
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:
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