Hi,
Could someone please share your idea on how to write a simple Hello World Boot Loader. I have been using OpenSuse Linux and and x86. I was able to write a single letter using the corresponding Ascii key. What about a string?

Thanks,
Citizen.

Recommended Answers

All 7 Replies

Did you already write your bootloader? If yes, than most work is already done. You just place all the following stuff at the end of the loader, load that stuff into mem and execute it by setting CS to that point.

Displaying a string is the same as displaying a single char just in a loop. If you use C-strings with 0-termination the you loop through the string until a 0 occurs. Eg

mystring DB 'Hello world!',0
XOR BX,BX
print:
MOV AL,[mystring+BX]
JZ end
;output AL (don't know the code itm)
LOOP print
end:

thanks a lot for your reply and code snippet. I have a doubt here. the processor understands hexadecimal value and displays the corresponding ascii values. for eg. when use #0x41 as the value it will displays character 'A' (well, this is what I tried). How would the processor understands a string. When I tried a code similar to yours it only displayed some ascii characters. the code i tried is in http://linuxgazette.net/issue79/krishnakumar.html. Please let me know regarding this. I am getting really interested in OS and boot loader concepts, but only getting minimal guidance in this area.

Thanks a lot.

Assuming you're using nasm and you're on an x86 processor, here's a quick example of boot sector code to print "Hello world"

;=============================================================================;
; helloworld.asm: print "Hello world" to the screen and hang                  ;
;=============================================================================;

section .text
;=============================================================================;
; start: entry point
start:
[org 0x7c00] ; Self-relocate origin to 0x7c00
	cli ; Disable interrupts

	mov si, msg ; Place message in si
	call putstr ; Print the string
;-----------------------------------------------------------------------------;
; hang: hang the machine indefinitely
hang:
	jmp hang
;-----------------------------------------------------------------------------;
; putstr: print a string given in si to the screen
putstr:
	pusha ; Push all registers
	mov ah, 0eh ; 
	
	; putchar: print a character from the string
	putchar:
		lodsb ; Get a character
		cmp al, 0 ; Check for null-terminator
		je .return ; NULL found, stop
		; Not NULL, print the character
		int 0x10
		jmp putchar
	.return:
		popa ; Pop all registers
		mov ax, 0
		ret ; Return (0 in ax)
;=============================================================================;

section .data ; This always goes at the end of the binary, so putting it at the
; end of the source file makes sense.
;=============================================================================;
msg	db	'Hello world', 13, 10, 0 ; The 13, 10, 0 refers to '\r\n\0' in C/C++.
	times	482-($-$$)	db	0 ; Fill the binary until it's 512 bytes
	dw	0xaa55 ; Boot signature stored as 0x55 0xaa in memory (little endian)
;=============================================================================;

Now, for some reason that times isn't working. Really it should be

times 510-($-SS) db 0

but for some reason, that never works for me.

Hopefully you can compare my printing function and yours, and see where yours goes wrong.

how can i write a bootloader which loads a linux kernel ? i want to write such a simple bootloader as mentioned above ?

Regards,
Mohsin

how can i write a bootloader which loads a linux kernel ? i want to write such a simple bootloader as mentioned above ?

Regards,
Mohsin

It's a lot more complicated to boot the Linux kernel. You have to be able to load all it's boot modules, including the initial ramdisk, and tell it where they are, as well as what the root device is.

Try writing a simple stage1 (by the way, I figured out why times wasn't working -- if you let NASM do your sectioning itself (so it chooses what goes in .data, .bss, .text) then the times command times 510 - ($ - $$) db 0 will work.

All you need to do for a stage1 is read some sectors from the boot device (I would say between 8 and 32 (4 kiB and 16 kiB respectively), although GRUB loads about 60 sectors (30 kiB) AFAIK) and then jump to [ES:BX]. The program you load has to be a flat binary, so you're pretty much in the same position as your stage1 loader with one major advantage -- no 512 byte limit.

In the second stage I would implement a filesystem (FAT32, ext2 or ReiserFS (I would choose ext2 because it and Reiser are unencumbered by patents, but Linux usually resides on an ext{2, 3, 4} partition (3 and 4 are backwards-compatible) so I'd choose ext2) and an executable format (e.g. ELF, COFF, AOUT, PE (again, ELF, COFF and AOUT (a.out) aren't patented formats, so they're a better choice over windows' PE, and also, ELF is very well documented and Linux, by default, is compiled as an ELF (COFF and AOUT are old anyway)).

So, at this point you gather whatever information you want from the BIOS, load your third stage or a kernel (I would have 3 stages so as to be able to write the third in "normal" C or something, but you might want to do all stages in asm to avoid a third stage), switch to protected mode (or don't, it's up to you) and then jump to wherever you loaded the kernel.

akernelloader is a very simple program. I worked alone to include fat filesystems

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.