rel_1.6.0 init

This commit is contained in:
guocheng.kgc 2020-06-18 20:06:52 +08:00 committed by shengdong.dsd
commit 27b3e2883d
19359 changed files with 8093121 additions and 0 deletions

201
Living_SDK/framework/uOTA/LICENSE Executable file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1,65 @@
## Contents
```sh
OTA
├── hal
├── ota_service.c
├── src
│   ├── 2nd_boot
│   ├── device
│   ├── download
│   ├── transport
│   └── verify
└── aos.mk
```
## Introduction
An over-the-air update is the wireless delivery of new software or data to smart devices, especially IoT devices. Wireless carriers and OEMs typically use over-the-air (OTA) updates to deploy the new operating systems and the software app to these devices.
## Features
1. Differential incremental upgrade;
2. Dual banker:AB partition upgrade to support rollback to old version;
3. Secure download channel;
4. Firmware digital signature verification.
5. footprint: ROM-->12K~18K RAM: 3K~8K
## Dependencies
Linkkit MQTT channel
Linkkit CoAP channel
## API
User service APIs:
```c
/*OTA export service APIs*/
int ota_service_init(ota_service_t* ctx);
int ota_service_deinit(ota_service_t* ctx);
```
for sample code please check [otaapp](../../../app/example/otaapp/).
## RTOS build
```sh
cd ROOT DIR;
aos make otaapp@board;
```
## run CLI CMDs
1. connect network
```
netmgr connect ssid passwd
```
2. run ota demo
```
OTA_APP pk dn ds ps
```
## Reference
* [AliOS-Things OTA使用说明](https://github.com/alibaba/AliOS-Things/wiki/OTA-Tutorial)
* [OTA flash分区说明文档](https://github.com/alibaba/AliOS-Things/wiki/OTA-Flash-Partitions-Overview)
* [云端一体化差分+安全升级AliOS Things物联网升级“利器”](https://mp.weixin.qq.com/s/Pb8Lleuww1r7qQJHu5ON8g)

View file

@ -0,0 +1,80 @@
## Contents
```sh
hal
├── aos.mk
├── Config.in
├── ota_hal_host.c
├── ota_hal_module.c
├── ota_hal_os.c
├── ota_hal_os.h
├── ota_hal_plat.c
├── ota_hal_plat.h
└── README.md
```
## Introduction
An over-the-air update is the wireless delivery of new software or data to smart devices, especially IoT devices. Wireless carriers and OEMs typically use over-the-air (OTA) updates to deploy the new operating systems and the software app to these devices.
## Features
1. Differential incremental upgrade;
2. Dual banker:AB partition upgrade to support rollback to old version;
3. Secure download channel;
4. Firmware digital signature verification.
## Dependencies
Linkkit MQTT channel
Linkkit CoAP channel
## API
User service APIs:
```c
typedef struct {
unsigned char inited; /*If is inted*/
char pk[20+1];/*Product Key*/
char ps[64+1];/*Product secret*/
char dn[32+1];/*Device name*/
char ds[64+1];/*Device secret*/
OTA_PROTCOL_E trans_protcol; /*default:0--> MQTT 1-->COAP*/
OTA_PROTCOL_E dl_protcol; /*default:3--> HTTPS 1-->COAP 2-->HTTP*/
unsigned char sign_type; /*default:0--> sha256 1--> md5 2-->RSA*/
char ota_ver[OTA_MAX_VER_LEN]; /*OTA FW version*/
char sys_ver[OTA_MAX_VER_LEN]; /*OTA System version*/
ota_transport_t *h_tr; /*OTA tansport manager*/
ota_download_t *h_dl; /*OTA download manager*/
void* h_ch; /*OTA channel handle:mqtt,coap*/
} ota_service_t;
/*OTA export service APIs*/
int ota_service_init(ota_service_t* ctx);
int ota_service_deinit(ota_service_t* ctx);
```
for sample code please check [otaapp](../../../app/example/otaapp/).
## RTOS build
```sh
cd ROOT DIR;
aos make otaapp@board;
```
## run CLI CMDs
1. connect network
```
netmgr connect ssid passwd
```
2. run ota demo
```
OTA_APP pk dn ds ps
```
## Reference
* [AliOS-Things OTA使用说明](https://github.com/alibaba/AliOS-Things/wiki/OTA-Tutorial)
* [OTA flash分区说明文档](https://github.com/alibaba/AliOS-Things/wiki/OTA-Flash-Partitions-Overview)
* [云端一体化差分+安全升级AliOS Things物联网升级“利器”](https://mp.weixin.qq.com/s/Pb8Lleuww1r7qQJHu5ON8g)

View file

@ -0,0 +1,71 @@
NAME := ota_hal
$(NAME)_MBINS_TYPE := kernel
$(NAME)_VERSION := 1.0.0
$(NAME)_SUMMARY := ota porting HAL APIs
#default gcc
ifeq ($(COMPILER),)
$(NAME)_CFLAGS += -Wall -Werror
else ifeq ($(COMPILER),gcc)
$(NAME)_CFLAGS += -Wall -Werror
endif
$(NAME)_COMPONENTS += base64
$(NAME)_SOURCES := \
ota_hal_module.c \
ota_hal_os.c \
ifeq ($(CONFIG_SUPPORT_MCU_OTA), ENABLE)
$(NAME)_SOURCES += ota_hal_mcu.c
endif
ifneq (,$(filter linux,$(HOST_MCU_FAMILY)))
$(NAME)_SOURCES += ota_hal_host.c
else
ifneq (,$(filter esp32,$(HOST_MCU_FAMILY)))
GLOBAL_DEFINES += AOS_OTA_BANK_DUAL
GLOBAL_DEFINES += AOS_OTA_DISABLE_MD5
$(NAME)_SOURCES += ota_hal_$(HOST_MCU_FAMILY).c
else
ifneq (,$(filter bk7231u,$(HOST_MCU_FAMILY)))
$(NAME)_SOURCES += ota_hal_beken.c
else
ifneq (,$(filter bk7231s,$(HOST_MCU_FAMILY)))
$(NAME)_SOURCES += ota_hal_beken.c
else
ifneq (,$(filter rtl8710bn,$(HOST_MCU_FAMILY)))
else
ifneq (,$(filter asr5501,$(HOST_MCU_FAMILY)))
GLOBAL_DEFINES += AOS_OTA_DISABLE_MD5
GLOBAL_DEFINES += OTA_BOOT_PAPA_COMPATIBAL
else
$(NAME)_SOURCES += ota_hal_plat.c
endif
endif
endif
endif
endif
endif
ifneq (,$(filter rtl8710bn esp8266,$(HOST_MCU_FAMILY)))
GLOBAL_DEFINES += AOS_OTA_BANK_DUAL
GLOBAL_DEFINES += AOS_OTA_DISABLE_MD5
endif
ifeq ($(FEATURE_SUPPORT_ITLS),y)
GLOBAL_DEFINES += AOS_OTA_ITLS
$(NAME)_COMPONENTS += itls
else
$(NAME)_COMPONENTS += imbedtls
endif
ifeq ($(MD5_CHECK),0)
GLOBAL_DEFINES += AOS_OTA_DISABLE_MD5
endif
GLOBAL_INCLUDES += . \
../inc \
../src/verify/crc \
../src/2nd_boot

View file

@ -0,0 +1,541 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "aos/kernel.h"
#include "aos/kv.h"
#include "hal/soc/flash.h"
#include "ota_hal_plat.h"
#include "ota_hal_os.h"
#include "ota_log.h"
#define KV_HAL_OTA_CRC16 "hal_ota_get_crc16"
#define OTA_UPG_FLAG 0xA55A
#define OTA_PINGPONG_FLAG 0xB55B
typedef struct
{
uint32_t ota_len;
uint32_t ota_crc;
} ota_reboot_info_t;
typedef struct
{
uint32_t dst_adr;
uint32_t src_adr;
uint32_t size;
uint16_t crc;
uint16_t upg_flag;
} __attribute__((packed)) ota_hdl_t;
static ota_reboot_info_t ota_info = {0};
static ota_crc16_ctx contex = {0};
static uint32_t _off_set = 0;
static uint16_t hal_ota_get_crc16(void);
static void hal_ota_save_crc16(uint16_t crc16);
#ifdef AOS_OTA_BANK_DUAL
#define OTA_IMAGE_A 0
#define OTA_IMAGE_B 1
#define KV_HAL_OTA_HDR "hal_ota_get_hdr"
typedef struct
{
uint32_t version;
uint32_t hdr_num;
struct
{
uint32_t img_ID;
uint32_t hdr_len;
uint32_t checksum;
uint32_t img_len;
uint32_t img_offset;
uint32_t flash_offset;
}ota_file[2];
}ota_hdr_t;
static ota_hdr_t ota_hdr_info = {0};
static uint8_t ota_index = 0;
static uint8_t ota_hdr_check = 0;
static int hal_get_ota_hdr(void)
{
int len, ret;
len = sizeof(ota_hdr_t);
ret = aos_kv_get(KV_HAL_OTA_HDR, &ota_hdr_info, &len);
return ret;
}
static int hal_ota_save_hdr(void)
{
int len, ret;
len = sizeof(ota_hdr_t);
ret = aos_kv_set(KV_HAL_OTA_HDR, &ota_hdr_info, len, 1);
return ret;
}
static void hal_get_ota_index(void)
{
uint32_t offset, boot_addr;
hal_logic_partition_t *partition_info;
offset = 0x00;
hal_flash_read(HAL_PARTITION_PARAMETER_1, &offset, (void *)&boot_addr, sizeof(boot_addr));
partition_info = hal_flash_get_info(HAL_PARTITION_OTA_TEMP);
if(boot_addr == partition_info->partition_start_addr) {
ota_index = OTA_IMAGE_A; //update to image A
}
else {
ota_index = OTA_IMAGE_B; //update to image B
}
return;
}
static int hal_verify_ota_head(void)
{
char imgid[5];
if(~ota_hdr_info.version) {
OTA_LOG_E("check ota version error %x", ota_hdr_info.version);
return 1;
}
if(ota_hdr_info.hdr_num != 2) {
OTA_LOG_E("check ota number error %d", ota_hdr_info.hdr_num);
return 1;
}
memset(imgid, 0, sizeof(imgid));
memcpy(imgid, (char *)&ota_hdr_info.ota_file[0].img_ID, 4);
if(strcmp(imgid, "OTA1")) {
OTA_LOG_E("OTA1 image id error.");
return 1;
}
memcpy(imgid, (char *)&ota_hdr_info.ota_file[1].img_ID, 4);
if(strcmp(imgid, "OTA2")) {
OTA_LOG_E("OTA2 image id error.");
return 1;
}
if(ota_hdr_info.ota_file[0].checksum == 0) {
OTA_LOG_E("OTA1 checksum is zaro.");
return 1;
}
if(ota_hdr_info.ota_file[1].checksum == 0) {
OTA_LOG_E("OTA2 checksum is zaro.");
return 1;
}
return 0;
}
static int hal_verify_ota_checksum(uint8_t crc_partition_idx, uint32_t crc_len)
{
uint8_t *f_data;
ota_crc16_ctx ctx;
uint16_t ota_crc;
uint32_t i = 0, j = 0, len = 0, checksum = 0;
ota_crc16_final(&contex, &ota_info.ota_crc);//download crc
if(ota_info.ota_crc == 0) {
OTA_LOG_E("crc is zaro.");
return -1;
}
f_data = (uint8_t *)aos_malloc(0x1000);
if(f_data == NULL) {
OTA_LOG_E("hal_ota_crc16_compute malloc fail.");
return -1;
}
_off_set = 0;
ota_crc16_init(&ctx);
while(i < crc_len) {
if((0x1000 + i) < crc_len) {
len = 0x1000;
}
else {
len = crc_len - i;
}
hal_flash_read(crc_partition_idx, &_off_set, f_data, len);
/*update checksum*/
for(j = 0; j < len; j++) {
checksum += f_data[j];
}
/*update crc16*/
ota_crc16_update(&ctx, f_data, len);
i += len;
}
ota_crc16_final(&ctx, &ota_crc);
if(f_data) {
aos_free(f_data);
}
/*verify crc*/
if(ota_info.ota_crc != ota_crc) {
OTA_LOG_E("crc check error: download_crc=0x%x, comput_crc=0x%x.", ota_info.ota_crc, ota_crc);
return -1;
}
/*verify checksum*/
if(ota_hdr_info.ota_file[ota_index].checksum != checksum) {
OTA_LOG_E("checksum error: gen_chcksum=0x%x, comput_checksum=0x%x.",
ota_hdr_info.ota_file[ota_index].checksum, checksum);
return -1;
}
return 0;
}
static int ota_init(void *something)
{
ota_boot_param_t *param = (ota_boot_param_t *)something;
uint32_t offset = 0, delta = 0;
hal_logic_partition_t *partition_info;
if(param == NULL) {
return;
}
offset = param->off_bp;
hal_flash_dis_secure(0, 0, 0);//disable flash protect
hal_get_ota_index();
if(offset == 0) {
OTA_LOG_I("ota start :%d off:%d", ota_index, offset);
if(ota_index == OTA_IMAGE_A) {
partition_info = hal_flash_get_info(HAL_PARTITION_APPLICATION);
hal_flash_erase(HAL_PARTITION_APPLICATION, 0, partition_info->partition_length);
}
else {
partition_info = hal_flash_get_info(HAL_PARTITION_OTA_TEMP);
hal_flash_erase(HAL_PARTITION_OTA_TEMP, 0, partition_info->partition_length);
}
_off_set = 0;
ota_hdr_check = 0;
memset(&ota_info, 0, sizeof(ota_info));
memset(&ota_hdr_info, 0, sizeof(ota_hdr_info));
ota_crc16_init(&contex);
}
else {
OTA_LOG_I("header:%d off:%d", ota_hdr_check, offset);
ota_info.ota_len = offset;
ota_info.ota_crc = 0;
if(hal_get_ota_hdr()) {
OTA_LOG_E("get ota header fail");
return -1;
}
if(offset < sizeof(ota_hdr_t)) {
ota_hdr_check = 0;
}
else {
OTA_LOG_I("verfiy header");
ota_hdr_check = hal_verify_ota_head();
if(ota_hdr_check == 0) {
if(offset < ota_hdr_info.ota_file[1].img_offset) {
delta = offset - sizeof(ota_hdr_t);
if(ota_index == OTA_IMAGE_A) {
_off_set = delta;
}
}
else {
delta = offset - ota_hdr_info.ota_file[1].img_offset;
if(ota_index == OTA_IMAGE_B) {
_off_set = delta;
}
}
}
else {
OTA_LOG_E("check ota header error.");
return -1;
}
}
contex.crc = hal_ota_get_crc16();
}
OTA_LOG_I("ota init over");
return 0;
}
static int ota_read(int* off, char* out_buf, int out_buf_len)
{
if(ota_index == OTA_IMAGE_A) {
hal_flash_read(HAL_PARTITION_APPLICATION, off, out_buf, out_buf_len);
}
else {
hal_flash_read(HAL_PARTITION_OTA_TEMP, off, out_buf, out_buf_len);
}
return 0;
}
static int ota_write(int* off, char* in_buf, int in_buf_len)
{
uint32_t offset = 0;
if(ota_hdr_check) {
OTA_LOG_E("check ota header fail.");
return -1;
}
else {
/*OTA_LOG_I(".");*/
}
if(ota_info.ota_len < sizeof(ota_hdr_t)) {
OTA_LOG_I("ota header w check:%d", ota_hdr_check);
offset = sizeof(ota_hdr_t) - ota_info.ota_len;
if(in_buf_len < offset) {
memcpy((uint8_t *)&ota_hdr_info + ota_info.ota_len, in_buf, in_buf_len);
}
else {
memcpy((uint8_t *)&ota_hdr_info + ota_info.ota_len, in_buf, offset);
ota_hdr_check = hal_verify_ota_head();
if(ota_hdr_check == 0 && ota_index == OTA_IMAGE_A) {
ota_crc16_update(&contex, in_buf + offset, in_buf_len - offset);
hal_flash_write(HAL_PARTITION_APPLICATION, &_off_set, in_buf + offset, in_buf_len - offset);
}
}
}
else {
if(ota_index == OTA_IMAGE_A) {
if(ota_info.ota_len + in_buf_len < ota_hdr_info.ota_file[1].img_offset) {
ota_crc16_update(&contex, in_buf, in_buf_len);
hal_flash_write(HAL_PARTITION_APPLICATION, &_off_set, in_buf, in_buf_len);
}
else {
if(ota_info.ota_len < ota_hdr_info.ota_file[1].img_offset) {
offset = ota_hdr_info.ota_file[1].img_offset - ota_info.ota_len;
ota_crc16_update(&contex, in_buf, offset);
hal_flash_write(HAL_PARTITION_APPLICATION, &_off_set, in_buf, offset);
}
}
}
else {
if(ota_info.ota_len > ota_hdr_info.ota_file[1].img_offset) {
ota_crc16_update(&contex, in_buf, in_buf_len);
hal_flash_write(HAL_PARTITION_OTA_TEMP, &_off_set, in_buf, in_buf_len);
}
else {
if(ota_info.ota_len + in_buf_len > ota_hdr_info.ota_file[1].img_offset) {
offset = ota_hdr_info.ota_file[1].img_offset - ota_info.ota_len;
ota_crc16_update(&contex, in_buf + offset, in_buf_len - offset);
hal_flash_write(HAL_PARTITION_OTA_TEMP, &_off_set, in_buf + offset, in_buf_len - offset);
}
}
}
}
ota_info.ota_len += in_buf_len;
return 0;
}
static int ota_boot(void *something)
{
int ret = 0;
uint32_t offset;
uint32_t crc_partition_idx, crc_len;
hal_logic_partition_t *partition_info;
ota_boot_param_t *param;
ota_hdl_t ota_hdl, ota_hdl_rb;
param = (ota_boot_param_t *)something;
if (param == NULL) {
OTA_LOG_E("finish type is null.");
return -1;
}
if(ota_hdr_check) {
OTA_LOG_E("check ota head fail.");
return -1;
}
if(param->res_type == OTA_FINISH) {
if(ota_index == OTA_IMAGE_A) {
crc_partition_idx = HAL_PARTITION_APPLICATION;
crc_len = ota_hdr_info.ota_file[0].img_len;
partition_info = hal_flash_get_info(HAL_PARTITION_APPLICATION);
}
else {
crc_partition_idx = HAL_PARTITION_OTA_TEMP;
crc_len = ota_hdr_info.ota_file[1].img_len;
partition_info = hal_flash_get_info(HAL_PARTITION_OTA_TEMP);
}
ret = hal_verify_ota_checksum(crc_partition_idx, crc_len);
if(ret) {
return -1;
}
offset = 0x00;
hal_flash_erase(HAL_PARTITION_PARAMETER_1, offset, sizeof(ota_hdl));
offset = 0x00;
memset(&ota_hdl, 0, sizeof(ota_hdl_t));
ota_hdl.dst_adr = partition_info->partition_start_addr;
ota_hdl.upg_flag = OTA_PINGPONG_FLAG;
hal_flash_write(HAL_PARTITION_PARAMETER_1, &offset, (const void *)&ota_hdl, sizeof(ota_hdl));
offset = 0x00;
memset(&ota_hdl_rb, 0, sizeof(ota_hdl_t));
hal_flash_read(HAL_PARTITION_PARAMETER_1, &offset, &ota_hdl_rb, sizeof(ota_hdl_rb));
if(memcmp(&ota_hdl, &ota_hdl_rb, sizeof(ota_hdl_t)) != 0) {
OTA_LOG_I("write boot address fail.\r\n");
return -1;
}
}
else {
ret = hal_ota_save_hdr();
if(ret) {
OTA_LOG_E("save ota header fail.");
return -1;
}
hal_ota_save_crc16(contex.crc);
}
hal_reboot();
return ret;
}
#else
static int hal_ota_switch_to_new_fw(void)
{
hal_logic_partition_t *partition_info;
uint32_t offset;
ota_hdl_t ota_hdl, ota_hdl_rb;
offset = 0x00;
hal_flash_erase(HAL_PARTITION_PARAMETER_1, offset, sizeof(ota_hdl_t));
offset = 0x00;
memset(&ota_hdl, 0, sizeof(ota_hdl_t));
partition_info = hal_flash_get_info(HAL_PARTITION_APPLICATION);
ota_hdl.dst_adr = partition_info->partition_start_addr;
partition_info = hal_flash_get_info(HAL_PARTITION_OTA_TEMP);
ota_hdl.src_adr = partition_info->partition_start_addr;
ota_hdl.size = ota_info.ota_len;
ota_hdl.crc = ota_info.ota_crc;
ota_hdl.upg_flag = OTA_UPG_FLAG;
hal_flash_write(HAL_PARTITION_PARAMETER_1, &offset, (const void *)&ota_hdl, sizeof(ota_hdl_t));
offset = 0x00;
memset(&ota_hdl_rb, 0, sizeof(ota_hdl_t));
hal_flash_read(HAL_PARTITION_PARAMETER_1, &offset, &ota_hdl_rb, sizeof(ota_hdl_t));
if(memcmp(&ota_hdl, &ota_hdl_rb, sizeof(ota_hdl_t)) != 0) {
OTA_LOG_I("OTA header compare failed.\r\n");
return -1;
}
/* reboot */
hal_reboot();
return 0;
}
static int ota_init(void *something)
{
ota_boot_param_t *param = (ota_boot_param_t *)something;
if(param == NULL) {
return -1;
}
hal_logic_partition_t *part_info = hal_flash_get_info(HAL_PARTITION_OTA_TEMP);
if(part_info->partition_length < param->len || param->len == 0) {
return -1;
}
ota_info.ota_len = param->off_bp;
hal_flash_dis_secure(0, 0, 0);//disable flash protect
if(param->off_bp == 0) {
hal_flash_erase(HAL_PARTITION_OTA_TEMP, 0, part_info->partition_length);
ota_crc16_init(&contex);
}
else {
contex.crc = hal_ota_get_crc16();
OTA_LOG_I("--------get crc16 context.crc=%d!--------\n", contex.crc);
}
return 0;
}
static int ota_write(int *off_set, char *in_buf , int in_buf_len)
{
int ret = 0;
if(ota_info.ota_len == 0) {
_off_set = 0;
ota_crc16_init(&contex);
memset(&ota_info, 0, sizeof(ota_info));
}
ota_crc16_update(&contex, in_buf, in_buf_len);
ret = hal_flash_write(HAL_PARTITION_OTA_TEMP, &_off_set, in_buf, in_buf_len);
ota_info.ota_len += in_buf_len;
return ret;
}
static int ota_read(int *off_set, char *out_buf , int out_buf_len)
{
hal_flash_read(HAL_PARTITION_OTA_TEMP, off_set, out_buf, out_buf_len);
return 0;
}
static int ota_boot(void *something)
{
ota_boot_param_t *param = (ota_boot_param_t *)something;
if(param == NULL) {
return -1;
}
if(param->res_type == OTA_FINISH) {
ota_crc16_final(&contex, &ota_info.ota_crc);
OTA_LOG_I("beken set boot\n");
hal_ota_switch_to_new_fw();
}
else if(param->res_type == OTA_BREAKPOINT) {
OTA_LOG_I("-------save bp crc=%d--------------\n", contex.crc);
hal_ota_save_crc16(contex.crc);
}
return 0;
}
#endif
static uint16_t hal_ota_get_crc16(void)
{
int len = 2;
uint16_t crc16 = 0;
aos_kv_get(KV_HAL_OTA_CRC16, &crc16, &len);
return crc16;
}
static void hal_ota_save_crc16(uint16_t crc16)
{
aos_kv_set(KV_HAL_OTA_CRC16, &crc16, 2, 1);
}
static int ota_rollback(void *something)
{
int offset = 0x00;
int param_part = HAL_PARTITION_PARAMETER_1;
ota_boot_param_t param_w, param_r;
memset(&param_w, 0, sizeof(ota_boot_param_t));
hal_flash_read(param_part, (uint32_t*)&offset, &param_w, sizeof(ota_boot_param_t));
if((param_w.boot_count != 0) && (param_w.boot_count != 0xff)) {
ota_crc16_ctx ctx1;
unsigned short crc;
param_w.upg_flag = 0;
param_w.boot_count = 0; /*Clear bootcount to avoid rollback*/
ota_crc16_init(&ctx1);
ota_crc16_update(&ctx1, &param_w, sizeof(ota_boot_param_t) - sizeof(unsigned short));
ota_crc16_final(&ctx1, &crc);
param_w.param_crc = crc;
offset = 0x00;
hal_flash_erase(param_part, offset, sizeof(ota_boot_param_t));
offset = 0x00;
hal_flash_write(param_part, (uint32_t*)&offset, &param_w, sizeof(ota_boot_param_t));
offset = 0x00;
memset(&param_r, 0, sizeof(ota_boot_param_t));
hal_flash_read(param_part, (uint32_t*)&offset, &param_r, sizeof(ota_boot_param_t));
if(memcmp(&param_w, &param_r, sizeof(ota_boot_param_t)) != 0) {
OTA_LOG_E("rollback failed\n");
return -1;
}
}
return 0;
}
const char *aos_get_app_version(void);
static const char *ota_get_version(unsigned char dev_type)
{
if(dev_type) {
return "v1.0.0-20180101-1000";//SYSINFO_APP_VERSION;
} else {
return aos_get_app_version();
}
}
ota_hal_module_t ota_hal_module = {
.init = ota_init,
.write = ota_write,
.read = ota_read,
.boot = ota_boot,
.rollback = ota_rollback,
.version = ota_get_version,
};

View file

@ -0,0 +1,153 @@
#include "esp_ota_ops.h"
#include "ota_log.h"
#include "ota_hal_plat.h"
#include <string.h>
#include <malloc.h>
#include "esp_spi_flash.h"
#include "rom/spi_flash.h"
#include "hal/soc/flash.h"
static esp_partition_t operate_partition;
static esp_ota_handle_t out_handle;
static esp_err_t esp_write_error;
extern void esp_restart(void);
bool esp_ota_prepare()
{
esp_err_t err;
const esp_partition_t *esp_current_partition = esp_ota_get_boot_partition();
if (esp_current_partition == NULL) {
OTA_LOG_E("Got null partition.");
return false;
}
if (esp_current_partition->type != ESP_PARTITION_TYPE_APP) {
OTA_LOG_E("Err part type");
return false;
}
esp_partition_t find_partition;
/*choose which OTA image should we write to*/
switch (esp_current_partition->subtype) {
case ESP_PARTITION_SUBTYPE_APP_FACTORY:
find_partition.subtype = ESP_PARTITION_SUBTYPE_APP_OTA_0;
break;
case ESP_PARTITION_SUBTYPE_APP_OTA_0:
find_partition.subtype = ESP_PARTITION_SUBTYPE_APP_OTA_1;
break;
case ESP_PARTITION_SUBTYPE_APP_OTA_1:
find_partition.subtype = ESP_PARTITION_SUBTYPE_APP_OTA_0;
break;
default:
find_partition.subtype = ESP_PARTITION_SUBTYPE_APP_OTA_0;
break;
}
find_partition.type = ESP_PARTITION_TYPE_APP;
const esp_partition_t *partition = esp_partition_find_first(find_partition.type, find_partition.subtype, NULL);
assert(partition != NULL);
memset(&operate_partition, 0, sizeof(esp_partition_t));
OTA_LOG_I("ota_begin part type 0x%x sub:0x%x addr:0x%x size:0x%x label:%s encry:0x%x\n", partition->type, partition->subtype, partition->address, partition->size, partition->label, partition->encrypted);
esp_write_error = ESP_OK;
err = esp_ota_begin(partition, OTA_SIZE_UNKNOWN, &out_handle);
if (err != ESP_OK) {
OTA_LOG_E("begin err=0x%x!", err);
return false;
} else {
memcpy(&operate_partition, partition, sizeof(esp_partition_t));
OTA_LOG_I("ota init OK");
return true;
}
return false;
}
static int ota_init(void *something)
{
ota_boot_param_t *param = (ota_boot_param_t *)something;
uint32_t offset = param->off_bp;
OTA_LOG_I("ota_init off:0x%x \n",offset);
if(offset==0) {
/* prepare to os update */
if (esp_ota_prepare() != true) {
return -1;
}
}
return 0;
}
static int ota_write(int* off, char* buf ,int buf_len)
{
esp_err_t err = ESP_OK;
err = esp_ota_write(out_handle, (const void *)buf, (size_t)buf_len);
if (err != ESP_OK) {
esp_write_error = err;
OTA_LOG_E("write err=%x", err);
return -1;
}
return 0;
}
static int ota_boot(void *something)
{
esp_err_t err = ESP_OK;
ota_boot_param_t *param = (ota_boot_param_t *)something;
if (param == NULL) {
return -1;
}
if (param->res_type == OTA_FINISH) {
if (esp_ota_end(out_handle) != ESP_OK) {
OTA_LOG_E("end failed!");
return -1;
}
if(esp_write_error ) {
OTA_LOG_E("write_error %d!",esp_write_error);
return -1;
}
err = esp_ota_set_boot_partition(&operate_partition);
if (err != ESP_OK) {
OTA_LOG_E("set part failed! err=0x%x", err);
return -1;
}
OTA_LOG_I("restart system!");
esp_restart();
}
else if (param->res_type==OTA_BREAKPOINT) {
}
else {
return -1;
}
return 0;
}
static int ota_read(int* off, char* out_buf, int out_buf_len)
{
return hal_flash_read(HAL_PARTITION_OTA_TEMP, (uint32_t*)off, out_buf, out_buf_len);
}
static int ota_rollback(void *something)
{
return 0;
}
const char *aos_get_app_version(void);
static const char *ota_get_version(unsigned char dev_type)
{
if(dev_type) {
return "v1.0.0-20180101-1000";//SYSINFO_APP_VERSION;
} else {
return SYSINFO_APP_VERSION;
}
}
ota_hal_module_t ota_hal_module = {
.init = ota_init,
.write = ota_write,
.read = ota_read,
.boot = ota_boot,
.rollback = ota_rollback,
.version = ota_get_version,
};

View file

@ -0,0 +1,216 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "ota_log.h"
#include "ota_hal_plat.h"
static FILE* ota_fd = NULL;
static int offset = 0;
#if defined PLAT_RASPBERRY /*raspberry*/
static int boot_part = 2;
static int boot_part_in = 3;
#define OTA_IMAGE_FILE "/dev/mmcblk0p"
#else
static int boot_part = 4;
static int boot_part_in = 5;
#define OTA_IMAGE_FILE "rkflash0p"
#endif
int getCmdVal(const char *cmd)
{
char ps[1024]={0};
FILE *ptr = NULL;
char *sstr = NULL;
if((ptr=popen(cmd, "r"))!=NULL)
{
while(fgets(ps, 1024, ptr)!=NULL)
{
}
pclose(ptr);
ptr = NULL;
OTA_LOG_I("ret:%s\n",ps);
}
else
{
OTA_LOG_E("popen %s error\n", ps);
}
sstr = strstr(ps, "mender_boot_part=");
if (sstr) {
sscanf(sstr, "%*[^ ]%d", &boot_part);
OTA_LOG_I("mender_boot_part:%d \n", boot_part);
}
#if defined PLAT_RASPBERRY
if(boot_part == 3) {
boot_part_in = 2;
} else {
boot_part_in = 3;
}
#else
if(boot_part == 5) {
boot_part_in = 4;
} else {
boot_part_in = 5;
}
#endif
OTA_LOG_I("ota init:%d boot_part_in:%d\n", boot_part,boot_part_in);
return 0;
}
static int ota_init(void *something)
{
char path[64] = {0};
int ret = 0;
ota_boot_param_t * param = (ota_boot_param_t*)something;
getCmdVal("fw_printenv mender_boot_part");
snprintf(path,sizeof(path),"%s%d",OTA_IMAGE_FILE,boot_part_in);
offset= param->off_bp;
OTA_LOG_I("init off: %d size:0x%x \n", offset,param->len);
if(param->len == 0) {
OTA_LOG_E("ota init size error:");
return -1;
}
#if !defined PLAT_RASPBERRY
if(param->len > 0x3100000){
OTA_LOG_E("firmware size is too big.\n");
return -1;
}
#endif
if(offset!=0){ /*breakpoint resume*/
if(ota_fd==NULL){
if((ota_fd = fopen(path, "a+"))==NULL) {
OTA_LOG_E("init err: %d, %s\n", ret, strerror(errno));
return -1;
}
if(ftell(ota_fd)<=0){
OTA_LOG_E("init error: %d, %s\n", ret, strerror(errno));
return -1;
}
}
}
return ret;
}
int ota_write(int *off_set, char *in_buf, int in_buf_len)
{
int ret = 0;
if(ota_fd == NULL)
{
char path[64] = {0};
snprintf(path,sizeof(path),"%s%d",OTA_IMAGE_FILE,boot_part_in);
ota_fd = fopen(path, "w");
}
ret = fwrite(in_buf, in_buf_len, 1, ota_fd);
if (ret < 0) {
OTA_LOG_E("write err: %d, %d ,%s\n", ret, in_buf_len,
strerror(errno));
return -1;
}
return 0;
}
static int ota_read(int *off_set, char *out_buf, int out_buf_len)
{
if (ota_fd != NULL) {
fflush(ota_fd);
fclose(ota_fd);
ota_fd = NULL;
}
int ret = 0;
if(ota_fd == NULL)
{
char path[64] = {0};
snprintf(path,sizeof(path),"%s%d",OTA_IMAGE_FILE,boot_part_in);
ota_fd = fopen(path, "r");
}
ret = fseek(ota_fd, *off_set, SEEK_SET);
ret = fread(out_buf, out_buf_len, 1, ota_fd);
if (ret != 1) {
OTA_LOG_E("read err: %d, %d ,%s\n", ret, out_buf_len, strerror(errno));
return -1;
}
fclose(ota_fd);
ota_fd = NULL;
*off_set += out_buf_len;
return 0;
}
static int ota_boot(void *something)
{
int ret = 0;
if (ota_fd != NULL) {
fflush(ota_fd);
fclose(ota_fd);
ota_fd = NULL;
}
char cmd1[64] = { 0 };
ota_boot_param_t *param = (ota_boot_param_t *)something;
if (param==NULL){
OTA_LOG_E("boot err\n");
return -1;
}
if (param->res_type==OTA_FINISH) {
sprintf(cmd1, "fw_setenv mender_boot_part %d",boot_part_in);
ret = system(cmd1);
if(ret < 0) {
OTA_LOG_E("set boot part err.\n");
return -1;
}
OTA_LOG_E("boot:%s \n",cmd1);
memset(cmd1,0x00,sizeof(cmd1));
sprintf(cmd1, "fw_setenv upgrade_available 1");
ret = system(cmd1);
if(ret < 0) {
OTA_LOG_E("upgrade_available err\n");
return -1;
}
OTA_LOG_E("boot:%s \n",cmd1);
memset(cmd1,0x00,sizeof(cmd1));
sprintf(cmd1, "sync;reboot");
ret = system(cmd1);
if(ret < 0) {
OTA_LOG_E("sync err\n");
return -1;
}
}
OTA_LOG_I("Rebooting and updating FLASH now....\n");
return 0;
}
static int ota_rollback(void *something)
{
char cmd1[128] = {0};
int ret = 0;
sprintf(cmd1, "fw_setenv upgrade_available 0; fw_setenv bootcount 0; sync");
ret = system(cmd1);
if(ret < 0) {
OTA_LOG_E("roll system fail .");
}
OTA_LOG_I("roll:%s \n",cmd1);
return 0;
}
const char *aos_get_app_version(void);
static const char *ota_get_version(unsigned char dev_type)
{
if(dev_type) {
return "v1.0.0-20180101-1000";//SYSINFO_APP_VERSION;
} else {
return aos_get_app_version();
}
}
ota_hal_module_t ota_hal_module = {
.init = ota_init,
.write = ota_write,
.read = ota_read,
.boot = ota_boot,
.rollback = ota_rollback,
.version = ota_get_version,
};

View file

@ -0,0 +1,87 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "aos/kernel.h"
#include "aos/kv.h"
#include "ota_hal_plat.h"
#include "ota_hal_os.h"
#include "ota_log.h"
#include "ota_verify.h"
#include "ota_hal_mcu.h"
#define OTA_CRC16 "ota_file_crc16"
static unsigned int wdata_len = 0;
static ota_crc16_ctx ctx = {0};
static unsigned short ota_get_crc16(void)
{
int len = 2;
unsigned short crc16=0;
aos_kv_get(OTA_CRC16, &crc16, &len);
return crc16;
}
static void ota_set_crc16(unsigned short crc16)
{
aos_kv_set(OTA_CRC16, &crc16, 2, 1);
}
int ota_mcu_init(void *something)
{
int ret = 0;
ota_boot_param_t *param = (ota_boot_param_t *)something;
param->off_bp = ota_get_break_point();
if (param->off_bp >= param->len) {
param->off_bp = 0;
}
wdata_len = param->off_bp;
if (param->off_bp == 0) {
ota_crc16_init(&ctx);
} else {
ctx.crc = ota_get_crc16();
}
OTA_LOG_I("ota mcu init off:0x%08x len:%d crc:0x%04x\n", param->off_bp, param->len, ctx.crc);
return ret;
}
int ota_mcu_write(int* off, char* in_buf ,int in_buf_len)
{
int ret = 0;
if (off != NULL) {
OTA_LOG_I("recv MCU data off:%d", *off);
}
/* for only test */
wdata_len = wdata_len + in_buf_len;
OTA_LOG_I("recv MCU data wdata_len:%d, in_buf_len:%d", wdata_len, in_buf_len);
ota_crc16_update(&ctx, in_buf, in_buf_len);
return ret;
}
int ota_mcu_boot(void *something)
{
int ret = 0;
ota_boot_param_t *param = (ota_boot_param_t *)something;
if (param == NULL) {
ret = OTA_REBOOT_FAIL;
return ret;
}
if (param->res_type == OTA_FINISH) {
ota_crc16_final(&ctx, &param->crc);
ota_set_break_point(0);
ota_msleep(1500);
ota_reboot();
} else if(param->res_type == OTA_BREAKPOINT) {
OTA_LOG_I("save bp crc:0x%04x", ctx.crc);
ota_set_crc16(ctx.crc);
}
return ret;
}

View file

@ -0,0 +1,21 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef MCU_HAL_OTA_H
#define MCU_HAL_OTA_H
#ifdef __cplusplus
extern "C" {
#endif
int ota_mcu_init(void *something);
int ota_mcu_write(int* off, char* in_buf ,int in_buf_len);
int ota_mcu_boot(void *something);
#ifdef __cplusplus
}
#endif
#endif /* MCU_HAL_OTA_H */

View file

@ -0,0 +1,154 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include "ota_log.h"
#include "ota_hal_plat.h"
static ota_hal_module_t *ota_module = NULL;
void ota_hal_register_module(ota_hal_module_t *module)
{
ota_module = module;
}
int ota_hal_init(void *something)
{
#ifdef OTA_BOOT_PAPA_COMPATIBAL
struct {
unsigned int dst_adr;
unsigned int src_adr;
unsigned int len;
unsigned short crc;
unsigned int upg_flag;
unsigned char boot_count;
unsigned int rec_size;
unsigned int splict_size;
int off_bp; /*Break point offset*/
OTA_RES_TYPE_E res_type; /*result type: OTA_FINISH, OTA_BREAKPOINT*/
unsigned short param_crc; /*Parameter crc*/
} __attribute__((packed)) boot_para_more;
ota_boot_param_t *boot_para_less = (ota_boot_param_t *)something;
boot_para_more.dst_adr = boot_para_less->dst_adr ;
boot_para_more.src_adr = boot_para_less->src_adr ;
boot_para_more.len = boot_para_less->len ;
boot_para_more.crc = boot_para_less->crc ;
boot_para_more.upg_flag = boot_para_less->upg_flag ;
boot_para_more.boot_count = boot_para_less->boot_count ;
boot_para_more.rec_size = 0 ;
boot_para_more.splict_size = boot_para_less->splict_size;
boot_para_more.off_bp = boot_para_less->off_bp ;
boot_para_more.res_type = boot_para_less->res_type ;
boot_para_more.param_crc = boot_para_less->param_crc ;
something = (void *)&boot_para_more;
#endif
if (ota_module == NULL) {
return -1;
}
if (ota_module != NULL && ota_module->init != NULL) {
return ota_module->init(something);
}
return 0;
}
int ota_hal_write(int *off_set, char *in_buf , int in_buf_len)
{
if (ota_module == NULL) {
return -1;
}
if (ota_module != NULL && ota_module->write != NULL) {
return ota_module->write(off_set, in_buf, in_buf_len);
}
return 0;
}
int ota_hal_read(int *off_set, char *out_buf, int out_buf_len)
{
if (ota_module == NULL) {
return -1;
}
if (ota_module != NULL && ota_module->read != NULL) {
return ota_module->read(off_set, out_buf, out_buf_len);
}
return 0;
}
int ota_hal_boot(void *something)
{
#ifdef OTA_BOOT_PAPA_COMPATIBAL
struct {
unsigned int dst_adr;
unsigned int src_adr;
unsigned int len;
unsigned short crc;
unsigned int upg_flag;
unsigned char boot_count;
unsigned int rec_size;
unsigned int splict_size;
int off_bp; /*Break point offset*/
OTA_RES_TYPE_E res_type; /*result type: OTA_FINISH, OTA_BREAKPOINT*/
unsigned short param_crc; /*Parameter crc*/
} __attribute__((packed)) boot_para_more;
ota_boot_param_t *boot_para_less = (ota_boot_param_t *)something;
boot_para_more.dst_adr = boot_para_less->dst_adr ;
boot_para_more.src_adr = boot_para_less->src_adr ;
boot_para_more.len = boot_para_less->len ;
boot_para_more.crc = boot_para_less->crc ;
boot_para_more.upg_flag = boot_para_less->upg_flag ;
boot_para_more.boot_count = boot_para_less->boot_count ;
boot_para_more.rec_size = 0 ;
boot_para_more.splict_size = boot_para_less->splict_size;
boot_para_more.off_bp = boot_para_less->off_bp ;
boot_para_more.res_type = boot_para_less->res_type ;
boot_para_more.param_crc = boot_para_less->param_crc ;
something = (void *)&boot_para_more;
#endif
if (ota_module == NULL) {
return -1;
}
if (ota_module != NULL && ota_module->boot != NULL) {
return ota_module->boot(something);
}
return 0;
}
int ota_hal_rollback(void *something)
{
if (ota_module == NULL) {
return -1;
}
if (ota_module != NULL && ota_module->rollback != NULL) {
return ota_module->rollback(something);
}
return 0;
}
const char *ota_hal_get_version(unsigned char dev_type)
{
if (ota_module == NULL) {
return NULL;
}
if (ota_module != NULL && ota_module->version != NULL) {
return ota_module->version(dev_type);
}
return NULL;
}

View file

@ -0,0 +1,843 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <string.h>
#include "ota_hal_os.h"
#include "ota_log.h"
#if !defined (AOS_OTA_RSA)
#if defined AOS_OTA_ITLS
#include "itls/sha256.h"
#include "itls/md5.h"
#else
#include "mbedtls/sha256.h"
#include "mbedtls/md5.h"
#endif
#endif
#if (OTA_SIGNAL_CHANNEL) == 1
#include "iot_export.h"
#include "iot_import.h"
#include "iot_export_coap.h"
#endif
#if (OTA_SIGNAL_CHANNEL) == 2
#include "iot_import.h"
#endif
#ifdef OTA_LINUX
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
#include <sys/reboot.h>
#else
#include "aos/kernel.h"
#include "aos/kv.h"
#endif
/*Memory realloc*/
void *ota_realloc(void *ptr, int size)
{
#if defined OTA_WITH_LINKKIT
return HAL_Realloc(ptr, size);
#elif !defined OTA_LINUX
return aos_realloc(ptr, size);
#else
return realloc(ptr, size);
#endif
}
/*Memory calloc*/
void *ota_calloc(int n, int size)
{
#if defined OTA_WITH_LINKKIT
return HAL_Malloc(size);
#elif !defined OTA_LINUX
return aos_calloc(n, size);
#else
return calloc(n, size);
#endif
}
/*Reboot*/
void ota_reboot(void)
{
#if defined OTA_WITH_LINKKIT
HAL_Reboot();
#elif !defined OTA_LINUX
aos_reboot();
#else
reboot(0x1234567);
#endif
}
/*Memory malloc*/
void *ota_malloc(int size)
{
#if defined OTA_WITH_LINKKIT
return HAL_Malloc(size);
#elif !defined OTA_LINUX
return aos_malloc(size);
#else
return malloc(size);
#endif
}
/*Memory free*/
void ota_free(void *ptr)
{
#if defined OTA_WITH_LINKKIT
return HAL_Free(ptr);
#elif !defined OTA_LINUX
aos_free(ptr);
#else
free(ptr);
#endif
}
/*Semaphore init*/
void *ota_semaphore_create(void)
{
#if defined OTA_WITH_LINKKIT
return HAL_SemaphoreCreate();
#elif !defined OTA_LINUX
aos_sem_t *sem = (aos_sem_t *)ota_malloc(sizeof(aos_sem_t));
if (NULL == sem) {
return NULL;
}
if (0 != aos_sem_new(sem, 0)) {
ota_free(sem);
return NULL;
}
return sem;
#else
sem_t *sem = (sem_t *)ota_malloc(sizeof(sem_t));
if (NULL == sem) {
return NULL;
}
if (0 != sem_init(sem, 0, 0)) {
ota_free(sem);
return NULL;
}
return sem;
#endif
}
/*Semaphore wait*/
int ota_semaphore_wait(void *sem, int ms)
{
#if defined OTA_WITH_LINKKIT
return HAL_SemaphoreWait(sem, ms);
#elif !defined OTA_LINUX
return aos_sem_wait((aos_sem_t *)sem, ms);
#else
if ((~0) == ms) {
sem_wait(sem);
return 0;
} else {
struct timespec ts;
int s;
/* Restart if interrupted by handler */
do {
if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
return -1;
}
s = 0;
ts.tv_nsec += (ms % 1000) * 1000000;
if (ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
s = 1;
}
ts.tv_sec += ms / 1000 + s;
} while (((s = sem_timedwait(sem, &ts)) != 0) && errno == EINTR);
return (s == 0) ? 0 : -1;
}
return 0;
#endif
}
/*Semaphore post*/
void ota_semaphore_post(void *sem)
{
#if defined OTA_WITH_LINKKIT
return HAL_SemaphorePost(sem);
#elif !defined OTA_LINUX
aos_sem_signal((aos_sem_t *)sem);
#else
sem_post((sem_t *)sem);
#endif
}
/*Semaphore destroy*/
void ota_semaphore_destroy(void *sem)
{
#if defined OTA_WITH_LINKKIT
return HAL_SemaphoreDestroy(sem);
#elif !defined OTA_LINUX
aos_sem_free((aos_sem_t *)sem);
aos_free(sem);
#else
sem_destroy((sem_t *)sem);
free(sem);
#endif
}
/*Sleep ms*/
void ota_msleep(int ms)
{
#if defined OTA_WITH_LINKKIT
return HAL_SleepMs(ms);
#elif !defined OTA_LINUX
aos_msleep(ms);
#else
usleep(1000 * ms);
#endif
}
#if defined OTA_WITH_LINKKIT
;
#elif !defined OTA_LINUX
typedef struct
{
aos_task_t task;
int detached;
void * arg;
void *(*routine)(void *arg);
} task_context_t;
static void task_wrapper(void *arg)
{
task_context_t *task = arg;
task->routine(task->arg);
if (task) {
aos_free(task);
task = NULL;
}
}
#endif
#define OTA_THREAD_NAME "OTA_Thread"
#if defined AOS_OTA_TLS
#define OTA_THREAD_SIZE (8 * 1024)
#else
#define OTA_THREAD_SIZE (4 * 1024)
#endif
#define OTA_THREAD_PRI 30
/*Thread create*/
int ota_thread_create(void **thread_handle, void *(*work_routine)(void *), void *arg, void *pm, int stack_size)
{
int ret = -1;
#if defined OTA_WITH_LINKKIT
hal_os_thread_param_t task_parms;
task_parms.stack_size = OTA_THREAD_SIZE;
task_parms.name = OTA_THREAD_NAME;
ret = HAL_ThreadCreate(thread_handle, work_routine, arg, &task_parms, 0);
#elif !defined OTA_LINUX
char * tname = OTA_THREAD_NAME;
if(stack_size <= 0) {
stack_size = OTA_THREAD_SIZE;
}
task_context_t *task = aos_malloc(sizeof(task_context_t));
if (!task) {
return -1;
}
memset(task, 0, sizeof(task_context_t));
task->arg = arg;
task->routine = work_routine;
ret = aos_task_new_ext(&task->task, tname, task_wrapper, task, stack_size, OTA_THREAD_PRI);
*thread_handle = (void *)task;
#else
ret = pthread_create((pthread_t *)thread_handle, NULL, work_routine, arg);
#endif
return ret;
}
/*Thread exit*/
void ota_thread_exit(void *thread)
{
#if defined OTA_WITH_LINKKIT
return HAL_ThreadDelete(thread);
#elif !defined OTA_LINUX
aos_task_exit(0);
#else
pthread_exit(0);
#endif
}
#if defined OTA_WITH_LINKKIT
/*KV set*/
int ota_kv_set(const char *key, const void *val, int len, int sync)
{
return HAL_Kv_Set(key, val, len, sync);
}
/*KV get*/
int ota_kv_get(const char *key, void *buffer, int *len)
{
return HAL_Kv_Get(key, buffer, len);
}
#elif !defined OTA_LINUX
/*KV set*/
int ota_kv_set(const char *key, const void *val, int len, int sync)
{
return aos_kv_set(key, val, len, sync);
}
/*KV get*/
int ota_kv_get(const char *key, void *buffer, int *len)
{
return aos_kv_get(key, buffer, len);
}
#else
#define KV_FILE_PATH "./uota.kv"
#define ITEM_MAX_KEY_LEN 128
#define ITEM_MAX_VAL_LEN 256
#define ITEM_LEN 512
typedef struct
{
int flag;
int val_len;
} kv_state_t;
typedef struct
{
char key[ITEM_MAX_KEY_LEN];
char val[ITEM_MAX_VAL_LEN];
kv_state_t state;
} kv_t;
static pthread_mutex_t mutex_kv = PTHREAD_MUTEX_INITIALIZER;
/* get file size and item num */
static int hal_fopen(FILE **fp, int *size, int *num)
{
/* create an file to save the kv */
if ((*fp = fopen(KV_FILE_PATH, "a+")) == NULL) {
OTA_LOG_E("open err:%s\n", strerror(errno));
return -1;
}
fseek(*fp, 0L, SEEK_END);
if ((*size = ftell(*fp)) % ITEM_LEN) {
fclose(*fp);
return -1;
}
*num = ftell(*fp) / ITEM_LEN;
fseek(*fp, 0L, SEEK_SET);
return 0;
}
/*KV set*/
int ota_kv_set(const char *key, const void *val, int len, int sync)
{
FILE *fp = NULL;
int file_size = 0, block_num = 0, ret = 0, cur_pos = 0;
kv_t kv_item;
int i;
/* check parameter */
if (key == NULL || val == NULL) {
return -1;
}
pthread_mutex_lock(&mutex_kv);
if (hal_fopen(&fp, &file_size, &block_num) != 0) {
goto ERR;
}
for (i = 0; i < block_num; i++) {
memset(&kv_item, 0, sizeof(kv_t));
cur_pos = ftell(fp);
/* read an kv item(512 bytes) from file */
if ((ret = fread(&kv_item, 1, ITEM_LEN, fp)) != ITEM_LEN) {
goto ERR;
}
/* key compared */
if (strcmp(kv_item.key, key) == 0) {
/* set value and write to file */
memset(kv_item.val, 0, ITEM_MAX_VAL_LEN);
memcpy(kv_item.val, val, len);
kv_item.state.val_len = len;
fseek(fp, cur_pos, SEEK_SET);
fwrite(&kv_item, 1, ITEM_LEN, fp);
goto END;
}
}
/* key not compared, append an kv to file */
memset(&kv_item, 0, sizeof(kv_t));
strcpy(kv_item.key, key);
memcpy(kv_item.val, val, len);
kv_item.state.val_len = len;
fseek(fp, 0L, SEEK_END);
fwrite(&kv_item, 1, ITEM_LEN, fp);
goto END;
ERR:
if (fp == NULL) {
pthread_mutex_unlock(&mutex_kv);
return -1;
}
OTA_LOG_E("read err:%s\n", strerror(errno));
fflush(fp);
fclose(fp);
pthread_mutex_unlock(&mutex_kv);
return -1;
END:
fflush(fp);
fclose(fp);
pthread_mutex_unlock(&mutex_kv);
return 0;
}
/*KV get*/
int ota_kv_get(const char *key, void *buffer, int *len)
{
FILE *fp = NULL;
int i;
/* read from file */
int file_size = 0, block_num = 0;
kv_t kv_item;
/* check parameter */
if (key == NULL || buffer == NULL || len == NULL) {
return -1;
}
pthread_mutex_lock(&mutex_kv);
if (hal_fopen(&fp, &file_size, &block_num) != 0) {
goto ERR;
}
for (i = 0; i < block_num; i++) {
memset(&kv_item, 0, sizeof(kv_t));
/* read an kv item(512 bytes) from file */
if (fread(&kv_item, 1, ITEM_LEN, fp) != ITEM_LEN) {
goto ERR;
}
/* key compared */
if (strcmp(kv_item.key, key) == 0) {
/* set value and write to file */
*len = kv_item.state.val_len;
memcpy(buffer, kv_item.val, *len);
goto END;
}
}
goto END;
ERR:
if (fp == NULL) {
pthread_mutex_unlock(&mutex_kv);
return -1;
}
OTA_LOG_E("read err:%s\n", strerror(errno));
fflush(fp);
fclose(fp);
pthread_mutex_unlock(&mutex_kv);
return -1;
END:
fflush(fp);
fclose(fp);
pthread_mutex_unlock(&mutex_kv);
return 0;
}
#endif /*Linux end*/
/*Socket API*/
void* ota_socket_connect(char *host, int port)
{
#ifdef OTA_WITH_LINKKIT
return (void*)HAL_TCP_Establish(host, port);
#else
return 0;
#endif
}
int ota_socket_send(void* fd, char *buf, int len)
{
#ifdef OTA_WITH_LINKKIT
return HAL_TCP_Write((uintptr_t)fd, buf, len, OTA_SSL_TIMEOUT);
#else
return 0;
#endif
}
int ota_socket_recv(void* fd, char *buf, int len)
{
#ifdef OTA_WITH_LINKKIT
return HAL_TCP_Read((uintptr_t)fd, buf, len, OTA_SSL_TIMEOUT);
#else
return 0;
#endif
}
void ota_socket_close(void* fd)
{
#ifdef OTA_WITH_LINKKIT
HAL_TCP_Destroy((uintptr_t)fd);
#endif
}
/*SSL connect*/
void *ota_ssl_connect(const char *host, unsigned short port, const char *ca_crt, int ca_crt_len)
{
#ifdef OTA_WITH_LINKKIT
return (void*)HAL_SSL_Establish(host, port, ca_crt, ca_crt_len);
#else
return 0;
#endif
}
/*SSL send*/
int ota_ssl_send(void *ssl, char *buf, int len)
{
#ifdef OTA_WITH_LINKKIT
return HAL_SSL_Write((uintptr_t)ssl, buf, len, OTA_SSL_TIMEOUT);
#else
return 0;
#endif
}
/*SSL recv*/
int ota_ssl_recv(void *ssl, char *buf, int len)
{
#ifdef OTA_WITH_LINKKIT
return HAL_SSL_Read((uintptr_t)ssl, buf, len, OTA_SSL_TIMEOUT);
#else
return 0;
#endif
}
#if !defined (AOS_OTA_RSA)
/*SHA256*/
extern void mbedtls_sha256_free(mbedtls_sha256_context* ctx);
extern void mbedtls_sha256_init(mbedtls_sha256_context*ctx);
extern void mbedtls_sha256_starts(mbedtls_sha256_context*ctx, int is224);
extern void mbedtls_sha256_update(mbedtls_sha256_context*ctx, const unsigned char *input, unsigned int ilen);
extern void mbedtls_sha256_finish(mbedtls_sha256_context*ctx, unsigned char output[32]);
void ota_sha256_free(ota_sha256_context *ctx)
{
mbedtls_sha256_free((mbedtls_sha256_context*)ctx);
}
void ota_sha256_init(ota_sha256_context *ctx)
{
mbedtls_sha256_init((mbedtls_sha256_context*)ctx);
}
void ota_sha256_starts(ota_sha256_context *ctx, int is224)
{
mbedtls_sha256_starts((mbedtls_sha256_context*)ctx, is224);
}
void ota_sha256_update(ota_sha256_context *ctx, const unsigned char *input, unsigned int ilen)
{
mbedtls_sha256_update((mbedtls_sha256_context*)ctx, input, ilen);
}
void ota_sha256_finish(ota_sha256_context *ctx, unsigned char output[32])
{
mbedtls_sha256_finish((mbedtls_sha256_context*)ctx, output);
}
/*MD5*/
extern void mbedtls_md5_free(mbedtls_md5_context*ctx);
extern void mbedtls_md5_init(mbedtls_md5_context*ctx);
extern void mbedtls_md5_starts(mbedtls_md5_context*ctx);
extern void mbedtls_md5_update(mbedtls_md5_context*ctx, const unsigned char *input, unsigned int ilen);
extern void mbedtls_md5_finish(mbedtls_md5_context*ctx, unsigned char output[32]);
void ota_md5_free(ota_md5_context *ctx)
{
mbedtls_md5_free((mbedtls_md5_context*)ctx);
}
void ota_md5_init(ota_md5_context *ctx)
{
mbedtls_md5_init((mbedtls_md5_context*)ctx);
}
void ota_md5_starts(ota_md5_context *ctx)
{
mbedtls_md5_starts((mbedtls_md5_context*)ctx);
}
void ota_md5_update(ota_md5_context *ctx, const unsigned char *input, unsigned int ilen)
{
mbedtls_md5_update((mbedtls_md5_context*)ctx, input, ilen);
}
void ota_md5_finish(ota_md5_context *ctx, unsigned char output[16])
{
mbedtls_md5_finish((mbedtls_md5_context*)ctx, output);
}
/*RSA*/
extern int ali_rsa_get_pubkey_size(unsigned int keybits, unsigned int *size);
extern int ali_rsa_init_pubkey(unsigned int keybits, const unsigned char *n, unsigned int n_size,
const unsigned char *e, unsigned int e_size, ota_rsa_pubkey_t *pubkey);
extern int ali_rsa_verify(const ota_rsa_pubkey_t *pub_key, const unsigned char *dig, unsigned int dig_size,
const unsigned char *sig, unsigned int sig_size, ota_rsa_padding_t padding, bool *p_result);
int ota_rsa_get_pubkey_size(unsigned int keybits, unsigned int *size)
{
return ali_rsa_get_pubkey_size(keybits, size);
}
int ota_rsa_init_pubkey(unsigned int keybits, const unsigned char *n, unsigned int n_size,
const unsigned char *e, unsigned int e_size, ota_rsa_pubkey_t *pubkey){
return ali_rsa_init_pubkey(keybits, n, n_size, e, e_size, pubkey);
}
int ota_rsa_verify(const ota_rsa_pubkey_t *pub_key, const unsigned char *dig, unsigned int dig_size,
const unsigned char *sig, unsigned int sig_size, ota_rsa_padding_t padding, bool *p_result)
{
return ali_rsa_verify(pub_key,dig,dig_size,sig,sig_size,padding,p_result);
}
#endif
static const unsigned char base64_dec_map[128] =
{
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 127, 127, 127, 127, 127
};
int ota_base64_decode(const unsigned char *src, int slen, unsigned char *dst, int *dlen)
{
unsigned int i, n;
unsigned int j, x;
unsigned char *p;
for( i = n = j = 0; i < slen; i++ )
{
if( ( slen - i ) >= 2 &&
src[i] == '\r' && src[i + 1] == '\n' )
continue;
if( src[i] == '\n' )
continue;
if( src[i] == '=' && ++j > 2 )
return -1;
if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
return -1;
if( base64_dec_map[src[i]] < 64 && j != 0 )
return -1;
n++;
}
if( n == 0 )
return 0;
n = ( ( n * 6 ) + 7 ) >> 3;
n -= j;
if( dst == 0 || *dlen < n )
{
*dlen = n;
return -2;
}
for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
{
if( *src == '\r' || *src == '\n' )
continue;
j -= ( base64_dec_map[*src] == 64 );
x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
if( ++n == 4 )
{
n = 0;
if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
if( j > 2 ) *p++ = (unsigned char)( x );
}
}
*dlen = p - dst;
return 0;
}
/*CRC16*/
static unsigned short update_crc16(unsigned short crcIn, unsigned char byte)
{
unsigned int crc = crcIn;
unsigned int in = byte | 0x100;
do {
crc <<= 1;
in <<= 1;
if (in & 0x100) {
++crc;
}
if (crc & 0x10000) {
crc ^= 0x1021;
}
} while (!(in & 0x10000));
return crc & 0xffffu;
}
void ota_crc16_init(ota_crc16_ctx *inCtx)
{
inCtx->crc = 0;
}
void ota_crc16_update(ota_crc16_ctx *inCtx, const void *inSrc, unsigned int inLen)
{
const unsigned char *src = (const unsigned char *) inSrc;
const unsigned char *srcEnd = src + inLen;
while ( src < srcEnd ) {
inCtx->crc = update_crc16(inCtx->crc, *src++);
}
}
void ota_crc16_final(ota_crc16_ctx *inCtx, unsigned short *outResult )
{
inCtx->crc = update_crc16(inCtx->crc, 0);
inCtx->crc = update_crc16(inCtx->crc, 0);
*outResult = inCtx->crc & 0xffffu;
}
/*MQTT API*/
int ota_hal_mqtt_publish(char *topic, int qos, void *data, int len)
{
#if (OTA_SIGNAL_CHANNEL) == 1
return IOT_MQTT_Publish_Simple(NULL, topic, qos, data, len);
#else
return 0;
#endif
}
int ota_hal_mqtt_subscribe(char *topic, void *cb, void *ctx)
{
#if (OTA_SIGNAL_CHANNEL) == 1
#ifdef MQTT_AUTO_SUBSCRIBE
return IOT_MQTT_Subscribe_Sync(NULL, topic, IOTX_MQTT_QOS3_SUB_LOCAL, cb, ctx, 1000);
#else
return IOT_MQTT_Subscribe_Sync(NULL, topic, IOTX_MQTT_QOS0, cb, ctx, 1000);
#endif
#else
return 0;
#endif
}
int ota_hal_mqtt_deinit(void)
{
#if (OTA_SIGNAL_CHANNEL) == 1
return IOT_MQTT_Destroy(NULL);
#else
return 0;
#endif
}
int ota_hal_mqtt_init(void)
{
#if (OTA_SIGNAL_CHANNEL) == 1
return (IOT_MQTT_Construct(NULL) == NULL)? -1 : 0;
#else
return 0;
#endif
}
/*CoAP API*/
int ota_coap_send(void *p_context, char *p_path, void *p_message)
{
#if (OTA_SIGNAL_CHANNEL) == 2
return IOT_CoAP_SendMessage(p_context, p_path, p_message);
#else
return 0;
#endif
}
int ota_coap_parse_block(void *p_message, int type, int *num, int *more, int *size)
{
#if (OTA_SIGNAL_CHANNEL) == 2
return IOT_CoAP_ParseOption_block(p_message, type, num, more, size);
#else
return 0;
#endif
}
int ota_coap_send_block(void *p_context, char *p_path, void *p_message, int block_type, int num, int more, int size)
{
#if (OTA_SIGNAL_CHANNEL) == 2
return IOT_CoAP_SendMessage_block(p_context, p_path, p_message, block_type,num, more, size);
#else
return 0;
#endif
}
int ota_coap_get_payload(void *p_message, const char **pp_payload, int *p_len)
{
#if (OTA_SIGNAL_CHANNEL) == 2
return IOT_CoAP_GetMessagePayload(p_message, pp_payload, p_len);
#else
return 0;
#endif
}
int ota_coap_get_code(void *p_message, void *p_resp_code)
{
#if (OTA_SIGNAL_CHANNEL) == 2
return IOT_CoAP_GetMessageCode(p_message, p_resp_code);
#else
return 0;
#endif
}
int ota_coap_init(void)
{
#if (OTA_SIGNAL_CHANNEL) == 2
#define COAP_ONLINE_DTLS_SERVER_URL "coaps://%s.iot-as-coap.cn-shanghai.aliyuncs.com:5684"
int ret = 0;
iotx_coap_config_t config;
iotx_device_info_t dev;
memset(&config, 0, sizeof(config));
memset(&dev, 0, sizeof(dev));
strncpy(dev.device_id, get_ota_service()->ps, sizeof(dev.device_id)-1);
strncpy(dev.product_key, get_ota_service()->pk, sizeof(dev.product_key)-1);
strncpy(dev.device_name, get_ota_service()->dn, sizeof(dev.device_name)-1);
strncpy(dev.device_secret, get_ota_service()->ds, sizeof(dev.device_secret)-1);
config.p_devinfo = &dev;
char url[256] = { 0 };
ota_snprintf(url, sizeof(url), COAP_ONLINE_DTLS_SERVER_URL,get_ota_service()->pk);
config.p_url = url;
get_ota_service()->h_ch = (void *)ota_IOT_CoAP_Init(&config);
if (get_ota_service()->h_ch) {
ret = ota_IOT_CoAP_DeviceNameAuth(get_ota_service()->h_ch);
if (ret < 0) {
OTA_LOG_E("COAP error");
return ret;
}
}
#else
return 0;
#endif
}
int ota_coap_deinit(void)
{
#if (OTA_SIGNAL_CHANNEL) == 2
IOT_CoAP_Deinit(get_ota_service()->h_ch);
#endif
return 0;
}

View file

@ -0,0 +1,173 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef OTA_PLATFORM_OS_H_
#define OTA_PLATFORM_OS_H_
#include "ota_service.h"
#define OTA_SSL_TIMEOUT 5000
#define ota_snprintf snprintf
#ifndef false
#define false 0
#endif
#ifndef true
#define true 1
#endif
#ifndef bool
#define bool char
#endif
#ifndef NULL
#define NULL 0
#endif
#define OTA_IMAGE_MD5_LEN (16)
#define OTA_IMAGE_RESERVER_SIZE (2)
typedef struct
{
unsigned int image_magic;
unsigned int image_size;
unsigned char image_md5_value[OTA_IMAGE_MD5_LEN];
unsigned char image_reserver[OTA_IMAGE_RESERVER_SIZE];
unsigned short image_crc16;
} ota_image_t;
/*memory*/
void *ota_malloc(int size);
void *ota_realloc(void *ptr, int size);
void *ota_calloc(int n, int size);
void ota_free(void *ptr);
/*Semaphore*/
void *ota_semaphore_create(void);
int ota_semaphore_wait(void *sem, int ms);
void ota_semaphore_post(void *sem);
void ota_semaphore_destroy(void *sem);
/*Thread*/
int ota_thread_create(
void **thread_handle,
void *(*work_routine)(void *),
void *arg,
void *param,
int stack_size);
void ota_thread_exit(void *thread);
void ota_msleep(int ms);
/*KV store*/
int ota_kv_set(const char *key, const void *val, int len, int sync);
int ota_kv_get(const char *key, void *buffer, int *len);
/*Reboot*/
void ota_reboot(void);
/*Socket API*/
void* ota_socket_connect(char *host, int port);
int ota_socket_send(void* fd, char *buf, int len);
int ota_socket_recv(void* fd, char *buf, int len);
void ota_socket_close(void* fd);
/*SSL*/
void* ota_ssl_connect(const char *host, unsigned short port, const char *ca, int len);
int ota_ssl_send(void* ssl, char *buf, int len);
int ota_ssl_recv(void* ssl, char *buf, int len);
/*Verify API*/
typedef struct
{
unsigned int total[2];
unsigned int state[4];
unsigned char buffer[64];
}ota_md5_context;
typedef struct {
unsigned int total[2];
unsigned int state[8];
unsigned char buffer[64];
int is224;
}ota_sha256_context;
/*SHA256*/
void ota_sha256_free(ota_sha256_context *ctx);
void ota_sha256_init(ota_sha256_context *ctx);
void ota_sha256_starts(ota_sha256_context *ctx, int is224);
void ota_sha256_update(ota_sha256_context *ctx, const unsigned char *input, unsigned int ilen);
void ota_sha256_finish(ota_sha256_context *ctx, unsigned char output[32]);
/*MD5*/
void ota_md5_free(ota_md5_context *ctx);
void ota_md5_init(ota_md5_context *ctx);
void ota_md5_starts(ota_md5_context *ctx);
void ota_md5_update(ota_md5_context *ctx, const unsigned char *input, unsigned int ilen);
void ota_md5_finish(ota_md5_context *ctx, unsigned char output[16]);
/*CRC16*/
typedef struct {
unsigned short crc;
} ota_crc16_ctx;
void ota_crc16_init(ota_crc16_ctx *ctx);
void ota_crc16_update(ota_crc16_ctx *ctx, const void *inSrc, unsigned int inLen);
void ota_crc16_final(ota_crc16_ctx *ctx, unsigned short *outResult);
/*Base64*/
int ota_base64_decode(const unsigned char *input, int input_len, unsigned char *output, int *output_len);
/*RSA*/
#define HASH_NONE OTA_HASH_NONE
#define SHA256 OTA_SHA256
#define MD5 OTA_MD5
#define RSASSA_PKCS1_V1_5 OTA_RSASSA_PKCS1_V1_5
typedef enum {
HASH_NONE = 0,
SHA256 = 3,
MD5 = 6,
} OTA_HASH_E;
typedef enum {
RSASSA_PKCS1_V1_5 = 20,
} ota_rsa_pad_type_t;
typedef struct{
ota_rsa_pad_type_t type;
union {
struct {
OTA_HASH_E type;
} rsaes_oaep;
struct {
OTA_HASH_E type;
} rsassa_v1_5;
struct {
OTA_HASH_E type;
unsigned int salt_len;
} rsassa_pss;
} pad;
} ota_rsa_padding_t;
#define TEE_MIN_RSA_KEY_SIZE (256)
#define TEE_MAX_RSA_KEY_SIZE (2048)
typedef struct{
unsigned int magic;
unsigned int n_size;
unsigned int e_size;
unsigned char n[(TEE_MAX_RSA_KEY_SIZE >> 3)];
unsigned char e[(TEE_MAX_RSA_KEY_SIZE >> 3)];
} ota_rsa_pubkey_t;
int ota_rsa_get_pubkey_size(unsigned int keybits, unsigned int *size);
int ota_rsa_init_pubkey(unsigned int keybits, const unsigned char *n, unsigned int n_size,
const unsigned char *e, unsigned int e_size, ota_rsa_pubkey_t *pubkey);
/*MQTT*/
int ota_hal_mqtt_publish(char *topic, int qos, void *data, int len);
int ota_hal_mqtt_subscribe(char *topic, void* cb, void *ctx);
int ota_hal_mqtt_deinit(void);
int ota_hal_mqtt_init(void);
/*COAP*/
int ota_coap_send(void *p_context, char *p_path, void *p_message);
int ota_coap_send_block(void *p_context, char *p_path, void *p_message,
int block_type, int num, int more, int size);
int ota_coap_parse_block(void *p_message, int type, int *num,int *more, int *size);
int ota_coap_get_payload(void *p_message, const char **pp_payload, int *p_len);
int ota_coap_get_code(void *p_message, void *p_resp_code);
int ota_coap_init(void);
int ota_coap_deinit(void);
#endif

View file

@ -0,0 +1,362 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "aos/kernel.h"
#include "aos/kv.h"
#include "hal/soc/flash.h"
#include "ota_hal_plat.h"
#include "ota_hal_os.h"
#include "ota_log.h"
#if defined (AOS_OTA_RECOVERY_TYPE)
#include "rec_define.h"
#endif
#if defined (BOARD_ESP8266)
#include "esp_system.h"
#include "upgrade.h"
#include "esp_wifi.h"
#elif defined (STM32L496xx)
#define OTA_CACHE_SIZE 2048
uint8_t *ota_cache = NULL;
uint8_t *ota_cache_actual = NULL;
uint32_t ota_cache_len = 0;
uint32_t ota_fw_size = 0;
uint32_t ota_receive_total_len = 0;
#endif
#define OTA_CRC16 "ota_file_crc16"
static int boot_part = HAL_PARTITION_OTA_TEMP;
static unsigned int _offset = 0;
static ota_crc16_ctx ctx = {0};
#if defined (SUPPORT_MCU_OTA)
char cur_ota_ver[OTA_MAX_VER_LEN] = {0};
#endif
unsigned short ota_get_crc16(void)
{
int len = 2;
unsigned short crc16=0;
aos_kv_get(OTA_CRC16, &crc16, &len);
return crc16;
}
void ota_set_crc16(unsigned short crc16)
{
aos_kv_set(OTA_CRC16, &crc16, 2, 1);
}
void ota_reboot_bank(void)
{
#if defined (BOARD_ESP8266)
wifi_set_sleep_type(NONE_SLEEP_T);
ota_msleep(300);
system_upgrade_init();
system_upgrade_flag_set(UPGRADE_FLAG_FINISH);
printf("---reboot_system---\n");
system_upgrade_reboot();
#elif defined (STM32L496xx) || defined (SV6266)
extern int flash_sw_bank(void);
flash_sw_bank();
#endif
}
static int ota_init(void *something)
{
int ret = 0;
ota_boot_param_t *param = (ota_boot_param_t *)something;
param->off_bp = 0;
hal_flash_dis_secure(0, 0, 0);
_offset = param->off_bp;
hal_logic_partition_t *part_info = hal_flash_get_info(boot_part);
if(part_info->partition_length < param->len || param->len == 0) {
ret = OTA_PARAM_FAIL;
return ret;
}
#if defined (STM32L496xx)
ota_fw_size = param->len;
ota_receive_total_len = _offset;
ota_cache = ota_malloc(OTA_CACHE_SIZE + 8);
if (ota_cache != NULL) {
/*Align with 8 bytes*/
ota_cache_actual = (uint8_t *)((uint32_t)ota_cache & ~0x7);
}
else {
ret = OTA_INIT_FAIL;
return ret;
}
#endif
if(param->off_bp == 0) {
int ret = 0;
ret = hal_flash_erase(boot_part, _offset, part_info->partition_length);
if(ret != 0) {
ret = OTA_INIT_FAIL;
return ret;
}
ota_crc16_init(&ctx);
}
else {
ctx.crc=ota_get_crc16();
}
OTA_LOG_I("ota init off:0x%08x part:%d len:%d crc:0x%04x\n",param->off_bp,boot_part,param->len,ctx.crc);
return ret;
}
static int ota_write(int* off, char* in_buf ,int in_buf_len)
{
int ret = 0;
#if defined (STM32L496xx)
uint32_t tocopy = 0;
if(in_buf_len > OTA_CACHE_SIZE) {
ret = OTA_UPGRADE_FAIL;
return ret;
}
ota_crc16_update(&ctx, in_buf, in_buf_len);
if (in_buf_len <= OTA_CACHE_SIZE - ota_cache_len) {
tocopy = in_buf_len;
}
else {
tocopy = OTA_CACHE_SIZE - ota_cache_len;
}
/*Start from last byte of remaing data*/
memcpy(ota_cache_actual + ota_cache_len, in_buf, tocopy);
ota_cache_len += tocopy;
if (ota_cache_len == OTA_CACHE_SIZE) {
ret = hal_flash_write(HAL_PARTITION_OTA_TEMP, &_offset, ota_cache_actual, OTA_CACHE_SIZE);
}
/*keep remaining data*/
if (in_buf_len - tocopy > 0) {
/*Now ota_cache only contains remaing data*/
memcpy(ota_cache_actual, in_buf + tocopy, in_buf_len - tocopy);
ota_cache_len = in_buf_len - tocopy;
}
ota_receive_total_len += in_buf_len;
if(ota_receive_total_len == ota_fw_size) {
if (ota_cache_len != 0) {
int ret = hal_flash_write(HAL_PARTITION_OTA_TEMP, &_offset, ota_cache_actual, ota_cache_len);
ota_free(ota_cache);
}
}
#else
ota_crc16_update(&ctx, in_buf, in_buf_len);
ret = hal_flash_write(boot_part, (uint32_t*)&_offset, in_buf, in_buf_len);
#endif
return ret;
}
static int ota_read(int* off, char* out_buf, int out_buf_len)
{
return hal_flash_read(boot_part, (uint32_t*)off, out_buf, out_buf_len);
}
static int ota_boot(void *something)
{
int ret = 0;
ota_boot_param_t *param = (ota_boot_param_t *)something;
if (param == NULL) {
ret = OTA_REBOOT_FAIL;
return ret;
}
if (param->res_type == OTA_FINISH) {
ota_crc16_final(&ctx, &param->crc);
if (param->upg_flag == OTA_DIFF) {
#if defined (AOS_OTA_RECOVERY_TYPE)
int offset = 0x00;
int param_part = HAL_PARTITION_PARAMETER_1;
PatchStatus ota_param,ota_param_r;
memset(&ota_param, 0, sizeof(PatchStatus));
ota_param.dst_adr = HAL_PARTITION_APPLICATION;
ota_param.src_adr = HAL_PARTITION_OTA_TEMP;
ota_param.len = 0;
ota_param.crc = param->crc;
ota_param.splict_size = param->splict_size;
ota_param.rec_size = param->rec_size;
ota_param.diff = 1;
ota_param.upg_flag = REC_RECOVERY_FLAG;
ota_crc16_ctx ctx1;
unsigned short crc;
ota_crc16_init(&ctx1);
ota_crc16_update(&ctx1, &ota_param, sizeof(PatchStatus) - sizeof(unsigned short));
ota_crc16_final(&ctx1, &crc);
ota_param.patch_crc = crc;
offset = 0x00;
hal_flash_erase(param_part, offset, sizeof(PatchStatus));
offset = 0x00;
hal_flash_write(param_part, (uint32_t*)&offset, &ota_param, sizeof(PatchStatus));
offset = 0x00;
memset(&ota_param_r, 0, sizeof(PatchStatus));
hal_flash_read(param_part, (uint32_t*)&offset, &ota_param_r, sizeof(PatchStatus));
if(memcmp(&ota_param, &ota_param_r, sizeof(PatchStatus)) != 0) {
ret = OTA_REBOOT_FAIL;
return ret;
}
OTA_LOG_I("diff dst:0x%08x src:0x%08x len:0x%08x, crc:0x%04x pcrc:0x%04x splict:%d.\r\n",
ota_param_r.dst_adr,ota_param_r.src_adr, ota_param_r.rec_size, ota_param_r.crc,
ota_param_r.patch_crc, ota_param_r.splict_size);
#endif
}
else {
#if defined AOS_OTA_BANK_DUAL
int offset = 0x00;
ota_crc16_ctx tmp_ctx;
unsigned short crc;
int param_part = HAL_PARTITION_PARAMETER_1;
param->src_adr = 0x00;
param->dst_adr = 0x00;
#if defined (AOS_OTA_RECOVERY_TYPE)
param->upg_flag = REC_DUAL_UPDATE_FLAG;
#else
param->upg_flag = 0x00;
#endif
ota_crc16_init(&tmp_ctx);
ota_crc16_update(&tmp_ctx, param, sizeof(ota_boot_param_t) - sizeof(unsigned short));
ota_crc16_final(&tmp_ctx, &crc);
param->param_crc = crc;
ota_boot_param_t param_r;
offset = 0x00;
hal_flash_erase(param_part, offset, sizeof(ota_boot_param_t));
offset = 0x00;
hal_flash_write(param_part, (uint32_t*)&offset, param, sizeof(ota_boot_param_t));
offset = 0x00;
memset(&param_r, 0, sizeof(ota_boot_param_t));
hal_flash_read(param_part, (uint32_t*)&offset, &param_r, sizeof(ota_boot_param_t));
if(memcmp(param, &param_r, sizeof(ota_boot_param_t)) != 0) {
return -1;
}
OTA_LOG_I("OTA finish dst:0x%08x src:0x%08x len:0x%08x, crc:0x%04x.\r\n", param_r.dst_adr, param_r.src_adr, param_r.len, param_r.crc);
ota_reboot_bank();
#else
#ifndef SV6266
int offset = 0x00;
ota_crc16_ctx ctx1;
unsigned short crc;
int param_part = HAL_PARTITION_PARAMETER_1;
#if !defined (RDA5981x) && !defined (RDA5981A)
extern int app_download_addr;
extern int kernel_download_addr;
#endif
hal_logic_partition_t *part_info = hal_flash_get_info(boot_part);
#ifndef AOS_OTA_2BOOT_UPDATE_SUPPORT
#if !defined (RDA5981x) && !defined (RDA5981A)
param->src_adr = part_info->partition_start_addr;
param->dst_adr = (param->upg_flag == OTA_APP)? (int)&app_download_addr : (int)&kernel_download_addr;
#endif
#else
param->src_adr = 0;
param->dst_adr = 0;
param->len = 0;
param->upg_flag = REC_SWAP_UPDATE_FLAG;
#endif
ota_crc16_init(&ctx1);
ota_crc16_update(&ctx1, param, sizeof(ota_boot_param_t) - sizeof(unsigned short));
ota_crc16_final(&ctx1, &crc);
param->param_crc = crc;
ota_boot_param_t param_r;
offset = 0x00;
hal_flash_erase(param_part, offset, sizeof(ota_boot_param_t)); //PARTITION_BACKUP_PARAM
offset = 0x00;
hal_flash_write(param_part, (uint32_t*)&offset, param, sizeof(ota_boot_param_t));
offset = 0x00;
memset(&param_r, 0, sizeof(ota_boot_param_t));
hal_flash_read(param_part, (uint32_t*)&offset, &param_r, sizeof(ota_boot_param_t));
if(memcmp(param, &param_r, sizeof(ota_boot_param_t)) != 0) {
ret = OTA_REBOOT_FAIL;
return ret;
}
OTA_LOG_I("OTA finish dst:0x%08x src:0x%08x len:0x%08x, crc:0x%04x.\r\n", param_r.dst_adr, param_r.src_adr, param_r.len, param_r.crc);
#else
ota_reboot_bank();
OTA_LOG_I("OTA finish, boot para self defined!");
#endif
#endif
}
ota_msleep(1500);
ota_reboot();
}
else if(param->res_type == OTA_BREAKPOINT) {
OTA_LOG_I("save bp crc:0x%04x", ctx.crc);
#if defined (STM32L496xx)
if (ota_cache_len != 0) {
int ret = hal_flash_write(HAL_PARTITION_OTA_TEMP, &_offset, ota_cache_actual, ota_cache_len);
ota_free(ota_cache);
}
#endif
ota_set_crc16(ctx.crc);
}
return ret;
}
static int ota_rollback(void *something)
{
int offset = 0x00;
int param_part = HAL_PARTITION_PARAMETER_1;
ota_boot_param_t param_w, param_r;
memset(&param_w, 0, sizeof(ota_boot_param_t));
hal_flash_read(param_part, (uint32_t*)&offset, &param_w, sizeof(ota_boot_param_t));
if((param_w.boot_count != 0) && (param_w.boot_count != 0xff)) {
ota_crc16_ctx ctx1;
unsigned short crc;
param_w.upg_flag = 0;
param_w.boot_count = 0; /*Clear bootcount to avoid rollback*/
ota_crc16_init(&ctx1);
ota_crc16_update(&ctx1, &param_w, sizeof(ota_boot_param_t) - sizeof(unsigned short));
ota_crc16_final(&ctx1, &crc);
param_w.param_crc = crc;
offset = 0x00;
hal_flash_erase(param_part, offset, sizeof(ota_boot_param_t));
offset = 0x00;
hal_flash_write(param_part, (uint32_t*)&offset, &param_w, sizeof(ota_boot_param_t));
offset = 0x00;
memset(&param_r, 0, sizeof(ota_boot_param_t));
hal_flash_read(param_part, (uint32_t*)&offset, &param_r, sizeof(ota_boot_param_t));
if(memcmp(&param_w, &param_r, sizeof(ota_boot_param_t)) != 0) {
OTA_LOG_E("rollback failed\n");
return -1;
}
}
return 0;
}
const char *aos_get_app_version(void);
static const char *ota_get_version(unsigned char dev_type)
{
if(dev_type) {
return "v1.0.0-20180101-1000";//SYSINFO_APP_VERSION;
} else {
#if defined (SUPPORT_MCU_OTA)
char mcu_ver[16] = {0};
int len = sizeof(mcu_ver);
aos_kv_get("mcu_version", mcu_ver, &len);
if (0 == strlen(mcu_ver)) {
strcpy((char *)mcu_ver, "mcu-1.0.0");
OTA_LOG_I("use default MCU version:%s", mcu_ver);
}
memset(cur_ota_ver, 0, OTA_MAX_VER_LEN);
snprintf(cur_ota_ver, OTA_MAX_VER_LEN, "%s-%s", mcu_ver, aos_get_app_version());
OTA_LOG_I("current ota version:%s", cur_ota_ver);
return (const char *)cur_ota_ver;
#else
return aos_get_app_version();
#endif
}
}
ota_hal_module_t ota_hal_module = {
.init = ota_init,
.write = ota_write,
.read = ota_read,
.boot = ota_boot,
.rollback = ota_rollback,
.version = ota_get_version,
};

View file

@ -0,0 +1,120 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef HAL_OTA_H
#define HAL_OTA_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
OTA_RAW = 0,
OTA_DIFF = 1,
OTA_KERNEL = 2,
OTA_APP = 4,
} OTA_UPD_TYPE_E;
typedef enum {
OTA_FINISH,
OTA_BREAKPOINT
} OTA_RES_TYPE_E;
typedef struct {
unsigned int dst_adr;
unsigned int src_adr;
unsigned int len;
unsigned short crc;
unsigned int upg_flag;
unsigned char boot_count;
unsigned int splict_size;
int off_bp; /*Break point offset*/
OTA_RES_TYPE_E res_type; /*result type: OTA_FINISH, OTA_BREAKPOINT*/
unsigned short param_crc; /*Parameter crc*/
} __attribute__((packed)) ota_boot_param_t;
typedef struct ota_hal_module_s {
int (*init)(void *something);
int (*write)(int *off_set, char *in_buf , int in_buf_len);
int (*read)(int *off_set, char *out_buf , int out_buf_len);
int (*boot)(void *something);
int (*rollback)(void *something);
const char *(*version)(unsigned char dev_type);
}ota_hal_module_t;
/**
* Arch register a new module before HAL startup
*/
void ota_hal_register_module(ota_hal_module_t *module);
/**
* init ota partition
*
* @note when ota start, maybe it need init something
* @param something extra info for ota init
*
* @return 0 : On success, 1 : If an error occurred with any step
*/
int ota_hal_init(void *something);
/**
* Write data to an area on ota partition
*
* @param off_set Point to the start address that the data is written to, and
* point to the last unwritten address after this function is
* returned, so you can call this function serval times without
* update this start address.
* @param inbuf point to the data buffer that will be written to flash
* @param in_buf_len The length of the buffer
*
* @return 0 : On success, 1 : If an error occurred with any step
*/
int ota_hal_write(int *off_set,char *in_buf , int in_buf_len);
/**
* Read data from an area on ota Flash to data buffer in RAM
*
* @param off_set Point to the start address that the data is read, and
* point to the last unread address after this function is
* returned, so you can call this function serval times without
* update this start address.
* @param out_buf Point to the data buffer that stores the data read from flash
* @param out_buf_len The length of the buffer
*
* @return 0 : On success, 1 : If an error occurred with any step
*/
int ota_hal_read(int *off_set,char *out_buf, int out_buf_len);
/**
* Set boot options when ota reboot
*
* @param something boot parms
*
* @return kNoErr : On success. kGeneralErr : If an error occurred with any step
*/
int ota_hal_boot(void *something);
/**
* Set rollback when failed to boot
*
* @param something
*
* @return kNoErr : On success. kGeneralErr : If an error occurred with any step
*/
int ota_hal_rollback(void *something);
/**
* get system version
*
* @param device type
*
* @return version
*/
const char *ota_hal_get_version(unsigned char dev_type);
#ifdef __cplusplus
}
#endif
#endif /* HAL_OTA_H */

View file

@ -0,0 +1,41 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _OTA_LOG_H_
#define _OTA_LOG_H_
#include <stdarg.h>
#include <stdio.h>
#if defined(OTA_ALIOS)
#include "aos/log.h"
#if defined(LOG_SIMPLE)
#define OTA_LOG_D(fmt, ...) LOGD("uota","file %s, line %d", __FILE__, __LINE__)
#define OTA_LOG_I(fmt, ...) LOGE("uota",fmt,##__VA_ARGS__)
#define OTA_LOG_W(fmt, ...) LOGW("uota","file %s, line %d", __FILE__, __LINE__)
#define OTA_LOG_E(fmt, ...) LOGE("uota",fmt,##__VA_ARGS__)
#else
#define OTA_LOG_D(fmt, ...) LOGD("uota",fmt,##__VA_ARGS__)
#define OTA_LOG_I(fmt, ...) LOGI("uota",fmt,##__VA_ARGS__)
#define OTA_LOG_W(fmt, ...) LOGW("uota",fmt,##__VA_ARGS__)
#define OTA_LOG_E(fmt, ...) LOGE("uota",fmt,##__VA_ARGS__)
#endif
#elif defined(CSP_LINUXHOST)
#define OTA_LOG_D(fmt, ...) printf("[%s:%d]"fmt"\r\n" ,__FUNCTION__,__LINE__,##__VA_ARGS__)
#define OTA_LOG_I(fmt, ...) printf("[%s:%d]"fmt"\r\n" ,__FUNCTION__,__LINE__,##__VA_ARGS__)
#define OTA_LOG_W(fmt, ...) printf("[%s:%d]"fmt"\r\n" ,__FUNCTION__,__LINE__,##__VA_ARGS__)
#define OTA_LOG_E(fmt, ...) printf("[%s:%d]"fmt"\r\n" ,__FUNCTION__,__LINE__,##__VA_ARGS__)
#elif defined(OTA_WITH_LINKKIT)
#include "iotx_log.h"
#define OTA_LOG_D(...) log_debug("uota", __VA_ARGS__)
#define OTA_LOG_I(...) log_info("uota", __VA_ARGS__)
#define OTA_LOG_W(...) log_warning("uota", __VA_ARGS__)
#define OTA_LOG_E(...) log_err("uota", __VA_ARGS__)
#else
#define OTA_LOG_D(fmt, ...) printf("[%s:%d]"fmt"\r\n" ,__FUNCTION__,__LINE__,##__VA_ARGS__)
#define OTA_LOG_I(fmt, ...) printf("[%s:%d]"fmt"\r\n" ,__FUNCTION__,__LINE__,##__VA_ARGS__)
#define OTA_LOG_W(fmt, ...) printf("[%s:%d]"fmt"\r\n" ,__FUNCTION__,__LINE__,##__VA_ARGS__)
#define OTA_LOG_E(fmt, ...) printf("[%s:%d]"fmt"\r\n" ,__FUNCTION__,__LINE__,##__VA_ARGS__)
#endif
#endif // _OTA_LOG_H_

View file

@ -0,0 +1,156 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef OTA_SERVICE_H_
#define OTA_SERVICE_H_
#define UOTA_VERSION "1.0.0"
#define OTA_MAX_VER_LEN (64)
#define OTA_MSG_REPORT_LEN (256)
#define OTA_MSG_INFORM_LEN (128)
#define OTA_MSG_LEN_MAX (2048)
#define OTA_COAP_URI_MAX_LEN (135)
#define OTA_MQTT_TOPIC_LEN (136)
#define OTA_URL_LEN (512)
#define OTA_RESP_MAX_LEN (OTA_URL_LEN + 512)
#define OTA_SIGN_LEN 256
#define OTA_HASH_LEN 66
typedef enum{
OTA_PROTCOL_MQTT=0,
OTA_PROTCOL_COAP,
OTA_PROTCOL_HTTP,
OTA_PROTCOL_HTTPS,
OTA_PROTCOL_COAP_LOCAL,
}OTA_PROTCOL_E;
typedef enum {
OTA_PARAM_FAIL = -17,
OTA_PARSE_FAIL = -16,
OTA_REBOOT_FAIL = -15,
OTA_UPGRADE_DIFF_FAIL = -14,
OTA_UPGRADE_FAIL = -13,
OTA_VERIFY_RSA_FAIL = -12,
OTA_VERIFY_HASH_FAIL = -11,
OTA_VERIFY_FAIL = -10,
OTA_DOWNLOAD_WRITE_FAIL = -9,
OTA_DOWNLOAD_READ_FAIL = -8,
OTA_DOWNLOAD_CON_FAIL = -7,
OTA_DOWNLOAD_IP_FAIL = -6,
OTA_DOWNLOAD_URL_FAIL = -5,
OTA_DOWNLOAD_FAIL = -4,
OTA_TRANSPORT_FAIL = -3,
OTA_INIT_VER_FAIL = -2,
OTA_INIT_FAIL = -1,
OTA_INIT = 0,
OTA_CANCEL = 1,
OTA_TRANSPORT = 2,
OTA_DOWNLOAD = 3,
OTA_VERIFY = 4,
OTA_UPGRADE = 5,
OTA_REBOOT = 6,
OTA_MAX
} OTA_STATUS_E;
typedef enum
{
COAP_CONTENT_TYPE_JSON,
COAP_CONTENT_TYPE_CBOR,
}coap_content_type_e;
typedef enum
{
COAP_MESSAGE_CON = 0, /* confirmable message */
COAP_MESSAGE_NON = 1, /* non-confirmable message */
}coap_msg_type_e;
typedef void (*coap_cb_t)(void *p_arg, void *p_message);
typedef struct
{
unsigned char *p_payload;
unsigned short payload_len;
coap_content_type_e content_type;
coap_msg_type_e msg_type;
void *user_data;
coap_cb_t resp_callback;
}ota_coap_message_t;
typedef struct {
unsigned short packet_id;
unsigned char qos;
unsigned char dup;
unsigned char retain;
unsigned short topic_len;
unsigned int payload_len;
const char *ptopic;
const char *payload;
} ota_mqtt_topic_t;
typedef enum {
OTA_MQTT_EVENT_SUB_SUCCESS = 3,
OTA_MQTT_EVENT_PUB_RECEIVED = 12,
OTA_MQTT_EVENT_BUF_OVERFLOW = 13,
} ota_mqtt_event_t;
typedef struct {
ota_mqtt_event_t event;
ota_mqtt_topic_t *topic;
} ota_mqtt_msg_t;
typedef void (*ota_cloud_cb_t)(void* ctx, char *json);
typedef struct
{
int (*init)(void);
int (*inform)(void* ctx);
int (*upgrade)(void* ctx);
int (*request)(void* pctx);
int (*status)(int per, void* ctx);
int (*deinit)(void);
} ota_transport_t;
typedef struct {
int (*start)(void *ctx); /*start download*/
int (*stop)(void); /*stop download*/
}ota_download_t;
typedef struct {
unsigned char inited; /*If is inted*/
char pk[20+1];/*Product Key*/
char ps[64+1];/*Product secret*/
char dn[32+1];/*Device name*/
char ds[64+1];/*Device secret*/
OTA_PROTCOL_E trans_protcol; /*default:0--> MQTT 1-->COAP 4-->COAP_LOCAL*/
OTA_PROTCOL_E dl_protcol; /*default:3--> HTTPS 1-->COAP 2-->HTTP*/
char ota_ver[OTA_MAX_VER_LEN]; /*OTA FW version*/
char sys_ver[OTA_MAX_VER_LEN]; /*OTA System version*/
unsigned char dev_type; /*device type: 0-->main dev 1-->sub dev*/
unsigned char hash_type; /*Hash algor type*/
unsigned char sign_en; /*Sign is on/off*/
int sign_len; /*Sign len*/
unsigned char sign_type; /*default:0--> sha256 1--> md5 2-->RSA*/
int upg_status; /*Upgrade status in progress*/
char* url; /*Dowdload URL*/
char* hash; /*Dowdload hash*/
unsigned char* sign; /*Dowdload signatue*/
ota_transport_t *h_tr; /*OTA tansport manager*/
ota_download_t *h_dl; /*OTA download manager*/
void* h_ch; /*OTA channel handle:mqtt,coap*/
int (*upgrade_cb)(void* ctx, char *json); /*upgrade callback*/
void* boot_param; /*Boot parameter*/
unsigned char upg_mcu_flag; /*upgrade mcu flag: 0-->upgrade app, 1-->upgrade mcu*/
} ota_service_t;
/*OTA export APIs*/
int ota_service_init(ota_service_t* ctx);
int ota_service_deinit(ota_service_t* ctx);
int ota_service_inform(ota_service_t *ctx);
/*OTA intenal APIs*/
ota_transport_t *ota_get_transport(void);
ota_download_t *ota_get_download(void);
int ota_hex_str2buf(const char* src, char* dest, unsigned int dest_len);
#endif /* OTA_SERVICE_H_ */

View file

@ -0,0 +1,676 @@
/*
*Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <string.h>
#include <cJSON.h>
#include "ota_service.h"
#include "ota_hal_os.h"
#include "ota_verify.h"
#include "ota_hal_plat.h"
#include "ota_log.h"
#include "iot_export.h"
#if (defined SUPPORT_MCU_OTA)
#include "aos/kv.h"
#include "ota_hal_mcu.h"
#endif
#if (defined BOARD_ESP8266)
#include "k_api.h"
#endif
extern ota_hal_module_t ota_hal_module;
static unsigned char ota_is_on_going = 0;
void ota_on_going_reset()
{
ota_is_on_going = 0;
}
unsigned char ota_get_on_going_status()
{
return ota_is_on_going;
}
void ota_set_status_on_going()
{
ota_is_on_going = 1;
}
const char *ota_to_capital(char *value, int len)
{
if (value == NULL || len <= 0) {
return NULL;
}
int i = 0;
for (; i < len; i++) {
if (*(value + i) >= 'a' && *(value + i) <= 'z') {
*(value + i) -= 'a' - 'A';
}
}
return value;
}
int ota_hex_str2buf(const char* src, char* dest, unsigned int dest_len)
{
int i, n = 0;
if(src == NULL || dest == NULL) {
return -1;
}
if(dest_len < strlen(src) / 2) {
return -1;
}
for(i = 0; src[i]; i += 2) {
if(src[i] >= 'A' && src[i] <= 'F')
dest[n] = src[i] - 'A' + 10;
else
dest[n] = src[i] - '0';
if(src[i + 1] >= 'A' && src[i + 1] <= 'F')
dest[n] = (dest[n] << 4) | (src[i + 1] - 'A' + 10);
else dest[n] = (dest[n] << 4) | (src[i + 1] - '0');
++n;
}
return n;
}
static int ota_parse(void* pctx, const char *json)
{
int ret = 0;
cJSON *root = NULL;
ota_service_t* ctx = pctx;
if(!ctx) {
ret = OTA_PARAM_FAIL;
goto parse_failed;
}
char *url = ctx->url;
char *hash = ctx->hash;
unsigned char *sign = ctx->sign;
ota_boot_param_t *ota_param = (ota_boot_param_t *)ctx->boot_param;
if(!url || !hash || !ota_param) {
ret = OTA_PARAM_FAIL;
goto parse_failed;
}
root = cJSON_Parse(json);
if (!root) {
ret = OTA_PARAM_FAIL;
goto parse_failed;
} else {
if(ctx->trans_protcol != OTA_PROTCOL_COAP_LOCAL) {
cJSON *message = cJSON_GetObjectItem(root, "message");
if (NULL == message) {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
if ((strncmp(message->valuestring, "success", strlen("success")))) {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
}
cJSON *json_obj = NULL;
if(ctx->trans_protcol != OTA_PROTCOL_COAP_LOCAL) {
json_obj = cJSON_GetObjectItem(root, "data");
}else {
json_obj = cJSON_GetObjectItem(root, "params");
}
if (!json_obj) {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
cJSON *resourceUrl = cJSON_GetObjectItem(json_obj, "url");
if (!resourceUrl) {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
cJSON *version = cJSON_GetObjectItem(json_obj, "version");
if (!version) {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
strncpy(ctx->ota_ver, version->valuestring, sizeof(ctx->ota_ver));
strncpy(url, resourceUrl->valuestring, OTA_URL_LEN - 1);
cJSON *signMethod = cJSON_GetObjectItem(json_obj, "signMethod");
if (signMethod) {
memset(hash, 0x00, OTA_HASH_LEN);
ota_to_capital(signMethod->valuestring, strlen(signMethod->valuestring));
if (0 == strncmp(signMethod->valuestring, "MD5", strlen("MD5"))) {
cJSON *md5 = cJSON_GetObjectItem(json_obj, "sign");
if (!md5) {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
ctx->hash_type = MD5;
strncpy(hash, md5->valuestring, strlen(md5->valuestring)+1);
hash[strlen(md5->valuestring)] = '\0';
ota_to_capital(hash, strlen(hash));
} else if (0 == strncmp(signMethod->valuestring, "SHA256", strlen("SHA256"))) {
cJSON *sha256 = cJSON_GetObjectItem(json_obj, "sign");
if (!sha256) {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
ctx->hash_type = SHA256;
strncpy(hash, sha256->valuestring, strlen(sha256->valuestring) + 1);
hash[strlen(sha256->valuestring)] = '\0';
ota_to_capital(hash, strlen(hash));
} else {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
} else { // old protocol
memset(hash, 0x00, OTA_HASH_LEN);
cJSON *md5 = cJSON_GetObjectItem(json_obj, "md5");
if (!md5) {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
ctx->hash_type = MD5;
strncpy(hash, md5->valuestring, strlen(md5->valuestring) + 1);
hash[strlen(md5->valuestring)] = '\0';
ota_to_capital(hash, strlen(hash));
}
cJSON *size = cJSON_GetObjectItem(json_obj, "size");
if (!size) {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
ota_param->len = size->valueint;
ota_param->upg_flag = OTA_RAW;
cJSON *diff = cJSON_GetObjectItem(json_obj, "isDiff");
if (diff) {
int is_diff = diff->valueint;
if (is_diff) {
ota_param->upg_flag = OTA_DIFF;
cJSON *splictSize = cJSON_GetObjectItem(json_obj, "splictSize");
if (splictSize) {
ota_param->splict_size = splictSize->valueint;
}
}
}
#ifdef DEV_OFFLINE_SECURE_OTA_ENABLE
bool isSecureOfflineOta = true;
#else
bool isSecureOfflineOta = false;
#endif
cJSON *digestSign = cJSON_GetObjectItem(json_obj, "digestsign");
if (digestSign) {
if((ctx->trans_protcol == OTA_PROTCOL_COAP_LOCAL)&&(isSecureOfflineOta == false)) {
/*1,only for offline normal ota*/
ctx->sign_en = OTA_SIGN_OFF;
} else {
/*1,online OTA; 2,offline secure ota*/
memset(sign, 0x00, OTA_SIGN_LEN);
ctx->sign_en = OTA_SIGN_ON;
ctx->sign_len = strlen(digestSign->valuestring);
if(ota_base64_decode((const unsigned char*)digestSign->valuestring, strlen(digestSign->valuestring),sign, &ctx->sign_len) != 0 ) {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
}
} else {
/*1,online OTA; 2,offline normal ota*/
ctx->sign_en = OTA_SIGN_OFF;
/*1,only for offline secure ota*/
if((ctx->trans_protcol == OTA_PROTCOL_COAP_LOCAL)&&(isSecureOfflineOta == true)) {
ret = OTA_PARSE_FAIL;
goto parse_failed;
}
}
}
goto parse_success;
parse_failed:
OTA_LOG_E("parse failed err:%d", ret);
if (root) {
cJSON_Delete(root);
}
return -1;
parse_success:
if (root) {
cJSON_Delete(root);
}
return ret;
}
#ifdef DEV_OFFLINE_OTA_ENABLE
static void notify_offline_ota_result(ota_service_t* ctx)
{
int offline_ota_resp_code = DEV_OFFLINE_OTA_RSP_OK;
if (ctx->upg_status == OTA_DOWNLOAD)
offline_ota_resp_code = DEV_OFFLINE_OTA_RSP_OK;
else if (ctx->upg_status == OTA_DOWNLOAD_FAIL)
offline_ota_resp_code = DEV_OFFLINE_OTA_RSP_DOWNLOAD_FAILED;
else
offline_ota_resp_code = DEV_OFFLINE_OTA_RSP_VERIFY_FAILED;
/*notify 10 times to assure APP to receive successfully */
uint8_t i = 0;
for(; i < 10; i++) {
dev_notify_offline_ota_result(offline_ota_resp_code);
ota_msleep(300);
}
}
#endif
static void ota_download_thread(void *hand)
{
int ret = 0;
ota_service_t* ctx = hand;
if (!ctx) {
OTA_LOG_E("ctx is NULL.\n");
ota_on_going_reset();
return;
}
ota_boot_param_t *ota_param = (ota_boot_param_t *)ctx->boot_param;
if (!ctx->boot_param) {
ret = OTA_PARAM_FAIL;
ctx->upg_status = OTA_DOWNLOAD_FAIL;
goto ERR;
}
#ifdef AOS_COMP_PWRMGMT
pwrmgmt_suspend_lowpower();
#endif
#if (defined BOARD_ESP8266)
ktask_t* h = NULL;
#ifdef WIFI_PROVISION_ENABLED
extern int awss_suc_notify_stop(void);
awss_suc_notify_stop();
#endif
#ifdef DEV_BIND_ENABLED
extern int awss_dev_bind_notify_stop(void);
awss_dev_bind_notify_stop();
#endif
h = krhino_task_find("linkkit");
if(h)
krhino_task_dyn_del(h);
ota_msleep(500);
h = krhino_task_find("netmgr_start");
if(h)
krhino_task_dyn_del(h);
ota_msleep(500);
h = krhino_task_find("reset");
ota_msleep(500);
OTA_LOG_I("awss_notify stop.");
h = krhino_task_find("event_task");
if(h)
krhino_task_dyn_del(h);
ota_msleep(500);
#endif
ota_param->off_bp = 0;
ota_param->res_type = OTA_FINISH;
#if defined (SUPPORT_MCU_OTA)
OTA_LOG_I("upg_mcu_flag:%d", ctx->upg_mcu_flag);
if (ctx->upg_mcu_flag == 1) {
ret = ota_mcu_init((void *)(ota_param));
if(ret < 0) {
ctx->upg_status = OTA_DOWNLOAD_FAIL;
goto ERR;
}
} else {
ret = ota_hal_init((void *)(ota_param));
if(ret < 0) {
ctx->upg_status = OTA_DOWNLOAD_FAIL;
goto ERR;
}
}
#else
ret = ota_hal_init((void *)(ota_param));
if(ret < 0) {
ctx->upg_status = OTA_DOWNLOAD_FAIL;
goto ERR;
}
#endif
ret = ota_malloc_hash_ctx(ctx->hash_type);
if (ret < 0) {
ret = OTA_PARAM_FAIL;
ctx->upg_status = OTA_DOWNLOAD_FAIL;
goto ERR;
}
ctx->upg_status = OTA_DOWNLOAD;
if(ctx->trans_protcol != OTA_PROTCOL_COAP_LOCAL) {
ctx->h_tr->status(0, ctx);
}
ret = ctx->h_dl->start((void*)ctx);
if (ret < 0) {
ota_param->res_type = OTA_BREAKPOINT;
#if defined (SUPPORT_MCU_OTA)
if (ctx->upg_mcu_flag == 1) {
ret = ota_mcu_boot((void*)(ota_param));
} else {
ret = ota_hal_boot((void*)(ota_param));
}
#else
ret = ota_hal_boot((void*)(ota_param));
#endif
ctx->upg_status = OTA_DOWNLOAD_FAIL;
goto ERR;
}
if (ret == OTA_CANCEL) {
ota_param->res_type = OTA_BREAKPOINT;
#if defined (SUPPORT_MCU_OTA)
if (ctx->upg_mcu_flag == 1) {
ret = ota_mcu_boot((void*)(ota_param));
} else {
ret = ota_hal_boot((void*)(ota_param));
}
#else
ret = ota_hal_boot((void*)(ota_param));
#endif
ctx->upg_status = OTA_CANCEL;
goto ERR;
}
ret = ota_check_hash((OTA_HASH_E)ctx->hash_type, ctx->hash);
if (ret < 0) {
ctx->upg_status = OTA_VERIFY_HASH_FAIL;
goto ERR;
}
#if !defined(BOARD_ESP32)
if( ctx->sign_en == OTA_SIGN_ON) {
ret = ota_verify_download_rsa_sign((unsigned char*)ctx->sign, (const char*)ctx->hash, (OTA_HASH_E)ctx->hash_type);
if(ret < 0) {
ctx->upg_status = OTA_VERIFY_RSA_FAIL;
goto ERR;
}
}
#endif
#if defined (SUPPORT_MCU_OTA)
if (ctx->upg_mcu_flag == 1) {
OTA_LOG_I("MCU upgrade no check image");
/* need update save mcu version when upgrade ok */
char mcu_ver[16] = {0};
int mcu_ver_len = 0;
char *pos1 = strstr(ctx->ota_ver, "mcu-");
char *pos2 = strstr(ctx->ota_ver, "app-");
mcu_ver_len = pos2 - pos1 - 1;
strncpy(mcu_ver, ctx->ota_ver, mcu_ver_len);
aos_kv_set("mcu_version", (void *)mcu_ver, sizeof(mcu_ver), 1);
OTA_LOG_I("update save MCU ver:%s", mcu_ver);
} else {
if(ota_param->upg_flag != OTA_DIFF) {
ret = ota_check_image(ota_param->len);
if (ret < 0) {
ctx->upg_status = OTA_VERIFY_HASH_FAIL;
goto ERR;
}
}
}
#else
if(ota_param->upg_flag != OTA_DIFF){
ret = ota_check_image(ota_param->len);
if (ret < 0) {
ctx->upg_status = OTA_VERIFY_HASH_FAIL;
goto ERR;
}
}
#endif
ota_param->res_type = OTA_FINISH;
#ifdef DEV_OFFLINE_OTA_ENABLE
if(ctx->trans_protcol == OTA_PROTCOL_COAP_LOCAL) {
notify_offline_ota_result(ctx);
}
#endif
#if defined (SUPPORT_MCU_OTA)
if (ctx->upg_mcu_flag == 1) {
ret = ota_mcu_boot((void*)(ota_param));
} else {
ret = ota_hal_boot((void*)(ota_param));
}
#else
ret = ota_hal_boot((void*)(ota_param));
#endif
ctx->upg_status = OTA_REBOOT;
ERR:
OTA_LOG_E("upgrade over err:%d", ret);
#if defined (RDA5981x) || defined (RDA5981A)
OTA_LOG_I("clear ota part. \n");
#if defined (SUPPORT_MCU_OTA)
if (ctx->upg_mcu_flag == 1) {
ota_mcu_init((void *)(ota_param));
} else {
ota_hal_init((void *)(ota_param));
}
#else
ota_hal_init((void *)(ota_param));
#endif
#endif
if(ctx->trans_protcol != OTA_PROTCOL_COAP_LOCAL) {
#if (!defined BOARD_ESP8266)
ctx->h_tr->status(100, ctx);
#endif
}
#ifdef DEV_OFFLINE_OTA_ENABLE
else {
notify_offline_ota_result(ctx);
}
#endif
ota_free_hash_ctx();
#ifdef AOS_COMP_PWRMGMT
pwrmgmt_resume_lowpower();
#endif
ota_on_going_reset();
ota_msleep(3000);
#if defined (SUPPORT_MCU_OTA)
if ((ctx->upg_mcu_flag == 1) && (ota_param->res_type == OTA_BREAKPOINT)) {
OTA_LOG_I("ota breakpoint no reboot\n");
} else {
ota_reboot();
}
#else
#if (defined BOARD_ESP8266) //If 8266 reboot directly
ota_reboot();
#else
if (ctx->upg_status == OTA_REBOOT) //only reboot status then do reboot
{
ota_reboot();
}
#endif
#endif
}
int ota_upgrade_cb(void* pctx, char *json)
{
int ret = -1;
int ret_offline_ota = DEV_OFFLINE_OTA_RSP_OK;
int is_ota = 0;
void *thread = NULL;
ota_service_t *ctx = pctx;
if (!ctx || !json) {
return ret;
}
if (0 == ota_parse(ctx, json)) {
ret = 0;
#if defined (SUPPORT_MCU_OTA)
int is_upg_mcu = 0;
int is_upg_app = 0;
int mcu_ver_len = 0;
char *pos1 = strstr(ctx->ota_ver, "mcu-");
char *pos2 = strstr(ctx->ota_ver, "app-");
mcu_ver_len = pos2 - pos1 - 1;
if ((pos1 != NULL) && (pos2 != NULL) && (mcu_ver_len > 0)) {
is_upg_mcu = strncmp(ctx->ota_ver, ctx->sys_ver, mcu_ver_len);
OTA_LOG_I("is_upg_mcu:%d", is_upg_mcu);
is_upg_app = strncmp(ctx->ota_ver + (mcu_ver_len + 1), ctx->sys_ver + (mcu_ver_len + 1), strlen(ctx->ota_ver) - (mcu_ver_len + 1));
OTA_LOG_I("is_upg_app:%d", is_upg_app);
if ((is_upg_mcu > 0) && (is_upg_app == 0)) {
is_ota = 1;
ctx->upg_mcu_flag = 1;
OTA_LOG_I("MCU OTA");
} else if ((is_upg_app > 0) && (is_upg_mcu == 0)) {
is_ota = 1;
ctx->upg_mcu_flag = 0;
OTA_LOG_I("APP OTA");
} else if ((is_upg_mcu > 0) && (is_upg_app > 0)) {
OTA_LOG_E("no support MCU and APP ota at the same time, discard it.");
is_ota = 0;
} else {
is_ota = 0;
}
}
#else
is_ota = strncmp(ctx->ota_ver,ctx->sys_ver,strlen(ctx->ota_ver));
#endif
if(is_ota > 0) {
if(ota_get_on_going_status() == 1) {
OTA_LOG_E("ota is on going, go out!!!");
if(ctx->trans_protcol != OTA_PROTCOL_COAP_LOCAL) {
return ret;
} else {
return ret_offline_ota;
}
}
ota_set_status_on_going();
ret = ota_thread_create(&thread, (void *)ota_download_thread, (void *)ctx, NULL, 4096);
if(ret < 0) {
ota_on_going_reset();
OTA_LOG_E("ota create task failed!");
#ifdef BOARD_ESP8266 /* workaround for ota pressure test */
ota_msleep(200);
ota_reboot();
while (1);
#endif
}
} else {
OTA_LOG_E("ota version is too old, discard it.");
ret_offline_ota = DEV_OFFLINE_OTA_RSP_SAME_VERSION;
ctx->upg_status = OTA_INIT_VER_FAIL;
if(ctx->trans_protcol != OTA_PROTCOL_COAP_LOCAL) {
ctx->h_tr->status(0, ctx);
}
}
}
else
{
ret_offline_ota = DEV_OFFLINE_OTA_RSP_INVALID_PARAM;
}
if(ctx->trans_protcol != OTA_PROTCOL_COAP_LOCAL) {
return ret;
} else {
return ret_offline_ota;
}
}
#ifdef DEV_OFFLINE_OTA_ENABLE
static int offline_ota_upgrade_cb(void* pctx, char *json)
{
ota_service_t* ctx =(ota_service_t*)pctx;
ctx->trans_protcol = OTA_PROTCOL_COAP_LOCAL;
//format req's json
//start dl ota_thread_create
return ota_upgrade_cb(pctx,json);
//send resp
}
#endif
int ota_service_init(ota_service_t *ctx)
{
int ret = 0;
if (!ctx) {
ctx = ota_malloc(sizeof(ota_service_t));
memset(ctx, 0, sizeof(ota_service_t));
}
if(!ctx) {
ret = OTA_INIT_FAIL;
return ret;
}
ota_hal_register_module(&ota_hal_module);
ctx->upgrade_cb = ota_upgrade_cb;
ctx->boot_param = ota_malloc(sizeof(ota_boot_param_t));
if(!ctx->boot_param) {
ret = OTA_INIT_FAIL;
return ret;
}
memset(ctx->boot_param, 0, sizeof(ota_boot_param_t));
if(ctx->inited) {
ret = OTA_INIT_FAIL;
return ret;
}
ctx->inited = 1;
ota_on_going_reset();
ctx->url = ota_malloc(OTA_URL_LEN);
if(NULL == ctx->url){
ret = OTA_INIT_FAIL;
return ret;
}
memset(ctx->url, 0, OTA_URL_LEN);
ctx->hash = ota_malloc(OTA_HASH_LEN);
if(NULL == ctx->hash){
ret = OTA_INIT_FAIL;
return ret;
}
memset(ctx->hash, 0, OTA_HASH_LEN);
ctx->sign = ota_malloc(OTA_SIGN_LEN);
if(NULL == ctx->sign){
ret = OTA_INIT_FAIL;
return ret;
}
strncpy(ctx->sys_ver, ota_hal_get_version(ctx->dev_type), sizeof(ctx->sys_ver) -1);
memset(ctx->sign, 0, OTA_SIGN_LEN);
ctx->h_tr = ota_get_transport();
ctx->h_dl = ota_get_download();
#ifdef DEV_OFFLINE_OTA_ENABLE
dev_offline_ota_module_init(ctx, offline_ota_upgrade_cb);
#else
ota_service_inform(ctx);
#endif
OTA_LOG_I("ota init success, ver:%s type:%d", ctx->sys_ver, ctx->dev_type);
ota_hal_rollback(NULL);
return ret;
}
int ota_service_inform(ota_service_t *ctx)
{
int ret = 0;
ctx->h_tr->init();
ret = ctx->h_tr->inform(ctx);
if(ret < 0){
return ret;
}
ret = ctx->h_tr->upgrade(ctx);
return ret;
}
int ota_service_deinit(ota_service_t *ctx)
{
if(!ctx) {
return -1;
}
if(ctx->h_ch) {
ota_free(ctx->h_ch);
ctx->h_ch = NULL;
}
ctx->h_tr = NULL;
ctx->h_dl = NULL;
ctx->inited = 0;
if(ctx->url){
ota_free(ctx->url);
ctx->url = NULL;
}
if(ctx->hash){
ota_free(ctx->hash);
ctx->hash = NULL;
}
if(ctx->sign){
ota_free(ctx->sign);
ctx->sign = NULL;
}
if(ctx->boot_param){
ota_free(ctx->boot_param);
ctx->boot_param = NULL;
}
if(ctx){
ota_free(ctx);
ctx = NULL;
}
return 0;
}

View file

@ -0,0 +1,24 @@
NAME := ota_2nd_boot
$(NAME)_MBINS_TYPE := kernel
$(NAME)_VERSION := 1.0.0
$(NAME)_SUMMARY := 2nd boot support single/dual banker upgrade
#default gcc
ifeq ($(COMPILER),)
$(NAME)_CFLAGS += -Wall -Werror
else ifeq ($(COMPILER),gcc)
$(NAME)_CFLAGS += -Wall -Werror
endif
$(NAME)_COMPONENTS += framework.uOTA.src.2nd_boot.nbpatch
$(NAME)_COMPONENTS += framework.uOTA.src.2nd_boot.xz
$(NAME)_SOURCES += rec_libc.c rec_main.c rec_2boot.c rec_ymodem.c
$(NAME)_INCLUDES += nbpatch
GLOBAL_INCLUDES += ./ ../service
CONFIG_SYSINFO_2BOOT_VERSION = aos-2nd_boot-1.0.0
$(info 2boot_version:${CONFIG_SYSINFO_2BOOT_VERSION})
GLOBAL_CFLAGS += -DSYSINFO_2BOOT_VERSION=\"$(CONFIG_SYSINFO_2BOOT_VERSION)\"

View file

@ -0,0 +1,68 @@
## Contents
```sh
2nd_boot
├── aos.mk
├── Config.in
├── nbpatch
├── README.md
├── rec_2boot.c
├── rec_common.c
├── rec_common.h
├── rec_define.h
├── rec_libc.c
├── rec_main.c
├── rec_pub.h
├── rec_ymodem.c
└── xz
```
## Introduction
An over-the-air update is the wireless delivery of new software or data to smart devices, especially IoT devices. Wireless carriers and OEMs typically use over-the-air (OTA) updates to deploy the new operating systems and the software app to these devices.
## Features
1. Differential incremental upgrade;
2. Dual banker:AB partition upgrade to support rollback to old version;
3. Secure download channel;
4. Firmware digital signature verification.
## Dependencies
Linkkit MQTT channel
Linkkit CoAP channel
## API
User service APIs:
```c
/*OTA export service APIs*/
int ota_service_init(ota_service_t* ctx);
int ota_service_deinit(ota_service_t* ctx);
```
for sample code please check [otaapp](../../../app/example/otaapp/).
## RTOS build
```sh
cd ROOT DIR;
aos make otaapp@board;
```
## run CLI CMDs
1. connect network
```
netmgr connect ssid passwd
```
2. run ota demo
```
OTA_APP pk dn ds ps
```
## Reference
* [AliOS-Things OTA使用说明](https://github.com/alibaba/AliOS-Things/wiki/OTA-Tutorial)
* [OTA flash分区说明文档](https://github.com/alibaba/AliOS-Things/wiki/OTA-Flash-Partitions-Overview)
* [云端一体化差分+安全升级AliOS Things物联网升级“利器”](https://mp.weixin.qq.com/s/Pb8Lleuww1r7qQJHu5ON8g)

View file

@ -0,0 +1,69 @@
## Contents
```sh
├── aos.mk
├── Config.in
├── flash_hal.c
├── flash_hal.h
├── nbpatch.c
├── nbpatch.h
├── nbpatch_io.c
├── nbpatch_main.c
├── README.md
├── rec_md5.c
├── rec_md5.h
├── rec_verify_fw.c
├── rec_verify_fw.h
├── xzdec.c
└── xzdec.h
```
## Introduction
An over-the-air update is the wireless delivery of new software or data to smart devices, especially IoT devices. Wireless carriers and OEMs typically use over-the-air (OTA) updates to deploy the new operating systems and the software app to these devices.
## Features
1. Differential incremental upgrade;
2. Dual banker:AB partition upgrade to support rollback to old version;
3. Secure download channel;
4. Firmware digital signature verification.
## Dependencies
Linkkit MQTT channel
Linkkit CoAP channel
## API
User service APIs:
```c
/*OTA export service APIs*/
int ota_service_init(ota_service_t* ctx);
int ota_service_deinit(ota_service_t* ctx);
```
for sample code please check [otaapp](../../../app/example/otaapp/).
## RTOS build
```sh
cd ROOT DIR;
aos make otaapp@board;
```
## run CLI CMDs
1. connect network
```
netmgr connect ssid passwd
```
2. run ota demo
```
OTA_APP pk dn ds ps
```
## Reference
* [AliOS-Things OTA使用说明](https://github.com/alibaba/AliOS-Things/wiki/OTA-Tutorial)
* [OTA flash分区说明文档](https://github.com/alibaba/AliOS-Things/wiki/OTA-Flash-Partitions-Overview)
* [云端一体化差分+安全升级AliOS Things物联网升级“利器”](https://mp.weixin.qq.com/s/Pb8Lleuww1r7qQJHu5ON8g)

View file

@ -0,0 +1,128 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include "flash_hal.h"
#include "nbpatch.h"
uint32_t patch_flash_get_partion_length(int par)
{
hal_logic_partition_t *logic_partition;
logic_partition = (hal_logic_partition_t *)rec_flash_get_info(par);
return logic_partition->partition_length;
}
static hal_logic_partition_t *patch_flash_get_info(hal_partition_t par)
{
hal_logic_partition_t *logic_partition;
logic_partition = (hal_logic_partition_t *)rec_flash_get_info(par);
return logic_partition;
}
int patch_flash_write(int par, const unsigned char *buffer, unsigned long offset, unsigned long len)
{
uint32_t start_addr;
hal_logic_partition_t *partition_info;
partition_info = patch_flash_get_info( par );
if(partition_info == NULL || offset + len > partition_info->partition_length){
return -1;
}
start_addr = partition_info->partition_start_addr + offset;
rec_wdt_feed();
rec_flash_write_data((unsigned char *)buffer, start_addr, len);
rec_wdt_feed();
return len;
}
int patch_flash_read(int par, const unsigned char *buffer, unsigned long offset, unsigned long len)
{
uint32_t start_addr;
hal_logic_partition_t *partition_info;
partition_info = patch_flash_get_info( par );
if (partition_info == NULL || offset + len > partition_info->partition_length){
return -1;
}
start_addr = partition_info->partition_start_addr + offset;
rec_wdt_feed();
rec_flash_read_data((unsigned char *)buffer, start_addr, len);
rec_wdt_feed();
return len;
}
int patch_flash_erase(int par, unsigned long offset, size_t esize)
{
uint32_t addr;
uint32_t start_addr, end_addr;
hal_logic_partition_t *partition_info;
partition_info = patch_flash_get_info( par );
if (partition_info == NULL || offset + esize > partition_info->partition_length) {
return -1;
}
start_addr = (partition_info->partition_start_addr + offset) & (~(SECTOR_SIZE-1));
end_addr = (partition_info->partition_start_addr + offset + esize - 1) & (~(SECTOR_SIZE-1));
for(addr = start_addr; addr <= end_addr; addr += SECTOR_SIZE) {
rec_wdt_feed();
rec_flash_erase(addr);
rec_wdt_feed();
}
return esize;
}
#if (AOS_OTA_RECOVERY_TYPE != OTA_RECOVERY_TYPE_DIRECT)
int patch_flash_copy(int par, unsigned long dst_offset, unsigned long src_offset, size_t size)
{
unsigned char tmp_buf[SECTOR_SIZE];
uint32_t pos = 0;
int ret = 0;
while(pos < size){
memset(tmp_buf, 0, SECTOR_SIZE);
ret = patch_flash_read(par, tmp_buf, src_offset + pos, SECTOR_SIZE);
if(ret < 0) {
return -1;
}
patch_flash_erase(par, dst_offset + pos, SECTOR_SIZE);
ret = patch_flash_write(par, tmp_buf, dst_offset + pos, SECTOR_SIZE);
if (ret < 0) {
return -1;
}
pos += SECTOR_SIZE;
}
return 0;
}
int patch_flash_copy_par(int dst_par, int src_par, unsigned long offset, size_t size)
{
unsigned char tmp_buf[SECTOR_SIZE];
uint32_t pos = 0;
int ret = 0;
while(pos < size){
memset(tmp_buf, 0, SECTOR_SIZE);
ret = patch_flash_read(src_par, tmp_buf, offset + pos, SECTOR_SIZE);
if(ret < 0){
return ret;
}
patch_flash_erase(dst_par, offset + pos, SECTOR_SIZE);
ret = patch_flash_write(dst_par, tmp_buf, offset + pos, SECTOR_SIZE);
if(ret < 0) {
return ret;
}
pos += SECTOR_SIZE;
}
return 0;
}
#endif

View file

@ -0,0 +1,23 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef FLASH_HAL_H_
#define FLASH_HAL_H_
#include "rec_pub.h"
void patch_flash_init(const char *file);
int patch_flash_write(int par, const unsigned char *buffer, unsigned long address, unsigned long len);
int patch_flash_read(int par, const unsigned char *buffer, unsigned long address, unsigned long len);
int patch_flash_erase(int par, unsigned long address, size_t splict_size);
uint32_t patch_flash_get_partion_length(int par);
int patch_flash_copy(int par, unsigned long dst_offset, unsigned long src_offset, size_t size);
int patch_flash_copy_par(int dst_par, int src_par, unsigned long offset, size_t size);
#endif /* FLASH_HAL_H_ */

View file

@ -0,0 +1,404 @@
/*-
* Copyright 2003-2005 Colin Percival
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "xzdec.h"
#include "nbpatch.h"
int err_code;
static void *nbpatch_buffer;
void nbpatch_buffer_init()
{
nbpatch_buffer = NULL;
}
void * nbpatch_buffer_alloc(size_t size)
{
if(nbpatch_buffer != NULL) {
#if (!defined BOARD_ESP8266)
free(nbpatch_buffer);
#endif
}
#if (!defined BOARD_ESP8266)
nbpatch_buffer = malloc(size);
#else
nbpatch_buffer = (void *)IRAM_HEAP_BASE;
#endif
return nbpatch_buffer;
}
void * nbpatch_buffer_get()
{
return nbpatch_buffer;
}
void nbpatch_buffer_free()
{
if(nbpatch_buffer != NULL) {
#if (!defined BOARD_ESP8266)
free(nbpatch_buffer);
#endif
}
nbpatch_buffer = NULL;
}
off_t offtin(u_char *buf) {
off_t y;
y = buf[7] & 0x7F;
y = y * 256;
y += buf[6];
y = y * 256;
y += buf[5];
y = y * 256;
y += buf[4];
y = y * 256;
y += buf[3];
y = y * 256;
y += buf[2];
y = y * 256;
y += buf[1];
y = y * 256;
y += buf[0];
if (buf[7] & 0x80)
y = -y;
return y;
}
static off_t nbpatch_section(const unsigned long src, off_t old_end, unsigned long dst, off_t *seek_pos, off_t splict_size, int num) ;
off_t nbpatch(unsigned long old_t, off_t old_size, const unsigned long new_t, off_t new_size, off_t splict_size) {
int ret = -1;
PatchStatus * pstatus = NULL;
if (!old_t || !new_t || old_size <= 0 || new_size <= 0 || splict_size <= 0) {
err_code = NBDIFF_PARAMS_INPUT_ERROR;
return err_code;
}
off_t seekpos = 0;
off_t patchsize = 0;
off_t pendingsize = 0;
int num = 0;
pstatus = nbpatch_get_pstatus();
if(pstatus == NULL) {
return -1;
}
memset(pstatus, 0, sizeof(PatchStatus));
read_patch_status(pstatus);
num = pstatus->num;
seekpos = pstatus->seekpos;
patchsize = pstatus->patched_size;
pendingsize = pstatus->pending_size;
LOG("pendsize %ld, num %d, pos %d, psize %d pstatus %d", pendingsize, num, seekpos, patchsize, pstatus->status);
while (seekpos < new_size || pstatus->status != 0) {
if(!pstatus->status) {
pendingsize = nbpatch_section(old_t, old_size, new_t, &seekpos, splict_size, num);
if (err_code) {
LOG("sec err:%d\n", err_code);
nbpatch_buffer_free();
goto nbpatch_error;
}
#if (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_DIRECT)
pstatus->num = ++num;
pstatus->seekpos = seekpos;
pstatus->patched_size = patchsize;
pstatus->pending_size = pendingsize;
pstatus->status = 1;
save_patch_status(pstatus);
#endif
}
off_t offset = 0;
off_t copy_size = load_bakeup_data(patchsize, pendingsize, offset);
if((copy_size == -1)||(copy_size != (pendingsize - offset))) {
LOG("err %ld, %ld, err %d", copy_size, pendingsize, err_code = NBDIFF_FILE_OP_FAIL);
nbpatch_buffer_free();
goto nbpatch_error;
}
patchsize += pendingsize;
pstatus->status = 0;
#if (AOS_OTA_RECOVERY_TYPE != OTA_RECOVERY_TYPE_DIRECT)
pstatus->pending_size = pendingsize;
pstatus->seekpos = seekpos;
nbpatch_ota_addr_free(seekpos); //already unpacked, can free now
pstatus->num = ++num;
#endif
pstatus->patched_size = patchsize;
nbpatch_buffer_free();
save_patch_status(pstatus);
}
ret = patchsize;
nbpatch_error:
LOG("nbpatch suc:%d\n",ret);
pstatus->num = 0;
pstatus->patched_size = 0;
pstatus->seekpos = 0;
pstatus->status = 0;
pstatus->crc = 0;
pstatus->pending_size = 0;
save_patch_status(pstatus);
return ret;
}
static off_t nbpatch_section(const unsigned long src, off_t old_size, unsigned long dst, off_t *seek_pos, off_t splict_size, int num)
{
off_t newsize = 0;
off_t bzctrllen, bzdatalen ,bzextralen;
u_char header[HEADER_SIZE], buf[8];
u_char *old = NULL;
u_char *newbuf;
off_t oldpos=0;
off_t newpos=0;
off_t ctrl[3];
off_t lenread;
off_t i;
if(!src || !dst || !seek_pos ) {
err_code = NBDIFF_PARAMS_INPUT_ERROR;
goto patch_error;
}
off_t seekpos = *seek_pos;
rec_wdt_feed();
old = (u_char *)(malloc(SECTOR_SIZE));
if (old == NULL){
err_code = NBDIFF_MEM_OP_FAIL;
goto patch_error;
}
/*
File format:
0 8 "BSDIFF40"
8 8 X
16 8 Y
24 8 sizeof(newfile)
32 X bzip2(control block)
32+X Y bzip2(diff block)
32+X+Y ??? bzip2(extra block)
with control block a set of triples (x,y,z) meaning "add x bytes
from oldfile to x bytes from the diff block; copy y bytes from the
extra block; seek forwards in oldfile by z bytes".
*/
int ret = nbpatch_read(dst, header, seekpos, HEADER_SIZE, 0);
if(ret < 0) {
err_code = NBDIFF_FILE_OP_FAIL;
goto patch_error;
}
/* Check for appropriate magic */
if (memcmp(header, "BSDIFF40", 8) != 0) {
err_code = NBDIFF_LZAM_OP_FAIL;
goto patch_error;
}
/* Read lengths from header */
bzctrllen = offtin(header + 8);
bzdatalen = offtin(header + 16);
bzextralen = offtin(header + 24);
newsize = offtin(header + 32);
uint16_t crc = offtin(header + 40);
if ((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0)) {
err_code = NBDIFF_LZAM_OP_FAIL;
goto patch_error;
}
if ((newbuf = (u_char *)nbpatch_buffer_alloc(newsize + 1)) == 0) {
err_code = NBDIFF_MEM_OP_FAIL;
goto patch_error;
}
struct xz_dec *ctrl_dec = NULL;
struct xz_buf cb;
struct xz_dec *diff_dec = NULL;
struct xz_buf db;
struct xz_dec *extra_dec = NULL;
struct xz_buf eb;
int success = 0;
xz_crc32_init();
success = xz_init(&ctrl_dec, &cb);
if (!success) {
err_code = NBDIFF_LZAM_OP_FAIL;
goto patch_error;
}
success = xz_init(&diff_dec, &db);
if (!success) {
err_code = NBDIFF_LZAM_OP_FAIL;
goto patch_error;
}
success = xz_init(&extra_dec,&eb);
if (!success) {
err_code = NBDIFF_LZAM_OP_FAIL;
goto patch_error;
}
xzReadHandler cbhandler;
memset(&cbhandler, 0, sizeof(xzReadHandler));
cbhandler.avail_size = bzctrllen;
cbhandler.read_pos = seekpos + HEADER_SIZE;
xzReadHandler diffhandler;
memset(&diffhandler, 0, sizeof(xzReadHandler));
diffhandler.avail_size = bzdatalen;
diffhandler.read_pos = seekpos + HEADER_SIZE + bzctrllen;
xzReadHandler extrahandler;
memset(&extrahandler, 0, sizeof(xzReadHandler));
extrahandler.avail_size = bzextralen;
extrahandler.read_pos = seekpos + HEADER_SIZE + bzctrllen + bzdatalen;
while (newpos < newsize) {
/* Read control data */
for (i = 0; i <= 2; i++) {
lenread = xz_read(&cbhandler, &cb, ctrl_dec, dst, buf, 8);
if (lenread < 8)
{
err_code = NBDIFF_LZAM_OP_FAIL;
goto patch_error;
}
ctrl[i] = offtin(buf);
//LOG("ctrlp[i] %ld", ctrl[i]);
};
/* Sanity-check */
if (newpos + ctrl[0] > newsize){
err_code = NBDIFF_LZAM_OP_FAIL;
goto patch_error;
}
/* Read diff string */
lenread = xz_read(&diffhandler, &db, diff_dec, dst, newbuf + newpos, ctrl[0]);
if ((lenread < ctrl[0])){
err_code = NBDIFF_LZAM_OP_FAIL;
goto patch_error;
}
if(oldpos > old_size || oldpos + ctrl[0] > old_size) {
LOG("pos over: %ld, %ld, %ld",oldpos,ctrl[0] ,old_size);
err_code = NBDIFF_LZAM_OP_FAIL;
goto patch_error;
}
off_t cp_size = ctrl[0];
off_t base_pos = 0;
int num = 0;
off_t i;
for (i = 0; i < ctrl[0]; i++) {
if (!(i % SECTOR_SIZE)) {
base_pos = (num++) * SECTOR_SIZE;
off_t siz = cp_size > SECTOR_SIZE ? SECTOR_SIZE : cp_size;
memset(old, 0, siz);
nbpatch_read(src, old, oldpos + base_pos, siz, 1);
cp_size -= siz;
//LOG("start cp %ld, %ld",cp_size, base_pos);
}
if (i >= base_pos) {
//LOG("oldpos %d", old[i - base_pos]);
newbuf[newpos + i] += old[i - base_pos];
}
}
rec_wdt_feed();
//LOG("oldpos %ld, newpos %ld",oldpos, newpos);
/* Adjust pointers */
newpos += ctrl[0];
oldpos += ctrl[0];
/* Sanity-check */
if (newpos + ctrl[1] > newsize) {
err_code = NBDIFF_LZAM_OP_FAIL;
goto patch_error;
}
/* Read extra string */
lenread = xz_read(&extrahandler, &eb, extra_dec, dst, newbuf + newpos, ctrl[1]);
if (lenread < ctrl[1]) {
err_code = NBDIFF_LZAM_OP_FAIL;
goto patch_error;
}
/* Adjust pointers */
newpos += ctrl[1];
oldpos += ctrl[2];
rec_wdt_feed();
};
if(newsize > splict_size) {
err_code = NBDIFF_PATCH_OP_FAIL;
goto patch_error;
}
uint16_t cal_crc = 0;
CRC16_Context crc_context;
CRC16_Init(&crc_context);
CRC16_Update(&crc_context, newbuf, newsize);
CRC16_Final(&crc_context, &cal_crc);
if(cal_crc != crc) {
LOG("cal %0x != crc %0x", cal_crc, crc);
err_code = NBDIFF_CRC_OP_FAIL;
goto patch_error;
}
#if (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_DIRECT)
ret = save_bakeup_data((unsigned long )newbuf, newsize);
if(ret < 0) {
err_code = NBDIFF_FILE_OP_FAIL;
goto patch_error;
}
#endif
seekpos += HEADER_SIZE;
seekpos += bzctrllen;
seekpos += bzdatalen;
seekpos += bzextralen;
*seek_pos = seekpos;
err_code = 0;
patch_error:
LOG("nb section:%d num:%d", err_code,num);
if(ctrl_dec){
xz_end(ctrl_dec);
ctrl_dec = NULL;
}
if(diff_dec) {
xz_end(diff_dec);
diff_dec = NULL;
}
if(extra_dec){
xz_end(extra_dec);
extra_dec = NULL;
}
if(old){
free(old);
old = NULL;
}
return newsize;
}

View file

@ -0,0 +1,69 @@
/*
* nbpatch.h
*
* Created on: 2017128
* Author: ting.guit
*/
#ifndef NBPATCH_H_
#define NBPATCH_H_
#include "rec_pub.h"
#include "flash_hal.h"
#define HEADER_SIZE 48
#define PARTITION_PARAM HAL_PARTITION_PARAMETER_1
#define PARTITION_OTA HAL_PARTITION_OTA_TEMP
#define PARTITION_BACKUP_PARAM HAL_PARTITION_RECOVERY_BACK_PARA
#define NBDIFF_PARAMS_INPUT_ERROR 1
#define NBDIFF_MEM_OP_FAIL 2
#define NBDIFF_FILE_OP_FAIL 3
#define NBDIFF_LZAM_OP_FAIL 4
#define NBDIFF_PATCH_OP_FAIL 5
#define NBDIFF_CRC_OP_FAIL 6
enum {
NBPATCH_ST_FAIL=-4,
NBPATCH_PARAM_FAIL=-3,
NBPATCH_DIFF_FAIL=-2,
NBPATCH_SIZE_FAIL=-1,
};
off_t nbpatch(unsigned long old_t, off_t old_size, const unsigned long new_t, off_t new_size, off_t splict_size);
int nbpatch_error(unsigned long src);
int nbpatch_eof(unsigned long src);
int nbpatch_read(unsigned long src, const unsigned char *buffer, unsigned long pos, size_t size, u_char is_old);
int nbpatch_write(unsigned long dst, const unsigned char *buffer, unsigned long pos, size_t size);
int nbpatch_main();
off_t offtin(u_char *buf) ;
PatchStatus *nbpatch_get_pstatus(void);
int save_patch_status(PatchStatus *status);
int read_patch_status(PatchStatus *status);
off_t save_bakeup_data(unsigned long src, off_t bsize);
off_t load_bakeup_data(unsigned long dst, off_t size, off_t offset);
void nbpatch_ota_addr_free(off_t range);
off_t nbpatch_ota_addr_get(off_t old_offset);
int nbpatch_flash_status_check(uint32_t addr);
void nbpatch_ota_status_set(off_t offset, uint32_t status);
void nbpatch_ota_addr_set(off_t old_offset, off_t new_offset);
off_t nbpatch_find_free_space(void);
int nbpatch_flash_status_check(uint32_t addr);
void nbpatch_buffer_init();
#endif /* NBPATCH_H_ */

View file

@ -0,0 +1,20 @@
NAME := ota_2boot_nbpatch
$(NAME)_CFLAGS += -Wall -Werror
$(NAME)_MBINS_TYPE := kernel
$(NAME)_VERSION := 1.0.0
$(NAME)_SUMMARY := Differential recovery algorithm
$(NAME)_SOURCES := nbpatch.c \
nbpatch_io.c \
xzdec.c \
flash_hal.c \
nbpatch_main.c \
rec_md5.c \
rec_verify_fw.c
$(NAME)_INCLUDES += ../xz/linux/include/linux \
../xz/linux/lib/xz \
../xz/userspace

View file

@ -0,0 +1,288 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include "nbpatch.h"
extern void * nbpatch_buffer_get();
int nbpatch_eof(unsigned long src)
{
return 0;
}
#if (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_DIRECT)
int nbpatch_read(unsigned long src, const unsigned char *buffer, unsigned long pos, size_t size, u_char is_old)
{
unsigned long base = pos;
size_t read_size = 0;
int ret = 0;
while(size > 0) {
read_size = size > SECTOR_SIZE ? SECTOR_SIZE : size;
ret = patch_flash_read(src, buffer+pos-base, pos, read_size);
if(ret < 0) {
return -1;
}
pos += read_size;
size -= read_size;
}
return pos - base;
}
#else
int nbpatch_read(unsigned long src, const unsigned char *buffer, unsigned long pos, size_t size, u_char is_old)
{
unsigned long base = pos;
size_t read_size = 0;
int ret = 0;
unsigned long new_src = src;
while (size > 0) {
read_size = size > SECTOR_SIZE ? SECTOR_SIZE : size;
if(is_old) {
if (nbpatch_flash_status_check(pos) == 2){
if (SPLICT_SIZE - pos % SPLICT_SIZE < read_size){
read_size = SPLICT_SIZE - pos % SPLICT_SIZE;
}
new_src = PARTITION_OTA;
}else{
new_src = src;
}
} else {
if (SPLICT_SIZE - pos % SPLICT_SIZE < read_size){
read_size = SPLICT_SIZE - pos % SPLICT_SIZE;
}
new_src = src;
}
ret = patch_flash_read(new_src, buffer + pos - base, (is_old==0)?nbpatch_ota_addr_get(pos):pos, read_size);
if (ret < 0) {
return ret;
}
pos += read_size;
size -= read_size;
}
return pos - base;
}
#endif
int nbpatch_write(unsigned long dst, const unsigned char *buffer, unsigned long pos, size_t size)
{
unsigned long base = pos;
size_t write_size = 0;
int ret = 0;
while(size > 0) {
write_size = size > SECTOR_SIZE? SECTOR_SIZE:size;
ret = patch_flash_write(dst, buffer+pos-base, pos, write_size);
if(ret < 0) {
return ret;
}
pos += write_size;
size -= write_size;
}
return pos - base;
}
uint16_t cal_crc(void *addr, off_t len)
{
uint16_t patch_crc = 0;
CRC16_Context crc_context;
CRC16_Init(&crc_context);
CRC16_Update(&crc_context, addr, len);
CRC16_Final(&crc_context, &patch_crc);
return patch_crc;
}
int save_patch_status(PatchStatus *status)
{
int ret = 0;
uint16_t patch_crc = 0;
if (!status) {
return -1;
}
patch_crc = cal_crc(status, sizeof(PatchStatus) - sizeof(uint16_t));
status->patch_crc = patch_crc;
ret = patch_flash_erase(PARTITION_PARAM, DIFF_CONF_OFFSET, sizeof(PatchStatus));
if(ret < 0) {
goto ERR;
}
ret = patch_flash_write(PARTITION_PARAM, (unsigned char *) status,
DIFF_CONF_OFFSET, sizeof(PatchStatus));
if (ret < 0) {
goto ERR;
}
//bakeup patchstatus
ret = patch_flash_erase(PARTITION_BACKUP_PARAM, DIFF_CONF_OFFSET, sizeof(PatchStatus));
if (ret < 0) {
goto ERR;
}
ret = patch_flash_write(PARTITION_BACKUP_PARAM, (unsigned char *) status,
DIFF_CONF_OFFSET, sizeof(PatchStatus));
if (ret < 0) {
goto ERR;
}
return 0;
ERR:
LOG("st err:%d",ret);
return ret;
}
int read_patch_status(PatchStatus *status)
{
uint16_t patch_crc = 0;
if (!status) {
return -1;
}
int ret = patch_flash_read(PARTITION_PARAM,
(unsigned char *) status, DIFF_CONF_OFFSET, sizeof(PatchStatus));
if(ret < 0) {
return ret;
}
uint16_t patch_crc2 = status->patch_crc;
patch_crc = cal_crc(status, sizeof(PatchStatus) - sizeof(uint16_t));
if(patch_crc == patch_crc2) {
return 0;
}
ret = patch_flash_read(PARTITION_BACKUP_PARAM, (unsigned char *) status,
DIFF_CONF_OFFSET, sizeof(PatchStatus));
if (ret < 0) {
return ret;
}
patch_crc2 = status->patch_crc;
patch_crc = cal_crc(status, sizeof(PatchStatus) - sizeof(uint16_t));
if (patch_crc == patch_crc2) {
return 0;
}
LOG("crc err %d, %d", patch_crc, patch_crc2);
return -1;
}
#if (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_DIRECT)
off_t save_bakeup_data(unsigned long src, off_t size)
{
u_char buffer[SECTOR_SIZE];
unsigned long pos = 0;
size_t bsiz = 0;
uint16_t crc = 0;
int ret = 0;
memset(buffer, 0, sizeof(buffer));
CRC16_Context crc_context;
CRC16_Init(&crc_context);
ret = patch_flash_erase(PARTITION_OTA, DIFF_BACKUP_OFFSET, size);
if(ret < 0) {
return ret;
}
while (size > 0) {
bsiz = size > SECTOR_SIZE ? SECTOR_SIZE : size;
ret = patch_flash_write(PARTITION_OTA, (const unsigned char *)(src + pos), DIFF_BACKUP_OFFSET + pos, bsiz);
if(ret < 0) {
return ret;
}
ret = patch_flash_read(PARTITION_OTA, buffer, DIFF_BACKUP_OFFSET + pos, bsiz);
if(ret < 0) {
return ret;
}
if(memcmp((const void *)buffer, (const void *)(src+pos), bsiz) != 0) {
LOG("crc %d err", crc_context.crc);
return -1;
}
CRC16_Update(&crc_context, buffer, bsiz);
pos += bsiz;
size -= bsiz;
}
CRC16_Final(&crc_context, &crc);
return 0;
}
off_t load_bakeup_data(unsigned long dst, off_t size, off_t offset) {
u_char buffer[SECTOR_SIZE];
unsigned long pos = offset;
size_t bsiz = 0;
int ret = 0;
size -= offset;
memset(buffer, 0, sizeof(buffer));
uint16_t crc = 0;
CRC16_Context crc_context;
CRC16_Init(&crc_context);
patch_flash_erase(HAL_PARTITION_APPLICATION, dst + pos, size);
while (size > 0) {
bsiz = size > SECTOR_SIZE ? SECTOR_SIZE : size;
memset(buffer, 0, SECTOR_SIZE);
ret = patch_flash_read(HAL_PARTITION_OTA_TEMP, buffer, DIFF_BACKUP_OFFSET + pos, bsiz);
if(ret < 0) {
return ret;
}
ret = patch_flash_write(HAL_PARTITION_APPLICATION, buffer, dst + pos, bsiz);
if(ret < 0) {
return ret;
}
CRC16_Update(&crc_context, buffer, bsiz);
pos += bsiz;
size -= bsiz;
}
CRC16_Final(&crc_context, &crc);
return pos;
}
#else
off_t load_bakeup_data(unsigned long dst, off_t size, off_t offset) {
u_char buffer[SECTOR_SIZE];
unsigned long pos = offset;
size_t bsiz = 0;
int ret = 0;
off_t free_offset = 0xFFFFFFFF;
void *buf = nbpatch_buffer_get();
size -= offset;
memset(buffer, 0, sizeof(buffer));
uint16_t crc = 0;
CRC16_Context crc_context;
CRC16_Init(&crc_context);
if(nbpatch_flash_status_check(dst) != 0) {
free_offset = nbpatch_find_free_space();
if(free_offset == 0xFFFFFFFF) {
LOG("find space err\n");
return -1;
}
patch_flash_copy(PARTITION_OTA, free_offset, dst, SPLICT_SIZE);
nbpatch_ota_status_set(free_offset, OTA_FLASH_STATUS_USED);
nbpatch_ota_addr_set(dst, free_offset);
}
patch_flash_erase(PARTITION_OTA, dst + pos, size);
//copy decompressed data from memory to destination flash partion
while (size > 0) {
bsiz = size > SECTOR_SIZE ? SECTOR_SIZE : size;
ret = patch_flash_write(PARTITION_OTA, (const unsigned char *)((uint32_t)buf + pos), dst + pos, bsiz);
if(ret < 0) {
return ret;
}
CRC16_Update(&crc_context, buffer, bsiz);
pos += bsiz;
size -= bsiz;
}
CRC16_Final(&crc_context, &crc);
nbpatch_ota_status_set(dst, OTA_FLASH_STATUS_REVY);
return pos;
}
#endif

View file

@ -0,0 +1,368 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include "nbpatch.h"
#include "rec_verify_fw.h"
static PatchStatus *g_pstatus = NULL;
PatchStatus *nbpatch_get_pstatus(void)
{
if(g_pstatus == NULL)
{
g_pstatus = (PatchStatus *)malloc(sizeof(PatchStatus)); // this memory will not free
if(NULL != g_pstatus) {
memset(g_pstatus, 0, sizeof(PatchStatus));
}
}
return g_pstatus;
}
#if (AOS_OTA_RECOVERY_TYPE != OTA_RECOVERY_TYPE_DIRECT)
void nbpatch_flash_status_init(uint32_t ota_len)
{
uint32_t i = 0;
uint32_t num = 0;
PatchStatus* pstatus = nbpatch_get_pstatus();
uint32_t par_len = patch_flash_get_partion_length(HAL_PARTITION_OTA_TEMP);
memset(pstatus->REC_FLASH_STAT_E, OTA_FLASH_STATUS_NULL, SPLISE_NUM);
memset(pstatus->ota_addr, 0xFF, OTA_ADDR_NUM * sizeof(uint16_t));
num = ota_len / SPLICT_SIZE + (((ota_len % SPLICT_SIZE) == 0)?0:1);
if(num > OTA_ADDR_NUM){
num = OTA_ADDR_NUM;
}
for(i = 0; i < num; i++) {
pstatus->REC_FLASH_STAT_E[i] = OTA_FLASH_STATUS_USED;
pstatus->ota_addr[i] = i; // addr is the number of SPLICT_SIZE
}
num = par_len / SPLICT_SIZE ;
for(; i < num; i++) {
pstatus->REC_FLASH_STAT_E[i] = OTA_FLASH_STATUS_FREE;
}
pstatus->recovery_phase = REC_PHASE_NBPATCH;
save_patch_status(pstatus);
}
int nbpatch_flash_status_check(uint32_t addr)
{
PatchStatus* pstatus = nbpatch_get_pstatus();
if(addr / SPLICT_SIZE >= SPLISE_NUM) {
return -1;
}
return pstatus->REC_FLASH_STAT_E[addr / SPLICT_SIZE];
}
void nbpatch_ota_status_set(off_t offset, uint32_t status)
{
PatchStatus* pstatus = nbpatch_get_pstatus();
if(offset / SPLICT_SIZE >= SPLISE_NUM) {
return;
}
pstatus->REC_FLASH_STAT_E[offset / SPLICT_SIZE] = status;
save_patch_status(pstatus);
}
void nbpatch_ota_addr_set(off_t old_offset, off_t new_offset)
{
uint32_t i = 0;
PatchStatus* pstatus = nbpatch_get_pstatus();
if ((old_offset / SPLICT_SIZE >= SPLISE_NUM) || (new_offset / SPLICT_SIZE >= SPLISE_NUM)){
return;
}
for(i = 0; i < OTA_ADDR_NUM; i++)
{
if(((pstatus->ota_addr[i] * SPLICT_SIZE) == old_offset) && (pstatus->ota_addr[i] != 0xFFFF))
{
pstatus->ota_addr[i] = new_offset / SPLICT_SIZE;
}
}
save_patch_status(pstatus);
}
off_t nbpatch_ota_addr_get(off_t old_offset)
{
off_t new_offset;
PatchStatus* pstatus = nbpatch_get_pstatus();
if (old_offset / SPLICT_SIZE >= OTA_ADDR_NUM) {
return old_offset;
}
new_offset = pstatus->ota_addr[old_offset / SPLICT_SIZE] * SPLICT_SIZE + old_offset % SPLICT_SIZE;
return new_offset;
}
// find free space from end to front
off_t nbpatch_find_free_space(void)
{
int i = 0;
PatchStatus* pstatus = nbpatch_get_pstatus();
for(i = SPLISE_NUM - 1; i >= 0; i--) {
if(pstatus->REC_FLASH_STAT_E[i] == 0) {
return i * SPLICT_SIZE;
}
}
return 0xFFFFFFFF;
}
void nbpatch_ota_addr_free(off_t range)
{
int i = 0;
PatchStatus* pstatus = nbpatch_get_pstatus();
if ( range / SPLICT_SIZE > OTA_ADDR_NUM) {
return;
}
for(i = 0; i < (range / SPLICT_SIZE); i++)
{
if(pstatus->ota_addr[i] != 0)
{
pstatus->REC_FLASH_STAT_E[pstatus->ota_addr[i]] = OTA_FLASH_STATUS_FREE;
pstatus->ota_addr[i] = 0;
}
}
save_patch_status(pstatus);
}
void nbpatch_copy_app2ota() {
int i = 0;
int num = 0;
int ret = 0;
PatchStatus* pstatus = nbpatch_get_pstatus();
unsigned int par_len = patch_flash_get_partion_length(HAL_PARTITION_OTA_TEMP);
pstatus->recovery_phase = REC_PHASE_COPY;
save_patch_status(pstatus);
num = par_len / SPLICT_SIZE;
for(i = 0; i < num; i++) {
if((pstatus->REC_FLASH_STAT_E[i] != OTA_FLASH_STATUS_REVY) && (pstatus->REC_FLASH_STAT_E[i] != OTA_FLASH_STATUS_SYNC)) {
LOG("copy to addr 0x%x, status %d\n", i * SPLICT_SIZE, pstatus->REC_FLASH_STAT_E[i]);
ret = patch_flash_copy_par(HAL_PARTITION_OTA_TEMP, HAL_PARTITION_APPLICATION, i * SPLICT_SIZE, SPLICT_SIZE);
LOG("copy to addr 0x%x, st:%d ret:%d\n", i * SPLICT_SIZE, pstatus->REC_FLASH_STAT_E[i], ret);
pstatus->REC_FLASH_STAT_E[i] = OTA_FLASH_STATUS_SYNC;
save_patch_status(pstatus);
}
}
save_patch_status(pstatus);
}
#endif
#if (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_ABBACK)
int nbpatch_swap_section(int par1, int par2, int offset, size_t swap_size, unsigned int sec)
{
int i;
int num;
void *buf = NULL;
void *buf2 = NULL;
PatchStatus* pstatus = nbpatch_get_pstatus();
LOG("swap offset 0x%x\n", offset);
buf = malloc(SECTOR_SIZE);
if(NULL == buf) {
return -1;
}
buf2 = malloc(SECTOR_SIZE);
if(NULL == buf2) {
free(buf);
return -1;
}
rec_wdt_feed();
num = swap_size / SECTOR_SIZE;
for(i = sec; i < num; i ++ ) {
if((sec != 0) && (sec == i) && (0 != pstatus->swaped_state)) {
if (1 == pstatus->swaped_state) {
patch_flash_read(PARTITION_BACKUP_PARAM, (const unsigned char *)buf, offset + i*SECTOR_SIZE, SECTOR_SIZE);
patch_flash_read(par2, (const unsigned char *)buf2, offset + i*SECTOR_SIZE, SECTOR_SIZE);
goto state1_label;
} else if(2 == pstatus->swaped_state) {
patch_flash_read(PARTITION_BACKUP_PARAM, (const unsigned char *)buf, offset + i*SECTOR_SIZE, SECTOR_SIZE);
goto state2_label;
} else if(3 == pstatus->swaped_state) {
continue;
}
} else {
patch_flash_read(par1, (const unsigned char *)buf, offset + i*SECTOR_SIZE, SECTOR_SIZE);
patch_flash_read(par2, (const unsigned char *)buf2, offset + i*SECTOR_SIZE, SECTOR_SIZE);
}
pstatus->swaped_idx = i;
pstatus->swaped_state = 0;
save_patch_status(pstatus);
if(0 == memcmp(buf, buf2, SECTOR_SIZE)) {
continue;
}
patch_flash_erase(PARTITION_BACKUP_PARAM, SECTOR_SIZE, SECTOR_SIZE);
patch_flash_write(PARTITION_BACKUP_PARAM, (const unsigned char *)buf, SECTOR_SIZE, SECTOR_SIZE);
pstatus->swaped_state = 1;
save_patch_status(pstatus);
state1_label:
patch_flash_erase(par1, offset + i*SECTOR_SIZE, SECTOR_SIZE);
patch_flash_write(par1, (const unsigned char *)buf2, offset + i*SECTOR_SIZE, SECTOR_SIZE);
pstatus->swaped_state = 2;
save_patch_status(pstatus);
state2_label:
patch_flash_erase(par2, offset + i*SECTOR_SIZE, SECTOR_SIZE);
patch_flash_write(par2, (const unsigned char *)buf, offset + i*SECTOR_SIZE, SECTOR_SIZE);
pstatus->swaped_state = 3;
save_patch_status(pstatus);
}
free(buf);
free(buf2);
return 0;
}
//swap the difference between the app and ota partion
int nbpatch_swap_app2ota(unsigned char all_flag)
{
unsigned int i = 0;
unsigned int sec = 0;
char version[OTA_MAX_VER_LEN];
unsigned int par_len = patch_flash_get_partion_length(HAL_PARTITION_APPLICATION);
PatchStatus* pstatus = nbpatch_get_pstatus();
read_patch_status(pstatus);
rec_wdt_feed();
if(REC_PHASE_SWAP == pstatus->recovery_phase) {
i = pstatus->swap_addr;
}
if(0 != i) {
sec = pstatus->swaped_idx;
}
LOG("swap offset 0x%x, index %d\r\n", i*SPLICT_SIZE, sec);
pstatus->recovery_phase = REC_PHASE_SWAP;
save_patch_status(pstatus);
for(; i < par_len / SPLICT_SIZE; i++) {
if((TRUE == all_flag) || (OTA_FLASH_STATUS_REVY == pstatus->REC_FLASH_STAT_E[i])) {
pstatus->swap_addr = i;
nbpatch_swap_section(HAL_PARTITION_APPLICATION, HAL_PARTITION_OTA_TEMP, i*SPLICT_SIZE, SPLICT_SIZE, sec);
sec = 0;
}
}
pstatus->recovery_phase = REC_PHASE_DONE;
//switch the version string
memset(version, 0, OTA_MAX_VER_LEN);
memcpy(version, pstatus->app_version, OTA_MAX_VER_LEN);
memcpy(pstatus->app_version, pstatus->ota_version, OTA_MAX_VER_LEN);
memcpy(pstatus->ota_version, version, OTA_MAX_VER_LEN);
save_patch_status(pstatus);
return 0;
}
#endif
int nbpatch_main(void)
{
int ret = 0;
int nbpatch_size = 0;
PatchStatus * pstatus = NULL;
pstatus = nbpatch_get_pstatus();
if(pstatus == NULL) {
ret = NBPATCH_ST_FAIL;
goto END;
}
read_patch_status(pstatus);
if (pstatus->dst_adr > HAL_PARTITION_OTA_TEMP || pstatus->src_adr > HAL_PARTITION_OTA_TEMP) {
ret = NBPATCH_PARAM_FAIL;
goto END;
}
if (!pstatus->diff) {
ret = NBPATCH_DIFF_FAIL;
goto END;
}
uint32_t old_size = patch_flash_get_partion_length(pstatus->dst_adr);
if(pstatus->len > old_size || pstatus->len == 0) {
ret = NBPATCH_DIFF_FAIL;
goto END;
}
#if (AOS_OTA_RECOVERY_TYPE != OTA_RECOVERY_TYPE_DIRECT)
if(pstatus->patch_index == 0) {
nbpatch_flash_status_init(pstatus->len);
}
pstatus->patch_index += 1;
save_patch_status(pstatus);
if(pstatus->patch_index > 1) {
switch (pstatus->recovery_phase) {
case REC_PHASE_COPY:
goto nbpatch_copy_lable;
break;
#if (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_ABBACK)
case REC_PHASE_SWAP:
goto nbpatch_swap_lable;
break;
#endif
default:
break;
};
}
#endif
if(pstatus->status > 1) {//first recovery, init patch status
pstatus->seekpos = 0;
pstatus->patched_size = 0;
pstatus->pending_size = 0;
pstatus->status = 0;
pstatus->num = 0;
save_patch_status(pstatus);
}
nbpatch_buffer_init();
nbpatch_size = nbpatch(pstatus->dst_adr, old_size, pstatus->src_adr, pstatus->len, SPLICT_SIZE);
if(nbpatch_size <= 0) {
ret = NBPATCH_DIFF_FAIL;
goto END;
}
#if (AOS_OTA_RECOVERY_TYPE != OTA_RECOVERY_TYPE_DIRECT)
else{
nbpatch_copy_lable:
nbpatch_copy_app2ota();
ret = rec_verify_firmware(pstatus->src_adr, nbpatch_size);
LOG("verify fw adr:0x%x len:0x%x ret:0x%x\r\n", pstatus->src_adr, nbpatch_size,ret);
#if (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_ABBACK)
nbpatch_swap_lable:
ret = nbpatch_swap_app2ota(FALSE);
#endif
}
#endif
#if (AOS_OTA_RECOVERY_TYPE != OTA_RECOVERY_TYPE_ABBOOT)
pstatus->recovery_phase = REC_PHASE_DONE;
#else
pstatus->recovery_phase = REC_PHASE_SWITCH;
#endif
save_patch_status(pstatus);
END:
LOG("nbpatch end:%d",ret);
return ret;
}

View file

@ -0,0 +1,249 @@
#include "rec_md5.h"
#include "rec_pub.h"
#ifndef GET_UINT32_LE
#define GET_UINT32_LE(n,b,i) \
{ \
(n) = ( (unsigned int) (b)[(i) ] ) \
| ( (unsigned int) (b)[(i) + 1] << 8 ) \
| ( (unsigned int) (b)[(i) + 2] << 16 ) \
| ( (unsigned int) (b)[(i) + 3] << 24 ); \
}
#endif
#ifndef PUT_UINT32_LE
#define PUT_UINT32_LE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
(b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
(b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
(b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
}
#endif
static void rec_zeroize( void *v, unsigned int n )
{
volatile unsigned char *p = v;
while ( n-- ) {
*p++ = 0;
}
}
void rec_md5_free( rec_md5_context *ctx )
{
if ( ctx == NULL ) {
return;
}
rec_zeroize( ctx, sizeof( rec_md5_context ) );
}
void rec_md5_init( rec_md5_context *ctx )
{
rec_memset( ctx, 0, sizeof( rec_md5_context ) );
}
void rec_md5_starts( rec_md5_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
}
void rec_md5_process( rec_md5_context *ctx, const unsigned char data[64] )
{
unsigned int X[16], A, B, C, D;
GET_UINT32_LE( X[ 0], data, 0 );
GET_UINT32_LE( X[ 1], data, 4 );
GET_UINT32_LE( X[ 2], data, 8 );
GET_UINT32_LE( X[ 3], data, 12 );
GET_UINT32_LE( X[ 4], data, 16 );
GET_UINT32_LE( X[ 5], data, 20 );
GET_UINT32_LE( X[ 6], data, 24 );
GET_UINT32_LE( X[ 7], data, 28 );
GET_UINT32_LE( X[ 8], data, 32 );
GET_UINT32_LE( X[ 9], data, 36 );
GET_UINT32_LE( X[10], data, 40 );
GET_UINT32_LE( X[11], data, 44 );
GET_UINT32_LE( X[12], data, 48 );
GET_UINT32_LE( X[13], data, 52 );
GET_UINT32_LE( X[14], data, 56 );
GET_UINT32_LE( X[15], data, 60 );
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define P(a,b,c,d,k,s,t) \
{ \
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
#define F(x,y,z) (z ^ (x & (y ^ z)))
P( A, B, C, D, 0, 7, 0xD76AA478 );
P( D, A, B, C, 1, 12, 0xE8C7B756 );
P( C, D, A, B, 2, 17, 0x242070DB );
P( B, C, D, A, 3, 22, 0xC1BDCEEE );
P( A, B, C, D, 4, 7, 0xF57C0FAF );
P( D, A, B, C, 5, 12, 0x4787C62A );
P( C, D, A, B, 6, 17, 0xA8304613 );
P( B, C, D, A, 7, 22, 0xFD469501 );
P( A, B, C, D, 8, 7, 0x698098D8 );
P( D, A, B, C, 9, 12, 0x8B44F7AF );
P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
P( B, C, D, A, 11, 22, 0x895CD7BE );
P( A, B, C, D, 12, 7, 0x6B901122 );
P( D, A, B, C, 13, 12, 0xFD987193 );
P( C, D, A, B, 14, 17, 0xA679438E );
P( B, C, D, A, 15, 22, 0x49B40821 );
#undef F
#define F(x,y,z) (y ^ (z & (x ^ y)))
P( A, B, C, D, 1, 5, 0xF61E2562 );
P( D, A, B, C, 6, 9, 0xC040B340 );
P( C, D, A, B, 11, 14, 0x265E5A51 );
P( B, C, D, A, 0, 20, 0xE9B6C7AA );
P( A, B, C, D, 5, 5, 0xD62F105D );
P( D, A, B, C, 10, 9, 0x02441453 );
P( C, D, A, B, 15, 14, 0xD8A1E681 );
P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
P( A, B, C, D, 9, 5, 0x21E1CDE6 );
P( D, A, B, C, 14, 9, 0xC33707D6 );
P( C, D, A, B, 3, 14, 0xF4D50D87 );
P( B, C, D, A, 8, 20, 0x455A14ED );
P( A, B, C, D, 13, 5, 0xA9E3E905 );
P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
P( C, D, A, B, 7, 14, 0x676F02D9 );
P( B, C, D, A, 12, 20, 0x8D2A4C8A );
#undef F
#define F(x,y,z) (x ^ y ^ z)
P( A, B, C, D, 5, 4, 0xFFFA3942 );
P( D, A, B, C, 8, 11, 0x8771F681 );
P( C, D, A, B, 11, 16, 0x6D9D6122 );
P( B, C, D, A, 14, 23, 0xFDE5380C );
P( A, B, C, D, 1, 4, 0xA4BEEA44 );
P( D, A, B, C, 4, 11, 0x4BDECFA9 );
P( C, D, A, B, 7, 16, 0xF6BB4B60 );
P( B, C, D, A, 10, 23, 0xBEBFBC70 );
P( A, B, C, D, 13, 4, 0x289B7EC6 );
P( D, A, B, C, 0, 11, 0xEAA127FA );
P( C, D, A, B, 3, 16, 0xD4EF3085 );
P( B, C, D, A, 6, 23, 0x04881D05 );
P( A, B, C, D, 9, 4, 0xD9D4D039 );
P( D, A, B, C, 12, 11, 0xE6DB99E5 );
P( C, D, A, B, 15, 16, 0x1FA27CF8 );
P( B, C, D, A, 2, 23, 0xC4AC5665 );
#undef F
#define F(x,y,z) (y ^ (x | ~z))
P( A, B, C, D, 0, 6, 0xF4292244 );
P( D, A, B, C, 7, 10, 0x432AFF97 );
P( C, D, A, B, 14, 15, 0xAB9423A7 );
P( B, C, D, A, 5, 21, 0xFC93A039 );
P( A, B, C, D, 12, 6, 0x655B59C3 );
P( D, A, B, C, 3, 10, 0x8F0CCC92 );
P( C, D, A, B, 10, 15, 0xFFEFF47D );
P( B, C, D, A, 1, 21, 0x85845DD1 );
P( A, B, C, D, 8, 6, 0x6FA87E4F );
P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
P( C, D, A, B, 6, 15, 0xA3014314 );
P( B, C, D, A, 13, 21, 0x4E0811A1 );
P( A, B, C, D, 4, 6, 0xF7537E82 );
P( D, A, B, C, 11, 10, 0xBD3AF235 );
P( C, D, A, B, 2, 15, 0x2AD7D2BB );
P( B, C, D, A, 9, 21, 0xEB86D391 );
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
}
void rec_md5_update( rec_md5_context *ctx, const unsigned char *input, unsigned int ilen )
{
unsigned int fill;
unsigned int left;
if ( ilen == 0 ) {
return;
}
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (unsigned int) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if ( ctx->total[0] < (unsigned int) ilen ) {
ctx->total[1]++;
}
if ( left && ilen >= fill ) {
rec_memcpy( (void *) (ctx->buffer + left), input, fill );
rec_md5_process( ctx, ctx->buffer );
input += fill;
ilen -= fill;
left = 0;
}
while ( ilen >= 64 ) {
rec_md5_process( ctx, input );
input += 64;
ilen -= 64;
}
if ( ilen > 0 ) {
rec_memcpy( (void *) (ctx->buffer + left), input, ilen );
}
}
static const unsigned char md5_padding[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
void rec_md5_finish( rec_md5_context *ctx, unsigned char output[16] )
{
unsigned int last, padn;
unsigned int high, low;
unsigned char msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32_LE( low, msglen, 0 );
PUT_UINT32_LE( high, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
rec_md5_update( ctx, md5_padding, padn );
rec_md5_update( ctx, msglen, 8 );
PUT_UINT32_LE( ctx->state[0], output, 0 );
PUT_UINT32_LE( ctx->state[1], output, 4 );
PUT_UINT32_LE( ctx->state[2], output, 8 );
PUT_UINT32_LE( ctx->state[3], output, 12 );
}

View file

@ -0,0 +1,21 @@
#ifndef _REC_MD5_H_
#define _REC_MD5_H_
typedef struct
{
unsigned int total[2];
unsigned int state[4];
unsigned char buffer[64];
}rec_md5_context;
#ifndef NULL
#define NULL (0)
#endif
void rec_md5_free( rec_md5_context *ctx );
void rec_md5_init( rec_md5_context *ctx );
void rec_md5_starts( rec_md5_context *ctx );
void rec_md5_update( rec_md5_context *ctx, const unsigned char *input, unsigned int ilen );
void rec_md5_finish( rec_md5_context *ctx, unsigned char output[16] );
#endif

View file

@ -0,0 +1,109 @@
#include "rec_verify_fw.h"
#include "nbpatch.h"
#include "rec_md5.h"
typedef struct _fw_info{
unsigned int image_magic;
unsigned int image_size;
unsigned char image_md5_value[16];
unsigned char image_reserver[2];
unsigned short image_crc16;
}rec_fw_info;
static int rec_get_fw_store_md5(unsigned long fw_tag, unsigned int fw_len, unsigned char store_md5_value[16])
{
int ret = 0;
unsigned int off_set = 0;
int real_read_size = 0;
rec_fw_info fw_info;
off_set = fw_len - sizeof(rec_fw_info);
real_read_size = nbpatch_read(fw_tag, (const unsigned char*)&fw_info, off_set, sizeof(rec_fw_info),2);
if (real_read_size != sizeof(rec_fw_info)) {
ret = -1;
rec_printf("rec md5 read flash failed!");
}
rec_memcpy(store_md5_value, fw_info.image_md5_value, 16);
return ret;
}
static int rec_get_fw_md5(unsigned long fw_tag, unsigned int fw_len, unsigned char md5_value[16])
{
int ret = 0;
int fw_info_size = 0;
volatile unsigned int off_set = 0;
unsigned int read_size = 0;
int real_read_size = 0;
unsigned char *rd_buf = NULL;
rec_md5_context *rec_md5_ctx = NULL;
int bin_size = 0;
fw_info_size = sizeof(rec_fw_info);
if(fw_len <= fw_info_size) {
ret = -1;
rec_printf("recovery fw verify input parameters error!\n");
return ret;
}
rd_buf = rec_malloc(512);
if (rd_buf == NULL) {
ret = -1;
rec_printf("rec verify fw malloc failed\n");
return ret;
}
rec_md5_ctx = rec_malloc(sizeof(rec_md5_context));
if (rec_md5_ctx == NULL) {
ret = -1;
rec_printf("recovery malloc md5 ctx failed!\n");
rec_free(rd_buf);
return ret;
}
rec_md5_init(rec_md5_ctx);
rec_md5_starts(rec_md5_ctx);
off_set = 0;
bin_size = fw_len - fw_info_size;
while (off_set < bin_size) {
(bin_size - off_set >= 512) ? (read_size = 512)
: (read_size = bin_size - off_set);
real_read_size = nbpatch_read(fw_tag, rd_buf, off_set, read_size,2);
if (real_read_size < 0) {
ret = -1;
rec_printf("rec md5 read flash failed!");
goto REC_HASH_FAILED;
}
off_set += real_read_size;
rec_md5_update(rec_md5_ctx, (const unsigned char *)rd_buf, real_read_size);
}
rec_md5_finish(rec_md5_ctx, md5_value);
REC_HASH_FAILED:
rec_free(rd_buf);
rec_free(rec_md5_ctx);
return ret;
}
int rec_verify_firmware(unsigned long fw_tag, unsigned int fw_len)
{
unsigned char rec_fw_store_md5[16];
unsigned char rec_fw_real_md5[16];
rec_memset(rec_fw_store_md5, 0x00, 16);
rec_memset(rec_fw_real_md5, 0x00, 16);
if(rec_get_fw_md5(fw_tag, fw_len, rec_fw_real_md5) < 0) {
rec_printf("rec get fw md5 failed\n");
return -1;
}
if(rec_get_fw_store_md5(fw_tag, fw_len, rec_fw_store_md5) < 0) {
rec_printf("rec get fw md5 failed\n");
return -1;
}
if(rec_memcmp(rec_fw_real_md5, rec_fw_store_md5, sizeof(rec_fw_store_md5)) == 0) {
rec_printf("rec md5 verify successfully\n");
return 0;
}
return -1;
}

View file

@ -0,0 +1,6 @@
#ifndef _REC_VERIFY_FW_
#define _REC_VERIFY_FW_
int rec_verify_firmware(unsigned long fw_tag, unsigned int fw_len);
#endif

View file

@ -0,0 +1,177 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file xzdec.c
/// \brief deCompress from stdin to stdout in multi-call mode
///
//
// Author: ting.guit
//
// This file has been put into the public domain.
// You can do whatever you want with this file.
//
///////////////////////////////////////////////////////////////////////////////
#include "xzdec.h"
#if (defined BOARD_ESP8266)
#define DICT_SIZE (1<<12)
#else
#define DICT_SIZE (1<<14)
#endif
/* same with "enum xz_ret" */
static const char *errorinfo[] =
{"XZ_OK\n",
"XZ_STREAM_END\n",
"XZ_UNSUPPORTED_CHECK\n",
"XZ_MEM_ERROR\n",
"XZ_MEMLIMIT_ERROR\n",
"XZ_FORMAT_ERROR\n",
"XZ_OPTIONS_ERROR\n",
"XZ_DATA_ERROR\n",
"XZ_BUF_ERROR\n",
"BUG!\n"
};
int geterror(enum xz_ret ret)
{
if ( ret == XZ_OK || ret == XZ_STREAM_END )
{
return 0;
}
ret = ret > sizeof(errorinfo)/sizeof(errorinfo[0]) ?
sizeof(errorinfo)/sizeof(errorinfo[0]) - 1 : ret;
LOG("err: %d\n", ret);
return -1;
}
bool xz_init(struct xz_dec **s, struct xz_buf *b)
{
if(!b || !s) {
return false;
}
*s = xz_dec_init(XZ_DYNALLOC, DICT_SIZE);
if (*s == NULL) {
return false;
}
b->in_pos = 0;
b->in_size = 0;
return true;
}
bool xz_end(struct xz_dec *s)
{
xz_dec_end(s);
return true;
}
size_t xz_read(xzReadHandler *handler, struct xz_buf *b,struct xz_dec *s, unsigned long in_file, u_char *buf, int buf_len) {
if (handler == NULL || b == NULL || s == NULL || in_file == 0 || buf == NULL || buf_len < 0)
{ return 0; };
if(buf_len == 0) {
return 0;
}
enum xz_ret ret;
b->out = buf;
b->out_pos = 0;
b->out_size = buf_len;
while(true) {
if (b->in_pos == b->in_size && !nbpatch_eof(in_file) && handler->avail_size > 0) {
size_t readsize = IN_BUF_MAX > handler->avail_size ? handler->avail_size:IN_BUF_MAX;
b->in_size = nbpatch_read(in_file, handler->in_buf, handler->read_pos, readsize,0);
handler->avail_size -= readsize;
handler->read_pos += readsize;
b->in_pos = 0;
b->in = handler->in_buf;
}
ret = xz_dec_run(s, b);
if(geterror(ret)) {
return 0;
}
//LOG("\nhandler->avail_size %ld b->in_pos :%ld,b->in_size :%ld buflen %ld, %ld\n", handler->avail_size,b->in_pos, b->in_size, buf_len, b->out_pos);
if (handler->avail_size <= 0 && b->in_pos == b->in_size
&& b->out_pos < buf_len) {
return b->out_pos;
}
if (b->out_pos == buf_len) {
return buf_len;
}
}
}
#if LZMA
size_t xz_Read(xzReadHandler *handler, lzma_stream *strm, unsigned long in_file, u_char *buf, int buf_len)
{
if (handler == NULL || strm == NULL || in_file == 0 || buf == NULL || buf_len < 0)
{ return 0; };
if(buf_len == 0) {
LOG("read: 0\n");
return 0;
}
lzma_action action;
lzma_ret ret_xz;
size_t n;
strm->next_out = buf;
strm->avail_out = buf_len;
int in_finished = 0;
static unsigned long in_end = 0l;
while (true) {
if (strm->avail_in == 0 && !nbpatch_eof(in_file))
{
size_t readsize = IN_BUF_MAX > handler->avail_size ? handler->avail_size:IN_BUF_MAX;
n = nbpatch_read(in_file, handler->in_buf, handler->read_pos, readsize);
if (nbpatch_error(in_file))
{
return 0;
}
handler->avail_size -= readsize;
handler->read_pos += readsize;
in_end = in_file + handler->read_pos;
//LOG("in_end %ld, %ld\n", in_end, handler->avail_size);
strm->next_in = handler->in_buf;
strm->avail_in = n;
}
if (nbpatch_eof(in_end)) {
in_finished = 1;
}
action = in_finished ? LZMA_FINISH : LZMA_RUN;
/* decompress data */
ret_xz = lzma_code(strm, action);
if (!get_error(ret_xz)) {
return 0;
}
//LOG("\n strm->avail_in :%ld,strm->avail_out :%ld\n", strm->avail_in, strm->avail_out);
if (nbpatch_eof(in_file) && strm->avail_in == 0 && strm->avail_out > 0) {
LOG("in: %ld,out:%ld\n", strm->avail_in, strm->avail_out);
return buf_len - strm->avail_out;
}
if (strm->avail_out == 0) {
return buf_len;
}
}
return 0;
}
#endif

View file

@ -0,0 +1,31 @@
/*
* xzlib.h
*
* Created on: 20171114
* Author: ting.guit
*/
#ifndef XZDEC_H_
#define XZDEC_H_
#include "rec_pub.h"
#include "xz.h"
#include "nbpatch.h"
#define IN_BUF_MAX 1024
#define OUT_BUF_MAX 4096
#define RET_OK 0
#define RET_ERROR 1
typedef struct xzReadHandler {
uint8_t in_buf [IN_BUF_MAX];
size_t avail_size;
size_t read_pos;
} xzReadHandler;
bool xz_init(struct xz_dec **s, struct xz_buf *b);
bool xz_end(struct xz_dec *s);
size_t xz_read(xzReadHandler *handler, struct xz_buf *b,struct xz_dec *s, unsigned long in_file, u_char *buf, int buf_len);
#endif /* XZDEC_H_ */

View file

@ -0,0 +1,141 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include "rec_pub.h"
#define REC_2BOOT_VERSION SYSINFO_2BOOT_VERSION
int rec_2boot_cmd_flags = 0;
int rec_process_flags = 0;
int rec_2boot_cmd_check(void)
{
rec_flag_info_t rec_flag_info = {0, 0};
#ifdef AOS_OTA_2BOOT_CLI
unsigned char c = 0;
unsigned int i = 0;
rec_uart_init();
printf("\r\nPress key \'w\' into 2nd boot cmd, Waiting 100ms ... \r\n");
while(1) {
if(uart_recv_byte(&c) && ('w' == c)) {
printf("2nd boot cmd:\r\n");
return 0;
}
i ++;
if(i >= 100)break;
rec_delayms(1);
}
printf("Bootup, flag 0x%x, num 0x%x\r\n", rec_flag_info.flag, rec_flag_info.num);
#endif
rec_flash_init();
recovery_get_flag_info(&rec_flag_info);
if(REC_RECOVERY_VERIFY_FLAG == rec_flag_info.flag) {
rec_wdt_init(REC_WDT_TIMEOUT_MS);
rec_wdt_feed();
}
return 1;
}
#ifdef AOS_OTA_2BOOT_CLI
void print_usage()
{
printf("aos 2nd bootloader ver: " REC_2BOOT_VERSION "\r\n");
printf("[1] Query FW version info \r\n");
printf("[2] Update FW by UART YMODEM \r\n");
printf("[3] Update FW by CANbus \r\n");
printf("[4] Update FW by USB \r\n");
printf("[5] Active Part B\r\n");
printf("[6] Reboot\r\n");
printf("[h] Help info\r\n");
printf("Please input 1-6 to select functions\r\n");
}
#endif
void rec_2boot_cmd_process()
{
#ifdef AOS_OTA_2BOOT_CLI
PatchStatus *pstatus;
unsigned char c = 0;
pstatus = nbpatch_get_pstatus();
read_patch_status(pstatus);
print_usage();
printf("aos boot# ");
while(1) {
if(uart_recv_byte(&c)) {
if('w' == c) {
continue;
}
if( ('\r' == c) || ('\n' == c) ) {
printf("\r\naos boot# ");
continue;
}
printf("%c \r\n", c);
switch(c) {
case '1' :
printf("part A version: %s\r\n", pstatus->app_version);
printf("part B version: %s\r\n", pstatus->ota_version);
break;
case '2' :
rec_ymodem_cmd();
break;
case '3' :
case '4' :
printf("CMD %c not supported \r\n", c);
break;
case '5' :
printf("Active part A %s\r\n", pstatus->ota_version);
nbpatch_swap_app2ota(TRUE);
//说明此处激活备区版本后直接复位故此处不需要break
case '6' :
printf("Reboot \r\n");
rec_reboot();
break;
case 'h' :
print_usage();
break;
default:
printf("Please input 1-6 to select functions\r\n");
break;
}
printf("\r\naos boot# ");
rec_delayms(1);
}
}
#endif
}
void rec_2boot_roolback_count_clear()
{
rec_flag_info_t rec_flag_info;
recovery_get_flag_info(&rec_flag_info);
rec_flag_info.num = 0;
recovery_set_flag_info(&rec_flag_info);
return;
}
void rec_2boot_rollback(void)
{
#if (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_ABBACK)
nbpatch_swap_app2ota(TRUE);
#elif (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_ABBOOT)
#endif
rec_2boot_roolback_count_clear();
printf("rec rollback.");
rec_reboot();
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include <string.h>
#include "rec_pub.h"
#include "rec_define.h"
#include "rec_common.h"
#include "aos/hal/flash.h"
#include "aos/hal/wdg.h"
void rec_read_status(PatchStatus *status)
{
unsigned int offset = 0;
hal_flash_read( HAL_PARTITION_PARAMETER_1, &offset, status, sizeof(PatchStatus));
}
void rec_write_status(PatchStatus *status)
{
unsigned int offset = 0;
CRC16_Context contex;
uint16_t crc;
CRC16_Init(&contex);
CRC16_Update(&contex, status, sizeof(PatchStatus) - sizeof(uint16_t));
CRC16_Final(&contex, &crc);
status->patch_crc = crc;
offset = 0x00;
hal_flash_erase( HAL_PARTITION_PARAMETER_1, offset, sizeof(PatchStatus) );
hal_flash_write( HAL_PARTITION_PARAMETER_1, &offset, (const void *)status, sizeof(PatchStatus));
offset = 0x00;
hal_flash_erase( HAL_PARTITION_RECOVERY_BACK_PARA, offset, sizeof(PatchStatus) );
hal_flash_write( HAL_PARTITION_RECOVERY_BACK_PARA, &offset, (const void *)status, sizeof(PatchStatus));
}
void rec_startup_success()
{
PatchStatus status;
hal_wdg_finalize(0);
rec_read_status(&status);
status.upg_flag = REC_NORMAL_FLAG;
status.boot_count = 0;
rec_write_status(&status);
}

View file

@ -0,0 +1,10 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _REC_COMMON_H_
#define _REC_COMMON_H_
#include "rec_define.h"
void rec_read_status(PatchStatus *status);
void rec_startup_success();
#endif

View file

@ -0,0 +1,99 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _REC_DEFINE_H_
#define _REC_DEFINE_H_
#include <stddef.h>
#include <stdint.h>
#include "typedef.h"
#include "hal/soc/flash.h"
#include "rec_hal.h"
#ifndef OTA_MAX_VER_LEN
#define OTA_MAX_VER_LEN (64)
#endif
#ifndef OTA_MAX_VER_LEN
#define SPLISE_NUM (1024*1024/0x10000)
#endif
//0 recovery start, 1 normal start, 2 upgrade to another partion, 3 first start after recovery
#define REC_RECOVERY_START 0
#define REC_NORMAL_START 1
#define REC_UPGRADE_START 2 // just for esp8266
#define REC_ROLLBACK_START 3
#define REC_SWAP_UPDATE_START 4
#define REC_NORMAL_FLAG 0
#define REC_RECOVERY_FLAG 0x52455659 //"REVY"
#define REC_UPGRADE_FLAG 0x55504745 //"UPGE"
#define REC_ROLLBACK_FLAG 0x524F424B //"ROBK"
#define REC_RECOVERY_VERIFY_FLAG 0x52455656 //"REVV"
#define REC_SWAP_UPDATE_FLAG 0x52535546 //"RSUF"
#define REC_DUAL_UPDATE_FLAG 0x52445546 //"RDUF"
#define REC_MAX_NUM 3
#define REC_WDT_TIMEOUT_MS 6000
#define OTA_RECOVERY_TYPE_DIRECT 0 //直接恢复,无备份回滚
#define OTA_RECOVERY_TYPE_ABBACK 1 //双分区备份,支持回滚,单启动地址
#define OTA_RECOVERY_TYPE_ABBOOT 2 //双分区备份,支持回滚,双启动地址
#ifndef OTA_RECOVERY_TYPE
#define OTA_RECOVERY_TYPE OTA_RECOVERY_TYPE_DIRECT
#endif
typedef enum {
OTA_FLASH_STATUS_FREE = 0, // 空闲
OTA_FLASH_STATUS_USED = 1, // 已占用
OTA_FLASH_STATUS_REVY = 2, // 已恢复出来
OTA_FLASH_STATUS_SYNC = 3, // 已与主区同步
OTA_FLASH_STATUS_NULL, // 无效
} REC_FLASH_STAT_E;
typedef enum {
REC_PHASE_INIT = 0, // 初始化
REC_PHASE_NBPATCH = 1, // 差分恢复中
REC_PHASE_COPY = 2, // APP拷贝到OTA
REC_PHASE_SWAP = 3, // APP与OTA交换
REC_PHASE_SWITCH = 4, // 切换启动地址仅针对OTA_RECOVERY_TYPE_ABBOOT
REC_PHASE_DONE, // 完成
} REC_STAT_PHASE_E;
//该结构体仅用于读flash时使用写flash时需要使用结构PatchStatus
typedef struct
{
unsigned int flag; // recovery标志
unsigned int num; // recovery序号
} rec_flag_info_t;
//该结构体存储与PARAM1长度不能超过4k
typedef struct
{
unsigned int dst_adr;
unsigned int src_adr;
unsigned int len;
unsigned short crc;
unsigned int upg_flag;
unsigned char boot_count;
unsigned int splict_size;
unsigned short recovery_phase;
unsigned int seekpos;
unsigned int patched_size;
unsigned int pending_size;
unsigned short status;
unsigned char diff;
unsigned short num;
unsigned short swap_addr; // 分区内相对于起始地址的偏移再除以分片size
unsigned short swaped_idx; // 分片片内相对于起始分片的偏移再除以4k
unsigned short swaped_state; //0表示APP数据还在APP区OTA数据在OTA区1表示APP数据在备份区2表示OTA数据拷贝到APP区3表示完成交换
unsigned char patch_index; // 进入patch模式的次数。如果一次patch完成该值为0否则会增加
unsigned char REC_FLASH_STAT_E[SPLISE_NUM]; // 每1byte代表64k的状态REC_FLASH_STAT_E
unsigned short ota_addr[OTA_ADDR_NUM]; //OTA数据的地址序号乘以64k后为分区偏移最多256k即最多4个64k。
char ota_version[OTA_MAX_VER_LEN];
char app_version[OTA_MAX_VER_LEN];
unsigned short patch_crc;
}__attribute__((packed)) PatchStatus;
#endif

View file

@ -0,0 +1,498 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdarg.h>
#include "rec_pub.h"
/*******************************************************************************/
void *rec_memcpy(void *dest, const void *src, size_t n)
{
if (NULL == dest || NULL == src)
return NULL;
char *tempDest = (char *)dest;
char *tempSrc = (char *)src;
while (n-- > 0)
*tempDest++ = *tempSrc++;
return dest;
}
void *rec_memset(void *s, int c, size_t n)
{
if (NULL == s)
return NULL;
char * tmpS = (char *)s;
while(n-- > 0)
*tmpS++ = c;
return s;
}
size_t rec_strlen(char * str)
{
const char *eos = str;
while( *eos++ ) ;
return( eos - str - 1 );
}
char *rec_strcat (char * dst, const char * src)
{
char * cp = dst;
while( *cp )
cp++; /* find end of dst */
while( cp && src)
{
*cp++ = *src++ ; /* Copy src to end of dst */
}
return( dst ); /* return dst */
}
int rec_memcmp(const void * buf1, const void * buf2, size_t count)
{
if (!count)
return(0);
while ( --count && *(char *)buf1 == *(char *)buf2 ) {
buf1 = (char *)buf1 + 1;
buf2 = (char *)buf2 + 1;
}
return( *((unsigned char *)buf1) - *((unsigned char *)buf2) );
}
void *rec_memmove(void *dest, const void *src, size_t count)
{
char *tmp;
const char *s;
if (dest <= src) {
tmp = dest;
s = src;
while (count--)
*tmp++ = *s++;
} else {
tmp = dest;
tmp += count;
s = src;
s += count;
while (count--)
*--tmp = *--s;
}
return dest;
}
/*******************************************************************************/
#define PRT_BUFF_LEN 256
int rec_puts(const char *str)
{
rec_uart_send_string((char *)str);
return 1;
}
char* uitoa_16(uint32_t value, char *str){
char reverse[36];
char *p = reverse;
*p++ = '\0';
do{
*p++ = "0123456789abcdef"[value%16];
value /= 16;
}while(value != 0);
p--;
while (p >= reverse){
*str++ = *p--;
}
return str;
}
char* uitoa_10(uint32_t value, char *str){
char reverse[36];
char *p = reverse;
*p++ = '\0';
do{
*p++ = "0123456789"[value%10];
value /= 10;
}while(value != 0);
p--;
while (p >= reverse){
*str++ = *p--;
}
return str;
}
/* only support %x %p %d %c %s */
void vsprint(char *buf, const char *fmt, va_list args)
{
char *p = NULL;
char *s = NULL;
int i = 0;
int len = 0;
int waiting_fmt = 0;
va_list next_arg = args;
for (p = buf; *fmt;)
{
if (waiting_fmt == 0 && *fmt != '%')
{
*p++ = *fmt++;
continue;
}
if ( waiting_fmt > 8 )
{
puts("Non supported format!\r\n");
*p = '\0';
return;
}
fmt++;
switch (*fmt){
case 'd':
case 'u':
uitoa_10(va_arg(next_arg, unsigned int),p);
p += strlen(p);
waiting_fmt = 0;
fmt++;
break;
case 'x':
case 'p':
uitoa_16(va_arg(next_arg, unsigned int),p);
p += strlen(p);
waiting_fmt = 0;
fmt++;
break;
case 'c':
*p++ = va_arg(next_arg, int);
waiting_fmt = 0;
fmt++;
break;
case 's':
*p = '\0';
s = va_arg(args, char *);
if (!s) {
s = "<NULL>";
len = 7;
} else {
len = (strlen(s) > 128 ? 128 : strlen(s));
}
for (i = 0; i < len; ++i) *p++ = *s++;
waiting_fmt = 0;
fmt++;
break;
default:
waiting_fmt++;
break;
}
}
*p = '\0';
}
int rec_printf(const char *fmt, ...)
{
char buf[PRT_BUFF_LEN];
va_list args;
memset(buf, 0, sizeof(buf));
va_start(args, fmt);
vsprint(buf, fmt, args);
va_end(args);
return puts(buf);
}
/*******************************************************************************/
/********* RECOVERY heap config: *********/
extern void *_rec_heap_start;
extern void *_rec_heap_end;
extern void *_rec_heap_len;
/* Heap should align to REC_HEAP_ALIGNMENT */
#define REC_HEAP_BASE ((intptr_t)&_rec_heap_start)
/* Size should be smaller than ~REC_HEAP_MAGIC */
#define REC_HEAP_SIZE ((intptr_t)&_rec_heap_len)
/********* RECOVERY heap config end ******/
#define ALIGN(x,a) (((x) + (a) - 1) & ~((a) - 1))
#define REC_HEAP_ALIGNMENT 4
/* At the beginning of allocated memory */
#define REC_HEAP_BLK_HEAD_SIZE ALIGN(sizeof(blk_head_t), REC_HEAP_ALIGNMENT)
/* Block sizes must not get too small. */
#define REC_HEAP_BLK_MIN ((REC_HEAP_BLK_HEAD_SIZE) << 1)
/* blk belong to APP, magic set
blk belong to free list, magic clear */
#define REC_HEAP_MAGIC (0xF0000000)
/* block head, before each blocks */
typedef struct blklist
{
/* free memory block list, order by address*/
struct blklist *next;
/* when blk in APP: REC_HEAP_MAGIC & size
when blk in freelist: only size
size include blk_head_t self */
size_t magic_size;
} blk_head_t;
/* free block list: order by address, from low to high */
/* first free block. */
static blk_head_t freelist_head;
/* point to last free block. */
static blk_head_t *freelist_tail;
/* For statistic. */
static size_t heap_free_size = REC_HEAP_SIZE;
static size_t heap_free_size_min = REC_HEAP_SIZE;
/* Init heap, with one free block */
static void heap_init(void)
{
blk_head_t *free_blk;
if ( REC_HEAP_BASE%REC_HEAP_ALIGNMENT != 0
|| REC_HEAP_SIZE > (~REC_HEAP_MAGIC)
|| REC_HEAP_SIZE < REC_HEAP_BLK_MIN*2 )
{
printf("err:param invalid!\n");
return;
}
freelist_head.next = (void *) REC_HEAP_BASE;
freelist_head.magic_size = (size_t) 0;
freelist_tail = (void *)(REC_HEAP_BASE + ALIGN(REC_HEAP_SIZE, REC_HEAP_ALIGNMENT) -
REC_HEAP_BLK_HEAD_SIZE);
freelist_tail->next = NULL;
freelist_tail->magic_size = 0;
/* Only one block when init. */
free_blk = (void *) REC_HEAP_BASE;
free_blk->next = freelist_tail;
free_blk->magic_size = (size_t)freelist_tail - (size_t) free_blk;
heap_free_size = free_blk->magic_size;
heap_free_size_min = free_blk->magic_size;
}
static void heap_freeblk_insert(blk_head_t *blk_insert)
{
blk_head_t *blk_before; /* before the blk_insert */
blk_head_t *blk_after; /* after the blk_insert */
/* freelist is ordered by address, find blk_before */
for (blk_before = &freelist_head; blk_before->next < blk_insert; blk_before = blk_before->next)
{
if (blk_before == freelist_tail)
{
return;
}
}
blk_after = blk_before->next;
/* now: blk_before < blk_insert < blk_after */
/* try to merge blk_before and blk_insert */
if ((char *)blk_before + blk_before->magic_size == (char *)blk_insert)
{
blk_before->magic_size += blk_insert->magic_size;
blk_insert = blk_before;
}
else
{
/* do not merge, just insert new node to freelist */
blk_before->next = blk_insert;
}
/* try to merge blk_insert and blk_after */
if (blk_after != freelist_tail &&
(char *)blk_insert + blk_insert->magic_size == (char *)blk_after)
{
blk_insert->magic_size += blk_after->magic_size;
blk_insert->next = blk_after->next;
}
else
{
/* do not merge, just insert new node to freelist */
blk_insert->next = blk_after;
}
}
static void *heap_malloc(size_t alloc_size)
{
blk_head_t *blk_alloc;
blk_head_t *blk_prev;
blk_head_t *blk_left;
//krhino_sched_disable();
/* first call to malloc, init is needed */
if (freelist_tail == NULL)
{
heap_init();
}
if ((alloc_size == 0)
|| (alloc_size > heap_free_size))
{
/* not enough memory */
//krhino_sched_enable();
return NULL;
}
alloc_size += REC_HEAP_BLK_HEAD_SIZE;
alloc_size = ALIGN(alloc_size, REC_HEAP_ALIGNMENT);
/* find a free block bigger than alloc_size */
blk_prev = &freelist_head;
blk_alloc = freelist_head.next;
while ((blk_alloc->magic_size < alloc_size) && (blk_alloc->next != NULL))
{
blk_prev = blk_alloc;
blk_alloc = blk_alloc->next;
}
if (blk_alloc->next == NULL)
{
/* this means "blk_alloc == freelist_tail" */
//krhino_sched_enable();
return NULL;
}
/* delete blk_alloc from freelist */
blk_prev->next = blk_alloc->next;
/* check whether blk_alloc can split */
if (blk_alloc->magic_size - alloc_size > REC_HEAP_BLK_MIN)
{
/* split */
blk_left = (void *)((char *)blk_alloc + alloc_size);
blk_left->magic_size = blk_alloc->magic_size - alloc_size;
blk_alloc->magic_size = alloc_size;
/* Insert the new block into the list of free blocks. */
heap_freeblk_insert(blk_left);
}
/* update statistic */
heap_free_size -= blk_alloc->magic_size;
if (heap_free_size < heap_free_size_min)
{
heap_free_size_min = heap_free_size;
}
//krhino_sched_enable();
/* blk belong to APP, magic set */
blk_alloc->magic_size |= REC_HEAP_MAGIC;
blk_alloc->next = NULL;
/* app used addr is after blk_head_t */
return (void *)((char *)blk_alloc + REC_HEAP_BLK_HEAD_SIZE);
}
static void heap_free(void *pfree)
{
blk_head_t *free_blk;
if (pfree == NULL)
{
return;
}
/* app used addr is after blk_head_t */
free_blk = (blk_head_t *)((char *)pfree - REC_HEAP_BLK_HEAD_SIZE);
/* blk damaged check */
if (free_blk->next != NULL
||(free_blk->magic_size & REC_HEAP_MAGIC) != REC_HEAP_MAGIC)
{
printf("err:block destroyed!\n");
return;
}
/* blk belong to free list, magic clear */
free_blk->magic_size &= ~REC_HEAP_MAGIC;
/* update statistic */
heap_free_size += free_blk->magic_size;
//krhino_sched_disable();
heap_freeblk_insert(free_blk);
//krhino_sched_enable();
}
void *rec_malloc(size_t alloc_size)
{
return heap_malloc(alloc_size);
}
void rec_free(void *pfree)
{
heap_free(pfree);
}
size_t rec_freesize(void)
{
return heap_free_size;
}
size_t rec_freesize_min(void)
{
return heap_free_size_min;
}
/*******************************************************************************/
static uint16_t UpdateCRC16(uint16_t crcIn, uint8_t byte)
{
uint32_t crc = crcIn;
uint32_t in = byte | 0x100;
do {
crc <<= 1;
in <<= 1;
if (in & 0x100) {
++crc;
}
if (crc & 0x10000) {
crc ^= 0x1021;
}
} while (!(in & 0x10000));
return crc & 0xffffu;
}
void rec_CRC16_Init( CRC16_Context *inContext )
{
inContext->crc = 0;
}
void rec_CRC16_Update( CRC16_Context *inContext, const void *inSrc, size_t inLen )
{
const uint8_t *src = (const uint8_t *) inSrc;
const uint8_t *srcEnd = src + inLen;
while ( src < srcEnd ) {
inContext->crc = UpdateCRC16(inContext->crc, *src++);
}
}
void rec_CRC16_Final( CRC16_Context *inContext, uint16_t *outResult )
{
inContext->crc = UpdateCRC16(inContext->crc, 0);
inContext->crc = UpdateCRC16(inContext->crc, 0);
*outResult = inContext->crc & 0xffffu;
}

View file

@ -0,0 +1,224 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#if (defined BOARD_ESP8266)
#include "k_api.h"
#endif
#include "rec_pub.h"
#include "nbpatch.h"
unsigned int *reg_flash_flags = NULL;
#if (defined BOARD_ESP8266)
extern void vPortETSIntrLock(void);
extern void vPortETSIntrUnlock(void);
#endif
////////////////////////////////////////////////////////////////////////////////////////////////
void recovery_get_flag_info(rec_flag_info_t *rec_flag_info)
{
int ret = 0;
PatchStatus pstatus;
memset(&pstatus, 0, sizeof(PatchStatus));
ret = patch_flash_read(HAL_PARTITION_PARAMETER_1,
(unsigned char *) &pstatus, 0, sizeof(PatchStatus));
if(ret < 0) {
LOG("read flag err.");
return;
}
rec_flag_info->flag = pstatus.upg_flag;
rec_flag_info->num = pstatus.boot_count;
}
void recovery_set_flag_info(rec_flag_info_t *rec_flag_info)
{
int ret = 0;
PatchStatus pstatus;
memset(&pstatus, 0, sizeof(PatchStatus));
ret = patch_flash_read(HAL_PARTITION_PARAMETER_1,
(unsigned char *) &pstatus, 0, sizeof(PatchStatus));
if(ret < 0) {
LOG("read err");
return;
}
pstatus.upg_flag = rec_flag_info->flag;
pstatus.boot_count = rec_flag_info->num;
save_patch_status(&pstatus);
}
/* return value: 0 recovery start, 1 normal start, 2 upgrade to another partion */
int recovery_check(void)
{
int flag = REC_NORMAL_START;
rec_flag_info_t rec_flag_info = {0, 0};
rec_flash_init();
recovery_get_flag_info(&rec_flag_info);
switch (rec_flag_info.flag) {
case REC_RECOVERY_FLAG :
flag = REC_RECOVERY_START;
break;
case REC_SWAP_UPDATE_FLAG :
flag = REC_SWAP_UPDATE_START;
break;
case REC_RECOVERY_VERIFY_FLAG :
if(rec_flag_info.num <= REC_MAX_NUM) {
rec_flag_info.num += 1;
recovery_set_flag_info(&rec_flag_info);
flag = REC_NORMAL_START;
} else { // more than 3 startup failures, automatic rollback
rec_flag_info.flag = REC_ROLLBACK_FLAG;
rec_flag_info.num = 0;
recovery_set_flag_info(&rec_flag_info);
flag = REC_ROLLBACK_START;
}
break;
case REC_ROLLBACK_FLAG :
flag = REC_ROLLBACK_START;
break;
#if (defined BOARD_ESP8266)
case REC_UPGRADE_FLAG :
flag = REC_UPGRADE_START;
break;
#endif
default:
flag = REC_NORMAL_START;
break;
}
return flag;
}
int recovery_flag_update()
{
int flag = REC_NORMAL_START;
rec_flag_info_t rec_flag_info = {0, 0};
rec_flag_info_t rec_flag_set = {REC_NORMAL_FLAG, 0};
recovery_get_flag_info(&rec_flag_info);
printf("flag = 0x%x\n", rec_flag_info.flag);
switch (rec_flag_info.flag) {
case REC_RECOVERY_FLAG :
if(rec_flag_info.num <= REC_MAX_NUM) {
rec_flag_set.flag = REC_RECOVERY_FLAG;
rec_flag_set.num = rec_flag_info.num + 1;
}
flag = REC_RECOVERY_START;
break;
case REC_SWAP_UPDATE_FLAG :
flag = REC_SWAP_UPDATE_START;
break;
case REC_ROLLBACK_FLAG :
flag = REC_ROLLBACK_START;
break;
#if (defined BOARD_ESP8266)
case REC_UPGRADE_FLAG :
flag = REC_UPGRADE_START;
break;
#endif
default:
flag = REC_RECOVERY_START;
break;
}
recovery_set_flag_info(&rec_flag_set);
return flag;
}
void recovery_error(void *errinfo)
{
rec_err_print(errinfo);
rec_reboot();
}
void rec_success()
{
rec_flag_info_t rec_flag_info = {0, 0};
#if (defined BOARD_ESP8266)
rec_flag_info.flag = REC_UPGRADE_FLAG;
#else
rec_flag_info.flag = REC_RECOVERY_VERIFY_FLAG;
#endif
recovery_set_flag_info(&rec_flag_info);
rec_delayms(500);
rec_reboot();
}
void rec_start()
{
rec_flag_info_t rec_flag_info = {0, 0};
rec_flag_info.flag = REC_RECOVERY_FLAG;
recovery_set_flag_info(&rec_flag_info);
rec_delayms(500);
LOG("reboot ...\r\n");
rec_reboot();
}
void recovery_process()
{
int ret;
/* recovery start */
ret = nbpatch_main();
/* recovery end */
#if (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_DIRECT) //
ret = 0;
#endif
if(ret == 0) {
LOG("rec succ!\r\n");
rec_success();
}
else {
LOG("rec fail!\r\n");
rec_reboot();
}
}
#if (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_ABBACK)
void rec_swap_update_process()
{
int ret;
ret = nbpatch_swap_app2ota(TRUE);
if(ret == 0) {
LOG("update succ!\r\n");
rec_success();
}
else {
LOG("update fail!\r\n");
rec_reboot();
}
}
#endif
void recovery_main()
{
int flag = 0;
#if (defined BOARD_ESP8266)
RHINO_CPU_INTRPT_DISABLE_NMI();
vPortETSIntrLock();
#endif
rec_hal_init();
flag = recovery_flag_update();
#if (defined BOARD_ESP8266)
if((REC_UPGRADE_START == flag) || (REC_ROLLBACK_START == flag)) {
vPortETSIntrUnlock();
RHINO_CPU_INTRPT_ENABLE_NMI();
rec_upgrade_reboot();
return;
}
// switch the stack space, it's very important for esp8266
__asm__ volatile("movi a1, 0x3FFFFFF0" : : : "memory");
#else
rec_wdt_init(REC_WDT_TIMEOUT_MS);
rec_wdt_feed();
if(REC_ROLLBACK_START == flag) {
rec_2boot_rollback();
return;
}
#if (AOS_OTA_RECOVERY_TYPE == OTA_RECOVERY_TYPE_ABBACK)
else if (REC_SWAP_UPDATE_START == flag) {
rec_swap_update_process();
return;
}
#endif
#endif
recovery_process();
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _REC_PUB_H_
#define _REC_PUB_H_
#include "rec_define.h"
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (1)
#endif
typedef unsigned char u_char;
typedef signed long off_t;
#define LOG(fmt, ...) printf("%d: "fmt"\r\n", __LINE__, ##__VA_ARGS__)
/* !!!attention!!! do not use any libc func in fota update process */
#define memset rec_memset
#define memcpy rec_memcpy
#define memcmp rec_memcmp
#define memmove rec_memmove
#define strlen rec_strlen
#define strcat rec_strcat
#define puts rec_puts
#define printf rec_printf
#define malloc rec_malloc
#define free rec_free
void *rec_memset(void *s, int c, size_t n);
void *rec_memcpy(void *dest, const void *src, size_t n);
int rec_memcmp(const void * buf1, const void * buf2, size_t count);
void *rec_memmove(void *dest, const void *src, size_t count);
size_t rec_strlen(char * str);
char *rec_strcat (char * dst, const char * src);
int rec_puts(const char *str);
int rec_printf(const char *format, ...);
void *rec_malloc(size_t alloc_size);
void rec_free(void *pfree);
size_t rec_freesize(void);
size_t rec_freesize_min(void);
/* CRC lib */
#define CRC16_Init rec_CRC16_Init
#define CRC16_Update rec_CRC16_Update
#define CRC16_Final rec_CRC16_Final
typedef struct {
uint16_t crc;
} CRC16_Context;
void rec_CRC16_Init( CRC16_Context *inContext );
void rec_CRC16_Update( CRC16_Context *inContext, const void *inSrc, size_t inLen );
void rec_CRC16_Final( CRC16_Context *inContext, unsigned short *outResult );
/* hal api for fota update process, defined by soc */
void rec_start();
void rec_hal_init();
void rec_uart_init();
void rec_reboot();
void rec_err_print(void *errinfo);
void rec_delayms(volatile int ms);
void rec_uart_send(unsigned char *buff, int len);
void rec_uart_send_string(char *buff);
unsigned char uart_recv_byte(unsigned char *c);
void rec_uart_send_byte(unsigned char buff);
void rec_flash_init(void);
void rec_flash_erase(unsigned long offset);
void rec_flash_read_data(unsigned char *buffer, unsigned long offset, unsigned long len);
void rec_flash_write_data(unsigned char *buffer, unsigned long offset, unsigned long len);
hal_logic_partition_t *rec_flash_get_info(hal_partition_t pno);
void rec_wdt_init(unsigned int timeout_ms);
void rec_wdt_start();
void rec_wdt_feed();
void rec_wdt_stop();
void rec_2boot_rollback();
void recovery_get_flag_info(rec_flag_info_t *rec_flag_info);
void recovery_set_flag_info(rec_flag_info_t *rec_flag_info);
void rec_ymodem_cmd();
#endif //_REC_PUB_H_

View file

@ -0,0 +1,322 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include "rec_pub.h"
#define YMODEM_OK 0
#define YMODEM_ERR (-1)
#define YMODEM_SOH 0x01
#define YMODEM_STX 0x02
#define YMODEM_EOT 0x04
#define YMODEM_ACK 0x06
#define YMODEM_NAK 0x15
#define YMODEM_CAN 0x18
#define YMODEM_CCHAR 'C'
#define SOH_DATA_LEN 128
#define STX_DATA_LEN 1024
#define UART_RECV_TIMEOUT 400000
#define YMODEM_STATE_INIT 0
#define YMODEM_STATE_WAIT_HEAD 1
#define YMODEM_STATE_WAIT_DATA 2
#define YMODEM_STATE_WAIT_END 3
#define YMODEM_STATE_WAIT_NEXT 4
static unsigned int ymodem_flash_addr = 0;
static unsigned int ymodem_flash_size = 0;
static unsigned short cal_crc(void *addr, size_t len)
{
unsigned short crc = 0;
CRC16_Context crc_context;
CRC16_Init(&crc_context);
CRC16_Update(&crc_context, addr, len);
CRC16_Final(&crc_context, &crc);
return crc;
}
unsigned int ymodem_str2int(char *buf, unsigned int buf_len)
{
int type = 10;
int value = 0;
int i = 0;
if ( (buf[0] == '0') && (buf[1] == 'x' || buf[1] == 'X') ) {
type = 16;
buf += 2;
}
for (i = 0; i < buf_len; buf++, i++) {
if(*buf == 0) {
return value;
}
if (*buf >= '0' && *buf <= '9') {
value = value * type + *buf - '0';
} else {
if(10 == type) {
return value;
}
if (*buf >= 'A' && *buf <= 'F') {
value = value * 16 + *buf - 'A' + 10;
}
else if (*buf >= 'a' && *buf <= 'f') {
value = value * 16 + *buf - 'a' + 10;
} else {
return value;
}
}
}
return value;
}
unsigned int ymodem_recv_bytes(unsigned char *buffer, unsigned int nbytes, unsigned int timeout)
{
int ret = 0;
unsigned char c = 0;
unsigned int i = 0;
unsigned int t = 0;
while ((i < nbytes) && (t < timeout)) {
ret = uart_recv_byte(&c);
if (1 == ret) {
buffer[i] = c;
i++;
}
t++;
}
return i;
}
int ymodem_data_head_parse(unsigned char data_type)
{
int i = 0;
int ret = YMODEM_ERR;
int lp = 0;
size_t buf_len = 0;
unsigned char *buffer = NULL;
unsigned short crc = 0;
unsigned int value = 0;
buf_len = ((YMODEM_SOH == data_type) ? SOH_DATA_LEN : STX_DATA_LEN) + 4;
buffer = malloc(buf_len);
memset(buffer, 0, buf_len);
//SOH HEAD
value = ymodem_recv_bytes(buffer, buf_len, UART_RECV_TIMEOUT);
if( (buf_len != value) || (0 != buffer[0]) || (0xFF != buffer[1]) ) {
goto err_exit;
}
//check CRC
crc = cal_crc(&buffer[2], buf_len-4);
if (((crc >> 8) != buffer[buf_len - 2]) || ((crc & 0xFF) != buffer[buf_len - 1])) {
goto err_exit;
}
//parse file name && file length
for(i = 2; i < buf_len - 2; i++) {
if((0 == buffer[i]) && (0 == lp)) {
lp = i + 1;
continue;
}
if((0 == buffer[i]) && (0 != lp)) {
//from buffer[lp] to buffer[i] is file length ascii
value = ymodem_str2int((char *)&buffer[lp], i - lp);
if (0 == value) {
goto err_exit;
}
ymodem_flash_size = value;
break;
}
}
for (i = 2; i < buf_len - 4; i ++) {
if (buffer[i] != 0) {
ret = YMODEM_OK;
}
}
err_exit:
free(buffer);
return ret;
}
void ymodem_write_data_to_flash(unsigned char *buffer, unsigned int addr, unsigned int len)
{
unsigned int write_len = len;
static unsigned int erase_addr = 0;
if(addr + len > ymodem_flash_addr + ymodem_flash_size) {
write_len = ymodem_flash_addr + ymodem_flash_size - addr;
}
if( (erase_addr + FLASH_SECTOR_SIZE) < addr + write_len) {
erase_addr = (addr + write_len) / FLASH_SECTOR_SIZE * FLASH_SECTOR_SIZE;
rec_flash_erase(erase_addr);
}
rec_flash_write_data(buffer, addr, write_len);
}
int ymodem_data_parse(unsigned char data_type, unsigned int *addr)
{
int ret = YMODEM_ERR;
size_t buf_len = 0;
unsigned short crc = 0;
unsigned int value = 0;
unsigned char *buffer = NULL;
buf_len = ((YMODEM_SOH == data_type) ? SOH_DATA_LEN : STX_DATA_LEN) + 4;
buffer = malloc(buf_len);
memset(buffer, 0, buf_len);
if(NULL == addr) {
goto err_exit;
}
//SOH HEAD
value = ymodem_recv_bytes(buffer, buf_len, UART_RECV_TIMEOUT);
if ((buf_len != value) || (0xFF != buffer[0] + buffer[1])) {
goto err_exit;
}
//check CRC
crc = cal_crc(&buffer[2], buf_len - 4);
if (((crc >> 8) != buffer[buf_len - 2]) || ((crc & 0xFF) != buffer[buf_len - 1])) {
goto err_exit;
}
//write data fo flash
ymodem_write_data_to_flash(&buffer[2], *addr, buf_len - 4);
*addr += buf_len - 4;
ret = YMODEM_OK;
err_exit :
free(buffer);
return ret;
}
int ymodem_recv_file(unsigned int flash_addr)
{
int i = 0;
int ret = 0;
int state = 0;
unsigned char c = 0;
unsigned int bytes = 0;
unsigned int addr = flash_addr;
//send C
while (1)
{
if(state != YMODEM_STATE_INIT) {
bytes = ymodem_recv_bytes(&c, 1, 5000);
}
switch (state)
{
case YMODEM_STATE_INIT: // send 'C'
if(i % 500 == 0) {
rec_uart_send_byte(YMODEM_CCHAR);
}
state = YMODEM_STATE_WAIT_HEAD;
break;
case YMODEM_STATE_WAIT_HEAD: // wait SOH
if(1 != bytes) {
i ++;
state = 0;
break;
}
if(( YMODEM_SOH == c ) || ( YMODEM_STX == c )) {
ret = ymodem_data_head_parse(c);
if (ret == YMODEM_OK) {
rec_uart_send_byte(YMODEM_ACK);
rec_delayms(100);
rec_uart_send_byte(YMODEM_CCHAR);
state = YMODEM_STATE_WAIT_DATA;
break;
} else {
//end
rec_uart_send_byte(YMODEM_ACK);
rec_delayms(1000);
return 0;
}
} else if (3 == c) { // ctrl+c abort ymodem
printf("Abort ymodem file.\n");
return 0;
}
break;
case YMODEM_STATE_WAIT_DATA: //receive data
if(1 == bytes) {
if( (YMODEM_SOH == c) || (YMODEM_STX == c) ) {
ret = ymodem_data_parse(c, &addr);
if (ret == YMODEM_OK) {
rec_uart_send_byte(YMODEM_ACK);
}
} else if( YMODEM_EOT == c ) {
rec_uart_send_byte(YMODEM_NAK);
state = YMODEM_STATE_WAIT_END;
}
}
break;
case YMODEM_STATE_WAIT_END: //receive end eot
if ((1 == bytes) && (YMODEM_EOT == c)) {
rec_uart_send_byte(YMODEM_ACK);
i = 0;
state = YMODEM_STATE_INIT;
}
break;
default:
state = YMODEM_STATE_INIT;
break;
}
}
return 0;
}
void rec_ymodem_cmd()
{
unsigned char c = 0;
int i = 0;
unsigned int addr = 0;
char buf[64];
printf("\r\nPlease input flash addr: ");
memset(buf, 0, 64);
while(1) {
if(uart_recv_byte(&c)) {
printf("%c", c);
if((c == '\r') || (i >= 64)) {
break;
}
buf[i] = c;
i ++;
}
}
printf("\nflash addr:%s \n", buf);
addr = ymodem_str2int(buf, 64);
if(addr == 0) {
printf("addr %s is invalid!\n", buf);
return;
}
printf("Please start ymodem ... (press ctrl+c to cancel)\n");
ymodem_flash_addr = addr;
ymodem_recv_file(addr);
printf("Rece flash addr 0x%x \n", addr);
}

View file

@ -0,0 +1,76 @@
## Contents
```sh
xz
├── aos.mk
├── Config.in
├── linux
│   ├── include
│   │   └── linux
│   │   ├── decompress
│   │   │   └── unxz.h
│   │   └── xz.h
│   └── lib
│   ├── decompress_unxz.c
│   └── xz
│   ├── xz_config.h
│   ├── xz_crc32.c
│   ├── xz_crc64.c
│   ├── xz_dec_bcj.c
│   ├── xz_dec_lzma2.c
│   ├── xz_dec_stream.c
│   ├── xz_lzma2.h
│   ├── xz_private.h
│   └── xz_stream.h
└── README.md
```
## Introduction
An over-the-air update is the wireless delivery of new software or data to smart devices, especially IoT devices. Wireless carriers and OEMs typically use over-the-air (OTA) updates to deploy the new operating systems and the software app to these devices.
## Features
1. Differential incremental upgrade;
2. Dual banker:AB partition upgrade to support rollback to old version;
3. Secure download channel;
4. Firmware digital signature verification.
## Dependencies
Linkkit MQTT channel
Linkkit CoAP channel
## API
User service APIs:
```c
/*OTA export service APIs*/
int ota_service_init(ota_service_t* ctx);
int ota_service_deinit(ota_service_t* ctx);
```
for sample code please check [otaapp](../../../app/example/otaapp/).
## RTOS build
```sh
cd ROOT DIR;
aos make otaapp@board;
```
## run CLI CMDs
1. connect network
```
netmgr connect ssid passwd
```
2. run ota demo
```
OTA_APP pk dn ds ps
```
## Reference
* [AliOS-Things OTA使用说明](https://github.com/alibaba/AliOS-Things/wiki/OTA-Tutorial)
* [OTA flash分区说明文档](https://github.com/alibaba/AliOS-Things/wiki/OTA-Flash-Partitions-Overview)
* [云端一体化差分+安全升级AliOS Things物联网升级“利器”](https://mp.weixin.qq.com/s/Pb8Lleuww1r7qQJHu5ON8g)

View file

@ -0,0 +1,19 @@
/*
* Wrapper for decompressing XZ-compressed kernel, initramfs, and initrd
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#ifndef DECOMPRESS_UNXZ_H
#define DECOMPRESS_UNXZ_H
int unxz(unsigned char *in, int in_size,
int (*fill)(void *dest, unsigned int size),
int (*flush)(void *src, unsigned int size),
unsigned char *out, int *in_used,
void (*error)(char *x));
#endif

View file

@ -0,0 +1,298 @@
/*
* XZ decompressor
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <http://7-zip.org/>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#ifndef XZ_H
#define XZ_H
#include "rec_pub.h"
#ifdef __cplusplus
extern "C" {
#endif
/* In Linux, this is used to make extern functions static when needed. */
#ifndef XZ_EXTERN
# define XZ_EXTERN extern
#endif
/**
* enum xz_mode - Operation mode
*
* @XZ_SINGLE: Single-call mode. This uses less RAM than
* than multi-call modes, because the LZMA2
* dictionary doesn't need to be allocated as
* part of the decoder state. All required data
* structures are allocated at initialization,
* so xz_dec_run() cannot return XZ_MEM_ERROR.
* @XZ_PREALLOC: Multi-call mode with preallocated LZMA2
* dictionary buffer. All data structures are
* allocated at initialization, so xz_dec_run()
* cannot return XZ_MEM_ERROR.
* @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is
* allocated once the required size has been
* parsed from the stream headers. If the
* allocation fails, xz_dec_run() will return
* XZ_MEM_ERROR.
*
* It is possible to enable support only for a subset of the above
* modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC,
* or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled
* with support for all operation modes, but the preboot code may
* be built with fewer features to minimize code size.
*/
enum xz_mode {
XZ_SINGLE,
XZ_PREALLOC,
XZ_DYNALLOC
};
/**
* enum xz_ret - Return codes
* @XZ_OK: Everything is OK so far. More input or more
* output space is required to continue. This
* return code is possible only in multi-call mode
* (XZ_PREALLOC or XZ_DYNALLOC).
* @XZ_STREAM_END: Operation finished successfully.
* @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding
* is still possible in multi-call mode by simply
* calling xz_dec_run() again.
* Note that this return value is used only if
* XZ_DEC_ANY_CHECK was defined at build time,
* which is not used in the kernel. Unsupported
* check types return XZ_OPTIONS_ERROR if
* XZ_DEC_ANY_CHECK was not defined at build time.
* @XZ_MEM_ERROR: Allocating memory failed. This return code is
* possible only if the decoder was initialized
* with XZ_DYNALLOC. The amount of memory that was
* tried to be allocated was no more than the
* dict_max argument given to xz_dec_init().
* @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than
* allowed by the dict_max argument given to
* xz_dec_init(). This return value is possible
* only in multi-call mode (XZ_PREALLOC or
* XZ_DYNALLOC); the single-call mode (XZ_SINGLE)
* ignores the dict_max argument.
* @XZ_FORMAT_ERROR: File format was not recognized (wrong magic
* bytes).
* @XZ_OPTIONS_ERROR: This implementation doesn't support the requested
* compression options. In the decoder this means
* that the header CRC32 matches, but the header
* itself specifies something that we don't support.
* @XZ_DATA_ERROR: Compressed data is corrupt.
* @XZ_BUF_ERROR: Cannot make any progress. Details are slightly
* different between multi-call and single-call
* mode; more information below.
*
* In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
* to XZ code cannot consume any input and cannot produce any new output.
* This happens when there is no new input available, or the output buffer
* is full while at least one output byte is still pending. Assuming your
* code is not buggy, you can get this error only when decoding a compressed
* stream that is truncated or otherwise corrupt.
*
* In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
* is too small or the compressed input is corrupt in a way that makes the
* decoder produce more output than the caller expected. When it is
* (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
* is used instead of XZ_BUF_ERROR.
*/
enum xz_ret {
XZ_OK,
XZ_STREAM_END,
XZ_UNSUPPORTED_CHECK,
XZ_MEM_ERROR,
XZ_MEMLIMIT_ERROR,
XZ_FORMAT_ERROR,
XZ_OPTIONS_ERROR,
XZ_DATA_ERROR,
XZ_BUF_ERROR
};
/**
* struct xz_buf - Passing input and output buffers to XZ code
* @in: Beginning of the input buffer. This may be NULL if and only
* if in_pos is equal to in_size.
* @in_pos: Current position in the input buffer. This must not exceed
* in_size.
* @in_size: Size of the input buffer
* @out: Beginning of the output buffer. This may be NULL if and only
* if out_pos is equal to out_size.
* @out_pos: Current position in the output buffer. This must not exceed
* out_size.
* @out_size: Size of the output buffer
*
* Only the contents of the output buffer from out[out_pos] onward, and
* the variables in_pos and out_pos are modified by the XZ code.
*/
struct xz_buf {
const uint8_t *in;
size_t in_pos;
size_t in_size;
uint8_t *out;
size_t out_pos;
size_t out_size;
};
/**
* struct xz_dec - Opaque type to hold the XZ decoder state
*/
struct xz_dec;
/**
* xz_dec_init() - Allocate and initialize a XZ decoder state
* @mode: Operation mode
* @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for
* multi-call decoding. This is ignored in single-call mode
* (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes
* or 2^n + 2^(n-1) bytes (the latter sizes are less common
* in practice), so other values for dict_max don't make sense.
* In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB,
* 512 KiB, and 1 MiB are probably the only reasonable values,
* except for kernel and initramfs images where a bigger
* dictionary can be fine and useful.
*
* Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at
* once. The caller must provide enough output space or the decoding will
* fail. The output space is used as the dictionary buffer, which is why
* there is no need to allocate the dictionary as part of the decoder's
* internal state.
*
* Because the output buffer is used as the workspace, streams encoded using
* a big dictionary are not a problem in single-call mode. It is enough that
* the output buffer is big enough to hold the actual uncompressed data; it
* can be smaller than the dictionary size stored in the stream headers.
*
* Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes
* of memory is preallocated for the LZMA2 dictionary. This way there is no
* risk that xz_dec_run() could run out of memory, since xz_dec_run() will
* never allocate any memory. Instead, if the preallocated dictionary is too
* small for decoding the given input stream, xz_dec_run() will return
* XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be
* decoded to avoid allocating excessive amount of memory for the dictionary.
*
* Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC):
* dict_max specifies the maximum allowed dictionary size that xz_dec_run()
* may allocate once it has parsed the dictionary size from the stream
* headers. This way excessive allocations can be avoided while still
* limiting the maximum memory usage to a sane value to prevent running the
* system out of memory when decompressing streams from untrusted sources.
*
* On success, xz_dec_init() returns a pointer to struct xz_dec, which is
* ready to be used with xz_dec_run(). If memory allocation fails,
* xz_dec_init() returns NULL.
*/
XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max);
/**
* xz_dec_run() - Run the XZ decoder
* @s: Decoder state allocated using xz_dec_init()
* @b: Input and output buffers
*
* The possible return values depend on build options and operation mode.
* See enum xz_ret for details.
*
* Note that if an error occurs in single-call mode (return value is not
* XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the
* contents of the output buffer from b->out[b->out_pos] onward are
* undefined. This is true even after XZ_BUF_ERROR, because with some filter
* chains, there may be a second pass over the output buffer, and this pass
* cannot be properly done if the output buffer is truncated. Thus, you
* cannot give the single-call decoder a too small buffer and then expect to
* get that amount valid data from the beginning of the stream. You must use
* the multi-call decoder if you don't want to uncompress the whole stream.
*/
XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b);
/**
* xz_dec_reset() - Reset an already allocated decoder state
* @s: Decoder state allocated using xz_dec_init()
*
* This function can be used to reset the multi-call decoder state without
* freeing and reallocating memory with xz_dec_end() and xz_dec_init().
*
* In single-call mode, xz_dec_reset() is always called in the beginning of
* xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
* multi-call mode.
*/
XZ_EXTERN void xz_dec_reset(struct xz_dec *s);
/**
* xz_dec_end() - Free the memory allocated for the decoder state
* @s: Decoder state allocated using xz_dec_init(). If s is NULL,
* this function does nothing.
*/
XZ_EXTERN void xz_dec_end(struct xz_dec *s);
/*
* Standalone build (userspace build or in-kernel build for boot time use)
* needs a CRC32 implementation. For normal in-kernel use, kernel's own
* CRC32 module is used instead, and users of this module don't need to
* care about the functions below.
*/
#ifndef XZ_INTERNAL_CRC32
# ifdef __KERNEL__
# define XZ_INTERNAL_CRC32 0
# else
# define XZ_INTERNAL_CRC32 1
# endif
#endif
/*
* If CRC64 support has been enabled with XZ_USE_CRC64, a CRC64
* implementation is needed too.
*/
#ifndef XZ_USE_CRC64
# undef XZ_INTERNAL_CRC64
# define XZ_INTERNAL_CRC64 0
#endif
#ifndef XZ_INTERNAL_CRC64
# ifdef __KERNEL__
# error Using CRC64 in the kernel has not been implemented.
# else
# define XZ_INTERNAL_CRC64 1
# endif
#endif
#if XZ_INTERNAL_CRC32
/*
* This must be called before any other xz_* function to initialize
* the CRC32 lookup table.
*/
XZ_EXTERN void xz_crc32_init(void);
/*
* Update CRC32 value using the polynomial from IEEE-802.3. To start a new
* calculation, the third argument must be zero. To continue the calculation,
* the previously returned value is passed as the third argument.
*/
XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc);
#endif
#if XZ_INTERNAL_CRC64
/*
* This must be called before any other xz_* function (except xz_crc32_init())
* to initialize the CRC64 lookup table.
*/
XZ_EXTERN void xz_crc64_init(void);
/*
* Update CRC64 value using the polynomial from ECMA-182. To start a new
* calculation, the third argument must be zero. To continue the calculation,
* the previously returned value is passed as the third argument.
*/
XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc);
#endif
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,397 @@
/*
* Wrapper for decompressing XZ-compressed kernel, initramfs, and initrd
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
/*
* Important notes about in-place decompression
*
* At least on x86, the kernel is decompressed in place: the compressed data
* is placed to the end of the output buffer, and the decompressor overwrites
* most of the compressed data. There must be enough safety margin to
* guarantee that the write position is always behind the read position.
*
* The safety margin for XZ with LZMA2 or BCJ+LZMA2 is calculated below.
* Note that the margin with XZ is bigger than with Deflate (gzip)!
*
* The worst case for in-place decompression is that the beginning of
* the file is compressed extremely well, and the rest of the file is
* uncompressible. Thus, we must look for worst-case expansion when the
* compressor is encoding uncompressible data.
*
* The structure of the .xz file in case of a compresed kernel is as follows.
* Sizes (as bytes) of the fields are in parenthesis.
*
* Stream Header (12)
* Block Header:
* Block Header (8-12)
* Compressed Data (N)
* Block Padding (0-3)
* CRC32 (4)
* Index (8-20)
* Stream Footer (12)
*
* Normally there is exactly one Block, but let's assume that there are
* 2-4 Blocks just in case. Because Stream Header and also Block Header
* of the first Block don't make the decompressor produce any uncompressed
* data, we can ignore them from our calculations. Block Headers of possible
* additional Blocks have to be taken into account still. With these
* assumptions, it is safe to assume that the total header overhead is
* less than 128 bytes.
*
* Compressed Data contains LZMA2 or BCJ+LZMA2 encoded data. Since BCJ
* doesn't change the size of the data, it is enough to calculate the
* safety margin for LZMA2.
*
* LZMA2 stores the data in chunks. Each chunk has a header whose size is
* a maximum of 6 bytes, but to get round 2^n numbers, let's assume that
* the maximum chunk header size is 8 bytes. After the chunk header, there
* may be up to 64 KiB of actual payload in the chunk. Often the payload is
* quite a bit smaller though; to be safe, let's assume that an average
* chunk has only 32 KiB of payload.
*
* The maximum uncompressed size of the payload is 2 MiB. The minimum
* uncompressed size of the payload is in practice never less than the
* payload size itself. The LZMA2 format would allow uncompressed size
* to be less than the payload size, but no sane compressor creates such
* files. LZMA2 supports storing uncompressible data in uncompressed form,
* so there's never a need to create payloads whose uncompressed size is
* smaller than the compressed size.
*
* The assumption, that the uncompressed size of the payload is never
* smaller than the payload itself, is valid only when talking about
* the payload as a whole. It is possible that the payload has parts where
* the decompressor consumes more input than it produces output. Calculating
* the worst case for this would be tricky. Instead of trying to do that,
* let's simply make sure that the decompressor never overwrites any bytes
* of the payload which it is currently reading.
*
* Now we have enough information to calculate the safety margin. We need
* - 128 bytes for the .xz file format headers;
* - 8 bytes per every 32 KiB of uncompressed size (one LZMA2 chunk header
* per chunk, each chunk having average payload size of 32 KiB); and
* - 64 KiB (biggest possible LZMA2 chunk payload size) to make sure that
* the decompressor never overwrites anything from the LZMA2 chunk
* payload it is currently reading.
*
* We get the following formula:
*
* safety_margin = 128 + uncompressed_size * 8 / 32768 + 65536
* = 128 + (uncompressed_size >> 12) + 65536
*
* For comparison, according to arch/x86/boot/compressed/misc.c, the
* equivalent formula for Deflate is this:
*
* safety_margin = 18 + (uncompressed_size >> 12) + 32768
*
* Thus, when updating Deflate-only in-place kernel decompressor to
* support XZ, the fixed overhead has to be increased from 18+32768 bytes
* to 128+65536 bytes.
*/
/*
* STATIC is defined to "static" if we are being built for kernel
* decompression (pre-boot code). <linux/decompress/mm.h> will define
* STATIC to empty if it wasn't already defined. Since we will need to
* know later if we are being used for kernel decompression, we define
* XZ_PREBOOT here.
*/
#ifdef STATIC
# define XZ_PREBOOT
#endif
#ifdef __KERNEL__
# include <linux/decompress/mm.h>
#endif
#define XZ_EXTERN STATIC
#ifndef XZ_PREBOOT
# include <linux/slab.h>
# include <linux/xz.h>
#else
/*
* Use the internal CRC32 code instead of kernel's CRC32 module, which
* is not available in early phase of booting.
*/
#define XZ_INTERNAL_CRC32 1
/*
* For boot time use, we enable only the BCJ filter of the current
* architecture or none if no BCJ filter is available for the architecture.
*/
#ifdef CONFIG_X86
# define XZ_DEC_X86
#endif
#ifdef CONFIG_PPC
# define XZ_DEC_POWERPC
#endif
#ifdef CONFIG_ARM
# define XZ_DEC_ARM
#endif
#ifdef CONFIG_IA64
# define XZ_DEC_IA64
#endif
#ifdef CONFIG_SPARC
# define XZ_DEC_SPARC
#endif
/*
* This will get the basic headers so that memeq() and others
* can be defined.
*/
#include "xz/xz_private.h"
/*
* Replace the normal allocation functions with the versions from
* <linux/decompress/mm.h>. vfree() needs to support vfree(NULL)
* when XZ_DYNALLOC is used, but the pre-boot free() doesn't support it.
* Workaround it here because the other decompressors don't need it.
*/
#undef kmalloc
#undef kfree
#undef vmalloc
#undef vfree
#define kmalloc(size, flags) malloc(size)
#define kfree(ptr) free(ptr)
#define vmalloc(size) malloc(size)
#define vfree(ptr) do { if (ptr != NULL) free(ptr); } while (0)
/*
* FIXME: Not all basic memory functions are provided in architecture-specific
* files (yet). We define our own versions here for now, but this should be
* only a temporary solution.
*
* memeq and memzero are not used much and any remotely sane implementation
* is fast enough. memcpy/memmove speed matters in multi-call mode, but
* the kernel image is decompressed in single-call mode, in which only
* memcpy speed can matter and only if there is a lot of uncompressible data
* (LZMA2 stores uncompressible chunks in uncompressed form). Thus, the
* functions below should just be kept small; it's probably not worth
* optimizing for speed.
*/
#ifndef memeq
static bool memeq(const void *a, const void *b, size_t size)
{
const uint8_t *x = a;
const uint8_t *y = b;
size_t i;
for (i = 0; i < size; ++i)
if (x[i] != y[i])
return false;
return true;
}
#endif
#ifndef memzero
static void memzero(void *buf, size_t size)
{
uint8_t *b = buf;
uint8_t *e = b + size;
while (b != e)
*b++ = '\0';
}
#endif
#ifndef memmove
/* Not static to avoid a conflict with the prototype in the Linux headers. */
void *memmove(void *dest, const void *src, size_t size)
{
uint8_t *d = dest;
const uint8_t *s = src;
size_t i;
if (d < s) {
for (i = 0; i < size; ++i)
d[i] = s[i];
} else if (d > s) {
i = size;
while (i-- > 0)
d[i] = s[i];
}
return dest;
}
#endif
/*
* Since we need memmove anyway, would use it as memcpy too.
* Commented out for now to avoid breaking things.
*/
/*
#ifndef memcpy
# define memcpy memmove
#endif
*/
#include "xz/xz_crc32.c"
#include "xz/xz_dec_stream.c"
#include "xz/xz_dec_lzma2.c"
#include "xz/xz_dec_bcj.c"
#endif /* XZ_PREBOOT */
/* Size of the input and output buffers in multi-call mode */
#define XZ_IOBUF_SIZE 4096
/*
* This function implements the API defined in <linux/decompress/generic.h>.
*
* This wrapper will automatically choose single-call or multi-call mode
* of the native XZ decoder API. The single-call mode can be used only when
* both input and output buffers are available as a single chunk, i.e. when
* fill() and flush() won't be used.
*/
STATIC int INIT unxz(unsigned char *in, int in_size,
int (*fill)(void *dest, unsigned int size),
int (*flush)(void *src, unsigned int size),
unsigned char *out, int *in_used,
void (*error)(char *x))
{
struct xz_buf b;
struct xz_dec *s;
enum xz_ret ret;
bool must_free_in = false;
#if XZ_INTERNAL_CRC32
xz_crc32_init();
#endif
if (in_used != NULL)
*in_used = 0;
if (fill == NULL && flush == NULL)
s = xz_dec_init(XZ_SINGLE, 0);
else
s = xz_dec_init(XZ_DYNALLOC, (uint32_t)-1);
if (s == NULL)
goto error_alloc_state;
if (flush == NULL) {
b.out = out;
b.out_size = (size_t)-1;
} else {
b.out_size = XZ_IOBUF_SIZE;
b.out = malloc(XZ_IOBUF_SIZE);
if (b.out == NULL)
goto error_alloc_out;
}
if (in == NULL) {
must_free_in = true;
in = malloc(XZ_IOBUF_SIZE);
if (in == NULL)
goto error_alloc_in;
}
b.in = in;
b.in_pos = 0;
b.in_size = in_size;
b.out_pos = 0;
if (fill == NULL && flush == NULL) {
ret = xz_dec_run(s, &b);
} else {
do {
if (b.in_pos == b.in_size && fill != NULL) {
if (in_used != NULL)
*in_used += b.in_pos;
b.in_pos = 0;
in_size = fill(in, XZ_IOBUF_SIZE);
if (in_size < 0) {
/*
* This isn't an optimal error code
* but it probably isn't worth making
* a new one either.
*/
ret = XZ_BUF_ERROR;
break;
}
b.in_size = in_size;
}
ret = xz_dec_run(s, &b);
if (flush != NULL && (b.out_pos == b.out_size
|| (ret != XZ_OK && b.out_pos > 0))) {
/*
* Setting ret here may hide an error
* returned by xz_dec_run(), but probably
* it's not too bad.
*/
if (flush(b.out, b.out_pos) != (int)b.out_pos)
ret = XZ_BUF_ERROR;
b.out_pos = 0;
}
} while (ret == XZ_OK);
if (must_free_in)
free(in);
if (flush != NULL)
free(b.out);
}
if (in_used != NULL)
*in_used += b.in_pos;
xz_dec_end(s);
switch (ret) {
case XZ_STREAM_END:
return 0;
case XZ_MEM_ERROR:
/* This can occur only in multi-call mode. */
error("XZ decompressor ran out of memory");
break;
case XZ_FORMAT_ERROR:
error("Input is not in the XZ format (wrong magic bytes)");
break;
case XZ_OPTIONS_ERROR:
error("Input was encoded with settings that are not "
"supported by this XZ decoder");
break;
case XZ_DATA_ERROR:
case XZ_BUF_ERROR:
error("XZ-compressed data is corrupt");
break;
default:
error("Bug in the XZ decompressor");
break;
}
return -1;
error_alloc_in:
if (flush != NULL)
free(b.out);
error_alloc_out:
xz_dec_end(s);
error_alloc_state:
error("XZ decompressor ran out of memory");
return -1;
}
/*
* This macro is used by architecture-specific files to decompress
* the kernel image.
*/
#define decompress unxz

View file

@ -0,0 +1,121 @@
/*
* Private includes and definitions for userspace use of XZ Embedded
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#ifndef XZ_CONFIG_H
#define XZ_CONFIG_H
/* Uncomment to enable CRC64 support. */
/* #define XZ_USE_CRC64 */
/* Uncomment as needed to enable BCJ filter decoders. */
/* #define XZ_DEC_X86 */
/* #define XZ_DEC_POWERPC */
/* #define XZ_DEC_IA64 */
/* #define XZ_DEC_ARM */
/* #define XZ_DEC_ARMTHUMB */
/* #define XZ_DEC_SPARC */
/*
* MSVC doesn't support modern C but XZ Embedded is mostly C89
* so these are enough.
*/
#ifdef _MSC_VER
typedef unsigned char bool;
# define true 1
# define false 0
# define inline __inline
#else
# include <stdbool.h>
#endif
#include "xz.h"
#define kmalloc(size, flags) malloc(size)
#define kfree(ptr) free(ptr)
#define vmalloc(size) malloc(size)
#define vfree(ptr) free(ptr)
#define memeq(a, b, size) (memcmp(a, b, size) == 0)
#define memzero(buf, size) memset(buf, 0, size)
#ifndef min
# define min(x, y) ((x) < (y) ? (x) : (y))
#endif
#define min_t(type, x, y) min(x, y)
/*
* Some functions have been marked with __always_inline to keep the
* performance reasonable even when the compiler is optimizing for
* small code size. You may be able to save a few bytes by #defining
* __always_inline to plain inline, but don't complain if the code
* becomes slow.
*
* NOTE: System headers on GNU/Linux may #define this macro already,
* so if you want to change it, you need to #undef it first.
*/
#ifndef __always_inline
# ifdef __GNUC__
# define __always_inline \
inline __attribute__((__always_inline__))
# else
# define __always_inline inline
# endif
#endif
/* Inline functions to access unaligned unsigned 32-bit integers */
#ifndef get_unaligned_le32
static inline uint32_t get_unaligned_le32(const uint8_t *buf)
{
return (uint32_t)buf[0]
| ((uint32_t)buf[1] << 8)
| ((uint32_t)buf[2] << 16)
| ((uint32_t)buf[3] << 24);
}
#endif
#ifndef get_unaligned_be32
static inline uint32_t get_unaligned_be32(const uint8_t *buf)
{
return (uint32_t)(buf[0] << 24)
| ((uint32_t)buf[1] << 16)
| ((uint32_t)buf[2] << 8)
| (uint32_t)buf[3];
}
#endif
#ifndef put_unaligned_le32
static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
{
buf[0] = (uint8_t)val;
buf[1] = (uint8_t)(val >> 8);
buf[2] = (uint8_t)(val >> 16);
buf[3] = (uint8_t)(val >> 24);
}
#endif
#ifndef put_unaligned_be32
static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
{
buf[0] = (uint8_t)(val >> 24);
buf[1] = (uint8_t)(val >> 16);
buf[2] = (uint8_t)(val >> 8);
buf[3] = (uint8_t)val;
}
#endif
/*
* Use get_unaligned_le32() also for aligned access for simplicity. On
* little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr))
* could save a few bytes in code size.
*/
#ifndef get_le32
# define get_le32 get_unaligned_le32
#endif
#endif

View file

@ -0,0 +1,45 @@
/*
* CRC32 using the polynomial from IEEE-802.3
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <http://7-zip.org/>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
/*
* This is not the fastest implementation, but it is pretty compact.
* The fastest versions of xz_crc32() on modern CPUs without hardware
* accelerated CRC instruction are 3-5 times as fast as this version,
* but they are bigger and use more memory for the lookup table.
*/
#include "xz_private.h"
/*
* STATIC_RW_DATA is used in the pre-boot environment on some architectures.
* See <linux/decompress/mm.h> for details.
*/
#ifndef STATIC_RW_DATA
# define STATIC_RW_DATA static
#endif
STATIC_RW_DATA const uint32_t xz_crc32_table[256]= {0x00000000,0x77073096,0xee0e612c,0x990951ba,0x076dc419,0x706af48f,0xe963a535,0x9e6495a3,0x0edb8832,0x79dcb8a4,0xe0d5e91e,0x97d2d988,0x09b64c2b,0x7eb17cbd,0xe7b82d07,0x90bf1d91,0x1db71064,0x6ab020f2,0xf3b97148,0x84be41de,0x1adad47d,0x6ddde4eb,0xf4d4b551,0x83d385c7,0x136c9856,0x646ba8c0,0xfd62f97a,0x8a65c9ec,0x14015c4f,0x63066cd9,0xfa0f3d63,0x8d080df5,0x3b6e20c8,0x4c69105e,0xd56041e4,0xa2677172,0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b,0x35b5a8fa,0x42b2986c,0xdbbbc9d6,0xacbcf940,0x32d86ce3,0x45df5c75,0xdcd60dcf,0xabd13d59,0x26d930ac,0x51de003a,0xc8d75180,0xbfd06116,0x21b4f4b5,0x56b3c423,0xcfba9599,0xb8bda50f,0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924,0x2f6f7c87,0x58684c11,0xc1611dab,0xb6662d3d,0x76dc4190,0x01db7106,0x98d220bc,0xefd5102a,0x71b18589,0x06b6b51f,0x9fbfe4a5,0xe8b8d433,0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818,0x7f6a0dbb,0x086d3d2d,0x91646c97,0xe6635c01,0x6b6b51f4,0x1c6c6162,0x856530d8,0xf262004e,0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457,0x65b0d9c6,0x12b7e950,0x8bbeb8ea,0xfcb9887c,0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65,0x4db26158,0x3ab551ce,0xa3bc0074,0xd4bb30e2,0x4adfa541,0x3dd895d7,0xa4d1c46d,0xd3d6f4fb,0x4369e96a,0x346ed9fc,0xad678846,0xda60b8d0,0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9,0x5005713c,0x270241aa,0xbe0b1010,0xc90c2086,0x5768b525,0x206f85b3,0xb966d409,0xce61e49f,0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4,0x59b33d17,0x2eb40d81,0xb7bd5c3b,0xc0ba6cad,0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a,0xead54739,0x9dd277af,0x04db2615,0x73dc1683,0xe3630b12,0x94643b84,0x0d6d6a3e,0x7a6a5aa8,0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1,0xf00f9344,0x8708a3d2,0x1e01f268,0x6906c2fe,0xf762575d,0x806567cb,0x196c3671,0x6e6b06e7,0xfed41b76,0x89d32be0,0x10da7a5a,0x67dd4acc,0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5,0xd6d6a3e8,0xa1d1937e,0x38d8c2c4,0x4fdff252,0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b,0xd80d2bda,0xaf0a1b4c,0x36034af6,0x41047a60,0xdf60efc3,0xa867df55,0x316e8eef,0x4669be79,0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236,0xcc0c7795,0xbb0b4703,0x220216b9,0x5505262f,0xc5ba3bbe,0xb2bd0b28,0x2bb45a92,0x5cb36a04,0xc2d7ffa7,0xb5d0cf31,0x2cd99e8b,0x5bdeae1d,0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a,0x9c0906a9,0xeb0e363f,0x72076785,0x05005713,0x95bf4a82,0xe2b87a14,0x7bb12bae,0x0cb61b38,0x92d28e9b,0xe5d5be0d,0x7cdcefb7,0x0bdbdf21,0x86d3d2d4,0xf1d4e242,0x68ddb3f8,0x1fda836e,0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777,0x88085ae6,0xff0f6a70,0x66063bca,0x11010b5c,0x8f659eff,0xf862ae69,0x616bffd3,0x166ccf45,0xa00ae278,0xd70dd2ee,0x4e048354,0x3903b3c2,0xa7672661,0xd06016f7,0x4969474d,0x3e6e77db,0xaed16a4a,0xd9d65adc,0x40df0b66,0x37d83bf0,0xa9bcae53,0xdebb9ec5,0x47b2cf7f,0x30b5ffe9,0xbdbdf21c,0xcabac28a,0x53b39330,0x24b4a3a6,0xbad03605,0xcdd70693,0x54de5729,0x23d967bf,0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94,0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d};
XZ_EXTERN void xz_crc32_init(void)
{
return;
}
XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
{
crc = ~crc;
while (size != 0) {
crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
--size;
}
return ~crc;
}

View file

@ -0,0 +1,50 @@
/*
* CRC64 using the polynomial from ECMA-182
*
* This file is similar to xz_crc32.c. See the comments there.
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <http://7-zip.org/>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#include "xz_private.h"
#ifndef STATIC_RW_DATA
# define STATIC_RW_DATA static
#endif
STATIC_RW_DATA uint64_t xz_crc64_table[256];
XZ_EXTERN void xz_crc64_init(void)
{
const uint64_t poly = 0xC96C5795D7870F42;
uint32_t i;
uint32_t j;
uint64_t r;
for (i = 0; i < 256; ++i) {
r = i;
for (j = 0; j < 8; ++j)
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
xz_crc64_table[i] = r;
}
return;
}
XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc)
{
crc = ~crc;
while (size != 0) {
crc = xz_crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
--size;
}
return ~crc;
}

View file

@ -0,0 +1,574 @@
/*
* Branch/Call/Jump (BCJ) filter decoders
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <http://7-zip.org/>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#include "xz_private.h"
/*
* The rest of the file is inside this ifdef. It makes things a little more
* convenient when building without support for any BCJ filters.
*/
#ifdef XZ_DEC_BCJ
struct xz_dec_bcj {
/* Type of the BCJ filter being used */
enum {
BCJ_X86 = 4, /* x86 or x86-64 */
BCJ_POWERPC = 5, /* Big endian only */
BCJ_IA64 = 6, /* Big or little endian */
BCJ_ARM = 7, /* Little endian only */
BCJ_ARMTHUMB = 8, /* Little endian only */
BCJ_SPARC = 9 /* Big or little endian */
} type;
/*
* Return value of the next filter in the chain. We need to preserve
* this information across calls, because we must not call the next
* filter anymore once it has returned XZ_STREAM_END.
*/
enum xz_ret ret;
/* True if we are operating in single-call mode. */
bool single_call;
/*
* Absolute position relative to the beginning of the uncompressed
* data (in a single .xz Block). We care only about the lowest 32
* bits so this doesn't need to be uint64_t even with big files.
*/
uint32_t pos;
/* x86 filter state */
uint32_t x86_prev_mask;
/* Temporary space to hold the variables from struct xz_buf */
uint8_t *out;
size_t out_pos;
size_t out_size;
struct {
/* Amount of already filtered data in the beginning of buf */
size_t filtered;
/* Total amount of data currently stored in buf */
size_t size;
/*
* Buffer to hold a mix of filtered and unfiltered data. This
* needs to be big enough to hold Alignment + 2 * Look-ahead:
*
* Type Alignment Look-ahead
* x86 1 4
* PowerPC 4 0
* IA-64 16 0
* ARM 4 0
* ARM-Thumb 2 2
* SPARC 4 0
*/
uint8_t buf[16];
} temp;
};
#ifdef XZ_DEC_X86
/*
* This is used to test the most significant byte of a memory address
* in an x86 instruction.
*/
static inline int bcj_x86_test_msbyte(uint8_t b)
{
return b == 0x00 || b == 0xFF;
}
static size_t bcj_x86(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
static const bool mask_to_allowed_status[8]
= { true, true, true, false, true, false, false, false };
static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
size_t i;
size_t prev_pos = (size_t)-1;
uint32_t prev_mask = s->x86_prev_mask;
uint32_t src;
uint32_t dest;
uint32_t j;
uint8_t b;
if (size <= 4)
return 0;
size -= 4;
for (i = 0; i < size; ++i) {
if ((buf[i] & 0xFE) != 0xE8)
continue;
prev_pos = i - prev_pos;
if (prev_pos > 3) {
prev_mask = 0;
} else {
prev_mask = (prev_mask << (prev_pos - 1)) & 7;
if (prev_mask != 0) {
b = buf[i + 4 - mask_to_bit_num[prev_mask]];
if (!mask_to_allowed_status[prev_mask]
|| bcj_x86_test_msbyte(b)) {
prev_pos = i;
prev_mask = (prev_mask << 1) | 1;
continue;
}
}
}
prev_pos = i;
if (bcj_x86_test_msbyte(buf[i + 4])) {
src = get_unaligned_le32(buf + i + 1);
while (true) {
dest = src - (s->pos + (uint32_t)i + 5);
if (prev_mask == 0)
break;
j = mask_to_bit_num[prev_mask] * 8;
b = (uint8_t)(dest >> (24 - j));
if (!bcj_x86_test_msbyte(b))
break;
src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
}
dest &= 0x01FFFFFF;
dest |= (uint32_t)0 - (dest & 0x01000000);
put_unaligned_le32(dest, buf + i + 1);
i += 4;
} else {
prev_mask = (prev_mask << 1) | 1;
}
}
prev_pos = i - prev_pos;
s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
return i;
}
#endif
#ifdef XZ_DEC_POWERPC
static size_t bcj_powerpc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t instr;
for (i = 0; i + 4 <= size; i += 4) {
instr = get_unaligned_be32(buf + i);
if ((instr & 0xFC000003) == 0x48000001) {
instr &= 0x03FFFFFC;
instr -= s->pos + (uint32_t)i;
instr &= 0x03FFFFFC;
instr |= 0x48000001;
put_unaligned_be32(instr, buf + i);
}
}
return i;
}
#endif
#ifdef XZ_DEC_IA64
static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
static const uint8_t branch_table[32] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4, 4, 6, 6, 0, 0, 7, 7,
4, 4, 0, 0, 4, 4, 0, 0
};
/*
* The local variables take a little bit stack space, but it's less
* than what LZMA2 decoder takes, so it doesn't make sense to reduce
* stack usage here without doing that for the LZMA2 decoder too.
*/
/* Loop counters */
size_t i;
size_t j;
/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
uint32_t slot;
/* Bitwise offset of the instruction indicated by slot */
uint32_t bit_pos;
/* bit_pos split into byte and bit parts */
uint32_t byte_pos;
uint32_t bit_res;
/* Address part of an instruction */
uint32_t addr;
/* Mask used to detect which instructions to convert */
uint32_t mask;
/* 41-bit instruction stored somewhere in the lowest 48 bits */
uint64_t instr;
/* Instruction normalized with bit_res for easier manipulation */
uint64_t norm;
for (i = 0; i + 16 <= size; i += 16) {
mask = branch_table[buf[i] & 0x1F];
for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
if (((mask >> slot) & 1) == 0)
continue;
byte_pos = bit_pos >> 3;
bit_res = bit_pos & 7;
instr = 0;
for (j = 0; j < 6; ++j)
instr |= (uint64_t)(buf[i + j + byte_pos])
<< (8 * j);
norm = instr >> bit_res;
if (((norm >> 37) & 0x0F) == 0x05
&& ((norm >> 9) & 0x07) == 0) {
addr = (norm >> 13) & 0x0FFFFF;
addr |= ((uint32_t)(norm >> 36) & 1) << 20;
addr <<= 4;
addr -= s->pos + (uint32_t)i;
addr >>= 4;
norm &= ~((uint64_t)0x8FFFFF << 13);
norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
norm |= (uint64_t)(addr & 0x100000)
<< (36 - 20);
instr &= (1 << bit_res) - 1;
instr |= norm << bit_res;
for (j = 0; j < 6; j++)
buf[i + j + byte_pos]
= (uint8_t)(instr >> (8 * j));
}
}
}
return i;
}
#endif
#ifdef XZ_DEC_ARM
static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t addr;
for (i = 0; i + 4 <= size; i += 4) {
if (buf[i + 3] == 0xEB) {
addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
| ((uint32_t)buf[i + 2] << 16);
addr <<= 2;
addr -= s->pos + (uint32_t)i + 8;
addr >>= 2;
buf[i] = (uint8_t)addr;
buf[i + 1] = (uint8_t)(addr >> 8);
buf[i + 2] = (uint8_t)(addr >> 16);
}
}
return i;
}
#endif
#ifdef XZ_DEC_ARMTHUMB
static size_t bcj_armthumb(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t addr;
for (i = 0; i + 4 <= size; i += 2) {
if ((buf[i + 1] & 0xF8) == 0xF0
&& (buf[i + 3] & 0xF8) == 0xF8) {
addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
| ((uint32_t)buf[i] << 11)
| (((uint32_t)buf[i + 3] & 0x07) << 8)
| (uint32_t)buf[i + 2];
addr <<= 1;
addr -= s->pos + (uint32_t)i + 4;
addr >>= 1;
buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
buf[i] = (uint8_t)(addr >> 11);
buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
buf[i + 2] = (uint8_t)addr;
i += 2;
}
}
return i;
}
#endif
#ifdef XZ_DEC_SPARC
static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t instr;
for (i = 0; i + 4 <= size; i += 4) {
instr = get_unaligned_be32(buf + i);
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
instr <<= 2;
instr -= s->pos + (uint32_t)i;
instr >>= 2;
instr = ((uint32_t)0x40000000 - (instr & 0x400000))
| 0x40000000 | (instr & 0x3FFFFF);
put_unaligned_be32(instr, buf + i);
}
}
return i;
}
#endif
/*
* Apply the selected BCJ filter. Update *pos and s->pos to match the amount
* of data that got filtered.
*
* NOTE: This is implemented as a switch statement to avoid using function
* pointers, which could be problematic in the kernel boot code, which must
* avoid pointers to static data (at least on x86).
*/
static void bcj_apply(struct xz_dec_bcj *s,
uint8_t *buf, size_t *pos, size_t size)
{
size_t filtered;
buf += *pos;
size -= *pos;
switch (s->type) {
#ifdef XZ_DEC_X86
case BCJ_X86:
filtered = bcj_x86(s, buf, size);
break;
#endif
#ifdef XZ_DEC_POWERPC
case BCJ_POWERPC:
filtered = bcj_powerpc(s, buf, size);
break;
#endif
#ifdef XZ_DEC_IA64
case BCJ_IA64:
filtered = bcj_ia64(s, buf, size);
break;
#endif
#ifdef XZ_DEC_ARM
case BCJ_ARM:
filtered = bcj_arm(s, buf, size);
break;
#endif
#ifdef XZ_DEC_ARMTHUMB
case BCJ_ARMTHUMB:
filtered = bcj_armthumb(s, buf, size);
break;
#endif
#ifdef XZ_DEC_SPARC
case BCJ_SPARC:
filtered = bcj_sparc(s, buf, size);
break;
#endif
default:
/* Never reached but silence compiler warnings. */
filtered = 0;
break;
}
*pos += filtered;
s->pos += filtered;
}
/*
* Flush pending filtered data from temp to the output buffer.
* Move the remaining mixture of possibly filtered and unfiltered
* data to the beginning of temp.
*/
static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
{
size_t copy_size;
copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
b->out_pos += copy_size;
s->temp.filtered -= copy_size;
s->temp.size -= copy_size;
memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
}
/*
* The BCJ filter functions are primitive in sense that they process the
* data in chunks of 1-16 bytes. To hide this issue, this function does
* some buffering.
*/
XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
struct xz_dec_lzma2 *lzma2,
struct xz_buf *b)
{
size_t out_start;
/*
* Flush pending already filtered data to the output buffer. Return
* immediatelly if we couldn't flush everything, or if the next
* filter in the chain had already returned XZ_STREAM_END.
*/
if (s->temp.filtered > 0) {
bcj_flush(s, b);
if (s->temp.filtered > 0)
return XZ_OK;
if (s->ret == XZ_STREAM_END)
return XZ_STREAM_END;
}
/*
* If we have more output space than what is currently pending in
* temp, copy the unfiltered data from temp to the output buffer
* and try to fill the output buffer by decoding more data from the
* next filter in the chain. Apply the BCJ filter on the new data
* in the output buffer. If everything cannot be filtered, copy it
* to temp and rewind the output buffer position accordingly.
*
* This needs to be always run when temp.size == 0 to handle a special
* case where the output buffer is full and the next filter has no
* more output coming but hasn't returned XZ_STREAM_END yet.
*/
if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {
out_start = b->out_pos;
memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
b->out_pos += s->temp.size;
s->ret = xz_dec_lzma2_run(lzma2, b);
if (s->ret != XZ_STREAM_END
&& (s->ret != XZ_OK || s->single_call))
return s->ret;
bcj_apply(s, b->out, &out_start, b->out_pos);
/*
* As an exception, if the next filter returned XZ_STREAM_END,
* we can do that too, since the last few bytes that remain
* unfiltered are meant to remain unfiltered.
*/
if (s->ret == XZ_STREAM_END)
return XZ_STREAM_END;
s->temp.size = b->out_pos - out_start;
b->out_pos -= s->temp.size;
memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
/*
* If there wasn't enough input to the next filter to fill
* the output buffer with unfiltered data, there's no point
* to try decoding more data to temp.
*/
if (b->out_pos + s->temp.size < b->out_size)
return XZ_OK;
}
/*
* We have unfiltered data in temp. If the output buffer isn't full
* yet, try to fill the temp buffer by decoding more data from the
* next filter. Apply the BCJ filter on temp. Then we hopefully can
* fill the actual output buffer by copying filtered data from temp.
* A mix of filtered and unfiltered data may be left in temp; it will
* be taken care on the next call to this function.
*/
if (b->out_pos < b->out_size) {
/* Make b->out{,_pos,_size} temporarily point to s->temp. */
s->out = b->out;
s->out_pos = b->out_pos;
s->out_size = b->out_size;
b->out = s->temp.buf;
b->out_pos = s->temp.size;
b->out_size = sizeof(s->temp.buf);
s->ret = xz_dec_lzma2_run(lzma2, b);
s->temp.size = b->out_pos;
b->out = s->out;
b->out_pos = s->out_pos;
b->out_size = s->out_size;
if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
return s->ret;
bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
/*
* If the next filter returned XZ_STREAM_END, we mark that
* everything is filtered, since the last unfiltered bytes
* of the stream are meant to be left as is.
*/
if (s->ret == XZ_STREAM_END)
s->temp.filtered = s->temp.size;
bcj_flush(s, b);
if (s->temp.filtered > 0)
return XZ_OK;
}
return s->ret;
}
XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call)
{
struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (s != NULL)
s->single_call = single_call;
return s;
}
XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id)
{
switch (id) {
#ifdef XZ_DEC_X86
case BCJ_X86:
#endif
#ifdef XZ_DEC_POWERPC
case BCJ_POWERPC:
#endif
#ifdef XZ_DEC_IA64
case BCJ_IA64:
#endif
#ifdef XZ_DEC_ARM
case BCJ_ARM:
#endif
#ifdef XZ_DEC_ARMTHUMB
case BCJ_ARMTHUMB:
#endif
#ifdef XZ_DEC_SPARC
case BCJ_SPARC:
#endif
break;
default:
/* Unsupported Filter ID */
return XZ_OPTIONS_ERROR;
}
s->type = id;
s->ret = XZ_OK;
s->pos = 0;
s->x86_prev_mask = 0;
s->temp.filtered = 0;
s->temp.size = 0;
return XZ_OK;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,863 @@
/*
* .xz Stream decoder
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#include "xz_private.h"
#include "xz_stream.h"
#ifdef XZ_USE_CRC64
# define IS_CRC64(check_type) ((check_type) == XZ_CHECK_CRC64)
#else
# define IS_CRC64(check_type) false
#endif
/* Hash used to validate the Index field */
struct xz_dec_hash {
vli_type unpadded;
vli_type uncompressed;
uint32_t crc32;
};
struct xz_dec {
/* Position in dec_main() */
enum {
SEQ_STREAM_HEADER,
SEQ_BLOCK_START,
SEQ_BLOCK_HEADER,
SEQ_BLOCK_UNCOMPRESS,
SEQ_BLOCK_PADDING,
SEQ_BLOCK_CHECK,
SEQ_INDEX,
SEQ_INDEX_PADDING,
SEQ_INDEX_CRC32,
SEQ_STREAM_FOOTER
} sequence;
/* Position in variable-length integers and Check fields */
uint32_t pos;
/* Variable-length integer decoded by dec_vli() */
vli_type vli;
/* Saved in_pos and out_pos */
size_t in_start;
size_t out_start;
#ifdef XZ_USE_CRC64
/* CRC32 or CRC64 value in Block or CRC32 value in Index */
uint64_t crc;
#else
/* CRC32 value in Block or Index */
uint32_t crc;
#endif
/* Type of the integrity check calculated from uncompressed data */
enum xz_check check_type;
/* Operation mode */
enum xz_mode mode;
/*
* True if the next call to xz_dec_run() is allowed to return
* XZ_BUF_ERROR.
*/
bool allow_buf_error;
/* Information stored in Block Header */
struct {
/*
* Value stored in the Compressed Size field, or
* VLI_UNKNOWN if Compressed Size is not present.
*/
vli_type compressed;
/*
* Value stored in the Uncompressed Size field, or
* VLI_UNKNOWN if Uncompressed Size is not present.
*/
vli_type uncompressed;
/* Size of the Block Header field */
uint32_t size;
} block_header;
/* Information collected when decoding Blocks */
struct {
/* Observed compressed size of the current Block */
vli_type compressed;
/* Observed uncompressed size of the current Block */
vli_type uncompressed;
/* Number of Blocks decoded so far */
vli_type count;
/*
* Hash calculated from the Block sizes. This is used to
* validate the Index field.
*/
struct xz_dec_hash hash;
} block;
/* Variables needed when verifying the Index field */
struct {
/* Position in dec_index() */
enum {
SEQ_INDEX_COUNT,
SEQ_INDEX_UNPADDED,
SEQ_INDEX_UNCOMPRESSED
} sequence;
/* Size of the Index in bytes */
vli_type size;
/* Number of Records (matches block.count in valid files) */
vli_type count;
/*
* Hash calculated from the Records (matches block.hash in
* valid files).
*/
struct xz_dec_hash hash;
} index;
/*
* Temporary buffer needed to hold Stream Header, Block Header,
* and Stream Footer. The Block Header is the biggest (1 KiB)
* so we reserve space according to that. buf[] has to be aligned
* to a multiple of four bytes; the size_t variables before it
* should guarantee this.
*/
struct {
size_t pos;
size_t size;
uint8_t buf[1024];
} temp;
struct xz_dec_lzma2 *lzma2;
#ifdef XZ_DEC_BCJ
struct xz_dec_bcj *bcj;
bool bcj_active;
#endif
};
#ifdef XZ_DEC_ANY_CHECK
/* Sizes of the Check field with different Check IDs */
static const uint8_t check_sizes[16] = {
0,
4, 4, 4,
8, 8, 8,
16, 16, 16,
32, 32, 32,
64, 64, 64
};
#endif
/*
* Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
* must have set s->temp.pos to indicate how much data we are supposed
* to copy into s->temp.buf. Return true once s->temp.pos has reached
* s->temp.size.
*/
static bool fill_temp(struct xz_dec *s, struct xz_buf *b)
{
size_t copy_size = min_t(size_t,
b->in_size - b->in_pos, s->temp.size - s->temp.pos);
memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
b->in_pos += copy_size;
s->temp.pos += copy_size;
if (s->temp.pos == s->temp.size) {
s->temp.pos = 0;
return true;
}
return false;
}
/* Decode a variable-length integer (little-endian base-128 encoding) */
static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,
size_t *in_pos, size_t in_size)
{
uint8_t byte;
if (s->pos == 0)
s->vli = 0;
while (*in_pos < in_size) {
byte = in[*in_pos];
++*in_pos;
s->vli |= (vli_type)(byte & 0x7F) << s->pos;
if ((byte & 0x80) == 0) {
/* Don't allow non-minimal encodings. */
if (byte == 0 && s->pos != 0)
return XZ_DATA_ERROR;
s->pos = 0;
return XZ_STREAM_END;
}
s->pos += 7;
if (s->pos == 7 * VLI_BYTES_MAX)
return XZ_DATA_ERROR;
}
return XZ_OK;
}
/*
* Decode the Compressed Data field from a Block. Update and validate
* the observed compressed and uncompressed sizes of the Block so that
* they don't exceed the values possibly stored in the Block Header
* (validation assumes that no integer overflow occurs, since vli_type
* is normally uint64_t). Update the CRC32 or CRC64 value if presence of
* the CRC32 or CRC64 field was indicated in Stream Header.
*
* Once the decoding is finished, validate that the observed sizes match
* the sizes possibly stored in the Block Header. Update the hash and
* Block count, which are later used to validate the Index field.
*/
static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
{
enum xz_ret ret;
s->in_start = b->in_pos;
s->out_start = b->out_pos;
#ifdef XZ_DEC_BCJ
if (s->bcj_active)
ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
else
#endif
ret = xz_dec_lzma2_run(s->lzma2, b);
s->block.compressed += b->in_pos - s->in_start;
s->block.uncompressed += b->out_pos - s->out_start;
/*
* There is no need to separately check for VLI_UNKNOWN, since
* the observed sizes are always smaller than VLI_UNKNOWN.
*/
if (s->block.compressed > s->block_header.compressed
|| s->block.uncompressed
> s->block_header.uncompressed)
return XZ_DATA_ERROR;
if (s->check_type == XZ_CHECK_CRC32)
s->crc = xz_crc32(b->out + s->out_start,
b->out_pos - s->out_start, s->crc);
#ifdef XZ_USE_CRC64
else if (s->check_type == XZ_CHECK_CRC64)
s->crc = xz_crc64(b->out + s->out_start,
b->out_pos - s->out_start, s->crc);
#endif
if (ret == XZ_STREAM_END) {
if (s->block_header.compressed != VLI_UNKNOWN
&& s->block_header.compressed
!= s->block.compressed)
return XZ_DATA_ERROR;
if (s->block_header.uncompressed != VLI_UNKNOWN
&& s->block_header.uncompressed
!= s->block.uncompressed)
return XZ_DATA_ERROR;
s->block.hash.unpadded += s->block_header.size
+ s->block.compressed;
#ifdef XZ_DEC_ANY_CHECK
s->block.hash.unpadded += check_sizes[s->check_type];
#else
if (s->check_type == XZ_CHECK_CRC32)
s->block.hash.unpadded += 4;
else if (IS_CRC64(s->check_type))
s->block.hash.unpadded += 8;
#endif
s->block.hash.uncompressed += s->block.uncompressed;
s->block.hash.crc32 = xz_crc32(
(const uint8_t *)&s->block.hash,
sizeof(s->block.hash), s->block.hash.crc32);
++s->block.count;
}
return ret;
}
/* Update the Index size and the CRC32 value. */
static void index_update(struct xz_dec *s, const struct xz_buf *b)
{
size_t in_used = b->in_pos - s->in_start;
s->index.size += in_used;
s->crc = xz_crc32(b->in + s->in_start, in_used, s->crc);
}
/*
* Decode the Number of Records, Unpadded Size, and Uncompressed Size
* fields from the Index field. That is, Index Padding and CRC32 are not
* decoded by this function.
*
* This can return XZ_OK (more input needed), XZ_STREAM_END (everything
* successfully decoded), or XZ_DATA_ERROR (input is corrupt).
*/
static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
{
enum xz_ret ret;
do {
ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
if (ret != XZ_STREAM_END) {
index_update(s, b);
return ret;
}
switch (s->index.sequence) {
case SEQ_INDEX_COUNT:
s->index.count = s->vli;
/*
* Validate that the Number of Records field
* indicates the same number of Records as
* there were Blocks in the Stream.
*/
if (s->index.count != s->block.count)
return XZ_DATA_ERROR;
s->index.sequence = SEQ_INDEX_UNPADDED;
break;
case SEQ_INDEX_UNPADDED:
s->index.hash.unpadded += s->vli;
s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
break;
case SEQ_INDEX_UNCOMPRESSED:
s->index.hash.uncompressed += s->vli;
s->index.hash.crc32 = xz_crc32(
(const uint8_t *)&s->index.hash,
sizeof(s->index.hash),
s->index.hash.crc32);
--s->index.count;
s->index.sequence = SEQ_INDEX_UNPADDED;
break;
}
} while (s->index.count > 0);
return XZ_STREAM_END;
}
/*
* Validate that the next four or eight input bytes match the value
* of s->crc. s->pos must be zero when starting to validate the first byte.
* The "bits" argument allows using the same code for both CRC32 and CRC64.
*/
static enum xz_ret crc_validate(struct xz_dec *s, struct xz_buf *b,
uint32_t bits)
{
do {
if (b->in_pos == b->in_size)
return XZ_OK;
if (((s->crc >> s->pos) & 0xFF) != b->in[b->in_pos++])
return XZ_DATA_ERROR;
s->pos += 8;
} while (s->pos < bits);
s->crc = 0;
s->pos = 0;
return XZ_STREAM_END;
}
#ifdef XZ_DEC_ANY_CHECK
/*
* Skip over the Check field when the Check ID is not supported.
* Returns true once the whole Check field has been skipped over.
*/
static bool check_skip(struct xz_dec *s, struct xz_buf *b)
{
while (s->pos < check_sizes[s->check_type]) {
if (b->in_pos == b->in_size)
return false;
++b->in_pos;
++s->pos;
}
s->pos = 0;
return true;
}
#endif
/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
static enum xz_ret dec_stream_header(struct xz_dec *s)
{
if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
return XZ_FORMAT_ERROR;
if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
!= get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
return XZ_DATA_ERROR;
if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
return XZ_OPTIONS_ERROR;
/*
* Of integrity checks, we support none (Check ID = 0),
* CRC32 (Check ID = 1), and optionally CRC64 (Check ID = 4).
* However, if XZ_DEC_ANY_CHECK is defined, we will accept other
* check types too, but then the check won't be verified and
* a warning (XZ_UNSUPPORTED_CHECK) will be given.
*/
s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
#ifdef XZ_DEC_ANY_CHECK
if (s->check_type > XZ_CHECK_MAX)
return XZ_OPTIONS_ERROR;
if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
return XZ_UNSUPPORTED_CHECK;
#else
if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
return XZ_OPTIONS_ERROR;
#endif
return XZ_OK;
}
/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
static enum xz_ret dec_stream_footer(struct xz_dec *s)
{
if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
return XZ_DATA_ERROR;
if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
return XZ_DATA_ERROR;
/*
* Validate Backward Size. Note that we never added the size of the
* Index CRC32 field to s->index.size, thus we use s->index.size / 4
* instead of s->index.size / 4 - 1.
*/
if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
return XZ_DATA_ERROR;
if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
return XZ_DATA_ERROR;
/*
* Use XZ_STREAM_END instead of XZ_OK to be more convenient
* for the caller.
*/
return XZ_STREAM_END;
}
/* Decode the Block Header and initialize the filter chain. */
static enum xz_ret dec_block_header(struct xz_dec *s)
{
enum xz_ret ret;
/*
* Validate the CRC32. We know that the temp buffer is at least
* eight bytes so this is safe.
*/
s->temp.size -= 4;
if (xz_crc32(s->temp.buf, s->temp.size, 0)
!= get_le32(s->temp.buf + s->temp.size))
return XZ_DATA_ERROR;
s->temp.pos = 2;
/*
* Catch unsupported Block Flags. We support only one or two filters
* in the chain, so we catch that with the same test.
*/
#ifdef XZ_DEC_BCJ
if (s->temp.buf[1] & 0x3E)
#else
if (s->temp.buf[1] & 0x3F)
#endif
return XZ_OPTIONS_ERROR;
/* Compressed Size */
if (s->temp.buf[1] & 0x40) {
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
!= XZ_STREAM_END)
return XZ_DATA_ERROR;
s->block_header.compressed = s->vli;
} else {
s->block_header.compressed = VLI_UNKNOWN;
}
/* Uncompressed Size */
if (s->temp.buf[1] & 0x80) {
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
!= XZ_STREAM_END)
return XZ_DATA_ERROR;
s->block_header.uncompressed = s->vli;
} else {
s->block_header.uncompressed = VLI_UNKNOWN;
}
#ifdef XZ_DEC_BCJ
/* If there are two filters, the first one must be a BCJ filter. */
s->bcj_active = s->temp.buf[1] & 0x01;
if (s->bcj_active) {
if (s->temp.size - s->temp.pos < 2)
return XZ_OPTIONS_ERROR;
ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
if (ret != XZ_OK)
return ret;
/*
* We don't support custom start offset,
* so Size of Properties must be zero.
*/
if (s->temp.buf[s->temp.pos++] != 0x00)
return XZ_OPTIONS_ERROR;
}
#endif
/* Valid Filter Flags always take at least two bytes. */
if (s->temp.size - s->temp.pos < 2)
return XZ_DATA_ERROR;
/* Filter ID = LZMA2 */
if (s->temp.buf[s->temp.pos++] != 0x21)
return XZ_OPTIONS_ERROR;
/* Size of Properties = 1-byte Filter Properties */
if (s->temp.buf[s->temp.pos++] != 0x01)
return XZ_OPTIONS_ERROR;
/* Filter Properties contains LZMA2 dictionary size. */
if (s->temp.size - s->temp.pos < 1)
return XZ_DATA_ERROR;
ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
if (ret != XZ_OK)
return ret;
/* The rest must be Header Padding. */
while (s->temp.pos < s->temp.size)
if (s->temp.buf[s->temp.pos++] != 0x00)
return XZ_OPTIONS_ERROR;
s->temp.pos = 0;
s->block.compressed = 0;
s->block.uncompressed = 0;
return XZ_OK;
}
static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
{
enum xz_ret ret;
/*
* Store the start position for the case when we are in the middle
* of the Index field.
*/
s->in_start = b->in_pos;
while (true) {
switch (s->sequence) {
case SEQ_STREAM_HEADER:
/*
* Stream Header is copied to s->temp, and then
* decoded from there. This way if the caller
* gives us only little input at a time, we can
* still keep the Stream Header decoding code
* simple. Similar approach is used in many places
* in this file.
*/
if (!fill_temp(s, b))
return XZ_OK;
/*
* If dec_stream_header() returns
* XZ_UNSUPPORTED_CHECK, it is still possible
* to continue decoding if working in multi-call
* mode. Thus, update s->sequence before calling
* dec_stream_header().
*/
s->sequence = SEQ_BLOCK_START;
ret = dec_stream_header(s);
if (ret != XZ_OK)
return ret;
/* Fall through */
case SEQ_BLOCK_START:
/* We need one byte of input to continue. */
if (b->in_pos == b->in_size)
return XZ_OK;
/* See if this is the beginning of the Index field. */
if (b->in[b->in_pos] == 0) {
s->in_start = b->in_pos++;
s->sequence = SEQ_INDEX;
break;
}
/*
* Calculate the size of the Block Header and
* prepare to decode it.
*/
s->block_header.size
= ((uint32_t)b->in[b->in_pos] + 1) * 4;
s->temp.size = s->block_header.size;
s->temp.pos = 0;
s->sequence = SEQ_BLOCK_HEADER;
/* Fall through */
case SEQ_BLOCK_HEADER:
if (!fill_temp(s, b))
return XZ_OK;
ret = dec_block_header(s);
if (ret != XZ_OK)
return ret;
s->sequence = SEQ_BLOCK_UNCOMPRESS;
/* Fall through */
case SEQ_BLOCK_UNCOMPRESS:
ret = dec_block(s, b);
if (ret != XZ_STREAM_END)
return ret;
s->sequence = SEQ_BLOCK_PADDING;
/* Fall through */
case SEQ_BLOCK_PADDING:
/*
* Size of Compressed Data + Block Padding
* must be a multiple of four. We don't need
* s->block.compressed for anything else
* anymore, so we use it here to test the size
* of the Block Padding field.
*/
while (s->block.compressed & 3) {
if (b->in_pos == b->in_size)
return XZ_OK;
if (b->in[b->in_pos++] != 0)
return XZ_DATA_ERROR;
++s->block.compressed;
}
s->sequence = SEQ_BLOCK_CHECK;
/* Fall through */
case SEQ_BLOCK_CHECK:
if (s->check_type == XZ_CHECK_CRC32) {
ret = crc_validate(s, b, 32);
if (ret != XZ_STREAM_END)
return ret;
}
else if (IS_CRC64(s->check_type)) {
ret = crc_validate(s, b, 64);
if (ret != XZ_STREAM_END)
return ret;
}
#ifdef XZ_DEC_ANY_CHECK
else if (!check_skip(s, b)) {
return XZ_OK;
}
#endif
s->sequence = SEQ_BLOCK_START;
break;
case SEQ_INDEX:
ret = dec_index(s, b);
if (ret != XZ_STREAM_END)
return ret;
s->sequence = SEQ_INDEX_PADDING;
/* Fall through */
case SEQ_INDEX_PADDING:
while ((s->index.size + (b->in_pos - s->in_start))
& 3) {
if (b->in_pos == b->in_size) {
index_update(s, b);
return XZ_OK;
}
if (b->in[b->in_pos++] != 0)
return XZ_DATA_ERROR;
}
/* Finish the CRC32 value and Index size. */
index_update(s, b);
/* Compare the hashes to validate the Index field. */
if (!memeq(&s->block.hash, &s->index.hash,
sizeof(s->block.hash)))
return XZ_DATA_ERROR;
s->sequence = SEQ_INDEX_CRC32;
/* Fall through */
case SEQ_INDEX_CRC32:
ret = crc_validate(s, b, 32);
if (ret != XZ_STREAM_END)
return ret;
s->temp.size = STREAM_HEADER_SIZE;
s->sequence = SEQ_STREAM_FOOTER;
/* Fall through */
case SEQ_STREAM_FOOTER:
if (!fill_temp(s, b))
return XZ_OK;
return dec_stream_footer(s);
}
}
/* Never reached */
}
/*
* xz_dec_run() is a wrapper for dec_main() to handle some special cases in
* multi-call and single-call decoding.
*
* In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
* are not going to make any progress anymore. This is to prevent the caller
* from calling us infinitely when the input file is truncated or otherwise
* corrupt. Since zlib-style API allows that the caller fills the input buffer
* only when the decoder doesn't produce any new output, we have to be careful
* to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
* after the second consecutive call to xz_dec_run() that makes no progress.
*
* In single-call mode, if we couldn't decode everything and no error
* occurred, either the input is truncated or the output buffer is too small.
* Since we know that the last input byte never produces any output, we know
* that if all the input was consumed and decoding wasn't finished, the file
* must be corrupt. Otherwise the output buffer has to be too small or the
* file is corrupt in a way that decoding it produces too big output.
*
* If single-call decoding fails, we reset b->in_pos and b->out_pos back to
* their original values. This is because with some filter chains there won't
* be any valid uncompressed data in the output buffer unless the decoding
* actually succeeds (that's the price to pay of using the output buffer as
* the workspace).
*/
XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
{
size_t in_start;
size_t out_start;
enum xz_ret ret;
if (DEC_IS_SINGLE(s->mode))
xz_dec_reset(s);
in_start = b->in_pos;
out_start = b->out_pos;
ret = dec_main(s, b);
if (DEC_IS_SINGLE(s->mode)) {
if (ret == XZ_OK)
ret = b->in_pos == b->in_size
? XZ_DATA_ERROR : XZ_BUF_ERROR;
if (ret != XZ_STREAM_END) {
b->in_pos = in_start;
b->out_pos = out_start;
}
} else if (ret == XZ_OK && in_start == b->in_pos
&& out_start == b->out_pos) {
if (s->allow_buf_error)
ret = XZ_BUF_ERROR;
s->allow_buf_error = true;
} else {
s->allow_buf_error = false;
}
return ret;
}
XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
{
struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (s == NULL)
return NULL;
s->mode = mode;
#ifdef XZ_DEC_BCJ
s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
if (s->bcj == NULL)
goto error_bcj;
#endif
s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
if (s->lzma2 == NULL)
goto error_lzma2;
xz_dec_reset(s);
return s;
error_lzma2:
#ifdef XZ_DEC_BCJ
xz_dec_bcj_end(s->bcj);
error_bcj:
#endif
kfree(s);
return NULL;
}
XZ_EXTERN void xz_dec_reset(struct xz_dec *s)
{
s->sequence = SEQ_STREAM_HEADER;
s->allow_buf_error = false;
s->pos = 0;
s->crc = 0;
memzero(&s->block, sizeof(s->block));
memzero(&s->index, sizeof(s->index));
s->temp.pos = 0;
s->temp.size = STREAM_HEADER_SIZE;
}
XZ_EXTERN void xz_dec_end(struct xz_dec *s)
{
if (s != NULL) {
xz_dec_lzma2_end(s->lzma2);
#ifdef XZ_DEC_BCJ
xz_dec_bcj_end(s->bcj);
#endif
kfree(s);
}
}

View file

@ -0,0 +1,205 @@
/*
* LZMA2 definitions
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <http://7-zip.org/>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#ifndef XZ_LZMA2_H
#define XZ_LZMA2_H
/* Range coder constants */
#define RC_SHIFT_BITS 8
#define RC_TOP_BITS 24
#define RC_TOP_VALUE (1 << RC_TOP_BITS)
#define RC_BIT_MODEL_TOTAL_BITS 11
#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS)
#define RC_MOVE_BITS 5
/*
* Maximum number of position states. A position state is the lowest pb
* number of bits of the current uncompressed offset. In some places there
* are different sets of probabilities for different position states.
*/
#define POS_STATES_MAX (1 << 4)
/*
* This enum is used to track which LZMA symbols have occurred most recently
* and in which order. This information is used to predict the next symbol.
*
* Symbols:
* - Literal: One 8-bit byte
* - Match: Repeat a chunk of data at some distance
* - Long repeat: Multi-byte match at a recently seen distance
* - Short repeat: One-byte repeat at a recently seen distance
*
* The symbol names are in from STATE_oldest_older_previous. REP means
* either short or long repeated match, and NONLIT means any non-literal.
*/
enum lzma_state {
STATE_LIT_LIT,
STATE_MATCH_LIT_LIT,
STATE_REP_LIT_LIT,
STATE_SHORTREP_LIT_LIT,
STATE_MATCH_LIT,
STATE_REP_LIT,
STATE_SHORTREP_LIT,
STATE_LIT_MATCH,
STATE_LIT_LONGREP,
STATE_LIT_SHORTREP,
STATE_NONLIT_MATCH,
STATE_NONLIT_REP
};
/* Total number of states */
#define STATES 12
/* The lowest 7 states indicate that the previous state was a literal. */
#define LIT_STATES 7
/* Indicate that the latest symbol was a literal. */
static inline void lzma_state_literal(enum lzma_state *state)
{
if (*state <= STATE_SHORTREP_LIT_LIT)
*state = STATE_LIT_LIT;
else if (*state <= STATE_LIT_SHORTREP)
*state -= 3;
else
*state -= 6;
}
/* Indicate that the latest symbol was a match. */
static inline void lzma_state_match(enum lzma_state *state)
{
*state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
}
/* Indicate that the latest state was a long repeated match. */
static inline void lzma_state_long_rep(enum lzma_state *state)
{
*state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
}
/* Indicate that the latest symbol was a short match. */
static inline void lzma_state_short_rep(enum lzma_state *state)
{
*state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
}
/* Test if the previous symbol was a literal. */
static inline bool lzma_state_is_literal(enum lzma_state state)
{
return state < LIT_STATES;
}
/* Each literal coder is divided in three sections:
* - 0x001-0x0FF: Without match byte
* - 0x101-0x1FF: With match byte; match bit is 0
* - 0x201-0x2FF: With match byte; match bit is 1
*
* Match byte is used when the previous LZMA symbol was something else than
* a literal (that is, it was some kind of match).
*/
#define LITERAL_CODER_SIZE 0x300
/* Maximum number of literal coders */
//#define LITERAL_CODERS_MAX (1 << 4)
#define LITERAL_CODERS_MAX (1 << 3)
/* Minimum length of a match is two bytes. */
#define MATCH_LEN_MIN 2
/* Match length is encoded with 4, 5, or 10 bits.
*
* Length Bits
* 2-9 4 = Choice=0 + 3 bits
* 10-17 5 = Choice=1 + Choice2=0 + 3 bits
* 18-273 10 = Choice=1 + Choice2=1 + 8 bits
*/
#define LEN_LOW_BITS 3
#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
#define LEN_MID_BITS 3
#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
#define LEN_HIGH_BITS 8
#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
/*
* Maximum length of a match is 273 which is a result of the encoding
* described above.
*/
#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
/*
* Different sets of probabilities are used for match distances that have
* very short match length: Lengths of 2, 3, and 4 bytes have a separate
* set of probabilities for each length. The matches with longer length
* use a shared set of probabilities.
*/
#define DIST_STATES 4
/*
* Get the index of the appropriate probability array for decoding
* the distance slot.
*/
static inline uint32_t lzma_get_dist_state(uint32_t len)
{
return len < DIST_STATES + MATCH_LEN_MIN
? len - MATCH_LEN_MIN : DIST_STATES - 1;
}
/*
* The highest two bits of a 32-bit match distance are encoded using six bits.
* This six-bit value is called a distance slot. This way encoding a 32-bit
* value takes 6-36 bits, larger values taking more bits.
*/
#define DIST_SLOT_BITS 6
#define DIST_SLOTS (1 << DIST_SLOT_BITS)
/* Match distances up to 127 are fully encoded using probabilities. Since
* the highest two bits (distance slot) are always encoded using six bits,
* the distances 0-3 don't need any additional bits to encode, since the
* distance slot itself is the same as the actual distance. DIST_MODEL_START
* indicates the first distance slot where at least one additional bit is
* needed.
*/
#define DIST_MODEL_START 4
/*
* Match distances greater than 127 are encoded in three pieces:
* - distance slot: the highest two bits
* - direct bits: 2-26 bits below the highest two bits
* - alignment bits: four lowest bits
*
* Direct bits don't use any probabilities.
*
* The distance slot value of 14 is for distances 128-191.
*/
#define DIST_MODEL_END 14
/* Distance slots that indicate a distance <= 127. */
#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
/*
* For match distances greater than 127, only the highest two bits and the
* lowest four bits (alignment) is encoded using probabilities.
*/
#define ALIGN_BITS 4
#define ALIGN_SIZE (1 << ALIGN_BITS)
#define ALIGN_MASK (ALIGN_SIZE - 1)
/* Total number of all probability variables */
#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE)
/*
* LZMA remembers the four most recent match distances. Reusing these
* distances tends to take less space than re-encoding the actual
* distance value.
*/
#define REPS 4
#endif

View file

@ -0,0 +1,156 @@
/*
* Private includes and definitions
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#ifndef XZ_PRIVATE_H
#define XZ_PRIVATE_H
#ifdef __KERNEL__
# include <linux/xz.h>
# include <linux/kernel.h>
# include <asm/unaligned.h>
/* XZ_PREBOOT may be defined only via decompress_unxz.c. */
# ifndef XZ_PREBOOT
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/string.h>
# ifdef CONFIG_XZ_DEC_X86
# define XZ_DEC_X86
# endif
# ifdef CONFIG_XZ_DEC_POWERPC
# define XZ_DEC_POWERPC
# endif
# ifdef CONFIG_XZ_DEC_IA64
# define XZ_DEC_IA64
# endif
# ifdef CONFIG_XZ_DEC_ARM
# define XZ_DEC_ARM
# endif
# ifdef CONFIG_XZ_DEC_ARMTHUMB
# define XZ_DEC_ARMTHUMB
# endif
# ifdef CONFIG_XZ_DEC_SPARC
# define XZ_DEC_SPARC
# endif
# define memeq(a, b, size) (memcmp(a, b, size) == 0)
# define memzero(buf, size) memset(buf, 0, size)
# endif
# define get_le32(p) le32_to_cpup((const uint32_t *)(p))
#else
/*
* For userspace builds, use a separate header to define the required
* macros and functions. This makes it easier to adapt the code into
* different environments and avoids clutter in the Linux kernel tree.
*/
# include "xz_config.h"
#endif
/* If no specific decoding mode is requested, enable support for all modes. */
#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \
&& !defined(XZ_DEC_DYNALLOC)
# define XZ_DEC_SINGLE
# define XZ_DEC_PREALLOC
# define XZ_DEC_DYNALLOC
#endif
/*
* The DEC_IS_foo(mode) macros are used in "if" statements. If only some
* of the supported modes are enabled, these macros will evaluate to true or
* false at compile time and thus allow the compiler to omit unneeded code.
*/
#ifdef XZ_DEC_SINGLE
# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE)
#else
# define DEC_IS_SINGLE(mode) (false)
#endif
#ifdef XZ_DEC_PREALLOC
# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC)
#else
# define DEC_IS_PREALLOC(mode) (false)
#endif
#ifdef XZ_DEC_DYNALLOC
# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC)
#else
# define DEC_IS_DYNALLOC(mode) (false)
#endif
#if !defined(XZ_DEC_SINGLE)
# define DEC_IS_MULTI(mode) (true)
#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC)
# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE)
#else
# define DEC_IS_MULTI(mode) (false)
#endif
/*
* If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ.
* XZ_DEC_BCJ is used to enable generic support for BCJ decoders.
*/
#ifndef XZ_DEC_BCJ
# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
|| defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
|| defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
|| defined(XZ_DEC_SPARC)
# define XZ_DEC_BCJ
# endif
#endif
/*
* Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used
* before calling xz_dec_lzma2_run().
*/
XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
uint32_t dict_max);
/*
* Decode the LZMA2 properties (one byte) and reset the decoder. Return
* XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not
* big enough, and XZ_OPTIONS_ERROR if props indicates something that this
* decoder doesn't support.
*/
XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s,
uint8_t props);
/* Decode raw LZMA2 stream from b->in to b->out. */
XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
struct xz_buf *b);
/* Free the memory allocated for the LZMA2 decoder. */
XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
#ifdef XZ_DEC_BCJ
/*
* Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before
* calling xz_dec_bcj_run().
*/
XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call);
/*
* Decode the Filter ID of a BCJ filter. This implementation doesn't
* support custom start offsets, so no decoding of Filter Properties
* is needed. Returns XZ_OK if the given Filter ID is supported.
* Otherwise XZ_OPTIONS_ERROR is returned.
*/
XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id);
/*
* Decode raw BCJ + LZMA2 stream. This must be used only if there actually is
* a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run()
* must be called directly.
*/
XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
struct xz_dec_lzma2 *lzma2,
struct xz_buf *b);
/* Free the memory allocated for the BCJ filters. */
#define xz_dec_bcj_end(s) kfree(s)
#endif
#endif

View file

@ -0,0 +1,62 @@
/*
* Definitions for handling the .xz file format
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#ifndef XZ_STREAM_H
#define XZ_STREAM_H
#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32
# include <linux/crc32.h>
# undef crc32
# define xz_crc32(buf, size, crc) \
(~crc32_le(~(uint32_t)(crc), buf, size))
#endif
/*
* See the .xz file format specification at
* http://tukaani.org/xz/xz-file-format.txt
* to understand the container format.
*/
#define STREAM_HEADER_SIZE 12
#define HEADER_MAGIC "\3757zXZ"
#define HEADER_MAGIC_SIZE 6
#define FOOTER_MAGIC "YZ"
#define FOOTER_MAGIC_SIZE 2
/*
* Variable-length integer can hold a 63-bit unsigned integer or a special
* value indicating that the value is unknown.
*
* Experimental: vli_type can be defined to uint32_t to save a few bytes
* in code size (no effect on speed). Doing so limits the uncompressed and
* compressed size of the file to less than 256 MiB and may also weaken
* error detection slightly.
*/
typedef uint64_t vli_type;
#define VLI_MAX ((vli_type)-1 / 2)
#define VLI_UNKNOWN ((vli_type)-1)
/* Maximum encoded size of a VLI */
#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7)
/* Integrity Check types */
enum xz_check {
XZ_CHECK_NONE = 0,
XZ_CHECK_CRC32 = 1,
XZ_CHECK_CRC64 = 4,
XZ_CHECK_SHA256 = 10
};
/* Maximum possible Check ID */
#define XZ_CHECK_MAX 15
#endif

View file

@ -0,0 +1,22 @@
NAME := ota_2boot_xz
#default gcc
ifeq ($(COMPILER),)
$(NAME)_CFLAGS += -Wall -Werror
else ifeq ($(COMPILER),gcc)
$(NAME)_CFLAGS += -Wall -Werror
endif
$(NAME)_MBINS_TYPE := kernel
$(NAME)_VERSION := 1.0.0
$(NAME)_SUMMARY := XZ uncompress algorithm
$(NAME)_SOURCES := linux/lib/xz/xz_crc32.c \
linux/lib/xz/xz_dec_lzma2.c \
linux/lib/xz/xz_dec_stream.c
$(NAME)_INCLUDES := linux/include/linux \
linux/lib/xz \
userspace

View file

@ -0,0 +1,66 @@
## Contents
```sh
ble
├── ble.mk
├── Config.in
├── inc
│   ├── ais_ota.h
│   ├── ota_breeze_export.h
│   ├── ota_breeze.h
│   └── ota_breeze_transport.h
├── README.md
└── src
├── ota_breeze.c
└── ota_breeze_transport.c
```
## Introduction
An over-the-air update is the wireless delivery of new software or data to smart devices, especially IoT devices. Wireless carriers and OEMs typically use over-the-air (OTA) updates to deploy the new operating systems and the software app to these devices.
## Features
1. Differential incremental upgrade;
2. Dual banker:AB partition upgrade to support rollback to old version;
3. Secure download channel;
4. Firmware digital signature verification.
## Dependencies
Linkkit MQTT channel
Linkkit CoAP channel
## API
User service APIs:
```c
/*OTA export service APIs*/
int ota_service_init(ota_service_t* ctx);
int ota_service_deinit(ota_service_t* ctx);
```
for sample code please check [otaapp](../../../app/example/otaapp/).
## RTOS build
```sh
cd ROOT DIR;
aos make otaapp@board;
```
## run CLI CMDs
1. connect network
```
netmgr connect ssid passwd
```
2. run ota demo
```
OTA_APP pk dn ds ps
```
## Reference
* [AliOS-Things OTA使用说明](https://github.com/alibaba/AliOS-Things/wiki/OTA-Tutorial)
* [OTA flash分区说明文档](https://github.com/alibaba/AliOS-Things/wiki/OTA-Flash-Partitions-Overview)
* [云端一体化差分+安全升级AliOS Things物联网升级“利器”](https://mp.weixin.qq.com/s/Pb8Lleuww1r7qQJHu5ON8g)

View file

@ -0,0 +1,21 @@
NAME := ota_ble
$(NAME)_MBINS_TYPE := kernel
$(NAME)_VERSION := 1.0.0
$(NAME)_SUMMARY := ble device upgrade
$(NAME)_SOURCES += \
src/ota_breeze.c \
src/ota_breeze_service.c \
src/ota_breeze_transport.c \
src/ota_breeze_plat.c
$(NAME)_COMPONENTS += middleware.uagent.uota.hal
GLOBAL_INCLUDES += . \
inc
GLOBAL_DEFINES += OTA_BLE
#GLOBAL_DEFINES += OTA_BLE_LOG_INFO
#GLOBAL_DEFINES += OTA_BLE_LOG_DEBUG
#GLOBAL_DEFINES += OTA_BLE_LOG_ERR

View file

@ -0,0 +1,84 @@
#ifndef _AIS_OTA_H_
#define _AIS_OTA_H_
#include <stdbool.h>
#include <bluetooth/bluetooth.h>
#define ALI_OTA_BIN_TYPE_INFO_OFFSET 0x28
#define ALI_OTA_BIN_TYPE_MAGIC_APP 0xabababab
#define ALI_OTA_BIN_TYPE_MAGIC_KERNEL 0xcdcdcdcd
#define ALI_OTA_BIN_TYPE_MAGIC_SINGLE 0xefefefef
typedef enum
{
ALI_OTA_BIN_TYPE_APP = 0,
ALI_OTA_BIN_TYPE_KERNEL,
ALI_OTA_BIN_TYPE_SINGLE,
ALI_OTA_BIN_TYPE_MAX,
ALI_OTA_BIN_TYPE_INVALID = 0xff
} ali_ota_bin_type_t;
typedef struct {
ali_ota_bin_type_t type;
uint32_t magic;
} ali_ota_bin_info_t;
typedef enum {
ALI_OTA_FLASH_ERASE_OK = 0,
ALI_OTA_FLASH_ERASE_FAIL,
ALI_OTA_FLASH_STORE_OK,
ALI_OTA_FLASH_STORE_FAIL,
ALI_OTA_FLASH_ERROR = 0xff
} ali_ota_flash_evt_t;
typedef enum {
ALI_OTA_FLASH_CODE_SUCCESS,
ALI_OTA_FLASH_CODE_ERROR
} ali_ota_flash_err_t;
typedef enum {
ALI_OTA_SETTINGS_CODE_SUCCESS,
ALI_OTA_SETTINGS_CODE_ERROR
} ali_ota_settings_err_t;
typedef void (*flash_event_handler_t)(ali_ota_flash_evt_t t);
typedef void (*settings_event_handler_t)(ali_ota_flash_evt_t t);
uint32_t ais_ota_get_setting_fw_offset();
void ais_ota_set_setting_fw_offset(uint32_t offset);
uint32_t ais_ota_get_page_size();
ali_ota_flash_err_t ais_ota_flash_erase(uint32_t const *addr, uint32_t num_pages, flash_event_handler_t cb);
ali_ota_flash_err_t ais_ota_flash_store(uint32_t const *addr, uint32_t const * p_data, uint16_t len, flash_event_handler_t cb);
void ais_ota_flash_init();
void ais_ota_settings_init();
uint32_t ais_ota_get_dst_addr();
ali_ota_settings_err_t ais_ota_settings_write(settings_event_handler_t cb);
bool ais_ota_check_if_resume(uint8_t * p_data, uint16_t length);
void ais_ota_update_fw_version(uint8_t * p_data, uint16_t length);
bool ais_ota_check_if_update_finished();
void ais_ota_update_settings_after_update_finished();
void ais_ota_update_setting_after_xfer_finished(uint32_t img_size, uint32_t img_crc);
int ais_ota_bt_storage_init();
int ais_ota_get_local_addr(bt_addr_le_t *addr);
void ais_ota_set_upgrade_bin_type_info(ali_ota_bin_type_t type);
bool ais_ota_check_if_bins_supported();
#endif

View file

@ -0,0 +1,138 @@
#ifndef _OTA_BREEZE_H
#define _OTA_BREEZE_H
#include "ota_breeze_export.h"
#ifndef true
#define true (1)
#endif
#ifndef false
#define false (0)
#endif
#ifndef NULL
#define NULL 0
#endif
#define OTA_IMAGE_MAGIC_OFFSET 0x00
#define OTA_IMAGE_SIZE_OFFSET 0X04
#define OTA_IMAGE_MD5_OFFSET 0x08
#define OTA_BIN_TYPE_MAGIC_APP 0xabababab
#define OTA_BIN_TYPE_MAGIC_KERNEL 0xcdcdcdcd
#define OTA_BIN_TYPE_MAGIC_SINGLE 0xefefefef
#define OTA_BIN_TYPE_MAGIC_APP_KERNEL 0xabcdabcd
typedef enum
{
OTA_BIN_TYPE_APP = 0,
OTA_BIN_TYPE_KERNEL,
OTA_BIN_TYPE_SINGLE,
OTA_BIN_TYPE_APP_KERNEL,
OTA_BIN_TYPE_MAX,
OTA_BIN_TYPE_INVALID = 0xff
} ota_breeze_bin_type_t;
typedef enum {
OTA_BREEZE_FLASH_CODE_SUCCESS,
OTA_BREEZE_FLASH_CODE_ERROR
} ota_breeze_flash_err_t;
#define OTA_BREEZE_CMD_TYPE_MASK 0xF0
/* Error codes. */
#define OTA_BREEZE_SUCCESS (0)
#define OTA_BREEZE_ERROR_INVALID_PARAM (1)
#define OTA_BREEZE_ERROR_DATA_SIZE (2)
#define OTA_BREEZE_ERROR_INVALID_STATE (3)
#define OTA_BREEZE_ERROR_TIMEOUT (4)
#define OTA_BREEZE_ERROR_BUSY (5)
#define OTA_BREEZE_ERROR_INVALID_DATA (6)
#define OTA_BREEZE_ERROR_INTERNAL (7)
#define OTA_BREEZE_ERROR_INVALID_ADDR (8)
#define OTA_BREEZE_ERROR_NOT_SUPPORTED (9)
#define OTA_BREEZE_ERROR_NO_MEM (10)
#define OTA_BREEZE_ERROR_FORBIDDEN (11)
#define OTA_BREEZE_ERROR_NULL (12)
#define OTA_BREEZE_ERROR_INVALID_LENGTH (13)
#define OTA_BREEZE_ERROR_TRANSPORT_TX_FAILURE (14)
#define OTA_BREEZE_ERROR_FLASH_STORE_FAIL (15)
#define OTA_BREEZE_ERROR_FLASH_ERASE_FAIL (16)
#define OTA_BREEZE_ERROR_SETTINGS_FAIL (17)
#define OTA_BREEZE_ERROR_INVALID_BIN_TYPE (18)
#define OTA_BREEZE_ERROR_BIN_UPGRADE_NOT_SUPPORTED (19)
#define OTA_BREEZE_ERROR_BINS_UPGRADE_NOT_SUPPORTED (20)
#define OTA_BREEZE_ERROR_SAVE_BREAKPOINT_FAIL (21)
#define OTA_BREEZE_ERROR_GET_BREAKPOINT_FAIL (22)
#define OTA_BREEZE_CMD_TYPE_GENERIC 0x00 /**< Command type: generic */
#define OTA_BREEZE_CMD_ERROR (OTA_BREEZE_CMD_TYPE_GENERIC | 0xF) /**< Error notification from peripheral to central. */
#define OTA_BREEZE_CMD_TYPE_FW_UPGRADE 0x20 /**< Command type: firmware upgrade */
#define OTA_BREEZE_CMD_FW_VERSION_REQ (OTA_BREEZE_CMD_TYPE_FW_UPGRADE | 0x0) /**< Query on firmware version, sent from central. */
#define OTA_BREEZE_CMD_FW_VERSION_RSP (OTA_BREEZE_CMD_TYPE_FW_UPGRADE | 0x1) /**< Response to @ref ALI_CMD_FW_VERSION_REQ. */
#define OTA_BREEZE_CMD_FW_UPGRADE_REQ (OTA_BREEZE_CMD_TYPE_FW_UPGRADE | 0x2) /**< Request to start firmware upgrade, sent from central. */
#define OTA_BREEZE_CMD_FW_UPGRADE_RSP (OTA_BREEZE_CMD_TYPE_FW_UPGRADE | 0x3) /**< Response to @ref ALI_CMD_FW_UPGRADE_REQ. */
#define OTA_BREEZE_CMD_FW_BYTES_RECEIVED (OTA_BREEZE_CMD_TYPE_FW_UPGRADE | 0x4) /**< Response to @ref ALI_CMD_FW_GET_INITIAL_SIZE or @ref ALI_CMD_FW_DATA on the progress of firmware download, conveying the last known valid frame sequence and data offset. */
#define OTA_BREEZE_CMD_FW_CHECK_RESULT (OTA_BREEZE_CMD_TYPE_FW_UPGRADE | 0x5) /**< Result of firmware check after the whole firmware image has been received. */
#define OTA_BREEZE_CMD_FW_UPDATE_PROCESS (OTA_BREEZE_CMD_TYPE_FW_UPGRADE | 0x6) /**< Notification from peripheral on the progress of firmware upgrade. */
#define OTA_BREEZE_CMD_FW_GET_INIT_FW_SIZE (OTA_BREEZE_CMD_TYPE_FW_UPGRADE | 0x7) /**< Request to get the desired offset of firmware image. */
#define OTA_BREEZE_CMD_FW_XFER_FINISH (OTA_BREEZE_CMD_TYPE_FW_UPGRADE | 0x8) /**< Message from the central to indicate the end of firmware transfer. */
#define OTA_BREEZE_CMD_FW_DATA (OTA_BREEZE_CMD_TYPE_FW_UPGRADE | 0xF) /**< Speciial packet for firmware data. */
#define OTA_BREEZE_RECEIVE_BUF_NUMB (3)
#define OTA_BREEZE_REC_PER_FRAME_LEN (256)
#define OTA_BREEZE_EVENT_AUTH (0x01)
#define OTA_BREEZE_EVENT_TX_DONE (0x02)
typedef struct _ota_breeze_rec_data_{
unsigned char cmd;
unsigned char num_frames;
unsigned short length;
unsigned char rec_buf[OTA_BREEZE_REC_PER_FRAME_LEN];
}ota_breeze_rec_t;
typedef enum
{
OTA_BREEZE_STATE_OFF, /**< Off, expects authentication results. */
OTA_BREEZE_STATE_IDLE, /**< Idle, expects commands 0x20 (version query) or 0x22 (update request) */
OTA_BREEZE_STATE_RECEIVE, /**< Receive firmware, expects commands 0x27 (progress query) or 0x2F (Firmware data). */
OTA_BREEZE_STATE_RECEIVE_ERR, /**< Receive firmware, but frame discontinuity happened, waiting for error (cmd=0x0F) sent. */
OTA_BREEZE_STATE_WRITE_SETTINGS, /**< Settings write after flash write, expects bootloader_settings completion event. */
OTA_BREEZE_STATE_FW_CHECK, /**< Flash check, expects command 0x28 (Firmware check) to make sure the peer will not send anything in between. */
OTA_BREEZE_STATE_RESET_PREPARE, /**< Reset prepare, expects Tx-done event to make sure commands 0x25 (firmware check result) is sent. */
} ota_breeze_state_t;
typedef struct _ota_ble_global_dat{
ota_breeze_version_t verison;
volatile unsigned char feature_enable;
volatile unsigned char ota_breeze_task_active_ctrl;
volatile unsigned char ota_breeze_task_active_flag;
volatile unsigned char ota_breeze_status;
unsigned int rx_fw_size; /**< Size of firmware to be received. */
unsigned int valid_fw_size; /**< After removing image info size*/
unsigned int bytes_recvd; /**< Size of firmware received. */
unsigned int valid_bytes_recvd; /**< Don't include iamge info FM size*/
unsigned short frames_recvd; /**< Number of frames of firmware received. */
unsigned short crc;
}_ota_ble_global_dat_t;
typedef struct {
ota_breeze_bin_type_t type;
unsigned int magic;
} ota_breeze_bin_info_t;
_ota_ble_global_dat_t* ota_breeze_get_global_data_center(void);
void ota_breeze_get_data(unsigned char ota_cmd, unsigned char num_frame, unsigned char *buffer, unsigned int length);
void ota_breeze_relate_event(unsigned char event_type, unsigned char sub_status);
void ota_breeze_set_task_active_flag(volatile unsigned char flag);
volatile unsigned char ota_breeze_get_task_active_flag(void);
void ota_breeze_set_task_active_ctrl(volatile unsigned char is_enable);
volatile unsigned char ota_breeze_get_task_active_ctrl_status(void);
#endif

View file

@ -0,0 +1,24 @@
#ifndef _OTA_BREEZE_EXPORT_H
#define _OTA_BREEZE_EXPORT_H
#include "breeze_export.h"
#define OTA_BREEZE_FW_VER_LEN (8)
typedef void (*ota_breeze_get_data_t) (breeze_otainfo_t* breeze_info);
typedef struct _ota_ble_version_{
unsigned char fw_ver[OTA_BREEZE_FW_VER_LEN];
unsigned int fw_ver_len;
}ota_breeze_version_t;
typedef struct _ota_ble_service_dat{
unsigned char is_ota_enable;
ota_breeze_version_t verison;
ota_breeze_get_data_t get_dat_cb;
}ota_breeze_service_manage_t;
int ota_breeze_service_init(ota_breeze_service_manage_t* ota_manage);
#endif

View file

@ -0,0 +1,83 @@
#ifndef __HAL_OTA_BREEZE_PLAT_H
#define __HAL_OTA_BREEZE_PLAT_H
#define BREEZE_OTA_INFO_CMD_LEN (256)
#ifndef bool
#define bool unsigned char
#endif
#define ALI_OTA_BIN_TYPE_MAGIC_APP 0xabababab
#define ALI_OTA_BIN_TYPE_MAGIC_KERNEL 0xcdcdcdcd
#define ALI_OTA_BIN_TYPE_MAGIC_SINGLE 0xefefefef
#define PAGE_SIZE 0x1000
#define PROGRAM_UNIT 4
#define ERASE_UNIT PAGE_SIZE
#define INIT_COMMAND_MAX_SIZE 256 /**< Maximum size of the init command stored in dfu_settings. */
#define NRF_DFU_CURRENT_BANK_0 0x00
#define NRF_DFU_CURRENT_BANK_1 0x01
#define NRF_DFU_BANK_LAYOUT_DUAL 0x00
#define NRF_DFU_BANK_LAYOUT_SINGLE 0x01
#define UPDATE_FINISHED 0xAB
/** @brief DFU bank state codes.
*
* @details The DFU bank state indicates the content of a bank:
* A valid image of a certain type or an invalid image.
*/
#define NRF_DFU_BANK_INVALID 0x00 /**< Invalid image. */
#define NRF_DFU_BANK_VALID_APP 0x01 /**< Valid application. */
#define NRF_DFU_BANK_VALID_SD 0xA5 /**< Valid SoftDevice. */
#define NRF_DFU_BANK_VALID_BL 0xAA /**< Valid bootloader. */
#define NRF_DFU_BANK_VALID_SD_BL 0xAC /**< Valid SoftDevice and bootloader. */
#define RESERVED_SIZE1 (20)
#define RESERVED_SIZE2 (20)
#define RESERVED_SIZE3 (17)
#define VERSION_BUF_SIZE (64)
#define OTA_ONLY_UPGRADE_FW (0x4F4F5546)//"OOUF"
#define OTA_DUAL_UPGRADE_FW (0x4F445546)//"ODUF"
#define OTA_ROLLBACK_FW_VERSION (0x4F524656)//"ORFV"
#define OTA_UPGRADE_FW_SUCC (0x4F554653)//OUFS
#define OTA_UPGRADE_FINISH (0xFFFFFFFF)
typedef struct
{
unsigned int settings_crc32;
unsigned int ota_flag;
unsigned int src_addr;
unsigned int dest_addr;
unsigned int image_size;
unsigned int image_crc32;
unsigned int image_has_copy_len; /*remember the copy len for off line*/
unsigned char reserved_buf1[RESERVED_SIZE1];
/*backup image include store addr, recovery bank addr, image size and image crc32*/
unsigned int backup_store_addr;
unsigned int backup_dest_addr;
unsigned int backup_image_size;
unsigned int backup_image_crc32;
unsigned int backup_has_copy_len; /*remember the copy len for off line*/
unsigned char reserved_buf2[RESERVED_SIZE2];
/*down_loader image parameters*/
unsigned int break_point_offset; /*breakpoint save when ota processing.*/
unsigned char version_store_buf[VERSION_BUF_SIZE]; /*version save*/
unsigned short image_info_crc16; /*image info crc value*/
unsigned char bin_type; /*Image type*/
unsigned char reserved_buf3[RESERVED_SIZE3];
} ota_settings_t;
void ota_breeze_set_image_info_crc16(unsigned char* data, unsigned int len);
void ota_breeze_set_bin_type(unsigned char type);
int ota_breeze_breakpoint_process(unsigned int iamge_size, unsigned int* break_point, bool breakpoint_valid);
int ota_breeze_write(unsigned int* off, char* in_buf ,int in_buf_len);
int ota_breeze_read(unsigned int* off, char* out_buf, int out_buf_len);
int ota_breeze_save_breakpoint(unsigned int break_point);
int ota_breeze_set_boot(void);
int ota_breeze_rollback(void);
#endif

View file

@ -0,0 +1,25 @@
#ifndef _OTA_BREEZE_TRANSPORT_H
#define _OTA_BREEZE_TRANSPORT_H
typedef enum {
OTA_BREEZE_FLASH_ERASE_OK = 0,
OTA_BREEZE_FLASH_ERASE_FAIL,
OTA_BREEZE_FLASH_STORE_OK,
OTA_BREEZE_FLASH_STORE_FAIL,
OTA_BREEZE_FLASH_ERROR = 0xff
} ota_breeze_flash_evt_t;
void ota_breeze_send_error(void);
unsigned int ota_breeze_send_fw_version_rsp(unsigned char ota_cmd, unsigned char *buffer, unsigned int length);
int ota_breeze_split_sw_ver(char *data, unsigned int *v0, unsigned int *v1, unsigned int *v2);
void ota_breeze_on_auth(unsigned char is_authenticated);
void ota_breeze_on_tx_done(unsigned char cmd);
void ota_breeze_reset(void);
void ota_breeze_disconnect(void);
void ota_breeze_on_discontinuous_frame(void);
unsigned int ota_breeze_on_fw_upgrade_req(unsigned char *buffer, unsigned int length);
unsigned int ota_breeze_send_bytes_received(void);
unsigned int ota_breeze_is_in_check_status(void);
unsigned int ota_breeze_on_fw_data(unsigned char *buffer, unsigned int length, unsigned char num_frames);
#endif

View file

@ -0,0 +1,284 @@
#include "ota_breeze.h"
#include "ota_hal_os.h"
#include "ota_log.h"
static ota_breeze_rec_t* ota_breeze_queue = NULL;
static unsigned char ota_breeze_queue_ptr_in = 0;
static unsigned char ota_breeze_queue_ptr_out = 0;
static unsigned int ota_breeze_creat_receive_buf()
{
if(ota_breeze_queue != NULL) {
return OTA_BREEZE_ERROR_INVALID_PARAM;
}
ota_breeze_queue = ota_malloc(OTA_BREEZE_RECEIVE_BUF_NUMB * sizeof(ota_breeze_rec_t));
if(ota_breeze_queue == NULL) {
return OTA_BREEZE_ERROR_NULL;
}
memset(ota_breeze_queue, 0x00, OTA_BREEZE_RECEIVE_BUF_NUMB * sizeof(ota_breeze_rec_t));
return OTA_BREEZE_SUCCESS;
}
static void ota_breeze_destroy_receive_buf()
{
if(ota_breeze_queue != NULL) {
ota_free(ota_breeze_queue);
}
ota_breeze_queue = NULL;
}
static unsigned int ota_breeze_init_receive_buf()
{
unsigned int error_code = 0;
ota_breeze_destroy_receive_buf();
error_code = ota_breeze_creat_receive_buf();
if(error_code != OTA_BREEZE_SUCCESS) {
return error_code;
}
ota_breeze_queue_ptr_in = 0;
ota_breeze_queue_ptr_out = 0;
return OTA_BREEZE_SUCCESS;
}
static void ota_breeze_receive_data_product(unsigned char ota_cmd, unsigned char num_frame, unsigned char *buffer, unsigned int length)
{
if(ota_breeze_queue == NULL) {
return;
}
if(length > OTA_BREEZE_REC_PER_FRAME_LEN) {
return;
}
ota_breeze_queue[ota_breeze_queue_ptr_in].cmd = ota_cmd;
ota_breeze_queue[ota_breeze_queue_ptr_in].length = length;
ota_breeze_queue[ota_breeze_queue_ptr_in].num_frames = num_frame;
if(buffer != NULL) {
memcpy(ota_breeze_queue[ota_breeze_queue_ptr_in].rec_buf, buffer, length);
}
ota_breeze_queue_ptr_in++;
ota_breeze_queue_ptr_in = ota_breeze_queue_ptr_in % OTA_BREEZE_RECEIVE_BUF_NUMB;
}
static unsigned int ota_breeze_receive_data_consume(ota_breeze_rec_t* out_queue)
{
if(ota_breeze_queue == NULL) {
return OTA_BREEZE_ERROR_NULL;
}
if(ota_breeze_queue_ptr_out != ota_breeze_queue_ptr_in) {
out_queue->cmd = ota_breeze_queue[ota_breeze_queue_ptr_out].cmd;
out_queue->length = ota_breeze_queue[ota_breeze_queue_ptr_out].length;
out_queue->num_frames = ota_breeze_queue[ota_breeze_queue_ptr_out].num_frames;
memcpy(out_queue->rec_buf, ota_breeze_queue[ota_breeze_queue_ptr_out].rec_buf, out_queue->length);
ota_breeze_queue_ptr_out++;
ota_breeze_queue_ptr_out = ota_breeze_queue_ptr_out % OTA_BREEZE_RECEIVE_BUF_NUMB;
}
else {
return OTA_BREEZE_ERROR_NULL;
}
return OTA_BREEZE_SUCCESS;
}
static unsigned int ota_breeze_init()
{
ota_breeze_set_status(OTA_BREEZE_STATE_IDLE);
ota_breeze_set_task_active_ctrl(true);
ota_breeze_set_task_active_flag(true);
return OTA_BREEZE_SUCCESS;
}
static unsigned int ota_breeze_start()
{
ota_breeze_rec_t tmp_queue;
ota_breeze_state_t cur_breeze_status;
ota_breeze_version_t* tmp_verion = NULL;
unsigned int error_code = 0;
unsigned char send_err = false;
if(ota_breeze_init() != OTA_BREEZE_SUCCESS) {
return OTA_BREEZE_ERROR_NULL;
}
while(1) {
if(ota_breeze_get_task_active_ctrl_status() == false) {
goto OTA_BREEZE_OVER;
}
if(ota_breeze_receive_data_consume(&tmp_queue) == OTA_BREEZE_SUCCESS) {
if ((tmp_queue.cmd & OTA_BREEZE_CMD_TYPE_MASK) != OTA_BREEZE_CMD_TYPE_FW_UPGRADE) {
printf("cmd err\r\n");
}
else {
cur_breeze_status = ota_breeze_get_status();
switch(cur_breeze_status) {
case OTA_BREEZE_STATE_IDLE:
send_err = true;
if (tmp_queue.cmd == OTA_BREEZE_CMD_FW_VERSION_REQ) { // cmd=0x20
tmp_verion = ota_breeze_get_version();
error_code = ota_breeze_send_fw_version_rsp(OTA_BREEZE_CMD_FW_VERSION_RSP, tmp_verion->fw_ver, tmp_verion->fw_ver_len);
if(error_code != OTA_BREEZE_SUCCESS) {
printf("send ver failed\r\n");
goto OTA_BREEZE_OVER;
}
send_err = false;
}
else if (tmp_queue.cmd == OTA_BREEZE_CMD_FW_UPGRADE_REQ) { // cmd=0x22
error_code = ota_breeze_on_fw_upgrade_req(tmp_queue.rec_buf, tmp_queue.length);
if (error_code == OTA_BREEZE_SUCCESS) {
error_code = ota_breeze_send_fw_upgrade_rsp(true);
if (error_code == OTA_BREEZE_SUCCESS) {
ota_breeze_set_status(OTA_BREEZE_STATE_RECEIVE);
send_err = false;
}
}
else {
(void)ota_breeze_send_fw_upgrade_rsp(false);
goto OTA_BREEZE_OVER;
}
}
break;
case OTA_BREEZE_STATE_RECEIVE:
send_err = true;
if (tmp_queue.cmd == OTA_BREEZE_CMD_FW_DATA) { // cmd=0x2F
error_code = ota_breeze_on_fw_data(tmp_queue.rec_buf, tmp_queue.length, tmp_queue.num_frames);
if(error_code == OTA_BREEZE_SUCCESS) {
if(ota_breeze_is_in_check_status() == OTA_BREEZE_SUCCESS) {
ota_breeze_set_status(OTA_BREEZE_STATE_FW_CHECK);
}
error_code = ota_breeze_send_bytes_received();
if(error_code == OTA_BREEZE_SUCCESS) {
send_err = false;
}
}
else {
printf("rece data failed\r\n");
}
}
else if (tmp_queue.cmd == OTA_BREEZE_CMD_FW_GET_INIT_FW_SIZE) { // cmd=0x27
error_code = ota_breeze_send_bytes_received();
if(error_code == OTA_BREEZE_SUCCESS) {
if(ota_breeze_is_in_check_status() == OTA_BREEZE_SUCCESS) {
ota_breeze_set_status(OTA_BREEZE_STATE_FW_CHECK);
}
send_err = false;
}
}
break;
case OTA_BREEZE_STATE_FW_CHECK:
send_err = true;
if (tmp_queue.cmd == OTA_BREEZE_CMD_FW_XFER_FINISH) { // cmd=0x28
if(ota_breeze_set_boot() == 0) {
ota_msleep(2000);
ota_breeze_send_crc_result(true);
ota_breeze_set_status(OTA_BREEZE_STATE_RESET_PREPARE);
printf("setboot over\r\n");
send_err = false;
}
else {
(void)ota_breeze_send_crc_result(false);
if (error_code == OTA_BREEZE_SUCCESS) {
ota_breeze_set_status(OTA_BREEZE_STATE_IDLE);
}
printf("setboot failed\r\n");
}
}
break;
case OTA_BREEZE_STATE_RESET_PREPARE:
case OTA_BREEZE_STATE_OFF:
send_err = true;
break;
default:
break;
}
if(send_err) {
ota_breeze_send_error();
printf("send err report\r\n");
goto OTA_BREEZE_OVER;
}
}
}
ota_msleep(1);
}
OTA_BREEZE_OVER:
printf("task over!\r\n");
ota_breeze_destroy_receive_buf();
ota_breeze_set_task_active_flag(false);
ota_breeze_set_status(OTA_BREEZE_STATE_IDLE);
return 0;
}
static unsigned int ota_breeze_start_task()
{
int ret = 0;
unsigned int error_code = 0;
void *thread = NULL;
ret = ota_thread_create(&thread, (void *)ota_breeze_start, (void *)NULL, NULL, 2048);
if (ret != 0) {
printf("creat task failed\r\n");
error_code = OTA_BREEZE_ERROR_BUSY;
}
return error_code;
}
void ota_breeze_get_data(unsigned char ota_cmd, unsigned char num_frame, unsigned char *buffer, unsigned int length)
{
volatile unsigned char tm_cnt = 0;
if((ota_breeze_get_status() == OTA_BREEZE_STATE_IDLE) && (ota_cmd == OTA_BREEZE_CMD_FW_VERSION_REQ)) {
if(ota_breeze_get_task_active_flag() == true) {
ota_breeze_set_task_active_ctrl(false);
while(ota_breeze_get_task_active_flag() == true) {
ota_breeze_set_task_active_ctrl(false);
ota_msleep(1);
if(tm_cnt > 2) {
printf("last task over failed\r\n");
return;
}
tm_cnt++;
}
ota_breeze_set_status(OTA_BREEZE_STATE_IDLE);
}
if(ota_breeze_init_receive_buf() != OTA_BREEZE_SUCCESS) {
return;
}
ota_breeze_receive_data_product(ota_cmd, num_frame, buffer, length);
if(ota_breeze_start_task() != OTA_BREEZE_SUCCESS) {
printf("ota task creat failed\r\n");
return;
}
}
else if((ota_breeze_get_task_active_flag() == true) && (ota_breeze_get_status() != OTA_BREEZE_STATE_OFF)) {
ota_breeze_receive_data_product(ota_cmd, num_frame, buffer, length);
}
else {
ota_breeze_set_task_active_ctrl(false);
ota_breeze_set_status(OTA_BREEZE_STATE_IDLE);
printf("ota stus err\r\n");
}
}
void ota_breeze_relate_event(unsigned char event_type, unsigned char sub_status)
{
switch(event_type) {
case ALI_OTA_ON_AUTH_EVT:
ota_breeze_on_auth(sub_status);
break;
case ALI_OTA_ON_TX_DONE:
ota_breeze_on_tx_done(sub_status);
break;
case ALI_OTA_ON_DISCONNECTED:
ota_msleep(1000);
ota_breeze_set_task_active_ctrl(false);
ota_msleep(1000);
ota_breeze_reset();
break;
case ALI_OTA_ON_DISCONTINUE_ERR:
ota_msleep(1000);
ota_breeze_set_task_active_ctrl(false);
ota_msleep(1000);
ota_breeze_on_discontinuous_frame();
break;
default:
break;
}
}

View file

@ -0,0 +1,342 @@
#include <aos/hal/flash.h>
#include "ota_breeze.h"
#include "ota_hal_os.h"
#include "ota_breeze_plat.h"
static unsigned int has_erase_page_numbs = 0;
static unsigned int total_erase_page_numbs = 0;
static unsigned int erase_sector_size = 0;
static int ota_part = HAL_PARTITION_OTA_TEMP;
static ota_settings_t breeze_ota_settings;
static unsigned short ota_breeze_crc16_calculate(unsigned char const* p_data, unsigned int size, unsigned short const* p_crc)
{
unsigned short crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
for (unsigned int i = 0; i < size; i++) {
crc = (unsigned char)(crc >> 8) | (crc << 8);
crc ^= p_data[i];
crc ^= (unsigned char)(crc & 0xFF) >> 4;
crc ^= (crc << 8) << 4;
crc ^= ((crc & 0xFF) << 4) << 1;
}
return crc;
}
static unsigned int ota_breeze_crc32_calculate(unsigned char const* p_data, unsigned int size, unsigned int const* p_crc)
{
unsigned int crc;
crc = (p_crc == NULL) ? 0xFFFFFFFF : ~(*p_crc);
for (unsigned int i = 0; i < size; i++) {
crc = crc ^ p_data[i];
for (unsigned int j = 8; j > 0; j--) {
crc = (crc >> 1) ^ (0xEDB88320U & ((crc & 1) ? 0xFFFFFFFF : 0));
}
}
return ~crc;
}
void ota_breeze_set_image_info_crc16(unsigned char* data, unsigned int len)
{
breeze_ota_settings.image_info_crc16 = ota_breeze_crc16_calculate(data, len, NULL);
}
static unsigned short ota_breeze_get_image_info_crc16()
{
return breeze_ota_settings.image_info_crc16;
}
static unsigned short ota_breeze_get_image_crc16()
{
unsigned int tmp_offset = 0;
unsigned char tmp_buf[32];
unsigned int read_len = 0;
unsigned short crc = 0xFFFF;
_ota_ble_global_dat_t* p_ota = ota_breeze_get_global_data_center();
if(p_ota == NULL) {
return crc;
}
crc = ota_breeze_get_image_info_crc16();
while(tmp_offset < p_ota->valid_fw_size) {
if(p_ota->valid_fw_size - tmp_offset > sizeof(tmp_buf)) {
read_len = sizeof(tmp_buf);
}
else {
read_len = p_ota->valid_fw_size - tmp_offset;
}
if(ota_breeze_read(&tmp_offset, tmp_buf, read_len) != 0) {
break;
}
crc = ota_breeze_crc16_calculate(tmp_buf, read_len, &crc);
}
return crc;
}
static unsigned int ota_breeze_get_image_crc32()
{
unsigned int tmp_offset = 0;
unsigned char tmp_buf[32];
unsigned int read_len = 0;
unsigned int crc = 0xFFFFFFFF;
_ota_ble_global_dat_t* p_ota = ota_breeze_get_global_data_center();
if(p_ota == NULL) {
return crc;
}
while(tmp_offset < p_ota->valid_fw_size) {
if(p_ota->valid_fw_size - tmp_offset > sizeof(tmp_buf)) {
read_len = sizeof(tmp_buf);
}
else {
read_len = p_ota->valid_fw_size - tmp_offset;
}
if(ota_breeze_read(&tmp_offset, tmp_buf, read_len) != 0) {
break;
}
crc = ota_breeze_crc32_calculate(tmp_buf, read_len, &crc);
}
return crc;
}
bool ota_breeze_check_if_resume(unsigned char * p_data, unsigned short length)
{
bool ret = false;
int i;
if(ota_breeze_get_image_info(&breeze_ota_settings) == 0) {
if(memcmp(breeze_ota_settings.version_store_buf, p_data, length) == 0) {
ret = true;
}
}
return ret;
}
void ota_breeze_update_fw_version(unsigned char * p_data, unsigned short length)
{
memcpy(breeze_ota_settings.version_store_buf, p_data, length);
}
void ota_breeze_set_bin_type(unsigned char type)
{
breeze_ota_settings.bin_type = type;
}
unsigned char ota_breeze_get_bin_type()
{
return breeze_ota_settings.bin_type;
}
static int ota_breeze_get_parttion_id(unsigned char bin_type)
{
int part_id = 0xff;
switch(bin_type) {
case OTA_BIN_TYPE_APP:
part_id = HAL_PARTITION_MBINS_APP;
break;
case OTA_BIN_TYPE_KERNEL:
part_id = HAL_PARTITION_MBINS_KERNEL;
break;
case OTA_BIN_TYPE_APP_KERNEL:
part_id = HAL_PARTITION_APPLICATION;
break;
case OTA_BIN_TYPE_SINGLE:
part_id = HAL_PARTITION_APPLICATION;
break;
default:
break;
}
return part_id;
}
int ota_breeze_get_image_info(ota_settings_t* tmp_info)
{
int ret = 0;
unsigned int off = 0;
unsigned int tmp_crc = 0;
if(tmp_info == NULL) {
return -1;
}
ret = hal_flash_read(HAL_PARTITION_PARAMETER_1, (unsigned int*)&off, (void*)tmp_info, sizeof(ota_settings_t));
if(ret == 0) {
tmp_crc = ota_breeze_crc32_calculate((unsigned char*)tmp_info + 4, sizeof(ota_settings_t) - 4, NULL);
if(tmp_crc == tmp_info->settings_crc32) {
ret = 0;
}
else {
ret = -1;
}
}
return ret;
}
static int ota_breeze_save_image_info(ota_settings_t* tmp_info)
{
int ret = -1;
unsigned int off = 0;
if(tmp_info == NULL) {
return -1;
}
tmp_info->settings_crc32 = ota_breeze_crc32_calculate((unsigned char*)tmp_info + 4, sizeof(ota_settings_t) - 4, NULL);
ret = hal_flash_erase(HAL_PARTITION_PARAMETER_1, 0x00, erase_sector_size);
if(ret == 0) {
ret = hal_flash_write(HAL_PARTITION_PARAMETER_1, &off, (void*)tmp_info, sizeof(ota_settings_t));
}
return ret;
}
static unsigned int ota_breeze_align_to_page(unsigned int val, unsigned int page_size)
{
return ((val + page_size - 1) & ~(page_size - 1));
}
int ota_breeze_breakpoint_process(unsigned int iamge_size, unsigned int* break_point, bool breakpoint_valid)
{
int ret = 0;
unsigned int num_pages = 0;
int err_code = 0;
if(iamge_size == 0 || break_point == NULL) {
ret = -1;
goto OTA_BREEZE_PROCESS_BREAKPOINT_OVER;
}
if (breakpoint_valid) {
if(iamge_size == breeze_ota_settings.break_point_offset) {
*break_point = breeze_ota_settings.break_point_offset;
}
else {
*break_point = breeze_ota_settings.break_point_offset & ~(erase_sector_size - 1);
}
}
else {
breeze_ota_settings.break_point_offset = 0;
*break_point = 0;
}
num_pages = ota_breeze_align_to_page(iamge_size - *break_point, erase_sector_size) / erase_sector_size;
if (num_pages == 0) {
ret = 0;
goto OTA_BREEZE_PROCESS_BREAKPOINT_OVER;
}
else {
has_erase_page_numbs = *break_point / erase_sector_size;
total_erase_page_numbs = num_pages + has_erase_page_numbs;
err_code = hal_flash_erase(ota_part, *break_point, erase_sector_size);
if (err_code != 0) {
printf(" f-erase failed\r\n");
ret = -1;
goto OTA_BREEZE_PROCESS_BREAKPOINT_OVER;
}
has_erase_page_numbs++;
}
OTA_BREEZE_PROCESS_BREAKPOINT_OVER:
return ret;
}
int ota_breeze_save_breakpoint(unsigned int break_point)
{
breeze_ota_settings.break_point_offset = break_point;
return ota_breeze_save_image_info(&breeze_ota_settings);
}
int ota_breeze_write(unsigned int* off, char* in_buf ,int in_buf_len)
{
int ret = 0;
if((has_erase_page_numbs <= total_erase_page_numbs) && (*off % erase_sector_size + in_buf_len >= erase_sector_size)) {
ret = hal_flash_erase(ota_part, *off + in_buf_len, erase_sector_size);
if(ret == 0) {
has_erase_page_numbs++;
}
}
if(ret == 0) {
ret = hal_flash_write(ota_part, off, in_buf, in_buf_len);
}
return ret;
}
int ota_breeze_read(unsigned int* off, char* out_buf, int out_buf_len)
{
return hal_flash_read(ota_part, (unsigned int*)off, out_buf, out_buf_len);
}
int ota_breeze_set_boot()
{
int ret = 0;
unsigned short crc = 0;
unsigned int img_crc = 0;
unsigned int tmp_offset = 0;
int dest_part = 0;
hal_logic_partition_t *dest_part_info = NULL;
hal_logic_partition_t *ota_part_info = hal_flash_get_info(ota_part);
dest_part = ota_breeze_get_parttion_id(ota_breeze_get_bin_type());
if(dest_part == 0xff) {
ret = -1;
goto OTA_BREEZE_SET_BOOT_OVER;
}
dest_part_info = hal_flash_get_info(dest_part);
_ota_ble_global_dat_t* p_ota = ota_breeze_get_global_data_center();
if(p_ota == NULL) {
ret = -1;
goto OTA_BREEZE_SET_BOOT_OVER;
}
crc = ota_breeze_get_image_crc16();
if (crc == p_ota->crc) {
printf("crc16 ok\r\n");
img_crc = ota_breeze_get_image_crc32();
breeze_ota_settings.ota_flag = OTA_ONLY_UPGRADE_FW;
breeze_ota_settings.backup_dest_addr = breeze_ota_settings.dest_addr;
breeze_ota_settings.backup_store_addr = breeze_ota_settings.src_addr;
breeze_ota_settings.backup_image_size = breeze_ota_settings.image_size;
breeze_ota_settings.backup_image_crc32 = breeze_ota_settings.image_crc32;
breeze_ota_settings.backup_has_copy_len = 0;
breeze_ota_settings.image_size = p_ota->valid_fw_size;
breeze_ota_settings.image_crc32 = img_crc;
breeze_ota_settings.dest_addr = dest_part_info->partition_start_addr;
breeze_ota_settings.src_addr = ota_part_info->partition_start_addr;
breeze_ota_settings.image_has_copy_len = 0;
breeze_ota_settings.settings_crc32 = ota_breeze_crc32_calculate((unsigned char*)&breeze_ota_settings + 4, sizeof(breeze_ota_settings) - 4, NULL);
ret = hal_flash_erase(HAL_PARTITION_PARAMETER_1, 0x00, erase_sector_size);
if(ret == 0) {
ret = hal_flash_write(HAL_PARTITION_PARAMETER_1, &tmp_offset, &breeze_ota_settings, sizeof(breeze_ota_settings));
}
}
else {
printf("crc16 error!\r\n");
breeze_ota_settings.break_point_offset = 0;
breeze_ota_settings.image_info_crc16 = 0;
breeze_ota_settings.bin_type = 0xff;
memset(breeze_ota_settings.version_store_buf, 0x00, sizeof(breeze_ota_settings.version_store_buf));
ota_breeze_save_image_info(&breeze_ota_settings);
ret = -1;
}
OTA_BREEZE_SET_BOOT_OVER:
return ret;
}
int ota_breeze_rollback()
{
unsigned int tmp_crc = 0;
unsigned int tmp_offset = 0;
int ret = -1;
erase_sector_size = hal_flash_erase_sector_size();
memset(&breeze_ota_settings, 0x00, sizeof(ota_settings_t));
if(hal_flash_read(HAL_PARTITION_PARAMETER_1, &tmp_offset, &breeze_ota_settings, sizeof(ota_settings_t)) != 0) {
ret = -1;
goto OTA_BREEZE_ROLLBACK_OVER;
}
tmp_crc = ota_breeze_crc32_calculate((unsigned char*)&breeze_ota_settings + 4, sizeof(breeze_ota_settings) - 4, NULL);
if(breeze_ota_settings.settings_crc32 == tmp_crc) {
if(breeze_ota_settings.ota_flag == OTA_UPGRADE_FW_SUCC) {
breeze_ota_settings.ota_flag = OTA_UPGRADE_FINISH;
breeze_ota_settings.break_point_offset = 0;
breeze_ota_settings.image_info_crc16 = 0;
breeze_ota_settings.bin_type = 0xff;
memset(breeze_ota_settings.version_store_buf, 0x00, sizeof(breeze_ota_settings.version_store_buf));
breeze_ota_settings.settings_crc32 = ota_breeze_crc32_calculate((unsigned char*)&breeze_ota_settings + 4, sizeof(breeze_ota_settings) - 4, NULL);
ret = hal_flash_erase(HAL_PARTITION_PARAMETER_1, 0x00, erase_sector_size);
if(ret == 0) {
ret = hal_flash_write(HAL_PARTITION_PARAMETER_1, &tmp_offset, &breeze_ota_settings, sizeof(breeze_ota_settings));
}
}
}
OTA_BREEZE_ROLLBACK_OVER:
return ret;
}

View file

@ -0,0 +1,124 @@
#include "ota_breeze.h"
#include "ota_breeze_export.h"
#include "ota_log.h"
#include "breeze_export.h"
static _ota_ble_global_dat_t g_ctx;
_ota_ble_global_dat_t* ota_breeze_get_global_data_center()
{
return &g_ctx;
}
void ota_breeze_set_task_active_ctrl(volatile unsigned char is_enable)
{
g_ctx.ota_breeze_task_active_ctrl = is_enable;
}
volatile unsigned char ota_breeze_get_task_active_ctrl_status()
{
return g_ctx.ota_breeze_task_active_ctrl;
}
void ota_breeze_set_task_active_flag(volatile unsigned char flag)
{
g_ctx.ota_breeze_task_active_flag = flag;
}
volatile unsigned char ota_breeze_get_task_active_flag()
{
return g_ctx.ota_breeze_task_active_flag;
}
void ota_breeze_set_status(ota_breeze_state_t status)
{
g_ctx.ota_breeze_status = status;
}
ota_breeze_state_t ota_breeze_get_status()
{
return g_ctx.ota_breeze_status;
}
static int ota_breeze_parse_firmware_version(unsigned char *data, unsigned char len)
{
int err_code = 0;
unsigned int v[3];
unsigned char l_data[OTA_BREEZE_FW_VER_LEN + 1]; // +1 for trailing zero
if ((data == NULL) || (len == 0)) {
return -1;
}
memcpy(l_data, data, len);
l_data[len] = 0;
if(ota_breeze_split_sw_ver((char *)l_data, v, v + 1, v + 2) < 0) {
return -1;
}
memset(l_data, 0, sizeof(l_data));
sprintf((char *)l_data, "%d.%d.%d", (int)v[0], (int)v[1], (int)v[2]);
if (memcmp(l_data, data, len) == 0) {
return 0;
} else {
return -1;
}
}
static int ota_breeze_set_version(unsigned char* fw_ver, unsigned char fw_ver_len)
{
memset(&g_ctx.verison, 0x00, sizeof(ota_breeze_version_t));
if (fw_ver_len == 0 || fw_ver_len > OTA_BREEZE_FW_VER_LEN) {
return -1;
}
g_ctx.verison.fw_ver_len = fw_ver_len;
memcpy(g_ctx.verison.fw_ver, fw_ver, fw_ver_len);
return 0;
}
ota_breeze_version_t* ota_breeze_get_version()
{
return &g_ctx.verison;
}
void ota_breeze_disconnect()
{
/* still have data feedback to app, so do disconnection after a * while */
ota_msleep(2000);
breeze_disconnect_ble();
}
void ota_breeze_process_message(breeze_otainfo_t* breeze_info)
{
if(breeze_info != NULL) {
if(breeze_info->type == OTA_CMD) {
ota_breeze_get_data(breeze_info->cmd_evt.m_cmd.cmd, breeze_info->cmd_evt.m_cmd.frame,
breeze_info->cmd_evt.m_cmd.data, breeze_info->cmd_evt.m_cmd.len);
}
else if(breeze_info->type == OTA_EVT) {
ota_breeze_relate_event(breeze_info->cmd_evt.m_evt.evt, breeze_info->cmd_evt.m_evt.d);
}
}
}
int ota_breeze_service_init(ota_breeze_service_manage_t* ota_manage)
{
if(ota_manage == NULL) {
return -1;
}
if(ota_breeze_parse_firmware_version(ota_manage->verison.fw_ver, ota_manage->verison.fw_ver_len) < 0) {
printf("ver parse failed\r\n");
return -1;
}
memset(&g_ctx, 0x00, sizeof(_ota_ble_global_dat_t));
if(ota_breeze_set_version(ota_manage->verison.fw_ver, ota_manage->verison.fw_ver_len) < 0) {
printf("ver set failed");
return -1;
}
g_ctx.feature_enable = ota_manage->is_ota_enable;
ota_manage->get_dat_cb = ota_breeze_process_message;
ota_breeze_set_status(OTA_BREEZE_STATE_OFF);
return 0;
}

View file

@ -0,0 +1,401 @@
#include "ota_breeze_transport.h"
#include "ota_breeze.h"
#include "ota_hal_os.h"
#include "ota_log.h"
#include "ota_breeze_plat.h"
static unsigned char ota_breeze_new_fw = 0;
#define EXTRACT_U16(d) (*((unsigned char *)(d)) | (*((unsigned char *)(d) + 1) << 8))
#define EXTRACT_U32(d) \
(*((unsigned char *)(d)) | (*((unsigned char *)(d) + 1) << 8) | \
(*((unsigned char *)(d) + 2) << 16) | (*((unsigned char *)(d) + 3) << 24))
#define ENCODE_U16(d, val) \
{ \
*((unsigned char *)(d)) = (val)&0xFF; \
*((unsigned char *)(d) + 1) = ((val) >> 8) & 0xFF; \
}
#define ENCODE_U32(d, val) \
{ \
*((unsigned char *)(d)) = (val)&0xFF; \
*((unsigned char *)(d) + 1) = ((val) >> 8) & 0xFF; \
*((unsigned char *)(d) + 2) = ((val) >> 16) & 0xFF; \
*((unsigned char *)(d) + 3) = ((val) >> 24) & 0xFF; \
}
bool ota_breeze_check_if_bins_supported()
{
#ifdef AOS_BINS
bool is_support_mbins = true;
#else
bool is_support_mbins = false;
#endif
return is_support_mbins;
}
void ota_breeze_send_error()
{
unsigned int err_code = 0;
err_code = breeze_post_ext(OTA_BREEZE_CMD_ERROR, NULL, 0);
if (err_code != OTA_BREEZE_SUCCESS) {
printf("send err failed\r\n");
}
}
unsigned int ota_breeze_send_fw_version_rsp(unsigned char ota_cmd, unsigned char *buffer, unsigned int length)
{
if((buffer == NULL) || (length == 0)) {
return OTA_BREEZE_ERROR_INVALID_PARAM;
}
return breeze_post_ext(OTA_BREEZE_CMD_FW_VERSION_RSP, buffer, length);
}
int ota_breeze_split_sw_ver(char *data, unsigned int *v0, unsigned int *v1, unsigned int *v2)
{
int i = sscanf(data, "%d.%d.%d", (int *)v0, (int *)v1, (int *)v2);
return ((i == 3) ? 0 : -1);
}
static unsigned int ota_breeze_check_upgrade_fw_version(ota_breeze_version_t *version, unsigned char *p_data, unsigned char length)
{
unsigned int v_old[3], v_new[3];
unsigned char l_data_old[OTA_BREEZE_FW_VER_LEN + 1]; // +1 for trailing zero
unsigned char l_data_new[OTA_BREEZE_FW_VER_LEN + 1]; // +1 for trailing zero
unsigned char l_len;
if((version == NULL) || (p_data == NULL) || (length == 0)) {
return OTA_BREEZE_ERROR_INVALID_PARAM;
}
// Copy to stack variable as trailing zero is required.
memcpy(l_data_old, version->fw_ver, version->fw_ver_len);
l_data_old[version->fw_ver_len] = 0;
l_len = length - sizeof(unsigned int) - sizeof(unsigned short) - 1;
memcpy(l_data_new, p_data, l_len);
l_data_new[l_len] = 0;
// Split SW version into 3 parts.
if(ota_breeze_split_sw_ver((char *)l_data_old, v_old, v_old + 1, v_old + 2) < 0) {
return OTA_BREEZE_ERROR_INVALID_DATA;
}
if(ota_breeze_split_sw_ver((char *)l_data_new, v_new, v_new + 1, v_new + 2) < 0) {
return OTA_BREEZE_ERROR_INVALID_DATA;
}
// Try to reconstruct the version string.
memset(l_data_new, 0, sizeof(l_data_new));
sprintf((char *)l_data_new, "%d.%d.%d", (int)v_new[0], (int)v_new[1],
(int)v_new[2]);
if (memcmp(l_data_new, p_data, l_len) != 0) {
return OTA_BREEZE_ERROR_FORBIDDEN;
}
// Check digits in software version
if (v_new[0] > v_old[0]) { // x
return 0;
} else if (v_new[0] < v_old[0]) {
return OTA_BREEZE_ERROR_FORBIDDEN;
}
if (v_new[1] > v_old[1]) { // y
return 0;
} else if (v_new[1] < v_old[1]) {
return OTA_BREEZE_ERROR_FORBIDDEN;
}
if (v_new[2] <= v_old[2]) { // z
return OTA_BREEZE_ERROR_FORBIDDEN;
}
return OTA_BREEZE_SUCCESS;
}
unsigned int ota_breeze_align_to_page(unsigned int val, unsigned int page_size)
{
return ((val + page_size - 1) & ~(page_size - 1));
}
/**@brief Send firmware upgrade response. */
unsigned int ota_breeze_send_fw_upgrade_rsp(unsigned char allow_upgrade)
{
unsigned char ack = 0;
ack = (allow_upgrade) ? 1 : 0;
return breeze_post_ext(OTA_BREEZE_CMD_FW_UPGRADE_RSP, &ack, 1);
}
unsigned int ota_breeze_send_fwup_success()
{
unsigned int err_code;
unsigned char fwup_success = 0x01;
return breeze_post_ext(OTA_BREEZE_CMD_FW_UPDATE_PROCESS, &fwup_success, 1);
}
/**@brief Send number of bytes of firmware received. */
unsigned int ota_breeze_send_bytes_received()
{
unsigned int err_code;
unsigned char tx_buff[16];
_ota_ble_global_dat_t* p_ota = ota_breeze_get_global_data_center();
if(p_ota == NULL) {
return OTA_BREEZE_ERROR_INVALID_PARAM;
}
memset(tx_buff, 0x00, sizeof(tx_buff));
ENCODE_U16(tx_buff, p_ota->frames_recvd);
ENCODE_U32(tx_buff + sizeof(unsigned short), p_ota->bytes_recvd);
err_code = breeze_post_ext(OTA_BREEZE_CMD_FW_BYTES_RECEIVED, tx_buff, sizeof(unsigned short) + sizeof(unsigned int));
if (err_code != OTA_BREEZE_SUCCESS) {
printf("send rec err\r\n");
}
return err_code;
}
/**@brief Send the result of CRC check. */
unsigned int ota_breeze_send_crc_result(unsigned char crc_ok)
{
unsigned char ack = 0;
ack = (crc_ok) ? 1 : 0;
return breeze_post_ext(OTA_BREEZE_CMD_FW_CHECK_RESULT, &ack, 1);
}
ota_breeze_bin_type_t ota_breeze_get_image_type(unsigned int image_magic)
{
ota_breeze_bin_type_t image_type = OTA_BIN_TYPE_INVALID;
switch(image_magic) {
case OTA_BIN_TYPE_MAGIC_APP:
image_type = OTA_BIN_TYPE_APP;
break;
case OTA_BIN_TYPE_MAGIC_KERNEL:
image_type = OTA_BIN_TYPE_MAGIC_KERNEL;
break;
case OTA_BIN_TYPE_MAGIC_SINGLE:
image_type = OTA_BIN_TYPE_SINGLE;
break;
case OTA_BIN_TYPE_MAGIC_APP_KERNEL:
image_type = OTA_BIN_TYPE_SINGLE;
break;
default:
break;
}
return image_type;
}
unsigned int ota_breeze_on_fw_upgrade_req(unsigned char *buffer, unsigned int length)
{
unsigned int err_code = 0;
unsigned char l_len = 0;
unsigned char resume = false;
int ret = 0;
_ota_ble_global_dat_t* p_ota = NULL;
if((buffer == NULL) || (length < sizeof(unsigned int) + sizeof(unsigned short))) {
return OTA_BREEZE_ERROR_INVALID_PARAM;
}
p_ota = ota_breeze_get_global_data_center();
if(p_ota == NULL) {
return OTA_BREEZE_ERROR_INVALID_PARAM;
}
resume = ota_breeze_check_if_resume(buffer, length);
ret = ota_breeze_check_upgrade_fw_version(&p_ota->verison, buffer, length);
if (ret == 0 || resume) {
ota_breeze_update_fw_version(buffer, length);
l_len = length - sizeof(unsigned int) - sizeof(unsigned short);
p_ota->rx_fw_size = EXTRACT_U32(buffer + l_len);
p_ota->frames_recvd = 0;
p_ota->crc = EXTRACT_U16(buffer + l_len + sizeof(unsigned int));
if(p_ota->rx_fw_size > sizeof(ota_image_t)) {
p_ota->valid_fw_size = p_ota->rx_fw_size - sizeof(ota_image_t);
ret = ota_breeze_breakpoint_process(p_ota->valid_fw_size, &p_ota->valid_bytes_recvd, resume);
if(ret == 0) {
if(p_ota->valid_bytes_recvd > 0) {
p_ota->bytes_recvd = p_ota->valid_bytes_recvd + sizeof(ota_image_t);
}
}
else {
err_code = OTA_BREEZE_ERROR_GET_BREAKPOINT_FAIL;
}
}
else {
err_code = OTA_BREEZE_ERROR_DATA_SIZE;
}
}
return err_code;
}
unsigned int ota_breeze_on_fw_data(unsigned char *buffer, unsigned int length, unsigned char num_frames)
{
unsigned int err_code = OTA_BREEZE_SUCCESS;
unsigned int i = 0;
unsigned int bin_info_len = 0;
ota_image_t bin_info;
ota_breeze_bin_type_t bin_type;
static unsigned short last_percent = 0;
unsigned short percent;
_ota_ble_global_dat_t* p_ota = NULL;
if((buffer == NULL) || (length == 0)) {
err_code = OTA_BREEZE_ERROR_INVALID_PARAM;
goto OTA_BREEZE_TRANS_ERRO;
}
if ((length & 0x03) != 0) {
ota_breeze_send_error();
err_code = OTA_BREEZE_ERROR_DATA_SIZE;
goto OTA_BREEZE_TRANS_ERRO;
}
p_ota = ota_breeze_get_global_data_center();
if(p_ota == NULL) {
err_code = OTA_BREEZE_ERROR_INVALID_PARAM;
goto OTA_BREEZE_TRANS_ERRO;
}
bin_info_len = sizeof(ota_image_t);
if (p_ota->valid_bytes_recvd == OTA_IMAGE_MAGIC_OFFSET) {
if(length >= bin_info_len) {
memcpy(&bin_info, buffer, bin_info_len);
bin_type = ota_breeze_get_image_type(bin_info.image_magic);
if(bin_type == OTA_BIN_TYPE_INVALID) {
printf("magic error\r\n");
err_code = OTA_BREEZE_ERROR_NOT_SUPPORTED;
goto OTA_BREEZE_TRANS_ERRO;
}
if ((bin_type != OTA_BIN_TYPE_SINGLE) &&
(ota_breeze_check_if_bins_supported() == false)) {
err_code = OTA_BREEZE_ERROR_NOT_SUPPORTED;
goto OTA_BREEZE_TRANS_ERRO;
}
if(bin_info.image_size != p_ota->valid_fw_size) {
err_code = OTA_BREEZE_ERROR_INVALID_LENGTH;
goto OTA_BREEZE_TRANS_ERRO;
}
ota_breeze_set_image_info_crc16(buffer, bin_info_len);
buffer += bin_info_len;
length -= bin_info_len;
p_ota->bytes_recvd += bin_info_len;
ota_breeze_set_bin_type((unsigned char)bin_type);
}
else {
err_code = OTA_BREEZE_ERROR_INVALID_LENGTH;
goto OTA_BREEZE_TRANS_ERRO;
}
}
if (ota_breeze_write(&p_ota->valid_bytes_recvd, (char *)buffer, length) != 0) {
err_code = OTA_BREEZE_ERROR_FLASH_STORE_FAIL;
goto OTA_BREEZE_TRANS_ERRO;
}
p_ota->frames_recvd += num_frames;
p_ota->bytes_recvd += length;
percent = p_ota->bytes_recvd * 100 / p_ota->rx_fw_size; /* Ensure no overflow */
if(percent < last_percent) {
/*breakpoint need to clear last_percent*/
last_percent = 0;
}
if ((percent - last_percent) >= 5) {
printf("===>%dB\t%d%% ...\r\n", p_ota->bytes_recvd, percent);
last_percent = percent;
if(ota_breeze_save_breakpoint(p_ota->valid_bytes_recvd) !=0 ) {
err_code = OTA_BREEZE_ERROR_SETTINGS_FAIL;
}
}
OTA_BREEZE_TRANS_ERRO:
return err_code;
}
unsigned int ota_breeze_is_in_check_status()
{
unsigned int status = OTA_BREEZE_ERROR_INVALID_STATE;
_ota_ble_global_dat_t* p_ota = ota_breeze_get_global_data_center();
if(p_ota == NULL) {
return OTA_BREEZE_ERROR_INVALID_PARAM;
}
if (p_ota->bytes_recvd >= p_ota->rx_fw_size) {
status = OTA_BREEZE_SUCCESS;
}
return status;
}
void ota_breeze_reset()
{
_ota_ble_global_dat_t* p_ota = ota_breeze_get_global_data_center();
if(p_ota == NULL) {
return;
}
printf("discnt\r\n");
/* Reset state machine. */
p_ota->ota_breeze_status = OTA_BREEZE_STATE_OFF;
p_ota->rx_fw_size = 0;
p_ota->bytes_recvd = 0;
p_ota->frames_recvd = 0;
p_ota->crc = 0;
p_ota->valid_bytes_recvd = 0;
if (ota_breeze_new_fw) {
ota_reboot();
}
}
void ota_breeze_on_tx_done(unsigned char cmd)
{
_ota_ble_global_dat_t* p_ota = ota_breeze_get_global_data_center();
if(p_ota == NULL) {
return;
}
switch (p_ota->ota_breeze_status) {
case OTA_BREEZE_STATE_RESET_PREPARE:
if (cmd == OTA_BREEZE_CMD_FW_CHECK_RESULT) {
ota_breeze_new_fw = true;
ota_breeze_disconnect();
}
break;
case OTA_BREEZE_STATE_RECEIVE_ERR:
if (cmd == OTA_BREEZE_CMD_ERROR) {
ota_breeze_send_bytes_received();
}
else if (cmd == OTA_BREEZE_CMD_FW_BYTES_RECEIVED) {
p_ota->ota_breeze_status = OTA_BREEZE_STATE_RECEIVE;
}
break;
default:
break;
}
}
void ota_breeze_on_auth(unsigned char is_authenticated)
{
unsigned int err_code;
_ota_ble_global_dat_t* p_ota = ota_breeze_get_global_data_center();
if(p_ota == NULL) {
goto OTA_BREEZE_AUTH_OVER;
}
if (ota_breeze_rollback() == 0) {
if(ota_breeze_send_fwup_success() != OTA_BREEZE_SUCCESS) {
goto OTA_BREEZE_AUTH_OVER;
}
printf("OTA OK!\r\n");
}
if (!is_authenticated) {
goto OTA_BREEZE_AUTH_OVER;
}
if (p_ota->ota_breeze_status == OTA_BREEZE_STATE_OFF) {
if (p_ota->feature_enable) {
p_ota->ota_breeze_status = OTA_BREEZE_STATE_IDLE;
}
}
else {
printf("err stus\r\n");
}
OTA_BREEZE_AUTH_OVER:
printf("auth over\r\n");
return;
}
void ota_breeze_on_discontinuous_frame()
{
_ota_ble_global_dat_t* p_ota = ota_breeze_get_global_data_center();
if(p_ota == NULL) {
return;
}
if (p_ota->ota_breeze_status == OTA_BREEZE_STATE_RECEIVE) {
p_ota->ota_breeze_status = OTA_BREEZE_STATE_RECEIVE_ERR;
}
ota_reboot();
}

View file

@ -0,0 +1,60 @@
## Contents
```sh
download
├── aos.mk
├── Config.in
├── ota_download_coap.c
├── ota_download_http.c
└── README.md
```
## Introduction
An over-the-air update is the wireless delivery of new software or data to smart devices, especially IoT devices. Wireless carriers and OEMs typically use over-the-air (OTA) updates to deploy the new operating systems and the software app to these devices.
## Features
1. Differential incremental upgrade;
2. Dual banker:AB partition upgrade to support rollback to old version;
3. Secure download channel;
4. Firmware digital signature verification.
## Dependencies
Linkkit MQTT channel
Linkkit CoAP channel
## API
User service APIs:
```c
/*OTA export service APIs*/
int ota_service_init(ota_service_t* ctx);
int ota_service_deinit(ota_service_t* ctx);
```
for sample code please check [otaapp](../../../app/example/otaapp/).
## RTOS build
```sh
cd ROOT DIR;
aos make otaapp@board;
```
## run CLI CMDs
1. connect network
```
netmgr connect ssid passwd
```
2. run ota demo
```
OTA_APP pk dn ds ps
```
## Reference
* [AliOS-Things OTA使用说明](https://github.com/alibaba/AliOS-Things/wiki/OTA-Tutorial)
* [OTA flash分区说明文档](https://github.com/alibaba/AliOS-Things/wiki/OTA-Flash-Partitions-Overview)
* [云端一体化差分+安全升级AliOS Things物联网升级“利器”](https://mp.weixin.qq.com/s/Pb8Lleuww1r7qQJHu5ON8g)

View file

@ -0,0 +1,29 @@
NAME := ota_download
#default gcc
ifeq ($(COMPILER),)
$(NAME)_CFLAGS += -Wall -Werror
else ifeq ($(COMPILER),gcc)
$(NAME)_CFLAGS += -Wall -Werror
endif
$(NAME)_MBINS_TYPE := kernel
$(NAME)_VERSION := 1.0.0
$(NAME)_SUMMARY := Download firmware form OTA server.
ifeq ($(DOWNLOAD),coap)
$(NAME)_SOURCES := ota_download_coap.c
else
$(NAME)_SOURCES := ota_download_http.c
endif
ifeq ($(TLS_DL),1)
GLOBAL_DEFINES += AOS_OTA_TLS
endif
ifeq ($(ITLS_DL),1)
GLOBAL_DEFINES += AOS_OTA_ITLS
endif
GLOBAL_INCLUDES += . ../../inc ../../hal ../verify

View file

@ -0,0 +1,138 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "utils_md5.h"
#include "ota_service.h"
#include "ota_log.h"
#include "ota_hal_os.h"
#include "ota_hal_plat.h"
#include "ota_verify.h"
#define OTA_COAP_BLOCK_SIZE 1024
#define COAP_OPTION_BLOCK2 23
#define MAX_RETRY 10
#define DOWNLOAD_PATH "/topic/ota/device/download/%s/%s"
static int block_cur_num = 0;
static int block_more = 1;
static int block_size = OTA_COAP_BLOCK_SIZE;
static int total_size = 0;
static int coap_client_running = 0;
static int retry_cnt = 5;
static void *sem_send;
static void iotx_response_block_handler(void *arg, void *p_response);
static int ota_download_start(void *pctx)
{
int ret = 0;
int breakpoint = 0;
char path[128] = {0};
ota_service_t* ctx = pctx;
if (!ctx || !(ctx->h_ch)) {
return -1;
}
ret = ota_snprintf(path, sizeof(path), DOWNLOAD_PATH, ctx->pk, ctx->dn);
if (ret < 0) {
return -1;
}
retry_cnt = 0;
breakpoint = ota_get_break_point();
if (breakpoint) {
block_cur_num = breakpoint / OTA_COAP_BLOCK_SIZE;
} else {
breakpoint = 0;
block_cur_num = 0;
}
coap_client_running = 1;
sem_send = ota_semaphore_create();
while (coap_client_running && block_more) {
iotx_message_t message;
message.p_payload = NULL;
message.payload_len = 0;
message.resp_callback = iotx_response_block_handler;
message.msg_type = COAP_MESSAGE_CON;
message.content_type = COAP_CONTENT_TYPE_JSON;
ota_coap_send_block(ctx->h_ch, path, &message, COAP_OPTION_BLOCK2, block_cur_num, block_more, block_size);
ret = ota_semaphore_wait(&sem_send, 5000);
if(ret < 0) {
ret = OTA_DOWNLOAD_FAIL;
OTA_LOG_E("download error %s", strerror(errno));
break;
}
}
if (block_more == 0 && block_cur_num) {
OTA_LOG_I("download finish.");
ota_set_break_point(0);
} else {
ota_set_break_point(breakpoint);
}
return ret;
}
static void iotx_response_block_handler(void *arg, void *p_response)
{
int len = 0;
int cur_num = 0;
int more = 0;
int size = 0;
int breakpoint = 0;
char *p_payload = NULL;
iotx_coap_resp_code_t resp_code;
ota_coap_get_code(p_response, &resp_code);
if (resp_code == 0x45) {
ota_coap_get_payload(p_response, (const char**)&p_payload, &len);
if (ota_coap_parse_block(p_response, COAP_OPTION_BLOCK2, &cur_num, &more, &size)) {
OTA_LOG_I("num: %d, more: %d,size: %d", cur_num, more, size);
block_size = size;
if (cur_num == block_cur_num) {
if (more == 0) {
block_more = 0;
} else {
block_cur_num++;
}
total_size += len;
// OTA_LOG_I("size:%d, n:%d", size, nbytes);
int ret = 0;
ret = ota_hal_write(&breakpoint, p_payload,len);
if (ret < 0) {
OTA_LOG_E("write err:%d\n", ret);
return;
}
}
} else {
if (retry_cnt++ > MAX_RETRY) {
coap_client_running = 0;
}
}
} else {
if (retry_cnt++ > MAX_RETRY) {
coap_client_running = 0;
}
}
ota_semaphore_post(&sem_send);
}
static int ota_download_stop(void)
{
return 0;
}
static ota_download_t dl_coap = {
.start = ota_download_start,
.stop = ota_download_stop,
};
ota_download_t *ota_get_download(void)
{
return &dl_coap;
}

View file

@ -0,0 +1,371 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "ota_service.h"
#include "ota_log.h"
#include "ota_hal_os.h"
#include "ota_hal_plat.h"
#include "ota_verify.h"
#if defined (AOS_OTA_ITLS)
#include "iot_import.h"
#endif
#if (defined SUPPORT_MCU_OTA)
#include "ota_hal_mcu.h"
#endif
#ifndef EINTR
#define EINTR 4
#endif
#define OTA_BUFFER_MAX_SIZE 513
#define HTTP_HEADER \
"GET /%s HTTP/1.1\r\nAccept:*/*\r\n\
User-Agent: Mozilla/5.0\r\n\
Cache-Control: no-cache\r\n\
Connection: close\r\n\
Host:%s:%d\r\n\r\n"
#define HTTP_HEADER_RESUME \
"GET /%s HTTP/1.1\r\nAccept:*/*\r\n\
User-Agent: Mozilla/5.0\r\n\
Cache-Control: no-cache\r\n\
Connection: close\r\n\
Range: bytes=%d-\r\n\
Host:%s:%d\r\n\r\n"
#if defined AOS_OTA_TLS
static const char *ca = \
{
\
"-----BEGIN CERTIFICATE-----\r\n"
"MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" \
"A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" \
"b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" \
"MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" \
"YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" \
"aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" \
"jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" \
"xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" \
"1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" \
"snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" \
"U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" \
"9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" \
"BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" \
"AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" \
"yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" \
"38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" \
"AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" \
"DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" \
"HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" \
"-----END CERTIFICATE-----"
};
#endif
static int isHttps = 0;
/**
* @brief http_gethost_info
*
* @Param: src url
* @Param: web WEB
* @Param: file download filename
* @Param: port default 80
*/
static void http_gethost_info(char *src, char **web, char **file, int *port)
{
char *pa;
char *pb;
isHttps = 0;
if (!src || strlen(src) == 0) {
OTA_LOG_E("http_gethost_info parms error!\n");
return;
}
*port = 0;
if (!(*src)) {
return;
}
pa = src;
if (!strncmp(pa, "https://", strlen("https://"))) {
pa = src + strlen("https://");
isHttps = 1;
}
if (!isHttps) {
if (!strncmp(pa, "http://", strlen("http://"))) {
pa = src + strlen("http://");
}
}
*web = pa;
pb = strchr(pa, '/');
if (pb) {
*pb = 0;
pb += 1;
if (*pb) {
*file = pb;
*((*file) + strlen(pb)) = 0;
}
} else {
(*web)[strlen(pa)] = 0;
}
#if defined AOS_OTA_TLS || defined AOS_OTA_ITLS
isHttps = 1;
#else
isHttps = 0;
#endif
pa = strchr(*web, ':');
if (pa) {
*pa = 0;
*port = atoi(pa + 1);
} else {
if (isHttps) {
*port = 443;
} else {
*port = 80;
}
}
}
static int ota_download_start(void *pctx)
{
int ret = 0;
void *sockfd = NULL;
int port = 0;
int nbytes = 0;
int send = 0;
int totalsend = 0;
int size = 0;
int header_found = 0;
char *pos = 0;
int file_size = 0;
ota_hash_param_t *hash_ctx = NULL;
char *host_file = NULL;
char *host_addr = NULL;
char *http_buffer = NULL;
void *ssl = NULL;
char retry = 0;
unsigned int ota_percent = 0;
unsigned int divisor = 10;
ota_service_t* ctx = (ota_service_t*)pctx;
if (!ctx) {
ret = OTA_PARAM_FAIL;
return ret;
}
ota_boot_param_t *ota_param = (ota_boot_param_t *)ctx->boot_param;
if (!ctx->boot_param) {
ret = OTA_PARAM_FAIL;
return ret;
}
char* url = ctx->url;
if (!url || strlen(url) == 0) {
ret = OTA_PARAM_FAIL;
return ret;
}
http_gethost_info(url, &host_addr, &host_file, &port);
OTA_LOG_I("uOTA Http Download:url:%s,host_addr:%s,host_file:%s,port=%d.",ctx->url,host_addr,host_file,port);
if (host_file == NULL || host_addr == NULL) {
ret = OTA_DOWNLOAD_IP_FAIL;
return ret;
}
if (isHttps) {
#if defined AOS_OTA_ITLS
char pkps[128] = {0};
int len = strlen(ctx->pk);
strncpy(pkps, ctx->pk, len);
HAL_GetProductSecret(pkps + len + 1);
len += strlen(pkps + len + 1) + 2;
ssl = ota_ssl_connect(host_addr, port, pkps,len);
#elif defined AOS_OTA_TLS
ssl = ota_ssl_connect(host_addr, port, ca, strlen(ca)+1);
#endif
if (ssl == NULL) {
ret = OTA_DOWNLOAD_CON_FAIL;
return ret;
}
} else {
sockfd = ota_socket_connect(host_addr, port);
if ((intptr_t)sockfd < 0) {
ret = OTA_DOWNLOAD_CON_FAIL;
return ret;
}
}
http_buffer = ota_malloc(OTA_BUFFER_MAX_SIZE);
if(NULL == http_buffer) {
ret = OTA_DOWNLOAD_FAIL;
goto END;
}
hash_ctx = ota_get_hash_ctx();
if (hash_ctx == NULL || hash_ctx->ctx_hash == NULL || hash_ctx->ctx_size == 0) {
ret = OTA_DOWNLOAD_FAIL;
goto END;;
}
memset(http_buffer, 0, OTA_BUFFER_MAX_SIZE);
if (ota_param->off_bp) {
ota_snprintf(http_buffer, OTA_BUFFER_MAX_SIZE - 1, HTTP_HEADER_RESUME, host_file, ota_param->off_bp, host_addr, port);
ota_get_last_hash_ctx(hash_ctx);
} else {
ota_param->off_bp = 0;
ota_snprintf(http_buffer, OTA_BUFFER_MAX_SIZE - 1, HTTP_HEADER, host_file, host_addr, port);
if (ota_hash_init(hash_ctx->hash_method, hash_ctx->ctx_hash) < 0) {
ret = OTA_VERIFY_HASH_FAIL;
goto END;
}
}
ota_set_cur_hash(ctx->hash);
send = 0;
totalsend = 0;
nbytes = strlen(http_buffer);
OTA_LOG_I("http dl send: %s", http_buffer);
while (totalsend < nbytes) {
send = ((isHttps) ? ota_ssl_send(ssl, (char *)(http_buffer + totalsend), (int)(nbytes - totalsend))
:ota_socket_send(sockfd, http_buffer + totalsend, nbytes - totalsend));
if (send <= 0) {
ret = OTA_DOWNLOAD_WRITE_FAIL;
goto END;
}
totalsend += send;
OTA_LOG_I("%d bytes send.", totalsend);
}
memset(http_buffer, 0, OTA_BUFFER_MAX_SIZE);
while (1) {
nbytes = ((isHttps) ? ota_ssl_recv(ssl, http_buffer, OTA_BUFFER_MAX_SIZE - 1):ota_socket_recv(sockfd, http_buffer, OTA_BUFFER_MAX_SIZE - 1));
if(retry > 5) {
OTA_LOG_I("retry complete:%d",nbytes);
break;
} else if((nbytes <= 0)&&(retry <= 5)){
retry++;
OTA_LOG_I("retry cn:%d",retry);
ota_msleep(500);
continue;
} else {
retry=0;
}
if (nbytes < 0) {
if (errno != EINTR) {
ret = OTA_DOWNLOAD_READ_FAIL;
break;
} else {
continue;
}
}
if (!header_found) {
if (!file_size) {
char *ptr = strstr(http_buffer, "Content-Length:");
if (ptr) {
ret = sscanf(ptr, "%*[^ ]%d", &file_size);
if(ret < 0) {
OTA_LOG_E("Content-Length error.");
}
}
}
pos = strstr(http_buffer, "\r\n\r\n");
if (pos != NULL) {
pos += 4;
int len = pos - http_buffer;
header_found = 1;
size = nbytes - len;
if (size > 0) { /* no valid data, just continue recieve */
if (ota_hash_update((const unsigned char *)pos, size, hash_ctx->ctx_hash) < 0) {
ota_set_break_point(0);
ret = OTA_VERIFY_HASH_FAIL;
goto END;
}
#if defined (SUPPORT_MCU_OTA)
if (ctx->upg_mcu_flag == 1) {
ret = ota_mcu_write(&ota_param->off_bp, pos, size);
} else {
ret = ota_hal_write(&ota_param->off_bp, pos, size);
}
#else
ret = ota_hal_write(&ota_param->off_bp, pos, size);
#endif
if (ret < 0) {
ret = OTA_UPGRADE_FAIL;
goto END;
}
}
}
memset(http_buffer, 0, OTA_BUFFER_MAX_SIZE);
continue;
}
if (ota_hash_update((const unsigned char *)http_buffer, nbytes, hash_ctx->ctx_hash) < 0) {
ota_set_break_point(0);
ret = OTA_VERIFY_HASH_FAIL;
goto END;
}
#if defined (SUPPORT_MCU_OTA)
if (ctx->upg_mcu_flag == 1) {
ret = ota_mcu_write(NULL, http_buffer, nbytes);
} else {
ret = ota_hal_write(NULL, http_buffer, nbytes);
}
#else
ret = ota_hal_write(NULL, http_buffer, nbytes);
#endif
if (ret < 0) {
ret = OTA_UPGRADE_FAIL;
goto END;
}
size += nbytes;
if(ctx->trans_protcol != OTA_PROTCOL_COAP_LOCAL) {
if(file_size) {
ota_percent = ((long long)size * 100) / (long long)file_size;
if(ota_percent / divisor) {
divisor += 5;
#if (!defined BOARD_ESP8266)
ctx->h_tr->status(ota_percent, ctx);
#endif
OTA_LOG_I("s:%d %d per:%d", size, nbytes, ota_percent);
}
}
}
if (size == file_size) {
nbytes = 0;
break;
}
if (ctx->upg_status == OTA_CANCEL) {
break;
}
}
if (nbytes < 0) {
ota_save_state(size + ota_param->off_bp, hash_ctx);
ret = OTA_DOWNLOAD_FAIL;
} else if (nbytes == 0) {
ota_set_break_point(0);
} else {
ota_save_state(size + ota_param->off_bp, hash_ctx);
ret = OTA_CANCEL;
}
END:
OTA_LOG_I("download finish ret:%d err:%d.", ret, errno);
if(http_buffer)
ota_free(http_buffer);
if(sockfd)
ota_socket_close(sockfd);
return ret;
}
static int ota_download_stop(void)
{
return 0;
}
static ota_download_t dl_http = {
.start = ota_download_start,
.stop = ota_download_stop,
};
ota_download_t *ota_get_download(void)
{
return &dl_http;
}

View file

@ -0,0 +1,227 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <string.h>
#include <stdlib.h>
#include "ota_log.h"
#include "ota_service.h"
#include "ota_verify.h"
#include "ota_hal_os.h"
// Generate topic name according to @ota_topic_type, @product_key, @device_name
// and then copy to @buf.
// 0, successful; -1, failed
static int otacoap_GenTopicName(char *buf, int len, char *topic, char *pk, char *dn)
{
int ret = 0;
if (buf == NULL || topic == NULL) {
return -1;
}
ret = ota_snprintf(buf, len, "/topic/ota/device/%s/%s/%s", topic, pk, dn);
if (ret < 0) {
return -1;
}
return 0;
}
// Generate firmware information according to @id, @version
// and then copy to @buf.
// 0, successful; -1, failed
static int otalib_GenReqMsg(char *buf, int len, int id, const char *ver)
{
int ret = 0;
ret = ota_snprintf(buf, len, "{\"id\":%d,\"params\":{\"mode\":\"coap\",\"version\":\"%s\"}}", id, ver? ver: NULL);
if (ret < 0) {
return -1;
}
return 0;
}
// Generate report information according to @id, @msg
// and then copy to @buf.
// 0, successful; -1, failed
static int otalib_GenReportMsg(char *buf, int len, int id, int progress, const char *msg)
{
int ret = 0;
ret = ota_snprintf(buf, len, "{\"id\":%d,\"params\":{\"step\": \"%d\",\"desc\":\"%s\"}}", id,progress, msg?msg:NULL);
if (ret < 0) {
return -1;
}
return 0;
}
static void otacoap_response_handler(void *arg, void *p_response)
{
int len = 0;
char *p_payload = NULL;
unsigned char resp_code = 0;
ota_coap_get_code(p_response, &resp_code);
ota_coap_get_payload(p_response, (const char **)&p_payload, &len);
OTA_LOG_I("coap res code = %d, len=%d, msg=%s", resp_code,len, p_payload ? p_payload : NULL);
ota_service_t* ctx = (ota_service_t*)arg;
if (!ctx->upgrade_cb) {
return;
}
if ((NULL != ctx->h_ch) && (NULL != p_payload)) {
ctx->trans_protcol = OTA_PROTCOL_COAP;
ctx->upgrade_cb(ctx, p_payload);
}
}
// report progress of OTA
static int otacoap_Publish(char *topic, char *msg, void* pctx)
{
int ret = 0;
ota_coap_message_t message;
ota_service_t* ctx = pctx;
if (!ctx || !(ctx->h_ch)) {
return -1;
}
message.p_payload = (unsigned char *)msg;
message.payload_len = (unsigned short)strlen(msg);
message.resp_callback = otacoap_response_handler;
message.msg_type = COAP_MESSAGE_CON;
message.content_type = COAP_CONTENT_TYPE_JSON;
ret = otacoap_GenTopicName(ctx->url, OTA_COAP_URI_MAX_LEN, topic, ctx->pk, ctx->dn);
if (ret < 0) {
return -1;
}
OTA_LOG_I("coap pub url:%s msg:%s\n", ctx->url, msg);
if (0 !=(ret = ota_coap_send(ctx->h_ch, ctx->url, &message))) {
return -1;
}
return 0;
}
static int ota_trans_inform(void *pctx)
{
int ret = 0;
char msg[OTA_MSG_INFORM_LEN] = {0};
ota_service_t* ctx = pctx;
if (!ctx || !(ctx->h_ch)) {
return -1;
}
ret = otalib_GenReqMsg(msg, OTA_MSG_INFORM_LEN, 0, ctx->sys_ver);
if (ret != 0) {
return -1;
}
OTA_LOG_I("coap pub msg:%s\n", msg);
ret = otacoap_Publish("request", msg, ctx);
if (0 != ret) {
return OTA_TRANSPORT_FAIL;
}
return 0;
}
int ota_trans_init(void)
{
int ret = 0;
ret = ota_coap_init();
if (ret < 0) {
return OTA_TRANSPORT_FAIL;
}
return 0;
}
int ota_trans_response(const char *response)
{
return 0;
}
static int ota_trans_upgrade(void *pctx)
{
return 0;
}
static int ota_trans_status(int progress, void *pctx)
{
int ret = -1;
char msg[OTA_MSG_REPORT_LEN] = {0};
char err[OTA_MAX_VER_LEN] = {0};
ota_service_t* ctx = pctx;
if (!ctx) {
OTA_LOG_E("parameter null.");
return -1;
}
int status = ctx->upg_status;
memset(err, 0x00, sizeof(err));
if (status < 0) {
progress = status;
switch (status) {
case OTA_INIT_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota init failed");
break;
case OTA_INIT_VER_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota version not match");
break;
case OTA_DOWNLOAD_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota download failed");
break;
case OTA_DOWNLOAD_URL_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota download url failed");
break;
case OTA_DOWNLOAD_IP_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota download ip failed");
break;
case OTA_DOWNLOAD_CON_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota download connect failed");
break;
case OTA_DOWNLOAD_READ_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota download read failed");
break;
case OTA_DOWNLOAD_WRITE_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota download write failed");
break;
case OTA_VERIFY_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota verify failed");
break;
case OTA_UPGRADE_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota upgrade failed");
break;
case OTA_REBOOT_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota reboot failed");
break;
case OTA_VERIFY_RSA_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota verify rsa failed");
break;
case OTA_VERIFY_HASH_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota verify hash failed");
break;
case OTA_UPGRADE_DIFF_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota diff failed");
break;
default:
ota_snprintf(err, OTA_MAX_VER_LEN-1, "%s", "ota undefined failed");
break;
}
}
ret = otalib_GenReportMsg(msg, OTA_MSG_REPORT_LEN, 0, progress, err);
if (0 != ret) {
return -1;
}
ret = otacoap_Publish("progress", msg, ctx);
if (0 != ret) {
return OTA_TRANSPORT_FAIL;
}
return ret;
}
static int ota_trans_deinit(void)
{
return ota_coap_deinit();
}
static ota_transport_t trans_coap = {
.init = ota_trans_init,
.inform = ota_trans_inform,
.upgrade = ota_trans_upgrade,
.status = ota_trans_status,
.deinit = ota_trans_deinit,
};
ota_transport_t *ota_get_transport(void)
{
return &trans_coap;
}

View file

@ -0,0 +1,247 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <string.h>
#include <stdlib.h>
#include "ota_log.h"
#include "ota_service.h"
#include "ota_hal_os.h"
#include "ota_hal_plat.h"
#include "ota_verify.h"
static int ota_gen_info_msg(char *buf, int len, int id, const char *ver)
{
int ret = 0;
ret = ota_snprintf(buf, len, "{\"id\":%d,\"params\":{\"version\":\"%s\"}}", id, ver);
if (ret < 0) {
return -1;
}
return 0;
}
// Generate report information according to @id, @msg
// and then copy to @buf.
// 0, successful; -1, failed
static int ota_gen_report_msg(char *buf, int len, int id, int progress, const char *msg)
{
int ret = 0;
ret = ota_snprintf(buf, len, "{\"id\":%d,\"params\":{\"step\": \"%d\",\"desc\":\"%s\"}}", id, progress, msg?msg:NULL);
if (ret < 0) {
return -1;
}
return 0;
}
// Generate topic name according to @ota_topic_type, @product_key, @device_name
// and then copy to @buf.
// 0, successful; -1, failed
static int ota_mqtt_gen_topic_name(char *buf, int len, const char *topic, char *pk, char *dn)
{
int ret = 0;
ret = ota_snprintf(buf, len, "/ota/device/%s/%s/%s", topic, pk, dn);
if (ret < 0) {
return -1;
}
return 0;
}
static int ota_mqtt_publish(const char *topic, const char *msg, char *pk, char *dn)
{
int ret = 0;
char name[OTA_MQTT_TOPIC_LEN] = {0};
if (topic == NULL || msg == NULL || pk == NULL || dn == NULL) {
return -1;
}
ret = ota_mqtt_gen_topic_name(name, OTA_MQTT_TOPIC_LEN, topic, pk, dn);
if (ret < 0) {
return -1;
}
OTA_LOG_I("Public name:%s msg:%s",name,msg);
ret = ota_hal_mqtt_publish(name, 1, (void *)msg, strlen(msg) + 1);
if (ret < 0) {
return ret;
}
return 0;
}
static void ota_mqtt_sub_cb(void *pcontext, void *pclient, void* msg)
{
char *payload = NULL;
if (msg == NULL) {
return;
}
ota_mqtt_msg_t *mqtt_msg = (ota_mqtt_msg_t*)msg;
switch (mqtt_msg->event) {
case OTA_MQTT_EVENT_PUB_RECEIVED:
payload = (char *)mqtt_msg->topic->payload;
break;
default:
return;
}
if(payload == NULL) {
OTA_LOG_E("payload is null");
return;
}
ota_service_t* ctx = (ota_service_t*)pcontext;
OTA_LOG_I("mqtt cb evt:%d %s", mqtt_msg->event, payload);
if ((!ctx)||!(ctx->upgrade_cb)) {
return;
}
ctx->trans_protcol = OTA_PROTCOL_MQTT;
ctx->upgrade_cb(ctx, payload);
}
static int ota_trans_inform(void* pctx)
{
int ret = 0;
char msg[OTA_MSG_INFORM_LEN] = {0};
ota_service_t* ctx = pctx;
if (!ctx) {
return -1;
}
ret = ota_gen_info_msg(msg, OTA_MSG_INFORM_LEN, 0, ctx->sys_ver);
if (ret != 0) {
return -1;
}
ret = ota_mqtt_publish("inform", msg, ctx->pk, ctx->dn);
if (0 != ret) {
return OTA_TRANSPORT_FAIL;
}
return ret;
}
static int ota_trans_request(void* pctx)
{
int ret = 0;
char msg[OTA_MSG_INFORM_LEN] = {0};
ota_service_t* ctx = pctx;
if (!ctx) {
return -1;
}
ret = ota_gen_info_msg(msg, OTA_MSG_INFORM_LEN, 0, ctx->sys_ver);
if (ret != 0) {
return -1;
}
ret = ota_mqtt_publish("request", msg, ctx->pk, ctx->dn);
if (0 != ret) {
return OTA_TRANSPORT_FAIL;
}
return ret;
}
static int ota_trans_upgrade(void* pctx)
{
int ret = 0;
char name[OTA_MQTT_TOPIC_LEN] = {0};
ota_service_t* ctx = pctx;
if (!ctx) {
return -1;
}
ret = ota_mqtt_gen_topic_name(name, OTA_MQTT_TOPIC_LEN, "upgrade", ctx->pk, ctx->dn);
if (ret < 0) {
return -1;
}
OTA_LOG_I("upgrade:%s",name);
ret = ota_hal_mqtt_subscribe(name, ota_mqtt_sub_cb, pctx);
if (ret < 0) {
return OTA_TRANSPORT_FAIL;
}
return ret;
}
static int ota_trans_status(int progress, void* pctx)
{
int ret = -1;
char msg[OTA_MSG_REPORT_LEN] = {0};
char err[OTA_MAX_VER_LEN] = {0};
ota_service_t* ctx = pctx;
if (!ctx) {
return -1;
}
int status = ctx->upg_status;
memset(err, 0x00, sizeof(err));
if (status < 0) {
progress = status;
switch (status) {
case OTA_INIT_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota init failed");
break;
case OTA_INIT_VER_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota version not match");
break;
case OTA_DOWNLOAD_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota download failed");
break;
case OTA_DOWNLOAD_URL_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota download url failed");
break;
case OTA_DOWNLOAD_IP_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota download ip failed");
break;
case OTA_DOWNLOAD_CON_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota download connect failed");
break;
case OTA_DOWNLOAD_READ_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota download read failed");
break;
case OTA_DOWNLOAD_WRITE_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota download write failed");
break;
case OTA_VERIFY_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota verify failed");
break;
case OTA_UPGRADE_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota upgrade failed");
break;
case OTA_REBOOT_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota reboot failed");
break;
case OTA_VERIFY_RSA_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota verify rsa failed");
break;
case OTA_VERIFY_HASH_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota verify hash failed");
break;
case OTA_UPGRADE_DIFF_FAIL:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota diff failed");
break;
default:
ota_snprintf(err, OTA_MAX_VER_LEN - 1, "%s", "ota undefined failed");
break;
}
}
ret = ota_gen_report_msg(msg, OTA_MSG_REPORT_LEN, 0, progress, err);
if (0 != ret) {
return -1;
}
ret = ota_mqtt_publish("progress", msg, ctx->pk, ctx->dn);
if (0 != ret) {
return OTA_TRANSPORT_FAIL;
}
return ret;
}
static int ota_trans_init(void)
{
return ota_hal_mqtt_init();
}
static int ota_trans_deinit(void)
{
return ota_hal_mqtt_deinit();
}
static ota_transport_t trans_mqtt = {
.init = ota_trans_init,
.inform = ota_trans_inform,
.upgrade = ota_trans_upgrade,
.request = ota_trans_request,
.status = ota_trans_status,
.deinit = ota_trans_deinit,
};
ota_transport_t *ota_get_transport(void)
{
return &trans_mqtt;
}

View file

@ -0,0 +1,22 @@
NAME := ota_transport
#default gcc
ifeq ($(COMPILER),)
$(NAME)_CFLAGS += -Wall -Werror
else ifeq ($(COMPILER),gcc)
$(NAME)_CFLAGS += -Wall -Werror
endif
$(NAME)_MBINS_TYPE := kernel
$(NAME)_VERSION := 1.0.0
$(NAME)_SUMMARY := ota transport message on clould.
ifeq ($(TRANSPORT),coap)
$(NAME)_SOURCES := ota_transport_coap.c
else
$(NAME)_SOURCES := ota_transport_mqtt.c
endif
GLOBAL_INCLUDES += . ../../inc ../../hal ../verify ../verify/base64 ../verify/hash ../verify/rsa

View file

@ -0,0 +1,459 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <string.h>
#include "ota_service.h"
#include "ota_log.h"
#include "ota_verify.h"
#include "ota_hal_plat.h"
#define KEY_OTA_BREAKPOINT "key_ota_breakpoint"
#define KEY_OTA_HASH "key_ota_hash"
#define KEY_OTA_HASH_CTX_HEAD "key_ota_hash_ctx_head"
#define KEY_OTA_HASH_CTX_BODY "key_ota_hash_ctx_body"
#define OTA_BUF_VERIFY 512
static ota_hash_param_t g_ctx = { 0, 0, NULL };
static ota_hash_param_t image_md5_ctx = { 0, 0, NULL };
int ota_hash_get_ctx_size(OTA_HASH_E type, unsigned int *size)
{
if (NULL == size) {
return OTA_CRYPTO_INVALID_ARG;
}
switch(type) {
case SHA256:
case MD5:
break;
default:
OTA_LOG_E("invalid type(%d)\n", type);
return OTA_CRYPTO_INVALID_TYPE;
}
*size = sizeof(ota_hash_ctx_t);
return OTA_CRYPTO_SUCCESS;
}
int ota_hash_init(OTA_HASH_E type, void *context)
{
ota_hash_ctx_t *hash_ctx;
if (NULL == context) {
return OTA_CRYPTO_INVALID_CONTEXT;
}
hash_ctx = (ota_hash_ctx_t *)context;
if ((IS_VALID_CTX_MAGIC(hash_ctx->magic) &&
hash_ctx->status != CRYPTO_STATUS_FINISHED) &&
hash_ctx->status != CRYPTO_STATUS_CLEAN) {
OTA_LOG_E("bad:%d", (int)hash_ctx->status);
return OTA_CRYPTO_ERR_STATE;
}
switch(type) {
case SHA256: {
ota_sha256_init(&hash_ctx->sha256_ctx);
ota_sha256_starts(&hash_ctx->sha256_ctx, 0);
break;
}
case MD5: {
ota_md5_init(&hash_ctx->md5_ctx);
ota_md5_starts(&hash_ctx->md5_ctx);
break;
}
default:
OTA_LOG_E("invalid type:%d", type);
return OTA_CRYPTO_INVALID_TYPE;
}
hash_ctx->type = type;
hash_ctx->status = CRYPTO_STATUS_INITIALIZED;
INIT_CTX_MAGIC(hash_ctx->magic);
return OTA_CRYPTO_SUCCESS;
}
int ota_hash_update(const unsigned char *src, unsigned int size, void *context)
{
ota_hash_ctx_t *hash_ctx;
if (context == NULL) {
return OTA_CRYPTO_INVALID_CONTEXT;
}
if (src == NULL && size != 0) {
return OTA_CRYPTO_INVALID_ARG;
}
hash_ctx = (ota_hash_ctx_t *)context;
if (!IS_VALID_CTX_MAGIC(hash_ctx->magic)) {
return OTA_CRYPTO_INVALID_CONTEXT;
}
if ((hash_ctx->status != CRYPTO_STATUS_INITIALIZED) &&
(hash_ctx->status != CRYPTO_STATUS_PROCESSING)) {
OTA_LOG_E("bad :%d", (int)hash_ctx->status);
return OTA_CRYPTO_ERR_STATE;
}
switch(hash_ctx->type) {
case SHA256: {
ota_sha256_update(&hash_ctx->sha256_ctx,
(const unsigned char *)src, size);
break;
}
case MD5: {
ota_md5_update(&hash_ctx->md5_ctx,
(const unsigned char *)src, size);
break;
}
default:
OTA_LOG_E("invalid:%d", hash_ctx->type);
return OTA_CRYPTO_INVALID_TYPE;
}
hash_ctx->status = CRYPTO_STATUS_PROCESSING;
return OTA_CRYPTO_SUCCESS;
}
int ota_hash_final(unsigned char *dgst, void *context)
{
ota_hash_ctx_t *hash_ctx;
if (context == NULL) {
return OTA_CRYPTO_INVALID_CONTEXT;
}
if (dgst == NULL) {
return OTA_CRYPTO_ERROR;
}
hash_ctx = (ota_hash_ctx_t *)context;
if (!IS_VALID_CTX_MAGIC(hash_ctx->magic)) {
return OTA_CRYPTO_INVALID_CONTEXT;
}
if ((hash_ctx->status != CRYPTO_STATUS_INITIALIZED) &&
(hash_ctx->status != CRYPTO_STATUS_PROCESSING)) {
OTA_LOG_E("bad :%d", (int)hash_ctx->status);
return OTA_CRYPTO_ERR_STATE;
}
switch(hash_ctx->type) {
case SHA256: {
ota_sha256_finish(&hash_ctx->sha256_ctx, (unsigned char *)dgst);
ota_sha256_free(&hash_ctx->sha256_ctx);
break;
}
case MD5: {
ota_md5_finish(&hash_ctx->md5_ctx, (unsigned char *)dgst);
ota_md5_free(&hash_ctx->md5_ctx);
break;
}
default:
OTA_LOG_E("invalid :%d", hash_ctx->type);
return OTA_CRYPTO_INVALID_TYPE;
}
CLEAN_CTX_MAGIC(hash_ctx->magic);
hash_ctx->status = CRYPTO_STATUS_FINISHED;
return OTA_CRYPTO_SUCCESS;
}
int ota_hash_digest(OTA_HASH_E type, const unsigned char *src, unsigned int size, unsigned char *dgst)
{
ota_hash_ctx_t hash_ctx;
if ((src == NULL && size != 0) || dgst == NULL) {
return OTA_CRYPTO_INVALID_ARG;
}
switch(type) {
case SHA256: {
ota_sha256_init(&hash_ctx.sha256_ctx);
ota_sha256_starts(&hash_ctx.sha256_ctx, 0);
ota_sha256_update(&hash_ctx.sha256_ctx, (const unsigned char *)src, size);
ota_sha256_finish(&hash_ctx.sha256_ctx, (unsigned char *)dgst);
ota_sha256_free(&hash_ctx.sha256_ctx);
break;
}
case MD5: {
ota_md5_init(&hash_ctx.md5_ctx);
ota_md5_starts(&hash_ctx.md5_ctx);
ota_md5_update(&hash_ctx.md5_ctx, (const unsigned char *)src, size);
ota_md5_finish(&hash_ctx.md5_ctx, (unsigned char *)dgst);
ota_md5_free(&hash_ctx.md5_ctx);
break;
}
default:
OTA_LOG_E("invalid:%d", type);
return OTA_CRYPTO_INVALID_TYPE;
}
return OTA_CRYPTO_SUCCESS;
}
int ota_malloc_hash_ctx(OTA_HASH_E type)
{
g_ctx.hash_method = type;
ota_hash_get_ctx_size(type, (unsigned int*)&g_ctx.ctx_size);
if (g_ctx.ctx_hash == NULL) {
g_ctx.ctx_hash = (void *)ota_malloc(g_ctx.ctx_size);
}
if (g_ctx.ctx_hash == NULL) {
g_ctx.hash_method = 0;
g_ctx.ctx_size = 0;
return -1;
}
memset(g_ctx.ctx_hash, 0, g_ctx.ctx_size);
return 0;
}
ota_hash_param_t *ota_get_hash_ctx(void)
{
return &g_ctx;
}
void ota_free_hash_ctx(void)
{
if (g_ctx.ctx_hash) {
ota_free(g_ctx.ctx_hash);
}
g_ctx.ctx_hash = NULL;
g_ctx.hash_method = 0;
g_ctx.ctx_size = 0;
}
void ota_save_state(int breakpoint, ota_hash_param_t *hash_ctx)
{
ota_set_break_point(breakpoint);
ota_set_cur_hash_ctx(hash_ctx);
}
int ota_get_break_point(void)
{
uint32_t offset = 0;
int len = 4;
if (ota_kv_get(KEY_OTA_BREAKPOINT, &offset, &len)) {
offset = 0;
}
return offset;
}
int ota_set_break_point(int offset)
{
return ota_kv_set(KEY_OTA_BREAKPOINT, &offset, 4, 1);
}
int ota_get_last_hash(char *value)
{
int len = 66;
int ret = ota_kv_get(KEY_OTA_HASH, value, &len);
return ret;
}
int ota_set_cur_hash(char *value)
{
return ota_kv_set(KEY_OTA_HASH, value, 66, 1);
}
int ota_get_last_hash_ctx(ota_hash_param_t *hash_ctx)
{
int ret = 0;
if (hash_ctx == NULL || hash_ctx->ctx_hash == NULL ||
hash_ctx->ctx_size == 0) {
return 0;
}
int head_len = sizeof hash_ctx->hash_method + sizeof hash_ctx->ctx_size;
int body_len = hash_ctx->ctx_size;
ret = ota_kv_get(KEY_OTA_HASH_CTX_HEAD, hash_ctx, &head_len);
if (ret == 0) {
return ota_kv_get(KEY_OTA_HASH_CTX_BODY, hash_ctx->ctx_hash, &body_len);
}
return ret;
}
int ota_set_cur_hash_ctx(ota_hash_param_t *hash_ctx)
{
int ret = 0;
if (hash_ctx == NULL || hash_ctx->ctx_hash == NULL ||
hash_ctx->ctx_size == 0) {
return 0;
}
int head_len = sizeof hash_ctx->hash_method + sizeof hash_ctx->ctx_size;
int body_len = hash_ctx->ctx_size;
ret = ota_kv_set(KEY_OTA_HASH_CTX_HEAD, hash_ctx, head_len, 1);
if (ret == 0) {
return ota_kv_set(KEY_OTA_HASH_CTX_BODY, hash_ctx->ctx_hash, body_len, 1);
} else {
return ret;
}
}
static int ota_check_md5(const unsigned char *cur_hash, const char *download_hash)
{
if (cur_hash == NULL || download_hash == NULL) {
return -1;
}
char digest_str[33] = {0};
int i = 0;
for (; i < 16; i++) {
ota_snprintf(digest_str + i * 2, 2 + 1, "%02X", cur_hash[i]);
}
OTA_LOG_I("md5 src=%s dst=%s", download_hash, digest_str);
if (strncmp(digest_str, download_hash, 32)) {
return -1;
}
return 0;
}
static int ota_check_sha256(const unsigned char *cur_hash, const char *download_hash)
{
if (cur_hash == NULL || download_hash == NULL) {
return -1;
}
char digest_str[65] = {0};
int i = 0;
for (; i < 32; i++) {
ota_snprintf(digest_str + i * 2, 2 + 1, "%02X", cur_hash[i]);
}
OTA_LOG_I("SHA256 src=%s dst:%s", download_hash, digest_str);
if (strncmp(digest_str, download_hash, 64)) {
OTA_LOG_E("SHA256 check FAIL!");
return -1;
}
return 0;
}
int ota_check_hash(OTA_HASH_E hash_type, char* hash)
{
if (hash == NULL) {
return -1;
}
int ret = -1;
unsigned char digest[64] = { 0 };
ota_hash_param_t *hash_ctx = ota_get_hash_ctx();
if (OTA_CRYPTO_SUCCESS != ota_hash_final(digest, hash_ctx->ctx_hash)) {
return -1;
}
switch (hash_type) {
case SHA256: {
ret = ota_check_sha256(digest, hash);
break;
}
case MD5: {
ret = ota_check_md5(digest, hash);
break;
}
default:
return -1;
}
return ret;
}
// below is about check image
int ota_init_bin_md5_context()
{
image_md5_ctx.hash_method = MD5;
ota_hash_get_ctx_size(MD5, (unsigned int*)&image_md5_ctx.ctx_size);
if (image_md5_ctx.ctx_hash == NULL) {
image_md5_ctx.ctx_hash = (void *)ota_malloc(image_md5_ctx.ctx_size);
}
if (image_md5_ctx.ctx_hash == NULL) {
image_md5_ctx.hash_method = 0;
image_md5_ctx.ctx_size = 0;
return -1;
}
memset(image_md5_ctx.ctx_hash, 0, image_md5_ctx.ctx_size);
return 0;
}
void ota_destroy_bin_md5_context()
{
if (image_md5_ctx.ctx_hash) {
ota_free(image_md5_ctx.ctx_hash);
}
image_md5_ctx.ctx_hash = NULL;
image_md5_ctx.hash_method = 0;
image_md5_ctx.ctx_size = 0;
}
int ota_check_image(unsigned int size)
{
int ret = 0;
#if !defined (AOS_OTA_DISABLE_MD5)
int i = 0;
int off_set = 0;
char image_md5_value[33] = {0};
char download_md5_str_value[33] = {0};
unsigned int read_size = 0;
char *rd_buf = NULL;
char test_buf[33] = { 0 };
int bin_size = size;
ota_image_t ota_image_identity = { 0};
if(size <= sizeof(ota_image_t)){
ret = OTA_VERIFY_HASH_FAIL;
return ret;
}
off_set = bin_size - sizeof(ota_image_t);
OTA_LOG_I("bin s:%d off:%d", bin_size, off_set);
if (ota_hal_read(&off_set, (char*)&ota_image_identity, sizeof(ota_image_t)) < 0) {
ret = OTA_VERIFY_HASH_FAIL;
return ret;
}
memset(test_buf, 0x00, sizeof(test_buf));
for (i = 0; i < 16; i++) {
ota_snprintf((char *)(test_buf + i * 2), 2 + 1, "%02X", ota_image_identity.image_md5_value[i]);
}
OTA_LOG_I("magic:0x%04x size:%d md5:%s crc16:0x%02x", ota_image_identity.image_magic,ota_image_identity.image_size, test_buf, ota_image_identity.image_crc16);
if ((ota_image_identity.image_magic != AOS_SINGLE_TAG) &&
(ota_image_identity.image_magic != AOS_KERNEL_TAG) &&
(ota_image_identity.image_magic != AOS_APP_TAG)) {
ret = OTA_PARAM_FAIL;
return ret;
}
bin_size = ota_image_identity.image_size;
rd_buf = ota_malloc(OTA_BUF_VERIFY);
if (rd_buf == NULL) {
ret = OTA_PARAM_FAIL;
return ret;
}
if (ota_init_bin_md5_context() < 0) {
ret = OTA_PARAM_FAIL;
goto err;
}
ret = ota_hash_init(image_md5_ctx.hash_method, image_md5_ctx.ctx_hash);
if (ret < 0) {
OTA_LOG_I("hash init.\n");
goto err;
}
off_set = 0;
while (off_set < bin_size) {
(bin_size - off_set >= OTA_BUF_VERIFY) ? (read_size = OTA_BUF_VERIFY):(read_size = bin_size - off_set);
if (ota_hal_read(&off_set, rd_buf, read_size) < 0) {
ret = OTA_UPGRADE_FAIL;
goto err;
}
ret = ota_hash_update((const uint8_t *)rd_buf, read_size, image_md5_ctx.ctx_hash);
if (ret < 0) {
OTA_LOG_E("hash update err.\n");
goto err;
}
}
memset(image_md5_value, 0x00, sizeof(image_md5_value));
ret = ota_hash_final((unsigned char *)image_md5_value, image_md5_ctx.ctx_hash);
if (ret < 0) {
OTA_LOG_E("hash final err.\n");
goto err;
}
memset(download_md5_str_value, 0x00, sizeof(download_md5_str_value));
for (i = 0; i < 16; i++) {
ota_snprintf((char *)download_md5_str_value + i * 2, 2 + 1, "%02X", ota_image_identity.image_md5_value[i]);
}
ret = ota_check_md5((const unsigned char *)image_md5_value, (const char *)&download_md5_str_value);
if (ret < 0) {
OTA_LOG_E("hash check err.\n");
goto err;
}
err:
OTA_LOG_I("OTA md5 ret:%d",ret);
if(rd_buf) {
ota_free(rd_buf);
rd_buf = NULL;
}
ota_destroy_bin_md5_context();
#endif
return ret;
}

View file

@ -0,0 +1,12 @@
#ifndef OTA_PUBLIC_KEY_CONFIG_H_
#define OTA_PUBLIC_KEY_CONFIG_H_
/*below two bufs are about the rsa public key, user needs sign in alibaba cloud to get them*/
//static const unsigned char ota_pubn_buf[256] = {0x00};
//static const unsigned char ota_pube_buf[3] = {0x00};
static const unsigned char ota_pubn_buf[256] = {0xA9, 0x82, 0x89, 0x44, 0x46, 0xC3, 0x1A, 0xA3, 0x50, 0x8C, 0x46, 0x4A, 0x78, 0x62, 0x71, 0xFB, 0xCF, 0x2B, 0xFF, 0x9D, 0x1F, 0x8B, 0xE8, 0x71, 0x74, 0xA4, 0xE9, 0x1D, 0xC7, 0x93, 0x79, 0x30, 0x60, 0xD7, 0x63, 0x8C, 0x02, 0x50, 0xC9, 0xC0, 0xFE, 0x57, 0x0F, 0x32, 0x65, 0xB1, 0xC1, 0x48, 0x08, 0x64, 0xEE, 0x04, 0x07, 0x87, 0x4C, 0xE5, 0xA3, 0x82, 0xFA, 0x78, 0xEE, 0x7E, 0x13, 0x09, 0x72, 0x80, 0x13, 0x19, 0xCC, 0x24, 0x85, 0x56, 0xBF, 0x18, 0x63, 0x38, 0x51, 0xB6, 0x5F, 0x2F, 0xE8, 0xBE, 0x06, 0x8C, 0x77, 0x7D, 0xD0, 0xBF, 0x12, 0xD0, 0xE9, 0xA3, 0xFB, 0x98, 0xFF, 0x4F, 0x7E, 0x88, 0x50, 0xFF, 0x56, 0x96, 0x32, 0xC7, 0x89, 0x29, 0x0D, 0xFA, 0x8E, 0xCC, 0x4B, 0x14, 0x5E, 0xB7, 0xD2, 0xE0, 0x07, 0x3D, 0x67, 0xB4, 0x51, 0x27, 0x7B, 0xEE, 0x52, 0x9B, 0x99, 0xAE, 0xCE, 0xFD, 0x10, 0x5E, 0xFE, 0xF5, 0x23, 0x44, 0x81, 0x25, 0x33, 0x5B, 0xF4, 0x57, 0xF9, 0x75, 0x06, 0xF7, 0x3D, 0xB9, 0x70, 0x10, 0x93, 0xB5, 0x46, 0x9C, 0x38, 0x04, 0x6A, 0xCA, 0x7E, 0xC7, 0xD0, 0x26, 0x29, 0x24, 0xD1, 0x7E, 0xBC, 0xEF, 0x22, 0x42, 0xDF, 0x8C, 0x6E, 0x8D, 0x55, 0x9D, 0xC2, 0xE7, 0xDE, 0xB4, 0x24, 0x91, 0x30, 0x4F, 0xFC, 0xC1, 0x38, 0xF2, 0xD2, 0xEB, 0xF1, 0xD8, 0x07, 0xAC, 0xA9, 0x91, 0xEF, 0x54, 0x2C, 0x44, 0x5A, 0xEF, 0xFD, 0x7D, 0x83, 0xC1, 0x7A, 0xC6, 0xCB, 0x45, 0xE1, 0xD7, 0xF4, 0x85, 0xAF, 0xD9, 0x8F, 0x1F, 0x54, 0xDF, 0x1E, 0xA8, 0xB8, 0x0E, 0x7A, 0x34, 0x1D, 0xD0, 0x09, 0x91, 0xE0, 0xE9, 0xE2, 0x4A, 0x70, 0x64, 0x0F, 0x97, 0x48, 0xC5, 0x9F, 0x2E, 0x2D, 0x76, 0x68, 0x22, 0x58, 0xF5, 0x63, 0xE5, 0x53, 0x81, 0x80, 0x5B, 0x5F, 0x57};
static const unsigned char ota_pube_buf[3] = {0x01, 0x00, 0x01};
#endif

View file

@ -0,0 +1,185 @@
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#include "string.h"
#include "ota_log.h"
#include "ota_service.h"
#include "ota_public_key_config.h"
#include "ota_verify.h"
static char ota_get_sign_hash_method(void)
{
return SHA256;
}
static const unsigned char *ota_get_pubkey_n(void)
{
return ota_pubn_buf;
}
static const unsigned char *ota_get_pubkey_e(void)
{
return ota_pube_buf;
}
int ota_get_public_key_bitnumb(void)
{
unsigned int ota_rsabitnumb = 0;
ota_rsabitnumb = sizeof(ota_pubn_buf) * 8;
return ota_rsabitnumb;
}
int ota_make_public_key(unsigned char* pub_key)
{
int pubkey_n_size = 0;
int pubkey_e_size = 0;
int bitnumb = ota_get_public_key_bitnumb();
const unsigned char *pubkey_n = ota_get_pubkey_n();
const unsigned char *pubkey_e = ota_get_pubkey_e();
if((NULL == pubkey_n) || (NULL == pubkey_e) || (bitnumb < 2048)) {
OTA_LOG_E("init_pubkey: get parameter error!");
return -1;
}
pubkey_n_size = bitnumb >> 3;
pubkey_e_size = 3;
return ota_rsa_init_pubkey(bitnumb, pubkey_n, pubkey_n_size, pubkey_e, pubkey_e_size, (ota_rsa_pubkey_t *)pub_key);
}
int ota_make_rsa_verify_dig_data(unsigned char* src_data, int src_len, unsigned char* dig_data, unsigned char hash_type)
{
int ret = 0;
unsigned int ctx_size = 0;
void* hash_ctx = NULL;
if((NULL == src_data) || (0 == src_len) || (NULL == dig_data) || ((hash_type != SHA256) && (hash_type != MD5))) {
return -1;
}
ota_hash_get_ctx_size(hash_type, (unsigned int*)&ctx_size);
hash_ctx = ota_malloc(ctx_size);
if(NULL == hash_ctx) {
return -1;
}
if(OTA_CRYPTO_SUCCESS != ota_hash_init(hash_type, hash_ctx)) {
ret = -1;
goto OTA_DIG_OVER;
}
if(OTA_CRYPTO_SUCCESS != ota_hash_update((const uint8_t *)src_data, src_len, hash_ctx)) {
ret = -1;
goto OTA_DIG_OVER;
}
if(OTA_CRYPTO_SUCCESS != ota_hash_final(dig_data, hash_ctx)) {
OTA_LOG_E("ota verify rsa hash final fail\n ");
ret = -1;
goto OTA_DIG_OVER;
}
OTA_DIG_OVER:
ota_free(hash_ctx);
return ret;
}
static int ota_verify_rsa_sign(unsigned char* src_value, int src_len, int rsabitnumb, unsigned char* signature_value)
{
if((rsabitnumb < 2048) || (NULL == src_value) ||
(src_len == 0) || (NULL == signature_value)) {
OTA_LOG_E("ota verify rsa sign: input parameters error ");
return -1;
}
int ret = 0;
OTA_HASH_E hash_method;
bool result = false;
ota_rsa_padding_t rsa_padding;
unsigned int pub_key_len = 0;
int dig_value_len = 0;
unsigned char *pubkey = NULL;
unsigned char *dig_value = NULL;
ret = ota_rsa_get_pubkey_size(rsabitnumb, &pub_key_len);
if (ret != OTA_CRYPTO_SUCCESS) {
OTA_LOG_E("init_key: get pubkey size fail");
return -1;
}
pubkey = ota_malloc(pub_key_len);
if (NULL == pubkey) {
OTA_LOG_E("init_key: public key malloc fail");
return -1;
}
hash_method = ota_get_sign_hash_method();
switch (hash_method) {
case MD5:
dig_value_len = 16;
break;
case SHA256:
dig_value_len = 32;
break;
default:
OTA_LOG_E("ota verify rsa sign: don't support your hash type");
ota_free(pubkey);
return -1;
}
dig_value = ota_malloc(dig_value_len);
if(NULL == dig_value) {
OTA_LOG_E("ota verify rsa sign: malloc dig_value failed");
ota_free(pubkey);
return -1;
}
memset(pubkey, 0, pub_key_len);
if(ota_make_public_key(pubkey) != 0) {
ret = -1;
OTA_LOG_E("make pub key failed");
goto OTA_RSA_OVER;
}
memset(dig_value, 0, dig_value_len);
if (ota_make_rsa_verify_dig_data(src_value, src_len, dig_value, hash_method) != 0) {
ret = -1;
OTA_LOG_E("make rsa dig data fail");
goto OTA_RSA_OVER;
}
rsa_padding.type = RSASSA_PKCS1_V1_5;
rsa_padding.pad.rsassa_v1_5.type = hash_method;
ret = ota_rsa_verify((ota_rsa_pubkey_t *)pubkey, dig_value, dig_value_len,
signature_value, rsabitnumb >> 3, rsa_padding, &result);
OTA_RSA_OVER:
ota_free(pubkey);
ota_free(dig_value);
OTA_LOG_I("rsa verify OK:%d res:%d",ret, result);
return ret;
}
int ota_verify_download_rsa_sign(unsigned char* sign_dat, const char* src_hash_dat, OTA_HASH_E src_hash_method)
{
char tmp_buf[32] = {0};
int sign_bitnumb = 0;
int src_dat_len = 0;
if((NULL == sign_dat) || (NULL == src_hash_dat)) {
OTA_LOG_E("ota verify download sign input parameter NULL");
return -1;
}
switch(src_hash_method) {
case MD5:
src_dat_len = 16;
break;
case SHA256:
src_dat_len = 32;
break;
default:
OTA_LOG_E("ota rsa sign input hash type error!");
return -1;
}
if(ota_hex_str2buf(src_hash_dat, tmp_buf, sizeof(tmp_buf)) < 0) {
OTA_LOG_E("rsa verify:str2buf translate failed!");
return -1;
}
sign_bitnumb = ota_get_public_key_bitnumb();
return ota_verify_rsa_sign((unsigned char*)tmp_buf, src_dat_len, sign_bitnumb, sign_dat);
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef _OTA_VERIFY_H_
#define _OTA_VERIFY_H_
#include "ota_hal_os.h"
#include "stdint.h"
#define AOS_SINGLE_TAG (0xabababab)
#define AOS_KERNEL_TAG (0xcdcdcdcd)
#define AOS_APP_TAG (0xefefefef)
typedef enum {
OTA_CRYPTO_ERROR = (int)0xffff0000,
OTA_CRYPTO_NOSUPPORT,
OTA_CRYPTO_INVALID_KEY,
OTA_CRYPTO_INVALID_TYPE,
OTA_CRYPTO_INVALID_CONTEXT,
OTA_CRYPTO_INVALID_PADDING,
OTA_CRYPTO_INVALID_AUTHENTICATION,
OTA_CRYPTO_INVALID_ARG,
OTA_CRYPTO_INVALID_PACKET,
OTA_CRYPTO_LENGTH_ERR,
OTA_CRYPTO_OUTOFMEM,
OTA_CRYPTO_SHORT_BUFFER,
OTA_CRYPTO_NULL,
OTA_CRYPTO_ERR_STATE,
OTA_CRYPTO_SUCCESS = 0,
} OTA_VERIFY_E;
typedef enum {
OTA_SIGN_OFF = 0,
OTA_SIGN_ON
} OTA_SIGN_E;
typedef struct {
char sign_enable;
unsigned char sign_value[256];
}ota_sign_t;
typedef struct
{
OTA_HASH_E hash_method;
char hash_value[65];
} ota_hash_t;
typedef struct
{
OTA_HASH_E hash_method;
int ctx_size;
void *ctx_hash;
} ota_hash_param_t;
typedef struct {
unsigned int magic;
unsigned int status;
OTA_HASH_E type;
union {
ota_md5_context md5_ctx;
ota_sha256_context sha256_ctx;
};
} ota_hash_ctx_t;
enum {
CRYPTO_STATUS_CLEAN = 0,
CRYPTO_STATUS_INITIALIZED = 1,
CRYPTO_STATUS_PROCESSING = 2,
CRYPTO_STATUS_FINISHED = 3,
};
#define INIT_CTX_MAGIC(m) (m = 0x12345678)
#define IS_VALID_CTX_MAGIC(m) (0x12345678 == m)
#define CLEAN_CTX_MAGIC(m) (m = 0x0)
int ota_hash_init(OTA_HASH_E type, void *context);
int ota_hash_update(const unsigned char *src, unsigned int size, void *context);
int ota_hash_final(unsigned char *dgst, void *context);
int ota_hash_get_ctx_size(OTA_HASH_E type, unsigned int *size);
int ota_hash_digest(OTA_HASH_E type, const unsigned char *src, unsigned int size, unsigned char *dgst);
void ota_save_state(int breakpoint, ota_hash_param_t *hash_ctx);
void ota_free_hash_ctx(void);
int ota_get_break_point(void);
int ota_malloc_hash_ctx(OTA_HASH_E type);
int ota_check_hash(OTA_HASH_E hash_type, char* hash);
int ota_set_break_point(int offset);
int ota_get_last_hash_ctx(ota_hash_param_t *hash_ctx);
int ota_set_cur_hash_ctx(ota_hash_param_t *hash_ctx);
int ota_get_last_hash(char *value);
int ota_set_cur_hash(char *value);
int ota_verify_hash_value(ota_hash_t last_hash, ota_hash_t cur_hash);
int ota_get_public_key_bitnumb(void);
int ota_rsa_verify(const ota_rsa_pubkey_t *pub_key, const unsigned char *dig, unsigned int dig_size,
const unsigned char *sig, unsigned int sig_size, ota_rsa_padding_t padding, bool *p_result);
int ota_verify_download_rsa_sign(unsigned char* sign_dat, const char* src_hash_dat, OTA_HASH_E src_hash_method);
ota_hash_param_t *ota_get_hash_ctx(void);
unsigned char *ota_get_identity_image_md5_strvalue(void);
int ota_check_image(unsigned int size);
#endif

View file

@ -0,0 +1,17 @@
NAME := ota_verify
#default gcc
ifeq ($(COMPILER),)
$(NAME)_CFLAGS += -Wall -Werror
else ifeq ($(COMPILER),gcc)
$(NAME)_CFLAGS += -Wall -Werror
endif
$(NAME)_MBINS_TYPE := kernel
$(NAME)_VERSION := 1.0.0
$(NAME)_SUMMARY := Verify OTA firmware with Hash or RSA.
$(NAME)_SOURCES := ota_sign.c \
ota_hash.c
GLOBAL_INCLUDES += . ../../inc ../../hal ../verify

View file

@ -0,0 +1,25 @@
NAME := ota
$(NAME)_MBINS_TYPE := kernel
$(NAME)_VERSION := 1.0.0
$(NAME)_SUMMARY := An over-the-air update is the wireless delivery of new software.
#default gcc
ifeq ($(COMPILER),)
$(NAME)_CFLAGS += -Wall -Werror
else ifeq ($(COMPILER),gcc)
$(NAME)_CFLAGS += -Wall -Werror
endif
$(NAME)_COMPONENTS += framework.uOTA.hal
$(NAME)_COMPONENTS += framework.uOTA.src.transport
$(NAME)_COMPONENTS += framework.uOTA.src.download
$(NAME)_COMPONENTS += framework.uOTA.src.verify
$(NAME)_SOURCES := ota_service.c
GLOBAL_INCLUDES += inc
GLOBAL_DEFINES += OTA_ALIOS
GLOBAL_DEFINES += OTA_WITH_LINKKIT
GLOBAL_DEFINES += OTA_SIGNAL_CHANNEL=1