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.
Hey guys! Well i finally got my C kernel running and booting from GRUB! Now that i had that working, i though id get a simple print function working. I made my own and compiled/linked with no errors. Now i copied the binary to my floppy and booted and got a GRUB error 13. I was very confused and starting playing with my code and commenting out certain parts to see which was causing this ERROR 13. I found out that it was my print function! Whenever i called my print function i would get this grub error 13. After that, i narrowed it down to the pointer ARG. It seems to be causing this error 13, but why? Anyone have any ideas. Also my print func is k_printf();
//Minux OS kernel main
//Function Defines
//Ports
unsigned char inportb(unsigned short _port);
void outportb(unsigned short _port, unsigned char _data);
//Video
void init_video();
void clear_screen();
void print_character(char c);
void k_printf(unsigned char *text);
//void print_character(char c, unsigned int line);
//Vars
int cursor_x = 0;
int cursor_y = 0;
void kmain( void* mbd, unsigned int magic )
{
if ( magic != 0x2BADB002 )
{
/* Something went not according to specs. Print an error */
/* message and halt, but do *not* rely on the multiboot */
/* data structure. */
}
/* You could either use multiboot.h */
/* (http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#multiboot_002eh) */
/* or do your offsets yourself. The following is merely an example. */
char * boot_loader_name =(char*) ((long*)mbd)[16];
/* Print a letter to screen to see everything is working: */
unsigned char *videoram = (unsigned char *) 0xb8000;
videoram[0] = 65; /* character 'A' */
videoram[1] = 0x07; /* forground, background color. */
clear_screen();
k_printf("Hello World!");
//k_printf("Hello!");
/* Write your kernel here. */
}
/* We will use this later on for reading from the I/O ports to get data
* from devices such as the keyboard. We are using what is called
* 'inline assembly' in these routines to actually do the work */
unsigned char inportb (unsigned short _port)
{
unsigned char rv;
__asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
return rv;
}
/* We will use this to write to I/O ports to send bytes to devices. This
* will be used in the next tutorial for changing the textmode cursor
* position. Again, we use some inline assembly for the stuff that simply
* cannot be done in C */
void outportb (unsigned short _port, unsigned char _data)
{
__asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
}
void init_video()
{
clear_screen();
}
void clear_screen() // clear the entire text screen
{
char *vidmem = (char *) 0xb8000;
unsigned int i=0;
while(i < (80*25*2))
{
vidmem[i]=' ';
i++;
vidmem[i]= 0x07;
i++;
}
}
void print_character(char c)
{
if(c == '\n')
{
cursor_x =0;
cursor_y++;
}
if(cursor_x >= 80)
{
cursor_x = 0;
cursor_y++;
}
char *vidmem = (char *) 0xb8000;
int i = 0;
i = (cursor_y * 80 * 2);
vidmem[i] = c;
i++;
vidmem[i] = 0x07;
}
void k_printf(unsigned char *text)
{
int i;
for(i = 0; i < 20; i++)
{
print_character(text[i]);
}
}
/*
void print_character(char c, unsigned int line)
{
char *vidmem = (char *) 0xb8000;
unsigned int i=0;
i = (line*80*2);
vidmem[i] = c;
i++;
vidmem[i] = 0x07;
}
*/
//Minux OS kernel main
//Function Defines
//Ports
unsigned char inportb(unsigned short _port);
void outportb(unsigned short _port, unsigned char _data);
//Video
void init_video();
void clear_screen();
void print_character(char c);
void k_printf(unsigned char *text);
unsigned int k_printf2(char *message, unsigned int line);
//void print_character(char c, unsigned int line);
//Vars
int cursor_x = 0;
int cursor_y = 0;
void kmain( void* mbd, unsigned int magic )
{
if ( magic != 0x2BADB002 )
{
/* Something went not according to specs. Print an error */
/* message and halt, but do *not* rely on the multiboot */
/* data structure. */
}
/* You could either use multiboot.h */
/* (http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#multiboot_002eh) */
/* or do your offsets yourself. The following is merely an example. */
char * boot_loader_name =(char*) ((long*)mbd)[16];
/* Print a letter to screen to see everything is working: */
unsigned char *videoram = (unsigned char *) 0xb8000;
videoram[0] = 65; /* character 'A' */
videoram[1] = 0x07; /* forground, background color. */
clear_screen();
//k_printf2("Hello World!",0);
k_printf("AA");
//k_printf("Hello!");
while(1)
{
}
/* Write your kernel here. */
}
/* We will use this later on for reading from the I/O ports to get data
* from devices such as the keyboard. We are using what is called
* 'inline assembly' in these routines to actually do the work */
unsigned char inportb (unsigned short _port)
{
unsigned char rv;
__asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
return rv;
}
/* We will use this to write to I/O ports to send bytes to devices. This
* will be used in the next tutorial for changing the textmode cursor
* position. Again, we use some inline assembly for the stuff that simply
* cannot be done in C */
void outportb (unsigned short _port, unsigned char _data)
{
__asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
}
void init_video()
{
clear_screen();
}
void clear_screen() // clear the entire text screen
{
char *vidmem = (char *) 0xb8000;
unsigned int i=0;
while(i < (80*25*2))
{
vidmem[i]=' ';
i++;
vidmem[i]= 0x07;
i++;
}
}
void print_character(char c)
{
if(c == '\n')
{
cursor_x =0;
cursor_y++;
}
if(cursor_x >= 80)
{
cursor_x = 0;
cursor_y++;
}
char *vidmem = (char *) 0xb8000;
int i = 0;
//i = (cursor_y * 80 * 2);
i = (cursor_y * 80 + cursor_x);
vidmem[i] = c;
i++;
vidmem[i] = 0x07;
cursor_x++;
}
void k_printf(unsigned char *text)
{
int i;
for(i = 0; i < 2; i++)
{
print_character(text[i]);
}
}
unsigned int k_printf2(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]=0x07;
i++;
};
};
return(1);
};
/*
void print_character(char c, unsigned int line)
{
char *vidmem = (char *) 0xb8000;
unsigned int i=0;
i = (line*80*2);
vidmem[i] = c;
i++;
vidmem[i] = 0x07;
}
*/
Specifically with k_printf();
And yes i know the for loop is messed up, but im only printing two characters.
Yes, the formula to calculate it is wrong. Since you're using a pointer to a char (1 byte) instead of a short/word (2 bytes), you will have to multiply the offset by 2 in order to get the correct number of bytes.
Tosi wrote:Yes, the formula to calculate it is wrong. Since you're using a pointer to a char (1 byte) instead of a short/word (2 bytes), you will have to multiply the offset by 2 in order to get the correct number of bytes.
No, of course not (Do you see it anywhere in your code?). As mentioned above, you need to multiply the offset by 2 sense you are working with a byte pointer - your code doesnt do that. clear_screen() in your provided code performs this calculation correctly - just do the same for your character display routine.
Alternatively, just use a word pointer and write the attribute and character bytes at the same time.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}