--- /dev/null
+/*\r
+ MMURTL Operating System Source Code\r
+ Copyright 1991,1992,1993,1994 Richard A. Burgess\r
+ ALL RIGHTS RESERVED\r
+ Version 1.0\r
+*/\r
+\r
+/* This file contains functions and data used to support\r
+ loading or terminating jobs (or services).\r
+ It contains the public functions:\r
+\r
+ Chain() Loads new job run file in current JCB & PD\r
+ LoadNewJob() Loads a new job into a new JCB & PD\r
+ ExitJob() Exits current job, loads ExitJob if specified\r
+\r
+ GetExitJob() Gets run file name that will be loaded upon ExitJob\r
+ SetExitJob() Sets run file name to load upon ExitJob\r
+\r
+ SetCmdLine() Sets the command line for next job\r
+ GetCmdLine() Gets the command line for the current job\r
+\r
+ GetPath() Gets the path prefix for the current job\r
+ Setpath() Sets the path prefix for the current job\r
+\r
+ SetUserName() Sets the Username for the current job\r
+ GetUserName() Gets the Username for the current job\r
+\r
+*/\r
+\r
+\r
+#define U32 unsigned long\r
+#define S32 long\r
+#define U16 unsigned int\r
+#define S16 int\r
+#define U8 unsigned char\r
+#define S8 char\r
+#define TRUE 1\r
+#define FALSE 1\r
+\r
+#include "MKernel.h"\r
+#include "MMemory.h"\r
+#include "MData.h"\r
+#include "MTimer.h"\r
+#include "MVid.h"\r
+#include "MKbd.h"\r
+#include "MJob.h"\r
+#include "MFiles.h"\r
+\r
+#include "runfile.h"\r
+\r
+#define MEMUSERD 7 /* User Writable (Data) */\r
+\r
+#define ErcOpCancel 4 /* Operator cancel */\r
+#define ErcOutOfRange 10 /* Bad Exchange specified in OS call */\r
+#define ErcBadJobNum 70 /* A Bad job number was specified */\r
+#define ErcNoExitJob 76 /* No ExitJob specified on ExitJob(n)*/\r
+#define ErcBadRunFile 74 /* Couldn't load specified ExitRunFile */\r
+\r
+/* Near Support Calls from JobCode.ASM */\r
+\r
+extern long AllocJCB(long *pdJobNumRet, char *ppJCBRet);\r
+extern long RemoveRdyJob(char *pJCB);\r
+extern long GetExchOwner(long Exch, char *pJCBRet);\r
+extern long SetExchOwner(long Exch, char *pNewJCB);\r
+extern long SendAbort(long JobNum, long Exch);\r
+\r
+/* Temporary NEAR externals from the monitor program for debugging */\r
+\r
+extern long xprintf(char *fmt, ...);\r
+extern U32 Dump(unsigned char *pb, long cb);\r
+\r
+/* We switch to this stack when we clean out a user\r
+ PD before we rebuild it.\r
+*/\r
+\r
+static long TmpStack[128]; /* 512 byte temporary stack */\r
+\r
+/* Used for allocating/filling in new JCB */\r
+\r
+static struct JCBRec *pNewJCB; /* Used to access a JCB */\r
+static struct JCBRec *pTmpJCB;\r
+static struct JCBRec *pCrntJCB;\r
+\r
+static long JobNum;\r
+\r
+/* For ExitJob and Chain cause They can't have local vars! */\r
+\r
+static long JobNumE, job_fhE;\r
+static long ExchE, ercE, iE;\r
+static long BogusMsg[2];\r
+static long *pPDE;\r
+static char *pExchJCBE\r
+static long KeyCodeE;\r
+\r
+static char aFileE[80];\r
+static long cbFileE;\r
+\r
+extern unsigned long KillExch; /* From the Monitor */\r
+\r
+/* Run file data */\r
+\r
+static char *pCode, *pData, *pStack; /* Ptrs in User mem to load to */\r
+static long sCode, sData, sStack; /* Size of segments */\r
+static unsigned long oCode, oData; /* Offset in file to Code & Data */\r
+\r
+static long offCode = 0, /* Virtual Offset for Code & Data Segs */\r
+ offData = 0;\r
+\r
+static unsigned long nCDFIX = 0,\r
+ oCDFIX = 0,\r
+ nCCFIX = 0,\r
+ oCCFIX = 0,\r
+ nDDFIX = 0,\r
+ oDDFIX = 0,\r
+ nDCFIX = 0,\r
+ oDCFIX = 0;\r
+\r
+static char *pStart, filetype;\r
+\r
+static struct tagtype tag;\r
+\r
+\r
+/************* INTERNAL SUPPORT CALLS ******************/\r
+\r
+/******************************************************\r
+ This deallocates all user memory in a PD. This is\r
+ used when we ExitJob to free up all the memory.\r
+ We get the pointer to the PD and "walk" through all\r
+ the User PTs deallocating linear memory. When all\r
+ PTs have been cleaned, we eliminate the user PDEs.\r
+ This leaves a blank PD for reuse if needed.\r
+ NOTE: This must be called from a task that is\r
+ running in the JCB that owns the memory!\r
+******************************************************/\r
+\r
+static void CleanUserPD(long *pPD)\r
+{\r
+long i, j, k, erc;\r
+unsigned long *pPT;\r
+char *pMem;\r
+\r
+ for (i=768; i<1024; i++) { /* Look at each shadow PDE */\r
+ if (pPD[i]) { /* If it's a linear address (non 0)*/\r
+ pPT = pPD[i] & 0xFFFFF000; /* Point to Page Table */\r
+ for (j=0; j<1024; j++) {\r
+\r
+ /* Get Beginning address for each run to deallocate */\r
+\r
+ k = 0; /* nPages to deallocate */\r
+ pMem = ((i-512) * 0x400000) + (j * 4096);\r
+ while ((pPT[j++]) && (j<1024))\r
+ k++; /* one more page */\r
+ if (k)\r
+ { /* we have pages (one or more) */\r
+ erc = DeAllocPage(pMem, k);\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/*********************************************************\r
+ This opens, reads and validates the run file.\r
+ If all is well, it leaves it open and returns the\r
+ file handle, else it closes the run file and returns\r
+ the error to the caller.\r
+ The caller is responsible for closing the file!!!\r
+*********************************************************/\r
+\r
+static long GetRunFile(char *pFileName, long cbFileName, long *pfhRet)\r
+{\r
+long erc, i, fh, dret;\r
+char fDone, junk;\r
+\r
+ offCode = 0;\r
+ offData = 0;\r
+ nCDFIX = 0;\r
+ oCDFIX = 0;\r
+ nCCFIX = 0;\r
+ oCCFIX = 0;\r
+ nDDFIX = 0;\r
+ oDDFIX = 0;\r
+ nDCFIX = 0;\r
+ oDCFIX = 0;\r
+ fh = 0;\r
+\r
+ *pfhRet = 0; /* default to 0 */\r
+\r
+ /* Mode Read, Stream type */\r
+ erc = OpenFile(pFileName, cbFileName, 0, 1, &fh);\r
+\r
+ if (!erc) { /* File opened OK */\r
+\r
+ fDone = 0;\r
+ while ((!erc) && (!fDone)) {\r
+ tag.id = 0;\r
+ erc = ReadBytes (fh, &tag, 5, &dret);\r
+\r
+ switch (tag.id) {\r
+ case IDTAG:\r
+ erc = ReadBytes (fh, &filetype, 1, &dret);\r
+ if ((filetype < 1) || (filetype > 3))\r
+ erc = ErcBadRunFile + 30000;\r
+ break;\r
+ case SEGTAG:\r
+ erc = ReadBytes (fh, &sStack, 4, &dret);\r
+ if (!erc) erc = ReadBytes (fh, &sCode, 4, &dret);\r
+ if (!erc) erc = ReadBytes (fh, &sData, 4, &dret);\r
+ break;\r
+ case DOFFTAG:\r
+ erc = ReadBytes (fh, &offData, 4, &dret);\r
+ break;\r
+ case COFFTAG:\r
+ erc = ReadBytes (fh, &offCode, 4, &dret);\r
+ break;\r
+ case STRTTAG:\r
+ erc = ReadBytes (fh, &pStart, 4, &dret);\r
+ break;\r
+ case CODETAG:\r
+ erc = GetFileLFA(fh, &oCode);\r
+ if (!erc)\r
+ erc = SetFileLFA(fh, oCode+tag.len); /* skip it */\r
+ break;\r
+ case DATATAG:\r
+ erc = GetFileLFA(fh, &oData);\r
+ if (!erc)\r
+ erc = SetFileLFA(fh, oData+tag.len); /* skip it */\r
+ break;\r
+ case CDFIXTAG:\r
+ erc = GetFileLFA(fh, &oCDFIX);\r
+ nCDFIX = tag.len/4;\r
+ if (!erc)\r
+ erc = SetFileLFA(fh, oCDFIX+tag.len); /* skip it */\r
+ break;\r
+ case CCFIXTAG:\r
+ erc = GetFileLFA(fh, &oCCFIX);\r
+ nCCFIX = tag.len/4;\r
+ if (!erc)\r
+ erc = SetFileLFA(fh, oCCFIX+tag.len); /* skip it */\r
+ break;\r
+ case DDFIXTAG:\r
+ erc = GetFileLFA(fh, &oDDFIX);\r
+ nDDFIX = tag.len/4;\r
+ if (!erc)\r
+ erc = SetFileLFA(fh, oDDFIX+tag.len); /* skip it */\r
+ break;\r
+ case DCFIXTAG:\r
+ erc = GetFileLFA(fh, &oDCFIX);\r
+ nDCFIX = tag.len/4;\r
+ if (!erc)\r
+ erc = SetFileLFA(fh, oDCFIX+tag.len); /* skip it */\r
+ break;\r
+ case ENDTAG:\r
+ fDone = TRUE;\r
+ break;\r
+ default:\r
+ erc = GetFileLFA(fh, &i);\r
+ if (tag.len > 1024)\r
+ erc = ErcBadRunFile;\r
+ if (!erc)\r
+ erc = SetFileLFA(fh, i+tag.len); /* skip it */\r
+ if (erc)\r
+ erc = ErcBadRunFile;\r
+ break;\r
+ }\r
+\r
+ }\r
+ if (erc)\r
+ CloseFile(fh);\r
+ }\r
+ if (!erc)\r
+ *pfhRet = fh;\r
+\r
+ return (erc);\r
+}\r
+\r
+/********************************************************/\r
+/*********** PUBLIC CALLS FOR JOB MANAGEMENT ************/\r
+/********************************************************/\r
+\r
+/**************************************************/\r
+long far _SetExitJob(char *pRunFile, long dcbRunFile)\r
+{\r
+long JobNum;\r
+\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ if (dcbRunFile > 79)\r
+ return (ErcBadJobParam);\r
+ else if (!dcbRunFile)\r
+ pTmpJCB->JcbExitRF[0] = 0;\r
+ else {\r
+ CopyData(pRunFile, &pTmpJCB->JcbExitRF[1], dcbRunFile);\r
+ pTmpJCB->JcbExitRF[0] = dcbRunFile;\r
+ }\r
+ return(0);\r
+}\r
+\r
+/**************************************************/\r
+long far _GetExitJob(char *pRunRet, long *pdcbRunRet)\r
+{\r
+long JobNum, i;\r
+\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ i = pTmpJCB->JcbExitRF[0];\r
+ if (i)\r
+ CopyData(&pTmpJCB->JcbExitRF[1], pRunRet, i);\r
+ *pdcbRunRet = i;\r
+ return(0);\r
+}\r
+\r
+/**************************************************/\r
+long far _SetPath(char *pPath, long dcbPath)\r
+{\r
+long JobNum;\r
+\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ if (dcbPath > 69)\r
+ return (ErcBadJobParam);\r
+ else if (!dcbPath)\r
+ pTmpJCB->sbPath[0] = 0;\r
+ else {\r
+ CopyData(pPath, &pTmpJCB->sbPath[1], dcbPath);\r
+ pTmpJCB->sbPath[0] = dcbPath;\r
+ }\r
+ return(0);\r
+}\r
+\r
+/**************************************************/\r
+long far _GetPath(long JobNum, char *pPathRet, long *pdcbPathRet)\r
+{\r
+long i, erc;\r
+\r
+ erc = GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to JobNum */\r
+ if (!erc) {\r
+ i = pTmpJCB->sbPath[0];\r
+ if (i)\r
+ CopyData(&pTmpJCB->sbPath[1], pPathRet, i);\r
+ *pdcbPathRet = i;\r
+ }\r
+ return(erc);\r
+}\r
+/**************************************************/\r
+long far _SetCmdLine(char *pCmd, long dcbCmd)\r
+{\r
+long JobNum;\r
+\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ if (dcbCmd > 79)\r
+ return (ErcBadJobParam);\r
+ else if (!dcbCmd)\r
+ pTmpJCB->JcbCmdLine[0] = 0;\r
+ else {\r
+ CopyData(pCmd, &pTmpJCB->JcbCmdLine[1], dcbCmd);\r
+ pTmpJCB->JcbCmdLine[0] = dcbCmd;\r
+ }\r
+ return(0);\r
+}\r
+\r
+/**************************************************/\r
+long far _GetCmdLine(char *pCmdRet, long *pdcbCmdRet)\r
+{\r
+long JobNum, i;\r
+\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ i = pTmpJCB->JcbCmdLine[0];\r
+ if (i)\r
+ CopyData(&pTmpJCB->JcbCmdLine[1], pCmdRet, i);\r
+ *pdcbCmdRet = i;\r
+ return(0);\r
+}\r
+\r
+\r
+/**************************************************/\r
+long far _SetUserName(char *pUser, long dcbUser)\r
+{\r
+long JobNum;\r
+\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ if (dcbUser > 29)\r
+ return (ErcBadJobParam);\r
+ else if (!dcbUser)\r
+ pTmpJCB->sbUserName[0] = 0;\r
+ else {\r
+ CopyData(pUser, &pTmpJCB->sbUserName[1], dcbUser);\r
+ pTmpJCB->sbUserName[0] = dcbUser;\r
+ }\r
+ return(0);\r
+}\r
+\r
+/**************************************************/\r
+long far _GetUserName(char *pUserRet, long *pdcbUserRet)\r
+{\r
+long JobNum, i;\r
+\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ i = pTmpJCB->sbUserName[0];\r
+ if (i)\r
+ CopyData(&pTmpJCB->sbUserName[1], pUserRet, i);\r
+ *pdcbUserRet = i;\r
+ return(0);\r
+}\r
+\r
+/**************************************************/\r
+long far _SetSysIn(char *pName, long dcbName)\r
+{\r
+long JobNum;\r
+\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ if ((dcbName > 49) || (!dcbName))\r
+ return (ErcBadJobParam);\r
+ else {\r
+ CopyData(pName, &pTmpJCB->JcbSysIn[1], dcbName);\r
+ pTmpJCB->JcbSysIn[0] = dcbName;\r
+ }\r
+ return(0);\r
+}\r
+\r
+/**************************************************/\r
+long far _GetSysIn(char *pFileRet, long *pdcbFileRet)\r
+{\r
+long JobNum, i;\r
+\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ i = pTmpJCB->JcbSysIn[0];\r
+ if (i)\r
+ CopyData(&pTmpJCB->JcbSysIn[1], pFileRet, i);\r
+ *pdcbFileRet = i;\r
+ return(0);\r
+}\r
+\r
+/**************************************************/\r
+long far _SetSysOut(char *pName, long dcbName)\r
+{\r
+long JobNum;\r
+\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ if ((dcbName > 49) || (!dcbName))\r
+ return (ErcBadJobParam);\r
+ else {\r
+ CopyData(pName, &pTmpJCB->JcbSysOut[1], dcbName);\r
+ pTmpJCB->JcbSysOut[0] = dcbName;\r
+ }\r
+ return(0);\r
+}\r
+\r
+/**************************************************/\r
+long far _GetSysOut(char *pFileRet, long *pdcbFileRet)\r
+{\r
+long JobNum, i;\r
+\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ i = pTmpJCB->JcbSysOut[0];\r
+ if (i)\r
+ CopyData(&pTmpJCB->JcbSysOut[1], pFileRet, i);\r
+ *pdcbFileRet = i;\r
+ return(0);\r
+}\r
+\r
+/**************************************************/\r
+long far _SetJobName(char *pName, long dcbName)\r
+{\r
+long JobNum;\r
+ GetJobNum(&JobNum);\r
+ GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */\r
+ if (dcbName > 13)\r
+ dcbName = 13;\r
+ if (dcbName)\r
+ CopyData(pName, &pTmpJCB->sbJobName[1], dcbName);\r
+ pTmpJCB->sbJobName[0] = dcbName;\r
+ return(0);\r
+}\r
+\r
+/*********************************************************\r
+ This creates and loads a new Job from a RUN file.\r
+ This returns ErcOK and new job number if loaded OK\r
+ else an error is returned.\r
+*********************************************************/\r
+\r
+long far _LoadNewJob(char *pFileName, long cbFileName, long *pJobNumRet)\r
+{\r
+long erc, i, fh, dret, nPages;\r
+unsigned long *pPD, *pPT, *pVid, *pOSPD;\r
+long *pFix;\r
+U32 PhyAdd;\r
+\r
+\r
+ erc = GetRunFile(pFileName, cbFileName, &fh);\r
+\r
+ if (!erc) {\r
+\r
+ /* We set these to zero so we can tell if they have\r
+ been allocated in case we fail so we know what to deallocate\r
+ */\r
+\r
+ JobNum = 0;\r
+ pNewJCB = 0;\r
+ pPD = 0;\r
+ pPT = 0;\r
+ pVid = 0;\r
+\r
+ erc = AllocJCB(&JobNum, &pNewJCB);\r
+\r
+ /* Alloc OS memory pages required for new job */\r
+\r
+ if (!erc)\r
+ erc = AllocOSPage(3, &pPD); /* Job's PD, PT * pVirtVid */\r
+\r
+ pPT = pPD + 4096; /* 1 page later */\r
+ pVid = pPD + 8192; /* 2 pages later */\r
+\r
+ if (!erc) {\r
+ FillData(pPT, 4096, 0); /* Zero user PT */\r
+ FillData(pVid, 4096, 0); /* Zero user video */\r
+\r
+ GetpJCB(1, &pTmpJCB); /* Get OS pJCB */\r
+ pOSPD = pTmpJCB->pJcbPD; /* Pointer to OS PD */\r
+\r
+ GetPhyAdd(1, pPT, &PhyAdd); /* Get Phy Add for new PT */\r
+\r
+ PhyAdd |= MEMUSERD; /* Set user code bits in PDE */\r
+\r
+ pOSPD[256] = PhyAdd; /* Make User PDE in OS PD */\r
+ pOSPD[768] = pPT; /* Shadow Linear Address of PT */\r
+\r
+ /* for serious troubleshooting...\r
+ xprintf("pOSPD : %08x\r\n", pOSPD);\r
+ xprintf("pUserPD: %08x\r\n", pPD);\r
+ xprintf("pUserPT: %08x\r\n", pPT);\r
+ xprintf("PhyAdd : %08x\r\n", PhyAdd);\r
+ ReadKbd(&KeyCodeE, 1);\r
+ */\r
+\r
+ /* Now we can allocate User Job Memory */\r
+ /* Allocate user memory for Stack Code and Data */\r
+ /* This is STILL done in the OS PD */\r
+\r
+ nPages = sStack/4096;\r
+ if (sStack%4096) nPages++;\r
+ erc = AllocPage(nPages, &pStack);\r
+ sStack = nPages * 4096; /* set to whole pages */\r
+\r
+ nPages = sCode/4096;\r
+ if (sCode%4096) nPages++;\r
+ if (!erc)\r
+ erc = AllocPage(nPages, &pCode);\r
+\r
+ nPages = sData/4096;\r
+ if (sData%4096) nPages++;\r
+ if (!erc)\r
+ erc = AllocPage(nPages, &pData);\r
+\r
+ /* Right now, the OS PD looks exacly like we want\r
+ the User PD to look. We will now copy the entire\r
+ OS PD into the User's New PD.\r
+ */\r
+\r
+ CopyData(pOSPD, pPD, 4096); /* Copy OS PD to User PD */\r
+\r
+ /* All Job memory is now allocated, so let's LOAD IT! */\r
+\r
+ if (!erc)\r
+ erc = SetFileLFA(fh, oCode);\r
+ if (!erc)\r
+ erc = ReadBytes (fh, pCode, sCode, &dret);\r
+\r
+ if (!erc)\r
+ erc = SetFileLFA(fh, oData);\r
+ if (!erc)\r
+ erc = ReadBytes (fh, pData, sData, &dret);\r
+\r
+ /* Now that we have read in the code and data we\r
+ apply fixups to these segments from the runfile\r
+ */\r
+\r
+ if (!erc) {\r
+\r
+ if (nCDFIX) {\r
+ erc = SetFileLFA(fh, oCDFIX); /* back to fixups */\r
+ while ((nCDFIX--) && (!erc)) {\r
+ erc = ReadBytes (fh, &i, 4, &dret);\r
+ pFix = pCode + i; /* Where in CSeg */\r
+ *pFix = *pFix - offData + pData;\r
+ }\r
+ }\r
+\r
+ if (nCCFIX) {\r
+ erc = SetFileLFA(fh, oCCFIX); /* back to fixups */\r
+ while ((nCCFIX--) && (!erc)) {\r
+ erc = ReadBytes (fh, &i, 4, &dret);\r
+ pFix = pCode + i; /* Where in CSeg */\r
+ *pFix = *pFix - offCode + pCode;\r
+ }\r
+ }\r
+\r
+ if (nDCFIX) {\r
+ erc = SetFileLFA(fh, oDCFIX); /* back to fixups */\r
+ while ((nDCFIX--) && (!erc)) {\r
+ erc = ReadBytes (fh, &i, 4, &dret);\r
+ pFix = pData + i; /* Where in DSeg */\r
+ *pFix = *pFix - offCode + pCode;\r
+ }\r
+ }\r
+\r
+ if (nDDFIX) {\r
+ erc = SetFileLFA(fh, oDDFIX); /* back to fixups */\r
+ while ((nDDFIX--) && (!erc)) {\r
+ erc = ReadBytes (fh, &i, 4, &dret);\r
+ pFix = pData + i; /* Where in DSeg */\r
+ *pFix = *pFix - offData + pData;\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ /* Clean the OS PD of User memory */\r
+\r
+ FillData(&pOSPD[256], 1024, 0); /* Clean OS PD of User PDEs */\r
+ FillData(&pOSPD[768], 1024, 0); /* Clean OS PD of User Shadow */\r
+\r
+ /* Now we fill in the rest of the User's JCB */\r
+\r
+ pNewJCB->pJcbPD = pPD; /* Lin Add of PD */\r
+ pNewJCB->pJcbStack = pStack; /* Add of Stack */\r
+ pNewJCB->sJcbStack = sStack; /* Size of Code */\r
+ pNewJCB->pJcbCode = pCode; /* Add of Code */\r
+ pNewJCB->sJcbCode = sCode; /* Size of Code */\r
+ pNewJCB->pJcbData = pData; /* Add of Code */\r
+ pNewJCB->sJcbData = sData; /* Size of Code */\r
+\r
+ pNewJCB->sbUserName[0] = 0; /* Zero UserName */\r
+ pNewJCB->sbPath[0] = 0; /* No Default path */\r
+ pNewJCB->JcbExitRF[0] = 0; /* No Exit Run File */\r
+ pNewJCB->JcbCmdLine[0] = 0; /* No Cmd Line */\r
+\r
+ CopyData("KBD", &pNewJCB->JcbSysIn[1], 3);\r
+ pNewJCB->JcbSysIn[0] = 3; /* Size */\r
+\r
+ CopyData("VID", &pNewJCB->JcbSysOut[1], 3);\r
+ pNewJCB->JcbSysOut[0] = 3; /* Size */\r
+\r
+ pNewJCB->pVidMem = pVid; /* Default to Virt Vid */\r
+ pNewJCB->pVirtVid = pVid; /* Virtual Video memory */\r
+ pNewJCB->CrntX = 0; /* Vid X Position */\r
+ pNewJCB->CrntY = 0; /* Vid Y Position */\r
+ pNewJCB->nCols = 80; /* Columns */\r
+ pNewJCB->nLines = 25; /* Lines */\r
+\r
+ pNewJCB->VidMode = 0; /* 80x25 VGA Color Text */\r
+ pNewJCB->fCursOn = 1; /* Cursor On */\r
+ pNewJCB->fCursType = 0; /* UnderLine */\r
+\r
+\r
+ /* Finally, we crank up the new task and schedule it for\r
+ execution!\r
+ */\r
+ if (!erc)\r
+ erc = AllocExch(&i);\r
+\r
+ if (!erc)\r
+ erc = NewTask(JobNum, 0x18, 25, 0, i,\r
+ pStack+sStack-4,\r
+ pStart+pCode-offCode);\r
+ if (!erc)\r
+ SetExchOwner(i, pNewJCB); /* Exch now belongs to new JCB */\r
+ }\r
+\r
+ CloseFile(fh);\r
+ } /* read run file OK */\r
+\r
+ if (!erc)\r
+ *pJobNumRet = JobNum;\r
+\r
+ return(erc);\r
+}\r
+\r
+/*********************************************************\r
+ This loads a job into an existing PD and JCB. This is\r
+ called by Chain() and may also be called by ExitJob()\r
+ if an ExitJob was specified in the current JCB.\r
+ The PD, pVid & first PT still exist in OS memory.\r
+ (CleanPD left the first PT for us). ExitJob and Chain\r
+ are responsible for opening and validating the runfile\r
+ and setting up the run file variables.\r
+*********************************************************/\r
+\r
+static long LoadJob(char *pJCB, long fh)\r
+{\r
+long erc, i, dret, nPages;\r
+long *pFix;\r
+\r
+ pNewJCB = pJCB;\r
+\r
+ /* Allocate user memory for Stack, Code and Data */\r
+ /* This is done in the context of the USER PD */\r
+\r
+ nPages = sStack/4096;\r
+ if (sStack%4096) nPages++;\r
+ erc = AllocPage(nPages, &pStack);\r
+ sStack = nPages * 4096; /* set to whole pages */\r
+\r
+ nPages = sCode/4096;\r
+ if (sCode%4096) nPages++;\r
+ if (!erc)\r
+ erc = AllocPage(nPages, &pCode);\r
+\r
+ nPages = sData/4096;\r
+ if (sData%4096) nPages++;\r
+\r
+ erc = AllocPage(nPages, &pData);\r
+\r
+ /* All Job memory is now allocated, so let's LOAD IT! */\r
+\r
+ if (!erc)\r
+ erc = SetFileLFA(fh, oCode);\r
+ if (!erc)\r
+ erc = ReadBytes (fh, pCode, sCode, &dret);\r
+\r
+ if (!erc)\r
+ erc = SetFileLFA(fh, oData);\r
+ if (!erc)\r
+ erc = ReadBytes (fh, pData, sData, &dret);\r
+\r
+ /* Now that we have read in the code and data we\r
+ apply fixups to these segments from the runfile\r
+ */\r
+\r
+ if (!erc) {\r
+ if (nCDFIX) {\r
+ erc = SetFileLFA(fh, oCDFIX); /* back to fixups */\r
+ while ((nCDFIX--) && (!erc)) {\r
+ erc = ReadBytes (fh, &i, 4, &dret);\r
+ pFix = pCode + i; /* Where in CSeg */\r
+ *pFix = *pFix - offData + pData;\r
+ }\r
+ }\r
+\r
+ if (nCCFIX) {\r
+ erc = SetFileLFA(fh, oCCFIX); /* back to fixups */\r
+ while ((nCCFIX--) && (!erc)) {\r
+ erc = ReadBytes (fh, &i, 4, &dret);\r
+ pFix = pCode + i; /* Where in CSeg */\r
+ *pFix = *pFix - offCode + pCode;\r
+ }\r
+ }\r
+\r
+ if (nDCFIX) {\r
+ erc = SetFileLFA(fh, oDCFIX); /* back to fixups */\r
+ while ((nDCFIX--) && (!erc)) {\r
+ erc = ReadBytes (fh, &i, 4, &dret);\r
+ pFix = pData + i; /* Where in DSeg */\r
+ *pFix = *pFix - offCode + pCode;\r
+ }\r
+ }\r
+\r
+ if (nDDFIX) {\r
+ erc = SetFileLFA(fh, oDDFIX); /* back to fixups */\r
+ while ((nDDFIX--) && (!erc)) {\r
+ erc = ReadBytes (fh, &i, 4, &dret);\r
+ pFix = pData + i; /* Where in DSeg */\r
+ *pFix = *pFix - offData + pData;\r
+ }\r
+ }\r
+\r
+ /* Now we fill in the rest of the User's JCB */\r
+ pNewJCB->pJcbStack = pStack; /* Add of Stack */\r
+ pNewJCB->sJcbStack = sStack; /* Size of Code */\r
+ pNewJCB->pJcbCode = pCode; /* Add of Code */\r
+ pNewJCB->sJcbCode = sCode; /* Size of Code */\r
+ pNewJCB->pJcbData = pData; /* Add of Code */\r
+ pNewJCB->sJcbData = sData; /* Size of Code */\r
+\r
+ }\r
+ CloseFile(fh);\r
+ return(erc);\r
+}\r
+\r
+\r
+/******************************************************\r
+ This is started as new task in the context of a\r
+ job that is being killed off. This is done to allow\r
+ memory access and also reuse the code for ExitJob\r
+ in the monitor. This task, it's exchange, and TSS\r
+ will be reclaimed by the monitor along with the\r
+ JCB and all OS memory pages for the PD,PT and video.\r
+******************************************************/\r
+\r
+void _KillTask(void)\r
+{\r
+\r
+ GetJobNum(&JobNumE);\r
+ GetpJCB(JobNumE, &pTmpJCB); /* Get pJCB to this Job */\r
+\r
+ /* Clean the PD of all user memory leaving OS memory to be\r
+ deallocated by the caller (monitor or whoever).\r
+ */\r
+\r
+ pPDE = pTmpJCB->pJcbPD;\r
+ CleanUserPD(pPDE);\r
+\r
+ GetTSSExch(&ExchE);\r
+\r
+ ercE = 0;\r
+ while(!ercE) /* clear the exchange */\r
+ ercE = CheckMsg(ExchE, BogusMsg);\r
+\r
+ ISendMsg(KillExch, ExchE, ErcOpCancel);\r
+ SetPriority(31);\r
+ WaitMsg(ExchE, BogusMsg);\r
+\r
+ while(1); /* in case we get scheduled again RAB */\r
+\r
+ /* He's History! */\r
+}\r
+\r
+\r
+/******************************************************\r
+ This called from one job to kill another job or\r
+ service. This cleans up ALL resources that the\r
+ job had allocated.\r
+ This is used to kill run-away jobs, or terminate a\r
+ job just for the fun ot it.\r
+ It results in a violent death for the job specified.\r
+ This must never be called from a task within the job\r
+ to be killed. A job may terminate itself with ExitJob().\r
+******************************************************/\r
+\r
+long far _KillJob(long JobNum)\r
+{\r
+long erc;\r
+ /* Make sure it's not the Monitor, Debugger or the current job. */\r
+\r
+ GetJobNum(&JobNumE);\r
+ if ((JobNum == JobNumE) ||\r
+ (JobNum == 1) ||\r
+ (JobNum == 2))\r
+\r
+ return(ErcBadJobNum);\r
+\r
+ erc = GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to the Job */\r
+ if (erc)\r
+ return(erc);\r
+\r
+ pTmpJCB->ExitError = ErcOpCancel; /* Operator said DIE! */\r
+\r
+ /* Remove ALL tasks for this job that are at the ReadyQue.\r
+ The task we are in does not belong to the job we are\r
+ killing so we can remove them all.\r
+ */\r
+\r
+ RemoveRdyJob(pTmpJCB); /* It always returns ErcOk */\r
+\r
+ /* Deallocate ALL exchanges for this job */\r
+\r
+ ercE = 0;\r
+ iE = 0;\r
+ while (ercE != ErcOutOfRange)\r
+ {\r
+ ercE = GetExchOwner(iE, &pExchJCBE);\r
+ if ((!ercE) && (pExchJCBE == pTmpJCB))\r
+ DeAllocExch(iE);\r
+ iE++;\r
+ }\r
+ ercE = 0; /* Clear the error */\r
+\r
+ /* Now that the user can't make anymore requests,\r
+ We send "Abort" messages to all services.\r
+ This closes all files that were opened by the Job\r
+ and frees up any other resources held for this\r
+ job by any service.\r
+\r
+ We will allocate one exchange for the job\r
+ that is being killed so we can use it for SendAbort\r
+ and also as the exchange number we send to the\r
+ KillExch in the monitor which will kill of the JCB\r
+ completely (he also switches video and keyboard\r
+ if needed).\r
+ */\r
+\r
+ erc = AllocExch(&ExchE); /* Get an Exch */\r
+ SetExchOwner(ExchE, pTmpJCB); /* make him the owner */\r
+ SendAbort(JobNum, ExchE); /* Notify all services */\r
+\r
+ /*JobNum, CodeSeg, Priority, fDebug, Exch, ESP, EIP */\r
+ erc = NewTask(JobNum, 0x08, 3, 0, ExchE, &TmpStack[127], &_KillTask);\r
+ return(erc);\r
+\r
+ /* He's History! */\r
+}\r
+\r
+/******************************************************\r
+ This called from Exit() in C or directly from a user\r
+ job or service. This cleans up ALL resources that the\r
+ job had allocated.\r
+ This also checks for an exit run file to load if\r
+ one is specified. If no exit run file is specified\r
+ we just kill the JCB entirely and if video and\r
+ keyboard are assigned we assign them to the Monitor.\r
+******************************************************/\r
+\r
+void far _ExitJob(long dError)\r
+{\r
+/* NO LOCAL VARIABLES BECAUSE WE SWITCH STACKS!! */\r
+\r
+ GetJobNum(&JobNumE);\r
+ GetpJCB(JobNumE, &pCrntJCB); /* Get pJCB to current Job */\r
+ pCrntJCB->ExitError = dError;\r
+\r
+ /* Remove ALL tasks for this job that are at the ReadyQue.\r
+ The task we are in won't be removed because its RUNNING!\r
+ */\r
+\r
+ RemoveRdyJob(pCrntJCB); /* It always returns ErcOk */\r
+\r
+ /* Deallocate all exchanges for this job except the one belonging\r
+ to current TSS! The Dealloc Exchange call will invalidate\r
+ all TSSs found at exchanges belonging to this user, and\r
+ will also free up RQBs and Link Blocks. The job will not be\r
+ able to initiate requests or send messages after this unless\r
+ it is done with the TSSExchange because it will get a kernel\r
+ error (invalid exchange).\r
+ */\r
+\r
+ /* Find out what our TSS exchange is so\r
+ we don't deallocate it to! We need it. */\r
+\r
+ GetTSSExch(&ExchE);\r
+\r
+ ercE = 0;\r
+ iE = 0;\r
+ while (ercE != ErcOutOfRange)\r
+ {\r
+ ercE = GetExchOwner(iE, &pExchJCBE);\r
+ if ((!ercE) && (iE != ExchE) && (pExchJCBE == pCrntJCB))\r
+ DeAllocExch(iE);\r
+ iE++;\r
+ }\r
+\r
+ /* Now that the user can't make anymore requests,\r
+ Send Abort messages to all services.\r
+ This closes all files that were opened by the Job\r
+ and frees up any other resources held for this\r
+ job by any service.\r
+ */\r
+\r
+ SendAbort(JobNumE, ExchE);\r
+\r
+ ercE = 0; /* Clear the error */\r
+ while(!ercE) /* clear the exchange */\r
+ ercE = CheckMsg(ExchE, BogusMsg);\r
+ ercE = 0; /* Clear the error */\r
+\r
+ /* We must now switch to a temporary stack so we can\r
+ clean out the user PD (we are on his stack right now!).\r
+ */\r
+\r
+#asm\r
+ MOV EAX, OFFSET _TmpStack\r
+ ADD EAX, 508\r
+ MOV ESP, EAX\r
+ MOV EBP, EAX\r
+#endasm\r
+\r
+ /* Clean the PD of all user memory leaving OS memory for next\r
+ job if there is one.\r
+ */\r
+\r
+ pPDE = pCrntJCB->pJcbPD;\r
+ CleanUserPD(pPDE);\r
+\r
+ /* Look for Exit Run file to load if any exists. If no exit run\r
+ file, we deallocate the PD and JCB then return to JOB 1. */\r
+\r
+ GetExitJob(aFileE, &cbFileE); /* Exit Run File!! */\r
+\r
+ if (!cbFileE)\r
+ ercE = ErcNoExitJob;\r
+\r
+ if (!ercE)\r
+ ercE = GetRunFile(aFileE, cbFileE, &job_fhE);\r
+\r
+ if (!ercE)\r
+ ercE = LoadJob(pCrntJCB, job_fhE);\r
+\r
+ if (!ercE) {\r
+\r
+ pStart = pStart+pCode-offCode;\r
+\r
+ /* Now we RETURN to new job's address after we put him\r
+ on his new stack. */\r
+\r
+#asm\r
+ MOV EAX, _pStack\r
+ MOV EBX, _sStack\r
+ ADD EAX, EBX\r
+ SUB EAX, 4\r
+ MOV ESP, EAX\r
+ MOV EBP, EAX\r
+ PUSH 18h\r
+ MOV EAX, _pStart\r
+ PUSH EAX\r
+ RETF ;We are history!\r
+#endasm\r
+\r
+ }\r
+\r
+ if (ercE) { /* something failed or we don't have an ExitRF */\r
+\r
+ /* In case there is no job to run or a fatal error has happened\r
+ we send a message (ISendMsg) to the monitor status\r
+ task with our TSSExch and the Error. Then he will WIPE US OUT!\r
+ We use ISend (vice send) so he can't run before we get to\r
+ the exchange otherwise we will be placed back on the readyQueue!\r
+ */\r
+\r
+ ISendMsg(KillExch, ExchE, ercE);\r
+ SetPriority(31);\r
+ WaitMsg(ExchE, BogusMsg);\r
+\r
+ while(1); /* in case we get scheduled again RAB */\r
+\r
+ /* We are NO MORE */\r
+ }\r
+}\r
+\r
+/******************************************************\r
+ This is called to execute a program without changing\r
+ the ExitJob. This is so you can run program B from\r
+ program A and return to program A when program B is\r
+ done. This runs Job B in the "context" of Job A\r
+ which means Job B inherits the JCB and PD of job A\r
+ so it can use things like the command line and\r
+ path that were set up by A.\r
+ Information can be passed to Job B by calling\r
+ SetCmdLine (if Job B reads it), and also by\r
+ setting the ExitError value in the parameter.\r
+ Chain will only return to you if there was an\r
+ error loading the Job. In other words, if Chain\r
+ fails in a critial section we try to load the\r
+ ExitJob and pass it the error.\r
+******************************************************/\r
+\r
+long far _Chain(char *pFileName, long cbFileName, long dExitError)\r
+{\r
+/* NO LOCAL VARIABLES BECAUSE WE SWITCH STACKS!! */\r
+\r
+ CopyData(pFileName, aFileE, cbFileName);\r
+ cbFileE = cbFileName;\r
+\r
+ ercE = GetRunFile(pFileName, cbFileName, &job_fhE);\r
+ if (ercE)\r
+ {\r
+ CloseFile(job_fhE); /* if it had a handle at all */\r
+ return(ercE);\r
+ }\r
+\r
+ CloseFile(job_fhE); /* we will open it again after SendAbort */\r
+\r
+ GetJobNum(&JobNumE);\r
+ GetpJCB(JobNumE, &pCrntJCB); /* Get pJCB to current Job */\r
+ pCrntJCB->ExitError = dExitError;\r
+\r
+ /* Remove ALL tasks for this job that are at the ReadyQue.\r
+ The task we are in won't be removed because its RUNNING!\r
+ */\r
+\r
+ RemoveRdyJob(pCrntJCB); /* It always returns ErcOk */\r
+\r
+ /* Deallocate all exchanges for this job except the one belonging\r
+ to current TSS! The Dealloc Exchange call will invalidate\r
+ all TSSs found at exchanges belonging to this user, and\r
+ will also free up RQBs and Link Blocks. The job will not be\r
+ able to initiate requests or send messages after this unless\r
+ it is done with the TSSExchange because it will get a kernel\r
+ error (invalid exchange).\r
+ */\r
+\r
+ /* Find out what our TSS exchange is so\r
+ we don't deallocate it to! */\r
+\r
+ GetTSSExch(&ExchE);\r
+\r
+ ercE = 0;\r
+ iE = 0;\r
+ while (ercE != ErcOutOfRange) \r
+ {\r
+ ercE = GetExchOwner(iE, &pExchJCBE);\r
+ if ((!ercE) && (iE != ExchE) && (pExchJCBE == pCrntJCB))\r
+ DeAllocExch(iE);\r
+ iE++;\r
+ }\r
+\r
+ /* Now that the user can't make anymore requests,\r
+ Send Abort messages to all services.\r
+ This closes all files that were opened by the Job\r
+ and frees up any other resources held for this\r
+ job by any services.\r
+ */\r
+\r
+ SendAbort(JobNumE, ExchE);\r
+\r
+ ercE = 0; /* Clear the error */\r
+ while(!ercE) /* clear the exchange of abort responses*/\r
+ ercE = CheckMsg(ExchE, BogusMsg);\r
+ ercE = 0; /* Clear the error */\r
+\r
+ /* We must now switch to a temporary stack so we can\r
+ clean out the user PD (we are on his stack right now!).\r
+ */\r
+\r
+#asm\r
+ MOV EAX, OFFSET _TmpStack\r
+ ADD EAX, 508\r
+ MOV ESP, EAX\r
+ MOV EBP, EAX\r
+#endasm\r
+\r
+ /* Clean the PD of all user memory leaving OS memory for next\r
+ job if there is one.\r
+ */\r
+\r
+ pPDE = pCrntJCB->pJcbPD;\r
+ CleanUserPD(pPDE);\r
+\r
+ /* Try to load the Chain file. Don't bother checking error\r
+ cause it was valid if we got here!\r
+ */\r
+\r
+ GetRunFile(aFileE, cbFileE, &job_fhE); /* it was valid before!*/\r
+ ercE = LoadJob(pCrntJCB, job_fhE);\r
+\r
+ if (ercE) \r
+ {\r
+ /* We have errored in a critical part of Chain (LoadJob).\r
+ The original user's job is destroyed, and we can't run the\r
+ chain file (bummer).\r
+ The only thing left to do is Look for Exit Run file to load\r
+ if any exists. If no exit run file, we kill this guy\r
+ and return to the monitor if he had the screen. */\r
+\r
+ GetExitJob(aFileE, &cbFileE); /* Exit Run File!! */\r
+\r
+ if (!cbFileE)\r
+ ercE = ErcNoExitJob;\r
+\r
+ if (!ercE)\r
+ ercE = GetRunFile(aFileE, cbFileE, &job_fhE);\r
+\r
+ if (!ercE)\r
+ ercE = LoadJob(pCrntJCB, job_fhE);\r
+ }\r
+\r
+ if (!ercE) \r
+ { /* No error */\r
+\r
+ pStart = pStart+pCode-offCode;\r
+\r
+ /* Now we RETURN to new job's address after we put him\r
+ on his new stack. */\r
+\r
+#asm\r
+ MOV EAX, _pStack\r
+ MOV EBX, _sStack\r
+ ADD EAX, EBX\r
+ SUB EAX, 4\r
+ MOV ESP, EAX\r
+ MOV EBP, EAX\r
+ PUSH 18h\r
+ MOV EAX, _pStart\r
+ PUSH EAX\r
+ RETF ;We are history!\r
+#endasm\r
+ }\r
+\r
+ if (ercE) \r
+ { /* Something failed loading the job (Chain or Exit) */\r
+\r
+ /* In case there is no job to run or a fatal error has happened\r
+ we send a message (ISendMsg) to the monitor status\r
+ task with our TSSExch and the Error. Then he will WIPE US OUT!\r
+ We use ISend (vice send) so he can't run before we get to\r
+ the exchange otherwise we will be placed back on the readyQueue!\r
+ */\r
+\r
+ ISendMsg(KillExch, ExchE, ercE); /* ISend clears ints! */\r
+#asm\r
+ STI\r
+#endasm\r
+ SetPriority(31);\r
+ WaitMsg(ExchE, BogusMsg);\r
+\r
+ while(1); /* in case we get scheduled again RAB */\r
+\r
+ /* We are NO MORE */\r
+\r
+ }\r
+}\r
+\r
+/*********************** End of Module *****************/\r