Newer
Older
* 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
* Morfed from the FreeBSD file by Peter Van Eynde (July 1996)
* GENCGC support by Douglas Crosher, 1996, 1997.
* $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/Linux-os.c,v 1.20 2004/07/08 04:10:09 rtoy Exp $
*
*/
#include <stdio.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/socket.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <signal.h>
/* #include <sys/sysinfo.h> */
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <netdb.h>
#if defined GENCGC
#include "gencgc.h"
#endif
#if ((LINUX_VERSION_CODE >= linuxversion(2,1,0)) || (__GNU_LIBRARY__ >= 6))
int PVE_stub_errno;
#endif
#if ((LINUX_VERSION_CODE >= linuxversion(2,1,0)) || (__GNU_LIBRARY__ >= 6))
void update_errno (void)
{
PVE_stub_errno = errno;
}
#endif
{
printf("Linux version must be later then 2.0.0!\n");
exit(2);
}
#if (LINUX_VERSION_CODE >= linuxversion(2,1,0)) || (__GNU_LIBRARY__ >= 6)
{
switch(offset)
{
case 0: return c->eax;
case 2: return c->ecx;
case 4: return c->edx;
case 6: return c->ebx;
case 8: return c->esp;
case 10: return c->ebp;
case 12: return c->esi;
case 14: return c->edi;
}
return 0;
}
#ifdef __x86_64
#if (LINUX_VERSION_CODE >= linuxversion(2,1,0)) || (__GNU_LIBRARY__ >= 6)
int sc_reg(struct sigcontext *c, int offset)
#else
int sc_reg(struct sigcontext_struct *c, int offset)
#endif
{
switch(offset)
{
case 0: return c->rax;
case 2: return c->rcx;
case 4: return c->rdx;
case 6: return c->rbx;
case 8: return c->rsp;
case 10: return c->rbp;
case 12: return c->rsi;
case 14: return c->rdi;
}
return 0;
}
#endif
/*
* Called from interrupt handlers so C stuff knows things set in Lisp.
os_vm_address_t os_validate(os_vm_address_t addr, os_vm_size_t len)
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
if (addr)
flags |= MAP_FIXED;
else
flags |= MAP_VARIABLE;
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;
DPRINTF(0, (stderr, "%p\n", addr));
return addr;
DPRINTF(0, (stderr, "os_invalidate %p %d\n", addr, len));
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)
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)
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;
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 ))
static void sigsegv_handle_now(HANDLER_ARGS)
{
interrupt_handle_now(signal, contextstruct);
}
void sigsegv_handler(HANDLER_ARGS)
#if (LINUX_VERSION_CODE >= linuxversion(2,1,0)) || (__GNU_LIBRARY__ >= 6)
int fault_addr = ((struct sigcontext *) (&contextstruct))->cr2;
#else
int fault_addr = ((struct sigcontext_struct *) (&contextstruct))->cr2;
if (os_control_stack_overflow ((void *) fault_addr, &contextstruct))
return;
#endif
/* check if the fault is within the dynamic space. */
/* Un-protect the page */
/* The page should have been marked write protected */
if (!PAGE_WRITE_PROTECTED(page_index))
fprintf(stderr, "*** Sigsegv in page not marked as write protected\n");
os_protect(page_address(page_index), 4096, OS_VM_PROT_ALL);
page_table[page_index].flags &= ~PAGE_WRITE_PROTECTED_MASK;
page_table[page_index].flags |= PAGE_WRITE_PROTECT_CLEARED_MASK;
#if defined(__x86_64)
DPRINTF(0,(stderr,"sigsegv: rip: %p\n",context->rip));
#else
DPRINTF(0,(stderr,"sigsegv: eip: %lx\n",context->eip));
sigsegv_handle_now(signal, contextstruct);
#define CONTROL_STACK_TOP (((char*) CONTROL_STACK_START) + CONTROL_STACK_SIZE)
addr = arch_get_bad_addr(signal,code,context);
if (addr != NULL && context->sc_regs[reg_ALLOC] & (1 << 63)) {
context->sc_regs[reg_ALLOC] -= (1 << 63);
interrupt_handle_pending(context);
} else if (addr > CONTROL_STACK_TOP && addr < BINDING_STACK_START) {
fprintf(stderr, "Possible stack overflow at 0x%08lX!\n", addr);
/* try to fix control frame pointer */
while (!(CONTROL_STACK_START <= *current_control_frame_pointer &&
*current_control_frame_pointer <= CONTROL_STACK_TOP))
((char*) current_control_frame_pointer) -= sizeof(lispobj);
ldb_monitor();
} else if (!interrupt_maybe_gc(signal, code, context))
interrupt_handle_now(signal, code, context);
#endif
DPRINTF(1, (stderr, "sigbus:\n")); /* there is no sigbus in linux??? */
interrupt_install_low_level_handler(SIGSEGV, sigsegv_handler);
interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
/* Some symbols, most notably stat and lstat, don't appear at all in
the glibc .so files as a result of preprocessor and linker magic /
braindamage. So, try falling back to a stub in linux-stubs.S that
will call the proper function if it's one of those. */
static void *dlsym_fallback(void *handle, const char *name)
{
char newsym[1024];
void *sym_addr;
strcpy(newsym, "PVE_stub_");
strcat(newsym, name);
sym_addr = dlsym(handle, newsym);
#ifdef DEBUG
if (sym_addr == 0) {
return sym_addr;
}
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);
if (!sym_addr && dlerror()) {
return dlsym_fallback(program_handle,sym_name);
} else {
return sym_addr;
}
}