Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Обновление встроенного ПО компонента (CFU) — это протокол и процесс отправки новых образов встроенного ПО, установленных на целевом устройстве.
Замечание
CFU доступен в Windows 10 версии 2004 (обновление Windows 10 мая 2020 г.) и более поздних версий.
Подача CFU в резидентную прошивку — это пары файлов, один файл является частью предложения, а другой — частью содержимого. Каждое отправление CFU (каждая пара предложения и содержимого) должно быть создано вне сети перед отправкой во встроенное ПО, реализующее процесс CFU.
В образце исходного кода встроенного ПО в репозитории CFU на GitHub содержится общий код, независимый от конкретной реализации для CFU. Все остальные файлы — это вспомогательные файлы, которые можно обновить или изменить в уникальной реализации разработчика.
Содержимое
- Части предложения и контента
Части предложения и контента
Предложение и содержимое составляют пару файлов в схеме CFU.
Часть предложения — это просто 16-байтовый длинный файл, который сопоставляется со структурой FWUPDATE_OFFER_COMMAND, описанной ниже.
Часть содержимого, само встроенное ПО, подлежащее обновлению, представлено в формате, определяемом разработчиком для конечного пользователя. Предоставленный пример кода CFU использует файлы SREC для содержимого встроенного ПО.
Предложение представляет собой 16-байтовую последовательность. Эта структура предложения помещается в файл предложения. Это, по сути, двоичные данные, а не текст, так как предложение содержит битовые поля определенного значения.
Предложение, представленное в файле, сопоставляется с этой структурой C:
typedef struct
{
struct
{
UINT8 segmentNumber;
UINT8 reserved0 : 6;
UINT8 forceImmediateReset : 1;
UINT8 forceIgnoreVersion : 1;
UINT8 componentId;
UINT8 token;
} componentInfo;
UINT32 version;
UINT32 hwVariantMask;
struct
{
UINT8 protocolRevision : 4;
UINT8 bank : 2;
UINT8 reserved0 : 2;
UINT8 milestone : 3;
UINT8 reserved1 : 5;
UINT16 productId;
} productInfo;
} FWUPDATE_OFFER_COMMAND;
От низкого адреса до высокого адреса первый байт предложения является номером сегмента.
<------- 4 bytes -----------> <-- 8 bytes --> <-------- 4 bytes --------->
+================================-=============================================+
| 15:0 7:3 2:0 7:6 5:4 3:0 31:0 31:0 7:0 7:0 7:7 6:6 5:0 7:0 |
| PI | R1 | MS | R0 | BK | PR | VM | VN | TK | CI | FV | FR | R0 | SN |
+================================-=============================================+
От высокого адреса до низкого адреса:
Byte(s) Value
---------------------------------------------------------
15:14 | (PI) Product ID is 2 bytes
13 | (R1) Reserved1 5-bit register
| (MS) Milestone 3-bit register
12 | (R2) Reserved2 2-bit register
| (BK) Bank 2-bit register
| (PR) Protocol Revision 2-bit register
11:8 | (VM) Hardware Variant Mask 32-bit register
7:4 | (VN) Version 32-bit register
3 | (TK) Token 8-bit register
2 | (CI) Component ID 8-bit register
1 | (FV) Force Ignore Version 1-bit register
| (FR) Force Immediate Reset 1-bit register
| (R0) Reserved0 6-bit register
0 | (SN) Segment Number 8-bit register
---------------------------------------------------------
Сведения о регистрации предложения
Идентификатор продукта. К этому полю можно применить уникальное значение ID продукта для образа CFU.
UINT16 productID;
Веха в развитии встроенного ПО, которое представлено содержимым предложения. Вехи могут быть различными версиями сборки HW, например сборка EV1, сборка EV2 и т. д. Определение вехи и назначение значений остаются для разработчика.
UINT8 milestone : 3;
Если встроенное ПО предназначено для конкретного банка - 2-разрядное поле поддерживает четыре банка. Использование банковского регистра включается в формат предложения, так как существуют экземпляры, в которых целевые устройства используют банковские регионы встроенного ПО.
Если бы это было так, и предложение предназначалось для обновления используемого банка, встроенное ПО, реализующее CFU на целевом устройстве, может отклонить предложение. Кроме того, встроенное ПО в целевом объекте, реализующее CFU, может предпринять другие действия, как это оправдано.
Если использование банков встроенных образов ПО не предусмотрено в разработке встроенного ПО конечного пользователя, то это поле целесообразно игнорировать (установите любые удобные значения, но значение в поле банка является необязательным и зависит от того, как CFU реализуется во встроенном ПО целевого устройства).
UINT8 bank : 2;
Версия протокола CFU представлена 4 битами.
UINT8 protocolRevision : 4;
Битовая маска, соответствующая всему уникальному оборудованию (HW), с которым этот образ встроенного ПО может работать. Например, предложение может означать, что оно может работать на версии X аппаратного обеспечения, но не на версии Y аппаратного обеспечения. Задание определения битов и назначение значений остаётся на усмотрение разработчика.
UINT32 hwVariantMask;
Версия предлагаемого встроенного ПО.
UINT32 version;
Маркер байтов для идентификации пользовательского программного обеспечения, осуществляющего предложение. Это предназначено для различения драйверов и средств, которые могут пытаться обновить одно и то же работающее встроенное ПО. Например, драйвер обновления CFU может получить токен 0xA, а инструмент для разработки обновлений может получить токен 0xB. Теперь запущенное встроенное ПО может выборочно принимать или игнорировать команды на основе того, какой процесс пытается обновить его.
UINT8 token;
Компонент на устройстве для применения обновления встроенного ПО.
UINT8 componentId;
Настройка флагов интерпретации: Если необходимо, чтобы встроенное ПО игнорировало несоответствие версий (когда более старая версия используется вместо более новой), установите бит принудительного игнорирования версии.
UINT8 forceIgnoreVersion: 1;
Принудительный сброс становится активным при установке одного бита. Если этот бит установлен, ведущее программное обеспечение ожидает, что встроенное ПО in situ вызовет сброс устройства. Специфика действий сброса зависит от платформы. Встроенное ПО устройства может принять меры, чтобы переключить банки и сделать недавно обновленное ПО текущим активным ПО. Или нет. Это зависит от реализации встроенного ПО. Обычно ожидается, что если активирована принудительная немедленная перезагрузка, устройство выполнит все необходимые действия, чтобы обновить новый банк и сделать его активным встроенным ПО, которое будет запущено на целевом устройстве.
UINT8 forceImmediateReset : 1;
В случае, если часть содержимого предложения и пары контента включает несколько частей содержимого.
UINT8 segmentNumber;
Обработка предложений
API ProcessCFWUOffer принимает два аргумента:
void ProcessCFWUOffer(FWUPDATE_OFFER_COMMAND* pCommand,
FWUPDATE_OFFER_RESPONSE* pResponse)
В этом случае предположим, что пользовательское программное обеспечение отправляет байты данных в запущенную прошивку, а первое сообщение — это сообщение-предложение.
Сообщение предложения — это 16-байтное сообщение, описанное выше (структура FWUPDATE_OFFER_COMMAND).
Это сообщение о предложении — это данные, используемые запущенным встроенным ПО для обработки предложения.
Во время обработки предложения запущенное встроенное ПО уведомляет отправителя, заполняя поля в структуре FWUPDATE_OFFER_RESPONSE.
Интерпретация предложения
Выполняющееся встроенное ПО должно отслеживать своё состояние в процессе CFU. Это может быть готово к принятию предложения, находиться в процессе транзакции CFU, или ожидать переключения банков между активным и неактивным состоянием прошивки.
Если запущенное встроенное ПО находится в середине транзакции CFU, не принимать или обрабатывать это предложение и уведомьте узел соответствующим образом.
if (s_currentOffer.updateInProgress)
{
memset(pResponse, 0, sizeof (FWUPDATE_OFFER_RESPONSE));
pResponse->status = FIRMWARE_UPDATE_OFFER_BUSY;
pResponse->rejectReasonCode = FIRMWARE_UPDATE_OFFER_BUSY;
pResponse->token = token;
return;
}
Поле идентификатора компонента предложения может использоваться для сигнала работающему встроенному ПО о том, что от него требуется особое действие. В примере кода CFU команда специального предложения используется хостом для получения состояния подсистемы CFU — способно ли и готово ли запущенное программное обеспечение принимать предложения CFU.
else if (componentId == CFU_SPECIAL_OFFER_CMD)
{
FWUPDATE_SPECIAL_OFFER_COMMAND* pSpecialCommand =
(FWUPDATE_SPECIAL_OFFER_COMMAND*)pCommand;
if (pSpecialCommand->componentInfo.commandCode == CFU_SPECIAL_OFFER_GET_STATUS)
{
memset(pResponse, 0, sizeof (FWUPDATE_OFFER_RESPONSE));
pResponse->status = FIRMWARE_UPDATE_OFFER_COMMAND_READY;
pResponse->token = token;
return;
}
}
Наконец, проверяется, ожидается ли обмен банковскими данными. Смена банков относится к тому, как встроенное ПО сохраняет сведения о том, находится ли оно еще в процессе переключения с запущенного активного приложения на как только что скачанный образ.
Где и как выполняется переключение банка — это задача, зависящая от реализации встроенного ПО. Протокол и процесс CFU позволяют обмениваться информацией между удаленным пользовательским приложением, осуществляющим CFU, и встроенным ПО, работающим на месте.
else if (s_bankSwapPending)
{
memset(pResponse, 0, sizeof (FWUPDATE_OFFER_RESPONSE));
pResponse->status = FIRMWARE_UPDATE_OFFER_REJECT;
pResponse->rejectReasonCode = FIRMWARE_UPDATE_OFFER_SWAP_PENDING;
pResponse->token = token;
return;
}
Наконец, если состояние запущенной прошивки не занято, и componentId не является специальной командой, и нет ожидающего переключения банка - ТО мы можем обработать этот запрос.
Обработка предложения включает в себя, но не ограничивается четырьмя этапами, описанными ниже.
Шаг 1. Проверка банка
Проверьте базу данных запущенного приложения на соответствие базе данных в предложении. Они одинаковы или разные?
Если же это же, отклоните предложение (мы не хотим перезаписать запущенный или активный образ).
Иначе продолжить.
Шаг 2. Проверка hwVariantMask
Работающее встроенное ПО проверяет hwVariantMask предложение на HW, на котором он работает. Это позволяет встроенному встроенному ПО отклонять предложение, если предложение недопустимо для целевого объекта. (например, если запущенное встроенное ПО находится в старой сборке HW и новое предлагаемое встроенное ПО предназначено для более новой, сборка HW - то запущенное встроенное ПО должно отклонить это предложение)
Если это недопустимо, отклоните предложение.
Иначе продолжить.
Шаг 3. Проверка версии встроенного ПО
Проверьте, имеет ли предлагаемая версия встроенного ПО более раннюю или более новую версию по сравнению с текущим встроенным ПО приложения.
На усмотрение пользователей и их реализации остается решение, каким образом проверять, какое встроенное ПО превосходит другое, а также следует ли разрешать использование поля 'ForceIgnoreVersion' в предложении. Типичная разработка встроенного ПО позволяет использовать поле ForceIgnoreVersion во время разработки продукта и в отладочных версиях встроенного ПО, но запрещает (не позволяя обновлять старое встроенное ПО на основе нового встроенного ПО) в встроенном ПО продукта или выпуска.
Если эта проверка завершилась ошибкой, отклоните предложение.
Иначе продолжить.
Шаг 4. Принятие предложения
Предложение хорошо. Примите предложение с ответом, адаптированным под способы, которыми встроенное ПО возвращает сообщения и статус удалённому пользовательскому приложению. Так называемый "ответ" — это данные (упакованная структура данных, как показано в демонстрационных файлах заголовков), и эти данные записываются в пользовательское приложение соответствующими средствами для устройства.
Обработка содержимого
Обработка содержимого обычно является многоэтапным процессом. Несколько шагов относятся к возможности встроенного ПО принимать образ встроенного ПО в частях, также известных как "блоки" данных. Не всегда целесообразно отправлять весь образ одновременно во встроенное ПО, поэтому реалистично ожидать реализации протокола CFU и процесса приёма содержимого в небольших фрагментах.
В этом обсуждении используется предположение при описании процесса содержимого CFU.
Компьютер состояния обработки содержимого включает в себя три состояния.
Состояние обработки первого блока.
Состояние обработки последнего блока.
Состояние обработки любого блока между первым и последним.
Структура команды управления содержимым
Как и предложение, контент имеет структуру с полями, используемыми алгоритмами CFU в демонстрации.
typedef struct
{
UINT8 flags;
UINT8 length;
UINT16 sequenceNumber;
UINT32 address;
UINT8 pData[MAX_UINT8];
} FWUPDATE_CONTENT_COMMAND;
Структура команды содержимого проще структуры предложения. Содержимое определяется как последовательность байтов для записи в память. Предварительная часть содержимого — это поля этой структуры:
UINT8 flagsУказывает, является ли содержимое "блоком" первым, последним или другим.UINT8 lengthПомечает длинуpDataполя. В демонстрационном коде для CFU ограничениеpDataразмера составляет 255 байт. Другие реализации могут варьировать максимальный размер блока.UINT16 sequenceNumberПомечает счетчик индекса, из которого блок отправляется в виде содержимого.UINT32 addressСмещение адреса блока. В демонстрации CFU этого выпуска в реализации заложена предопределённая информация о физическом адресе каждого региона приложения. Например, реализация встроенного ПО с двумя банковыми областями может предусматривать, что App1 начинается с адреса0x9000, а App2 начинается с адреса0xA0000. Таким образом, в зависимости от способа подготовки образа прошивки в формате S-Records, адрес в SREC может быть либо физическим адресом, либо смещением. В любом случае необходимо иметь общее представление о подготовке содержимого и конкретных подпрограммах реализации обработки содержимого CFU, чтобы определить истинный физический адрес места записи блока в памяти. Разработчику встроенного ПО необходимо внедрять передовые практики и выполнять проверки допустимых диапазонов адресов для каждого блока содержимого. Например, код CFU демонстрирует проверку, выполненную, если, возможно, App1 (предназначено для0x9000) имеет адреса, которые перекрываются в App2 и т. д.UINT8 pData[MAX_UINT8]— Это необработанные байты блока образа встроенного ПО. Особое внимание уделяется в пользовательском приложении, чтобы помещать только байтыlengthв целостный поток байтов блока содержимого.
Битовые поля, используемые в структуре содержимого, отсутствуют в демонстрации CFU из предоставленного кода.
Первый блок
Первый блок запускает скачивание содержимого встроенного ПО. Встроенное ПО, запущенное, пытается записать блок в ненезависимую память. Конечно, содержимое "блок" содержит сведения о том, где в памяти должен быть записан блок, сколько данных для записи и других полей.
Каждое целевое устройство componentID отличается и существует несколько методов для сохранения данных в памяти. Например, одному компоненту может потребоваться запись во внутреннюю flash-память, другой компонент может записывать во внешний SPI флэш или другой может использовать протокол I2C другого IC для обновления своего образа. Демонстрация, включенная в этот документ, подчеркивает использование функции под названием ICompFwUpdateBspWrite, которую каждое уникальное встроенное ПО должно реализовать, обладая знанием об основных функциях ввода-вывода энергонезависимой памяти целевого объекта, для которого оно было разработано.
Любой другой блок, кроме первого или последнего
Процесс принятия новых блоков продолжается, когда клиентское приложение доставляет другой блок, опять же с метаданными в сообщении для адреса, куда следует записать блок, сколько байтов содержится в блоке, а также другую необходимую информацию.
Встроенное ПО на месте будет обрабатывать это так же, как сценарий первого блока.
Однако следует отметить, что в любое время, когда система теряет способность захватывать и сохранять блок в памяти, это ответственность встроенного ПО для ответить кодом ошибки.
Последний блок
Последний блок представляет проблему только в том случае, если прошивка на месте должна выполнять задачи для проверки образа, который был только что записан в память.
Во-первых, последний блок записывается в память.
Затем, по крайней мере, необходимо выполнить проверку CRC между данными, уже записанными в память (от первых до последних блоков) по сравнению с полем CRC в последнем блоке. Оставлено на усмотрение каждой реализации встроенного ПО, как получить CRC для загруженного образа.
Помните, что выполнение проверки CRC занимает время. В отличие от обычного потока выполнения CFU для отправки предложения и блока. Последняя отправка блока, если она включает проверку CRC, будет иметь определенную задержку вследствие того, что проверка CRC потенциально проверяет большой участок памяти. В зависимости от целевого устройства и других факторов это может не быть проблемой.
Это важно
Проверка CRC для входящего изображения является необязательной и может быть закомментирована. Тем не менее, нужно внедрить лучшие практики, чтобы как минимум реализовать эту проверку. Настоятельно рекомендуется на этом этапе процесса CFU предпринять другие действия, чтобы обеспечить целостность скаченного образа. Некоторые из этих действий могут включать проверку "подписанной" части образа и /или проверки цепочек сертификатов доверия или других подходов к обеспечению безопасного образа встроенного ПО. Эти вопросы оставляются на усмотрение разработчика встроенного ПО.
Очистка после последнего блока
Теперь, когда последний блок записан и проверка CRC завершена, прошивка может вернуться с сообщением об ошибке, если любая часть проверки корректности завершилась неудачей.
В противном случае ожидается, что процесс CFU во встроенном ПО ответит успешным статусом.
Принудительная перезагрузка проверена
Флаг принудительного сброса в предложении используется для определения того, должен ли MCU целевого объекта пройти сброс (определяемый пользователем сброс).
Как правило, при принудительном сбросе намерение заключается в том, чтобы вызвать сброс MCU и принудить переключение банка приложений. Обновление постоянных переменных для обозначения того, какой образ прошивки будет загружен при перезагрузке, остается на усмотрение разработчика прошивки.