当前位置: 首页 > 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,等这台来了,再继续研究。

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

相关文章:

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

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

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

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

浅谈 Vue3 中的设计模式

设计模式是软件开发中的一种最佳实践&#xff0c;它提供了解决特定问题的通用解决方案。通过合理运用设计模式&#xff0c;可以提高代码的可维护性、可扩展性和可读性。在 Vue3 的源码中&#xff0c;设计模式被广泛应用于各个模块中&#xff0c;充分体现了其在现代前端框架中的…...

Unix Domain Socket、IPC、RPC与gRPC的深度解析与实战

Unix Domain Socket、IPC、RPC与gRPC的深度解析与实战 引言 在分布式系统和本地服务通信中&#xff0c;进程间通信&#xff08;IPC&#xff09;与远程过程调用&#xff08;RPC&#xff09;是核心能力。本文将深入剖析 Unix Domain Socket&#xff08;UDS&#xff09;、IPC、RP…...

07_JavaScript函数作用域_递归

目录 一、作用域&#xff08;重点&#xff09; 二、变量的使用规则 &#xff08;重点&#xff09; 2.1 访问规则 2.2 赋值规则 三、递归函数 &#xff08;难点&#xff09; 了解 四、对象 4.1 对象的创建 一、作用域&#xff08;重点&#xff09; 什么是作用域 ? 作用…...

.gitignore使用指南

.gitignore使用指南 目录 什么是.gitignore为什么需要.gitignore如何创建.gitignore文件.gitignore文件的语法规则 忽略单个文件忽略目录忽略特定类型的文件不忽略特定文件或目录递归匹配 示例.gitignore文件注意事项更多特殊场景匹配规则 忽略多个特定后缀的文件忽略特定目录…...

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

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

深入解析 Spring Framework 5.1.8.RELEASE 的源码目录结构

深入解析 Spring Framework 5.1.8.RELEASE 的源码目录结构 1. 引言 Spring Framework 是 Java 领域最流行的企业级开发框架之一&#xff0c;广泛用于 Web 开发、微服务架构、数据访问等场景。本文将深入解析 Spring Framework 5.1.8.RELEASE 的源码目录结构&#xff0c;帮助开…...

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;用来…...

[数据结构] 动态顺序表应用

可扩容顺序表顺序表 SeqList.hSeqList.cTest.c 动态顺序表能够根据数据存储的需要动态地管理内存空间。 SeqList.h #include<stdio.h> #include<stdlib.h>//静态顺序表 //小了不够用&#xff0c;多了浪费 //#define N 10 //typedef int SLDatatype; //struct SeqL…...

MinIO-对象存储方案

MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。 MinIO是一个非常轻量的服务…...

装饰器模式 (Decorator Pattern)

装饰器模式 (Decorator Pattern) 是一种结构型设计模式,它动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式相比生成子类更为灵活。 一、基础 1 意图 动态地给一个对象添加一些额外的职责。 就增加功能来说,装饰器模式相比生成子类更为灵活。 2 适用场景 当…...

手动配置树莓派wifi联网连接热点手机热点

手动配置树莓派wifi联网连接热点 修改wifi配置文件: 运行命令: sudo nano /etc/wpa_supplicant/wpa_supplicant.conf 在文件中添加无线网配置信息: ctrl_interfaceDIR/var/run/wpa_supplicant GROUPnetdev update_config1 countryCN network{ ssid”你的无线网名字” psk”…...

【学习笔记】麦肯锡《超级智能体:赋能人们释放人工智能的全部潜力》

麦肯锡《超级智能体&#xff1a;赋能人们释放人工智能的全部潜力》报告的学习笔记&#xff1a; 报告背景与意义 • 科技发展趋势&#xff1a;随着人工智能技术的飞速发展&#xff0c;其在各行业的应用逐渐深入&#xff0c;麦肯锡的这份报告正是基于这一背景&#xff0c;旨在深入…...

ENSP学习day9

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

文章记单词 | 第2篇(六级)

一&#xff0c;单词释义 story&#xff1a;名词&#xff08;n.&#xff09;故事&#xff1b;小说&#xff1b;&#xff08;真实情况的&#xff09;叙述&#xff0c;描述&#xff1b;楼层&#xff08;美语写法&#xff0c;英式英语为 storey&#xff09;stress&#xff1a;名词…...

【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…...

团体协作项目总结Git

使用Git开放时候发现本地, 有些代码并没有被拉取到本地仓库, 又不想再commit一次, 这时候我就想到了 git commit --amend 合并提交 git commit --amend 修改git提交记录用法详解 可以将本次提交记录合并到上一次合并提交 git commit --amendgit rebase -i master^^ // 假设我…...

solana/web3.js 2.0:Solana 转账全流程解析

Solana 区块链以高吞吐量和低交易成本&#xff0c;已成为开发者的热门选择。而 solana /web3.js 2.0 作为最新一代 JavaScript 库&#xff0c;为与 Solana 网络交互提供了更高效、模块化的工具。本文将深入剖析如何使用 solana /web3.js 2.0 实现 Solana 区块链上的转账操作&am…...

数模转换电路(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…...

PHP接口开发:从基础到高级的全面指南

一、接口基础与核心概念(约800字) 1.1 接口的本质定义 在PHP中,接口(Interface)是一种特殊的抽象结构,它通过interface关键字定义一组方法的契约规范,不包含具体实现。这种设计强制实现类必须遵循统一的调用标准,如: interface PaymentGateway {public function proc…...