cpuid和序列号背后的那些故事( 二 )

本地没有msvc编译环境,就不做测试了 。
2.linux x86/amd64获取CPU ID在Linux上呢,我们也可以用C内联汇编来实现
#include <stdio.h>static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,unsigned int *ecx, unsigned int *edx){/* ecx is often an input as well as an output. */asm volatile("cpuid": "=a" (*eax),"=b" (*ebx),"=c" (*ecx),"=d" (*edx): "0" (*eax), "2" (*ecx));}int main(int argc, char **argv){unsigned eax, ebx, ecx, edx;eax = 1; /* processor info and feature bits */native_cpuid(&eax, &ebx, &ecx, &edx);printf("stepping %dn", eax & 0xF);printf("model %dn", (eax >> 4) & 0xF);printf("family %dn", (eax >> 8) & 0xF);printf("processor type %dn", (eax >> 12) & 0x3);printf("extended model %dn", (eax >> 16) & 0xF);printf("extended family %dn", (eax >> 20) & 0xFF);/* EDIT */eax = 3; /* processor serial number */native_cpuid(&eax, &ebx, &ecx, &edx);/** see the CPUID Wikipedia article on which models return the serialnumber in which registers. The example here is forPentium III */printf("cpu serial number 0x%08x%08xn", edx, ecx);native_cpuid这段代码来自linux kernel里的源码,其实gcc里有cpuid.h这个文件,它封装了ASM代码,直接引入即可 。
看下运行结果:
[root@localhost xx]# gcc cpu_x86.c -o cpu_x86[root@localhost xx]# ./cpu_x86stepping 4model 5family 6processor type 0extended model 5extended family 0serial number 0x0000000000000000【cpuid和序列号背后的那些故事】如上所示,eax, ebx, ecx, edx这四个寄存器对应的内容就是cpu id 。跟dmidecode的结果比较下,可以对应上 。
[root@localhost xx]# dmidecode -t 4# dmidecode 3.0Getting SMBIOS data from sysfs.SMBIOS 2.7 present.Handle 0x0004, DMI type 4, 42 bytesProcessor InformationSocket Designation: CPU #000Type: Central ProcessorFamily: UnknownManufacturer: GenuineIntelID: 54 06 05 00 FF FB AB 0FVersion: Intel(R) Xeon(R) Gold 6152 CPU @ 2.10GHzVoltage: 3.3 VExternal Clock: UnknownMax Speed: 30000 MHzCurrent Speed: 2100 MHzStatus: Populated, EnabledUpgrade: ZIF SocketL1 Cache Handle: 0x0016L2 Cache Handle: 0x0018L3 Cache Handle: Not ProvidedSerial Number: Not SpecifiedAsset Tag: Not SpecifiedPart Number: Not SpecifiedCore Count: 1Core Enabled: 1Characteristics:64-bit capableExecute Protection3.aarch64下获取CPU ID如果是aarch64架构,CPU架构不一样,就不能用同样的ASM汇编了,找了下ARM官方文档,
https://developer.arm.com/documentation/ddi0500/d/system-control/aarch64-register-descriptions/main-id-register–el1?lang=en,参考CPU架构,可以从MIDR_EL1寄存器获取
#include <stdio.h>int main(int argc, char **argv){unsigned long arm_cpuid;__asm__("mrs %0, MIDR_EL1" : "=r"(arm_cpuid));printf("%-20s: 0x%016lxn", "MIDR_EL1=", arm_cpuid);}输出如下
[root@master98 xx]# gcc cpu.c -o cpu[root@master98 xx]# ./cpuMIDR_EL1=: 0x00000000701f6633正好与dmidecode中的ID对应 。经过测试,重启后cpuid是不会改变的 。
4.CPU ID or Serial Number?JAVA代码里匹配的是Serial Number,这里一直说的是CPU ID,这俩东西到底是不是同一个事呢?
结论是: 1.CPU Serial Number是一个Embedded 96-bit code during chip fabrication,但废弃标准,不应该使用,而应该使用CPU ID来判断 。
2.因为涉及隐私问题(Serial Number is Readable by networks & Applications),现在的服务器架构已经不支持CPU Serial Number的获取了,用dmidecode获取到的Serial Number不保证有值的 。
3.CPU ID包含的是CPU架构的一些信息,更接近条形码的概念,并不是唯一身份标识,不保证唯一性 。
4.dmidecode在国产服务器架构下获取到的CPU Serial Number,其实又叫PSN(Processor Serial Number) 。之所以国产化服务器能拿到PSN,是因为国产服务器是aarch64架构,并且是自主化研发,并没有遵循Intel的规范 。另外同为国产化服务器,不同的厂家实现也不一样,有的重启即变,有的并不会变化 。关于PSN的开启,应该是可以在BIOS里配置 。其实,PSN should NOT exist at all 。为什么国产服务器还保留PSN,就不做过多展开了 。有兴趣的可以自行阅读PSN相关文档
最后,修改很简单,如果使用场景不严格,可以使用CPU ID,或者System Information中的UUID即可,两者都能保证重启不变,但System Information中的UUID能保证唯一性,而CPU ID不能。





推荐阅读