Rockchip u-boot阶段命令行和代码方式读取u盘内容并解析

U-boot是一个常用的嵌入式系统启动加载器,它可以支持多种设备和文件系统,比如USB、SATA、FAT、EXT等。在U-boot阶段,我们有时候需要从U盘/SD卡中读取一些文件,并对文件内容进行解析和处理,比如获取一些配置参数或者加载一些镜像。这篇博客将介绍两种在Rockchip u-boot阶段读取U盘内容并解析的方法:命令行方式和代码方式。

命令行方式

命令行方式是指在U-boot的控制台中输入一些命令来操作U盘和文件系统,这种方式比较简单和直观,但是功能有限,只能实现一些基本的操作。以下是命令行方式的具体步骤:

  1. 启动U-boot,并插入U盘到主板上。
  2. (必须)输入usb start命令来启动USB子系统,并检测U盘的设备信息。例如:
=> usb dev 0
USB is stopped. Please issue 'usb start' first.
//必须先执行usb start 不然执行其他usb xxx命令是不能用的
=> usb start
starting USB...
Bus dwc3@fcc00000: Register 2000140 NbrPorts 2
Starting the controller
USB XHCI 1.10
Bus dwc3@fd000000: Register 2000140 NbrPorts 2
Starting the controller
USB XHCI 1.10
Bus usb@fd800000: USB EHCI 1.00
Bus usb@fd840000: USB OHCI 1.0
Bus usb@fd880000: USB EHCI 1.00
Bus usb@fd8c0000: USB OHCI 1.0
scanning bus dwc3@fcc00000 for devices... 1 USB Device(s) found
scanning bus dwc3@fd000000 for devices... 2 USB Device(s) found
scanning bus usb@fd800000 for devices... 1 USB Device(s) found
scanning bus usb@fd840000 for devices... 1 USB Device(s) found
scanning bus usb@fd880000 for devices... 1 USB Device(s) found
scanning bus usb@fd8c0000 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 1 Storage Device(s) found
  1. 输入usb info命令来查看U盘的详细信息,包括设备号、厂商、产品、类型和容量等。例如:
=> usb info
1: Hub,  USB Revision 3.0
 - U-Boot XHCI Host Controller 
 - Class: Hub
 - PacketSize: 512  Configurations: 1
 - Vendor: 0x0000  Product 0x0000 Version 1.0
   Configuration: 1
   - Interfaces: 1 Self Powered 0mA
     Interface: 0
     - Alternate Setting 0, Endpoints: 1
     - Class Hub
     - Endpoint 1 In Interrupt MaxPacket 8 Interval 255ms

1: Hub,  USB Revision 3.0
 - U-Boot XHCI Host Controller 
 - Class: Hub
 - PacketSize: 512  Configurations: 1
 - Vendor: 0x0000  Product 0x0000 Version 1.0
   Configuration: 1
   - Interfaces: 1 Self Powered 0mA
     Interface: 0
     - Alternate Setting 0, Endpoints: 1
     - Class Hub
     - Endpoint 1 In Interrupt MaxPacket 8 Interval 255ms

2: Mass Storage,  USB Revision 2.0
 - SanDisk Cruzer Glide 20042605620A22C31651
 - Class: (from Interface) Mass Storage
 - PacketSize: 64  Configurations: 1
 - Vendor: 0x0781  Product 0x5575 Version 1.38
   Configuration: 1
   - Interfaces: 1 Bus Powered 200mA
     Interface: 0
     - Alternate Setting 0, Endpoints: 2
     - Class Mass Storage, Transp. SCSI, Bulk only
     - Endpoint 1 In Bulk MaxPacket 512
     - Endpoint 2 Out Bulk MaxPacket 512

