@onlyonemac: I was confused too, until I noticed that the code is setting ES, via BX, and then clearing BX. IOW, it's not not writing to 0000:7c00 (computed absolute address 7c00 hex, or 31,774 decimal), where the BIOS loads the boot sector) but to 7c00:0000 (computed absolute address 7c000, or 507,904 decimal) - which is a much higher, being about 5/6ths of the way towards the top of base RAM memory according to the
Memory Map.
You're point about it overwriting the first loaded sector is correct. However, in this instance, the OP would probably use something closer to this, assuming that ES and BX are not clobbered by the BIOS:
Code: Select all
add bx, 0x10 ; advance the load location by 512 bytes
int 0x13
@stevewoods1986: In my own
VERBUM boot sector demonstrator, I use an approach similar to the one onlyonemac used (as shown above), but I also used some NASM assembler macros to ease the process of calling some routines (though not the one for reading from disk), EQUates to give names to important constants, and memory variables to hold the values rather than hard-coding them.
equates:
Code: Select all
;;constants
;
%define boot_base 0x0000 ; the segment:offset pair for the
%define boot_offset 0x7C00 ; boot code entrypoint
stage2_base equ 0x1000 ; the segment:offset to load
stage2_offset equ 0x0000 ; the second stage into
stack_seg equ 0x9000
stack_top equ 0xFFFC
VBIOS equ 0x10 ; BIOS interrupt vector for video services
GOTO_XY equ 0x02 ; VBIOS routine - go to the given x, y coordinates
block_write equ 0x09 ; VBIOS routine - write a fixed number of times to the screen
ttype equ 0x0E ; VBIOS routine - print character, teletype mode
DBIOS equ 0x13 ; BIOS interrupt vector for disk services
disk_reset equ 0x00 ; disk reset service
disk_read equ 0x02 ; disk read service
; BIOS error codes
reset_failure equ 0x01 ; error code returned on disk reset failure
read_failure equ 0x02 ; error code returned on disk read failure
; operational constants
tries equ 0x03 ; number of times to attempt to access the FDD
macros:
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; macros
;
%define zero(x) xor x, x
%macro write 1
mov si, %1
call printstr
%endmacro
data section (which I put below the code):
Code: Select all
[section data]
loading db 'Loading stage two... ', NULL
done db 'done.', CR, LF, NULL
snd_stage db 'Second stage loaded, proceeding to switch context.', CR, LF, NULL
returned db 'Control returned to first stage, ', NULL
reset_failed db 'Could not reset drive,', NULL
read_failed db 'Could not read second stage, ', NULL
exit db ' system halted.', NULL
bootdrv resb 1 ; byte reserved for boot drive ID number
; DBIOS arguments, values given are defaults
cyl db 0 ; cylinder to read from
head db 0 ; head to read from
startsector db 2 ; sector to start reading at
numsectors db 1 ; number of sectors to read
disk reset and read functions
Code: Select all
; reset_disk
reset_disk:
mov dl, [bootdrv]
mov ah, disk_reset
int DBIOS
ret
; read_disk
read_disk:
mov cx, tries ; set count of attempts for disk reads
.try_read:
push cx
mov cx, tries ; set count of attempts to reset disk
.try_reset:
call reset_disk
jnc short .read
loop .try_reset ; if the reset fails, try up to three times
mov ax, reset_failure ; if all three fail, set an error code and return
pop cx ; make sure that the stack is correctly aligned
jmp short .end_fail
.read:
mov ax, stage2_base
mov es, ax
mov dl, [bootdrv]
mov ch, [cyl] ; cylinder
mov dh, [head] ; head
mov cl, [startsector] ; first sector
mov al, [numsectors] ; number of sectors to load
mov ah, disk_read
mov bx, stage2_offset
int DBIOS
jnc short .end_success
pop cx
loop .try_read
mov ax, read_failure ; if attempts to read the disk fail, report error code
jmp short .end_fail
.end_success:
pop cx ; make sure that the stack is correctly aligned
zero(ax)
.end_fail:
ret
The part of the actual loader that calls this is:
Code: Select all
mov [bootdrv], dl ; save boot drive info for later use
; read in the data from disk and load it to ES:BX (already initialized)
write loading
call read_disk
cmp ax, reset_failure
jne good_reset
write reset_failed
jmp short shutdown
The point is that just because you are using assembly doesn't mean you have to throw good coding practices out the window. In this case, I probably should re-write this to use parameters for those arguments, as onlyonemac did, rather than hard-coding in the addresses, but one thing at a time.