summaryrefslogtreecommitdiff
path: root/lib/libpthread/arch/alpha
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpthread/arch/alpha')
-rw-r--r--lib/libpthread/arch/alpha/machdep.c204
-rw-r--r--lib/libpthread/arch/alpha/machdep.h111
-rw-r--r--lib/libpthread/arch/alpha/syscall-template.S46
-rw-r--r--lib/libpthread/arch/alpha/syscall.S224
4 files changed, 585 insertions, 0 deletions
diff --git a/lib/libpthread/arch/alpha/machdep.c b/lib/libpthread/arch/alpha/machdep.c
new file mode 100644
index 00000000000..0932c421ea2
--- /dev/null
+++ b/lib/libpthread/arch/alpha/machdep.c
@@ -0,0 +1,204 @@
+/* ==== machdep.c ============================================================
+ * Copyright (c) 1993, 1994 Chris Provenzano, proven@athena.mit.edu
+ *
+ * Description : Machine dependent functions for NetBSD/Alpha 1.1(+)
+ *
+ * 1.00 93/08/04 proven
+ * -Started coding this file.
+ *
+ * 95/04/22 cgd
+ * -Modified to make it go with NetBSD/Alpha
+ */
+
+#ifndef lint
+static const char rcsid[] = "engine-alpha-osf1.c,v 1.4.4.1 1995/12/13 05:41:37 proven Exp";
+#endif
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_save_state()
+ */
+int machdep_save_state(void)
+{
+ return __machdep_save_int_state(pthread_run->machdep_data.machdep_istate);
+}
+
+void machdep_restore_state(void)
+{
+ __machdep_restore_int_state(pthread_run->machdep_data.machdep_istate);
+}
+
+void machdep_save_float_state (void)
+{
+ __machdep_save_fp_state(pthread_run->machdep_data.machdep_fstate);
+}
+
+void machdep_restore_float_state (void)
+{
+ __machdep_restore_fp_state(pthread_run->machdep_data.machdep_fstate);
+}
+
+/* ==========================================================================
+ * machdep_set_thread_timer()
+ */
+void machdep_set_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ if (setitimer(ITIMER_VIRTUAL, &(machdep_pthread->machdep_timer), NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_unset_thread_timer()
+ */
+void machdep_unset_thread_timer(struct machdep_pthread *machdep_pthread)
+{
+ struct itimerval zeroval = { { 0, 0 }, { 0, 0} };
+
+ if (setitimer(ITIMER_VIRTUAL, &zeroval, NULL)) {
+ PANIC();
+ }
+}
+
+/* ==========================================================================
+ * machdep_pthread_cleanup()
+ */
+void *machdep_pthread_cleanup(struct machdep_pthread *machdep_pthread)
+{
+ return(machdep_pthread->machdep_stack);
+}
+
+/* ==========================================================================
+ * machdep_pthread_start()
+ */
+void machdep_pthread_start(void)
+{
+ context_switch_done();
+ pthread_sched_resume ();
+
+ /* Run current threads start routine with argument */
+ pthread_exit(pthread_run->machdep_data.start_routine
+ (pthread_run->machdep_data.start_argument));
+
+ /* should never reach here */
+ PANIC();
+}
+
+/* ==========================================================================
+ * __machdep_stack_free()
+ */
+void __machdep_stack_free(void * stack)
+{
+ free(stack);
+}
+
+/* ==========================================================================
+ * __machdep_stack_alloc()
+ */
+void * __machdep_stack_alloc(size_t size)
+{
+ void * stack;
+
+ return(malloc(size));
+}
+
+/* ==========================================================================
+ * __machdep_pthread_create()
+ */
+void __machdep_pthread_create(struct machdep_pthread *machdep_pthread,
+ void *(* start_routine)(), void *start_argument,
+ long stack_size, long nsec, long flags)
+{
+ machdep_pthread->start_routine = start_routine;
+ machdep_pthread->start_argument = start_argument;
+
+ machdep_pthread->machdep_timer.it_value.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_sec = 0;
+ machdep_pthread->machdep_timer.it_interval.tv_usec = 0;
+ machdep_pthread->machdep_timer.it_value.tv_usec = nsec / 1000;
+
+ /* Set up new stack frame so that it looks like it returned from a
+ longjmp() to the beginning of machdep_pthread_start(). */
+ machdep_pthread->machdep_istate[8/*ISTATE_RA*/] = 0;
+ machdep_pthread->machdep_istate[0/*ISTATE_PC*/] = (long)machdep_pthread_start;
+ machdep_pthread->machdep_istate[10/*ISTATE_PV*/] = (long)machdep_pthread_start;
+
+ /* Alpha stack starts high and builds down. */
+ {
+ long stk_addr = (long) machdep_pthread->machdep_stack;
+ stk_addr += stack_size - 1024;
+ stk_addr &= ~15;
+ machdep_pthread->machdep_istate[9/*ISTATE_SP*/] = stk_addr;
+ }
+}
+
+int safe_store (loc, new)
+ int *loc;
+ int new;
+{
+ int locked, old;
+ asm ("mb" : : : "memory");
+ do {
+ asm ("ldl_l %0,%1" : "=r" (old) : "m" (*loc));
+ asm ("stl_c %0,%1" : "=r" (locked), "=m" (*loc) : "0" (new));
+ } while (!locked);
+ asm ("mb" : : : "memory");
+ return old;
+}
+
+/* ==========================================================================
+ * machdep_sys_creat()
+ */
+machdep_sys_creat(char * path, int mode)
+{
+ return(machdep_sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode));
+}
+
+/* ==========================================================================
+ * machdep_sys_wait3()
+ */
+machdep_sys_wait3(int * b, int c, int * d)
+{
+ return(machdep_sys_wait4(0, b, c, d));
+}
+
+/* ==========================================================================
+ * machdep_sys_waitpid()
+ */
+machdep_sys_waitpid(int a, int * b, int c)
+{
+ return(machdep_sys_wait4(a, b, c, NULL));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdtablesize()
+ */
+machdep_sys_getdtablesize()
+{
+ return(sysconf(_SC_OPEN_MAX));
+}
+
+/* ==========================================================================
+ * machdep_sys_lseek()
+ */
+off_t machdep_sys_lseek(int fd, off_t offset, int whence)
+{
+ extern off_t __syscall();
+
+ return(__syscall((quad_t)SYS_lseek, fd, 0, offset, whence));
+}
+
+/* ==========================================================================
+ * machdep_sys_getdirentries()
+ */
+machdep_sys_getdirentries(int fd, char * buf, int len, int * seek)
+{
+ return(machdep_sys_getdents(fd, buf, len));
+}
diff --git a/lib/libpthread/arch/alpha/machdep.h b/lib/libpthread/arch/alpha/machdep.h
new file mode 100644
index 00000000000..50c872da7b6
--- /dev/null
+++ b/lib/libpthread/arch/alpha/machdep.h
@@ -0,0 +1,111 @@
+/* ==== machdep.h ============================================================
+ * Copyright (c) 1994 Chris Provenzano (proven@athena.mit.edu) and
+ * Ken Raeburn (raeburn@mit.edu).
+ *
+ * engine-alpha-osf1.h,v 1.4.4.1 1995/12/13 05:41:42 proven Exp
+ *
+ */
+
+#include <unistd.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+
+/* The first machine dependent functions are the SEMAPHORES needing
+ the test and set instruction.
+
+ On the Alpha, the actual values here are irrelevant; they just have
+ to be different. */
+#define SEMAPHORE_CLEAR 0
+#define SEMAPHORE_SET 1
+
+#if 0
+#define SEMAPHORE_TEST_AND_SET(lock) \
+({ int *_sem_lock = (lock), locked, old; \
+ asm ("mb" : : : "memory"); \
+ do { asm ("ldl_l %0,%1" : "=r" (old) : "m" (*_sem_lock)); \
+ /* ?? if (old != SEMAPHORE_CLEAR) break; */ \
+ asm ("stl_c %0,%1" : "=r" (locked), "=m" (*_sem_lock) \
+ : "0" (SEMAPHORE_SET)); \
+ } while (!locked); \
+ asm ("mb" : : : "memory"); \
+ old == SEMAPHORE_CLEAR; })
+
+#define SEMAPHORE_RESET(lock) \
+({ int *_sem_lock = (lock); \
+ *_sem_lock = SEMAPHORE_CLEAR; \
+ asm ("mb" : : : "memory"); })
+#endif
+
+/*
+ * New types
+ */
+typedef int semaphore;
+
+/*
+ * sigset_t macros
+ */
+#define SIG_ANY(sig) (sig)
+#define SIGMAX 31
+
+/*
+ * New Strutures
+ */
+struct machdep_pthread {
+ void *(*start_routine)(void *);
+ void *start_argument;
+ void *machdep_stack;
+ struct itimerval machdep_timer;
+ unsigned long machdep_istate[11];
+ unsigned long machdep_fstate[9];
+};
+
+/*
+ * Static machdep_pthread initialization values.
+ * For initial thread only.
+ */
+#define MACHDEP_PTHREAD_INIT \
+ { NULL, NULL, NULL, { { 0, 0 }, { 0, 100000 } }, 0 }
+
+/*
+ * Minimum stack size
+ */
+#define PTHREAD_STACK_MIN 2048
+
+/*
+ * Some fd flag defines that are necessary to distinguish between posix
+ * behavior and bsd4.3 behavior.
+ */
+#define __FD_NONBLOCK O_NONBLOCK
+
+/*
+ * New functions
+ */
+
+__BEGIN_DECLS
+
+#if defined(PTHREAD_KERNEL)
+
+#define __machdep_stack_get(x) (x)->machdep_stack
+#define __machdep_stack_set(x, y) (x)->machdep_stack = y
+#define __machdep_stack_repl(x, y) \
+{ \
+ if (stack = __machdep_stack_get(x)) { \
+ __machdep_stack_free(stack); \
+ } \
+ __machdep_stack_set(x, y); \
+}
+
+void * __machdep_stack_alloc __P_((size_t));
+void __machdep_stack_free __P_((void *));
+
+int machdep_save_state __P_((void));
+
+int __machdep_save_int_state __P_((unsigned long *));
+void __machdep_restore_int_state __P_((unsigned long *));
+void __machdep_save_fp_state __P_((unsigned long *));
+void __machdep_restore_fp_state __P_((unsigned long *));
+
+#endif
+
+__END_DECLS
diff --git a/lib/libpthread/arch/alpha/syscall-template.S b/lib/libpthread/arch/alpha/syscall-template.S
new file mode 100644
index 00000000000..a2941ece7c9
--- /dev/null
+++ b/lib/libpthread/arch/alpha/syscall-template.S
@@ -0,0 +1,46 @@
+#include <machine/asm.h>
+#define COMPAT_43
+#include <sys/syscall.h>
+#define CHMK() call_pal 0x83
+
+#undef SYSCALL
+
+/* Kernel syscall interface:
+ Input:
+ v0 - system call number
+ a* - arguments, as in C
+ Output:
+ a3 - zero iff successful
+ v0 - errno value on failure, else result
+
+ This macro is similar to SYSCALL in asm.h, but not completely.
+ There's room for optimization, if we assume this will continue to
+ be assembled as one file.
+
+ This macro expansions does not include the return instruction.
+ If there's no other work to be done, use something like:
+ SYSCALL(foo) ; ret
+ If there is other work to do (in fork, maybe?), do it after the
+ SYSCALL invocation. */
+
+#define SYSCALL(x) \
+ .align 4 ;\
+ .globl machdep_sys_##x ;\
+ .ent machdep_sys_##x, 0 ;\
+machdep_sys_##x: ;\
+ .frame sp,0,ra ;\
+ ldiq v0, SYS_##x ;\
+ CHMK() ;\
+ beq a3, Lsys_noerr_##x ;\
+ br gp, Lsys_err_##x ;\
+Lsys_err_##x: ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+ jmp zero, machdep_cerror ;\
+Lsys_noerr_##x:
+
+#define SIMPLE_SYSCALL(x) SYSCALL(x) ; ret ; .end machdep_sys_##x
+
+#define XSYSCALL(x) SIMPLE_SYSCALL(x)
+
+XSYSCALL(SYSCALL_NAME)
diff --git a/lib/libpthread/arch/alpha/syscall.S b/lib/libpthread/arch/alpha/syscall.S
new file mode 100644
index 00000000000..eda44311281
--- /dev/null
+++ b/lib/libpthread/arch/alpha/syscall.S
@@ -0,0 +1,224 @@
+#include <machine/asm.h>
+#define CHMK() call_pal 0x83
+#define COMPAT_43
+#include <sys/syscall.h>
+#ifndef __CONCAT
+#include <sys/cdefs.h>
+#endif
+#define CONCAT __CONCAT
+
+#undef SYSCALL
+
+/* Kernel syscall interface:
+ Input:
+ v0 - system call number
+ a* - arguments, as in C
+ Output:
+ a3 - zero iff successful
+ v0 - errno value on failure, else result
+
+ This macro is similar to SYSCALL in asm.h, but not completely.
+ There's room for optimization, if we assume this will continue to
+ be assembled as one file.
+
+ This macro expansions does not include the return instruction.
+ If there's no other work to be done, use something like:
+ SYSCALL(foo) ; ret
+ If there is other work to do (in fork, maybe?), do it after the
+ SYSCALL invocation. */
+
+#define SYSCALL(x) \
+ .align 4 ;\
+ .globl CONCAT(machdep_sys_,x) ;\
+ .ent CONCAT(machdep_sys_,x), 0 ;\
+CONCAT(machdep_sys_,x): ;\
+ .frame sp,0,ra ;\
+ ldiq v0, CONCAT(SYS_,x) ;\
+ CHMK() ;\
+ beq a3, CONCAT(Lsys_noerr_,x) ;\
+ br gp, CONCAT(Lsys_err_,x) ;\
+CONCAT(Lsys_err_,x): ;\
+ /* Load gp so we can find cerror to jump to. */;\
+ ldgp gp, 0(gp) ;\
+ jmp zero, machdep_cerror ;\
+CONCAT(Lsys_noerr_,x):
+
+#define XSYSCALL(x) SYSCALL(x) ; RET ; .end CONCAT(machdep_sys_,x)
+
+ .globl machdep_cerror
+machdep_cerror:
+ br t0, Lmachdep_cerror_setgp
+Lmachdep_cerror_setgp:
+ ldgp gp, 0(t0)
+ stl v0, errno
+#if 0
+ ldiq v0, -1
+#else
+ subq zero, v0, v0
+#endif
+ RET
+
+/* The fork system call is special... */
+SYSCALL(fork)
+ cmovne a4, 0, v0
+ RET
+ .end machdep_sys_fork
+
+/* The pipe system call is special... */
+SYSCALL(pipe)
+ stl v0, 0(a0)
+ stl a4, 4(a0)
+ mov zero, v0
+ RET
+ .end machdep_sys_pipe
+
+/* The sigsuspend system call is special... */
+ .align 4
+ .globl machdep_sys_sigsuspend
+ .ent machdep_sys_sigsuspend, 0
+machdep_sys_sigsuspend:
+ ldl a0, 0(a0) /* pass *mask instead of mask */
+ ldiq v0, SYS_sigsuspend
+ CHMK()
+ mov zero, v0 /* shouldn't need; just in case... */
+ RET
+ .end machdep_sys_sigsuspend
+
+/* The sigprocmask system call is special... */
+ .align 4
+ .globl machdep_sys_sigprocmask
+ .ent machdep_sys_sigprocmask, 0
+machdep_sys_sigprocmask:
+ mov a2, a5 /* safe */
+ cmoveq a1, 1, a0 /* if set == NULL, how = SIG_BLOCK */
+ beq a1, Ldoit /* and set = 0, and do it. */
+ ldl a1, 0(a1) /* load the set from *set */
+Ldoit: ldiq v0, SYS_sigprocmask
+ CHMK()
+ beq a5, Lret /* if they don't want old mask, done */
+ stl v0, 0(a5) /* otherwise, give it to them. */
+Lret: mov zero, v0
+ RET
+ .end machdep_sys_sigprocmask
+
+/* More stuff ... */
+ .align 4
+ .global __machdep_save_int_state
+ .ent __machdep_save_int_state, 0
+__machdep_save_int_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* save integer registers */
+ stq ra, ( 0 * 8)(a0) /* return address */
+ stq s0, ( 1 * 8)(a0) /* callee-saved registers */
+ stq s1, ( 2 * 8)(a0)
+ stq s2, ( 3 * 8)(a0)
+ stq s3, ( 4 * 8)(a0)
+ stq s4, ( 5 * 8)(a0)
+ stq s5, ( 6 * 8)(a0)
+ stq s6, ( 7 * 8)(a0)
+ stq sp, ( 9 * 8)(a0)
+ stq ra, ( 8 * 8)(a0) /* RA on return */
+ stq pv, (10 * 8)(a0) /* and PV; we restore it */
+
+ mov zero, v0
+ lda sp, 16(sp)
+ RET
+ .end __machdep_save_int_state
+
+ .align 4
+ .global __machdep_restore_int_state
+ .ent __machdep_restore_int_state, 0
+__machdep_restore_int_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* restore integer registers */
+ ldq t0, ( 0 * 8)(a0) /* return address */
+ ldq s0, ( 1 * 8)(a0) /* callee-saved registers */
+ ldq s1, ( 2 * 8)(a0)
+ ldq s2, ( 3 * 8)(a0)
+ ldq s3, ( 4 * 8)(a0)
+ ldq s4, ( 5 * 8)(a0)
+ ldq s5, ( 6 * 8)(a0)
+ ldq s6, ( 7 * 8)(a0)
+ ldq ra, ( 8 * 8)(a0) /* RA after return */
+ ldq sp, ( 9 * 8)(a0)
+ ldq pv, (10 * 8)(a0) /* and PV; we restore it */
+
+ ldiq v0, 1
+ ret zero,(t0),1
+ .end __machdep_restore_int_state
+
+ .align 4
+ .global __machdep_save_fp_state
+ .ent __machdep_save_fp_state, 0
+__machdep_save_fp_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* save FP registers */
+ stt fs0, (0 * 8)(a0) /* callee-saved registers */
+ stt fs1, (1 * 8)(a0)
+ stt fs2, (2 * 8)(a0)
+ stt fs3, (3 * 8)(a0)
+ stt fs4, (4 * 8)(a0)
+ stt fs5, (5 * 8)(a0)
+ stt fs6, (6 * 8)(a0)
+ stt fs7, (7 * 8)(a0)
+ mf_fpcr ft0 /* and FP control reg */
+ stt ft0, (8 * 8)(a0)
+
+ lda sp, 16(sp)
+ RET
+ .end __machdep_save_fp_state
+
+ .align 4
+ .global __machdep_restore_fp_state
+ .ent __machdep_restore_fp_state, 0
+__machdep_restore_fp_state:
+ .frame sp, 16, ra
+ ldgp gp, 0(t12)
+ lda sp, -16(sp)
+ stq ra, 0(sp)
+
+ /* restore FP registers */
+ ldt fs0, (0 * 8)(a0) /* callee-saved registers */
+ ldt fs1, (1 * 8)(a0)
+ ldt fs2, (2 * 8)(a0)
+ ldt fs3, (3 * 8)(a0)
+ ldt fs4, (4 * 8)(a0)
+ ldt fs5, (5 * 8)(a0)
+ ldt fs6, (6 * 8)(a0)
+ ldt fs7, (7 * 8)(a0)
+ ldt ft0, (8 * 8)(a0)
+ mt_fpcr ft0 /* and FP control reg */
+
+ lda sp, 16(sp)
+ RET
+ .end __machdep_restore_fp_state
+
+/* For fstat() we actually syscall fstat13. */
+ .align 4
+ .globl machdep_sys_fstat
+ .ent machdep_sys_fstat, 0
+machdep_sys_fstat:
+ .frame sp,0,ra
+ ldiq v0, SYS___fstat13
+ CHMK()
+ beq a3, Lsys_noerr_fstat
+ br gp, Lsys_err_fstat
+Lsys_err_fstat:
+ /* Load gp so we can find cerror to jump to. */
+ ldgp gp, 0(gp)
+ jmp zero, machdep_cerror
+Lsys_noerr_fstat:
+ RET
+ .end machdep_sys_fstat