Update of /cvsroot/sbcl/sbcl/src/runtime
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20005/src/runtime
Added Files:
Tag: x86-64-again-branch
x86-64-arch.c x86-64-arch.h x86-64-assem.S x86-64-linux-os.c
x86-64-linux-os.h x86-64-lispregs.h
Log Message:
"The good news is that in 1995 we will have a good operating
system and programming language; the bad news is that they
will be Unix and C++."
Expunge bits of long-float support as and when we see it
Cold boot doesn't need complex numbers (I think; at least,
don't need them yet) so temprarily comment out the definitions
of realpart and imagpart
c-call for an x86-64 looks remarkably like that for an x86.
We should find a better target-feature for "uses alien stack"
than (or x86 x86-64)
some 64 vs 32 bit issues in primtype still need working
through
add FP-{SINGLE,DOUBLE}-ZERO IMMEDIATE-CONSTANTs: currently we
reserve xmm15 for that purpose
movzx won't load a short immediate number and zero-extend it;
substitute lea
comparison vops for floats had info args all ove the place:
tidy
new SINGLE-FLOAT-BITS, DOUBLE-FLOAT-HIGH-BITS, DOUBLE-FLOAT-LOW-BITS
vops
make REG-TN-ENCODING and EMIT-EA and all that stuff understand
FLOAT-REGISTERs
Various float VOP brainos, fixed
Added a bunch of files that missed CVS last time
--- NEW FILE: x86-64-arch.c ---
/*
* This software is part of the SBCL system. See the README file for
* more information.
*
* This software is derived from the CMU CL system, which was
* written at Carnegie Mellon University and released into the
* public domain. The software is in the public domain and is
* provided with absolutely no warranty. See the COPYING and CREDITS
* files for more information.
*/
#include <stdio.h>
#include "sbcl.h"
#include "runtime.h"
#include "globals.h"
#include "validate.h"
#include "os.h"
#include "sbcl.h"
#include "arch.h"
#include "lispregs.h"
#include "signal.h"
#include "alloc.h"
#include "interrupt.h"
#include "interr.h"
#include "breakpoint.h"
#include "monitor.h"
#include "thread.h"
#include "genesis/static-symbols.h"
#include "genesis/symbol.h"
#define BREAKPOINT_INST 0xcc /* INT3 */
unsigned long fast_random_state = 1;
void arch_init(void)
{}
/*
* hacking signal contexts
*
* (This depends both on architecture, which determines what we might
* want to get to, and on OS, which determines how we get to it.)
*/
int *
context_eflags_addr(os_context_t *context)
{
#if defined __linux__
/* KLUDGE: As of kernel 2.2.14 on Red Hat 6.2, there's code in the
* <sys/ucontext.h> file to define symbolic names for offsets into
* gregs[], but it's conditional on __USE_GNU and not defined, so
* we need to do this nasty absolute index magic number thing
* instead. */
return &context->uc_mcontext.gregs[16];
#elif defined __FreeBSD__
return &context->uc_mcontext.mc_eflags;
#elif defined __OpenBSD__
return &context->sc_eflags;
#else
#error unsupported OS
#endif
}
void arch_skip_instruction(os_context_t *context)
{
/* Assuming we get here via an INT3 xxx instruction, the PC now
* points to the interrupt code (a Lisp value) so we just move
* past it. Skip the code; after that, if the code is an
* error-trap or cerror-trap then skip the data bytes that follow. */
int vlen;
int code;
/* Get and skip the Lisp interrupt code. */
code = *(char*)(*os_context_pc_addr(context))++;
switch (code)
{
case trap_Error:
case trap_Cerror:
/* Lisp error arg vector length */
vlen = *(char*)(*os_context_pc_addr(context))++;
/* Skip Lisp error arg data bytes. */
while (vlen-- > 0) {
( (char*)(*os_context_pc_addr(context)) )++;
}
break;
case trap_Breakpoint: /* not tested */
case trap_FunEndBreakpoint: /* not tested */
break;
case trap_PendingInterrupt:
case trap_Halt:
/* only needed to skip the Code */
break;
default:
fprintf(stderr,"[arch_skip_inst invalid code %d\n]\n",code);
break;
}
FSHOW((stderr,
"/[arch_skip_inst resuming at %x]\n",
*os_context_pc_addr(context)));
}
unsigned char *
arch_internal_error_arguments(os_context_t *context)
{
return 1 + (unsigned char *)(*os_context_pc_addr(context));
}
boolean
arch_pseudo_atomic_atomic(os_context_t *context)
{
return SymbolValue(PSEUDO_ATOMIC_ATOMIC,arch_os_get_current_thread());
}
void
arch_set_pseudo_atomic_interrupted(os_context_t *context)
{
SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(1),
arch_os_get_current_thread());
}
/*
* This stuff seems to get called for TRACE and debug activity.
*/
unsigned long
arch_install_breakpoint(void *pc)
{
unsigned long result = *(unsigned long*)pc;
*(char*)pc = BREAKPOINT_INST; /* x86 INT3 */
*((char*)pc+1) = trap_Breakpoint; /* Lisp trap code */
return result;
}
void
arch_remove_breakpoint(void *pc, unsigned long orig_inst)
{
*((char *)pc) = orig_inst & 0xff;
*((char *)pc + 1) = (orig_inst & 0xff00) >> 8;
}
/* When single stepping, single_stepping holds the original instruction
* PC location. */
unsigned int *single_stepping = NULL;
#ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
unsigned int single_step_save1;
unsigned int single_step_save2;
unsigned int single_step_save3;
#endif
void
arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
{
unsigned int *pc = (unsigned int*)(*os_context_pc_addr(context));
/* Put the original instruction back. */
*((char *)pc) = orig_inst & 0xff;
*((char *)pc + 1) = (orig_inst & 0xff00) >> 8;
#ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
/* Install helper instructions for the single step:
* pushf; or [esp],0x100; popf. */
single_step_save1 = *(pc-3);
single_step_save2 = *(pc-2);
single_step_save3 = *(pc-1);
*(pc-3) = 0x9c909090;
*(pc-2) = 0x00240c81;
*(pc-1) = 0x9d000001;
#else
*context_eflags_addr(context) |= 0x100;
#endif
single_stepping = (unsigned int*)pc;
#ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
*os_context_pc_addr(context) = (char *)pc - 9;
#endif
}
void
sigtrap_handler(int signal, siginfo_t *info, void *void_context)
{
int code = info->si_code;
os_context_t *context = (os_context_t*)void_context;
unsigned int trap;
sigset_t ss;
if (single_stepping && (signal==SIGTRAP))
{
/* fprintf(stderr,"* single step trap %x\n", single_stepping); */
#ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
/* Un-install single step helper instructions. */
*(single_stepping-3) = single_step_save1;
*(single_stepping-2) = single_step_save2;
*(single_stepping-1) = single_step_save3;
#else
*context_eflags_addr(context) ^= 0x100;
#endif
/* Re-install the breakpoint if possible. */
if (*os_context_pc_addr(context) == (int)single_stepping + 1) {
fprintf(stderr, "warning: couldn't reinstall breakpoint\n");
} else {
*((char *)single_stepping) = BREAKPOINT_INST; /* x86 INT3 */
*((char *)single_stepping+1) = trap_Breakpoint;
}
single_stepping = NULL;
return;
}
/* This is just for info in case the monitor wants to print an
* approximation. */
current_control_stack_pointer =
(lispobj *)*os_context_sp_addr(context);
/* FIXME: CMUCL puts the float control restoration code here.
Thus, it seems to me that single-stepping won't restore the
float control. Since SBCL currently doesn't support
single-stepping (as far as I can tell) this is somewhat moot,
but it might be worth either moving this code up or deleting
the single-stepping code entirely. -- CSR, 2002-07-15 */
#ifdef LISP_FEATURE_LINUX
os_restore_fp_control(context);
#endif
/* On entry %eip points just after the INT3 byte and aims at the
* 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a
* number of bytes will follow, the first is the length of the byte
* arguments to follow. */
trap = *(unsigned char *)(*os_context_pc_addr(context));
switch (trap) {
case trap_PendingInterrupt:
FSHOW((stderr, "/<trap pending interrupt>\n"));
arch_skip_instruction(context);
sigemptyset(&ss);
sigaddset(&ss,SIGTRAP);
sigprocmask(SIG_UNBLOCK,&ss,0);
interrupt_handle_pending(context);
break;
case trap_Halt:
/* Note: the old CMU CL code tried to save FPU state
* here, and restore it after we do our thing, but there
* seems to be no point in doing that, since we're just
* going to lose(..) anyway. */
fake_foreign_function_call(context);
lose("%%PRIMITIVE HALT called; the party is over.");
case trap_Error:
case trap_Cerror:
FSHOW((stderr, "<trap error/cerror %d>\n", code));
interrupt_internal_error(signal, info, context, code==trap_Cerror);
break;
case trap_Breakpoint:
(char*)(*os_context_pc_addr(context)) -= 1;
handle_breakpoint(signal, info, context);
break;
case trap_FunEndBreakpoint:
(char*)(*os_context_pc_addr(context)) -= 1;
*os_context_pc_addr(context) =
(int)handle_fun_end_breakpoint(signal, info, context);
break;
default:
FSHOW((stderr,"/[C--trap default %d %d %x]\n",
signal, code, context));
interrupt_handle_now(signal, info, context);
break;
}
}
static void
sigill_handler(int signal, siginfo_t *siginfo, void *void_context) {
os_context_t *context = (os_context_t*)void_context;
fake_foreign_function_call(context);
monitor_or_something();
}
void
arch_install_interrupt_handlers()
{
SHOW("entering arch_install_interrupt_handlers()");
/* Note: The old CMU CL code here used sigtrap_handler() to handle
* SIGILL as well as SIGTRAP. I couldn't see any reason to do
* things that way. So, I changed to separate handlers when
* debugging a problem on OpenBSD, where SBCL wasn't catching
* SIGILL properly, but was instead letting the process be
* terminated with an "Illegal instruction" output. If this change
* turns out to break something (maybe breakpoint handling on some
* OS I haven't tested on?) and we have to go back to the old CMU
* CL way, I hope there will at least be a comment to explain
* why.. -- WHN 2001-06-07 */
undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler);
undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler);
SHOW("returning from arch_install_interrupt_handlers()");
}
/* This is implemented in assembly language and called from C: */
extern lispobj
call_into_lisp(lispobj fun, lispobj *args, int nargs);
/* These functions are an interface to the Lisp call-in facility.
* Since this is C we can know nothing about the calling environment.
* The control stack might be the C stack if called from the monitor
* or the Lisp stack if called as a result of an interrupt or maybe
* even a separate stack. The args are most likely on that stack but
* could be in registers depending on what the compiler likes. So we
* copy the args into a portable vector and let the assembly language
* call-in function figure it out. */
lispobj
funcall0(lispobj function)
{
lispobj *args = NULL;
FSHOW((stderr, "/entering funcall0(0x%lx)\n", (long)function));
return call_into_lisp(function, args, 0);
}
lispobj
funcall1(lispobj function, lispobj arg0)
{
lispobj args[1];
args[0] = arg0;
return call_into_lisp(function, args, 1);
}
lispobj
funcall2(lispobj function, lispobj arg0, lispobj arg1)
{
lispobj args[2];
args[0] = arg0;
args[1] = arg1;
return call_into_lisp(function, args, 2);
}
lispobj
funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
{
lispobj args[3];
args[0] = arg0;
args[1] = arg1;
args[2] = arg2;
return call_into_lisp(function, args, 3);
}
--- NEW FILE: x86-64-arch.h ---
/* FIXME: Aren't preprocessor symbols with underscore prefixes
* reserved for the system libraries? If so, it would be tidy to
* rename flags like _X86_ARCH_H so their names are in a part of the
* namespace that we control. */
#ifndef _X86_ARCH_H
#define _X86_ARCH_H
#define ARCH_HAS_STACK_POINTER
/* FIXME: Do we also want
* #define ARCH_HAS_FLOAT_REGISTERS
* here? (The answer wasn't obvious to me when merging the
* architecture-abstracting patches for CSR's SPARC port. -- WHN 2002-02-15) */
static inline void
get_spinlock(lispobj *word,int value)
{
#if 0
u32 eax=0;
do {
asm ("xor %0,%0\n\
lock cmpxchg %1,%2"
: "=a" (eax)
: "r" (value), "m" (*word)
: "memory", "cc");
} while(eax!=0);
#else
*word=value;
#endif
}
static inline void
release_spinlock(lispobj *word)
{
*word=0;
}
#endif /* _X86_ARCH_H */
--- NEW FILE: x86-64-assem.S ---
/*
* very-low-level utilities for runtime support
*/
/*
* This software is part of the SBCL system. See the README file for
* more information.
*
* This software is derived from the CMU CL system, which was
* written at Carnegie Mellon University and released into the
* public domain. The software is in the public domain and is
* provided with absolutely no warranty. See the COPYING and CREDITS
* files for more information.
*/
#define LANGUAGE_ASSEMBLY
#include "validate.h"
#include "sbcl.h"
#include "genesis/closure.h"
#include "genesis/fdefn.h"
#include "genesis/static-symbols.h"
#include "genesis/symbol.h"
#include "genesis/thread.h"
/* Minimize conditionalization for different OS naming schemes. */
#if defined __linux__ || defined __FreeBSD__ /* (but *not* OpenBSD) */
#define GNAME(var) var
#else
#define GNAME(var) _##var
#endif
/* Get the right type of alignment. Linux and FreeBSD (but not OpenBSD)
* want alignment in bytes. */
#if defined(__linux__) || defined(__FreeBSD__)
#define align_4byte 4
#define align_8byte 8
#define align_16byte 16
#define align_32byte 32
#else
#define align_4byte 2
#define align_8byte 3
#define align_16byte 4
#endif
.text
.global GNAME(foreign_function_call_active)
.global GNAME(all_threads)
/* From lower to higher-numbered addresses, the stack contains
* return address, arg 0, arg 1, arg 2 ...
* rax contains the address of the function to call
* Lisp expects return value in rax, whic is already consistent with C
* XXXX correct floating point handling is unimplemented so far
* Based on comments cleaned from x86-assem.S, we believe that
* Lisp is expecting us to preserve rsi, rdi, rsp (no idea about r8-15)
*/
.text
.align align_16byte,0x90
.global GNAME(call_into_c)
.type GNAME(call_into_c),@function
GNAME(call_into_c):
push %rbp # Save old frame pointer.
mov %rsp,%rbp # Establish new frame.
push %rsi # args are going in here
push %rdi
mov 16(%rbp),%rdi
mov 24(%rbp),%rsi
mov 32(%rbp),%rdx
mov 40(%rbp),%rcx
mov 48(%rbp),%rcx
mov 56(%rbp),%r8
mov 64(%rbp),%r9
call *%rax
mov %rbp,%rsp
pop %rbp
ret
.size GNAME(call_into_c), . - GNAME(call_into_c)
.text
.global GNAME(call_into_lisp_first_time)
.type GNAME(call_into_lisp_first_time),@function
/* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
* the stack changes. We don't worry too much about saving registers
* here, because we never expect to return from the initial call to lisp
* anyway */
.align align_16byte,0x90
GNAME(call_into_lisp_first_time):
push %rbp # Save old frame pointer.
mov %rsp,%rbp # Establish new frame.
mov %rsp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
mov GNAME(all_threads),%rax
mov THREAD_CONTROL_STACK_START_OFFSET(%rax) ,%rsp
/* don't think too hard about what happens if we get interrupted
* here */
add $THREAD_CONTROL_STACK_SIZE-8,%rsp
jmp Lstack
.text
.global GNAME(call_into_lisp)
.type GNAME(call_into_lisp),@function
/*
* amd64 calling convention: C expects that
* arguments go in rdi rsi rdx rcx r8 r9
* return values in rax rdx
* callee saves rbp rbx r12-15 if it uses them
*/
.align align_16byte,0x90
GNAME(call_into_lisp):
push %rbp # Save old frame pointer.
mov %rsp,%rbp # Establish new frame.
Lstack:
/* FIXME x86 saves FPU state here */
push %rbx
push %r12
push %r13
push %r14
push %r15
mov %rsp,%rbx # remember current stack
push %rbx # Save entry stack on (maybe) new stack.
/* Establish Lisp args. */
mov %rdi,%rax # lexenv?
mov %rsi,%rbx # address of arg vec
mov %rdx,%rcx # num args
xor %rdx,%rdx # clear any descriptor registers
xor %rdi,%rdi # that we can't be sure we'll
xor %rsi,%rsi # initialise properly. XX do r8-r15 too?
shl $3,%rcx # (fixnumize num-args)
cmp $0,%rcx
je Ldone
mov 0(%rbx),%rdx # arg0
cmp $8,%rcx
je Ldone
mov 8(%rbx),%rdi # arg1
cmp $16,%rcx
je Ldone
mov 16(%rbx),%rsi # arg2
Ldone:
/* Registers rax, rcx, rdx, rdi, and rsi are now live. */
xor %rbx,%rbx # available
/* Alloc new frame. */
mov %rsp,%rbx # The current sp marks start of new frame.
push %rbp # fp in save location S0
sub $16,%rsp # Ensure 3 slots are allocated, one above.
mov %rbx,%rbp # Switch to new frame.
Lcall:
call *CLOSURE_FUN_OFFSET(%rax)
/* If the function returned multiple values, it will return to
this point. Lose them */
mov %rbx, %rsp
/* A singled value function returns here */
/* Restore the stack, in case there was a stack change. */
pop %rsp # c-sp
/* Restore C regs */
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
/* FIXME Restore the NPX state. */
pop %rbp # c-sp
/* return value is already in rax where lisp expects it */
ret
.size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
/* support for saving and restoring the NPX state from C */
.text
.global GNAME(fpu_save)
.type GNAME(fpu_save),@function
.align 2,0x90
GNAME(fpu_save):
mov 4(%rsp),%rax
fnsave (%rax) # Save the NPX state. (resets NPX)
ret
.size GNAME(fpu_save),.-GNAME(fpu_save)
.global GNAME(fpu_restore)
.type GNAME(fpu_restore),@function
.align 2,0x90
GNAME(fpu_restore):
mov 4(%rsp),%rax
frstor (%rax) # Restore the NPX state.
ret
.size GNAME(fpu_restore),.-GNAME(fpu_restore)
/*
* the undefined-function trampoline
*/
.text
.align align_4byte,0x90
.global GNAME(undefined_tramp)
.type GNAME(undefined_tramp),@function
GNAME(undefined_tramp):
int3
.byte trap_Error
.byte 2
.byte UNDEFINED_FUN_ERROR
.byte sc_DescriptorReg # eax in the Descriptor-reg SC
ret
.size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
.text
.align align_4byte,0x90
.global GNAME(alloc_tramp)
.type GNAME(alooc_tramp),@function
GNAME(alloc_tramp):
push %rbp # Save old frame pointer.
mov %rsp,%rbp # Establish new frame.
push %rax
push %rcx
push %rdx
push %rsi
push %rdi
push %r8
push %r9
push %r10
push %r11
mov 16(%rbp),%rdi
call alloc
mov %rax,16(%rbp)
pop %r11
pop %r10
pop %r9
pop %r8
pop %rdi
pop %rsi
pop %rdx
pop %rcx
pop %rax
pop %rbp
ret
.size GNAME(alloc_tramp),.-GNAME(alloc_tramp)
/*
* the closure trampoline
*/
.text
.align align_4byte,0x90
.global GNAME(closure_tramp)
.type GNAME(closure_tramp),@function
GNAME(closure_tramp):
mov FDEFN_FUN_OFFSET(%rax),%rax
/* FIXME: The '*' after "jmp" in the next line is from PVE's
* patch posted to the CMU CL mailing list Oct 6, 1999. It looks
* reasonable, and it certainly seems as though if CMU CL needs it,
* SBCL needs it too, but I haven't actually verified that it's
* right. It would be good to find a way to force the flow of
* control through here to test it. */
jmp *CLOSURE_FUN_OFFSET(%rax)
.size GNAME(closure_tramp), .-GNAME(closure_tramp)
/*
* fun-end breakpoint magic
*/
.text
.global GNAME(fun_end_breakpoint_guts)
.align align_4byte
GNAME(fun_end_breakpoint_guts):
/* Multiple Value return */
jmp multiple_value_return
/* Single value return: The eventual return will now use the
multiple values return convention but with a return values
count of one. */
mov %rsp,%rbx # Setup ebx - the ofp.
sub $4,%rsp # Allocate one stack slot for the return value
mov $4,%rcx # Setup ecx for one return value.
mov $NIL,%rdi # default second value
mov $NIL,%rsi # default third value
multiple_value_return:
.global GNAME(fun_end_breakpoint_trap)
GNAME(fun_end_breakpoint_trap):
int3
.byte trap_FunEndBreakpoint
hlt # We should never return here.
.global GNAME(fun_end_breakpoint_end)
GNAME(fun_end_breakpoint_end):
.global GNAME(do_pending_interrupt)
.type GNAME(do_pending_interrupt),@function
.align align_4byte,0x90
GNAME(do_pending_interrupt):
int3
.byte trap_PendingInterrupt
ret
.size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
#ifdef LISP_FEATURE_GENCGC
/* This is a fast bzero using the FPU. The first argument is the start
* address which needs to be aligned on an 8 byte boundary, the second
* argument is the number of bytes, which must be a nonzero multiple
* of 8 bytes. */
/* FIXME whether this is still faster than using the OS's bzero or
* equivalent, we don't know */
.text
.globl GNAME(i586_bzero)
.type GNAME(i586_bzero),@function
.align align_4byte,0x90
GNAME(i586_bzero):
mov 4(%rsp),%rdx # Load the start address.
mov 8(%rsp),%rax # Load the number of bytes.
fldz
l1: fstl 0(%rdx)
add $8,%rdx
sub $8,%rax
jnz l1
fstp %st(0)
ret
.size GNAME(i586_bzero),.-GNAME(i586_bzero)
#endif
.end
--- NEW FILE: x86-64-linux-os.c ---
/*
* The x86 Linux incarnation of arch-dependent OS-dependent routines.
* See also "linux-os.c".
*/
/*
* This software is part of the SBCL system. See the README file for
* more information.
*
* This software is derived from the CMU CL system, which was
* written at Carnegie Mellon University and released into the
* public domain. The software is in the public domain and is
* provided with absolutely no warranty. See the COPYING and CREDITS
* files for more information.
*/
#include <stdio.h>
#include <stddef.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#define __USE_GNU
#include <sys/ucontext.h>
#undef __USE_GNU
#include "./signal.h"
#include "os.h"
#include "arch.h"
#include "globals.h"
#include "interrupt.h"
#include "interr.h"
#include "lispregs.h"
#include "sbcl.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 <asm/ldt.h>
#include <linux/unistd.h>
#include <sys/mman.h>
#include <linux/version.h>
#include "thread.h" /* dynamic_values_bytes */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#define user_desc modify_ldt_ldt_s
#endif
_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount );
#include "validate.h"
size_t os_vm_page_size;
u32 local_ldt_copy[LDT_ENTRIES*LDT_ENTRY_SIZE/sizeof(u32)];
/* This is never actually called, but it's great for calling from gdb when
* users have thread-related problems that maintainers can't duplicate */
void debug_get_ldt()
{
int n=modify_ldt (0, local_ldt_copy, sizeof local_ldt_copy);
printf("%d bytes in ldt: print/x local_ldt_copy\n", n);
}
lispobj modify_ldt_lock; /* protect all calls to modify_ldt */
int arch_os_thread_init(struct thread *thread) {
stack_t sigstack;
#ifdef LISP_FEATURE_SB_THREAD
/* this must be called from a function that has an exclusive lock
* on all_threads
*/
struct user_desc ldt_entry = {
1, 0, 0, /* index, address, length filled in later */
1, MODIFY_LDT_CONTENTS_DATA, 0, 0, 0, 1
};
int n;
get_spinlock(&modify_ldt_lock,thread);
n=modify_ldt(0,local_ldt_copy,sizeof local_ldt_copy);
/* get next free ldt entry */
if(n) {
u32 *p;
for(n=0,p=local_ldt_copy;*p;p+=LDT_ENTRY_SIZE/sizeof(u32))
n++;
}
ldt_entry.entry_number=n;
ldt_entry.base_addr=(unsigned long) thread;
ldt_entry.limit=dynamic_values_bytes;
ldt_entry.limit_in_pages=0;
if (modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0) {
modify_ldt_lock=0;
/* modify_ldt call failed: something magical is not happening */
return -1;
}
__asm__ __volatile__ ("movw %w0, %%fs" : : "q"
((n << 3) /* selector number */
+ (1 << 2) /* TI set = LDT */
+ 3)); /* privilege level */
thread->tls_cookie=n;
modify_ldt_lock=0;
if(n<0) return 0;
#endif
#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
/* Signal handlers are run on the control stack, so if it is exhausted
* we had better use an alternate stack for whatever signal tells us
* we've exhausted it */
sigstack.ss_sp=((void *) thread)+dynamic_values_bytes;
sigstack.ss_flags=0;
sigstack.ss_size = 32*SIGSTKSZ;
sigaltstack(&sigstack,0);
#endif
return 1;
}
struct thread *debug_get_fs() {
register u32 fs;
__asm__ __volatile__ ("movl %%fs,%0" : "=r" (fs) : );
return fs;
}
/* free any arch/os-specific resources used by thread, which is now
* defunct. Not called on live threads
*/
int arch_os_thread_cleanup(struct thread *thread) {
struct user_desc ldt_entry = {
0, 0, 0,
0, MODIFY_LDT_CONTENTS_DATA, 0, 0, 0, 0
};
ldt_entry.entry_number=thread->tls_cookie;
get_spinlock(&modify_ldt_lock,thread);
if (modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0) {
modify_ldt_lock=0;
/* modify_ldt call failed: something magical is not happening */
return 0;
}
modify_ldt_lock=0;
return 1;
}
os_context_register_t *
os_context_register_addr(os_context_t *context, int offset)
{
switch(offset) {
case reg_RAX: return &context->uc_mcontext.gregs[11];
case reg_RCX: return &context->uc_mcontext.gregs[10];
case reg_RDX: return &context->uc_mcontext.gregs[9];
case reg_RBX: return &context->uc_mcontext.gregs[8];
case reg_RSP: return &context->uc_mcontext.gregs[7];
case reg_RBP: return &context->uc_mcontext.gregs[6];
case reg_RSI: return &context->uc_mcontext.gregs[5];
case reg_RDI: return &context->uc_mcontext.gregs[4];
default:
if(offset<32)
return &context->uc_mcontext.gregs[offset/2+4];
else return 0;
}
return &context->uc_mcontext.gregs[offset];
}
os_context_register_t *
os_context_pc_addr(os_context_t *context)
{
return &context->uc_mcontext.gregs[REG_RIP]; /* REG_EIP */
}
os_context_register_t *
os_context_sp_addr(os_context_t *context)
{
return &context->uc_mcontext.gregs[REG_RSP];
}
os_context_register_t *
os_context_fp_addr(os_context_t *context)
{
return &context->uc_mcontext.gregs[REG_RBP];
}
unsigned long
os_context_fp_control(os_context_t *context)
{
#if 0
return ((((context->uc_mcontext.fpregs->cw) & 0xffff) ^ 0x3f) |
(((context->uc_mcontext.fpregs->sw) & 0xffff) << 16));
#else
return 0;
#endif
}
sigset_t *
os_context_sigmask_addr(os_context_t *context)
{
return &context->uc_sigmask;
}
void
os_restore_fp_control(os_context_t *context)
{
#if 0
asm ("fldcw %0" : : "m" (context->uc_mcontext.fpregs->cw));
#endif
}
void
os_flush_icache(os_vm_address_t address, os_vm_size_t length)
{
}
--- NEW FILE: x86-64-linux-os.h ---
#ifndef _X86_LINUX_OS_H
#define _X86_LINUX_OS_H
typedef struct ucontext os_context_t;
typedef long os_context_register_t;
static inline os_context_t *arch_os_get_context(void **void_context) {
return (os_context_t *) *void_context;
}
unsigned long os_context_fp_control(os_context_t *context);
void os_restore_fp_control(os_context_t *context);
#endif /* _X86_LINUX_OS_H */
--- NEW FILE: x86-64-lispregs.h ---
/*
* These register names and offsets correspond to definitions in
* compiler/x86/vm.lisp. They map into accessors in the OS-dependent
* POSIX signal context structure os_context_t via the
* os_context_register_addr(..) OS-dependent function.
*/
/*
* This software is part of the SBCL system. See the README file for
* more information.
*
* This software is derived from the CMU CL system, which was
* written at Carnegie Mellon University and released into the
* public domain. The software is in the public domain and is
* provided with absolutely no warranty. See the COPYING and CREDITS
* files for more information.
*/
/* the number of registers visible as registers in the virtual machine
* (excludes stuff like segment registers) */
#define NREGS (16)
#ifdef LANGUAGE_ASSEMBLY
#define REG(num) $ ## num
#else
#define REG(num) num
#endif
#define reg_RAX REG( 0)
#define reg_RCX REG( 2)
#define reg_RDX REG( 4)
#define reg_RBX REG( 6)
#define reg_RSP REG( 8)
#define reg_RBP REG(10)
#define reg_RSI REG(12)
#define reg_RDI REG(14)
#define reg_R(n) REG((n)*2)
#define REGNAMES "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"
/* classification of registers
*
* reg_SP = the register used by Lisp as stack pointer
* reg_FP = the register used by Lisp as frame pointer
* BOXED_REGISTERS =
* the registers which may contain Lisp object pointers */
#define reg_SP reg_RSP
#define reg_FP reg_RBP
#define BOXED_REGISTERS {\
reg_RAX, reg_RCX, reg_RDX, reg_RBX, reg_RSI, reg_RDI \
}
|