Согласно Dolphin, /boot/vmlinuz — это. Исполняемый файл DOS/Windows.
Какие ассоциации файлов где нарушены? С какого перепугу он так думает? При чём тут винды с досами? Открыл Свойства файла по правой кнопке, там «Параметры типа файла», он говорит, что это формат «*.exe, *.com».
ChekPuk ★★★
01.11.20 20:43:15 MSK
открой для себя EFISTUB
anonymous
( 01.11.20 20:44:28 MSK )
Ответ на: комментарий от anonymous 01.11.20 20:44:28 MSK
И? Почему он не пишет, что это линуксовый исполняемый файл?
ChekPuk ★★★
( 01.11.20 20:45:20 MSK ) автор топика
Ответ на: комментарий от ChekPuk 01.11.20 20:45:20 MSK
потому, что стандарт требует PE-заголовок в файле, или что-то такое
anonymous
( 01.11.20 20:46:03 MSK )
Очевидно, что едро у тебя собрано с ключиком про ефистаб, а значит является ефи-приложением, а все ефи-приложения у нас в формате Portable Executable, т.е. исполняемый файл DOS/Windows. Сам можешь его открыть и увидеть сигнатуру — первые два байта MZ.
Глава 4. Ядро
< Прим. пер.: если вас интересует процесс сборки самого ядра и связанных с нею подробностей, рекомендуем вам ознакомиться с нашим переводом книги Программирование ядра Linux Кайваня Н Биллимория, изданной Packt Publishing в марте 2021. >
Загрузка своего ядра в оперативную память
Это занимательная глава. До сих пор мы наблюдали, что вплоть до данного этапа GRUB 2 полностью контролировал нашу процедуру запуска. Теперь он обязан передать управление своему ядру. В этой главе мы увидим как и куда наш начальный загрузчик загружает своё ядро. Иными словами, как извлекается само ядро? Далее мы рассмотрим относящиеся к запуску задач успешно выполняемых соответствующим ядром Linux и, в конце, как это ядро запускает systemd .
Тот исходный код ядра, который применяется в этой главе это версия kernel-5.4.4 . Когда я писал эту книгу это был самый последний код из доступных; отсылаем к https://www.kernel.org/. Исключительным ресурсом по этой теме является Inside Linux, написанная 0xAX. Я почерпнул многое из неё, и я уверен что вы также сделаете это.
Для передачи управления своему ядру нашему начальному загрузчику приходится добиться двую главных моментов.
- Загрузить это ядро в оперативную память
- Установить некие из имеющихся полей этого ядра согласно протоколу запуска.
Полный протокол доступен по https://www.kernel.org/doc/Documentation/x86/boot.txt. Первоначальный протокол запуска был определён никем иным как Линусом Торвальдсом.
~ ~ | Protected-mode kernel | 100000 +-------------------------------+ | I/O memory hole | 0A0000 +-------------------------------+ | Reserved for BIOS | Остаётся как можно дольше неиспользованным ~ ~ | Command line | (Может также быть ниже отметки X+10000) X+10000 +-------------------------------+ | Stack/heap | For use by the kernel real-mode code. X+08000 +-------------------------------+ | Kernel setup | Код ядра реального режима. | Kernel boot sector | Наследуемый загрузочный сектор ядра. X +-------------------------------+ | Boot loader |
Согласно установленному протоколу запуска именно начальный загрузчик обязан передать или установить некоторые поля в заголовке своего ядра. Этими полями являются название корневого устройства, параметры монтирования, такие как ro или rw , название initramfs, его размер и т.п. Эти же поля имеют название параметров командной строки ядра и мы уже знаем, что эти параметры командной строки ядра передаются GRUB/ соответствующим начальным загрузчиком в его ядро.
GRUB не будет загружать своё ядро ( /boot/vmlinuz ) в любом случайно выбранном месте; оно всегда будет загружаться в неком конкретном месте. Значение конкретного места будет меняться для каждого дистрибутива Linux и используемой вами версии для установленной архитектуры ЦПУ в вашей системе. vmlinuz является неким архивным файлом и этот архив составлен из трёх частей.
Vmlinuz (bZimage) = Header + kernel setup code + vmlinux (actual compressed kernel) (part-1) (part-2) (part-3)
После загрузки ядра в память
Теперь нам необходимо представить, что GRUB 2 загрузил своё ядро в оперативную память в особом месте. Вот шаги самого начального уровня, выполняемые архивным файлом vmlinuz сразу после его загрузки в память.
- Как только наш начальный загрузчик загружает необходимое ядро в оперативную память в конкретное место, запускается исполняемый файл, сделанный из arch/x86/boot/header.S .
- Путаница случается когда vmlinuz является неким архивом, а наш начальный загрузчик ещё пока не распаковал его. Наш начальный загрузчик только загрузил это ядро в конкретное место. Тогда как же этот код внутри файла своего архива vmlinuz способен выполняться?
- Сначала мы рассмотрим короткий ответ, а длинный ответ мы рассмотрим в своём разделе Что распаковывает vmlinuz? в этой главе. Итак, короткий ответ состоит в исполняемом файле, сделанном из файла /x86/boot/header.S не является таким архивом; вместо этого он выступает частью заголовка который выполняет задачу kernel_setup . Этот заголовок пребывает вне архива.
Vmlinuz (bZimage) = Header + kernel setup code + vmlinux (actual compressed kernel) --->Outside of archiveInside archiveheader.s file is here
- Налаживает регистры своего сегмента
- Устанавливает стек и BSS
В каждой главе некая блок- схема снабжает нас чётким пониманием относительно изученного нами и, с точки зрения запуска,чего мы достигли. Рисунок 4-1 показывает самое начало той блок-схемы, которую мы сконструируем в этой главе по мере её развития. Она отображает те действия, которые выполняются кодом kernel_setup из header.s ..
Рисунок 4-1