1: Hub,  USB Revision 2.0
 - u-boot EHCI Host Controller 
 - Class: Hub
 - PacketSize: 64  Configurations: 1
 - Vendor: 0x0000  Product 0x0000 Version 1.0
   Configuration: 1
   - Interfaces: 1 Self Powered 0mA
     Interface: 0
     - Alternate Setting 0, Endpoints: 1
     - Class Hub
     - Endpoint 1 In Interrupt MaxPacket 8 Interval 255ms

1: Hub,  USB Revision 1.10
 -  U-Boot Root Hub 
 - Class: Hub
 - PacketSize: 8  Configurations: 1
 - Vendor: 0x0000  Product 0x0000 Version 0.0
   Configuration: 1
   - Interfaces: 1 Self Powered 0mA
     Interface: 0
     - Alternate Setting 0, Endpoints: 1
     - Class Hub
     - Endpoint 1 In Interrupt MaxPacket 2 Interval 255ms

1: Hub,  USB Revision 2.0
 - u-boot EHCI Host Controller 
 - Class: Hub
 - PacketSize: 64  Configurations: 1
 - Vendor: 0x0000  Product 0x0000 Version 1.0
   Configuration: 1
   - Interfaces: 1 Self Powered 0mA
     Interface: 0
     - Alternate Setting 0, Endpoints: 1
     - Class Hub
     - Endpoint 1 In Interrupt MaxPacket 8 Interval 255ms

1: Hub,  USB Revision 1.10
 -  U-Boot Root Hub 
 - Class: Hub
 - PacketSize: 8  Configurations: 1
 - Vendor: 0x0000  Product 0x0000 Version 0.0
   Configuration: 1
   - Interfaces: 1 Self Powered 0mA
     Interface: 0
     - Alternate Setting 0, Endpoints: 1
     - Class Hub
     - Endpoint 1 In Interrupt MaxPacket 2 Interval 255ms

=> usb storage
  Device 0: Vendor: SanDisk  Rev: 1.26 Prod: Cruzer Glide    
            Type: Removable Hard Disk
            Capacity: 7633.5 MB = 7.4 GB (15633408 x 512)
=>
  1. 输入part usb 命令来查看U盘的分区表,包括分区号、起始扇区、扇区数、UUID和类型等。例如:
=> usb part

Partition Map for USB device 0  --   Partition Type: DOS

Part	Start Sector	Num Sectors	UUID		Type
  4	256       	15633152  	cad4ebea-04	0c Boot
  1. 输入fs_set_blk_dev <dev[:part]> 命令来设置U盘为当前的设备和文件系统,其中interface为usb,dev为设备号,part为分区号,fstype为文件系统类型,可以是FS_TYPE_ANY、FS_TYPE_FAT、FS_TYPE_EXT等。例如:
=> fs_set_blk_dev usb 0:4 FS_TYPE_ANY
  1. 输入fs_size 命令来获取U盘中某个文件的大小,并赋值给一个变量。例如:
=> fs_size uboot_file file_size
24 bytes read in 22 ms (1000 Bytes/s)
  1. 输入fatload usb 0:4 <addr> <filename>命令来从U盘读取某个文件的内容,并存储到指定的内存地址。其中filename为文件名,addr为内存地址。例如:
=> fatload usb 0:4 0x007ef000 uboot_file
reading uboot_file
24 bytes read in 22 ms (1000 Bytes/s)
  1. 输入md.b <addr> <len>命令来查看内存中的文件内容,其中addr为内存地址,len为要查看的字节数。例如:
=> md.b 0x007ef000 512
007ef000: 6c 63 64 5f 78 3d 31 39 32 30 3b 0d 0a 6c 63 64    lcd_x=1920;..lcd
007ef010: 5f 79 3d 31 30 38 30 3b ff ff ff ff ff ff ff ff    _y=1080;........
007ef020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
007ef030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
007ef040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
007ef050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
  1. 根据文件内容的格式和意义,进行相应的解析和处理。例如,如果文件内容是一些键值对,我们可以使用strtok函数来分割字符串,并使用strtol函数来转换数值。例如:
