59

I am learning device drivers and Kernel programming. According to Jonathan Corbet's book, there is no main() function in device drivers.

So I two questions:

  • Why don't we need a main() function in device drivers?
  • Does the kernel itself have a main() function?

Can someone explain this to me?

Mat
  • 51,578
  • 10
  • 158
  • 140
someone
  • 693
  • 1
  • 7
  • 12

3 Answers3

89

In user space programs, main() is the entry point to the program that is called by the libc initialization code when the binary is executed. Kernel code does not have the luxury to rely on libc, as libc itself relies on the kernel syscall interface for memory allocation, I/O, process managements etc.

That said, the equivalent of main() in kernel code is start_kernel(), which is called by the bootloader after having loaded the kernel image, decompressed it into memory and setup essential hardware and memory paging. start_kernel() performs the majority of the system setup and eventually spawns the init process.

The entry point to Linux kernel modules is an init function that is registered with the kernel by calling the module_init() macro. The registered module init function is then called by kernel code through the do_initcalls() function during kernel startup.

Thomas Nyman
  • 29,912
  • 10
  • 65
  • 77
  • 11
    Thank you for recognizing the real purpose of the `main` method in C. (It is an all too commonly held misconception that the OS makes a direct call to `main`, which isn't the case and is even less the case in e.g. C++.) I'd give you another upvote if I could just for that. – user Aug 16 '13 at 08:01
  • 1
    @Thomas... Thanks for this excellent answer.... – someone Aug 16 '13 at 19:30
18

The kernel does not have a main function. main is a concept of the C language. The kernel is written in C and assembly. The entry code of the kernel is written by assembly.

The boot sequence is organized as follows:

  1. The BIOS usually loads a boot loader from a boot block device. A popular boot loader right now is grub.
  2. Grub loads a kernel image into ram, possible with an initial root device (initrd). Then code at some address is executed.
  3. The kernel image has some kernel modules, for example: filesystem modules, device drivers. The kernel image use the filesystem module to mount the root filesystem. Now the kernel can load and run all kernel modules from disk.
  4. The kernel runs initialization tasks. For example: traverse PCI bus and find all PCI devices, initialize all device drivers.
  5. Finally the kernel creates process 0 and process 1 (the init process), switches the context of CPU from ring 0 to ring 3, and starts the init process (the process id is 1). Now the kernel boot is finished!
  6. The init program runs all init scripts. All services are started. Shell is called. Users can login.

The main function is a C function. Actually main method is not the entry point of C programs. The C runtime calls many functions before main. GCC has a extend feature: constructors. Functions declared "constructor" are called before main.

For example:

/* This should not be used directly. Use block_init etc. instead. */ 
#define module_init(function, type) \
    static void _attribute__((constructor)) do_qemu_init ## function(void) { \
    register_module_init(function, type); \
} 

This macro is from the qemu project.

Edward Shen
  • 868
  • 4
  • 8
  • Main method is a c method.Actually main method is not the entry of c program.C runtime has called many methods before main method. – Edward Shen Aug 16 '13 at 06:10
  • well, bios usually loads a boot loader, and that boot loader loads a kernel image (and possibly an initrd). The code of the kernel is in the kernel image, not initrd – Stéphane Chazelas Aug 16 '13 at 06:11
  • GCC has a extend feature: constructor. The method declaration "constructor" is called before main method. For example: /* This should not be used directly. Use block_init etc. instead. */ #define module_init(function, type) \ static void __attribute__((constructor)) do_qemu_init_ ## function(void) { \ register_module_init(function, type); \ } – Edward Shen Aug 16 '13 at 06:12
  • Well,1)bios usually load a boot loader----most popular is "grub". 2) Grub load a kernel image(most popular is initrd.img) 3) kernel image has some kernel module,for example:filesystem module,device driver. kernel image use filesystem module to mount root filesystem. Now kernel can run all kernel code. 4)kernel exec init work. Finally kernel create process 0 and process 1.Switch the context of CPU from ring 0 to ring 3,and init process(The process id is 1) exec code.Now kernel booted has finished! – Edward Shen Aug 16 '13 at 06:20
  • Please edit your answer if you need to add more information. – Stéphane Chazelas Aug 16 '13 at 06:20
  • 1
    `initrd.img` *IS NOT* the kernel image. It's a set of modules loaded by the kernel at boot. Kernel images usually have names starting with "vmlinuz" but differ from distro to distro. – goldilocks Aug 16 '13 at 06:52
  • 3
    This answer is chock-full of "everything is a PC/Linux/i86" and it boots that way and the kernel is that way... Why does everybody think that's the only possible way in the world? – Jens Aug 16 '13 at 17:35
10

There is e.g. a main() function in arch/x86/boot/main.c for preparing the system to switch from the real to the protected mode but other architectures don't have such a code. There is a nice overview how booting of Linux kernel 2.6.x on x86 platform works. It's really worth reading it.

According the document HOWTO do Linux kernel development, the Linux kernel is

a freestanding C environment, with no reliance on the standard C library, so some portions of the C standard are not supported.

what according the C standard BTW means that

It is implementation-defined whether a program in a freestanding environment is required to define a 'main' function.

user
  • 28,161
  • 13
  • 75
  • 138
dsmsk80
  • 3,038
  • 1
  • 15
  • 20