Перейти к содержанию
    

Стартовый загрузчик

Хочется понять, как работает эта штука? В моём представлении это маленькая программа, находящаяся где-то в хвосте флеш-памяти. При старте начинается выполнение программы с нулевого адреса, где проверяется выполнение какого-то условия, например, уровень на определённой ножке. Если условие выполняется, то следует инструкция вроде JMP Bootloader, т.е. переход в область флеш, содержащей команды загрузчика, которые выполняет ЦПУ. Загрузчик принимает данные в виде файла *.bin по какому-либо интерфейсу МК, эти данные он раскладывает во флеш-памяти, затирая старую версию прошивки. Причём в новой версии программы должна быть та же самая процедура перехода в область загрузчика на случай следующего обновления. Если в этом месте мысли правильные, то дальше имеются мысли по поводу организации самопального загрузчика:

1. Пишется программа загрузчика - процедуры приёма и раскладки данных в памяти, компилируется в виде файла *.bin.

2. Пишется программа для записи полученного файла куда-нибудь в дальний угол памяти, начиная с определённого адреса, допустим 0х1000000. Всё, загрузчик находится в памяти.

3. Пишем рабочую программу, которая в самом начале содержит условие с переходом вроде JMP 0x1000000. Размер прошивки должен быть всегда такой, чтобы не затёрся код загрузчика.

 

Примерно такие у меня измышления. Насколько они правильные? Если правильные, то имеются попутные вопросы:

1. Как организовать запись байта по определённому адресу флеш на С в IAR?

2. В MSP430 перед изменением флеш нужно предварительно настроить контроллер флеш-памяти. Как обстоит дело в LPC1778?

3. Если в LPC1778 прошивка записывается через UART0, то там уже есть загрузчик? Если он есть, то можно ли его случайно стереть?

 

Где можно подробнее почитать на эту тему с самого нуля с пошаговой инструкцией создания загрузчика?

 

P.S Вынтернете гуглил на эту тему ровно несколько минут, попадались всякие описания загрузчиков планшетов, смартфонов и прочих девайсов.

Изменено пользователем ДЕЙЛ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

находящаяся где-то в хвосте флеш-памяти

нет. может и в начале быть.

 

Где можно подробнее почитать на эту тему с самого нуля с пошаговой инструкцией создания загрузчика?

в примерах от производителя обычно всё есть.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

нет. может и в начале быть.

В начале находится таблица векторов прерываний. Пока нет желания возиться с её переносом. Я так понял, что расположение загрузчика в памяти непринципиально? Главное не затирать код программы.

 

И ещё попутный вопрос. Как в С сделать условный переход программы на определённый адрес флеш? На ассемблере это JMP adres, JMZ adres, JMN adres и т.п. Как это будет выглядеть на С?

Изменено пользователем ДЕЙЛ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если загрузчик и программа используют одно прерывание, ну например прием и передачу по последовательному интерфейсу, как тогда поступают с таблицей векторов? Загрузчик свою таблицу использует, а когда передает управление программе, то программа должна таблицу векторов переписать на свою?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Таблицу векторов переносить нужно. В Cortex-M3 это делается легко.

Логика должна быть другой:

- стартует проц в режиме загрузчика;

- загрузчик проверяет условие и если оно не выполнено, то передает управление пользовательской программе;

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

 

Пользовательская программа вправе вообще ничего не знать про загрузчик.

Загрузчик обязан работать даже если пользовательская программа битая/отсутствует.

 

Загрузчик и пользовательская программа - это две параллельные сущности с точностью до карты памяти.

Т.е. пользовательская программа и загрузчик не должны пересекаться во флеши.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3. Если в LPC1778 прошивка записывается через UART0, то там уже есть загрузчик? Если он есть, то можно ли его случайно стереть?

 

Где можно подробнее почитать на эту тему с самого нуля с пошаговой инструкцией создания загрузчика?

 

Конечно есть там уже загрузчик. А то откуда там ISP и IAP? Из воздуха возникают?

Программными средствами там и защита делается. Поэтому LPC так легко взламывают.

 

Прочитать тоже об этом так просто не получится, на форумах про NXP изредка светятся энтузиасты занимающиеся реверсингом встроенных загрузчиков.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Справа вверху кнопка "Поиск", в выпадающем окне есть "расширенный поиск", в нем можно ограничить поиск разделом "ARM". Выдает 16 страниц сообщений, из них примерно четверть как раз на интересующую вас тему, да и в остальных сможете почерпнуть полезную информацию.

 

