内核第一阶段初始化

u-boot第一阶段启动过程 第一阶段主要完成一些依赖于CPU体系结构的初始化,并调用第二阶段的代码;第二阶段则通常使用C语言来实现,这样可以实现更复杂的功能,而且代码会有更好的可读性和可移植性。它是自动生成的,生成的源码包括start.S, uart驱动文件,sd(SPI)驱动文件,设备树等。a.根据链接脚本,使用gcc把汇编代码,编译为elf格式的目标文件。· 为加载u-boot的第二阶段代码准备RAM空间。d.把img文件中的内容复制到bootrom.sv中。· 复制u-boot的第二阶段代码到RAM空间中。 阅读详情

初始化阶段1包括从内核入口1MB处的startup_32到公共的start_kernel函数

=============================== arch/i386/kernel/head.S =================================
 50 /*
 51  * 32-bit kernel entrypoint; only used by the boot CPU.  On entry,
 52  * %esi points to the real-mode code as a 32-bit pointer.
 53  * CS and DS must be 4 GB flat segments, but we don't depend on
 54  * any particular GDT layout, because we load our own as soon as we
 55  * can.
 56  */
 57 ENTRY(startup_32)
 58 
 59 /*
 60  * Set segments to known values.
 61  */
 62     cld
 63     lgdt boot_gdt_descr - __PAGE_OFFSET
 64     movl $(__BOOT_DS),%eax
 65     movl %eax,%ds
 66     movl %eax,%es
 67     movl %eax,%fs
 68     movl %eax,%gs

在内核的链接脚本中指定了startup_32是程序入口而且代码段从__PAGE_OFFSET + 0x100000处开始,所以代码中的符号地址都是高地址(3GB+1MB以上),而内核代码运行时被加载到低地址1MB,此时是实模式,代码中访问的地址要用物理地址。所以lgdt要在符号地址boot_gdt_descr上减去__PAGE_OFFSET。

=============================== arch/i386/kernel/head.S =================================
450 boot_gdt_descr:
451     .word __BOOT_DS+7
452     .long boot_gdt_table - __PAGE_OFFSET

boot_gdt_descr处是要存放到gdtr的值,第一个.word表示gdt的长度-1,接下来的.long表示gdt的起始地址。

================================ include/asm/segment.h ==================================
 83 /* Simple and small GDT entries for booting only */
 84 
 85 #define GDT_ENTRY_BOOT_CS       2                                                                                                                                       
 86 #define __BOOT_CS   (GDT_ENTRY_BOOT_CS * 8)
 87 
 88 #define GDT_ENTRY_BOOT_DS       (GDT_ENTRY_BOOT_CS + 1)
 89 #define __BOOT_DS   (GDT_ENTRY_BOOT_DS * 8)

CS段描述符在第2条,DS在第3条,__BOOT_DS的值为24,所以bootgdt的大小就是24+7。

=============================== arch/i386/kernel/head.S =================================
471     .align L1_CACHE_BYTES
472 ENTRY(boot_gdt_table)
473     .fill GDT_ENTRY_BOOT_CS,8,0
474     .quad 0x00cf9a000000ffff    /* kernel 4GB code at 0x00000000 */
475     .quad 0x00cf92000000ffff    /* kernel 4GB data at 0x00000000 */

段描述符表的内容。.fill标记的意思是产生GDT_ENTRY_BOOT_CS条(2条)长度为8内容为0的条目。boot gdt总共4条,CS和DS都是4G范围的平坦映射。

接着回到startup_32,把__BOOT_DS段选择子赋给ds、es、fs、gs(没有ss),它们会刷新自己的影子寄存器。

=============================== arch/i386/kernel/head.S =================================
 70 /*
 71  * Clear BSS first so that there are no surprises...
 72  * No need to cld as DF is already clear from cld above...
 73  */
 74     xorl %eax,%eax
 75     movl $__bss_start - __PAGE_OFFSET,%edi
 76     movl $__bss_stop - __PAGE_OFFSET,%ecx
 77     subl %edi,%ecx
 78     shrl $2,%ecx
 79     rep ; stosl

