Page 1 of 2

Call Simple C Kernel

Posted: Wed Oct 29, 2014 9:23 am
by dromenox
I'll start developing my first operating system and wanted to do the kernel in C because it is much easier than Assembly. I know that the bootloader has to be done in assembly but that's not the problem. The problem is that I'm not getting the bootloader to call the program in C. I know I'll have to create the libraries but for now just want to test it. I found some tutorials that used Grub to call the C but I want to build my own bootloader.

I want the kernel to run in 32-bit protected mode, but still did not understand how to do this.

I did this misery code but do not know what the right way to compile and link.

Code: Select all

[BITS 16]
[ORG 0x7C00]

extern kmain

call kmain

TIMES 510 - ($ - $$) db 0
DW 0xAA55

Code: Select all

void kmain(void)
{
	
}


If someone can give me the base I'll be able to start developing the functions like print and read the keyboard.

Thank you and sorry for these basic questions.

Re: Call Simple C Kernel

Posted: Wed Oct 29, 2014 9:49 am
by iansjack
The Wiki outlines what you need to do. http://wiki.osdev.org/Rolling_Your_Own_Bootloader

Whilst some will argue that there are good reasons to write your own bootloader, you are making life difficult for yourself when you are clearly just starting out. I'd strongly advise you to use Grub until you have learnt a whole lot more.

Re: Call Simple C Kernel

Posted: Wed Oct 29, 2014 9:54 am
by Cjreek
You have to enter protected mode before calling your kernel because your kernel is 32 bit code.
also you won't get far except your kernel fits into the first 512-2 Bytes of a floppy Disk. (Which is also very unlikely).

You probably should read some tutorials in the wiki on Bootloaders and how to start with your OS.

Re: Call Simple C Kernel

Posted: Wed Oct 29, 2014 9:57 am
by dromenox
iansjack wrote:The Wiki outlines what you need to do. http://wiki.osdev.org/Rolling_Your_Own_Bootloader

Whilst some will argue that there are good reasons to write your own bootloader, you are making life difficult for yourself when you are clearly just starting out. I'd strongly advise you to use Grub until you have learnt a whole lot more.
I understood the code of the bootloader line by line. What I dont know how to do is enter protected mode and call the kernel in C.

Re: Call Simple C Kernel

Posted: Wed Oct 29, 2014 10:14 am
by Combuster
dromenox wrote:I understood the code of the bootloader line by line. What I dont know how to do is enter protected mode and call the kernel in C.
Did you realize you're contradicting yourself?

Re: Call Simple C Kernel

Posted: Wed Oct 29, 2014 11:21 am
by iansjack
dromenox wrote:I understood the code of the bootloader line by line. What I dont know how to do is enter protected mode and call the kernel in C.
Well, if you managed to write a bootloader all by yourself then you should have no problem understanding the rest. It's all clearly detailed in the Intel Programmer's Manuals - reading these is a prerequisite for OS development on x86 processors. On the other hand, if you have just cut-and-pasted a bootloader from somewhere that probably doesn't mean you have the requisite knowledge to do the rest.

In either case, you need no further help from us. I have already pointed you to the appropriate page in the Wiki.

(I still think you should choose the easy route and use Grub to start with.)

Re: Call Simple C Kernel

Posted: Wed Oct 29, 2014 2:58 pm
by b.zaar
dromenox wrote:
iansjack wrote:The Wiki outlines what you need to do. http://wiki.osdev.org/Rolling_Your_Own_Bootloader

Whilst some will argue that there are good reasons to write your own bootloader, you are making life difficult for yourself when you are clearly just starting out. I'd strongly advise you to use Grub until you have learnt a whole lot more.
I understood the code of the bootloader line by line. What I dont know how to do is enter protected mode and call the kernel in C.
The boot loader doesn't directly call the C kernel, that's the job of an asm stub that you will need with your kernel when using your own boot loader or Grub. Your own boot loader should load the kernel and maybe a ramdisk then set up the system with a very basic protected mode environment by setting the GDT, A20 line and disabling interrupts. From the boot loader you jump to the start adress in the kernel which should point to your asm stub that then saves any information like the multiboot parameters and calls your C kernel.

