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

news2025/3/26 9:59:37

昨天发了文章《网心云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,等这台来了,再继续研究。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2321893.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

web爬虫笔记:js逆向案例十一 某数cookie(补环境流程)

web爬虫笔记:js逆向案例十一 某数cookie(补环境流程) 一、获取网页数据请求流程 二、目标网址、cookie生成(逐步分析) 1、目标网址:aHR0cHM6Ly9zdWdoLnN6dS5lZHUuY24vSHRtbC9OZXdzL0NvbHVtbnMvNy9JbmRleC5odG1s 2、快速定位入口方法 1、通过脚本监听、hook_cookie等操作可…

Excel多级联动下拉菜单的自动化设置(使用Python中的openpyxl模块)

1 主要目的 在Excel中&#xff0c;经常会遇到需要制作多级联动下拉菜单的情况&#xff0c;要求单元格内填写的内容只能从指定的多个选项中进行选择&#xff0c;并且需要设置多级目录&#xff0c;其中下级目录的选项内容要根据上级目录的填写内容确定&#xff0c;如下图所示&am…

excalidraw画图工具——背景画布有无格子设置

服啦找了大半天&#xff0c;愣是没找到 toggle grid &#xff1a; 切换格子… Excalidraw的背景格子 只要右键&#xff0c;将这个勾取消就好了&#xff1f;

计算机组成原理———I\O系统精讲<1>

本篇文章主要介绍输入输出系统的发展概况 一.输入输出系统的发展概况 1.早期阶段 该阶段的特点是I/O设备与主存交换信息都必须通过CPU 当时的I/O设备有如下几个特点&#xff1a; &#xff08;1&#xff09;每个I\O设备都必须配有一套独立的逻辑电路与CPU相连&#xff0c;用来…

ENSP学习day9

ACL访问控制列表实验 ACL&#xff08;Access Control List&#xff0c;访问控制列表&#xff09;是一种用于控制用户或系统对资源&#xff08;如文件、文件夹、网络等&#xff09;访问权限的机制。通过ACL&#xff0c;系统管理员可以定义哪些用户或系统可以访问特定资源&#x…

【C++动态规划 数学】1039. 多边形三角剖分的最低得分|2130

本文涉及知识点 C动态规划 数学 LeetCode1039. 多边形三角剖分的最低得分 你有一个凸的 n 边形&#xff0c;其每个顶点都有一个整数值。给定一个整数数组 values &#xff0c;其中 values[i] 是第 i 个顶点的值&#xff08;即 顺时针顺序 &#xff09;。 假设将多边形 剖分 …

5.go切片和map

切片的概念 数组和切片相比较切片的长度是不固定的&#xff0c;可以追加元素&#xff0c;在追加时可能会使切片的容量增大&#xff0c;所以可以将切片理解成 "动态数组"&#xff0c;但是&#xff0c;它不是数组&#xff0c;而是构建在数组基础上的更高级的数据结构。…

【Linux网络-多路转接select】

代码&#xff1a;https://gitee.com/nanyi-c/linux/tree/master/day50 一、I/O多路转接之select 1.初始select 系统提供select函数来实现多路复用输入/输出模型 select系统调用是用来让我们的程序监视多个文件描述符的状态变化的程序会停在select这里等待&#xff0c;直到被…

cmd命令查看电脑的CPU、内存、存储量

目录 获取计算机硬件的相关信息的命令分别的功能结果展示结果说明获取计算机硬件的相关信息的命令 wmic cpu get name wmic memorychip get capacity wmic diskdrive get model,size,mediaType分别的功能 获取计算机中央处理器(CPU)的名称 获取计算机内存(RAM)芯片的容量…

LVS的 NAT 模式实现 3 台RS的轮询访问

使用LVS的 NAT 模式实现 3 台RS的轮询访问 1.配置 RS&#xff08;NAT模式&#xff09;2. 配置 LVS 主机&#xff08;仅主机、NAT模式&#xff09;2.1 配置仅主机网卡&#xff08;192.168.66.150/24 VIP &#xff09;2.2 配置 NAT 网卡&#xff08;192.168.88.6/24 DIP&#xff…

