I was trying to write my own bootloader on fasm assembly, but unsucces.
Result: Prefetch: EIP 00010000 > CS.limit 0000ffff
Code:
org 0x7C00
mov ax, 0x02
int 0x10
mov si, boot_msg
call printf
mov al, 0x01 ; secror to read
mov bx, 0x7E00 ; dest
mov cx, 0x0002 ; cylinder:sector
mov dl, 0x01 ; floppy
call disk_read
mov ax, 0x7E00
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x7E00:0x0000
include 'disk.asm'
include 'printh.asm'
boot_msg db 'R-OS BOOTLOADER
',\
'KERNEL CHS 0 0 1', 0x00
times 510-$ $$ db 0x00
dw 0xAA55
;;;;;;;;; kernel! ;;;;;;;;;;
org 0x7E00
mov ah, 0x0E
mov al, 'X'
int 0x10
cli hlt
times 4096-512-$ $$ db 0x00
disk.asm:
disk_read:
pusha
mov si, 0x02
.top:
mov ah, 0x02
int 0x13
jnc .end
xor ah, ah
int 0x13
jnc .top
jc .err
.end:
popa
ret
.msg db 'disk rw err', 0x00
.err:
popa
pusha
mov ah, 0x0E
mov si, .msg
jmp .l
.l:
lodsb
cmp al, 0x00
je .end
int 0x10
printh.asm just have print functions.
I cant understand, why it is doesn't work. I was trying a lot of variants of solve, but not one working in this list.
please, help
CodePudding user response:
To successfully use the BIOS.ReadSectors function 02h, you need to setup all its parameters! You didn't initialize the ES
segment register, nor did you specify the head number in the DH
register. Presumably you think that all registers start out with zero, but this is not the case! The only register that your bootloader receives is the DL
register that holds the number for the boot drive. That will be the number that you need to provide to this function.
You are loading the additional sector at offset address 0x7E00. Because ES=0
(assuming), this is segmented address 0x0000:0x7E00. You can jmp
to this address in a number of ways, but if you want to do it with a zero offset, then the segment part will have to be 0x07E0. That's how segmentation works.
You can read more about bootloaders in my answer at (https://stackoverflow.com/questions/34216893/disk-read-error-while-loading-sectors-into-memory/34382681?r=SearchResults&s=21|9.2814#34382681) and in Michael Petch's answer at (https://stackoverflow.com/questions/32701854/boot-loader-doesnt-jump-to-kernel-code/32705076?r=SearchResults&s=46|10.4269#32705076).
This is an improved version:
ORG 0x7C00
xor ax, ax ; Setup segment registers in accordance with the `ORG 0x7C00`
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
cld ; Once at the top of every program
mov ax, 0x0003
int 0x10
mov si, boot_msg
call printf
mov al, 1 ; Number of sectors to read
mov bx, 0x7E00 ; ES:BX
mov cx, 0x0002 ; Cylinder, Sector
mov dh, 0 ; Head, DL is bootdrive
call disk_read
mov ax, 0x07E0 ; How segmentation works!
mov ds, ax
mov es, ax
jmp 0x07E0:0x0000
include 'disk.asm'
include 'printh.asm'
boot_msg db 'R-OS BOOTLOADER
',\
'KERNEL CHS 0 0 1', 0
times 510-($-$$) db 0
dw 0xAA55
;;;;;;;;; kernel! ;;;;;;;;;;
ORG 0x7E00
mov bh, 0 ; Don't forget to mention the DisplayPage
mov ah, 0x0E
mov al, 'X'
int 0x10
cli
hlt
jmp $-2
times 4096-512-($-$$) db 0
In the disk.asm file, you are trying to implement a retry count, but you forget to actually decrement the counter if an error occured.
Also if you display an error message here, it's kinda fatal, so make the code halt.
Again an improved version:
disk_read:
pusha
mov si, 5 ; Retry count
.top:
mov ah, 0x02
int 0x13
jnc .OK
mov ah, 0x00
int 0x13
dec si
jnz .top ; More tries
jmp .fatal
.OK:
popa
ret
.msg db 'disk rw err', 0
.fatal:
mov bh, 0 ; Don't forget to mention the DisplayPage
mov ah, 0x0E
mov si, .msg
lodsb
.next:
int 0x10
lodsb
cmp al, 0
jne .next
cli
hlt
jmp $-2
printh.asm just have print functions.
It is important to include as much information as possible! In my above improved code I assumed that printf does not destroy the DL
register.
Please make sure it preserves at least DX
.
If you would have included the code in the printh.asm file, I would have verified this already for you...