Jump to content

uniLoader (Русский)

From postmarketOS Wiki
uniLoader
Пример загрузки uniLoader
Пример загрузки uniLoader
Название uniLoader
Первый этап
Unavailable
Второй этап
Works
Ресурсы исходный код

uniLoader — это вторичный загрузчик, способный загружать Linux на устройствах на базе Android и iOS. Такой загрузчик встраивает ramdisk, ядро и DTB в свой собственный бинарный образ (под названием uniLoader, который затем копируется в ОЗУ) и, наконец, после перемещения ядра передаёт ему управление.

Портирование

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

  • board/Kconfig
  • board/Makefile
  • board/<производитель>/board-<кодовое_название_устройства>.c
  • configs/<кодовое_название_устройства>_defconfig

Пример board/Kconfig

config NOTHING_SPACEWAR
		bool "Support for Nothing Phone (1)"
		default n
		depends on SM7325
		help
		  Say Y if you want to include support for Nothing Phone (1)

Пример board/Makefile

lib-$(CONFIG_NOTHING_SPACEWAR) += nothing/board-spacewar.o

board/<производитель>/board-<кодовое_название_устройства>.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2026 Ryo "evilMyQueen" Yamada <evilMyQueen@mainlining.org>
 */

#include <board.h>
#include <util.h>
#include <drivers/framework.h>
#include <lib/simplefb.h>

static struct video_info spacewar_fb = {
	.format = FB_FORMAT_ARGB8888,
	.width = 1080,
	.height = 2400,
	.stride = 4,
	.scale = 2,
	.address = (void *)0xe1000000
};

static const struct device spacewar_devices[] = {
	{ "simplefb", &spacewar_fb, "fb" },
};

struct board_data board_ops = {
	.name = "nothing-spacewar",
	.ops = {
	},
	.devices = spacewar_devices,
	.num_devices = ARRAY_SIZE(spacewar_devices),
	.quirks = 0
};

Пример configs/<кодовое_название_устройства>_defconfig

CONFIG_POSITION_INDEPENDENT=y
CONFIG_LINUX_KRNL_HEADER_IMG=y
CONFIG_SM7325=y
CONFIG_NOTHING_SPACEWAR=y
CONFIG_TEXT_BASE=0x83600000
CONFIG_RAMDISK_ENTRY=0xadb6c000
CONFIG_PAYLOAD_ENTRY=0xc5100000

Нахождение базового адреса

Найдите базовый адрес — то есть адрес в ОЗУ, по которому штатный загрузчик загружает Linux (или uniLoader).

Как его найти:

  • Посмотрите логи загрузчика (например, Booting Linux at 0xf00ba0).

Вам потребуется загрузить устройство несколько раз и проверить, остаётся ли адрес неизменным или меняется между загрузками. Эта информация понадобится для дальнейших действий.

Опции defconfig

CONFIG_POSITION_INDEPENDENT

Установка значения =y сообщает uniLoader, что его базовый адрес может меняться между загрузками. Технически это заставляет бинарный файл uniLoader использовать позиционно‑независимый код (PIC). Кроме того, это заставляет uniLoader во время выполнения копировать себя в область, заданную в CONFIG_TEXT_BASE. Используйте =y, если базовый адрес меняется между загрузками. Если он не меняется, можно использовать =n, хотя =y тоже может работать — при условии, что остальные опции заданы корректно.

CONFIG_TEXT_BASE

Начальный адрес uniLoader в ОЗУ.

Как вычислить (не PIC):

  • Используйте ваш базовый адрес без изменений.

Как вычислить (PIC):

  • Выберите произвольный незарезервированный адрес в памяти (проверьте /proc/iomem в работающей системе с downstream-ядром), где достаточно места для размещения бинарного файла uniLoader.

CONFIG_PAYLOAD_ENTRY

Адрес в памяти, куда загружается ядро Linux. После завершения работы uniLoader этот адрес становится новым базовым адресом.

