Does kernel have main function?

南笙酒味 提交于 2019-11-29 06:48:36

问题


I am learning Device Driver and Kernel programming.According to Jonathan Corbet book we do not have main() function in device drivers.

#include <linux/init.h>
#include <linux/module.h>

static int my_init(void)
{
     return  0;
}

static void my_exit(void)
{
     return;
}

module_init(my_init);
module_exit(my_exit);

Here I have two questions :

  1. Why we do not need main() function in Device Drivers?
  2. Does Kernel have main() function?

回答1:


Fundamentally, there is nothing special about a routine being named main(). As alluded to above, main() serves as the entry point for an executable load module. However, you can define different entry points for a load module. In fact, you can define more than one entry point, for example, refer to your favorite dll.

From the operating system's (OS) point of view, all it really needs is the address of the entry point of the code that will function as a device driver. The OS will pass control to that entry point when the device driver is required to perform I/O to the device.

A system programmer defines (each OS has its own method) the connection between a device, a load module that functions as the device's driver, and the name of the entry point in the load module.

Each OS has its own kernel (obviously) and some might/maybe start with main() but I would be surprised to find a kernel that used main() other than in a simple one, such as UNIX! By the time you are writing kernel code you have long moved past the requirement to name every module you write as main().

Hope this helps?

Found this code snippet from the kernel for Unix Version 6. As you can see main() is just another program, trying to get started!

main()
{
     extern schar;
     register i, *p;
     /*
     * zero and free all of core
     */

     updlock = 0;
     i = *ka6 + USIZE;
     UISD->r[0] = 077406;
     for(;;) {
        if(fuibyte(0) < 0) break;
        clearsig(i);
        maxmem++;
        mfree(coremap, 1, i);
         i++;
     }
     if(cputype == 70) 
     for(i=0; i<62; i=+2) {
       UBMAP->r[i] = i<<12;
       UBMAP->r[i+1] = 0;
      }

    // etc. etc. etc.



回答2:


start_kernel

On 4.2, start_kernel from init/main.c is a considerable initialization process and could be compared to a main function.

It is the first arch independent code to run, and sets up a large part of the kernel. So much like main, start_kernel is preceded by some lower level setup code (done in the crt* objects in userland main), after which the "main" generic C code runs.

How start_kernel gets called in x86_64

arch/x86/kernel/vmlinux.lds.S, a linker script, sets:

ENTRY(phys_startup_64)

and

phys_startup_64 = startup_64 - LOAD_OFFSET;

and:

#define LOAD_OFFSET __START_KERNEL_map

arch/x86/include/asm/page_64_types.h defines __START_KERNEL_map as:

#define __START_KERNEL_map  _AC(0xffffffff80000000, UL)

which is the kernel entry address. TODO how is that address reached exactly? I have to understand the interface Linux exposes to bootloaders.

arch/x86/kernel/vmlinux.lds.S sets the very first bootloader section as:

.text :  AT(ADDR(.text) - LOAD_OFFSET) {
    _text = .;
    /* bootstrapping code */
    HEAD_TEXT

include/asm-generic/vmlinux.lds.h defines HEAD_TEXT:

#define HEAD_TEXT  *(.head.text)

arch/x86/kernel/head_64.S defines startup_64. That is the very first x86 kernel code that runs. It does a lot of low level setup, including segmentation and paging.

That is then the first thing that runs because the file starts with:

.text
__HEAD
.code64
.globl startup_64

and include/linux/init.h defines __HEAD as:

#define __HEAD      .section    ".head.text","ax"

so the same as the very first thing of the linker script.

At the end it calls x86_64_start_kernel a bit awkwardly with and lretq:

movq    initial_code(%rip),%rax
pushq   $0      # fake return address to stop unwinder
pushq   $__KERNEL_CS    # set correct cs
pushq   %rax        # target address in negative space
lretq

and:

.balign 8
GLOBAL(initial_code)
.quad   x86_64_start_kernel

arch/x86/kernel/head64.c defines x86_64_start_kernel which calls x86_64_start_reservations which calls start_kernel.




回答3:


Several ways to look at it:

  1. Device drivers are not programs. They are modules that are loaded into another program (the kernel). As such, they do not have a main() function.

  2. The fact that all programs must have a main() function is only true for userspace applications. It does not apply to the kernel, nor to device drivers.




回答4:


With main() you propably mean what main() is to a program, namely its "entry point".

For a module that is init_module().

From Linux Device Driver's 2nd Edition:

Whereas an application performs a single task from beginning to end, a module registers itself in order to serve future requests, and its "main" function terminates immediately. In other words, the task of the function init_module (the module's entry point) is to prepare for later invocation of the module's functions; it's as though the module were saying, "Here I am, and this is what I can do." The second entry point of a module, cleanup_module, gets invoked just before the module is unloaded. It should tell the kernel, "I'm not there anymore; don't ask me to do anything else."




回答5:


Yes, the Linux kernel has a main function, it is located in arch/x86/boot/main.c file. But Kernel execution starts from arch/x86/boot/header.S assembly file and the main() function is called from there by "calll main" instruction. Here is that main function:

void main(void)
{
    /* First, copy the boot header into the "zeropage" */
    copy_boot_params();

    /* Initialize the early-boot console */
    console_init();
    if (cmdline_find_option_bool("debug"))
        puts("early console in setup code.\n");

    /* End of heap check */
    init_heap();

    /* Make sure we have all the proper CPU support */
    if (validate_cpu()) {
        puts("Unable to boot - please use a kernel appropriate "
             "for your CPU.\n");
        die();
    }

    /* Tell the BIOS what CPU mode we intend to run in. */
    set_bios_mode();

    /* Detect memory layout */
    detect_memory();

    /* Set keyboard repeat rate (why?) and query the lock flags */
    keyboard_init();

    /* Query Intel SpeedStep (IST) information */
    query_ist();

    /* Query APM information */
#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
    query_apm_bios();
#endif

    /* Query EDD information */
#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
    query_edd();
#endif

    /* Set the video mode */
    set_video();

    /* Do the last things and invoke protected mode */
    go_to_protected_mode();
}



回答6:


While the function name main() is just a common convention (there is no real reason to use it in kernel mode) the linux kernel does have a main() function for many architectures, and of course usermode linux has a main function.

Note the the OS runtime loads the main() function to start an app, when an operating system boots there is no runtime, the kernel is simply loaded to a address by the boot loader which is loaded by the MBR which is loaded by the hardware. So while a kernel may contain a function called main it need not be the entry point.

See Also:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms633559%28v=vs.85%29.aspx

Linux kernel source:

x86: linux-3.10-rc6/arch/x86/boot/main.c

arm64: linux-3.10-rc6/arch/arm64/kernel/asm-offsets.c



来源:https://stackoverflow.com/questions/18266063/does-kernel-have-main-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!