diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index f688a206cb..204c901814 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -367,9 +367,14 @@ extern "C" { struct arch_thread; - +#ifdef __x86_64__ +void __x86_setup_system_time(uint64 conversionFactor, + uint64 conversionFactorNsecs); +#else void __x86_setup_system_time(uint32 conversionFactor, uint32 conversionFactorNsecs, bool conversionFactorNsecsShift); +#endif + void x86_context_switch(struct arch_thread* oldState, struct arch_thread* newState); void x86_userspace_thread_exit(void); diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index a618504d7f..6a7a2069b1 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -820,6 +820,12 @@ arch_cpu_init(kernel_args* args) uint32 conversionFactor = args->arch_args.system_time_cv_factor; uint64 conversionFactorNsecs = (uint64)conversionFactor * 1000; +#ifdef __x86_64__ + // The x86_64 system_time() implementation uses 64-bit multiplication and + // therefore shifting is not necessary for low frequencies (it's also not + // too likely that there'll be any x86_64 CPUs clocked under 1GHz). + __x86_setup_system_time(conversionFactor, conversionFactorNsecs); +#else if (conversionFactorNsecs >> 32 != 0) { // the TSC frequency is < 1 GHz, which forces us to shift the factor __x86_setup_system_time(conversionFactor, conversionFactorNsecs >> 16, @@ -828,6 +834,7 @@ arch_cpu_init(kernel_args* args) // the TSC frequency is >= 1 GHz __x86_setup_system_time(conversionFactor, conversionFactorNsecs, false); } +#endif return B_OK; } 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 index d6df8fa806..f63bdf35ba 100644 --- a/src/system/libroot/os/arch/x86_64/system_time_asm.S +++ b/src/system/libroot/os/arch/x86_64/system_time_asm.S @@ -7,143 +7,65 @@ * 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 +.lcomm cv_factor 8 +.lcomm cv_factor_nsecs 8 .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 + movq %rdi, cv_factor + movq %rsi, cv_factor_nsecs ret FUNCTION_END(__x86_setup_system_time) /* int64 system_time(); */ FUNCTION(system_time): - pushl %ebx - pushl %ecx - movl cv_factor, %ebx + movq cv_factor, %rcx - /* load 64-bit factor into %eax (low), %edx (high) */ - rdtsc /* time in %edx,%eax */ + // Load 64-bit TSC into %eax (low), %edx (high). + rdtsc - 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 + // Convert into a single 64-bit value. + shl $32, %rdx + orq %rdx, %rax + + // Multiply by conversion factor, result in %rax (low), %rdx (high). + mulq %rcx + + // Shift the result right by 32 bits. + shr $32, %rax + shl $32, %rdx + orq %rdx, %rax 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. + movq cv_factor_nsecs, %rcx - /* same algorithm as system_time(), just with a different factor */ + // Load 64-bit TSC into %eax (low), %edx (high). + rdtsc - pushl %ebx - pushl %ecx - movl cv_factor_nsecs, %ebx + // Convert into a single 64-bit value. + shl $32, %rdx + orq %rdx, %rax - /* load 64-bit factor into %eax (low), %edx (high) */ - rdtsc /* time in %edx,%eax */ + // Multiply by conversion factor, result in %rax (low), %rdx (high). + mulq %rcx - 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 + // Shift the result right by 32 bits. + shr $32, %rax + shl $32, %rdx + orq %rdx, %rax ret FUNCTION_END(system_time_nsecs) -#endif