6.828课程的lab1主要集中在讲解8086的启动过程,其中有几道习题,我们把这节lab拆分到N篇文章中,分开记录
AT&T: movl %eax, %ebx 代表把eax的值放到ebx里面
咱们不着急,一行一行的读
#include
# Start the CPU: switch to 32-bit protected mode, jump into C.
# The BIOS loads this code from the first sector of the hard disk into
# memory at physical address 0x7c00 and starts executing in real mode
# with %cs=0 %ip=7c00.
.set PROT_MODE_CSEG, 0x8 # kernel code segment selector
.set PROT_MODE_DSEG, 0x10 # kernel data segment selector
.set CR0_PE_ON, 0x1 # protected mode enable flag
兄弟们,姐妹们,同志们,这块代码,就是BIOS同启动盘第一块扇区读出来的,我们自己的做的启动盘的第一块内容,大概率也是长这样子的,激不激动!兴不兴奋!
首先,8~10行,相当于C语言中的Define,具体什么意思咱们后文分述
接着看
.globl start
start:
.code16 # Assemble for 16-bit mode
cli # Disable interrupts
cld # String operations increment
这里就是汇编执行入口(梦开始的地方),cli 和 cld 分别把BIOS可能设置的中断和字符串读入方向清除掉,方便后续代码执行
不能停!
# Set up the important data segment registers (DS, ES, SS).
xorw %ax,%ax # Segment number zero
movw %ax,%ds # -> Data Segment
movw %ax,%es # -> Extra Segment
movw %ax,%ss # -> Stack Segment
第一句,把ax寄存器自己跟自己异或(你说啥意思呢?就是清零啊喂!)同时把DS,ES,SS寄存器全部清零
# Enable A20:
# For backwards compatibility with the earliest PCs, physical
# address line 20 is tied low, so that addresses higher than
# 1MB wrap around to zero by default. This code undoes this.
seta20.1:
inb $0x64,%al # Wait for not busy
testb $0x2,%al
jnz seta20.1
movb $0xd1,%al # 0xd1 -> port 0x64
outb %al,$0x64
seta20.2:
inb $0x64,%al # Wait for not busy
testb $0x2,%al
jnz seta20.2
movb $0xdf,%al # 0xdf -> port 0x60
outb %al,$0x60
这一段代码比较好玩,咱们仔细看一看,首先我们看注释,知道这段目的是 使能A20 地址线,这是为什么呢?这个时候,就需要拿出6.828这张著名内存图了
早年间呐,电脑是个稀罕东西,内存(RAM)更别提了,所以,那个时候的内存只有1MB,而几乎一半还被BIOS等设备驱动占去了,而随着RAM变大,设计师们不得不对内存结构进行更改,所以呢,现在的操作系统都会留出这么一个洞,就是为了向前兼容。
OK,说到这里,聪明的同学大概已经知道这个 使能A20 是什么意思了,意思就是,在8086中只有20地址线,所以BIOS中会默认把20以上的地址线设为0,这段代码undo this,让我们有更多的地址可以支配,从而有更多可以使用的内存
首先,inb $0x64,%al
,
in 读取指定 IO端口状态 到 指定寄存器
out 向 IO 进行写操作、
意思是,把0x64端口状态读出到al寄存器,然后testb $0x2,%al
test指令和and 指令执行同样的操作,但test指令不送回操作结果,而仅仅影响标志位
所以,这段代码就是检测 al寄存器中的第二位,然而,为什么检测第二位就可以知道端口是不是正忙呢?我们看这个链接
端口大全
我们可以看到,端口状态的第二位为1表示 input buffer full,一切都明白啦
我们再看下一句,movb $0xd1,%al outb %al,$0x64
,意思是向0064端口写入0xd1,这又是在干什么呢?
所以,写入d1的意思是,下一个写向 0060 端口的 字节 将会写往 804x端口,我们向后peek一下,发现果然,下一个写操作
movb $0xdf,%al outb %al,$0x60
,把df写到这个804x端口,这又是干什么呢?接着看端口大全
嘿嘿!被我逮到了,搞半天,还是为了使能A20嘛
好了好了,我们继续读代码
# Switch from real to protected mode, using a bootstrap GDT
# and segment translation that makes virtual addresses
# identical to their physical addresses, so that the
# effective memory map does not change during the switch.
lgdt gdtdesc
movl %cr0, %eax
orl $CR0_PE_ON, %eax
movl %eax, %cr0
先看看解释,这段的意思就是转换了,从实模式转换到了保护模式,不得了啊,不行,太困了,明天再写,今天先洗洗睡了