Jump to content

    
Sign in to follow this  
Macslim

Вызов функций и процедур

Recommended Posts

Возник вопрос оптимизации размера программы.

Имеется устройство, ПО которого состоит из двух частей:
1. Программа "загрузчик", которая содержит процедуры функции:
- инициализация периферии и работу с ней.
- работа с протоколом
- шифрования/расшифровка данных.

- логика работы "загрузчика"


2. Программа "прошивка", которая содержит процедуры функции:
- инициализация периферии и работу с ней.
- работа с протоколом
- шифрования/расшифровка данных.

- логика работы "прошивки"
- данные для работы "прошивки"

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

Встал вопрос оптимизации программы, невооруженным взглядом видно, что "загрузчик" и "прошивка" содержат одинаковые части кода (отмечено жирным). В идеале, было бы здорово, чтобы структура выродилась в следующее:
1. Программа "загрузчик", которая содержит процедуры функции:
- инициализация периферии и работу с ней.
- работа с протоколом
- шифрования/расшифровка данных.
- логика работы "загрузчика"

2. Программа "прошивка", которая содержит процедуры функции:
- логика работы "прошивки"
- данные для работы "прошивки"

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

Не подскажите что почитать или где можно посмотреть об этом?

Share this post


Link to post
Share on other sites

Не ясно, где располагаются загрузчик с прошивкой (флеш NOR или NAND, флеш-диск и т.д.), т.е можно ли напрямую выполнять подпрограммы загрузчика из доступной области памяти или требуется копирование, разжатие, расшифровка и т.д. Можно собрать требуемые подпрограммы принципиально позиционно-независимыми и перемещаемыми, чтобы выдернуть их в ОЗУ, можно предусмотреть формирование в процессе сборки табличек для релокации (на основе соотв. сегмента из например ELF-файла, из которого формируется загрузчик - это зависит от используемой платформы, я делал такое для MIPS), которые используются для настройки подпрограмм после копирования в ОЗУ. Да, и достаточно ли будет ОЗУ для размещения в нём требуемого?

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

Share this post


Link to post
Share on other sites
16 minutes ago, GeorgK said:

Не ясно, где располагаются загрузчик с прошивкой (флеш NOR или NAND, флеш-диск и т.д.), т.е можно ли напрямую выполнять подпрограммы загрузчика из доступной области памяти или требуется копирование, разжатие, расшифровка и т.д. Можно собрать требуемые подпрограммы принципиально позиционно-независимыми и перемещаемыми, чтобы выдернуть их в ОЗУ, можно предусмотреть формирование в процессе сборки табличек для релокации (на основе соотв. сегмента из например ELF-файла, из которого формируется загрузчик - это зависит от используемой платформы, я делал такое для MIPS), которые используются для настройки подпрограмм после копирования в ОЗУ. Да, и достаточно ли будет ОЗУ для размещения в нём требуемого?

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

Ну если более детально то выглядит приблизительно так:
"Загрузчик" располагается с адреса 0x8000000
"Прошивка" с адреса 0x8008000

Разработка ведется в Keil.
Вызвать метод по указанному адресу у меня проблем не вызывает. Проблема в том каким методом, при изменении в общих процедурах и функциях, менять указатели на процедуры и функции. Я понял что Вы предлагаете вычитывать это из ELF файлов, то есть написать некую внешнную программу которая будет вызываться по окончанию компиляции "загрузчика", и формировать некий файл описания на основе ELF файла, для последующего использования в "Прошивке"? Я правильно понимаю?

Share this post


Link to post
Share on other sites
7 минут назад, Macslim сказал:

Проблема в том каким методом, при изменении в общих процедурах и функциях, менять указатели на процедуры и функции. Я понял что Вы предлагаете вычитывать это из ELF файлов

Хотите - ковыряйте эльфы, можно проще, в заранее отведенную область памяти записать адреса вызываемых функций, как это делается с векторами прерываний...

