uboot环境变量分析

2023-10-31

项目情景

最近我在一个新平台的开发过程中遇到烧录问题. 具体的问题是使用原厂提供的烧录脚本烧录成功,但是固件却没有更新.
其中kernel和dtb烧录指令如下:

adnl.exe Partition -M mem -P 0x1000000 -F linux.dtb
adnl.exe Partition -M mem -P 0x1000 -F boot.img
adnl.exe oem "run storeargs;run bootcmd"

我老想着走捷径解决问题,不想去看代码.折腾到筋疲力尽,最后我还是妥协了,好好分析了代码,总结了原因, 需要解决两个疑问点:

  1. 烧录的dtb的地址
  2. 烧录内核的格式和地址

分析总结

遇到烧录后固件没更新的问题,第一个能想到的是烧录地址与启动地址不匹配.具体从uboot的环境变量开始分析问题.
在设备上电后,首先敲回车,进入uboot终端模式,敲入printenv,回车,查看如下:

ad402# print
EnableSelinux=enforcing
Irq_check_en=0
active_slot=normal
arch=arm
baudrate=115200
bcb_cmd=get_valid_slot;
board=a1_ad402
board_name=a1_ad402
boot_part=boot
bootargs=init=/init console=ttyS0,115200 no_console_suspend earlycon=aml_uart,0xfe002000 ramoops.pstore_en=1 ramoops.record_size=0x8000 ramoops.console_size=0x4000 rootfstype=ramfs otg_device=1 logo=osd0,loaded,0x00300000 vout=1080p60hz,enable panel_type=lcd_1 hdmitx=, hdmimode=1080p60hz frac_rate_policy=1 hdmi_read_edid= cvbsmode=576cvbs osd_reverse=0 video_reverse=0 irq_check_en=0 androidboot.selinux=enforcing androidboot.firstboot=1 jtag=disable androidboot.hardware=amlogic androidboot.wificountrycode=US androidboot.serialno=1234567890
bootcmd=run storeboot
bootdelay=2
bootm_low=0
bootm_size=8000000
cmdline_keys=setenv usid 1234567890; setenv region_code US;if keyman init 0x1234; then if keyman read usid ${loadaddr} str; then fi;if keyman read region_code ${loadaddr} str; then fi;if keyman read mac ${loadaddr} str; then setenv bootargs ${bootargs} mac=${mac} androidboot.mac=${mac};fi;if keyman read deviceid ${loadaddr} str; then setenv bootargs ${bootargs} androidboot.deviceid=${deviceid};fi;if keyman read mac_wifi ${loadaddr} str; then setenv bootargs ${bootargs} mac_wifi=${mac_wifi} androidboot.mac_wifi=${mac_wifi};fi;if keyman read mac_bt ${loadaddr} str; then setenv bootargs ${bootargs} mac_bt=${mac_bt} androidboot.mac_bt=${mac_bt};fi;fi;setenv bootargs ${bootargs} androidboot.wificountrycode=${region_code};setenv bootargs ${bootargs} androidboot.serialno=${usid};setenv serial ${usid}; setenv serial# ${usid};
common_dtb_load=imgread dtb _aml_dtb ${dtb_mem_addr}
cpu=armv8
cvbs_drv=0
cvbsmode=576cvbs
display_bpp=16
display_color_bg=0
display_color_fg=0xffff
display_color_index=16
display_height=1080
display_layer=osd0
display_width=1920
dtb_mem_addr=0x01000000
fatload_dev=usb
fb_addr=0x00300000
fb_height=1080
fb_width=1920
fdt_high=0x20000000
fdtaddr=1000000
fdtcontroladdr=fff2be40
firstboot=1
frac_rate_policy=1
fs_type=rootfstype=ramfs
gatewayip=10.18.9.1
get_os_type=if store read ${os_ident_addr} ${boot_part} 0 0x1000; then os_ident ${os_ident_addr}; fi
hdmimode=1080p60hz
hostname=arm_gxbb
initargs=init=/init console=ttyS0,115200 no_console_suspend earlycon=aml_uart,0xfe002000 ramoops.pstore_en=1 ramoops.record_size=0x8000 ramoops.console_size=0x4000 
ipaddr=10.18.9.97
jtag=disable
loadaddr=0x00020000
loadaddr_kernel=0x00020000
loadaddr_rtos=0x00001000
netmask=255.255.255.0
os_ident_addr=0x00500000
osd_reverse=0
otg_device=1
outputmode=1080p60hz
panel_type=lcd_1
preboot=run bcb_cmd; run upgrade_check;run storeargs;
recovery_from_fat_dev=setenv loadaddr ${loadaddr_kernel};if fatload ${fatload_dev} 0 ${loadaddr} aml_autoscript; then autoscr ${loadaddr}; fi;if fatload ${fatload_dev} 0 ${loadaddr} recovery.img; then if fatload ${fatload_dev} 0 ${dtb_mem_addr} dtb.img; then echo ${fatload_dev} dtb.img loaded; fi;bootm ${loadaddr};fi;
recovery_from_flash=setenv loadaddr ${loadaddr_kernel};setenv bootargs ${bootargs} aml_dt=${aml_dt} recovery_part={recovery_part} recovery_offset={recovery_offset};if imgread dtb recovery ${dtb_mem_addr}; then else echo restore dtb; run common_dtb_load;fi;if imgread kernel ${recovery_part} ${loadaddr} ${recovery_offset}; then bootm ${loadaddr}; fi;
recovery_from_udisk=setenv fatload_dev usb;if usb start 0; then run recovery_from_fat_dev; fi;
recovery_offset=0
recovery_part=recovery
region_code=US
sdcburncfg=aml_sdc_burn.ini
serial=1234567890
serial#=1234567890
serverip=10.18.9.113
soc=a1
stderr=serial@2000
stdin=serial@2000
stdout=serial@2000
storeargs=setenv bootargs ${initargs} ${fs_type} otg_device=${otg_device} logo=${display_layer},loaded,${fb_addr} vout=${outputmode},enable panel_type=${panel_type} hdmitx=${cecconfig},${colorattribute} hdmimode=${hdmimode} frac_rate_policy=${frac_rate_policy} hdmi_read_edid=${hdmi_read_edid} cvbsmode=${cvbsmode} osd_reverse=${osd_reverse} video_reverse=${video_reverse} irq_check_en=${Irq_check_en}  androidboot.selinux=${EnableSelinux} androidboot.firstboot=${firstboot} jtag=${jtag}; setenv bootargs ${bootargs} androidboot.hardware=amlogic;run cmdline_keys;
storeboot=run get_os_type;if test ${os_type} = rtos; then setenv loadaddr ${loadaddr_rtos};store read ${loadaddr} ${boot_part} 0 0x400000;bootm ${loadaddr};else if test ${os_type} = kernel; then if fdt addr ${dtb_mem_addr}; then else echo retry common dtb; run common_dtb_load; fi;setenv loadaddr ${loadaddr_kernel};if imgread kernel ${boot_part} ${loadaddr}; then bootm ${loadaddr}; fi;else echo wrong OS format ${os_type}; fi;fi;echo try upgrade as booting failure; run update;
switch_bootmode=get_rebootmode;if test ${reboot_mode} = factory_reset; then run recovery_from_flash;else if test ${reboot_mode} = update; then run update;else if test ${reboot_mode} = quiescent; then setenv bootargs ${bootargs} androidboot.quiescent=1;else if test ${reboot_mode} = recovery_quiescent; then setenv bootargs ${bootargs} androidboot.quiescent=1;run recovery_from_flash;else if test ${reboot_mode} = cold_boot; then else if test ${reboot_mode} = fastboot; then fastboot;fi;fi;fi;fi;fi;fi;
update=run usb_burning; run recovery_from_udisk;run recovery_from_flash;
upgrade_check=echo recovery_status=${recovery_status};if itest.s "${recovery_status}" == "in_progress"; then run storeargs; run recovery_from_flash;else fi;echo upgrade_step=${upgrade_step}; if itest ${upgrade_step} == 3; then run storeargs; run update; fi;
upgrade_step=2
usb_burning=adnl 1000
usid=1234567890
vendor=amlogic
video_reverse=0

