Skip to content
Permalink
Browse files

Add OMR macros for processor feature detection

Move required macros, enums and structs from OpenJ9 to OMR's port library
Add function signatures for processor/feature detection to OMR
Implement processor detection on Windows
Add processor and feature detection for Unix Includes Linux,
AIX PPC and ZOS systems
Add test to verify processor/feature detection.

Signed-off-by: Aidan Ha <qbha@edu.uwaterloo.ca>
  • Loading branch information
AidanHa committed Sep 30, 2019
1 parent 7b2e5df commit 0f824c60338729eb8da4f891cbe3642fcd25308c
@@ -2343,3 +2343,34 @@ TEST(PortSysinfoTest, sysinfo_cgroup_get_memlimit)
reportTestExit(OMRPORTLIB, testName);
return;
}

/**
* Test GetProcessorDescription.
*/
TEST(PortSysinfoTest, GetProcessorDescription)
{
OMRPORT_ACCESS_FROM_OMRPORT(portTestEnv->getPortLibrary());
OMRProcessorDesc desc;

ASSERT_NE(omrsysinfo_get_processor_description(&desc), -1);

#if defined(J9X86) || defined(J9HAMMER)
ASSERT_GE(desc.processor, OMR_PROCESSOR_X86_UNKNOWN);
ASSERT_GE(desc.physicalProcessor, OMR_PROCESSOR_X86_UNKNOWN);
#elif defined(AIXPPC) || defined(LINUXPPC)
ASSERT_GE(desc.processor, OMR_PROCESSOR_PPC_UNKNOWN);
ASSERT_LT(desc.processor, OMR_PROCESSOR_X86_UNKNOWN);
ASSERT_GE(desc.physicalProcessor, OMR_PROCESSOR_PPC_UNKNOWN);
ASSERT_LT(desc.physicalProcessor, OMR_PROCESSOR_X86_UNKNOWN);
#elif defined(S390) || defined(J9ZOS390)
ASSERT_GE(desc.processor, OMR_PROCESSOR_S390_UNKNOWN);
ASSERT_LT(desc.processor, OMR_PROCESSOR_PPC_UNKNOWN);
ASSERT_GE(desc.physicalProcessor, OMR_PROCESSOR_S390_UNKNOWN);
ASSERT_LT(desc.physicalProcessor, OMR_PROCESSOR_PPC_UNKNOWN);
#endif

for (int i = 0; i < OMRPORT_SYSINFO_FEATURES_SIZE * 32; i++) {
BOOLEAN feature = omrsysinfo_processor_has_feature(&desc, i);
ASSERT_TRUE(feature == TRUE || feature == FALSE);
}
}

Large diffs are not rendered by default.

@@ -193,9 +193,7 @@ list(APPEND OBJECTS
omrsysinfo.c
)

if(OMR_HOST_OS STREQUAL zos)
list(APPEND OBJECTS omrsysinfo_helpers.c)
endif()
list(APPEND OBJECTS omrsysinfo_helpers.c)

list(APPEND OBJECTS omrsyslog.c)

