Esempio n. 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;
  int		npages;

  QueueInsertLast (&freepcbs, &pcb->l);
  // Free the process's memory.  This is easy with a one-level page
  // table, but could get more complex with two-level page tables.
  npages = pcb->npages;

  for (i=0; i<npages; i++)
  {
    MemoryFreeSharedPte(pcb, i); // *MUST* be called before calling
    				 // MemoryFreePte. MemoryFreePte does not know
				 // anything about shared pages, and hence it
				 // might screw up big time
  }
  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);
}
Esempio n. 2
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");
}
Esempio n. 3
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;
  int usrsp = MEM_ADDRESS_TO_PAGE(pcb->currentSavedFrame[PROCESS_STACK_USER_STACKPOINTER]);
  
  // 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");
    exitsim();
  }
  // 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");
    exitsim();
  }

  //------------------------------------------------------------
  // STUDENT: Free any memory resources on process death here.
  //------------------------------------------------------------
  for(i = 0; i < 5; i++) {
    MemoryFreePte(pcb->pagetable[i]);
  }
  for(i = usrsp; i <= MEM_ADDRESS_TO_PAGE(MEM_MAX_VIRTUAL_ADDRESS); i++) {
    MemoryFreePte(pcb->pagetable[i]);
  }
  MemoryFreePage (pcb->sysStackArea / MEM_PAGESIZE);
  ProcessSetStatus (pcb, PROCESS_STATUS_FREE);
  dbprintf ('p', "ProcessFreeResources: function complete\n");
}
//----------------------------------------------------------------------
//
//	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)
{
    int i, sleeptime_inseconds;
    float temp_estcpu, power;

    dbprintf ('p',"Waking up PCB 0x%x.\n", wakeup);
    // Make sure it's not yet a runnable process.
    ASSERT (wakeup->flags & PROCESS_STATUS_WAITING,
            "Trying to wake up a non-sleeping process!\n");

    sleeptime_inseconds = (my_timer_get() - wakeup->sleeptime)/1000;

    // Adjust the estimated CPU time
    if(sleeptime_inseconds >= 1) {
        temp_estcpu = ((((float)2 * wakeup->load)/((float)2 * wakeup->load + 1)) * wakeup->estcpu); // Base
        power = temp_estcpu;
        for(i = 1; i < sleeptime_inseconds; i++) {
            temp_estcpu *= power;  // To the power of sleeptime_inseconds
        }
        wakeup->estcpu = (int)temp_estcpu;
    }

    // Recalculate priority
    wakeup->prio = PUSER + (wakeup->estcpu/4) + (2*wakeup->p_nice);
    wakeup->runQueueNum = wakeup->prio/4;

    // Put the process on a run queue based on Priority
    ProcessSetStatus (wakeup, PROCESS_STATUS_RUNNABLE);
    QueueRemove (&wakeup->l);
    QueueInsertLast (&runQueue[wakeup->runQueueNum], &wakeup->l);

}
Esempio n. 5
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', "Entering ProcessDestroy for 0x%x.\n", pcb);
  ProcessSetStatus (pcb, PROCESS_STATUS_ZOMBIE);
  QueueRemove (&pcb->l);
  QueueInsertFirst (&zombieQueue, &pcb->l);
  dbprintf('p', "Leaving ProcessDestroy for 0x%x.\n", pcb);
}
//----------------------------------------------------------------------
//
//	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', "Suspending PCB 0x%x (%s).\n", suspend, suspend->name);
  ASSERT (suspend->flags & PROCESS_STATUS_RUNNABLE,
	  "Trying to suspend a non-running process!\n");
  ProcessSetStatus (suspend, PROCESS_STATUS_WAITING);
  QueueRemove (&suspend->l);
  QueueInsertLast (&waitQueue, &suspend->l);
}
//----------------------------------------------------------------------
//
//	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 PCB 0x%x.\n", wakeup);
  // 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);
  QueueRemove (&wakeup->l);
  QueueInsertLast (&runQueue, &wakeup->l);
}
Esempio n. 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', "Entering ProcessDestroy for 0x%x.\n", (int)pcb);
  ProcessSetStatus (pcb, PROCESS_STATUS_ZOMBIE);
  if (AQueueRemove(&(pcb->l)) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not remove link from queue in ProcessDestroy!\n");
    exitsim();
  }
  if ((pcb->l = AQueueAllocLink(pcb)) == NULL) {
    printf("FATAL ERROR: could not get link for zombie PCB in ProcessDestroy!\n");
    exitsim();
  }
  if (AQueueInsertFirst(&zombieQueue, pcb->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert link into runQueue in ProcessWakeup!\n");
    exitsim();
  }
  dbprintf('p', "Leaving ProcessDestroy for 0x%x.\n", (int)pcb);
}
Esempio n. 9
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());
}
Esempio n. 10
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;
  uint32 page;

  // 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");
    exitsim();
  }
  // 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");
    exitsim();
  }

  //------------------------------------------------------------
  // STUDENT: Free any memory resources on process death here.
  //------------------------------------------------------------

  /////////////////////////////////////////////////////////////
  // TODO CHANGE FOR 2 LEVEL Free Resource
  // JSM - free all physical pages corresponding to valid page table entries in process
  // AS WEL AS FREEING SYSTEM STACK PAGE ASSOCIATED WITH PROCESS
  for (i = 0; i < MEM_L1_PAGE_TABLE_SIZE; i++)
  {
  	if(pcb->pagetable[i] & MEM_PTE_VALID) // For every page currently valid in page table
  	{
  		pcb->pagetable[i] &= ~(MEM_PTE_VALID);  // Invalidate page table entry
  		page = (pcb->pagetable[i]) / MEM_PAGE_SIZE;
  		dbprintf ('p', "Preparing to free physical page #%d\n", page);
  		MemoryFreePage(page); // Free page in freemap
  	}
  }
	dbprintf ('p', "Preparing to free physical page #%d (System Stack)\n", (pcb->sysStackArea / MEM_PAGE_SIZE) );
	MemoryFreePage(pcb->sysStackArea / MEM_PAGE_SIZE); // Free page in freemap

  /////////////////////////////////////////////////////////////

  dbprintf ('p', "Free Resources DONE!\n\n");
  //while(1);

  ProcessSetStatus (pcb, PROCESS_STATUS_FREE);
}
Esempio n. 11
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");
    exitsim();
  }
  if ((wakeup->l = AQueueAllocLink(wakeup)) == NULL) {
    printf("FATAL ERROR: could not get link for wakeup PCB in ProcessWakeup!\n");
    exitsim();
  }
  if (AQueueInsertLast(&runQueue, wakeup->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert link into runQueue in ProcessWakeup!\n");
    exitsim();
  }
}
Esempio n. 12
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', "Suspending PCB 0x%x (%s).\n", (int)suspend, suspend->name);
  ASSERT (suspend->flags & PROCESS_STATUS_RUNNABLE, "Trying to suspend a non-running process!\n");
  ProcessSetStatus (suspend, PROCESS_STATUS_WAITING);
  ClkResetProcess();
  if (AQueueRemove(&(suspend->l)) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not remove process from run Queue in ProcessSuspend!\n");
    exitsim();
  }
  if ((suspend->l = AQueueAllocLink(suspend)) == NULL) {
    printf("FATAL ERROR: could not get Queue Link in ProcessSuspend!\n");
    exitsim();
  }
  if (AQueueInsertLast(&waitQueue, suspend->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert suspend PCB into waitQueue!\n");
    exitsim();
  }
}
Esempio n. 13
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());
}
Esempio n. 14
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)
{
  uint32 currTime;
  int i;
  dbprintf ('p',"Waking up PCB 0x%x.\n", wakeup);
  // 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);
  QueueRemove (&wakeup->l);
  
  currTime = my_timer_get();
  if (currTime - wakeup->sleeptime >= 10) {
    //printf("Updating prio after long wakeup");
    for (i = 0; i < (currTime - wakeup->sleeptime); i++) 
        wakeup->estcpu *= (2.0f/(2 + 1));
    wakeup->prio = PUSER + (int)(wakeup->estcpu/4) + 2*wakeup->p_nice;
  }
  wakeup->processed = 1 - processedFlag;
  QueueInsertLast (&runQueue[wakeup->prio/4], &wakeup->l);
}
//----------------------------------------------------------------------
//
//	ProcessFreeResources
//
//	Free the resources associated with a process.  This assumes the
//	process isn't currently on any queue.
//
//----------------------------------------------------------------------
void
ProcessFreeResources (PCB *pcb)
{
  int		i;
  int		npages;

  QueueInsertLast (&freepcbs, &pcb->l);
  // Free the process's memory.  This is easy with a one-level page
  // table, but could get more complex with two-level page tables.

//------------------------------------------
// You may change the code below
//------------------------------------------

  npages = pcb->npages;

  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);
}
Esempio n. 16
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 i,j;                   // Loop index variable
  int fd, n;               // Used for reading code from files.
  int start, codeS, codeL; // Used for reading code from files.
  int dataS, dataL;        // Used for reading code from files.
  int addr = 0;            // Used for reading code from files.
  unsigned char buf[100];  // Used for reading code from files.
  uint32 *stackframe;      // Stores address of current stack frame.
  PCB *pcb;                // Holds pcb while we build it for this process.
  int intrs;               // Stores previous interrupt settings.
  uint32  initial_user_params[MAX_ARGS+2]; // Initial memory for user parameters (argc, argv)
                                           // initial_user_params[0] = argc
                                           // initial_user_params[1] = argv, points to initial_user_params[2]
                                           // initial_user_params[2] = address of string for argv[0]
                                           // initial_user_params[3] = address of string for argv[1]
                                           //                           ...
  uint32 argc=0;           // running counter for number of arguments
  uint32 offset;           // Used in parsing command line argument strings, holds offset (in bytes) from 
                           // beginning of the string to the current argument.
  uint32 initial_user_params_bytes;  // total number of bytes in initial user parameters array

  int newpage;
  int index;
  int *p;


  intrs = DisableIntrs ();
  dbprintf ('I', "ProcessFork-Old interrupt value was 0x%x.\n", intrs);
  dbprintf ('p', "ProcessFork-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 ("ProcessFork-FATAL error: no free processes!\n");
    exitsim ();	// NEVER RETURNS!
  }
  pcb = (PCB *)AQueueObject(AQueueFirst (&freepcbs));
  dbprintf ('p', "ProcessFork-Got a link @ 0x%x\n", (int)(pcb->l));
  if (AQueueRemove (&(pcb->l)) != QUEUE_SUCCESS) {
    printf("ProcessFork-FATAL ERROR: could not remove link from freepcbsQueue in ProcessFork!\n");
    exitsim();
  }
  // 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.
  RestoreIntrs (intrs);

  // Copy the process name into the PCB.
  dstrcpy(pcb->name, name);

  //----------------------------------------------------------------------
  // This section initializes the memory for this process
  //----------------------------------------------------------------------
  // Allocate 1 page for system stack, 1 page for user stack (at top of
  // virtual address space), and 4 pages for user code and global data.

  //---------------------------------------------------------
  // STUDENT: allocate pages for a new process here.  The
  // code below assumes that you set the "stackframe" variable
  // equal to the last 4-byte-aligned address in physical page
  // for the system stack.
  //---------------------------------------------------------

  ////////////////////////////////////////////////////////////////
  // JSM, allocate 6 physical pages for new process

  // First, get L2 Page Table for index 0 of L1 Page Table
  index = MemoryAllocateL2PT();
	if (index == -1)
	{
		printf ("ProcessFork-FATAL: couldn't allocate L2 Page Table for index 0 of L1 Page Table - no free page tables!\n");
		exitsim ();	// NEVER RETURNS!
	}
  // Assign L1 entry to address of start of L2 Page Table
	pcb->pagetable[0] = (uint32)&level2_pt_block[index];

	p = (uint32 *)pcb->pagetable[0];//L2

  // Allocate 4 pages for code and data
  for(i = 0; i < 4; i++)
  {
		newpage = MemoryAllocatePage();
		if (newpage == 0)
		{
			printf ("ProcessFork-FATAL: couldn't allocate memory - no free pages!\n");
			exitsim ();	// NEVER RETURNS!
		}
		dbprintf('p', "ProcessFork-Allocating physical page #%d (Address 0x%.8X) for process virtual page #%d (data/code)\n", newpage, (newpage*MEM_PAGE_SIZE), i);

		*(p+i) = ((newpage*MEM_PAGE_SIZE) | MEM_PTE_VALID);
		dbprintf('p', "Contents at 0x%.8X: 0x%.8X\n\n", (int)(p+i), *(p+i));
  }
	/////////////////////////////////////////////////////
	//YF ADDED allocate page for heap
  // First, initialize the heapfree map
  for (j=0; j<MEM_MAX_HEAP_FREEMAP; j++){
  	pcb->HeapFreeMap[j] = 0;
  }
  for (j =0; j<MEM_MAX_HEAP_POINTER_ARRAY; j++){
  	pcb->HeapPtrSizes[j] = 0;
  }

  index = MemoryAllocateL2PT();
	if (index == -1)
	{
		printf ("ProcessFork-FATAL: couldn't allocate L2 Page Table for index 0 of L1 Page Table - no free page tables!\n");
		exitsim ();	// NEVER RETURNS!
	}
  // Assign L1 entry to address of start of L2 Page Table
	pcb->pagetable[0] = (uint32)&level2_pt_block[index];
	p = (uint32 *)pcb->pagetable[0];

	newpage = MemoryAllocatePage();
	if (newpage == 0)
	{
		printf ("ProcessFork-FATAL: couldn't allocate memory - no free pages!\n");
		exitsim ();	// NEVER RETURNS!
	}
	dbprintf('p', "ProcessFork-Allocating physical page #%d (Address 0x%.8X) for process virtual page #%d (Heap Allocation)\n", newpage, (newpage*MEM_PAGE_SIZE), i);
	//address for catch in Memory translate. UserHeap Address =0x4000 =
	*(p+i) = ((newpage*MEM_PAGE_SIZE) | MEM_PTE_VALID | MEM_PTE_HEAP); //TODO ProcessFork: marked as a heap.
	pcb->userHeapArea = (uint32 *)(newpage*MEM_PAGE_SIZE);
	dbprintf('p', "Heap area is at physical address:0x%.8X   L2 Address: 0x%.8X\n", (int)(newpage*MEM_PAGE_SIZE), *(p+i));
	dbprintf('p', "Contents at 0x%.8X: 0x%.8X\n\n", (int)(p+i), *(p+i));
	//Done with Heap allocation

