1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 *
5 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
6 * Distributed under the terms of the NewOS License.
7 */
8
9#include <asm_defs.h>
10
11
12/* saves the conversion factor needed for system_time */
13.lcomm cv_factor				4
14.lcomm cv_factor_nsecs			4
15.lcomm cv_factor_nsecs_shift	1
16
17
18.text
19
20
21FUNCTION(__x86_setup_system_time):
22	movl	4(%esp), %eax
23	movl	%eax, cv_factor
24	movl	8(%esp), %eax
25	movl	%eax, cv_factor_nsecs
26	movb	12(%esp), %al
27	movb	%al, cv_factor_nsecs_shift
28	ret
29FUNCTION_END(__x86_setup_system_time)
30
31
32/* int64 system_time(); */
33FUNCTION(system_time):
34	pushl	%ebx
35	pushl	%ecx
36	movl	cv_factor, %ebx
37
38	/* load 64-bit factor into %eax (low), %edx (high) */
39	rdtsc		/* time in %edx,%eax */
40
41	movl	%edx, %ecx	/* save high half */
42	mull	%ebx 		/* truncate %eax, but keep %edx */
43	movl	%ecx, %eax
44	movl	%edx, %ecx	/* save high half of low */
45	mull	%ebx /*, %eax*/
46	/* now compute  [%edx, %eax] + [%ecx], propagating carry */
47	subl	%ebx, %ebx	/* need zero to propagate carry */
48	addl	%ecx, %eax
49	adc		%ebx, %edx
50	popl	%ecx
51	popl	%ebx
52	ret
53FUNCTION_END(system_time)
54
55
56/* int64 system_time_nsecs(); */
57FUNCTION(system_time_nsecs):
58	testb	$0, cv_factor_nsecs_shift
59	jne		1f
60
61	/* same algorithm as system_time(), just with a different factor */
62
63	pushl	%ebx
64	pushl	%ecx
65	movl	cv_factor_nsecs, %ebx
66
67	/* load 64-bit factor into %eax (low), %edx (high) */
68	rdtsc		/* time in %edx,%eax */
69
70	movl	%edx, %ecx	/* save high half */
71	mull	%ebx 		/* truncate %eax, but keep %edx */
72	movl	%ecx, %eax
73	movl	%edx, %ecx	/* save high half of low */
74	mull	%ebx /*, %eax*/
75	/* now compute  [%edx, %eax] + [%ecx], propagating carry */
76	subl	%ebx, %ebx	/* need zero to propagate carry */
77	addl	%ecx, %eax
78	adc		%ebx, %edx
79	popl	%ecx
80	popl	%ebx
81	ret
82
831:
84	/* TSC frequency is less than 1 GHz -- we shift everything up 16 bit */
85
86	pushl	%ebx
87	pushl	%ecx
88	pushl	%esi
89	movl	cv_factor_nsecs, %ebx
90
91	/* load 64-bit factor into %eax (low), %edx (high) */
92	rdtsc		/* time in %edx,%eax */
93
94	/* save high half */
95	movl	%edx, %ecx
96
97	/* multiply low half by conversion factor */
98	mull	%ebx
99
100	/* save result */
101	movl	%eax, %esi	/* low half -> %esi */
102	movl	%ecx, %eax
103	movl	%edx, %ecx	/* high half -> %ecx */
104
105	/* multiply high half by conversion factor */
106	mull	%ebx
107
108	/* now compute  [%edx, %eax] + [%ecx], propagating carry */
109	xorl	%ebx, %ebx	/* need zero to propagate carry */
110	addl	%ecx, %eax
111	adc		%ebx, %edx
112
113	/* shift the result left 16 bit */
114	shl		$16, %edx
115	movl	%eax, %ebx
116	shr		$16, %ebx
117	orw		%bx, %dx
118	shl		$16, %eax
119
120	/* add the high 16 bit of the low half of the low product */
121	shr		$16, %esi
122	orw		%si, %ax
123
124	popl	%esi
125	popl	%ecx
126	popl	%ebx
127	ret
128FUNCTION_END(system_time_nsecs)
129