Files
org-hyperion-cules/loadmem.c
Enrico Sorichetti c396a57818 Fixed some (silenced others) clang warnings
more to analyze and fix for linux
2014-10-08 12:49:31 +02:00

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
}