U-boot(五):启动内核

本文主要探讨210的uboot启动内核过程。

嵌入式系统状态启动
        未上电时bootloader、kernel、rootfs以镜像形式存储在启动介质中(X210为iNand/SD卡),运行时搬运到DDR中
        未上电时u-boot.bin,zImage,rootfs在SD卡中各自对应的分区中,启动时去对应分区寻找(分区表一致)
        动态启动为从SD卡到DDR内存,并且运行启动代码进行硬/软件初始化
        uboo在第一阶段重定位时将第二阶段(整个uboot镜像)加载到DDR的0xc3e00000地址处(uboot链接地址)
        uboot启动内核时从SD卡读取内核到DDR地址是0x30008000(内核链接地址)
        uboot启动内核:将内核搬移到DDR中,校验内核格式、CRC等,准备传参,跳转执行内核
        启动内核主要函数是:do_boom,do_bootm_linux
        uboot能启动的内核格式:zImage,uImage,fdt

image_header_t

typedef struct image_header {uint32_t    ih_magic;    /* Image Header Magic Number    */uint32_t    ih_hcrc;    /* Image Header CRC Checksum    */uint32_t    ih_time;    /* Image Creation Timestamp    */uint32_t    ih_size;    /* Image Data Size        */uint32_t    ih_load;    /* Data     Load  Address        */uint32_t    ih_ep;        /* Entry Point Address        */uint32_t    ih_dcrc;    /* Image Data CRC Checksum    */uint8_t        ih_os;        /* Operating System        */uint8_t        ih_arch;    /* CPU architecture        */uint8_t        ih_type;    /* Image Type            */uint8_t        ih_comp;    /* Compression Type        */uint8_t        ih_name[IH_NMLEN];    /* Image Name        */
} image_header_t;
image_header_t    *hdr;

        uboot启动内核使用的数据结构(镜像头部信息)


内核启动
        内核不能自主开机,uboot帮助内核重定位到链接地址(SD卡到DDR)并且给内核传递启动参数
        210的iNand版本uboot使用movi命令完成内核重定位(movi read kernel 30008000),kernel为uboot中kernel分区

do_bootm(cmd_bootm.c)

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])/* find out kernel image address */if (argc < 2) {addr = load_addr;debug ("*  kernel: default image load address = 0x%08lx\n",load_addr);} else {addr = simple_strtoul(argv[1], NULL, 16);debug ("*  kernel: cmdline image address = 0x%08lx\n", img_addr);}
ulong load_addr = CFG_LOAD_ADDR;    /* Default Load Address */#define CFG_LOAD_ADDR        MEMORY_BASE_ADDRESS    /* default load address    */#define MEMORY_BASE_ADDRESS    0x30000000

        启动命令:bootm 0x30008000,故do_boom的argc=2,argv[0]=bootm,argv[1]=0x30008000
        启动命令:bootm,从CFG_LOAD_ADDR地址启动(x210_sd.h)


vmlinuz,zImage,uImage
        uboot编译生成u-boot(elf格式),由u-boot用arm-linux-objcopy工具加工得到u-boot.bin(镜像)用来烧录
        linux内核编译生成vmlinux或vmlinuz(几十M)(elf格式),用objcopy工具加工成烧录Image镜像(几M),对Image压缩,在image压缩后的文件前端附加解压缩代码构成zImage
        uImage是由zImage加工得到,mkimage工具由zImage加工生成uImage给uboot启动,在zImage前加64字节头信息即可得到


zImage启动

#ifdef CONFIG_ZIMAGE_BOOT
#define LINUX_ZIMAGE_MAGIC    0x016f2818/* find out kernel image address */if (argc < 2) {addr = load_addr;debug ("*  kernel: default image load address = 0x%08lx\n",load_addr);} else {addr = simple_strtoul(argv[1], NULL, 16);debug ("*  kernel: cmdline image address = 0x%08lx\n", img_addr);}if (*(ulong *)(addr + 9*4) == LINUX_ZIMAGE_MAGIC) {printf("Boot with zImage\n");addr = virt_to_phys(addr);hdr = (image_header_t *)addr;hdr->ih_os = IH_OS_LINUX;hdr->ih_ep = ntohl(addr);memmove (&images.legacy_hdr_os_copy, hdr, sizeof(image_header_t));/* save pointer to image header */images.legacy_hdr_os = hdr;images.legacy_hdr_valid = 1;goto after_header_check;}
#endif

        CONFIG_ZIMAGE_BOOT(x210_sd.h)用宏控制编译支持zImage格式的内核启动
        LINUX_ZIMAGE_MAGIC是魔数(0x016f2818)来表示zImage,即zImage格式镜像在头部存放该数作为标记辨别它是否是zImage(是否等于LINUX_ZIMAGE_MAGIC),若为在Image则对头部信息改造,用头信息初始化images,完成了校验

