diff options
Diffstat (limited to 'lib/libpthread/arch/alpha')
-rw-r--r-- | lib/libpthread/arch/alpha/machdep.c | 204 | ||||
-rw-r--r-- | lib/libpthread/arch/alpha/machdep.h | 111 | ||||
-rw-r--r-- | lib/libpthread/arch/alpha/syscall-template.S | 46 | ||||
-rw-r--r-- | lib/libpthread/arch/alpha/syscall.S | 224 |
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 |