Skip to content
Darwin-os.c 13.7 KiB
Newer Older
/*
 * Darwin-os.c.
 * 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 Darwin by Pierre R. Mai, 2003.
 *
 */

#include <stdio.h>
#include <sys/param.h>
#include <sys/file.h>
#include <errno.h>
cshapiro's avatar
cshapiro committed
#include <dlfcn.h>
#include "os.h"
#include "arch.h"
#include "globals.h"
#include "interrupt.h"
#include "lispregs.h"
#include "internals.h"
rtoy's avatar
rtoy committed
#ifdef GENCGC
#include "gencgc.h"
#endif

#include <sys/types.h>
#include <signal.h>
/* #include <sys/sysinfo.h> */
/* #include <sys/proc.h> */
/* For timebase info */
#include <sys/sysctl.h>


/* Need this to define ppc_saved_state_t (for 10.4) */
#include <mach/thread_status.h>

#include "validate.h"
vm_size_t os_vm_page_size;

/*
 * This is accessed by Lisp!  Make this a static symbol?
 */
int cycles_per_tick = 1;

/*
 * Compute the conversion factor from the numbef of time base ticks to
 * clock frequency.  The timebase counter on PPC is not a cycle
 * counter; we have to derive the relationship ourselves.
 */

cshapiro's avatar
cshapiro committed
#ifdef __ppc__
    int mib[2];
    int tbfrequency;
    int cpufrequency;
    unsigned int miblen;
    size_t len;
    /*
     * Mac OS X 10.2.8 doesn't have this, so we take it from 10.3.8,
     * which does.
     */
#endif
    mib[1] = HW_TB_FREQ;
    miblen = 2;
    len = sizeof(tbfrequency);

    if (sysctl(mib, miblen, &tbfrequency, &len, NULL, 0) == -1) {
	perror("Error getting HW_TB_FREQ from sysctl: ");
    }
    mib[0] = CTL_HW;
    mib[1] = HW_CPU_FREQ;
    miblen = 2;
    len = sizeof(cpufrequency);
    if (sysctl(mib, miblen, &cpufrequency, &len, NULL, 0) == -1) {
	perror("Error getting HW_CPU_FREQ from sysctl: ");
    }

    cycles_per_tick = cpufrequency / tbfrequency;
}
cshapiro's avatar
cshapiro committed
#endif
void
os_init0(const char *argv[], const char *envp[])
{}

rtoy's avatar
rtoy committed
os_init(const char *argv[], const char *envp[])
    os_vm_page_size = OS_VM_DEFAULT_PAGESIZE;
cshapiro's avatar
cshapiro committed
#ifdef __ppc__
cshapiro's avatar
cshapiro committed
#endif
cshapiro's avatar
cshapiro committed
#if defined(__ppc__)
#if __DARWIN_UNIX03
  /* Nothing needed for 10.5 */
#else
/* For 10.4 */
#define __ss ss
#define __r0 r0
#define __r1 r1
#define __r2 r2
#define __r3 r3
#define __r4 r4
#define __r5 r5
#define __r6 r6
#define __r7 r7
#define __r8 r8
#define __r9 r9
#define __r10 r10
#define __r11 r11
#define __r12 r12
#define __r13 r13
#define __r14 r14
#define __r15 r15
#define __r16 r16
#define __r17 r17
#define __r18 r18
#define __r19 r19
#define __r20 r20
#define __r21 r21
#define __r22 r22
#define __r23 r23
#define __r24 r24
#define __r25 r25
#define __r26 r26
#define __r27 r27
#define __r28 r28
#define __r29 r29
#define __r30 r30
#define __r31 r31
#define __lr lr
#define __ctr ctr
#define __es es
#define __dar dar
#define __dsisr dsisr
#endif

unsigned int *
sc_reg(os_context_t * context, int offset)
    _STRUCT_PPC_THREAD_STATE *state = &context->uc_mcontext->__ss;
      case 34:
	  /*
	   * Not sure if this is really defined anywhere, but after
	   * r31 is cr, xer, lr, and ctr.  So we let 34 be lr.
	   */
	  return &context->uc_mcontext->__es.__dar;
	  return &context->uc_mcontext->__es.__dsisr;
    return (unsigned int *) 0;
cshapiro's avatar
cshapiro committed
#elif defined(__i386__)
#if __DARWIN_UNIX03
  /* Nothing needed for 10.5 */
#else
  /* This is for 10.4 */