@@ -72,6 +72,8 @@ static OMRPortLibrary MasterPortLibraryTable = {
omrsysinfo_get_OS_version, /* sysinfo_get_OS_version */
omrsysinfo_get_env, /* sysinfo_get_env */
omrsysinfo_get_CPU_architecture, /* sysinfo_get_CPU_architecture */
omrsysinfo_get_processor_description, /* omrsysinfo_get_processor_description */
omrsysinfo_processor_has_feature, /* omrsysinfo_processor_has_feature */
omrsysinfo_get_OS_type, /* sysinfo_get_OS_type */
omrsysinfo_get_executable_name, /* sysinfo_get_executable_name */
omrsysinfo_get_username, /* sysinfo_get_username */
@@ -1101,3 +1101,9 @@ TraceException=Trc_PRT_vmem_omrvmem_findAvailableMemoryBlockNoMalloc_parseFirstA
TraceException=Trc_PRT_vmem_omrvmem_findAvailableMemoryBlockNoMalloc_parseDashFailed Group=mem Overhead=1 Level=5 NoEnv Template="findAvailableMemoryBlockNoMalloc parser failed to get dash from line (%s)"
TraceException=Trc_PRT_vmem_omrvmem_findAvailableMemoryBlockNoMalloc_parseSecondAddressFailed Group=mem Overhead=1 Level=5 NoEnv Template="findAvailableMemoryBlockNoMalloc parser failed to get second address from line (%s)"
TraceException=Trc_PRT_vmem_omrvmem_findAvailableMemoryBlockNoMalloc_addressesMismatch Group=mem Overhead=1 Level=5 NoEnv Template="findAvailableMemoryBlockNoMalloc parser found addresses mismatch from line (%s)"

TraceEntry=Trc_PRT_sysinfo_get_processor_description_Entered Group=j9sysinfo Overhead=1 Level=5 NoEnv Template="sysinfo_get_processor_description: desc = %p"
TraceExit=Trc_PRT_sysinfo_get_processor_description_Exit Group=j9sysinfo Overhead=1 Level=5 NoEnv Template="sysinfo_get_processor_description: returning with %zd"

TraceEntry=Trc_PRT_sysinfo_processor_has_feature_Entered Group=sysinfo Overhead=1 Level=5 NoEnv Template="sysinfo_processor_has_feature: desc = %p, feature = %d"
TraceExit=Trc_PRT_sysinfo_processor_has_feature_Exit Group=sysinfo Overhead=1 Level=5 NoEnv Template="sysinfo_processor_has_feature: returning with %zu."
@@ -89,6 +89,42 @@ omrsysinfo_get_CPU_architecture(struct OMRPortLibrary *portLibrary)
return "unknown";
#endif
}

/**
* Determine CPU type and features.
*
* @param[in] portLibrary The port library.
* @param[out] desc pointer to the struct that will contain the CPU type and features.
* - desc will still be initialized if there is a failure.
*
* @return 0 on success, -1 on failure
*/
intptr_t
omrsysinfo_get_processor_description(struct OMRPortLibrary *portLibrary, OMRProcessorDesc *desc)
{
Trc_PRT_sysinfo_get_processor_description_Entered(desc);
intptr_t rc = OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM;
Trc_PRT_sysinfo_get_processor_description_Exit(rc);
return rc;
}

/**
* Determine if a CPU feature is present.
*
* @param[in] portLibrary The port library.
* @param[in] desc The struct that will contain the CPU type and features.
* @param[in] feature The feature to check (see j9port.h for list of features J9PORT_{PPC,S390,PPC}_FEATURE_*)
*
* @return TRUE if feature is present, FALSE otherwise.
*/
BOOLEAN
omrsysinfo_processor_has_feature(struct OMRPortLibrary *portLibrary, OMRProcessorDesc *desc, uint32_t feature)
{
Trc_PRT_sysinfo_processor_has_feature_Entered(desc, feature);
BOOLEAN rc = FALSE;
Trc_PRT_sysinfo_processor_has_feature_Exit((uintptr_t)rc);
return rc;
}
/**
* Query the operating system for environment variables.
*
@@ -0,0 +1,212 @@
/*******************************************************************************
* Copyright (c) 2019, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/
/**
* @file
* @ingroup Port
* @brief System information
*/

#include "omrsysinfo_helpers.h"

#include "omrport.h"
#include "omrporterror.h"
#include "portnls.h"

#include <string.h>
#if defined(WIN32)
#include <intrin.h>
#endif /* defined(WIN32) */

/* defines for the CPUID instruction */
#define CPUID_VENDOR_INFO 0
#define CPUID_FAMILY_INFO 1

#define CPUID_VENDOR_INTEL "GenuineIntel"
#define CPUID_VENDOR_AMD "AuthenticAMD"
#define CPUID_VENDOR_LENGTH 12

#define CPUID_SIGNATURE_FAMILY 0x00000F00
#define CPUID_SIGNATURE_MODEL 0x000000F0
#define CPUID_SIGNATURE_EXTENDEDMODEL 0x000F0000

