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