Re: Call Simple C Kernel

Posted: Fri Nov 21, 2014 3:51 pm
by remy
Here is what I successed to do but with a kernel written in asm :

boot.asm :

Code: Select all

[org 0x7c00]

KERNEL_OFFSET equ 0x1000

call load_kernel

;Switch PM
cli
lgdt [gdt_descriptor] 

mov eax, cr0 
or eax, 0x1 
mov cr0, eax 

jmp 0x8:init_pm 

[bits 32]
init_pm :
	mov ax, 0x10
	mov ds, ax
	mov ss, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	
	mov ebp, 0x90000
	mov esp, ebp
	
	call KERNEL_OFFSET
	jmp $

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[bits 16]

load_kernel:
	mov bx, KERNEL_OFFSET
	mov dh, 15
	mov dl, 0
	
	mov ah, 0x02
	mov al, dh
	mov ch, 0x00
	mov dh, 0x00
	mov cl, 0x02
	int 0x13
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[bits 16]

GDT:
;null : 
	dd 0x0 
	dd 0x0

;code : 
	dw 0xffff		;Limit
	dw 0x0			;Base
	db 0x0			;Base
	db 10011010b 	;1st flag, Type flag
	db 11001111b 	;2nd flag, Limit
	db 0x0			;Base

;data : 
	dw 0xffff		
	dw 0x0			
	db 0x0
	db 10010010b 
	db 11001111b 
	db 0x0

gdt_descriptor :
	dw $ - GDT - 1 		;16-bit size
	dd GDT				;32-bit start address

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
times 510 -($-$$) db 0
dw 0xaa55
kernel.asm:

Code: Select all

[bits 32]

mov al, 'K'
mov ah, 3 ; cyan
mov edx, 0xb8000
mov [edx], ax
jmp $
I build the floppy image so that:

Code: Select all

nasm boot.asm -o boot.bin
dd if=/dev/zero of=image.bin bs=512 count=2880
dd if=boot.bin of=image.bin conv=notrunc

nasm kernel.asm -o kernel.bin
dd if=kernel.bin of=image.bin conv=notrunc bs=512 seek=1

qemu -fda image.bin -boot a
This way it works ! that's almost that...
But now, I replace kernel.asm by this kernel.c

kernel.c

Code: Select all

void main () {
	char * vga = (char *) 0xb8000 ;
	*vga = "X";
}
And the following script:

Code: Select all

nasm boot.asm -o boot.bin
dd if=/dev/zero of=image.bin bs=512 count=2880
dd if=boot.bin of=image.bin conv=notrunc

gcc -ffreestanding -m32 -c kernel32.c -o kernel.bin
dd if=kernel.bin of=image.bin conv=notrunc bs=512 seek=1

qemu -fda image.bin -boot a
Note that I'm running a 64bit Linux distro, so I use the '-m32' gcc option to compile to 32bits
But it doesn't work...... please help !

Re: Call Simple C Kernel

Posted: Fri Nov 21, 2014 4:07 pm
by seuti
remy wrote:-snip-
What about it doesn't work? Do you get an error?