after_header_check

#if defined(CONFIG_ZIMAGE_BOOT)
after_header_check:os = hdr->ih_os;
#endifswitch (os) {default:            /* handled by (original) Linux case */case IH_OS_LINUX:
#ifdef CONFIG_SILENT_CONSOLEfixup_silent_linux();
#endifdo_bootm_linux (cmdtp, flag, argc, argv, &images);break;case IH_OS_NETBSD:do_bootm_netbsd (cmdtp, flag, argc, argv, &images);break;#ifdef CONFIG_LYNXKDIcase IH_OS_LYNXOS:do_bootm_lynxkdi (cmdtp, flag, argc, argv, &images);break;
#endifcase IH_OS_RTEMS:do_bootm_rtems (cmdtp, flag, argc, argv, &images);break;#if defined(CONFIG_CMD_ELF)case IH_OS_VXWORKS:do_bootm_vxworks (cmdtp, flag, argc, argv, &images);break;case IH_OS_QNX:do_bootm_qnxelf (cmdtp, flag, argc, argv, &images);break;
#endif#ifdef CONFIG_ARTOScase IH_OS_ARTOS:do_bootm_artos (cmdtp, flag, argc, argv, &images);break;
#endif}show_boot_progress (-9);
#ifdef DEBUGputs ("\n## Control returned to monitor - resetting...\n");do_reset (cmdtp, flag, argc, argv);
#endifif (iflag)enable_interrupts();return 1;
}


        确定image类型,依据类型进行头信息校验,校验通过则准备启动内核


uImage启动和设备数启动