char *ptr_x = strtok(buffer, "=");
char *ptr_y = strtok(NULL, "=");
long lcd_x = strtol(ptr_x, NULL, 10);
long lcd_y = strtol(ptr_y, NULL, 10);
printf("lcd_x = %ld, lcd_y = %ld\n", lcd_x, lcd_y);

代码方式

代码方式是指在U-boot的源码中编写一些函数或命令来操作U盘和文件系统,这种方式比较灵活和强大,但是需要一定的编程知识和编译环境。以下是代码方式的具体步骤:

  1. 进入Rockchip u-boot的源码配置和编译u-boot。
  2. 在drivers/usb/gadget目录下创建一个新的C文件,比如usb_file_parser.c,并在其中包含一些必要的头文件,比如common.h、command.h、fs.h、usb.h等。
  3. 在usb_file_parser.c文件中定义一个新的函数,比如do_read_uboot_file,并在其中实现从U盘中读取并解析文件的逻辑。可以参考以下链接中的示例代码来实现这个函数。
  4. 在usb_file_parser.c文件中定义一个新的命令结构体,比如read_uboot_file_cmd,并在其中指定命令名、参数个数、重复性、函数指针、描述和用法等。
  5. 在usb_file_parser.c文件中使用U_BOOT_CMD宏来注册这个新的命令,并将其添加到u-boot命令列表中。
  6. 在drivers/usb/gadget/Makefile文件中添加usb_file_parser.o到obj-y变量中,以便编
    重新编译u-boot,并烧录到主板上。

