214 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* This file contains memory management routines for RS.
 | 
						|
 *
 | 
						|
 * Changes:
 | 
						|
 *   Nov 22, 2009: Created    (Cristiano Giuffrida)
 | 
						|
 */
 | 
						|
 | 
						|
#include "inc.h"
 | 
						|
#include "kernel/const.h"
 | 
						|
#include "kernel/type.h"
 | 
						|
#include "kernel/proc.h"
 | 
						|
 | 
						|
EXTERN char *_brksize;
 | 
						|
 | 
						|
PRIVATE char * _rs_startbrksize = NULL;
 | 
						|
PRIVATE char * _rs_endbrksize = NULL;
 | 
						|
 | 
						|
#define munmap _munmap
 | 
						|
#define munmap_text _munmap_text
 | 
						|
#include <sys/mman.h>
 | 
						|
#undef munmap
 | 
						|
#undef munmap_text
 | 
						|
 | 
						|
PUBLIC int unmap_ok = 0;
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *			      check_mem_available			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PRIVATE int check_mem_available(char *new_brksize)
 | 
						|
{
 | 
						|
/* Check if enough memory is available to grow break size. */
 | 
						|
  register struct mem_map *mem_sp, *mem_dp;
 | 
						|
  vir_clicks sp_click, gap_base, sp_lower;
 | 
						|
  int s;
 | 
						|
  long base_of_stack, sp_delta;	/* longs avoid certain problems */
 | 
						|
  vir_bytes sp;
 | 
						|
  struct proc proc;
 | 
						|
  vir_clicks data_clicks;
 | 
						|
 | 
						|
  /* Get stack pointer and pointers to data/stack segment maps. */
 | 
						|
  if ((s=sys_getproc(&proc, SELF)) != OK) {
 | 
						|
      return(s);
 | 
						|
  }
 | 
						|
  sp = proc.p_reg.sp;                    /* stack pointer */
 | 
						|
  mem_dp = &proc.p_memmap[D];            /* pointer to data segment map */
 | 
						|
  mem_sp = &proc.p_memmap[S];            /* pointer to stack segment map */
 | 
						|
 | 
						|
  /* Compute how many clicks the data segment is to become. */
 | 
						|
  data_clicks = (vir_clicks) (CLICK_CEIL(new_brksize) >> CLICK_SHIFT)
 | 
						|
	- mem_dp->mem_vir;
 | 
						|
 | 
						|
  /* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */
 | 
						|
  base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len;
 | 
						|
  sp_click = sp >> CLICK_SHIFT;	/* click containing sp */
 | 
						|
  if (sp_click >= base_of_stack)
 | 
						|
  {
 | 
						|
	return(ENOMEM);	/* sp too high */
 | 
						|
  }
 | 
						|
 | 
						|
  /* Compute size of gap between stack and data segments. */
 | 
						|
  sp_delta = (long) mem_sp->mem_vir - (long) sp_click;
 | 
						|
  sp_lower = (sp_delta > 0 ? sp_click : mem_sp->mem_vir);
 | 
						|
 | 
						|
  /* Add a safety margin for future stack growth. Impossible to do right. */
 | 
						|
#define SAFETY_BYTES  (384 * sizeof(char *))
 | 
						|
#define SAFETY_CLICKS ((vir_clicks) (CLICK_CEIL(SAFETY_BYTES) >> CLICK_SHIFT))
 | 
						|
  gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
 | 
						|
  if (sp_lower < gap_base)
 | 
						|
  {
 | 
						|
	return(ENOMEM);	/* data and stack collided */
 | 
						|
  }
 | 
						|
 | 
						|
  return(OK);
 | 
						|
}
 | 
						|
  
 | 
						|
