linux - 引导 linux 内核和独立应用程序有什么区别?
问题描述
我有一个基于 MIPS 的板(联发科 mt7620),它带有一个专有的封闭式引导加载程序(u-boot),它切断了很多功能,比如booting a standalone application
. (我不允许更改/重新刷新这个引导加载程序,因为很多客户都使用这个板,如果我们更新引导加载程序并且它失败了,我们将面临很多砖块:)(引导加载程序支持boot over tftp
协议))
我正在尝试更改电路板制造商提供的引导顺序:ROM bootloader --> flash bootloader (u-boot) --> linux kernel to a: ROM bootloader --> flash bootloader (u-boot) -->引导陷阱-> linux内核。对于另一个具有支持 u-boot 的板(mt7621),booting a standalone application
我能够创建一些boot trap
u-boot 映像(独立应用程序)并将其放入闪存而不是 linux 内核(我将 linux 内核向下移动)。(这可以通过跳转表使用 u-boot 提供boot trap
的功能来完成一些工作、加载和引导 linux 内核。ranand_read/do_bootm
正如我所提到的,基于 mt7620 的板的 u-boot 不支持booting a standalone application
,所以我决定创建一个boot trap
作为 u-boot linux 映像(而不是作为 u-boot 独立应用程序映像)保持代码boot trap
几乎相同(我只更改了函数签名:对于独立应用程序 u-boot 映像,传递了 2 个 args,对于 linux u-boot 映像 - 4;和加载/入口地址)。
这是来自串行端口的日志,用于基于 mt7621 的板:
## Booting image at bc140000 ...
Image Name: Boot trap
Image Type: MIPS U-Boot Standalone Program (uncompressed)
Data Size: 524 Bytes = 0.5 kB
Load Address: a0600000
Entry Point: a0600000
Verifying Checksum ... OK
OK
boot trap: got a control
boot trap: load a real kernel...
.......................
boot trap: boot a real kernel...
## Booting image at 88000000 ...
Image Name: OpenWrt Linux-3.10.14
Image Type: MIPS Linux Kernel Image (lzma compressed)
Data Size: 1494179 Bytes = 1.4 MB
Load Address: 80001000
Entry Point: 80001000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
No initrd
## Transferring control to Linux (at address 80001000) ...
## Giving linux memsize in MB, 256
Starting kernel ...
LINUX started...
对于基于 mt7620 的板:
## Booting image at bc140000 ...
Image Name: Boot trap
Image Type: MIPS Linux Kernel Image (lzma compressed)
Data Size: 345 Bytes = 0.3 kB
Load Address: 80001000
Entry Point: 80001000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
No initrd
## Transferring control to Linux (at address 80001000) ...
## Giving linux memsize in MB, 256
Starting kernel ...
如您所见,“引导陷阱”(作为 linux u-boot 映像)中的代码卡住了,我没有JTAG
调试器,所以我只能猜测发生了一些异常,并且板卡在该异常处理程序内的无限循环中。
我在基于 mt7621 的板的 u-boot 源代码中看到(我有它们:))这样的代码行:
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
...
switch (hdr->ih_type) {
case IH_TYPE_STANDALONE:
appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep);
(*appl)(argc-1, &argv[1]); // <--- pass a control to a standalone app
return 0;
...
switch (hdr->ih_os) {
default:
case IH_OS_LINUX:
do_bootm_linux (cmdtp, flag, argc, argv,
addr, len_ptr, verify);
break;
...
和下一行:
void do_bootm_linux (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[],
ulong addr, ulong * len_ptr, int verify)
{
...
void (*theKernel) (int, char **, char **, int *);
theKernel = (void (*)(int, char **, char **, int *)) ntohl (hdr->ih_ep);
...
theKernel (linux_argc, linux_argv, linux_env, 0); // <--- pass a control to a linux kernel
}
所以问题是引导 linux 内核和独立应用程序之间有什么区别?如果我们已经有一个有效的 C 环境,为什么 linux 在获得控制(linux/arch/mips/kernel/head.S)后必须设置一个堆栈指针?为什么 linux 在将控制权传递给自己的第一个 C 函数之前必须做这么多工作(在独立应用程序中,我们能够将 C 函数代码直接放入地址,u-boot 将控制权传递给)?
为什么不可能将代码放置在 u-boot 将控件传递到的地址中并让它像我为独立应用程序制作的那样运行?
解决方案
Linux 内核设计用于在从小型嵌入式设备到大型服务器的数千种不同系统上运行。在内核中包含每个可能的架构、电路板或配置的代码是不切实际的,因此内核定义了一组启动要求,必须满足这些要求才能运行。引导加载程序的任务通常是设置适当的环境并满足这些要求。
相比之下,“独立应用程序”通常是为特定的目标系统(架构、电路板、配置)编写的,并负责自行设置大部分内容。
这就是为什么 u-boot 以不同方式处理这两种情况的原因。如果您正在引导 Linux 内核,那么 u-boot 会按照内核期望的方式设置所有内容。如果您正在启动一个独立的应用程序,则假定该应用程序将执行所需的任何操作。
推荐阅读
- reactjs - 我有一个反应应用程序我通过道具从父组件发送api数据到子组件,它看到的值是未定义的
- python - 如何通过 pandas 将变量值导入 csv 文件
- html - 如何在不调用 View MVC 中的 foreach 循环的情况下从模型中获取项目
- javascript - 通过多个条件优化 Array.sort
- android - 如何修复包含 SQL 注入漏洞的内容提供程序
- xcode - .gpx 文件选择在我尝试将其添加到 Xcode 时被禁用
- python - 2 个值,3 个空格 - 如何循环返回所有不同的变化
- python - 为什么在构建二叉树时忽略二叉树重复值的节点?
- c# - 在应用程序执行其他操作时修改组件属性
- javascript - 使用 React Context vs Event Bus 连接深度嵌套的独立组件