Environment size: 5556/8188 bytes

抓住uboot命令行的两个重点参数:
bootargs: 传递给Linux内核的启动参数
bootcmd: 自动启动时执行命令

分析bootcmd

bootcmd=run storeboot

其中run是一个命令,对应u-boot源代码cmd/nvedit.c目录:

U_BOOT_CMD_COMPLETE(
>...run,>...CONFIG_SYS_MAXARGS,>1,>.do_run,
>..."run commands in an environment variable",
>..."var [...]\n"
>..."    - run the commands in the environment variable(s) 'var'",
>...var_complete
);

在uboot中,大多数命令都能在代码中找到前缀为do_xxx的函数实现. 其中do_run函数是run命令的具体实现.

#if defined(CONFIG_CMD_RUN)
int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])                                                                                                                                                                          
{
>...int i;

>...if (argc < 2)
>...>...return CMD_RET_USAGE;

>...for (i = 1; i < argc; ++i) {
>...>...char *arg;
		//获取命令参数:如run storeboot,通过env_get得到storeboot
>...>...arg = env_get(argv[i]);
>...>...if (arg == NULL) {
>...>...>...printf("## Error: \"%s\" not defined\n", argv[i]);
>...>...>...return 1;
>...>...}
		//执行命令,调用函数do_storeboot
>...>...if (run_command(arg, flag | CMD_FLAG_ENV) != 0)
>...>...>...return 1;
>...}
>...return 0;
}
#endif

