QEMU запускает ядро x86-Linux


Введение в QEMU

QEMU (быстрый эмулятор) — это аппаратный симулятор общего назначения с открытым исходным кодом, который может имитировать различные аппаратные архитектуры (такие как x86, ARM, ARM64, MIPS, PowerPC и т. д.), и в настоящее время является популярным кросс-платформенным программным обеспечением для моделирования.

К основным методам эмуляции QEMU относятся: полная эмуляция системы и эмуляция пользовательского режима.

Полная эмуляция системы, QEMU предоставляет виртуальную модель всей машины (включая периферийные устройства, такие как ЦП, память и эмулируемые устройства) для запуска гостевой операционной системы. В этом режиме он эквивалентен виртуальной машине системного уровня.

Эмуляция пользовательского режима QEMU позволяет приложению выполняться на процессорах с различной архитектурой, что эквивалентно виртуальной машине уровня процесса.

вставьте сюда описание изображения

В этой статье описывается, как использовать эмулятор QEMU для запуска ядра Linux, используя режим полной эмуляции системы QEMU.

процесс загрузки линукс

Прежде чем начать, вам необходимо понять процесс загрузки Linux.Для получения подробной информации вы можете самостоятельно обратиться к информации, такой как « Анализ процесса загрузки Linux » в «Частной кухне Linux от Brother Bird ». Кратко: BIOS, MBR, запуск загрузчика, загрузка ядра, монтирование виртуальных rootfs, монтирование реальных rootfs, инициализация пользовательской программы (т.е. выполнение процесса инициализации).

Зачем там виртуальный rootfs? Это включает в себя initrd (полное имя RAM-диск, инициализированный загрузчиком, инициализированный диск памяти), RAM-диск предназначен для выделения части памяти в качестве раздела и использования ее в качестве диска, initrd — это диск памяти, инициализированный загрузчиком.

Появляется фон initrd.

Раньше носителем, используемым для хранения rootfs в системе Linux, обычно был только жесткий диск или дискета Ядро интегрировало эти дисковые драйверы, и ядро ​​могло напрямую монтировать дисковые rootfs при загрузке. Позже встроенные системы могут хранить rootfs на различных носителях, включая IDE, SCSI, SATA, Flash, u-disk и т. д. Если все медиадрайверы скомпилированы в ядро, ядро ​​будет становиться все более и более раздутым. Просто скомпилируйте драйвера всех носителей в модули ядра и сохраните их ko-файлы в rootfs, которые можно загрузить по требованию. Затем возникает проблема: если ядро ​​хочет смонтировать rootfs, оно должно сначала загрузить соответствующий модуль драйвера носителя данных, а если ядро ​​хочет загрузить модуль драйвера носителя данных, оно должно сначала смонтировать rootfs. Что появилось раньше, курица или яйцо?

Чтобы решить это противоречие, появился initrd на виртуальном диске. initrd — это сжатый небольшой корневой каталог, который содержит необходимые модули драйверов, исполняемые файлы и сценарии запуска на этапе запуска. В случае, если Bootloader настроен с помощью initrd, запуск ядра делится на два этапа: на первом этапе монтируются виртуальные крыши на основе диска памяти, часть системной памяти монтируется как корневая файловая система, и выполняется запуск в файловой системе initrd.Скрипт выполняет такие задачи, как загрузка модуля драйвера, а второй этап монтирует настоящую rootfs и выполняет процесс инициализации пользовательской программы.

initrd — это блочное устройство на основе памяти (т. е. RAM-диск), одним из недостатков которого является то, что он имеет фиксированный размер и является устаревшим механизмом. Linux 2.6 начал заменять initrd на initramfs.initramfs (файловая система init ram) — это файловая система в памяти (т. е. ramfs), и размер ее пространства может быть изменен динамически. В этой статье используется initramfs.

Подводя итог, прежде чем монтировать настоящую корневую файловую систему на диске, сначала будет смонтирована виртуальная корневая файловая система в памяти (реализованная через initrd или initramfs). такие вещи, как загрузка необходимых модулей драйверов и монтирование настоящих rootfs.

При использовании полного режима эмуляции системы QEMU для запуска ядра linux BIOS, MBR и загрузчик уже встроены в QEMU, нам нужно только подготовить образ ядра linux и initramfs. В этой статье основное внимание уделяется демонстрации того, что QEMU запускает ядро, и выполнение завершается, когда достигается виртуальная корневая файловая система в памяти, а настоящая корневая файловая система не подготовлена.

Образ ядра linux можно получить, скомпилировав исходный код ядра, а initramfs можно сделать с помощью busybox.

мое окружение

