示例#1
0
/* This function make perfect mapping from kernel virtual memory phyical memory 
 */
void init_kernel_page_table() {
    kernel_page_table = (pte_t*) malloc(sizeof(pte_t) * GET_PAGE_NUMBER(VMEM_0_SIZE));
    
    // For text segment mapping
    TracePrintf(0, "Text Start=%p, End=%p\n", kernel_memory.text_low, kernel_memory.data_low);
    write_kernel_pte(kernel_memory.text_low, kernel_memory.data_low
            , _VALID, PROT_READ | PROT_EXEC);
    
    // For data segment mapping
    TracePrintf(0, "Data Start=%p, End=%p\n", kernel_memory.data_low, kernel_memory.brk_low);
    write_kernel_pte(kernel_memory.data_low, kernel_memory.brk_low
            , _VALID, PROT_READ | PROT_WRITE);
    
    // For stack segment mapping, noted that stack space is reserved even if it is not used
    TracePrintf(0, "Stack Start=%p, End=%p\n", KERNEL_STACK_BASE, KERNEL_STACK_LIMIT);
    write_kernel_pte(KERNEL_STACK_BASE, KERNEL_STACK_LIMIT
            , _VALID, PROT_READ | PROT_WRITE);
    
    int i;
    // Add free pages between heap and stack
    int start_pfn = GET_PAGE_NUMBER(UP_TO_PAGE(kernel_memory.brk_high));
    int end_pfn = GET_PAGE_NUMBER(DOWN_TO_PAGE(KERNEL_STACK_BASE));
    for(i = start_pfn; i < end_pfn; i++) {
        add_tail_available_frame(i);
    }
    // Add free pages above kernel space
    start_pfn = GET_PAGE_NUMBER(UP_TO_PAGE(VMEM_0_LIMIT));
    end_pfn = GET_PAGE_NUMBER(DOWN_TO_PAGE(PMEM_BASE)) + PAGE_SIZE;
    for(i = start_pfn; i < end_pfn; i++) {
        add_tail_available_frame(i);
    }
}
extern void trapMemory(ExceptionStackFrame *exceptionStackFrame)
{
	TracePrintf(512, "trapMemory: vector(%d), code(%d), addr(%d), psr(%d), pc(%d), sp(%d), regs(%s)\n",
	      exceptionStackFrame->vector, exceptionStackFrame->code, exceptionStackFrame->addr,
	      exceptionStackFrame->psr, exceptionStackFrame->pc, exceptionStackFrame->sp,
	      exceptionStackFrame->regs);

	if( exceptionStackFrame -> addr > current -> stack_brk )
	{
		 TracePrintf(0, "Trap Memory Error: addr: %d is large than stack_brk: %d\n", exceptionStackFrame -> addr, current -> stack_brk);
		 //Exit;
	}

	if( exceptionStackFrame -> addr < UP_TO_PAGE(current -> heap_brk) + PAGESIZE )
	{
		 TracePrintf(0, "Trap Memory Error: addr: %d is smaller than heap_brk: %d\n", exceptionStackFrame -> addr, current -> heap_brk);
		 //Exit;
	}

	long userTablePTE;	
	TracePrintf(510, "Moving user stack down to address: %d (%d)\n", exceptionStackFrame -> addr, (long)exceptionStackFrame -> addr >> PAGESHIFT);
	for (userTablePTE = (DOWN_TO_PAGE(exceptionStackFrame -> addr)); userTablePTE < (DOWN_TO_PAGE(current -> stack_brk)); userTablePTE += PAGESIZE)
	{
		unsigned int i = ((userTablePTE) >> PAGESHIFT) % PAGE_TABLE_LEN;
		UserPageTable[i].valid = 1;
		UserPageTable[i].uprot = PROT_NONE;
		UserPageTable[i].kprot = PROT_READ | PROT_WRITE;
		/* Need to change the pfn here */
		UserPageTable[i].pfn = allocatePhysicalPage();
		TracePrintf(250, "Allocate physical pages for user process: PID(%d), VPN(%d), PFN(%d).\n", current -> PID, i, UserPageTable[i].pfn);
	}
}
extern int KernelBrk(void *addr, struct PCBNode *pcb)
{
	TracePrintf(256, "Brk: addr(%d)\n", addr);

	//check if the addr is illegal
	if(addr < MEM_INVALID_SIZE)
	{
		  TracePrintf(0, "Error in KernelBrk: Trying to set the brk below MEM_INVALID_SIZE.\n");
		  //Exit the program.
	}

	if(addr > DOWN_TO_PAGE(pcb -> stack_brk) - PAGESIZE)
	{
		  TracePrintf(0, "Error in KernelBrk: Trying to set the brk inside or above the red zone.\n");
	}

    unsigned int userTablePTE;
    //Only allocate for entire pages??
    unsigned int gap = (UP_TO_PAGE(addr)-UP_TO_PAGE(pcb -> heap_brk));
    if(gap>0)
	{
		TracePrintf(250, "Moving user brk up to address: %d (%d)\n", addr, (long)addr >> PAGESHIFT);
		for (userTablePTE = (UP_TO_PAGE(pcb -> heap_brk)); userTablePTE < (UP_TO_PAGE(addr)); userTablePTE += PAGESIZE)
		{
			unsigned int i = ((userTablePTE) >> PAGESHIFT) % PAGE_TABLE_LEN;
			UserPageTable[i].valid = 1;
			UserPageTable[i].uprot = PROT_NONE;
			UserPageTable[i].kprot = PROT_READ | PROT_WRITE;
			/* Need to change the pfn here */
			UserPageTable[i].pfn = allocatePhysicalPage();
			TracePrintf(250, "Allocate physical pages for user process: PID(%d), VPN(%d), PFN(%d).\n", pcb -> PID, i, UserPageTable[i].pfn);
		}
	}
示例#4
0
#include "dlist.h"
#include "proc.h"
#include "load.h"
#include "common.h"
#include "tty.h"

trap_handler interrupt_vector[TRAP_VECTOR_SIZE];

void SetKernelData _PARAMS((void *_Kernel_Data_Start, void *_Kernel_Data_End)) {
    // Set kernel vm boundaries, noted that most of the *_high is implicitly represented by other's *_low 
    kernel_memory.text_low     = (unsigned int)VMEM_BASE;
    kernel_memory.data_low     = (unsigned int)_Kernel_Data_Start;
    kernel_memory.brk_low      = (unsigned int)_Kernel_Data_End;
    kernel_memory.brk_high     = (unsigned int)_Kernel_Data_End;
    kernel_memory.stack_low    = (unsigned int)KERNEL_STACK_BASE;
    kernel_memory.swap_addr    = (unsigned int)DOWN_TO_PAGE(KERNEL_STACK_BASE) - PAGESIZE;
}

/* 
 * Initialize trap vector
 */
void init_trap_vector() {
    interrupt_vector[TRAP_KERNEL] = trap_kernel_handler;
    interrupt_vector[TRAP_CLOCK] = trap_clock_handler;
    interrupt_vector[TRAP_ILLEGAL] = trap_illegal_handler;
    interrupt_vector[TRAP_MEMORY] = trap_memory_handler;
    interrupt_vector[TRAP_MATH] = trap_math_handler;
    interrupt_vector[TRAP_TTY_RECEIVE] = trap_tty_receive_handler;
    interrupt_vector[TRAP_TTY_TRANSMIT] = trap_tty_transmit_handler;
    interrupt_vector[TRAP_DISK] = trap_disk_handler;
}
示例#5
0
/*
 *  Load a program into an existing address space.  The program comes from
 *  the Linux file named "name", and its arguments come from the array at
 *  "args", which is in standard argv format.  The argument "proc" points
 *  to the process or PCB structure for the process into which the program
 *  is to be loaded. 
 */
int
LoadProgram(char *name, char *args[], PCB *proc) 
//==>> Declare the argument "proc" to be a pointer to your PCB or
//==>> process descriptor data structure.  We assume you have a member
//==>> of this structure used to hold the cpu context 
//==>> for the process holding the new program.  
{
  int fd;
  int (*entry)();
  struct load_info li;
  int i;
  char *cp;
  char **cpp;
  char *cp2;
  int argcount;
  int size;
  int text_pg1;
  int data_pg1;
  int data_npg;
  int stack_npg;
  long segment_size;
  char *argbuf;

  
  /*
   * Open the executable file 
   */
  if ((fd = open(name, O_RDONLY)) < 0) {
    TracePrintf(0, "LoadProgram: can't open file '%s'\n", name);
    return FAILURE;
  }

  if (LoadInfo(fd, &li) != LI_NO_ERROR) {
    TracePrintf(0, "LoadProgram: '%s' not in Yalnix format\n", name);
    close(fd);
    return FAILURE;
  }

  if (li.entry < VMEM_1_BASE) {
    TracePrintf(0, "LoadProgram: '%s' not linked for Yalnix\n", name);
    close(fd);
    return FAILURE;
  }
  /*
   * Figure out in what region 1 page the different program sections
   * start and end
   */
  text_pg1 = (li.t_vaddr - VMEM_1_BASE) >> PAGESHIFT;
  data_pg1 = (li.id_vaddr - VMEM_1_BASE) >> PAGESHIFT;
  data_npg = li.id_npg + li.ud_npg;

  /*
   * Store end of bss as UserDataEnd and as user brk
   */
  proc->userDataEnd = (void *) UP_TO_PAGE(li.ud_end);
  proc->brk = proc->userDataEnd + 1;
  /*
   *  Figure out how many bytes are needed to hold the arguments on
   *  the new stack that we are building.  Also count the number of
   *  arguments, to become the argc that the new "main" gets called with.
   */
  size = 0;
  for (i = 0; args[i] != NULL; i++) {
    TracePrintf(3, "counting arg %d = '%s'\n", i, args[i]);
    size += strlen(args[i]) + 1;
  }
  argcount = i;

 TracePrintf(2, "LoadProgram: argsize %d, argcount %d\n", size, argcount);
  
  /*
   *  The arguments will get copied starting at "cp", and the argv
   *  pointers to the arguments (and the argc value) will get built
   *  starting at "cpp".  The value for "cpp" is computed by subtracting
   *  off space for the number of arguments (plus 3, for the argc value,
   *  a NULL pointer terminating the argv pointers, and a NULL pointer
   *  terminating the envp pointers) times the size of each,
   *  and then rounding the value *down* to a double-word boundary.
   */
  cp = ((char *)VMEM_1_LIMIT) - size;

  cpp = (char **)
    (((int)cp - 
      ((argcount + 3 + POST_ARGV_NULL_SPACE) *sizeof (void *))) 
     & ~7);

  /*
   * Compute the new stack pointer, leaving INITIAL_STACK_FRAME_SIZE bytes
   * reserved above the stack pointer, before the arguments.
   */
  cp2 = (caddr_t)cpp - INITIAL_STACK_FRAME_SIZE;



  TracePrintf(1, "prog_size %d, text %d data %d bss %d pages\n",
	      li.t_npg + data_npg, li.t_npg, li.id_npg, li.ud_npg);


  /* 
   * Compute how many pages we need for the stack */
  stack_npg = (VMEM_1_LIMIT - DOWN_TO_PAGE(cp2)) >> PAGESHIFT;

  TracePrintf(11, "LoadProgram: heap_size %d, stack_size %d\n",
	      li.t_npg + data_npg, stack_npg);

  /*
   * Store stack base in pcb
   */
  proc->stackBase = (void *) DOWN_TO_PAGE(cp2);

  /*
   * If free frames are not enough, return FAILURE
   */
  int page_in_use = (Page(proc->brk) - MAX_PT_LEN) + (NUM_VPN - Page(proc->stackBase));
  if (page_in_use > FreeFrameCount) {
	return FAILURE;
  }

  /* leave at least one page between heap and stack */
  if (stack_npg + data_pg1 + data_npg >= MAX_PT_LEN) {
    close(fd);
    return FAILURE;
  }

  /*
   * This completes all the checks before we proceed to actually load
   * the new program.  From this point on, we are committed to either
   * loading succesfully or killing the process.
   */

  /*
   * Set the new stack pointer value in the process's exception frame.
   */

//==>> Here you replace your data structure proc
//==>> proc->context.sp = cp2;
  proc->uctxt.sp = cp2; 

  /*
   * Now save the arguments in a separate buffer in region 0, since
   * we are about to blow away all of region 1.
   */
  cp2 = argbuf = (char *)malloc(size);
//==>> You should perhaps check that malloc returned valid space
  if (NULL == cp2) {
    TracePrintf(0, "Malloc returned NULL when saving arguments in a separate buffer in region 0.\n");
    close(fd);
    return FAILURE;
  }

  for (i = 0; args[i] != NULL; i++) {
    TracePrintf(3, "saving arg %d = '%s'\n", i, args[i]);
    strcpy(cp2, args[i]);
    cp2 += strlen(cp2) + 1;
  }

  /*
   * Set up the page tables for the process so that we can read the
   * program into memory.  Get the right number of physical pages
   * allocated, and set them all to writable.
   */

//==>> Throw away the old region 1 virtual address space of the
//==>> curent process by freeing
//==>> all physical pages currently mapped to region 1, and setting all 
//==>> region 1 PTEs to invalid.
//==>> Since the currently active address space will be overwritten
//==>> by the new program, it is just as easy to free all the physical
//==>> pages currently mapped to region 1 and allocate afresh all the
//==>> pages the new program needs, than to keep track of
//==>> how many pages the new process needs and allocate or
//==>> deallocate a few pages to fit the size of memory to the requirements
//==>> of the new process.

  disablePTE(MAX_PT_LEN, NUM_VPN);

//==>> Allocate "li.t_npg" physical pages and map them starting at
//==>> the "text_pg1" page in region 1 address space.  
//==>> These pages should be marked valid, with a protection of 
//==>> (PROT_READ | PROT_WRITE).

  enablePTE(MAX_PT_LEN + text_pg1, MAX_PT_LEN + text_pg1 + li.t_npg, PROT_READ | PROT_WRITE);

//==>> Allocate "data_npg" physical pages and map them starting at
//==>> the  "data_pg1" in region 1 address space.  
//==>> These pages should be marked valid, with a protection of 
//==>> (PROT_READ | PROT_WRITE).

  enablePTE(MAX_PT_LEN + data_pg1, MAX_PT_LEN + data_pg1 + data_npg, PROT_READ | PROT_WRITE);

  /*
   * Allocate memory for the user stack too.
   */
//==>> Allocate "stack_npg" physical pages and map them to the top
//==>> of the region 1 virtual address space.
//==>> These pages should be marked valid, with a
//==>> protection of (PROT_READ | PROT_WRITE).

  enablePTE(NUM_VPN - stack_npg, NUM_VPN, PROT_READ | PROT_WRITE);

  /*
   * All pages for the new address space are now in the page table.  
   * But they are not yet in the TLB, remember!
   */
  /*
   * Read the text from the file into memory.
   */
  lseek(fd, li.t_faddr, SEEK_SET);
  segment_size = li.t_npg << PAGESHIFT;
  if (read(fd, (void *) li.t_vaddr, segment_size) != segment_size) {
    close(fd);
//==>> KILL is not defined anywhere: it is an error code distinct
//==>> from ERROR because it requires different action in the caller.
//==>> Since this error code is internal to your kernel, you get to define it.
    return KILL;
  }
  /*
   * Read the data from the file into memory.
   */
  lseek(fd, li.id_faddr, 0);
  segment_size = li.id_npg << PAGESHIFT;

  if (read(fd, (void *) li.id_vaddr, segment_size) != segment_size) {
    close(fd);
    return KILL;
  }

  /*
   * Now set the page table entries for the program text to be readable
   * and executable, but not writable.
   */

//==>> Change the protection on the "li.t_npg" pages starting at
//==>> virtual address VMEM_1_BASE + (text_pg1 << PAGESHIFT).  Note
//==>> that these pages will have indices starting at text_pg1 in 
//==>> the page table for region 1.
//==>> The new protection should be (PROT_READ | PROT_EXEC).
//==>> If any of these page table entries is also in the TLB, either
//==>> invalidate their entries in the TLB or write the updated entries
//==>> into the TLB.  It's nice for the TLB and the page tables to remain
//==>> consistent.

  for (i = 0; i < li.t_npg; i++) {
    changePTE(MAX_PT_LEN + text_pg1 + i, PROT_READ | PROT_EXEC, -1);
  }

  close(fd);			/* we've read it all now */

  /*
   * Zero out the uninitialized data area
   */
  bzero(li.id_end, li.ud_end - li.id_end);

  /*
   * Set the entry point in the exception frame.
   */
//==>> Here you should put your data structure (PCB or process)
//==>> proc->context.pc = (caddr_t) li.entry;
  proc->uctxt.pc = (caddr_t) li.entry;
  /*
   * Now, finally, build the argument list on the new stack.
   */

#ifdef LINUX
  memset(cpp, 0x00, VMEM_1_LIMIT - ((int) cpp));
#endif



  *cpp++ = (char *)argcount;		/* the first value at cpp is argc */
  cp2 = argbuf;
  for (i = 0; i < argcount; i++) {      /* copy each argument and set argv */
    *cpp++ = cp;
    strcpy(cp, cp2);
    cp += strlen(cp) + 1;
    cp2 += strlen(cp2) + 1;
  }
  free(argbuf);
  *cpp++ = NULL;			/* the last argv is a NULL pointer */
  *cpp++ = NULL;			/* a NULL pointer for an empty envp */

  return SUCCESS;
}