Загрузчик🔗
Общие сведения и назначение🔗
Загрузчик предназначен для выполнения операций начальной инициализации аппаратуры SoC, конфигурирования памяти (таблица трансляции адресов MMU и размещение сегментов OCM) и загрузки образа прикладной программы из флешь памяти в OCM с последующей передачей ей управления.
На начальном этапе загрузчик производит низкоуровневую инициализацию (SCU, MMU, кэши L1 и L2 уровней), настройку режимов процессора (SPSR и SP) и выполняет код стартапа C/C++.
Затем управление передаётся функции main
загрузчика, которая осуществляет ремап таблицы трансляции MMU, перемещение сегментов OCM и собственно загрузку образа прикладной программы из флешь памяти в OCM.
Начальный код загрузчика реализован на основе FSBL (First Stage Boot Loader) для Zynq-7000, который в свою очередь во многом базируется на референсном коде от ARM. Ниже приведено конспективное описание работы загрузчика.
Работа загрузчика состоит из нескольких этапов, которые подробнее описаны на соответствующих страницах:
- начальный старт и низкоуровневая инициализация;
- инициализация периферийных устройств и подготовка к запуску основной части загрузчика;
- выполнение основной части.
Начальный старт и низкоуровневая инициализация🔗
Точка старта – адрес 0x00000000
, на этот адрес управление передаёт BootROM после загрузки кода из внешней ПЗУ. На этом этапе производится низкоуровневая инициализация связанных с CPU устройств: кэшей данных и инструкций, MMU, предсказателя ветвлений, настройка указателей стека и т.п. Особенностью данной реализации является то, что кэши данных и инструкций не разрешаются перед передачей управления следующему этапу. Это сделано из-за того, что далее будет осуществляться загрузка (копирование) кода и данных основной части загрузчика DRAM, кэши для этого не нужны и даже мешают (более подробно описано на соответствующей странице).
Низкоуровневая инициализация подробно описана на странице Старт и низкоуровневая инициализация
Инициализация периферийных устройств и запуск основного загрузчика🔗
Эти действия выполняются в коде функции _start
, управление которой передаёт код низкоуровневой инициализации. По сути это функция C/C++ стартапа, которая, как правило, осуществляет инициализацию указателя стека, статическую и динамическую инициализацию и передаёт управление функции main
. В данном случае действия существенно отличаются от обычного сценария, т.к. эта функция помимо перечисленного выполняет копирование кода и данных основной части загрузчика в DRAM.
Описание стартапа приведено на странице С/C++ Startup.
Работа основной части загрузчика🔗
Код основной части загрузчика выполняет следующие действия:
- перемещает таблицу трансляции MMU в старшие адреса OCM;
- перемещает сегменты OCM из младших адресов в старшие;
- конфигурирует PL;
- загружает образ целевой программы в OCM;
- передаёт управление целевой программе.
Подробно перечисленные действия описаны на странице Основной код загрузчика.
Заключение🔗
При разработке и отладке прикладной программы рекомендуется использовать эмуляцию работы загрузчика.