I am writing a bootloader in assembly and it seems to work fine on qemu, bochs and virtualbox. However, it is not loading the kernel on real hardware (it seems).
The bootloader starts off by writing a character to the video memory (for debugging), it then reads sector 2 off the drive and far jumps to the kernel. The kernel is then writing some characters to video memory.
On a real machine, I see the character from the bootloader on the screen, and there it hangs (blinking caret).
I have tried to set DS, ES, SI to zero, and I am also setting up a stack segment.
I am reading sector 2 off of the drive using bios int 13 function 2. I kind of suspect that it has something to do with the drive number. I have both tried to use the drive number passed to the bootloader on startup (in dl), and setting it manually to 0x0, 0x80 and 0x81.
One strange thing I noticed is that the labels I use to near jump, magically gets the correct address. Using objdump I see for example: jmp 0x2, while using gdb and qemu, it says: jmp 0x7c02. CS and all the other segment registers are zero. Whether I use -Ttext 0x0 or -Ttext 0x7c00 in the linking, the bootloader works fine on all the emulators. objdump says jmp 0x7c02 when I link with -Ttext 0x7c00.
EDIT, the bootloader looks like this:
.code16
.text
movw $0xb800, %ax
movw %ax, %ds
movw $0x0741, (0x0)
xorw %ax, %ax
movw %ax, %ds
movw %ax, %si
movw %ax, %es
movw $0x8000, %ax
movw %ax, %ss
movw $0, %sp
movb $2, %ah
movb $1, %al
movw $0x02, %cx
movb $0x00, %dh
movw $0x5000, %bx
movw %bx, %es
movw $0x0, %bx
int $0x13
ljmpw $0x5000, $0x0000
Edit, Second stage:
.code16
.text
movw $0xb800, %ax
movw %ax, %ds
movw $0x0742, (0x2)
forever:
jmp forever
-Ttext 0x0
and-Ttext 0x7c00
will only work the same if there are no near absolute references to labels. If your bootloader code were to have an instruction where there was such a reference it would not work in a bootloader unless-Ttext 0x7c00
is used. If you were to create a string in the bootloader and tried to move the address to the start of it into a register that would be such an example. (iemovw $mystring, %di
) – Cheltenhammovw $0x074b, (0x1)
seems wrong. Each cell is 2 bytes. Did you meanmovw $0x074b, (0x2)
? – Cheltenham0xb800
in ES and then do memory accesses with a segment override likemovw $0x74b, %es:(0x02)
– Cheltenham