分析分析storeboot

storeboot=run get_os_type;if test ${os_type} = rtos; then setenv loadaddr ${loadaddr_rtos};store read ${loadaddr} ${boot_part} 0 0x400000;bootm ${loadaddr};else if test ${os_type} = kernel; then if fdt addr ${dtb_mem_addr}; then else echo retry common dtb; run common_dtb_load; fi;setenv loadaddr ${loadaddr_kernel};if imgread kernel ${boot_part} ${loadaddr}; then bootm ${loadaddr}; fi;else echo wrong OS format ${os_type}; fi;fi;echo try upgrade as booting failure; run update;

首先调用了get_os_type函数,判断Flash上某地址的镜像类型.

get_os_type的具体实现

os_ident_addr=0x00500000
get_os_type=if store read ${os_ident_addr} ${boot_part} 0 0x1000; then os_ident ${os_ident_addr}; fi

其中store命令对应do_store函数,仿照分析do_run函数的流程得知, do_store函数的用法:
意思是从flash boot分区0地址读取0x1000大小内容到DDR内存的 0x00500000地址.

"store read addr [partition name] off size\n"
        "       read 'size' bytes from offset 'off'\n"
        "       of device/partition 'partition name' to.\n"
        "       address 'addr' of memory.\n"
        "       if partition name not value. read start with\n"
        "       offset in normal logic area,if tpl area exist\n"
        "       read offset at end of tpl area\n"

os_ident 命令对应do_os_ident函数:

static int do_os_ident(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
        int ret = -1;

        if (argc < 2) {
                printf("Err! OS hdr addr not specified!\n");
                return ret;
        }

        const void *img_addr = simple_strtoul(argv[1], NULL, 16);
        debug_print("os hdr addr: 0x%lx\n", (ulong)img_addr);

        ret = genimg_get_format(img_addr);
        switch (ret) {
                case IMAGE_FORMAT_LEGACY:
                        debug_print("IMAGE_FORMAT_LEGACY format\n");
                        //将os类型填入环境变量"os_type"中.
                        env_set("os_type", "rtos");
                        break;
                case IMAGE_FORMAT_FIT:
                        debug_print("IMAGE_FORMAT_FIT format\n");
                        /* ignore fdt format, it's not an OS */
                        //env_set("os_type", "fdt");
                        break;
                case IMAGE_FORMAT_ANDROID:
                        debug_print("IMAGE_FORMAT_ANDROID format\n");
                        env_set("os_type", "kernel");
                        break;
                case IMAGE_FORMAT_INVALID:
                        debug_print("IMAGE_FORMAT_INVALID format\n");
                        env_set("os_type", "invalid");
                        break;
                default:
                        debug_print("default format\n");
                        break;
        }

        return ret;
}

由于项目开发用到的是linux系统,所以从上代码分析得知,Flash boot分区的0地址烧录android格式的kernel镜像, 也就是boot.img是android格式的镜像.

接着分析dtb的读取:

else if test ${os_type} = kernel; then if fdt addr ${dtb_mem_addr}; then else echo retry common dtb; run common_dtb_load; fi;setenv loadaddr ${loadaddr_kernel};if imgread kernel ${boot_part} ${loadaddr}; then bootm ${loadaddr}; fi;

