blob: 76d3197a7e3dd6eb29ca91da9cbccf9071015248 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include "../include/v3_tool_def.h"
#include <mmc.h>
int v3tool_simg2img_init(const ImgDownloadPara* downPara);
int v3tool_simg2img_get_img(UsbDownInf* downInf);
int v3tool_simg2img_write_img(const UsbDownInf* downInf, const ImgDownloadPara* downPara);
int v3tool_simg2img_verify_img(sha1_context* ctx, const char* partName, int64_t partBase);
#ifndef CONFIG_V3_KEY_BURNING_SUPPORT
static int v2_key_read(const char* keyName, u8* keyVal, const unsigned keyValLen, char* errInfo, unsigned* fmtLen)
{
FB_ERR("burn key not supported as CONFIG_UNIFY_KEY_MANAGE undef!!");
return -1;
}
static unsigned v2_key_burn(const char* keyName, const u8* keyVal, const unsigned keyValLen, char* errInfo)
{
FB_ERR("burn key not supported as CONFIG_UNIFY_KEY_MANAGE undef!!");
return -1;
}
#define key_manage_query_size(a,b) 1
#endif// //#ifdef CONFIG_V3_KEY_BURNING_SUPPORT
static struct {
ImgTransPara imgTransPara;//user para
int isDownload;
int dataBufCap;
char* dataBuf;
char* verifyInfo;//verifyInfo will saved while downloading, and used while verify
int inited;
}_imgTransferInfo;
static UsbDownInf _usbDownInf = {0};
static UsbUpInf _usbUpInf = {0};
static int64_t _rawImgFileOffset = 0;
static int64_t _rawImgVryLen = 0;
//isn't pc get busy info and so still waiting
static int _dnl_check_if_PC_waiting(void)
{
return !strncmp(fb_response_str - 4, "INFO", 4);
}
int v3tool_buffman_img_verify_sha1sum(unsigned char* vrySum)
{
static sha1_context ctx;
const ImgDownloadPara* imgDownPara = &_imgTransferInfo.imgTransPara.download;
const ImgCommonPara* imgCmnPara = &imgDownPara->commonInf;
const int media = imgCmnPara->mediaType;
const int imgFmt = imgDownPara->imgFmt;
const char* part = imgCmnPara->partName;
const int64_t imgTotalLen = imgCmnPara->imgSzTotal;
const int64_t partBase = imgCmnPara->partStartOff;
unsigned char* vryBuff = (unsigned char*)V3_DOWNLOAD_MEM_BASE;
const int vryBuffLen = (2<<20);
int64_t vryLen = _rawImgVryLen;
int ret = 0;
if (!_imgTransferInfo.isDownload) {
FBS_ERR(_ACK, "only download can support verify now.");
return -__LINE__;
}
if ( V3TOOL_MEDIA_TYPE_STORE != media ) {
FBS_ERR(_ACK, "verify can'tsupport media[%d]", media);
return -__LINE__;
}
//report busy, then continue verify at next pc bulk-in request
if ( !_dnl_check_if_PC_waiting() ) {
sha1_starts(&ctx);
FB_DBG("init ctx\n");
}
if ( !strcmp("bootloader", part) ) {
ret = bootloader_read(vryBuff, 0, imgTotalLen);
sha1_update(&ctx, vryBuff, imgTotalLen);
} else if ( !strcmp("_aml_dtb", part) ) {
ret = store_dtb_rw(vryBuff, imgTotalLen, 2);
sha1_update(&ctx, vryBuff, imgTotalLen);
} else if (!strcmp("gpt", part)) {
ret = store_gpt_ops(imgTotalLen, vryBuff,0);
sha1_update(&ctx, vryBuff, imgTotalLen);
} else {
switch (imgFmt)
{
case V3TOOL_PART_IMG_FMT_RAW:
{
int thisVryLen = 0;
static unsigned long _lastReportTick = 0;
if (!vryLen) _lastReportTick = get_timer(0);
for (; vryLen < imgTotalLen; vryLen += thisVryLen)
{
thisVryLen = imgTotalLen - vryLen;
thisVryLen = thisVryLen > vryBuffLen ? vryBuffLen : thisVryLen;
ret = store_logic_read(part, vryLen + partBase, thisVryLen, vryBuff);
if ( ret ) {
FBS_ERR(_ACK, "FAil in store read");
return -__LINE__;
}
sha1_update(&ctx, vryBuff, thisVryLen);
if (get_timer(_lastReportTick) >= 4000) {
_lastReportTick += get_timer(_lastReportTick);
_rawImgVryLen = vryLen + thisVryLen;
char info[64];
sprintf(info, "%06lld / %06lld MBytes", (vryLen>>20), (imgTotalLen>>20));
v3tool_media_set_busy(info);
return 0;
}
}
}break;
case V3TOOL_PART_IMG_FMT_SPARSE:
{
ret = v3tool_simg2img_verify_img(&ctx, part, partBase);
if ( ret ) {
FB_ERR("fail in very img,ret %d\n", ret);
return -__LINE__;
}
if (v3tool_media_is_busy()) {
return 0;
}
}break;
default:
FBS_ERR(_ACK, "imgFmt[%x] cannot verify", imgFmt);
return -__LINE__;
}
}
sha1_finish(&ctx, vrySum);
v3tool_media_set_free(NULL);
return 0;
}
static int _buffman_img_init_mmc(const char* partName, const int isDownload, const int64_t imgSize, const int64_t partStartOff)
{
#if CONFIG_IS_ENABLED(MMC_WRITE)
int dev = -1;
if (strcmp("1", partName) && strcmp("0", partName)) {
FBS_ERR(_ACK, "mmc part[%s] invalid\n", partName); return -__LINE__;
}
env_set("mmc_dev_id", partName);
env_set("mmc_select_dev", "mmc dev ${mmc_dev_id}");
if (run_command("printenv mmc_select_dev; run mmc_select_dev", 0)) {
FBS_ERR(_ACK, "Fail in init mmc dev %s\n", partName); return -__LINE__;
}
dev = partName[0] - '0';
struct mmc* mmc = find_mmc_device(dev);
if (!mmc) {
FBS_ERR(_ACK, "no mmc device at slot %x\n", dev); return -__LINE__;
}
if (mmc_init(mmc)) {
FBS_ERR(_ACK, "fail in init mmc %d\n", dev); return -__LINE__;
}
const int64_t capacity = mmc->capacity_user;
if (capacity < partStartOff + imgSize) {
FBS_ERR(_ACK, "capacity < partStartOff + imgSize 0x:%llx %llx %llx\n", capacity, partStartOff, imgSize);
return -__LINE__;
}
if (mmc_getwp(mmc) == 1) {
FBS_ERR(_ACK, "Error: mmc(%s) is write protected!\n", partName);
return -__LINE__;
}
run_command("store rsv protect key off", 0);//disprotect key for write/dump all emmc
return 0;
#else
FBS_ERR(_ACK, "CONFIG_MMC_WRITE not enabled\n");
return -__LINE__;
#endif//#if CONFIG_IS_ENABLED(MMC_WRITE)
}
//@imgPara:
//@isDownload: 1 if download, 0 if upload
//@needVerify: 1 if need verify, if need verify, will save some info while downloading
// will ignored if not download mode
int v3tool_buffman_img_init(ImgTransPara* imgPara, const int isDownload)
{
_imgTransferInfo.isDownload = isDownload;
memcpy(&_imgTransferInfo.imgTransPara, imgPara, sizeof(ImgTransPara));
_imgTransferInfo.dataBuf = (char*)V3_DOWNLOAD_MEM_BASE;
_imgTransferInfo.dataBufCap = V3_DOWNLOAD_MEM_SIZE;
_imgTransferInfo.verifyInfo = isDownload ? (char*)V3_DOWNLOAD_VERIFY_INFO : NULL;
_imgTransferInfo.inited = 1;
ImgCommonPara* commonInf = &imgPara->commonInf;
const int64_t imgSize = commonInf->imgSzTotal;
const int64_t partStartOff = commonInf->partStartOff;
const char* partName = commonInf->partName;
int ret = 0;
switch (commonInf->mediaType)
{
case V3TOOL_MEDIA_TYPE_MEM:
{ //User should make sure mem address is able to access by himself if media is mem
_imgTransferInfo.dataBuf = (char*)commonInf->partStartOff;
_imgTransferInfo.dataBufCap = imgSize;
_imgTransferInfo.verifyInfo = NULL;
} break;
case V3TOOL_MEDIA_TYPE_STORE:
{
ret = v3tool_media_check_image_size(imgSize + partStartOff, partName);
if ( ret ) {
FB_EXIT("Fail in check img sz\n");
}
}break;
case V3TOOL_MEDIA_TYPE_UNIFYKEY:
{
if (!isDownload) {
const char* queryKey = commonInf->partName;
ssize_t keySz = 0;
ret = key_manage_query_size(queryKey,&keySz);
if (ret) {
FB_EXIT("Fail get sz for key[%s]\n", queryKey);
}
if (keySz != imgSize) {
FB_EXIT("key[%s] sz %zd != cmd key sz %lld\n", queryKey, keySz, imgSize);
}
}
} break;
case V3TOOL_MEDIA_TYPE_MMC:
{
ret = _buffman_img_init_mmc(partName, isDownload, imgSize, partStartOff);
if (ret) FB_EXIT("Fail in init mmc %s\n", partName);
} break;
default:
FB_EXIT("Exception, err media type 0x%x\n", commonInf->mediaType);
}
if (V3TOOL_PART_IMG_FMT_SPARSE == imgPara->download.imgFmt && isDownload) {
imgPara->download.needVerify = 1;
if (v3tool_simg2img_init(&imgPara->download)) {
FB_ERR("Fail in simg init\n");
return -__LINE__;
}
}
//Init _usbDownInf for raw image
_rawImgFileOffset = 0;
_rawImgVryLen = 0;
optimus_progress_init((unsigned)(imgSize>>32), (unsigned)imgSize, 0, 100);
return 0;
}
static int _v3tool_buffman_next_download_info_rawimg(ImgDownloadPara* imgPara)
{
ImgCommonPara* cmnInf = &imgPara->commonInf;
switch (cmnInf->mediaType) {
case V3TOOL_MEDIA_TYPE_MEM:
{
_usbDownInf.fileOffset = _rawImgFileOffset;
int64_t leftLen = cmnInf->imgSzTotal - _rawImgFileOffset;
_usbDownInf.dataSize = _mymin(leftLen, _RAW_IMG_TRANSFER_LEN);
_usbDownInf.dataBuf = _imgTransferInfo.dataBuf + _rawImgFileOffset;
FB_DBG("dataBuf %p, dataSize %x\n", _usbDownInf.dataBuf, _usbDownInf.dataSize);
}break;
case V3TOOL_MEDIA_TYPE_MMC:
case V3TOOL_MEDIA_TYPE_STORE:
{
_usbDownInf.fileOffset = _rawImgFileOffset;
int64_t leftLen = cmnInf->imgSzTotal - _rawImgFileOffset;
if (strcmp("bootloader", cmnInf->partName) && strcmp("_aml_dtb", cmnInf->partName)
&& strcmp("gpt", cmnInf->partName))
{_usbDownInf.dataSize = _mymin(leftLen, _RAW_IMG_TRANSFER_LEN);}
else _usbDownInf.dataSize = leftLen;
_usbDownInf.dataBuf = (char*)V3_DOWNLOAD_MEM_BASE;
}break;
case V3TOOL_MEDIA_TYPE_UNIFYKEY:
{
_usbDownInf.fileOffset = _rawImgFileOffset;
_usbDownInf.dataSize = cmnInf->imgSzTotal - _rawImgFileOffset;
_usbDownInf.dataBuf = (char*)V3_DOWNLOAD_MEM_BASE;
} break;
default:
{
FB_EXIT("err media type %d\n", cmnInf->mediaType);
}break;
}
//for next raw img download
_rawImgFileOffset += _usbDownInf.dataSize;
return 0;
}
int v3tool_buffman_next_download_info(UsbDownInf** downloadInf)
{
int ret = 0;
*downloadInf = NULL;
if (!_imgTransferInfo.inited || !_imgTransferInfo.isDownload) {
FBS_ERR(_ACK, "buffman %d, %d\n", _imgTransferInfo.inited ,_imgTransferInfo.isDownload);
return -__LINE__;
}
ImgDownloadPara* imgPara = &_imgTransferInfo.imgTransPara.download;
ImgCommonPara* cmnInf = &imgPara->commonInf;
switch (imgPara->imgFmt) {
case V3TOOL_PART_IMG_FMT_RAW:
{
ret = _v3tool_buffman_next_download_info_rawimg(imgPara);
if ( ret ) FB_EXIT("FAil in get buf for raw img\n");
*downloadInf = &_usbDownInf;
return 0;
}
case V3TOOL_PART_IMG_FMT_SPARSE:
{
switch (cmnInf->mediaType) {
case V3TOOL_MEDIA_TYPE_STORE:
{
ret = v3tool_simg2img_get_img(&_usbDownInf);
if ( !ret ) *downloadInf = &_usbDownInf;
else {
FBS_ERR(_ACK, "fail in get next sp img data");
return -__LINE__;
}
}break;
default:
{
FBS_ERR(fb_response_str, "err media %d for sparse fmt", cmnInf->mediaType);
}break;
}
}break;
default:
FBS_ERR(_ACK, "unsupported imgFmt 0x%x", imgPara->imgFmt);
return -__LINE__;
}
return ret;
}
static int _v3tool_mmc_rw(const char* partName, const int write, const int thisTransferLen, loff_t partOffset, void* dataBuf)
{
#if CONFIG_IS_ENABLED(MMC_WRITE)
int dev = *partName - '0';
struct mmc *mmc = find_mmc_device(dev);
if (!mmc) {
FBS_ERR(_ACK, "no mmc device at slot %x\n", dev); return -__LINE__;
}
if (mmc_init(mmc)) {
FBS_ERR(_ACK, "fail mmc_init[%s]", partName); return -__LINE__;
}
u32 cnt = (thisTransferLen + 511) >> 9;
u32 blk = partOffset>>9;
u32 n = 0;
if (write) n = blk_dwrite(mmc_get_blk_desc(mmc), blk, cnt, dataBuf);
else n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, dataBuf);
return (n == cnt) ? 0 : -__LINE__;
#else
FBS_ERR(_ACK, "CONFIG_MMC_WRITE not enabled\n");
return -__LINE__;
#endif//#if CONFIG_IS_ENABLED(MMC_WRITE)
}
int v3tool_buffman_data_complete_download(const UsbDownInf* downloadInf)
{
ImgCommonPara* cmnInf = &_imgTransferInfo.imgTransPara.commonInf;
ImgDownloadPara* downInf = &_imgTransferInfo.imgTransPara.download;
const int imgFmt = downInf->imgFmt;
/*const int needVerify = downInf->needVerify;*/
const int mediaType = cmnInf->mediaType;
const char* partName = cmnInf->partName;
int ret = 0;
const int thisTransferLen = downloadInf->dataSize;
u8* dataBuf = (u8*)downloadInf->dataBuf;
loff_t partOffset = downloadInf->fileOffset + cmnInf->partStartOff;
switch ( imgFmt ) {
case V3TOOL_PART_IMG_FMT_RAW:
{
switch ( mediaType ) {
case V3TOOL_MEDIA_TYPE_STORE:
{
if ( !strcmp("bootloader", partName) ) {
ret = bootloader_write(dataBuf, 0, thisTransferLen);
} else if ( !strcmp("_aml_dtb", partName) ) {
ret = store_dtb_rw(dataBuf, thisTransferLen, 1);
} else if ( !strcmp("gpt", partName) ) {
ret = store_gpt_ops(thisTransferLen, dataBuf, 1);
} else {
ret = store_logic_write(partName, partOffset, thisTransferLen, dataBuf);
}
} break;
case V3TOOL_MEDIA_TYPE_MEM:
break;
case V3TOOL_MEDIA_TYPE_UNIFYKEY:
ret = v2_key_burn(partName, dataBuf, thisTransferLen, _ACK);
if (ret != thisTransferLen) {
FBS_ERR(_ACK, "err in program key to media,ret %d", ret);
ret = -__LINE__;
} else ret = 0;
break;
case V3TOOL_MEDIA_TYPE_MMC:
{
ret = _v3tool_mmc_rw(partName, 1, thisTransferLen, partOffset, dataBuf);
} break;
default:
FBS_ERR(fb_response_str, "err media type %d for raw img", mediaType);
break;
}
}break;
case V3TOOL_PART_IMG_FMT_SPARSE:
{
FB_DBG("buf %p, sz %d\n", downloadInf->dataBuf, thisTransferLen);
ret = v3tool_simg2img_write_img(downloadInf, &_imgTransferInfo.imgTransPara.download);
} break;
case V3TOOL_PART_IMG_FMT_UBIFS:
break;
default:
FBS_ERR(fb_response_str, "err media type %d for sp img", mediaType);
break;
}
if ( !ret )optimus_update_progress(thisTransferLen);
return ret;
}
int v3tool_buffman_data_complete_upload(const UsbUpInf* uploadInf)
{
//for next download
_rawImgFileOffset += uploadInf->dataSize;
return 0;
}
int v3tool_buffman_next_upload_info(UsbUpInf** uploadInfo)
{
int ret = 0;
*uploadInfo = NULL;
if (!_imgTransferInfo.inited || _imgTransferInfo.isDownload) {
FB_ERR("buffman %d, %d\n", _imgTransferInfo.inited ,_imgTransferInfo.isDownload);
return -__LINE__;
}
ImgUploadPara* upInf = &_imgTransferInfo.imgTransPara.upload;
ImgCommonPara* cmnInf = &upInf->commonInf;
char* partName = (char*)cmnInf->partName;
int64_t leftLen = cmnInf->imgSzTotal - _rawImgFileOffset;
if ( !leftLen ) {
_usbUpInf.dataSize = 0;
*uploadInfo = &_usbUpInf;
return 0;
}
_usbUpInf.dataSize = _mymin(leftLen, _RAW_IMG_TRANSFER_LEN);
_usbUpInf.dataBuf = (char*)V3_DOWNLOAD_MEM_BASE;
u8* dataBuf = (u8*)_usbUpInf.dataBuf;
unsigned dataSize = _usbUpInf.dataSize;
loff_t partOffset = _rawImgFileOffset + cmnInf->partStartOff;
switch (cmnInf->mediaType) {
case V3TOOL_MEDIA_TYPE_MEM:
{
_usbUpInf.dataBuf = (char*)cmnInf->partStartOff + _rawImgFileOffset;
}break;
case V3TOOL_MEDIA_TYPE_STORE:
{
if ( !strcmp("bootloader", partName) || !strcmp("_aml_dtb", partName)
|| !strcmp("gpt", partName)) {
dataSize = _usbUpInf.dataSize = leftLen;
}
if (!strcmp("bootloader", partName)) {
ret = bootloader_read(dataBuf, 0, dataSize);
} else if (!strcmp("_aml_dtb", partName)) {
//'2' means using 'store dtb iread' rather than 'read'
ret = store_dtb_rw(dataBuf, dataSize, 2);
} else if ( !strcmp("gpt", partName) ) {
ret = store_gpt_ops(dataSize, dataBuf, 0);
} else {
ret = store_logic_read(partName, _rawImgFileOffset + cmnInf->partStartOff, dataSize, dataBuf);
}
if (ret) {
FB_ERR("Fail in read store at offset %llx\n", _rawImgFileOffset);
return -__LINE__;
}
}break;
case V3TOOL_MEDIA_TYPE_UNIFYKEY:
{
_usbUpInf.dataSize = leftLen;
unsigned keySz = 0;
ret = v2_key_read(partName, (u8*)_usbUpInf.dataBuf, leftLen, _ACK, &keySz);
if (ret || keySz != leftLen) {
FB_ERR("Fail in key read,ret %d\n", ret);
return -__LINE__;
}
}break;
case V3TOOL_MEDIA_TYPE_MMC:
{
ret = _v3tool_mmc_rw(partName, 0, dataSize, partOffset, dataBuf);
} break;
default:
FB_ERR("unsupported media %d\n", cmnInf->mediaType);
break;
}
FB_DBG("dataBuf %p, dataSize %x\n", _usbUpInf.dataBuf, _usbUpInf.dataSize);
*uploadInfo = &_usbUpInf;
return 0;
}