#define CPUID_SIGNATURE_FAMILY_SHIFT 8
#define CPUID_SIGNATURE_MODEL_SHIFT 4
#define CPUID_SIGNATURE_EXTENDEDMODEL_SHIFT 12

#define CPUID_FAMILYCODE_INTELPENTIUM 0x05
#define CPUID_FAMILYCODE_INTELCORE 0x06
#define CPUID_FAMILYCODE_INTELPENTIUM4 0x0F

#define CPUID_MODELCODE_INTELHASWELL 0x3A
#define CPUID_MODELCODE_SANDYBRIDGE 0x2A
#define CPUID_MODELCODE_INTELWESTMERE 0x25
#define CPUID_MODELCODE_INTELNEHALEM 0x1E
#define CPUID_MODELCODE_INTELCORE2 0x0F

#define CPUID_FAMILYCODE_AMDKSERIES 0x05
#define CPUID_FAMILYCODE_AMDATHLON 0x06
#define CPUID_FAMILYCODE_AMDOPTERON 0x0F

#define CPUID_MODELCODE_AMDK5 0x04

/**
* @internal
* Populates OMRProcessorDesc *desc on Windows and Linux (x86)
*
* @param[in] desc pointer to the struct that will contain the CPU type and features.
*
* @return 0 on success, -1 on failure
*/
intptr_t
getX86Description(struct OMRPortLibrary *portLibrary, OMRProcessorDesc *desc)
{
uint32_t CPUInfo[4] = {0};
char vendor[12];
uint32_t familyCode = 0;
uint32_t processorSignature = 0;

desc->processor = OMR_PROCESSOR_X86_UNKNOWN;

/* vendor */
getX86CPUID(CPUID_VENDOR_INFO, CPUInfo);
memcpy(vendor + 0, &CPUInfo[1], sizeof(uint32_t));
memcpy(vendor + 4, &CPUInfo[3], sizeof(uint32_t));
memcpy(vendor + 8, &CPUInfo[2], sizeof(uint32_t));

/* family and model */
getX86CPUID(CPUID_FAMILY_INFO, CPUInfo);
processorSignature = CPUInfo[0];
familyCode = (processorSignature & CPUID_SIGNATURE_FAMILY) >> CPUID_SIGNATURE_FAMILY_SHIFT;
if (0 == strncmp(vendor, CPUID_VENDOR_INTEL, CPUID_VENDOR_LENGTH)) {
switch (familyCode) {
case CPUID_FAMILYCODE_INTELPENTIUM:
desc->processor = OMR_PROCESSOR_X86_INTELPENTIUM;
break;
case CPUID_FAMILYCODE_INTELCORE:
{
uint32_t modelCode = (processorSignature & CPUID_SIGNATURE_MODEL) >> CPUID_SIGNATURE_MODEL_SHIFT;
uint32_t extendedModelCode = (processorSignature & CPUID_SIGNATURE_EXTENDEDMODEL) >> CPUID_SIGNATURE_EXTENDEDMODEL_SHIFT;
uint32_t totalModelCode = modelCode + extendedModelCode;

if (totalModelCode > CPUID_MODELCODE_INTELHASWELL) {
desc->processor = OMR_PROCESSOR_X86_INTELHASWELL;
} else if (totalModelCode >= CPUID_MODELCODE_SANDYBRIDGE) {
desc->processor = OMR_PROCESSOR_X86_INTELSANDYBRIDGE;
} else if (totalModelCode >= CPUID_MODELCODE_INTELWESTMERE) {
desc->processor = OMR_PROCESSOR_X86_INTELWESTMERE;
} else if (totalModelCode >= CPUID_MODELCODE_INTELNEHALEM) {
desc->processor = OMR_PROCESSOR_X86_INTELNEHALEM;
} else if (totalModelCode == CPUID_MODELCODE_INTELCORE2) {
desc->processor = OMR_PROCESSOR_X86_INTELCORE2;
} else {
desc->processor = OMR_PROCESSOR_X86_INTELP6;
}
break;
}
case CPUID_FAMILYCODE_INTELPENTIUM4:
desc->processor = OMR_PROCESSOR_X86_INTELPENTIUM4;
break;
}
} else if (0 == strncmp(vendor, CPUID_VENDOR_AMD, CPUID_VENDOR_LENGTH)) {
switch (familyCode) {
case CPUID_FAMILYCODE_AMDKSERIES:
{
uint32_t modelCode = (processorSignature & CPUID_SIGNATURE_FAMILY) >> CPUID_SIGNATURE_MODEL_SHIFT;
if (modelCode < CPUID_MODELCODE_AMDK5) {
desc->processor = OMR_PROCESSOR_X86_AMDK5;
}
desc->processor = OMR_PROCESSOR_X86_AMDK6;
break;
}
case CPUID_FAMILYCODE_AMDATHLON:
desc->processor = OMR_PROCESSOR_X86_AMDATHLONDURON;
break;
case CPUID_FAMILYCODE_AMDOPTERON:
desc->processor = OMR_PROCESSOR_X86_AMDOPTERON;
break;
}
}

desc->physicalProcessor = desc->processor;

/* features */
desc->features[0] = CPUInfo[3];
desc->features[1] = CPUInfo[2];
desc->features[2] = 0; /* reserved for future expansion */

return 0;
}

