Page 1 of 3

Kernel using C

Posted: Mon Jun 25, 2007 9:41 am
by nitinjavakid
Hi all, its been a while since I posted something on this forum.
I had been practicing OS development to a small extent using assembly. Now, I wanna do it using C(for more productivity). Can anyone please write a small kernel(which prints "H" on the screen) which can be compiled using gcc?

I tried all the stuff at www.osdever.net but nothing seemed to work. Also, if possible a link for linker scripting(I hope thats what it is called).

Regards,

Nitin

Posted: Mon Jun 25, 2007 9:49 am
by AJ

Posted: Mon Jun 25, 2007 10:09 am
by Bughunter
And if you're on Windows, you'll want to setup Cygwin to be able to use a cross compiler (GCC?) to support executable formats like ELF (commonly-used in OSdevving)

http://www.osdev.org/wiki/GCC_Cross-Compiler

Posted: Mon Jun 25, 2007 10:37 am
by t0xic
Like this?

Code: Select all


int x, y;
int putc( unsigned char c )
{
unsigned char *vidmem = (char*)0xb8000;
vidmem[ (y*2)+x ] = c;
}

int main( void )
{
putc('h');
}


--t0xic

Posted: Mon Jun 25, 2007 10:44 am
by Bughunter
t0xic wrote:Like this?

Code: Select all

...a tiny "kernel"...
--t0xic
:lol:
I think he could have thought of that code by himself if he did a small kernel in assembly. I think he wants some help to get him started doing it in C, like setting up the toolsets (maybe a cross compiler), linking scripts etc.

Posted: Mon Jun 25, 2007 12:14 pm
by t0xic
@Bughunter, oh

@nitinjavakid

Try Bran's kernel dev and also read the articles on the wiki. For starters, use djgpp or cygwin. I started with djgpp and now I am having a tough time switching over to my gcc cross compiler, so stick with what you start with.
Just my thoughts,
--t0xic

Posted: Mon Jun 25, 2007 9:26 pm
by nitinjavakid
These need GRUB to be installed. I want something that does not require GRUB. Like the ones we did in assembly.

Posted: Mon Jun 25, 2007 9:27 pm
by nitinjavakid
t0xic wrote:Like this?

Code: Select all


int x, y;
int putc( unsigned char c )
{
unsigned char *vidmem = (char*)0xb8000;
vidmem[ (y*2)+x ] = c;
}

int main( void )
{
putc('h');
}


--t0xic
nice program :D. But, man I want this to be loadable as an image(floppy image).

Posted: Mon Jun 25, 2007 9:30 pm
by nitinjavakid
Looking at those codes I found one thing common.
All are 32 bit codes. So, I guess protected(or unreal) mode is required right?

Posted: Tue Jun 26, 2007 1:11 am
by AJ
Yes. If you don't want that (or GRUB, as you said earlier), you will need to write your own bootloader (in asm) to load the kernel and switch to protected mode.

Posted: Tue Jun 26, 2007 1:39 am
by Combuster
There is a ton on the wiki about that as well: Babystep

Posted: Tue Jun 26, 2007 2:07 am
by nitinjavakid
I was doing some R&D (rewrite and diagnose :D), but bochs just flickers

kernel_start.asm

Code: Select all

[BITS 16]

[global start]

start:

   xor ax, ax
   mov ds, ax
   mov es, ax
   cli      

   lgdt [gdtinfo]   

   mov  eax, cr0   
   or al,1         
   mov  cr0, eax

   mov  bx,10000b
   mov  ds, bx 
   mov ss, bx
   mov esp,0x9200
   call _k_main
[BITS 32]
[extern _k_main]
  jmp $

gdt        dd 0,0  
code    db 0xFF, 0x00, 0x00, 0x7C00, 0, 10011010b, 11000000b, 0
datastack    db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0   
gdt_end:

gdtinfo:
   dw gdt_end - gdt - 1  
   dw gdt 
kernel.c

Code: Select all

#define WHITE_TXT 0x07 // white on black text

void k_clear_screen();
unsigned int k_printf(char *message, unsigned int line);
void update_cursor(int row, int col); 

_k_main() // like main in a normal C program
{
	//k_clear_screen();
	k_printf("Hi!\nHow's this for a starter OS?", 0);
};


void k_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]=WHITE_TXT;
		i++;
	};
};

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);
};
link.ld

Code: Select all

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

Code: Select all

nasm -f aout kernel_start.asm -o ks.o
gcc -c kernel.c -o kernel.o
ld -T link.ld -o kernel.bin ks.o kernel.o
Its not working. Plz help

Posted: Tue Jun 26, 2007 2:29 am
by Combuster
It seems to me you are writing a bootsector. Two issues with that:

1: it needs the signature
2: it must be 512 bytes

your code doesn't satisfy requirement 1. That means several bioses including bochs' will not boot it under normal circumstances. the second requirement is violated due to the aligning to 4096-byte boundaries between sections. It means that only the first 512 bytes of the code section are ever loaded but the variables (initialized and uninitialized) contain garbage. Even then you don't know wether you have all of the code in memory.

The rule of thumb is: The bootsector must be 100% asm.

I suggest you read the babysteps or alternatively reconsider GRUB as your bootloader as the current setup is fundamentally flawed.

Posted: Tue Jun 26, 2007 5:36 am
by nitinjavakid
Ok that signature thing, currently I am just running bochs with signature test disabled.

Also I read some manuals from Redhat and wrote this little thing. Have a look plz. Although the result is the same, it works when I use an asm instead of a C program.
kernel_start.asm

Code: Select all

[BITS 16]

[global start]

start:

   xor ax, ax
   mov ds, ax
   mov es, ax
   mov ax,0xb800
   mov es,ax
   mov byte ah,[man]
   mov byte [es:0x00],ah
   cli

   lgdt [gdtinfo]

   mov  eax, cr0
   or al,1
   mov  cr0, eax
   mov  bx,10000b
   mov  ds, bx ; [b]if i dont put jmp $ before this then bochs restarts :([/b]
   mov ss, bx
   mov esp,0x9200
   jmp 08h:temp
[BITS 32]
[extern _k_main]
temp:
   call _k_main
   jmp $

man  db 'w'

gdt        dd 0,0  ; entry 0 is always unused
code    db 0xff, 0xff, 0, 0, 0, 10011010b, 11000000b, 0 ; code buffer
datastack    db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0                     ;
gdt_end:

gdtinfo:
   dw gdt_end - gdt - 1
   dw gdt
kernel.c

Code: Select all

_k_main() // like main in a normal C program
{
	char *vidmem = (char *) 0xb8000;
	vidmem[0] = 'k';
}
link.ld

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS
{
	. = 0x7C00;
	.text : {ks.o(.text)}
	.text : {kernel.o(.text)}
	.comment : {kernel.o(.comment)}
}
Please refer the bold letters in the kernel_start.asm code and suggest corrections

Posted: Tue Jun 26, 2007 6:47 am
by t0xic
I did my first simple kernel using Bran's dev, and I wrote my own bootloader that I am still using. Grub doesn't seem to want to configure on my system, and it's nice to know exactly what your bootloader is doing.

--t0xic