Please be more descriptive and follow the Posting Checklist (http://wiki.osdev.org/Posting_Checklist)

Re: Call Simple C Kernel

Posted: Fri Nov 21, 2014 5:34 pm
by neon
The boot loader doesn't directly call the C kernel
That is not entirely correct. To see why, we must differentiate between a boot loader and boot manager. The boot loader portion is responsible for loading and setting the environment for use by a specific operating system. The boot manager is responsible for calling other boot loaders. Under these terms, the boot loader component of the software is already well aware of the requirements of the respective operating system and thus can call its entry point directly without concern. This is an important task as it allows boot loader configuration for setting kernel initialization command line flags.

The "assembly stub" that is being referred to here that is common in tutorials has nothing to do with calling the kernel program. The assembly stub exports the real entry point method in the same way that a C compiler would export _main. Thus from the perspective of the boot application, executing the entry point is the same regardless if an assembly stub is used.

With that said, nothing in this thread is about a boot loader but a boot record which is very different software and is what I think you were referring to. In other words, remy provided us a boot record not a boot loader which has very different requirements. And not even a valid boot record (many systems will not attempt to boot it.)

Given the space limitations of boot records, I suggest for remy to load a separate program and remain in real mode. This separate program is the boot loader, kernel, or executive (depending on your design goals and needs) that can include an assembly stub that switches to protected mode and goes into C.

In short, don't attempt protected mode in a boot record.

Re: Call Simple C Kernel

Posted: Fri Nov 21, 2014 5:39 pm
by remy
NB: sorry I actually switch to the wrong post, but it's okay for me, this is the same subject

While with the kernel.asm, I actually get something on the screen, there is nothing printed with the kernel.c (wich is actually black on black, but I should see it as it overrides the qemu splash screen)
I can't tell more because I have no idea why I can't jump to the C main...

Re: Call Simple C Kernel

Posted: Fri Nov 21, 2014 10:15 pm
by b.zaar
neon wrote:The "assembly stub" that is being referred to here that is common in tutorials has nothing to do with calling the kernel program. The assembly stub exports the real entry point method in the same way that a C compiler would export _main. Thus from the perspective of the boot application, executing the entry point is the same regardless if an assembly stub is used.
The stub will create a stack and push the multiboot values on to the stack before the C kernel main is called, this step could be overlooked but it's much easily writing it in asm to create the final environment for the kernel.

Re: Call Simple C Kernel

Posted: Fri Nov 21, 2014 10:20 pm
by b.zaar
@remy the C kernel may be failing if the sections are not linked and then loaded in the order you're expecting. Generate a map file to look at the output.

Re: Call Simple C Kernel

Posted: Sat Nov 22, 2014 12:15 am
by neon
b.zaar wrote:
neon wrote:The "assembly stub" that is being referred to here that is common in tutorials has nothing to do with calling the kernel program. The assembly stub exports the real entry point method in the same way that a C compiler would export _main. Thus from the perspective of the boot application, executing the entry point is the same regardless if an assembly stub is used.
The stub will create a stack and push the multiboot values on to the stack before the C kernel main is called, this step could be overlooked but it's much easily writing it in asm to create the final environment for the kernel.
That is correct. However this is for the kernel whereas the original poster is transitioning from a boot record. He does not even have a boot loader - his boot record just loads a raw sector and calls the kernel directly skipping the boot loader stage completely. In other words, he still needs to scan the headers of the image to properly align the sections and call the entry point that was exported.

Re: Call Simple C Kernel

Posted: Sat Nov 22, 2014 1:17 am
by b.zaar
neon wrote:
b.zaar wrote:
neon wrote:The "assembly stub" that is being referred to here that is common in tutorials has nothing to do with calling the kernel program. The assembly stub exports the real entry point method in the same way that a C compiler would export _main. Thus from the perspective of the boot application, executing the entry point is the same regardless if an assembly stub is used.
The stub will create a stack and push the multiboot values on to the stack before the C kernel main is called, this step could be overlooked but it's much easily writing it in asm to create the final environment for the kernel.
That is correct. However this is for the kernel whereas the original poster is transitioning from a boot record. He does not even have a boot loader - his boot record just loads a raw sector and calls the kernel directly skipping the boot loader stage completely. In other words, he still needs to scan the headers of the image to properly align the sections and call the entry point that was exported.
But the intention by both people was to call main, whether from a boot sector or a boot loader you rarely if ever call main directly. Even the multiboot specification includes an asm stub.

My advice was simply to create a stub that calls main and that is what you are saying "is not entirely correct."

I may be wrong but is there currently a kernel that links without some kind of asm stub?