2.4.2 Запуск ядра |
Предыдущая Содержание Следующая |
Запуск ядра можно разделить на следующие этапы.
Инициализация, зависящая от CPU/платформы
Если вы переносите Linux на вашу платформу, этот раздел очень важен, поскольку он знаменует важный этап в переносе BSP. Платформо-зависимая инициализация состоит из следующих шагов.
Инициализация подсистем
Она включает:
▪Инициализацию планировщика ▪Инициализацию контроллера памяти ▪Инициализацию VFS
Обратите внимание, что большая часть инициализации подсистем выполняется в функции start_kernel(). В конце этой функции ядро создаёт новый процесс, процесс инициализации, init, чтобы выполнить остальную инициализацию (инициализацию драйверов, initcalls, монтирование корневой файловой системы и переход в пространство пользователя) и текущий процесс становится фоновым процессом с идентификатором процесса, равным 0.
Инициализация драйверов
Инициализация драйверов выполняется после того, как запущен управляющий процесс и управление памятью. Это может быть сделано в контексте процесса init.
Монтирование корневой файловой системы
Напомним, что корневая файловая система является основной используемой файловой системой с помощью которой могут быть смонтированы другие файловые системы. Монтирование её знаменует собой важный процесс в стадии загрузки, так как ядро может начать свой переход в пользовательское пространство. Блочное устройство, содержащее корневую файловую систему, может быть жёстко закодировано в ядре (при сборке ядра), или оно может быть передано в качестве аргумента командной строки из загрузчика с помощью параметра загрузчика "root=". На встроенных системах обычно используются три вида корневых файловых систем:
▪Начальный электронный диск ▪Сетевая файловая система, использующая NFS ▪Файловая система на основе флеш-памяти
Обратите внимание, что корневая файловая система на основе NFS используется в основном для целей отладки; две другие используются для сборок для производства. Электронный диск имитирует блочное устройство с помощью системной памяти, поэтому он может быть использован для монтирования файловых систем при условии, что образ файловой системы копируется на него. Электронный диск может использоваться в качестве корневой файловой системы; это использование электронного диска известно как initrd (краткая форма initial ram disk). Initrd - это очень мощная концепция и имеет широкое использование, особенно на начальной стадии разработки встраиваемого Linux, когда у вас нет готового драйвера флеш-памяти, но ваши приложения готовы для тестирования (часто это тот случай, когда есть отдельные команды, разрабатывающие драйверы и приложения, и работающие параллельно). Так как же обойтись без корневой файловой системы во флеш-памяти? Можно использовать сетевую файловую систему при условии, что ваш сетевой драйвер готов; если нет, то лучшим вариантом является initrd. Создание начального электронного диска более подробно объясняется в Главе 8. Этот же раздел объясняет, как ядро монтирует initrd в качестве корневой файловой системы. Если вы хотите, чтобы ядро загрузило initrd, необходимо настроить ядро в процессе сборки с помощью параметра CONFIG_BVLK_DEV_INITRD. Как объяснялось ранее, образ initrd загружается вместе с образом ядра и ядру должен быть передан начальный и конечный адрес initrd с помощью аргументов командной строки. Как только они стали известны, ядро смонтирует корневую файловую систему, загруженную на initrd. Обычно используемыми файловыми системами являются romfs и ext2. У initrd есть много больше возможностей. Initrd является корневой файловой системой используй-и-выброси. Она может быть использована для монтирования другой корневой файловой системы. Почему это необходимо? Предположим, что корневая файловая система монтируется на устройство хранения, драйвер которого является модулем ядра. Так что он должен присутствовать в файловой системе. Это представляет собой проблему курицы и яйца; модуль должен быть в файловой системе, которая, в свою очередь, требует, чтобы сначала был загружен модуль. Чтобы обойти это, может быт использована initrd. Драйвер может быть выполнен в виде модуля в initrd; раз initrd смонтирована, то модуль драйвера может быть загружен и, следовательно, устройство хранения может быть доступно. Затем файловая система на этом устройстве хранения может быть смонтирована в качестве фактической корневой файловой системы и, наконец, initrd может быть отброшен. Ядро Linux предоставляет возможность для такого её использования и отбрасывания; оно ищет файл linuxrc в корне initrd и выполняет его. Если этот двоичный файл возвращается, то ядро предполагает, что в initrd больше необходимости нет, и оно переключается на фактическую корневую файловую систему (файл linuxrc может быть использован для загрузки модулей драйверов). NFS и файловые системы на базе флеш-памяти более подробно описаны в Главе 4. Если корневая файловая система не смонтирована, то ядро остановит выполнение и после выдачи сообщения в консоль перейдёт в режим паники:
Unable to mount root fs on device
Выполнение Initcall и освобождение памяти, используемой при инициализации
Если вы откроете скрипт компоновщика для любой архитектуры, он будет иметь раздел init. Начало этого раздела помечено с помощью __init_begin, а конец отмечен с помощью __init_end. Идея этого раздела в том, что он содержит текст и данные, которые могут быть отброшены после того, как они используются один раз во время запуска системы. Функции инициализации драйверов - это пример функции используй-и-выброси. Как только драйвер, статически скомпонованный с ядром, выполнит свою регистрацию и инициализацию, эта функция не будет вызываться снова и, следовательно, её можно отбросить. Идея состоит в том, чтобы положить все эти функции вместе, чтобы вся память, занимаемая всеми такими функциями, могла быть освобождена как большой кусок и, следовательно, будет доступна для диспетчера памяти в качестве свободных страниц. Учитывая, что память на встраиваемых системах является дефицитным ресурсом, читателю рекомендуется эффективно использовать эту концепцию. Функция или переменная используй-и-выброси объявляется с помощью директивы __init. После того, как будет сделана вся инициализация драйверов и подсистем, код запуск всю эту память освобождает. Это делается прямо перед переходом в пространство пользователя. Linux также предоставляет способ группировки функций, которые должны быть вызваны при запуске системы. Это можно сделать, объявив функцию с директивой __initcall. Эти функции автоматически вызываются во время запуска ядра, так что не требуется вставлять их в код запуска системы.
Переход в пользовательское пространство
Ядро, которое выполняется в контексте процесса инициализации, переходит в пространство пользователя, перекрывая себя (при помощи execve) исполняемым образом специальной программы, также называемом как init. Этот исполняемый файл обычно находится в корневой файловой системе в каталоге /sbin. Обратите внимание, что пользователь может указать программу инициализации, используя аргументы командной строки ядра. Однако, если ядро не может загрузить указанную пользователем программу инициализации или заданную по умолчанию, после выдачи сообщения, оно входит в состояние паники:
No init found. Try passing init= option to the kernel.
| |
Предыдущая Содержание Следующая |