///////////////////////////////////////////////////////////////////////////////////////////////////
  // Allocate page for user stack
  // First, get L2 Page Table for index 15 of L1 Page Table
  index = MemoryAllocateL2PT();
	if (index == -1)
	{
		printf ("ProcessFork-FATAL: couldn't allocate L2 Page Table for index 0 of L1 Page Table - no free page tables!\n");
		exitsim ();	// NEVER RETURNS!
	}
  // Assign L1 entry to address of start of L2 Page Table
	pcb->pagetable[MEM_L1_PAGE_TABLE_SIZE-1] = (uint32)&level2_pt_block[index];
	p = (uint32 *)pcb->pagetable[MEM_L1_PAGE_TABLE_SIZE-1];

	newpage = MemoryAllocatePage();
	if (newpage == 0)
	{
		printf ("ProcessFork-FATAL: couldn't allocate memory - no free pages!\n");
		exitsim ();	// NEVER RETURNS!
	}
	dbprintf('p', "ProcessFork-Allocating physical page #%d (Address 0x%.8X) for process virtual page #%d (user stack)\n\n", newpage, (newpage*MEM_PAGE_SIZE), (MEM_L1_PAGE_TABLE_SIZE*MEM_L2_PAGE_TABLE_SIZE)-1);

	*(p+(MEM_L2_PAGE_TABLE_SIZE-1)) = ((newpage*MEM_PAGE_SIZE) | MEM_PTE_VALID);
	dbprintf('p', "Contents at 0x%.8X: 0x%.8X\n\n", (int)(p+(MEM_L2_PAGE_TABLE_SIZE-1)), *(p+(MEM_L2_PAGE_TABLE_SIZE-1)));

  // Allocate page for system stack
	newpage = MemoryAllocatePage();
	if (newpage == 0)
	{
		printf ("ProcessFork-FATAL: couldn't allocate memory - no free pages!\n");
		exitsim ();	// NEVER RETURNS!
	}
	dbprintf('p', "ProcessFork-Allocating physical page #%d (Address 0x%.8X) for process system stack\n\n", newpage, (newpage*MEM_PAGE_SIZE));
	pcb->sysStackArea = newpage * MEM_PAGE_SIZE;
	stackframe = (uint32 *)(pcb->sysStackArea + (MEM_PAGE_SIZE-4));
	dbprintf('p', "ProcessFork-Initializing system stack pointer to 0x%.8X\n\n", (uint32)stackframe);

  ////////////////////////////////////////////////////////////////

  // Now that the stack frame points at the bottom of the system stack memory area, we need to
  // move it up (decrement it) by one stack frame size because we're about to fill in the
  // initial stack frame that will be loaded for this PCB when it gets switched in by 
  // ProcessSchedule the first time.
  stackframe -= PROCESS_STACK_FRAME_SIZE;

  // 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;

  //----------------------------------------------------------------------
  // 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.
  dbprintf('m', "ProcessFork-ProcessFork: stackframe = 0x%x\n", (int)stackframe);
  stackframe[PROCESS_STACK_PREV_FRAME] = 0;

  //----------------------------------------------------------------------
  // STUDENT: setup the PTBASE, PTBITS, and PTSIZE here on the current
  // stack frame.
  //----------------------------------------------------------------------

  // JSM added PTBASE, PTBITS, and PTSIZE on stack frame
  //////////////////////////////////////////////////////////
  stackframe[PROCESS_STACK_PTBASE] = (uint32)&(pcb->pagetable[0]);
  dbprintf('p', "ProcessFork-PTBASE: 0x%.8X\n\n", (uint32)&(pcb->pagetable[0]));
  stackframe[PROCESS_STACK_PTSIZE] = MEM_L1_PAGE_TABLE_SIZE;
  dbprintf('p', "ProcessFork-PTSIZE: 0x%.8X\n\n", MEM_L1_PAGE_TABLE_SIZE);
  stackframe[PROCESS_STACK_PTBITS] = (MEM_L2FIELD_FIRST_BITNUM << 16) | MEM_L1FIELD_FIRST_BITNUM;
  dbprintf('p', "ProcessFork-PTBITS: 0x%.8X\n\n", (MEM_L2FIELD_FIRST_BITNUM << 16) | MEM_L1FIELD_FIRST_BITNUM);

  //////////////////////////////////////////////////////////

  if (isUser) {//user prog .dlx.obj
    dbprintf ('p', "ProcessFork-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', "ProcessFork-File %s -> start=0x%08x\n", name, start);
    dbprintf ('p', "ProcessFork-File %s -> code @ 0x%08x (size=0x%08x)\n", name, codeS,
	      codeL);
    dbprintf ('p', "ProcessFork-File %s -> data @ 0x%08x (size=0x%08x)\n", name, dataS,
	      dataL);

    while ((n = ProcessGetFromFile (fd, buf, &addr, sizeof (buf))) > 0) {
      dbprintf ('p', "ProcessFork-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, (char *)(addr - n), n);
    }
    FsClose (fd);
    stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_USER;

    //----------------------------------------------------------------------
    // STUDENT: setup the initial user stack pointer here as the top
    // of the process's virtual address space (4-byte aligned).
    //----------------------------------------------------------------------

    // JSM initialized user stack pointer
    //////////////////////////////////////////////////////////
    stackframe[PROCESS_STACK_USER_STACKPOINTER] = (MEM_MAX_VIRTUAL_ADDRESS-3);
    dbprintf('p', "ProcessFork-USER_STACKPOINTER: 0x%.8X\n\n", stackframe[PROCESS_STACK_USER_STACKPOINTER]);
    //////////////////////////////////////////////////////////

    //--------------------------------------------------------------------
    // This part is setting up the initial user stack with argc and argv.
    //--------------------------------------------------------------------

    // Copy the entire set of strings of command line parameters onto the user stack.
    // The "param" variable is a pointer to the start of a sequenial set of strings,
    // each ending with its own '\0' character.  The final "string" of the sequence
    // must be an empty string to indicate that the sequence is done.  Since we
    // can't figure out how long the set of strings actually is in this scenario,
    // we have to copy the maximum possible string length and parse things manually.
    stackframe[PROCESS_STACK_USER_STACKPOINTER] -= SIZE_ARG_BUFF;
    MemoryCopySystemToUser (pcb, (char *)param, (char *)stackframe[PROCESS_STACK_USER_STACKPOINTER], SIZE_ARG_BUFF);

    // Now that the main string is copied into the user space, we need to setup
    // argv as an array of pointers into that string, and argc as the total
    // number of arguments found in the string.  The first call to get_argument
    // should return 0 as the offset of the first string.
    offset = get_argument((char *)param);
   
    // Compute the addresses in user space of where each string for the command line arguments
    // begins.  These addresses make up the argv array.
    for(argc=0; argc < MAX_ARGS; argc++) {
      // The "+2" is because initial_user_params[0] is argc, and initial_user_params[1] is argv.
      // The address can be found as the current stack pointer (which points to the start of
      // the params list) plus the byte offset of the parameter from the beginning of
      // the list of parameters.
      initial_user_params[argc+2] = stackframe[PROCESS_STACK_USER_STACKPOINTER] + offset;
      offset = get_argument(NULL);
      if (offset == 0) {
        initial_user_params[argc+2+1] = 0; // last entry should be a null value
        break;
      }
    }
    // argc is currently the index of the last command line argument.  We need it to instead
    // be the number of command line arguments, so we increment it by 1.
    argc++;

    // Now argc can be stored properly
    initial_user_params[0] = argc;

    // Compute where initial_user_params[3] will be copied in user space as the 
    // base of the array of string addresses.  The entire initial_user_params array
    // of uint32's will be copied onto the stack.  We'll move the stack pointer by
    // the necessary amount, then start copying the array.  Therefore, initial_user_params[3]
    // will reside at the current stack pointer value minus the number of command line
    // arguments (argc).
    initial_user_params[1] = stackframe[PROCESS_STACK_USER_STACKPOINTER] - (argc*sizeof(uint32));

    // Now copy the actual memory.  Remember that stacks grow down from the top of memory, so 
    // we need to move the stack pointer first, then do the copy.  The "+2", as before, is 
    // because initial_user_params[0] is argc, and initial_user_params[1] is argv.
    initial_user_params_bytes = (argc + 2) * sizeof(uint32);

    stackframe[PROCESS_STACK_USER_STACKPOINTER] -= initial_user_params_bytes;
    MemoryCopySystemToUser (pcb, (char *)initial_user_params, (char *)(stackframe[PROCESS_STACK_USER_STACKPOINTER]), initial_user_params_bytes);

    // Set the correct address at which to execute a user process.
    stackframe[PROCESS_STACK_IAR] = (uint32)start;

    // Flag this as a user process
    pcb->flags |= PROCESS_TYPE_USER;
  } else {
    // Don't worry about messing with any code here for kernel processes because
    // there aren't any kernel processes in DLXOS.

    // 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 + MEM_PAGESIZE;

    // 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 the PCB onto the run queue.
  intrs = DisableIntrs ();
  if ((pcb->l = AQueueAllocLink(pcb)) == NULL) {
    printf("FATAL ERROR: could not get link for forked PCB in ProcessFork!\n");
    exitsim();
  }
  if (AQueueInsertLast(&runQueue, pcb->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert link into runQueue in ProcessFork!\n");
    exitsim();
  }
  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).
  return (pcb - pcbs);
}
Esempio n. 17
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,j;
  uint32 entry, page;
  uint32 *p;

  // 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");
    exitsim();
  }
  // 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");
    exitsim();
  }

  //------------------------------------------------------------
  // STUDENT: Free any memory resources on process death here.
  //------------------------------------------------------------

  /////////////////////////////////////////////////////////////
  // TODO4 CHANGE FOR 2 LEVEL DONE
  // JSM - free all physical pages corresponding to valid page table entries in process
  // AS WELL AS FREEING SYSTEM STACK PAGE ASSOCIATED WITH PROCESS
  for (i = 0; i < MEM_L1_PAGE_TABLE_SIZE; i++)
  {
  	if(pcb->pagetable[i] != 0) // For every page currently valid in L1 Page Table
  	{
  		dbprintf ('p', "\nFreeing L2 PT entries from L1 PT index #%d\n", i);
  		dbprintf ('p', "L1P1 index #%d Contents: %d\n", i, pcb->pagetable[i]);
  		dbprintf ('p', "Start of corresponding L2PT Block: %d\n", (uint32)(level2_pt_block));
  		entry = ((pcb->pagetable[i])-(uint32)(level2_pt_block))/(sizeof(level2_pt));
  		dbprintf ('p', "Level2_pt_block entry for L1 PT index #%d is: %d\n\n", i, entry);

  		p = (uint32 *)&level2_pt_block[entry];
  	  for (j = 0; j < MEM_L2_PAGE_TABLE_SIZE; j++)
  	  {
  	  	if(*(p+j) & MEM_PTE_VALID) // For every page currently valid in page table
  	  	{
  	  		dbprintf ('p', "Invalidating L1_idx: %d, L2_idx:%d\n", i, j);
  	  		*(p+j) &= ~(MEM_PTE_VALID);  // Invalidate page table entry
  	  		page = (*(p+j) / MEM_PAGE_SIZE);
  	  		dbprintf ('p', "Preparing to free physical page #%d\n", page);
  	  		MemoryFreePage(page); // Free page in freemap
  	  	}
  	  }
  	  // Invalidate L1 Page Table Entry
  	  pcb->pagetable[i] = 0;
  	  // FREE L2 PAGE TABLE
  	  MemoryFreeL2PT(entry);
  	}
  }

	dbprintf ('p', "\nPreparing to free physical page #%d (System Stack)\n", (pcb->sysStackArea / MEM_PAGE_SIZE) );
	MemoryFreePage(pcb->sysStackArea / MEM_PAGE_SIZE); // Free page in freemap

  /////////////////////////////////////////////////////////////

  dbprintf ('M', "Free Resources DONE!\n\n");
	for(i=0; i<MEM_FREEMAP_SIZE_IN_WORDS; i++)
	{
		dbprintf('M', "Freemap Int #%d value: 0x%.8X\n", i, freemap[i]);
	}
	dbprintf('m', "\n");
	for(i=0; i<MEM_FREEMAP_PT_SIZE_IN_WORDS; i++)
	{
		dbprintf('M', "freemap_pt index #%d value: 0x%.8X\n", i, pt_freemap[i]);
	}

  ProcessSetStatus (pcb, PROCESS_STATUS_FREE);
}
Esempio n. 18
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 i;                   // Loop index variable
  int fd, n;               // Used for reading code from files.
  int start, codeS, codeL; // Used for reading code from files.
  int dataS, dataL;        // Used for reading code from files.
  int addr = 0;            // Used for reading code from files.
  unsigned char buf[100];  // Used for reading code from files.
  uint32 *stackframe;      // Stores address of current stack frame.
  PCB *pcb;                // Holds pcb while we build it for this process.
  int intrs;               // Stores previous interrupt settings.
  uint32  initial_user_params[MAX_ARGS+2]; // Initial memory for user parameters (argc, argv)
                                           // initial_user_params[0] = argc
                                           // initial_user_params[1] = argv, points to initial_user_params[2]
                                           // initial_user_params[2] = address of string for argv[0]
                                           // initial_user_params[3] = address of string for argv[1]
                                           //                           ...
  uint32 argc=0;           // running counter for number of arguments
  uint32 offset;           // Used in parsing command line argument strings, holds offset (in bytes) from
                           // beginning of the string to the current argument.
  uint32 initial_user_params_bytes;  // total number of bytes in initial user parameters array
  int newPage;


  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");
    exitsim ();	// 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");
    exitsim();
  }
  // 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.
  RestoreIntrs (intrs);

  // Copy the process name into the PCB.
  dstrcpy(pcb->name, name);

  //----------------------------------------------------------------------
  // This section initializes the memory for this process
  //----------------------------------------------------------------------
  // Allocate 1 page for system stack, 1 page for user stack (at top of
  // virtual address space), and 4 pages for user code and global data.
  //---------------------------------------------------------
  // STUDENT: allocate pages for a new process here.  The
  // code below assumes that you set the "stackframe" variable
  // equal to the last 4-byte-aligned address in physical page
  // for the system stack.
  //---------------------------------------------------------
  // Pages for code and global data and Heap
  pcb->npages = 5;
  for(i = 0; i < pcb->npages; i++) {
    newPage = MemoryAllocPage();
    if(newPage == MEM_FAIL) {
      printf ("FATAL: couldn't allocate memory - no free pages!\n");
      ProcessFreeResources (pcb);
      return PROCESS_FORK_FAIL;
    }
    pcb->pagetable[i] = MemorySetupPte (newPage);
  }
  // Initialize nodes in pool
  for (i = 1; i <= MEM_HEAP_MAX_NODES; i++) {
    pcb->htree_array[i].parent = NULL;
    pcb->htree_array[i].cleft = NULL;
    pcb->htree_array[i].crght = NULL;
    pcb->htree_array[i].index = i;
    pcb->htree_array[i].size = -1;
    pcb->htree_array[i].addr = -1;
    pcb->htree_array[i].inuse = 0;
    pcb->htree_array[i].order = -1;
  }
  // Initialize Heap tree
  pcb->htree_array[1].size = MEM_PAGESIZE;
  pcb->htree_array[1].addr = 0;
  pcb->htree_array[1].order = 7;
  // user stack
  pcb->npages += 1;
  newPage = MemoryAllocPage();
  if(newPage == MEM_FAIL) {
    printf ("FATAL: couldn't allocate user stack - no free pages!\n");
    ProcessFreeResources (pcb);
    return PROCESS_FORK_FAIL;
  }
  pcb->pagetable[MEM_ADDRESS_TO_PAGE(MEM_MAX_VIRTUAL_ADDRESS)] = MemorySetupPte (newPage);

  // for system stack
  newPage = MemoryAllocPage ();
  if(newPage == MEM_FAIL) {
    printf ("FATAL: couldn't allocate system stack - no free pages!\n");
    ProcessFreeResources (pcb);
    return PROCESS_FORK_FAIL;
  }

  pcb->sysStackArea = newPage * MEM_PAGESIZE;
  //----------------------------------------------------------------------
  // 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 + MEM_PAGESIZE - 4);
  dbprintf('p', "ProcessFork: SystemStack page=%d sysstackarea=0x%x\n", newPage, pcb->sysStackArea);

  // Now that the stack frame points at the bottom of the system stack memory area, we need to
  // move it up (decrement it) by one stack frame size because we're about to fill in the
  // initial stack frame that will be loaded for this PCB when it gets switched in by
  // ProcessSchedule the first time.
  stackframe -= PROCESS_STACK_FRAME_SIZE;

  // 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 * MEM_PAGESIZE);

  //----------------------------------------------------------------------
  // 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.
  dbprintf('p', "ProcessFork: stackframe = 0x%x\n", (int)stackframe);
  stackframe[PROCESS_STACK_PREV_FRAME] = 0;

  //----------------------------------------------------------------------
  // STUDENT: setup the PTBASE, PTBITS, and PTSIZE here on the current
  // stack frame.
  //----------------------------------------------------------------------
  // 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] = MEM_PAGE_TBL_SIZE;

  // 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] = (MEM_L1FIELD_FIRST_BITNUM << 16) + MEM_L1FIELD_FIRST_BITNUM;

  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 ('i', "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, (char *)(addr - n), n);
    }
    FsClose (fd);
    stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_USER;

    //----------------------------------------------------------------------
    // STUDENT: setup the initial user stack pointer here as the top
    // of the process's virtual address space (4-byte aligned).
    //----------------------------------------------------------------------
    stackframe[PROCESS_STACK_USER_STACKPOINTER] = MEM_MAX_VIRTUAL_ADDRESS - 3;
    dbprintf('p', "ProcessFork: UserStack usrsp=0x%x\n", stackframe[PROCESS_STACK_USER_STACKPOINTER]);

    //--------------------------------------------------------------------
    // This part is setting up the initial user stack with argc and argv.
    //--------------------------------------------------------------------

    // Copy the entire set of strings of command line parameters onto the user stack.
    // The "param" variable is a pointer to the start of a sequenial set of strings,
    // each ending with its own '\0' character.  The final "string" of the sequence
    // must be an empty string to indicate that the sequence is done.  Since we
    // can't figure out how long the set of strings actually is in this scenario,
    // we have to copy the maximum possible string length and parse things manually.
    stackframe[PROCESS_STACK_USER_STACKPOINTER] -= SIZE_ARG_BUFF;
    MemoryCopySystemToUser (pcb, (char *)param, (char *)stackframe[PROCESS_STACK_USER_STACKPOINTER], SIZE_ARG_BUFF);

    // Now that the main string is copied into the user space, we need to setup
    // argv as an array of pointers into that string, and argc as the total
    // number of arguments found in the string.  The first call to get_argument
    // should return 0 as the offset of the first string.
    offset = get_argument((char *)param);

    // Compute the addresses in user space of where each string for the command line arguments
    // begins.  These addresses make up the argv array.
    for(argc=0; argc < MAX_ARGS; argc++) {
      // The "+2" is because initial_user_params[0] is argc, and initial_user_params[1] is argv.
      // The address can be found as the current stack pointer (which points to the start of
      // the params list) plus the byte offset of the parameter from the beginning of
      // the list of parameters.
      initial_user_params[argc+2] = stackframe[PROCESS_STACK_USER_STACKPOINTER] + offset;
      offset = get_argument(NULL);
      if (offset == 0) {
        initial_user_params[argc+2+1] = 0; // last entry should be a null value
        break;
      }
    }
    // argc is currently the index of the last command line argument.  We need it to instead
    // be the number of command line arguments, so we increment it by 1.
    argc++;

    // Now argc can be stored properly
    initial_user_params[0] = argc;

    // Compute where initial_user_params[3] will be copied in user space as the
    // base of the array of string addresses.  The entire initial_user_params array
    // of uint32's will be copied onto the stack.  We'll move the stack pointer by
    // the necessary amount, then start copying the array.  Therefore, initial_user_params[3]
    // will reside at the current stack pointer value minus the number of command line
    // arguments (argc).
    initial_user_params[1] = stackframe[PROCESS_STACK_USER_STACKPOINTER] - (argc*sizeof(uint32));

    // Now copy the actual memory.  Remember that stacks grow down from the top of memory, so
    // we need to move the stack pointer first, then do the copy.  The "+2", as before, is
    // because initial_user_params[0] is argc, and initial_user_params[1] is argv.
    initial_user_params_bytes = (argc + 2) * sizeof(uint32);

    stackframe[PROCESS_STACK_USER_STACKPOINTER] -= initial_user_params_bytes;
    MemoryCopySystemToUser (pcb, (char *)initial_user_params, (char *)(stackframe[PROCESS_STACK_USER_STACKPOINTER]), initial_user_params_bytes);

    // Set the correct address at which to execute a user process.
    stackframe[PROCESS_STACK_IAR] = (uint32)start;

    // Flag this as a user process
    pcb->flags |= PROCESS_TYPE_USER;
  } else {
    // Don't worry about messing with any code here for kernel processes because
    // there aren't any kernel processes in DLXOS.

    // 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 + MEM_PAGESIZE;

    // 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 the PCB onto the run queue.
  intrs = DisableIntrs ();
  if ((pcb->l = AQueueAllocLink(pcb)) == NULL) {
    printf("FATAL ERROR: could not get link for forked PCB in ProcessFork!\n");
    exitsim();
  }
  if (AQueueInsertLast(&runQueue, pcb->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert link into runQueue in ProcessFork!\n");
    exitsim();
  }
  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).
  return (pcb - pcbs);
}
Esempio n. 19
0
int ProcessRealFork (PCB* ppcb) {
  PCB *cpcb;                // Holds pcb while we build it for this process.
  int intrs;               // Stores previous interrupt settings.
  int newPage;
  int i;
  uint32 *stackframe;


  intrs = DisableIntrs ();
  dbprintf ('I', "Old interrupt value was 0x%x.\n", intrs);
  dbprintf ('p', "Entering ProcessRealFork ppcb=%d\n", GetPidFromAddress(ppcb));
  // Get a free PCB for the new process
  if (AQueueEmpty(&freepcbs)) {
    printf ("FATAL error: no free processes!\n");
    exitsim (); // NEVER RETURNS!
  }
  cpcb = (PCB *)AQueueObject(AQueueFirst (&freepcbs));
  dbprintf ('p', "Got a link @ 0x%x\n", (int)(cpcb->l));
  if (AQueueRemove (&(cpcb->l)) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not remove link from freepcbsQueue in ProcessFork!\n");
    exitsim();
  }
  // This prevents someone else from grabbing this process
  ProcessSetStatus (cpcb, PROCESS_STATUS_RUNNABLE);
  
  // cpcb shares code and global data with ppcb
  for(i = 0; i < 4; i++) {
    ppcb->pagetable[i] |= MEM_PTE_READONLY;
    MemorySharePage(ppcb->pagetable[i]);
  }
  // user stack is also shared at first
  ppcb->pagetable[MEM_ADDRESS_TO_PAGE(MEM_MAX_VIRTUAL_ADDRESS)] |= MEM_PTE_READONLY; 
  MemorySharePage(ppcb->pagetable[MEM_ADDRESS_TO_PAGE(MEM_MAX_VIRTUAL_ADDRESS)]);

  // copy parent pcb to child pcb
  bcopy((char *)ppcb, (char *)cpcb, sizeof(PCB));
  // 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.
  RestoreIntrs (intrs);

  // for system stack
  newPage = MemoryAllocPage ();
  if(newPage == MEM_FAIL) {
    printf ("FATAL: couldn't allocate system stack - no free pages!\n");
    ProcessFreeResources (cpcb);
    return PROCESS_FORK_FAIL;
  }
  cpcb->sysStackArea = newPage * MEM_PAGESIZE;
  // copy system stack from ppcb to cpcb
  bcopy((char *)(ppcb->sysStackArea), (char *)(cpcb->sysStackArea), MEM_PAGESIZE);
  dbprintf('p', "ProcessRealFork: SystemStack page=%d sysstackarea=0x%x\n", newPage, cpcb->sysStackArea);
  // printf("ProcessRealFork: parent_sysstackarea=0x%x child_sysstackarea=0x%x\n", ppcb->sysStackArea, cpcb->sysStackArea);

  //----------------------------------------------------------------------
  // 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 *)(cpcb->sysStackArea + MEM_PAGESIZE - 4);

  // Now that the stack frame points at the bottom of the system stack memory area, we need to
  // move it up (decrement it) by one stack frame size because we're about to fill in the
  // initial stack frame that will be loaded for this PCB when it gets switched in by
  // ProcessSchedule the first time.
  stackframe -= PROCESS_STACK_FRAME_SIZE;

  // The system stack pointer is set to the base of the current interrupt stack frame.
  cpcb->sysStackPtr = stackframe;
  // The current stack frame pointer is set to the same thing.
  cpcb->currentSavedFrame = stackframe;

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

  //----------------------------------------------------------------------
  // STUDENT: setup the PTBASE, PTBITS, and PTSIZE here on the current
  // stack frame.
  //----------------------------------------------------------------------
  // 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)(&(cpcb->pagetable[0]));

  // Place the PCB onto the run queue.
  intrs = DisableIntrs ();
  if ((cpcb->l = AQueueAllocLink(cpcb)) == NULL) {
    printf("FATAL ERROR: could not get link for forked PCB in ProcessFork!\n");
    exitsim();
  }
  if (AQueueInsertLast(&runQueue, cpcb->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert link into runQueue in ProcessFork!\n");
    exitsim();
  }
  RestoreIntrs (intrs);
  ProcessSetResult(cpcb, 0);
  ProcessSetResult(ppcb, GetPidFromAddress(cpcb));
  
  // TEST PRINTS
  printf("\nIn ProcessRealFork:\n");
  printf("----- Page table of parent process PID:%d -----\n", GetPidFromAddress(ppcb));
  ProcessForkTestPrints(ppcb);
  printf("\n----- Page table of child process PID: %d -----\n", GetPidFromAddress(cpcb));
  ProcessForkTestPrints(cpcb);

  dbprintf ('p', "Leaving ProcessRealFork cpcbid=%d\n", GetPidFromAddress(cpcb));
  return PROCESS_FORK_SUCCESS;
}
Esempio n. 20
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, int p_nice, int p_info,char *name, int isUser)
{
  int		i, j, fd, n;
  Link		*l;
  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;


  intrs = DisableIntrs ();
  dbprintf ('I', "Old interrupt value was 0x%x.\n", intrs);
  dbprintf ('p', "Entering ProcessFork args=0x%x 0x%x %s %d\n", func,
	    param, name, isUser);
  // Get a free PCB for the new process
  if (QueueEmpty (&freepcbs)) {
    printf ("FATAL error: no free processes!\n");
    exitsim ();	// NEVER RETURNS!
  }
  l = QueueFirst (&freepcbs);
  dbprintf ('p', "Got a link @ 0x%x\n", l);
  QueueRemove (l);
  pcb = (PCB *)(l->object);
  // 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", CurrentIntrs());
  RestoreIntrs (intrs);
  dbprintf ('I', "New interrupt value is 0x%x.\n", CurrentIntrs());

  // Copy the process name into the PCB.
  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");
    exitsim ();	// NEVER RETURNS!
  }
  pcb->pagetable[0] = MemorySetupPte (newPage);
  newPage = MemoryAllocPage ();
  if (newPage == 0) {
    printf ("bFATAL: couldn't allocate system stack - no free pages!\n");
    exitsim ();	// NEVER RETURNS!
  }
  pcb->sysStackArea = newPage * MEMORY_PAGE_SIZE;


  //---------------------------------------
  // Lab3: initialized pcb member for your scheduling algorithm here
  //--------------------------------------
  pcb->p_nice = p_nice < 0 ? 0 : p_nice;
  pcb->p_info = p_info;
  pcb->sleeptime = my_timer_get();
  pcb->estcpu = 0;
  pcb->prio = PUSER;
  pcb->processed = 1 - processedFlag;
  pcb->estcputime = 0;
  //----------------------------------------------------------------------
  // 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",
	    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 the PCB onto the run queue.
  intrs = DisableIntrs ();
  QueueInsertLast (&runQueue[pcb->prio/4], l);
  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",
	      pcb, 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).
  return (pcb - pcbs);
}