/* get kernel image header, start address and length */os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,&images, &os_data, &os_len);if (os_len == 0) {puts ("ERROR: can't get kernel image!\n");return 1;}/* get image parameters */switch (genimg_get_format (os_hdr)) {case IMAGE_FORMAT_LEGACY:type = image_get_type (os_hdr);comp = image_get_comp (os_hdr);os = image_get_os (os_hdr);image_end = image_get_image_end (os_hdr);load_start = image_get_load (os_hdr);break;
#if defined(CONFIG_FIT)case IMAGE_FORMAT_FIT:if (fit_image_get_type (images.fit_hdr_os,images.fit_noffset_os, &type)) {puts ("Can't get image type!\n");show_boot_progress (-109);return 1;}if (fit_image_get_comp (images.fit_hdr_os,images.fit_noffset_os, &comp)) {puts ("Can't get image compression!\n");show_boot_progress (-110);return 1;}if (fit_image_get_os (images.fit_hdr_os,images.fit_noffset_os, &os)) {puts ("Can't get image OS!\n");show_boot_progress (-111);return 1;}break;
#endifdefault:puts ("ERROR: unknown image format type!\n");return 1;}image_start = (ulong)os_hdr;load_end = 0;type_name = genimg_get_type_name (type);
static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],bootm_headers_t *images, ulong *os_data, ulong *os_len){image_header_t    *hdr;ulong        img_addr;
#if defined(CONFIG_FIT)void        *fit_hdr;const char    *fit_uname_config = NULL;const char    *fit_uname_kernel = NULL;const void    *data;size_t        len;int        cfg_noffset;int        os_noffset;
#endif/* find out kernel image address */if (argc < 2) {img_addr = load_addr;debug ("*  kernel: default image load address = 0x%08lx\n",load_addr);
#if defined(CONFIG_FIT)} else if (fit_parse_conf (argv[1], load_addr, &img_addr,&fit_uname_config)) {debug ("*  kernel: config '%s' from image at 0x%08lx\n",fit_uname_config, img_addr);} else if (fit_parse_subimage (argv[1], load_addr, &img_addr,&fit_uname_kernel)) {debug ("*  kernel: subimage '%s' from image at 0x%08lx\n",fit_uname_kernel, img_addr);
#endif} else {img_addr = simple_strtoul(argv[1], NULL, 16);debug ("*  kernel: cmdline image address = 0x%08lx\n", img_addr);}show_boot_progress (1);/* copy from dataflash if needed */img_addr = genimg_get_image (img_addr);/* check image type, for FIT images get FIT kernel node */*os_data = *os_len = 0;switch (genimg_get_format ((void *)img_addr)) {case IMAGE_FORMAT_LEGACY:printf ("## Booting kernel from Legacy Image at %08lx ...\n",img_addr);hdr = image_get_kernel (img_addr, images->verify);if (!hdr)return NULL;show_boot_progress (5);/* get os_data and os_len */switch (image_get_type (hdr)) {case IH_TYPE_KERNEL:*os_data = image_get_data (hdr);*os_len = image_get_data_size (hdr);break;case IH_TYPE_MULTI:image_multi_getimg (hdr, 0, os_data, os_len);break;default:printf ("Wrong Image Type for %s command\n", cmdtp->name);show_boot_progress (-5);return NULL;}/** copy image header to allow for image overwrites during kernel* decompression.*/memmove (&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t));/* save pointer to image header */images->legacy_hdr_os = hdr;images->legacy_hdr_valid = 1;show_boot_progress (6);break;
#if defined(CONFIG_FIT)case IMAGE_FORMAT_FIT:fit_hdr = (void *)img_addr;printf ("## Booting kernel from FIT Image at %08lx ...\n",img_addr);if (!fit_check_format (fit_hdr)) {puts ("Bad FIT kernel image format!\n");show_boot_progress (-100);return NULL;}show_boot_progress (100);if (!fit_uname_kernel) {/** no kernel image node unit name, try to get config* node first. If config unit node name is NULL* fit_conf_get_node() will try to find default config node*/show_boot_progress (101);cfg_noffset = fit_conf_get_node (fit_hdr, fit_uname_config);if (cfg_noffset < 0) {show_boot_progress (-101);return NULL;}/* save configuration uname provided in the first* bootm argument*/images->fit_uname_cfg = fdt_get_name (fit_hdr, cfg_noffset, NULL);printf ("   Using '%s' configuration\n", images->fit_uname_cfg);show_boot_progress (103);os_noffset = fit_conf_get_kernel_node (fit_hdr, cfg_noffset);fit_uname_kernel = fit_get_name (fit_hdr, os_noffset, NULL);} else {/* get kernel component image node offset */show_boot_progress (102);os_noffset = fit_image_get_node (fit_hdr, fit_uname_kernel);}if (os_noffset < 0) {show_boot_progress (-103);return NULL;}printf ("   Trying '%s' kernel subimage\n", fit_uname_kernel);show_boot_progress (104);if (!fit_check_kernel (fit_hdr, os_noffset, images->verify))return NULL;/* get kernel image data address and length */if (fit_image_get_data (fit_hdr, os_noffset, &data, &len)) {puts ("Could not find kernel subimage data!\n");show_boot_progress (-107);return NULL;}show_boot_progress (108);*os_len = len;*os_data = (ulong)data;images->fit_hdr_os = fit_hdr;images->fit_uname_os = fit_uname_kernel;images->fit_noffset_os = os_noffset;break;
#endifdefault:printf ("Wrong Image Format for %s command\n", cmdtp->name);show_boot_progress (-108);return NULL;}debug ("   kernel data at 0x%08lx, len = 0x%08lx (%ld)\n",*os_data, *os_len, *os_len);return (void *)img_addr;
}

        IMAGE_FORMAT_LEGACY为uImage启动方式,启动校验在boot_get_kernel函数:校验uImage头信息,得kernel起始位置去启动
        CONFIG_FIT:设备树方式启动

do_bootm_linux(zImage)

