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

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

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

 

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

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

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

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

asm (" B 1 ");

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

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


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

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

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

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

и ещё вопрос

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

 

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

 

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

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

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

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


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

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

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

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

 

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

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

 

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

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

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

 

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

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

 

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

 

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

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

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

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

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


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

Может лучше исходить из конечной цели?

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

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

 

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


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

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

 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 

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

 

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

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

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

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

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

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


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

Вот исходники загрузчика для LPC178X. Практически один в один по описанию из первого поста:

 

https://github.com/blackyblack/LPC-DfuSe-Bootloader

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


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

LPC так легко взламывают.

 

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

 

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

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


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

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

 

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

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

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

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

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

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

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


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

В мануале что-то написано, но нет примеров.

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

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

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


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

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

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

 

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

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

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


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

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

 

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

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

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


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

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

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

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

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


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

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

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

 

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

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

 

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

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

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


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

:bb-offtopic:

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

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


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

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

 

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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