Jump to content

    
Sign in to follow this  
ДЕЙЛ

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

Recommended Posts

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

 

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

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

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

С этим разобрался, для программного сброса перезапуска программы и соответственно для передачи управления по какому-либо адресу младший бит этого адреса должен быть всегда установлен, если используется Cortex-M3. Т.е. для программного перезапуска нужно написать:

asm (" B 1 ");

Для меня этот эксперимент принципиален для уяснения принципа передачи управления по конкретному адресу флеш, т.к. бутлоадер таким способом запускает программу, как я представляю.

Share this post


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

А если у меня в проекте никакие библиотеки не подключены? Просто имеется такой код:

void main (void)
{
  while(1)
  {
  }
}

и ещё вопрос

Если я участок памяти программы, начиная с нулевого адреса, полностью скопирую в ОЗУ по адресу ADRES, затем после процедуры копирования сделаю перескок ассемблерной инструкцией asm (" B ADRES ");, то это будет равносильно выполнению программы заново? Работать будет?

 

Пока в матчасть вникаю, до железа руки не доходят.

 

Вот ещё непонятность.

в описании ядра CM3 есть такие слова: "Таблица векторов прерываний может быть перемещена по другому адресу в области кода или в области ОЗУ" и далее имеется описание регистра смещения таблицы векторов VTOR. Как выглядит участок программы, который перемещает эту таблицу векторов? Нужно просто в регистр смещения записать новый адрес? Какие-то дополнительные действия нужны? Хотелось бы посмотреть пример исходника.

Edited by ДЕЙЛ

Share this post


Link to post
Share on other sites
А если у меня в проекте никакие библиотеки не подключены? Просто имеется такой код:

void main (void)
{
  while(1)
  {
  }
}

SysInit находится до этого кода. Есть ли он или нет надо смотреть в стартап-файле, но даже если его нет, все остальное остается в силе и не зависит от того используешь ты библиотеки или нет.

 

Если я участок памяти программы, начиная с нулевого адреса, полностью скопирую в ОЗУ по адресу ADRES, затем после процедуры копирования сделаю перескок ассемблерной инструкцией asm (" B ADRES ");, то это будет равносильно выполнению программы заново? Работать будет?

В общем случае нет. На этапе компоновки вместо вызовов функций и обращений к переменным подставляются абсолютные адреса, то есть необходимо заранее знать где будет исполняться программа. Если ты переместишь программу в другое место, то все сломается. Однако, компоновщик может поддерживать генерацию кода, инвариантного к расположению в памяти (position independent). По крайней мере в тулчейне от ARM я видео такую опцию, но подробно не интересовался.

 

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

будет равносильно выполнению программы заново? Работать будет?

В общем случае нет.

 

Пока в матчасть вникаю, до железа руки не доходят.

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

 

Может лучше исходить из конечной цели? Например, сделать загрузчик для такого-то МК, который должен то-то и то-то, а не "что будет, если я вызову инструкцию перехода". Так сказать от общего к частному, сначала по советам сделаешь работающий загрузчик, а потом будешь разбираться почему именно так.

 

Вот ещё непонятность.

в описании ядра CM3 есть такие слова: "Таблица векторов прерываний может быть перемещена по другому адресу в области кода или в области ОЗУ" и далее имеется описание регистра смещения таблицы векторов VTOR. Как выглядит участок программы, который перемещает эту таблицу векторов? Нужно просто в регистр смещения записать новый адрес? Какие-то дополнительные действия нужны? Хотелось бы посмотреть пример исходника.

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

Edited by menzoda

Share this post


Link to post
Share on other sites
Может лучше исходить из конечной цели?

конечная цель такая: имеется LPC1778, имеется скомпилированный файл proga.bin.

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

 

Share this post


Link to post
Share on other sites

В кратце опишу, как я это вижу. Подробности поведения загрузчика опускаю, это уже на твоей совести.

 

- Думаем сколько секторов памяти (начиная с первого) выделить под загрузчик.

- Настраиваем проект1 загрузчика так, чтобы его таблица векторов прерываний располагалась по нулевому адресу2, а остальной код не выходил за рамки отведенной памяти.

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

- Загрузчик может работать с файлами формата Intel HEX. Файл состоит из простых текстовых строк с данными и адресом, куда эти данные записать. Это стандарт де-факто для прошивки различных устройств. Генерируется всеми средствами разработки. Можно использовать и другие форматы.

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

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

- Для перехода к основному ПО необходимо (именно в такой последовательности):

1. запретить все прерывания

2. привести состояние использованной периферии к начальному

3. задать в регистре смещения новое положение таблицы векторов прерываний основного ПО

4. совершить переход

- Загрузчик может получать файл прошивки по любому интерфейсу. При получении файла он разбирает его формат и записывает содержимое в соответствующую область памяти. Если используется формат Intel HEX, то мы имеем явное указание куда записывать данные3. Если используется простой бинарный образ, то записываем его последовательно в начало области, отведенной под основное ПО.

- Перед переходом к основному ПО загрузчик должен убедиться, что оно существует. Для этого при записи ПО подсчитываем его контрольную сумму, результат записываем в заранее определенное место. Перед переходом пробегаемся по области основного ПО и сверяем контрольную сумму. Если все хорошо - переходим, если не сошлось - остаемся в загрузчике4.

- Чтобы перейти из основного ПО в загрузчик - программно сбрасываем контроллер.

 

Вроде все верно. Если что - другие поправят.

 

1 Настраивать придется скрипт компоновщика (линкера).

2 Имеется ввиду адрес, к которому обращается ядро после сброса. Он обычно (но необязательно) численно равен нулю.

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

