boot_jump_linux函数,阅读linux0.11——boot

原标题:阅读linux0.11——boot

本文主要围绕三个问题展开:

1、为什么要有引导程序?

2、什么是引导程序?

3、Linux 0.11引导程序怎么工作?

一、为什么要有引导程序?

解释这个问题以前,先说一点BIOS的工作。当你按下电源键以后,计算机先进行的工作是加电自检,自检完了然后就到了BIOS大展身手了,它负责“点醒”硬件,然后把引导程序BIOS也不知道自己把什么东西加载进内存。这里要注意BIOS加载的位置:把硬盘上的第一个扇区加载进内存的0x7c00位置。

所以第一个问题就来了,我们知道一个扇区只有512字节,假设我们没有引导程序,BIOS把系统加载进内存,那就意味着你的系统代码只有512字节。你没有看错是512字节,这其中还包括了实模式的跳转代码和你写的注释。

如果你说,我geek一点,我写的系统就是只有512字节。那么本文对你来说没有任何需要阅读的意义。

所以为了突破这个512字节的限制,我们设计出了引导程序。这就引入了第二个问题,什么是引导程序。

二、什么是引导程序

引导程序顾名思义就是负责把系统引导进内存的程序,刚刚已经解释了这个的重要性。现在来看看引导程序到底实际上需要做什么。

第一点也是最重要的一点,把系统load进内存一个特定的位置。其次,刚开机的时候是不是还在实模式下,如果可能的话我们希望引导也能帮我跳转到保护模式。我希望我的系统第一个模块就是在32位系统下运行的。

捋一下就是主要有两件事:

1、加载系统

2、跳转到保护模式

是的,就是这么简单,我们下来看看具体的实现。

三、Linux 0.11引导程序怎么工作

Linux0.11boot主要分为三个部分,分别在三个程序里面实现,bootsect.s、head.s和setup.s。这个三个程序运行的顺序是:bootsect–>setup–>head。

bootsec:把自己从0x7c00位置移动到0x90000位置,加载setup程序把系统加载在0x10000位置,

setup:把系统搬移到0x00000位置,读取一个磁盘、显示或者内存的参数并保存在合适的位置,然后跳转到保护模式(保护模式跳转的详细分析见博文)

1、bootsect.s

这个程序是最先被执行的,根据Linus的解释说,这个程序会被BIOS启动例程(bios-startup routines)加载到内存的0x7c00处(这个地址是BIOS约定好的,每一个系统的引导都会从硬盘的第一个扇区被读入这个位置。这也就一意味着,每一个引导都要在第一个扇区,包括自己写的)。但是这里请大家注意,这个地址的表示方式是16位的,表示现在还是在实模式下。然后bootsect.s程序会把自己移动到内存的0x90000处,这个地址是20位的地址了。最后jump到0x90000处。程序加载setup程序到内存的0x90200处,并且此时系统在内存的0x10000处。

下面是程序的详细解释:

58e7b9c0a85efbc3f688dd7474bfcc96.png

这里说一点题外话,汇编也是有类似于别的语言的函数,我们称之为过程,过程的调用原理类似于c语言的函数调用,调用完了还是要回到过程被调用的地方来。为了使大家对程序也有更清晰的认识,我们按照程序执行的顺序对程序分层,按照层次讲解。因此这两个过程解析见后文。

3e139e06a09128cb05416dfbf4b5fde0.png

到这里程序的主要部分就结束了,在分析read_it过程之前,先来捋一下。我们可以根据以上的分析得出如下结论:

1、bootsect程序执行的主要工作是把自己从内存的0x7c00处移山填海到0x90000处,把setup程序搬移到0x90200处。实际上还有一个很重要的工作,就是把存在磁盘上的系统读入内存的0x10000处

2、根据这个内存的安排我们可以大胆的认为:bootsect程序没有0x0200字节长(请大家注意这一点)。

5aa667c8175799487f901285c1808520.png

这里boot程序执行完了,并把控制权交给了setup程序。

2、setup程序

前面已经大致解释了setup程序完成的功能:调用BIOS中断获取一些系统的参数,依次把它们顺序保存在0x90000位置(覆盖了bootsect程序),然后把系统搬移到0x00000位置,最后跳转至保护模式,把控制权交给head程序。语言看起来清晰明朗,这里不在赘述。

值得一提的是,bootsect程序和setup程序都算是引导程序,为什么把它们写了两个程序,这个原因跟为什么要引入引导程序一样,因为512字节写不下。

head是系统的第一个模块,运行在保护模式下。所以汇编的格式和前面的引导程序格式不一样。这个格式是AT&T格式,而引导程序使用intel汇编写的。

有人会问为什么要用intel汇编写?这里我想说的是,我倒是想用强大的写呢,问题是这个时候计算机要什么没什么,跑不起来啊。除了bios给你的一些中断之外,其他的什么也没有,别说一个java的编译器了,就连java源程序都是存储在磁盘上,加载不到内存中。这是一个很尴尬的事,什么也不能用,所以我们第一件事必须脱离这个尴尬至极的境地。当当当当,引导程序就是这么来的。

在引导程序的结尾部分,控制权被交给了head这个程序,所以我想看看head这个程序是怎么工作的,就是这么简单。

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`bootstage_mark_name` 函数是 U-Boot 中的一个用于性能分析和跟踪的函数,它的作用是在 U-Boot 启动过程中标记一个阶段的名称和时间戳。 具体来说,`bootstage_mark_name` 函数会记录当前时间,并将该时间与指定的阶段名称一起保存在一个全局的数据结构中。在 U-Boot 启动过程中的不同阶段调用 `bootstage_mark_name` 函数,可以记录不同阶段的时间戳,并最终生成一个启动时间轴,用于分析和优化 U-Boot 启动性能。 `bootstage_mark_name` 函数的定义如下: ```c void bootstage_mark_name(enum bootstage_id id, const char *name) { if (!bootstage_started(id)) { return; } if (!name || !*name) { debug("bootstage: empty name (id=%d)\n", id); return; } debug("bootstage: %s (%d) @ %llu\n", name, id, timer_get_us()); bootstage_add_record(id, name, timer_get_us()); } ``` 该函数的参数包括 `enum bootstage_id id` 和 `const char *name`,分别表示阶段的 ID 和名称。 函数首先通过 `bootstage_started` 函数检查指定 ID 的阶段是否已经启动,如果没有启动,则直接返回。然后检查指定的名称是否为空,如果为空,则打印一条调试信息并返回。最后,调用 `bootstage_add_record` 函数,将该阶段的 ID、名称和时间戳添加到全局的数据结构中。 `bootstage_add_record` 函数的作用是将指定的阶段信息添加到全局的数据结构中,用于生成启动时间轴。 总之,`bootstage_mark_name` 函数是 U-Boot 中用于性能分析和跟踪的函数,它的作用是在 U-Boot 启动过程中标记一个阶段的名称和时间戳。通过调用该函数,可以记录 U-Boot 启动过程中的不同阶段的时间戳,并最终生成一个启动时间轴,用于分析和优化 U-Boot 启动性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值