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.14 2002/08/28 07:16:38 moore 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;
}
/*
* 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;
addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
if(addr == (os_vm_address_t) -1)
perror("mmap");
return NULL;
return addr;
DPRINTF(0, (stderr, "os_invalidate %x %d\n", addr, len));
if (munmap(addr, len) == -1)
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 ))
#if defined GENCGC
void sigsegv_handler(HANDLER_ARGS)
int fault_addr = ((struct sigcontext_struct *) (&contextstruct))->cr2;
int page_index = find_page_index((void *) fault_addr);
/* 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;
return;
}
DPRINTF(0,(stderr,"sigsegv: eip: %p\n",context->eip));
interrupt_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);
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
/* 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);
if ((sym_addr = dlsym(handle, newsym)) == 0) {
fputs(dlerror(), stderr);
}
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;
}
}