Page 1 of 2

Test kernels refuses to print to screen

Posted: Wed Apr 27, 2005 9:40 pm
by HeronMarked
I've been following along with Bran's kernel tutorial and just put the basic vga driver together. Everything compiles and links fine but when I boot it in Bochs and Vmware it does nothing aside from clearing the screen. I tried another test kernel from Bona Fide with the same results, cls works fine but actually displaying characters doesn't. However, if I add something like:
mov word [0B8000h],9F44h
to the start.asm and comment out the calls to main, a white D with a blue background will display. My development environment is Gentoo, using ld and gcc. Here are my link.ld and makefile contents:
link.ld

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x00100000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}
makefile:

Code: Select all

nasm -f aout -o start.o start.asm
gcc -Wall -O -fleading-underscore -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o main.o main.c
gcc -Wall -O -fleading-underscore -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o scrn.o scrn.c
ld -T link.ld -o kernel.bin start.o main.o scrn.o
I can attach a zip file of both test kernels I'm attempting to use. I've just been banging my head against a wall over this all day.

Re:Test kernels refuses to print to screen

Posted: Thu Apr 28, 2005 12:17 am
by AR
How are you writing to the screen (it is very odd that you ask why your output code doesn't work when you haven't shown us what the code is)? I don't know what tutorials you're refering to so I'll just show how it should work:

Code: Select all

char *FrameBuffer = 0xB8000;
int CursorPos;
void print(char *msg)
{
    while(*msg)
    {
         putchar(*msg);
         ++msg;
    }
}

void putchar(char c)
{
    switch(c)
    {
    case '\n':
        CursorPos += 160;
        break;

    default:
        FrameBuffer[CursorPos] = c;
        ++CursorPos;
        FrameBuffer[CursorPos] = 0x07;
        ++CursorPos;
    }
    
    if(CursorPos > 4000)
    {
         memcpy(FrameBuffer, FrameBuffer+160, 3840);
         CursorPos -= 160;
    }
}
Have you set the attribute byte? If the attribute byte is 0 then you aren't going to see anything

Re:Test kernels refuses to print to screen

Posted: Thu Apr 28, 2005 7:45 am
by HeronMarked
I've tried two different methods

Code: Select all

#define WHITE_TXT 0x07

unsigned int k_printf(char *message, unsigned int line) // the message and then
the line #
{
        char *vidmem = (char *) 0xb8000;
        unsigned int i=0;

        i=(line*80*2);

        while(*message!=0)
        {
                if(*message=='\n') // check for a new line
                {
                        line++;
                        i=(line*80*2);
                        *message++;
                } else {
                        vidmem[i]=*message;
                        *message++;
                        i++;
                        vidmem[i]=WHITE_TXT;
                        i++;
                };
        };

        return(1);
};
and from Barn's tutorial

Code: Select all

unsigned short *textmemptr;
int attrib = 0x0F;
int csr_x = 0, csr_y = 0;

void putch(unsigned char c)
{
    unsigned short *where;
    unsigned att = attrib << 8;

    if(c == 0x08)
    {
        if(csr_x != 0) csr_x--;
    }
    else if(c == 0x09)
    {
        csr_x = (csr_x + 8) & ~(8 - 1);
    }
    else if(c == '\r')
    {
        csr_x = 0;
    }
    else if(c == '\n')
    {
        csr_x = 0;
        csr_y++;
    }
    else if(c >= ' ')
    {
        where = textmemptr + (csr_y * 80 + csr_x);
        *where = c | att;
        csr_x++;
    }
    if(csr_x >= 80)
    {
        csr_x = 0;
        csr_y++;
    }
    scroll();
    move_csr();
}
I've even tried downloading the zipped code archives that come with the tutorials and compiling that. They give the same results.

Re:Test kernels refuses to print to screen

Posted: Thu Apr 28, 2005 8:19 am
by Colonel Kernel
HeronMarked wrote:

Code: Select all

                if(*message=='\n') // check for a new line
                {
                        line++;
                        i=(line*80*2);
                        *message++;
                } else {
                        vidmem[i]=*message;
                        *message++;
                        i++;
                        vidmem[i]=WHITE_TXT;
                        i++;
                };
For one thing, *message++ increments the character pointed to by message, rather than moving message to point to the next character. You want message++, not *message++.

Re:Test kernels refuses to print to screen

Posted: Thu Apr 28, 2005 8:55 am
by HeronMarked
I tried your fix Colonel. Same results, the weird thing is the clear screen functions work. If I comment out the clear screen though I get the usual Multiboot kludge message and then a non-blinking cursor. What gets me is that it happens with multiple kernels from tutorials. It makes me wonder if I'm doing something wrong.

Re:Test kernels refuses to print to screen

Posted: Thu Apr 28, 2005 9:52 am
by HeronMarked
Haha, I feel like an idiot. -fwriteable-strings fixed it. I assumed the link.ld scripts were correct, that'll teach me.

Re:Test kernels refuses to print to screen