void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],bootm_headers_t *images){ulong    initrd_start, initrd_end;ulong    ep = 0;bd_t    *bd = gd->bd;char    *s;int    machid = bd->bi_arch_number;void    (*theKernel)(int zero, int arch, uint params);int    ret;#ifdef CONFIG_CMDLINE_TAGchar *commandline = getenv ("bootargs");
#endif/* find kernel entry point */if (images->legacy_hdr_valid) {ep = image_get_ep (&images->legacy_hdr_os_copy);
#if defined(CONFIG_FIT)} else if (images->fit_uname_os) {ret = fit_image_get_entry (images->fit_hdr_os,images->fit_noffset_os, &ep);if (ret) {puts ("Can't get entry point property!\n");goto error;}
#endif} else {puts ("Could not find kernel entry point!\n");goto error;}theKernel = (void (*)(int, int, uint))ep;s = getenv ("machid");if (s) {machid = simple_strtoul (s, NULL, 16);printf ("Using machid 0x%x from environment\n", machid);}ret = boot_get_ramdisk (argc, argv, images, IH_ARCH_ARM,&initrd_start, &initrd_end);if (ret)goto error;show_boot_progress (15);debug ("## Transferring control to Linux (at address %08lx) ...\n",(ulong) theKernel);#if defined (CONFIG_SETUP_MEMORY_TAGS) || \defined (CONFIG_CMDLINE_TAG) || \defined (CONFIG_INITRD_TAG) || \defined (CONFIG_SERIAL_TAG) || \defined (CONFIG_REVISION_TAG) || \defined (CONFIG_LCD) || \defined (CONFIG_VFD) || \defined (CONFIG_MTDPARTITION)setup_start_tag (bd);
#ifdef CONFIG_SERIAL_TAGsetup_serial_tag (&params);
#endif
#ifdef CONFIG_REVISION_TAGsetup_revision_tag (&params);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGSsetup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAGsetup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAGif (initrd_start && initrd_end)setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)setup_videolfb_tag ((gd_t *) gd);
#endif#ifdef CONFIG_MTDPARTITIONsetup_mtdpartition_tag();
#endifsetup_end_tag (bd);
#endif/* we assume that the kernel is in place */printf ("\nStarting kernel ...\n\n");#ifdef CONFIG_USB_DEVICE{extern void udc_disconnect (void);udc_disconnect ();}
#endifcleanup_before_linux ();theKernel (0, machid, bd->bi_boot_params);/* does not return */return;error:do_reset (cmdtp, flag, argc, argv);return;
}

        ulong    ep = 0;ep(entrypoint)是程序入口,镜像文件起始执行部分不在镜像开头,在镜像开头某个字节处(有偏移量)
        运行镜像过程:读取头信息MAGIC_NUM来确定镜像种类,镜像校验,读取头信息获取镜像信息(镜像长度,种类,入口地址),去entrypoint处运行镜像
        theKernel = (void (*)(int, int, uint))ep;将ep赋值给theKernel,函数指向OS镜像真正入口地址(操作系统运行首代码)。
        int    machid = bd->bi_arch_number;uboot启动内核时,机器码传给内核,uboot通过全局变量gd->bd->bi_arch_num将x210_sd.h定义的机器码传给uboot
        函数(110-144)是uboot给linux内核传递参数处理
        Starting kernel标志uboot加载内核镜像,校验通过,获得内核入口地址


tag传参

struct tag {struct tag_header hdr;union { struct tag_core         core;struct tag_mem32        mem;struct tag_videotext    videotext;struct tag_ramdisk      ramdisk;struct tag_initrd       initrd;struct tag_serialnr     serialnr;struct tag_revision     revision;struct tag_videolfb     videolfb;struct tag_cmdline      cmdline;/** Acorn specific*/struct tag_acorn        acorn;/** DC21285 specific*/struct tag_memclk       memclk;struct tag_mtdpart      mtdpart_info;} u;
};
struct tag_header {u32 size;u32 tag;
};
static struct tag *params;

        tag_header中有tag的size和类型编码


        tag函数参宏

ATAG_NONE	                tag_header        tag结束
ATAG_CORE	                tag_core
ATAG_MEM	                tag_mem32         内存配置信息
ATAG_VIDEOTEXT	            tag_videotext
ATAG_RAMDISK	            tag_ramdisk
ATAG_INITRD	                tag_initrd
ATAG_SERIAL	                tag_serialnr
ATAG_REVISION	            tag_revision
ATAG_VIDEOLFB	            tag_videolfb
ATAG_CMDLINE	            tag_cmdline      启动命令参数(的bootargs)
ATAG_ACORN	                tag_acorn        tag起始
ATAG_MEMCLK	                tag_memclk
ATAG_MTDPART                tag_mtdpart      iNand/SD卡分区表
/* The list must start with an ATAG_CORE node */
#define ATAG_CORE	0x54410001struct tag_core {u32 flags;		/* bit 0 = read-only */u32 pagesize;u32 rootdev;
};

theKernel (0, machid, bd->bi_boot_params);/* does not return */

        uboot调用theKernel函数来运行linux内核,uboot调用时传递3个参数:(0,机器码,tag首地址)

demo:

        编译uImage

ubuntu:

