Page 1 of 3
Bootloaderis not consistent when booting in real hardware
Posted: Sat Jun 12, 2021 4:21 pm
by liwinux
Hi, i'm facing an issue that I can't really fix and it drives me nuts !
Basically, I have two computers, one a little bit older but it as still a 64 bits CPU and a modern one which also run on a 64 bit CPU. The problem is that on the older one, I can successfully read my boot sectors but on the modern one, it does not even print one of the first strings. Instead it print some garbage things all around the screen for like 2 seconds and then hangs.. I have the csm enabled in bios settings (in order to boot on my usb stick). Can someone help me ?
Bootloader.asm
Code: Select all
[org 0x7c00]
[bits 16]
section .text
global BOOTSECT
BOOTSECT:
; Making sure to reset every segment before loading.
; Because some BIOS tend to modify those..
cli
xor ax, ax
mov ss, ax
mov ds, ax
mov es, ax
cld
sti
; Changing the bios background color to the default black one...
mov ah, 0x0b ;Function Code
mov bh, 0x00 ; Function parameter
mov bl, 0x00 ;Background color
int 0x10
mov bx, MSG_START
call print
mov bx, MSG_READING
call print
mov al, 1
mov cl, 2
mov bx, 0x1000
call readSector
; Changing the bios background color if success (GREEN)
mov ah, 0x0b ;Function Code
mov bh, 0x00 ; Function parameter
mov bl, 0x08 ;Background color
int 0x10
mov bx, MSG_SUCCESS_DISK
call print
jmp $
%include "print.asm"
%include "readSector.asm"
MSG_START: db "[INFO] Starting in 16-bit Real Mode !",13 ,10 ,0
MSG_READING: db "[INFO] Reading Sectors...",13 ,10 ,0
MSG_ERROR_DISK: db "[ERROR] Error Loading Disk !", 13 ,10 ,0
MSG_SUCCESS_DISK: db "[SUCCESS] Loading Disk Into Memory Succeded !", 13 ,10 ,0
times 510-($-$$) db 0
dw 0xaa55
times 512 db 0
readSector.asm
Code: Select all
readSector:
pusha
mov ah, 0x02
mov ch, 0
mov dh, 0
int 0x13
jc disk_error
popa
ret
disk_error:
; Changing the bios background color FAIL (RED)...
mov ah, 0x0b ;Function Code
mov bh, 0x00 ; Function parameter
mov bl, 0x04 ;Background color
int 0x10
mov bx, MSG_ERROR_DISK
call print
jmp $
print.asm
Code: Select all
print:
pusha
printloop:
mov ah, 0x0e
mov al, [bx]
cmp al, 0
je done
int 0x10
inc bx
jmp printloop
done:
popa
ret
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sat Jun 12, 2021 7:29 pm
by Octocontrabass
Are you perhaps using a USB flash drive? Firmware gets picky if you don't have either a MBR with a valid partition table and one active partition, or a FAT VBR with a valid BPB. The firmware might be trying to "correct" the geometry in your BPB, but since those bytes are part of your code instead of a BPB, it ends up corrupting your code.
I also found a bug:
You set SS but not SP. Where is your stack? You don't know! If your stack is somewhere it shouldn't be, that could also corrupt your code and result in strange behavior.
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sun Jun 13, 2021 3:55 am
by liwinux
Octocontrabass wrote:Are you perhaps using a USB flash drive? Firmware gets picky if you don't have either a MBR with a valid partition table and one active partition, or a FAT VBR with a valid BPB. The firmware might be trying to "correct" the geometry in your BPB, but since those bytes are part of your code instead of a BPB, it ends up corrupting your code.
I also found a bug:
You set SS but not SP. Where is your stack? You don't know! If your stack is somewhere it shouldn't be, that could also corrupt your code and result in strange behavior.
HI, thanks for taking the time to answer my question !
Correct me if I'm wrong but isn't the instruction
[org 0x7c00] supposed to align the addresses ? So if I understood correctly, the stack would begin at the address
0x7c00 and that can cause the issue then right ?
Also, I don't get the part where you talk about the MBR, what am I supposed to do then ? How can I be sure that it will always boot ? I also should have pointed out before posting that I've made two bootable usb drives just to be sure and I got the same result.
Thanks again !
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sun Jun 13, 2021 4:31 am
by nexos
In theory, the BIOS only depends on the last two bytes of a 512 byte bootsector to be 0xAA55. Many BIOSes, however, require an MBR and/or a partition table to load. Lookup Master Boot Record strucutre and partition table structure. It is a structure that takes the first bytes of a bootsector. Also, stack issues could very well be a problem as well. Many BIOSes are really quirky, so don't be surprised by anything in a boot sector.
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sun Jun 13, 2021 8:53 am
by bzt
liwinux wrote:The problem is that on the older one, I can successfully read my boot sectors but on the modern one, it does not even print one of the first strings. Instead it print some garbage things all around the screen for like 2 seconds and then hangs.. I have the csm enabled in bios settings (in order to boot on my usb stick). Can someone help me ?
It is a wonder that you can read sectors with floppy services from an device. My guess is, your newer machine does not support floppies and CHS addressing any more, so you'll have to use LBA addressing and
Int 13/AH=42h. That always worked on all legacy CSM emulations I've run into.
Other than that, you don't set up a stack, so god knows what's going to happen on the first "call" instruction. You set "ss", but not the pointer, "sp", as Octocontrabass said. Aligning the address only means that your Assembler will produce code in compile-time expecting to be ran on that address, but this has nothing to do with setting up registers in run-time.
About the partitioning table and such: don't care. It only happens on some buggy BIOSes when they are in some kind of strange emulation mode. Your BIOS reads the boot sector, so don't mind that all. The magic bytes should be enough, and they are on both of your machines.
Cheers,
bzt
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sun Jun 13, 2021 10:14 am
by Octocontrabass
liwinux wrote:Correct me if I'm wrong but isn't the instruction [org 0x7c00] supposed to align the addresses ? So if I understood correctly, the stack would begin at the address 0x7c00 and that can cause the issue then right ?
No. The org statement only tells the assembler where in memory your code will be loaded, relative to the segment base, so it can translate labels into numeric addresses. You have to set both SS and SP to set the stack location.
liwinux wrote:Also, I don't get the part where you talk about the MBR, what am I supposed to do then ? How can I be sure that it will always boot ?
I recommend adding a
partition table with one active partition.
bzt wrote:It is a wonder that you can read sectors with floppy services from an device.
CHS addressing has been a hard disk service since hard disks were first added to PCs. Have you found any CSMs that don't support CHS addressing?
bzt wrote:About the partitioning table and such: don't care. It only happens on some buggy BIOSes when they are in some kind of strange emulation mode. Your BIOS reads the boot sector, so don't mind that all. The magic bytes should be enough, and they are on both of your machines.
Yes, it boots, but it doesn't work. A BPB or partition table is required to make it work.
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sun Jun 13, 2021 2:02 pm
by liwinux
Hi guys, thanks for all those useful information, really...
I made some little changes as you all suggested me but still no luck... This time, it prints the first string 2X times. Still don't know what's going on here. I've removed every almost everything including the function where I read sectors just to test if at least printing things to the screen works, but as you can see it's still not working... If you could take a look, that would be awesome from you guys. I think i'm missing something here that I can't really understand.
Also, I've made MBR partition, used DD, also used Etcher etc...
Code: Select all
[org 0x7c00]
[bits 16]
section .text
global BOOTSECT
BOOTSECT:
; Making sure to reset every segment before loading.
; Because some BIOS tend to modify those..
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
cld
sti
mov bp , 0x8000
mov sp, bp
mov bx, MSG_START ; This line is printed two times....
call print
jmp $
%include "print.asm"
%include "readSector.asm"
MSG_START: db "[INFO] Starting in 16-bit Real Mode !",13 ,10 ,0
MSG_READING: db "[INFO] Reading Sectors...",13 ,10 ,0
MSG_SUCCESS_DISK: db "[SUCCESS] Loading Disk Into Memory Succeded !", 13 ,10 ,0
times 510-($-$$) db 0
dw 0xaa55
times 512 db 0
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sun Jun 13, 2021 2:13 pm
by rdos
I start my boot sector with a far call so I'm independent on which CS BIOS uses. You only know that the code is loaded at 7C00, not that CS is 0.
Actually, I don't set CS to zero as it is much more convinient to set it to 7C0, because then there is no need to org the code.
Also, you clobber SS by resetting it to zero, and before you load SP with a reasonable value, you enable interrupts. This is not ok. You always must make sure that SS & SP are loaded as a pair without any possibilities for interviening interrupts. The usual way to do this is to load SS first, and then in the next instruction SP. This works since the CPU is designed to run those as atomic.
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sun Jun 13, 2021 3:46 pm
by liwinux
rdos wrote:I start my boot sector with a far call so I'm independent on which CS BIOS uses. You only know that the code is loaded at 7C00, not that CS is 0.
Actually, I don't set CS to zero as it is much more convinient to set it to 7C0, because then there is no need to org the code.
Also, you clobber SS by resetting it to zero, and before you load SP with a reasonable value, you enable interrupts. This is not ok. You always must make sure that SS & SP are loaded as a pair without any possibilities for interviening interrupts. The usual way to do this is to load SS first, and then in the next instruction SP. This works since the CPU is designed to run those as atomic.
So, I've modified once again my code, and it stills fail.
Code: Select all
[org 0x7c00]
[bits 16]
section .text
global BOOTSECT
BOOTSECT:
; Making sure to reset every segment before loading.
; Because some BIOS tend to modify those..
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov bp, 0x8000
mov sp, bp
cld
sti
mov bx, MSG_START ; This line is printed two times....
call print
jmp $
%include "print.asm"
%include "readSector.asm"
MSG_START: db "[INFO] Starting in 16-bit Real Mode !",13 ,10 ,0
MSG_READING: db "[INFO] Reading Sectors...",13 ,10 ,0
MSG_SUCCESS_DISK: db "[SUCCESS] Loading Disk Into Memory Succeded !", 13 ,10 ,0
times 510-($-$$) db 0
dw 0xaa55
times 512 db 0
Now, I'm wondering If it's more like an hardware compatibility issue at this point.
but I thought someone could write a boot loader to test if it works on my machine, that way I would be sure that I'm not doing anything wrong. If it works then most likely I was doing something bad and I could learn from my mistakes.. So could someone do that for me and be sure that it will work ? Just a simple one to test if it prints correctly. It could be written in asm as well in nasm I'll compile it myself.
Thanks again for taking the time to help me with my issue and teaching me new things, really appreciate it you all !
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sun Jun 13, 2021 4:22 pm
by Ethin
How do you know your stack is at 0x8000? (Also, don't set CS to 7C0 -- just set it to 0 unless you want to be dealing with multiple segments.) Does your linker script place the stack at 0x8000?
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sun Jun 13, 2021 4:30 pm
by liwinux
Ethin wrote:How do you know your stack is at 0x8000? (Also, don't set CS to 7C0 -- just set it to 0 unless you want to be dealing with multiple segments.) Does your linker script place the stack at 0x8000?
Well, I don't use any linker script. In fact I just compile it and ask nasm to create a binary file. And also, if I set CS to 0, nothing works in QEMU. So, I just decide to set the stack safely away from 0X7C000
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sun Jun 13, 2021 4:34 pm
by neon
Hi,
Load sp right after setting ss. I.e. there should be no instruction (like your load to bp) in between.
Also as noted above, your first instruction should be jmp 0:fixcs (due to org 7c00) to load cs:ip with known values.
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Sun Jun 13, 2021 5:03 pm
by Octocontrabass
liwinux wrote:Also, I've made MBR partition, used DD, also used Etcher etc...
After creating the partition table on the disk, read it back and see what bytes it contains. If it's not valid or there's no active partition, it won't work. Post it here if you're not sure.
rdos wrote:Actually, I don't set CS to zero as it is much more convinient to set it to 7C0, because then there is no need to org the code.
I disagree. Having nonzero segment bases now will just make things more confusing later.
liwinux wrote:And also, if I set CS to 0, nothing works in QEMU.
The MOV instruction cannot be used to load the CS register. You have to use something like a far JMP if you want to set CS to 0. It's a good idea to set CS to a known value at some point, but your current code will work perfectly fine even if you don't set CS.
liwinux wrote:So, I just decide to set the stack safely away from 0X7C000
The stack grows down, so placing it at 0x8000 gives you 512 bytes of stack before it starts to overwrite your boot sector. Some BIOS calls require more stack space than that!
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Mon Jun 14, 2021 1:01 am
by liwinux
So guys I think I made it , kind of because I don't really understand why it works now...
So basically what I've done is just relocate my "%include" at the beginning of my bootloader file as it was at the end before my padding... I don't know why it works now.. Can someone explain it to me ? Also, if I replace my "%include" where they were (at the end) AND remove the "section .text" part, it works too. It doesn't really make sense to me. I'm missing something here for sure !
Code: Select all
[org 0x7c00]
[bits 16]
section .text
global BOOTSECT
jmp 0x0000:BOOTSECT
%include "print.asm"
%include "readSector.asm"
BOOTSECT:
; Making sure to reset every segment before loading.
; Because some BIOS tend to modify those..
cli
xor ax, ax
mov ss, ax
mov sp, 0x9000
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
cld
sti
mov bx, MSG_START ; This line is printed two times....
call print
mov bx, MSG_READING
call print
mov al, 1
mov cl, 2
mov bx, 0x1000
call readSector
; Changing the bios background color if success (GREEN)
mov ah, 0x0b ;Function Code
mov bh, 0x00 ; Function parameter
mov bl, 0x08 ;Background color
int 0x10
mov bx, MSG_SUCCESS_DISK
call print
jmp $
;; I used to place my %include here...
MSG_START: db "[INFO] Starting in 16-bit Real Mode !",13 ,10 ,0
MSG_READING: db "[INFO] Reading Sectors...",13 ,10 ,0
MSG_SUCCESS_DISK: db "[SUCCESS] Loading Disk Into Memory Succeded !", 13 ,10 ,0
times 510-($-$$) db 0
dw 0xaa55
times 512 db 0
Re: Bootloaderis not consistent when booting in real hardwar
Posted: Mon Jun 14, 2021 8:53 am
by Octocontrabass
liwinux wrote:I don't know why it works now.. Can someone explain it to me ?
It's hard to say for sure without being able to run dozens of tests. Maybe you finally got a valid partition table. Maybe something about the far JMP instruction you added convinces your firmware that it doesn't need to "fix" the BPB anymore. Maybe your 4.5kiB stack is finally big enough. (Some uncommon BIOS calls still need a bigger stack!)