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
12/*
13 * Copyright 2023 Oxide Computer Company
14 */
15
16#include <sys/asm_linkage.h>
17
18/*
19 * TSC math functions that require multiplication of 64-bit numbers with
20 * intermediate steps requiring 128-bit precision.
21 *
22 * See block comment in vmm.c for more details.
23 */
24
25
26/*
27 * calc_freq_multiplier: calculates the ratio of guest_hz / host_hz, with
28 * `frac_size` fractional bits.
29 *
30 * (guest_hz * (1 << FRAC_SIZE)) / host_hz
31 *
32 * Note: this will generate a #DE if:
33 * - the integer portion of the ratio does not fit into (64 - FRAC_SIZE) bits
34 * - host_hz is 0
35 * Callers should validate input appropriately.
36 *
37 *
38 * uint64_t calc_freq_multiplier(uint64_t guest_hz, uint64_t host_hz,
39 *     uint32_t frac_size)
40 * %rdi: uint64_t guest_hz
41 * %rsi: uint64_t host_hz
42 * %edx: uint32_t frac_size
43 */
44ENTRY_NP(calc_freq_multiplier)
45	/*
46	 * Create scaling factor: 1 << frac_size
47	 * Store result in %rax
48	 */
49	movl $1, %eax
50	movl %edx, %ecx
51	shlq %cl, %rax
52
53	/*
54	 * Multiply: guest_hz (%rdi) * scaling_factor (%rax)
55	 * Result is in %rdx:%rax
56	 */
57	mulq %rdi
58
59	/* Divide: result by host_hz (%rsi) */
60	divq %rsi
61	ret
62SET_SIZE(calc_freq_multiplier)
63
64
65/*
66 * scale_tsc: Scales a TSC value based on a frequency multiplier with
67 * FRAC_SIZE fractional bits.
68 *
69 * (tsc * multiplier) >> FRAC_SIZE
70 *
71 *
72 * uint64_t scale_tsc(uint64_t tsc, uint64_t multiplier, uint32_t frac_size)
73 * %rdi: uint64_t tsc
74 * %rsi: uint64_t multiplier
75 * %edx: uint32_t frac_size
76 */
77ENTRY_NP(scale_tsc)
78	/* Save `frac_size` */
79	mov %edx, %ecx
80
81	/*
82	 * Multiply tsc (%rdi) * multiplier (%rsi)
83	 * mulq result is in %rdx:%rax
84	 */
85	movq %rdi, %rax
86	mulq %rsi
87
88	/*
89	 * Shift the 128-bit product right `frac_size` bits:
90	 * - shift lower 64 bits right, `frac_size` bits
91	 * - shift upper 64 bits left, (64 - `frac_size`) bits
92	 * - bitwise OR upper bits and lower bits
93	 */
94
95	/* Shift lower 64 bits right `frac_size` */
96	shrq %cl, %rax
97
98	/* Compute 64 - FRAC_SIZE and store result in %cl */
99	movl %ecx, %r9d
100	movl $64, %ecx
101	subl %r9d, %ecx
102
103	/* Shift upper 64 bits left, (64 - `frac_size`) bits */
104	shlq %cl, %rdx
105
106	/* Bitwise OR upper and lower bits */
107	orq %rdx, %rax
108
109	ret
110SET_SIZE(scale_tsc)
111