[OS64][033] 源码阅读:程序8-2 物理机器 CPUID 查询处理器固件信息

学习笔记

使用教材(配书源码以及使用方法)
《一个64位操作系统的设计与实现》
http://www.ituring.com.cn/book/2450
https://www.jianshu.com/p/28f9713a9171

源码结构

  • 配书代码包 :第8章 \ 程序 \ 程序8-2

实验操作

1、虚拟机:生成boot.bin 、loader.bin以及kernel.bin 并复制到U盘

[anno@localhost 32MB-bootloader]$ 
sudo dd if=boot.bin of=/dev/sdb bs=512 count=1 conv=notrunc

[anno@localhost 物理平台]$ cd kernel
[anno@localhost kernel]$ make
gcc -E head.S > head.s
as --64 -o head.o head.s
gcc -E entry.S > entry.s
as --64 -o entry.o entry.s
gcc  -mcmodel=large -fno-builtin -m64 -c main.c
gcc  -mcmodel=large -fno-builtin -m64 -c printk.c
gcc  -mcmodel=large -fno-builtin -m64 -c trap.c
gcc  -mcmodel=large -fno-builtin -m64 -c memory.c
gcc  -mcmodel=large -fno-builtin -m64 -c interrupt.c
gcc  -mcmodel=large -fno-builtin -m64 -c task.c 
gcc  -mcmodel=large -fno-builtin -m64 -c cpu.c
ld -b elf64-x86-64 -z muldefs -o system head.o entry.o main.o printk.o trap.o memory.o interrupt.o task.o cpu.o -T Kernel.lds 
objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary system kernel.bin

根据自己使用的U盘,修改bootloader部分源码的方法参见
[OS64][031]实验操作:程序7-3 移植到物理平台 U盘启动
https://www.jianshu.com/p/a84b45ae3219

  • 其实程序8-2程序7-3使用的bootloader代码是一致的,如果在程序7-3的实验中已经按照自己的U盘规格制作好了boot.binloader.bin可以直接拿来用了

2、物理机器:插上U盘,显示运行画面

[OS64][033] 源码阅读:程序8-2 物理机器 CPUID 查询处理器固件信息_第1张图片
程序8-2 运行画面

源码阅读

get_cpuid 用于获取处理器固件信息

CPUID指令将通过EAX寄存器输入查询的主功能号,如果有需要,则再向ECX寄存器输入查询的子功能号。
当这条汇编指令执行结束后,查询的返回值将保存在EAX、EBX、ECX和EDX寄存器

代码清单8-4 第8章\程序\程序8-2\物理平台\kernel\cpu.h

inline void get_cpuid(unsigned int Mop,
    unsigned int Sop,
    unsigned int * a,
    unsigned int * b,
    unsigned int * c,
    unsigned int * d)
{
    __asm__ __volatile__    (    "cpuid    \n\t"
                                 :"=a"(*a),"=b"(*b),"=c"(*c),"=d"(*d)
                                 :"0"(Mop),"2"(Sop)
                            );
}

  • CPUID汇编指令封装成get_cpuid函数
  • MopSop参数用于向CPUID指令传递主功能号子功能号
  • 将查询的返回值保存到指针变量a、b、c和d指向的内存

init_cpu() 中调用 get_cpuid(...)