Как вычислить:

  • Выберите произвольный незарезервированный адрес в памяти (проверьте /proc/iomem в работающей системе с downstream-ядром), где достаточно места для размещения ядра Linux.

CONFIG_RAMDISK_ENTRY

Адрес в памяти, куда загружается ramdisk.

Как вычислить:

  • Возьмите значение свойства linux,initrd-start из downstream-DTS.
  • Выберите произвольный незарезервированный адрес в памяти (проверьте /proc/iomem в работающей системе с downstream-ядром), в котором достаточно места для размещения ramdisk.

CONFIG_LINUX_KRNL_HEADER_IMG

Добавляет заголовок ядра Linux к исполняемому файлу uniLoader. Заставляет ваш загрузчик думать, что он имеет дело с ядром Linux, а не с произвольным бинарным файлом.

Сборка образа uniLoader

Установите кросс-компилятор

Debian/Ubuntu/Linux Mint:

# apt install aarch64-linux-gnu

Fedora:

# dnf install gcc-aarch64-linux-gnu

Arch Linux:

# pacman -S aarch64-linux-gnu-gcc

Клонируйте репозиторий и перейдите в его директорию

$ git clone https://github.com/ivoszbg/uniLoader
$ cd uniLoader

Подготовьте нужные файлы

Скопируйте образ ядра, DTB, и ramdisk в директорию blob:

$ cp $HOME/$USER/linux/arch/arm64/boot/Image blob/Image
$ cp $HOME/$USER/linux/arch/arm64/boot/dts/<чипсет>/<модель_чипсета>-<кодовое_название_устройства>.dtb blob/dtb
$ cp $HOME/$USER/ramdisk.gz blob/ramdisk

Запустите сборку

$ make ARCH=aarch64 CROSS_COMPILE=aarch64-linux-gnu- <кодовое_название_устройства>_defconfig
$ make ARCH=aarch64 CROSS_COMPILE=aarch64-linux-gnu-

Запаковка в boot.img

Выполните эту команду на штатном boot.img, чтобы получить пример вывода mkbootimg:

$ unpack_bootimg --boot_img boot.img --out unpack --format=mkbootimg

Пример вывода:

--header_version 1 --kernel unpack/kernel --ramdisk unpack/ramdisk --pagesize 0x00000800 --base 0x00000000 --kernel_offset 0x10008000 --ramdisk_offset 0x00000000 --second_offset 0x00000000 --tags_offset 0x10000100 --cmdline 'androidboot.selinux=permissive'

Теперь замените значение, передаваемое аргументу --kernel, на uniLoader или uniLoader.gz. Добавьте аргумент --out вместе с желаемым именем выходного образа. Используйте полученный результат с mkbootimg:

$ mkbootimg --header_version 1 --kernel uniLoader --ramdisk unpack/ramdisk --pagesize 0x00000800 --base 0x00000000 --kernel_offset 0x10008000 --ramdisk_offset 0x00000000 --second_offset 0x00000000 --tags_offset 0x10000100 --cmdline 'androidboot.selinux=permissive' --out boot-uniLoader.img

Если есть ограничения по объёму, вместо использования штатного ramdisk создайте пустой:

$ touch empty_ramdisk
$ # используйте через --ramdisk empty_ramdisk

uniLoader или uniLoader.gz?

Выбирайте вариант в соответствии с методом сжатия в штатном boot.img. Проверить его можно по распакованному ядру с помощью команды ниже:

$ file unpack/kernel

Пример вывода, когда следует использовать uniLoader:

unpack/kernel: Linux kernel ARM64 boot executable Image, little-endian, 4K pages

Пример вывода, когда следует использовать uniLoader.gz:

unpack/kernel: gzip compressed data, max compression, from Unix, original size modulo 2^32 7630437

Даже если в mkbootimg вы передаёте сжатый образ ядра, в директории uniLoader/blob всегда должен находиться несжатый образ.

Ссылки