Path: blob/master/runtime/j9vm31/j9cel4ro64.c
12923 views
/*******************************************************************************1* Copyright (c) 2021, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* 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-exception20*******************************************************************************/2122#include "j9cel4ro64.h"23#include <assert.h> /* Required for __gtca() */2425/* Function descriptor of CEL4RO64 runtime call from GTCA control block */26typedef void cel4ro64_cwi_func(void*);27#pragma linkage (cel4ro64_cwi_func,OS_UPSTACK)28#define CEL4RO64_FNPTR ((cel4ro64_cwi_func *)(*(int*)((char*)(*(int*)(((char*)__gtca())+1024))+8)))2930/* CEEPCB_3164 indicator is the 6th bit of PCB's CEEPCBFLAG6 field (byte 84).31* CEECAAPCB field is byte 756 of CAA.32*33* References for AMODE31:34* https://www.ibm.com/docs/en/zos/2.4.0?topic=conventions-language-environment-process-control-block35* https://www.ibm.com/docs/en/zos/2.4.0?topic=conventions-language-environment-common-anchor-area36*/37#define CEL4RO64_CEEPCBFLAG6_VALUE *((char *)(*(int *)(((char *)__gtca())+756))+84)38#define CEL4RO64_CEEPCB_3164_MASK 0x43940#pragma linkage (J9VM_STE,OS)41float J9VM_STE(void);42#pragma linkage (J9VM_STD,OS)43double J9VM_STD(void);44#pragma linkage (J9VM_LE,OS)45void J9VM_LE(float);46#pragma linkage (J9VM_LD,OS)47void J9VM_LD(double);4849/**50* Populate the arguments from argValues in outgoing 64-bit representation based on the types provided.51* This routine will zero extend upper 32-bits as necessary.52*53* @param[in] outgoingArgs The outgoing argument storage area with first 4-bytes as length.54* @param[in] argTypes An array of argument types for call.55* @param[in] argsValues An uint64_t array of argument values.56* @param[in] numArgs Number of arguments.57*/58static void59populateArguments(uint64_t *outgoingArgs, J9_CEL4RO64_ArgType *argTypes, uint64_t *argValues, uint32_t numArgs)60{61/* First field of outgoingArgs is length member - each argument on 64-bit side is62* in an 8-byte slot. Bump outgoingArgs by 4-bytes afterwards.63*/64uint32_t *lengthPtr = (uint32_t*)outgoingArgs;65*lengthPtr = sizeof(uint64_t) * numArgs;66outgoingArgs = (uint64_t *)&(lengthPtr[1]);6768for (uint32_t i = 0; i < numArgs; i++) {69J9_CEL4RO64_ArgType argType = argTypes[i];70jfloat floatArg;71jdouble doubleArg;7273switch(argType) {74case CEL4RO64_type_jboolean:75case CEL4RO64_type_jbyte:76case CEL4RO64_type_jchar:77case CEL4RO64_type_jshort:78case CEL4RO64_type_jint:79case CEL4RO64_type_jsize:80case CEL4RO64_type_uint32_ptr:81outgoingArgs[i] = argValues[i] & 0xFFFFFFFF;82break;83case CEL4RO64_type_jfloat:84/* Note: Float argument requires special handling as the value needs to be loaded into FPR0.85* Only set*FloatField JNI functions have a jfloat parameter, so only need to handle86* one instance.87*/88floatArg = *(jfloat *)(&(argValues[i]));89/* Ideally, we could have used the following inline asm90* but V2R1 xlc does not support that yet.91* __asm(" LE 0,%0" : : "m"(floatArg));92*/93J9VM_LE(floatArg);94break;95case CEL4RO64_type_jdouble:96/* Note: Double argument requires special handling as the value needs to be loaded into FPR0.97* Only set*DoubleField JNI functions have a jdouble parameter, so only need to handle98* one instance.99*/100doubleArg = *(jdouble *)(&(argValues[i]));101/* Ideally, we could have used the following inline asm102* but V2R1 xlc does not support that yet.103* __asm(" LD 0,%0" : : "m"(doubleArg));104*/105J9VM_LD(doubleArg);106break;107case CEL4RO64_type_jlong:108case CEL4RO64_type_jobject:109case CEL4RO64_type_jweak:110case CEL4RO64_type_jclass:111case CEL4RO64_type_jstring:112case CEL4RO64_type_jthrowable:113case CEL4RO64_type_jarray:114case CEL4RO64_type_jmethodID:115case CEL4RO64_type_jfieldID:116case CEL4RO64_type_JNIEnv64:117case CEL4RO64_type_JavaVM64:118outgoingArgs[i] = argValues[i];119break;120default:121break;122}123}124}125126/**127* Populate the return storage buffer with the appropriate return value from CEL4RO64 call.128*129* @param[in] controlBlock The outgoing argument storage area.130* @param[in] returnType The return type of target function.131* @param[in] returnStorage The storage location to store return value.132*/133static void134populateReturnValue(J9_CEL4RO64_controlBlock *controlBlock, J9_CEL4RO64_ArgType returnType, void *returnStorage)135{136/* Integral and pointer data types <= 64 bits in length are widened to 64 bits and returned in GPR3. */137uint64_t GPR3returnValue = controlBlock->gpr3ReturnValue;138139/* Cannot initialize these floating point variables, as it might kill FPR0 which contains the real140* return value.141*/142jfloat floatReturnValue;143jdouble doubleReturnValue;144145switch(returnType) {146case CEL4RO64_type_jboolean:147*((jboolean *)returnStorage) = (jboolean)GPR3returnValue;148break;149case CEL4RO64_type_jbyte:150*((jbyte *)returnStorage) = (jbyte)GPR3returnValue;151break;152case CEL4RO64_type_jchar:153*((jchar *)returnStorage) = (jchar)GPR3returnValue;154break;155case CEL4RO64_type_jshort:156*((jshort *)returnStorage) = (jshort)GPR3returnValue;157break;158case CEL4RO64_type_jint:159case CEL4RO64_type_jsize:160*((jint *)returnStorage) = (jint)GPR3returnValue;161break;162case CEL4RO64_type_jfloat:163/* Float return values are returned via FPR0.164* Ideally, we could have used the following inline asm165* but V2R1 xlc does not support that yet.166* __asm(" STE 0,%0" : "=m"(floatReturnValue));167*/168floatReturnValue = J9VM_STE();169*((jfloat *)returnStorage) = floatReturnValue;170break;171case CEL4RO64_type_jdouble:172/* Double return values are returned via FPR0.173* Ideally, we could have used the following inline asm174* but V2R1 xlc does not support that yet.175* __asm(" STD 0,%0" : "=m"(doubleReturnValue));176*/177doubleReturnValue = J9VM_STD();178*((jdouble *)returnStorage) = doubleReturnValue;179break;180case CEL4RO64_type_jlong:181case CEL4RO64_type_jobject:182case CEL4RO64_type_jweak:183case CEL4RO64_type_jclass:184case CEL4RO64_type_jstring:185case CEL4RO64_type_jthrowable:186case CEL4RO64_type_jarray:187case CEL4RO64_type_jmethodID:188case CEL4RO64_type_jfieldID:189case CEL4RO64_type_JNIEnv64:190case CEL4RO64_type_JavaVM64:191/* These are all 64-bit types. */192*((uint64_t*)returnStorage) = GPR3returnValue;193break;194case CEL4RO64_type_uint32_ptr:195*((uint32_t *)returnStorage) = (uint32_t)GPR3returnValue;196break;197default:198break;199}200}201202uint32_t203j9_cel4ro64_call_function(204uint64_t functionDescriptor, J9_CEL4RO64_ArgType *argTypes, uint64_t *argValues, uint32_t numArgs,205J9_CEL4RO64_ArgType returnType, void *returnStorage)206{207uint32_t retcode = J9_CEL4RO64_RETCODE_OK;208uint32_t argumentAreaInBytes = (0 == numArgs) ? 0 : (sizeof(uint64_t) * numArgs + sizeof(uint32_t)); /* 8 byte slots + 4 byte length member. */209J9_CEL4RO64_controlBlock *controlBlock = NULL;210211/* The CEL4RO64 function may not be available if the LE ++APAR is not installed. */212if (!j9_cel4ro64_isSupported()) {213fprintf(stderr, "CEL4RO64: %s\n", j9_cel4ro64_get_error_message(J9_CEL4RO64_RETCODE_ERROR_LE_RUNTIME_SUPPORT_NOT_FOUND));214return J9_CEL4RO64_RETCODE_ERROR_LE_RUNTIME_SUPPORT_NOT_FOUND;215}216217controlBlock = (J9_CEL4RO64_controlBlock *)malloc(sizeof(J9_CEL4RO64_controlBlock) + argumentAreaInBytes);218219if (NULL == controlBlock) {220retcode = J9_CEL4RO64_RETCODE_ERROR_STORAGE_ISSUE;221fprintf(stderr, "CEL4RO64: malloc failed: %s\n", j9_cel4ro64_get_error_message(retcode));222return retcode;223}224225/* Initialize the control block members and calculate the various offsets. */226controlBlock->version = 1;227controlBlock->flags = J9_CEL4RO64_FLAG_EXECUTE_TARGET_FUNC;228controlBlock->moduleOffset = sizeof(J9_CEL4RO64_controlBlock);229controlBlock->functionOffset = sizeof(J9_CEL4RO64_controlBlock);230controlBlock->dllHandle = 0;231controlBlock->functionDescriptor = functionDescriptor;232233/* If no arguments, the argumentOffset must be zero. */234if (0 == numArgs) {235controlBlock->argumentsOffset = 0;236} else {237uint64_t *argumentsArea = (uint64_t *)((char *)(controlBlock) + sizeof(J9_CEL4RO64_controlBlock));238controlBlock->argumentsOffset = sizeof(J9_CEL4RO64_controlBlock);239populateArguments(argumentsArea, argTypes, argValues, numArgs);240}241242CEL4RO64_FNPTR(controlBlock);243retcode = controlBlock->retcode;244if ((J9_CEL4RO64_RETCODE_OK == retcode) && (CEL4RO64_type_void != returnType)) {245populateReturnValue(controlBlock, returnType, returnStorage);246}247248free(controlBlock);249return retcode;250}251252uint32_t253j9_cel4ro64_load_query_call_function(254const char* moduleName, const char* functionName, J9_CEL4RO64_ArgType *argTypes,255uint64_t *argValues, uint32_t numArgs, J9_CEL4RO64_ArgType returnType, void *returnStorage)256{257uint32_t retcode = J9_CEL4RO64_RETCODE_OK;258uint32_t IPBLength = 0;259uint32_t moduleNameLength = strlen(moduleName);260uint32_t functionNameLength = strlen(functionName);261uint32_t argsLength = sizeof(uint64_t) * numArgs + sizeof(uint32_t); /* 8 byte slots + 4 byte length member. */262J9_CEL4RO64_infoBlock *infoBlock = NULL;263J9_CEL4RO64_controlBlock *controlBlock = NULL;264J9_CEL4RO64_module *moduleBlock = NULL;265J9_CEL4RO64_function *functionBlock = NULL;266267/* The CEL4RO64 function may not be available if the LE ++APAR is not installed. */268if (!j9_cel4ro64_isSupported()) {269fprintf(stderr, "CEL4RO64: %s\n", j9_cel4ro64_get_error_message(J9_CEL4RO64_RETCODE_ERROR_LE_RUNTIME_SUPPORT_NOT_FOUND));270return J9_CEL4RO64_RETCODE_ERROR_LE_RUNTIME_SUPPORT_NOT_FOUND;271}272273IPBLength = sizeof(J9_CEL4RO64_infoBlock) + moduleNameLength + functionNameLength + argsLength +274sizeof(moduleBlock->length) + sizeof(functionBlock->length);275infoBlock = (J9_CEL4RO64_infoBlock *) malloc(IPBLength);276if (NULL == infoBlock) {277retcode = J9_CEL4RO64_RETCODE_ERROR_STORAGE_ISSUE;278fprintf(stderr, "CEL4RO64: malloc failed: %s\n", j9_cel4ro64_get_error_message(retcode));279return retcode;280}281282controlBlock = &(infoBlock->ro64ControlBlock);283284/* Initialize the control block members and calculate the various offsets. */285controlBlock->version = 1;286controlBlock->flags = J9_CEL4RO64_FLAG_ALL_LOAD_QUERY_EXECUTE;287controlBlock->moduleOffset = sizeof(J9_CEL4RO64_controlBlock);288if (0 == moduleNameLength) {289controlBlock->functionOffset = controlBlock->moduleOffset;290} else {291controlBlock->functionOffset = controlBlock->moduleOffset + moduleNameLength + sizeof(moduleBlock->length);292}293294/* For execute target function operations, we need to ensure args reference is set295* up appropriately. If no arguments, argumentsOffset needs to be 0.296*/297if (0 == argsLength) {298controlBlock->argumentsOffset = 0;299} else if (0 == functionNameLength) {300controlBlock->argumentsOffset = controlBlock->functionOffset;301} else {302controlBlock->argumentsOffset = controlBlock->functionOffset + functionNameLength + sizeof(functionBlock->length);303}304305/* For DLL load operations, we need a module name specified. */306moduleBlock = (J9_CEL4RO64_module *)((char *)(controlBlock) + controlBlock->moduleOffset);307infoBlock->ro64Module = moduleBlock;308moduleBlock->length = moduleNameLength;309strncpy(moduleBlock->moduleName, moduleName, moduleNameLength);310311/* For DLL query operations, we need a function name specified. */312functionBlock = (J9_CEL4RO64_function *)((char *)(controlBlock) + controlBlock->functionOffset);313infoBlock->ro64Function = functionBlock;314functionBlock->length = functionNameLength;315strncpy(functionBlock->functionName, functionName, functionNameLength);316317/* For execute target function operations, we need to ensure args is set318* up appropriately. If no arguments, argumentsOffset needs to be 0.319*/320if (0 == numArgs) {321controlBlock->argumentsOffset = 0;322} else {323uint64_t *argumentsArea = (uint64_t *)((char *)(controlBlock) + controlBlock->argumentsOffset);324populateArguments(argumentsArea, argTypes, argValues, numArgs);325}326327CEL4RO64_FNPTR(controlBlock);328retcode = controlBlock->retcode;329if ((J9_CEL4RO64_RETCODE_OK == retcode) && (CEL4RO64_type_void != returnType)) {330populateReturnValue(controlBlock, returnType, returnStorage);331}332333free(infoBlock);334return retcode;335}336337jboolean338j9_cel4ro64_isSupported(void)339{340return (CEL4RO64_CEEPCB_3164_MASK == (CEL4RO64_CEEPCBFLAG6_VALUE & CEL4RO64_CEEPCB_3164_MASK));341}342343const char*344j9_cel4ro64_get_error_message(int retCode)345{346const char* errorMessage;347switch(retCode) {348case J9_CEL4RO64_RETCODE_OK:349errorMessage = "No errors detected.";350break;351case J9_CEL4RO64_RETCODE_ERROR_MULTITHREAD_INVOCATION:352errorMessage = "Multi-threaded invocation not supported.";353break;354case J9_CEL4RO64_RETCODE_ERROR_STORAGE_ISSUE:355errorMessage = "Storage issue detected.";356break;357case J9_CEL4RO64_RETCODE_ERROR_FAILED_AMODE64_ENV:358errorMessage = "Failed to initialize AMODE64 environment.";359break;360case J9_CEL4RO64_RETCODE_ERROR_FAILED_LOAD_TARGET_DLL:361errorMessage = "DLL module not found.";362break;363case J9_CEL4RO64_RETCODE_ERROR_FAILED_QUERY_TARGET_FUNC:364errorMessage = "Target function not found.";365break;366case J9_CEL4RO64_RETCODE_ERROR_LE_RUNTIME_SUPPORT_NOT_FOUND:367errorMessage = "CEL4RO64 runtime support not found.";368break;369default:370errorMessage = "Unexpected return code.";371break;372}373return errorMessage;374}375376377