xref: /illumos-gate/usr/src/uts/intel/io/vmm/vmm_time_support.S (revision fdad6fbf87b201fdb96a704fc41fa8be1e4efbc8)
1/*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source.  A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11/* This file is dual-licensed; see usr/src/contrib/bhyve/LICENSE */
12
13/*
14 * Copyright 2023 Oxide Computer Company
15 */
16
17#include <sys/asm_linkage.h>
18
19/*
20 * TSC math functions that require multiplication of 64-bit numbers with
21 * intermediate steps requiring 128-bit precision.
22 *
23 * See block comment in vmm.c for more details.
24 */
25
26
27/*
28 * calc_freq_multiplier: calculates the ratio of guest_hz / host_hz, with
29 * `frac_size` fractional bits.
30 *
31 * (guest_hz * (1 << FRAC_SIZE)) / host_hz
32 *
33 * Note: this will generate a #DE if:
34 * - the integer portion of the ratio does not fit into (64 - FRAC_SIZE) bits
35 * - host_hz is 0
36 * Callers should validate input appropriately.
37 *
38 *
39 * uint64_t calc_freq_multiplier(uint64_t guest_hz, uint64_t host_hz,
40 *     uint32_t frac_size)
41 * %rdi: uint64_t guest_hz
42 * %rsi: uint64_t host_hz
43 * %edx: uint32_t frac_size
44 */
45ENTRY_NP(calc_freq_multiplier)
46	/*
47	 * Create scaling factor: 1 << frac_size
48	 * Store result in %rax
49	 */
50	movl $1, %eax
51	movl %edx, %ecx
52	shlq %cl, %rax
53
54	/*
55	 * Multiply: guest_hz (%rdi) * scaling_factor (%rax)
56	 * Result is in %rdx:%rax
57	 */
58	mulq %rdi
59
60	/* Divide: result by host_hz (%rsi) */
61	divq %rsi
62	ret
63SET_SIZE(calc_freq_multiplier)
64
65
66/*
67 * scale_tsc: Scales a TSC value based on a frequency multiplier with
68 * FRAC_SIZE fractional bits.
69 *
70 * (tsc * multiplier) >> FRAC_SIZE
71 *
72 *
73 * uint64_t scale_tsc(uint64_t tsc, uint64_t multiplier, uint32_t frac_size)
74 * %rdi: uint64_t tsc
75 * %rsi: uint64_t multiplier
76 * %edx: uint32_t frac_size
77 */
78ENTRY_NP(scale_tsc)
79	/* Save `frac_size` */
80	mov %edx, %ecx
81
82	/*
83	 * Multiply tsc (%rdi) * multiplier (%rsi)
84	 * mulq result is in %rdx:%rax
85	 */
86	movq %rdi, %rax
87	mulq %rsi
88
89	/*
90	 * Shift the 128-bit product right `frac_size` bits:
91	 * - shift lower 64 bits right, `frac_size` bits
92	 * - shift upper 64 bits left, (64 - `frac_size`) bits
93	 * - bitwise OR upper bits and lower bits
94	 */
95
96	/* Shift lower 64 bits right `frac_size` */
97	shrq %cl, %rax
98
99	/* Compute 64 - FRAC_SIZE and store result in %cl */
100	movl %ecx, %r9d
101	movl $64, %ecx
102	subl %r9d, %ecx
103
104	/* Shift upper 64 bits left, (64 - `frac_size`) bits */
105	shlq %cl, %rdx
106
107	/* Bitwise OR upper and lower bits */
108	orq %rdx, %rax
109
110	ret
111SET_SIZE(scale_tsc)
112