cpuid: first revision

This commit is contained in:
Alibek Omarov 2021-03-21 19:44:53 +03:00
parent 909201d125
commit 8beef4d855
3 changed files with 226 additions and 1 deletions

View File

@ -1,3 +1,9 @@
# e2k-libs
Small e2k single header libraries for everyone to use
Small e2k single header libraries for everyone to use
## cpuid
A CPUID that doesn't rely on Linux kernel to get processor info.
Maybe useful for those cases, when /proc/cpuinfo is not available or invalid.

200
cpuid/e2k_cpuid.h Normal file
View File

@ -0,0 +1,200 @@
/*
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_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 *out, 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_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;
}
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 );
}
// 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

19
cpuid/example.c Normal file
View File

@ -0,0 +1,19 @@
#define E2K_CPUID_IMPLEMENTATION
#include "e2k_cpuid.h"
#include <stdio.h>
int main( int argc, char **argv )
{
int err;
e2k_cpuid_t cpuid;
if(( err = e2k_cpuid( &cpuid )))
{
printf( "Error %d\n", err );
return err;
}
printf( "Model: %s\nRevision: %d\nCores: %d\nL2 writeback length: %d\nHave VT: %d\nVT version: %d\nUnder KVM: %d\n",
cpuid.model, cpuid.revision, cpuid.cores, cpuid.l2_wb_len, cpuid.have_vt, cpuid.vt_version, cpuid.is_guest );
return 0;
}