关于瑞芯微开发工具(RKDevTool)刷机下载Boot失败原因的研究

关于瑞芯微开发工具(RKDevTool)刷机下载Boot失败原因的研究

昨天发了文章《网心云OEC/OEC-turbo刷机问题——刷机教程、救砖方法、技术要点及下载boot失败异常解决尝试》,其中有关于刷机各种问题的一些解决方法。

网心云OEC/OEC-turbo刷机问题——刷机教程、救砖方法、技术要点及下载boot失败异常解决尝试-CSDN博客文章浏览阅读899次,点赞10次,收藏13次。OEC/OEC-turbo的产品设计出来,是想让买家跑PCDN,随着对PCDN的各种管控,各种宽带限速,大量的设备上了小黄鱼。前段时间弄了台斐讯的N1,简直是刷机神器,解过之后,可以刷各种系统,完全没有限制。对比斐讯N1和OEC-turbo这两款产品,N1除了硬盘空间不足,芯片性能略低外,优点是有无线网卡,虽然只是一款百兆的,但聊胜于无。更重要的是省电,2W的功率,长年开着都不心疼了。准备一头USB-A,另一端Type-C的数据线,先USB连接电脑,然后短接主板,再将C端插上板子,等2-3秒松开短接。https://blog.csdn.net/John_Lenon/article/details/146461220

个人感觉,日常刷机最大的问题就是“下载Boot失败”的问题了。

所以今天从rkdeveloptool的源码来分析一下,究竟是什么原因导致了反复出现这个问题,而让刷机成功成了一个玄学问题。

比如下面这条刷机日志:

20:26:37 485 瑞芯微开发工具 v2.8.4.0 start run

20:30:36 790 ERROR:Boot_VendorRequest-->DeviceIoControl failed,Total(100354),Sended(0),bRet(1),err(0)

20:30:36 790 ERROR:DownloadBoot-->Boot_VendorRequest472 failed,index(0)

20:30:36 799 Layer<1-4>: RunProc is ending, ret=0

两条报错位置可以看到,分别是 “ERROR:DownloadBoot-->Boot_VendorRequest472”,“ERROR:Boot_VendorRequest-->DeviceIoControl failed”。

查看rkdeveloptool源码(这个源码比较旧了,而且是适用于linux和macos的源码):

GitHub - rockchip-linux/rkdeveloptoolContribute to rockchip-linux/rkdeveloptool development by creating an account on GitHub.https://github.com/rockchip-linux/rkdeveloptool直接搜“Boot_VendorRequest”, 可以在“RKDevice.cpp”中看到相关的函数:

int CRKDevice::DownloadBoot()

{

UCHAR i;

DWORD dwSize, dwDelay;

PBYTE pBuffer = NULL;

for ( i = 0; i < m_pImage->m_bootObject->Entry471Count; i++ ) {

if ( !m_pImage->m_bootObject->GetEntryProperty(ENTRY471, i, dwSize, dwDelay) ) {

if (m_pLog) {

m_pLog->Record(" ERROR:DownloadBoot-->GetEntry471Property failed,index(%d)", m_layerName, i);

}

return -2;

}

if (dwSize>0) {

pBuffer = new BYTE[dwSize];

if ( !m_pImage->m_bootObject->GetEntryData(ENTRY471, i, pBuffer) ) {

if (m_pLog) {

m_pLog->Record(" ERROR:DownloadBoot-->GetEntry471Data failed,index(%d)", m_layerName, i);

}

delete []pBuffer;

return -3;

}

if ( !Boot_VendorRequest(0x0471,pBuffer,dwSize) ) {

if (m_pLog) {

m_pLog->Record(" ERROR:DownloadBoot-->Boot_VendorRequest471 failed,index(%d)", m_layerName, i);

}

delete []pBuffer;

return -4;

}

delete []pBuffer;

pBuffer = NULL;

if (dwDelay>0) {

usleep(dwDelay * 1000);

}

}

}

for ( i=0; i < m_pImage->m_bootObject->Entry472Count; i++ ) {

if ( !m_pImage->m_bootObject->GetEntryProperty(ENTRY472, i, dwSize, dwDelay) ) {

if (m_pLog) {

m_pLog->Record(" ERROR:DownloadBoot-->GetEntry472Property failed,index(%d)", m_layerName, i);

}

return -2;

}

if (dwSize > 0) {

pBuffer = new BYTE[dwSize];

if ( !m_pImage->m_bootObject->GetEntryData(ENTRY472, i, pBuffer) ) {

if (m_pLog) {

m_pLog->Record(" ERROR:DownloadBoot-->GetEntry472Data failed,index(%d)", m_layerName, i);

}

delete []pBuffer;

return -3;

}

if ( !Boot_VendorRequest(0x0472, pBuffer, dwSize) ) {

if (m_pLog) {

m_pLog->Record(" ERROR:DownloadBoot-->Boot_VendorRequest472 failed,index(%d)", m_layerName, i);

}

delete []pBuffer;

return -4;

}

delete []pBuffer;

pBuffer = NULL;

if (dwDelay > 0) {

usleep(dwDelay * 1000);

}

}

}

sleep(1);

return 0;

}

很明白地可以看到出错的位置在:Boot_VendorRequest函数, 因为其返回了false。

bool CRKDevice::Boot_VendorRequest( DWORD requestCode, PBYTE pBuffer, DWORD dwDataSize)

{

int iRet;

iRet = m_pComm->RKU_DeviceRequest(requestCode, pBuffer, dwDataSize);

return (iRet == ERR_SUCCESS) ? true : false;

}

也就是说是m_pComm->RKU_DeviceRequest函数返回值不是ERR_SUCCESS。

继续跟进到CRKUsbComm::RKU_DeviceRequest

