一个操作系统的实现(7):内核雏形

一、boot.bin:
加载loader.bin到内存并运行,该内容及下面的加载内核的方法可查看前一篇文章。


二、loader.bin:
加载内核到内存、跳入保护模式、开启分段分页机制、重新放置内核并向内核交出控制权。
这里要分析的只有“重新放置内核并向内核交出控制权”,这段内容。

InitKernel:     ; 遍历每个Program Header,根据其中信息确定把什么放入内存,放到什么位置,以及放多少。
        xor     esi, esi
        mov     cx, word [BaseOfKernelFilePhyAddr + 2Ch]; \u2513 ecx <- pELFHdr->e_phnum
        movzx   ecx, cx                                 ; \u251b
        mov     esi, [BaseOfKernelFilePhyAddr + 1Ch]    ; esi <- pELFHdr->e_phoff
        add     esi, BaseOfKernelFilePhyAddr            ; esi <- OffsetOfKernel + pELFHdr->e_phoff
.Begin:
        mov     eax, [esi + 0]
        cmp     eax, 0                          ; PT_NULL
        jz      .NoAction
        push    dword [esi + 010h]              ; size  \u2513
        mov     eax, [esi + 04h]                ;       \u2503
        add     eax, BaseOfKernelFilePhyAddr    ;       \u2523 ::memcpy(     (void*)(pPHdr->p_vaddr),
        push    eax                             ; src   \u2503               uchCode + pPHdr->p_offset,
        push    dword [esi + 08h]               ; dst   \u2503               pPHdr->p_filesz;
        call    MemCpy                          ;       \u2503
        add     esp, 12                         ;       \u251b
.NoAction:
        add     esi, 020h                       ; esi += pELFHdr->e_phentsize
        dec     ecx
        jnz     .Begin


        ret
        ;***************************************************************
        jmp     SelectorFlatC:KernelEntryPointPhyAddr   ; 正式进入内核
        ;***************************************************************


KernelEntryPointPhyAddr的值是0x30400。这个值与内核编译时指定的入口地址一致。


三、kernel

_start:                         ;内核入口
	; 把 esp 从 LOADER 挪到 KERNEL
	mov	esp, StackTop	; 堆栈在 bss 段中


	mov	dword [disp_pos], 0


	sgdt	[gdt_ptr]	; cstart() 中将会用到 gdt_ptr
	call	cstart		; 1)在此函数中改变了gdt_ptr,让它指向新的GDT;  2)初始化中断、异常处理
	lgdt	[gdt_ptr]	; 使用新的GDT


	lidt	[idt_ptr]


	jmp	SELECTOR_KERNEL_CS:csinit
csinit:
	sti
	hlt



1)切换堆栈和GDT

PUBLIC void cstart()
{
	disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
		 "-----\"cstart\" begins-----\n");


	/* a)将 LOADER 中的 GDT 复制到新的 GDT 中 */
	memcpy(&gdt,				  /* New 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]);
	u32* p_gdt_base  = (u32*)(&gdt_ptr[2]);
	*p_gdt_limit = GDT_SIZE * sizeof(DESCRIPTOR) - 1;
	*p_gdt_base  = (u32)&gdt;


	/* idt_ptr[6] 共 6 个字节:0~15:Limit  16~47:Base。用作 sidt/lidt 的参数。*/
	u16* p_idt_limit = (u16*)(&idt_ptr[0]);
	u32* p_idt_base  = (u32*)(&idt_ptr[2]);
	*p_idt_limit = IDT_SIZE * sizeof(GATE) - 1;
	*p_idt_base  = (u32)&idt;


	2)初始化中断、异常处理
	init_prot();


	disp_str("-----\"cstart\" ends-----\n");
}


2)初始化中断、异常处理

PUBLIC void init_prot()
{
	init_8259A();


	// 全部初始化成中断门(没有陷阱门)
	init_idt_desc(INT_VECTOR_DIVIDE,	DA_386IGate,
		      divide_error,		PRIVILEGE_KRNL);


	init_idt_desc(INT_VECTOR_DEBUG,		DA_386IGate,
		      single_step_exception,	PRIVILEGE_KRNL);


	.
	.
	.


        init_idt_desc(INT_VECTOR_IRQ8 + 6,      DA_386IGate,
                      hwint14,                  PRIVILEGE_KRNL);


        init_idt_desc(INT_VECTOR_IRQ8 + 7,      DA_386IGate,
                      hwint15,                  PRIVILEGE_KRNL);
}

 *----------------------------------------------------------------------*
 初始化 386 中断门
 *======================================================================*/
PRIVATE void init_idt_desc(unsigned char vector, u8 desc_type,
			  int_handler handler, unsigned char privilege)
{
	GATE *	p_gate	= &idt[vector];
	u32	base	= (u32)handler;
	p_gate->offset_low	= base & 0xFFFF;
	p_gate->selector	= SELECTOR_KERNEL_CS;
	p_gate->dcount		= 0;
	p_gate->attr		= desc_type | (privilege << 5);
	p_gate->offset_high	= (base >> 16) & 0xFFFF;
}




你可能感兴趣的:(一个操作系统的实现(7):内核雏形)