当前位置: 首页 > article >正文

关于瑞芯微开发工具(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	<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,等这台来了,再继续研究。

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

原文地址:https://blog.csdn.net/John_Lenon/article/details/146513493
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/600899.html

相关文章:

  • VUE3项目VITE打包优化
  • leetcode3.无重复字符的最长字串
  • G 2024hubei province 学习到的内容
  • 各类神经网络学习:(四)RNN 循环神经网络(下集),pytorch 版的 RNN 代码编写
  • AI+数字孪生:能碳管理中心的智能预测与动态优化
  • Python Django系列—多数据库
  • 干货分享|DeepSeek技术革命、算力范式重构与场景落地洞察
  • JavaEE企业级开发 延迟双删+版本号机制(乐观锁) 事务保证redis和mysql的数据一致性 示例
  • 常用的几种思维方式
  • 2024年MathorCup数学建模C题物流网络分拣中心货量预测及人员排班解题全过程文档加程序
  • Android 12.0 WiFi连接默认设置静态IP地址功能实现
  • 【免费】2007-2019年各省地方财政非税收入数据
  • 【从零实现Json-Rpc框架】- 第三方库介绍 - Muduo篇
  • python每日十题(9)
  • 怎么用 DeepSeek 替你做外贸
  • C++设计模式-装饰模式:从基本介绍,内部原理、应用场景、使用方法,常见问题和解决方案进行深度解析
  • 【C语言】信号
  • Linux防火墙基础部分Firewalld防火墙(小白入门级别)
  • Linux 配置时间服务器
  • 2025 JMeter平替的五款工具