From 73f27ecd3a30c16c2363de51891534c09601ea6b Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 15 Jun 2012 19:57:21 +0100 Subject: [PATCH] Implementations of some libroot functions for x86_64. These are the functions required by the kernel. These are all full implementations except for system_time(), which will be implemented later. --- headers/posix/arch/x86_64/arch_setjmp.h | 5 +- src/system/libroot/os/arch/x86_64/atomic.S | 128 +++++++++++++++ src/system/libroot/os/arch/x86_64/byteorder.S | 54 +++++++ .../libroot/os/arch/x86_64/system_time.c | 4 + .../libroot/os/arch/x86_64/system_time_asm.S | 149 ++++++++++++++++++ .../posix/arch/x86_64/setjmp_internal.h | 20 +++ .../libroot/posix/arch/x86_64/siglongjmp.S | 32 ++++ .../libroot/posix/arch/x86_64/sigsetjmp.S | 39 +++++ 8 files changed, 428 insertions(+), 3 deletions(-) create mode 100644 src/system/libroot/os/arch/x86_64/atomic.S create mode 100644 src/system/libroot/os/arch/x86_64/byteorder.S create mode 100644 src/system/libroot/os/arch/x86_64/system_time.c create mode 100644 src/system/libroot/os/arch/x86_64/system_time_asm.S create mode 100644 src/system/libroot/posix/arch/x86_64/setjmp_internal.h create mode 100644 src/system/libroot/posix/arch/x86_64/siglongjmp.S create mode 100644 src/system/libroot/posix/arch/x86_64/sigsetjmp.S diff --git a/headers/posix/arch/x86_64/arch_setjmp.h b/headers/posix/arch/x86_64/arch_setjmp.h index 3780e9bb78..2d8f39ec4d 100644 --- a/headers/posix/arch/x86_64/arch_setjmp.h +++ b/headers/posix/arch/x86_64/arch_setjmp.h @@ -1,12 +1,11 @@ /* - * Copyright 2005-2010 Haiku Inc. All Rights Reserved. + * Copyright 2005-2012 Haiku Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _ARCH_SETJMP_H_ #define _ARCH_SETJMP_H_ -/* TODO: A jmp_buf size of 12 might not be large enough. Increase to a large size if needed. */ -typedef int __jmp_buf[12]; +typedef int __jmp_buf[8]; #endif /* _ARCH_SETJMP_H_ */ diff --git a/src/system/libroot/os/arch/x86_64/atomic.S b/src/system/libroot/os/arch/x86_64/atomic.S new file mode 100644 index 0000000000..7abf2d2743 --- /dev/null +++ b/src/system/libroot/os/arch/x86_64/atomic.S @@ -0,0 +1,128 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Distributed under the terms of the MIT License. + */ + + +#include + + +.text + +/* int32 atomic_set(vint32 *value, int32 newValue) */ +FUNCTION(atomic_set): + movl %esi, %eax + lock + xchgl %eax, (%rdi) + ret +FUNCTION_END(atomic_set) + +/* int32 atomic_test_and_set(vint32 *value, int32 newValue, int32 testAgainst) */ +FUNCTION(atomic_test_and_set): + movl %edx, %eax + lock + cmpxchgl %esi, (%rdi) + ret +FUNCTION_END(atomic_test_and_set) + +/* int32 atomic_add(vint32 *value, int32 addValue) */ +FUNCTION(atomic_add): + movl %esi, %eax + lock + xaddl %eax, (%rdi) + ret +FUNCTION_END(atomic_add) + +/* int32 atomic_and(vint32 *value, int32 andValue) */ +FUNCTION(atomic_and): + movl (%rdi), %eax +1: movl %eax, %edx + movl %eax, %ecx + andl %esi, %edx + lock + cmpxchgl %edx, (%rdi) + jnz 1b + movl %ecx, %eax + ret +FUNCTION_END(atomic_and) + +/* int32 atomic_or(vint32 *value, int32 orValue) */ +FUNCTION(atomic_or): + movl (%rdi), %eax +1: movl %eax, %edx + movl %eax, %ecx + orl %esi, %edx + lock + cmpxchgl %edx, (%rdi) + jnz 1b + movl %ecx, %eax + ret +FUNCTION_END(atomic_or) + +/* int32 atomic_get(vint32 *value) */ +FUNCTION(atomic_get): + movl (%rdi), %eax +1: lock + cmpxchgl %eax, (%rdi) + jnz 1b + ret +FUNCTION_END(atomic_get) + +/* int64 atomic_set64(vint64 *value, int64 newValue) */ +FUNCTION(atomic_set64): + movq %rsi, %rax + lock + xchgq %rax, (%rdi) + ret +FUNCTION_END(atomic_set64) + +/* int64 atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst) */ +FUNCTION(atomic_test_and_set64): + movq %rdx, %rax + lock + cmpxchgq %rsi, (%rdi) + ret +FUNCTION_END(atomic_test_and_set64) + +/* int64 atomic_add64(vint64 *value, int64 addValue) */ +FUNCTION(atomic_add64): + movq %rsi, %rax + lock + xaddq %rax, (%rdi) + ret +FUNCTION_END(atomic_add64) + +/* int64 atomic_and64(vint64 *value, int64 andValue) */ +FUNCTION(atomic_and64): + movq (%rdi), %rax +1: movq %rax, %rdx + movq %rax, %rcx + andq %rsi, %rdx + lock + cmpxchgq %rdx, (%rdi) + jnz 1b + movq %rcx, %rax + ret +FUNCTION_END(atomic_and64) + +/* int64 atomic_or64(vint64 *value, int64 orValue) */ +FUNCTION(atomic_or64): + movq (%rdi), %rax +1: movq %rax, %rdx + movq %rax, %rcx + orq %rsi, %rdx + lock + cmpxchgq %rdx, (%rdi) + jnz 1b + movq %rcx, %rax + ret +FUNCTION_END(atomic_or64) + +/* int64 atomic_get64(vint64 *value) */ +FUNCTION(atomic_get64): + movq (%rdi), %rax +1: lock + cmpxchgq %rax, (%rdi) + jnz 1b + ret +FUNCTION_END(atomic_get64) diff --git a/src/system/libroot/os/arch/x86_64/byteorder.S b/src/system/libroot/os/arch/x86_64/byteorder.S new file mode 100644 index 0000000000..9b346809fa --- /dev/null +++ b/src/system/libroot/os/arch/x86_64/byteorder.S @@ -0,0 +1,54 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Distributed under the terms of the MIT License. + */ + + +#include + + +/* uint16 __swap_int16(uint16 value) */ +FUNCTION(__swap_int16): + movl %edi, %eax + bswap %eax + shr $16, %eax + ret +FUNCTION_END(__swap_int16) + +/* uint32 __swap_int32(uint32 value) */ +FUNCTION(__swap_int32): + movl %edi, %eax + bswap %eax + ret +FUNCTION_END(__swap_int32) + +/* uint64 __swap_int64(uint64 value) */ +FUNCTION(__swap_int64): + movq %rdi, %rax + bswap %rax + ret +FUNCTION_END(__swap_int64) + +/* float __swap_float(float value) */ +FUNCTION(__swap_float): + sub $8, %rsp + movss %xmm0, (%rsp) + movl (%rsp), %eax + bswap %eax + movl %eax, (%rsp) + movss (%rsp), %xmm0 + add $8, %rsp + ret +FUNCTION_END(__swap_float) + +/* double __swap_double(double value) */ +FUNCTION(__swap_double): + sub $8, %rsp + movsd %xmm0, (%rsp) + movq (%rsp), %rax + bswap %rax + movq %rax, (%rsp) + movsd (%rsp), %xmm0 + add $8, %rsp + ret +FUNCTION_END(__swap_double) diff --git a/src/system/libroot/os/arch/x86_64/system_time.c b/src/system/libroot/os/arch/x86_64/system_time.c new file mode 100644 index 0000000000..6b4e3d7df9 --- /dev/null +++ b/src/system/libroot/os/arch/x86_64/system_time.c @@ -0,0 +1,4 @@ +/* + Just a dummy to avoid a special case in the build system. system_time() + is implemented in system_time_asm.S. +*/ diff --git a/src/system/libroot/os/arch/x86_64/system_time_asm.S b/src/system/libroot/os/arch/x86_64/system_time_asm.S new file mode 100644 index 0000000000..d6df8fa806 --- /dev/null +++ b/src/system/libroot/os/arch/x86_64/system_time_asm.S @@ -0,0 +1,149 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Distributed under the terms of the MIT License. + * + * Copyright 2001, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ + +#include + +FUNCTION(__x86_setup_system_time): + ret +FUNCTION_END(__x86_setup_system_time) + +// TODO: Implement these. + +/* int64 system_time(); */ +FUNCTION(system_time): + ud2a + ret +FUNCTION_END(system_time) + + +/* int64 system_time_nsecs(); */ +FUNCTION(system_time_nsecs): + ud2a + ret +FUNCTION_END(system_time_nsecs) + +#if 0 +/* saves the conversion factor needed for system_time */ +.lcomm cv_factor 4 +.lcomm cv_factor_nsecs 4 +.lcomm cv_factor_nsecs_shift 1 + + +.text + + +FUNCTION(__x86_setup_system_time): + movl 4(%esp), %eax + movl %eax, cv_factor + movl 8(%esp), %eax + movl %eax, cv_factor_nsecs + movb 12(%esp), %al + movb %al, cv_factor_nsecs_shift + ret +FUNCTION_END(__x86_setup_system_time) + + +/* int64 system_time(); */ +FUNCTION(system_time): + pushl %ebx + pushl %ecx + movl cv_factor, %ebx + + /* load 64-bit factor into %eax (low), %edx (high) */ + rdtsc /* time in %edx,%eax */ + + movl %edx, %ecx /* save high half */ + mull %ebx /* truncate %eax, but keep %edx */ + movl %ecx, %eax + movl %edx, %ecx /* save high half of low */ + mull %ebx /*, %eax*/ + /* now compute [%edx, %eax] + [%ecx], propagating carry */ + subl %ebx, %ebx /* need zero to propagate carry */ + addl %ecx, %eax + adc %ebx, %edx + popl %ecx + popl %ebx + ret +FUNCTION_END(system_time) + + +/* int64 system_time_nsecs(); */ +FUNCTION(system_time_nsecs): + testb $0, cv_factor_nsecs_shift + jne 1f + + /* same algorithm as system_time(), just with a different factor */ + + pushl %ebx + pushl %ecx + movl cv_factor_nsecs, %ebx + + /* load 64-bit factor into %eax (low), %edx (high) */ + rdtsc /* time in %edx,%eax */ + + movl %edx, %ecx /* save high half */ + mull %ebx /* truncate %eax, but keep %edx */ + movl %ecx, %eax + movl %edx, %ecx /* save high half of low */ + mull %ebx /*, %eax*/ + /* now compute [%edx, %eax] + [%ecx], propagating carry */ + subl %ebx, %ebx /* need zero to propagate carry */ + addl %ecx, %eax + adc %ebx, %edx + popl %ecx + popl %ebx + ret + +1: + /* TSC frequency is less than 1 GHz -- we shift everything up 16 bit */ + + pushl %ebx + pushl %ecx + pushl %esi + movl cv_factor_nsecs, %ebx + + /* load 64-bit factor into %eax (low), %edx (high) */ + rdtsc /* time in %edx,%eax */ + + /* save high half */ + movl %edx, %ecx + + /* multiply low half by conversion factor */ + mull %ebx + + /* save result */ + movl %eax, %esi /* low half -> %esi */ + movl %ecx, %eax + movl %edx, %ecx /* high half -> %ecx */ + + /* multiply high half by conversion factor */ + mull %ebx + + /* now compute [%edx, %eax] + [%ecx], propagating carry */ + xorl %ebx, %ebx /* need zero to propagate carry */ + addl %ecx, %eax + adc %ebx, %edx + + /* shift the result left 16 bit */ + shl $16, %edx + movl %eax, %ebx + shr $16, %ebx + orw %bx, %dx + shl $16, %eax + + /* add the high 16 bit of the low half of the low product */ + shr $16, %esi + orw %si, %ax + + popl %esi + popl %ecx + popl %ebx + ret +FUNCTION_END(system_time_nsecs) +#endif diff --git a/src/system/libroot/posix/arch/x86_64/setjmp_internal.h b/src/system/libroot/posix/arch/x86_64/setjmp_internal.h new file mode 100644 index 0000000000..6d7ed7c56f --- /dev/null +++ b/src/system/libroot/posix/arch/x86_64/setjmp_internal.h @@ -0,0 +1,20 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Distributed under the terms of the MIT License. + */ +#ifndef SETJMP_INTERNAL_H +#define SETJMP_INTERNAL_H + + +#define JMP_REGS_IP 0 +#define JMP_REGS_SP 8 +#define JMP_REGS_BP 16 +#define JMP_REGS_BX 24 +#define JMP_REGS_R12 32 +#define JMP_REGS_R13 40 +#define JMP_REGS_R14 48 +#define JMP_REGS_R15 56 + +#include + +#endif /* SETJMP_INTERNAL_H */ diff --git a/src/system/libroot/posix/arch/x86_64/siglongjmp.S b/src/system/libroot/posix/arch/x86_64/siglongjmp.S new file mode 100644 index 0000000000..5acae0990f --- /dev/null +++ b/src/system/libroot/posix/arch/x86_64/siglongjmp.S @@ -0,0 +1,32 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Distributed under the terms of the MIT License. + */ + +#include "setjmp_internal.h" + + +/* int __siglongjmp(jmp_buf buffer, int value) */ +FUNCTION(siglongjmp): +FUNCTION(longjmp): +FUNCTION(_longjmp): + // Restore new callee-save registers. + movq JMP_REGS_R15(%rdi), %r15 + movq JMP_REGS_R14(%rdi), %r14 + movq JMP_REGS_R13(%rdi), %r13 + movq JMP_REGS_R12(%rdi), %r12 + movq JMP_REGS_BX(%rdi), %rbx + movq JMP_REGS_BP(%rdi), %rbp + + // Restore new stack pointer and push return address. + movq JMP_REGS_SP(%rdi), %rsp + movq JMP_REGS_IP(%rdi), %rax + push %rax + + // __longjmp_return restores the signal mask and sets the return value. + call __longjmp_return + ret +FUNCTION_END(siglongjmp) + + +#pragma weak longjmp=siglongjmp diff --git a/src/system/libroot/posix/arch/x86_64/sigsetjmp.S b/src/system/libroot/posix/arch/x86_64/sigsetjmp.S new file mode 100644 index 0000000000..25bef80a68 --- /dev/null +++ b/src/system/libroot/posix/arch/x86_64/sigsetjmp.S @@ -0,0 +1,39 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Distributed under the terms of the MIT License. + */ + +#include "setjmp_internal.h" + + +/* int sigsetjmp(jmp_buf buffer, int saveMask) */ +FUNCTION(__sigsetjmp): +FUNCTION(sigsetjmp): + // Save instruction/stack pointers. + movq (%rsp), %rax + movq %rax, JMP_REGS_IP(%rdi) + leaq 8(%rsp), %rax + movq %rax, JMP_REGS_SP(%rdi) + + // Save callee-save registers. + movq %rbp, JMP_REGS_BP(%rdi) + movq %rbx, JMP_REGS_BX(%rdi) + movq %r12, JMP_REGS_R12(%rdi) + movq %r13, JMP_REGS_R13(%rdi) + movq %r14, JMP_REGS_R14(%rdi) + movq %r15, JMP_REGS_R15(%rdi) + + // __setjmp_save_sigs handles signal mask and return value. + jmp __setjmp_save_sigs +FUNCTION_END(setjmp) + + +/* int setjmp(jmp_buf buffer) */ +FUNCTION(setjmp): + // Jump to sigsetjmp with a zero saveMask. + xorl %edi, %edi + jmp sigsetjmp +FUNCTION_END(setjmp) + + +#pragma weak _setjmp=setjmp