Page 1 of 2
Bloody Beginner
Posted: Tue Jul 08, 2008 11:41 am
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
Re: Bloody Beginner
Posted: Tue Jul 08, 2008 2:08 pm
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.
Re: Bloody Beginner
Posted: Tue Jul 08, 2008 2:56 pm
by hpclutz
Hmmm, you're absolutely right about the *message: no idea how I managed to change that
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
Re: Bloody Beginner
Posted: Tue Jul 08, 2008 4:18 pm
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.
Re: Bloody Beginner
Posted: Tue Jul 08, 2008 4:31 pm
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.
Re: Bloody Beginner
Posted: Tue Jul 08, 2008 5:07 pm
by pcmattman
Well, first up:
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:
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).
Re: Bloody Beginner
Posted: Tue Jul 08, 2008 5:15 pm
by PatrickV
To me looks like a virus is hiting the program, lol
. 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
Re: Bloody Beginner
Posted: Tue Jul 08, 2008 5:24 pm
by Adek336
If you use a hexeditor to view your binary file, is the whole string in it?
Re: Bloody Beginner
Posted: Tue Jul 08, 2008 10:51 pm
by bewing
Yeah, try changing the mov cl, 20 to mov cl, 26 -- and let's see what changes.
Re: Bloody Beginner
Posted: Tue Jul 08, 2008 11:36 pm
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!!
Re: Bloody Beginner
Posted: Tue Jul 08, 2008 11:59 pm
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.... ???
Re: Bloody Beginner
Posted: Wed Jul 09, 2008 12:32 am
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??
Re: Bloody Beginner
Posted: Wed Jul 09, 2008 12:41 am
by octa
*string++ does not load the char in string..
string has address of variable and *string point to it..
Re: Bloody Beginner
Posted: Wed Jul 09, 2008 12:49 am
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
Re: Bloody Beginner
Posted: Wed Jul 09, 2008 1:14 am
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