清除内存上.bss段所指的范围。bss段是未初始化的全局变量和初始值为0的全局变量,它们在elf文件中只需要存放相应的符号名称,不存放那些0(初始值不为0的变量当然需要在二进制文件中存放它的初始值)。在加载的时候要分配空间给这些变量,并初始化为0。

=============================== arch/i386/kernel/head.S =================================
 81 /*
 82  * Initialize page tables.  This creates a PDE and a set of page
 83  * tables, which are located immediately beyond _end.  The variable
 84  * init_pg_tables_end is set up to point to the first "safe" location.
 85  * Mappings are created both at virtual address 0 (identity mapping)
 86  * and PAGE_OFFSET for up to _end+sizeof(page tables)+INIT_MAP_BEYOND_END.
 87  *
 88  * Warning: don't use %esi or the stack in this code.  However, %esp
 89  * can be used as a GPR if you really need it...
 90  */
 91 page_pde_offset = (__PAGE_OFFSET >> 20);
 92 
 93     movl $(pg0 - __PAGE_OFFSET), %edi
 94     movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
 95     movl $0x007, %eax           /* 0x007 = PRESENT+RW+USER */
 96 10:
 97     leal 0x007(%edi),%ecx           /* Create PDE entry */
 98     movl %ecx,(%edx)            /* Store identity PDE entry */
 99     movl %ecx,page_pde_offset(%edx)     /* Store kernel PDE entry */
100     addl $4,%edx
101     movl $1024, %ecx
102 11:
103     stosl
104     addl $0x1000,%eax
105     loop 11b
106     /* End condition: we must map up to and including INIT_MAP_BEYOND_END */
107     /* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */
108     leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp
109     cmpl %ebp,%eax
110     jb 10b
111     movl %edi,(init_pg_tables_end - __PAGE_OFFSET)

va右移20位就是该地址在页目录表中表项偏移,page_pde_offset就是内核代码高地址空间的起始页目录项偏移。
pg0是在下面的链接脚本中定义,是bss段之后的第一个页地址,链接脚本中的变量用的也是虚拟地址(高地址)。93行把pg0的物理地址存放到edi,pg0标志着内核代码所占内存的界限,同时它也是第0个页表的地址,最初映射的页表都是直接从这里分配的。

=========================== arch/i386/kernel/vmlinux.lds.s ============================
linux页表机制管理初始化 linux页表机制的建立分为两个阶段,第一个阶段在启动初始化时,调用汇编代码实现临时的分页;第二阶段在内核初始化时建立完整的完整的页表机制。对于物理地址扩展(PAE)分页机制中,intel通过在她得处理器上把管脚数从32增加到36已经满足了这些需求,寻址能力可以达到64GB。不过,只有引入一种新的分页机制把32位线性地址转换为36位物理地址才能使用所增加的物理地址。linux为对多种体系的支持,选 阅读详情

相关推荐

【0273】深入分析 relcache(relation descriptor cache)初始化第一阶段(1)

本文是的前传。本文主要内容将详细讲解PG内核中初始化relcache时,其第一阶段主要负责完成的任务是什么?以及该阶段完成了什么功能。对于第一阶段:这将初始化关系表描述符缓存。在调用这个函数的时候,我们还不能访问数据库(主要是因为事务子系统还没有启动);我们所做的就是创建一个空的缓存哈希表。这必须在开始初始化事务之前完成,否则如果事务在我们可以设置relcache之前终止,会崩溃。

Postgres 数据库内核开发工程师 518

RAD Studio 12安装全攻略:从下载到破解InterBase的完整流程(附KeyPatch使用技巧)

