Example #1
0
//----------------------------------------------------------------------
//
//	ProcessFreeResources
//
//	Free the resources associated with a process.  This assumes the
//	process isn't currently on any queue.
//
//----------------------------------------------------------------------
void ProcessFreeResources (PCB *pcb) {
  int i = 0;

  dbprintf ('p', "ProcessFreeResources: function started\n");

  // Allocate a new link for this pcb on the freepcbs queue
  if ((pcb->l = AQueueAllocLink(pcb)) == NULL) {
    printf("FATAL ERROR: could not get Queue Link in ProcessFreeResources!\n");
    GracefulExit();
  }
  // Set the pcb's status to available
  pcb->flags = PROCESS_STATUS_FREE;
  // Insert the link into the freepcbs queue
  if (AQueueInsertLast(&freepcbs, pcb->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert PCB link into freepcbs queue in ProcessFreeResources!\n");
    GracefulExit();
  }

  // Free the process's memory.
  for (i = 0; i < pcb->npages; i++) {
    MemoryFreePte (pcb->pagetable[i]);
  }
  // Free the page allocated for the system stack
  MemoryFreePage (pcb->sysStackArea / MEMORY_PAGE_SIZE);
  ProcessSetStatus (pcb, PROCESS_STATUS_FREE);
  dbprintf ('p', "ProcessFreeResources: function complete\n");
}
Example #2
0
//----------------------------------------------------------------------
//
//	ProcessModuleInit
//
//	Initialize the process module.  This involves initializing all
//	of the process control blocks to appropriate values (ie, free
//	and available).  We also need to initialize all of the queues.
//
//----------------------------------------------------------------------
void ProcessModuleInit () {
  int		i;

  dbprintf ('p', "ProcessModuleInit: function started\n");
  AQueueInit (&freepcbs);
  AQueueInit(&runQueue);
  AQueueInit (&waitQueue);
  AQueueInit (&zombieQueue);
  // For each PCB slot in the global pcbs array:
  for (i = 0; i < PROCESS_MAX_PROCS; i++) {
    dbprintf ('p', "Initializing PCB %d @ 0x%x.\n", i, (int)&(pcbs[i]));
    // First, set the internal PCB link pointer to a newly allocated link
    if ((pcbs[i].l = AQueueAllocLink(&pcbs[i])) == NULL) {
      printf("FATAL ERROR: could not allocate link in ProcessModuleInit!\n");
      GracefulExit();
    }
    // Next, set the pcb to be available
    pcbs[i].flags = PROCESS_STATUS_FREE;
    // Finally, insert the link into the queue
    if (AQueueInsertFirst(&freepcbs, pcbs[i].l) != QUEUE_SUCCESS) {
      printf("FATAL ERROR: could not insert PCB link into queue in ProcessModuleInit!\n");
      GracefulExit();
    }
  }
  // There are no processes running at this point, so currentPCB=NULL
  currentPCB = NULL;
  dbprintf ('p', "ProcessModuleInit: function complete\n");
}
static THREAD_FUNC StatusServer(void *argptr)
{
FILE *fp;
UINT16 port;
int sd, peer;
struct sockaddr_in serv_addr, cli_addr;
int yes = 1, ilen = sizeof(int), clen = sizeof(cli_addr);
static char *fid = "StatusServer";

    LogMsg(LOG_DEBUG, "%s: thread started, id = %d", fid, THREAD_SELF());

/* Create socket and bind */

    port = *((UINT16 *) argptr);

    if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        LogMsg(LOG_ERR, "%s: socket: %s", fid, strerror(errno));
        GracefulExit(MY_MOD_ID + 1);
    }
    memset((void *) &serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(port);
    setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, ilen);

    if (bind( sd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) != 0) {
        LogMsg(LOG_ERR, "%s: bind: %s", fid, strerror(errno));
        GracefulExit(MY_MOD_ID + 2);
    }

/* Start listening for connectinos */

    if (listen(sd, 5) != 0) {
        LogMsg(LOG_ERR, "%s: listen: %s", fid, strerror(errno));
        GracefulExit(MY_MOD_ID + 3);
    }

/* Service one connection at a time */

    LogMsg(LOG_INFO, "listening for status requests at port %hu", port);
    while (1) {
        peer = INVALID_SOCKET;
        while (peer == INVALID_SOCKET) {
            peer = accept(sd, (struct sockaddr *) &cli_addr, &clen);
            if (peer == INVALID_SOCKET && errno != EINTR) {
                LogMsg(LOG_ERR, "%s: accept: %s (ignored)", fid, strerror(errno));
            } else {
                if ((fp = fdopen(peer, "w")) == NULL) {
                    LogMsg(LOG_ERR, "%s: fdopen: %s", fid, strerror(errno));
                } else {
                    PrintStatusReport(fp);
                    fclose(fp);
                }
                shutdown(peer, 2);
                close(peer);
            }
        }
    }
}
VOID InitClientList(PARAM *par)
{
UINT32 i;
static char *fid = "InitClientList";

    ClientList.num = par->maxclient;
    ClientList.client = (CLIENT *) calloc(1,ClientList.num * sizeof(CLIENT));
    if (ClientList.client == NULL) {
        LogMsg(LOG_ERR, "%s: calloc: %s", fid, strerror(errno));
        GracefulExit(MY_MOD_ID + 1);
    }

    for (i = 0; i < ClientList.num; i++) {
        MUTEX_INIT(&ClientList.client[i].mutex);
        ClientList.client[i].index = i;
        ClientList.client[i].iacp     = (IACP *) NULL;
        ClientList.client[i].ident    = (char *) NULL;
        ClientList.client[i].finished  = FALSE;
        ClientList.client[i].result    = IACP_ALERT_NONE;
        ClientList.client[i].master   = par->master;
        isiInitIncoming(&ClientList.client[i].incoming);
        isiInitDataRequest(&ClientList.client[i].datreq);
        ClientList.client[i].send.buflen  = par->buflen.send;
        ClientList.client[i].send.buf = (UINT8 *) malloc(ClientList.client[i].send.buflen);
        if (ClientList.client[i].send.buf == NULL) {
            LogMsg(LOG_ERR, "%s: malloc: %s", fid, strerror(errno));
            GracefulExit(MY_MOD_ID + 2);
        }
        ClientList.client[i].recv.buflen  = par->buflen.recv;
        ClientList.client[i].recv.buf = (UINT8 *) malloc(ClientList.client[i].recv.buflen);
        if (ClientList.client[i].recv.buf == NULL) {
            LogMsg(LOG_ERR, "%s: malloc: %s", fid, strerror(errno));
            GracefulExit(MY_MOD_ID + 3);
        }
        ClientList.client[i].temp.buflen  = par->buflen.send * 2; /* bigger to handle compression failure */
        ClientList.client[i].temp.buf = (UINT8 *) malloc(ClientList.client[i].temp.buflen);
        if (ClientList.client[i].temp.buf == NULL) {
            LogMsg(LOG_ERR, "%s: malloc: %s", fid, strerror(errno));
            GracefulExit(MY_MOD_ID + 4);
        }
        ClientList.client[i].last.msg.len = 0;
        ClientList.client[i].last.msg.data = (UINT8 *) malloc(ClientList.client[i].recv.buflen);
        if (ClientList.client[i].last.msg.data == NULL) {
            LogMsg(LOG_ERR, "%s: malloc: %s", fid, strerror(errno));
            GracefulExit(MY_MOD_ID + 3);
        }
        ClientList.client[i].last.datreq = NULL;
        ClientList.client[i].pkt.indx = -1;
        listInit(&ClientList.client[i].history);
    }
}
Example #5
0
int DiskCreate() {
  char *filename = NULL;
  int fsfd = -1;
  disk_block b;
  int i;

  // Check that you remembered to rename the filename for your group
  filename = DISK_FILENAME;
  if (filename[11] == 'X') {
    printf("DiskCreate: you didn't change the filesystem filename in include/os/disk.h.  Cowardly refusing to do anything.\n");
    GracefulExit();
  }
  // Open the hard disk file
  if ((fsfd = FsOpen(DISK_FILENAME, FS_MODE_WRITE)) < 0) {
    printf ("DiskCreate: File system %s cannot be opened!\n", DISK_FILENAME);
    return DISK_FAIL;
  }

  // Write all zeros to the hard disk file to make sure it is the right size.
  // You need to do this because the writeblock/readblock operations are allowed in
  // random order.
  bzero(b.data, DISK_BLOCKSIZE);
  for(i=0; i<DISK_NUMBLOCKS; i++) {
    FsWrite(fsfd, b.data, DISK_BLOCKSIZE);
  }
  
  // Close the hard disk file
  if (FsClose(fsfd) < 0) {
    printf("DiskCreate: unable to close open file!\n");
    return DISK_FAIL;
  }
  return DISK_SUCCESS;
}
Example #6
0
// file_delete(char *filename)
int TrapFileDeleteHandler(uint32 *trapArgs, int sysMode) {
  char filename[FILE_MAX_FILENAME_LENGTH];
  char *user_filename = NULL;
  int i;

  // If we're not in system mode, we need to copy everything from the
  // user-space virtual address to the kernel space address
  if (!sysMode) {
    // Get the arguments themselves into system space
    // Argument 0: userland pointer to filename string
    MemoryCopyUserToSystem (currentPCB, (trapArgs+0), &user_filename, sizeof(uint32));

    // Now copy userland filename string into our filename buffer
    for(i=0; i<FILE_MAX_FILENAME_LENGTH; i++) {
      MemoryCopyUserToSystem(currentPCB, (user_filename+i), &(filename[i]), sizeof(char));
      // Check for end of user-space string
      if (filename[i] == '\0') break;
    }
    if (i == FILE_MAX_FILENAME_LENGTH) {
      printf("TrapFileDeleteHandler: length of filename longer than allowed!\n");
      GracefulExit();
    }
    dbprintf('F', "TrapDeleteCloseHandler: just parsed filename (%s) from trapArgs\n", filename);
 
  } else {
    // Already in kernel space, no address translation necessary
    dstrncpy(filename, (char *)(trapArgs[0]), FILE_MAX_FILENAME_LENGTH);
  }
  return FileDelete(filename);
}
Example #7
0
//----------------------------------------------------------------------
//
//	ProcessSchedule
//
//	Schedule the next process to run.  If there are no processes to
//	run, exit.  This means that there should be an idle loop process
//	if you want to allow the system to "run" when there's no real
//	work to be done.
//
//	NOTE: the scheduler should only be called from a trap or interrupt
//	handler.  This way, interrupts are disabled.  Also, it must be
//	called consistently, and because it might be called from an interrupt
//	handler (the timer interrupt), it must ALWAYS be called from a trap
//	or interrupt handler.
//
//	Note that this procedure doesn't actually START the next process.
//	It only changes the currentPCB and other variables so the next
//	return from interrupt will restore a different context from that
//	which was saved.
//
//----------------------------------------------------------------------
void ProcessSchedule () {
  PCB *pcb=NULL;
  int i=0;
  Link *l=NULL;

  dbprintf ('p', "Now entering ProcessSchedule (cur=0x%x, %d ready)\n",
	    (int)currentPCB, AQueueLength (&runQueue));
  // The OS exits if there's no runnable process.  This is a feature, not a
  // bug.  An easy solution to allowing no runnable "user" processes is to
  // have an "idle" process that's simply an infinite loop.
  if (AQueueEmpty(&runQueue)) {
    if (!AQueueEmpty(&waitQueue)) {
      printf("FATAL ERROR: no runnable processes, but there are sleeping processes waiting!\n");
      l = AQueueFirst(&waitQueue);
      while (l != NULL) {
        pcb = AQueueObject(l);
        printf("Sleeping process %d: ", i++); printf("PID = %d\n", (int)(pcb - pcbs));
        l = AQueueNext(l);
      }
      GracefulExit();
    }
    printf ("No runnable processes - exiting!\n");
    GracefulExit ();	// NEVER RETURNS
  }

  // Move the front of the queue to the end.  The running process was the one in front.
  AQueueMoveAfter(&runQueue, AQueueLast(&runQueue), AQueueFirst(&runQueue));

  // Now, run the one at the head of the queue.
  pcb = (PCB *)AQueueObject(AQueueFirst(&runQueue));
  currentPCB = pcb;
  dbprintf ('p',"About to switch to PCB 0x%x,flags=0x%x @ 0x%x\n",
	    (int)pcb, pcb->flags, (int)(pcb->sysStackPtr[PROCESS_STACK_IAR]));

  // Clean up zombie processes here.  This is done at interrupt time
  // because it can't be done while the process might still be running
  while (!AQueueEmpty(&zombieQueue)) {
    pcb = (PCB *)AQueueObject(AQueueFirst(&zombieQueue));
    dbprintf ('p', "Freeing zombie PCB 0x%x.\n", (int)pcb);
    if (AQueueRemove(&(pcb->l)) != QUEUE_SUCCESS) {
      printf("FATAL ERROR: could not remove zombie process from zombieQueue in ProcessSchedule!\n");
      GracefulExit();
    }
    ProcessFreeResources(pcb);
  }
  dbprintf ('p', "Leaving ProcessSchedule (cur=0x%x)\n", (int)currentPCB);
}
Example #8
0
//----------------------------------------------------------------------
//
//	ProcessDestroy
//
//	Destroy a process by setting its status to zombie and putting it
//	on the zombie queue.  The next time the scheduler is called, this
//	process will be marked as free.  We can't necessarily do it now
//	because we might be the currently running process.
//
//	NOTE: This must only be called from an interrupt or trap.  However,
//	it need not be followed immediately by a ProcessSchedule() because
//	the process can continue running.
//
//----------------------------------------------------------------------
void ProcessDestroy (PCB *pcb) {
  dbprintf ('p', "ProcessDestroy (%d): function started\n", GetCurrentPid());
  ProcessSetStatus (pcb, PROCESS_STATUS_ZOMBIE);
  if (AQueueRemove(&(pcb->l)) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not remove link from queue in ProcessDestroy!\n");
    GracefulExit();
  }
  if ((pcb->l = AQueueAllocLink(pcb)) == NULL) {
    printf("FATAL ERROR: could not get link for zombie PCB in ProcessDestroy!\n");
    GracefulExit();
  }
  if (AQueueInsertFirst(&zombieQueue, pcb->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert link into runQueue in ProcessWakeup!\n");
    GracefulExit();
  }
  dbprintf ('p', "ProcessDestroy (%d): function complete\n", GetCurrentPid());
}
Example #9
0
//----------------------------------------------------------------------
//
//	ProcessWakeup
//
//	Wake up a process from its slumber.  This only involves putting
//	it on the run queue; it's not guaranteed to be the next one to
//	run.
//
//	NOTE: This must only be called from an interrupt or trap.  It
//	need not be followed immediately by ProcessSchedule() because
//	the currently running process is unaffected.
//
//----------------------------------------------------------------------
void ProcessWakeup (PCB *wakeup) {
  dbprintf ('p',"Waking up PID %d.\n", (int)(wakeup - pcbs));
  // Make sure it's not yet a runnable process.
  ASSERT (wakeup->flags & PROCESS_STATUS_WAITING, "Trying to wake up a non-sleeping process!\n");
  ProcessSetStatus (wakeup, PROCESS_STATUS_RUNNABLE);
  if (AQueueRemove(&(wakeup->l)) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not remove wakeup PCB from waitQueue in ProcessWakeup!\n");
    GracefulExit();
  }
  if ((wakeup->l = AQueueAllocLink(wakeup)) == NULL) {
    printf("FATAL ERROR: could not get link for wakeup PCB in ProcessWakeup!\n");
    GracefulExit();
  }
  if (AQueueInsertLast(&runQueue, wakeup->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert link into runQueue in ProcessWakeup!\n");
    GracefulExit();
  }
}
Example #10
0
//----------------------------------------------------------------------
//
//	ProcessSuspend
//
//	Place a process in suspended animation until it's
//	awakened by ProcessAwaken.
//
//	NOTE: This must only be called from an interrupt or trap.  It
//	should be immediately followed by ProcessSchedule().
//
//----------------------------------------------------------------------
void ProcessSuspend (PCB *suspend) {
  // Make sure it's already a runnable process.
  dbprintf ('p', "ProcessSuspend (%d): function started\n", GetCurrentPid());
  ASSERT (suspend->flags & PROCESS_STATUS_RUNNABLE, "Trying to suspend a non-running process!\n");
  ProcessSetStatus (suspend, PROCESS_STATUS_WAITING);

  if (AQueueRemove(&(suspend->l)) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not remove process from run Queue in ProcessSuspend!\n");
    GracefulExit();
  }
  if ((suspend->l = AQueueAllocLink(suspend)) == NULL) {
    printf("FATAL ERROR: could not get Queue Link in ProcessSuspend!\n");
    GracefulExit();
  }
  if (AQueueInsertLast(&waitQueue, suspend->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert suspend PCB into waitQueue!\n");
    GracefulExit();
  }
  dbprintf ('p', "ProcessSuspend (%d): function complete\n", GetCurrentPid());
}
Example #11
0
VOID StartStatusServer(PARAM *par)
{
THREAD tid;
static UINT16 StaticPort;
static char *fid = "StartStatusServer";

    StaticPort = par->status;

    if (!THREAD_CREATE(&tid, StatusServer, (void *) &StaticPort)) {
        LogMsg(LOG_ERR, "%s: THREAD_CREATE: %s", fid, strerror(errno));
        GracefulExit(MY_MOD_ID + 0);
    }
    THREAD_DETACH(tid);
}
Example #12
0
int DiskWriteBlock (uint32 blocknum, disk_block *b) {
  int fsfd = -1;
  uint32 intrvals = 0;
  char *filename = NULL;

  if (blocknum >= DISK_NUMBLOCKS) {
    printf("DiskWriteBlock: cannot write to block larger than filesystem size\n");
    return DISK_FAIL;
  }

  // Check that you remembered to rename the filename for your group
  filename = DISK_FILENAME;
  if (filename[11] == 'X') {
    printf("DiskWriteBlock: you didn't change the filesystem filename in include/os/disk.h.  Cowardly refusing to do anything.\n");
    GracefulExit();
  }

  intrvals = DisableIntrs();

  // Open the hard disk file
  if ((fsfd = FsOpen(DISK_FILENAME, FS_MODE_RW)) < 0) {
    printf ("DiskWriteBlock: File system %s cannot be opened!\n", DISK_FILENAME);
    return DISK_FAIL;
  }

  /* printf("DiskWriteBlock: fsfd = %d\n", fsfd); */

  // Write data to virtual disk
  FsSeek(fsfd, blocknum * DISK_BLOCKSIZE, FS_SEEK_SET);
  if (FsWrite(fsfd, b->data, DISK_BLOCKSIZE) != DISK_BLOCKSIZE) {
    printf ("DiskWriteBlock: Block %d could not be written!\n", blocknum);
    FsClose (fsfd);
    return DISK_FAIL;
  }

  // Close the hard disk file
  FsClose (fsfd);

  RestoreIntrs(intrvals);
  return DISK_BLOCKSIZE;
}
Example #13
0
//----------------------------------------------------------------------
//
//	main
//
//	This routine is called when the OS starts up.  It allocates a
//	PCB for the first process - the one corresponding to the initial
//	thread of execution.  Note that the stack pointer is already
//	set correctly by _osinit (assembly language code) to point
//	to the stack for the 0th process.  This stack isn't very big,
//	though, so it should be replaced by the system stack of the
//	currently running process.
//
//----------------------------------------------------------------------
void main (int argc, char *argv[])
{
  int i,j;
  int n;
  char buf[120];
  char *userprog = (char *)0;
  int base=0;
  int numargs=0;
  int allargs_offset = 0;
  char allargs[SIZE_ARG_BUFF];
  
  debugstr[0] = '\0';

  printf ("Got %d arguments.\n", argc);
  printf ("Available memory: 0x%x -> 0x%x.\n", (int)lastosaddress, MemoryGetSize ());
  printf ("Argument count is %d.\n", argc);
  for (i = 0; i < argc; i++) {
    printf ("Argument %d is %s.\n", i, argv[i]);
  }

  FsModuleInit ();
  for (i = 0; i < argc; i++) 
  {
    if (argv[i][0] == '-') 
    {
      switch (argv[i][1]) 
      {
      case 'D':
	dstrcpy (debugstr, argv[++i]);
	break;
      case 'i':
	n = dstrtol (argv[++i], (void *)0, 0);
	ditoa (n, buf);
	printf ("Converted %s to %d=%s\n", argv[i], n, buf);
	break;
      case 'f':
      {
	int	start, codeS, codeL, dataS, dataL, fd, j;
	int	addr = 0;
	static unsigned char buf[200];
	fd = ProcessGetCodeInfo (argv[++i], &start, &codeS, &codeL, &dataS,
				 &dataL);
	printf ("File %s -> start=0x%08x\n", argv[i], start);
	printf ("File %s -> code @ 0x%08x (size=0x%08x)\n", argv[i], codeS,
		codeL);
	printf ("File %s -> data @ 0x%08x (size=0x%08x)\n", argv[i], dataS,
		dataL);
	while ((n = ProcessGetFromFile (fd, buf, &addr, sizeof (buf))) > 0) 
	{
	  for (j = 0; j < n; j += 4) 
	  {
	    printf ("%08x: %02x%02x%02x%02x\n", addr + j - n, buf[j], buf[j+1],
		    buf[j+2], buf[j+3]);
	  }
	}
	close (fd);
	break;
      }
      case 'u':
	userprog = argv[++i];
        base = i; // Save the location of the user program's name 
	break;
      default:
	printf ("Option %s not recognized.\n", argv[i]);
	break;
      }
      if(userprog)
        break;
    }
  }
  dbprintf ('i', "About to initialize queues.\n");
  AQueueModuleInit ();
  dbprintf ('i', "After initializing queues.\n");
  MemoryModuleInit ();
  dbprintf ('i', "After initializing memory.\n");
  ProcessModuleInit ();
  dbprintf ('i', "After initializing processes.\n");
  SynchModuleInit ();
  dbprintf ('i', "After initializing synchronization tools.\n");
  KbdModuleInit ();
  dbprintf ('i', "After initializing keyboard.\n");
  ClkModuleInit();
  for (i = 0; i < 100; i++) {
    buf[i] = 'a';
  }
  i = FsOpen ("vm", FS_MODE_WRITE);
  dbprintf ('i', "VM Descriptor is %d\n", i);
  FsSeek (i, 0, FS_SEEK_SET);
  FsWrite (i, buf, 80);
  FsClose (i);

  DfsModuleInit();
  dbprintf ('i', "After initializing dfs filesystem.\n");

  FileModuleInit();
  dbprintf ('i', "After initializing file module.\n");

  // Setup command line arguments
  if (userprog != (char *)0) {
    numargs=0;
    allargs_offset = 0;
    // Move through each of the argv addresses
    for(i=0; i<argc-base; i++) {
      // At each argv address, copy the string into allargs, including the '\0'
      for(j=0; allargs_offset < SIZE_ARG_BUFF; j++) {
        allargs[allargs_offset++] = argv[i+base][j];
        if (argv[i+base][j] == '\0') break; // end of this string
      }
      numargs++;
    }
    allargs[SIZE_ARG_BUFF-1] = '\0'; // set last char to NULL for safety
    ProcessFork(0, (uint32)allargs, userprog, 1);
  } else {
    dbprintf('i', "No user program passed!\n");
  }

  // Start the clock which will in turn trigger periodic ProcessSchedule's
  ClkStart();

  intrreturn ();
  // Should never be called because the scheduler exits when there
  // are no runnable processes left.
  GracefulExit();	// NEVER RETURNS!
}
Example #14
0
//----------------------------------------------------------------------
//
//	ProcessFork
//
//	Create a new process and make it runnable.  This involves the
//	following steps:
//	* Allocate resources for the process (PCB, memory, etc.)
//	* Initialize the resources
//	* Place the PCB on the runnable queue
//
//	NOTE: This code has been tested for system processes, but not
//	for user processes.
//
//----------------------------------------------------------------------
int ProcessFork (VoidFunc func, uint32 param, char *name, int isUser) {
  int		fd, n;
  int		start, codeS, codeL, dataS, dataL;
  uint32	*stackframe;
  int		newPage;
  PCB		*pcb;
  int	addr = 0;
  int		intrs;
  unsigned char buf[100];
  uint32 dum[MAX_ARGS+8], count, offset;
  char *str;

  dbprintf ('p', "ProcessFork (%d): function started\n", GetCurrentPid());
  intrs = DisableIntrs ();
  dbprintf ('I', "Old interrupt value was 0x%x.\n", intrs);
  dbprintf ('p', "Entering ProcessFork args=0x%x 0x%x %s %d\n", (int)func,
	    param, name, isUser);
  // Get a free PCB for the new process
  if (AQueueEmpty(&freepcbs)) {
    printf ("FATAL error: no free processes!\n");
    GracefulExit ();	// NEVER RETURNS!
  }
  pcb = (PCB *)AQueueObject(AQueueFirst (&freepcbs));
  dbprintf ('p', "Got a link @ 0x%x\n", (int)(pcb->l));
  if (AQueueRemove (&(pcb->l)) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not remove link from freepcbsQueue in ProcessFork!\n");
    GracefulExit();
  }
  // This prevents someone else from grabbing this process
  ProcessSetStatus (pcb, PROCESS_STATUS_RUNNABLE);

  // At this point, the PCB is allocated and nobody else can get it.
  // However, it's not in the run queue, so it won't be run.  Thus, we
  // can turn on interrupts here.
  dbprintf ('I', "Before restore interrupt value is 0x%x.\n", (int)CurrentIntrs());
  RestoreIntrs (intrs);
  dbprintf ('I', "New interrupt value is 0x%x.\n", (int)CurrentIntrs());

  // Copy the process name into the PCB.
  dbprintf('p', "ProcessFork: Copying process name (%s) to pcb\n", name);
  dstrcpy(pcb->name, name);

  //----------------------------------------------------------------------
  // This section initializes the memory for this process
  //----------------------------------------------------------------------
  // For now, we'll use one user page and a page for the system stack.
  // For system processes, though, all pages must be contiguous.
  // Of course, system processes probably need just a single page for
  // their stack, and don't need any code or data pages allocated for them.
  pcb->npages = 1;
  newPage = MemoryAllocPage ();
  if (newPage == 0) {
    printf ("aFATAL: couldn't allocate memory - no free pages!\n");
    GracefulExit ();	// NEVER RETURNS!
  }
  pcb->pagetable[0] = MemorySetupPte (newPage);
  newPage = MemoryAllocPage ();
  if (newPage == 0) {
    printf ("bFATAL: couldn't allocate system stack - no free pages!\n");
    GracefulExit ();	// NEVER RETURNS!
  }
  pcb->sysStackArea = newPage * MEMORY_PAGE_SIZE;

  //----------------------------------------------------------------------
  // Stacks grow down from the top.  The current system stack pointer has
  // to be set to the bottom of the interrupt stack frame, which is at the
  // high end (address-wise) of the system stack.
  stackframe = ((uint32 *)(pcb->sysStackArea + MEMORY_PAGE_SIZE)) -
    (PROCESS_STACK_FRAME_SIZE + 8);
  // The system stack pointer is set to the base of the current interrupt
  // stack frame.
  pcb->sysStackPtr = stackframe;
  // The current stack frame pointer is set to the same thing.
  pcb->currentSavedFrame = stackframe;

  dbprintf ('p',
	    "Setting up PCB @ 0x%x (sys stack=0x%x, mem=0x%x, size=0x%x)\n",
	    (int)pcb, pcb->sysStackArea, pcb->pagetable[0],
	    pcb->npages * MEMORY_PAGE_SIZE);

  //----------------------------------------------------------------------
  // This section sets up the stack frame for the process.  This is done
  // so that the frame looks to the interrupt handler like the process
  // was "suspended" right before it began execution.  The standard
  // mechanism of swapping in the registers and returning to the place
  // where it was "interrupted" will then work.
  //----------------------------------------------------------------------

  // The previous stack frame pointer is set to 0, meaning there is no
  // previous frame.
  stackframe[PROCESS_STACK_PREV_FRAME] = 0;

  // Set the base of the level 1 page table.  If there's only one page
  // table level, this is it.  For 2-level page tables, put the address
  // of the level 1 page table here.  For 2-level page tables, we'll also
  // have to build up the necessary tables....
  stackframe[PROCESS_STACK_PTBASE] = (uint32)&(pcb->pagetable[0]);

  // Set the size (maximum number of entries) of the level 1 page table.
  // In our case, it's just one page, but it could be larger.
  stackframe[PROCESS_STACK_PTSIZE] = pcb->npages;

  // Set the number of bits for both the level 1 and level 2 page tables.
  // This can be changed on a per-process basis if desired.  For now,
  // though, it's fixed.
  stackframe[PROCESS_STACK_PTBITS] = (MEMORY_L1_PAGE_SIZE_BITS
					  + (MEMORY_L2_PAGE_SIZE_BITS << 16));


  if (isUser) {
    dbprintf ('p', "About to load %s\n", name);
    fd = ProcessGetCodeInfo (name, &start, &codeS, &codeL, &dataS, &dataL);
    if (fd < 0) {
      // Free newpage and pcb so we don't run out...
      ProcessFreeResources (pcb);
      return (-1);
    }
    dbprintf ('p', "File %s -> start=0x%08x\n", name, start);
    dbprintf ('p', "File %s -> code @ 0x%08x (size=0x%08x)\n", name, codeS,
	      codeL);
    dbprintf ('p', "File %s -> data @ 0x%08x (size=0x%08x)\n", name, dataS,
	      dataL);
    while ((n = ProcessGetFromFile (fd, buf, &addr, sizeof (buf))) > 0) {
      dbprintf ('p', "Placing %d bytes at vaddr %08x.\n", n, addr - n);
      // Copy the data to user memory.  Note that the user memory needs to
      // have enough space so that this copy will succeed!
      MemoryCopySystemToUser (pcb, buf, addr - n, n);
    }
    FsClose (fd);
    stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_USER;
    // Set the initial stack pointer correctly.  Currently, it's just set
    // to the top of the (single) user address space allocated to this
    // process.
    str = (char *)param;
    stackframe[PROCESS_STACK_IREG+29] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF;
    // Copy the initial parameter to the top of stack
    MemoryCopySystemToUser (pcb, (char *)str,
			    (char *)stackframe[PROCESS_STACK_IREG+29],
			    SIZE_ARG_BUFF-32);
    offset = get_argument((char *)param);

    dum[2] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF + offset; 
    for(count=3;;count++)
    {
      offset=get_argument(NULL);
      dum[count] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF + offset;
      if(offset==0)
      {
        break;
      }
    }
    dum[0] = count-2;
    dum[1] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF - (count-2)*4;
    MemoryCopySystemToUser (pcb, (char *)dum,
			    (char *)(stackframe[PROCESS_STACK_IREG+29]-count*4),
			    (count)*sizeof(uint32));
    stackframe[PROCESS_STACK_IREG+29] -= 4*count;
    // Set the correct address at which to execute a user process.
    stackframe[PROCESS_STACK_IAR] = (uint32)start;
    pcb->flags |= PROCESS_TYPE_USER;
  } else {
    // Set r31 to ProcessExit().  This will only be called for a system
    // process; user processes do an exit() trap.
    stackframe[PROCESS_STACK_IREG+31] = (uint32)ProcessExit;

    // Set the stack register to the base of the system stack.
    stackframe[PROCESS_STACK_IREG+29]=pcb->sysStackArea + MEMORY_PAGE_SIZE-32;

    // Set the initial parameter properly by placing it on the stack frame
    // at the location pointed to by the "saved" stack pointer (r29).
    *((uint32 *)(stackframe[PROCESS_STACK_IREG+29])) = param;

    // Set up the initial address at which to execute.  This is done by
    // placing the address into the IAR slot of the stack frame.
    stackframe[PROCESS_STACK_IAR] = (uint32)func;

    // Set the initial value for the interrupt status register
    stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_SYS;

    // Mark this as a system process.
    pcb->flags |= PROCESS_TYPE_SYSTEM;
  }

  // Place PCB onto run queue
  intrs = DisableIntrs ();
  if ((pcb->l = AQueueAllocLink(pcb)) == NULL) {
    printf("FATAL ERROR: could not get link for forked PCB in ProcessFork!\n");
    GracefulExit();
  }
  if (AQueueInsertLast(&runQueue, pcb->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert link into runQueue in ProcessFork!\n");
    GracefulExit();
  }
  RestoreIntrs (intrs);

  // If this is the first process, make it the current one
  if (currentPCB == NULL) {
    dbprintf ('p', "Setting currentPCB=0x%x, stackframe=0x%x\n", (int)pcb, (int)(pcb->currentSavedFrame));
    currentPCB = pcb;
  }

  dbprintf ('p', "Leaving ProcessFork (%s)\n", name);
  // Return the process number (found by subtracting the PCB number
  // from the base of the PCB array).
  dbprintf ('p', "ProcessFork (%d): function complete\n", GetCurrentPid());

  return (pcb - pcbs);
}
Example #15
0
//----------------------------------------------------------------------
//
//	doInterrupt
//
//	Handle an interrupt or trap.
//
//----------------------------------------------------------------------
void
dointerrupt (unsigned int cause, unsigned int iar, unsigned int isr,
	     uint32 *trapArgs)
{
  int	result;
  int	i;
  uint32	args[4];
  int	intrs;
  uint32 handle;
  int ihandle;

  dbprintf ('t',"Interrupt cause=0x%x iar=0x%x isr=0x%x args=0x%08x.\n",
	    cause, iar, isr, (int)trapArgs);
  // If the TRAP_INSTR bit is set, this was from a trap instruction.
  // If the bit isn't set, this was a system interrupt.
  if (cause & TRAP_TRAP_INSTR) {
    cause &= ~TRAP_TRAP_INSTR;
    switch (cause) {
    case TRAP_CONTEXT_SWITCH:
      dbprintf ('t', "Got a context switch trap!\n");
      ProcessSchedule ();
      ClkResetProcess();
      break;
    case TRAP_EXIT:
    case TRAP_USER_EXIT:
      dbprintf ('t', "Got an exit trap!\n");
      ProcessDestroy (currentPCB);
      ProcessSchedule ();
      ClkResetProcess();
      break;
    case TRAP_PROCESS_FORK:
      dbprintf ('t', "Got a fork trap!\n");
      break;
    case TRAP_PROCESS_SLEEP:
      dbprintf ('t', "Got a process sleep trap!\n");
      ProcessSuspend (currentPCB);
      ProcessSchedule ();
      ClkResetProcess();
      break;
    case TRAP_PRINTF:
      // Call the trap printf handler and pass the arguments and a flag
      // indicating whether the trap was called from system mode.
      dbprintf ('t', "Got a printf trap!\n");
      TrapPrintfHandler (trapArgs, isr & DLX_STATUS_SYSMODE);
      break;
    case TRAP_OPEN:
      // Get the arguments to the trap handler.  If this is a user mode trap,
      // copy them from user space.
      if (isr & DLX_STATUS_SYSMODE) {
	args[0] = trapArgs[0];
	args[1] = trapArgs[1];
      } else {
	char	filename[32];
	// trapArgs points to the trap arguments in user space.  There are
	// two of them, so copy them to to system space.  The first argument
	// is a string, so it has to be copied to system space and the
	// argument replaced with a pointer to the string in system space.
	MemoryCopyUserToSystem (currentPCB, trapArgs, args, sizeof(args[0])*2);
	MemoryCopyUserToSystem (currentPCB, args[0], filename, 31);
	// Null-terminate the string in case it's longer than 31 characters.
	filename[31] = '\0';
	// Set the argument to be the filename
	args[0] = (uint32)filename;
      }
      // Allow Open() calls to be interruptible!
      intrs = EnableIntrs ();
      ProcessSetResult (currentPCB, args[1] + 0x10000);
      printf ("Got an open with parameters ('%s',0x%x)\n", (char *)(args[0]), args[1]);
      RestoreIntrs (intrs);
      break;
    case TRAP_CLOSE:
      // Allow Close() calls to be interruptible!
      intrs = EnableIntrs ();
      ProcessSetResult (currentPCB, -1);
      RestoreIntrs (intrs);
      break;
    case TRAP_READ:
      // Allow Read() calls to be interruptible!
      intrs = EnableIntrs ();
      ProcessSetResult (currentPCB, -1);
      RestoreIntrs (intrs);
      break;
    case TRAP_WRITE:
      // Allow Write() calls to be interruptible!
      intrs = EnableIntrs ();
      ProcessSetResult (currentPCB, -1);
      RestoreIntrs (intrs);
      break;
    case TRAP_DELETE:
      intrs = EnableIntrs ();
      ProcessSetResult (currentPCB, -1);
      RestoreIntrs (intrs);
      break;
    case TRAP_SEEK:
      intrs = EnableIntrs ();
      ProcessSetResult (currentPCB, -1);
      RestoreIntrs (intrs);
      break;
    case TRAP_PROCESS_GETPID:
      ProcessSetResult(currentPCB, GetCurrentPid()); 
      break;
    case TRAP_PROCESS_CREATE:
      TrapProcessCreateHandler(trapArgs, isr & DLX_STATUS_SYSMODE);
      break;
    case TRAP_SEM_CREATE:
      ihandle = GetIntFromTrapArg(trapArgs, isr & DLX_STATUS_SYSMODE);
      ihandle = SemCreate(ihandle);
      ProcessSetResult(currentPCB, ihandle); //Return handle
      break;
    case TRAP_SEM_WAIT:
      ihandle = GetIntFromTrapArg(trapArgs, isr & DLX_STATUS_SYSMODE);
      handle = SemHandleWait(ihandle);
      ProcessSetResult(currentPCB, handle); //Return 1 or 0
      break;
    case TRAP_SEM_SIGNAL:
      ihandle = GetIntFromTrapArg(trapArgs, isr & DLX_STATUS_SYSMODE);
      handle = SemHandleSignal(ihandle);
      ProcessSetResult(currentPCB, handle); //Return 1 or 0
      break;
    case TRAP_LOCK_CREATE:
      ihandle = LockCreate();
      ProcessSetResult(currentPCB, ihandle); //Return handle
      break;
    case TRAP_LOCK_ACQUIRE:
      ihandle = GetIntFromTrapArg(trapArgs, isr & DLX_STATUS_SYSMODE);
      handle = LockHandleAcquire(ihandle);
      ProcessSetResult(currentPCB, handle); //Return 1 or 0
      break;
    case TRAP_LOCK_RELEASE:
      ihandle = GetIntFromTrapArg(trapArgs, isr & DLX_STATUS_SYSMODE);
      handle = LockHandleRelease(ihandle);
      ProcessSetResult(currentPCB, handle); //Return 1 or 0
      break;
    case TRAP_COND_CREATE:
      ihandle = GetIntFromTrapArg(trapArgs, isr & DLX_STATUS_SYSMODE);
      ihandle = CondCreate(ihandle);
      ProcessSetResult(currentPCB, ihandle); //Return handle
      break;
    case TRAP_COND_WAIT:
      ihandle = GetIntFromTrapArg(trapArgs, isr & DLX_STATUS_SYSMODE);
      ihandle = CondHandleWait(ihandle);
      ProcessSetResult(currentPCB, ihandle); //Return 1 or 0
      break;
    case TRAP_COND_SIGNAL:
      ihandle = GetIntFromTrapArg(trapArgs, isr & DLX_STATUS_SYSMODE);
      ihandle = CondHandleSignal(ihandle);
      ProcessSetResult(currentPCB, ihandle); //Return 1 or 0
      break;
    case TRAP_COND_BROADCAST:
      ihandle = GetIntFromTrapArg(trapArgs, isr & DLX_STATUS_SYSMODE);
      ihandle = CondHandleBroadcast(ihandle);
      ProcessSetResult(currentPCB, ihandle); //Return 1 or 0
      break;

    // Traps for Disk Access
    case TRAP_DISK_WRITE_BLOCK:
        ihandle = TrapDiskWriteBlockHandler(trapArgs, isr & DLX_STATUS_SYSMODE);
        ProcessSetResult(currentPCB, ihandle);  
      break;
    case TRAP_DISK_SIZE:
        ProcessSetResult(currentPCB, DiskSize());
      break;
    case TRAP_DISK_BLOCKSIZE:
        ProcessSetResult(currentPCB, DiskBytesPerBlock());
      break;
    case TRAP_DISK_CREATE:
        ProcessSetResult(currentPCB, DiskCreate());
      break;

    // Traps for DFS filesystem
    case TRAP_DFS_INVALIDATE:
        DfsInvalidate();
      break;

    // Traps for file functions
    case TRAP_FILE_OPEN:
        ProcessSetResult(currentPCB, TrapFileOpenHandler(trapArgs, isr & DLX_STATUS_SYSMODE));
      break;
    case TRAP_FILE_CLOSE:
        ProcessSetResult(currentPCB, TrapFileCloseHandler(trapArgs, isr & DLX_STATUS_SYSMODE));
      break;
    case TRAP_FILE_DELETE:
        ProcessSetResult(currentPCB, TrapFileDeleteHandler(trapArgs, isr & DLX_STATUS_SYSMODE));
      break;
    case TRAP_FILE_READ:
        ProcessSetResult(currentPCB, TrapFileReadHandler(trapArgs, isr & DLX_STATUS_SYSMODE));
      break;
    case TRAP_FILE_WRITE:
        ProcessSetResult(currentPCB, TrapFileWriteHandler(trapArgs, isr & DLX_STATUS_SYSMODE));
      break;
    case TRAP_FILE_SEEK:
        ProcessSetResult(currentPCB, TrapFileSeekHandler(trapArgs, isr & DLX_STATUS_SYSMODE));
      break;

    // Traps for running OS testing code
    case TRAP_TESTOS:
        RunOSTests();
      break;

    default:
      printf ("Got an unrecognized trap (0x%x) - exiting!\n",
	      cause);
      GracefulExit ();
      break;
    }
  } else {
    switch (cause) {
    case TRAP_TIMER:
      dbprintf ('t', "Got a timer interrupt!\n");
      // ClkInterrupt returns 1 when 1 "process quantum" has passed, meaning
      // that it's time to call ProcessSchedule again.
      if (ClkInterrupt()) {
        ProcessSchedule ();
      }
      break;
    case TRAP_KBD:
      do {
	i = *((uint32 *)DLX_KBD_NCHARSIN);
	result = *((uint32 *)DLX_KBD_GETCHAR);
	printf ("Got a keyboard interrupt (char=0x%x(%c), nleft=%d)!\n",
		result, result, i);
      } while (i > 1);
      break;
    case TRAP_ACCESS:
      printf ("Exiting after illegal access at iar=0x%x, isr=0x%x\n",
	      iar, isr);
      GracefulExit ();
      break;
    case TRAP_ADDRESS:
      printf ("Exiting after illegal address at iar=0x%x, isr=0x%x\n",
	      iar, isr);
      GracefulExit ();
      break;
    case TRAP_ILLEGALINST:
      printf ("Exiting after illegal instruction at iar=0x%x, isr=0x%x\n",
	      iar, isr);
      GracefulExit ();
      break;
    case TRAP_PAGEFAULT:
      printf ("Exiting after page fault at iar=0x%x, isr=0x%x\n",
	      iar, isr);
      GracefulExit ();
      break;
    default:
      printf ("Got an unrecognized system interrupt (0x%x) - exiting!\n",
	      cause);
      GracefulExit ();
      break;
    }
  }
  dbprintf ('t',"About to return from dointerrupt.\n");
  // Note that this return may schedule a new process!
  intrreturn ();
}
Example #16
0
//--------------------------------------------------------------------
//
// int process_create(char *exec_name, ...);
//
// Here we support reading command-line arguments.  Maximum MAX_ARGS 
// command-line arguments are allowed.  Also the total length of the 
// arguments including the terminating '\0' should be less than or 
// equal to SIZE_ARG_BUFF.
//
//--------------------------------------------------------------------
static void TrapProcessCreateHandler(uint32 *trapArgs, int sysMode) {
  char allargs[SIZE_ARG_BUFF];  // Stores full string of arguments (unparsed)
  char name[PROCESS_MAX_NAME_LENGTH]; // Local copy of name of executable (100 chars or less)
  char *username=NULL;          // Pointer to user-space address of exec_name string
  int i=0, j=0;                 // Loop index variables
  char *args[MAX_ARGS];         // All parsed arguments (char *'s)
  int allargs_position = 0;     // Index into current "position" in allargs
  char *userarg = NULL;         // Current pointer to user argument string
  int numargs = 0;              // Number of arguments passed on command line

  dbprintf('p', "TrapProcessCreateHandler: function started\n");
  // Initialize allargs string to all NULL's for safety
  for(i=0;i<SIZE_ARG_BUFF; i++) {
    allargs[i] = '\0';
  }

  // First deal with user-space addresses
  if(!sysMode) {
    dbprintf('p', "TrapProcessCreateHandler: creating user process\n");
    // Get the known arguments into the kernel space.
    // Argument 0: user-space pointer to name of executable
    MemoryCopyUserToSystem (currentPCB, (trapArgs+0), &username, sizeof(char *));

    // Copy the user-space string at user-address "username" into kernel space
    for(i=0; i<PROCESS_MAX_NAME_LENGTH; i++) {
      MemoryCopyUserToSystem(currentPCB, (username+i), &(name[i]), sizeof(char));
      // Check for end of user-space string
      if (name[i] == '\0') break;
    }
    dbprintf('p', "TrapProcessCreateHandler: just parsed executable name (%s) from trapArgs\n", name);
    if (i == PROCESS_MAX_NAME_LENGTH) {
      printf("TrapProcessCreateHandler: length of executable filename longer than allowed!\n");
      GracefulExit();
    }

    // Copy the program name into "allargs", since it has to be the first argument (i.e. argv[0])
    allargs_position = 0;
    dstrcpy(&(allargs[allargs_position]), name);
    allargs_position += dstrlen(name) + 1; // The "+1" is so we're pointing just beyond the NULL

    // Rest of arguments: a series of char *'s until we hit NULL or MAX_ARGS
    for(i=0; i<MAX_ARGS; i++) {
      // First, must copy the char * itself into kernel space in order to read its value
      MemoryCopyUserToSystem(currentPCB, (trapArgs+1+i), &userarg, sizeof(char *));
      // If this is a NULL in the set of char *'s, this is the end of the list
      if (userarg == NULL) break;
      // Store a pointer to the kernel-space location where we're copying the string
      args[i] = &(allargs[allargs_position]);
      // Copy the string into the allargs, starting where we left off last time through this loop
      for (j=0; j<SIZE_ARG_BUFF; j++) {
        MemoryCopyUserToSystem(currentPCB, (userarg+j), &(allargs[allargs_position]), sizeof(char));
        // Move current character in allargs to next spot
        allargs_position++;
        // Check that total length of arguments is still ok
        if (allargs_position == SIZE_ARG_BUFF) {
          printf("TrapProcessCreateHandler: strlen(all arguments) > maximum length allowed!\n");
          GracefulExit();
        }
        // Check for end of user-space string
        if (allargs[allargs_position-1] == '\0') break;
      }
    }
    if (i == MAX_ARGS) {
      printf("TrapProcessCreateHandler: too many arguments on command line (did you forget to pass a NULL?)\n");
      GracefulExit();
    }
    numargs = i+1;
    // Arguments are now setup
  } else {
    // Addresses are already in kernel space, so just copy into our local variables 
    // for simplicity
    // Argument 0: (char *) name of program
    dstrncpy(name, (char *)(trapArgs[0]), PROCESS_MAX_NAME_LENGTH);
    // Copy the program name into "allargs", since it has to be the first argument (i.e. argv[0])
    allargs_position = 0;
    dstrcpy(&(allargs[allargs_position]), name);
    allargs_position += dstrlen(name) + 1;  // The "+1" is so that we are now pointing just beyond the "null" in the name
    allargs_position = 0;
    for (i=0; i<MAX_ARGS; i++) {
      userarg = (char *)(trapArgs[i+1]);
      if (userarg == NULL) break; // found last argument
      // Store the address of where we're copying the string
      args[i] = &(allargs[allargs_position]);
      // Copy string into allargs
      for(j=0; j<SIZE_ARG_BUFF; j++) {
        allargs[allargs_position] = userarg[j];
        allargs_position++;
        if (allargs_position == SIZE_ARG_BUFF) {
          printf("TrapProcessCreateHandler: strlen(all arguments) > maximum length allowed!\n");
          GracefulExit();
        }
        // Check for end of user-space string
        if (allargs[allargs_position-1] == '\0') break;
      }
    }
    if (i == MAX_ARGS) {
      printf("TrapProcessCreateHandler: too many arguments on command line (did you forget to pass a NULL?)\n");
      GracefulExit();
    }
    numargs = i+1;
  }

  ProcessFork(0, (uint32)allargs, name, 1);
}