| // Copyright 2018 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| #include <stdint.h> |
| |
| #if defined(__i386__) || defined(__x86_64__) |
| #include <cpuid.h> |
| #include <x86intrin.h> |
| #endif |
| |
| #include "runtime.h" |
| |
| #if defined(__i386__) || defined(__x86_64__) |
| |
| struct cpuid_ret { |
| uint32_t eax; |
| uint32_t ebx; |
| uint32_t ecx; |
| uint32_t edx; |
| }; |
| |
| struct cpuid_ret cpuid(uint32_t, uint32_t) |
| __asm__(GOSYM_PREFIX "internal_1cpu.cpuid") |
| __attribute__((no_split_stack)); |
| |
| struct cpuid_ret cpuid(uint32_t eaxArg, uint32_t ecxArg) { |
| unsigned int eax = 0; |
| unsigned int ebx = 0; |
| unsigned int ecx = 0; |
| unsigned int edx = 0; |
| struct cpuid_ret ret; |
| |
| __get_cpuid_count(eaxArg, ecxArg, &eax, &ebx, &ecx, &edx); |
| ret.eax = (uint32_t)(eax); |
| ret.ebx = (uint32_t)(ebx); |
| ret.ecx = (uint32_t)(ecx); |
| ret.edx = (uint32_t)(edx); |
| return ret; |
| } |
| |
| struct xgetbv_ret { |
| uint32_t eax; |
| uint32_t edx; |
| }; |
| |
| struct xgetbv_ret xgetbv(void) |
| __asm__(GOSYM_PREFIX "internal_1cpu.xgetbv") |
| __attribute__((no_split_stack)); |
| |
| #pragma GCC push_options |
| #pragma GCC target("xsave") |
| |
| struct xgetbv_ret xgetbv(void) { |
| struct xgetbv_ret ret; |
| |
| // At some point, use call to _xgetbv() instead: |
| // |
| // long long r = _xgetbv(0); |
| // ret.eax = r & 0xffffffff; |
| // ret.edx = r >> 32; |
| // |
| unsigned int __eax, __edx, __xcr_no = 0; |
| __asm__ ("xgetbv" : "=a" (__eax), "=d" (__edx) : "c" (__xcr_no)); |
| ret.eax = __eax; |
| ret.edx = __edx; |
| return ret; |
| } |
| |
| #pragma GCC pop_options |
| |
| #endif /* defined(__i386__) || defined(__x86_64__) */ |
| |
| #ifdef __s390x__ |
| |
| struct facilityList { |
| uint64_t bits[4]; |
| }; |
| |
| struct queryResult { |
| uint64_t bits[2]; |
| }; |
| |
| struct facilityList stfle(void) |
| __asm__(GOSYM_PREFIX "internal_1cpu.stfle") |
| __attribute__((no_split_stack)); |
| |
| struct facilityList stfle(void) { |
| struct facilityList ret; |
| __asm__ ("la %%r1, %[ret]\t\n" |
| "lghi %%r0, 3\t\n" // last doubleword index to store |
| "xc 0(32,%%r1), 0(%%r1)\t\n" // clear 4 doublewords (32 bytes) |
| ".long 0xb2b01000\t\n" // store facility list extended (STFLE) |
| :[ret] "=Q" (ret) : : "r0", "r1", "cc"); |
| return ret; |
| } |
| |
| struct queryResult kmQuery(void) |
| __asm__(GOSYM_PREFIX "internal_1cpu.kmQuery") |
| __attribute__((no_split_stack)); |
| |
| struct queryResult kmQuery() { |
| struct queryResult ret; |
| |
| __asm__ ("lghi %%r0, 0\t\n" // set function code to 0 (KM-Query) |
| "la %%r1, %[ret]\t\n" |
| ".long 0xb92e0024\t\n" // cipher message (KM) |
| :[ret] "=Q" (ret) : : "r0", "r1", "cc"); |
| return ret; |
| } |
| |
| struct queryResult kmcQuery(void) |
| __asm__(GOSYM_PREFIX "internal_1cpu.kmcQuery") |
| __attribute__((no_split_stack)); |
| |
| struct queryResult kmcQuery() { |
| struct queryResult ret; |
| |
| __asm__ ("lghi %%r0, 0\t\n" // set function code to 0 (KMC-Query) |
| "la %%r1, %[ret]\t\n" |
| ".long 0xb92f0024\t\n" // cipher message with chaining (KMC) |
| :[ret] "=Q" (ret) : : "r0", "r1", "cc"); |
| |
| return ret; |
| } |
| |
| struct queryResult kmctrQuery(void) |
| __asm__(GOSYM_PREFIX "internal_1cpu.kmctrQuery") |
| __attribute__((no_split_stack)); |
| |
| struct queryResult kmctrQuery() { |
| struct queryResult ret; |
| |
| __asm__ ("lghi %%r0, 0\t\n" // set function code to 0 (KMCTR-Query) |
| "la %%r1, %[ret]\t\n" |
| ".long 0xb92d4024\t\n" // cipher message with counter (KMCTR) |
| :[ret] "=Q" (ret) : : "r0", "r1", "cc"); |
| |
| return ret; |
| } |
| |
| struct queryResult kmaQuery(void) |
| __asm__(GOSYM_PREFIX "internal_1cpu.kmaQuery") |
| __attribute__((no_split_stack)); |
| |
| struct queryResult kmaQuery() { |
| struct queryResult ret; |
| |
| __asm__ ("lghi %%r0, 0\t\n" // set function code to 0 (KMA-Query) |
| "la %%r1, %[ret]\t\n" |
| ".long 0xb9296024\t\n" // cipher message with authentication (KMA) |
| :[ret] "=Q" (ret) : : "r0", "r1", "cc"); |
| |
| return ret; |
| } |
| |
| struct queryResult kimdQuery(void) |
| __asm__(GOSYM_PREFIX "internal_1cpu.kimdQuery") |
| __attribute__((no_split_stack)); |
| |
| struct queryResult kimdQuery() { |
| struct queryResult ret; |
| |
| __asm__ ("lghi %%r0, 0\t\n" // set function code to 0 (KIMD-Query) |
| "la %%r1, %[ret]\t\n" |
| ".long 0xb93e0024\t\n" // compute intermediate message digest (KIMD) |
| :[ret] "=Q" (ret) : : "r0", "r1", "cc"); |
| |
| return ret; |
| } |
| |
| struct queryResult klmdQuery(void) |
| __asm__(GOSYM_PREFIX "internal_1cpu.klmdQuery") |
| __attribute__((no_split_stack)); |
| |
| struct queryResult klmdQuery() { |
| struct queryResult ret; |
| |
| __asm__ ("lghi %%r0, 0\t\n" // set function code to 0 (KLMD-Query) |
| "la %%r1, %[ret]\t\n" |
| ".long 0xb93f0024\t\n" // compute last message digest (KLMD) |
| :[ret] "=Q" (ret) : : "r0", "r1", "cc"); |
| |
| return ret; |
| } |
| |
| struct queryResult kdsaQuery(void) |
| __asm__(GOSYM_PREFIX "internal_1cpu.kdsaQuery") |
| __attribute__((no_split_stack)); |
| |
| struct queryResult kdsaQuery() { |
| struct queryResult ret; |
| |
| __asm__ ("lghi %%r0, 0\t\n" // set function code to 0 (KDSA-Query) |
| "la %%r1, %[ret]\t\n" |
| ".long 0xb93a0024\t\n" // kdsa |
| :[ret] "=QRST" (ret) : : "r0", "r1", "cc"); |
| |
| return ret; |
| } |
| |
| #endif /* defined(__s390x__) */ |
| |
| #ifdef __aarch64__ |
| |
| uint64_t getisar0(void) |
| __asm__(GOSYM_PREFIX "internal_1cpu.getisar0") |
| __attribute__((no_split_stack)); |
| |
| uint64_t getisar0() { |
| uint64_t isar0; |
| |
| __asm__("mrs %0,id_aa64isar0_el1" : "=r"(isar0)); |
| return isar0; |
| } |
| |
| uint64_t getMIDR(void) |
| __asm__(GOSYM_PREFIX "internal_1cpu.getMIDR") |
| __attribute__((no_split_stack)); |
| |
| uint64_t getMIDR() { |
| uint64_t MIDR; |
| |
| __asm__("mrs %0,midr_el1" : "=r"(MIDR)); |
| return MIDR; |
| } |
| |
| #endif /* defined(__aarch64__) */ |