本文提供RAD Studio 12的完整安装指南,包括系统要求、安装步骤及InterBase数据库的高效配置方法。详细介绍了如何使用KeyPatch工具进行许可证处理,并分享了IDE优化和开发技巧,帮助开发者快速上手这一强大的跨平台开发工具。

q6r7s8t9的博客 951

高校学籍管理系统(SQL Server数据库课程设计)

摘要: 高校的管理工作是一项复杂且系统化的工作。而随着当代社会积极响应国家“科教兴国”的战略。高校建设规模和招生人数每年均高不下,庞大的学生群体对高校的管理工作带来了巨大的挑战。而对学生的学籍管理工作更是高校管理工作的一个重要环节。 面对高校学生学籍信息如此庞大的数据群,如采用传统的管理模式,管理工作的效率不仅低下,而且数据错误的发生率相对较高,还会产生人力和物力上的巨大开支。面对这样的情况,开发一个高校学籍管理系统就显得尤为重要。 运用高校学籍管理系统可以大大提高高校管理工作效率、方便系统维护、减小开支、

qq_52030824的博客 7万+

AIOps智能运维:从数据治理到故障自愈的实践指南

AIOps(智能运维)通过融合人工智能与运维管理,构建了感知-决策-执行的闭环体系。其核心技术包括多维度数据采集、机器学习算法和自动化执行,显著提升了告警治理、故障定位和容量预测的效率。在数据层,全量性、实时性的数据采集是基础,而算法层的异常检测和根因分析则依赖统计方法、孤立森林和LSTM等模型。AIOps尤其适用于处理告警风暴和复杂系统故障,如在电商大促中通过K-Means聚类减少92%的告警量。随着云原生和边缘计算的普及,AIOps正逐步实现与Service Mesh、Serverless等技术的深度集

weixin_30175731的博客 288

使用Java实现CRC16 MODBUS 格式校验

CRC16校验,测试如下 String str = "a5 98 03 00 00 5f c6 0f 7c 40 78 06 09 46 dc 6e db 00 16 3e 12 5c 98 00 19 98 0e 10 03 06 09 46 dc 6e db 03 0b bf 5f c6 0f 7c 43 bd b9 61 ee 96 76 99"; 校验规则: /** * CRC16_CCITT:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,高位在后,结

weixin_45063710的博客 1315

强化学习(Q-learning、DQN) —— 理论、案例与交互式 GUI 实现

本文详细介绍了强化学习中基于值函数的 Q-learning 算法及深度强化学习的 DQN 方法,从基本理论、数学模型到算法流程均进行了全面阐述。通过迷宫导航、股票交易策略和机器人控制等典型案例,展示了强化学习在处理高维、非线性和时变问题中的强大适应性。为了帮助工程师和研究者更直观地理解强化学习的训练过程,本文还提供了一份基于 Python 与 PyQt6 实现的交互式 GUI 演示系统代码示例,用户可以在线调整参数,实时观察累计奖励和 Q 值的变化,从而更深入地理解算法收敛和策略演化的过程。

闲人编程的博客 1475

脉冲变压器电感选型参数,结构原理,工艺与注意问题总结

脉冲变压器电感简称脉冲变压器,是一种特殊类型的变压器,主要用于处理脉冲信号。它的主要特性是能够在短时间内承受高电压和大电流。脉冲变压器主要用于开关电源、脉冲功率放大、雷达脉冲调制等领域。本文对脉冲变压器的工作原理,结构特点,工艺流程,选型参数及设计注意事项进行总结。

fydar的博客 1347

手把手教你学simulink(8.39)--基于Simulink的步进电机(Stepper Motor)仿真实例

通过这个仿真实例,你可以学习如何使用Simulink构建和仿真步进电机(Stepper Motor)系统。你可以根据实际需求调整模型和参数,进行更复杂的仿真和分析。希望这个例子对你有所帮助,祝你学习愉快!

MHD0815的博客 1052

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: Why the “volatile” type class should not be used
InvokerZhang
博客等级 码龄11年 9粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值