Аппаратная платформа хоста: x86_64
Операционная система хоста: Ubuntu 20.04 (Linux 5.4.0-139-универсальная)
Версия QEMU: qemu-4.2.1
Экспериментальное ядро: linux-5.19
Версия busybox: busybox-1.35.0

Установить QEMU

Существует два способа установки qemu: установка пакета Linux, компиляция исходного кода и установка.

установка пакета

$ sudo apt-get install qemu-system-x86

$ qemu-system-x86_64 --version
QEMU emulator version 4.2.1 (Debian 1:4.2-3ubuntu6.24)
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers

Исходная установка

В официальной документации есть подробное введение в сборку QEMU для Linux для справки.

Установите зависимости.Если вы не знаете, установлено ваше окружение или нет, не нужно спешить с их установкой.Вы можете установить соответствующие зависимости согласно подсказке об ошибке компиляции:

sudo apt-get install git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build

Скачайте и скомпилируйте:

$ mkdir ~/kvm
$ cd ~/kvm/
$ wget https://download.qemu.org/qemu-7.2.0.tar.xz
$ tar -xf qemu-7.2.0.tar.xz
$ cd qemu-7.2.0
$ ./configure --target-list=x86_64-softmmu
$ make -j`nproc`

проиллюстрировать:

  1. По умолчанию QEMU для всех платформ (таких как arm, i386, x86_64 и т. д.) будет компилироваться, что будет очень медленно.Добавьте параметр --target-list=x86_64-softmmu, чтобы скомпилировать только версию x86_64, необходимую среды для ускорения компиляции.
  2. Добавление параметра -j для make может ускорить компиляцию.Команда nproc используется для получения количества доступных ядер ЦП.Вообще говоря, максимальное количество параллельных задач для -j может быть установлено в два раза больше числа ЦП.

Результат компиляции находится в подкаталоге build каталога исходного кода:

$ ./build/qemu-system-x86_64 --version
QEMU emulator version 7.2.0
Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers

Проблемы с зависимостями, с которыми я столкнулся в процессе компиляции исходного кода:

Ошибка 1:

$ ./configure
Using './build' as the directory for build output
 
ERROR: Cannot find Ninja

Решение 1:

$ sudo apt-get install ninja-build

Ошибка 2:

$ ./configure 
Using './build' as the directory for build output

ERROR: glib-2.56 gthread-2.0 is required to compile QEMU

Решение 2:

$ sudo apt-get install libglib2.0-dev

Ошибка 3:

$ ./configure 
Using './build' as the directory for build output

../meson.build:553:2: ERROR: Dependency "pixman-1" not found, tried pkgconfig

ERROR: meson setup failed

Решение 3:

$ sudo apt-get install libpixman-1-dev

Скомпилируйте ядро ​​линукса

$ mkdir ~/kvm
$ cd ~/kvm/
$ wget https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/snapshot/linux-5.19.tar.gz
$ tar -xf linux-5.19.tar.gz
$ cd linux-5.19/
$ make defconfig
$ make menuconfig
$ make -j `nproc`

Следующий журнал указывает на то, что компиляция прошла успешно:

Kernel: arch/x86/boot/bzImage is ready

Файл bzImage представляет собой скомпилированный файл образа ядра:

$ file arch/x86/boot/bzImage
arch/x86/boot/bzImage: Linux kernel x86 boot executable bzImage, version 5.19.0 (kaoya@kaoya-Inspiron-7472) #1 SMP PREEMPT_DYNAMIC Mon Feb 27 00:26:06 CST 2023, RO-rootFS, swap_dev 0xA, Normal VGA

Примечание:
3. В этом эксперименте команда make menuconfig не вносила никаких изменений, просто выберите сохранение и выход.
4. Добавление параметра -j к make может ускорить компиляцию.Команда nproc используется для получения количества доступных ядер ЦП.Вообще говоря, максимальное количество параллельных задач для -j может быть установлено в два раза больше числа ЦП.
5. Процесс make может вызвать ошибки из-за отсутствия зависимостей в системе, просто установите соответствующие зависимости согласно подсказкам.

Моя среда сообщает об ошибках во время процесса make, и их решения следующие:
$ sudo apt install bison
сообщает об ошибке 1:

$ make defconfig

 /bin/sh: 1: flex: not found

Решение 1:

$ sudo apt install flex

Ошибка 2:

$ make defconfig

/bin/sh: 1: bison: not found

Решение 2:

在这里插入代码片

скомпилировать BusyBox

$ mkdir ~/kvm
$ cd ~/kvm/
$ wget https://busybox.net/downloads/busybox-1.35.0.tar.bz2
$ tar -xf busybox-1.35.0.tar.bz2
$ cd busybox-1.35.0/
$ make menuconfig