Предпринимаемые kernel_setup шаги
Vmlinuz (bZimage) = Header + kernel setup code + vmlinux (actual compressed kernel) --->Outside of archiveInside archivemain.c file is here 134 void main(void) 135 < 136 /* First, copy the boot header into the "zeropage" */ 137 copy_boot_params(); 138 139 /* Initialize the early-boot console */ 140 console_init(); 141 if (cmdline_find_option_bool("debug")) 142 puts("early console in setup code\n"); 143 144 /* End of heap check */ 145 init_heap(); 146 147 /* Make sure we have all the proper CPU support */ 148 if (validate_cpu()) < 149 puts("Unable to boot - please use a kernel appropriate " 150 "for your CPU.\n"); 151 die(); 152 >153 154 /* Tell the BIOS what CPU mode we intend to run in. */ 155 set_bios_mode(); 156 157 /* Detect memory layout */ 158 detect_memory(); 159 160 /* Set keyboard repeat rate (why?) and query the lock flags */ 161 keyboard_init(); 162 163 /* Query Intel SpeedStep (IST) information */ 164 query_ist(); 165 166 /* Query APM information */ 167 #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) 168 query_apm_bios(); 169 #endif 170 171 /* Query EDD information */ 172 #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) 173 query_edd(); 174 #endif 175 176 /* Set the video mode */ 177 set_video(); 178 179 /* Do the last things and invoke protected mode */ 180 go_to_protected_mode(); 181 >
Как вы можете видеть, исходный код main.c отвечает за следующее:
- Он копирует установленные параметры запуска (параметры командной строки своего ядра) из своего начального загрузчика. Функция copy_boot_params будет применена для копирования следующих параметров запуска, передаваемых его начальным загрузчиком:
vfs.zfs.vdev.cache.size=debug, earlyprintk, ro, root, ramdisk_image, ramdisk_size и т.п.
[ 0.000000] BIOS-provided physical RAM map: [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x0000000000057fff] usable [ 0.000000] BIOS-e820: [mem 0x0000000000058000-0x0000000000058fff] reserved [ 0.000000] BIOS-e820: [mem 0x0000000000059000-0x000000000009cfff] usable [ 0.000000] BIOS-e820: [mem 0x000000000009d000-0x00000000000fffff] reserved [ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000007e5f7fff] usable [ 0.000000] BIOS-e820: [mem 0x000000007e5f8000-0x000000007e5f8fff] ACPI NVS [ 0.000000] BIOS-e820: [mem 0x000000007e5f9000-0x000000007e5f9fff] reserved [ 0.000000] BIOS-e820: [mem 0x000000007e5fa000-0x0000000087f62fff] usable [ 0.000000] BIOS-e820: [mem 0x0000000087f63000-0x000000008952bfff] reserved [ 0.000000] BIOS-e820: [mem 0x000000008952c000-0x0000000089599fff] ACPI NVS [ 0.000000] BIOS-e820: [mem 0x000000008959a000-0x00000000895fefff] ACPI data [ 0.000000] BIOS-e820: [mem 0x00000000895ff000-0x00000000895fffff] usable [ 0.000000] BIOS-e820: [mem 0x0000000089600000-0x000000008f7fffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000f0000000-0x00000000f7ffffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fe010000-0x00000000fe010fff] reserved [ 0.000000] BIOS-e820: [mem 0x0000000100000000-0x000000086e7fffff] usable
Рисунок 4-2

Наша блок- схема
Защищённый режим
Вплоть до этого момента мы работали в реальном режиме, который обладает ограничениями в адресации 20 битами, так как он не способен выполнять доступ к памяти свыше МБ. При помощи функции go_to_protected_mode() наше ядро переключило свой ЦПУ с реального режима на его защищённый режим. Защищённый режим обладает ограничением в адресации в 32 бита, а потому его ЦПУ способен выполнять доступ вплоть до 4 ГБ памяти. Проще говоря, в реальном режиме будут исполняться лишь те программы, которые обладают 16- битным наборов инструкций, к примеру, сам BIOS. В защищённом режиме будут запускаться только 32- битные программы. В защищённом режиме имеющееся ядро выполняет некоторые относящиеся к аппаратным средствам задачи и далее запускаем ЦПУ в длинном режиме.
Обратите,пожалуйста внимание, что эта книга следует архитектуре x86 Intel и обсуждения, относящиеся к реальному, защищённому и длинному режимам основаны на 64- битной архитектуре x86 Intel.
Длинный режим
Длинный режим не накладывает никаких ограничений на свой ЦПУ. Он способен применять всю установленную память. Помещение своег ЦПУ в длинный режим будет достигаться файлом head_64.S из arch/x86/boot/compressed/head_64.S . Он отвечает за следующее:
- Подготовку к длинному режиму означает, что он проверяет поддеривается ли длинный режим или нет.
- Вход вдлинный режим.
- Распаковку своего ядра.
Приводимые ниже функции вызываются из файла ассемблера head_64.S :
$ cat arch/x86/boot/compressed/head_64.S | grep -i call call 1f call verify_cpu call get_sev_encryption_bit call 1f call 1f call .Ladjust_got * this function call. call paging_prepare * this function call. call cleanup_trampoline call 1f call .Ladjust_got call 1f * Relocate efi_config->call(). call make_boot_params call 1f * Relocate efi_config->call(). call efi_main call extract_kernel /* returns kernel location in %rax */ .quad efi_call
verify_cpu
Проверяет наличие длинного режима ЦПУ
make_boot_params
Заботится о передаваемых начальным загрузчиком параметров времени запуска
efi_main
Относящееся к встроенному ПО наполнение
extract_kernel
Эта функция определена в arch/x86/boot/compressed_misc.c
Именно эта функция распаковывает vmlinux из vmlinuz
Для лучшего понимания обратитесь, пожалуйста к показанной на Рисунке 4-3 блок- схеме.
Рисунок 4-3

