学习笔记
使用教材(配书源码以及使用方法)
《一个64位操作系统的设计与实现》
http://www.ituring.com.cn/book/2450
https://www.jianshu.com/p/28f9713a9171
源码结构
- 配书代码包:第4章\程序\程序4-1
命令行操作
[anno@localhost bootloader]$ make
nasm boot.asm -o boot.bin
nasm loader.asm -o loader.bin
[anno@localhost kernel]$ make
gcc -E head.S > head.s
as --64 -o head.o head.s
gcc -mcmodel=large -fno-builtin -m64 -c main.c
ld -b elf64-x86-64 -o system head.o main.o -T Kernel.lds
objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary system kernel.bin
[anno@localhost 4-1]$ sudo mount boot.img media -t vfat -o loop
[anno@localhost 4-1]$ sudo cp bootloader/loader.bin media
[anno@localhost 4-1]$ sync
[anno@localhost 4-1]$ sudo cp bootloader/boot.bin media
[anno@localhost 4-1]$ sync
[anno@localhost 4-1]$ sudo cp kernel/kernel.bin media
[anno@localhost 4-1]$ sync
[anno@localhost 4-1]$ bochs -f ./bochsrc
调试过程
源码阅读
内核执行头程序 head.S
- 内核执行头程序
head.S
: 设置寄存器、GDTR、IDTR、CR3,跳转到内核主程序;
线性地址 与 物理地址
- 内核层的起始线性地址
0x ffff 8000 0000 0000
对应着物理地址0
处 - 内核程序的起始线性地址位于
0x ffff 8000 0000 0000 + 0x 10 0000
处
设置 四级页表 PML4 - PDPT - PDT - PT
//======= init page
.align 8
.org 0x1000
__PML4E:
.quad 0x102007
.fill 255,8,0
.quad 0x102007
.fill 255,8,0
.org 0x2000
__PDPTE:
.quad 0x103003
.fill 511,8,0
.org 0x3000
__PDE:
.quad 0x000083
.quad 0x200083
.quad 0x400083
.quad 0x600083
.quad 0x800083
.quad 0xe0000083 /*0x a00000*/
.quad 0xe0200083
.quad 0xe0400083
.quad 0xe0600083 /*0x1000000*/
.quad 0xe0800083
.quad 0xe0a00083
.quad 0xe0c00083
.quad 0xe0e00083
.fill 499,8,0
- 使用2MB大小的物理页,页表结构参考
Linear-Address Translation to a 2-MByte Page using 4-Level Paging
设置CR3
//======= load cr3
movq $0x101000, %rax
movq %rax, %cr3
movq switch_seg(%rip), %rax
pushq $0x08
pushq %rax
lretq
-
CR3寄存器 存放
PML4
的 物理基地址 0x101000
GDT
//======= GDT_Table
.section .data
.globl GDT_Table
GDT_Table:
.quad 0x0000000000000000 /*0 NULL descriptor 00*/
.quad 0x0020980000000000 /*1 KERNEL Code 64-bit Segment 08*/
.quad 0x0000920000000000 /*2 KERNEL Data 64-bit Segment 10*/
.quad 0x0020f80000000000 /*3 USER Code 64-bit Segment 18*/
.quad 0x0000f20000000000 /*4 USER Data 64-bit Segment 20*/
.quad 0x00cf9a000000ffff /*5 KERNEL Code 32-bit Segment 28*/
.quad 0x00cf92000000ffff /*6 KERNEL Data 32-bit Segment 30*/
.fill 10,8,0 /*8 ~ 9 TSS (jmp one segment <7>) in long-mode 128-bit 40*/
GDT_END:
GDT_POINTER:
GDT_LIMIT: .word GDT_END - GDT_Table - 1
GDT_BASE: .quad GDT_Table
.quad 0x0020980000000000 /*1 KERNEL Code 64-bit Segment 08*/
这一串是代码段描述符 单个描述符长度是八字节
位于第二项即内核代码段选择子0x08
跳转到内核主程序
//======= 64-bit mode code
switch_seg:
.quad entry64
entry64:
movq $0x10, %rax
movq %rax, %ds
movq %rax, %es
movq %rax, %gs
movq %rax, %ss
movq $0xffff800000007E00, %rsp /* rsp address */
movq go_to_kernel(%rip), %rax /* movq address */
pushq $0x08
pushq %rax
lretq
go_to_kernel:
.quad Start_Kernel
movq go_to_kernel(%rip), %rax
Rip relative addressing RIP相对寻址
pushq $0x08
pushq %rax
lretq
相当于jmp 0x08 : rax
0x08
是内核代码段选择子
内核主程序 main.c
- 内核主程序
main.c
:目前只有一个死循环,目前只是提供一个内核主程序的入口;
void Start_Kernel(void)
{
while(1)
;
}
参考资料
- 四级页表结构
Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4
Volume 3 / CHAPTER 4 PAGING / 4.5 4-LEVEL PAGING
https://software.intel.com/en-us/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4
- Rip relative addressing
从机器码理解RIP 相对寻址https://www.cnblogs.com/papertree/p/6298763.html