Вот тут я описывал, как реализован загрузчик у меня. В последующих сообщениях объясняю, почему сделано именно так. Вот тут более подробно, но для MSP430. Идея та же, отличаются детали реализации - для Cortex-M3 вместо копирования векторов в ОЗУ надо прописать их адрес в VTOR и для Coretx-M0/M3 надо загрузить из таблицы векторов MSP. Вот тут описывал, как это реализовываю в Cortex-M3.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если загрузчик и программа используют одно прерывание, ну например прием и передачу по последовательному интерфейсу, как тогда поступают с таблицей векторов? Загрузчик свою таблицу использует, а когда передает управление программе, то программа должна таблицу векторов переписать на свою?

Думаю, что можно пользоваться каким-то флагом, указывающим, что именно сейчас выполняется - загрузчик или программа. Например, при выполнении кода загрузчика в определённой ячейке памяти одно число записано, при работе программы другой и в самом начале обработчика прерываний смотреть на эту ячейку для выбора дальнейшего варианта действий.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Думаю, что можно пользоваться каким-то флагом, указывающим, что именно сейчас выполняется - загрузчик или программа.

В таком случае нужно определится что вы собираетесь сделать:

- загрузчик

- или программу, которая имеет возможность менять часть своего кода.

 

Второе гораздо сложнее в проектировании и менее востребовано в жизни.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот тут я описывал, как реализован загрузчик у меня. В последующих сообщениях объясняю, почему сделано именно так.

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

 

Пока понял так, что загрузчик и программе есть абсолютно независимые программы, связь между которыми в самом простом случае на уровне ассемблерной инструкции JMP Program_addres или JMP Bootloader_addres. Так?

Если скомпилировать бинарный файл прошивки и записать его по нестандартному адресу флеш (не 0x0000, а, допустим, по адресу 0x30000, вставив по адресу 0x0000 инструкцию JMP 0x30000), то программа будет работоспособной или компилятор делает привязку к абсолютным адресам? Пока не рассматриваю конкретный МК.

Как реализовать на Си запись данных во флеш по конкретным адресам в LPC1778? Интересно посмотреть пример кода. Можно даташит пожевать или у гугла спросить, но если кто-то может за пять минут сказать то, что я могу полдня искать, то лучше спросить. Иначе на форуме тогда не было бы смысла читать-писать :)

 

 

В таком случае нужно определится что вы собираетесь сделать:

- загрузчик

- или программу, которая имеет возможность менять часть своего кода.

 

Второе гораздо сложнее в проектировании и менее востребовано в жизни.

я свои измышления пишу, в этой теме пока на нуле

Изменено пользователем ДЕЙЛ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

я свои измышления пишу, в этой теме пока на нуле

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

Может, вам загрузчик и не нужен.

 

Хочется понять, как работает эта штука?

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

1. Загрузчики по последовательным интерфейсам, поставляемые в микроконтроллере производителем ("железный");

2. Пользовательские загрузчики ожидающие программу извне и прошивающие ее в МК ("с одной копией программы");

3. Загрузчики копирующие образ программы из внутренней или внешней флеш в область программы и стартующие ее.

Образ получает и пишет сама пользовательская программа ("с двумя копиями программы");

4. и т.п. ...

 

Кроме этого:

- нужна ли кнопка для инициализации обновления. алгоритм ее работы;

- нужна ли CRC прошивки. какая?

- шифрование прошивки. как и чем?

- индикация проблем в загрузчике, в прошивке и т.п.

- контроль версий.

- одна прошивка для разный видов МК.

- экспортируемые из загрузчика функции.

- передача параметров в загрузчик при перезагрузке.

- перенос векторов прерываний.

- и т.п.

 

По каждому из этих пунктов тоже можно долго дискутировать. Была тут война из-за кнопки, как-то)

 

UPD. Да, задачу защиты от "кирпича" не упомянул.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Думаю, что можно пользоваться каким-то флагом, указывающим, что именно сейчас выполняется - загрузчик или программа.
Не нужно изобретать велосипед. Такой флаг уже заложен производителем. И называется он "ремап" у ARM7, Cortex-M0 и "регистр VTOR" у Cortex-M3/M4. Один раз прописали как надо и дальше проверка делается в железе. Недостатки вашего варианта с программной проверкой флага: а) программа теряет время на проверку. б) вы обязательно забудете такую проверку в каком-нибудь прерывании.