int CRKUsbComm::RKU_DeviceRequest(DWORD dwRequest, BYTE *lpBuffer, DWORD dwDataSize)

{

if (m_deviceDesc.emUsbType != RKUSB_MASKROM) {

if (m_log) {

m_log->Record("Error:RKU_DeviceRequest failed,device not support");

}

return ERR_DEVICE_NOT_SUPPORT;

}

if ((dwRequest != 0x0471) && (dwRequest != 0x0472)) {

if (m_log) {

m_log->Record("Error:RKU_DeviceRequest failed,request not support");

}

return ERR_REQUEST_NOT_SUPPORT;

}

bool bSendPendPacket = false;

USHORT crcValue = 0xffff;

BYTE *pData = NULL;

pData = new BYTE[dwDataSize + 5];

memset(pData, 0, dwDataSize + 5);

memcpy(pData, lpBuffer, dwDataSize);

switch(dwDataSize % 4096) {

case 4095:

++dwDataSize;

break;

case 4094:

bSendPendPacket = true;

break;

case 0:

default:

break;

}

crcValue = CRC_CCITT(pData, dwDataSize);

pData[dwDataSize] = (crcValue & 0xff00) >> 8;

pData[dwDataSize+1] = crcValue & 0x00ff;

dwDataSize += 2;

UINT nSendBytes = 0;

DWORD dwTotalSended = 0;

int iRet;

while(dwTotalSended < dwDataSize) {

nSendBytes = ( (dwDataSize - dwTotalSended) > 4096) ? 4096 : (dwDataSize - dwTotalSended);

iRet = libusb_control_transfer((libusb_device_handle *)m_pUsbHandle, 0x40, 0xC, 0, dwRequest, pData + dwTotalSended, nSendBytes, CMD_TIMEOUT);

if (iRet != (int)nSendBytes) {

if (m_log) {

m_log->Record("Error:RKU_DeviceRequest-->DeviceRequest vendor=0x%x failed, err=%d",dwRequest, iRet);

}

delete []pData;

return ERR_REQUEST_FAIL;

}

dwTotalSended += nSendBytes;

}

if(bSendPendPacket) {

BYTE ucFillByte = 0;

iRet = libusb_control_transfer((libusb_device_handle *)m_pUsbHandle, 0x40, 0xC, 0, dwRequest, &ucFillByte, 1, CMD_TIMEOUT);

if (iRet != 0) {

if (m_log) {

m_log->Record("Error:RKU_DeviceRequest-->DeviceRequest vendor=0x%x failed, err=%d", dwRequest, iRet);

}

delete []pData;

return ERR_REQUEST_FAIL;

}

}

delete []pData;

return ERR_SUCCESS;

}

发现错误代码已经和Windows运行的报错日志不一致了。说明在这一块的代码更新过了。

那么,接下来的结论只能靠猜测了。

整个下载Boot的逻辑是这样的:

// main.cpp

-> bool download_boot(STRUCT_RKDEVICE_DESC &dev, char *szLoader);

// CRKDevice *pDevice;

-> pDevice->DownloadBoot();

// RKDevice.cpp

-> int CRKDevice::DownloadBoot();

-> bool CRKDevice::Boot_VendorRequest( DWORD requestCode, PBYTE pBuffer, DWORD dwDataSize);

// RKComm.cpp

-> int CRKUsbComm::RKU_DeviceRequest(DWORD dwRequest, BYTE *lpBuffer, DWORD dwDataSize);

// RKU_DeviceRequest函数应该是出错位置

接下来的内容,只能靠猜测了:

不管是我们看到的过时代码里面的CRKUsbComm::RKU_DeviceRequest, 还是报错日志里面的Boot_VendorRequest-->DeviceIoControl, 从代码和函数名上看,猜测都是用来向USB设备发送数据的。

我们是不是可以大胆猜测这个时候出错,很可能是旧代码里面的libusb_control_transfer函数出错了。但是在新版应用里无法看到旧版代码里面的libusb_control_transfer的返回值,这个是真的遗憾。

而从报错日志上可以看到“Total(100354),Sended(0),bRet(1),err(0)”字样 ,猜测确实有Boot数据,但在通过usb写入设备的时候出错了。

这么猜测的话,usb驱动冲突或者有问题的可能性还真的很大。这也有一些文章中提到了。

RK3568 Maskrom提示“下载boot失败”的解决方法-CSDN博客文章浏览阅读1.5k次。长按“Maskrom”键,并同时按一下“RESET”键重启单板,设备将被RKDevTool识别,此时升级固件提示“下载boot失败”在uboot下可以正常下载,但进入Maskrom后设备能被正常识别但无法下载,提示“下载boot失败”(1)将PC上与RK相关的USB驱动统统卸载干净,可用DriverInstall.exe工具卸载;(3)管理员方式打开DriverInstall.exe,重新安装驱动;(2)断开设备,重启PC;(4)重新下载固件。_下载boot失败https://blog.csdn.net/t15900325509/article/details/144197764

RK3568下载BOOT失败的解决-CSDN博客文章浏览阅读7.7k次,点赞3次,收藏12次。RK3568使用瑞芯微官方工具,烧录固件或者擦除Flash时出现下载Boot失败。_下载boot失败https://blog.csdn.net/qq_19440071/article/details/129447541

那么解决思路就来了:

1、卸载冲突的驱动。

2、不使用Windows

但是问题也来了,卸载windows的usb驱动连我都搞不太明白。

而不用windows刷机,暂时还没试,但看了看项目底下的吐槽,瞬间我就不困了~~

因为手上的一台,已经刷好系统,暂时有用。我刚又在小黄鱼上又下单一台OEC-turbo,等这台来了,再继续研究。

唉!技术宅的乐趣,也就是这样了~

相关推荐