|
Стартовый загрузчик, с нуля |
|
|
|
Sep 2 2014, 09:34
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Хочется понять, как работает эта штука? В моём представлении это маленькая программа, находящаяся где-то в хвосте флеш-памяти. При старте начинается выполнение программы с нулевого адреса, где проверяется выполнение какого-то условия, например, уровень на определённой ножке. Если условие выполняется, то следует инструкция вроде JMP Bootloader, т.е. переход в область флеш, содержащей команды загрузчика, которые выполняет ЦПУ. Загрузчик принимает данные в виде файла *.bin по какому-либо интерфейсу МК, эти данные он раскладывает во флеш-памяти, затирая старую версию прошивки. Причём в новой версии программы должна быть та же самая процедура перехода в область загрузчика на случай следующего обновления. Если в этом месте мысли правильные, то дальше имеются мысли по поводу организации самопального загрузчика: 1. Пишется программа загрузчика - процедуры приёма и раскладки данных в памяти, компилируется в виде файла *.bin. 2. Пишется программа для записи полученного файла куда-нибудь в дальний угол памяти, начиная с определённого адреса, допустим 0х1000000. Всё, загрузчик находится в памяти. 3. Пишем рабочую программу, которая в самом начале содержит условие с переходом вроде JMP 0x1000000. Размер прошивки должен быть всегда такой, чтобы не затёрся код загрузчика.
Примерно такие у меня измышления. Насколько они правильные? Если правильные, то имеются попутные вопросы: 1. Как организовать запись байта по определённому адресу флеш на С в IAR? 2. В MSP430 перед изменением флеш нужно предварительно настроить контроллер флеш-памяти. Как обстоит дело в LPC1778? 3. Если в LPC1778 прошивка записывается через UART0, то там уже есть загрузчик? Если он есть, то можно ли его случайно стереть?
Где можно подробнее почитать на эту тему с самого нуля с пошаговой инструкцией создания загрузчика?
P.S Вынтернете гуглил на эту тему ровно несколько минут, попадались всякие описания загрузчиков планшетов, смартфонов и прочих девайсов.
Сообщение отредактировал ДЕЙЛ - Sep 2 2014, 09:39
|
|
|
|
|
 |
Ответов
|
Sep 3 2014, 10:34
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Есть ещё вопрос по безусловному переходу. если написать такой код: Код int i; void main (void) { for (i = 0; i<20; i++) { asm (" nop "); } asm (" B 0x???? "); } то по какому адресу нужно сделать безусловный переход, чтобы программа стала заново выполняться и возможно ли это? МК LPC1778, среда IAR.
|
|
|
|
|
Sep 4 2014, 05:33
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 13-09-12
Пользователь №: 73 530

