扩充内核 start.c 、kernel.asm详细解释
在前面堆栈,esp,GDT等内容还在Loader中,为了方便控制,我们得把它们放进内核才行。
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
start.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "const.h"
#include "protect.h"
PUBLIC void* memcpy(void* pDst, void* pSrc, int iSize);
PUBLIC void disp_str(char * pszInfo); //定义了两个函数
PUBLIC u8 gdt_ptr[6]; /* 0~15:Limit 16~47:Base */ //定义了一个gdt_ptr数组,6个U8大小,一共48个字节 gdt_ptr[0]limit
gdt_ptr[2]gdt基址
PUBLIC DESCRIPTOR gdt[GDT_SIZE]; //定义了一个全局gdt表 128*64字节大小
PUBLIC void cstart()
{
disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
"-----\"cstart\" begins-----\n");
/* 将 LOADER 中的 GDT 复制到新的 GDT 中 */
memcpy(&gdt, /* New GDT */ //把原来的gdt拷贝到现在的gdt中
(void*)(*((u32*)(&gdt_ptr[2]))), /* Base of Old GDT */
*((u16*)(&gdt_ptr[0])) + 1 /* Limit of Old GDT */
);
/* gdt_ptr[6] 共 6 个字节:0~15:Limit 16~47:Base。用作 sgdt/lgdt 的参数。*/
u16* p_gdt_limit = (u16*)(&gdt_ptr[0]); //定义了两个指针,p_gdt_limit,并指向gdt_ptr[0]这个地址
u32* p_gdt_base = (u32*)(&gdt_ptr[2]); // p_gdt_base,指向gdt_ptr[2]这个地址
*p_gdt_limit = GDT_SIZE * sizeof(DESCRIPTOR) - 1; // 由这两个指针,对gdt_ptr[0]、gdt_ptr[2]分别赋值,这时gdt_ptr
*p_gdt_base = (u32)&gdt; // 就得到新的值,基址指向新定义的gdt表。
}
--------------------------------------------------------------------------------------------------------------------------------------------------------------
kernel.asm
SELECTOR_KERNEL_CS equ 8 //如果按楼主的写法:a equ 8 jmp a:b 这里的8指的是偏移,即相对于GDT首地址的偏移是8个字节。
extern cstart // 导入函数
extern gdt_ptr //导入全局变量
[SECTION .bss] //bssBSS(Block Started by Symbol)通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。
StackSpace resb 2 * 1024 // 注意和数据段的区别,BSS存放的是未初始化的全局变量和静态变量,数据段存放的是初始化后的全局变量和静态变量。
StackTop: ; 栈顶
[section .text] // 代码在此
global _start // 导出 _start
_start:
; 把 esp 从 LOADER 挪到 KERNEL
mov esp, StackTop ; 堆栈在 bss 段中 //转移esp
sgdt [gdt_ptr] ; cstart() 中将会用到 gdt_ptr //保存gdt寄存器到[gdt_ptr],gdt_ptr是一个数组,gdt_ptr就是这个数组的首地址
call cstart // 在此函数中改变了gdt_ptr,让它指向新的GDT
lgdt [gdt_ptr] // 使用新的GDT
;lidt [idt_ptr]
jmp SELECTOR_KERNEL_CS:csinit
csinit: // “这个跳转指令强制使用刚刚初始化的结构”——<<OS:D&I 2nd>> P90.
push 0
popfd //Pop top of stack into EFLAGS
hlt //HLT 执行操作后,使机器暂停工作,使处理器CPU处于停机...
------------------------------------------------------------------------------------------------------------------------------------------------------------