linux 0.11 源码学习(四)
setup.s
在setup中最主要的工作是使系统进入保护模式,并转入system模块具体如下:
- 通过BIOS中断读取系统数据,如光标、显卡、硬盘等信息,这些信息存放至内存0x9000至0x901FC处,典型代码如下:
! ok, the read went well so we get current cursor position and save it for ! posterity. mov ax,#INITSEG ! this is done in bootsect already, but... mov ds,ax mov ah,#0x03 ! read cursor pos xor bh,bh int 0x10 ! save it in known place, con_init fetches mov [0],dx ! it from 0x90000.
- 将system模块移到内存0x0000处(这里看代码有点不懂,感觉只移动了64K,而不是完整 system的512K):
mov ax,#0x0000 cld ! 'direction'=0, movs moves forward do_move: mov es,ax ! destination segment //es+di 目的地址 add ax,#0x1000 cmp ax,#0x9000 jz end_move mov ds,ax ! source segment //ds+si:源地址 sub di,di sub si,si mov cx,#0x8000 //movsw循环的次数 rep movsw jmp do_move
- 加载GDT和LDT,选择A20地址线,系统进入保护模式。其中GDT初始设置值(包含三个描述符)如下:
gdt: .word 0,0,0,0 ! dummy .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) //代码段 .word 0x0000 ! base address=0 .word 0x9A00 ! code read/exec .word 0x00C0 ! granularity=4096, 386 .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) //数据段 .word 0x0000 ! base address=0 .word 0x9200 ! data read/write .word 0x00C0 ! granularity=4096, 386
备注:GDT描述符定义 -》 BYTE0,BYTE1(段界限),BYTE2、BYTE3、BYTE4(段基地址1),BYTE5,BYTE6(属性)、BYTE7(段基地址2)。上述代码中比较困惑的是为什么代码段和地址段的基地址都是0x0000。
- 操作8259中断控制器,应该是初始化芯片,未细看;
- 跳转至gdt的第二个描述符,即地址0x0000处,为sysyem模块的head.s,参看链接过程中生成的system.map,该地址重定向到的函数是head.s的startup。这里比较困惑的是为什么0x0000处会是head.s,代码段在链接的时候,多个目标文件不是会重新组合吗?难道是老的连接器采用不整合,简单拼接的方法??
mov ax,#0x0001 ! protected mode (PE) bit lmsw ax ! This is it! jmpi 0,8 ! jmp offset 0 of segment 8 (cs) //一定要注意此时已经是保护模式,跳转的是GDT的偏移:)
【推荐】国内首个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)