Page 1 of 1

Problems with loading the kernel

Posted: Sat May 29, 2010 3:19 pm
by proog
First of all, I'm rather new to Assembly on x86, and my understanding of the language is somewhat limited, so please bear with me.

By using examples on the Internet and experimenting with the language, I'm trying to write a very simple bootloader that should load a very simple kernel in real mode. However, I'm having a problem in the loading process. My intention is to have the bootloader occupy the first 512 bytes (naturally) with the kernel following right behind. From what I understand, I can do this by reading the kernel part from the drive into a memory location with interrupt 13 and then jump to that point in memory. This is my bootloader code:

Code: Select all

[ORG 0x7C00]    ; The BIOS loads the boot sector into memory location 0x7C00

mov     ah, 02h ;read function.
mov     al, 1 ;sectors to read.
mov     ch, 0 ;track.
mov     cl, 2 ;sector.
mov     dh, 0 ;head.

mov     bx, 0800h ;kernel memory point
mov     es, bx
mov     bx, 0h

int     13h ;read!
jmp     0800h:0000h ;go to kernel memory point

times 510-($-$$) db 0	;Fill the rest of the files with zeros, until we reach 510 bytes
db 0x55
db 0xAA
This code is supposed to read sector 2 (512+ bytes) into memory, and then jumping to the kernel. The kernel code is this:

Code: Select all

mov si, msgwelcome
print_str:
	lodsb
	cmp al, 0 ;0 is end of string
	je stop
	mov ah, 0Eh ;teletype output
	int 10h ;write!
	jmp print_str ;next char!

stop:
	cli
	hlt

msgwelcome db 'Welcome.', 13, 10, 0
My intention is to simply printing each character in the string and then halting.
I'm using NASM to assemble the two files and writing them to a disk image with dd (on Windows):

Code: Select all

nasm -f bin -o boot.bin boot.asm
nasm -f bin -o kernel.bin kernel.asm
dd if=boot.bin of=run.img
dd if=kernel.bin of=run.img seek=1
After this, I have a "run.img" file of 540 bytes. When booting it with Bochs, however, it boots and seemingly loads something, saying:

Code: Select all

Booting from Floppy...
  _
... and then hanging. The last lines from the Bochs console are as follows:

Code: Select all

00014041543i[BIOS ] Booting from 0000:7c00
00014042376i[FDD  ] partial read() on floppy image returns 28/512
00014088485i[CPU0 ] WARNING: HLT instruction with IF=0!
I have found that when adding [ORG 0x8000] at the start of the kernel source makes it print the string correctly. This, however, does not work when booting it on a real machine. I hope someone can point out the error. :)

Re: Problems with loading the kernel

Posted: Sat May 29, 2010 4:07 pm
by Combuster
All addresses depend on a pair of values. Right now, you are making assumptions about the value in DS - the second of the two registers used by lodsb. If you look lodsb in the manual you'll see it does the same as mov AL, [DS:SI]; add SI, 1; only in far less bytes.

Re: Problems with loading the kernel

Posted: Sun May 30, 2010 4:52 am
by proog
I see. It seems to me that I can use

Code: Select all

mov ax, <segment>
mov ds, ax
to assign the segment to DS. How should I determine the segment for the string?

Re: Problems with loading the kernel

Posted: Sun May 30, 2010 11:14 am
by Gigasoft
DS should be set to 0, since you have org 0x7c00.

Re: Problems with loading the kernel

Posted: Sun May 30, 2010 12:42 pm
by Combuster
Have you noticed something odd?

Code: Select all

jmp     0800h:0000h ;go to kernel memory point
(...)
org 0x8000
The offset part seems to differ between your jump, and your file.

Also, do you know how physical addresses are calculated in real mode? In the common case its (segment * 16 + offset) So you can calculate the correct values with a 6-years-old's math knowledge. There are two obvious ways to fix the above problem. In one gigasoft's value works, in the other it doesn't. Consider it homework to discover both ways and figure which one requires what value in DS.

Re: Problems with loading the kernel

Posted: Mon May 31, 2010 4:22 am
by proog
Thank you, both of you.
The offset wasn't originally set in the kernel code, but for some reason it worked when running it in Bochs.

Here's what I've been able to figure out:
The kernel's memory point is at segment 0x800, which equals 2048. 2048*16 + offset 0 = 0x8000, and according to the OSDev article on real mode, "physical address 0x210 can be 0020:0010, 0000:0210, or 0021:0000". I would then say that I could assign 0x0800 to DS for DS:SI to be 0800:message. Is this correct or am I just thick?

Re: Problems with loading the kernel

Posted: Mon May 31, 2010 10:12 am
by Combuster
It's only half the answer. Setting DS to 0x800 or 0 or 0xABCD does not affect the value of message, in each case the linear address is different. The value of message however depends on two other things: the location in the file, and the ORG directive. Since the ORG gets added to all absolute addresses, it is important that you get it right: 0x800:0x0000+message isn't the same address as 0x800:0x8000+message, but it is the same as 0x000:0x8000+message...

Re: Problems with loading the kernel

Posted: Mon May 31, 2010 11:54 am
by qw
Another issue. You should test if the read succeeded. If it didn't, you should reset the disk system and try again. Attempt to read at least four times. On emulators this is usually not necessary, but on real hardware the first few attempts may fail.

Re: Problems with loading the kernel

Posted: Tue Jun 01, 2010 6:47 am
by proog
Alright, I'll look into the issues, thanks again.