CFU(구성 요소 펌웨어 업데이트) 펌웨어 구현 가이드
CFU(구성 요소 펌웨어 업데이트)는 대상 디바이스에 설치할 새 펌웨어 이미지를 제출하는 프로토콜 및 프로세스입니다.
참고
CFU는 Windows 10 버전 2004(Windows 10 2020년 5월 업데이트) 이상 버전에서 사용할 수 있습니다.
상주 펌웨어에 대한 CFU 제출은 파일 쌍이고, 한 파일은 제품 파트이고, 다른 파일은 콘텐츠 부분입니다. 제출이 CFU 프로세스를 구현하는 펌웨어로 전송되기 전에 각 CFU 제출(각 제품 및 콘텐츠 쌍)을 오프라인으로 만들어야 합니다.
GitHub의 CFU 리포지토리에 있는 샘플 펌웨어 소스 코드에서 CFU에 대한 일반적인 구현에 구애받지 않은 일반 코드는 에 ComponentFwUpdate.c
포함되어 있습니다. 다른 모든 파일은 개발자의 고유한 구현으로 업데이트하거나 수정할 수 있는 도우미 파일입니다.
콘텐츠
제품 및 콘텐츠 파트
제품 및 콘텐츠는 CFU 스키마의 파일 쌍을 구성합니다.
제품 부분은 아래에 설명된 FWUPDATE_OFFER_COMMAND 구조에 매핑되는 16바이트 길이의 파일일 뿐입니다.
업데이트할 실제 펌웨어의 콘텐츠 부분은 최종 사용자 개발자가 지정한 형식입니다. 제공된 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 이미지의 고유한 제품 ID 값을 이 필드에 적용할 수 있습니다.
UINT16 productID;
제품의 콘텐츠가 나타내는 펌웨어의 마일스톤입니다. 중요 시점은 HW 빌드의 다른 버전(예: EV1 빌드, EV2 빌드 등)일 수 있습니다. 중요 시점 정의 및 값 할당은 개발자에게 맡기게 됩니다.
UINT8 milestone : 3;
펌웨어가 특정 은행을 대상으로 하는 경우 2비트 필드는 4개의 은행을 지원합니다. 대상 디바이스가 뱅크 펌웨어 지역을 사용하는 인스턴스가 있기 때문에 은행 레지스터의 사용은 제품 형식에 포함됩니다.
이 경우 제품이 사용 중인 은행을 업데이트하기 위한 것이라면 대상에서 CFU를 구현하는 펌웨어가 제안을 거부할 수 있습니다. 그렇지 않으면 CFU를 구현하는 대상의 펌웨어가 보증된 대로 다른 작업을 수행할 수 있습니다.
펌웨어 이미지의 뱅킹이 최종 사용자 펌웨어의 디자인에 없는 경우 이 필드를 무시하는 것이 합리적입니다(편리한 값으로 설정하지만 은행 필드의 값은 선택 사항이며 대상 펌웨어에서 CFU를 구현하는 방법에 따라 다름).
UINT8 bank : 2;
사용되는 CFU 프로토콜의 프로토콜 버전은 4비트입니다.
UINT8 protocolRevision : 4;
이 펌웨어 이미지가 작동할 수 있는 모든 고유 HW에 해당하는 비트 마스크입니다. 예를 들어 제품은 HW의 verX에서 실행할 수 있지만 HW의 verY에서는 실행할 수 없음을 나타낼 수 있습니다. 비트 정의 및 값 할당은 개발자에게 맡기게 됩니다.
UINT32 hwVariantMask;
제공되는 펌웨어의 버전입니다.
UINT32 version;
제품을 만드는 사용자별 소프트웨어를 식별하는 바이트 토큰입니다. 이는 동일한 실행 중인 펌웨어를 업데이트하려고 할 수 있는 드라이버와 도구를 구분하기 위한 것입니다. 예를 들어 CFU 업데이트 드라이버에 토큰 0xA 할당될 수 있으며 개발 업데이트 도구가 0xB 할당될 수 있습니다. 이제 실행 중인 펌웨어는 업데이트를 시도하는 프로세스에 따라 명령을 수락하거나 무시하도록 선택적으로 선택할 수 있습니다.
UINT8 token;
펌웨어 업데이트를 적용할 디바이스의 구성 요소입니다.
UINT8 componentId;
제품 해석 플래그: 현장의 펌웨어에서 버전 불일치(이전 버전)를 무시하려면 비트를 설정하여 버전 무시를 강제합니다.
UINT8 forceIgnoreVersion: 1;
즉시 다시 설정 강제 적용은 한 비트로 어설션됩니다. 해당 비트가 어설션된 경우 호스트 소프트웨어는 in situ 펌웨어로 인해 디바이스가 다시 설정될 것으로 예상합니다. 다시 설정의 작업은 플랫폼에 따라 다릅니다. 디바이스의 펌웨어는 은행을 교체하여 새로 업데이트된 펌웨어를 현장 펌웨어에서 활성화하는 조치를 취할 수 있습니다. 아니면 그렇지 않습니다. 펌웨어 구현에 따라 다릅니다. 일반적으로 강제 즉시 재설정이 어설션되면 디바이스가 펌웨어가 새 뱅크를 업데이트하도록 하는 데 필요한 모든 작업을 수행하여 대상 디바이스에서 실행되는 활성 펌웨어가 될 것이라는 기대가 있습니다.
UINT8 forceImmediateReset : 1;
제품 및 콘텐츠 쌍의 콘텐츠 부분에 콘텐츠의 여러 부분이 포함되는 경우
UINT8 segmentNumber;
제안 처리
ProcessCFWUOffer API는 다음 두 인수를 허용합니다.
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;
}
제품의 구성 요소 ID 필드를 사용하여 실행 중인 펌웨어에서 특별한 작업이 요청되었음을 실행 중인 펌웨어에 알릴 수 있습니다. 예제 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가 특별한 명령이 아니며 보류 중인 은행 스왑이 없는 경우 이 제품을 처리할 수 있습니다.
제품 처리에는 아래에 설명된 4단계가 포함되지만 이에 국한되지는 않습니다.
1단계 - 은행 확인
제품에서 실행 중인 애플리케이션의 은행을 은행에 확인합니다. 그들은 동일하거나 다른가요?
동일한 경우 제안을 거부합니다(실행 중/활성 이미지를 덮어쓰지 않음).
그렇지 않으면 계속됩니다.
2단계 - hwVariantMask 확인
실행 중인 펌웨어는 실행 중인 HW에 대해 제품의 를 확인 hwVariantMask
합니다. 이렇게 하면 대상에 대한 제품이 유효하지 않은 경우 포함된 펌웨어가 제안을 거부할 수 있습니다. (예: 실행 중인 펌웨어가 이전 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
콘텐츠 "block"이 첫 번째, 마지막 또는 기타인지를 표시합니다.UINT8 length
필드의 길이를 표시합니다pData
. CFU에 대한 데모 코드에서 의pData
크기에 대한 제한은 255바이트입니다. 다른 구현은 "블록"의 최대 크기를 변경할 수 있습니다.UINT16 sequenceNumber
블록이 콘텐츠로 제출되는 인덱스 카운터를 표시합니다.UINT32 address
블록의 주소 오프셋입니다. 이 릴리스의 CFU 데모에서 구현에는 각 앱 지역의 실제 주소에 대한 미리 정의된 정보가 있습니다. 예를 들어 두 개의 은행 펌웨어 구현은 App1이 주소에서 시작되고 App2는 주소0x9000
0xA0000
에서 시작될 수 있습니다. 따라서 펌웨어 이미지가 준비된 방법에 따라(S-레코드) SREC의 주소는 물리적 주소 또는 오프셋일 수 있습니다. 어쨌든 메모리에 블록을 쓸 위치의 실제 실제 주소를 결정하기 위해 콘텐츠 준비와 CFU 콘텐츠 처리의 구현 특정 루틴 간에 공유된 이해가 있어야 합니다. 펌웨어 개발자는 모범 사례를 채택하고 각 콘텐츠 블로그에 유효한 주소 범위를 확인해야 합니다. 예를 들어 CFU 코드는 App1(용0x9000
)에 App2와 겹치는 주소가 있는 경우 만들어진 검사 보여 줍니다.UINT8 pData[MAX_UINT8]
- 펌웨어 이미지 블록의 원시 바이트입니다. 사용자 애플리케이션에서 콘텐츠 블록의 전체 바이트 스트림에 바이트만 넣length
도록 주의합니다.
제공된 코드의 CFU 데모에 따라 콘텐츠 구조에 사용되는 비트 필드가 없습니다.
첫 번째 블록
첫 번째 블록은 펌웨어 콘텐츠의 다운로드를 시작합니다. 실행 중인 펌웨어는 비휘발성 메모리에 블록을 쓰려고 시도합니다. 물론 콘텐츠 "블록"에는 메모리에서 블록을 작성해야 하는 위치, 작성할 데이터 양 및 기타 필드에 대한 정보가 포함되어 있습니다.
각 componentID 대상 디바이스는 서로 다르며 데이터를 메모리에 유지하는 여러 가지 방법이 있습니다. 예를 들어 한 componentId는 내부 플래시에 쓰기가 필요할 수 있으며, 다른 componentId는 외부 SPI 플래시에 쓰거나 다른 componentId는 다른 IC의 I2C 프로토콜을 활용하여 이미지를 업데이트할 수 있습니다. 이 문서에 포함된 데모에서는 각 고유 펌웨어가 설계한 대상의 기본 비휘발성 메모리 I/O 함수에 대한 지식으로 구현해야 하는 라는 ICompFwUpdateBspWrite
함수의 사용을 강조 표시합니다.
첫 번째 또는 마지막을 제외한 다른 모든 블록
새 블록을 수락하는 프로세스는 사용자 애플리케이션이 다른 블록을 배달할 때 계속되며, 메시지의 메타 데이터와 함께 블록을 작성해야 하는 주소, 포함된 바이트 수 및 기타 필드가 있습니다.
in situ 펌웨어는 이를 첫 번째 블록 시나리오처럼 처리합니다.
그러나 시스템이 블록을 캡처하고 메모리에 유지하지 못할 때마다 오류 코드로 응답하는 것은 현장 펌웨어의 여야 합니다.
마지막 블록
마지막 블록은 현장 펌웨어의 가 메모리에 방금 기록된 이미지의 유효성을 검사하기 위해 작업을 수행해야 하는 경우에만 문제를 표시합니다.
먼저 마지막 블록이 메모리에 기록됩니다.
그런 다음 최소한 마지막 블록의 CRC 필드와 비교하여 메모리에 이미 기록된 데이터(첫 번째 블록에서 마지막 블록까지) 간에 CRC 검사 만들어야 합니다. 다운로드한 이미지에 대한 CRC를 획득하는 방법을 알아보려면 각 구현 펌웨어에 남아 있습니다.
CRC 검사 실행하는 데 시간이 걸립니다. 제품 및 블록 제출에 대한 CFU 실행의 일반적인 흐름과는 다릅니다. 마지막 블록 제출에 CRC 검사 포함된 경우 CRC 검사 잠재적으로 큰 메모리 영역을 검사하고 있다는 사실만으로 특정 지연이 발생합니다. 대상 디바이스 및 기타 요인에 따라 문제가 되지 않을 수 있습니다.
중요
들어오는 이미지의 CRC 검사 선택 사항이며 주석 처리될 수 있습니다. 그러나 적어도 이 검사 채택하려면 모범 사례를 마련해야 합니다. CFU 프로세스의 이 시점에서 다운로드한 이미지의 무결성을 보장하기 위해 다른 작업을 수행하는 것이 좋습니다. 이러한 작업 중 일부에는 이미지의 '서명된' 부분 확인 및/또는 보안 펌웨어 이미지를 보장하기 위한 신뢰할 수 있는 인증서 체인 또는 기타 모범 사례 방법 검사 포함될 수 있습니다. 이는 펌웨어 개발자에게 달려 있습니다.
마지막 블록 후 정리
마지막 블록이 작성되고 CRC 검사 완료되었으므로 유효성 검사의 일부가 실패하면 펌웨어가 실패로 응답할 수 있습니다.
그렇지 않으면 펌웨어의 CFU 프로세스가 성공적인 상태 응답할 것으로 예상합니다.
강제 재설정 확인됨
제품의 강제 재설정 플래그는 대상의 MCU가 재설정(사용자 정의 재설정)을 받아야 하는지 여부를 결정하는 데 사용됩니다.
일반적으로 재설정이 강제로 수행되면 앱 뱅크가 전환되도록 MCU가 재설정을 수행하도록 하는 것이 목적입니다. 초기화 시 부팅할 펌웨어 이미지를 나타내도록 영구 변수를 업데이트하는 것은 펌웨어 개발자에게 남습니다.