Наша обновлённая блок- схема
Постойте, однако: если наше ядро ещё пока не распаковано, тогда как мы продолжаем выполнение в данный момент? Тут настаёт время нашего длинного ответа.
Что распаковывает vmlinuz?
К данному моменту мы осознали, что именно GRUB загрузил необходимое ядро в память, но в то же самое время, мы отметили, что наш образ vmlinuz содержится в неком архиве. Итак, что же распаковывает этот образ? Делает ли это GRUB?
Нет, это не GRUB. Вместо этого именно само ядро распаковывает себя. Да, я сказал что именно само ядро распаковывает это ядро. Возможно, vmlinuz единственный в мире файл операционной системы, который сам извлекает себя. Но как это возможно распаковывать себя самостоятельно? Чтобы понять это давайте для начала разберёмся с vmlinuz .
" vm " из vmlinuz это сокращение для "virtual memory". на самых ранних стадиях разработки Linux само понятие виртуальной памяти ещё не было проработано, а потому когда оно было добавлено эти символы " vm " и были добавлены к общему названию ядра Linux. Символ " z " это сокращение для ziiped файла.
$ file vmlinuz-5.0.9-301.fc30.x86_64 vmlinuz-5.0.9-301.fc30.x86_64: Linux kernel x86 boot executable bzImage, version 5.0.9-301.fc30.x86_64 (mockbuild@bkernel04.phx2.fedoraproject.org) #1 SMP Tue Apr 23 23:57:35 U, RO-rootFS, swap_dev 0x8, Normal VGA
Как вы можете видеть vmlinuz это bzImage ( bzImage сокращение для "big zimage"). vmlinuz это сжатый файл реального исполняемого файла vmlinuz . Вы не сможете распаковать этот файл при помощи gunzip/bunzip или даже tar . Самым простым способом распаковки vmlinuz является использование файла сценария extract-vmlinuz , предоставляемого пакетом kernel-devel (в случае Fedora). Этот файл будет представлен в /usr/src/kernels//scripts/extract-vmlinux .
# ./extract-vmlinux /boot/vmlinuz-5.3.7-301.fc31.x86_64 >gt; /boot/temp/vmlinux # file /boot/temp/* /boot/temp/vmlinux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=ec96b29d8e4079950644230c0b7868942bb70366, stripped
Существуют разнообразные способы раскрытия файлов ядра vmlinux и vmlinuz .
$ xxd vmlinux | less $ objdump vmlinux | less $ objdump vmlinux -D | less $ hexdump vmlinux | less $ od vmlinux | less
Мы воспользуемся командой od с некими переключателями для открытия своего файла vmlinuz .
$ od -A d -t x1 vmlinuz-5.0.9-301.fc30.x86_64 | less 0000000 4d 5a ea 07 00 c0 07 8c c8 8e d8 8e c0 8e d0 31 0000016 e4 fb fc be 40 00 ac 20 c0 74 09 b4 0e bb 07 00 0000032 cd 10 eb f2 31 c0 cd 16 cd 19 ea f0 ff 00 f0 00 0000048 00 00 00 00 00 00 00 00 00 00 00 00 82 00 00 00 0000064 55 73 65 20 61 20 62 6f 6f 74 20 6c 6f 61 64 65 0000080 72 2e 0d 0a 0a 52 65 6d 6f 76 65 20 64 69 73 6b 0000096 20 61 6e 64 20 70 72 65 73 73 20 61 6e 79 20 6b 0000112 65 79 20 74 6f 20 72 65 62 6f 6f 74 2e 2e 2e 0d 0000128 0a 00 50 45 00 00 64 86 04 00 00 00 00 00 00 00 0000144 00 00 01 00 00 00 a0 00 06 02 0b 02 02 14 80 37 0000160 8e 00 00 00 00 00 80 86 26 02 f0 48 00 00 00 02 0000176 00 00 00 00 00 00 00 00 00 00 20 00 00 00 20 00 0000192 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000208 00 00 00 c0 b4 02 00 02 00 00 00 00 00 00 0a 00 0000224 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 * 0000256 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00 00 0000272 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000288 00 00 00 00 00 00 00 00 00 00 80 39 8e 00 48 09 0000304 00 00 00 00 00 00 00 00 00 00 2e 73 65 74 75 70 0000320 00 00 e0 43 00 00 00 02 00 00 e0 43 00 00 00 02 0000336 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 0000352 50 60 2e 72 65 6c 6f 63 00 00 20 00 00 00 e0 45 0000368 00 00 20 00 00 00 e0 45 00 00 00 00 00 00 00 00 0000384 00 00 00 00 00 00 40 00 10 42 2e 74 65 78 74 00 0000400 00 00 80 f3 8d 00 00 46 00 00 80 f3 8d 00 00 46 0000416 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 0000432 50 60 2e 62 73 73 00 00 00 00 80 86 26 02 80 39 0000448 8e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000464 00 00 00 00 00 00 80 00 00 c8 00 00 00 00 00 00 0000480 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff 0000496 ff 22 01 00 38 df 08 00 00 00 ff ff 00 00 55 aa 0000512 eb 66 48 64 72 53 0d 02 00 00 00 00 00 10 c0 37 0000528 00 01 00 80 00 00 10 00 00 00 00 00 00 00 00 00 0000544 00 00 00 00 50 5a 00 00 00 00 00 00 ff ff ff 7f 0000560 00 00 00 01 01 15 3f 00 ff 07 00 00 00 00 00 00 0000576 00 00 00 00 00 00 00 00 b1 03 00 00 11 f3 89 00 0000592 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 0000608 00 c0 b4 02 90 01 00 00 8c d8 8e c0 fc 8c d2 39 0000624 c2 89 e2 74 16 ba 50 58 f6 06 11 02 80 74 04 8b # od -A d -t x1 /boot/vmlinuz-5.3.7-301.fc31.x86_64 | grep -i '1f 8b 08 00' 0018864 8f 1f 8b 08 00 00 00 00 00 02 03 ec fd 79 7c 54
итак, по адресу 0018864 начинается реальное ядро ( vmlinux ), в то время как сам файл vmlinuz стартует с 0000000 . Это означает, что с 0000000 по 0018864 то что у нас имеется, это соответствующий заголовок нашего файла, такой как header.S , misc.c и т.п.. Именно он и распаковывает само реальное ядро ( vmlinux ) из vmlinuz . Вы можете рассматривать некий заголовок подобным нашлёпке поверх исполняемого файла vmlinux и когда эта нашлёпка доступна, он превращается в vmlinuz ю В своём следующем разделе мы увидим как соответствующая процедура ядра распаковыает vmlinuz .
extract_kernel
Давайте вернёмся назад к своей функции extract_kernel из arch/x86/boot/compressed/misc.c .
asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, unsigned char *input_data, unsigned long input_len, unsigned char *output, unsigned long output_len)
Как вы можете видеть, эта функция принимает семь параметров.
rmode
Указатель на структуру boot_params , которая заполняется запускающим начальным загрузчиком.
heap
Указатель на файл boot_params , который представляет стартовый адрес самой ранней кучи запуска.
input_data
Указатель на наало самого схатого ядра или, иначе говоря, указатель на arch/x86/boot/compressed/vmlinux.bin.bz2 .
input_len
Размер нашего сжатого ядра
output
Значение начального адреса нашего распаковываемого дале ядра
output_len
Значение размера распаковываемого ядра
run_size
Общий объём пространства, необходимый для выполнения самого ядра, включая разделы .bss и .brk
Наряду с самим ядром, наш начальный загрузчик также подгрузил в память и initramfs. Об initramfs мы поговорим в Главе 5. итак, перед распаковкой необходимого образа ядра, наш заголовок или соответствующая процедура ядра должен позаботиться о том, что распаковка vmlinuz не перекроет уже загруженный образ initramfs. По этой причине функция extract_kernel также заботится о вычислении адресного пространства initramfs и выполнит выравнивание соответствующим образом распакованный образ своего ядра. После того как мы получили верный адрес по которому наш заголовок может распаковывать vmlinuz , он выделит это ядро там.
340 asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, 341 unsigned char *input_data, 342 unsigned long input_len, 343 unsigned char *output, 344 unsigned long output_len) 345 < 346 const unsigned long kernel_total_size = VO__end - VO__text; 347 unsigned long virt_addr = LOAD_PHYSICAL_ADDR; 348 unsigned long needed_size; 349 350 /* Retain x86 boot parameters pointer passed from startup_32/64. */ 351 boot_params = rmode; 352 353 /* Clear flags intended for solely in-kernel use. */ 354 boot_params->hdr.loadflags &= ~KASLR_FLAG; 355 356 sanitize_boot_params(boot_params); 357 358 if (boot_params->screen_info.orig_video_mode == 7) < 359 vidmem = (char *) 0xb0000; 360 vidport = 0x3b4; 361 >else < 362 vidmem = (char *) 0xb8000; 363 vidport = 0x3d4; 364 >365 366 lines = boot_params->screen_info.orig_video_lines; 367 cols = boot_params->screen_info.orig_video_cols; 368 369 console_init(); 370 371 /* 372 * Save RSDP address for later use. Have this after console_init() 373 * so that early debugging output from the RSDP parsing code can be 374 * collected. 375 */ 376 boot_params->acpi_rsdp_addr = get_rsdp_addr(); 377 378 debug_putstr("early console in extract_kernel\n"); 379 380 free_mem_ptr = heap; /* Heap */ 381 free_mem_end_ptr = heap + BOOT_HEAP_SIZE; 382 383 /* 384 * The memory hole needed for the kernel is the larger of either 385 * the entire decompressed kernel plus relocation table, or the 386 * entire decompressed kernel plus .bss and .brk sections. 387 * 388 * On X86_64, the memory is mapped with PMD pages. Round the 389 * size up so that the full extent of PMD pages mapped is 390 * included in the check against the valid memory table 391 * entries. This ensures the full mapped area is usable RAM 392 * and doesnt include any reserved areas. 393 */ 394 needed_size = max(output_len, kernel_total_size); 395 #ifdef CONFIG_X86_64 396 needed_size = ALIGN(needed_size, MIN_KERNEL_ALIGN); 397 #endif 398 399 /* Report initial kernel position details. */ 400 debug_putaddr(input_data); 401 debug_putaddr(input_len); 402 debug_putaddr(output); 403 debug_putaddr(output_len); 404 debug_putaddr(kernel_total_size); 405 debug_putaddr(needed_size); 406 407 #ifdef CONFIG_X86_64 408 /* Report address of 32-bit trampoline */ 409 debug_putaddr(trampoline_32bit); 410 #endif 411 412 choose_random_location((unsigned long)input_data, input_len, 413 (unsigned long *)&output, 414 needed_size, 415 &virt_addr); 416 417 /* Validate memory location choices. */ 418 if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) 419 error("Destination physical address inappropriately aligned"); 420 if (virt_addr & (MIN_KERNEL_ALIGN - 1)) 421 error("Destination virtual address inappropriately aligned"); 422 #ifdef CONFIG_X86_64 423 if (heap > 0x3fffffffffffUL) 424 error("Destination address too large"); 425 if (virt_addr + max(output_len, kernel_total_size) > KERNEL_IMAGE_SIZE) 426 error("Destination virtual address is beyond the kernel mapping area"); 427 #else 428 if (heap > ((-__PAGE_OFFSET-(128
Необходимый метод распаковки будет выбран в соответствии с методом сжатия, использованном на момент компиляции ядра. Доступные методы распаковки можно обнаружить в том же самом файле misc.c .
57 #ifdef CONFIG_KERNEL_GZIP 58 #include "../../../../lib/decompress_inflate.c" 59 #endif 60 61 #ifdef CONFIG_KERNEL_BZIP2 62 #include "../../../../lib/decompress_bunzip2.c" 63 #endif 64 65 #ifdef CONFIG_KERNEL_LZMA 66 #include "../../../../lib/decompress_unlzma.c" 67 #endif 68 69 #ifdef CONFIG_KERNEL_XZ 70 #include "../../../../lib/decompress_unxz.c" 71 #endif 72 73 #ifdef CONFIG_KERNEL_LZO 74 #include "../../../../lib/decompress_unlzo.c" 75 #endif
После того как наше ядро распаковано в памяти, из самой функции extract_kernelc будет получена точка входа этого раскрытого ядра и наш ЦПУ выполнит безусловный переход вовнутрь ядра.
Внутри установленного ядра
Наше ядро выполняет большое число вещей, но я перечислю лишь то, что представляет наибольший интерес для вас, как кого- то изучающего запуск.
- Наше ядро настроит размер стека самого ядра на 16 кБ в случае когда архитектура 64- битная. Это означает, что всякий новый процесс будет получать сво1 собственный стек ядра, который будет обладать в размере 16 кБ.
- page_size будет установлен на 4 кБ, что является размером страницы по умолчанию для 64- битной архитектуры Intel.
- Наше ядро подготовит оответствующий механизм обработки прерываний и исключительных ситуаций, также именуемый таблицей дескрипторов прерываний (IDT, interrupt descriptor table).
- Ядро настроит необходимый механизм обработки отказов страниц.
- Установленное ядро соберёт подробности своего файла initramfs, такие как название файла, размер, адрес, адрес перемещения, старшие и младшие номера нового корневого устройства и т.п. из /arch/x86/kernel/setup.c .
- Далее оно выделит initramfs из его исходного кода в init/initramfs.c .
- Наконец, оно запустит systemd при помощи функции start_kernel из init/main.c .
Вы можете обратить внимание, что это самый первый случай, когда мы выходим за рамки своего каталога arch . Это означает, что мы можем рассматривать данный код как не зависимый от архитектуры. После того как наше ядро запущено, оно выполняет множество вещей и нет практически никакой возможности охватить их все в данной книге. С точки зрения запуска лозунгом нашего ядра выступает запуск systemd из initramfs. Поскольку initramfs уже была загружена в память начальным загрузчиком, выделение необходимого ядра initramfs потребует подробностей файла самой initramfs, которые наше ядро получает из /arch/x86/kernel/setup.c .
Initramfs file name, Initramfs file size, Initramfs files address, Initramfs files relocation address, Major and minor numbers on which initramfs will be mounted.
После того как наше ядро получило подробности и своём файле initramfs, оно выделяет сам архив initramfs из файла init/initramfs.c . Подробнее мы обсудим как в точности наше ядро раскрывает в памяти initramfs в Главе 5. Для монтирования initramfs в качестве корневого устройствапотребуются виртуальные файловые системы, такие как proc , sys , dev и т.п., а потому наше ядро подготавливает их надлежащим образом.
err = register_filesystem(&proc_fs_type); if (err) return;
Наше ядро позднее смонтирует свю выделенную initramfs при помощи функции do_mount_root из init/do_mounts.c . Как только initramfs смонтирована в памяти, наше ядро запустит оттуда systemd. systemd будет запущен через ту же самую функцию start_kernel из файла init/main.c .
asmlinkage void __init start_kernel(void)
В целом, когда наша корневая файловая система готова, она включится вовнутрь своей корневой файловой системы и создаст два потока: PID 1 это процесс systemd, а PID 2 это kthread. Для лучшего понимания отсылаем вас к показанной на Рисунке 4-4 блок- схеме.
Рисунок 4-4
Наша вновь обновлённая блок- схема
Рисунок 4-5. отображает окончательную последовательность запуска которую мы обсудили на данный момент.
Рисунок 4-5

