内核有主要function吗?

我正在学习Device DriverKernel编程。根据乔纳森科比特书,我们没有在设备驱动程序中的main()函数。

 #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); 

这里我有两个问题:

  1. 为什么我们不需要在设备驱动程序中使用main()函数?
  2. 内核是否有main()函数?

Solutions Collecting From Web of "内核有主要function吗?"

从根本上说,一个名为main()的例程没有什么特别之处。 如上所述, main()作为可执行加载模块的入口点。 但是,您可以为加载模块定义不同的入口点。 实际上,您可以定义多个入口点,例如,引用您最喜欢的dll。

从操作系统(OS)的角度来看,它真正需要的是将用作设备驱动程序的代码入口点的地址。 当设备驱动程序需要对设备执行I / O时,操作系统会将控制权交给该入口点。

系统程序员定义(每个OS都有自己的方法)设备,用作设备驱动程序的加载模块和加载模块中入口点的名称之间的连接。

每个操作系统都有自己的内核(显然),有些可能/可能以main()开头,但是如果找到一个使用main()的内核,而不是一个简单的内核,比如UNIX! 当你编写内核代码的时候,你已经经历了将你写的所有模块命名为main()

希望这可以帮助?

从Unix版本6的内核找到这个代码片段。正如你可以看到main()只是另一个程序,试图开始!

 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. 

几种方法来看看它:

  1. 设备驱动程序不是程序。 他们是加载到另一个程序(内核)的模块。 因此,他们没有main()函数。

  2. 所有程序必须具有main()函数的事实仅适用于用户空间应用程序。 它不适用于内核,也不适用于设备驱动程序。

main()你可以表示什么main()是一个程序,即它的“入口点”。

对于init_module()模块。

从Linux设备驱动程序的第二版 :

尽管应用程序从头到尾执行单个任务,但是一个模块注册自身以便为将来的请求提供服务,而其“主”功能立即终止。 换句话说,函数init_module(模块的入口点)的任务是准备稍后调用模块的函数; 就好像模块在说:“我在这里,这就是我能做的。” 模块的第二个入口点cleanup_module在模块卸载之前被调用。 它应该告诉内核:“我不在那里了,不要求我做别的事情。”

是的,Linux内核有一个主要功能,它位于arch / x86 / boot / main.c文件中。 但内核执行从arch / x86 / boot / header.S开始,通过“calll main”指令从那里调用汇编文件和main()函数。 这是主要功能:

 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(); } 

start_kernel

在4.2中, init/main.c中的start_kernel是一个相当可观的初始化过程,可以和main函数进行比较。

这是第一个独立运行的代码,并且设置了很大一部分内核。

但是,它并不是第一个运行的内核代码。

如何在x86_64中调用start_kernel

arch/x86/kernel/vmlinux.lds.S ,链接器脚本,设置:

 ENTRY(phys_startup_64) 

 phys_startup_64 = startup_64 - LOAD_OFFSET; 

和:

 #define LOAD_OFFSET __START_KERNEL_map 

arch/x86/include/asm/page_64_types.h__START_KERNEL_map定义为:

 #define __START_KERNEL_map _AC(0xffffffff80000000, UL) 

这是内核入口地址。 TODO这个地址如何到达? 我必须了解Linux暴露给引导程序的界面。

arch/x86/kernel/vmlinux.lds.S将第一个bootloader部分设置为:

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

include/asm-generic/vmlinux.lds.h定义了HEAD_TEXT

 #define HEAD_TEXT *(.head.text) 

arch/x86/kernel/head_64.S定义了startup_64 。 这是运行的第一个x86内核代码。 它做了很多低级别的设置,包括分割和分页。

那么这是第一件事,因为该文件开始于:

 .text __HEAD .code64 .globl startup_64 

并且include/linux/init.h__HEAD定义为:

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

所以就像链接器脚本的第一件事一样。

最后,它调用x86_64_start_kernel有点笨拙,而且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 

和:

 .balign 8 GLOBAL(initial_code) .quad x86_64_start_kernel 

arch/x86/kernel/head64.c定义了x86_64_start_kernel ,它调用了调用start_kernel x86_64_start_reservations

虽然函数名称main()只是一个常用的约定(在内核模式下没有真正的理由使用它),但linux内核对许多体系结构都有一个main()函数,当然usermode linux有一个main函数。

请注意,操作系统运行时加载main()函数来启动应用程序,当操作系统启动时没有运行时,内核通过由硬件加载的MBR加载的启动加载器简单地加载到地址。 所以当一个内核可能包含一个名为main的函数时,它不一定是入口点。

也可以看看:

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

Linux内核源码:

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

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