root@kaxi-virtual-machine:~/qt_x210v3s/kernel# cat mk
#!/bin/sh#QT_KERNEL_CONFIG=x210_jffs_defconfig
QT_KERNEL_CONFIG=x210ii_qt_defconfigCPU_NUM=$(cat /proc/cpuinfo |grep processor|wc -l)
CPU_NUM=$((CPU_NUM+1))make distclean
make cleanmake ${QT_KERNEL_CONFIG} 
make -j${CPU_NUM} 
cd qt_x210v3s/kernelvim MakefileCROSS_COMPILE   ?= /root/arm-2009q3/bin/arm-none-linux-gnueabi-make clean &> /dev/null && make distclean &> /dev/nullcp ../uboot/tools/mkimage /usr/local/bin/vim mkQT_KERNEL_CONFIG=x210ii_qt_defconfig生成zImage./mk &>/dev/nullmake uImage &>/dev/nullcp arch/arm/boot/uImage /root/tftp

uboot: 

tftp 30008000 uImagemovi read kernel 30008000bootm 30008000

结果示例: 

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

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

相关文章

【Java】实现一个自己的定时器

上文讲了怎样使用Java自带的定时器【Java】定时器的简单应用 这篇博客就来讲如何来编写一个自己实现的定时器 1、代码框架 由定时器的使用方法得知&#xff0c;我们在使用定时器的时候会添加一个任务timerTask类&#xff0c;而timer类则是我们行使任务的类&#xff0c;因此可…

【Apache Doris】Manager极致丝滑地运维管理

【Apache Doris】Manager极致丝滑地运维管理 1.标准VS可视化运维管理2. 环境信息2.1.硬件信息2.2.软件信息 3.前置准备3.1.安装包准备3.2.文档手册准备 4.集群初始化4.1.系统参数预设4.2.Manager部署4.3.新集群部署4.4 监控告警4.4.1 监控4.4.2 告警 5. 集群升级5.1 新包准备5.…

人力资源管理后台 === 登陆+主页鉴权

目录 1. 分析登录流程 2. Vuex中用户模块的实现 3.Vue-cli代理解决跨域 4.axios封装 5.环境区分 6. 登录联调 7.主页权限验证-鉴权 1. 分析登录流程 传统思路都是登录校验通过之后&#xff0c;直接调用接口&#xff0c;获取token之后&#xff0c;跳转到主页。 vue-elemen…

【数据库基础】

目录&#xff1a; 前言什么是数据库主流数据库服务器&#xff0c;数据库&#xff0c;表关系MySQL架构SQL分类存储引擎 前言 剑指offer&#xff1a;一年又1天 什么是数据库 存储数据用文件就可以了&#xff0c;为什么还要弄个数据库? 文件保存数据有以下几个缺点&#xff1a;…

大量索引场景下 Easysearch 和 Elasticsearch 的吞吐量差异

最近有客户在使用 Elasticsearch 搜索服务时发现集群有掉节点&#xff0c;并且有 master 收集节点信息超时的日志&#xff0c;节点的负载也很高&#xff0c;不只是 data 节点&#xff0c;master 和协调节点的 cpu 使用率都很高&#xff0c;看现象集群似乎遇到了性能瓶颈。 查看…

算法设计与分析(贪心法)

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

中国一年有457万人确诊癌症!医生提示:这4种食物,再爱吃也要管住嘴

癌症是威胁人类生命健康的重大疾病&#xff0c;癌症的发生因素一直以来都是专家学者重点探索的课题。据世卫组织最新公布的数据显示&#xff0c;食物或与癌症发生之间存在着密切的联系&#xff0c;某些食物的摄入过多可能会增加患癌症的风险&#xff0c;所以我们应该警惕&#…

IDEA中JDK21控制台打印的中文乱码

IDEA中&#xff0c;使用的JDK21&#xff0c;控制台打印中文乱码&#xff0c;解决办法是重装了一下JDK。 我之前安装的版本是“jdk-21_windows-x64_bin.exe”&#xff0c;我配置了多个JDK环境&#xff0c;所以使用的是安装文件进行安装的。这次解决乱码问题&#xff0c;我重新安…

代码随想录算法训练营第四十八天|121. 买卖股票的最佳时机、122. 买卖股票的最佳时机 II

LeetCode 121. 买卖股票的最佳时机 题目链接&#xff1a;121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09; 直觉告诉我要贪心算法&#xff0c;章节告诉我得用DP来做&#xff0c;行&#xff0c;都做一下&#xff01; 贪心&#xff1a;只能买一次&#xff0c;所…

