2013-08-16 2 views
13

Я изучаю Device Driver и Kernel программирование. Согласно книге Джонатана Корбета, у нас нет функции 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. Имеет ли Kernel main() функция?
+0

Если никто не знает ответа, почему вы голосуете за мой вопрос? – someone

+1

С 'main()' вы, возможно, означаете, что означает 'main()' для программы, а именно ее «точка входа»? – alk

+0

@ alk..Book говорит, что мы имеем 'init_module' как точку входа и' exit_module' как точку выхода. Я исхожу из фона 'C' и узнаю, что никакая программа не может выполняться без функции' main() '. поэтому просто хочу знать, как работают драйверы без 'main()'. – someone

ответ

11

По существу, нет ничего особенного в рутине, которая называется main(). Как указано выше, main() служит точкой входа для исполняемого модуля загрузки. Однако вы можете определить разные точки входа для модуля нагрузки. Фактически, вы можете определить более одной точки входа, например, обратиться к вашей любимой dll.

С точки зрения операционной системы (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. 
+0

JackCColeman ... Так что код ядра может иметь main(). Если вы можете предоставить некоторый фрагмент такого кода, это будет большой помощью. – someone

+0

@ Кришна, я не сделал ** НЕ ** означает подразумевать это. Скорее, при написании ядра программист достаточно опытен, чтобы знать, как определить точку входа модуля в коде и в редактор связей, и ** НЕ ** связан с использованием соглашения 'main()', используемого в приложения (т.е. не-ядрового кода). – JackCColeman

+0

@JackCColeman ... Спасибо ... – someone

2

С main() вы, возможно, означаете, что main() относится к программе, а именно к ее «точке входа».

Для модуля, который является init_module().

От Linux Device Driver's 2nd Edition:

В то время как приложение выполняет одну задачу от начала до конца, модуль регистрирует себя для того, чтобы обслуживать будущие запросы, а его «основная» функция завершается немедленно. Другими словами, задача функции init_module (точка входа модуля) заключается в подготовке для последующего вызова функций модуля; это как если бы модуль говорил: «Вот я, и это то, что я могу сделать». Вторая точка входа модуля, cleanup_module, вызывается непосредственно перед выгрузкой модуля. Он должен сказать ядро: «Меня больше нет, не просите меня сделать что-нибудь еще».

+0

Я уже сказал вам, что я хочу .. Пожалуйста, прочтите мой комментарий. – someone

+0

вы меня голосуете за мой вопрос? – someone

+0

@krishna: Нет ....! – alk

3

Несколько способов смотреть на него:

  1. Драйверы устройств не являются программами.Это модули, которые загружаются в другую программу (ядро). Таким образом, они не имеют функции main().

  2. Тот факт, что все программы должны иметь функцию main(), применим только для приложений пользовательского пространства. Это не относится к ядру и драйверам устройств.

+0

«... только для приложений для пользователей ...», потому что они в основном связаны с libc, который выполняет инициализацию, а затем _calls_ main. Имя main() - это просто соглашение libc. – linuxfan

0

В то время как имя функции Main() просто общее соглашение (нет никакой реальной причины, чтобы использовать его в режиме ядра) ядро ​​Linux действительно имеет основную функцию() для многих архитектур, и, конечно же, UserMode linux имеет основную функцию.

Обратите внимание, что время выполнения ОС загружает функцию main() для запуска приложения, когда загружается операционная система, нет времени выполнения, ядро ​​просто загружается в адрес загрузчиком, который загружается MBR, который загружается аппаратное обеспечение. Поэтому, когда ядро ​​может содержать функцию main, она не должна быть точкой входа.

Смотрите также:

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

Linux исходный код ядра:

x86: линукс-3,10-rc6/арка/x86/загрузки/main.c

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

1

start_kernel

В 4.2, start_kernel от init/main.c - значительный процесс инициализации и может быть сравнен с функцией main.

Это первый независимый от дуги код и устанавливает большую часть ядра.

Это, однако, не первый код ядра для запуска.

Как start_kernel вызывается в x86_64

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 устанавливает самую первую секцию загрузчика как:

.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, который вызывает x86_64_start_reservations который вызывает start_kernel.

+1

Интересный ответ. Я голосую. и что делает в файле /arch/um/kernel/um_arch.c функция linux_main (int argc, char ** argv), чем? – zviad

+1

@zviad Я понятия не имею! Но поскольку он находится внутри 'arch/um', я думаю, что это пользовательский режим Linux, https://en.wikipedia.org/wiki/User-mode_Linux, который выглядит круто, но я думаю, что он никогда не используется в обычной работе. –

1

Да, ядро ​​Linux имеет основную функцию, оно находится в файле arch/x86/boot/main.c. Но выполнение ядра начинается с файла arch/x86/boot/header.S и функции main() вызывается отсюда командой «calll main». Вот эта основная функция:

Смежные вопросы