Частичное обновление ПО.

Тема в разделе "Флудилка", создана пользователем Megakoteyka, 27 апр 2016.

  1. Megakoteyka

    Megakoteyka Оракул Модератор

    Встала задача обеспечить исправление кусков программы в процессоре в специфических условиях.
    Есть некоторые мысли по решению этой задачи, но хочется послушать, что скажет коллективный разум.
    Знаю, что на форуме обитает нкоторое количество матерых программеров и надеюсь, что им будет интересно поломать голову над задачкой.
    Итак.
    Есть прибор, имеющий в своем составе процессор, ПЗУ с программой и флэшку.
    В ПЗУ при изготовлении прибора намертво заливается прошивка и процессор всегда грузится из ПЗУ. Но в любой программе бывают ошибки, которые нужно исправлять. Поскольку данные, записанные в ПЗУ, изменить невозможно, остается 2 варианта:
    1. Загрузить новую версию прошивки на флэшку, а базовая версия при запуске будет проверять наличие новой версии и при необходимости загружать ее вместо себя.
    2. После загрузки в ОЗУ процессора базовой версии прошивки она проверяет наличие на флэшке пакетов с исправлениями и, найдя их, модифицирует себя в соответствии с инструкциями из пакета.
    Первый способ гораздо проще реализовать, но тогда придется передавать прошивку полностью, а это крайне нежелательно. Канал связи с прибором очень медленный, а сеансы связи короткие.
    Второй способ гораздо выгодней в плане объема передаваемых данных, но сложнее в реализации. Именно о нем и хотелось бы поговорить.

    Пока есть такие варианты исправления кода:
    1. Замена функций. В заранее выделенную секцию памяти заливается исправленный код функции. Процессор ищет в памяти вызовы исходной функции и подменяет в них адрес на адрес новой версии функции.
    2. Вставка вызова функций. В заранее выделенную секцию памяти заливается код функции, которая правильно выполняет проблемную часть алгоритма. Кусок кода (буквально несколько операторов), в котором содержится ошибка, заменяется NOP-ами, а в его начало вставляется вызов новой функции.
    3. Каждая функция в программе снабжается заглушкой. Если функция работает с ошибкой, то на флэшку передается новая версия этой функции, а в некоторую таблицу записывается ее адрес. Заглушка в исходной функции проверяет таблицу и при необходимости вызывает исправленную версию функции, а затем делает выход из исходной версии функции.
    Есть ли еще варианты решения задачи? Или мысли по поводу моих вариантов?
    Больше всего меня интересует вопрос, как из скомпилированной программы вытащить код нужной мне функции. Выписывать код в ручную из окошка дизассемблера не очень хочется. Что почитать про .obj и .elf, чтобы автоматизировать этот процесс?
     
  2. AlexU

    AlexU Гуру

    Каковы вычислительные возможности прибора -- можно ли запустить ОС типа Linux с поддержкой динамической загрузки/выгрузки модулей ядра или shared библиотек?

    И, так, мысль в догонку:
    Прибор может быть модифицирован или нет? Можно ли добавить резервное ПЗУ?
    Не знаю как сейчас, но раньше у материнок от Gigabyte была такая фишка -- DualBIOS -- матиринка была с двумя ПЗУ (BIOS), если после обновления одной из них материнка не стартовала или обновление было не удачным, то "битая" ПЗУ (BIOS) восстанавливалась из рабочей.
     
  3. Megakoteyka

    Megakoteyka Оракул Модератор

    Все сурово, ОС нет и не будет (иначе и проблемы бы не было), ничего модифицировать нельзя. Можно только заслать немножко данных.
    ПЗУ - имеется в виду однократка. Прожигается один раз и навсегда.
     
  4. ostrov

    ostrov Гуру

    Автоматическая орбитальная станция с плохим Интернетом?
     
  5. Megakoteyka

    Megakoteyka Оракул Модератор

    Ага, вроде того.
     
  6. AlexU

    AlexU Гуру

    Это Ваше решение, или требование заказчика, или ещё что?
    Про вычислительные мощности всё-таки хотелось бы узнать, если это не секрет. Почему спрашиваю -- в теории (но скоро возможно попробую на практике, если время будет) на вычислительных мощностях AVR-ок, можно запустить ОС реального времени типа FreeRTOS и т.п. Для того же Linux'а (по непроверенным данным) нужны 16 МБ оперативки, а может и меньше -- всё зависит от настроек ядра.
    Поэтому прежде, чем "изобретать велосипед", есть смысл рассмотреть уже имеющиеся методы/подходы решения аналогичных задач. А для этого нужно хоть немного понимать что за "железо".
     
  7. AlexU

    AlexU Гуру

    Скорее какой-нибудь глубоководный аппарат, т.к. с орбитальной станцией можно установить довольно скоростное соединение. Ещё в 70е годы использовались скорости до 480 кбит/с, а сейчас и подавно выше.
     
  8. ostrov

    ostrov Гуру

    Так при совке денег на космос не экономили. А теперь кризис, переходят на Ардуино. )
     
  9. ANV

    ANV Гуру

    ARM?
     
  10. Megakoteyka

    Megakoteyka Оракул Модератор

    100 МГц, 128 Кб ОЗУ. Для ОС маловато ОЗУ, да и не нужна она там по большому счету.
    Теперь импортозамещение, уж лучше бы на ардуино переходили.
    1892ВМ12Т
     
  11. Megakoteyka

    Megakoteyka Оракул Модератор

    Заблуждаетесь. Большие скорости используются полезной нагрузкой спутников, а технические каналы до сих пор медленные, но там и не нужна высокая скорость.
     
  12. AlexU

    AlexU Гуру

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

    Исходя из картины могу предложить следующее (т.к. моя картина мира может оказаться совсем не той, что в действительности, то вполне вероятно предложения могут показаться бредом):
    1. В начале адресного пространства (под адресным пространством понимать тот участок памяти, что выделяется "пользовательскому" коду) необходимо организовать, что-то вроде таблицы вызовов библиотечных функций (по аналогии с таблицей обработчиков прерываний или таблицей импорта в бинарниках). В этой таблице содержаться адреса точек входов в библиотечные функции;
    2. Если есть shared данные, которые могут менять свою структуру или тип, а так же используются несколькими функциями, то так же можно организовать таблицу с сылками на эти данные;
    3. Каждая библиотечная функция должна иметь своё адресное пространство, которое при необходимости разбивается на две части: опциональная первая часть -- статичные данные (non-shared данные), которые используются той или иной функцией, но при этом должны сохраняться между вызовами функций; вторая часть -- непосредственно код функции с точкой входа;
    4. Внутри кода каждой функции не должно быть: абсолютных переходов, абсолютных ссылок на данные. Для вызова других функций использовать "таблицу функций", для доступа к shared данным использовать "таблицу shared данных", для доступа к статичным данным функции использовать относительные ссылки на данные из первой части адресного пространства функции;
    5. Так же необходимо будет организовать хранение данных о свободных участках памяти, в которые можно будет загружать обновления;
    6. надеюсь ничего не упустил.
    Всё перечисленное в пп 1-5 позволит размещать библиотечные функции и shared данные без привязки к определённому адресу. Соответственно новая версия функции загружается в свободный участок памяти и после успешной загрузки подменяется адрес точки входа в таблице вызовов функций. Так же обновляется информация о свободной памяти. Аналогичным образом производиться обновление типа shared данных. При этом нужно учесть проблему фрагментации памяти -- можно производить дефрагментацию после каждого обновления, если обновления будут не частыми.

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

    PS: пробежался глазами по документации на 1892ВМ12Т:
     
  13. Megakoteyka

    Megakoteyka Оракул Модератор

    ОС нет, так что и понятий "процесс" и "поток" тоже нет. Просто работает прошивка, примерно как в Ардуино.

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

    Поддерживать-то он поддерживает, но ОС пожрет ресурсы, которых и так негусто. У меня весь софт сидит в 128 Кб ОЗУ и внешнюю память подключать - непозволительная роскошь, да и такты на ОС тратить не хотелось бы.

    В любом случае спасибо за участие - пока я думал над ответами и писал их, в голове кое-что прояснилось.
     
  14. AlexU

    AlexU Гуру

    На счет "проще" есть сомнения.
    Сколько итераций обновлений может выдержать такой подход?
    Т.е. "на борту" есть функционал (отжирающий ресурсы), который отчасти выполняет функции дизассемблера для поиска операции вызова функции, для подмены на вызов обновлённой функции? Потому что, если по всей прошивке тупо искать последовательность байт операции вызова, то можно повредить данные, которые просто данные, а не вызов функции.Что может привести к сбою в работе прошивки.

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

    Megakoteyka Оракул Модератор

    В плане реализации это самый простой способ, проще придумать не получилось.
    В зависимости от объема обновлений. Сейчас выделил 4 Кб - это 1024 инструкции, хватит на несколько небольших функций, а больше и не надо. Программа изначально очень тщательно тестируется, так что накатывать на нее десятки заплаток точно не потребуется. Это все на самый крайний случай, если вдруг все же вылезет небольшой косячок.
    В обновлении содержится диапазон адресов, в котором должна производиться замена, так что никакие лишние данные испортиться не могут. Можно вообще указать один адрес, в котором требуется заменить вызов. Это не дизассемблер, это тупая замена одного числа в памяти на другое. Цикл в несколько строк. И все это работает только в момент загрузки, а потом программа работает как обычно.
    Ну задачи накатывать сервиспаки из сотен заплаток и не стоит, это все же не винда :)
     
  16. ostrov

    ostrov Гуру

    Блин, да что же это за крылатая ракета со способностью менять цели и траекторию налету? А вообще решаемость задачи, я думаю, упирается в финансирование. При достаточно приличной поддержке в тему можно уйти с головой и почти наверняка что либо родить за достаточно короткое время.
     
  17. ostrov

    ostrov Гуру

    Хм, почитал инфо про Мегокотейку, оказывается я зря иронизировал. На самом деле космический аппарат какой то!
     
  18. Vad33

    Vad33 Капитан-оригинал

    Все это хорошо. А как насчет безопасности кода? Новые заплатки могут содержать новые баги, которые могут быть более разрушительные, чем старые. При перезапуске они снова будут накатываться. Так шта до следующего "сеанса связи" система может просто "не дожить".
     
  19. AlexU

    AlexU Гуру

    Сейчас вижу проблему, с которой можно столкнуться:
    фрагментация памяти -- после нескольких обновлений на "борту" свободной памяти в сумме будет достаточно для следующего обновления, но не будет сплошного участка, что приведёт к невозможности обновления. С Вашим подходом решить проблему фрагментации будет не очень просто.
    Вы на данный момент рассматриваете случай, когда обнаруживается ошибка в одной из функций. А если ошибка будет в "общей логике", когда потребуется обновление нескольких функций за один сеанс. С учетом
    вероятность возникновения ошибки в "логике" гораздо выше вероятности ошибки в конкретной функции (каждую конкретную функцию гораздо проще оттестировать и доказать её корректность, чем "логику" в целом). И с таким подходом может произойти ситуация, когда в общем обновление возможно -- памяти достаточно, а не может быть завершено, из-за того, что 4 кБ займут часть функций, а для остальных места не найдётся, хотя свободная память в достаточном объёме будет присутствовать (кусочки разбросанные по адресному пространству).
     
  20. Megakoteyka

    Megakoteyka Оракул Модератор

    Ошибка в "общей логике" - это уже из области фантастики. Общую логику задает ТЗ, а потом эта логика тестируется сперва на отдельном приборе, а затем в составе системы. Ошибка может затесаться как раз в отдельных кусочках реализации этой логики и чаще всего ошибку удается обойти при помощи штатных команд, выдаваемых прибору.
    Фрагментации памяти быть не может - память не выделяется динамически и никаких пустых кусочков нет. Есть только код, данные и стек. Все остальное можно выделить под секцию обновлений.