2

I am writing a boot sector that boots up, prints a message saying "Hello world." and enters an infinite loop. I am using int 0x10 to print characters of the message.

I have assembled the code using nasm and tested it on qemu. It works fine and the message is displayed. I also copied the boot sector to a USB drive using the command

dd if=welcome_message of=/dev/sdb bs=512 count=1

and booted from the USB drive using qemu

qemu-system-x86_64 /dev/sdb

The message is displayed. But when I restart my PC and boot from USB, it boots up but nothing is displayed. The cursor does move forward according to the length of the message but nothing is displayed. What am I missing ? It appears that the characters are displayed but somehow they are not visible. I have attached the code

;Print a welcome message after booting

[org 0x7c00]    ;BIOS loads this code at 0x7c00

mov ah, 0x0e    ;For Using BIOS to print a character

mov cl, len ;Used as counter inside the loop, so load with length

inc cl

mov si, welcome       ;Used as pointer to the character string

loop:

mov al, [si]    ;get the character in al

int 0x10    ;Print the character

inc si       ;Point to next character

dec cl        ;Decrement counter

jnz loop    ;Keep printing until you reach end of the welcome message

jmp $       ;Loop forever


welcome: db "Hello World ."

len equ $-welcome

times 510 - ($-$$) db 0     ;Put 0s till 510

dw 0xaa55

EDIT 0 : Setting DS to 0 starts the printing. But some characters are not printed. The expected output is "Hello World!" but I get "Hel orld ". What might be the problem ?

;Print a welcome message after booting
[bits 16]
[org 0x7c00]    ;BIOS loads this code at 0x7c00
mov ax, 0
mov ds, ax  ;Initialize data segment register
mov ah, 0x0e    ;For Using BIOS to print a character
mov cl, len ;Used as counter inside the loop, so load with length
inc cl
mov si, welcome
loop:
mov al, [si]    ;get the character in al
int 0x10    ;Print the character
inc si
dec cl
jnz loop    ;Keep printing until you reach end of the welcome message
jmp $       ;Loop forever

welcome: db "Hello World!"
len equ $-welcome
times 510 - ($-$$) db 0     ;Put 0s till 510
dw 0xaa55

EDIT 1: FInally I got the correct output. Check the comment thread for solution.

vkj
  • 43
  • 3
  • the `mov al,[si]` instruction does use `ds` implicitly to get full physical 20-bit memory address, and you don't set `ds` to anything, so it's "something" set by BIOS = so you are loading "string" from some completely other memory, not yours. Check some tutorial about real mode (x86-16) memory addressing, and how segment registers work. (also in extreme case one can be paranoic and think BIOS is using black ink on black paper, as you don't reset video mode either, but that's just hypothetical show how far you may go when working on machine level, in reality I haven't heard about such x86 BIOS) – Ped7g Jan 21 '19 at 09:59
  • What value should be loaded into cs and ds at this point – vkj Jan 21 '19 at 10:00
  • The `cs` is already loaded by BIOS (otherwise it wouldn't execute your code, but code somewhere else)... it should be `cs=0`, but some real PCs start bootloader instead by jumping to `07c0:0000` (same physical address as `0000:7c00`, but using `cs=07c0` and throwing off any naive bootloader which doesn't expect that). As you used `org 7c..`, you expect `ds` to be zero... (`welcome` is something like `7c30`, check map file or listing file after assembly, so `ds=0` will make your code reach for that). – Ped7g Jan 21 '19 at 10:05
  • Overall, there're many more obscure technical details/quirks for writing robust bootloader, if you are also just starting with x86-16 assembly, it may be better to learn first x86-16 basics (and to run code only in some friendly environment like qemu), then later to learn about bootloader specifics (as knowledge of assembler programming is "general" to some degree, while x86-16 bootloader quirks are specialized knowledge good only for x86-16 bootloader writing, which you will probably not do in your life, so it's nice to be aware of them, but "mastering" them... only if you really want to) – Ped7g Jan 21 '19 at 10:09
  • @Ped7g thanks a lot. Setting DS to 0 solves the problem but I am facing a weird error. The first three characters are printed, the next four aren't. Further 4 characters are printed and the next character is not printed. The output is "Hel orld " instead of "Hello World!" It seems as if some characters are loaded properly while garbage is loaded in case of the others. What might be the problem. I shall include the updated code. – vkj Jan 21 '19 at 13:21
  • For [`int 10h,0Eh` service](http://stanislavs.org/helppc/int_10-e.html) you should also set "page number" to 0 (see the docs, BH=0). If the problem still persist, I have no idea, after fixing BH I don't see any trivial mistake. (you may want also to reset `ah=0x0E` every time just to be sure, in case your BIOS will butcher the `ah` value, but that would be a bug on BIOS side.. although they happen, it's very rare) – Ped7g Jan 21 '19 at 14:10
  • 2
    @vkj : If you set DS to zero and it doesn't work quite as expected it may very well be that you are booting USB using Floppy Disk Drive emulation. If using FDD to boot you may need to allocate space for a BIOS Parameter Block because the BIOS may be overwriting part of your code with drive geometry data before it transfers control to your bootloader. That can cause weird and wonderful problems.See this SO answer about USB/FDD/BPB and a solution: https://stackoverflow.com/a/47320115/3857942 – Michael Petch Jan 21 '19 at 19:55
  • Thanks a lot . The problem is resolved. It turns out the BIOS was overwriting over some of the bytes of my bootloader. As pointed out in the link you provided, I put a string of zeros of length 0x50 before the actual bootloader. The first instruction just jumps to the actual bootloader. It solves the problem and I got the string displayed correctly. – vkj Jan 23 '19 at 04:55

0 Answers0