Пока понял так, что загрузчик и программе есть абсолютно независимые программы, связь между которыми в самом простом случае на уровне ассемблерной инструкции JMP Program_addres или JMP Bootloader_addres. Так?
Да, так.

Если скомпилировать бинарный файл прошивки и записать его по нестандартному адресу флеш
А вот тут не так - вы его должны скомпилить (точнее слинковать) в нестандартный адрес. Тогда он и запишется куда надо без лишних телодвижений и работать будет.

или компилятор делает привязку к абсолютным адресам?
Да, делает.

Как реализовать на Си запись данных во флеш по конкретным адресам в LPC1778? Интересно посмотреть пример кода. Можно даташит пожевать или у гугла спросить
В user manual целый раздел с примерами. У меня на чистом Си нет, есть на Си++.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Может, вам загрузчик и не нужен.

Мне нужно в перспективе реализовать удалённую смену прошивки, а для этого нужен тот самый пользовательский загрузчик, ожидающий программу извне. Но т.к. в этом деле пока ноль, то хочу сначала освоить основы. Это как с освоением способов обмена данными между программой на ПК и МК: сначала учимся отправлять-принимать байт, потом групповую передачу массива байтов, потом осваиваем алгоритмы обнаружения ошибок и т.д. Мало кто сразу начинает с освоения протоколов, минуя этап лицезрения отправки байта. Вот и я сначала хочу азы освоить.

 

 

Если скомпилировать бинарный файл прошивки и записать его по нестандартному адресу флеш

А вот тут не так - вы его должны скомпилить (точнее слинковать) в нестандартный адрес. Тогда он и запишется куда надо без лишних телодвижений и работать будет.

Уже интереснее. :) Как это сделать в IAR? И можно ли таким способом по одному адресу раздельно записать загрузчик, а по другому программу? Т.е. по очереди два файла загрузить. Флеш полностью не стирается перед записью?

 

UP1: В IAR нашёл настройку начальных адресов: Options -> Linker -> вкладка Config -> кнопка Edit

Изменено пользователем ДЕЙЛ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть ещё вопрос по безусловному переходу.

 

если написать такой код:

int i;
void main (void)
{
for (i = 0; i<20; i++)
      {
       asm (" nop ");
      }
asm (" B 0x???? ");
}

то по какому адресу нужно сделать безусловный переход, чтобы программа стала заново выполняться и возможно ли это? МК LPC1778, среда IAR.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уже интереснее. Как это сделать в IAR?

Есть скрипты компоновщика (линкера), в которых указывается расположение всех секций с кодом и данными. Мне совершенно не нравится формат этого файла, я в нем никогда не разбирался, так что сейчас ничего не скажу. Советую почитать документацию IAR по формату этого файла, там все написано.

 

И можно ли таким способом по одному адресу раздельно записать загрузчик, а по другому программу? Т.е. по очереди два файла загрузить.

Можно.

 

Флеш полностью не стирается перед записью?

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

 

по какому адресу нужно сделать безусловный переход, чтобы программа стала заново выполняться и возможно ли это?

Смотри, процесс загрузки выглядит следующим образом:

1. Сброс. Вызов соответствующего обработчика прерывания.

2. Если используется стандартный шаблон проекта, то в обработчике прерывания сброса обычно идет вызов процедуры SysInit, которая выполняет инициализацию некоторого оборудования (PLL например).

3. После SysInit вызывается процедура инициализации библиотеки времени исполнения (CRT, C Runtime Library). В Keil она имеет метку __main, в IAR не помню, может так же, может подругому. Эта процедура инициализирует кучу, статические переменные, ну и остальное по мелочи.

4. После инициализации, внутри __main вызывается уже твой main.

 

Получается, надо переходить на начало обработчика прерывания сброса. Перейти не проблема - нужно только расположить его по фиксированному адресу в скрипте компоновщика, проблема в другом. Смотри, ты поработал, повключал какие-то прерывания, настроил UART, еще что-нибудь, а потом переходишь на процедуру сброса. Как отреагирует твоя программа на "попорченные" настройки оборудования? Ведь обычно, она запускается со сброшенным оборудованием. Что будет, если при инициализации CRT начнут шпарить прерывания UART? Думаю ничего хорошего. Конечно, можно все это предусмотреть, но это сложно и чревато сложно отлавливаемыми ошибками, поэтому лучше сбрасывать контроллер, а не просто куда-то переходить.

Изменено пользователем menzoda

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...