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
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?