pd_entry* vmmngr_pdirectory_lookup_entry(pdirectory* p, virtual_addr addr)
{
	if (p)
		return &p->entries[PAGE_DIR_INDEX(addr)];

	set_last_error(EINVAL, VMEM_BAD_ARGUMENT, EO_VMMNGR);
	return 0;
}
Esempio n. 2
0
File: vm.c Progetto: jimlar/fusion
void do_page_fault (process_t     *proc,
		    unsigned int   linear_addr,
		    long           error_code)
{
  page_frame_t       *new_page, *page_frame;
  unsigned int        phys_frame_addr;
  pagetable_entry_t  *pte;
  int                 pf_ok;


  //Only handle usermode writes to present pages (not present ones later (pagein))
  //if ((error_code & PAGE_FAULT_P) &&
  //    (error_code & PAGE_FAULT_RW) &&
  //    (error_code & PAGE_FAULT_US))
  
  if (error_code & PAGE_FAULT_P) {
    
    //
    // CHECK IF WE REALLY SHOULD COPY THIS
    //  (with vm_blocks)
    //

    pf_ok = 0;

    //Only write pagefaults handled
    if (error_code & PAGE_FAULT_RW) {
      
      if ((linear_addr >= proc->vm_data.vm_start) &&
	  (linear_addr < proc->vm_data.vm_end) &&
	  (proc->vm_data.vm_flags & VM_READWRITE))
	pf_ok = 1;
      
      if ((linear_addr >= proc->vm_stack.vm_start) &&
	  (linear_addr < proc->vm_stack.vm_end) &&
	  (proc->vm_stack.vm_flags & VM_READWRITE))
	pf_ok = 1;
      
      if ((linear_addr >= proc->vm_kernel_stack.vm_start) &&
	  (linear_addr < proc->vm_kernel_stack.vm_end) &&
	  (proc->vm_kernel_stack.vm_flags & VM_READWRITE))
	pf_ok = 1;
    }


    if (!pf_ok)
    {
      printf ("*real* page fault (out of bounds), should terminate task!\n");
      printf ("present=%s, write=%s, usermode=%s, address=0x%x, dir=0x%x\n",
	      ((int) error_code & PAGE_FAULT_P) ? "true" : "false",
	      ((int) error_code & PAGE_FAULT_RW) ? "true" : "false",
	      ((int) error_code & PAGE_FAULT_US) ? "true" : "false",
	      linear_addr,
	      (int) (proc->tss.cr3));
      
      printf ("data start 0x%x, data end 0x%x, flags 0x%x\n",
	      (int) proc->vm_data.vm_start,
	      (int) proc->vm_data.vm_end,
	      (int) proc->vm_data.vm_flags);

      printf ("stack start 0x%x, stack end 0x%x, flags 0x%x\n",
	      (int) proc->vm_stack.vm_start,
	      (int) proc->vm_stack.vm_end,
	      (int) proc->vm_stack.vm_flags);

      while(1);
    }


    //Get dir
    pte = (pagetable_entry_t *) proc->tss.cr3;

    //Get table from dir
    pte = (pagetable_entry_t *) PTE_TO_PHYSICAL(pte[PAGE_DIR_INDEX(linear_addr)]);
    
    //Get page from table
    phys_frame_addr = PTE_TO_PHYSICAL(pte[PAGE_TABLE_INDEX(linear_addr)]);
 
    //Check use count of this page frame
    page_frame = &page_frames[PHYS_TO_FRAME_NR (phys_frame_addr)];
    
    if (page_frame->count > 1)
    {
      //Page in use by others, we need to copy
      new_page = get_free_page();

      if (new_page == NULL)
	panic ("Can't COW, no free pages!");

      //Copy page
      //printf ("COW(copy, 0x%x->0x%x)\n", phys_frame_addr, new_page->page_frame_nr * PAGE_SIZE);
 
      copy_page (phys_frame_addr, new_page->page_frame_nr * PAGE_SIZE);

      //Remap pagetable
      map_page (proc, new_page->page_frame_nr * PAGE_SIZE, 
		linear_addr & PHYS_PAGE_MASK, PAGE_PRESENT | PAGE_USER | PAGE_WRITEABLE);
    
      //Decrease use count
      page_frame->count--;

    } else if (page_frame->count == 1)
    {
      //The page is not in use by others, just remap
      //printf ("COW(remap, 0x%x)\n", linear_addr);
 
      //Remap pagetable
      map_page (proc, phys_frame_addr, 
		linear_addr & PHYS_PAGE_MASK, PAGE_PRESENT | PAGE_USER | PAGE_WRITEABLE);
  
    } else
    {
      printf ("Page frame has invalid use count!\n");
      while (1);
    }

    //Schedule next process
    schedule();

  } else {

    printf ("*real* page fault (page not present), should terminate task!\n");
 
    printf ("present=%s, write=%s, usermode=%s, address=0x%x, dir=0x%x\n",
	    ((int) error_code & PAGE_FAULT_P) ? "true" : "false",
	    ((int) error_code & PAGE_FAULT_RW) ? "true" : "false",
	    ((int) error_code & PAGE_FAULT_US) ? "true" : "false",
	    linear_addr,
	    (int) (proc->tss.cr3));
 
    printf ("data start 0x%x, data end 0x%x, flags 0x%x\n",
	      (int) proc->vm_data.vm_start,
	      (int) proc->vm_data.vm_end,
	      (int) proc->vm_data.vm_flags);

    printf ("stack start 0x%x, stack end 0x%x, flags 0x%x\n",
	    (int) proc->vm_stack.vm_start,
	    (int) proc->vm_stack.vm_end,
	    (int) proc->vm_stack.vm_flags);

    while(1);
  }
}