#define __ss ss
#define __eax eax
#define __ecx ecx
#define __edx edx
#define __ebx ebx
#define __esp esp
#define __ebp ebp
#define __esi esi
#define __edi edi
#define __eip eip  
#define __fs fs
#define __fpu_stmm0 fpu_stmm0
#define __fpu_stmm1 fpu_stmm1
#define __fpu_stmm2 fpu_stmm2
#define __fpu_stmm3 fpu_stmm3
#define __fpu_stmm4 fpu_stmm4
#define __fpu_stmm5 fpu_stmm5
#define __fpu_stmm6 fpu_stmm6
#define __fpu_stmm7 fpu_stmm7
#define __fpu_fcw   fpu_fcw
#define __fpu_fsw   fpu_fsw
#define __fpu_mxcsr fpu_mxcsr
#ifdef FEATURE_SSE2
#define __fpu_xmm0 fpu_xmm0
#define __fpu_xmm1 fpu_xmm1
#define __fpu_xmm2 fpu_xmm2
#define __fpu_xmm3 fpu_xmm3
#define __fpu_xmm4 fpu_xmm4
#define __fpu_xmm5 fpu_xmm5
#define __fpu_xmm6 fpu_xmm6
#define __fpu_xmm7 fpu_xmm7
#endif

unsigned long *
os_sigcontext_reg(ucontext_t *scp, int index)
{
    switch (index) {
    case 0:
	return (unsigned long *) &scp->uc_mcontext->__ss.__eax;
    case 2:
	return (unsigned long *) &scp->uc_mcontext->__ss.__ecx;
    case 4:
	return (unsigned long *) &scp->uc_mcontext->__ss.__edx;
    case 6:
	return (unsigned long *) &scp->uc_mcontext->__ss.__ebx;
    case 8:
	return (unsigned long *) &scp->uc_mcontext->__ss.__esp;
    case 10:
	return (unsigned long *) &scp->uc_mcontext->__ss.__ebp;
    case 12:
	return (unsigned long *) &scp->uc_mcontext->__ss.__esi;
    case 14:
	return (unsigned long *) &scp->uc_mcontext->__ss.__edi;
cshapiro's avatar
cshapiro committed
    }
cshapiro's avatar
cshapiro committed

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

unsigned char *
os_sigcontext_fpu_reg(ucontext_t *scp, int index)
{
    switch (index) {
    case 0:
	return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm0;
    case 1:
	return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm1;
    case 2:
	return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm2;
    case 3:
	return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm3;
    case 4:
	return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm4;
    case 5:
	return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm5;
    case 6:
	return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm6;
    case 7:
	return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm7;
#ifdef FEATURE_SSE2
    case 8:
       return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm0;
    case 9:
       return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm1;
    case 10:
       return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm2;
    case 11:
       return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm3;
    case 12:
       return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm4;
    case 13:
       return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm5;
    case 14:
       return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_xmm6;
    case 15:
       return (unsigned char *) &scp->uc_mcontext->__fs.__fpu_stmm7;
#endif
os_sigcontext_fpu_modes(ucontext_t *scp)
{
    unsigned int modes;
    unsigned int mxcsr;

    /*
     * Get the status word and the control word.  
     */
    memcpy(&cw, &scp->uc_mcontext->__fs.__fpu_fcw, sizeof(cw));
    memcpy(&sw, &scp->uc_mcontext->__fs.__fpu_fsw, sizeof(sw));

    /*
     * Put the cw in the upper bits and the status word in the lower 6
     * bits, ignoring everything except the exception masks and the
     * exception flags.
     */
    modes = ((cw & 0x3f) << 7) | (sw & 0x3f);
    
    DPRINTF(0, (stderr, "FPU modes = %08x (sw =  %4x, cw = %4x)\n",
		modes, (unsigned int) sw, (unsigned int) cw));

    if (fpu_mode == SSE2) {
      mxcsr = scp->uc_mcontext->__fs.__fpu_mxcsr;
      DPRINTF(0, (stderr, "SSE2 modes = %08x\n", mxcsr));
    DPRINTF(0, (stderr, "modes pre mask = %08x\n", modes));

    /* Convert exception mask to exception enable */
    modes ^= (0x3f << 7);
    DPRINTF(0, (stderr, "Finale = %08x\n", modes));
    return modes;
}

void
restore_fpu(ucontext_t *scp)
{
    unsigned short cw;
    unsigned int mxcsr;

    memcpy(&cw, &scp->uc_mcontext->__fs.__fpu_fcw, sizeof(cw));
    DPRINTF(0, (stderr, "restore_fpu: FPU cw = 0x%x\n", cw));
    __asm__ __volatile__ ("fclex");
    __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw));
            
    mxcsr = scp->uc_mcontext->__fs.__fpu_mxcsr;
    DPRINTF(0, (stderr, "restore_fpu:  mxcsr (raw) = %04x\n", mxcsr));
    __asm__ __volatile__ ("ldmxcsr %0" :: "m" (*&mxcsr));
cshapiro's avatar
cshapiro committed
}
#endif
os_vm_address_t
os_validate(os_vm_address_t addr, os_vm_size_t len)
    int flags = MAP_PRIVATE | MAP_ANON;
    if (addr)
	flags |= MAP_FIXED;
cshapiro's avatar
cshapiro committed
    DPRINTF(0, (stderr, "os_validate %p %d => ", addr, len));
    addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
    if (addr == (os_vm_address_t) - 1) {
	perror("mmap");
	return NULL;
cshapiro's avatar
cshapiro committed
    DPRINTF(0, (stderr, "%p\n", addr));
void
os_invalidate(os_vm_address_t addr, os_vm_size_t len)
cshapiro's avatar
cshapiro committed
    DPRINTF(0, (stderr, "os_invalidate %p %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");
void
os_flush_icache(os_vm_address_t address, os_vm_size_t length)
cshapiro's avatar
cshapiro committed
#ifdef __ppc__    
    ppc_flush_icache(address, length);
cshapiro's avatar
cshapiro committed
#endif
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)
    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)
rtoy's avatar
rtoy committed
#ifndef GENCGC
	|| in_range_p(addr, DYNAMIC_1_SPACE_START, dynamic_space_size)
rtoy's avatar
rtoy committed
#endif
	|| 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
sigbus_handle_now(HANDLER_ARGS)
{
    interrupt_handle_now(signal, code, context);
}
rtoy's avatar
rtoy committed
sigbus_handler(HANDLER_ARGS)
    os_context_t *os_context = (os_context_t *) context;
rtoy's avatar
rtoy committed
#if defined(GENCGC)
    caddr_t fault_addr = code->si_addr;
rtoy's avatar
rtoy committed
#endif
    
#ifdef RED_ZONE_HIT
    if (os_control_stack_overflow((void *) fault_addr, os_context))
#ifdef __ppc__
rtoy's avatar
rtoy committed
    DPRINTF(0, (stderr, "sigbus:\n"));
    DPRINTF(0, (stderr, " PC       = %p\n", SC_PC(os_context)));
    DPRINTF(0, (stderr, " ALLOC-TN = %p\n", SC_REG(os_context, reg_ALLOC)));
    DPRINTF(0, (stderr, " CODE-TN  = %p\n", SC_REG(os_context, reg_CODE)));
    DPRINTF(0, (stderr, " LRA-TN   = %p\n", SC_REG(os_context, reg_LRA)));
    DPRINTF(0, (stderr, " CFP-TN   = %p\n", SC_REG(os_context, reg_CFP)));
    DPRINTF(0, (stderr, " FDEFN-TN = %p\n", SC_REG(os_context, reg_FDEFN)));
rtoy's avatar
rtoy committed
    DPRINTF(0, (stderr, " foreign_function_call = %d\n", foreign_function_call_active));
#if defined(GENCGC)
#if defined(SIGSEGV_VERBOSE)
    fprintf(stderr, "Signal %d, fault_addr=%x, page_index=%d:\n",
	    signal, fault_addr, page_index);
#endif
    if (gc_write_barrier(code->si_addr))
	 return;
#else
    if (interrupt_maybe_gc(signal, code, os_context))
    /* a *real* protection fault */
    fprintf(stderr, "sigbus_handler: Real protection violation at %p, PC = %p\n",
            fault_addr, (void *) SC_PC(os_context));
    sigbus_handle_now(signal, code, os_context);
#ifdef __ppc__
    /* Work around G5 bug; fix courtesy gbyers via chandler */
cshapiro's avatar
cshapiro committed
#endif
void
os_install_interrupt_handlers(void)
    interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
void *
os_dlsym(const char *sym_name, lispobj lib_list)
{
    static void *program_handle;
    void *sym_addr = 0;

    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);
	    sym_addr = dlsym((void *) dlhandle->pointer, sym_name);
	    if (sym_addr)
		return sym_addr;
	}
    }
    sym_addr = dlsym(program_handle, sym_name);

    return sym_addr;
}

#ifdef i386
boolean
os_support_sse2()
{
    return TRUE;
}
#endif