|
Цитата Уже интереснее. Как это сделать в IAR? Есть скрипты компоновщика (линкера), в которых указывается расположение всех секций с кодом и данными. Мне совершенно не нравится формат этого файла, я в нем никогда не разбирался, так что сейчас ничего не скажу. Советую почитать документацию IAR по формату этого файла, там все написано. Цитата И можно ли таким способом по одному адресу раздельно записать загрузчик, а по другому программу? Т.е. по очереди два файла загрузить. Можно. Цитата Флеш полностью не стирается перед записью? Обычно, стирается по секторам, так что если разместить загрузчик и основное ПО в разных секторах проблем быть не должно. Цитата по какому адресу нужно сделать безусловный переход, чтобы программа стала заново выполняться и возможно ли это? Смотри, процесс загрузки выглядит следующим образом: 1. Сброс. Вызов соответствующего обработчика прерывания. 2. Если используется стандартный шаблон проекта, то в обработчике прерывания сброса обычно идет вызов процедуры SysInit, которая выполняет инициализацию некоторого оборудования (PLL например). 3. После SysInit вызывается процедура инициализации библиотеки времени исполнения (CRT, C Runtime Library). В Keil она имеет метку __main, в IAR не помню, может так же, может подругому. Эта процедура инициализирует кучу, статические переменные, ну и остальное по мелочи. 4. После инициализации, внутри __main вызывается уже твой main. Получается, надо переходить на начало обработчика прерывания сброса. Перейти не проблема - нужно только расположить его по фиксированному адресу в скрипте компоновщика, проблема в другом. Смотри, ты поработал, повключал какие-то прерывания, настроил UART, еще что-нибудь, а потом переходишь на процедуру сброса. Как отреагирует твоя программа на "попорченные" настройки оборудования? Ведь обычно, она запускается со сброшенным оборудованием. Что будет, если при инициализации CRT начнут шпарить прерывания UART? Думаю ничего хорошего. Конечно, можно все это предусмотреть, но это сложно и чревато сложно отлавливаемыми ошибками, поэтому лучше сбрасывать контроллер, а не просто куда-то переходить.
Сообщение отредактировал menzoda - Sep 4 2014, 05:35
|
|
|
|
|
Sep 5 2014, 10:08
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Цитата(menzoda @ Sep 4 2014, 09:33)  2. Если используется стандартный шаблон проекта, то в обработчике прерывания сброса обычно идет вызов процедуры SysInit, которая выполняет инициализацию некоторого оборудования (PLL например). А если у меня в проекте никакие библиотеки не подключены? Просто имеется такой код: Код void main (void) { while(1) { } } и ещё вопрос Если я участок памяти программы, начиная с нулевого адреса, полностью скопирую в ОЗУ по адресу ADRES, затем после процедуры копирования сделаю перескок ассемблерной инструкцией asm (" B ADRES ");, то это будет равносильно выполнению программы заново? Работать будет? Пока в матчасть вникаю, до железа руки не доходят. Вот ещё непонятность. в описании ядра CM3 есть такие слова: "Таблица векторов прерываний может быть перемещена по другому адресу в области кода или в области ОЗУ" и далее имеется описание регистра смещения таблицы векторов VTOR. Как выглядит участок программы, который перемещает эту таблицу векторов? Нужно просто в регистр смещения записать новый адрес? Какие-то дополнительные действия нужны? Хотелось бы посмотреть пример исходника.
Сообщение отредактировал ДЕЙЛ - Sep 5 2014, 10:43
|
|
|
|
|
Sep 5 2014, 10:45
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 13-09-12
Пользователь №: 73 530

|
Цитата(ДЕЙЛ @ Sep 5 2014, 14:08)  А если у меня в проекте никакие библиотеки не подключены? Просто имеется такой код: Код void main (void) { while(1) { } } SysInit находится до этого кода. Есть ли он или нет надо смотреть в стартап-файле, но даже если его нет, все остальное остается в силе и не зависит от того используешь ты библиотеки или нет. Цитата(ДЕЙЛ @ Sep 5 2014, 14:08)  Если я участок памяти программы, начиная с нулевого адреса, полностью скопирую в ОЗУ по адресу ADRES, затем после процедуры копирования сделаю перескок ассемблерной инструкцией asm (" B ADRES ");, то это будет равносильно выполнению программы заново? Работать будет? В общем случае нет. На этапе компоновки вместо вызовов функций и обращений к переменным подставляются абсолютные адреса, то есть необходимо заранее знать где будет исполняться программа. Если ты переместишь программу в другое место, то все сломается. Однако, компоновщик может поддерживать генерацию кода, инвариантного к расположению в памяти (position independent). По крайней мере в тулчейне от ARM я видео такую опцию, но подробно не интересовался. Кроме того, как я уже говорил - кто будет сбрасывать состояние оборудование перед началом выполнения программы? Все это реализуемо, но требует понимания проблемы и дополнительных телодвижение. Поэтому, подытожив, еще раз отвечу на твой вопрос: Цитата будет равносильно выполнению программы заново? Работать будет? В общем случае нет. Цитата Пока в матчасть вникаю, до железа руки не доходят. Мне кажется ты немного не с той стороны начал. Сейчас тебе на каждый вопрос надают кучу ответов, что можно, что нельзя, нужно то, нужно это, только запутают. Вон, хотя бы посмотреть на мои ответы - вроде как нельзя, но в принципе можно. Сейчас как зароешся во всем этом... Может лучше исходить из конечной цели? Например, сделать загрузчик для такого-то МК, который должен то-то и то-то, а не "что будет, если я вызову инструкцию перехода". Так сказать от общего к частному, сначала по советам сделаешь работающий загрузчик, а потом будешь разбираться почему именно так. Цитата Вот ещё непонятность. в описании ядра CM3 есть такие слова: "Таблица векторов прерываний может быть перемещена по другому адресу в области кода или в области ОЗУ" и далее имеется описание регистра смещения таблицы векторов VTOR. Как выглядит участок программы, который перемещает эту таблицу векторов? Нужно просто в регистр смещения записать новый адрес? Какие-то дополнительные действия нужны? Хотелось бы посмотреть пример исходника. Сначала скопировать таблицу векторов в нужное место, а потом в регистр смещения записать новый адрес. Скопировать можно как угодно, таблица векторов прерываний это просто числа в памяти. Никаких дополнительных действий не нужно.
Сообщение отредактировал menzoda - Sep 5 2014, 11:05
|
|
|
|
|
Sep 5 2014, 11:09
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Цитата(menzoda @ Sep 5 2014, 14:45)  Может лучше исходить из конечной цели? конечная цель такая: имеется LPC1778, имеется скомпилированный файл proga.bin. Нужно сделать так, чтобы я мог по какому-нибудь интерфейсу с ПК этот файл побайтно отправить своей программой, а в контроллере эти байты встретит чуть ранее загруженный самопальный бутлоадер, который всё принятое разложит в памяти и запустит на выполнение. С написанием программы для ПК проблем не вижу, больше вопросов по принимающей стороне, т.е. с организацией записи прошивки в МК самопальным загрузчиком. Далее предполагаю передавать прошивку по радиоканалу и тем самым иметь возможность удалённо перепрошивать девайс.
|
|
|
|
|
Sep 5 2014, 13:25
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 13-09-12
Пользователь №: 73 530

