文章目录
- [uboot_gpl 隔离 的目的](#uboot_gpl 隔离 的目的)
- [uboot_gpl 隔离基本原理](#uboot_gpl 隔离基本原理)
- [uboot_gpl 基本框架](#uboot_gpl 基本框架)
- [uboot_gpl 适配新平台的方式](#uboot_gpl 适配新平台的方式)
-
- [uboot 添加hikcmd功能](#uboot 添加hikcmd功能)
- 适配调试步骤
- 链接脚本语法
-
- 链接脚本的格式
- 链接脚本的简单示例
- 设置入口点(entry)
- 设置输出文件名
- 处理目标文件格式的命令
- [uboot_gpl 链接脚本的一般写法](#uboot_gpl 链接脚本的一般写法)
uboot_gpl 隔离 的目的
U-Boot 的 GPL 隔离是指在 U-Boot 中,将 GPL 认为具有侵权风险的代码与非 GPL 代码分隔开来,以避免 GPL 认为有侵权风险的代码"污染"了非 GPL 代码,从而使得整个 U-Boot 项目遵守 GPL 协议,保障代码的版权和使用权。 其主要作用如下:
- 保障代码的版权和使用权:U-Boot 作为开源软件,遵守 GPL 协议是其发展的基础,GPL 隔离可以使得 U-Boot 的使用和开发更加便捷和合法,同时也可以避免因 GPL 侵权而影响项目发展。
- 提高代码质量:执行 GPL 隔离可以使得开发者更加清晰地了解 U-Boot 中的 GPL 代码和非 GPL 代码,进而提高代码的可读性和可维护性。
- 提高代码的灵活性与可移植性:将 GPL 代码和非 GPL 代码分隔开来,有助于减少不同软件项目之间存在的依赖关系,从而增加了 U-Boot 的可移植性和灵活性,使得其更易于在不同的硬件平台和应用场景中使用和定制。
总之,U-Boot 的 GPL 隔离可以有效保障代码的版权和使用权,提高代码的质量和可维护性,增加了代码的灵活性和可移植性,使得整个项目更加健康、可持续发展
uboot_gpl 隔离基本原理
uboot gpl本质上是uboot中的standalone程序,也可以理解为独立的裸机代码。通过修改链接脚本指定代码段最开始的函数,uboot从flash中读入uboot_gpl镜像之后,只需要跳到这个镜像地址的位置,就可以直接运行指定在代码段最开始的函数。
链接脚本示例:
链接结果:
拼接方式:
uboot gpl镜像直接拼接在uboot镜像后面固定地址的位置,中间空出的地方用0x00 或者 0xff进行填充。这样uboot就可以直接算出gpl镜像在flash中的位置。
具体的计算方式可以使用:
uboot的起始偏移+uboot与gpl总镜像大小-gpl镜像大小
uboot_gpl 基本框架
uboot_gpl框架总体上可以分为四层,uboot运行层,hikcmd运行接口层,uboot_gpl运行支持层,uboot_gpl功能实现层。
uboot运行层是指uboot原始代码,是从芯片厂商哪里拿来的uboot的源码。
hikcmd运行支持层包含海康需要在原厂uboot添加的源码,以及运行gpl代码所需的代码。
uboot_gpl运行支持层包含一个小型的C库和一个命令分类器。命令分类器的作用就是通过hikcmd传入的功能参数,找到对应的uboot功能层提供的函数,以及传入uboot中传入的参数。
uboot_gpl功能层 ,需要进行gpl隔离的相关代码,目前包含psh,unpack等功能。
uboot_gpl 适配新平台的方式
uboot 添加hikcmd功能
为了可以调用gpl镜像,需要在uboot中添加hikuboot_gpl_init 功能 和 hikcmd 命令,hikuboot_gpl_init的作用是将uboot_gpl镜像读入内存,然后进行校验。hikcmd的作用是跳转到uboot_gpl镜像的开始位置并传入参数,其基本调用格式为:
hikcmd [load_addr] [function] [argv]
hikcmd 0x45000004 psh 0x%x 0x%x
适配调试步骤
到这里uboot gpl适配基本就完成了,适配完成后就可以将uboot.bin替代原有Uboot烧写到flash里面,这个时候可以尝试看看hikcmd能否调用gpl运行如果不行,需要检查原因。
可以尝试注掉main函数中所有内容,然后只有return , 然后看看uboot能否拿到这个return 的数值,如果数值返回异常说明调用异常。
如果有返回值,没有打印需要检查uboot提供的getc与putc是否正常。
链接脚本语法
链接脚本的格式
链接脚本是文本文件。你写一个链接脚本就是写一系列命令。每个命令要么是一个可能后面跟着参数的关键字,要么是对符号的赋值。命令可以用分号分隔。空格通常被忽略。
对于字符串,如文件或格式名称,通常可以直接放进去。如果文件名包含逗号等字符,由于这种符号会分隔文件名,为了避免被分隔,可以将文件名放在双引号中。不能在文件名中使用双引号字符。
你可以在链接脚本中包含注释,就像在C中一样,用 /* 和*/ 分隔。与C语言一样,注释在语法上等同于空格。
链接脚本的简单示例
许多链接脚本都相当简单。最简单的链接脚本只有一个命令:' SECTIONS '。可以使用' SECTIONS '命令来描述输出文件的内存布局。SECTIONS命令是一个功能强大的命令。这里我们将描述它的一个简单用法。让我们假设程序只由代码、初始化数据和未初始化数据组成。它们将分别在' .text '、' .data '和' .bss '区域中。让我们进一步假设这些节是在输入文件中出现的唯一的节,没有其他节。对于这个例子,假设代码应该在地址' 0x10000000'加载,并且数据应该从地址' 0x30000000'开始。下面的链接脚本将实现该功能
SECTIONS
{
. = 0x10000000;
.text : { *(.text) }
. = 0x30000000;
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) }
}
第 1 行我们先写了一个关键字"SECTIONS",后面跟了一个大括号,这个大括号和第 7 行的大括号是一对,这是必须的。看起来就跟 C 语言里面的函数一样。
第 2 行对一个特殊符号"."进行赋值,"."在链接脚本里面叫做定位计数器,默认的定位计数器为 0。我们要求代码链接到以 0X10000000 为起始地址的地方,因此这一行给"."赋值0X10000000,表示以 0X10000000 开始,后面的文件或者段都会以 0X10000000 为起始地址开始链接。
第 3 行的".text"是段名(代码段),后面的冒号是语法要求,冒号后面的大括号里面可以填上要链接到".text"这个段里面的所有文件,"(.text)"中的""是通配符,表示所有输入文件的.text段都放到".text"中。
第 4 行,我们的要求是数据放到 0X30000000 开始的地方,所以我们需要重新设置定位计数器".",将其改为 0X30000000。如果不重新设置的话会怎么样?假设".text"段大小为 0X10000,那么接下来的.data 段开始地址就是 0X10000000+0X10000=0X10010000,这明显不符合我们的要求。所以我们必须调整定位计数器为 0X30000000。
第 5 行跟第 3 行一样,定义了一个名为".data"的段(数据段),然后所有文件的".data"段都放到这里面。但是这一行多了一个"ALIGN(4)",这是什么意思呢?这是用来对".data"这个段的起始地址做字节对齐的, ALIGN(4)表示 4 字节对齐。也就是说段".data"的起始地址要能被 4 整除,一般常见的都是 ALIGN(4)或者 ALIGN(8),也就是 4 字节或者 8 字节对齐。
第 6 行定义了一个".bss"段(bss数据段x,表示定义了但是还没有初始化的数据段),所有文件中的".bss"数据都会被放到这个里面,".bss"数据就是那些定义了但是没有被初始化的变量。
设置入口点(entry)
程序执行的第一条指令称为入口点。你可以使用' ENTRY '链接脚本命令来设置入口点。参数是一个符号名:
typescript
ENTRY ( symbol )
有几种方法可以设置入口点。链接器将依次尝试以下方法来设置入口点,并在其中一个成功时停止:
- -e 入口命令选项( 译注 :-e是链接器的参数);
- 链接脚本中的ENTRY (symbol) 命令 ;
- 如果符号start定义了,那就是start符号的值;
- 如果存在.text节,那就是.text节的第一个字节的地址;
- 地址0
因为在gpl的运行方式中是直接获取text段地址然后跳过去执行,所以这里设置入口点对于gpl是不生效的。uboot 跳过来就会执行uboot_gpl镜像代码段的第一条。
设置输出文件名
' OUTPUT '命令给输出文件命名。使用"OUTPUT ( filename )'就像在命令行中使用' -o filename '一样。如果两者都使用,命令行选项优先。
你可以使用' OUTPUT '命令为输出文件定义一个默认名称,而不是通常默认的' a.out '。
处理目标文件格式的命令
一些链接脚本命令处理目标文件格式。OUTPUT_FORMAT (bfdname)
' OUTPUT_FORMAT '命令给输出文件指定BFD格式的名称。使用' OUTPUT_FORMAT (bfdname)'就像在命令行上使用' -oformat bfdname '一样。如果两者都使用,命令行选项优先。
可以使用带有三个参数的' OUTPUT_FORMAT '来基于' -EB '和' -EL '命令行选项使用不同的格式。这允许链接脚本根据所需的字节序设置输出格式。如果' -EB '和' -EL '都没有使用,那么输出格式将是第一个参数' DEFAULT '。如果使用' -EB ',输出格式将是第二个参数' BIG '。如果使用' -EL ',输出格式将是第三个参数' LITTLE '。例如,MIPS ELF目标的默认链接脚本使用以下命令:
cobol
OUTPUT_FORMAT(elf32-bigmips, elf32-bigmips, elf32-littlemips)
这说明输出文件的默认格式是' elf32-bigmips ',但是如果用户使用' -EL '命令行选项,输出文件将以' elf32-littlemips '格式创建。
uboot_gpl 链接脚本的一般写法
SECTIONS{
. = 0x00; //位置定位
.text : //代码段
{
source/main.o
*(.text)
}
.rodata ALIGN(4) : {*(.rodata*)} //只读数据段 const 变量
.data ALIGN(4) : { *(.data) } //数据段 已初始化全局变量
__bss_start = .; //定义bss_start 记录bss段开始位置
.bss ALIGN(4) : { *(.bss) *(COMMON) } //bss段 未初始化全局变量
__bss_end = .;
}