222 lines
5.6 KiB
C
222 lines
5.6 KiB
C
/*
|
|
Copyright (c) 2020 Alibek Omarov <a1ba.omarov@gmail.com>
|
|
|
|
This work is free. You can redistribute it and/or modify it under the
|
|
terms of the Do What The Fuck You Want To Public License, Version 2,
|
|
as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
|
|
*/
|
|
#pragma once
|
|
#ifndef E2K_CPUID_H
|
|
#define E2K_CPUID_H
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
|
|
/**
|
|
* e2k cpuid single-header library, v1
|
|
*
|
|
* Changes from v0:
|
|
* - initial release
|
|
*
|
|
**/
|
|
|
|
typedef struct e2k_cpuid_s
|
|
{
|
|
char model[16]; // string representation of model
|
|
uint32_t mdl; // actual model id
|
|
uint32_t revision;
|
|
uint32_t l2_wb_len; // L2 cache writeback length
|
|
uint32_t cores;
|
|
uint32_t pn; // ???
|
|
uint32_t vt_version;
|
|
uint32_t have_vt;
|
|
uint32_t is_guest;
|
|
} e2k_cpuid_t;
|
|
|
|
typedef enum e2k_cpuid_mdl_e
|
|
{
|
|
MDL_E2S = 0x03, /* Elbrus-4C */
|
|
MDL_ES2 = 0x04, /* Elbrus-2C+ */
|
|
MDL_RESERVED = 0x05, /* unknown "reserved" processor */
|
|
MDL_ES2_NO_DSP = 0x06, /* Elbrus-2CM */
|
|
MDL_E8C = 0x07, /* Elbrus-8C */
|
|
MDL_E1CP = 0x08, /* Elbrus-1C+ */
|
|
MDL_E8C2 = 0x09, /* Elbrus-8C2 */
|
|
MDL_E12C = 0x0a, /* Elbrus-12C */
|
|
MDL_E16C = 0x0b, /* Elbrus-16C */
|
|
MDL_E2C3 = 0x0c, /* Elbrus-2C3 */
|
|
} e2k_cpuid_mdl_t;
|
|
|
|
int e2k_cpuid( e2k_cpuid_t *cpuid );
|
|
int e2k_cpuid_from_regs( e2k_cpuid_t *cpuid, uint64_t idr, uint32_t core_mode /* only v6 */ );
|
|
int e2k_cpuid_model_from_mdl( char *modelname, size_t len, uint32_t mdl );
|
|
|
|
#ifdef E2K_CPUID_IMPLEMENTATION
|
|
|
|
#include <string.h>
|
|
|
|
#define extract32( v, s, len ) ((( v ) >> ( s )) & ( ~0U >> ( 32 - ( len ))))
|
|
#define extract64( v, s, len ) ((( v ) >> ( s )) & ( ~0ULL >> ( 64 - ( len ))))
|
|
|
|
#define IDR_MDL_START 0
|
|
#define IDR_MDL_BITS 8
|
|
#define IDR_REV_START ( IDR_MDL_START + IDR_MDL_BITS )
|
|
#define IDR_REV_BITS 4
|
|
#define IDR_WBL_START ( IDR_REV_START + IDR_REV_BITS )
|
|
#define IDR_WBL_BITS 3
|
|
#define IDR_CORE_START ( IDR_WBL_START + IDR_WBL_BITS )
|
|
#define IDR_CORE_BITS 5
|
|
#define IDR_PN_START ( IDR_CORE_START + IDR_CORE_BITS )
|
|
#define IDR_PN_BITS 4
|
|
#define IDR_HW_VT_START ( IDR_PN_START + IDR_PN_BITS )
|
|
#define IDR_HW_VT_BITS 1
|
|
#define IDR_HW_VT_VER_START ( IDR_HW_VT_START + IDR_HW_VT_BITS )
|
|
#define IDR_HW_VT_VER_BITS 4
|
|
|
|
#define CORE_MODE_GUEST_START 3
|
|
#define CORE_MODE_GUEST_BITS 1
|
|
|
|
#define IDR_WBL_TO_BYTES(wbl) ((wbl) ? (1 << (wbl + 4)) : 1)
|
|
|
|
int e2k_cpuid_model_from_mdl( char *out, size_t len, uint32_t mdl )
|
|
{
|
|
int retval = 0;
|
|
const char *str;
|
|
|
|
switch( mdl )
|
|
{
|
|
case MDL_E2S: str = "Elbrus-4C"; break;
|
|
case MDL_ES2: str = "Elbrus-2C+"; break;
|
|
case MDL_RESERVED: str = "Elbrus-Reserved"; break;
|
|
case MDL_ES2_NO_DSP: str = "Elbrus-2CM"; break;
|
|
case MDL_E8C: str = "Elbrus-8C"; break;
|
|
case MDL_E1CP: str = "Elbrus-1C+"; break;
|
|
case MDL_E8C2: str = "Elbrus-8C2"; break;
|
|
case MDL_E12C: str = "Elbrus-12C"; break;
|
|
case MDL_E16C: str = "Elbrus-16C"; break;
|
|
case MDL_E2C3: str = "Elbrus-2C3"; break;
|
|
default:
|
|
{
|
|
if( mdl < MDL_E2S )
|
|
str = "E3M LOL";
|
|
else if( mdl > MDL_E2C3 )
|
|
str = "UpdateCpuidPls";
|
|
retval = -1;
|
|
}
|
|
}
|
|
|
|
strncpy( out, str, len );
|
|
out[len - 1] = 0;
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int e2k_cpuid_cores_from_mdl( uint32_t mdl )
|
|
{
|
|
/* only for processors that doesn't report cores num through IDR */
|
|
switch( mdl )
|
|
{
|
|
case MDL_E1CP: return 1;
|
|
case MDL_ES2:
|
|
case MDL_ES2_NO_DSP: return 2;
|
|
case MDL_E2S: return 4;
|
|
case MDL_E8C2:
|
|
case MDL_E8C: return 8;
|
|
default: return 1;
|
|
}
|
|
}
|
|
|
|
int e2k_cpuid_from_regs( e2k_cpuid_t *cpuid, uint64_t idr, uint32_t core_mode )
|
|
{
|
|
int retval = 0;
|
|
|
|
memset( cpuid, 0, sizeof( *cpuid ));
|
|
|
|
cpuid->mdl = extract64( idr, IDR_MDL_START, IDR_MDL_BITS );
|
|
cpuid->revision = extract64( idr, IDR_REV_START, IDR_REV_BITS );
|
|
cpuid->l2_wb_len = extract64( idr, IDR_WBL_START, IDR_WBL_BITS );
|
|
|
|
// only v6 and higher
|
|
if( cpuid->mdl > MDL_E12C )
|
|
{
|
|
cpuid->cores = extract64( idr, IDR_CORE_START, IDR_CORE_BITS );
|
|
cpuid->pn = extract64( idr, IDR_PN_START, IDR_PN_BITS );
|
|
cpuid->have_vt = extract64( idr, IDR_HW_VT_START, IDR_HW_VT_BITS );
|
|
cpuid->vt_version = extract64( idr, IDR_HW_VT_VER_START, IDR_HW_VT_VER_BITS );
|
|
|
|
cpuid->is_guest = extract32( core_mode, CORE_MODE_GUEST_START, CORE_MODE_GUEST_BITS );
|
|
}
|
|
else
|
|
{
|
|
cpuid->cores = e2k_cpuid_cores_from_mdl( cpuid->mdl );
|
|
}
|
|
|
|
// finalize data
|
|
cpuid->l2_wb_len = IDR_WBL_TO_BYTES( cpuid->l2_wb_len );
|
|
retval = e2k_cpuid_model_from_mdl( cpuid->model, sizeof( cpuid->model ), cpuid->mdl );
|
|
|
|
return retval;
|
|
}
|
|
|
|
uint32_t e2k_get_core_mode( void ) __attribute__((noinline));
|
|
#if __iset__ >= 6
|
|
uint32_t e2k_get_core_mode( void )
|
|
{
|
|
register uint32_t core_mode = 0;
|
|
#pragma no_asm_inline
|
|
__asm__ volatile
|
|
(
|
|
"\t rrs \t%%core_mode, %0\n"
|
|
: "=r"(core_mode)
|
|
);
|
|
}
|
|
#else
|
|
__asm__ volatile
|
|
(
|
|
"e2k_get_core_mode:\n"
|
|
".dword 0x04108022\n"
|
|
".dword 0x58ecc082\n"
|
|
".dword 0x040000c4\n"
|
|
".dword 0x01c00000\n"
|
|
".dword 0x00000000\n"
|
|
".dword 0x00000110\n"
|
|
".dword 0x04000001\n"
|
|
".dword 0x90c0c083\n"
|
|
".dword 0x04100011\n"
|
|
".dword 0x3e04c083\n"
|
|
".dword 0x01c00000\n"
|
|
".dword 0x00000000\n"
|
|
".dword 0x04004292\n"
|
|
".dword 0x8cc68380\n"
|
|
".dword 0xf0000000\n"
|
|
".dword 0x00000000\n"
|
|
".dword 0x00001001\n"
|
|
".dword 0xc0000c20\n"
|
|
);
|
|
#endif
|
|
|
|
int e2k_cpuid( e2k_cpuid_t *cpuid )
|
|
{
|
|
uint64_t idr;
|
|
uint32_t core_mode = 0;
|
|
uint32_t mdl;
|
|
|
|
__asm__ volatile( "\trrd \t%%idr, %0\n" : "=r"(idr));
|
|
|
|
mdl = extract64( idr, IDR_MDL_START, IDR_MDL_BITS );
|
|
|
|
if( mdl >= MDL_E12C )
|
|
{
|
|
core_mode = e2k_get_core_mode();
|
|
}
|
|
|
|
return e2k_cpuid_from_regs( cpuid, idr, core_mode );
|
|
}
|
|
|
|
#undef IDR_WBL_TO_BYTES
|
|
#undef extract32
|
|
#undef extract64
|
|
|
|
#endif // E2K_CPUID_IMPLEMENTATION
|
|
#endif // E2K_CPUID_H
|