phpcms版AI自动发文插件,自动创作,自动配图,自动发布,支持多种大模型

phpcms版本的AI自动发文插件1.0.0版&#xff0c;支持自动写文章&#xff0c;自动配图&#xff0c;自动发布。目前支持DeepSeek&#xff0c;豆包&#xff0c;通义千问&#xff0c;文心一言&#xff0c;讯飞星火&#xff0c;KIMI&#xff0c;腾讯混元登大模型AI。同时有自定义字段…

C语言判断闰年相关问题

一、简单闰年问题引入 写一个判断年份是否为闰年的程序? 运行结果: 二、闰年问题进阶 使用switch语句根据用户输入的年份和月份,判断该月份有多少天? 第一种写法(判断年份写在switch的case的里面): 运行结果: 第二种解法(先判断闰年): 运行结果: 三、补充 switch中的ca…

数模转换电路(D/A转换器)

将数字信号转换成模拟信号称为数/模转换, 简称D/A&#xff08;Digital to Analog&#xff09;转换&#xff0c;实现 D/A 转换的器件称为D/A转换器&#xff0c;简称 DAC&#xff08;Digital-Analog Converter&#xff09;。 将模拟信号转换成数字信号称为模/数转换, 简称A/D&a…

网络基础-路由器和交换机工作配置

三、路由器和交换机的工作原理配置以及华为体系下的小型网络的搭建 3.1路由基础 3.1.1数据转发 通过链路层交换机和网络层路由器进行数据转发 交换机&#xff08;链路层&#xff09;mac地址表的数据转发路由器&#xff08;网络层&#xff09; ip路由表的数据转发 隔离广播域…

uv包简单使用案例

uv由Charlie Marsh开发&#xff0c;是Astral Tool的一个快速Python包安装器和解析器。它类似于pip和pip-tools&#xff0c;但速度更快。此外&#xff0c;uv还支持虚拟环境管理&#xff0c;替代venv和virtualenv。 参考&#xff1a;https://github.com/astral-sh/uv 安装&#x…

JAVA学习*String类

String类 基本知识 String类的构造方法 String类的构造方法有很多&#xff0c;我们需要掌握常见的构造方法&#xff0c;来赋初识值。 1、new一个String类的对象 String name new String("张三");2、使用字符串常量进行赋值 String name "张三";相当…

Java IO框架体系深度解析:从四基类到设计模式实践

Java IO框架体系深度解析&#xff1a;从四基类到设计模式实践 一、IO流体系架构总览 1.1 四基类设计哲学 Java IO框架以InputStream、OutputStream、Reader、Writer四个抽象类为根基&#xff0c;构建了完整的流式IO体系。这种设计体现了以下核心原则&#xff1a; 抽象分层&a…

【读书笔记】华为《从偶然到必然》

note 华为的成功并非偶然&#xff0c;而是通过IPD体系、投资组合管理、平台战略等系统性工具&#xff0c;将研发投资转化为可持续的商业竞争力。书中强调的“管理即内部因素”理念&#xff0c;揭示了企业规模扩张与管理能力匹配的深层规律&#xff0c;为高科技企业提供了可借鉴…

failed to load steamui.dll”错误:Steam用户的高频崩溃问题解析

当你满心欢喜地双击 Steam 图标&#xff0c;准备进入游戏世界时&#xff0c;屏幕上突然弹出 “failed to load steamui.dll” 的刺眼提示——这是全球数百万 Steam 用户最不愿见到的错误之一。作为 Steam 客户端的核心界面动态链接库文件&#xff0c;steamui.dll 的缺失或损坏会…

Linux多线程详解

Linux多线程详解 一、Linux多线程概念1.1 什么是线程1.2 进程和线程1.3 进程的多个线程共享1.4 进程和线程的关系 二、Linux线程控制2.1 POSIX线程库2.2 线程创建2.3 获取线程ID pthread_self2.4 线程等待pthread_join2.5 线程终止2.6 线程栈 && pthread_t2.7 线程的局…