Наша последовательность запуска в некой блок- схеме
Прежде чем мы продолжим и рассмотрим как наше ядро выделяет initramfs и запускает из него systemd, нам необходимо разобраться с основами самой initramfs, например, зачем она нам нужна, какова её структура и т.п.. После того как мы разберёмся с важностью и основами initramfs мы продолжим свою последовательность запуска ролью systemd в общей последовательности запуска.
Linux.yaroslavl.ru
Глава 5 Конфигурирование и создание оптимизированных, безопасных ядер (Часть 2)
| В это главе Ядро Linux Создание аварийных загрузочных дискет Безопасность ядра Компиляция ядра Инсталляция нового ядра Удаление программ, файлов и строк связанных с модулями Создание новой аварийной дискеты Создание аварийного загрузочного флоппи-диска Обновление “/dev” входов |
![]() |
Инсталляция нового ядра.
1. Копируйте “/usr/src/linux/arch/i386/boot/bzImage” из дерева исходных кодов ядра в каталог “/boot” и дайте ему новое имя.
[root@deep linux]# cp /usr/src/linux/arch/i386/boot/bzImage /boot/vmlinuz-kernel.version.number
Замечание. Я рекомендую название подобное vmlinuz-2.2.14, потому что если вы хотите создать новый спасательный или загрузочные диски при помощи mkbootdisk, то она требует некоторой точности, например vmlinuz-2.2.14 вместо vmlinuz-2.2.14.a
2. Копируйте “/usr/src/linux/System.map” из дерева исходных кодов ядра в каталог “/boot” и дайте ему новое имя.
[root@deep linux]# cp /usr/src/linux/System.map /boot/System.map-kernel.version.number
3. Переместитесь в каталог /boot и создайте символические ссылки vmlinuz и System.map.
[root@deep linux]# cd /boot
[root@deep /boot]# ln -fs vmlinuz-kernel.version.number vmlinuz
[root@deep /boot]# ln -fs System.map-kernel.version.number System.map
Мы должны пересоздать ссылки “vmlinuz” и “System.map” на новую версию ядра. Иначе lilo будет использовать старое ядро.
4. Удалите устаревшие и ненужные файлы из каталога “/boot”, чтобы освободить место на диске:
[root@deep /boot]# rm -f module-info
[root@deep /boot]# rm -f initrd-2.2.xx.img
“module-info” это ссылка на каталог с модулями к старому ядру. Так как мы инсталлируем новое ядро, мы не нуждаемся в потерянных ссылках. Файл “initrd-2.2.xx” содержит инициализационный образ RAM диска, который выступает как система пока не будут доступны диски. Этот файл будет существовать и будет инсталлирован в ходе установки сервера, если вы имеете SCSI диск. Все необходимые драйвера сейчас встроены в ваше монолитное ядро, поэтому спокойно удаляйте этот файл.
5. Создайте новый каталог, который будет содержать все необходимые заголовочные файлы, связанные с ядром, которые будут нужны в дальнейшем при компиляции нового программного обеспечения.
Помните, что мы должны создать три символические ссылки в “/usr/include”, которые являются точками входа в заголовочные файлы ядра Linux. Каталог “/usr/include” содержит все заголовочные файлы вашей системы, которые нужны для компиляции новых программ. Ссылки asm, linux и scsi используются когда программам нужно знать некоторые функции времени компиляции ядра инсталлированного на вашей системе. Программы вызывают другие заголовочные файлы из каталога “include” когда им нужна специальная информация, зависимости и т.д.
[root@deep /]# mkdir -p /usr/src/linux-2.2.14/include
[root@deep /]# cp -r /usr/src/linux/include/asm-generic /usr/src/linux-2.2.14/include
[root@deep /]# cp -r /usr/src/linux/include/asm-i386 /usr/src/linux-2.2.14/include
[root@deep /]# cp -r /usr/src/linux/include/linux /usr/src/linux-2.2.14/include
[root@deep /]# cp -r /usr/src/linux/include/net /usr/src/linux-2.2.14/include
[root@deep /]# cp -r /usr/src/linux/include/video /usr/src/linux-2.2.14/include
[root@deep /]# cp -r /usr/src/linux/include/scsi /usr/src/linux-2.2.14/include
[root@deep /]# rm -rf /usr/src/linux
[root@deep /]# cd /usr/src
[root@deep src]# ln -s /usr/src/linux-2.2.14 linux
Первое, мы создаем новый каталог “linux-2.2.14”, базирующийся на версии ядра, которое мы инсталлируем для более легкой интерпретации, затем мы копируем туда каталоги asm-generic, asm-i386, linux, net, video, и scsi из “/usr/linux/include”. После этого мы удаляем каталог в котором компилировали новое ядро и создаем в “/usr/src” ссылку “linux”, указывающую на “linux-2.2.14”. Последний шаг позволяет сэкономить место на диске. Ядро в разархивированном виде занимает около 75M, а каталоги “include” – 3M.
6. В заключении нам необходимо редактировать файл “/etc/lilo.conf”, чтобы сделать новое ядро, загружаемым по уолчанию.
Редактируем файл lilo.conf (vi /etc/lilo.conf) и делаем соответствующие изменения в линии “image=/boot/”:
[root@deep /]# vi /etc/lilo.conf
boot=/dev/sda
map=/boot/map
install=/boot/boot.b
prompt
timeout=00
restricted
password=somepasswd
image=/boot/vmlinuz-kernel.version.number #(добавьте здесь имя вашего нового ядра).
label=linux
root=/dev/sda6
read-only
Замечание. Не забудьте удалить строку “initrd=/boot/initrd-2.2.12-20.img”, так как она нам больше ну нужна.
Когда имя нового ядра было внесено в файл “/etc/lilo.conf”, как это было описано выше, мы должны дать следующие команды, чтобы изменения вступили в силу:
[root@deep /]# /sbin/lilo -v
LILO version 21, [Copyright 1992-1998 Werner Almesberger
Reading boot sector from /dev/sda
Merging with /boot/boot.b
Boot image: /boot/vmlinuz-2.2.14
Added linux *
/boot/boot.0800 exits – no backup copy made.
Writing boot sector.
ВАЖНОЕ ЗАМЕЧАНИЕ: Если вы сказали No на вопрос “Unix98 PTY support (CONFIG_UNIX98_PTYS)” во время конфигурирования ядра, то отредактируйте файл “/etc/fstab” и удалите следующую строку:
none /dev/pts devpts gid=5,mode=620 0 0
Удаление программ, файлов и строк связанных с модулями.
Когда вы инсталлируете Linux в первый раз (как это делали мы) у вас устанавливается модульное ядро. Это означает, что каждый элемент или функция, которые нам нужны, существует в виде модуля и контролируется демоном ядра, который называется kmod. Он автоматически загружает модули и функции в память, когда это нужно, и выгружает их, когда необходимости в них отпадает.
kmod и другие программы, управляющие модулями, включенные в RPM пакет “modutils” используют файл “conf.modules”, который находится в каталоге “/etc”. В этом файле определяется, например, какие Ethernet карты вы имеете и какие параметры настройки она использует. Так как мы не используем модулей в нашем новом ядре, мы удаляем файл “conf.modules” и полностью деинсталлируем пакет “modutils”.
[root@deep /]# rm -f /etc/conf.modules
[root@deep /]# rpm -e --nodeps modutils
Шаг 2.
Теперь необходимо редактировать файл “rc.sysinit” и закомментировать все строки, в которых упоминается “depmod -a”, вставив в их начало символ “#”. Это нужно потому, что при загрузке система читает скрипт “rc.sysinit” для поиска модульных зависимостей.
Под Red Hat Linux 6.1
Комментируем строку 260 в rc.sysinit file (vi +260 /etc/rc.d/rc.sysinit):
if [ -x /sbin/depmod -a -n "$USEMODULES" ]; then
#if [ -x /sbin/depmod -a -n "$USEMODULES" ]; then
Комментируем строки с 272 по 277 в rc.sysinit file (vi +272 /etc/rc.d/rc.sysinit):
if [ -L /lib/modules/default ]; then
INITLOG_ARGS= action "Finding module dependencies" depmod -a default
else
INITLOG_ARGS= action "Finding module dependencies" depmod -a
fi
fi
# if [ -L /lib/modules/default ]; then
# INITLOG_ARGS= action "Finding module dependencies" depmod -a default
# else
# INITLOG_ARGS= action "Finding module dependencies" depmod -a
# fi
#fi
ЗАМЕЧАНИЕ: Процедура описанная выше связана с пакетом initscripts-4_70-1 package дистрибутива Red Hat Linux 6.1.
Под Red Hat Linux 6.2
Комментируем строку 243 в rc.sysinit file (vi +243 /etc/rc.d/rc.sysinit):
if [ -x /sbin/depmod -a -n "$USEMODULES" ]; then
#if [ -x /sbin/depmod -a -n "$USEMODULES" ]; then
Комментируем строки с 255 по 260 в rc.sysinit file (vi +255 /etc/rc.d/rc.sysinit):
if [ -L /lib/modules/default ]; then
INITLOG_ARGS= action "Finding module dependencies" depmod -a default
else
INITLOG_ARGS= action "Finding module dependencies" depmod -a
fi
fi
# if [ -L /lib/modules/default ]; then
# INITLOG_ARGS= action "Finding module dependencies" depmod -a default
# else
# INITLOG_ARGS= action "Finding module dependencies" depmod -a
# fi
#fi
Замечание. Еще раз повторим, вся эта часть (“Удаление программ, файлов и строк связанных с модулями.”) требуется только если вы ответили No на вопрос “Enable loadable module support (CONFIG_MODULES)” при конфигурировании ядра.
Когда система перезагрузится и вы подключитесь к серверу, проверьте версию используемого ядра:
[root@deep /]# uname -a
Linux deep.openna.com 2.2.14 #1 Mon Jan 10 10:40:35 EDT 2000 i686 unknown
[root@deep]#
Создание новой аварийной дискеты
После перезагрузки сервера, вы должны получить систему с новым ядром. Теоретически, в этот момент, вам надо создать новую “спасательную” дискету с новым ядром. Что бы сделать это сделайте следующее:
Подключитесь к системе, вставьте новую дискету и выполните следующую команду:
[root@deep /]# mkbootdisk --device /dev/fd0 2.2.14
Insert a disk in /dev/fd0. Any information on the disk will be lost.
Press to continue or ^C to abort:
Важное замечание. Программа mkbootdisk запускается только для модульных ядер. Так, что вы не можете использовать ее на монолитном ядре, вместо этого создайте аварийную загрузочную дискету так, как это описано ниже.
Создание аварийного загрузочного флоппи-диска.
Так как создать спасательную дискету можно только с модульными ядрами, мы должны найти другой путь загрузки системы с дискеты если ядро на жестком диске испорчено. Это возможно с помощью аварийной загрузочной дискеты. Вы должны создать ее немедленно после первой удачной загрузки системы и подключения к ней как root.
Для создания аварийной загрузочной дискеты сделайте следующее:
Вставьте дискету и форматируйте ее, используя команду:
[root@deep /]# fdformat /dev/fd0H1440
Double-sided, 80 tracks, 18 sec/track. Total capacity 1440 kB.
Formatting . done
Verifying . done
Шаг 2.
Копируйте файл vmlinuz из каталога “/boot” на дискету:
[root@deep /]# cp /boot/vmlinuz /dev/fd0
cp: overwrite `/dev/fd0'? y
vmlinuz – это символическая ссылка на реальной ядро.
Определяем корневой раздел ядра:
[root@deep /]# rdev
/dev/sda12 /
Корневой раздел ядра – это раздел, где находится корневая файловая система. В этом примере, корневой раздел - “dev/sda12”; на вашей системе это имя может быть другим.
Устанавливаем корневой раздел ядра:
[root@deep /]# rdev /dev/fd0 /dev/sda12
В качестве корневого раздела ядра используется значение полученной на предыдущем шаге.
Маркируем корневой раздел как только для чтения:
[root@deep /]# rdev -R /dev/fd0 1
При инициализации Linux корневая файловая система монтируется только для чтения. Подобная установка избавит вас от ряда предупреждающих сообщений и сообщений об ошибках.
Вставьте загрузочную дискету в дисковод A: и перезагрузите систему:
Обновление “/dev” входов
Если вы добавили новое устройство в вашу систему или провели крупное обновление ядра (например, из версии 2.2.9 к 2.2.15), то необходимо обновить ваши входы в “/proc” для предотвращения проблем с потерянными устройствами. Мы можем решить эту задачу при помощи скрипта MAKEDEV. Он сканирует каталог “/proc”, где все устройства связываются с драйверами ядра. Специальная опция “update” позволяет утилите MAKEDEV создать новые
устройства, которые вы сконфигурировали в вашем ядре и удалить ненужные.
Для обновления входов в “/proc” выполните следующие команды:
[root@deep /]# cd /dev [root@deep /dev]# ./MAKEDEV update
linux samba mail postfix FreeBSD Unix doc linux howto ALTLinux PHP faq bind sendmail apache iptables firewall kernel rpm apt-get Slackware openssh Cisco debian vmware GNU oracle sun awk /etc/ passwd linux установка учебник книга скачать
Что такое ядро Linux?

Для обычных пользователей и менее чем хардкорных поклонников Linux — операционная система. Однако для пуристов название Linux зарезервировано для ядра, которое обеспечивает работу операционной системы.
Режимы
Прежде чем объяснить, что такое ядро, важно понять термины пользовательский режим и режим ядра . Пользовательский режим — это когда исполняемый код не имеет возможности прямого доступа к аппаратной или справочной памяти. Чтобы получить доступ к оборудованию и памяти, код, работающий в пользовательском режиме, должен делегировать инструкции системным интерфейсам прикладного программирования. Режим ядра — это когда исполняемый код имеет неограниченный доступ ко всему оборудованию — он зарезервирован для наиболее надежных функций операционной системы.
Что такое ядро?
Каждая операционная система имеет ядро. Windows, macOS , iOS , Android , Chrome OS и Linux имеют низкоуровневую систему, которая отвечает за взаимодействие всех приложений с физическим оборудованием компьютера. Без ядра ни одно из ваших приложений не сможет использовать физический компьютер; такие приложения, как Firefox, Chrome, LibreOffice или Outlook не будут работать. Ядро также отвечает за разрешение процессам обмениваться информацией, используя то, что называется межпроцессным взаимодействием.
Существует (вообще говоря) три типа ядер:
- Монолитные ядра . Эти ядра включают процессор , память, IPC, драйверы устройств, управление файловой системой и вызовы системного сервера. Он также отвечает за передачу свободной системной памяти приложениям. Эти типы ядер обычно лучше обращаются к оборудованию и многозадачности.
- Микроядра . Микроядра используют минималистский подход и управляют только процессором, памятью и IPC.
- Гибридные ядра : гибридные ядра имеют возможность решать, что они хотят запускать в режиме пользователя или в режиме ядра. Хотя это обеспечивает лучшее из обоих миров, от производителей оборудования требуется гораздо больше для создания драйверов, которые служат для взаимодействия между работающим кодом и оборудованием.
Linux использует открытый источник Monolithic Kernel, тогда как macOS и Windows используют Hybrid Kernels. Ядро Linux было задумано в 1991 году Линусом Торвальдсом. По сей день Торвальдс продолжает оставаться ведущим разработчиком ядра Linux, а разработчики со всего мира вносят свой вклад в ядро Linux. На самом деле, по оценкам, с начала отслеживания в 2005 году около 10 000 разработчиков из более чем 1000 компаний внесли свой вклад в ядро Linux.
Где ядро?
Если вы откроете окно терминала и введете команду ls / boot , вы увидите файл с именем vmlinuz-VERSION (где VERSION — имя или номер выпуска). Файл vmlinuz — это собственно загружаемое ядро Linux, а z указывает, что ядро сжато, поэтому вместо vmlinux у нас есть vmlinuz .

В этом каталоге / boot находятся другие важные файлы ядра, такие как initrd.img-VERSION, system.map-VERSION и config-VERSION (где VERSION — это имя или номер выпуска). Эти другие файлы служат следующим целям:
