8309258: RISC-V: Add riscv_hwprobe syscall

Reviewed-by: fjiang, stuefe, fyang, luhenry
This commit is contained in:
Robbin Ehn 2023-06-20 15:12:46 +00:00
parent 4a9cc8a000
commit 31b6fd775f
5 changed files with 529 additions and 109 deletions

@ -1,6 +1,7 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2023, Rivos Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -30,10 +31,20 @@
#include "utilities/formatBuffer.hpp"
#include "utilities/macros.hpp"
const char* VM_Version::_uarch = "";
const char* VM_Version::_vm_mode = "";
#include <ctype.h>
uint32_t VM_Version::_initial_vector_length = 0;
#define DEF_RV_FEATURE(NAME, PRETTY, BIT, FSTRING, FLAGF) \
VM_Version::NAME##RVFeatureValue VM_Version::NAME(PRETTY, BIT, FSTRING);
RV_FEATURE_FLAGS(DEF_RV_FEATURE)
#define ADD_RV_FEATURE_IN_LIST(NAME, PRETTY, BIT, FSTRING, FLAGF) \
&VM_Version::NAME,
VM_Version::RVFeatureValue* VM_Version::_feature_list[] = {
RV_FEATURE_FLAGS(ADD_RV_FEATURE_IN_LIST)
nullptr};
void VM_Version::initialize() {
_supports_cx8 = true;
_supports_atomic_getset4 = true;
@ -41,13 +52,14 @@ void VM_Version::initialize() {
_supports_atomic_getset8 = true;
_supports_atomic_getadd8 = true;
get_os_cpu_info();
setup_cpu_available_features();
// check if satp.mode is supported, currently supports up to SV48(RV64)
if (get_satp_mode() > VM_SV48) {
if (satp_mode.value() > VM_SV48 || satp_mode.value() < VM_MBARE) {
vm_exit_during_initialization(
err_msg("Unsupported satp mode: %s. Only satp modes up to sv48 are supported for now.",
_vm_mode));
err_msg(
"Unsupported satp mode: SV%d. Only satp modes up to sv48 are supported for now.",
(int)satp_mode.value()));
}
// https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva20-profiles
@ -165,16 +177,16 @@ void VM_Version::initialize() {
}
if (UseRVV) {
if (!(_features & CPU_V)) {
if (!ext_V.enabled()) {
warning("RVV is not supported on this CPU");
FLAG_SET_DEFAULT(UseRVV, false);
} else {
// read vector length from vector CSR vlenb
_initial_vector_length = get_current_vector_length();
_initial_vector_length = cpu_vector_length();
}
}
if (UseRVC && !(_features & CPU_C)) {
if (UseRVC && !ext_C.enabled()) {
warning("RVC is not supported on this CPU");
FLAG_SET_DEFAULT(UseRVC, false);
@ -185,7 +197,11 @@ void VM_Version::initialize() {
}
if (FLAG_IS_DEFAULT(AvoidUnalignedAccesses)) {
FLAG_SET_DEFAULT(AvoidUnalignedAccesses, true);
if (unaligned_access.value() != MISALIGNED_FAST) {
FLAG_SET_DEFAULT(AvoidUnalignedAccesses, true);
} else {
FLAG_SET_DEFAULT(AvoidUnalignedAccesses, false);
}
}
if (UseZbb) {
@ -208,16 +224,6 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(UseBlockZeroing, false);
}
char buf[512];
buf[0] = '\0';
if (_uarch != nullptr && strcmp(_uarch, "") != 0) snprintf(buf, sizeof(buf), "%s,", _uarch);
strcat(buf, "rv64");
#define ADD_FEATURE_IF_SUPPORTED(id, name, bit) if (_features & CPU_##id) strcat(buf, name);
CPU_FEATURE_FLAGS(ADD_FEATURE_IF_SUPPORTED)
#undef ADD_FEATURE_IF_SUPPORTED
_features_string = os::strdup(buf);
#ifdef COMPILER2
c2_initialize();
#endif // COMPILER2
@ -333,6 +339,6 @@ void VM_Version::initialize_cpu_information(void) {
_no_of_threads = _no_of_cores;
_no_of_sockets = _no_of_cores;
snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "RISCV64");
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", _features_string);
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", features_string());
_initialized = true;
}

@ -2,6 +2,7 @@
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2023, Rivos Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -30,55 +31,176 @@
#include "runtime/abstract_vm_version.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals_extension.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/sizes.hpp"
class RiscvHwprobe;
class VM_Version : public Abstract_VM_Version {
friend RiscvHwprobe;
private:
class RVFeatureValue {
const char* const _pretty;
const bool _feature_string;
const uint64_t _feature_bit;
bool _enabled;
int64_t _value;
public:
RVFeatureValue(const char* pretty, int bit_num, bool fstring) :
_pretty(pretty), _feature_string(fstring), _feature_bit(nth_bit(bit_num)),
_enabled(false), _value(-1) {
}
void enable_feature(int64_t value = 0) {
_enabled = true;
_value = value;
}
const char* const pretty() { return _pretty; }
const uint64_t feature_bit() { return _feature_bit; }
const bool feature_string() { return _feature_string; }
bool enabled() { return _enabled; }
int64_t value() { return _value; }
virtual void update_flag() = 0;
};
#define UPDATE_DEFAULT(flag) \
void update_flag() { \
assert(enabled(), "Must be."); \
if (FLAG_IS_DEFAULT(flag)) { \
FLAG_SET_DEFAULT(flag, true); \
} \
} \
#define NO_UPDATE_DEFAULT \
void update_flag() {} \
// Frozen standard extensions
// I RV64I
// M Integer Multiplication and Division
// A Atomic Instructions
// F Single-Precision Floating-Point
// D Single-Precision Floating-Point
// (G = M + A + F + D)
// Q Quad-Precision Floating-Point
// C Compressed Instructions
// H Hypervisor
//
// Others, open and non-standard
// V Vector
//
// Cache Management Operations
// Zicbom Cache Block Management Operations
// Zicboz Cache Block Zero Operations
// Zicbop Cache Block Prefetch Operations
//
// Bit-manipulation
// Zba Address generation instructions
// Zbb Basic bit-manipulation
// Zbc Carry-less multiplication
// Zbs Single-bit instructions
//
// Zicsr Control and Status Register (CSR) Instructions
// Zifencei Instruction-Fetch Fence
// Zic64b Cache blocks must be 64 bytes in size, naturally aligned in the address space.
// Zihintpause Pause instruction HINT
//
// Other features and settings
// mvendorid Manufactory JEDEC id encoded, ISA vol 2 3.1.2..
// marchid Id for microarch. Mvendorid plus marchid uniquely identify the microarch.
// mimpid A unique encoding of the version of the processor implementation.
// unaligned_access Unaligned memory accesses (unknown, unspported, emulated, slow, firmware, fast)
// satp mode SATP bits (number of virtual addr bits) mbare, sv39, sv48, sv57, sv64
#define RV_NO_FLAG_BIT (BitsPerWord+1) // nth_bit will return 0 on values larger than BitsPerWord
// declaration name , extension name, bit pos ,in str, mapped flag)
#define RV_FEATURE_FLAGS(decl) \
decl(ext_I , "i" , ('I' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_M , "m" , ('M' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_A , "a" , ('A' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_F , "f" , ('F' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_D , "d" , ('D' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_C , "c" , ('C' - 'A'), true , UPDATE_DEFAULT(UseRVC)) \
decl(ext_Q , "q" , ('Q' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_H , "h" , ('H' - 'A'), true , NO_UPDATE_DEFAULT) \
decl(ext_V , "v" , ('V' - 'A'), true , UPDATE_DEFAULT(UseRVV)) \
decl(ext_Zicbom , "Zicbom" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbom)) \
decl(ext_Zicboz , "Zicboz" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicboz)) \
decl(ext_Zicbop , "Zicbop" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbop)) \
decl(ext_Zba , "Zba" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZba)) \
decl(ext_Zbb , "Zbb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \
decl(ext_Zbc , "Zbc" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zbs , "Zbs" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \
decl(ext_Zicsr , "Zicsr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zifencei , "Zifencei" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zic64b , "Zic64b" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \
decl(ext_Zihintpause , "Zihintpause" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \
decl(mvendorid , "VendorId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
decl(marchid , "ArchId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
decl(mimpid , "ImpId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
decl(unaligned_access, "Unaligned" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
decl(satp_mode , "SATP" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \
#define DECLARE_RV_FEATURE(NAME, PRETTY, BIT, FSTRING, FLAGF) \
struct NAME##RVFeatureValue : public RVFeatureValue { \
NAME##RVFeatureValue(const char* pretty, int bit, bool fstring) : \
RVFeatureValue(pretty, bit, fstring) {} \
FLAGF; \
}; \
static NAME##RVFeatureValue NAME; \
RV_FEATURE_FLAGS(DECLARE_RV_FEATURE)
#undef DECLARE_RV_FEATURE
// VM modes (satp.mode) privileged ISA 1.10
enum VM_MODE : int {
VM_NOTSET = -1,
VM_MBARE = 0,
VM_SV39 = 39,
VM_SV48 = 48,
VM_SV57 = 57,
VM_SV64 = 64
};
static VM_MODE parse_satp_mode(const char* vm_mode);
// Values from riscv_hwprobe()
enum UNALIGNED_ACCESS : int {
MISALIGNED_UNKNOWN = 0,
MISALIGNED_EMULATED = 1,
MISALIGNED_SLOW = 2,
MISALIGNED_FAST = 3,
MISALIGNED_UNSUPPORTED = 4
};
// Null terminated list
static RVFeatureValue* _feature_list[];
// Enables features in _feature_list
static void setup_cpu_available_features();
// Helper for specific queries
static void os_aux_features();
static char* os_uarch_additional_features();
static void vendor_features();
// Vendors specific features
static void rivos_features();
// Determine vector length iff ext_V/UseRVV
static uint32_t cpu_vector_length();
static uint32_t _initial_vector_length;
#ifdef COMPILER2
private:
static void c2_initialize();
#endif // COMPILER2
// VM modes (satp.mode) privileged ISA 1.10
enum VM_MODE {
VM_MBARE = 0,
VM_SV39 = 8,
VM_SV48 = 9,
VM_SV57 = 10,
VM_SV64 = 11
};
protected:
static const char* _uarch;
static const char* _vm_mode;
static uint32_t _initial_vector_length;
static void get_os_cpu_info();
static uint32_t get_current_vector_length();
static VM_MODE get_satp_mode();
public:
public:
// Initialization
static void initialize();
static void initialize_cpu_information();
constexpr static bool supports_stack_watermark_barrier() { return true; }
static bool supports_on_spin_wait() { return UseZihintpause; }
enum Feature_Flag {
#define CPU_FEATURE_FLAGS(decl) \
decl(I, "i", 8) \
decl(M, "m", 12) \
decl(A, "a", 0) \
decl(F, "f", 5) \
decl(D, "d", 3) \
decl(C, "c", 2) \
decl(V, "v", 21)
#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (1 << bit),
CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG)
#undef DECLARE_CPU_FEATURE_FLAG
};
static void initialize_cpu_information(void);
};
#endif // CPU_RISCV_VM_VERSION_RISCV_HPP

@ -0,0 +1,136 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, Rivos Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "logging/log.hpp"
#include "riscv_hwprobe.hpp"
#include "runtime/os.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/debug.hpp"
#include <sched.h>
#include <sys/syscall.h>
#include <unistd.h>
// Syscall defined in kernel 6.4 and the defines will be in asm/hwprobe.h
#define RISCV_HWPROBE_KEY_MVENDORID 0
#define RISCV_HWPROBE_KEY_MARCHID 1
#define RISCV_HWPROBE_KEY_MIMPID 2
#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3
#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0)
#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
#define RISCV_HWPROBE_IMA_FD (1 << 0)
#define RISCV_HWPROBE_IMA_C (1 << 1)
#define RISCV_HWPROBE_KEY_CPUPERF_0 5
#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0)
#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0)
#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0)
#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0)
#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0)
#ifndef NR_riscv_hwprobe
#ifndef NR_arch_specific_syscall
#define NR_arch_specific_syscall 244
#endif
#define NR_riscv_hwprobe (NR_arch_specific_syscall + 14)
#endif
struct riscv_hwprobe {
int64_t key;
uint64_t value;
};
long sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pairc,
size_t cpuc, cpu_set_t *cpus,
unsigned int flags) {
return syscall(NR_riscv_hwprobe, pairs, pairc, cpuc, cpus, 0 /* flags*/);
}
static bool rw_hwprobe_completed = false;
static struct riscv_hwprobe query[] = {{RISCV_HWPROBE_KEY_MVENDORID, 0},
{RISCV_HWPROBE_KEY_MARCHID, 0},
{RISCV_HWPROBE_KEY_MIMPID, 0},
{RISCV_HWPROBE_KEY_BASE_BEHAVIOR, 0},
{RISCV_HWPROBE_KEY_IMA_EXT_0, 0},
{RISCV_HWPROBE_KEY_CPUPERF_0, 0}};
bool RiscvHwprobe::probe_features() {
assert(!rw_hwprobe_completed, "Called twice.");
int ret = sys_riscv_hwprobe(&query[0], sizeof(query) / sizeof(query[0]), 0, nullptr, 0);
rw_hwprobe_completed = true;
if (ret != 0) {
log_debug(os, cpu)("riscv_hwprobe unsupported");
return false;
}
log_debug(os, cpu)("riscv_hwprobe supported");
add_features_from_query_result();
return true;
}
static bool is_valid(int64_t key) {
return query[key].key != -1;
}
static bool is_set(int64_t key, uint64_t value_mask) {
if (is_valid(key)) {
return query[key].value & value_mask != 0;
}
return false;
}
void RiscvHwprobe::add_features_from_query_result() {
assert(rw_hwprobe_completed, "hwprobe not init yet.");
if (is_valid(RISCV_HWPROBE_KEY_MVENDORID)) {
VM_Version::mvendorid.enable_feature(query[RISCV_HWPROBE_KEY_MVENDORID].value);
}
if (is_valid(RISCV_HWPROBE_KEY_MARCHID)) {
VM_Version::marchid.enable_feature(query[RISCV_HWPROBE_KEY_MARCHID].value);
}
if (is_valid(RISCV_HWPROBE_KEY_MIMPID)) {
VM_Version::mimpid.enable_feature(query[RISCV_HWPROBE_KEY_MIMPID].value);
}
if (is_set(RISCV_HWPROBE_KEY_BASE_BEHAVIOR, RISCV_HWPROBE_BASE_BEHAVIOR_IMA)) {
VM_Version::ext_I.enable_feature();
VM_Version::ext_M.enable_feature();
VM_Version::ext_A.enable_feature();
}
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_IMA_FD)) {
VM_Version::ext_F.enable_feature();
VM_Version::ext_D.enable_feature();
}
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_IMA_C)) {
VM_Version::ext_C.enable_feature();
}
if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) {
VM_Version::unaligned_access.enable_feature(
query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK);
}
}

@ -0,0 +1,39 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, Rivos Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef OS_LINUX_RISCV_HWPROBE_LINUX_HPP
#define OS_LINUX_RISCV_HWPROBE_LINUX_HPP
#include "memory/allStatic.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/growableArray.hpp"
class RiscvHwprobe: public AllStatic {
static void add_features_from_query_result();
public:
static bool probe_features();
};
#endif // OS_LINUX_RISCV_HWPROBE_LINUX_HPP

@ -1,6 +1,7 @@
/*
* Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2023, Rivos Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,39 +26,50 @@
#include "precompiled.hpp"
#include "asm/register.hpp"
#include "logging/log.hpp"
#include "riscv_hwprobe.hpp"
#include "runtime/os.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/vm_version.hpp"
#include <asm/hwcap.h>
#include <ctype.h>
#include <sys/auxv.h>
#ifndef HWCAP_ISA_I
#define HWCAP_ISA_I (1 << ('I' - 'A'))
#define HWCAP_ISA_I nth_bit('I' - 'A')
#endif
#ifndef HWCAP_ISA_M
#define HWCAP_ISA_M (1 << ('M' - 'A'))
#define HWCAP_ISA_M nth_bit('M' - 'A')
#endif
#ifndef HWCAP_ISA_A
#define HWCAP_ISA_A (1 << ('A' - 'A'))
#define HWCAP_ISA_A nth_bit('A' - 'A')
#endif
#ifndef HWCAP_ISA_F
#define HWCAP_ISA_F (1 << ('F' - 'A'))
#define HWCAP_ISA_F nth_bit('F' - 'A')
#endif
#ifndef HWCAP_ISA_D
#define HWCAP_ISA_D (1 << ('D' - 'A'))
#define HWCAP_ISA_D nth_bit('D' - 'A')
#endif
#ifndef HWCAP_ISA_C
#define HWCAP_ISA_C (1 << ('C' - 'A'))
#define HWCAP_ISA_C nth_bit('C' - 'A')
#endif
#ifndef HWCAP_ISA_Q
#define HWCAP_ISA_Q nth_bit('Q' - 'A')
#endif
#ifndef HWCAP_ISA_H
#define HWCAP_ISA_H nth_bit('H' - 'A')
#endif
#ifndef HWCAP_ISA_V
#define HWCAP_ISA_V (1 << ('V' - 'A'))
#define HWCAP_ISA_V nth_bit('V' - 'A')
#endif
#define read_csr(csr) \
@ -70,68 +82,173 @@
__v; \
})
uint32_t VM_Version::get_current_vector_length() {
assert(_features & CPU_V, "should not call this");
uint32_t VM_Version::cpu_vector_length() {
assert(ext_V.enabled(), "should not call this");
return (uint32_t)read_csr(CSR_VLENB);
}
VM_Version::VM_MODE VM_Version::get_satp_mode() {
if (!strcmp(_vm_mode, "sv39")) {
void VM_Version::setup_cpu_available_features() {
assert(ext_I.feature_bit() == HWCAP_ISA_I, "Bit for I must follow Linux HWCAP");
assert(ext_M.feature_bit() == HWCAP_ISA_M, "Bit for M must follow Linux HWCAP");
assert(ext_A.feature_bit() == HWCAP_ISA_A, "Bit for A must follow Linux HWCAP");
assert(ext_F.feature_bit() == HWCAP_ISA_F, "Bit for F must follow Linux HWCAP");
assert(ext_D.feature_bit() == HWCAP_ISA_D, "Bit for D must follow Linux HWCAP");
assert(ext_C.feature_bit() == HWCAP_ISA_C, "Bit for C must follow Linux HWCAP");
assert(ext_Q.feature_bit() == HWCAP_ISA_Q, "Bit for Q must follow Linux HWCAP");
assert(ext_H.feature_bit() == HWCAP_ISA_H, "Bit for H must follow Linux HWCAP");
assert(ext_V.feature_bit() == HWCAP_ISA_V, "Bit for V must follow Linux HWCAP");
if (!RiscvHwprobe::probe_features()) {
os_aux_features();
}
char* uarch = os_uarch_additional_features();
vendor_features();
char buf[1024] = {};
if (uarch != nullptr && strcmp(uarch, "") != 0) {
// Use at max half the buffer.
snprintf(buf, sizeof(buf)/2, "%s,", uarch);
}
os::free((void*) uarch);
strcat(buf, "rv64");
int i = 0;
while (_feature_list[i] != nullptr) {
if (_feature_list[i]->enabled()) {
log_debug(os, cpu)("Enabled RV64 feature \"%s\" (%ld)",
_feature_list[i]->pretty(),
_feature_list[i]->value());
// The feature string
if (_feature_list[i]->feature_string()) {
const char* tmp = _feature_list[i]->pretty();
if (strlen(tmp) == 1) {
strcat(buf, tmp);
} else {
// Feature string is expected to be lower case.
// Turn Zxxx into zxxx
char prebuf[3] = {};
assert(strlen(tmp) > 1, "Must be");
prebuf[0] = '_';
prebuf[1] = (char)tolower(tmp[0]);
strcat(buf, prebuf);
strcat(buf, &tmp[1]);
}
}
// Feature bit
if (_feature_list[i]->feature_bit() != 0) {
_features |= _feature_list[i]->feature_bit();
}
// Change flag default
_feature_list[i]->update_flag();
}
i++;
}
_features_string = os::strdup(buf);
}
void VM_Version::os_aux_features() {
uint64_t auxv = getauxval(AT_HWCAP);
int i = 0;
while (_feature_list[i] != nullptr) {
if ((_feature_list[i]->feature_bit() & auxv) != 0) {
_feature_list[i]->enable_feature();
}
i++;
}
}
VM_Version::VM_MODE VM_Version::parse_satp_mode(const char* vm_mode) {
if (!strcmp(vm_mode, "sv39")) {
return VM_SV39;
} else if (!strcmp(_vm_mode, "sv48")) {
} else if (!strcmp(vm_mode, "sv48")) {
return VM_SV48;
} else if (!strcmp(_vm_mode, "sv57")) {
} else if (!strcmp(vm_mode, "sv57")) {
return VM_SV57;
} else if (!strcmp(_vm_mode, "sv64")) {
} else if (!strcmp(vm_mode, "sv64")) {
return VM_SV64;
} else {
return VM_MBARE;
}
}
void VM_Version::get_os_cpu_info() {
char* VM_Version::os_uarch_additional_features() {
char* ret = nullptr;
VM_MODE mode = VM_NOTSET;
uint64_t auxv = getauxval(AT_HWCAP);
FILE *f = fopen("/proc/cpuinfo", "r");
if (f == nullptr) {
return nullptr;
}
static_assert(CPU_I == HWCAP_ISA_I, "Flag CPU_I must follow Linux HWCAP");
static_assert(CPU_M == HWCAP_ISA_M, "Flag CPU_M must follow Linux HWCAP");
static_assert(CPU_A == HWCAP_ISA_A, "Flag CPU_A must follow Linux HWCAP");
static_assert(CPU_F == HWCAP_ISA_F, "Flag CPU_F must follow Linux HWCAP");
static_assert(CPU_D == HWCAP_ISA_D, "Flag CPU_D must follow Linux HWCAP");
static_assert(CPU_C == HWCAP_ISA_C, "Flag CPU_C must follow Linux HWCAP");
static_assert(CPU_V == HWCAP_ISA_V, "Flag CPU_V must follow Linux HWCAP");
// RISC-V has four bit-manipulation ISA-extensions: Zba/Zbb/Zbc/Zbs.
// Availability for those extensions could not be queried from HWCAP.
// TODO: Add proper detection for those extensions.
_features = auxv & (
HWCAP_ISA_I |
HWCAP_ISA_M |
HWCAP_ISA_A |
HWCAP_ISA_F |
HWCAP_ISA_D |
HWCAP_ISA_C |
HWCAP_ISA_V);
if (FILE *f = fopen("/proc/cpuinfo", "r")) {
char buf[512], *p;
while (fgets(buf, sizeof (buf), f) != nullptr) {
if ((p = strchr(buf, ':')) != nullptr) {
char buf[512], *p;
while (fgets(buf, sizeof (buf), f) != nullptr &&
(mode == VM_NOTSET || ret == nullptr)) {
if ((p = strchr(buf, ':')) != nullptr) {
if (mode == VM_NOTSET) {
if (strncmp(buf, "mmu", sizeof "mmu" - 1) == 0) {
if (_vm_mode[0] != '\0') {
continue;
}
char* vm_mode = os::strdup(p + 2);
vm_mode[strcspn(vm_mode, "\n")] = '\0';
_vm_mode = vm_mode;
} else if (strncmp(buf, "uarch", sizeof "uarch" - 1) == 0) {
char* uarch = os::strdup(p + 2);
uarch[strcspn(uarch, "\n")] = '\0';
_uarch = uarch;
break;
mode = VM_Version::parse_satp_mode(p);
}
}
if (ret == nullptr) {
if (strncmp(buf, "uarch", sizeof "uarch" - 1) == 0) {
ret = os::strdup(p + 2);
ret[strcspn(ret, "\n")] = '\0';
}
}
}
fclose(f);
}
if (mode == VM_NOTSET) {
mode = VM_MBARE;
}
fclose(f);
satp_mode.enable_feature(mode);
return ret;
}
void VM_Version::vendor_features() {
// JEDEC encoded as ((bank - 1) << 7) | (0x7f & JEDEC)
static constexpr int RIVOS_MVENDORID = 0x6cf; // JEDEC: 0x4f, Bank: 14
if (!mvendorid.enabled()) {
return;
}
switch (mvendorid.value()) {
case RIVOS_MVENDORID:
rivos_features();
break;
default:
break;
}
}
void VM_Version::rivos_features() {
// Enable common features not dependent on marchid/mimpid.
ext_I.enable_feature();
ext_M.enable_feature();
ext_A.enable_feature();
ext_F.enable_feature();
ext_D.enable_feature();
ext_C.enable_feature();
ext_H.enable_feature();
ext_V.enable_feature();
ext_Zicbom.enable_feature();
ext_Zicboz.enable_feature();
ext_Zicbop.enable_feature();
ext_Zba.enable_feature();
ext_Zbb.enable_feature();
ext_Zbs.enable_feature();
ext_Zicsr.enable_feature();
ext_Zifencei.enable_feature();
ext_Zic64b.enable_feature();
ext_Zihintpause.enable_feature();
unaligned_access.enable_feature(MISALIGNED_FAST);
satp_mode.enable_feature(VM_SV48);
// Features dependent on march/mimpid.
// I.e. march.value() and mimplid.value()
}