Share this post


Link to post
Share on other sites
4 minutes ago, mantech said:

Хотите - ковыряйте эльфы, можно проще, в заранее отведенную область памяти записать адреса вызываемых функций, как это делается с векторами прерываний...

То есть сделать таблицу с нужными указателями на нужные функции? Хм.. мне нравится. Спасибо!

Share this post


Link to post
Share on other sites
3 часа назад, Macslim сказал:

Но возникает вопрос, как вызывать процедуры и функции из разных программ?

А смысл? Вызывать несложно (если обе эти части выполняются из флешь), но тогда смысл деления на "загрузчик" и "прошивку" пропадает. Будет просто единое ПО, зачем-то компилируемое по частям (наверное чтоб создать как можно больше потенциальных граблей).

2 часа назад, Macslim сказал:

То есть сделать таблицу с нужными указателями на нужные функции? Хм.. мне нравится. Спасибо!

Не понятен смысл: зачем это всё нужно? Реально не хватает флеша? Это выглядит нереалистичным.

И какова была изначальная причина деления ПО на 2 части?

Share this post


Link to post
Share on other sites
3 часа назад, jcxz сказал:

И какова была изначальная причина деления ПО на 2 части?

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

Share this post


Link to post
Share on other sites

Как обычно, потом окажется, что той "инициализации периферии и работы с ней", реализованной в загрузчике, не хватит при внесении в ПО новых фич и придется в основном ПО писать патч-функции и не факт что их объем, в конечном счете, не превысит первоначальный... Также на ровном месте создаются явные зависимости между загрузчиком и основным ПО, которые, как сейчас может показаться, не должны привести к сложностям. Однако, ИМХО, это ложное предположение... Я бы на месте ТС пока что отложил эту идею и покопался в текущей реализации загрузчика/основного ПО на предмет банального оптимизирующего рефакторинга исходников. Ну а по теме можно посмотреть как, например, в LPC/XMC-микроконтроллерах реализованы так называемые IAP ROM-function. Это примерно то же самое, что Вы, @Macslim, хотите.

Share this post


Link to post
Share on other sites
7 часов назад, Macslim сказал:

сделать таблицу с нужными указателями на нужные функции?

Тут всё это подробно расписано.

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

Share this post


Link to post
Share on other sites
16 hours ago, Darth Vader said:

Тут всё это подробно расписано.

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

Большое спасибо за ссылку!

Ну собственно, сейчас так и есть, "прошивка" не знает о существовании "загрузчика".

По поводу почему программа разделена на "загрузчик" и "прошивку"? Это сделано из-за того что устройство меняет функционал, в зависимости от "прошивки". То есть, через протокол можно менять "прошивку". Например устройство с 4 реле может работать как 4 канала реле, или как два канала управления моторами. То есть аппаратная часть не меняется, а вот логика работы устройства за счет замены "прошивки" меняется кардинально.

Share this post


Link to post
Share on other sites
52 минуты назад, Macslim сказал:

По поводу почему программа разделена на "загрузчик" и "прошивку"? Это сделано из-за того что устройство меняет функционал, в зависимости от "прошивки". То есть, через протокол можно менять "прошивку". Например устройство с 4 реле может работать как 4 канала реле, или как два канала управления моторами. То есть аппаратная часть не меняется, а вот логика работы устройства за счет замены "прошивки" меняется кардинально.

И что? Это нисколько не мешает менять всю прошивку целиком. И не оправдывает деления на части и усложнения её.

Есть такой механизм: "условная компиляция", которая позволяет собирать одни и те же исходники под отличающийся функционал.

Share this post


Link to post
Share on other sites
1 minute ago, jcxz said:

И что? Это нисколько не мешает менять всю прошивку целиком. И не оправдывает деления на части и усложнения её.

Есть такой механизм: "условная компиляция", которая позволяет собирать одни и те же исходники под отличающийся функционал.