# 修改配置,选中如下项目,静态编译
# Settings –> Build Options –> [*] Build static binary(no share libs)

# 反选如下项目,否则后续qemu执行会提示 /bin/sh:can't access tty;job control turned off
# Shells  --->  [ ]   Job control

$ make -j `nproc`
$ make install

После установки он будет установлен в каталог _install/ каталога исходного кода по умолчанию:

$ ls _install/
bin  linuxrc  sbin  usr

Самое главное это _install/bin/busybox, остальные файлы ссылок.

$ file _install/bin/busybox 
_install/bin/busybox: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=8be05d97976fc5de35a9ebf2631529223523296f, for GNU/Linux 3.2.0, stripped

сделать initramfs

Используйте busybox для быстрого создания initramfs.

Создайте сценарий запуска inti в виртуальной корневой файловой системе и дайте ему права на выполнение:

$ cd ~/kvm/busybox-1.35.0/_install/
$ mkdir proc sys dev tmp
$ touch init
$ chmod +x init

Содержание скрипта:

#!/bin/sh

# 挂载一些必要的文件系统
mount -t proc none /proc
mount -t sysfs none /sys
mount -t tmpfs none /tmp
mount -t devtmpfs none /dev

echo
echo "Hello Linux"

# 显示开机消耗时间

echo "This boot took $(cut -d' ' -f1 /proc/uptime) seconds"
echo

# 停留在控制台
exec /bin/sh

Создайте файл initramfs, который представляет собой файл, упакованный с помощью cpio и сжатый с помощью gzip.Это файловая система памяти в формате cpio.

$ find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz

Используйте QEMU для запуска ядра Linux

После того, как образ ядра linux и initramfs готовы, вы можете использовать QEMU для запуска ядра linux.

Запустите QEMU с графическим интерфейсом:

$ cd ~/kvm/
$ qemu-system-x86_64 \
        -kernel ./linux-5.19/arch/x86/boot/bzImage \
        -initrd ./busybox-1.35.0/initramfs.cpio.gz \
        -append "init=/init"

Запустите QEMU в режиме символьного интерфейса (графический интерфейс не запускайте), при этом вывод лога в консоль:

$ qemu-system-x86_64 \
        -kernel ./linux-5.19/arch/x86/boot/bzImage \
        -initrd ./busybox-1.35.0/initramfs.cpio.gz \
        -nographic \
        -append "init=/init console=ttyS0"

Описание параметра QEMU (подробнее см. Стандартные параметры ):

  • -kernel: указывает образ ядра для запуска;
  • -initrd: укажите файловую систему памяти для запуска;
  • -append: параметры запуска, переданные ядру; вы можете использовать команду cat /proc/cmdline для проверки после запуска.
  • -nographic: запустить символьный интерфейс (не запускать графический интерфейс), перенаправить вывод в командную строку хоста и использовать его в сочетании с параметром console=ttyS0;

Используйте меню панели инструментов для операций с графическим интерфейсом и используйте сочетания клавиш для операций с символьным интерфейсом следующим образом (для получения дополнительной информации см.: Клавиши в мультиплексоре символов ):

Ca h распечатать эту справку
Ca x выйти из эмулятора
Ca s сохранить данные на диске обратно в файл (if -snapshot)
Cat t переключить временные метки консоли
Ca b отправить break (magic sysrq)
Ca c переключить между консолью и монитором
Ca Ca отправить Ca

упрощенная команда

Чтобы упростить ввод команд, вы можете создать Makefile со следующим содержимым:

$ vim ~/kvm/Makefile

initramfs:
	cd busybox-1.35.0/_install/ && find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz
        
run-win:
	qemu-system-x86_64 \
			-kernel ./linux-5.19/arch/x86/boot/bzImage \
			-initrd ./busybox-1.35.0/initramfs.cpio.gz \
			-append "init=/init"
        
run-console:
	qemu-system-x86_64 \
			-kernel ./linux-5.19/arch/x86/boot/bzImage \
			-initrd ./busybox-1.35.0/initramfs.cpio.gz \
			-nographic \
			-append "init=/init console=ttyS0"
  • сделать initramfs: сделать initramfs;
  • make run-win: запустить QEMU с графическим интерфейсом;
  • make run-console: запустить QEMU с символьным интерфейсом;

ссылка

Официальная документация QEMU: https://www.qemu.org/docs/master/
Википедия QEMU: https://wiki.qemu.org/Documentation

рекомендация

отblog.csdn.net/benkaoya/article/details/129469116