mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-13 07:25:22 +02:00
657 lines
24 KiB
C
657 lines
24 KiB
C
/* LOADMEM.C (c) Copyright Roger Bowler, 1999 */
|
|
/* (c) Copyright Paul Leisy, 2001 */
|
|
/* (c) Copyright TurboHercules SAS, 2010-2012 */
|
|
/* Load memory functions */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
|
|
#include "hstdinc.h"
|
|
|
|
#define _LOADMEM_C_
|
|
|
|
#include "hercules.h"
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* loadcore filename command - load a core image file */
|
|
/*-------------------------------------------------------------------*/
|
|
int loadcore_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
REGS *regs;
|
|
|
|
char *fname; /* -> File name (ASCIIZ) */
|
|
struct stat statbuff; /* Buffer for file status */
|
|
char *loadaddr; /* loadcore memory address */
|
|
U64 work64; /* 64-bit work variable */
|
|
RADR aaddr; /* Absolute storage address */
|
|
char pathname[MAX_PATH]; /* file in host path format */
|
|
|
|
UNREFERENCED(cmdline);
|
|
|
|
if (argc < 2)
|
|
{
|
|
WRMSG(HHC02202, "E", argv[0] );
|
|
return -1;
|
|
}
|
|
|
|
fname = argv[1];
|
|
hostpath(pathname, fname, sizeof(pathname));
|
|
|
|
if (stat(pathname, &statbuff) < 0)
|
|
{
|
|
WRMSG(HHC02219, "E", "stat()", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
if (argc < 3) aaddr = 0;
|
|
else
|
|
{
|
|
loadaddr = argv[2];
|
|
|
|
if (sscanf(loadaddr, "%"I64_FMT"x", &work64) !=1)
|
|
{
|
|
WRMSG(HHC02205, "E", loadaddr, ": invalid address" );
|
|
return -1;
|
|
}
|
|
aaddr = (RADR) work64;
|
|
}
|
|
|
|
obtain_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
|
|
if (!IS_CPU_ONLINE(sysblk.pcpu))
|
|
{
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
WRMSG(HHC00816, "W", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "online");
|
|
return 0;
|
|
}
|
|
regs = sysblk.regs[sysblk.pcpu];
|
|
|
|
/* Command is valid only when CPU is stopped */
|
|
if (CPUSTATE_STOPPED != regs->cpustate)
|
|
{
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
WRMSG(HHC02247, "E");
|
|
return -1;
|
|
}
|
|
|
|
// "Loading file %s to location %s"
|
|
{
|
|
char buf1[32];
|
|
MSGBUF( buf1, "%"I64_FMT"X", (U64) aaddr );
|
|
WRMSG(HHC02250, "I", fname, buf1 );
|
|
}
|
|
|
|
(void)load_main(fname, aaddr, 1);
|
|
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
|
|
// "Operation complete"
|
|
WRMSG(HHC02249, "I");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* loadtext filename command - load a text deck file */
|
|
/*-------------------------------------------------------------------*/
|
|
int loadtext_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
const char blanks[8] = {"\x40\x40\x40\x40\x40\x40\x40\x40"};
|
|
|
|
|
|
/* Object deck record format headers */
|
|
/* (names chosen not to conflict with future GOFF support) */
|
|
|
|
const char c_ObjectESD[9] = {"\xC5\xE2\xC4\x40\x40\x40\x40\x40\x40"}; // ESD - External Symbol Dictionary
|
|
const char c_ObjectTXT[4] = {"\xE3\xE7\xE3\x40"}; // TXT - Text
|
|
const char c_ObjectRLD[9] = {"\xD9\xD3\xC4\x40\x40\x40\x40\x40\x40"}; // RLD - Relocation Dictionary
|
|
const char c_ObjectEND[4] = {"\xC5\xD5\xC4\x40"}; // END - End
|
|
const char c_ObjectSYM[9] = {"\xE2\xE8\xD4\x40\x40\x40\x40\x40\x40"}; // SYM - Symbol
|
|
|
|
|
|
/* Special control directives from VM */
|
|
|
|
const char c_ObjectCPB[3] = {"\xC3\xD7\xC2"}; // CPB - Conditional Page Boundary
|
|
const char c_ObjectDEL[3] = {"\xC4\xD5\xD3"}; // DEL - Delete
|
|
const char c_ObjectICS[3] = {"\xC9\xC3\xE2"}; // ICS - Include Control Section
|
|
const char c_ObjectLDT[3] = {"\xD3\xC4\xE3"}; // LDT - Loader Termination
|
|
const char c_ObjectPAD[3] = {"\xD7\xC1\xC4"}; // PAD - Padding
|
|
const char c_ObjectPRT[3] = {"\xD7\xD8\xE3"}; // PRT - Printer
|
|
const char c_ObjectPRM[3] = {"\xD7\xD8\xD4"}; // PRM - Parameter
|
|
const char c_ObjectREP[3] = {"\xD9\xC5\xD7"}; // REP - Replace
|
|
const char c_ObjectSLC[3] = {"\xE2\xD3\xC3"}; // SLC - Set Location Counter
|
|
const char c_ObjectSPB[3] = {"\xE1\xD7\xC2"}; // SPB - Set Page Boundary
|
|
const char c_ObjectSYS[3] = {"\xE1\xE8\xE1"}; // SYS - Subsystem
|
|
const char c_ObjectUPB[3] = {"\xE4\xD7\xC2"}; // UPB - Unconditional Page Boundary
|
|
const char c_ObjectVER[3] = {"\xE5\xC5\xD8"}; // VER - Verify
|
|
|
|
|
|
/* Define byte tests for general record types */
|
|
|
|
#define TextRecord 0x02
|
|
#define GOFFRecord 0x03
|
|
#define CommentRecord 0x5C
|
|
#define LoaderBinderRecord 0x40
|
|
|
|
|
|
/* Define directive tests */
|
|
|
|
#define ObjectTest(n) (NCMP(c_Object##n, buf+1, sizeof(c_Object##n)))
|
|
|
|
#define ObjectESD (ObjectTest(ESD) && \
|
|
NCMP(buf+12, blanks, 2) && \
|
|
NCMP(buf+64, blanks, 8))
|
|
|
|
#define ObjectTXT (ObjectTest(TXT) && \
|
|
NCMP(buf+8, blanks, 2) && \
|
|
NCMP(buf+12, blanks, 2))
|
|
|
|
#define ObjectRLD (ObjectTest(RLD) && \
|
|
NCMP(buf+12, blanks, 4))
|
|
|
|
#define ObjectEND (ObjectTest(END) && \
|
|
NCMP(buf+8, blanks, 6) && \
|
|
NCMP(buf+24, blanks, 4) && \
|
|
NCMP(buf+71, blanks, 1))
|
|
|
|
#define ObjectSYM (ObjectTest(SYM) && \
|
|
NCMP(buf+12, blanks, 4))
|
|
|
|
|
|
#define ObjectCPB (ObjectTest(CPB))
|
|
#define ObjectDEL (ObjectTest(DEL))
|
|
#define ObjectICS (ObjectTest(ICS))
|
|
#define ObjectLDT (ObjectTest(LDT))
|
|
#define ObjectPAD (ObjectTest(PAD))
|
|
#define ObjectPRT (ObjectTest(PRT))
|
|
#define ObjectPRM (ObjectTest(PRM))
|
|
#define ObjectREP (ObjectTest(REP))
|
|
#define ObjectSLC (ObjectTest(SLC))
|
|
#define ObjectSPB (ObjectTest(SPB))
|
|
#define ObjectSYS (ObjectTest(SYS))
|
|
#define ObjectUPB (ObjectTest(UPB))
|
|
#define ObjectVER (ObjectTest(VER))
|
|
|
|
|
|
char *fname; /* -> File name (ASCIIZ) */
|
|
char *loadaddr; /* loadcore memory address */
|
|
U64 work64; /* 64-bit work variable */
|
|
RADR aaddr; /* Absolute storage address */
|
|
RADR ahighaddr; /* Absolute high address */
|
|
int fd; /* File descriptor */
|
|
BYTE buf[80]; /* Read buffer */
|
|
int recno; /* Record number */
|
|
int rc = 0; /* Return code */
|
|
int terminate = 0; /* Terminate load process */
|
|
REGS *regs;
|
|
char pathname[MAX_PATH];
|
|
|
|
UNREFERENCED(cmdline);
|
|
|
|
if (argc < 2)
|
|
{
|
|
WRMSG(HHC02202, "E", argv[0] );
|
|
return -1;
|
|
}
|
|
|
|
fname = argv[1];
|
|
|
|
if (argc < 3)
|
|
aaddr = 0;
|
|
else
|
|
{
|
|
loadaddr = argv[2];
|
|
|
|
if (sscanf(loadaddr, "%"I64_FMT"x", &work64) !=1)
|
|
{
|
|
WRMSG(HHC02205, "E", loadaddr, ": invalid address" );
|
|
return -1;
|
|
}
|
|
aaddr = (RADR) work64;
|
|
|
|
if (aaddr >= sysblk.mainsize)
|
|
{
|
|
WRMSG( HHC02251, "E" );
|
|
return -1;
|
|
}
|
|
|
|
/* Address must be on quadword boundary to maintain alignment */
|
|
if (aaddr & 0x0F)
|
|
{
|
|
WRMSG( HHC02306, "E", argv[0], loadaddr);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
ahighaddr = aaddr;
|
|
|
|
obtain_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
|
|
if (!IS_CPU_ONLINE(sysblk.pcpu))
|
|
{
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
WRMSG(HHC00816, "W", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "online");
|
|
return 0;
|
|
}
|
|
regs = sysblk.regs[sysblk.pcpu];
|
|
|
|
if (aaddr > regs->mainlim)
|
|
{
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
WRMSG(HHC02251, "E");
|
|
return -1;
|
|
}
|
|
|
|
/* Command is valid only when CPU is stopped */
|
|
if (CPUSTATE_STOPPED != regs->cpustate)
|
|
{
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
WRMSG(HHC02247, "E");
|
|
return -1;
|
|
}
|
|
|
|
/* Open the specified file name */
|
|
hostpath(pathname, fname, sizeof(pathname));
|
|
if ((fd = HOPEN (pathname, O_RDONLY | O_BINARY)) < 0)
|
|
{
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
WRMSG(HHC02219,"E", "open()", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
for ( recno = 1; rc == 0 || terminate; recno++ )
|
|
{
|
|
int rlen; /* Record Length */
|
|
|
|
/* Read 80 bytes into buffer */
|
|
rlen = read( fd, buf, sizeof(buf) );
|
|
|
|
/* Handle file read error conditions */
|
|
if ( rlen < 0 )
|
|
{
|
|
WRMSG(HHC02219,"E", "loadtext read()", strerror(errno));
|
|
rc = -1;
|
|
break;
|
|
}
|
|
|
|
/* if record length is not 80; leave */
|
|
else if ( rlen != sizeof(buf) )
|
|
{
|
|
if (rlen > 0)
|
|
{
|
|
WRMSG( HHC02301, "E", argv[0], recno, (int)sizeof(buf) );
|
|
rc = -1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
/*************************************************************/
|
|
/* */
|
|
/* Process valid Object Deck Records by type (0x02, */
|
|
/* 0x03, *, and blank) */
|
|
/* */
|
|
/*************************************************************/
|
|
|
|
switch (buf[0])
|
|
{
|
|
|
|
case TextRecord:
|
|
|
|
/*****************************************************/
|
|
/* */
|
|
/* Process valid Object Deck Records by */
|
|
/* occurrence priority */
|
|
/* */
|
|
/* - Columns 73-80 (Deck ID, sequence number, */
|
|
/* or both) are ignored for 0x02 compiler */
|
|
/* generated records. */
|
|
/* */
|
|
/*****************************************************/
|
|
|
|
/* if record is "TXT" then copy bytes to mainstore */
|
|
if (ObjectTXT)
|
|
{
|
|
u_int n = ((((buf[5] << 8) | buf[6])<<8) | buf[7]); // Relative address (positive)
|
|
u_int len = (buf[10] << 8) | buf[11]; // Byte count
|
|
if (len <= 56) // Process if useable count
|
|
{
|
|
RADR lastbyte = aaddr + n + len - 1;
|
|
if (lastbyte >= sysblk.mainsize) // Bytes must fit into storage
|
|
{
|
|
WRMSG(HHC02307,"E", argv[0], recno, (U64)lastbyte);
|
|
rc = -1;
|
|
break;
|
|
}
|
|
ahighaddr = MAX(ahighaddr, lastbyte); // Keep track of highsest byte used
|
|
memcpy(regs->mainstor + aaddr + n, &buf[16], len);
|
|
STORAGE_KEY(aaddr + n, regs) |= (STORKEY_REF | STORKEY_CHANGE);
|
|
STORAGE_KEY(aaddr + n + len - 1, regs) |= (STORKEY_REF | STORKEY_CHANGE);
|
|
}
|
|
}
|
|
|
|
/* if record is "RLD" then process */
|
|
else if (ObjectRLD)
|
|
{
|
|
|
|
/* Define local macros for relocation tests */
|
|
|
|
#define RLD_RELOC_A ((reloc[4] & 0x30) == 0x00) // A-constant
|
|
#define RLD_RELOC_V ((reloc[4] & 0x30) == 0x10) // V-constant
|
|
#define RLD_RELOC_Q ((reloc[4] & 0x30) == 0x20) // Q-constant
|
|
#define RLD_RELOC_CXD ((reloc[4] & 0x30) == 0x30) // CXD-constant
|
|
#define RLD_RELOC_RI2 ((reloc[4] & 0x7C) == 0x70) // 2-byte Relative-Immediate reference
|
|
#define RLD_RELOC_RI4 ((reloc[4] & 0x7C) == 0x78) // 4-byte Relative-Immediate reference
|
|
#define RLD_RELOC_RI (RLD_RELOC_RI2 || RLD_RELOC_RI4) // Relative-Immediate reference
|
|
#define RLD_RELOC_NEG ((reloc[4] & 0x02) == 0x02) // Negative relocation
|
|
#define RLD_RELOC_POS ((reloc[4] & 0x02) == 0x00) // Positive relocation
|
|
|
|
|
|
U16 count = (buf[10] << 8) | buf[11];
|
|
BYTE *rstart = buf + 16; // Start of relocation entries
|
|
BYTE *rend; // End of relocation entries
|
|
BYTE *reloc; // Current relocation entry
|
|
u_int seglength = 8; // Set initial segment length
|
|
U16 resdid; // Relocation ESDID
|
|
U16 pesdid; // Position ESDID
|
|
|
|
if (count > 56)
|
|
continue; // Skip if bad count
|
|
|
|
rend = rstart + count; // End of relocation
|
|
|
|
/* Process Relocation Dictionary Entries */
|
|
|
|
/* Note: All relocations are presently considered to only have */
|
|
/* relocation within a single object deck (ESDIDs ignored). */
|
|
|
|
for (reloc = rstart; reloc < rend;)
|
|
{
|
|
u_int acl; // Address constant length
|
|
u_int aarel; // Load relocation address
|
|
u_int n; // Working length
|
|
BYTE *vc; // Pointer to relocation constant
|
|
U64 v = 0; // Variable contents for relocation
|
|
|
|
|
|
/* Load new Relocation ESDID and Position ESDID */
|
|
/* (the first entry on record always contains a R-ESDID and P-ESDID) */
|
|
|
|
if (seglength > 4)
|
|
{
|
|
resdid = (reloc[0] << 8) | reloc[1];
|
|
pesdid = (reloc[2] << 8) | reloc[3];
|
|
}
|
|
|
|
UNREFERENCED(resdid); // relocation will be added later
|
|
UNREFERENCED(pesdid); // relocation will be added later
|
|
|
|
if (!(RLD_RELOC_Q || RLD_RELOC_CXD)) // Relocate all except Q/CXD-constants
|
|
{
|
|
|
|
/* Determine address constant length - 1 */
|
|
|
|
if (RLD_RELOC_RI) // Relative-Immediate?
|
|
acl = ((reloc[4] & 0x08) >> 2) + 1; // Set 2/4-byte Relative-Immediate length
|
|
else // Else set address constant length
|
|
acl = ((reloc[4] & 0x40) >> 4) + ((reloc[4] & 0x0C) >> 2);
|
|
|
|
|
|
/* Load relocation address */
|
|
|
|
aarel = (((reloc[5] << 8) | reloc[6]) << 8) | reloc[7];
|
|
|
|
|
|
/* Relocate address */
|
|
|
|
if ((aaddr + aarel + acl) < sysblk.mainsize)
|
|
{
|
|
|
|
/* Fetch variable length constant */
|
|
|
|
vc = (BYTE *)regs->mainstor + aaddr + aarel;
|
|
v = 0;
|
|
for (n = 0;;)
|
|
{
|
|
v |= vc[n];
|
|
if (n++ >= acl)
|
|
break;
|
|
v <<= 8;
|
|
}
|
|
|
|
/* Relocate value */
|
|
|
|
if (RLD_RELOC_POS) /* Positive relocation */
|
|
v += aaddr;
|
|
else /* Negative relocation */
|
|
v = aaddr - v;
|
|
|
|
|
|
/* Store variable length constant */
|
|
|
|
for (n = acl;;)
|
|
{
|
|
vc[n] = v & 0xFF;
|
|
if (n-- <= 0)
|
|
break;
|
|
v >>= 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WRMSG(HHC02307,"W", argv[0], recno, (RADR)aarel);
|
|
rc = 4;
|
|
}
|
|
}
|
|
|
|
|
|
/* Set length based on using last ESDID entries */
|
|
|
|
reloc += seglength = (reloc[4] & 0x01) ? 4 : 8;
|
|
}
|
|
|
|
/* Undefine local macros for relocation tests */
|
|
|
|
#undef RLD_RELOC_A // A-constant
|
|
#undef RLD_RELOC_V // V-constant
|
|
#undef RLD_RELOC_Q // Q-constant
|
|
#undef RLD_RELOC_CXD // CXD-constant
|
|
#undef RLD_RELOC_RI2 // 2-byte Relative-Immediate reference
|
|
#undef RLD_RELOC_RI4 // 4-byte Relative-Immediate reference
|
|
#undef RLD_RELOC_RI // Relative-Immediate reference
|
|
#undef RLD_RELOC_NEG // Negative relocation
|
|
#undef RLD_RELOC_POS // Positive relocation
|
|
|
|
}
|
|
|
|
/* if record is "ESD" then process */
|
|
else if (ObjectESD)
|
|
continue; // For now, fill in later
|
|
|
|
/* if record is "END" then process */
|
|
else if (ObjectEND)
|
|
{
|
|
/* Bump to next quadword boundary */
|
|
aaddr = (ahighaddr + 15) & 0xFFFFF0;
|
|
|
|
// Future processing may be to take start address
|
|
// from END card and place in PSW
|
|
|
|
}
|
|
|
|
/* if record is "SYM" then process */
|
|
else if (ObjectSYM)
|
|
continue; // For now, fill in later
|
|
|
|
|
|
/*****************************************************/
|
|
/* */
|
|
/* Process VM loader directives */
|
|
/* */
|
|
/*****************************************************/
|
|
|
|
/* if record is "SPB" then process */
|
|
else if (ObjectSPB)
|
|
{
|
|
aaddr = (MAX(aaddr, ahighaddr) + 4093) & 0xFFFFF000;
|
|
|
|
/* Warn if further action may exceed storage */
|
|
|
|
if (aaddr >= sysblk.mainsize)
|
|
{
|
|
WRMSG(HHC02307,"W", argv[0], recno, aaddr);
|
|
rc = 4;
|
|
}
|
|
}
|
|
|
|
/* if record is "LDT" then process and break out of loop */
|
|
else if (ObjectLDT)
|
|
{
|
|
terminate = 1; // Terminate process, leave RC alone
|
|
}
|
|
|
|
/* If unsupported VM record, just warn */
|
|
else if (ObjectCPB ||
|
|
ObjectDEL ||
|
|
ObjectICS ||
|
|
ObjectPAD ||
|
|
ObjectPRT ||
|
|
ObjectPRM ||
|
|
ObjectREP ||
|
|
ObjectSLC ||
|
|
ObjectSYS ||
|
|
ObjectUPB ||
|
|
ObjectVER)
|
|
{
|
|
char msgbuf[4];
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
msgbuf[0] = guest_to_host(buf[1]);
|
|
msgbuf[1] = guest_to_host(buf[2]);
|
|
msgbuf[2] = guest_to_host(buf[3]);
|
|
WRMSG( HHC02309, "W", argv[0], recno, msgbuf );
|
|
rc = 4;
|
|
}
|
|
|
|
|
|
/*****************************************************/
|
|
/* */
|
|
/* Handle unknown loader directive */
|
|
/* */
|
|
/*****************************************************/
|
|
|
|
/* If unknown object record, complain */
|
|
else
|
|
{
|
|
char msgbuf[4];
|
|
|
|
memset(msgbuf, 0, sizeof(msgbuf));
|
|
msgbuf[0] = guest_to_host(buf[1]);
|
|
msgbuf[1] = guest_to_host(buf[2]);
|
|
msgbuf[2] = guest_to_host(buf[3]);
|
|
WRMSG( HHC02302, "W", argv[0], recno, msgbuf );
|
|
rc = 4;
|
|
}
|
|
|
|
/* End of original object format handling */
|
|
break;
|
|
|
|
|
|
/*********************************************************/
|
|
/* */
|
|
/* Process GOFF records */
|
|
/* */
|
|
/*********************************************************/
|
|
|
|
case GOFFRecord:
|
|
|
|
/* Error if GOFF object (not handled yet) */
|
|
WRMSG( HHC02303, "E", argv[0], recno );
|
|
rc = -1;
|
|
break;
|
|
|
|
|
|
/*********************************************************/
|
|
/* */
|
|
/* Process VM comment record */
|
|
/* */
|
|
/*********************************************************/
|
|
|
|
case CommentRecord:
|
|
break; // Ignore record
|
|
|
|
|
|
/*********************************************************/
|
|
/* */
|
|
/* Process Linkage Editor / Loader / Binder */
|
|
/* directives */
|
|
/* */
|
|
/*********************************************************/
|
|
|
|
/* Skip if possible loader card, but complain anyways */
|
|
case LoaderBinderRecord:
|
|
WRMSG( HHC02304, "W", argv[0], recno );
|
|
rc = 4;
|
|
break;
|
|
|
|
|
|
/*********************************************************/
|
|
/* */
|
|
/* Process unknown/unsupported records and */
|
|
/* directives */
|
|
/* */
|
|
/*********************************************************/
|
|
|
|
default:
|
|
WRMSG( HHC02305, "E", argv[0], recno );
|
|
rc = -1;
|
|
}
|
|
|
|
}
|
|
|
|
/* Close file and issue status message */
|
|
close (fd);
|
|
|
|
if (rc >= 0 && rc < 8)
|
|
{
|
|
if (rc > 0)
|
|
WRMSG(HHC02308, "W", argv[0] );
|
|
// "Operation complete"
|
|
WRMSG(HHC02249, "I");
|
|
}
|
|
|
|
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
|
|
return rc;
|
|
|
|
/* Undefine macros for routine */
|
|
|
|
#undef TextRecord
|
|
#undef GOFFRecord
|
|
#undef CommentRecord
|
|
#undef LoaderBinderRecord
|
|
#undef ObjectTest
|
|
#undef ObjectESD
|
|
#undef ObjectTXT
|
|
#undef ObjectRLD
|
|
#undef ObjectEND
|
|
#undef ObjectSYM
|
|
#undef ObjectCPB
|
|
#undef ObjectDEL
|
|
#undef ObjectICS
|
|
#undef ObjectLDT
|
|
#undef ObjectPAD
|
|
#undef ObjectPRT
|
|
#undef ObjectPRM
|
|
#undef ObjectREP
|
|
#undef ObjectSLC
|
|
#undef ObjectSPB
|
|
#undef ObjectSYS
|
|
#undef ObjectUPB
|
|
#undef ObjectVER
|
|
|
|
}
|