/**
* Assembly code to get the register data from CPUID instruction
* This function executes the CPUID instruction based on which we can detect
* if the environment is virtualized or not, and also get the Hypervisor Vendor
* Name based on the same instruction. The leaf value specifies what information
* to return.
*
* @param[in] leaf The leaf value to the CPUID instruction.
* @param[out] cpuInfo Reference to the an integer array which holds the data
* of EAX,EBX,ECX and EDX registers.
* cpuInfo[0] To hold the EAX register data, value in this register at
* the time of CPUID tells what information to return
* EAX=0x1,returns the processor Info and feature bits
* in EBX,ECX,EDX registers.
* EAX=0x40000000 returns the Hypervisor Vendor Names
* in the EBX,ECX,EDX registers.
* cpuInfo[1] For EAX = 0x40000000 hold first 4 characters of the
* Hypervisor Vendor String
* cpuInfo[2] For EAX = 0x1, the 31st bit of ECX tells if its
* running on Hypervisor or not,For EAX = 0x40000000 holds the second
* 4 characters of the the Hypervisor Vendor String
* cpuInfo[3] For EAX = 0x40000000 hold the last 4 characters of the
* Hypervisor Vendor String
*
*/

void
getX86CPUID(uint32_t leaf, uint32_t *cpuInfo)
{
cpuInfo[0] = leaf;

/* Implemented for x86 & x86_64 bit platforms */
#if defined(WIN32)
/* Specific CPUID instruction available in Windows */
__cpuid(cpuInfo, cpuInfo[0]);

#elif defined(LINUX) || defined(OSX)
#if defined(J9X86)
__asm volatile
("mov %%ebx, %%edi;"
"cpuid;"
"mov %%ebx, %%esi;"
"mov %%edi, %%ebx;"
:"+a" (cpuInfo[0]), "=S" (cpuInfo[1]), "=c" (cpuInfo[2]), "=d" (cpuInfo[3])
: :"edi");

#elif defined(J9HAMMER)
__asm volatile(
"cpuid;"
:"+a" (cpuInfo[0]), "=b" (cpuInfo[1]), "=c" (cpuInfo[2]), "=d" (cpuInfo[3])
);
#endif
#endif
}
@@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright (c) 2019, 2019 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/
/**
* @file
* @ingroup Port
* @brief System information
*/

#ifndef SYSINFOHELPERS_H_
#define SYSINFOHELPERS_H_

#include "omrport.h"

extern void
getX86CPUID(uint32_t leaf, uint32_t *cpuInfo);

extern intptr_t
getX86Description(struct OMRPortLibrary *portLibrary, OMRProcessorDesc *desc);

#endif /* SYSINFOHELPERS_H_ */

0 comments on commit 0f824c6

Please sign in to comment.
You can’t perform that action at this time.