Внутреннее устройство ядра Linux 2.4

       

Разбор командной строки


Давайте посмотрим как выполняется разбор командной строки, передаваемой ядру на этапе загрузки:

  • LILO (или BCP) воспринимает командную строку через сервис клавиатуры BIOS-а, и размещает ее в физической памяти.
  • Код arch/i386/kernel/head.S копирует первые 2k в нулевую страницу (zeropage). Примечательно, что текущая версия LILO (21) ограничивает размер командной строки 79-ю символами. Это не просто ошибка в LILO (в случае включенной поддержки EBDA(LARGE_EBDA (Extended BIOS Data Area) --необходима для некоторых современных мультипроцессорных систем. Заставляет LILO загружаться в нижние адреса памяти, с целью оставить как можно больше пространства для EBDA, но ограничивает максимальный размер для "малых" ядер - т.е. "Image" и "zImage" прим. перев. )). Werner пообещал убрать это ограничение в ближайшее время. Если действительно необходимо передать ядру командную строку длиной более 79 символов, то можно использовать в качестве загрузчика BCP или подправить размер командной строки в функции arch/i386/kernel/setup.c:parse_mem_cmdline().
  • arch/i386/kernel/setup.c:parse_mem_cmdline()

    (вызывается из setup_arch(), которая в свою очередь вызывается из start_kernel()), копирует 256 байт из нулевой страницы в saved_command_line, которая отображается в /proc/cmdline. Эта же функция обрабатывает опцию "mem=", если она присутствует в командной строке, и выполняет соответствующие корректировки параметра VM.

  • далее, командная строка передается в parse_options() (вызывается из start_kernel()), где обрабатываются некоторые "in-kernel" параметры (в настоящее время "init=" и параметры для init) и каждый параметр передается в checksetup().
  • checksetup() проходит через код в ELF-секции .setup.init и вызывает каждую функцию, передавая ей полученное слово. Обратите внимание, что если функция, зарегистрированная через __setup(), возвращает 0, то становится возможной передача одного и того же "variable=value" нескольким функциям. Одни из них воспринимают параметр как ошибочный, другие -как правильный. Jeff Garzik говорит по этом у поводу: "hackers who do that get spanked :)" (не уверен в точности перевода, но тем не менее "программисты, работающие с ядром, иногда получают щелчок по носу". прим. перев.). Почему? Все зависит от порядка компоновки ядра, т.е. в одном случае functionA вызывается перед functionB, порядок может быть изменен с точностью до наоборот, результат зависит от порядка следования вызовов.

  • Для написания кода, обрабатывающего командную строку, следует использовать макрос __setup(), определенный в include/linux/init.h:

    /* * Used for kernel command line parameter setup */ struct kernel_param { const char *str; int (*setup_func)(char *); };

    extern struct kernel_param __setup_start, __setup_end;

    #ifndef MODULE #define __setup(str, fn) \ static char __setup_str_##fn[] __initdata = str; \ static struct kernel_param __setup_##fn __initsetup = \ { __setup_str_##fn, fn }

    #else #define __setup(str,func) /* nothing */ endif

    Ниже приводится типичный пример, при написании собственного кода (пример взят из реального кода драйвера BusLogic HBA drivers/scsi/BusLogic.c):

    static int __init BusLogic_Setup(char *str) { int ints[3];

    (void)get_options(str, ARRAY_SIZE(ints), ints);

    if (ints[0] != 0) { BusLogic_Error("BusLogic: Obsolete Command Line Entry " "Format Ignored\n", NULL); return 0; } if (str == NULL *str == '\0') return 0; return BusLogic_ParseDriverOptions(str); }

    __setup("BusLogic=", BusLogic_Setup);

    Обратите внимание, что __setup() не делает ничего в случае, когда определен литерал MODULE, так что, при необходимости обработки командной строки начальной загрузки как модуль, так и статически связанный код, должен вызывать функцию разбора параметров "вручную" в функции инициализации модуля. Это так же означает, что возможно написание кода, который обрабатывает командную строку, если он скомпилирован как модуль, и не обрабатывает, когда скомпилирован статически, и наоборот.

    Назад


    Содержание раздела