Test kernels refuses to print to screen

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.
HeronMarked

Test kernels refuses to print to screen

Post 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.
AR

Re:Test kernels refuses to print to screen

Post 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
HeronMarked

Re:Test kernels refuses to print to screen

Post 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.
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re:Test kernels refuses to print to screen

Post 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++.
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
HeronMarked

Re:Test kernels refuses to print to screen

Post 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.
HeronMarked

Re:Test kernels refuses to print to screen

Post by HeronMarked »

Haha, I feel like an idiot. -fwriteable-strings fixed it. I assumed the link.ld scripts were correct, that'll teach me.
proxy

Re:Test kernels refuses to print to screen

Post 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
proxy

Re:Test kernels refuses to print to screen

Post 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
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re:Test kernels refuses to print to screen

Post 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?
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
Farmer

Re:Test kernels refuses to print to screen

Post 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++;
   }
}
proxy

Re:Test kernels refuses to print to screen

Post 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
proxy

Re:Test kernels refuses to print to screen

Post 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;
}
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Test kernels refuses to print to screen

Post 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.
Every good solution is obvious once you've found it.
TheChuckster

Re:Test kernels refuses to print to screen

Post by TheChuckster »

I fixed it by changing the linker script to link to an ELF file.
dan

Re:Test kernels refuses to print to screen

Post 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.
Post Reply