|
В кратце опишу, как я это вижу. Подробности поведения загрузчика опускаю, это уже на твоей совести.
- Думаем сколько секторов памяти (начиная с первого) выделить под загрузчик. - Настраиваем проект1 загрузчика так, чтобы его таблица векторов прерываний располагалась по нулевому адресу2, а остальной код не выходил за рамки отведенной памяти. - Настраиваем проект основного ПО так, чтобы его образ не выходил за рамки отведенной области, а таблица векторов прерываний находилась в начале области. - Загрузчик может работать с файлами формата Intel HEX. Файл состоит из простых текстовых строк с данными и адресом, куда эти данные записать. Это стандарт де-факто для прошивки различных устройств. Генерируется всеми средствами разработки. Можно использовать и другие форматы. - Для простоты передача управления от загрузчика к основному ПО будет происходить через безусловный переход. При необходимости этот механизм можно заменить чем-нибудь другим. - Цель безусловного перехода - обработчик прерывания сброса основного ПО. Адрес обработчика находится в известном векторе прерывания. Таблица векторов прерываний находится в начале области, отведенной под основное ПО. - Для перехода к основному ПО необходимо (именно в такой последовательности): 1. запретить все прерывания 2. привести состояние использованной периферии к начальному 3. задать в регистре смещения новое положение таблицы векторов прерываний основного ПО 4. совершить переход - Загрузчик может получать файл прошивки по любому интерфейсу. При получении файла он разбирает его формат и записывает содержимое в соответствующую область памяти. Если используется формат Intel HEX, то мы имеем явное указание куда записывать данные3. Если используется простой бинарный образ, то записываем его последовательно в начало области, отведенной под основное ПО. - Перед переходом к основному ПО загрузчик должен убедиться, что оно существует. Для этого при записи ПО подсчитываем его контрольную сумму, результат записываем в заранее определенное место. Перед переходом пробегаемся по области основного ПО и сверяем контрольную сумму. Если все хорошо - переходим, если не сошлось - остаемся в загрузчике4. - Чтобы перейти из основного ПО в загрузчик - программно сбрасываем контроллер.
Вроде все верно. Если что - другие поправят.
1 Настраивать придется скрипт компоновщика (линкера). 2 Имеется ввиду адрес, к которому обращается ядро после сброса. Он обычно (но необязательно) численно равен нулю. 3 При этом все-равно нужно проверять, что мы попадаем в область основного ПО, чтобы при получении неправильного файла случайно не перетереть загрузчик. 4 Можно придумать какой-нибудь другой алгоритм определения наличия ПО.
Сообщение отредактировал menzoda - Sep 5 2014, 13:27
|
|
|
|
|
Oct 6 2014, 21:21
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Покопался в настройках линкера, нашёл настройки линкера: Config->Edit->Linker configuration file editor->Vector Table-> .intvec start = 0x7000 Config->Edit->Linker configuration file editor->Memory Regions-> ROM = 0x7000 - 0x7FFFF После компилирования и запуска в пошаговом режиме видно, что программа раположена по адресу, начиная с 0x7000, на этом этапе всё работает нормально - данные бегут из UART0. Получается, что программа уже нормально записана в память и работоспособна. Далее пробую написать маленькую программу, расположенную в обычном месте, т.е. в начальном секторе флеш. Пишу такой текст: Код main() { asm ("B 0x7000"); } Перебрал несколько возможных адресов, но всегда зависает в Hard Fault. Цитата(menzoda @ Sep 5 2014, 17:25)  - Для простоты передача управления от загрузчика к основному ПО будет происходить через безусловный переход. ...... - Цель безусловного перехода - обработчик прерывания сброса основного ПО. Адрес обработчика находится в известном векторе прерывания. Таблица векторов прерываний находится в начале области, отведенной под основное ПО. В каком известном векторе прерывания находится адрес обработчика? Как узнать этот адрес? Цитата(menzoda @ Sep 5 2014, 17:25)  - Для перехода к основному ПО необходимо (именно в такой последовательности): 1. запретить все прерывания 2. привести состояние использованной периферии к начальному 3. задать в регистре смещения новое положение таблицы векторов прерываний основного ПО 4. совершить переход Написал маленькую тестовую программу без подключения библиотек и лишних файлов Код unsigned int *VTOR int main() { VTOR = (unsigned int*)0xE000ED08; //адрес регистра смещения таблицы *VTOR = 0x7000; //смещение адреса таблицы веторов прерываний asm ("B 0x7000"); //адрес перехода } Т.е. 1. Прерывания не разрешал, близко к ним не подходил в этом коде. 2. Переферию не трогал 3. С этим вопрос - как узнать адрес? 4. По какому адресу переходить? Как его узнать? UP1: в прикреплённом архиве проект основного ПО и второй проект тестовой программы, которая должна запускть основное ПО
Сообщение отредактировал ДЕЙЛ - Oct 6 2014, 21:23
Эскизы прикрепленных изображений
|
|
|
|
|
Oct 8 2014, 05:17
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 13-09-12
Пользователь №: 73 530

|
Цитата В каком известном векторе прерывания находится адрес обработчика? Как узнать этот адрес? Первый вектор таблицы содержит адрес вершины стека, второй - адрес обработчика прерываний сброса, подробнее смотри в документации ARM на своё ядро (искать по словам vector table). Цитата Написал маленькую тестовую программу без подключения библиотек и лишних файлов Во-первых, ты переходишь по адресу в первом векторе таблицы, а это адрес вершины стека, так что надо переходить по второму. Во-вторых, ты переходишь в этот вектор, а надо прочитать значение из этого вектора и перейти уже по нему. Исходя из твоего третьего скриншота, тебе надо прочитать содержимое по адресу 0x7004, судя по скриншоту оно было равно 0x8105, и перейти в этот самый 0x8105.
Сообщение отредактировал menzoda - Oct 8 2014, 05:22
|
|
|
|
|
Oct 8 2014, 18:57
|
Местный
  
Группа: Участник
Сообщений: 234
Регистрация: 7-11-13
Пользователь №: 79 085

|
Цитата(menzoda @ Oct 8 2014, 09:17)  Во-первых, ты переходишь по адресу в первом векторе таблицы, а это адрес вершины стека, так что надо переходить по второму. Во-вторых, ты переходишь в этот вектор, а надо прочитать значение из этого вектора и перейти уже по нему.
Исходя из твоего третьего скриншота, тебе надо прочитать содержимое по адресу 0x7004, судя по скриншоту оно было равно 0x8105, и перейти в этот самый 0x8105. Написал две строки Код *VTOR = 0x380000; //смещение таблицы относительно начала области кода (0x0000) 0x7000 передвинуты на 7 бит влево, т.к. смещение записывается в битах 28:7 asm ("B 0x8105"); Нивкакую не работает. Что ещё упустил и как правильно написать для перехода к программе, начинающейся с адреса 0x7000?
|
|
|
|
Сообщений в этой теме
ДЕЙЛ Стартовый загрузчик Sep 2 2014, 09:34 smalcom Цитатанаходящаяся где-то в хвосте флеш-памяти
нет.... Sep 2 2014, 10:40 ДЕЙЛ Цитата(smalcom @ Sep 2 2014, 14:40) нет. ... Sep 2 2014, 11:43  adnega Цитата(ДЕЙЛ @ Sep 2 2014, 15:43) В начале... Sep 2 2014, 12:22 Lagman А если загрузчик и программа используют одно преры... Sep 2 2014, 11:47 ДЕЙЛ Цитата(Lagman @ Sep 2 2014, 15:47) А если... Sep 3 2014, 06:25  adnega Цитата(ДЕЙЛ @ Sep 3 2014, 10:25) Думаю, ч... Sep 3 2014, 06:29 AlexandrY Цитата(ДЕЙЛ @ Sep 2 2014, 12:34) 3. Если ... Sep 2 2014, 12:37 esaulenka Цитата(AlexandrY @ Sep 2 2014, 16:37) LPC... Sep 8 2014, 12:46 Сергей Борщ Справа вверху кнопка "Поиск", в выпадающ... Sep 2 2014, 13:10 ДЕЙЛ Цитата(Сергей Борщ @ Sep 2 2014, 17:10) В... Sep 3 2014, 06:47  adnega Цитата(ДЕЙЛ @ Sep 3 2014, 10:47) я свои и... Sep 3 2014, 07:53   ДЕЙЛ Цитата(adnega @ Sep 3 2014, 11:21) Дык, в... Sep 3 2014, 08:09 Сергей Борщ Цитата(ДЕЙЛ @ Sep 3 2014, 09:25) Думаю, ч... Sep 3 2014, 07:56 ДЕЙЛ Цитата(ДЕЙЛ @ Sep 3 2014, 14:34) Есть ещё... Sep 5 2014, 07:49 andrewlekar Вот исходники загрузчика для LPC178X. Практически ... Sep 8 2014, 06:39 ДЕЙЛ Пока в исходник загрузчика глубоко не влазил. Хочу... Sep 30 2014, 10:35 Сергей Борщ Цитата(ДЕЙЛ @ Sep 30 2014, 13:35) В мануа... Sep 30 2014, 11:36  ДЕЙЛ Цитата(Сергей Борщ @ Sep 30 2014, 15:36) ... Sep 30 2014, 12:50   Lagman Цитата(ДЕЙЛ @ Sep 30 2014, 16:50) Но ведь... Sep 30 2014, 14:00 toweroff ДЕЙЛ, я, конечно, ничего против не имею, но такая ... Oct 8 2014, 14:52 menzoda Не надо ничего сдвигать на 7 битов! Прочитай в... Oct 8 2014, 19:17 ДЕЙЛ Цитата(menzoda @ Oct 8 2014, 23:17) Не на... Oct 8 2014, 19:42 ДЕЙЛ Почему-то в пашаговом режиме после перехода по адр... Oct 8 2014, 20:55 menzoda Не так считаешь. Векторов прерываний 51, в байтах ... Oct 9 2014, 04:54 ДЕЙЛ насчёт перескока на 2кб на какой странице мануала ... Oct 9 2014, 06:47  menzoda Цитатанасчёт перескока на 2кб на какой странице ма... Oct 9 2014, 07:30   ДЕЙЛ Цитата(menzoda @ Oct 9 2014, 11:30) То ес... Oct 9 2014, 08:53 menzoda ЦитатаМошть ещё нужно указатель стека на нужное ме... Oct 9 2014, 10:15 ДЕЙЛ Железно заработало
дело было ещё и в указателе ... Oct 9 2014, 19:26 menzoda ЦитатаЖелезно заработало
Наконец! Всем миром з... Oct 10 2014, 04:59 ДЕЙЛ Оставлю тут свой код загрузчика на всякий случай, ... Feb 16 2015, 12:28
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|