U_BOOT_CMD(
        fdt,    255,    0,      do_fdt,
        "flattened device tree utility commands", fdt_help_text
        //展平的设备树实用程序命令
);
static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
>...if (argc < 2) 
>...>...return CMD_RET_USAGE;

>.../*
>... * Set the address of the fdt
>... */
>...if (strncmp(argv[1], "ad", 2) == 0) { 
>...>...unsigned long addr;
>...>...int control = 0; 
>...>...struct fdt_header *blob;
>...>.../*
>...>... * Set the address [and length] of the fdt.
>...>... */
>...>...argc -= 2;
>...>...argv += 2;
/* Temporary #ifdef - some archs don't have fdt_blob yet */
#ifdef CONFIG_OF_CONTROL
>...>...if (argc && !strcmp(*argv, "-c")) {
>...>...>...control = 1; 
>...>...>...argc--;
>...>...>...argv++;
>...>...}
#endif
>...>...if (argc == 0) { 
>...>...>...if (control)
>...>...>...>...blob = (struct fdt_header *)gd->fdt_blob;
>...>...>...else
>...>...>...>...blob = working_fdt;
>...>...>...if (!blob || !fdt_valid(&blob))
>...>...>...>...return 1;
>...>...>...printf("The address of the fdt is %#08lx\n",
>...>...>...       control ? (ulong)map_to_sysmem(blob) :
>...>...>...>...>...env_get_hex("fdtaddr", 0)); 
>...>...>...return 0;
>...>...}

>...>...addr = simple_strtoul(argv[0], NULL, 16); 
>...>...blob = map_sysmem(addr, 0);
>...>...if (!fdt_valid(&blob))
>...>...>...return 1;
>...>...if (control)
>...>...>...gd->fdt_blob = blob;
>...>...else
>...>...>...set_working_fdt_addr(addr);

>...>...if (argc >= 2) { 
>...>...>...int  len; 
>...>...>...int  err; 
>...>...>.../*
>...>...>... * Optional new length
>...>...>... */
>...>...>...len = simple_strtoul(argv[1], NULL, 16); 
>...>...>...if (len < fdt_totalsize(blob)) {
>...>...>...>...printf ("New length %d < existing length %d, "
>...>...>...>...>..."ignoring.\n",
>...>...>...>...>...len, fdt_totalsize(blob));
>...>...>...} else {

do_fdt的主要工作是:对fdt格式检查, 读取dtb. The working_fdt points to our working flattened device tree, (指向flash地址0x01000000). 所以对于第一个疑问:烧录dtb到flash的地址就应该是0x01000000

分析内核的读取和解压

setenv loadaddr ${loadaddr_kernel}
imgread kernel ${boot_part} ${loadaddr};
bootm ${loadaddr};

其中:
第一行意思是设置环境变量loadaddr的值为0x00020000
第二行意思是从boot分区值为loadaddr的地址读取内核,解压到内存中.
第三行意思是启动内核

下面看imgread命令对应do_imgread函数的介绍

U_BOOT_CMD(
   imgread,         //command name
   5,               //maxargs
   0,               //repeatable
   do_image_read,   //command function
   "Read the image from internal flash with actual size",           //description
   "    argv: <imageType> <part_name> <loadaddr> \n"   //usage
   "    - <image_type> Current support is kernel/res(ource).\n"
   "imgread kernel  --- Read image in fomart IMAGE_FORMAT_ANDROID\n"
   "imgread dtb     --- Read dtb in fomart IMAGE_FORMAT_ANDROID\n"
   "imgread res     --- Read image packed by 'Amlogic resource packer'\n"
   "imgread picture --- Read one picture from Amlogic logo"
   "    - e.g. \n"
   "        to read boot.img     from part boot     from flash: <imgread kernel boot loadaddr> \n"   //usage
   "        to read recovery.img from part recovery from flash: <imgread kernel recovery loadaddr $offset> \n"   //usage
   "        to read logo.img     from part logo     from flash: <imgread res    logo loadaddr> \n"   //usage
   "        to read one picture named 'bootup' from logo.img    from logo: <imgread pic logo bootup loadaddr> \n"   //usage
);

进一步印证了必须烧录android格式的kernel镜像.

对于bootm命令对应do_bootm函数,这个函数涉及到内核的读取,格式解析,解压和启动的过程,在后面的章节会详细论述. 这也是疑问二的解答重点.

结论
关于烧录问题目前的疑问解答了疑问1, 第二个疑问的解决在分析do_bootm函数时详细论证.
后面技术支持给出烧录文档,最新订正了内核的烧录地址. 这也是烧录后固件没有变化的原因.

adnl.exe Partition -M mem -P 0x1080000  -F /d/temp/a1/a1/boot.img

学习与探讨

  1. android格式的固件boot.img本身包含kernel, dtb, rootfs, 所以上面bootcmd中使用命令imgread从Flash读取boot.img, 又使用fdt addr ${dtb_mem_addr}命令读取dtb了.这是否是多此一举?

参考资料

Image uImage与zImage的区别
HOWTO: Unpack, Edit, and Re-Pack Boot Images
[uboot] uboot启动kernel篇(一)——Legacy-uImage & FIT-uImage

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

uboot环境变量分析 的相关文章

  • 强制卸载 NFS 安装目录 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案
  • 跟踪 Linux 程序中活跃使用的内存

    我想跟踪各种程序在特定状态下接触了多少内存 例如 假设我有一个图形程序 最小化时 它可能会使用更少的内存 因为它不会重新绘制窗口 这需要读取图像和字体并执行大量库函数 这些对象仍然可以在内存中访问 但实际上并没有被使用 类似的工具top它们
  • GLIBCXX_3.4.26 未找到在 BeagleBone 上运行交叉编译的程序

    我有以下程序 include
  • 如何使用 bash 锁定文件

    我有一个任务从远程服务器同步目录 rsync av email protected cdn cgi l email protection srv data srv data 为了使其定期运行并避免脚本 reEnter 问题 我使用 rsyn
  • 仅打印“docker-container ls -la”输出中的“Names”列

    发出时docker container ls la命令 输出如下所示 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a67f0c2b1769 busybox tail f dev
  • 如何在 Linux 中编写文本模式 GUI? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 当我编写脚本 程序时 我经常想弹出一个简单的文本 gui 来提示输入 我该怎么做 例如 来自 Shel
  • Jenkins中找不到环境变量

    我想在詹金斯中设置很多变量 我试过把它们放进去 bashrc bash profile and profile of the jenkins用户 但 Jenkins 在构建发生时找不到它们 唯一有效的方法是将所有环境变量放入Jenkinsf
  • Linux TUN/TAP:无法从 TAP 设备读回数据

    问题是关于如何正确配置想要使用 Tun Tap 模块的 Linux 主机 My Goal 利用现有的路由软件 以下为APP1和APP2 但拦截并修改其发送和接收的所有消息 由Mediator完成 我的场景 Ubuntu 10 04 Mach
  • 如何在 shell 脚本中并行运行多个实例以提高时间效率[重复]

    这个问题在这里已经有答案了 我正在使用 shell 脚本 它读取 16000 行的输入文件 运行该脚本需要8个多小时 我需要减少它 所以我将其划分为 8 个实例并读取数据 其中我使用 for 循环迭代 8 个文件 并在其中使用 while
  • gdb查找行号的内存地址

    假设我已将 gdb 附加到一个进程 并且在其内存布局中有一个文件和行号 我想要其内存地址 如何获取文件x中第n行的内存地址 这是在 Linux x86 上 gdb info line test c 56 Line 56 of test c
  • 为什么内核需要虚拟寻址?

    在Linux中 每个进程都有其虚拟地址空间 例如 32位系统为4GB 其中3GB为进程保留 1GB为内核保留 这种虚拟寻址机制有助于隔离每个进程的地址空间 对于流程来说这是可以理解的 因为有很多流程 但既然我们只有 1 个内核 那么为什么我
  • 大多数 Linux 系统头文件与 C++ 兼容吗?

    大多数 Linux 系统头文件 API C 兼容吗 今天我试图做这样的事情 include
  • 在哪里可以找到并安装 pygame 的依赖项?

    我对 Linux 比较陌生 正在尝试安装 python 的 pygame 开发环境 当我运行 setup py 时 它说我需要安装以下依赖项 我找到并安装了其中之一 SDL 然而 其他人则更加难以捉摸 Hunting dependencie
  • 添加要在给定命令中运行的 .env 变量

    我有一个 env 文件 其中包含如下变量 HELLO world SOMETHING nothing 前几天我发现了这个很棒的脚本 它将这些变量放入当前会话中 所以当我运行这样的东西时 cat env grep v xargs node t
  • 尝试安装 LESS 时出现“请尝试以 root/管理员身份再次运行此命令”错误

    我正在尝试在我的计算机上安装 LESS 并且已经安装了节点 但是 当我输入 node install g less 时 出现以下错误 并且不知道该怎么办 FPaulMAC bin paul npm install g less npm ER
  • 两种情况或 if 哪个更快? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我必须制作一个 非常 轻的脚本 它将接受用户的选项并调用脚本中的函数来执行一些任务 现在我可以使用 IF 和 CASE 选项 但我想知道两
  • 安装J语言的JQt IDE,出现错误

    我一直按照这里的说明进行操作 http code jsoftware com wiki System Installation Linux http code jsoftware com wiki System Installation L
  • 使用 sh 运行 bash 脚本

    我有 bash 脚本 它需要 bash 另一个人尝试运行它 sh script name sh 它失败了 因为 sh 是他的发行版中 dash 的符号链接 ls la bin sh lrwxrwxrwx 1 root root 4 Aug
  • 有谁知道在哪里定义硬件、版本和序列号。 /proc/cpuinfo 的字段?

    我想确保我的 proc cpuinfo 是准确的 目前它输出 Hardware am335xevm Revision 0000 Serial 0000000000000000 我可以在代码中的哪里更改它以给出实际值 这取决于 Linux 的
  • 如何通过ssh检查ubuntu服务器上是否存在php和apache

    如何通过ssh检查Ubuntu服务器上apache是 否安装了php和mysql 另外如果安装的话在哪个目录 如果安装了其他软件包 例如 lighttpd 那么它在哪里 确定程序是否已安装的另一种方法是使用which命令 它将显示您正在搜索

随机推荐

  • springboot将图片上传至七牛云服务器(超详细)

    我们在公司的业务开发中 经常会接触到图片上传功能 有很多小伙伴都会在这里遇坑 特别是将图片上传至七牛云服务器上 网上的很多讲解也都很不明确 那么今天我们就要来讲一讲如何将本地的图片上传至七牛云服务器上 配合步骤自己做一个小的demo吧 本文
  • VirtualBox 虚拟机里网络很慢的解决方法

    VirtualBox 升级到6 0 4 后发现这个问题 Mac 主机网速很快 但虚拟机 ubuntu 里网络很慢 首先尝试多种不同的网络连接模式 都不能解决 再回头调试 发现域名解析很慢 问题定位在 DNS 问题 ping 一下百度 15秒
  • 使用Python,OpenCV实现简单的场景边界/拍摄转换检测器

    使用Python OpenCV进行简单的场景边界 拍摄转换检测器 1 效果图 2 实现 2 1 步骤 2 2 什么是 场景边界 和 拍摄过渡 2 3 代码目录结构 2 源码 参考 这篇博客起源于朋友分享蝙蝠侠7更新了 而我没有办法去最近的书
  • Learing blockchain in go

    Windows下JetBrains GoLand环境配置记录 根据文末Reference 1 实现的迷你区块链 暂有 block chain pow UTXO 现在实现的bc存在double spending问题 并且创世区块和创世交易的哈
  • C++之合并两个链表

    题目 已有a b两个链表 每个链表中的结点包括学号 成绩 要求把两个链表合并 按学号升序排列 include
  • 程序员不擅长沟通???

    版权声明 原创作品 允许转载 转载时请务必以超链接形式标明文章原始出版 作者信息和本声明 否则将追究法律责任 本文地址 http blog csdn net jobchanceleo archive 2007 01 18 1487073 a
  • c++函数返回引用

    转自 http www cnblogs com floatedclouds archive 2011 10 13 2209917 html 1 什么是引用 引用就是变量的别名 操作一个变量的引用也就相当于操作变量本身 这一点跟指针很类似 但
  • Cursor,程序员的 AI 代码编辑助手

    相信大家都或多或少地听说过 了解过 chatGPT 半个月前发布的 GPT 4 可谓是 AI 赛道上的一个王炸 那么今天咸鱼给大家分享一个开源的 AI 代码编辑器 Cursor 让各位程序员在编程之路上一骑绝尘 介绍 Cursor 是一个人
  • minigui成功移植到ubuntu64位平台

    1 pc系统ubuntu14LTS 64bit 同时在32位ubuntu16 04上经过了测试 官方的所有范例程序都能运行 2 过两天会写份详细的移植教程 现在只是将移植好的文件上传到我的csdn下载 大家可以免费下载 3 做个简单的移植过
  • nginx代理去掉URl前缀

    今天接到一个配置nginx的需求是 需要访问某个域名时 nginx可以去掉前缀去代理访问到后端 正常配置情况下 在nginx配置文件中中设置了 location prod api api 时 浏览器访问 prod api api 反向代理到
  • ModbusPoll和Slave的使用教程

    ModbusPoll和Slave的使用教程 在工业领域 很多地方采用了Modbus协议 简单理解一下Modbus协议 就是把数据存在寄存器地址里面编号 然后通过协议读取 modbus有主机和从机 主机只有一个 从机可以有很多个 玩过Tcp的
  • PAT C语言入门题目-7-52 数组元素循环右移问题 (20 分)

    7 52 数组元素循环右移问题 20 分 一个数组A中存有N gt 0 个整数 在不允许使用另外数组的前提下 将每个整数循环向右移M 0 个位置 即将A中的数据由 A 0 A 1 A N 1 变换为 A N M A N 1 A 0 A 1
  • 尚硅谷-康师傅-MySQL详细笔记(10-18章)

    mysq详细笔记10 18章 第10章 创建和管理表 10 1 基础知识 10 1 1 一条数据存储的过程 10 1 2 标识符命名规则 10 1 3 MySQL中的数据类型 10 2 创建和管理数据库 10 2 1 创建数据库 10 2
  • 安卓移动应用开发之从零开始写安卓小程序3

    实验3 修改我们的HelloWorld程序 让它和我们的手机app外观差不多 一 打开我们的HelloWorld程序 没有的同学请自行创建或者下载我发上去的资源 大家如果遇到sync没有跳出来的 可以点击这个search 然后输入sync回
  • Nmap简单使用教程

    在Web攻防的过程中对有关主机存活 应用版本扫描的相关工具中 Nmap是最常使用的信息收集工具 Nmap是一款开源的网络探测和安全审核的工具 它的设计目标是快速地扫描大型网络 Nmap可以探测网络中有哪些主机存活 这些主机都提供了什么服务
  • 【山河送书第十期】:《Python 自动化办公应用大全》参与活动,送书两本!!

    山河送书第十期 Python 自动化办公应用大全 参与活动 送书两本 前言 一 书籍亮点 二 作者简介 三 内容简介 四 购买链接 五 参与方式 六 往期赠书回顾 前言 在过去的 5 年里 Python 已经 3 次获得 TIOBE 指数年
  • 基于IMU和超声的3D手势识别笔

    随着科技的发展 人机交互在商业中有了越来越多的应用 面对日益复杂的交互场景 手势识别逐渐成为虚拟现实等相关应用的主要交互手段 3D手势识别是一个具有挑战性的问题 常用的手势传感器有三种基本类型 多点触摸屏传感器 基于视觉的传感器和基于安装的
  • 微信小程序(订阅消息)

    小程序模板消息即将被废弃掉 于是有了新接口wx requestSubscribeMessage 订阅消息文档 步骤 1 获取用户openid access token 前面文章提到过 2 获取模板 ID 3 获取下发权限 api 4 发送订
  • 【项目】前端实习——后端接口数据获取与渲染

    后端数据获取与渲染 接口联调 数据渲染 挂载 生命周期 数据更新 实习项目开发与自己平时练习的项目最大的不同就是有接口数据 通过发起一定的请求获取到后端的数据 接口联调 在后端部署好后 通过网络请求去获取数据 前面我们已经定义好一些死的数据
  • uboot环境变量分析

    项目情景 最近我在一个新平台的开发过程中遇到烧录问题 具体的问题是使用原厂提供的烧录脚本烧录成功 但是固件却没有更新 其中kernel和dtb烧录指令如下 adnl exe Partition M mem P 0x1000000 F lin