linux 0.11 源码学习(五)
head.s
head.s 是系统模块的入口,其编译器已经是GNU汇编,但从功能上将仍然属于内核启动阶段,主要的功能是对386 CPU的初始化,如用户堆栈、IDT、GDT和页表。因此从文件夹的归属看,它仍然放在boot文件夹中,与bootsect和setup一块。head.s的核心功能(简单的寄存器初始化不做赘述)如下:
- 初始化堆栈寄存器:lss stack_start, %esp,其中stack_start定义在sched中,如下:
struct { long * a; short b; } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
- 初始化中断描述符表,256个中断描述符都被挂接一个叫ignore_int的函数,只打印消息不做处理,如下:
setup_idt: lea ignore_int,%edx movl $0x00080000,%eax movw %dx,%ax /* selector = 0x0008 = cs */ movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ lea idt,%edi //设置idt中的256个中断描述符 mov $256,%ecx rp_sidt: movl %eax,(%edi) movl %edx,4(%edi) addl $8,%edi dec %ecx jne rp_sidt //如果ecs(256) != 0,则跳转 lidt idt_descr //加载中断描述符表,这里的idt_desscr包含了idt变量(256个中断描述符) ret
- 加载全局描述符表寄存器
setup_gdt: lgdt gdt_descr ret
gdt_descr: .word 256*8-1 # so does gdt (not that that's any .long gdt # magic number, but it works for me :^) gdt: .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x00c09a0000000fff /* 16Mb */ .quad 0x00c0920000000fff /* 16Mb */ .quad 0x0000000000000000 /* TEMPORARY - don't use */ .fill 252,8,0 /* space for LDT's and TSS's etc */
- 检查A20地址线是否真实开启
- 初始化软盘缓冲区:tmp_floppy_area:.fill 1024,1,0
- 初始化页表:
注:在386体系的CPU中支持段页式的内存管理方式,即逻辑地址(基地址+偏移)->通过分段管理->线性地址->通过分页管理->物理地址。针对分页管理386的机制是CR3寄存器指向页表目录,页表目录中的PDE (page Directory Entry)指向一个页表,页表中的PTE(page Table Entry)指向一个物理页。因此386的线性地址实际上是三个偏移量:页目录表偏移量(找到页表)、页表的偏移量(找到物理页)、物理页的偏移量,三者的综合完成具体物理页面的转换。
在linux的页表初始化代码中主要是三块工作:
- 初始化一个页目录表和四个页表:
setup_paging: movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */ xorl %eax,%eax xorl %edi,%edi /* pg_dir is at 0x000 */ cld;rep;stosl movl $pg0+7,pg_dir /* set present bit/user r/w */ pg_dir的地址是0x000,没搞清楚为什么? movl $pg1+7,pg_dir+4 /* --------- " " --------- */ movl $pg2+7,pg_dir+8 /* --------- " " --------- */ movl $pg3+7,pg_dir+12 /* --------- " " --------- */
-
- 将edi指向最后一个页表的最后一项:movl $pg3+4092, %edi
- 设置页目录表的地址至CR3寄存器,设置CR0寄存器启动分页机制;
xorl %eax,%eax /* pg_dir is at 0x0000 */ movl %eax,%cr3 /* cr3 - page directory start */ //cr3被设置成0x0000 movl %cr0,%eax orl $0x80000000,%eax movl %eax,%cr0 /* set paging (PG) bit */ ret /* this also flushes prefetch-queue */
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)