Skip to content
FreeBSD-os.c 8.16 KiB
Newer Older
ram's avatar
ram committed
/*
 * FreeBSD-os.c. Maybe could be just BSD-os.c
 * From osf1-os.c,v 1.1 94/03/27 15:30:51 hallgren 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.
 *
ram's avatar
ram committed
 */

ram's avatar
ram committed
#include <sys/file.h>
ram's avatar
ram committed
#include <errno.h>
#include "arch.h"
#include "globals.h"
#include "interrupt.h"
#include "lispregs.h"
#include "internals.h"

moore's avatar
 
moore committed
#include <dlfcn.h>
#include "validate.h"
#include <stdio.h>
#include <unistd.h>

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

vm_size_t os_vm_page_size;
void
os_init0(const char *argv[], const char *envp[])
{}

rtoy's avatar
rtoy committed
os_init(const char *argv[], const char *envp[])
ram's avatar
ram committed
{
    os_vm_page_size = getpagesize();
ram's avatar
ram committed
}

unsigned long *
os_sigcontext_reg(ucontext_t *scp, int index)
{
        rv = &scp->uc_mcontext.mc_eax;
        break;
        rv = &scp->uc_mcontext.mc_ecx;
        break;
        rv = &scp->uc_mcontext.mc_edx;
        break;
        rv = &scp->uc_mcontext.mc_ebx;
        break;
        rv = &scp->uc_mcontext.mc_esp;
        break;
        rv = &scp->uc_mcontext.mc_ebp;
        break;
        rv = &scp->uc_mcontext.mc_esi;
        break;
        rv = &scp->uc_mcontext.mc_edi;
        break;
        rv = NULL;
    /* Pre-cast to (void *), to avoid the compiler warning:
     * dereferencing type-punned pointer will break strict-aliasing rules
    return (unsigned long *) (void *) rv;
}

unsigned long *
os_sigcontext_pc(ucontext_t *scp)
{
    return (unsigned long *) (void *) &scp->uc_mcontext.mc_eip;
}

unsigned char *
os_sigcontext_fpu_reg(ucontext_t *scp, int index)
{
    union savefpu *sv = (union savefpu *) scp->uc_mcontext.mc_fpstate;
    int fpformat = scp->uc_mcontext.mc_fpformat;
    unsigned char *reg = NULL;

    switch (fpformat) {
      case _MC_FPFMT_XMM:
          if (index < 8) {
              reg = sv->sv_xmm.sv_fp[index].fp_acc.fp_bytes;
          } else {
              reg = sv->sv_xmm.sv_xmm[index - 8].xmm_bytes;
          }
	  break;
      case _MC_FPFMT_387:
	  reg = sv->sv_87.sv_ac[index].fp_bytes;
	  break;
      case _MC_FPFMT_NODEV:
	  reg = NULL;
	  break;
ram's avatar
ram committed
    }
os_sigcontext_fpu_modes(ucontext_t *scp)
{
agoncharov's avatar
agoncharov committed
    union savefpu *sv = (union savefpu *) scp->uc_mcontext.mc_fpstate;
    int fpformat = scp->uc_mcontext.mc_fpformat;
agoncharov's avatar
agoncharov committed
    struct env87 *env_87 = &sv->sv_87.sv_env;
    struct envxmm *env_xmm = &sv->sv_xmm.sv_env;
    u_int16_t cw;
    u_int16_t sw;
agoncharov's avatar
agoncharov committed
	cw = env_xmm->en_cw;
	sw = env_xmm->en_sw;
    } else if (fpformat == _MC_FPFMT_387) {
agoncharov's avatar
agoncharov committed
	cw = env_87->en_cw & 0xffff;
	sw = env_87->en_sw & 0xffff;
    } else { /* _MC_FPFMT_NODEV */
agoncharov's avatar
agoncharov committed

    modes = ((cw & 0x3f) << 7) | (sw & 0x3f);

#ifdef FEATURE_SSE2
agoncharov's avatar
 
agoncharov committed
    if (fpu_mode == SSE2) {
	u_int32_t mxcsr = env_xmm->en_mxcsr;

	DPRINTF(0, (stderr, "SSE2 modes = %08x\n", (int)mxcsr));
agoncharov's avatar
agoncharov committed
	modes |= mxcsr;
    }
#endif
    modes ^= (0x3f << 7);
ram's avatar
ram committed
}
dtc's avatar
dtc committed

os_vm_address_t
os_validate(os_vm_address_t addr, os_vm_size_t len)
ram's avatar
ram committed
{
    int flags = MAP_PRIVATE | MAP_ANON;
dtc's avatar
dtc committed

    if (addr)
	flags |= MAP_FIXED;
ram's avatar
ram committed

    addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
dtc's avatar
dtc committed

    if (addr == (os_vm_address_t) - 1) {
	perror("mmap");
	return NULL;
ram's avatar
ram committed
    }
dtc's avatar
dtc committed

ram's avatar
ram committed
}

os_invalidate(os_vm_address_t addr, os_vm_size_t len)
ram's avatar
ram committed
{
    if (munmap(addr, len) == -1)
	perror("munmap");
ram's avatar
ram committed
}

os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
ram's avatar
ram committed
{
    addr = mmap(addr, len, OS_VM_PROT_ALL,
		MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, (off_t) offset);
dtc's avatar
dtc committed

    if (addr == (os_vm_address_t) - 1)
	perror("mmap");
dtc's avatar
dtc committed

ram's avatar
ram committed
}

