mirror of
https://github.com/Ai-Thinker-Open/Ai-Thinker-Open_RTL8710BX_ALIOS_SDK.git
synced 2026-07-08 11:45:37 +00:00
rel_1.6.0 init
This commit is contained in:
commit
27b3e2883d
19359 changed files with 8093121 additions and 0 deletions
201
Living_SDK/framework/uOTA/LICENSE
Executable file
201
Living_SDK/framework/uOTA/LICENSE
Executable 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.
|
||||
65
Living_SDK/framework/uOTA/README.md
Normal file
65
Living_SDK/framework/uOTA/README.md
Normal 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)
|
||||
80
Living_SDK/framework/uOTA/hal/README.md
Normal file
80
Living_SDK/framework/uOTA/hal/README.md
Normal 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)
|
||||
71
Living_SDK/framework/uOTA/hal/hal.mk
Executable file
71
Living_SDK/framework/uOTA/hal/hal.mk
Executable 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
|
||||
541
Living_SDK/framework/uOTA/hal/ota_hal_beken.c
Normal file
541
Living_SDK/framework/uOTA/hal/ota_hal_beken.c
Normal 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(¶m_w, 0, sizeof(ota_boot_param_t));
|
||||
hal_flash_read(param_part, (uint32_t*)&offset, ¶m_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, ¶m_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, ¶m_w, sizeof(ota_boot_param_t));
|
||||
offset = 0x00;
|
||||
memset(¶m_r, 0, sizeof(ota_boot_param_t));
|
||||
hal_flash_read(param_part, (uint32_t*)&offset, ¶m_r, sizeof(ota_boot_param_t));
|
||||
if(memcmp(¶m_w, ¶m_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,
|
||||
};
|
||||
153
Living_SDK/framework/uOTA/hal/ota_hal_esp32.c
Normal file
153
Living_SDK/framework/uOTA/hal/ota_hal_esp32.c
Normal 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,
|
||||
};
|
||||
216
Living_SDK/framework/uOTA/hal/ota_hal_host.c
Normal file
216
Living_SDK/framework/uOTA/hal/ota_hal_host.c
Normal 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,
|
||||
};
|
||||
87
Living_SDK/framework/uOTA/hal/ota_hal_mcu.c
Executable file
87
Living_SDK/framework/uOTA/hal/ota_hal_mcu.c
Executable 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, ¶m->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;
|
||||
}
|
||||
|
||||
21
Living_SDK/framework/uOTA/hal/ota_hal_mcu.h
Executable file
21
Living_SDK/framework/uOTA/hal/ota_hal_mcu.h
Executable 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 */
|
||||
|
||||
154
Living_SDK/framework/uOTA/hal/ota_hal_module.c
Normal file
154
Living_SDK/framework/uOTA/hal/ota_hal_module.c
Normal 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;
|
||||
}
|
||||
843
Living_SDK/framework/uOTA/hal/ota_hal_os.c
Normal file
843
Living_SDK/framework/uOTA/hal/ota_hal_os.c
Normal 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;
|
||||
}
|
||||
173
Living_SDK/framework/uOTA/hal/ota_hal_os.h
Normal file
173
Living_SDK/framework/uOTA/hal/ota_hal_os.h
Normal 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
|
||||
362
Living_SDK/framework/uOTA/hal/ota_hal_plat.c
Executable file
362
Living_SDK/framework/uOTA/hal/ota_hal_plat.c
Executable 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, ¶m->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(¶m_r, 0, sizeof(ota_boot_param_t));
|
||||
hal_flash_read(param_part, (uint32_t*)&offset, ¶m_r, sizeof(ota_boot_param_t));
|
||||
if(memcmp(param, ¶m_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(¶m_r, 0, sizeof(ota_boot_param_t));
|
||||
hal_flash_read(param_part, (uint32_t*)&offset, ¶m_r, sizeof(ota_boot_param_t));
|
||||
if(memcmp(param, ¶m_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(¶m_w, 0, sizeof(ota_boot_param_t));
|
||||
hal_flash_read(param_part, (uint32_t*)&offset, ¶m_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, ¶m_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, ¶m_w, sizeof(ota_boot_param_t));
|
||||
offset = 0x00;
|
||||
memset(¶m_r, 0, sizeof(ota_boot_param_t));
|
||||
hal_flash_read(param_part, (uint32_t*)&offset, ¶m_r, sizeof(ota_boot_param_t));
|
||||
if(memcmp(¶m_w, ¶m_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,
|
||||
};
|
||||
120
Living_SDK/framework/uOTA/hal/ota_hal_plat.h
Normal file
120
Living_SDK/framework/uOTA/hal/ota_hal_plat.h
Normal 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 */
|
||||
|
||||
41
Living_SDK/framework/uOTA/inc/ota_log.h
Normal file
41
Living_SDK/framework/uOTA/inc/ota_log.h
Normal 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_
|
||||
156
Living_SDK/framework/uOTA/inc/ota_service.h
Executable file
156
Living_SDK/framework/uOTA/inc/ota_service.h
Executable 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_ */
|
||||
676
Living_SDK/framework/uOTA/ota_service.c
Executable file
676
Living_SDK/framework/uOTA/ota_service.c
Executable 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;
|
||||
}
|
||||
24
Living_SDK/framework/uOTA/src/2nd_boot/2nd_boot.mk
Normal file
24
Living_SDK/framework/uOTA/src/2nd_boot/2nd_boot.mk
Normal 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)\"
|
||||
68
Living_SDK/framework/uOTA/src/2nd_boot/README.md
Normal file
68
Living_SDK/framework/uOTA/src/2nd_boot/README.md
Normal 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)
|
||||
69
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/README.md
Normal file
69
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/README.md
Normal 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)
|
||||
128
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/flash_hal.c
Normal file
128
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/flash_hal.c
Normal 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
|
||||
23
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/flash_hal.h
Normal file
23
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/flash_hal.h
Normal 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_ */
|
||||
404
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/nbpatch.c
Normal file
404
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/nbpatch.c
Normal 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;
|
||||
}
|
||||
69
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/nbpatch.h
Normal file
69
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/nbpatch.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* nbpatch.h
|
||||
*
|
||||
* Created on: 2017年12月8日
|
||||
* 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_ */
|
||||
20
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/nbpatch.mk
Normal file
20
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/nbpatch.mk
Normal 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
|
||||
|
||||
|
||||
288
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/nbpatch_io.c
Normal file
288
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/nbpatch_io.c
Normal 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
|
||||
368
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/nbpatch_main.c
Normal file
368
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/nbpatch_main.c
Normal 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;
|
||||
}
|
||||
249
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/rec_md5.c
Normal file
249
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/rec_md5.c
Normal 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 );
|
||||
}
|
||||
|
||||
21
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/rec_md5.h
Normal file
21
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/rec_md5.h
Normal 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
|
||||
|
||||
109
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/rec_verify_fw.c
Normal file
109
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/rec_verify_fw.c
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
177
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/xzdec.c
Normal file
177
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/xzdec.c
Normal 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
|
||||
|
||||
31
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/xzdec.h
Normal file
31
Living_SDK/framework/uOTA/src/2nd_boot/nbpatch/xzdec.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* xzlib.h
|
||||
*
|
||||
* Created on: 2017年11月14日
|
||||
* 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_ */
|
||||
141
Living_SDK/framework/uOTA/src/2nd_boot/rec_2boot.c
Normal file
141
Living_SDK/framework/uOTA/src/2nd_boot/rec_2boot.c
Normal 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();
|
||||
}
|
||||
|
||||
48
Living_SDK/framework/uOTA/src/2nd_boot/rec_common.c
Normal file
48
Living_SDK/framework/uOTA/src/2nd_boot/rec_common.c
Normal 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);
|
||||
|
||||
}
|
||||
10
Living_SDK/framework/uOTA/src/2nd_boot/rec_common.h
Normal file
10
Living_SDK/framework/uOTA/src/2nd_boot/rec_common.h
Normal 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
|
||||
99
Living_SDK/framework/uOTA/src/2nd_boot/rec_define.h
Normal file
99
Living_SDK/framework/uOTA/src/2nd_boot/rec_define.h
Normal 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
|
||||
498
Living_SDK/framework/uOTA/src/2nd_boot/rec_libc.c
Normal file
498
Living_SDK/framework/uOTA/src/2nd_boot/rec_libc.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
224
Living_SDK/framework/uOTA/src/2nd_boot/rec_main.c
Normal file
224
Living_SDK/framework/uOTA/src/2nd_boot/rec_main.c
Normal 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();
|
||||
}
|
||||
|
||||
86
Living_SDK/framework/uOTA/src/2nd_boot/rec_pub.h
Normal file
86
Living_SDK/framework/uOTA/src/2nd_boot/rec_pub.h
Normal 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_
|
||||
322
Living_SDK/framework/uOTA/src/2nd_boot/rec_ymodem.c
Normal file
322
Living_SDK/framework/uOTA/src/2nd_boot/rec_ymodem.c
Normal 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);
|
||||
}
|
||||
76
Living_SDK/framework/uOTA/src/2nd_boot/xz/README.md
Normal file
76
Living_SDK/framework/uOTA/src/2nd_boot/xz/README.md
Normal 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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
22
Living_SDK/framework/uOTA/src/2nd_boot/xz/xz.mk
Normal file
22
Living_SDK/framework/uOTA/src/2nd_boot/xz/xz.mk
Normal 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
|
||||
|
||||
|
||||
66
Living_SDK/framework/uOTA/src/device/ble/README.md
Normal file
66
Living_SDK/framework/uOTA/src/device/ble/README.md
Normal 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)
|
||||
21
Living_SDK/framework/uOTA/src/device/ble/ble.mk
Normal file
21
Living_SDK/framework/uOTA/src/device/ble/ble.mk
Normal 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
|
||||
84
Living_SDK/framework/uOTA/src/device/ble/inc/ais_ota.h
Normal file
84
Living_SDK/framework/uOTA/src/device/ble/inc/ais_ota.h
Normal 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
|
||||
138
Living_SDK/framework/uOTA/src/device/ble/inc/ota_breeze.h
Normal file
138
Living_SDK/framework/uOTA/src/device/ble/inc/ota_breeze.h
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
284
Living_SDK/framework/uOTA/src/device/ble/src/ota_breeze.c
Normal file
284
Living_SDK/framework/uOTA/src/device/ble/src/ota_breeze.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
342
Living_SDK/framework/uOTA/src/device/ble/src/ota_breeze_plat.c
Normal file
342
Living_SDK/framework/uOTA/src/device/ble/src/ota_breeze_plat.c
Normal 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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
60
Living_SDK/framework/uOTA/src/download/README.md
Normal file
60
Living_SDK/framework/uOTA/src/download/README.md
Normal 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)
|
||||
29
Living_SDK/framework/uOTA/src/download/download.mk
Normal file
29
Living_SDK/framework/uOTA/src/download/download.mk
Normal 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
|
||||
|
||||
|
||||
138
Living_SDK/framework/uOTA/src/download/ota_download_coap.c
Normal file
138
Living_SDK/framework/uOTA/src/download/ota_download_coap.c
Normal 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;
|
||||
}
|
||||
371
Living_SDK/framework/uOTA/src/download/ota_download_http.c
Executable file
371
Living_SDK/framework/uOTA/src/download/ota_download_http.c
Executable 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;
|
||||
}
|
||||
227
Living_SDK/framework/uOTA/src/transport/ota_transport_coap.c
Normal file
227
Living_SDK/framework/uOTA/src/transport/ota_transport_coap.c
Normal 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;
|
||||
}
|
||||
247
Living_SDK/framework/uOTA/src/transport/ota_transport_mqtt.c
Normal file
247
Living_SDK/framework/uOTA/src/transport/ota_transport_mqtt.c
Normal 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;
|
||||
}
|
||||
22
Living_SDK/framework/uOTA/src/transport/transport.mk
Normal file
22
Living_SDK/framework/uOTA/src/transport/transport.mk
Normal 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
|
||||
|
||||
|
||||
459
Living_SDK/framework/uOTA/src/verify/ota_hash.c
Normal file
459
Living_SDK/framework/uOTA/src/verify/ota_hash.c
Normal 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;
|
||||
}
|
||||
12
Living_SDK/framework/uOTA/src/verify/ota_public_key_config.h
Normal file
12
Living_SDK/framework/uOTA/src/verify/ota_public_key_config.h
Normal 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
|
||||
185
Living_SDK/framework/uOTA/src/verify/ota_sign.c
Normal file
185
Living_SDK/framework/uOTA/src/verify/ota_sign.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
98
Living_SDK/framework/uOTA/src/verify/ota_verify.h
Normal file
98
Living_SDK/framework/uOTA/src/verify/ota_verify.h
Normal 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
|
||||
17
Living_SDK/framework/uOTA/src/verify/verify.mk
Normal file
17
Living_SDK/framework/uOTA/src/verify/verify.mk
Normal 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
|
||||
25
Living_SDK/framework/uOTA/uOTA.mk
Normal file
25
Living_SDK/framework/uOTA/uOTA.mk
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue