I currently have a basic bootloader setup to load my kernel with some debug statements:
; Set offsets
[ 0x7c00]
KERNEL_OFFSET equ 0x2000
[bits 16]
; Setup Stack
mov bp, 0x1000
mov sp, bp
mov bx, RM_BOOT_MSG
call print_rm
call nl_rm
; Load kernel
mov bx, KERNEL_OFFSET ; Read from disk and store in KERNEL_OFFSET
mov dh, 10 ; Read X sectors
call load_disk
mov bx, KERNEL_LOAD_MSG
call print_rm
call nl_rm
mov bx, KERNEL_OFFSET
call print_rm_hex
call nl_rm
mov bx, [KERNEL_OFFSET]
call print_rm_hex
call nl_rm
mov bh, 0
mov bl, dl
call print_rm_hex
call nl_rm
call KERNEL_OFFSET ; Begin entering kernel
jmp $
%include "boot/disk.asm"
%include "boot/32b_gdt.asm"
RM_BOOT_MSG: dw "16-bit RM", 0
KERNEL_LOAD_MSG: dw "Kernel Successfully Loaded", 0
; Padding
times 510 - ($ - $$) db 0
dw 0xaa55
Here is my load_disk function:
; Disk
; See this for all int 0x13 notes: .html
; AH = 02
; AL = number of sectors to read (1-128 dec.)
; CH = track/cylinder number (0-1023 dec., see below)
; CL = sector number (1-17 dec.)
; DH = head number (0-15 dec.)
; DL = drive number (0=A:, 1=2nd floppy, 80h=drive 0, 81h=drive 1)
; ES:BX = pointer to buffer
; on return:
; AH = status (see INT 13,STATUS)
; AL = number of sectors read
; CF = 0 if successful
; = 1 if error
; Note 0x01 is the boot sector, 0x02 is the first free one
[bits 16]
; Load "dh" sectors for drive "dl" at es:bx
load_disk:
pusha
push dx
mov ah, 0x02
mov al, dh
mov ch, 0x00
mov cl, 0x02
mov dh, 0x00
int 0x13
jc .disk_error
pop dx
cmp al, dh
jne .sector_error
popa
ret
.disk_error:
mov bx, DISK_ERR_MSG
call print_rm
mov dh, ah
call print_rm_hex
call nl_rm
jmp .fail_loop
.sector_error:
mov bx, SECTOR_ERR_MSG
call print_rm
call nl_rm
.fail_loop:
jmp $
DISK_ERR_MSG: dw "Error loading from disk: ", 0
SECTOR_ERR_MSG: dw "Incorrect number of sectors read", 0
%include "boot/print_rm.asm"
When run via
qemu-system-i386 -s -usb -drive format=raw, file=\.\PHYSICALDRIVE2
it works as expected with no errors, specifically outputting
Kernel Successfully Loaded
0x2000 (the Kernel offset)
0xC6BB (what is stored at 0x2000)
0x0080 (the drive)
On real hardware, it outputs instead
Kernel Successfully Loaded
0x2000 (the Kernel offset)
0x519B (what is stored at 0x2000)
0x0080 (the drive)
i.e. it fails to load the correct data, causing call KERNEL_OFFSET
to fail (it may be noted that when call load_disk
is commented out, it still prints 0x519B as the data stored at 0x2000).
Any suggestions on how to resolve this difference between QEMU and real hardware would be greatly appreciated.
I currently have a basic bootloader setup to load my kernel with some debug statements:
; Set offsets
[ 0x7c00]
KERNEL_OFFSET equ 0x2000
[bits 16]
; Setup Stack
mov bp, 0x1000
mov sp, bp
mov bx, RM_BOOT_MSG
call print_rm
call nl_rm
; Load kernel
mov bx, KERNEL_OFFSET ; Read from disk and store in KERNEL_OFFSET
mov dh, 10 ; Read X sectors
call load_disk
mov bx, KERNEL_LOAD_MSG
call print_rm
call nl_rm
mov bx, KERNEL_OFFSET
call print_rm_hex
call nl_rm
mov bx, [KERNEL_OFFSET]
call print_rm_hex
call nl_rm
mov bh, 0
mov bl, dl
call print_rm_hex
call nl_rm
call KERNEL_OFFSET ; Begin entering kernel
jmp $
%include "boot/disk.asm"
%include "boot/32b_gdt.asm"
RM_BOOT_MSG: dw "16-bit RM", 0
KERNEL_LOAD_MSG: dw "Kernel Successfully Loaded", 0
; Padding
times 510 - ($ - $$) db 0
dw 0xaa55
Here is my load_disk function:
; Disk
; See this for all int 0x13 notes: https://stanislavs./helppc/int_13-2.html
; AH = 02
; AL = number of sectors to read (1-128 dec.)
; CH = track/cylinder number (0-1023 dec., see below)
; CL = sector number (1-17 dec.)
; DH = head number (0-15 dec.)
; DL = drive number (0=A:, 1=2nd floppy, 80h=drive 0, 81h=drive 1)
; ES:BX = pointer to buffer
; on return:
; AH = status (see INT 13,STATUS)
; AL = number of sectors read
; CF = 0 if successful
; = 1 if error
; Note 0x01 is the boot sector, 0x02 is the first free one
[bits 16]
; Load "dh" sectors for drive "dl" at es:bx
load_disk:
pusha
push dx
mov ah, 0x02
mov al, dh
mov ch, 0x00
mov cl, 0x02
mov dh, 0x00
int 0x13
jc .disk_error
pop dx
cmp al, dh
jne .sector_error
popa
ret
.disk_error:
mov bx, DISK_ERR_MSG
call print_rm
mov dh, ah
call print_rm_hex
call nl_rm
jmp .fail_loop
.sector_error:
mov bx, SECTOR_ERR_MSG
call print_rm
call nl_rm
.fail_loop:
jmp $
DISK_ERR_MSG: dw "Error loading from disk: ", 0
SECTOR_ERR_MSG: dw "Incorrect number of sectors read", 0
%include "boot/print_rm.asm"
When run via
qemu-system-i386 -s -usb -drive format=raw, file=\.\PHYSICALDRIVE2
it works as expected with no errors, specifically outputting
Kernel Successfully Loaded
0x2000 (the Kernel offset)
0xC6BB (what is stored at 0x2000)
0x0080 (the drive)
On real hardware, it outputs instead
Kernel Successfully Loaded
0x2000 (the Kernel offset)
0x519B (what is stored at 0x2000)
0x0080 (the drive)
i.e. it fails to load the correct data, causing call KERNEL_OFFSET
to fail (it may be noted that when call load_disk
is commented out, it still prints 0x519B as the data stored at 0x2000).
Any suggestions on how to resolve this difference between QEMU and real hardware would be greatly appreciated.
Share Improve this question edited Apr 12 at 22:22 Sep Roland 40k10 gold badges48 silver badges89 bronze badges asked Jan 26 at 23:30 MichaelT572MichaelT572 1902 silver badges12 bronze badges 2- 3 In general one thing is that you assume that the segment registers like DS and ES have zero in them. You really can't rely on the value of any register (except DL with boot drive) being what you want. This also applies to SS:SP. You set SP but SS isn't set. It appears you want to really load the segment registers DS/ES/SS with 0x0000 at the start. THe reason it may work in QEMU is that it happens to set the segment to 0x00 but on real hardware BIOSes that may not be the case. – Michael Petch Commented Jan 26 at 23:36
- 1 You may wish to read my bootloader tips in this answer: stackoverflow/a/32705076/3857942 . If you are booting on real hardware with USB using FDD emulation you could be running into another issue that is also discussed in that answer (item 7) – Michael Petch Commented Jan 26 at 23:38
2 Answers
Reset to default 2- Your current code works under the presumption that the segment registers DS and ES are zero. This might always be the case when running under Qemu, but in many other environments you need to setup the segment registers yourself.
- Your current code also sets up the SP register without making sure that it properly combines with the SS segment register. Once you load the SS register it is important that you load SP in the very next instruction. The architecture makes sure this sequence cannot get interrupted, thereby assuring the SS:SP pair is perfectly valid.
So, and this is different from your self-answer, what you need is:
[ 0x7C00]
KERNEL_OFFSET equ 0x2000
[bits 16]
; Setup stack and segment registers
mov bp, 0x1000
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax ; Keep together, and
mov sp, bp ; in this very order
Do note that once you start including references to the FS and GS segment registers, the computer is supposed to be at least 80386. This immediately entails that a construct like:
mov bh, 0
mov bl, dl
call print_rm_hex
would better be replaced with:
movzx bx, dl
call print_rm_hex
The load_disk function has a further error in:
mov dh, ah
call print_rm_hex
where the input to print_rm_hex really must go to BX, so write:
movzx bx, ah
call print_rm_hex
RM_BOOT_MSG: dw "16-bit RM", 0 KERNEL_LOAD_MSG: dw "Kernel Successfully Loaded", 0 DISK_ERR_MSG: dw "Error loading from disk: ", 0 SECTOR_ERR_MSG: dw "Incorrect number of sectors read", 0
Don't use dw
for your messages (BIOS doesn't deal with unicode). The strings themselves will get stored correctly, but each terminating zero would be wasting an extra byte. A bootsector is restricted to just 512 bytes, so every byte counts.
RM_BOOT_MSG: db "16-bit RM", 0
KERNEL_LOAD_MSG: db "Kernel Successfully Loaded", 0
DISK_ERR_MSG: db "Error loading from disk: ", 0
SECTOR_ERR_MSG: db "Incorrect number of sectors read", 0
As noted by Michael Petch, this is resolved by ensuring relevant segment registers are set to 0
mov ax, 0
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745318392a4622326.html
评论列表(0条)