os_flush_icache(os_vm_address_t address, os_vm_size_t length)
ram's avatar
ram committed
{
}

os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
ram's avatar
ram committed
{
    if (mprotect(address, length, prot) == -1)
	perror("mprotect");
ram's avatar
ram committed
}

dtc's avatar
dtc committed

in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
ram's avatar
ram committed
{
    char *beg = (char *) sbeg;
    char *end = (char *) sbeg + slen;
    char *adr = (char *) a;

    return adr >= beg && adr < end;
ram's avatar
ram committed
}
dtc's avatar
dtc committed

boolean
valid_addr(os_vm_address_t addr)
ram's avatar
ram committed
{
Raymond Toy's avatar
Raymond Toy committed
    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)
Raymond Toy's avatar
Raymond Toy committed
	|| in_range_p(addr, CONTROL_STACK_START, control_stack_size)
	|| in_range_p(addr, BINDING_STACK_START, binding_stack_size))
	return TRUE;
    return FALSE;
ram's avatar
ram committed
}

protection_violation_handler(HANDLER_ARGS)
ram's avatar
ram committed
{
    if (os_control_stack_overflow(code->si_addr, context))
ram's avatar
ram committed
#endif
    if (code->si_code == PROTECTION_VIOLATION_CODE) {
	if (gc_write_barrier(code->si_addr)) {
cshapiro's avatar
cshapiro committed
	    return;
	}
    interrupt_handle_now(signal, code, context);
ram's avatar
ram committed
}
dtc's avatar
dtc committed

/*
 * Restore the exception flags cleared by the kernel.  These bits must
 * be set for Lisp to determine which exception caused the signal.  At
 * present, there is no way to distinguish underflow exceptions from
 * denormalized operand exceptions.  An underflow exception is assumed
 * if the subcode is FPE_FLTUND.
 */
static void
sigfpe_handler(HANDLER_ARGS)
    ucontext_t *ucontext = (ucontext_t *) context;
    union savefpu *sv = (union savefpu *) ucontext->uc_mcontext.mc_fpstate;
    int fpformat = ucontext->uc_mcontext.mc_fpformat;
    unsigned char trap = 0;
    switch (code->si_code) {
      case FPE_FLTDIV:		/* ZE */
      case FPE_FLTOVF:		/* OE */
      case FPE_FLTUND:		/* DE or UE */
      case FPE_FLTRES:		/* PE */
      case FPE_FLTINV:		/* IE */
    }

    switch (fpformat) {
      case _MC_FPFMT_XMM:
	  sv->sv_xmm.sv_env.en_sw |= trap;
	  break;
      case _MC_FPFMT_387:
	  sv->sv_87.sv_env.en_sw |= trap;
	  break;
    }
    interrupt_handle_now(signal, code, context);
os_install_interrupt_handlers(void)
ram's avatar
ram committed
{
    interrupt_install_low_level_handler(PROTECTION_VIOLATION_SIGNAL,
					protection_violation_handler);
    interrupt_install_low_level_handler(SIGFPE, sigfpe_handler);
ram's avatar
ram committed
}
moore's avatar
 
moore committed

os_dlsym(const char *sym_name, lispobj lib_list)
moore's avatar
 
moore committed
{
    static void *program_handle;

    if (!program_handle)
	program_handle = dlopen((void *) 0, RTLD_LAZY | RTLD_GLOBAL);

    if (lib_list != NIL) {
	lispobj lib_list_head;

	for (lib_list_head = lib_list;
	     lib_list_head != NIL; lib_list_head = CONS(lib_list_head)->cdr) {
	    struct cons *lib_cons = CONS(CONS(lib_list_head)->car);
	    struct sap *dlhandle = (struct sap *)PTR(lib_cons->car);
	    void *sym_addr = dlsym((void *)dlhandle->pointer, sym_name);

	    if (sym_addr)
		return sym_addr;
moore's avatar
 
moore committed
	}
    }
    return dlsym(program_handle, sym_name);
moore's avatar
 
moore committed
}

void
restore_fpu(ucontext_t *scp)
{
    union savefpu *sv = (union savefpu *) scp->uc_mcontext.mc_fpstate;
    int fpformat = scp->uc_mcontext.mc_fpformat;
agoncharov's avatar
agoncharov committed
    struct env87 *env_87 = &sv->sv_87.sv_env;
    struct envxmm *env_xmm = &sv->sv_xmm.sv_env;
    u_int16_t cw;
agoncharov's avatar
agoncharov committed
	cw = env_xmm->en_cw;
    } else if (fpformat == _MC_FPFMT_387) {
agoncharov's avatar
agoncharov committed
	cw = env_87->en_cw & 0xffff;
    } else { /* _MC_FPFMT_NODEV */
    DPRINTF(0, (stderr, "restore_fpu:  cw = %08x\n", (int)cw));
    __asm__ __volatile__ ("fldcw %0"::"m"(*&cw));

agoncharov's avatar
agoncharov committed
#ifdef FEATURE_SSE2
	u_int32_t mxcsr = env_xmm->en_mxcsr;

	DPRINTF(0, (stderr, "restore_fpu:  mxcsr (raw) = %04x\n", mxcsr));
	__asm__ __volatile__ ("ldmxcsr %0"::"m"(*&mxcsr));
agoncharov's avatar
agoncharov committed
    }
#endif