Posted: Thu Apr 28, 2005 10:04 pm
by proxy
For one thing, *message++ increments the character pointed to by message, rather than moving message to point to the next character. You want message++, not *message++.
sorry, but this is horribly incorrect, it does in fact increment message. here's what _really_ happens.

++ always has a higher presidence than * unless parens alter that, so that goes first. however, portfix ++/-- is a little unusual. it will increment, but return the _old_ value.

so...

the code:

Code: Select all

int *p = <something>;
*p++ = 5;
is technically the same as

Code: Select all

int *p = <something>;
int *temp = p;
++p;
*temp = 5;
fortunately, pretty much all compilers are smart enough to optimize this into just a plain post increment, yeilding assembly which would be analogous to the following code.

Code: Select all

int *p = <something>;
*p = 5;
++p;

proof of concept. i've implemented MANY memory copy loops like so:

Code: Select all

while(n--) {
    *dst++ = *src++;
}
plus any operator presidence chart like here:
http://www.cppreference.com/operator_precedence.html

will show both -- and ++ to have a higher precidence than derefence.

finally one thing to note is that

Code: Select all

*p++;"
by itself is just silly, you are incrementing p, and dereferencing it..but you do nothing with that dereference value which is nothing more than a waste of cpu cycles.

if you intend to just increment a pointer just do:

Code: Select all

++p;
or
p++;
the first one being prefered especially in c++ because sometimes (particularly with objects with overloaded ++ operators) compilers can't eliminate the temp in the post increment/decrement.



proxy

Re:Test kernels refuses to print to screen

Posted: Thu Apr 28, 2005 10:07 pm
by proxy
also a better solution than adding -fwriteable-strings is to add

*(.rodata*)

to the .data section so your string constants go in there too.

proxy

Re:Test kernels refuses to print to screen

Posted: Fri Apr 29, 2005 12:23 am
by Colonel Kernel
proxy wrote: sorry, but this is horribly incorrect, it does in fact increment message. here's what _really_ happens.
D'oh! Serves me right for trying to be helpful before 9:00 AM. :P

BTW, calling it "incorrect" without the adjective would have been sufficient. ;)
finally one thing to note is that

Code: Select all

*p++;"
by itself is just silly
Which is exactly why it caught my attention in the first place. But of course you're right, I have written my share of copy loops as well. It's one of those things that becomes so automatic, you just don't think about it after a while.

I'm curious though... Do parens affect when the post-increment happens? In other words, is this:

Code: Select all

*(p++);
different than this:

Code: Select all

*p++;
or do they do the same thing?

Re:Test kernels refuses to print to screen

Posted: Fri Apr 29, 2005 2:35 am
by Farmer
Speaking of Bran's tutorial, which I am currently using:
In the early sections of the tutorial that I am still on, Bran wants me to code my own memcpy() function. I seem to be having trouble getting this code to work. I would appreciate any input as to why???

void *memcpy(void *dest, const void *src, int count)
{
   char *destptr = (char *)dest;
   const char *srcptr = (const char *)src;
   int i = 0;    
   while(i < count){
      *destptr = *srcptr;
      destptr++;
      srcptr++;
      i++;
   }
}

Re:Test kernels refuses to print to screen

Posted: Fri Apr 29, 2005 8:10 am
by proxy

Code: Select all

*(p++);
and
*p++;
are the same thing, because like i said, the ++ goes first by default anyway

if you want to increment what it points to:

Code: Select all

++(*p);
or
(*p)++;
will do nicely

proxy

Re:Test kernels refuses to print to screen

Posted: Fri Apr 29, 2005 8:13 am
by proxy
Farmer I don't see anything wrong with it at first glance besides the fact that you define the function as returning a void * and return nothing (which means whatever happens to be in eax when it's done will be returned...)

here's what my memcpy looks like

Code: Select all

void *memcpy(void *dest, const void *src, size_t n) {
   
   char *d_ptr = dest;
   const char *s_ptr = src;
   
   assert(dest != 0);
   assert(src != 0);

   while(n--) {
      *d_ptr++ = *s_ptr++;
   }
   
   return dest;
}

Re:Test kernels refuses to print to screen

Posted: Mon May 02, 2005 4:37 am
by Solar
proxy wrote: also a better solution than adding -fwriteable-strings is to add

*(.rodata*)

to the .data section so your string constants go in there too.
Actually that is the only solution that will still work with GCC 4.x, which no longer accepts -fwriteable-strings.

Re:Test kernels refuses to print to screen

Posted: Tue Oct 11, 2005 2:03 pm
by TheChuckster
I fixed it by changing the linker script to link to an ELF file.

Re:Test kernels refuses to print to screen

Posted: Thu Oct 27, 2005 11:38 am
by dan
I have the same problem described in the origonal post.

Im not sure exactly where to add *(.rodata*) to, I tried adding it in the .data section of my linker script, but it didn't fix the problem.
My linker script looks pretty much the exact same as the one in the origonal post. Any help would be greatly appreciated.

By the way, it seems to work if I push the address of the first character of my string onto the stack and manually call my puts function from the assembly code, but if I call it from the C code, it will not work.