当前位置:   article > 正文

Norlit OS —— 自制操作系统 第3章 长模式_长模式 ring0

长模式 ring0

3  长模式

3.1         何为长模式

本书虽然不是讲述64位操作系统的,但是讲到这里就快能够进入64位了,就写下这张供极客研究。不想看这章的话也可以直接跳过其余部分,只看3.3。这章的代码与前后一章是平行的,也就是说这章的代码是独立的。

长模式是AMD64(与IntelIA-32e)中的一个模式。进入长模式后,寄存器变成了64位,我们也可以访问64位的内存空间[1]了。长模式中也含有兼容模式,如果GDT中当前代码段的CS.L0,就会进入兼容模式。长模式忽略了分段,也就是说完全只靠分页机制。

多说也不说,先来掌握以下基本概念。

 

3.2         进入长模式的方法

我们知道,由实模式进入到保护模式由两步指令完成,CR0.PE=1和一个重载CS的跳转。

由保护模式进入长模式很相似,不过稍稍麻烦了点。我们看看步骤:

(1)    首先,要进入保护模式,即CR0.PE=1

(2)    其次,先初始化页表!但注意,千万不能打开先分页机制!

(3)    打开CR4.PAE

(4)    打开EFER.LME=1

(5)    打开CR0.PG=1,分页使能。

(6)    这时候处理器自动将EFER.LMA设置,进入长模式

(7)    一个跳转

你会想,这不是我们都做过的吗。但是,你错了,在长模式下,分页机制变成了4层。

3.2.1地址转换图

 

先来拿图吓你一下,不过我们不会马上讲。我们还不知道我们的CPU够不够格呢。

 

3.3         万能工具-CPUID的简单介绍

CPUID是一个指令,没有操作数。实际使用时,将一个入口参数放在EAX中然后执行指令CPUID,我们就可以在寄存器中找到CPU的各种特性。这个指令从486时代就有了。虽然我们应该先建立异常处理机制防止386的电脑出错(其实也可以用EFLAGS来判断CPUID是否可以用,但比之比较懒),但是现在已经没有386的电脑了,我们大可以缩小我们的操作系统能支持的范围。从486开始也包含了很多老式的电脑了呢。

         我们先来简单地熟悉一下CPUID命令。

        

CPUID指令功能号0h

入口参数

EAX

0h,表示获得基本信息

出口参数

EAX

最大可用功能号

EBX

Vendor(生产厂商)

Intel的处理器按顺序(EBXEDXECX)是

GenuineIntel

EDX

ECX

3.3.1 CPUIDEAX=0

 

由于CPUID内容实在太多,我把东西都放在cpuid.inc内,在loaderinclude了一下。

 

;=====================================================

; ShowCPUFeatures();显示CPU信息

;-----------------------------------------------------

; registers changed:

;   - All GPRs

ShowCPUFeatures:

   mov    esi, STR_CMIV

   call   DispStrPM

   mov    eax,0 ; CPU基本信息

   cpuid

   call   DispInt

   mov    [VENDOR],ebx

   mov    [VENDOR+4],edx

   mov    [VENDOR+8],ecx

   mov    esi,STR_VEN

   call   DispStrPM

   ret

   

_STR_CMIV  db13,10,"CPUIDMax Input Value: ",0

STR_CMIV   equ_STR_CMIV+LOADER_SEGPHYADDR

_STR_VEN   db13,10,"Vendor:"

_VENDOR    times13db0

STR_VEN    equ_STR_VEN+LOADER_SEGPHYADDR

VENDOR     equ _VENDOR+LOADER_SEGPHYADDR

代码3.3.1 ShowCPUFeatures V0.1(chapter3/a/boot/include/cpuid.inc)

 

         运行一下,看到最大Bochs支持的最大EAX0x5CPU厂商是GenuineIntel

 

3.3.1 CPUID V0.1(被笔者擅自去掉了干扰信息)

 

其实最重要的信息为功能号0x1,但是笔者比较想知道处理器的名字。其实我们也可以用CPUID功能号1获得CPU家族,但名字的话,这里我们要用到扩展CPUID指令。

 

扩展CPUID指令功能号80000000h

入口参数

EAX

80000000h,表示获得扩展信息

出口参数

EAX

最大可用扩展功能号

EBX

保留

EDX

ECX

3.3.2扩展CPUID

 

如果出口EAX=0表示不支持扩展CPUID指令。如果不为0,我们可以接着获得CPU名字了。

 

扩展CPUID指令功能号80000002h~80000004h

入口参数

EAX

80000002h~80000004h,表示获得处理器品牌字符串

出口参数

EAX~EDX

处理器品牌字符串的一部分。

 

   mov    eax,0x80000000; CPU扩展信息

   cpuid

   cmp    eax,0x80000004

   jb      .end         ;不支持就算了

   

   mov    esi, BRAND

   

   mov    eax,0x80000002

   cpuid

   mov    [esi],eax

   mov    [esi+4],ebx

   mov    [esi+8],ecx

   mov    [esi+12],edx

   add    esi,16

   mov    eax,0x80000003

   cpuid

   mov    [esi],eax

   mov    [esi+4],ebx

   mov    [esi+8],ecx

   mov    [esi+12],edx

   add    esi,16

   mov    eax,0x80000004

   cpuid

   mov    [esi],eax

   mov    [esi+4],ebx

   mov    [esi+8],ecx

   mov    [esi+12],edx

   

   mov    esi, STR_BRD

   call   DispStrPM

   

.end:

   ret

   

_STR_BRD   db13,10,"Brand:"

_BRAND     times65db0

 

STR_BRD    equ_STR_BRD+LOADER_SEGPHYADDR

BRAND     equ _BRAND+LOADER_SEGPHYADDR

代码3.3.2超长的代码 V1.0 (chapter3/a/boot/include/cpuid.inc)

 

虽然长了点,但是一点都不难。运行一下。

 

3.3.2笔者破电脑的CPUID

 

由于Hyper-V利用硬件虚拟化,所以这个CPUID就是笔者电脑本身的CPUID。而且与控制面板里的一模一样。Well done

好了,略微扯远了。我们现在就先看看这个CPU支不支持64位长模式。长模式标志位是0x80000001号扩展CPUID功能返回值EDX29位。

 

   mov    eax,0x80000001

   cpuid

   bt     edx,29

   jnc    .end

   

   mov    esi, STR_64

   call   DispStrPM

   

.end

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/1017350
推荐阅读
相关标签
  

闽ICP备14008679号