void init_cpu(void)
{
    int i,j;
    unsigned int CpuFacName[4] = {0,0,0,0};
    char    FactoryName[17] = {0};

    //vendor_string
    get_cpuid(0,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);

    *(unsigned int*)&FactoryName[0] = CpuFacName[1];

    *(unsigned int*)&FactoryName[4] = CpuFacName[3];

    *(unsigned int*)&FactoryName[8] = CpuFacName[2];    

    FactoryName[12] = '\0';
    color_printk(YELLOW,BLACK,"%s\t%#010x\t%#010x\t%#010x\n",FactoryName,CpuFacName[1],CpuFacName[3],CpuFacName[2]);
    
    //brand_string
    for(i = 0x80000002;i < 0x80000005;i++)
    {
        get_cpuid(i,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);

        *(unsigned int*)&FactoryName[0] = CpuFacName[0];

        *(unsigned int*)&FactoryName[4] = CpuFacName[1];

        *(unsigned int*)&FactoryName[8] = CpuFacName[2];

        *(unsigned int*)&FactoryName[12] = CpuFacName[3];

        FactoryName[16] = '\0';
        color_printk(YELLOW,BLACK,"%s",FactoryName);
    }
    color_printk(YELLOW,BLACK,"\n");

    //Version Informatin Type,Family,Model,and Stepping ID
    get_cpuid(1,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
    color_printk(YELLOW,BLACK,"Family Code:%#010x,Extended Family:%#010x,Model Number:%#010x,Extended Model:%#010x,Processor Type:%#010x,Stepping ID:%#010x\n",(CpuFacName[0] >> 8 & 0xf),(CpuFacName[0] >> 20 & 0xff),(CpuFacName[0] >> 4 & 0xf),(CpuFacName[0] >> 16 & 0xf),(CpuFacName[0] >> 12 & 0x3),(CpuFacName[0] & 0xf));

    //get Linear/Physical Address size
    get_cpuid(0x80000008,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
    color_printk(YELLOW,BLACK,"Physical Address size:%08d,Linear Address size:%08d\n",(CpuFacName[0] & 0xff),(CpuFacName[0] >> 8 & 0xff));

    //max cpuid operation code
    get_cpuid(0,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
    color_printk(WHITE,BLACK,"MAX Basic Operation Code :%#010x\t",CpuFacName[0]);

    get_cpuid(0x80000000,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
    color_printk(WHITE,BLACK,"MAX Extended Operation Code :%#010x\n",CpuFacName[0]);


}

功能号 0x00 获取处理器的供应商标识

功能号 0x00 获取处理器的供应商标识
  • get_cpuid(0,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]); 传入的功能号0x00
  • *(unsigned int*)&FactoryName[0] = CpuFacName[1];
    其中 CpuFacName[1] = 0x756e6547 代表 "Genu"
  • *(unsigned int*)&FactoryName[0] 先取FactoryName[0]的地址,然后就是将 0x756e6547 填入FactoryName[0] FactoryName[1] FactoryName[2] FactoryName[3]
  • color_printk(YELLOW,BLACK,"%s\t%#010x\t%#010x\t%#010x\n",FactoryName,CpuFacName[1],CpuFacName[3],CpuFacName[2]); 其中 %s0x756e6547 看做字符串 Genu输出,%#010x直接输出数值0x756e6547

功能号0x80002~0x80004 获取处理器商标信息

功能号0x80002~0x80004 获取处理器商标信息
  • for(i = 0x80000002;i < 0x80000005;i++) { }

init_cpu() 在何处被调用 ?

通常情况下,这些数据(处理器固件信息),应该最先被操作系统捕获,随后操作系统再根据处理器的固件信息来确定处理器支持的功能,以便进一步初始化处理器。
因此,将init_cpu函数插入到系统异常处理功能的初始化函数( sys_vector_init();)之后会更妥当一些

代码清单8-6 第8章\程序\程序8-2\物理平台\kernel\main.c

void Start_Kernel(void)
{
    ……
    sys_vector_init();

    init_cpu();
    ……
}

参考资料

[ATT汇编]程序举例:xxx.S 编译、链接、运行、调试 (CPUID命令 显示处理器厂商信息)
https://www.jianshu.com/p/91506500523a

[内联汇编]扩展asm:格式、占位符、跳转、内联汇编宏函数
https://www.jianshu.com/p/76fda24ee7f7

你可能感兴趣的:([OS64][033] 源码阅读:程序8-2 物理机器 CPUID 查询处理器固件信息)