commit 080d6d83136b1a7955e35f6f2bff74a0b3760cb7
parent 0177a332c666be1c03b59e8524fc425196147efe
Author: Armin Preiml <apreiml@strohwolke.at>
Date: Fri, 26 Nov 2021 13:34:04 +0100
add cpuid for x86_64 to check flags and vendor
Signed-off-by: Armin Preiml <apreiml@strohwolke.at>
Diffstat:
4 files changed, 187 insertions(+), 3 deletions(-)
diff --git a/rt/+x86_64/cpuid.ha b/rt/+x86_64/cpuid.ha
@@ -0,0 +1,119 @@
+export type cpuid_vendor = enum {
+ AMD,
+ INTEL,
+ WINCHIP,
+ TRANSMETA,
+ CYRIX,
+ CENTAUR,
+ NEXGEN,
+ UMC,
+ SIS,
+ NSC,
+ RISE,
+ VORTEX,
+ VIA,
+ ZHAOXIN,
+ HYGON,
+ MCST_ELBRUS,
+
+ // Virtual Machines.
+ VMWARE,
+ XENHVM,
+ MICROSOFT_HV,
+ PARALLELS,
+};
+
+export type cpuid_unknownvendor = !void;
+
+// cpuid vendor list taken from https://wiki.osdev.org/CPUID and
+// https://en.wikipedia.org/wiki/CPUID
+// Order and len matches the entries in the cpuid_vendor enum.
+const vendors: [_]str = [
+ "AuthenticAMD",
+ "GenuineIntel",
+ "CentaurHauls",
+ "GenuineTMx86",
+ "CyrixInstead",
+ "CentaurHauls",
+ "NexGenDriven",
+ "UMC UMC UMC ",
+ "SiS SiS SiS ",
+ "Geode by NSC",
+ "RiseRiseRise",
+ "Vortex86 SoC",
+ "VIA VIA VIA ",
+ " Shanghai ",
+ "HygonGenuine",
+ "E2K MACHINE",
+ "VMwareVMware",
+ "XenVMMXenVMM",
+ "Microsoft Hv",
+ " lrpepyh vr",
+];
+
+def VENDOR_OLDAMD: str = "AMDisbetter!";
+def VENDOR_OLDTRANSMETA: str = "TransmetaCPU";
+
+export type cpuid_edxflags = enum uint {
+ SSE = 1 << 25,
+ SSE2 = 1 << 26,
+};
+
+export type cpuid_ecxflags = enum uint {
+ SSE3 = 1 << 0,
+ AES = 1 << 25,
+};
+
+fn cpuid_getvendorstr(v: *[12]u8) void;
+
+fn cpuid_getfeatureflags(flags: *[2]u32) void;
+
+// Figures out cpu vendor using cpuid
+export fn cpuid_getvendor() (cpuid_vendor | cpuid_unknownvendor) = {
+ let vstr: [12]u8 = [0...];
+ cpuid_getvendorstr(&vstr);
+
+ for (let i = 0z; i < len(vendors); i += 1) {
+ if (bytes_equal(vstr, strings_toutf8(vendors[i]))) {
+ return i: cpuid_vendor;
+ };
+ };
+
+ // some vendors changed their strings in between cpu revisions
+ if (bytes_equal(vstr, strings_toutf8(VENDOR_OLDAMD))) {
+ return cpuid_vendor::AMD;
+ };
+
+ if (bytes_equal(vstr, strings_toutf8(VENDOR_OLDTRANSMETA))) {
+ return cpuid_vendor::TRANSMETA;
+ };
+
+ return cpuid_unknownvendor;
+};
+
+// Checks if cpu has given features. See [[cpuid_edxflags]] and
+// [[cpuid_ecxflags]] for available options.
+export fn cpuid_hasflags(edx: u32, ecx: u32) bool = {
+ let flags: [2]u32 = [0...];
+ cpuid_getfeatureflags(&flags);
+
+ return flags[0] & edx == edx && flags[1] & ecx == ecx;
+};
+
+// we can't use strings in rt so we add a helper here
+fn strings_toutf8(s: str) []u8 = {
+ return *(&s: *[]u8);
+};
+
+fn bytes_equal(a: []u8, b: []u8) bool = {
+ if (len(a) != len(b)) {
+ return false;
+ };
+
+ for (let i = 0z; i < len(a); i += 1) {
+ if (a[i] != b[i]) {
+ return false;
+ };
+ };
+ return true;
+};
diff --git a/rt/+x86_64/cpuid_native.s b/rt/+x86_64/cpuid_native.s
@@ -0,0 +1,41 @@
+.global rt.cpuid_getvendorstr
+.type rt.cpuid_getvendorstr,@function
+rt.cpuid_getvendorstr:
+ pushq %rdx
+ pushq %rcx
+ pushq %rbx
+
+ cpuid
+ movl %ebx, (%rdi)
+ movl %edx, 4(%rdi)
+ movl %ecx, 8(%rdi)
+
+ popq %rbx
+ popq %rcx
+ popq %rdx
+ ret
+
+.global rt.cpuid_getfeatureflags
+.type rt.cpuid_getfeatureflags,@function
+rt.cpuid_getfeatureflags:
+
+ pushq %rdx
+ pushq %rcx
+ pushq %rbx
+
+ movl $1, %eax
+ cpuid
+
+ movq %rdi, -0x8(%rsp)
+ movq -0x8(%rsp), %rax
+ movl %edx, (%rax)
+
+ movq -0x8(%rsp), %rax
+ add $0x4, %rax
+ movl %ecx, (%rax)
+
+ popq %rbx
+ popq %rcx
+ popq %rdx
+ ret
+
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -35,6 +35,7 @@ gensrcs_rt() {
'+$(ARCH)'/jmp.ha \
'+$(ARCH)'/backtrace.ha \
fenv_defs.ha \
+ +x86_64/cpuid.ha \
ensure.ha \
jmp.ha \
malloc.ha \
@@ -57,6 +58,7 @@ gensrcs_rt() {
+'$(ARCH)'/jmp.ha \
+'$(ARCH)'/backtrace.ha \
fenv_defs.ha \
+ +x86_64/cpuid.ha \
ensure.ha \
jmp.ha \
malloc.ha \
@@ -98,7 +100,8 @@ ${stdlib}_asm=\$($cache)/rt/syscall.o \\
\$($cache)/rt/restore.o \\
\$($cache)/rt/getfp.o \\
\$($cache)/rt/fenv.o \\
- \$($cache)/rt/start.o
+ \$($cache)/rt/start.o \\
+ \$($cache)/rt/cpuid_native.o
\$($cache)/rt/syscall.o: \$(STDLIB)/rt/+\$(PLATFORM)/syscall+\$(ARCH).s
@printf 'AS \t\$@\n'
@@ -130,6 +133,11 @@ ${stdlib}_asm=\$($cache)/rt/syscall.o \\
@mkdir -p \$($cache)/rt
@\$(AS) -o \$@ \$<
+\$($cache)/rt/cpuid_native.o: \$(STDLIB)/rt/+\$(ARCH)/cpuid_native.s
+ @printf 'AS \t\$@\n'
+ @mkdir -p \$($cache)/rt
+ @\$(AS) -o \$@ \$<
+
\$($cache)/rt/rt-linux.a: \$($cache)/rt/rt-linux.o \$(${stdlib}_asm)
@printf 'AR\t\$@\n'
@\$(AR) -csr \$@ \$($cache)/rt/rt-linux.o \$(${stdlib}_asm)
diff --git a/stdlib.mk b/stdlib.mk
@@ -19,6 +19,7 @@ stdlib_rt_linux_srcs= \
$(STDLIB)/rt/+$(ARCH)/jmp.ha \
$(STDLIB)/rt/+$(ARCH)/backtrace.ha \
$(STDLIB)/rt/fenv_defs.ha \
+ $(STDLIB)/rt/+x86_64/cpuid.ha \
$(STDLIB)/rt/ensure.ha \
$(STDLIB)/rt/jmp.ha \
$(STDLIB)/rt/malloc.ha \
@@ -44,6 +45,7 @@ stdlib_rt_freebsd_srcs= \
$(STDLIB)/rt/+$(ARCH)/jmp.ha \
$(STDLIB)/rt/+$(ARCH)/backtrace.ha \
$(STDLIB)/rt/fenv_defs.ha \
+ $(STDLIB)/rt/+x86_64/cpuid.ha \
$(STDLIB)/rt/ensure.ha \
$(STDLIB)/rt/jmp.ha \
$(STDLIB)/rt/malloc.ha \
@@ -77,7 +79,8 @@ stdlib_asm=$(HARECACHE)/rt/syscall.o \
$(HARECACHE)/rt/restore.o \
$(HARECACHE)/rt/getfp.o \
$(HARECACHE)/rt/fenv.o \
- $(HARECACHE)/rt/start.o
+ $(HARECACHE)/rt/start.o \
+ $(HARECACHE)/rt/cpuid_native.o
$(HARECACHE)/rt/syscall.o: $(STDLIB)/rt/+$(PLATFORM)/syscall+$(ARCH).s
@printf 'AS \t$@\n'
@@ -109,6 +112,11 @@ $(HARECACHE)/rt/getfp.o: $(STDLIB)/rt/+$(ARCH)/getfp.s
@mkdir -p $(HARECACHE)/rt
@$(AS) -o $@ $<
+$(HARECACHE)/rt/cpuid_native.o: $(STDLIB)/rt/+$(ARCH)/cpuid_native.s
+ @printf 'AS \t$@\n'
+ @mkdir -p $(HARECACHE)/rt
+ @$(AS) -o $@ $<
+
$(HARECACHE)/rt/rt-linux.a: $(HARECACHE)/rt/rt-linux.o $(stdlib_asm)
@printf 'AR\t$@\n'
@$(AR) -csr $@ $(HARECACHE)/rt/rt-linux.o $(stdlib_asm)
@@ -1910,6 +1918,7 @@ testlib_rt_linux_srcs= \
$(STDLIB)/rt/+$(ARCH)/jmp.ha \
$(STDLIB)/rt/+$(ARCH)/backtrace.ha \
$(STDLIB)/rt/fenv_defs.ha \
+ $(STDLIB)/rt/+x86_64/cpuid.ha \
$(STDLIB)/rt/ensure.ha \
$(STDLIB)/rt/jmp.ha \
$(STDLIB)/rt/malloc.ha \
@@ -1939,6 +1948,7 @@ testlib_rt_freebsd_srcs= \
$(STDLIB)/rt/+$(ARCH)/jmp.ha \
$(STDLIB)/rt/+$(ARCH)/backtrace.ha \
$(STDLIB)/rt/fenv_defs.ha \
+ $(STDLIB)/rt/+x86_64/cpuid.ha \
$(STDLIB)/rt/ensure.ha \
$(STDLIB)/rt/jmp.ha \
$(STDLIB)/rt/malloc.ha \
@@ -1976,7 +1986,8 @@ testlib_asm=$(TESTCACHE)/rt/syscall.o \
$(TESTCACHE)/rt/restore.o \
$(TESTCACHE)/rt/getfp.o \
$(TESTCACHE)/rt/fenv.o \
- $(TESTCACHE)/rt/start.o
+ $(TESTCACHE)/rt/start.o \
+ $(TESTCACHE)/rt/cpuid_native.o
$(TESTCACHE)/rt/syscall.o: $(STDLIB)/rt/+$(PLATFORM)/syscall+$(ARCH).s
@printf 'AS \t$@\n'
@@ -2008,6 +2019,11 @@ $(TESTCACHE)/rt/getfp.o: $(STDLIB)/rt/+$(ARCH)/getfp.s
@mkdir -p $(TESTCACHE)/rt
@$(AS) -o $@ $<
+$(TESTCACHE)/rt/cpuid_native.o: $(STDLIB)/rt/+$(ARCH)/cpuid_native.s
+ @printf 'AS \t$@\n'
+ @mkdir -p $(TESTCACHE)/rt
+ @$(AS) -o $@ $<
+
$(TESTCACHE)/rt/rt-linux.a: $(TESTCACHE)/rt/rt-linux.o $(testlib_asm)
@printf 'AR\t$@\n'
@$(AR) -csr $@ $(TESTCACHE)/rt/rt-linux.o $(testlib_asm)