Vatee万腾的科技冒险:Vatee独特探索力量的数字化征程

在数字化时代的激流中&#xff0c;Vatee万腾以其独特的科技冒险精神&#xff0c;引领着一场前所未有的数字化征程。这不仅仅是一次冒险&#xff0c;更是对未知的深度探索&#xff0c;将科技的力量推向新的高度。 Vatee万腾在科技领域敢于挑战传统&#xff0c;积极探索未知的可能…

快速解决Navicat连接数据库报错:10061

目录 问题原因&#xff1a; 错误提示&#xff1a; 解决方案&#xff1a; 问题1&#xff1a;如何进入指定目录&#xff1f; 问题2&#xff1a;若出现&#xff1a;“服务名无效” 将MySQL注册到win服务中 问题原因&#xff1a; mysql服务没有开启&#xff08;可能会在更新windows…

C#,《小白学程序》第三课:类class,类的数组及类数组的排序

类class把数值与功能巧妙的进行了结合&#xff0c;是编程技术的主要进步。 下面的程序你可以确立 分数 与 姓名 之间关系&#xff0c;并排序。 1 文本格式 /// <summary> /// 同学信息类 /// </summary> public class Classmate { /// <summary> /…

前端实现埋点

前端实现埋点 如何去了解用户呢&#xff1f;最直接有效的方式就是了解用户的行为&#xff0c;了解用户在网站中做了什么&#xff0c;呆了多久。而如何去实现这一操作&#xff0c;这就涉及到我们前端的埋点了。 埋点方式 什么是埋点&#xff1f; 所谓埋点是数据采集领域&…

【python】--文件/文件夹读写及操作

目录 一、文件读写1、文件读写代码示例 二、文件/文件夹操作1、代码示例 一、文件读写 读写文件就是请求操作系统打开一个文件对象&#xff08;通常称为文件描述符&#xff09;&#xff0c;然后通过操作系统提供的接口从这个文件对象中读取数据&#xff08;读文件&#xff09;…

机器人规划算法——movebase导航框架源码分析

这里对MoveBase类的类成员进行了声明&#xff0c;以下为比较重要的几个类成员函数。 构造函数 MoveBase::MoveBase | 初始化Action 控制主体 MoveBase::executeCb收到目标&#xff0c;触发全局规划线程&#xff0c;循环执行局部规划 全局规划线程 void MoveBase::planThread |…

学习笔记:如何分析财务报表

其实财务报表分析最核心的东西&#xff0c;是通过财务报表这个结果&#xff0c;由果推因&#xff0c;找出造成这个结果的原因。 会计是商业的语言 首先第一个问题是——会计是商业的语言&#xff0c;这是会计的根本。 什么叫“语言”&#xff0c;就是可以通过它进行交流。比如…

用队列和栈分别实现栈和队列

用队列实现栈 题目解读 本题的要求是要用两个队列来实现一个先进后出的栈&#xff0c;并且要有以下功能&#xff1a; 1.将元素压入栈中 2.移除栈顶元素并且返回他 3.返回栈顶元素 4.判断栈是否为空 题目构思和代码实现 我们首先要做的就是将实现队列的代码导入该题&#xff…

SSM 框架整合

1 整合配置 1.1 流程 1.2 Spring 整合 MyBatis 1.3 Spring 整合 SpringMVC 1.4 配置代码 JdbcConfig.java public class JdbcConfig {Value("${jdbc.driver}")private String driver;Value("${jdbc.url}")private String url;Value("${jdbc.usern…

四、IDEA创建项目时,Maven Archetype模板工程说明

什么是Maven Archetype Archetype是一个Maven项目的模板工具包&#xff0c;它定义了一类项目的基本架构。Archetype为开发人员提供了创建Maven项目的模板&#xff0c;同时它也可以根据已有的Maven项目生成参数化的模板。 官方文档&#xff1a;https://maven.apache.org/archet…

cuda magma 构建 使用cmake构建的步骤记录

这不是群论代数软件&#xff0c;而是cuda 矩阵计算软件 1. 生成其他精度的源代码 1.1 复制编辑 make.inc cp make.inc-examples/make.inc.openblas ./make.inc 并修改其中的定义&#xff1a; OPENBLASDIR ? /opt/OpenBLAS 这需要实现安装openblas到此处。文件夹解构&…