```bash
#include <common.h>
#include <command.h>
#include <fs.h>
#include <usb.h>
#include <stdlib.h>

#define FILE_PATH "uboot_file"
#define BUFFER_SIZE 512

int do_read_uboot_file(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
    
    
    char buffer[BUFFER_SIZE + 1];
    loff_t file_size, actread;
    int ret;
    // 启动USB子系统
    //usb_stop();
   // usb_start(); //没有这个 
    // 设置U盘为当前设备和文件系统,根据实际情况修改设备号和分区号
    if (fs_set_blk_dev("usb", "0:4", FS_TYPE_ANY)) {
    
    
        printf("Error setting block device.\n");
        return 1;
    }

    // 获取文件大小
    if (fs_size(FILE_PATH, &file_size) < 0) {
    
    
        printf("Error getting size of %s\n", FILE_PATH);
        return 1;
    }

    // 确保不尝试读取超出文件大小的内容
    if (file_size > BUFFER_SIZE) {
    
    
        printf("File is larger than buffer. Adjust BUFFER_SIZE.\n");
        return 1;
    }


    // 读取文件,选择一个合适的内存地址,避免与其他内存区域冲突
    actread = 0;
    //ret = fs_read(FILE_PATH, (ulong)0x60000000, 0, 0, &actread); // 修改这一行
   // ret = fs_read(FILE_PATH, (ulong)buffer, 0, file_size, &actread);
   //ret = fs_read(FILE_PATH, (ulong)0x60000000, 0, file_size, &actread);
    ret = fs_read(FILE_PATH, (ulong)0x7ef000, 0, file_size, &actread);
    if (ret) {
    
    
        printf("fs_read returned error code: %d\n", ret);
    }
    if (actread != file_size) {
    
    
        printf("Expected to read %lld bytes but read %lld bytes\n", file_size, actread);
    }
    if (ret || actread != file_size) {
    
    
        printf("Error reading %s\n", FILE_PATH);
        return 1;
    }

    // 确保字符串以null结尾
    buffer[actread] = '\0';

    // 解析文件内容
    char *ptr_x = strstr(buffer, "lcd_x=");
    char *ptr_y = strstr(buffer, "lcd_y=");
    if (ptr_x && ptr_y) {
    
    
        int lcd_x = simple_strtoul(ptr_x + 6, NULL, 10);
        int lcd_y = simple_strtoul(ptr_y + 6, NULL, 10);
        printf("lcd_x = %d, lcd_y = %d\n", lcd_x, lcd_y);
    } else {
    
    
        printf("Failed to parse the file\n");
    }
    return 0;
}

U_BOOT_CMD(
    read_uboot_file,    // command name
    1,                  // maxargs
    1,                  // repeatable
    do_read_uboot_file, // command function
    "Read and parse the uboot_file from USB",  // description
    "This command reads the uboot_file from USB and parses lcd_x and lcd_y values"  // usage
);

  1. 在增加fs.c的fs_read函数中增加更多的printf语句,以获取更详细的调试信息。
int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
            loff_t *actread)
{
    
    
        struct fstype_info *info = fs_get_info(fs_type);
        void *buf;
        int ret;

        // 增加的打印
        printf("fs_read called with:\n");
        printf("filename: %s\n", filename);
        printf("addr: %lx\n", addr);
        printf("offset: %lld\n", offset);
        printf("len: %lld\n", len);

        buf = map_sysmem(addr, len);
        if (!buf) {
    
    
            printf("Error mapping memory at address %lx\n", addr);
            return -1;
        }

        ret = info->read(filename, buf, offset, len, actread);

        // 增加的打印
        if (ret) {
    
    
            printf("info->read returned error code: %d\n", ret);
        }
        if (actread && *actread != len) {
    
    
            printf("Expected to read %lld bytes but read %lld bytes\n", len, *actread);
        }

        unmap_sysmem(buf);

        /* If we requested a specific number of bytes, check we got it */
        if (ret == 0 && len && *actread != len)
                printf("** %s shorter than offset + len **\n", filename);
        fs_close();

        return ret;
}
  1. 启动u-boot,并插入U盘到主板上。
  2. 输入read_uboot_file命令来执行从U盘中读取并解析文件的函数,并查看输出结果。例如:
//必须先执行usb start 不然执行其他usb xxx命令是不能用的
=> usb start
starting USB...
Bus dwc3@fcc00000: Register 2000140 NbrPorts 2
Starting the controller
USB XHCI 1.10
Bus dwc3@fd000000: Register 2000140 NbrPorts 2
Starting the controller
USB XHCI 1.10
Bus usb@fd800000: USB EHCI 1.00
Bus usb@fd840000: USB OHCI 1.0
Bus usb@fd880000: USB EHCI 1.00
Bus usb@fd8c0000: USB OHCI 1.0
scanning bus dwc3@fcc00000 for devices... 1 USB Device(s) found
scanning bus dwc3@fd000000 for devices... 2 USB Device(s) found
scanning bus usb@fd800000 for devices... 1 USB Device(s) found
scanning bus usb@fd840000 for devices... 1 USB Device(s) found
scanning bus usb@fd880000 for devices... 1 USB Device(s) found
scanning bus usb@fd8c0000 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 1 Storage Device(s) found
//----------------------
//uboot 反正目前一直是下面这个打印 能读到文件大小,但就是代码读不到文件内容。
//真™快吐了,折腾了我将近4小时 后面有时间在研究,
=> read_uboot_file 
fs_read called with:
filename: uboot_file
addr: 7ef000
offset: 0
len: 24
info->read returned error code: -1
Expected to read 24 bytes but read 0 bytes
fs_read returned error code: -1
1 Expected to read 24 bytes but read 0 bytes
Error reading uboot_file
=> 
//代码正确打印应该是
reading uboot_file
fs_read called with:
filename: uboot_file
addr: 7ef000
offset: 0
len: 0
reading uboot_file
Expected to read 0 bytes but read 24 bytes
lcd_x = 1920, lcd_y = 1080

//命令行正确打印
=> fatload usb 0:4 0x007ef000 uboot_file
fs_read called with:
filename: uboot_file
addr: 7ef000
offset: 0
len: 0
reading uboot_file
Expected to read 0 bytes but read 24 bytes
=> md.b 0x007ef000 512
007ef000: 6c 63 64 5f 78 3d 31 39 32 30 3b 0d 0a 6c 63 64    lcd_x=1920;..lcd
007ef010: 5f 79 3d 31 30 38 30 3b ff ff ff ff ff ff ff ff    _y=1080;........
007ef020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
007ef030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
007ef040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
007ef050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................

20230828更新
我换了个思路 , 既然fs_read函数死活读不到我就(参考uboot 读logo的方式)直接通过run_command读 , 果然成功了。
但目前有个缺点就是依然需要手动执行usb start , 通过run_command("usb start", 0)会提示Bad device usb 0
在这里插入图片描述

=> usb start
starting USB...
Bus dwc3@fcc00000: Register 2000140 NbrPorts 2
Starting the controller
USB XHCI 1.10
Bus dwc3@fd000000: Register 2000140 NbrPorts 2
Starting the controller
USB XHCI 1.10
Bus usb@fd800000: USB EHCI 1.00
Bus usb@fd840000: USB OHCI 1.0
Bus usb@fd880000: USB EHCI 1.00
Bus usb@fd8c0000: USB OHCI 1.0
scanning bus dwc3@fcc00000 for devices... 1 USB Device(s) found
scanning bus dwc3@fd000000 for devices... 2 USB Device(s) found
scanning bus usb@fd800000 for devices... 1 USB Device(s) found
scanning bus usb@fd840000 for devices... 1 USB Device(s) found
scanning bus usb@fd880000 for devices... 1 USB Device(s) found
scanning bus usb@fd8c0000 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 1 Storage Device(s) found
=> read_uboot_file 
fs_read called with:
filename: uboot_file
addr: 7ef000
offset: 0
len: 0
reading uboot_file
Expected to read 0 bytes but read 24 bytes
24 bytes read in 32 ms (0 Bytes/s)
lcd_x = 1920, lcd_y = 1080

#include <common.h>
#include <command.h>
#include <fs.h>
#include <usb.h>
#include <stdlib.h>

#define FILE_PATH "uboot_file"
#define BUFFER_SIZE 512

int do_read_uboot_file(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
    
    
    //char buffer[BUFFER_SIZE + 1]; //这个一定是要选一个可用的地址 不能这么干 可能读不到
    char *buffer = (char *)0x007ef000;  // 直接使用该地址
    char cmd[BUFFER_SIZE] = {
    
    "0"}; // 添加命令缓冲区

    // 初始化USB
    /*if (run_command("usb start", 0)) {
    
    
        printf("Error initializing USB.\n");
        return 1;
    }*/

    // 使用fatload命令读取文件到指定地址
    sprintf(cmd, "fatload usb 0:4 0x007ef000 %s", FILE_PATH);
    if (run_command(cmd, 0)) {
    
    
        printf("Error reading %s using fatload\n", FILE_PATH);
        return 1;
    }

    // 解析文件内容
    char *ptr_x = strstr(buffer, "lcd_x=");
    char *ptr_y = strstr(buffer, "lcd_y=");
    if (ptr_x && ptr_y) {
    
    
        int lcd_x = simple_strtoul(ptr_x + 6, NULL, 10);
        int lcd_y = simple_strtoul(ptr_y + 6, NULL, 10);
        printf("lcd_x = %d, lcd_y = %d\n", lcd_x, lcd_y);
    } else {
    
    
        printf("Failed to parse the file\n");
    }
    return 0;
}

U_BOOT_CMD(
    read_uboot_file,    // command name
    1,                  // maxargs
    1,                  // repeatable
    do_read_uboot_file, // command function
    "Read and parse the uboot_file from USB",  // description
    "This command reads the uboot_file from USB and parses lcd_x and lcd_y values"  // usage
);

总结

这篇博客介绍了两种在Rockchip u-boot阶段读取U盘内容并解析的方法:命令行方式和代码方式。命令行方式比较简单和直观,但是功能有限,只能实现一些基本的操作。

猜你喜欢

转载自blog.csdn.net/SHH_1064994894/article/details/132515787