diff --git a/CHANGELOG.md b/CHANGELOG.md index b36581ba4..b26f2711c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## `3.1.0` - Bugfix: removed "ByteOutputStream" debug message, which was part of the `zwe` command output (#491) +- Enhancement: module registry (#405) ## `3.0.0` - Feature: added javascript `zos.getStatvfs(path)` function to obtain file system information (#482). diff --git a/build_modreg.sh b/build_modreg.sh new file mode 100644 index 000000000..1050d7f36 --- /dev/null +++ b/build_modreg.sh @@ -0,0 +1,53 @@ +#!/bin/sh +set -e + +export _LD_SYSLIB="//'SYS1.CSSLIB'://'CEE.SCEELKEX'://'CEE.SCEELKED'://'CEE.SCEERUN'://'CEE.SCEERUN2'://'CSF.SCSFMOD0'" + +xlc -S -M -qmetal -q64 -DSUBPOOL=132 -DMETTLE=1 -DMSGPREFIX=\"ZWE\" \ + -qreserved_reg=r12 \ + -DHAVE_METALIO=1 \ + -Wc,langlvl\(extc99\),arch\(8\),agg,exp,list\(\),so\(\),off,xref,roconst,longname,lp64 \ + -I h -I /usr/include/zos \ + ./c/modreg.c \ + ./c/alloc.c \ + ./c/isgenq.c \ + ./c/lpa.c \ + ./c/qsam.c \ + ./c/metalio.c \ + ./c/utils.c \ + ./c/timeutls.c \ + ./c/zvt.c \ + ./c/zos.c \ + ./tests/modregtest.c + +for file in \ + modreg \ + alloc \ + isgenq \ + lpa \ + qsam \ + metalio \ + utils \ + timeutls \ + zvt \ + zos \ + modregtest +do + as -mgoff -mobject -mflag=nocont --TERM --RENT -aegimrsx=${file}.asm ${file}.s +done + +ld -V -b ac=1 -b rent -b case=mixed -b map -b xref -b reus -e main \ +-o "//'${USER}.LOADLIB(MODREG)'" \ +modreg.o \ +alloc.o \ +isgenq.o \ +lpa.o \ +qsam.o \ +metalio.o \ +utils.o \ +timeutls.o \ +zvt.o \ +zos.o \ +modregtest.o > MODREG.lnk + + diff --git a/c/crossmemory.c b/c/crossmemory.c index 5ddc6199e..dc37ca6cc 100644 --- a/c/crossmemory.c +++ b/c/crossmemory.c @@ -42,6 +42,7 @@ #include "stcbase.h" #include "utils.h" #include "zvt.h" +#include "modreg.h" #define CMS_STATIC_ASSERT($expr) typedef char p[($expr) ? 1 : -1] @@ -3388,15 +3389,27 @@ static int allocateGlobalResources(CrossMemoryServer *server) { globalArea->serverFlags |= server->flags; globalArea->serverASID = getMyPASID(); - /* Load the module to LPA if needed, otherwise re-use the existing module. */ + /* Register modules or load the module to LPA if needed, otherwise re-use + * the existing module. */ if (moduleAddressLPA == NULL) { - - int lpaAddRSN = 0; - int lpaAddRC = lpaAdd(&server->lpaCodeInfo, &server->ddname, &server->dsname, - &lpaAddRSN); - if (lpaAddRC != 0) { - zowelog(NULL, LOG_COMP_ID_CMS, ZOWE_LOG_SEVERE, CMS_LOG_LPA_LOAD_FAILURE_MSG, lpaAddRC, lpaAddRSN); - return RC_CMS_LPA_ADD_FAILED; + if (server->flags & CROSS_MEMORY_SERVER_FLAG_CLEAN_LPA) { + int lpaAddRSN = 0; + int lpaAddRC = lpaAdd(&server->lpaCodeInfo, &server->ddname, + &server->dsname, &lpaAddRSN); + if (lpaAddRC != 0) { + zowelog(NULL, LOG_COMP_ID_CMS, ZOWE_LOG_SEVERE, + CMS_LOG_LPA_LOAD_FAILURE_MSG, lpaAddRC, lpaAddRSN); + return RC_CMS_LPA_ADD_FAILED; + } + } else { + uint64_t modregRSN; + int modregRC = modregRegister(server->ddname, server->dsname, + &server->lpaCodeInfo, &modregRSN); + if (modregRC != 0) { + zowelog(NULL, LOG_COMP_ID_CMS, ZOWE_LOG_SEVERE, + CMS_LOG_MODREG_ADD_FAILURE_MSG, modregRC, modregRSN); + return RC_CMS_LPA_ADD_FAILED; + } } globalArea->lpaModuleInfo = server->lpaCodeInfo; diff --git a/c/modreg.c b/c/modreg.c new file mode 100644 index 000000000..fdd1a76fe --- /dev/null +++ b/c/modreg.c @@ -0,0 +1,512 @@ + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#include +#include +#include +#include +#include + +#include "zowetypes.h" +#include "lpa.h" +#include "isgenq.h" +#include "qsam.h" +#include "zos.h" +#include "zvt.h" + +#include + +#include "modreg.h" + +#include "logging.h" + +#ifndef METTLE +/* TODO LE support after c/lpa.c gets it */ +#error LE is not supported +#endif + +#define PACK_RC_RSN(rc32, rsn32) ((uint64_t) (rc32) << 32 | (rsn32)) + +#define LOG_DEBUG($fmt, ...) \ + zowelog(NULL, LOG_COMP_MODREG, ZOWE_LOG_DEBUG, \ + MODREG_LOG_DEBUG_MSG_ID"%s:%d: "$fmt, __FUNCTION__, __LINE__, \ + ##__VA_ARGS__) + +#define DUMP_DEBUG($data, $size) \ + zowedump(NULL, LOG_COMP_MODREG, ZOWE_LOG_DEBUG, (char *) $data, $size) + + +#ifndef MODREG_LOG_DEBUG_MSG_ID +#define MODREG_LOG_DEBUG_MSG_ID "" +#endif + +ZOWE_PRAGMA_PACK + +/* + * WARNING: THESE TWO VALUES MUST NEVER CHANGE!!! + */ +static const QName ZVTE_QNAME = {"ZWE "}; +static const RName ZVTE_RNAME = {8, "ISMODR "}; + +typedef struct ModuleMark_tag { + char eyecatcher[8]; +#define MODREG_MODULE_MARK_EYECATCHER "ZWECMOD:" + char buildTime[26]; + char reserved[6]; +} ModuleMark; + +typedef struct ModuleRegistryEntry_tag { + + char eyecatcher[8]; +#define MODREGE_EYECATCHER "ZWEMODRE" + uint8_t version; +#define MODREGE_VERSION 1 + uint8_t key; +#define MODREGE_KEY 0 + char reserved1[2]; + uint16_t size; + int8_t flag; + char reserved2[1]; + uint64_t creationTime; + char jobName[8]; + uint16_t asid; + + struct ModuleRegistryEntry_tag *next; + + char moduleName[8]; + ModuleMark mark; + + LPMEA lpaInfo; + +} ModuleRegistryEntry; + +ZOWE_PRAGMA_PACK_RESET + + +static void *allocateCommonStorage(uint32_t size, uint8_t key, + int *rc, int *rsn) { + + void *result = NULL; + key <<= 4; + + __asm( + ASM_PREFIX + " IARST64 REQUEST=GET" + ",SIZE=%[size]" + ",COMMON=YES" + ",OWNER=SYSTEM" + ",FPROT=NO" + ",SENSITIVE=NO" + ",TYPE=PAGEABLE" + ",CALLERKEY=NO,KEY00TOF0=%[key]" + ",FAILMODE=RC" + ",REGS=SAVE" + ",RETCODE=(%[rc]),RSNCODE=(%[rsn]) \n" + : "=NR:r1"(result) + : [size]"m"(size), [key]"m"(key), [rc]"r"(rc), [rsn]"r"(rsn) + : "r0", "r14", "r15" + ); + + return result; +} + +static void freeCommonStorage(void *data) { + + __asm( + ASM_PREFIX + " IARST64 REQUEST=FREE,AREAADDR=%[data],REGS=SAVE \n" + : + : [data]"m"(data) + : "r0", "r1", "r14", "r15" + ); + +} + +static uint64_t getAdjustedSTCK(void) { + // get store-clock value + uint64_t stckValue; + __asm(" STCK 0(%0)" : : "r"(&stckValue)); + // get leap seconds + CVT * __ptr32 cvt = *(void * __ptr32 * __ptr32)0x10; + void * __ptr32 cvtext2 = cvt->cvtext2; + int64_t *cvtlso = (int64_t * __ptr32)(cvtext2 + 0x50); + // return adjusted value + return stckValue - *cvtlso; +} + +static ModuleRegistryEntry *allocEntry(uint64_t *rsn) { + + ModuleRegistryEntry *entry = NULL; + + int wasProblemState = supervisorMode(TRUE); + + int originalKey = setKey(0); + { + int allocRC, allocRSN; + entry = allocateCommonStorage(sizeof(ModuleRegistryEntry), MODREGE_KEY, + &allocRC, &allocRSN); + if (entry != NULL) { + memset(entry, 0, sizeof(ModuleRegistryEntry)); + memcpy(entry->eyecatcher, MODREGE_EYECATCHER, sizeof(entry->eyecatcher)); + entry->version = MODREGE_VERSION; + entry->key = MODREGE_KEY; + entry->size = sizeof(ModuleRegistryEntry); + entry->creationTime = getAdjustedSTCK(); + memset(entry->moduleName, ' ', sizeof(entry->moduleName)); + + ASCB *ascb = getASCB(); + char *jobName = getASCBJobname(ascb); + if (jobName) { + memcpy(entry->jobName, jobName, sizeof(entry->jobName)); + } else { + memset(entry->jobName, ' ', sizeof(entry->jobName)); + } + entry->asid = ascb->ascbasid; + } else { + *rsn = PACK_RC_RSN(allocRC, allocRSN); + } + + } + setKey(originalKey); + + if (wasProblemState) { + supervisorMode(FALSE); + } + + return entry; +} + +static void freeEntry(ModuleRegistryEntry *entry) { + + int wasProblemState = supervisorMode(TRUE); + + int originalKey = setKey(0); + { + freeCommonStorage(entry); + } + setKey(originalKey); + + if (wasProblemState) { + supervisorMode(FALSE); + } + +} + +static const ModuleRegistryEntry *findModuleEntry(EightCharString module, + const ModuleMark *mark) { + ZVT *zvt = zvtGet(); + LOG_DEBUG("ZVT address = %p", zvt); + if (zvt == NULL) { + return NULL; + } + + LOG_DEBUG("looking for module %.8s; mark:", module.text); + DUMP_DEBUG(mark, sizeof(*mark)); + + ModuleRegistryEntry *entry = zvt->moduleRegistry; + while (entry) { + LOG_DEBUG("checking entry @ %p:", entry); + DUMP_DEBUG(entry, sizeof(*entry)); + if (!memcmp(module.text, entry->moduleName, sizeof(entry->moduleName)) && + !memcmp(mark, &entry->mark, sizeof(entry->mark))) { + LOG_DEBUG("entry matched"); + return entry; + } + entry = entry->next; + } + + return NULL; +} + +static int lockChain(ENQToken *lockToken, uint64_t *rsn) { + + *rsn = 0; + + int lockRSN = 0; + int lockRC = isgenqGetExclusiveLock(&ZVTE_QNAME, &ZVTE_RNAME, + ISGENQ_SCOPE_SYSTEM, lockToken, &lockRSN); + if (lockRC > 4) { + *rsn = PACK_RC_RSN(lockRC, lockRSN); + return RC_MODREG_CHAIN_NOT_LOCKED; + } + + return RC_MODREG_OK; +} + +static int unlockChain(ENQToken *lockToken, uint64_t *rsn) { + + *rsn = 0; + + int unlockRSN = 0; + int unlockRC = isgenqReleaseLock(lockToken, &unlockRSN); + if (unlockRC > 4) { + *rsn = PACK_RC_RSN(unlockRC, unlockRSN); + return RC_MODREG_CHAIN_NOT_UNLOCKED; + } + + return RC_MODREG_OK; +} + +static void *loadModule(const void *dcb, const char name[8], + struct exti * __ptr32 moduleInfo, + int *rc, int *rsn) { + + void * __ptr32 epAddress = NULL; + int abendCode = 0, abendRSN = 0; + char parmList[32] = {0}; + + __asm( + ASM_PREFIX + " LOAD EPLOC=(%[name]),DCB=(%[dcb]),ERRET=LOADMERR" + ",EXTINFO=(%[exti]),SF=(E,%[parm]) \n" + " J LOADMEXT \n" + "LOADMERR DS 0H \n" + " XGR 0,0 \n" + "LOADMEXT DS 0H \n" + : "=NR:r0"(epAddress), "=NR:r1"(abendCode), "=NR:r15"(abendRSN) + : [name]"r"(name), [dcb]"r"(dcb), [exti]"r"(moduleInfo), + [parm]"m"(parmList) + : "r0", "r1", "r14", "r15" + ); + + if (rc) *rc = abendCode; + if (rsn) *rsn = abendRSN; + + return (void *) ((int) epAddress & 0x7ffffffe); +} + +static int deleteModule(const char name[8]) { + + int rc = 0; + + __asm( + ASM_PREFIX + " DELETE EPLOC=(%[name]) \n" + : "=NR:r15"(rc) + : [name]"r"(name) + : "r0", "r1", "r14", "r15" + ); + + return rc; +} + +static const void *findBytes(const void *haystack, size_t haystackSize, + const void *needle, size_t needleSize) { + if ((haystackSize < needleSize) || !haystackSize || !needleSize) { + return NULL; + } + const char *currPos = haystack; + const char *endPos = (const char *) haystack + haystackSize - needleSize; + while (currPos <= endPos) { + currPos = memchr(currPos, *(const char *) needle, endPos - currPos + 1); + if (currPos == NULL) { + return NULL; + } + if (!memcmp(currPos, needle, needleSize)) { + return currPos; + } + currPos++; + } + return NULL; +} + +static const ModuleMark *findMark(const void *buffer, size_t bufferSize) { + ssize_t bufferOffset = 0; + while (true) { + LOG_DEBUG("looking for a mark in buffer %p (%zu) + %zd", + buffer, bufferSize, bufferOffset); + const char *markInModule = findBytes((char *) buffer + bufferOffset, + bufferSize - bufferOffset, + MODREG_MODULE_MARK_EYECATCHER, + strlen(MODREG_MODULE_MARK_EYECATCHER)); + LOG_DEBUG("mark found @ %p", markInModule); + if (markInModule) { + size_t markSpace = + (char *) buffer + bufferSize - (char *) markInModule; + LOG_DEBUG("mark space = %zu", markSpace); + const ModuleMark *candidate = (ModuleMark *) markInModule; + if (markSpace >= sizeof(ModuleMark) && + candidate->buildTime[0] == '2' && + candidate->buildTime[1] == '0') { + return candidate; + } else { + LOG_DEBUG("mark %p is not eligible", markInModule); + bufferOffset += markInModule - (char *) buffer + + strlen(MODREG_MODULE_MARK_EYECATCHER); + } + } else { + return NULL; + } + } +} + +static int readModuleMark(EightCharString ddname, EightCharString module, + ModuleMark *mark, uint64_t *rsn) { + + void *dcb = openSAM(ddname.text, OPEN_CLOSE_INPUT, FALSE, 0, 0, 0); + LOG_DEBUG("dcb = %p", dcb); + if (!dcb) { + return RC_MODREG_OPEN_SAM_ERROR; + } + + int rc = RC_MODREG_OK; + + struct exti modInfo; + int loadRC, loadRSN; + const void *ep = loadModule(dcb, module.text, &modInfo, &loadRC, &loadRSN); + LOG_DEBUG("load - ep = %p, rc = %d, rsn = 0x%08X", ep, loadRC, loadRSN); + if (!ep) { + *rsn = PACK_RC_RSN(loadRC, loadRSN); + rc = RC_MODREG_MODULE_LOAD_ERROR; + goto out_close_sam; + } + LOG_DEBUG("ext num = %d; mod info:", modInfo.exti_numextents); + DUMP_DEBUG(&modInfo, sizeof(modInfo)); + + rc = RC_MODREG_MARK_MISSING; + for (unsigned i = 0; i < modInfo.exti_numextents; i++) { + + struct extixe *moduleExtent = + (struct extixe *)&modInfo.exti_extent_area + i; + void *extentAddress = *(void **)moduleExtent->extixe_addr; + size_t extentSize = *(size_t *)moduleExtent->extixe_length; + LOG_DEBUG("ext addr = %d, size = %zu", extentAddress, extentSize); + + // TODO could a mark be in-between extents? + + const ModuleMark *candidate = findMark(extentAddress, extentSize); + if (candidate) { + *mark = *candidate; + rc = RC_MODREG_OK; + break; + } + + } + + int delRC = deleteModule(module.text); + LOG_DEBUG("delete - rc = %d", delRC); + // TODO consider making this non-fatal + rc = rc ? rc : (delRC ? RC_MODREG_MODULE_DELETE_ERROR : RC_MODREG_OK); + +out_close_sam: + closeSAM(dcb, OPEN_CLOSE_INPUT); + + return rc; +} + +static void initAndAddEntry(ZVT *zvt, ModuleRegistryEntry *entry, + EightCharString module, + const LPMEA *lpaInfo, + const ModuleMark *mark) { + int wasProblemState = supervisorMode(TRUE); + int originalKey = setKey(0); + { + *(LPMEA *) &entry->lpaInfo = *lpaInfo; + memcpy(entry->moduleName, module.text, sizeof(entry->moduleName)); + *(ModuleMark *) &entry->mark = *mark; + entry->next = zvt->moduleRegistry; + zvt->moduleRegistry = entry; + } + setKey(originalKey); + if (wasProblemState) { + supervisorMode(FALSE); + } +} + +int modregRegister(EightCharString ddname, EightCharString module, + LPMEA *lpaInfo, uint64_t *rsn) { + + uint64_t localRSN; + rsn = rsn ? rsn : &localRSN; + + ZVT *zvt = zvtGet(); + LOG_DEBUG("ZVT address = %p", zvt); + if (zvt == NULL) { + return RC_MODREG_ZVT_NULL; + } + + ModuleMark mark; + int readRC = readModuleMark(ddname, module, &mark, rsn); + if (readRC) { + return readRC; + } + + int lockRC; + uint64_t lockRSN; + ENQToken lockToken; + lockRC = lockChain(&lockToken, &lockRSN); + LOG_DEBUG("lock rc = %d, rsn = 0x%08X", lockRC, lockRSN); + if (lockRC) { + return lockRC; + } + + int rc = 0; + + const ModuleRegistryEntry *existingEntry = findModuleEntry(module, &mark); + LOG_DEBUG("existing entry found @ %p", existingEntry); + if (existingEntry) { + *lpaInfo = existingEntry->lpaInfo; + goto out_unlock; + } + + ModuleRegistryEntry *newEntry = allocEntry(rsn); + LOG_DEBUG("new entry allocated @ %p", newEntry); + if (!newEntry) { + rc = RC_MODREG_ALLOC_FAILED; + goto out_unlock; + } + + int lpaRC, lpaRSN; + lpaRC = lpaAdd(lpaInfo, &ddname, &module, &lpaRSN); + LOG_DEBUG("lpa add rc = %d, rsn = 0x%08X", lpaRC, lpaRSN); + if (lpaRC) { + *rsn = PACK_RC_RSN(lpaRC, lpaRSN); + rc = RC_MODREG_LPA_ADD_FAILED; + goto out_free_entry; + } + LOG_DEBUG("lpa info @ %p:", lpaInfo); + DUMP_DEBUG(lpaInfo, sizeof(*lpaInfo)); + + void *lpaModuleAddress = lpaInfo->outputInfo.stuff.successInfo.loadPointAddr; + int lpaModuleSize = *(int *) lpaInfo->outputInfo.stuff.successInfo.modLen; + LOG_DEBUG("lpaModuleAddress = %p, size = %d", + lpaModuleAddress, lpaModuleSize); + const ModuleMark *lpaMark = findMark(lpaModuleAddress, lpaModuleSize); + if (!lpaMark) { + LOG_DEBUG("mark not found in LPA module"); + rc = RC_MODREG_MARK_MISSING_LPA; + goto out_free_entry; + } + + initAndAddEntry(zvt, newEntry, module, lpaInfo, lpaMark); + +out_free_entry: + freeEntry(newEntry); + +out_unlock: + lockRC = unlockChain(&lockToken, &lockRSN); + LOG_DEBUG("unlock rc = %d, rsn = 0x%08X", lockRC, lockRSN); + rc = rc ? rc : lockRC; + + return rc; +} + + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + diff --git a/h/crossmemory.h b/h/crossmemory.h index aa4c14637..c386e3e5a 100644 --- a/h/crossmemory.h +++ b/h/crossmemory.h @@ -1162,6 +1162,12 @@ typedef struct CMSDynlinkEnv_tag { #define CMS_LOG_LOOKUP_ANC_RESET_WARN_MSG_TEXT "Look-up routine anchor discard RC = %d" #define CMS_LOG_LOOKUP_ANC_RESET_WARN_MSG CMS_LOG_LOOKUP_ANC_RESET_WARN_MSG_ID" "CMS_LOG_LOOKUP_ANC_RESET_WARN_MSG_TEXT +#ifndef CMS_LOG_MODREG_ADD_FAILURE_MSG_ID +#define CMS_LOG_MODREG_ADD_FAILURE_MSG_ID CMS_MSG_PRFX"0258E" +#endif +#define CMS_LOG_MODREG_ADD_FAILURE_MSG_TEXT "Module not registered, RC = %d, RSN = 0x%016X" +#define CMS_LOG_MODREG_ADD_FAILURE_MSG CMS_LOG_MODREG_ADD_FAILURE_MSG_ID" "CMS_LOG_MODREG_ADD_FAILURE_MSG_TEXT + #endif /* H_CROSSMEMORY_H_ */ diff --git a/h/logging.h b/h/logging.h index 1d7654f71..bc70ee950 100644 --- a/h/logging.h +++ b/h/logging.h @@ -92,6 +92,7 @@ ZOWE_PRAGMA_PACK_RESET #define LOG_COMP_LPA 0x008F0001000D0000LLU #define LOG_COMP_RESTDATASET 0x008F0001000E0000LLU #define LOG_COMP_RESTFILE 0x008F0001000F0000LLU +#define LOG_COMP_MODREG 0x008F000100100000LLU #define LOG_COMP_ZOS 0x008F000100130000LLU #define LOG_COMP_HTTPCLIENT 0x008F000100140000LLU #define LOG_COMP_JWT 0x008F000100150000LLU diff --git a/h/modreg.h b/h/modreg.h new file mode 100644 index 000000000..5070aef42 --- /dev/null +++ b/h/modreg.h @@ -0,0 +1,89 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef H_MODREG_H_ +#define H_MODREG_H_ 1 + +#ifdef METTLE +#include +#include +#else +#include +#endif + +#include "lpa.h" +#include "zowetypes.h" + +/** + * This macro marks a module as eligible for the module registry. The macro + * should be used once in the module code, for example, in the main function. + */ +#define MODREG_MARK_MODULE() \ + __asm( \ + " MACRO \n" \ + "&LABEL GENMMARK \n" \ + " DC CL8'ZWECMOD:' \n" \ + " DC CL26'&SYSCLOCK' \n" \ + " DC CL6' ' \n" \ + " MEND , \n" \ + "L$GMMBGN DS 0H \n" \ + " J L$GMMEXT \n" \ + " GENMMARK \n" \ + "L$GMMEXT DS 0H \n" \ + ) + +#define RC_MODREG_OK 0 +#define RC_MODREG_MARK_MISSING 1 +#define RC_MODREG_ZVT_NULL 2 +#define RC_MODREG_OPEN_SAM_ERROR 8 +#define RC_MODREG_MODULE_LOAD_ERROR 9 +#define RC_MODREG_MODULE_DELETE_ERROR 10 +#define RC_MODREG_MARK_MISSING_LPA 11 +#define RC_MODREG_CHAIN_NOT_LOCKED 12 +#define RC_MODREG_CHAIN_NOT_UNLOCKED 13 +#define RC_MODREG_ALLOC_FAILED 14 +#define RC_MODREG_LPA_ADD_FAILED 15 + +#ifndef __LONGNAME__ +#define modregRegister MODRRGST +#endif + +/** + * The function attempts to add a module to the module registry and the LPA; if + * the module is already in the registry, only the existing LPA info is + * returned; if the module has no "mark" defined by the @c MODREG_MARK_MODULE + * macro, no action will be taken and @c RC_MODREG_MARK_MISSING will be + * returned. + * + * When checking the registry, two modules are considered the same, if and + * only if, the modules names and their marks match. + * + * @param[in] ddname the DDNAME of the module to be registered. + * @param[in] module the module to be registered. + * @param[out] lpaInfo the LPA info of this module. + * @param[out] rsn an optional reason code variable providing additional + * information about the failure. + * @return @c RC_MODREG_OK in case of success and any other RC_MODREG_xxx in + * case of failure. + */ +int modregRegister(EightCharString ddname, EightCharString module, + LPMEA *lpaInfo, uint64_t *rsn); + +#endif /* H_MODREG_H_ */ + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ diff --git a/h/zvt.h b/h/zvt.h index c0464c470..6d1569b4c 100644 --- a/h/zvt.h +++ b/h/zvt.h @@ -85,6 +85,7 @@ typedef struct ZVT_tag { uint16_t asid; char reserved22[6]; PAD_LONG(9, void *cmsLookupRoutine); /* points at another page in 31-common */ + PAD_LONG(10, void *moduleRegistry); /* points at the module registry */ char reserved3[104]; struct { diff --git a/tests/modregtest.c b/tests/modregtest.c new file mode 100644 index 000000000..f3d0a24de --- /dev/null +++ b/tests/modregtest.c @@ -0,0 +1,43 @@ + +#include +#include +#include + +#include "zowetypes.h" +#include "lpa.h" +#include "utils.h" +#include "modreg.h" + +void zowelog(void *context, uint64 compID, int level, char *formatString, ...) { + va_list argPointer; + va_start(argPointer, formatString); + vfprintf(NULL, formatString, argPointer); + va_end(argPointer); + printf("\n"); +} + +void zowedump(void *context, uint64 compID, int level, void *data, + int dataSize) { + dumpbuffer(data, dataSize); +} + +int main() { + + MODREG_MARK_MODULE(); + + LPMEA lpaInfo; + int rc; + uint64_t rsn; + + rc = modregRegister((EightCharString) {"STEPLIB "}, + (EightCharString) {"MODREG "}, + &lpaInfo, &rsn); + printf("modregRegister() -> %d\n", rc); + + rc = modregRegister((EightCharString) {"STEPLIB "}, + (EightCharString) {"MODREG "}, + &lpaInfo, &rsn); + printf("modregRegister() -> %d\n", rc); + + return 0; +} \ No newline at end of file