// 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 #if defined(__i386__) || defined(__x86_64__) #include #include #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__) */