Skip to content
Snippets Groups Projects
NetBSD-os.c 5.37 KiB
Newer Older
/*
 * NetBSD-os.c.
 * From OpenBSD-os.c 1.1 2001/12/06 19:15:44 pmai Exp
 * From FreeBSD-os.c 1.6 2000/10/24 13:32:30 dtc Exp
 *
 * OS-dependent routines.  This file (along with os.h) exports an
 * OS-independent interface to the operating system VM facilities.
 * Suprisingly, this interface looks a lot like the Mach interface
 * (but simpler in some places).  For some operating systems, a subset
 * of these functions will have to be emulated.
 *
 * This is the OSF1 version.  By Sean Hallgren.
 * Much hacked by Paul Werkowski
 * GENCGC support by Douglas Crosher, 1996, 1997.
 * Frobbed for OpenBSD by Pierre R. Mai, 2001.
 * Frobbed for NetBSD by Pierre R. Mai, 2002.
 *
 * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/NetBSD-os.c,v 1.1 2002/01/28 20:19:39 pmai Exp $
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/file.h>
#include <errno.h>
#include "./signal.h"
#include "os.h"
#include "arch.h"
#include "globals.h"
#include "interrupt.h"
#include "lispregs.h"
#include "internals.h"

#include <sys/types.h>
#include <signal.h>
/* #include <sys/sysinfo.h> */
#include <sys/proc.h>
#include "validate.h"
size_t os_vm_page_size;

#define DPRINTF(t,a) {if (t) fprintf a;}

#if defined GENCGC
#include "gencgc.h"
#endif


void os_init(void)
{
  os_vm_page_size = OS_VM_DEFAULT_PAGESIZE;
}

int sc_reg(struct sigcontext *c, int offset)
{
  switch(offset)
    {
    case  0: return c->sc_eax;
    case  2: return c->sc_ecx;
    case  4: return c->sc_edx;
    case  6: return c->sc_ebx;
    case  8: return c->sc_esp;
    case 10: return c->sc_ebp;
    case 12: return c->sc_esi;
    case 14: return c->sc_edi;
    }
  return 0;
}

void os_save_context(void)
{
  /*
   * Called from interrupt handlers so C stuff knows things set in Lisp.
   */
}

void os_set_context(void)
{
}

os_vm_address_t os_validate(os_vm_address_t addr, os_vm_size_t len)
{
  int flags = MAP_PRIVATE | MAP_ANONYMOUS;

  /*
   * NetBSD 1.5.2 seems to insist on each mmap being less than 128MB.
   * So we mmap in 64MB steps.  This is probably inefficient, but the
   * missing CR2 reporting in signal handlers already ensures that
   * NetBSD/x86 is not a suitable platform for CMU CL as it stands.
   */
  
  if (addr)
    flags |= MAP_FIXED;
  else
    flags |= MAP_VARIABLE;

  DPRINTF(0, (stderr, "os_validate %x %d =>", addr, len));

  if (addr)
    {
      os_vm_address_t curaddr=addr;

      while (len>0)
	{
	  os_vm_address_t resaddr;
	  int curlen=MIN(64*1024*1024,len);
	  
	  resaddr = mmap(curaddr, curlen, OS_VM_PROT_ALL, flags, -1, 0);
	  
	  if (resaddr == (os_vm_address_t) -1)
	    {
	      perror("mmap");
	      
	      while (curaddr>addr)
		{
		  curaddr-=64*1024*1024;
		  munmap(curaddr,64*1024*1024);
		}
	      
	      return NULL;
	    }

	  DPRINTF(0, (stderr, " %x", resaddr));
	  
	  curaddr+=curlen;
	  len-=curlen;
	}
      
      DPRINTF(0, (stderr, "\n"));
    }
  else
    {
      addr = mmap(0, len, OS_VM_PROT_ALL, flags, -1, 0);

      if (addr == (os_vm_address_t) -1)
	{
	  perror("mmap");
	  return NULL;
	}
      
      DPRINTF(0, (stderr, " %x\n", addr));
    }

  return addr;
}

void os_invalidate(os_vm_address_t addr, os_vm_size_t len)
{
  DPRINTF(0, (stderr, "os_invalidate %x %d\n", addr, len));

  if (munmap(addr, len) == -1)
    perror("munmap");
}

os_vm_address_t os_map(int fd, int offset, os_vm_address_t addr,
		       os_vm_size_t len)
{
  addr = mmap(addr, len,
	      OS_VM_PROT_ALL,
	      MAP_PRIVATE | MAP_FILE | MAP_FIXED,
	      fd, (off_t) offset);

  if (addr == (os_vm_address_t) -1)
    perror("mmap");

  return addr;
}

void os_flush_icache(os_vm_address_t address, os_vm_size_t length)
{
}

void os_protect(os_vm_address_t address, os_vm_size_t length,
		os_vm_prot_t prot)
{
  if (mprotect(address, length, prot) == -1)
    perror("mprotect");
}



static boolean in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
{
  char* beg = (char*) sbeg;
  char* end = (char*) sbeg + slen;
  char* adr = (char*) a;
  return (adr >= beg && adr < end);
}

boolean valid_addr(os_vm_address_t addr)
{
  int ret;
  os_vm_address_t newaddr;
  newaddr = os_trunc_to_page(addr);

  if (   in_range_p(addr, READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE)
      || in_range_p(addr, STATIC_SPACE_START   , STATIC_SPACE_SIZE   )
      || in_range_p(addr, DYNAMIC_0_SPACE_START, dynamic_space_size  )
      || in_range_p(addr, DYNAMIC_1_SPACE_START, dynamic_space_size  )
      || in_range_p(addr, CONTROL_STACK_START  , CONTROL_STACK_SIZE  )
      || in_range_p(addr, BINDING_STACK_START  , BINDING_STACK_SIZE  ))
    return TRUE;
  return FALSE;
}


static void sigsegv_handler(HANDLER_ARGS)
{

  /*
   * Since NetBSD on x86 currently provides no way to get the faulting
   * memory address (i.e. the contents of the CR2 register), the page
   * protection mechanism of the generational GC currently can't be
   * used (see gengc.c), hence we don't neet to do anything here.
   *
   * See OpenBSD-os.c for details of what should be here, once NetBSD
   * provides siginfo_t.
   */

  SAVE_CONTEXT();

  DPRINTF(0, (stderr, "sigsegv:\n"));
  interrupt_handle_now(signal, code, context);
}

static void sigbus_handler(HANDLER_ARGS)
{
  SAVE_CONTEXT();

  DPRINTF(0, (stderr, "sigbus:\n"));
  interrupt_handle_now(signal, code, context);
}

void os_install_interrupt_handlers(void)
{
  interrupt_install_low_level_handler(SIGSEGV, sigsegv_handler);
  interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
}