操作系统实践之重置GDT

   为了进入保护模式,首先需要在实模式下设置GDT,并用lgdt指令保存GDT的地址,这个地址实际上是线性地址,只是在实模式中线性地址就是物理地址;当控制权转到内核时需要将GDT重新设置一下,以便在内核中设置GDT,为了保证这一点需要在设置GDT之前,通过分页机制仍然能够找到原先的GDT,即线性地址要映射到相同的物理地址中,否则就找不到原来的GDT,无法进行拷贝。在本次操作系统实践中,分页机制非常简单即f(线性地址)=物理地址,所以可以保证这一点,下面是内核重置GDT的代码:

;kernel.asm

SELECTOR_KERNEL_CS equ 0x10
extern cstart
extern gdt_ptr
[section .bss]
StackSpace resb 2*1024
StackTop equ $
[section .text]
global _start
_start:
  mov esp, StackTop;把esp从Loader挪到kernel
  sgdt [gdt_ptr];加载原先的GDT
  call cstart
  lgdt [gdt_ptr];使用新的GDT
  jmp SELECTOR_KERNEL_CS:csinit
csinit:
  mov ah, 0Fh
  mov al, 'K'
  mov [gs:((80 * 1 + 39) * 2)], ax
  jmp $

#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 t_8   gdt_ptr[6]; // 0~15:Limit  16~47:Base
PUBLIC DESCRIPTOR  gdt[GDT_SIZE];

 

//start.c设置新的GDT
PUBLIC void cstart()
{

 // 将 LOADER 中的 GDT 复制到新的 GDT 中
 memcpy( gdt,        // New GDT
  (void*)(*((t_32*)(&gdt_ptr[2]))),   // Base  of Old GDT
  *((t_16*)(&gdt_ptr[0])) + 1     // Limit of Old GDT
  );
 // gdt_ptr[6] 共 6 个字节:0~15:Limit  16~47:Base。用作 sgdt 以及 lgdt 的参数。
 t_16* p_gdt_limit = (t_16*)(&gdt_ptr[0]);
 t_32* p_gdt_base  = (t_32*)(&gdt_ptr[2]);
 *p_gdt_limit = GDT_SIZE * sizeof(DESCRIPTOR) - 1;
 *p_gdt_base  = (t_32)gdt;
}

你可能感兴趣的:(操作系统)