- Bootstrap
- Содержание
- «Раскрутка» ALT с нуля [ править ]
- Типичная процедура [ править ]
- Применяем ручки [ править ]
- Настраиваем hasher [ править ]
- первая стадия [ править ]
- вторая стадия [ править ]
- третья стадия [ править ]
- Расставляем ручки [ править ]
- Bootstrap
- Конфигурация RAM
- Адаптация кода для загрузки из Dataflash
- Адаптация кода для загрузки из Nandflash
- Сторожевой таймер
- Компилятор
- Компиляция
- Адаптация кода для прямого запуска ядра Linux
Bootstrap
Содержание
«Раскрутка» ALT с нуля [ править ]
. на новой архитектуре либо при необходимости обеспечить пересборку «с нуля» по иному поводу.
NB: glebfm@ разработан инструментарий для автоматизации процесса, см. тж. доклад на OSSDEVCONF-2017.
Типичная процедура [ править ]
Начинаем с какой-либо существующей бинарной среды, пригодной для сборки содержимого базовой сборочной системы сизифа (rpm-build и его зависимости); см., например, опыт портирования на ARM.
Поскольку на первых порах собираемое будет устанавливаться в неё же, есть смысл работать в чруте, представляющем из себя копию корневой файловой системы, со смонтированными /proc и /dev/pts.
- сперва собираем rpm
- для новой архитектуры потребуется дополнить installplatform, rpmrc.in
- может потребоваться подпирание по месту, отрыв функциональности и т.п.
- после успешной сборки устанавливаем полученное и собираем rpm.rpm
- затем собираем toolchain (binutils, gcc, glibc)
- устанавливаем в сборочное окружение по мере сборки
- собираем все архитектурнозависимые пакеты, необходимые для сборки hasher
- rpm —rebuild —nodeps
- см. далее про ручки помимо --with bootstrap
- основное отрываемое: check, static, doc, apidocs, selinux, ssl, python, java
- запустив hasher, пересобираем его сборочные зависимости в нём самом (порядка 150 пакетов)
- разворачиваем BuildRequires по мере возможности, продолжая на этой стадии отключать избыточное
- по возможности дополняем в спеках набор ручек для отключения лишнего (тоже см. ниже)
- не откладывая в долгий ящик, стараемся пропихнуть полученные патчи в сизиф
- продолжаем работу над пополнением порта
При длительной сборке пакетов и ошибке в %files могут оказаться полезными возможности rpmbuild по продолжению сборки пакета:
Форма с -bi выполнит повторно секцию %install, а -bb отработает по %files, предполагая наличие уже установленного в пакет-buildroot/ содержимого.
Обратите внимание, что rpmbuild при указании --nodeps игнорирует сборочные зависимости, а не установочные.
Применяем ручки [ править ]
Для начальной сборки при помощи rpm могут быть полезны следующие уже распространённые в сизифе ключи сборки пакетов:
- --disable check --without check --disable test --without test --disable static --without doc --without apidocs --without profile --disable selinux --without selinux --disable java --without java --without python3 --disable ldap --disable udev
Для конкретных пакетов могут быть реализованы иные, например:
- vim: --disable gui_gnome2 --disable gui_gtk2 --disable gui_neXtaw --disable perlinterp --disable rubyinterp --disable tclinterp --disable luainterp --disable gui_any
- python: --without valgrind --without tk
- libcap-ng: --without-python
- openssl10: --without-krb
- curl: --without-ssl
- libao: --disable pulse
- SDL: --without pulse
- libshell, libgtk+2: --disable man
- где-то ещё видел cxx, cpp, nls, included_gettext
- внимание: qt5-* используют --disable bootstrap в своих целях (отвязка от qt5-tools)! это не противоречит предлагаемому --with-bootstrap, но может сбить с толку
- внимание: а вот perl-* порой используют --without bootstrap в своих целях, причём в случае perl-Pod-Usage теряется зависимость на perl-podlators, что может неочевидным образом разваливать сборку других пакетов (вроде perl-Package)
- вполне возможно дополнить и другими ручками, но сперва лобовой rpm -ba --nodeps на имеющемся сборочном окружении
- хорошо бы по возможности приводить их к единой системе и фиксировать здесь
- тесты полезны в нормальном режиме, но занимают существенное время, а нередко требуют дополнительных BR или обламываются по мелочам (один перловый тест из
Настраиваем hasher [ править ]
Задействование этого всего вместе с указанием о необходимости перепаковки полученного на входе src.rpm может выглядеть в
первая стадия [ править ]
Отрываем всё, что можем, включаем перепаковку srpm перед выяснением сборочных зависимостей для учёта ключиков:
вторая стадия [ править ]
После успешной сборки openssl10:
- убираем —without ssl (т.е. разрешаем с ним собираться);
- пересобираем python,
после этого python-dev должен устанавливаться штатно без неудовлетворённой зависимости на _ssl.
третья стадия [ править ]
Разрешаем статическую сборку (убираем —disable static), пересобираем пакеты xz zlib bzip2 libpopt elfutils libdb4.7, затем rpm apt apt-repo-tools
Расставляем ручки [ править ]
Поскольку анализ и разрывание циклов сборочных зависимостей — занятие довольно трудоёмкое и муторное, стоит фиксировать информацию о них в сизифных пакетах, чтоб в следующий раз было чуть легче (и нет, я видел уже слишком много случаев «это же только сейчас помучиться»).
Предлагаю дополнять спеки пакетов, которые затрагивает бутстрап базового сборочного окружения, параметром bootstrap (with, не enable — см. ниже), не перекрывающимся с перечисленными выше уже существующими; в частности:
- отключать сборку man/info, если требует help2man / makeinfo / texinfo ;
- довольно неприятны в плане бутстрапа по части perl-* , если нет возможности воспользоваться имеющимися хостовыми или noarch-пакетами
- отключать поддержку SSL;
- задействовать bundle’ные gnulib/glib/. вместо системных, если есть;
- возможно, в %configure добавлять --disable-asm --disable-gtk-doc
Обратите внимание на то, что enable bootstrap используется в:
- qt5-xmlpatterns, qt5-declarative
- libpsl
Также обратите внимание на произведение --
Источник
Bootstrap
Загрузчик первого уровня. Его задача: провести начальную инициализацию процессора, настроить управление памятью, скопировать кусок данных из указанного ему места из энергонезависимой памяти в ОЗУ и передать управление на этот адрес, считая, что он скопировал программу. Чаще всего в качестве этой программы используется загрузчик второго уровня U-Boot . Можно также сразу запускать ядро Linux .
Bootstrap также производит необходимую настройку интерфейса процессора:
• шину SPI или параметры доступа к Nandflash;
Используем оригинальный AT91Bootstrap1.14 от Atmel.
Конфигурация RAM
В файле /board/at91sam9260ek/at91sam9260ek.c в функции void hw_init(void) выставить размер шины данных RAM (если используется микросхема памяти с другой организацией, проверить и другие параметры):
/* Configure SDRAM Controller */
AT91C_SDRAMC_TXSR_8, /* Control Register */
(MASTER_CLOCK * 7)/1000000, /* Refresh Timer Register */
AT91C_SDRAMC_MD_SDRAM); /* SDRAM (no low power) */
В функции void sdramc_hw_init(void) проверить инициализацию шины.
writel( 0xFFFF0000 , AT91C_BASE_PIOC + PIO_ASR(0));
writel( 0xFFFF0000 , AT91C_BASE_PIOC + PIO_PDR(0));
writel( 0x00000000 , AT91C_BASE_PIOC + PIO_ASR(0));
writel( 0x00000000 , AT91C_BASE_PIOC + PIO_PDR(0));
Адаптация кода для загрузки из Dataflash
Указать используемую микросхему Dataflash: /driver/dataflash.c , функция df_init .
В файле /board/at91sam9260ek/dataflash/at91sam9260ek.h :
Выставить рабочую частоту и параметры PLL для кварца 12 MHz:
#define MASTER_CLOCK (200000000/2)
#define PLLA_SETTINGS 0x2031BF03
#define PLLB_SETTINGS 0x10073F01
Понизить при необходимости частоту SPI:
#define AT91C_SPI_CLK 4800000
Проверить адресацию микросхемы Dataflash:
#define AT91C_SPI_PCS_DATAFLASH AT91C_SPI_PCS1_DATAFLASH /* Boot on SPI NCS0 */
Проверить параметры копирования и запуска:
#define IMG_ADDRESS 0x8400
#define IMG_SIZE 0x33900
#define JUMP_ADDR 0x23F00000
IMG_ADDRESS: адрес загрузки U-Boot;
IMG_SIZE: размер копируемых данных, должен быть не меньше размера u-boot.bin ;
JUMP_ADDR: адрес старта U-Boot, см. /u-boot/board/at91sam9260ek/config.mk ;
Проверить используемую шину данных для Nandflash в /board/at91sam9260ek/at91sam9260ek.c функция void nandflash_hw_init(void) :
writel((AT91C_SMC_READMODE | AT91C_SMC_WRITEMODE | AT91C_SMC_NWAITM_NWAIT_DISABLE |
Адаптация кода для загрузки из Nandflash
В файле /board/at91sam9260ek/nandflash/ :
Выставить рабочую частоту и параметры PLL для кварца 12 MHz:
#define MASTER_CLOCK (200000000/2)
#define PLLA_SETTINGS 0x2031BF03
#define PLLB_SETTINGS 0x10073F01
Проверить параметры копирования и запуска:
#define IMG_ADDRESS 0x8400
#define IMG_SIZE 0x33900
#define JUMP_ADDR 0x23F00000
IMG_ADDRESS: адрес загрузки U-Boot ;
IMG_SIZE: размер копируемых данных, должен быть не меньше размера u-boot.bin ;
JUMP_ADDR: адрес старта U-Boot , см. /u-boot/board/at91sam9260ek/config.mk ;
Проверить используемую шину данных для Nandflash в /board/at91sam9260ek/at91sam9260ek.c функция void nandflash_hw_init(void) :
writel((AT91C_SMC_READMODE | AT91C_SMC_WRITEMODE | AT91C_SMC_NWAITM_NWAIT_DISABLE |
Выставить параметры используемой микросхемы NandFlash. Эти же параметры надо прописать в ядре Linux. Приведены параметры для k9k8g08u0a :
/* These timings are specific to K9K8G08U0A (samsung) MCK = 100 MHZ */
#define AT91C_SM_NWE_SETUP (1
#define AT91C_SM_NCS_WR_SETUP (0
#define AT91C_SM_NRD_SETUP (1
#define AT91C_SM_NCS_RD_SETUP (0
#define AT91C_SM_NWE_PULSE (2
#define AT91C_SM_NCS_WR_PULSE (3
#define AT91C_SM_NRD_PULSE (2
#define AT91C_SM_NCS_RD_PULSE (2
#define AT91C_SM_NWE_CYCLE (3
#define AT91C_SM_NRD_CYCLE (3
#define AT91C_SM_TDF (2
Сторожевой таймер
По умолчанию Bootstrap его выключает, после чего его уже не включить.
Для запрета его выключения в /board/at91sam9260ek/at91sam9260ek.c в функции void hw_init(void) убрать строчку:
// writel(AT91C_WDTC_WDDIS, AT91C_BASE_WDTC + WDTC_WDMR);
Компилятор
Используется не новее 2007q1-21. Причина: непонятное увеличение размера скомпилированного файла.
Компиляция
Сделать файл следующего содержания, положить его в папку /dataflash или /nandflash и запустить:
Результат сборки: board/at91sam9260ek/dataflash/dataflash_at91sam9260ek.bin .
размер файла не должен превышать 4096 байта.
Адаптация кода для прямого запуска ядра Linux
При этом метода запуска используется компрессированный образ, полученный после компиляции Linux : /
• KERNEL_PARAMS_ADDRESS задаёт адрес таблицы параметров ядра. Обычно это смещение 0x100 от начала физической памяти. Начало памяти отводится для хранения векторов и таблицы страниц.
• JUMP_ADDRESS задаёт адрес, куда будет помещён компрессированный образ Linux ( zImage ). Некомпрессированное ядро не превышает 4 Мб. Для того, чтобы оно могло распаковаться, после zImage должно оставаться минимум 4 Мб свободной памяти. Общепринятым значением является смещение 0x8000 от начала памяти.
Параметры копирования и адреса старта и местонахождения параметров ядра /board/at91sam9260ek/dataflash/at91sam9260ek.h :
#define IMG_ADDRESS 0x42000 /* Image Address in DataFlash */
#define IMG_SIZE 0x210000 /* Image Size in DataFlash */
#define MACH_TYPE 0x44B /* AT91SAM9260-EK */
#define MEM_START 0x20000000 /* RAM base address */
#define MEM_SIZE 0x4000000 /* RAM size 64M */
#define JUMP_ADDR 0x20008000 /* kernel image address in RAM */
#define KERNEL_PARAMS_ADDRESS 0x20000100 /* kernel parameters in RAM */
#define BOOT_ARG "mem=64M console=ttyS0,115200"
#define BOOT_ARG "mem=64M console=ttyS0,115200 ubi.mtd=rootfs"
#define BOOT_ARG "mem=64M console=ttyS0,115200 " \
"rootfstype=ubifs rootflags=bulk_read,chk_data_crc rw"
#define BOOT_ARG "mem=64M console=ttyS0,115200 " \
Добавить в main.c функции инициализации:
/* list of possible tags */
#define ATAG_NONE 0x00000000
#define ATAG_CORE 0x54410001
#define ATAG_MEM 0x54410002
#define ATAG_CMDLINE 0x54410009
/* structures for each atag */
unsigned int size; /* length of tag in words including this header */
unsigned int tag; /* tag type */
unsigned int flags;
unsigned int pagesize;
unsigned int rootdev;
unsigned int size;
unsigned int start;
struct atag_header hdr;
struct atag_core core;
struct atag_mem mem;
struct atag_cmdline cmdline;
#define tag_next( t ) ((struct atag *)((unsigned int *)( t ) + ( t ) -> hdr.size))
#define tag_size( type ) ((sizeof(struct atag_header) + sizeof(struct type)) >> 2)
static struct atag *params; /* used to point at the current tag */
static void setup_core_tag()
params = (struct atag *)KERNEL_PARAMS_ADDRESS; /* Initialise parameters to start at given address */
params->hdr.tag = ATAG_CORE; /* start with the core tag */
params->hdr.size = tag_size( atag_core ); /* size the tag */
params->u.core.flags = 0; /* optional, ensure read-only */
params->u.core.pagesize = 0; /* optional, systems pagesize (4k) */
params->u.core.rootdev = 0; /* zero root device (typicaly overidden from commandline )*/
params = tag_next( params ); /* move pointer to next tag */
static void setup_mem_tag()
params->hdr.tag = ATAG_MEM; /* Memory tag */
params->hdr.size = tag_size( atag_mem ); /* size tag */
params->u.mem.start = RAM_BASE; /* start of physical memory */
params->u.mem.size = RAM_SIZE; /* memory size */
params = tag_next( params ); /* move pointer to next tag */
static void setup_cmdline_tag()
char* line = BOOT_ARG "\0"; /* place commandline into tag */
for( ; *(line + linelen) != 0; linelen++ ) < params->u.cmdline.cmdline[linelen] = *(line + linelen);>
if( !linelen ) /* do not insert a tag for an empty string */
params->hdr.tag = ATAG_CMDLINE; /* Commandline tag */
params->hdr.size = (sizeof(struct atag_header) + linelen + 1 + 4) >> 2;
params = tag_next(params); /* move pointer to next tag */
static void setup_end_tag()
params->hdr.tag = ATAG_NONE; /* Empty tag ends list */
params->hdr.size = 0; /* zero length */
Добавить в main.c функцию подготовки процессора к старту (запретить прерывания, выключить кэш данных):
static int cleanup_before_linux()
unsigned long i,old,temp;
__asm__ __volatile__("mrs %0, cpsr\n"
/* turn off I/D-cache */
asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i));
Заменить запуск приложения в main.c на вызовы функций:
setup_core_tag(); /* standard core tag */
setup_cmdline_tag(); /* commandline setting root device */
setup_end_tag(); /* end of tags */
void (*theKernel)(int zero, int arch, unsigned int params);
theKernel = (void (*)(int, int, unsigned int))JUMP_ADDR;
/* Jump to kernel with register set*/
theKernel( 0, MACH_TYPE, KERNEL_PARAMS_ADDRESS ); /* R0=0,R1=MACH_TYPE,R2=KERNEL_PARAMS_ADDRESS */
Источник