summaryrefslogtreecommitdiff
path: root/lib/libpthread/arch
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpthread/arch')
-rw-r--r--lib/libpthread/arch/amd64/_atomic_lock.c16
-rw-r--r--lib/libpthread/arch/amd64/uthread_machdep.c72
-rw-r--r--lib/libpthread/arch/amd64/uthread_machdep.h9
-rw-r--r--lib/libpthread/arch/amd64/uthread_machdep_asm.S62
-rw-r--r--lib/libpthread/arch/x86_64/_atomic_lock.c16
-rw-r--r--lib/libpthread/arch/x86_64/uthread_machdep.c72
-rw-r--r--lib/libpthread/arch/x86_64/uthread_machdep.h9
-rw-r--r--lib/libpthread/arch/x86_64/uthread_machdep_asm.S62
8 files changed, 298 insertions, 20 deletions
diff --git a/lib/libpthread/arch/amd64/_atomic_lock.c b/lib/libpthread/arch/amd64/_atomic_lock.c
index 087186e2858..70bdb487381 100644
--- a/lib/libpthread/arch/amd64/_atomic_lock.c
+++ b/lib/libpthread/arch/amd64/_atomic_lock.c
@@ -1,5 +1,6 @@
+/* $OpenBSD: _atomic_lock.c,v 1.2 2004/02/25 03:48:36 deraadt Exp $ */
/*
- * Atomic lock for amd64
+ * Atomic lock for amd64 -- taken from i386 code.
*/
#include "spinlock.h"
@@ -7,5 +8,16 @@
int
_atomic_lock(volatile _spinlock_lock_t *lock)
{
- /* dummy for now */
+ _spinlock_lock_t old;
+
+ /*
+ * Use the eXCHanGe instruction to swap the lock value with
+ * a local variable containing the locked state.
+ */
+ old = _SPINLOCK_LOCKED;
+ __asm__("xchg %0,%1"
+ : "=r" (old), "=m" (*lock)
+ : "0" (old), "1" (*lock));
+
+ return (old != _SPINLOCK_UNLOCKED);
}
diff --git a/lib/libpthread/arch/amd64/uthread_machdep.c b/lib/libpthread/arch/amd64/uthread_machdep.c
index d66bfbaa853..e01da1b6c58 100644
--- a/lib/libpthread/arch/amd64/uthread_machdep.c
+++ b/lib/libpthread/arch/amd64/uthread_machdep.c
@@ -2,26 +2,88 @@
#include <pthread.h>
#include "pthread_private.h"
+struct frame {
+ long fr_gs;
+ long fr_fs;
+ long fr_es;
+ long fr_ds;
+
+ long flag;
+ long fr_r15;
+ long fr_r14;
+ long fr_r13;
+ long fr_r12;
+
+ long fr_r11;
+ long fr_r10;
+ long fr_r9;
+ long fr_r8;
+
+ long fr_rdi;
+ long fr_rsi;
+ long fr_rbp;
+
+ long fr_rbx;
+ long fr_rdx;
+ long fr_rcx;
+ long fr_rax;
+
+ long fr_rip;
+ int fr_cs; /* XXX unreachable? */
+ int pad;
+};
+
+#define copyreg(reg, lval) \
+ __asm__("mov %%" #reg ", %0" : "=g"(lval))
+
/*
* Given a stack and an entry function, initialise a state
* structure that can be later switched to.
*/
void
_thread_machdep_init(struct _machdep_state* statep, void *base, int len,
- void (*entry)(void))
+ void (*entry)(void))
{
- /* dummy */
+ struct frame *f;
+ int foo;
+
+ /* Locate the initial frame, aligned at the top of the stack */
+ f = (struct frame *)(((long)base + len - sizeof *f) & ~ALIGNBYTES);
+
+ copyreg(cs, foo);
+ f->fr_cs = foo;
+ copyreg(ds, foo);
+ f->fr_ds = foo;
+ copyreg(es, foo);
+ f->fr_es = foo;
+ copyreg(fs, foo);
+ f->fr_fs = foo;
+ copyreg(gs, foo);
+ f->fr_gs = foo;
+
+ f->fr_rbp = (long)-1;
+ f->fr_rip = (long)entry;
+
+ statep->rsp = (long)f;
+
+ _thread_machdep_save_float_state(statep);
}
+#define fxsave(addr) __asm("fxsave %0" : "=m" (*addr))
+#define fxrstor(addr) __asm("fxrstor %0" : : "m" (*addr))
+#define fwait() __asm("fwait")
+#define fninit() __asm("fninit")
+
void
_thread_machdep_save_float_state(struct _machdep_state *ms)
{
- /* dummy */
+ fxsave(&ms->fpreg);
+ fninit();
+ fwait();
}
void
_thread_machdep_restore_float_state(struct _machdep_state *ms)
{
- /* dummy */
+ fxrstor(&ms->fpreg);
}
-
diff --git a/lib/libpthread/arch/amd64/uthread_machdep.h b/lib/libpthread/arch/amd64/uthread_machdep.h
index 46f5e9e87d1..43187585d17 100644
--- a/lib/libpthread/arch/amd64/uthread_machdep.h
+++ b/lib/libpthread/arch/amd64/uthread_machdep.h
@@ -1,5 +1,10 @@
-/* dummy */
+/* $OpenBSD: uthread_machdep.h,v 1.2 2004/02/25 03:48:36 deraadt Exp $ */
+
+#include <sys/types.h>
+#include <machine/fpu.h>
struct _machdep_state {
+ long rsp;
+ /* must be 128-bit aligned */
+ struct savefpu fpreg __attribute__ ((aligned (16)));
};
-
diff --git a/lib/libpthread/arch/amd64/uthread_machdep_asm.S b/lib/libpthread/arch/amd64/uthread_machdep_asm.S
index 3a5f255f285..51294f9ae5c 100644
--- a/lib/libpthread/arch/amd64/uthread_machdep_asm.S
+++ b/lib/libpthread/arch/amd64/uthread_machdep_asm.S
@@ -6,5 +6,65 @@
/* void _thread_machdep_switch(new, oldsave); */
ENTRY(_thread_machdep_switch)
- /* dummy */
+ pushq %rax
+ pushq %rcx
+ pushq %rdx
+ pushq %rbx
+
+ pushq %rbp
+ pushq %rsi
+ pushq %rdi
+
+ pushq %r8
+ pushq %r9
+ pushq %r10
+ pushq %r11
+
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+ movq $0xdeaf12345678beaf, %r15
+ pushq %r15
+
+ movl %ds,%eax
+ pushq %rax
+ movl %es,%eax
+ pushq %rax
+ movl %fs,%eax
+ pushq %rax
+ movl %gs,%eax
+ pushq %rax
+
+ movq %rsp, 0(%rsi) /* *arg2 = %rsp */
+ movq 0(%rdi), %rsp /* %rsp = *arg1 */
+
+ popq %rax
+ movl %eax,%gs
+ popq %rax
+ movl %eax,%fs
+ popq %rax
+ movl %eax,%es
+ popq %rax
+ movl %eax,%ds
+
+ popq %r15 # flag word.
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+
+ popq %rdi
+ popq %rsi
+ popq %rbp
+
+ popq %rbx
+ popq %rdx
+ popq %rcx
+ popq %rax
ret
diff --git a/lib/libpthread/arch/x86_64/_atomic_lock.c b/lib/libpthread/arch/x86_64/_atomic_lock.c
index 087186e2858..70bdb487381 100644
--- a/lib/libpthread/arch/x86_64/_atomic_lock.c
+++ b/lib/libpthread/arch/x86_64/_atomic_lock.c
@@ -1,5 +1,6 @@
+/* $OpenBSD: _atomic_lock.c,v 1.2 2004/02/25 03:48:36 deraadt Exp $ */
/*
- * Atomic lock for amd64
+ * Atomic lock for amd64 -- taken from i386 code.
*/
#include "spinlock.h"
@@ -7,5 +8,16 @@
int
_atomic_lock(volatile _spinlock_lock_t *lock)
{
- /* dummy for now */
+ _spinlock_lock_t old;
+
+ /*
+ * Use the eXCHanGe instruction to swap the lock value with
+ * a local variable containing the locked state.
+ */
+ old = _SPINLOCK_LOCKED;
+ __asm__("xchg %0,%1"
+ : "=r" (old), "=m" (*lock)
+ : "0" (old), "1" (*lock));
+
+ return (old != _SPINLOCK_UNLOCKED);
}
diff --git a/lib/libpthread/arch/x86_64/uthread_machdep.c b/lib/libpthread/arch/x86_64/uthread_machdep.c
index d66bfbaa853..e01da1b6c58 100644
--- a/lib/libpthread/arch/x86_64/uthread_machdep.c
+++ b/lib/libpthread/arch/x86_64/uthread_machdep.c
@@ -2,26 +2,88 @@
#include <pthread.h>
#include "pthread_private.h"
+struct frame {
+ long fr_gs;
+ long fr_fs;
+ long fr_es;
+ long fr_ds;
+
+ long flag;
+ long fr_r15;
+ long fr_r14;
+ long fr_r13;
+ long fr_r12;
+
+ long fr_r11;
+ long fr_r10;
+ long fr_r9;
+ long fr_r8;
+
+ long fr_rdi;
+ long fr_rsi;
+ long fr_rbp;
+
+ long fr_rbx;
+ long fr_rdx;
+ long fr_rcx;
+ long fr_rax;
+
+ long fr_rip;
+ int fr_cs; /* XXX unreachable? */
+ int pad;
+};
+
+#define copyreg(reg, lval) \
+ __asm__("mov %%" #reg ", %0" : "=g"(lval))
+
/*
* Given a stack and an entry function, initialise a state
* structure that can be later switched to.
*/
void
_thread_machdep_init(struct _machdep_state* statep, void *base, int len,
- void (*entry)(void))
+ void (*entry)(void))
{
- /* dummy */
+ struct frame *f;
+ int foo;
+
+ /* Locate the initial frame, aligned at the top of the stack */
+ f = (struct frame *)(((long)base + len - sizeof *f) & ~ALIGNBYTES);
+
+ copyreg(cs, foo);
+ f->fr_cs = foo;
+ copyreg(ds, foo);
+ f->fr_ds = foo;
+ copyreg(es, foo);
+ f->fr_es = foo;
+ copyreg(fs, foo);
+ f->fr_fs = foo;
+ copyreg(gs, foo);
+ f->fr_gs = foo;
+
+ f->fr_rbp = (long)-1;
+ f->fr_rip = (long)entry;
+
+ statep->rsp = (long)f;
+
+ _thread_machdep_save_float_state(statep);
}
+#define fxsave(addr) __asm("fxsave %0" : "=m" (*addr))
+#define fxrstor(addr) __asm("fxrstor %0" : : "m" (*addr))
+#define fwait() __asm("fwait")
+#define fninit() __asm("fninit")
+
void
_thread_machdep_save_float_state(struct _machdep_state *ms)
{
- /* dummy */
+ fxsave(&ms->fpreg);
+ fninit();
+ fwait();
}
void
_thread_machdep_restore_float_state(struct _machdep_state *ms)
{
- /* dummy */
+ fxrstor(&ms->fpreg);
}
-
diff --git a/lib/libpthread/arch/x86_64/uthread_machdep.h b/lib/libpthread/arch/x86_64/uthread_machdep.h
index 46f5e9e87d1..43187585d17 100644
--- a/lib/libpthread/arch/x86_64/uthread_machdep.h
+++ b/lib/libpthread/arch/x86_64/uthread_machdep.h
@@ -1,5 +1,10 @@
-/* dummy */
+/* $OpenBSD: uthread_machdep.h,v 1.2 2004/02/25 03:48:36 deraadt Exp $ */
+
+#include <sys/types.h>
+#include <machine/fpu.h>
struct _machdep_state {
+ long rsp;
+ /* must be 128-bit aligned */
+ struct savefpu fpreg __attribute__ ((aligned (16)));
};
-
diff --git a/lib/libpthread/arch/x86_64/uthread_machdep_asm.S b/lib/libpthread/arch/x86_64/uthread_machdep_asm.S
index 3a5f255f285..51294f9ae5c 100644
--- a/lib/libpthread/arch/x86_64/uthread_machdep_asm.S
+++ b/lib/libpthread/arch/x86_64/uthread_machdep_asm.S
@@ -6,5 +6,65 @@
/* void _thread_machdep_switch(new, oldsave); */
ENTRY(_thread_machdep_switch)
- /* dummy */
+ pushq %rax
+ pushq %rcx
+ pushq %rdx
+ pushq %rbx
+
+ pushq %rbp
+ pushq %rsi
+ pushq %rdi
+
+ pushq %r8
+ pushq %r9
+ pushq %r10
+ pushq %r11
+
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+ movq $0xdeaf12345678beaf, %r15
+ pushq %r15
+
+ movl %ds,%eax
+ pushq %rax
+ movl %es,%eax
+ pushq %rax
+ movl %fs,%eax
+ pushq %rax
+ movl %gs,%eax
+ pushq %rax
+
+ movq %rsp, 0(%rsi) /* *arg2 = %rsp */
+ movq 0(%rdi), %rsp /* %rsp = *arg1 */
+
+ popq %rax
+ movl %eax,%gs
+ popq %rax
+ movl %eax,%fs
+ popq %rax
+ movl %eax,%es
+ popq %rax
+ movl %eax,%ds
+
+ popq %r15 # flag word.
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+
+ popq %rdi
+ popq %rsi
+ popq %rbp
+
+ popq %rbx
+ popq %rdx
+ popq %rcx
+ popq %rax
ret