1
0
Fork 0
mirror of https://github.com/anrieff/libcpuid synced 2025-02-12 20:24:05 +00:00

Add rdcpuid interface for kernel drivers on ARM CPUs

This commit is contained in:
The Tumultuous Unicorn Of Darkness 2024-07-08 21:47:27 +02:00
parent 6e6b4bcbf5
commit 0f0b1e6060
No known key found for this signature in database
GPG key ID: 1E55EE2EFF18BC1A
6 changed files with 402 additions and 31 deletions

View file

@ -7,7 +7,8 @@ set(cpuid_sources
rdtsc.c
libcpuid_util.c
rdmsr.c
asm-bits.c)
asm-bits.c
rdcpuid.c)
if(WIN32)
list(APPEND cpuid_sources msrdriver.c)

View file

@ -31,6 +31,10 @@
#include "recog_intel.h"
#include "asm-bits.h"
#include "libcpuid_util.h"
#if defined(PLATFORM_ARM) || defined(PLATFORM_AARCH64)
# include "libcpuid_arm_driver.h"
# include "rdcpuid.h"
#endif /* ARM */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
@ -1280,9 +1284,6 @@ int cpuid_get_raw_data_core(struct cpu_raw_data_t* data, logical_cpu_t logical_c
{
bool affinity_saved = false;
if (!cpuid_present())
return cpuid_set_error(ERR_NO_CPUID);
if (logical_cpu != (logical_cpu_t) -1) {
debugf(2, "Getting raw dump for logical CPU %u\n", logical_cpu);
if (!set_cpu_affinity(logical_cpu))
@ -1292,6 +1293,10 @@ int cpuid_get_raw_data_core(struct cpu_raw_data_t* data, logical_cpu_t logical_c
#if defined(PLATFORM_X86) || defined(PLATFORM_X64)
unsigned i;
if (!cpuid_present())
return cpuid_set_error(ERR_NO_CPUID);
for (i = 0; i < 32; i++)
cpu_exec_cpuid(i, data->basic_cpuid[i]);
for (i = 0; i < 32; i++)
@ -1332,33 +1337,54 @@ int cpuid_get_raw_data_core(struct cpu_raw_data_t* data, logical_cpu_t logical_c
data->amd_fn80000026h[i][ECX] = i;
cpu_exec_cpuid_ext(data->amd_fn80000026h[i]);
}
#elif defined(PLATFORM_ARM)
/* We cannot support ARM CPUs running in 32-bit mode, because the Main ID Register is accessible only in privileged modes
Some related links:
- https://github.com/anrieff/libcpuid/issues/96
- https://developer.arm.com/documentation/ddi0406/b/System-Level-Architecture/Protected-Memory-System-Architecture--PMSA-/CP15-registers-for-a-PMSA-implementation/c0--Main-ID-Register--MIDR-
*/
# warning The 32-bit ARM platform is not supported (Main ID Register is accessible only in privileged modes)
UNUSED(data);
#elif defined(PLATFORM_AARCH64)
cpu_exec_mrs("MIDR_EL1", data->arm_midr);
cpu_exec_mrs("MPIDR_EL1", data->arm_mpidr);
cpu_exec_mrs("REVIDR_EL1", data->arm_revidr);
cpu_exec_mrs(SYS_ID_AA64DFR0_EL1, data->arm_id_aa64dfr[0]);
cpu_exec_mrs(SYS_ID_AA64DFR1_EL1, data->arm_id_aa64dfr[1]);
cpu_exec_mrs(SYS_ID_AA64ISAR0_EL1, data->arm_id_aa64isar[0]);
cpu_exec_mrs(SYS_ID_AA64ISAR1_EL1, data->arm_id_aa64isar[1]);
cpu_exec_mrs(SYS_ID_AA64ISAR2_EL1, data->arm_id_aa64isar[2]);
cpu_exec_mrs(SYS_ID_AA64MMFR0_EL1, data->arm_id_aa64mmfr[0]);
cpu_exec_mrs(SYS_ID_AA64MMFR1_EL1, data->arm_id_aa64mmfr[1]);
cpu_exec_mrs(SYS_ID_AA64MMFR2_EL1, data->arm_id_aa64mmfr[2]);
cpu_exec_mrs(SYS_ID_AA64MMFR3_EL1, data->arm_id_aa64mmfr[3]);
cpu_exec_mrs(SYS_ID_AA64MMFR4_EL1, data->arm_id_aa64mmfr[4]);
cpu_exec_mrs(SYS_ID_AA64PFR0_EL1, data->arm_id_aa64pfr[0]);
cpu_exec_mrs(SYS_ID_AA64PFR1_EL1, data->arm_id_aa64pfr[1]);
cpu_exec_mrs(SYS_ID_AA64PFR2_EL1, data->arm_id_aa64pfr[2]);
cpu_exec_mrs(SYS_ID_AA64SMFR0_EL1, data->arm_id_aa64smfr[0]);
cpu_exec_mrs(SYS_ID_AA64ZFR0_EL1, data->arm_id_aa64zfr[0]);
#elif defined(PLATFORM_ARM) || defined(PLATFORM_AARCH64)
unsigned i;
struct cpuid_driver_t *handle;
if ((handle = cpu_cpuid_driver_open_core(logical_cpu)) != NULL) {
debugf(2, "Using kernel driver to read register on logical CPU %u\n", logical_cpu);
cpu_read_arm_register_64b(handle, REQ_MIDR, &data->arm_midr);
cpu_read_arm_register_64b(handle, REQ_MPIDR, &data->arm_mpidr);
cpu_read_arm_register_64b(handle, REQ_REVIDR, &data->arm_revidr);
for (i = 0; i < MAX_ARM_ID_AFR_REGS; i++)
cpu_read_arm_register_32b(handle, REQ_ID_AFR0 + i, &data->arm_id_afr[i]);
for (i = 0; i < MAX_ARM_ID_DFR_REGS; i++)
cpu_read_arm_register_32b(handle, REQ_ID_DFR0 + i, &data->arm_id_dfr[i]);
for (i = 0; i < MAX_ARM_ID_ISAR_REGS; i++)
cpu_read_arm_register_32b(handle, REQ_ID_ISAR0 + i, &data->arm_id_isar[i]);
for (i = 0; i < MAX_ARM_ID_MMFR_REGS; i++)
cpu_read_arm_register_32b(handle, REQ_ID_MMFR0 + i, &data->arm_id_mmfr[i]);
for (i = 0; i < MAX_ARM_ID_PFR_REGS; i++)
cpu_read_arm_register_32b(handle, REQ_ID_PFR0 + i, &data->arm_id_pfr[i]);
cpu_cpuid_driver_close(handle);
}
# if defined(PLATFORM_AARCH64)
else {
if (!cpuid_present())
return cpuid_set_error(ERR_NO_CPUID);
debugf(2, "Using MRS instruction to read register on logical CPU %u\n", logical_cpu);
cpu_exec_mrs(AARCH64_REG_MIDR_EL1, data->arm_midr);
cpu_exec_mrs(AARCH64_REG_MPIDR_EL1, data->arm_mpidr);
cpu_exec_mrs(AARCH64_REG_REVIDR_EL1, data->arm_revidr);
cpu_exec_mrs(AARCH64_REG_ID_AA64AFR0_EL1, data->arm_id_aa64afr[0]);
cpu_exec_mrs(AARCH64_REG_ID_AA64AFR1_EL1, data->arm_id_aa64afr[1]);
cpu_exec_mrs(AARCH64_REG_ID_AA64DFR0_EL1, data->arm_id_aa64dfr[0]);
cpu_exec_mrs(AARCH64_REG_ID_AA64DFR1_EL1, data->arm_id_aa64dfr[1]);
cpu_exec_mrs(AARCH64_REG_ID_AA64ISAR0_EL1, data->arm_id_aa64isar[0]);
cpu_exec_mrs(AARCH64_REG_ID_AA64ISAR1_EL1, data->arm_id_aa64isar[1]);
cpu_exec_mrs(AARCH64_REG_ID_AA64ISAR2_EL1, data->arm_id_aa64isar[2]);
cpu_exec_mrs(AARCH64_REG_ID_AA64MMFR0_EL1, data->arm_id_aa64mmfr[0]);
cpu_exec_mrs(AARCH64_REG_ID_AA64MMFR1_EL1, data->arm_id_aa64mmfr[1]);
cpu_exec_mrs(AARCH64_REG_ID_AA64MMFR2_EL1, data->arm_id_aa64mmfr[2]);
cpu_exec_mrs(AARCH64_REG_ID_AA64MMFR3_EL1, data->arm_id_aa64mmfr[3]);
cpu_exec_mrs(AARCH64_REG_ID_AA64MMFR4_EL1, data->arm_id_aa64mmfr[4]);
cpu_exec_mrs(AARCH64_REG_ID_AA64PFR0_EL1, data->arm_id_aa64pfr[0]);
cpu_exec_mrs(AARCH64_REG_ID_AA64PFR1_EL1, data->arm_id_aa64pfr[1]);
cpu_exec_mrs(AARCH64_REG_ID_AA64PFR2_EL1, data->arm_id_aa64pfr[2]);
cpu_exec_mrs(AARCH64_REG_ID_AA64SMFR0_EL1, data->arm_id_aa64smfr[0]);
cpu_exec_mrs(AARCH64_REG_ID_AA64ZFR0_EL1, data->arm_id_aa64zfr[0]);
}
# endif /* PLATFORM_AARCH64 */
#else
# warning This CPU architecture is not supported by libcpuid
UNUSED(data);
@ -2204,6 +2230,7 @@ const char* cpuid_error(void)
{ ERR_HANDLE_R , "Error on handle read"},
{ ERR_INVRANGE , "Invalid given range"},
{ ERR_NOT_FOUND, "Requested type not found"},
{ ERR_IOCTL, "Error on ioctl"},
};
unsigned i;
for (i = 0; i < COUNT_OF(matchtable); i++)

View file

@ -1202,6 +1202,7 @@ typedef enum {
ERR_HANDLE_R = -15, /*!< Error on handle read */
ERR_INVRANGE = -16, /*!< Invalid given range */
ERR_NOT_FOUND= -17, /*!< Requested type not found */
ERR_IOCTL = -18, /*!< Error on ioctl */
} cpu_error_t;
/**

View file

@ -0,0 +1,129 @@
/*
* Copyright 2024 Veselin Georgiev,
* anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __LIBCPUID_ARM_DRIVER_H__
#define __LIBCPUID_ARM_DRIVER_H__
#define AARCH64_REG_MIDR_EL1 "S3_0_C0_C0_0"
#define AARCH64_REG_MPIDR_EL1 "S3_0_C0_C0_5"
#define AARCH64_REG_REVIDR_EL1 "S3_0_C0_C0_6"
#define AARCH64_REG_ID_AFR0 "S3_0_C0_C1_3"
#define AARCH64_REG_ID_DFR0 "S3_0_C0_C1_2"
#define AARCH64_REG_ID_DFR1 "S3_0_C0_C3_5"
#define AARCH64_REG_ID_ISAR0 "S3_0_C0_C2_0"
#define AARCH64_REG_ID_ISAR1 "S3_0_C0_C2_1"
#define AARCH64_REG_ID_ISAR2 "S3_0_C0_C2_2"
#define AARCH64_REG_ID_ISAR3 "S3_0_C0_C2_3"
#define AARCH64_REG_ID_ISAR4 "S3_0_C0_C2_4"
#define AARCH64_REG_ID_ISAR5 "S3_0_C0_C2_5"
#define AARCH64_REG_ID_ISAR6 "S3_0_C0_C2_7"
#define AARCH64_REG_ID_MMFR0 "S3_0_C0_C1_4"
#define AARCH64_REG_ID_MMFR1 "S3_0_C0_C1_5"
#define AARCH64_REG_ID_MMFR2 "S3_0_C0_C1_6"
#define AARCH64_REG_ID_MMFR3 "S3_0_C0_C1_7"
#define AARCH64_REG_ID_MMFR4 "S3_0_C0_C2_6"
#define AARCH64_REG_ID_MMFR5 "S3_0_C0_C3_6"
#define AARCH64_REG_ID_PFR0 "S3_0_C0_C1_0"
#define AARCH64_REG_ID_PFR1 "S3_0_C0_C1_1"
#define AARCH64_REG_ID_PFR2 "S3_0_C0_C3_4"
#define AARCH64_REG_ID_AA64AFR0_EL1 "S3_0_C0_C5_4"
#define AARCH64_REG_ID_AA64AFR1_EL1 "S3_0_C0_C5_5"
#define AARCH64_REG_ID_AA64DFR0_EL1 "S3_0_C0_C5_0"
#define AARCH64_REG_ID_AA64DFR1_EL1 "S3_0_C0_C5_1"
#define AARCH64_REG_ID_AA64ISAR0_EL1 "S3_0_C0_C6_0"
#define AARCH64_REG_ID_AA64ISAR1_EL1 "S3_0_C0_C6_1"
#define AARCH64_REG_ID_AA64ISAR2_EL1 "S3_0_C0_C6_2"
#define AARCH64_REG_ID_AA64MMFR0_EL1 "S3_0_C0_C7_0"
#define AARCH64_REG_ID_AA64MMFR1_EL1 "S3_0_C0_C7_1"
#define AARCH64_REG_ID_AA64MMFR2_EL1 "S3_0_C0_C7_2"
#define AARCH64_REG_ID_AA64MMFR3_EL1 "S3_0_C0_C7_3"
#define AARCH64_REG_ID_AA64MMFR4_EL1 "S3_0_C0_C7_4"
#define AARCH64_REG_ID_AA64PFR0_EL1 "S3_0_C0_C4_0"
#define AARCH64_REG_ID_AA64PFR1_EL1 "S3_0_C0_C4_1"
#define AARCH64_REG_ID_AA64PFR2_EL1 "S3_0_C0_C4_2"
#define AARCH64_REG_ID_AA64SMFR0_EL1 "S3_0_C0_C4_5"
#define AARCH64_REG_ID_AA64ZFR0_EL1 "S3_0_C0_C4_4"
typedef enum {
REQ_MIDR,
REQ_MPIDR,
REQ_REVIDR,
REQ_ID_AFR0,
REQ_ID_DFR0,
REQ_ID_DFR1,
REQ_ID_ISAR0,
REQ_ID_ISAR1,
REQ_ID_ISAR2,
REQ_ID_ISAR3,
REQ_ID_ISAR4,
REQ_ID_ISAR5,
REQ_ID_ISAR6,
REQ_ID_MMFR0,
REQ_ID_MMFR1,
REQ_ID_MMFR2,
REQ_ID_MMFR3,
REQ_ID_MMFR4,
REQ_ID_MMFR5,
REQ_ID_PFR0,
REQ_ID_PFR1,
REQ_ID_PFR2,
#if defined(__aarch64__)
REQ_ID_AA64AFR0,
REQ_ID_AA64AFR1,
REQ_ID_AA64DFR0,
REQ_ID_AA64DFR1,
REQ_ID_AA64ISAR0,
REQ_ID_AA64ISAR1,
REQ_ID_AA64ISAR2,
REQ_ID_AA64MMFR0,
REQ_ID_AA64MMFR1,
REQ_ID_AA64MMFR2,
REQ_ID_AA64MMFR3,
REQ_ID_AA64MMFR4,
REQ_ID_AA64PFR0,
REQ_ID_AA64PFR1,
REQ_ID_AA64PFR2,
REQ_ID_AA64SMFR0,
REQ_ID_AA64ZFR0,
#endif /* __aarch64__ */
/* termination: */
NUM_REG_REQUESTS,
REQ_INVALID = -1
} reg_request_t;
struct read_reg_t {
reg_request_t request;
union {
uint32_t value_32b;
uint64_t value_64b;
};
int err;
};
typedef struct read_reg_t read_reg_t;
#define ARM_IOC_READ_REG _IOWR('c', 0xB0, read_reg_t)
#endif /* __LIBCPUID_ARM_DRIVER_H__ */

179
libcpuid/rdcpuid.c Normal file
View file

@ -0,0 +1,179 @@
/*
* Copyright 2024 Veselin Georgiev,
* anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* freebsd requires _XOPEN_SOURCE 600 for snprintf()
* for linux it is enough 500 */
#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libcpuid.h"
#include "libcpuid_util.h"
#include "libcpuid_arm_driver.h"
#include "rdcpuid.h"
#define CPUID_PATH_LEN 32
#if defined (__linux__) || defined (__gnu_linux__) || defined (__FreeBSD__) || defined (__DragonFly__)
/* Assuming linux with /dev/cpu/x/cpuid: */
/* Assuming FreeBSD with /dev/cpuctlX */
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
struct cpuid_driver_t { int fd; };
static int load_driver(char *cpuid_path)
{
const int file_exists = !access(cpuid_path, F_OK);
const int file_readable = !access(cpuid_path, R_OK);
if (file_exists && file_readable)
return 1;
else if (file_exists && !file_readable)
return 0;
else if (getuid() != 0)
return 0;
else
# if defined (__linux__) || defined (__gnu_linux__)
return !system("modprobe cpuid 2> /dev/null");
# elif defined (__FreeBSD__) || defined (__DragonFly__)
return !system("kldload -n cpuctl 2> /dev/null");
# endif
}
struct cpuid_driver_t* cpu_cpuid_driver_open_core(unsigned core_num)
{
char cpuid[CPUID_PATH_LEN];
struct cpuid_driver_t* handle;
if (core_num >= cpuid_get_total_cpus()) {
cpuid_set_error(ERR_INVCNB);
return NULL;
}
# if defined (__linux__) || defined (__gnu_linux__)
snprintf(cpuid, CPUID_PATH_LEN, "/dev/cpu/%u/cpuid", core_num);
# elif defined (__FreeBSD__) || defined (__DragonFly__)
snprintf(cpuid, CPUID_PATH_LEN, "/dev/cpuid%u", core_num);
# endif
if(!load_driver(cpuid)) {
cpuid_set_error(ERR_NO_DRIVER);
return NULL;
}
int fd = open(cpuid, O_RDONLY);
if (fd < 0) {
if (errno == EIO) {
cpuid_set_error(ERR_NO_CPUID);
return NULL;
}
cpuid_set_error(ERR_NO_DRIVER);
return NULL;
}
handle = (struct cpuid_driver_t*) malloc(sizeof(struct cpuid_driver_t));
if (!handle) {
cpuid_set_error(ERR_NO_MEM);
close(fd);
return NULL;
}
handle->fd = fd;
return handle;
}
int cpu_read_arm_register_32b(struct cpuid_driver_t* driver, reg_request_t request, uint32_t* result)
{
struct read_reg_t read_reg;
read_reg.request = request;
if (!driver || driver->fd < 0)
return cpuid_set_error(ERR_HANDLE);
if(ioctl(driver->fd, ARM_IOC_READ_REG, &read_reg))
return cpuid_set_error(ERR_IOCTL);
*result = read_reg.value_32b;
return 0;
}
int cpu_read_arm_register_64b(struct cpuid_driver_t* driver, reg_request_t request, uint64_t* result)
{
struct read_reg_t read_reg;
read_reg.request = request;
if (!driver || driver->fd < 0)
return cpuid_set_error(ERR_HANDLE);
if(ioctl(driver->fd, ARM_IOC_READ_REG, &read_reg))
return cpuid_set_error(ERR_IOCTL);
*result = read_reg.value_64b;
return 0;
}
int cpu_cpuid_driver_close(struct cpuid_driver_t* drv)
{
if (drv && drv->fd >= 0) {
close(drv->fd);
free(drv);
}
return 0;
}
#else /* Unsupported OS */
/* On others OS (i.e., Darwin), we still do not support RDCPUID, so supply dummy struct
and functions */
struct cpuid_driver_t { int dummy; };
struct cpuid_driver_t* cpu_cpuid_driver_open_core(unsigned core_num)
{
UNUSED(core_num);
cpuid_set_error(ERR_NOT_IMP);
return NULL;
}
int cpu_read_arm_register_32b(struct cpuid_driver_t* driver, reg_request_t request, uint32_t* result)
{
UNUSED(driver);
UNUSED(request);
UNUSED(result);
return cpuid_set_error(ERR_NOT_IMP);
}
int cpu_read_arm_register_64b(struct cpuid_driver_t* driver, reg_request_t request, uint64_t* result)
{
UNUSED(driver);
UNUSED(request);
UNUSED(result);
return cpuid_set_error(ERR_NOT_IMP);
}
int cpu_cpuid_driver_close(struct cpuid_driver_t* driver)
{
UNUSED(driver);
return cpuid_set_error(ERR_NOT_IMP);
}
#endif /* Unsupported OS */

34
libcpuid/rdcpuid.h Normal file
View file

@ -0,0 +1,34 @@
/*
* Copyright 2024 Veselin Georgiev,
* anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __RDCPUID_H__
#define __RDCPUID_H__
struct cpuid_driver_t* cpu_cpuid_driver_open_core(unsigned core_num);
int cpu_read_arm_register_32b(struct cpuid_driver_t* driver, reg_request_t request, uint32_t* result);
int cpu_read_arm_register_64b(struct cpuid_driver_t* driver, reg_request_t request, uint64_t* result);
int cpu_cpuid_driver_close(struct cpuid_driver_t* drv);
#endif /* __RDCPUID_H__ */