Это понятно. Но как в таком случае менять прошивку если нет доступа до устройства (например под водой или под землей)?

Share this post


Link to post
Share on other sites
50 минут назад, Macslim сказал:

Это понятно. Но как в таком случае менять прошивку если нет доступа до устройства (например под водой или под землей)?

Также как всегда: отправить прошивку устройству (рабочему ПО по рабочему протоколу связи), оно сохранит её в памяти, перегрузится, а ПО загрузчика прошьёт прошивку в память программ.

Share this post


Link to post
Share on other sites
59 минут назад, jcxz сказал:

Также как всегда: отправить прошивку устройству (рабочему ПО по рабочему протоколу связи), оно сохранит её в памяти...

Не всегда лишнему корпусу на плате найдется места, равно как и ног у МК... А еще все зависит от девайса: где-то не допустимо отстраняться от основного функционала, отводя время для сервисных функций (в том числе на обновление ПО), а где-то вполне допустимо. А еще, например, способ с приемом прошивки в основном ПО и непосредственно прошивкой в загрузчике не совсем, ИМХО, безопасен - мало ли прошьют ПО с багом, не позволяющим больше скачать прошивку? У меня в последних > 10 устройствах, например, загрузчик - это полноценная программа, по максимуму отлаженная для приема, прошивки и запуска основного ПО. Она не меняется, поэтому нет возможности каким-либо образом запороть железку - пара "клиентское ПО на ПК для обновления"/"загрузочное ПО для МК" остаются статичными в разработке, а посему - стабильными. А коль уж загрузчик весьма сложен, то можно и логику обновления самих загрузчиков реализовать.

Share this post


Link to post
Share on other sites
19 минут назад, Arlleex сказал:

Не всегда лишнему корпусу на плате найдется места, равно как и ног у МК... А еще все зависит от девайса: где-то не допустимо отстраняться от основного функционала, отводя время для сервисных функций (в том числе на обновление ПО), а где-то вполне допустимо.

Так и я не говорил про "лишний корпус". Всё зависит от требований, предъявляемых к функционирования устройства: если ОЗУ много и внезапные перезагрузки не страшны - можно принимать в ОЗУ; если много флешь программ - можно в неё (если это не мешает нормальной работе устройства).

У меня, в одном проекте, как-то было много лишнего ОЗУ, а в SPI-флеши - мало места. И требоваось безопасное обновление (устойчивое к перезагрузкам). Так я сделал приём прошивки в ОЗУ (по рабочему протоколу), рестарт в загрузчик. А уже в загрузчике: проверку образа (в ОЗУ), запись его в верхнюю часть флеши программ (нерабочая область флеши), перезапись в рабочую область флеши. Получилось безопасное обновление и дополнительного внешнего чипа флеши не потребовалось.

Ну а если нет времени на "отстранение от основного функционала на обновление", то и обновление невозможно.

 

Цитата

А еще, например, способ с приемом прошивки в основном ПО и непосредственно прошивкой в загрузчике не совсем, ИМХО, безопасен - мало ли прошьют ПО с багом, не позволяющим больше скачать прошивку? У меня в последних > 10 устройствах, например, загрузчик - это полноценная программа, по максимуму отлаженная для приема, прошивки и запуска основного ПО. Она не меняется

А если "не меняется", то и нет возможности устранить баг в ней (загрузчике). А добавление функционала по приёму прошивки в загрузчик, увеличивает его сложность (особенно при сложном рабочем протоколе), а следовательно - повышает вероятность бага в нём. И тут гораздо больше шансов получить необновляемый кирпич. Чем если просто навести порядок в поддержке и не давать на обновление не оттестированные прошивки.

 

Цитата

поэтому нет возможности каким-либо образом запороть железку

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

Цитата

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

Вот вот...

 

PS: Обсуждали же это всё уже. И не один раз. Все плюсы и минусы разных подходов известны.

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