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?
--t0xic
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
. 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
), 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