4 Можно придумать какой-нибудь другой алгоритм определения наличия ПО.

Edited by menzoda

Share this post


Link to post
Share on other sites
LPC так легко взламывают.

 

Чтобы не быть голословным, что "плохие процессоры "эль" взламывают, а хорошие процессоры "ка" - не взламывают", можно увидеть ссылочки на проделанные работы? И порядок цен интересен.

 

Не корысти ради, а из любопытства, когда нам клиенты наши собственные прошивки принесут. Исправленные и дополненные.

Share this post


Link to post
Share on other sites

Пока в исходник загрузчика глубоко не влазил. Хочу попробовать что-либо записать во флеш из программы.

 

т.е. если написать вот так:

adres = (unsigned int*)0x20000200; //область оперативной памяти
*adres = 0x12345678;

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

adres = (unsigned int*)0x1000; //область флеш-памяти
*adres = 0x12345678;

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

Хотелось бы увидеть самый простой пример включения возможности записи в ячейку флеш. МК LPC1778

Share this post


Link to post
Share on other sites
В мануале что-то написано, но нет примеров.

Хотелось бы увидеть самый простой пример включения возможности записи в ячейку флеш. МК LPC1778

У них нет возможности записи в ячейку. Вы можете записать только блок. Пример там писать не стали - вся запись сводится к загрузке 4 регистров и вызвове одной функции IAP. Читайте раздел Flash Memory до просветления.

Share this post


Link to post
Share on other sites
У них нет возможности записи в ячейку. Вы можете записать только блок. Пример там писать не стали - вся запись сводится к загрузке 4 регистров и вызвове одной функции IAP. Читайте раздел Flash Memory до просветления.

Но ведь хочется спросить и тут разжёваный ответ получить :rolleyes: Спасибо за направляющий ответ, буду копать.

 

Как в общих чертах происходит запись блока? Какие шаги нужно проделать?

Edited by ДЕЙЛ

Share this post


Link to post
Share on other sites
Но ведь хочется спросить и тут разжёваный ответ получить :rolleyes: Спасибо за направляющий ответ, буду копать.

 

Как в общих чертах происходит запись блока? Какие шаги нужно проделать?

Прочитать сраницу из flash, изменить байтик, (возможно очистить flash), записать станицу во flash. Все подробности в application note (а такой есть 99%) на ваш процессор.

Share this post


Link to post
Share on other sites

Покопался в настройках линкера, нашёл настройки линкера:

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.

 

 

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

......

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

В каком известном векторе прерывания находится адрес обработчика? Как узнать этот адрес?

 

 

- Для перехода к основному ПО необходимо (именно в такой последовательности):

1. запретить все прерывания

2. привести состояние использованной периферии к начальному

3. задать в регистре смещения новое положение таблицы векторов прерываний основного ПО

4. совершить переход

Написал маленькую тестовую программу без подключения библиотек и лишних файлов

unsigned int *VTOR
int main()
{
VTOR = (unsigned int*)0xE000ED08; //адрес регистра смещения таблицы
*VTOR = 0x7000;  //смещение адреса таблицы веторов прерываний
asm ("B 0x7000"); //адрес перехода
}

Т.е.

1. Прерывания не разрешал, близко к ним не подходил в этом коде.

2. Переферию не трогал

3. С этим вопрос - как узнать адрес?

4. По какому адресу переходить? Как его узнать?

 

UP1: в прикреплённом архиве проект основного ПО и второй проект тестовой программы, которая должна запускть основное ПО

post-79085-1412629711_thumb.jpg

post-79085-1412629729_thumb.jpg

post-79085-1412629748_thumb.jpg

______________________________________________.rar

Edited by ДЕЙЛ

Share this post


Link to post
Share on other sites
В каком известном векторе прерывания находится адрес обработчика? Как узнать этот адрес?

Первый вектор таблицы содержит адрес вершины стека, второй - адрес обработчика прерываний сброса, подробнее смотри в документации ARM на своё ядро (искать по словам vector table).

 

Написал маленькую тестовую программу без подключения библиотек и лишних файлов

Во-первых, ты переходишь по адресу в первом векторе таблицы, а это адрес вершины стека, так что надо переходить по второму. Во-вторых, ты переходишь в этот вектор, а надо прочитать значение из этого вектора и перейти уже по нему.

 

Исходя из твоего третьего скриншота, тебе надо прочитать содержимое по адресу 0x7004, судя по скриншоту оно было равно 0x8105, и перейти в этот самый 0x8105.

Edited by menzoda

Share this post


Link to post
Share on other sites

:bb-offtopic:

ДЕЙЛ, я, конечно, ничего против не имею, но такая боевая расцветка темы оформления каждый день по несколько часов сидения у монитора глаза не заворачивает на затылок? :)

Share this post


Link to post
Share on other sites
Во-первых, ты переходишь по адресу в первом векторе таблицы, а это адрес вершины стека, так что надо переходить по второму. Во-вторых, ты переходишь в этот вектор, а надо прочитать значение из этого вектора и перейти уже по нему.

 

Исходя из твоего третьего скриншота, тебе надо прочитать содержимое по адресу 0x7004, судя по скриншоту оно было равно 0x8105, и перейти в этот самый 0x8105.

Написал две строки

*VTOR = 0x380000; //смещение таблицы относительно начала области кода (0x0000) 0x7000 передвинуты на 7 бит влево, т.к. смещение записывается в битах 28:7
asm ("B 0x8105");

Нивкакую не работает. Что ещё упустил и как правильно написать для перехода к программе, начинающейся с адреса 0x7000?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this