Разработка простого загрузчика для встроенной системы

#embedded #boot #bootstrapping

#встроенный #загрузка #начальная загрузка

Вопрос:

Мне было поручено разработать простой загрузчик для встроенной системы. Мы не используем никаких ОС или RTOS, поэтому я хочу, чтобы это было действительно просто.

Этот код будет сохранен в ПЗУ, и процессор начнет выполнение при включении питания.

Моя цель — написать первую часть на ASM, которая выполняла бы следующие операции:

  • Инициализируйте процессор
  • Скопируйте сегмент .data из ROM в RAM
  • Очистите сегмент .bss в оперативной памяти
  • Вызовите main

Очевидно, что Main будет написан на C и выполнять операции более высокого уровня, такие как самопроверка и т.д…

Чего я действительно не знаю, как сделать, так это объединить эти две программы в одну. Я нашел дерьмовый инструмент, который в основном использует objcopy для сбора разделов .text и .data из исполняемых файлов и добавляет некоторый asm спереди, но это, похоже, действительно уродливый способ сделать это, и мне было интересно, может ли кто-нибудь указать мне правильное направление?

Ответ №1:

Вы можете (в принципе) связать объектный файл, сгенерированный из кода на ассемблере, как вы связали бы любой объект из вашей программы.

Загвоздка в том, что вам нужно выложить сгенерированный исполняемый файл так, чтобы ваш код запуска был в начале. Если вы используете GNU ld, способ сделать это — скрипт компоновщика.

Примитивная настройка (не проверялась на наличие синтаксических ошибок):

 MEMORY
{
    FLASH (RX) : ORIGIN = 0,          LENGTH = 256K
    RAM (RWX)  : ORIGIN = 0x40000000, LENGTH = 4M
}

SECTIONS
{
   .bootloader 0 : AT(0) { bootloader.o(.text) } >FLASH AT>FLASH
   .text : { _stext = .; *(.text .text.* .rodata .rodata.*); _etext = . } >FLASH AT>FLASH
   .data : { _sdata = .; *(.data .data.*); _edata = .; _sdata_load = LOADADDR(.data) } >RAM AT>FLASH
   .bss (NOLOAD) { _sbss = .; *(.bss .bss.*); _ebss = . } >RAM
}
  

Основная идея состоит в том, чтобы дать компоновщику приблизительное представление о карте памяти, затем назначить разделы из входных файлов разделам в окончательной программе.

Компоновщик сохраняет различие между «виртуальным» и «загрузочным» адресами для каждого раздела вывода, поэтому вы можете указать ему сгенерировать двоичный файл, куда перемещается код для конечных адресов, но расположение в исполняемом файле отличается (здесь я говорю ему поместить раздел .data в RAM, но добавить его к разделу .text во flash).

Затем ваш загрузчик может использовать предоставленные символы ( _sdata , _edata , _sdata_load ), чтобы найти раздел данных как в оперативной памяти, так и во флэш-памяти и скопировать его.

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

Комментарии:

1. Большое спасибо за объяснение, это очень полезно.

Ответ №2:

Саймон прав. Существуют более простые скрипты компоновщика, чем этот, которые будут отлично работать для того, что вы делаете, но суть в том, что компоновщик берет объекты и создает двоичный файл, поэтому в зависимости от используемого вами компоновщика вы должны понимать способы, которыми вы можете сказать этому компоновщику, чтобы он что-то делал, а затем заставить его это делать. К сожалению, я не думаю, что для этого существует отраслевой стандарт, вам нужно переходить от компоновщика к компоновщику и понимать их. И, конечно, в gnu ld существует множество очень сложных скриптов компоновщика, некоторые люди живут, чтобы решать проблемы в компоновщике.

Комментарии:

1. github.com/dwelch67/raspberrypi У меня есть каталог databss или что-то в этом роде с некоторым текстом, в котором описываются эксперименты с gnu ld, то, что вы можете попробовать самостоятельно создать нужный вам скрипт компоновщика, а затем оттуда переменные, которые вы можете использовать в своем bootstrap для копирования .data, zero .bss и все остальное, что вас может заинтересовать.

2. Большое спасибо. Я посмотрю. У меня также есть Raspberry pi дома, так что это пригодилось бы 🙂