diff --git a/ldb/arch.h b/ldb/arch.h
new file mode 100644
index 0000000000000000000000000000000000000000..3947377261ac7239ac96ca74b4be1b765c25d33d
--- /dev/null
+++ b/ldb/arch.h
@@ -0,0 +1,8 @@
+#ifndef __ARCH_H__
+#define __ARCH_H__
+
+extern void arch_init();
+extern void arch_skip_instruction();
+extern os_vm_address_t arch_get_bad_addr();
+
+#endif /* __ARCH_H__ */
diff --git a/ldb/fake-mach.c b/ldb/fake-mach.c
new file mode 100644
index 0000000000000000000000000000000000000000..422e3e0f736a2a074ce877280d6f2282874fd222
--- /dev/null
+++ b/ldb/fake-mach.c
@@ -0,0 +1,53 @@
+#include "ldb.h"
+#include "os.h"
+
+#define KERN_SUCCESS		0
+#define KERN_INVALID_ADDRESS	1
+#define KERN_PROTECTION_FAILURE	2
+#define KERN_NO_SPACE		3
+#define KERN_INVALID_ARGUMENT	4
+#define KERN_FAILURE		5
+
+int task_self()
+{
+    return 0;
+}
+
+int thread_reply()
+{
+    return 0;
+}
+
+int task_notify()
+{
+    return 0;
+}
+
+int vm_allocate(task,addr_p,len,free)
+int task;
+os_vm_address_t *addr_p;
+os_vm_size_t len;
+int free;
+{
+    *addr_p=os_validate(free ? NULL : *addr_p,len);
+    return (*addr_p)==NULL ? KERN_FAILURE : KERN_SUCCESS;
+}
+
+int vm_deallocate(task,addr,len)
+int task;
+os_vm_address_t addr;
+os_vm_size_t len;
+{
+    os_invalidate(addr,len);
+    return KERN_SUCCESS;
+}
+
+int vm_copy()
+{
+    return KERN_FAILURE;
+}
+
+int vm_statistics()
+{
+    return KERN_FAILURE;
+}
diff --git a/ldb/mach-os.h b/ldb/mach-os.h
new file mode 100644
index 0000000000000000000000000000000000000000..d54ffbd053c287da849fb043e1e2256ebe08e9d0
--- /dev/null
+++ b/ldb/mach-os.h
@@ -0,0 +1,13 @@
+#include <mach.h>
+#include "ldb.h"
+
+typedef vm_address_t os_vm_address_t;
+typedef vm_size_t os_vm_size_t;
+typedef vm_offset_t os_vm_offset_t;
+typedef vm_prot_t os_vm_prot_t;
+
+#define OS_VM_PROT_READ VM_PROT_READ
+#define OS_VM_PROT_WRITE VM_PROT_WRITE
+#define OS_VM_PROT_EXECUTE VM_PROT_EXECUTE
+
+#define OS_VM_DEFAULT_PAGESIZE	4096
diff --git a/ldb/mips-arch.c b/ldb/mips-arch.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d997cfcb5ab28ad8648e56bbb758d20389209f6
--- /dev/null
+++ b/ldb/mips-arch.c
@@ -0,0 +1,134 @@
+#include <mips/cpu.h>
+
+#include "ldb.h"
+#include "lisp.h"
+#include "globals.h"
+#include "validate.h"
+#include "os.h"
+#include "arch.h"
+#include "lispregs.h"
+#include "signal.h"
+
+void arch_init()
+{
+}
+
+os_vm_address_t arch_get_bad_addr(context)
+struct sigcontext *context;
+{
+    /* Finding the bad address on the mips is easy. */
+    return (os_vm_address_t)context->sc_badvaddr;
+}
+
+void arch_skip_instruction(context)
+struct sigcontext *context;
+{
+    /* Skip the offending instruction */
+    if (context->sc_cause & CAUSE_BD)
+        emulate_branch(context, *(unsigned long *)context->sc_pc);
+    else
+        context->sc_pc += 4;
+}
+
+static void sigtrap_handler(signal, code, context)
+     int signal, code;
+     struct sigcontext *context;
+{
+    switch (code) {
+      case trap_PendingInterrupt:
+	interrupt_handle_pending(context);
+	break;
+
+      case trap_Halt:
+	crap_out("%primitive halt called; the party is over.\n");
+
+      case trap_Error:
+      case trap_Cerror:
+	interrupt_internal_error(signal, code, context, code==trap_Cerror);
+	break;
+
+      case trap_Breakpoint:
+	sigsetmask(context->sc_mask);
+	fake_foreign_function_call(context);
+	handle_breakpoint(signal, code, context);
+	undo_fake_foreign_function_call(context);
+	break;
+
+      default:
+	interrupt_handle_now(signal, code, context);
+	break;
+    }
+}
+
+static void sigfpe_handler(signal, code, context)
+int signal, code;
+struct sigcontext *context;
+{
+    unsigned long bad_inst;
+    unsigned int op, rs, rt, rd, funct, dest;
+    int immed;
+    long result;
+
+    if (context->sc_cause & CAUSE_BD)
+        bad_inst = *(unsigned long *)(context->sc_pc + 4);
+    else
+        bad_inst = *(unsigned long *)(context->sc_pc);
+
+    op = (bad_inst >> 26) & 0x3f;
+    rs = (bad_inst >> 21) & 0x1f;
+    rt = (bad_inst >> 16) & 0x1f;
+    rd = (bad_inst >> 11) & 0x1f;
+    funct = bad_inst & 0x3f;
+    immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
+
+    switch (op) {
+        case 0x0: /* SPECIAL */
+            switch (funct) {
+                case 0x20: /* ADD */
+                    result = FIXNUM_VALUE(context->sc_regs[rs]) + FIXNUM_VALUE(context->sc_regs[rt]);
+                    dest = rd;
+                    break;
+
+                case 0x22: /* SUB */
+                    result = FIXNUM_VALUE(context->sc_regs[rs]) - FIXNUM_VALUE(context->sc_regs[rt]);
+                    dest = rd;
+                    break;
+
+                default:
+                    dest = 32;
+                    break;
+            }
+            break;
+
+        case 0x8: /* ADDI */
+            result = FIXNUM_VALUE(context->sc_regs[rs]) + (immed>>2);
+            dest = rt;
+            break;
+
+        default:
+            dest = 32;
+            break;
+    }
+
+    if (dest < 32) {
+        set_global_pointer(saved_global_pointer);
+        current_dynamic_space_free_pointer =
+            (lispobj *) context->sc_regs[ALLOC];
+
+        context->sc_regs[dest] = alloc_number(result);
+
+	context->sc_regs[ALLOC] =
+	    (unsigned long) current_dynamic_space_free_pointer;
+
+        arch_skip_instruction(context);
+
+    }
+    else
+        interrupt_handle_now(signal, code, context);
+}
+
+void arch_install_interrupt_handlers()
+{
+    interrupt_install_low_level_handler(SIGTRAP,sigtrap_handler);
+    interrupt_install_low_level_handler(SIGEMT,sigemt_handler);
+}
diff --git a/ldb/mips-lispregs.h b/ldb/mips-lispregs.h
new file mode 100644
index 0000000000000000000000000000000000000000..613ce2a0f6d77cc5ec25024f224834560183c244
--- /dev/null
+++ b/ldb/mips-lispregs.h
@@ -0,0 +1,50 @@
+/* $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/ldb/Attic/mips-lispregs.h,v 1.1 1991/05/24 18:46:15 wlott Exp $ */
+
+#ifdef LANGUAGE_ASSEMBLY
+#define REG(num) $num
+#else
+#define REG(num) num
+#endif
+
+#define NREGS	(32)
+
+#define ZERO    REG(0)
+#define NL3     REG(1)
+#define NL4     REG(2)
+#define FLAGS   REG(3)
+#define NL0     REG(4)
+#define NL1     REG(5)
+#define NL2     REG(6)
+#define NARGS   REG(7)
+#define A0      REG(8)
+#define A1      REG(9)
+#define A2      REG(10)
+#define A3      REG(11)
+#define A4      REG(12)
+#define A5      REG(13)
+#define CNAME   REG(14)
+#define LEXENV  REG(15)
+#define NFP     REG(16)
+#define OCFP    REG(17)
+#define LRA     REG(18)
+#define L0      REG(19)
+#define NULLREG REG(20)
+#define BSP     REG(21)
+#define CFP     REG(22)
+#define CSP     REG(23)
+#define L1      REG(24)
+#define ALLOC   REG(25)
+#define L2      REG(28)
+#define NSP     REG(29)
+#define CODE    REG(30)
+#define LIP     REG(31)
+
+#define REGNAMES \
+	"ZERO",		"NL3",		"NL4",		"FLAGS", \
+	"NL0",		"NL1",		"NL2",		"NARGS", \
+	"A0",		"A1",		"A2",		"A3", \
+	"A4",		"A5",		"CNAME",       	"LEXENV", \
+	"NFP",		"OCFP",		"LRA",		"L0", \
+	"NULL",		"BSP",		"CFP",		"CSP", \
+	"L1",		"ALLOC",	"K0",		"K1", \
+	"L2",		"NSP",		"CODE",		"LIP"
diff --git a/ldb/os-common.c b/ldb/os-common.c
new file mode 100644
index 0000000000000000000000000000000000000000..9efd0332882cacef478298f4a340581003b98a76
--- /dev/null
+++ b/ldb/os-common.c
@@ -0,0 +1,88 @@
+#include <stdio.h>
+
+#include "ldb.h"
+#include "os.h"
+
+void os_zero(addr, length)
+os_vm_address_t addr;
+os_vm_size_t length;
+{
+    os_vm_address_t block_start;
+    os_vm_size_t block_size;
+
+#ifdef DEBUG
+    fprintf(stderr,";;; os_zero: addr: 0x%08x, len: 0x%08x\n",addr,length);
+#endif
+
+    block_start=os_round_up_to_page(addr);
+
+    length-=block_start-addr;
+    block_size=os_trunc_size_to_page(length);
+
+    if(block_start>addr)
+	bzero((char *)addr,block_start-addr);
+    if(block_size<length)
+	bzero((char *)block_start+block_size,length-block_size);
+    
+    if (block_size != 0) {
+	/* Now deallocate and allocate the block so that it */
+	/* faults in  zero-filled. */
+
+	os_invalidate(block_start,block_size);
+	addr=os_validate(block_start,block_size);
+
+	if(addr==NULL || addr!=block_start)
+	    fprintf(stderr,"os_zero: block moved, 0x%08x ==> 0x%08x!\n",block_start,addr);
+    }
+}
+
+os_vm_address_t os_allocate(len)
+os_vm_size_t len;
+{
+    return os_validate((os_vm_address_t)NULL,len);
+}
+
+void os_deallocate(addr,len)
+os_vm_address_t addr;
+os_vm_size_t len;
+{
+    os_invalidate(addr,len);
+}
+
+os_vm_address_t os_reallocate(addr,old_len,len)
+os_vm_address_t addr;
+os_vm_size_t old_len, len;
+{
+    addr=os_trunc_to_page(addr);
+    len=os_round_up_size_to_page(len);
+    old_len=os_round_up_size_to_page(old_len);
+
+    if(addr==NULL)
+	return os_allocate(len);
+    else{
+	long len_diff=old_len-len;
+	
+	if(len_diff<0)
+	    os_invalidate(addr+len,-len_diff);
+	else if(len_diff!=0){
+	    os_vm_address_t new=os_validate(addr+old_len,len_diff);
+
+	    if(new==NULL || new!=addr+old_len){
+		if(new!=NULL)
+		    /* allocated alright, but in the wrong place */
+		    os_invalidate(new,len_diff);
+
+		new=os_allocate(len);
+		
+		if(new!=NULL){
+		    bcopy(addr,new,old_len);
+		    os_invalidate(addr,old_len);
+		}
+		
+		addr=new;
+	    }
+	}
+	
+	return addr;
+    }
+}
diff --git a/ldb/rt-lispregs.h b/ldb/rt-lispregs.h
new file mode 100644
index 0000000000000000000000000000000000000000..c3254700b5336704eb20109a779d16e3d14e3cf6
--- /dev/null
+++ b/ldb/rt-lispregs.h
@@ -0,0 +1,32 @@
+/* $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/ldb/Attic/rt-lispregs.h,v 1.1 1991/05/24 18:46:09 wlott Exp $ */
+
+#ifdef LANGUAGE_ASSEMBLY
+#define REG(num) r/**/num
+#else
+#define REG(num) num
+#endif
+
+#define NREGS	(16)
+
+#define NARGS	REG(0)
+#define NSP	REG(1)
+#define NL0	REG(2)
+#define OCFP	REG(3)
+#define NFP	REG(4)
+#define CSP	REG(5)
+#define CFP	REG(6)
+#define CODE	REG(7)
+#define NULLREG	REG(8)
+#define CNAME	REG(9)
+#define LEXENV	REG(10)
+#define LRA	REG(11)
+#define A0	REG(12)
+#define A1	REG(13)
+#define A2	REG(14)
+#define LIP	REG(15)
+
+#define REGNAMES \
+	"NARGS",	"NSP",		"NL0",		"OCFP", \
+	"NFP",		"CSP",		"CFP",		"CODE", \
+	"NULL",		"CNAME",	"LEXENV",	"LRA", \
+	"A0",		"A1",		"A2",		"LIP"
diff --git a/ldb/sparc-arch.c b/ldb/sparc-arch.c
new file mode 100644
index 0000000000000000000000000000000000000000..666f8cd50988366a95df2de821ea8d6fe780b568
--- /dev/null
+++ b/ldb/sparc-arch.c
@@ -0,0 +1,168 @@
+#include <machine/trap.h>
+
+#include "ldb.h"
+#include "lisp.h"
+#include "globals.h"
+#include "validate.h"
+#include "os.h"
+#include "arch.h"
+#include "lispregs.h"
+#include "signal.h"
+
+void arch_init()
+{
+}
+
+os_vm_address_t arch_get_bad_addr(context)
+struct sigcontext *context;
+{
+    unsigned long badinst;
+    int rs1;
+
+    /* On the sparc, we have to decode the instruction. */
+
+    /* Make sure it's not the pc thats bogus, and that it was lisp code */
+    /* that caused the fault. */
+    if ((context->sc_pc & 3) != 0 ||
+	((context->sc_pc < READ_ONLY_SPACE_START ||
+	  context->sc_pc >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) &&
+	 ((lispobj *)context->sc_pc < current_dynamic_space &&
+	  (lispobj *)context->sc_pc >=
+	      current_dynamic_space + DYNAMIC_SPACE_SIZE)))
+	return NULL;
+
+    badinst = *(unsigned long *)context->sc_pc;
+
+    if ((badinst >> 30) != 3)
+	/* All load/store instructions have op = 11 (binary) */
+	return NULL;
+
+    rs1 = (badinst>>14)&0x1f;
+
+    if (badinst & (1<<13)) {
+	/* r[rs1] + simm(13) */
+	int simm13 = badinst & 0x1fff;
+
+	if (simm13 & (1<<12))
+	    simm13 |= -1<<13;
+
+	return (os_vm_address_t)(context->sc_regs[rs1] + simm13);
+    }
+    else {
+	/* r[rs1] + r[rs2] */
+	int rs2 = badinst & 0x1f;
+
+	return (os_vm_address_t)(context->sc_regs[rs1] + context->sc_regs[rs2]);
+    }
+
+}
+
+void arch_skip_instruction(context)
+struct sigcontext *context;
+{
+    /* Skip the offending instruction */
+    context->sc_pc = context->sc_npc;
+    context->sc_npc += 4;
+}
+
+static void sigill_handler(signal, code, context)
+int signal, code;
+struct sigcontext *context;
+{
+    int badinst;
+
+    if (code == T_UNIMP_INSTR) {
+	int trap;
+
+	trap = *(unsigned long *)(context->sc_pc) & 0x3fffff;
+
+	switch (trap) {
+	  case trap_PendingInterrupt:
+	    interrupt_handle_pending(context);
+	    break;
+
+	  case trap_Halt:
+	    crap_out("%primitive halt called; the party is over.\n");
+
+	  case trap_Error:
+	  case trap_Cerror:
+	    interrupt_internal_error(signal, code, context, trap == trap_Cerror);
+	    break;
+
+	  default:
+	    interrupt_handle_now(signal, code, context);
+	    break;
+	}
+    }
+    else if (code >= T_SOFTWARE_TRAP + 16 & code < T_SOFTWARE_TRAP + 32)
+	interrupt_internal_error(signal, code, context, FALSE);
+    else
+	interrupt_handle_now(signal, code, context);
+}
+
+static void sigemt_handler(signal, code, context)
+     int signal, code;
+     struct sigcontext *context;
+{
+    unsigned long badinst;
+    boolean subtract, immed;
+    int rd, rs1, op1, rs2, op2, result;
+
+    badinst = *(unsigned long *)context->sc_pc;
+    if ((badinst >> 30) != 2 || ((badinst >> 20) & 0x1f) != 0x11) {
+	/* It wasn't a tagged add.  Pass the signal into lisp. */
+	interrupt_handle_now(signal, code, context);
+	return;
+    }
+	
+    /* Extract the parts of the inst. */
+    subtract = badinst & (1<<19);
+    rs1 = (badinst>>14) & 0x1f;
+    op1 = context->sc_regs[rs1];
+    if ((op1 & 3) != 0) {
+	/* The first arg wan't a fixnum. */
+	interrupt_internal_error(signal, code, context, FALSE);
+	return;
+    }
+
+    if (immed = badinst & (1<<13)) {
+	op2 = badinst & 0x1fff;
+	if (op2 & (1<<12))
+	    op2 |= -1<<13;
+    }
+    else {
+	rs2 = badinst & 0x1f;
+	op2 = context->sc_regs[rs2];
+    }
+
+    if ((op2 & 3) != 0) {
+	/* The second arg wan't a fixnum. */
+	interrupt_internal_error(signal, code, context, FALSE);
+	return;
+    }
+
+    rd = (badinst>>25) & 0x1f;
+    if (rd != 0) {
+	/* Don't bother computing the result unless we are going to use it. */
+	if (subtract)
+	    result = (op1>>2) - (op2>>2);
+	else
+	    result = (op1>>2) + (op2>>2);
+
+        current_dynamic_space_free_pointer =
+            (lispobj *) context->sc_regs[ALLOC];
+
+	context->sc_regs[rd] = alloc_number(result);
+
+	context->sc_regs[ALLOC] =
+	    (unsigned long) current_dynamic_space_free_pointer;
+    }
+
+    arch_skip_instruction(context);
+}
+
+void arch_install_interrupt_handlers()
+{
+    interrupt_install_low_level_handler(SIGILL,sigill_handler);
+    interrupt_install_low_level_handler(SIGEMT,sigemt_handler);
+}
diff --git a/ldb/sparc-lispregs.h b/ldb/sparc-lispregs.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc9bad42308d69052a3650e3adbe21df06cc49fc
--- /dev/null
+++ b/ldb/sparc-lispregs.h
@@ -0,0 +1,64 @@
+/* $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/ldb/Attic/sparc-lispregs.h,v 1.1 1991/05/24 18:45:57 wlott Exp $ */
+
+#ifdef LANGUAGE_ASSEMBLY
+
+#define GREG(num) %g/**/num
+#define OREG(num) %o/**/num
+#define LREG(num) %l/**/num
+#define IREG(num) %i/**/num
+
+#else
+
+#define GREG(num) (num)
+#define OREG(num) ((num)+8)
+#define LREG(num) ((num)+16)
+#define IREG(num) ((num)+24)
+
+#endif
+
+#define NREGS	(32)
+
+#define ZERO	GREG(0)
+#define ALLOC	GREG(1)
+#define NULLREG	GREG(2)
+#define CSP	GREG(3)
+#define CFP	GREG(4)
+#define BSP	GREG(5)
+#define NFP	GREG(6)
+#define CFUNC	GREG(7)
+
+#define NL0	OREG(0)
+#define NL1	OREG(1)
+#define NL2	OREG(2)
+#define NL3	OREG(3)
+#define NL4	OREG(4)
+#define NL5	OREG(5)
+#define NSP	OREG(6)
+#define NARGS	OREG(7)
+
+#define A0	LREG(0)
+#define A1	LREG(1)
+#define A2	LREG(2)
+#define A3	LREG(3)
+#define A4	LREG(4)
+#define A5	LREG(5)
+#define OCFP	LREG(6)
+#define LRA	LREG(7)
+
+#define CNAME	IREG(0)
+#define LEXENV	IREG(1)
+#define L0	IREG(2)
+#define L1	IREG(3)
+#define L2	IREG(4)
+#define CODE	IREG(5)
+#define LIP	IREG(7)
+
+#define REGNAMES \
+	"ZERO",		"ALLOC",	"NULL",		"CSP", \
+	"CFP",		"BSP",		"NFP",		"CFUNC", \
+        "NL0",		"NL1",		"NL2",		"NL3", \
+        "NL4",		"NL5",		"NSP",		"NARGS", \
+        "A0",		"A1",		"A2",		"A3", \
+        "A4",		"A5",		"OCFP",		"LRA", \
+        "CNAME",	"LEXENV",	"L0",		"L1", \
+        "L2",		"CODE",		"???",		"LIP"
diff --git a/ldb/sunos-os.c b/ldb/sunos-os.c
new file mode 100644
index 0000000000000000000000000000000000000000..2cc9bd48e31cb1a8a5826adf6a369d5f6c6a607b
--- /dev/null
+++ b/ldb/sunos-os.c
@@ -0,0 +1,678 @@
+/*
+ * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/ldb/Attic/sunos-os.c,v 1.1 1991/05/24 18:43:45 wlott 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 SunOS version.
+ * March 1991, Miles Bader <miles@cogsci.ed.ack.uk> & ted <ted@edu.NMSU>
+ *
+ */
+
+/* #define DEBUG */
+
+#include <stdio.h>
+
+#include <signal.h>
+#include <sys/file.h>
+
+#include "ldb.h"
+#include "os.h"
+
+/* block size must be larger than the system page size */
+#define SPARSE_BLOCK_SIZE (1<<15)
+#define SPARSE_SIZE_MASK (SPARSE_BLOCK_SIZE-1)
+
+#define PROT_DEFAULT OS_VM_PROT_ALL
+
+#define OFFSET_NONE ((os_vm_offset_t)(~0))
+
+#define EMPTYFILE "/tmp/empty"
+#define ZEROFILE "/dev/zero"
+
+#define MAX_SEGS 64
+
+/* ---------------------------------------------------------------- */
+
+#define ADJ_OFFSET(off,adj) (((off)==OFFSET_NONE) ? OFFSET_NONE : ((off)+(adj)))
+
+long os_vm_page_size=(-1);
+
+static struct segment {
+    os_vm_address_t start;	/* note: start & length are expected to be on page */
+    os_vm_size_t length;        /*       boundaries */
+    long file_offset;
+    short mapped_fd;
+    short protection;
+} addr_map[MAX_SEGS];
+
+static int n_segments=0;
+
+static int zero_fd=(-1), empty_fd=(-1);
+
+static os_vm_address_t last_fault=0;
+static os_vm_size_t real_page_size_difference=0;
+
+void os_init()
+{
+    void sunos_segv_handler();
+
+    zero_fd=open(ZEROFILE,O_RDONLY);
+
+    empty_fd=open(EMPTYFILE,O_RDONLY|O_CREAT);
+    unlink(EMPTYFILE);
+
+    os_vm_page_size=getpagesize();
+
+    if(os_vm_page_size>OS_VM_DEFAULT_PAGESIZE){
+	fprintf(stderr,"os_init: Pagesize too large (%d > %d)\n",
+		os_vm_page_size,OS_VM_DEFAULT_PAGESIZE);
+	exit(1);
+    }else{
+	/*
+	 * we do this because there are apparently dependencies on
+	 * the pagesize being OS_VM_DEFAULT_PAGESIZE somewhere...
+	 * but since the OS doesn't know we're using this restriction,
+	 * we have to grovel around a bit to enforce it, thus anything
+	 * that uses real_page_size_difference.
+	 */
+	real_page_size_difference=OS_VM_DEFAULT_PAGESIZE-os_vm_page_size;
+	os_vm_page_size=OS_VM_DEFAULT_PAGESIZE;
+    }
+}
+
+/* ---------------------------------------------------------------- */
+
+void seg_force_resident(seg,addr,len)
+struct segment *seg;
+os_vm_address_t addr;
+os_vm_size_t len;
+{
+    int prot=seg->protection;
+
+    if(prot!=0){
+	os_vm_address_t end=addr+len, touch=addr;
+		
+	while(touch<end){
+	    int contents=(*(char *)touch);
+	    if(prot&OS_VM_PROT_WRITE)
+		(*(char *)touch)=contents;
+	    touch=(os_vm_address_t)(((long)touch+SPARSE_BLOCK_SIZE)&~SPARSE_SIZE_MASK);
+	}
+    }
+}
+
+static struct segment *seg_create_nomerge(addr,len,protection,mapped_fd,file_offset)
+os_vm_address_t addr;
+os_vm_size_t len;
+int protection;
+int mapped_fd;
+{
+    int n;
+    struct segment *seg;
+
+    if(len==0)
+	return NULL;
+
+    if(n_segments==MAX_SEGS){
+	fprintf(stderr,"seg_create_nomerge: Out of segments\n");
+	return NULL;
+    }
+
+    for(n=n_segments, seg=addr_map; n>0; n--, seg++)
+	if(addr<seg->start){
+	    seg=(&addr_map[n_segments]);
+	    while(n-->0){
+		seg[0]=seg[-1];
+		seg--;
+	    }
+	    break;
+	}
+
+    n_segments++;
+
+    seg->start=addr;
+    seg->length=len;
+    seg->protection=protection;
+    seg->mapped_fd=mapped_fd;
+    seg->file_offset=file_offset;
+
+    return seg;
+}
+
+/* returns the first segment containing addr */
+static struct segment *seg_find(addr)
+os_vm_address_t addr;
+{
+    int n;
+    struct segment *seg;
+
+    for(n=n_segments, seg=addr_map; n>0; n--, seg++)
+	if(seg->start<=addr && seg->start+seg->length>addr)
+	    return seg;
+
+    return NULL;
+}
+
+/* returns TRUE if the range from addr to addr+len intersects with any segment */
+static boolean collides_with_seg_p(addr,len)
+os_vm_address_t addr;
+os_vm_size_t len;
+{
+    int n;
+    struct segment *seg;
+    os_vm_address_t end=addr+len;
+
+    for(n=n_segments, seg=addr_map; n>0; n--, seg++)
+	if(seg->start>=end)
+	    return FALSE;
+	else if(seg->start+seg->length>addr)
+	    return TRUE;
+
+    return FALSE;
+}
+
+#define seg_last_p(seg) (((seg)-addr_map)>=n_segments-1)
+
+static void seg_destroy(seg)
+struct segment *seg;
+{
+    if(seg!=NULL){
+	int n;
+
+	for(n=seg-addr_map+1; n<n_segments; n++){
+	    seg[0]=seg[1];
+	    seg++;
+	}
+
+	n_segments--;
+    }
+}
+
+static void seg_try_merge_next(seg)
+struct segment *seg;
+{
+    struct segment *nseg=seg+1;
+
+    if(!seg_last_p(seg)
+       && seg->start+seg->length==nseg->start
+       && seg->protection==nseg->protection
+       && seg->mapped_fd==nseg->mapped_fd
+       && ADJ_OFFSET(seg->file_offset,seg->length)==nseg->file_offset)
+    {
+	/* can merge with the next segment */
+#ifdef DEBUG
+	fprintf(stderr,
+		";;; seg_try_merge: Merged 0x%08x[0x%08x] with 0x%08x[0x%08x]\n",
+		seg->start,seg->length,nseg->start,nseg->length);
+#endif
+
+	if(((long)nseg->start&SPARSE_SIZE_MASK)!=0){
+	    /*
+	     * if not on a block boundary, we have to ensure both parts
+	     * of a common block are in a known state
+	     */
+	    seg_force_resident(seg,nseg->start-1,1);
+	    seg_force_resident(nseg,nseg->start,1);
+	}
+
+	seg->length+=nseg->length;
+	seg_destroy(nseg);
+    }
+}
+
+
+/*
+ * Try to merge seg with adjacent segments.
+ */
+static void seg_try_merge_adjacent(seg)
+struct segment *seg;
+{
+    if(!seg_last_p(seg))
+	seg_try_merge_next(seg);
+    if(seg>addr_map)
+	seg_try_merge_next(seg-1);
+}
+
+static struct segment *seg_create(addr,len,protection,mapped_fd,file_offset)
+os_vm_address_t addr;
+os_vm_size_t len;
+int protection;
+int mapped_fd;
+{
+    struct segment *seg=seg_create_nomerge(addr,len,protection,mapped_fd,file_offset);
+    if(seg!=NULL)
+	seg_try_merge_adjacent(seg);
+    return seg;
+}
+
+/* 
+ * Change the attributes of the given range of an existing segment, and return
+ * a segment corresponding to the new bit.
+ */
+static struct segment *seg_change_range(seg,addr,len,protection,mapped_fd,file_offset)
+struct segment *seg;
+os_vm_address_t addr;
+os_vm_size_t len;
+int protection;
+int mapped_fd;
+{
+    os_vm_address_t end=addr+len;
+
+    if(len==0)
+	return NULL;
+
+    if(protection!=seg->protection
+       || mapped_fd!=seg->mapped_fd
+       || file_offset!=ADJ_OFFSET(seg->file_offset,addr-seg->start))
+    {
+	os_vm_size_t old_len=seg->length, seg_offset=(addr-seg->start);
+	
+	if(old_len<len+seg_offset){
+	    struct segment *next=seg+1;
+	    
+#ifdef DEBUG
+	    fprintf(stderr,
+		    ";;; seg_change_range: region 0x%08x[0x%08x] overflows 0x%08x[0x%08x]\n",
+		    addr,len,
+		    seg->start,old_len);
+#endif
+	    
+	    while(!seg_last_p(seg) && next->start+next->length<=end){
+#ifdef DEBUG
+		fprintf(stderr,
+			";;; seg_change_range: merging extra segment 0x%08x[0x%08x]\n",
+			next->start,
+			next->length);
+#endif
+		seg_destroy(next);
+	    }
+	    
+	    if(!seg_last_p(seg) && next->start<end){
+		next->length-=end-next->start;
+		next->start=end;
+		old_len=next->start-seg->start;
+	    }else
+		old_len=len+seg_offset;
+	    
+#ifdef DEBUG
+	    fprintf(stderr,
+		    ";;; seg_change_range: extended first seg to 0x%08x[0x%08x]\n",
+		    seg->start,
+		    old_len);
+#endif
+	}
+
+	if(seg_offset+len<old_len){
+	    /* add second part of old segment */
+	    seg_create_nomerge(end,
+			       old_len-(seg_offset+len),
+			       seg->protection,
+			       seg->mapped_fd,
+			       ADJ_OFFSET(seg->file_offset,seg_offset+len));
+
+#ifdef DEBUG
+	    fprintf(stderr,
+		    ";;; seg_change_range: Split off end of 0x%08x[0x%08x]: 0x%08x[0x%08x]\n",
+		    seg->start,old_len,
+		    end,old_len-(seg_offset+len));
+#endif
+	}
+
+	if(seg_offset==0){
+	    seg->length=len;
+	    seg->protection=protection;
+	    seg->mapped_fd=mapped_fd;
+	    seg->file_offset=file_offset;
+	}else{
+	    /* adjust first part of remaining old segment */
+	    seg->length=seg_offset;
+
+#ifdef DEBUG
+	    fprintf(stderr,
+		    ";;; seg_change_range: Split off beginning of 0x%08x[0x%08x]: 0x%08x[0x%08x]\n",
+		    seg->start,old_len,
+		    seg->start,seg_offset);
+#endif
+
+	    /* add new middle segment for new protected region */
+	    seg=seg_create_nomerge(addr,len,protection,mapped_fd,file_offset);
+	}
+
+	seg_try_merge_adjacent(seg);
+
+	last_fault=0;
+    }
+
+    return seg;
+}
+
+/* ---------------------------------------------------------------- */
+
+static os_vm_address_t mapin(addr,len,protection,map_fd,offset,is_readable)
+os_vm_address_t addr;
+os_vm_size_t len;
+int protection;
+int map_fd;
+long offset;
+int is_readable;
+{
+    os_vm_address_t real;
+    boolean sparse=(len>=SPARSE_BLOCK_SIZE);
+
+    if(offset!=OFFSET_NONE
+       && (offset<os_vm_page_size || (offset&(os_vm_page_size-1))!=0))
+    {
+	fprintf(stderr,
+		"mapin: file offset (%d) not multiple of pagesize (%d)\n",
+		offset,
+		os_vm_page_size);
+    }
+
+    if(addr==NULL)
+	len+=real_page_size_difference;	/* futz around to get an aligned region */
+
+    last_fault=0;
+    real=(os_vm_address_t)
+	mmap((caddr_t)addr,
+	     (long)len,
+	     sparse ? (is_readable ? PROT_READ : 0) : protection,
+	     (addr==NULL? 0 : MAP_FIXED)|MAP_PRIVATE,
+	     (is_readable || !sparse) ? map_fd : empty_fd,
+	     (off_t)(offset==OFFSET_NONE ? 0 : offset));
+
+    if((long)real==-1){
+	perror("mapin: mmap");
+	return NULL;
+    }
+
+    if(addr==NULL){
+	/*
+	 * now play around with what the os gave us to make it align by
+	 * our standards (which is why we overallocated)
+	 */
+	os_vm_size_t overflow;
+
+	addr=os_round_up_to_page(real);
+	if(addr!=real)
+	    munmap(real,addr-real);
+	
+	overflow=real_page_size_difference-(addr-real);
+	if(overflow!=0)
+	    munmap(addr+len-real_page_size_difference,overflow);
+
+	real=addr;
+    }
+
+
+    return real;
+}
+
+static os_vm_address_t map_and_remember(addr,len,protection,map_fd,offset,is_readable)
+os_vm_address_t addr;
+os_vm_size_t len;
+int protection;
+int map_fd;
+long offset;
+int is_readable;
+{
+    os_vm_address_t real=mapin(addr,len,protection,map_fd,offset,is_readable);
+
+    if(real!=NULL){
+	struct segment *seg=seg_find(real);
+
+	if(seg!=NULL)
+	    seg=seg_change_range(seg,real,len,protection,map_fd,offset);
+	else
+	    seg=seg_create(real,len,protection,map_fd,offset);
+
+	if(seg==NULL){
+	    munmap(real,len);
+	    return NULL;
+	}
+    }
+
+#ifdef DEBUG
+    fprintf(stderr,";;; map_and_remember: 0x%08x[0x%08x] offset: %d, mapped to: %d\n",
+	    real,len,offset,map_fd);
+#endif
+
+    return real;
+}
+
+/* ---------------------------------------------------------------- */
+
+os_vm_address_t os_validate(addr, len)
+os_vm_address_t addr;
+os_vm_size_t len;
+{
+    addr=os_trunc_to_page(addr);
+    len=os_round_up_size_to_page(len);
+
+#ifdef DEBUG
+    fprintf(stderr, ";;; os_validate: 0x%08x[0x%08x]\n",addr,len);
+#endif
+
+    if(addr!=NULL && collides_with_seg_p(addr,len))
+	return NULL;
+
+    return map_and_remember(addr,len,PROT_DEFAULT,zero_fd,OFFSET_NONE,FALSE);
+}
+
+void os_invalidate(addr, len)
+os_vm_address_t addr;
+os_vm_size_t len;
+{
+    struct segment *seg=seg_find(addr);
+
+    addr=os_trunc_to_page(addr);
+    len=os_round_up_size_to_page(len);
+
+#ifdef DEBUG
+    fprintf(stderr, ";;; os_invalidate: 0x%08x[0x%08x]\n",addr,len);
+#endif
+
+    if(seg==NULL)
+	fprintf(stderr, "os_invalidate: Unknown segment: 0x%08x[0x%08x]\n",addr,len);
+    else{
+	seg=seg_change_range(seg,addr,len,0,0,OFFSET_NONE);
+	if(seg!=NULL)
+	    seg_destroy(seg);
+
+	last_fault=0;
+	if(munmap(addr,len)!=0)
+	    perror("os_invalidate: munmap");
+    }
+}
+
+os_vm_address_t os_map(fd, offset, addr, len)
+int fd;
+os_vm_offset_t offset;
+os_vm_address_t addr;
+long len;
+{
+    addr=os_trunc_to_page(addr);
+    len=os_round_up_size_to_page(len);
+
+#ifdef DEBUG
+    fprintf(stderr, ";;; os_map: 0x%08x[0x%08x]\n",addr,len);
+#endif
+
+    return map_and_remember(addr,len,PROT_DEFAULT,fd,offset,TRUE);
+}
+
+void os_flush_icache(address, length)
+os_vm_address_t address;
+os_vm_size_t length;
+{
+#if defined(MACH) && defined(mips)
+	vm_machine_attribute_val_t flush;
+	kern_return_t kr;
+
+	flush = MATTR_VAL_ICACHE_FLUSH;
+
+	kr = vm_machine_attribute(task_self(), address, length,
+				  MATTR_CACHE, &flush);
+	if (kr != KERN_SUCCESS)
+		mach_error("Could not flush the instruction cache", kr);
+#endif
+}
+
+void os_protect(addr, len, prot)
+os_vm_address_t addr;
+os_vm_size_t len;
+int prot;
+{
+    struct segment *seg=seg_find(addr);
+
+    addr=os_trunc_to_page(addr);
+    len=os_round_up_size_to_page(len);
+
+#ifdef DEBUG
+    fprintf(stderr,";;; os_protect: 0x%08x[0x%08x]\n",addr,len);
+#endif
+
+    if(seg!=NULL){
+	int old_prot=seg->protection;
+
+	if(prot!=old_prot){
+	    /*
+	     * oooooh, sick: we have to make sure all the pages being protected have
+	     * faulted in, so they're in a known state...
+	     */
+	    seg_force_resident(seg,addr,len);
+
+	    seg_change_range(seg,addr,len,prot,seg->mapped_fd,seg->file_offset);
+
+	    if(mprotect((caddr_t)addr,(long)len,prot)!=0)
+		perror("os_unprotect: mprotect");
+	}
+    }else
+	fprintf(stderr,"os_protect: Unknown segment: 0x%08x[0x%08x]\n",addr,len);
+}
+
+boolean valid_addr(test)
+os_vm_address_t test;
+{
+    return seg_find(test)!=NULL;
+}
+
+/* ---------------------------------------------------------------- */
+
+static boolean maybe_gc(context)
+struct sigcontext *context;
+{
+    /*
+     * It's necessary to enable recursive SEGVs, since the handle is
+     * used for multiple things (e.g., both gc-trigger & faulting in pages).
+     * We check against recursive gc's though...
+     */
+
+    boolean did_gc;
+    static already_trying=0;
+
+    if(already_trying)
+	return FALSE;
+
+    sigsetmask(context->sc_mask);
+
+    already_trying=TRUE;
+    did_gc=interrupt_maybe_gc(context);
+    already_trying=FALSE;
+
+    return did_gc;
+}
+
+/*
+ * The primary point of catching segmentation violations is to allow 
+ * read only memory to be re-mapped with more permissions when a write
+ * is attempted.  this greatly decreases the residency of the program
+ * in swap space since read only areas don't take up room
+ *
+ * Running into the gc trigger page will also end up here...
+ */
+void segv_handler(sig, code, context, addr)
+int sig, code;
+struct sigcontext *context;
+caddr_t addr;
+{
+    if (code == SEGV_PROT) {	/* allow writes to this chunk */
+	struct segment *seg=seg_find(addr);
+
+	if(last_fault==addr){
+	    if(seg!=NULL && maybe_gc(context))
+		/* we just garbage collected */
+		return;
+	    else{
+		/* a *real* protection fault */
+		fprintf(stderr,
+			"segv_handler: Real protection violation: 0x%08x\n",
+			addr);
+		interrupt_handle_now(sig,code,context);
+	    }
+	}else
+	    last_fault=addr;
+
+	if(seg!=NULL){
+	    int err;
+	    /* round down to a page */
+	    os_vm_address_t block=(os_vm_address_t)((long)addr&~SPARSE_SIZE_MASK);
+	    os_vm_size_t length=SPARSE_BLOCK_SIZE;
+
+	    if(block < seg->start){
+		length-=(seg->start - block);
+		block=seg->start;
+	    }
+	    if(block+length > seg->start+seg->length)
+		length=seg->start+seg->length-block;
+
+#if 0
+	    /* unmap it.  probably redundant. */
+	    if(munmap(block,length) == -1)
+		perror("segv_handler: munmap");
+#endif
+
+	    /* and remap it with more permissions */
+	    err=(int)
+		mmap(block,
+		     length,
+		     seg->protection,
+		     MAP_PRIVATE|MAP_FIXED,
+		     seg->mapped_fd,
+		     seg->file_offset==OFFSET_NONE
+		       ? 0
+		       : seg->file_offset+(block-seg->start));
+
+	    if (err == -1) {
+		perror("segv_handler: mmap");
+		interrupt_handle_now(sig,code,context);
+	    }
+	}
+	else{
+	    fprintf(stderr, "segv_handler: 0x%08x not in any segment\n",addr);
+	    interrupt_handle_now(sig,code,context);
+	}
+    }
+    /*
+     * note that we check for a gc-trigger hit even if it's not a PROT error
+     */
+    else if(!maybe_gc(context)){
+	if(code == SEGV_NOMAP)
+	    fprintf(stderr, "segv_handler: No mapping fault: 0x%08x\n",addr);
+	else if (SEGV_CODE(code) == SEGV_OBJERR) {
+	    extern int errno;
+	    errno=SEGV_ERRNO(code);
+	    perror("segv_handler: Object error");
+	}
+
+	interrupt_handle_now(sig,code,context);
+    }
+}
+
+void os_install_interrupt_handlers()
+{
+    interrupt_install_low_level_handler(SIGSEGV,segv_handler);
+}
diff --git a/ldb/sunos-os.h b/ldb/sunos-os.h
new file mode 100644
index 0000000000000000000000000000000000000000..85992579bfa93163c8befaa8d9bbea78b1446eb2
--- /dev/null
+++ b/ldb/sunos-os.h
@@ -0,0 +1,13 @@
+#include <sys/types.h>
+#include <sys/mman.h>
+
+typedef caddr_t os_vm_address_t;
+typedef long os_vm_size_t;
+typedef off_t os_vm_offset_t;
+typedef int os_vm_prot_t;
+
+#define OS_VM_PROT_READ PROT_READ
+#define OS_VM_PROT_WRITE PROT_WRITE
+#define OS_VM_PROT_EXECUTE PROT_EXEC
+
+#define OS_VM_DEFAULT_PAGESIZE	8192