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.7 2007/07/30 07:24:46 cshapiro Exp $
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/file.h>
#include <errno.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;
sc_reg(os_context_t * c, int offset)
#ifdef i386
#if USE_SA_SIGINFO
switch (offset) {
case 0:
return &c->uc_mcontext.__gregs[_REG_EAX];
return &c->uc_mcontext.__gregs[_REG_ECX];
return &c->uc_mcontext.__gregs[_REG_EDX];
return &c->uc_mcontext.__gregs[_REG_EBX];
return &c->uc_mcontext.__gregs[_REG_ESP];
return &c->uc_mcontext.__gregs[_REG_EBP];
return &c->uc_mcontext.__gregs[_REG_ESI];
return &c->uc_mcontext.__gregs[_REG_EDI];
switch (offset) {
case 0:
return &c->sc_eax;
return &c->sc_ecx;
return &c->sc_edx;
return &c->sc_ebx;
return &c->sc_esp;
return &c->sc_ebp;
return &c->sc_esi;
return &c->sc_edi;
return (int *) 0;
os_vm_address_t
os_validate(os_vm_address_t addr, os_vm_size_t len)
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
* 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;
DPRINTF(0, (stderr, "os_validate %p %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);
DPRINTF(0, (stderr, " %p", 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, " %p\n", addr));
void
os_invalidate(os_vm_address_t addr, os_vm_size_t len)
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)
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)
|| 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)
caddr_t fault_addr = code ? code->si_addr : 0;
int page_index = find_page_index((void *) fault_addr);
fprintf(stderr, "Signal %d, fault_addr=%p, page_index=%d:\n",
signal, fault_addr, page_index);
/* Check if the fault is within the dynamic space. */
if (page_index != -1) {
/* 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;
DPRINTF(0, (stderr, "sigsegv:\n"));
interrupt_handle_now(signal, code, context);
static void
sigbus_handler(HANDLER_ARGS)
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);
os_dlsym(const char *sym_name, lispobj lib_list)
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;
return dlsym(RTLD_DEFAULT, sym_name);