1bf21cd93STycho Nightingale /*
2bf21cd93STycho Nightingale  * Copyright (c) 2004 Poul-Henning Kamp
3bf21cd93STycho Nightingale  * All rights reserved.
4bf21cd93STycho Nightingale  *
5bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
6bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
7bf21cd93STycho Nightingale  * are met:
8bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
9bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
10bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
11bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
12bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
13bf21cd93STycho Nightingale  *
14bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15bf21cd93STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16bf21cd93STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17bf21cd93STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18bf21cd93STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19bf21cd93STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20bf21cd93STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21bf21cd93STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22bf21cd93STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23bf21cd93STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24bf21cd93STycho Nightingale  * SUCH DAMAGE.
25bf21cd93STycho Nightingale  *
26bf21cd93STycho Nightingale  * $FreeBSD: head/sys/kern/subr_unit.c 255057 2013-08-30 07:37:45Z kib $
27bf21cd93STycho Nightingale  */
28bf21cd93STycho Nightingale /*
29bf21cd93STycho Nightingale  * This file and its contents are supplied under the terms of the
30bf21cd93STycho Nightingale  * Common Development and Distribution License ("CDDL"), version 1.0.
31bf21cd93STycho Nightingale  * You may only use this file in accordance with the terms of version
32bf21cd93STycho Nightingale  * 1.0 of the CDDL.
33bf21cd93STycho Nightingale  *
34bf21cd93STycho Nightingale  * A full copy of the text of the CDDL should have accompanied this
35bf21cd93STycho Nightingale  * source.  A copy of the CDDL is also available via the Internet at
36bf21cd93STycho Nightingale  * http://www.illumos.org/license/CDDL.
37bf21cd93STycho Nightingale  *
38bf21cd93STycho Nightingale  * Copyright 2014 Pluribus Networks Inc.
394c87aefeSPatrick Mooney  * Copyright 2019 Joyent, Inc.
40ee8ae3faSPatrick Mooney  * Copyright 2020 Oxide Computer Company
41bf21cd93STycho Nightingale  */
42bf21cd93STycho Nightingale 
43bf21cd93STycho Nightingale #include <sys/types.h>
44bf21cd93STycho Nightingale #include <sys/archsystm.h>
45bf21cd93STycho Nightingale #include <sys/cpuset.h>
46bf21cd93STycho Nightingale #include <sys/fp.h>
478130f8e1SPatrick Mooney #include <sys/kmem.h>
48bf21cd93STycho Nightingale #include <sys/queue.h>
49bf21cd93STycho Nightingale #include <sys/spl.h>
50bf21cd93STycho Nightingale #include <sys/systm.h>
514c87aefeSPatrick Mooney #include <sys/ddidmareq.h>
524c87aefeSPatrick Mooney #include <sys/id_space.h>
534c87aefeSPatrick Mooney #include <sys/psm_defs.h>
544c87aefeSPatrick Mooney #include <sys/smp_impldefs.h>
554c87aefeSPatrick Mooney #include <sys/modhash.h>
564c87aefeSPatrick Mooney #include <sys/hma.h>
57bf21cd93STycho Nightingale 
58eb9a1df2SHans Rosenfeld #include <sys/x86_archext.h>
59eb9a1df2SHans Rosenfeld 
60bf21cd93STycho Nightingale #include <machine/cpufunc.h>
61bf21cd93STycho Nightingale #include <machine/md_var.h>
62bf21cd93STycho Nightingale #include <machine/specialreg.h>
63bf21cd93STycho Nightingale #include <machine/vmm.h>
64cf409e3fSDan Cross #include <machine/vmparam.h>
65bf21cd93STycho Nightingale #include <sys/vmm_impl.h>
664c87aefeSPatrick Mooney #include <sys/kernel.h>
67bf21cd93STycho Nightingale 
68bf21cd93STycho Nightingale #include <vm/as.h>
69bf21cd93STycho Nightingale #include <vm/seg_kmem.h>
70bf21cd93STycho Nightingale 
71*17b3b9a6SPatrick Mooney 
72*17b3b9a6SPatrick Mooney static void vmm_tsc_init(void);
73*17b3b9a6SPatrick Mooney 
744c87aefeSPatrick Mooney SET_DECLARE(sysinit_set, struct sysinit);
754c87aefeSPatrick Mooney 
764c87aefeSPatrick Mooney void
sysinit(void)774c87aefeSPatrick Mooney sysinit(void)
784c87aefeSPatrick Mooney {
794c87aefeSPatrick Mooney 	struct sysinit **si;
804c87aefeSPatrick Mooney 
814c87aefeSPatrick Mooney 	SET_FOREACH(si, sysinit_set)
824c87aefeSPatrick Mooney 		(*si)->func((*si)->data);
834c87aefeSPatrick Mooney }
844c87aefeSPatrick Mooney 
85eb9a1df2SHans Rosenfeld void
invalidate_cache_all(void)860153d828SPatrick Mooney invalidate_cache_all(void)
87eb9a1df2SHans Rosenfeld {
88eb9a1df2SHans Rosenfeld 	cpuset_t cpuset;
89eb9a1df2SHans Rosenfeld 
90eb9a1df2SHans Rosenfeld 	kpreempt_disable();
91eb9a1df2SHans Rosenfeld 	cpuset_all_but(&cpuset, CPU->cpu_id);
92eb9a1df2SHans Rosenfeld 	xc_call((xc_arg_t)NULL, (xc_arg_t)NULL, (xc_arg_t)NULL,
93eb9a1df2SHans Rosenfeld 	    CPUSET2BV(cpuset), (xc_func_t)invalidate_cache);
94eb9a1df2SHans Rosenfeld 	invalidate_cache();
95eb9a1df2SHans Rosenfeld 	kpreempt_enable();
96eb9a1df2SHans Rosenfeld }
97eb9a1df2SHans Rosenfeld 
98bf21cd93STycho Nightingale vm_paddr_t
vtophys(void * va)990153d828SPatrick Mooney vtophys(void *va)
100bf21cd93STycho Nightingale {
101bf21cd93STycho Nightingale 	pfn_t	pfn;
102bf21cd93STycho Nightingale 
1034c87aefeSPatrick Mooney 	/*
1044c87aefeSPatrick Mooney 	 * Since hat_getpfnum() may block on an htable mutex, this is not at
1054c87aefeSPatrick Mooney 	 * all safe to run from a critical_enter/kpreempt_disable context.
1064c87aefeSPatrick Mooney 	 * The FreeBSD analog does not have the same locking constraints, so
1074c87aefeSPatrick Mooney 	 * close attention must be paid wherever this is called.
1084c87aefeSPatrick Mooney 	 */
1094c87aefeSPatrick Mooney 	ASSERT(curthread->t_preempt == 0);
1104c87aefeSPatrick Mooney 
111bf21cd93STycho Nightingale 	pfn = hat_getpfnum(kas.a_hat, (caddr_t)va);
112bf21cd93STycho Nightingale 	ASSERT(pfn != PFN_INVALID);
113bf21cd93STycho Nightingale 	return (pfn << PAGE_SHIFT) | ((uintptr_t)va & PAGE_MASK);
114bf21cd93STycho Nightingale }
115bf21cd93STycho Nightingale 
116bf21cd93STycho Nightingale int
cpusetobj_ffs(const cpuset_t * set)117bf21cd93STycho Nightingale cpusetobj_ffs(const cpuset_t *set)
118bf21cd93STycho Nightingale {
1194c87aefeSPatrick Mooney 	uint_t large, small;
120bf21cd93STycho Nightingale 
1214c87aefeSPatrick Mooney 	/*
1224c87aefeSPatrick Mooney 	 * Rather than reaching into the cpuset_t ourselves, leave that task to
1234c87aefeSPatrick Mooney 	 * cpuset_bounds().  The simplicity is worth the extra wasted work to
1244c87aefeSPatrick Mooney 	 * find the upper bound.
1254c87aefeSPatrick Mooney 	 */
1264c87aefeSPatrick Mooney 	cpuset_bounds(set, &small, &large);
127bf21cd93STycho Nightingale 
1284c87aefeSPatrick Mooney 	if (small == CPUSET_NOTINSET) {
1294c87aefeSPatrick Mooney 		/* The FreeBSD version returns 0 if it find nothing */
1304c87aefeSPatrick Mooney 		return (0);
1314c87aefeSPatrick Mooney 	}
132bf21cd93STycho Nightingale 
1334c87aefeSPatrick Mooney 	ASSERT3U(small, <=, INT_MAX);
134bf21cd93STycho Nightingale 
1354c87aefeSPatrick Mooney 	/* Least significant bit index starts at 1 for valid results */
1364c87aefeSPatrick Mooney 	return (small + 1);
137bf21cd93STycho Nightingale }
138bf21cd93STycho Nightingale 
1398130f8e1SPatrick Mooney struct vmm_ptp_item {
1408130f8e1SPatrick Mooney 	void *vpi_vaddr;
141bf21cd93STycho Nightingale };
1428130f8e1SPatrick Mooney static kmutex_t vmm_ptp_lock;
1434c87aefeSPatrick Mooney 
1448130f8e1SPatrick Mooney static mod_hash_t *vmm_ptp_hash;
1458130f8e1SPatrick Mooney uint_t vmm_ptp_hash_nchains = 16381;
1468130f8e1SPatrick Mooney uint_t vmm_ptp_hash_size = PAGESIZE;
1474c87aefeSPatrick Mooney 
1484c87aefeSPatrick Mooney static void
vmm_ptp_hash_valdtor(mod_hash_val_t val)1498130f8e1SPatrick Mooney vmm_ptp_hash_valdtor(mod_hash_val_t val)
1504c87aefeSPatrick Mooney {
1518130f8e1SPatrick Mooney 	struct vmm_ptp_item *i = (struct vmm_ptp_item *)val;
1524c87aefeSPatrick Mooney 
1538130f8e1SPatrick Mooney 	kmem_free(i->vpi_vaddr, PAGE_SIZE);
1548130f8e1SPatrick Mooney 	kmem_free(i, sizeof (*i));
1554c87aefeSPatrick Mooney }
1564c87aefeSPatrick Mooney 
1574c87aefeSPatrick Mooney static void
vmm_ptp_init(void)1588130f8e1SPatrick Mooney vmm_ptp_init(void)
1594c87aefeSPatrick Mooney {
1608130f8e1SPatrick Mooney 	vmm_ptp_hash = mod_hash_create_ptrhash("vmm_ptp_hash",
1618130f8e1SPatrick Mooney 	    vmm_ptp_hash_nchains, vmm_ptp_hash_valdtor, vmm_ptp_hash_size);
1624c87aefeSPatrick Mooney 
1638130f8e1SPatrick Mooney 	VERIFY(vmm_ptp_hash != NULL);
1644c87aefeSPatrick Mooney }
1654c87aefeSPatrick Mooney 
1664c87aefeSPatrick Mooney static uint_t
vmm_ptp_check(mod_hash_key_t key,mod_hash_val_t * val,void * unused)1678130f8e1SPatrick Mooney vmm_ptp_check(mod_hash_key_t key, mod_hash_val_t *val, void *unused)
1684c87aefeSPatrick Mooney {
1698130f8e1SPatrick Mooney 	struct vmm_ptp_item *i = (struct vmm_ptp_item *)val;
1704c87aefeSPatrick Mooney 
1718130f8e1SPatrick Mooney 	cmn_err(CE_PANIC, "!vmm_ptp_check: hash not empty: %p", i->vpi_vaddr);
1724c87aefeSPatrick Mooney 
1734c87aefeSPatrick Mooney 	return (MH_WALK_TERMINATE);
1744c87aefeSPatrick Mooney }
1754c87aefeSPatrick Mooney 
1764c87aefeSPatrick Mooney static void
vmm_ptp_cleanup(void)1778130f8e1SPatrick Mooney vmm_ptp_cleanup(void)
1784c87aefeSPatrick Mooney {
1798130f8e1SPatrick Mooney 	mod_hash_walk(vmm_ptp_hash, vmm_ptp_check, NULL);
1808130f8e1SPatrick Mooney 	mod_hash_destroy_ptrhash(vmm_ptp_hash);
1814c87aefeSPatrick Mooney }
182bf21cd93STycho Nightingale 
1838130f8e1SPatrick Mooney /*
1848130f8e1SPatrick Mooney  * The logic in VT-d uses both kernel-virtual and direct-mapped addresses when
1858130f8e1SPatrick Mooney  * freeing PTP pages.  Until the consuming code is improved to better track the
1868130f8e1SPatrick Mooney  * pages it allocates, we keep the kernel-virtual addresses to those pages in a
1878130f8e1SPatrick Mooney  * hash table for when they are freed.
1888130f8e1SPatrick Mooney  */
189bf21cd93STycho Nightingale void *
vmm_ptp_alloc(void)1908130f8e1SPatrick Mooney vmm_ptp_alloc(void)
191bf21cd93STycho Nightingale {
1928130f8e1SPatrick Mooney 	void *p;
1938130f8e1SPatrick Mooney 	struct vmm_ptp_item *i;
194bf21cd93STycho Nightingale 
1958130f8e1SPatrick Mooney 	p = kmem_zalloc(PAGE_SIZE, KM_SLEEP);
1968130f8e1SPatrick Mooney 	i = kmem_alloc(sizeof (struct vmm_ptp_item), KM_SLEEP);
1978130f8e1SPatrick Mooney 	i->vpi_vaddr = p;
1984c87aefeSPatrick Mooney 
1998130f8e1SPatrick Mooney 	mutex_enter(&vmm_ptp_lock);
2008130f8e1SPatrick Mooney 	VERIFY(mod_hash_insert(vmm_ptp_hash,
2014c87aefeSPatrick Mooney 	    (mod_hash_key_t)PHYS_TO_DMAP(vtophys(p)), (mod_hash_val_t)i) == 0);
2028130f8e1SPatrick Mooney 	mutex_exit(&vmm_ptp_lock);
203bf21cd93STycho Nightingale 
204bf21cd93STycho Nightingale 	return (p);
205bf21cd93STycho Nightingale }
206bf21cd93STycho Nightingale 
207bf21cd93STycho Nightingale void
vmm_ptp_free(void * addr)2088130f8e1SPatrick Mooney vmm_ptp_free(void *addr)
209bf21cd93STycho Nightingale {
2108130f8e1SPatrick Mooney 	mutex_enter(&vmm_ptp_lock);
2118130f8e1SPatrick Mooney 	VERIFY(mod_hash_destroy(vmm_ptp_hash,
2124c87aefeSPatrick Mooney 	    (mod_hash_key_t)PHYS_TO_DMAP(vtophys(addr))) == 0);
2138130f8e1SPatrick Mooney 	mutex_exit(&vmm_ptp_lock);
2144c87aefeSPatrick Mooney }
2154c87aefeSPatrick Mooney 
2168130f8e1SPatrick Mooney /* Reach into i86pc/os/ddi_impl.c for these */
2174c87aefeSPatrick Mooney extern void *contig_alloc(size_t, ddi_dma_attr_t *, uintptr_t, int);
2184c87aefeSPatrick Mooney extern void contig_free(void *, size_t);
219bf21cd93STycho Nightingale 
2204c87aefeSPatrick Mooney void *
vmm_contig_alloc(size_t size)2218130f8e1SPatrick Mooney vmm_contig_alloc(size_t size)
2224c87aefeSPatrick Mooney {
2234c87aefeSPatrick Mooney 	ddi_dma_attr_t attr = {
2244c87aefeSPatrick Mooney 		/* Using fastboot_dma_attr as a guide... */
2258130f8e1SPatrick Mooney 		.dma_attr_version	= DMA_ATTR_V0,
2268130f8e1SPatrick Mooney 		.dma_attr_addr_lo	= 0,
2278130f8e1SPatrick Mooney 		.dma_attr_addr_hi	= ~0UL,
2288130f8e1SPatrick Mooney 		.dma_attr_count_max	= 0x00000000FFFFFFFFULL,
2298130f8e1SPatrick Mooney 		.dma_attr_align		= PAGE_SIZE,
2308130f8e1SPatrick Mooney 		.dma_attr_burstsizes	= 1,
2318130f8e1SPatrick Mooney 		.dma_attr_minxfer	= 1,
2328130f8e1SPatrick Mooney 		.dma_attr_maxxfer	= 0x00000000FFFFFFFFULL,
2338130f8e1SPatrick Mooney 		.dma_attr_seg		= 0x00000000FFFFFFFFULL, /* any */
2348130f8e1SPatrick Mooney 		.dma_attr_sgllen	= 1,
2358130f8e1SPatrick Mooney 		.dma_attr_granular	= PAGE_SIZE,
2368130f8e1SPatrick Mooney 		.dma_attr_flags		= 0,
2374c87aefeSPatrick Mooney 	};
2388130f8e1SPatrick Mooney 	void *res;
2394c87aefeSPatrick Mooney 
2408130f8e1SPatrick Mooney 	res = contig_alloc(size, &attr, PAGE_SIZE, 1);
2418130f8e1SPatrick Mooney 	if (res != NULL) {
2428130f8e1SPatrick Mooney 		bzero(res, size);
2434c87aefeSPatrick Mooney 	}
2448130f8e1SPatrick Mooney 
2458130f8e1SPatrick Mooney 	return (res);
2464c87aefeSPatrick Mooney }
2474c87aefeSPatrick Mooney 
2484c87aefeSPatrick Mooney void
vmm_contig_free(void * addr,size_t size)2498130f8e1SPatrick Mooney vmm_contig_free(void *addr, size_t size)
2504c87aefeSPatrick Mooney {
2514c87aefeSPatrick Mooney 	contig_free(addr, size);
252bf21cd93STycho Nightingale }
253bf21cd93STycho Nightingale 
254bf21cd93STycho Nightingale void
critical_enter(void)255bf21cd93STycho Nightingale critical_enter(void)
256bf21cd93STycho Nightingale {
257bf21cd93STycho Nightingale 	kpreempt_disable();
258bf21cd93STycho Nightingale }
259bf21cd93STycho Nightingale 
260bf21cd93STycho Nightingale void
critical_exit(void)261bf21cd93STycho Nightingale critical_exit(void)
262bf21cd93STycho Nightingale {
263bf21cd93STycho Nightingale 	kpreempt_enable();
264bf21cd93STycho Nightingale }
265bf21cd93STycho Nightingale 
266bf21cd93STycho Nightingale 
267bf21cd93STycho Nightingale static void
vmm_glue_callout_handler(void * arg)268bf21cd93STycho Nightingale vmm_glue_callout_handler(void *arg)
269bf21cd93STycho Nightingale {
270bf21cd93STycho Nightingale 	struct callout *c = arg;
271bf21cd93STycho Nightingale 
272ee8ae3faSPatrick Mooney 	if (callout_active(c)) {
273ee8ae3faSPatrick Mooney 		/*
274ee8ae3faSPatrick Mooney 		 * Record the handler fire time so that callout_pending() is
275ee8ae3faSPatrick Mooney 		 * able to detect if the callout becomes rescheduled during the
276ee8ae3faSPatrick Mooney 		 * course of the handler.
277ee8ae3faSPatrick Mooney 		 */
278ee8ae3faSPatrick Mooney 		c->c_fired = gethrtime();
279bf21cd93STycho Nightingale 		(c->c_func)(c->c_arg);
280bf21cd93STycho Nightingale 	}
281bf21cd93STycho Nightingale }
282bf21cd93STycho Nightingale 
283bf21cd93STycho Nightingale void
vmm_glue_callout_init(struct callout * c,int mpsafe)284bf21cd93STycho Nightingale vmm_glue_callout_init(struct callout *c, int mpsafe)
285bf21cd93STycho Nightingale {
286bf21cd93STycho Nightingale 	cyc_handler_t	hdlr;
287bf21cd93STycho Nightingale 	cyc_time_t	when;
288bf21cd93STycho Nightingale 
289bf21cd93STycho Nightingale 	hdlr.cyh_level = CY_LOW_LEVEL;
290bf21cd93STycho Nightingale 	hdlr.cyh_func = vmm_glue_callout_handler;
291bf21cd93STycho Nightingale 	hdlr.cyh_arg = c;
292bf21cd93STycho Nightingale 	when.cyt_when = CY_INFINITY;
293bf21cd93STycho Nightingale 	when.cyt_interval = CY_INFINITY;
294ee8ae3faSPatrick Mooney 	bzero(c, sizeof (*c));
295bf21cd93STycho Nightingale 
296bf21cd93STycho Nightingale 	mutex_enter(&cpu_lock);
2974c87aefeSPatrick Mooney 	c->c_cyc_id = cyclic_add(&hdlr, &when);
298bf21cd93STycho Nightingale 	mutex_exit(&cpu_lock);
299bf21cd93STycho Nightingale }
300bf21cd93STycho Nightingale 
3015103e761SPatrick Mooney void
callout_reset_hrtime(struct callout * c,hrtime_t target,void (* func)(void *),void * arg,int flags)3025103e761SPatrick Mooney callout_reset_hrtime(struct callout *c, hrtime_t target, void (*func)(void *),
3035103e761SPatrick Mooney     void *arg, int flags)
304bf21cd93STycho Nightingale {
305bf21cd93STycho Nightingale 	ASSERT(c->c_cyc_id != CYCLIC_NONE);
306bf21cd93STycho Nightingale 
307ee8ae3faSPatrick Mooney 	if ((flags & C_ABSOLUTE) == 0) {
308ee8ae3faSPatrick Mooney 		target += gethrtime();
309ee8ae3faSPatrick Mooney 	}
310ee8ae3faSPatrick Mooney 
311bf21cd93STycho Nightingale 	c->c_func = func;
312bf21cd93STycho Nightingale 	c->c_arg = arg;
313ee8ae3faSPatrick Mooney 	c->c_target = target;
314e0994bd2SPatrick Mooney 	(void) cyclic_reprogram(c->c_cyc_id, target);
315bf21cd93STycho Nightingale }
316bf21cd93STycho Nightingale 
317e0994bd2SPatrick Mooney void
vmm_glue_callout_stop(struct callout * c)318bf21cd93STycho Nightingale vmm_glue_callout_stop(struct callout *c)
319bf21cd93STycho Nightingale {
320bf21cd93STycho Nightingale 	ASSERT(c->c_cyc_id != CYCLIC_NONE);
321ee8ae3faSPatrick Mooney 
322ee8ae3faSPatrick Mooney 	c->c_target = 0;
323e0994bd2SPatrick Mooney 	(void) cyclic_reprogram(c->c_cyc_id, CY_INFINITY);
324bf21cd93STycho Nightingale }
325bf21cd93STycho Nightingale 
326e0994bd2SPatrick Mooney void
vmm_glue_callout_drain(struct callout * c)327bf21cd93STycho Nightingale vmm_glue_callout_drain(struct callout *c)
328bf21cd93STycho Nightingale {
329bf21cd93STycho Nightingale 	ASSERT(c->c_cyc_id != CYCLIC_NONE);
330ee8ae3faSPatrick Mooney 
331ee8ae3faSPatrick Mooney 	c->c_target = 0;
332bf21cd93STycho Nightingale 	mutex_enter(&cpu_lock);
333bf21cd93STycho Nightingale 	cyclic_remove(c->c_cyc_id);
334bf21cd93STycho Nightingale 	c->c_cyc_id = CYCLIC_NONE;
335bf21cd93STycho Nightingale 	mutex_exit(&cpu_lock);
336bf21cd93STycho Nightingale }
337bf21cd93STycho Nightingale 
338bf21cd93STycho Nightingale void
vmm_glue_callout_localize(struct callout * c)3394c87aefeSPatrick Mooney vmm_glue_callout_localize(struct callout *c)
340bf21cd93STycho Nightingale {
3414c87aefeSPatrick Mooney 	mutex_enter(&cpu_lock);
3424c87aefeSPatrick Mooney 	cyclic_move_here(c->c_cyc_id);
3434c87aefeSPatrick Mooney 	mutex_exit(&cpu_lock);
344bf21cd93STycho Nightingale }
345bf21cd93STycho Nightingale 
3465103e761SPatrick Mooney /*
3475103e761SPatrick Mooney  * Given an interval (in ns) and a frequency (in hz), calculate the number of
3485103e761SPatrick Mooney  * "ticks" at that frequency which cover the interval.
3495103e761SPatrick Mooney  */
3505103e761SPatrick Mooney uint64_t
hrt_freq_count(hrtime_t interval,uint32_t freq)3515103e761SPatrick Mooney hrt_freq_count(hrtime_t interval, uint32_t freq)
3525103e761SPatrick Mooney {
3535103e761SPatrick Mooney 	ASSERT3S(interval, >=, 0);
3545103e761SPatrick Mooney 	const uint64_t sec = interval / NANOSEC;
3555103e761SPatrick Mooney 	const uint64_t nsec = interval % NANOSEC;
3565103e761SPatrick Mooney 
3575103e761SPatrick Mooney 	return ((sec * freq) + ((nsec * freq) / NANOSEC));
3585103e761SPatrick Mooney }
3595103e761SPatrick Mooney 
3605103e761SPatrick Mooney /*
3615103e761SPatrick Mooney  * Given a frequency (in hz) and number of "ticks", calculate the interval
3625103e761SPatrick Mooney  * (in ns) which would be covered by those ticks.
3635103e761SPatrick Mooney  */
3645103e761SPatrick Mooney hrtime_t
hrt_freq_interval(uint32_t freq,uint64_t count)3655103e761SPatrick Mooney hrt_freq_interval(uint32_t freq, uint64_t count)
3665103e761SPatrick Mooney {
3675103e761SPatrick Mooney 	const uint64_t sec = count / freq;
3685103e761SPatrick Mooney 	const uint64_t frac = count % freq;
3695103e761SPatrick Mooney 
3705103e761SPatrick Mooney 	return ((NANOSEC * sec) + ((frac * NANOSEC) / freq));
3715103e761SPatrick Mooney }
3725103e761SPatrick Mooney 
3735103e761SPatrick Mooney 
3742699b94cSPatrick Mooney uint_t	cpu_high;		/* Highest arg to CPUID */
3752699b94cSPatrick Mooney uint_t	cpu_exthigh;		/* Highest arg to extended CPUID */
3762699b94cSPatrick Mooney uint_t	cpu_id;			/* Stepping ID */
377bf21cd93STycho Nightingale char	cpu_vendor[20];		/* CPU Origin code */
378bf21cd93STycho Nightingale 
379bf21cd93STycho Nightingale static void
vmm_cpuid_init(void)380bf21cd93STycho Nightingale vmm_cpuid_init(void)
381bf21cd93STycho Nightingale {
3822699b94cSPatrick Mooney 	uint_t regs[4];
383bf21cd93STycho Nightingale 
384bf21cd93STycho Nightingale 	do_cpuid(0, regs);
385bf21cd93STycho Nightingale 	cpu_high = regs[0];
3862699b94cSPatrick Mooney 	((uint_t *)&cpu_vendor)[0] = regs[1];
3872699b94cSPatrick Mooney 	((uint_t *)&cpu_vendor)[1] = regs[3];
3882699b94cSPatrick Mooney 	((uint_t *)&cpu_vendor)[2] = regs[2];
389bf21cd93STycho Nightingale 	cpu_vendor[12] = '\0';
390bf21cd93STycho Nightingale 
391bf21cd93STycho Nightingale 	do_cpuid(1, regs);
392bf21cd93STycho Nightingale 	cpu_id = regs[0];
393bf21cd93STycho Nightingale 
394bf21cd93STycho Nightingale 	do_cpuid(0x80000000, regs);
395bf21cd93STycho Nightingale 	cpu_exthigh = regs[0];
396bf21cd93STycho Nightingale }
397bf21cd93STycho Nightingale 
3984c87aefeSPatrick Mooney void
vmm_sol_glue_init(void)3994c87aefeSPatrick Mooney vmm_sol_glue_init(void)
400bf21cd93STycho Nightingale {
4018130f8e1SPatrick Mooney 	vmm_ptp_init();
4024c87aefeSPatrick Mooney 	vmm_cpuid_init();
403*17b3b9a6SPatrick Mooney 	vmm_tsc_init();
404bf21cd93STycho Nightingale }
405bf21cd93STycho Nightingale 
406bf21cd93STycho Nightingale void
vmm_sol_glue_cleanup(void)4074c87aefeSPatrick Mooney vmm_sol_glue_cleanup(void)
408bf21cd93STycho Nightingale {
4098130f8e1SPatrick Mooney 	vmm_ptp_cleanup();
410bf21cd93STycho Nightingale }
411bf21cd93STycho Nightingale 
4124c87aefeSPatrick Mooney 
4134c87aefeSPatrick Mooney /* From FreeBSD's sys/kern/subr_clock.c */
4144c87aefeSPatrick Mooney 
4154c87aefeSPatrick Mooney /*-
4164c87aefeSPatrick Mooney  * Copyright (c) 1988 University of Utah.
4174c87aefeSPatrick Mooney  * Copyright (c) 1982, 1990, 1993
4184c87aefeSPatrick Mooney  *	The Regents of the University of California.  All rights reserved.
4194c87aefeSPatrick Mooney  *
4204c87aefeSPatrick Mooney  * This code is derived from software contributed to Berkeley by
4214c87aefeSPatrick Mooney  * the Systems Programming Group of the University of Utah Computer
4224c87aefeSPatrick Mooney  * Science Department.
4234c87aefeSPatrick Mooney  *
4244c87aefeSPatrick Mooney  * Redistribution and use in source and binary forms, with or without
4254c87aefeSPatrick Mooney  * modification, are permitted provided that the following conditions
4264c87aefeSPatrick Mooney  * are met:
4274c87aefeSPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
4284c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer.
4294c87aefeSPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
4304c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
4314c87aefeSPatrick Mooney  *    documentation and/or other materials provided with the distribution.
4324c87aefeSPatrick Mooney  * 4. Neither the name of the University nor the names of its contributors
4334c87aefeSPatrick Mooney  *    may be used to endorse or promote products derived from this software
4344c87aefeSPatrick Mooney  *    without specific prior written permission.
4354c87aefeSPatrick Mooney  *
4364c87aefeSPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
4374c87aefeSPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4384c87aefeSPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4394c87aefeSPatrick Mooney  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
4404c87aefeSPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4414c87aefeSPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4424c87aefeSPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4434c87aefeSPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4444c87aefeSPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4454c87aefeSPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4464c87aefeSPatrick Mooney  * SUCH DAMAGE.
4474c87aefeSPatrick Mooney  *
4484c87aefeSPatrick Mooney  *	from: Utah $Hdr: clock.c 1.18 91/01/21$
4494c87aefeSPatrick Mooney  *	from: @(#)clock.c	8.2 (Berkeley) 1/12/94
4504c87aefeSPatrick Mooney  *	from: NetBSD: clock_subr.c,v 1.6 2001/07/07 17:04:02 thorpej Exp
4514c87aefeSPatrick Mooney  *	and
4524c87aefeSPatrick Mooney  *	from: src/sys/i386/isa/clock.c,v 1.176 2001/09/04
4534c87aefeSPatrick Mooney  */
4544c87aefeSPatrick Mooney 
4554c87aefeSPatrick Mooney #include <sys/clock.h>
4564c87aefeSPatrick Mooney 
4572699b94cSPatrick Mooney /*
4584c87aefeSPatrick Mooney  * Generic routines to convert between a POSIX date
4594c87aefeSPatrick Mooney  * (seconds since 1/1/1970) and yr/mo/day/hr/min/sec
4604c87aefeSPatrick Mooney  * Derived from NetBSD arch/hp300/hp300/clock.c
4614c87aefeSPatrick Mooney  */
4624c87aefeSPatrick Mooney 
4634c87aefeSPatrick Mooney #define	FEBRUARY	2
46484971882SPatrick Mooney #define	days_in_year(y)		(leapyear(y) ? 366 : 365)
4654c87aefeSPatrick Mooney #define	days_in_month(y, m) \
4664c87aefeSPatrick Mooney 	(month_days[(m) - 1] + (m == FEBRUARY ? leapyear(y) : 0))
4674c87aefeSPatrick Mooney /* Day of week. Days are counted from 1/1/1970, which was a Thursday */
4684c87aefeSPatrick Mooney #define	day_of_week(days)	(((days) + 4) % 7)
4694c87aefeSPatrick Mooney 
4704c87aefeSPatrick Mooney static const int month_days[12] = {
4714c87aefeSPatrick Mooney 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
4724c87aefeSPatrick Mooney };
4734c87aefeSPatrick Mooney 
4744c87aefeSPatrick Mooney 
4754c87aefeSPatrick Mooney /*
4764c87aefeSPatrick Mooney  * This inline avoids some unnecessary modulo operations
4774c87aefeSPatrick Mooney  * as compared with the usual macro:
4784c87aefeSPatrick Mooney  *   ( ((year % 4) == 0 &&
4794c87aefeSPatrick Mooney  *      (year % 100) != 0) ||
4804c87aefeSPatrick Mooney  *     ((year % 400) == 0) )
4814c87aefeSPatrick Mooney  * It is otherwise equivalent.
4824c87aefeSPatrick Mooney  */
4834c87aefeSPatrick Mooney static int
leapyear(int year)4844c87aefeSPatrick Mooney leapyear(int year)
485bf21cd93STycho Nightingale {
4864c87aefeSPatrick Mooney 	int rv = 0;
4874c87aefeSPatrick Mooney 
4884c87aefeSPatrick Mooney 	if ((year & 3) == 0) {
4894c87aefeSPatrick Mooney 		rv = 1;
4904c87aefeSPatrick Mooney 		if ((year % 100) == 0) {
4914c87aefeSPatrick Mooney 			rv = 0;
4924c87aefeSPatrick Mooney 			if ((year % 400) == 0)
4934c87aefeSPatrick Mooney 				rv = 1;
4944c87aefeSPatrick Mooney 		}
495bf21cd93STycho Nightingale 	}
4964c87aefeSPatrick Mooney 	return (rv);
497bf21cd93STycho Nightingale }
498bf21cd93STycho Nightingale 
4994c87aefeSPatrick Mooney int
clock_ct_to_ts(struct clocktime * ct,struct timespec * ts)5004c87aefeSPatrick Mooney clock_ct_to_ts(struct clocktime *ct, struct timespec *ts)
501bf21cd93STycho Nightingale {
5024c87aefeSPatrick Mooney 	int i, year, days;
5034c87aefeSPatrick Mooney 
5044c87aefeSPatrick Mooney 	year = ct->year;
5054c87aefeSPatrick Mooney 
5064c87aefeSPatrick Mooney #ifdef __FreeBSD__
5074c87aefeSPatrick Mooney 	if (ct_debug) {
5084c87aefeSPatrick Mooney 		printf("ct_to_ts(");
5094c87aefeSPatrick Mooney 		print_ct(ct);
5104c87aefeSPatrick Mooney 		printf(")");
5114c87aefeSPatrick Mooney 	}
5124c87aefeSPatrick Mooney #endif
5134c87aefeSPatrick Mooney 
5144c87aefeSPatrick Mooney 	/* Sanity checks. */
5154c87aefeSPatrick Mooney 	if (ct->mon < 1 || ct->mon > 12 || ct->day < 1 ||
5164c87aefeSPatrick Mooney 	    ct->day > days_in_month(year, ct->mon) ||
5172699b94cSPatrick Mooney 	    ct->hour > 23 || ct->min > 59 || ct->sec > 59 ||
5182699b94cSPatrick Mooney 	    (sizeof (time_t) == 4 && year > 2037)) {	/* time_t overflow */
5194c87aefeSPatrick Mooney #ifdef __FreeBSD__
5204c87aefeSPatrick Mooney 		if (ct_debug)
5214c87aefeSPatrick Mooney 			printf(" = EINVAL\n");
5224c87aefeSPatrick Mooney #endif
5234c87aefeSPatrick Mooney 		return (EINVAL);
5244c87aefeSPatrick Mooney 	}
5254c87aefeSPatrick Mooney 
5264c87aefeSPatrick Mooney 	/*
5274c87aefeSPatrick Mooney 	 * Compute days since start of time
5284c87aefeSPatrick Mooney 	 * First from years, then from months.
5294c87aefeSPatrick Mooney 	 */
5304c87aefeSPatrick Mooney 	days = 0;
5314c87aefeSPatrick Mooney 	for (i = POSIX_BASE_YEAR; i < year; i++)
5324c87aefeSPatrick Mooney 		days += days_in_year(i);
5334c87aefeSPatrick Mooney 
5344c87aefeSPatrick Mooney 	/* Months */
5354c87aefeSPatrick Mooney 	for (i = 1; i < ct->mon; i++)
53684971882SPatrick Mooney 		days += days_in_month(year, i);
5374c87aefeSPatrick Mooney 	days += (ct->day - 1);
5384c87aefeSPatrick Mooney 
5394c87aefeSPatrick Mooney 	ts->tv_sec = (((time_t)days * 24 + ct->hour) * 60 + ct->min) * 60 +
5404c87aefeSPatrick Mooney 	    ct->sec;
5414c87aefeSPatrick Mooney 	ts->tv_nsec = ct->nsec;
5424c87aefeSPatrick Mooney 
5434c87aefeSPatrick Mooney #ifdef __FreeBSD__
5444c87aefeSPatrick Mooney 	if (ct_debug)
5454c87aefeSPatrick Mooney 		printf(" = %ld.%09ld\n", (long)ts->tv_sec, (long)ts->tv_nsec);
5464c87aefeSPatrick Mooney #endif
5474c87aefeSPatrick Mooney 	return (0);
548bf21cd93STycho Nightingale }
549bf21cd93STycho Nightingale 
550bf21cd93STycho Nightingale void
clock_ts_to_ct(struct timespec * ts,struct clocktime * ct)5514c87aefeSPatrick Mooney clock_ts_to_ct(struct timespec *ts, struct clocktime *ct)
5524c87aefeSPatrick Mooney {
5534c87aefeSPatrick Mooney 	int i, year, days;
5544c87aefeSPatrick Mooney 	time_t rsec;	/* remainder seconds */
5554c87aefeSPatrick Mooney 	time_t secs;
5564c87aefeSPatrick Mooney 
5574c87aefeSPatrick Mooney 	secs = ts->tv_sec;
5584c87aefeSPatrick Mooney 	days = secs / SECDAY;
5594c87aefeSPatrick Mooney 	rsec = secs % SECDAY;
5604c87aefeSPatrick Mooney 
5614c87aefeSPatrick Mooney 	ct->dow = day_of_week(days);
5624c87aefeSPatrick Mooney 
5634c87aefeSPatrick Mooney 	/* Subtract out whole years, counting them in i. */
5644c87aefeSPatrick Mooney 	for (year = POSIX_BASE_YEAR; days >= days_in_year(year); year++)
5654c87aefeSPatrick Mooney 		days -= days_in_year(year);
5664c87aefeSPatrick Mooney 	ct->year = year;
5674c87aefeSPatrick Mooney 
5684c87aefeSPatrick Mooney 	/* Subtract out whole months, counting them in i. */
5694c87aefeSPatrick Mooney 	for (i = 1; days >= days_in_month(year, i); i++)
5704c87aefeSPatrick Mooney 		days -= days_in_month(year, i);
5714c87aefeSPatrick Mooney 	ct->mon = i;
5724c87aefeSPatrick Mooney 
5734c87aefeSPatrick Mooney 	/* Days are what is left over (+1) from all that. */
5744c87aefeSPatrick Mooney 	ct->day = days + 1;
5754c87aefeSPatrick Mooney 
5764c87aefeSPatrick Mooney 	/* Hours, minutes, seconds are easy */
5774c87aefeSPatrick Mooney 	ct->hour = rsec / 3600;
5784c87aefeSPatrick Mooney 	rsec = rsec % 3600;
5794c87aefeSPatrick Mooney 	ct->min  = rsec / 60;
5804c87aefeSPatrick Mooney 	rsec = rsec % 60;
5814c87aefeSPatrick Mooney 	ct->sec  = rsec;
5824c87aefeSPatrick Mooney 	ct->nsec = ts->tv_nsec;
5834c87aefeSPatrick Mooney #ifdef __FreeBSD__
5844c87aefeSPatrick Mooney 	if (ct_debug) {
5854c87aefeSPatrick Mooney 		printf("ts_to_ct(%ld.%09ld) = ",
5864c87aefeSPatrick Mooney 		    (long)ts->tv_sec, (long)ts->tv_nsec);
5874c87aefeSPatrick Mooney 		print_ct(ct);
5884c87aefeSPatrick Mooney 		printf("\n");
5894c87aefeSPatrick Mooney 	}
5904c87aefeSPatrick Mooney #endif
591bf21cd93STycho Nightingale }
5929250eb13SPatrick Mooney 
593*17b3b9a6SPatrick Mooney /* Do the host CPU TSCs require offsets be applied for proper sync? */
594*17b3b9a6SPatrick Mooney static bool vmm_host_tsc_offset;
595*17b3b9a6SPatrick Mooney 
596*17b3b9a6SPatrick Mooney static void
vmm_tsc_init(void)597*17b3b9a6SPatrick Mooney vmm_tsc_init(void)
5989250eb13SPatrick Mooney {
5999250eb13SPatrick Mooney 	/*
6009250eb13SPatrick Mooney 	 * The timestamp logic will decide if a delta need be applied to the
6019250eb13SPatrick Mooney 	 * unscaled hrtime reading (effectively rdtsc), but we do require it be
6029250eb13SPatrick Mooney 	 * backed by the TSC itself.
6039250eb13SPatrick Mooney 	 */
6049250eb13SPatrick Mooney 	extern hrtime_t (*gethrtimeunscaledf)(void);
6059250eb13SPatrick Mooney 	extern hrtime_t tsc_gethrtimeunscaled(void);
6069250eb13SPatrick Mooney 	extern hrtime_t tsc_gethrtimeunscaled_delta(void);
6079250eb13SPatrick Mooney 
608*17b3b9a6SPatrick Mooney 	VERIFY(*gethrtimeunscaledf == tsc_gethrtimeunscaled ||
6099250eb13SPatrick Mooney 	    *gethrtimeunscaledf == tsc_gethrtimeunscaled_delta);
610*17b3b9a6SPatrick Mooney 
611*17b3b9a6SPatrick Mooney 	/*
612*17b3b9a6SPatrick Mooney 	 * If a delta is being applied to the TSC on a per-host-CPU basis,
613*17b3b9a6SPatrick Mooney 	 * expose that delta via vmm_host_tsc_delta().
614*17b3b9a6SPatrick Mooney 	 */
615*17b3b9a6SPatrick Mooney 	vmm_host_tsc_offset =
616*17b3b9a6SPatrick Mooney 	    (*gethrtimeunscaledf == tsc_gethrtimeunscaled_delta);
617*17b3b9a6SPatrick Mooney 
618*17b3b9a6SPatrick Mooney }
619*17b3b9a6SPatrick Mooney 
620*17b3b9a6SPatrick Mooney /* Equivalent to the FreeBSD rdtsc(), but with any necessary per-cpu offset */
621*17b3b9a6SPatrick Mooney uint64_t
rdtsc_offset(void)622*17b3b9a6SPatrick Mooney rdtsc_offset(void)
623*17b3b9a6SPatrick Mooney {
6249250eb13SPatrick Mooney 	return ((uint64_t)gethrtimeunscaledf());
6259250eb13SPatrick Mooney }
626*17b3b9a6SPatrick Mooney 
627*17b3b9a6SPatrick Mooney /*
628*17b3b9a6SPatrick Mooney  * The delta (if any) which needs to be applied to the TSC of this host CPU to
629*17b3b9a6SPatrick Mooney  * bring it in sync with the others.
630*17b3b9a6SPatrick Mooney  */
631*17b3b9a6SPatrick Mooney uint64_t
vmm_host_tsc_delta(void)632*17b3b9a6SPatrick Mooney vmm_host_tsc_delta(void)
633*17b3b9a6SPatrick Mooney {
634*17b3b9a6SPatrick Mooney 	if (vmm_host_tsc_offset) {
635*17b3b9a6SPatrick Mooney 		extern hrtime_t tsc_gethrtime_tick_delta(void);
636*17b3b9a6SPatrick Mooney 		return (tsc_gethrtime_tick_delta());
637*17b3b9a6SPatrick Mooney 	} else {
638*17b3b9a6SPatrick Mooney 		return (0);
639*17b3b9a6SPatrick Mooney 	}
640*17b3b9a6SPatrick Mooney }
641