/*===========================================================================*
 | 
						|
 *				rs_startup_sbrk				     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC void* rs_startup_sbrk(size)
 | 
						|
size_t size;                    /* the size to grow */
 | 
						|
{
 | 
						|
/* RS's own sbrk() used at startup. */
 | 
						|
  void* addr;
 | 
						|
  char* new_brksize;
 | 
						|
 | 
						|
  /* Check input for non-positive size or size overflows. */
 | 
						|
  new_brksize = _brksize + size;
 | 
						|
  if (size <= 0 || new_brksize < _brksize) {
 | 
						|
      return( (char *) -1);
 | 
						|
  }
 | 
						|
 | 
						|
  /* Check if enough memory is available. */
 | 
						|
  if(check_mem_available(new_brksize) != OK) {
 | 
						|
      return( (char *) -1);
 | 
						|
  }
 | 
						|
  
 | 
						|
  /* Save initial break size. */
 | 
						|
  if(_rs_startbrksize == NULL) {
 | 
						|
      _rs_startbrksize = _brksize;
 | 
						|
  }
 | 
						|
  
 | 
						|
  /* Set address and adjust break size. */
 | 
						|
  addr = _brksize;
 | 
						|
  _brksize = new_brksize;
 | 
						|
  _rs_endbrksize = _brksize;
 | 
						|
 | 
						|
  return addr;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				rs_startup_sbrk_synch			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC void* rs_startup_sbrk_synch(size)
 | 
						|
size_t size;                    /* the size to grow */
 | 
						|
{
 | 
						|
/* Synchronize RS's own sbrk() with the rest of the system right after
 | 
						|
 * startup. We use the original sbrk() here.
 | 
						|
 */
 | 
						|
  void* addr;
 | 
						|
 | 
						|
  /* Restore original break size. */
 | 
						|
  _brksize = _rs_startbrksize;
 | 
						|
 | 
						|
  /* Call original sbrk() and see if we observe the same effect. */
 | 
						|
  addr = (void*)sbrk(size);
 | 
						|
  if(_rs_startbrksize != addr) {
 | 
						|
      printf("Unable to synch rs_startup_sbrk() and sbrk(): addr 0x%x!=0x%x\n",
 | 
						|
          (int) _rs_startbrksize, (int) addr);
 | 
						|
      return( (char *) -1);
 | 
						|
  }
 | 
						|
  if(_rs_endbrksize != _brksize) {
 | 
						|
      printf("Unable to synch rs_startup_sbrk() and sbrk(): size 0x%x!=0x%x\n",
 | 
						|
         (int) _rs_endbrksize, (int) _brksize);
 | 
						|
      return( (char *) -1);
 | 
						|
  }
 | 
						|
 | 
						|
  return addr;
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				rs_startup_segcopy			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int rs_startup_segcopy(src_proc, src_seg, dst_seg, dst_vir, bytes)
 | 
						|
endpoint_t src_proc;            /* source process */
 | 
						|
int src_seg;                    /* source memory segment */
 | 
						|
int dst_seg;                    /* destination memory segment */
 | 
						|
vir_bytes dst_vir;              /* destination virtual address */
 | 
						|
phys_bytes bytes;               /* how many bytes */
 | 
						|
{
 | 
						|
/* Copy a process's T, D, S segment to RS's address space. Used at startup. */
 | 
						|
  struct proc src_p, dst_p;
 | 
						|
  phys_bytes src_phys, dst_phys;
 | 
						|
  int s;
 | 
						|
 | 
						|
  /* Check input. */
 | 
						|
  if((src_seg != T && src_seg != D && src_seg != S) || bytes <= 0) {
 | 
						|
      return EINVAL;
 | 
						|
  }
 | 
						|
 | 
						|
  /* We don't override normal behavior when not copying to our data segment. */
 | 
						|
  if(dst_seg != D) {
 | 
						|
      s = sys_vircopy(src_proc, src_seg, 0, SELF, dst_seg, dst_vir, bytes);
 | 
						|
      return(s);
 | 
						|
  }
 | 
						|
 | 
						|
  /* Get kernel process slot for both source and destination. */
 | 
						|
  if ((s=sys_getproc(&src_p, src_proc)) != OK) {
 | 
						|
      return(s);
 | 
						|
  }
 | 
						|
  if ((s=sys_getproc(&dst_p, SELF)) != OK) {
 | 
						|
      return(s);
 | 
						|
  }
 | 
						|
 | 
						|
  /* Map source address to physical address. */
 | 
						|
  src_phys = (phys_bytes) src_p.p_memmap[src_seg].mem_phys << CLICK_SHIFT;
 | 
						|
 | 
						|
  /* Check if destination address is out of bounds or overflows. */
 | 
						|
  if(dst_vir+bytes > (vir_bytes)_rs_endbrksize
 | 
						|
      || dst_vir < (vir_bytes)_rs_startbrksize || dst_vir+bytes < dst_vir) {
 | 
						|
      return EFAULT;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Map destination address to physical address. */
 | 
						|
  dst_phys = (phys_bytes) dst_p.p_memmap[D].mem_phys << CLICK_SHIFT;
 | 
						|
  dst_phys += dst_vir - (dst_p.p_memmap[D].mem_vir << CLICK_SHIFT);
 | 
						|
 | 
						|
  /* Make a physical copy for the requested data. */
 | 
						|
  s = sys_abscopy(src_phys, dst_phys, bytes);
 | 
						|
 | 
						|
  return(s);
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				    munmap	            		     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int munmap(void *addrstart, vir_bytes len)
 | 
						|
{
 | 
						|
  if(!unmap_ok) 
 | 
						|
      return ENOSYS;
 | 
						|
 | 
						|
  return _munmap(addrstart, len);
 | 
						|
}
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *			         munmap_text	            		     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int munmap_text(void *addrstart, vir_bytes len)
 | 
						|
{
 | 
						|
  if(!unmap_ok)
 | 
						|
      return ENOSYS;
 | 
						|
 | 
						|
  return _munmap_text(addrstart, len);
 | 
						|
}
 | 
						|
 |