#include <inc/mmu.h> # 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. 启动CPU,切换到32位保护模式,跳转到C代码 BIOS从硬盘的第一个扇区加载这个代码到 物理内存地址为0x7c00的地方,cs=0,ip=7c00 下面的3条.set指令类似于宏定义 内核代码段选择子 .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 定义一个全局名字start .globl start start: CPU刚启动为16位模式 .code16 # Assemble for 16-bit mode 关中断 cli # Disable interrupts 清方向标志 cld # String operations increment # Set up the important data segment registers (DS, ES, SS). 设置重要的数据段寄存器 ax清零 xorw %ax,%ax # Segment number zero ds清零 movw %ax,%ds # -> Data Segment es清零 movw %ax,%es # -> Extra Segment ss清零 movw %ax,%ss # -> Stack Segment # 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. 打开A20地址线 为了兼容早期的PC机,第20根地址线在实模式下不能使用 所以超过1MB的地址,默认就会返回到地址0,重新从0循环计数, 下面的代码打开A20地址线 seta20.1: 从0x64端口读入一个字节的数据到al中 inb $0x64,%al # Wait for not busy test指令可以当作and指令,只不过它不会影响操作数 testb $0x2,%al 如果上面的测试中发现al的第2位为0,就不执行该指令 否则就循环检查 jnz seta20.1 将0xd1写入到al中 movb $0xd1,%al # 0xd1 -> port 0x64 将al中的数据写入到端口0x64中 outb %al,$0x64 seta20.2: 从0x64端口读取一个字节的数据到al中 inb $0x64,%al # Wait for not busy 测试al的第2位是否为0 testb $0x2,%al 如果上面的测试中发现al的第2位为0,就不执行该指令 否则就循环检查 jnz seta20.2 将0xdf写入到al中 movb $0xdf,%al # 0xdf -> port 0x60 将al中的数据写入到0x60端口中 outb %al,$0x60 # 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 cr0中的第0位为1表示处于保护模式 cr0中的第0位为0,表示处于实模式 把控制寄存器cr0加载到eax中 movl %cr0, %eax 将eax中的第0位设置为1 orl $CR0_PE_ON, %eax 将eax中的值装入cr0中 movl %eax, %cr0 # Jump to next instruction, but in 32-bit code segment. # Switches processor into 32-bit mode. 跳转到32位模式中的下一条指令 将处理器切换为32位工作模式 下面这条指令执行的结果会将$PROT_MODE_CSEG加载到cs中,cs对应的高速缓冲存储器会加载代码段描述符 同样将$protcseg加载到ip中 ljmp $PROT_MODE_CSEG, $protcseg .code32 # Assemble for 32-bit mode protcseg: # Set up the protected-mode data segment registers 设置保护模式下的数据寄存器 将数据段选择子装入到ax中 movw $PROT_MODE_DSEG, %ax # Our data segment selector 将ax装入到其他数据段寄存器中,在装入的同时, 数据段描述符会自动的加入到这些段寄存器对应的高速缓冲寄存器中 movw %ax, %ds # -> DS: Data Segment movw %ax, %es # -> ES: Extra Segment movw %ax, %fs # -> FS movw %ax, %gs # -> GS movw %ax, %ss # -> SS: Stack Segment # Set up the stack pointer and call into C. 设置栈指针,并且调用c函数 movl $start, %esp 调用main.c中的bootmain函数 call bootmain # If bootmain returns (it shouldn‘t), loop. 如果bootmain返回的话,就一直循环 spin: jmp spin # Bootstrap GDT 强制4字节对齐 .p2align 2 # force 4 byte alignment 全局描述符表 gdt: SEG_NULL # null seg 代码段描述符 SEG(STA_X|STA_R, 0x0, 0xffffffff) # code seg 数据段描述符 SEG(STA_W, 0x0, 0xffffffff) # data seg 全局描述符表对应的描述符 gdtdesc: .word 0x17 # sizeof(gdt) - 1 .long gdt # address gdt
MIT6.828 boot.S文件分析,布布扣,bubuko.com
原文:http://blog.csdn.net/xiaocainiaoshangxiao/article/details/22417237