blob: 6a20b3944696fc3ee92ce1a79055d7c8da40c47e [file] [log] [blame]
// 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__) */