Bloody Beginner

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
hpclutz
Posts: 19
Joined: Tue Jul 08, 2008 11:30 am

Bloody Beginner

Post by hpclutz »

Dear all,

first of all "hi" to all forum members and all veteran OS developers - I am just beginning to fiddle with OS development and you owe my deepest respect already;)

As I said, I just only started and have developed my first "Hello World" kernel... and already run into first problems: I try to print "Hello Simple Kernel World!", but get more something like "Hello Simple§/(%&/§(&/&". I tried different approaches, but it seems like the memory I assigned for the text gets overwritten somehow(?) It always happens exactly after 12 chars, no matter where I "print", or how much strings I define.... does anybody know what this could be?

As additional information: I use the "Super Grub Floppy Disk" for booting my Kernel and develop using Visual C with assembler in accordance with http://ksrenevasan.blogspot.com/2005/10 ... using.html

As I said, I have tested different ways of printing, such as

Code: Select all

		  char *message1 = "Hello Simple Kernel World!";
		  
		  __asm
		  {
					mov ebx, 0
					mov edx, message1
					mov ah, 0x07

					mov cl, 20

				letter:
					mov al, [edx]
					mov [0xb8000+ebx], ax
					inc ebx
					inc ebx
					inc edx

					dec cl
					jnz letter
		  };
and

Code: Select all

void print(char* message, int line)
{
	unsigned char *vidmem = (unsigned char *) 0xb8000;

	unsigned int i=0;
	i=(line*80*2);

	while(*message!=0)
	{

		vidmem[i]=*message;
		*message++;
		i++;
		vidmem[i]=0x07;
		i++;
	};

}
ANY help would be highly appreciated - thanks a lot in advance
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: Bloody Beginner

Post by bewing »

The first routine should work. The error that is messing you up is in some other part of your code. Perhaps in an interrupt handler? Are you using Bochs with the debugger running? You should. It really helps a lot to be able to singlestep your way through code and WATCH it screw up.

The second routine has an error -- the line that says:
*message++;

should not have the * in it.
hpclutz
Posts: 19
Joined: Tue Jul 08, 2008 11:30 am

Re: Bloody Beginner

Post by hpclutz »

Hmmm, you're absolutely right about the *message: no idea how I managed to change that :shock:

Thanks for your reply - in fact, I am using Virtual PC, but I tested with BOCHS just now to see whether that would lead to more insight... same "error" though :(

There is no interrupt handling or any further code in my main function, besides for the declarations at http://ksrenevasan.blogspot.com/2005/10 ... using.html in order to bee multiboot compliant with Visual Studio. It seems to work for them... Hmmm, I even fail to get a Hello World OS running, this does not seem to be my league ;)

Any further ideas? Somebody came across similar problems?

Cheers
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Bloody Beginner

Post by pcmattman »

You might want to post the rest of your code (tar/zip it all up and attach here) so others can take a peek and see what's going on. I can't see any problems at first look at your code (other than the *message thing), so I think it must be somewhere else.
hpclutz
Posts: 19
Joined: Tue Jul 08, 2008 11:30 am

Re: Bloody Beginner

Post by hpclutz »

That's awfully nice of you - as I said, there is not a lot to it, so I don't think I need a zip attachment... here goes:

kernel.h:

Code: Select all

/* kernel.h */
// taken from http://ksrenevasan.blogspot.com/2005/10/writing-multiboot-pe-kernels-using.html
#ifndef __kernel_h__
#define __kernel_h__

#define dd(x)                            \
        __asm _emit (x)       & 0xff     \
        __asm _emit     (x) >> 8  & 0xff \
        __asm _emit     (x) >> 16 & 0xff \
        __asm _emit     (x) >> 24 & 0xff

#define KERNEL_STACK               0x00103fff
#define KERNEL_START               0x00101000
#define KERNEL_LENGTH               0x0000200F

void main(unsigned long, unsigned long);

#endif
kernel.c:

Code: Select all

/* kernel.c */
// taken from http://ksrenevasan.blogspot.com/2005/10/writing-multiboot-pe-kernels-using.html
#include "kernel.h"

__declspec(naked) void __multiboot_entry__(void)
{
          __asm {
          
          multiboot_header:
                    dd(0x1BADB002)               ; magic
                    dd(1 << 16)                    ; flags
                    dd(-(0x1BADB002 + (1 << 16)))     ; checksum
                    dd(0x00101000)               ; header_addr
                    dd(0x00101000)               ; load_addr
                    dd(0x0010200F)               ; load_end_addr
                    dd(0x0010200F)               ; bss_end_addr
                    dd(0x00101030)               ; entry_addr
                    dd(0x00000000)               ; mode_type
                    dd(0x00000000)               ; width
                    dd(0x00000000)               ; height
                    dd(0x00000000)               ; depth

          kernel_entry:
                    mov     esp,     KERNEL_STACK

                    xor     ecx,     ecx
                    push     ecx
                    popf

                    push     eax
                    push     ebx
                    call     main

                    jmp     $
          }
}

void main(unsigned long magic, unsigned long addr)
{
		  char *message1 = "Hello Simple Kernel World!";
		  
		  __asm
		  {
					mov ebx, 0
					mov edx, message1
					mov ah, 0x07

					mov cl, 20

				letter:
					mov al, [edx]
					mov [0xb8000+ebx], ax
					inc ebx
					inc ebx
					inc edx

					dec cl
					jnz letter
		  };

}
and I compile with

Code: Select all

cl /Gd /Fokernel.obj /Fm /TC /c kernel.c
link /safeseh:no /filealign:0x1000 /BASE:0x100000 /MAP:kernel.map /ENTRY:__multiboot_entry__ kernel.obj /NODEFAULTLIB:LIBC /SUBSYSTEM:CONSOLE /OUT:kernel.exe
As a result I get the output as can be seen in the picture attached.

:(
Attachments
Kernel.jpg
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Bloody Beginner

Post by pcmattman »

Well, first up:

Code: Select all

mov cl, 20
There aren't 20 characters in that string ;). Later on you might want to write a C function that'll do printing strings for you.

The only other thing I see is your kernel stack declaration:

Code: Select all

#define KERNEL_STACK               0x00103fff
Typically we all define KERNEL_STACK as a block of memory in the BSS section (or data section) so there's space already allocated for it. In your case you may have the stack growing down onto your data section which destroys the string. Maybe try (for a temporary fix) setting the KERNEL_STACK to something like 0x400000 (ie, at the 4 MB mark) and if it works try to figure out how to make a more robust stack (hint: char stack[1024]; will leave you with 1024 bytes in the data section of the binary).
PatrickV
Member
Member
Posts: 151
Joined: Sun Jul 06, 2008 7:50 pm
Location: New Zealand
Contact:

Re: Bloody Beginner

Post by PatrickV »

To me looks like a virus is hiting the program, lol :roll: . Well i can not say much but it looks like a linux look a like kind off. looks like you copy bits of peices and put together, or your code use to make the acsii is not working correct and causes to go all funny
User avatar
Adek336
Member
Member
Posts: 129
Joined: Thu May 12, 2005 11:00 pm
Location: Kabaty, Warszawa
Contact:

Re: Bloody Beginner

Post by Adek336 »

If you use a hexeditor to view your binary file, is the whole string in it?
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: Bloody Beginner

Post by bewing »

Yeah, try changing the mov cl, 20 to mov cl, 26 -- and let's see what changes.
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Bloody Beginner

Post by Omega »

@bewing: The second routine has an error -- the line that says:
*message++;

should not have the * in it.

Here is what I used to do and it worked fine

Code: Select all

void print(unsigned char color, char *string, int x, int y)
{
  char *vga = (char *) 0xb8000;
  unsigned int i = 160*y + 2*x;
  while (*string)
  {
	switch(*string)
	{
		case '\n': //newline
		y++;
		i = 160*y + 2*x;
		*string++;
		break;
	}
	//print formatted string
	vga[i++] = *string++;
	vga[i++] = color;
  }
}
So why is it incorrect to do that? I actually still use this function in some of my OS, so I know it works. Just curious.

Hello fellow Windows User, I think you should really try to use DJGPP instead and write your code in C. Use NASM to write your loader that loads main in your kernel. This way you can define all the stack stuff in ASM and define your mboot stuff as a struct in C and stop following that crazy blog post. Also, where did you get your print function, that wasn't in his guide? Use Bochs or don't use Bochs, I use Virtual PC too, so rock on!! :)
Free energy is indeed evil for it absorbs the light.
User avatar
octa
Member
Member
Posts: 50
Joined: Sat Jun 28, 2008 9:15 am

Re: Bloody Beginner

Post by octa »

*string++;
will work fine because of precedence...
but it is just like putting
string[5];
in middle of ur code..
does this have any meaning.... ???
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Bloody Beginner

Post by Omega »

It's just a pointer to the variable of string, it's size isn't pre-defined, so it is actually just a pointer to where that variable resides in memory, at least that's what I thought. So, it wouldn't be like string[5]; it would be like, Where is string at, oh there it is and by the way load the next char in the string.

Now if I went like:

Code: Select all

function ()
{
char buff[5];

for (...)
{
*buff++;
}

return 0;
}
..then the * would not be needed. Since I pass the variable to my function as a pointer then I must reference it as a pointer. Right??
Free energy is indeed evil for it absorbs the light.
User avatar
octa
Member
Member
Posts: 50
Joined: Sat Jun 28, 2008 9:15 am

Re: Bloody Beginner

Post by octa »

*string++ does not load the char in string..
string has address of variable and *string point to it..
User avatar
Omega
Member
Member
Posts: 250
Joined: Sun May 25, 2008 2:04 am
Location: United States
Contact:

Re: Bloody Beginner

Post by Omega »

I must be mistaken, I trust you are correct. I am going to go wipe the egg off my face and brush up on C variables now. Thanks
Free energy is indeed evil for it absorbs the light.
hpclutz
Posts: 19
Joined: Tue Jul 08, 2008 11:30 am

Re: Bloody Beginner

Post by hpclutz »

Curious how everybody goes on about the *message , which was a typo, the mov cl, 20, which, come on guys, is purely irrelevant as long as I try anything below 26. And finally, I simply reduced the length of code by removing the print function and it's content into my main block....

Thanks for all the answers though and yes, I can find the whole string in my binary and all. Moving the kernel_stack to another location doesn't help. Bochs or Virtual PC, same result :( Quite at a loss here

Since it seems that you all agree with me that the code should work (and don't start about the *message again ;) ) There must be something wrong with the approach in the first instance. Yes, I am a bloody Microsoft Windows Visual Studio user - after all, that's what I do for money ;)

Has anybody ever tried compiling a kernel using Visual Studio? And forgive my stupid asking: how else can I define a bootable header (never mind about multiboot or PE)

Thanks guys
Post Reply