昨天发了文章《网心云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 <LAYER 1-4> ERROR:Boot_VendorRequest-->DeviceIoControl failed,Total(100354),Sended(0),bRet(1),err(0)
20:30:36 790 <LAYER 1-4> 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("<LAYER %s> 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("<LAYER %s> 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("<LAYER %s> 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("<LAYER %s> 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("<LAYER %s> 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("<LAYER %s> 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,等这台来了,再继续研究。
唉!技术宅的乐趣,也就是这样了~