summaryrefslogtreecommitdiffstats
path: root/src/VBox/Runtime/r0drv/freebsd
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/r0drv/freebsd')
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/Makefile.kup0
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/alloc-r0drv-freebsd.c209
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/assert-r0drv-freebsd.c94
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/initterm-r0drv-freebsd.c77
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/memobj-r0drv-freebsd.c892
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/memuserkernel-r0drv-freebsd.c83
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/mp-r0drv-freebsd.c312
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/process-r0drv-freebsd.c75
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/semevent-r0drv-freebsd.c280
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/semeventmulti-r0drv-freebsd.c344
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/semfastmutex-r0drv-freebsd.c139
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/semmutex-r0drv-freebsd.c219
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h334
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/spinlock-r0drv-freebsd.c234
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/the-freebsd-kernel.h160
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/thread-r0drv-freebsd.c186
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/thread2-r0drv-freebsd.c179
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/time-r0drv-freebsd.c98
-rw-r--r--src/VBox/Runtime/r0drv/freebsd/timer-r0drv-freebsd.c310
19 files changed, 4225 insertions, 0 deletions
diff --git a/src/VBox/Runtime/r0drv/freebsd/Makefile.kup b/src/VBox/Runtime/r0drv/freebsd/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/Makefile.kup
diff --git a/src/VBox/Runtime/r0drv/freebsd/alloc-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/alloc-r0drv-freebsd.c
new file mode 100644
index 00000000..1e904202
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/alloc-r0drv-freebsd.c
@@ -0,0 +1,209 @@
+/* $Id: alloc-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Memory Allocation, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/mem.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/param.h>
+
+#include "r0drv/alloc-r0drv.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/* These two statements will define two globals and add initializers
+ and destructors that will be called at load/unload time (I think). */
+MALLOC_DEFINE(M_IPRTHEAP, "iprtheap", "IPRT - heap");
+MALLOC_DEFINE(M_IPRTCONT, "iprtcont", "IPRT - contiguous");
+
+
+DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
+{
+ size_t cbAllocated = cb;
+ PRTMEMHDR pHdr = NULL;
+
+#ifdef RT_ARCH_AMD64
+ /*
+ * Things are a bit more complicated on AMD64 for executable memory
+ * because we need to be in the ~2GB..~0 range for code.
+ */
+ if (fFlags & RTMEMHDR_FLAG_EXEC)
+ {
+ if (fFlags & RTMEMHDR_FLAG_ANY_CTX)
+ return VERR_NOT_SUPPORTED;
+
+# ifdef USE_KMEM_ALLOC_PROT
+ pHdr = (PRTMEMHDR)kmem_alloc_prot(kernel_map, cb + sizeof(*pHdr),
+ VM_PROT_ALL, VM_PROT_ALL, KERNBASE);
+# else
+ vm_object_t pVmObject = NULL;
+ vm_offset_t Addr = KERNBASE;
+ cbAllocated = RT_ALIGN_Z(cb + sizeof(*pHdr), PAGE_SIZE);
+
+ pVmObject = vm_object_allocate(OBJT_DEFAULT, cbAllocated >> PAGE_SHIFT);
+ if (!pVmObject)
+ return VERR_NO_EXEC_MEMORY;
+
+ /* Addr contains a start address vm_map_find will start searching for suitable space at. */
+#if __FreeBSD_version >= 1000055
+ int rc = vm_map_find(kernel_map, pVmObject, 0, &Addr,
+ cbAllocated, 0, VMFS_ANY_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0);
+#else
+ int rc = vm_map_find(kernel_map, pVmObject, 0, &Addr,
+ cbAllocated, TRUE, VM_PROT_ALL, VM_PROT_ALL, 0);
+#endif
+ if (rc == KERN_SUCCESS)
+ {
+ rc = vm_map_wire(kernel_map, Addr, Addr + cbAllocated,
+ VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
+ if (rc == KERN_SUCCESS)
+ {
+ pHdr = (PRTMEMHDR)Addr;
+
+ if (fFlags & RTMEMHDR_FLAG_ZEROED)
+ bzero(pHdr, cbAllocated);
+ }
+ else
+ vm_map_remove(kernel_map,
+ Addr,
+ Addr + cbAllocated);
+ }
+ else
+ vm_object_deallocate(pVmObject);
+# endif
+ }
+ else
+#endif
+ {
+ pHdr = (PRTMEMHDR)malloc(cb + sizeof(RTMEMHDR), M_IPRTHEAP,
+ fFlags & RTMEMHDR_FLAG_ZEROED ? M_NOWAIT | M_ZERO : M_NOWAIT);
+ }
+
+ if (RT_UNLIKELY(!pHdr))
+ return VERR_NO_MEMORY;
+
+ pHdr->u32Magic = RTMEMHDR_MAGIC;
+ pHdr->fFlags = fFlags;
+ pHdr->cb = cbAllocated;
+ pHdr->cbReq = cb;
+
+ *ppHdr = pHdr;
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(void) rtR0MemFree(PRTMEMHDR pHdr)
+{
+ pHdr->u32Magic += 1;
+
+#ifdef RT_ARCH_AMD64
+ if (pHdr->fFlags & RTMEMHDR_FLAG_EXEC)
+# ifdef USE_KMEM_ALLOC_PROT
+ kmem_free(kernel_map, (vm_offset_t)pHdr, pHdr->cb);
+# else
+ vm_map_remove(kernel_map, (vm_offset_t)pHdr, ((vm_offset_t)pHdr) + pHdr->cb);
+# endif
+ else
+#endif
+ free(pHdr, M_IPRTHEAP);
+}
+
+
+RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
+{
+ void *pv;
+
+ /*
+ * Validate input.
+ */
+ AssertPtr(pPhys);
+ Assert(cb > 0);
+
+ /*
+ * This API works in pages, so no need to do any size aligning.
+ */
+ pv = contigmalloc(cb, /* size */
+ M_IPRTCONT, /* type */
+ M_NOWAIT | M_ZERO, /* flags */
+ 0, /* lowest physical address*/
+ _4G-1, /* highest physical address */
+ PAGE_SIZE, /* alignment. */
+ 0); /* boundary */
+ if (pv)
+ {
+ Assert(!((uintptr_t)pv & PAGE_OFFSET_MASK));
+ *pPhys = vtophys(pv);
+ Assert(!(*pPhys & PAGE_OFFSET_MASK));
+ }
+ return pv;
+}
+
+
+RTR0DECL(void) RTMemContFree(void *pv, size_t cb)
+{
+ if (pv)
+ {
+ AssertMsg(!((uintptr_t)pv & PAGE_OFFSET_MASK), ("pv=%p\n", pv));
+ contigfree(pv, cb, M_IPRTCONT);
+ }
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/assert-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/assert-r0drv-freebsd.c
new file mode 100644
index 00000000..d4d17d8c
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/assert-r0drv-freebsd.c
@@ -0,0 +1,94 @@
+/* $Id: assert-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Assertion Workers, Ring-0 Drivers, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+
+#include <iprt/assert.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+#include <iprt/stdarg.h>
+
+#include "internal/assert.h"
+
+
+DECLHIDDEN(void) rtR0AssertNativeMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
+{
+ printf("\r\n!!Assertion Failed!!\r\n"
+ "Expression: %s\r\n"
+ "Location : %s(%d) %s\r\n",
+ pszExpr, pszFile, uLine, pszFunction);
+}
+
+
+DECLHIDDEN(void) rtR0AssertNativeMsg2V(bool fInitial, const char *pszFormat, va_list va)
+{
+ char szMsg[256];
+
+ RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
+ szMsg[sizeof(szMsg) - 1] = '\0';
+ printf("%s", szMsg);
+
+ NOREF(fInitial);
+}
+
+
+RTR0DECL(void) RTR0AssertPanicSystem(void)
+{
+ /** @todo implement RTR0AssertPanicSystem. */
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/initterm-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/initterm-r0drv-freebsd.c
new file mode 100644
index 00000000..40f7aac6
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/initterm-r0drv-freebsd.c
@@ -0,0 +1,77 @@
+/* $Id: initterm-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Initialization & Termination, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+
+#include <iprt/errcore.h>
+
+#include "internal/initterm.h"
+
+
+DECLHIDDEN(int) rtR0InitNative(void)
+{
+ /* nothing to do */
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(void) rtR0TermNative(void)
+{
+ /* nothing to undo */
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/memobj-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/memobj-r0drv-freebsd.c
new file mode 100644
index 00000000..0971624e
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/memobj-r0drv-freebsd.c
@@ -0,0 +1,892 @@
+/* $Id: memobj-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Ring-0 Memory Objects, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen, Andriy Gapon.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ * Copyright (c) 2011 Andriy Gapon <avg@FreeBSD.org>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+
+#include <iprt/memobj.h>
+#include <iprt/mem.h>
+#include <iprt/err.h>
+#include <iprt/assert.h>
+#include <iprt/log.h>
+#include <iprt/param.h>
+#include <iprt/process.h>
+#include "internal/memobj.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * The FreeBSD version of the memory object structure.
+ */
+typedef struct RTR0MEMOBJFREEBSD
+{
+ /** The core structure. */
+ RTR0MEMOBJINTERNAL Core;
+ /** The VM object associated with the allocation. */
+ vm_object_t pObject;
+} RTR0MEMOBJFREEBSD, *PRTR0MEMOBJFREEBSD;
+
+
+MALLOC_DEFINE(M_IPRTMOBJ, "iprtmobj", "IPRT - R0MemObj");
+
+
+/**
+ * Gets the virtual memory map the specified object is mapped into.
+ *
+ * @returns VM map handle on success, NULL if no map.
+ * @param pMem The memory object.
+ */
+static vm_map_t rtR0MemObjFreeBSDGetMap(PRTR0MEMOBJINTERNAL pMem)
+{
+ switch (pMem->enmType)
+ {
+ case RTR0MEMOBJTYPE_PAGE:
+ case RTR0MEMOBJTYPE_LOW:
+ case RTR0MEMOBJTYPE_CONT:
+ return kernel_map;
+
+ case RTR0MEMOBJTYPE_PHYS:
+ case RTR0MEMOBJTYPE_PHYS_NC:
+ return NULL; /* pretend these have no mapping atm. */
+
+ case RTR0MEMOBJTYPE_LOCK:
+ return pMem->u.Lock.R0Process == NIL_RTR0PROCESS
+ ? kernel_map
+ : &((struct proc *)pMem->u.Lock.R0Process)->p_vmspace->vm_map;
+
+ case RTR0MEMOBJTYPE_RES_VIRT:
+ return pMem->u.ResVirt.R0Process == NIL_RTR0PROCESS
+ ? kernel_map
+ : &((struct proc *)pMem->u.ResVirt.R0Process)->p_vmspace->vm_map;
+
+ case RTR0MEMOBJTYPE_MAPPING:
+ return pMem->u.Mapping.R0Process == NIL_RTR0PROCESS
+ ? kernel_map
+ : &((struct proc *)pMem->u.Mapping.R0Process)->p_vmspace->vm_map;
+
+ default:
+ return NULL;
+ }
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
+{
+ PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)pMem;
+ int rc;
+
+ switch (pMemFreeBSD->Core.enmType)
+ {
+ case RTR0MEMOBJTYPE_PAGE:
+ case RTR0MEMOBJTYPE_LOW:
+ case RTR0MEMOBJTYPE_CONT:
+ rc = vm_map_remove(kernel_map,
+ (vm_offset_t)pMemFreeBSD->Core.pv,
+ (vm_offset_t)pMemFreeBSD->Core.pv + pMemFreeBSD->Core.cb);
+ AssertMsg(rc == KERN_SUCCESS, ("%#x", rc));
+ break;
+
+ case RTR0MEMOBJTYPE_LOCK:
+ {
+ vm_map_t pMap = kernel_map;
+
+ if (pMemFreeBSD->Core.u.Lock.R0Process != NIL_RTR0PROCESS)
+ pMap = &((struct proc *)pMemFreeBSD->Core.u.Lock.R0Process)->p_vmspace->vm_map;
+
+ rc = vm_map_unwire(pMap,
+ (vm_offset_t)pMemFreeBSD->Core.pv,
+ (vm_offset_t)pMemFreeBSD->Core.pv + pMemFreeBSD->Core.cb,
+ VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
+ AssertMsg(rc == KERN_SUCCESS, ("%#x", rc));
+ break;
+ }
+
+ case RTR0MEMOBJTYPE_RES_VIRT:
+ {
+ vm_map_t pMap = kernel_map;
+ if (pMemFreeBSD->Core.u.ResVirt.R0Process != NIL_RTR0PROCESS)
+ pMap = &((struct proc *)pMemFreeBSD->Core.u.ResVirt.R0Process)->p_vmspace->vm_map;
+ rc = vm_map_remove(pMap,
+ (vm_offset_t)pMemFreeBSD->Core.pv,
+ (vm_offset_t)pMemFreeBSD->Core.pv + pMemFreeBSD->Core.cb);
+ AssertMsg(rc == KERN_SUCCESS, ("%#x", rc));
+ break;
+ }
+
+ case RTR0MEMOBJTYPE_MAPPING:
+ {
+ vm_map_t pMap = kernel_map;
+
+ if (pMemFreeBSD->Core.u.Mapping.R0Process != NIL_RTR0PROCESS)
+ pMap = &((struct proc *)pMemFreeBSD->Core.u.Mapping.R0Process)->p_vmspace->vm_map;
+ rc = vm_map_remove(pMap,
+ (vm_offset_t)pMemFreeBSD->Core.pv,
+ (vm_offset_t)pMemFreeBSD->Core.pv + pMemFreeBSD->Core.cb);
+ AssertMsg(rc == KERN_SUCCESS, ("%#x", rc));
+ break;
+ }
+
+ case RTR0MEMOBJTYPE_PHYS:
+ case RTR0MEMOBJTYPE_PHYS_NC:
+ {
+ VM_OBJECT_WLOCK(pMemFreeBSD->pObject);
+ vm_page_t pPage = vm_page_find_least(pMemFreeBSD->pObject, 0);
+#if __FreeBSD_version < 1000000
+ vm_page_lock_queues();
+#endif
+ for (vm_page_t pPage = vm_page_find_least(pMemFreeBSD->pObject, 0);
+ pPage != NULL;
+ pPage = vm_page_next(pPage))
+ {
+ vm_page_unwire(pPage, 0);
+ }
+#if __FreeBSD_version < 1000000
+ vm_page_unlock_queues();
+#endif
+ VM_OBJECT_WUNLOCK(pMemFreeBSD->pObject);
+ vm_object_deallocate(pMemFreeBSD->pObject);
+ break;
+ }
+
+ default:
+ AssertMsgFailed(("enmType=%d\n", pMemFreeBSD->Core.enmType));
+ return VERR_INTERNAL_ERROR;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+static vm_page_t rtR0MemObjFreeBSDContigPhysAllocHelper(vm_object_t pObject, vm_pindex_t iPIndex,
+ u_long cPages, vm_paddr_t VmPhysAddrHigh,
+ u_long uAlignment, bool fWire)
+{
+ vm_page_t pPages;
+ int cTries = 0;
+
+#if __FreeBSD_version > 1000000
+ int fFlags = VM_ALLOC_INTERRUPT | VM_ALLOC_NOBUSY;
+ if (fWire)
+ fFlags |= VM_ALLOC_WIRED;
+
+ while (cTries <= 1)
+ {
+ VM_OBJECT_WLOCK(pObject);
+ pPages = vm_page_alloc_contig(pObject, iPIndex, fFlags, cPages, 0,
+ VmPhysAddrHigh, uAlignment, 0, VM_MEMATTR_DEFAULT);
+ VM_OBJECT_WUNLOCK(pObject);
+ if (pPages)
+ break;
+#if __FreeBSD_version >= 1100092
+ if (!vm_page_reclaim_contig(cTries, cPages, 0, VmPhysAddrHigh, PAGE_SIZE, 0))
+ break;
+#else
+ vm_pageout_grow_cache(cTries, 0, VmPhysAddrHigh);
+#endif
+ cTries++;
+ }
+
+ return pPages;
+#else
+ while (cTries <= 1)
+ {
+ pPages = vm_phys_alloc_contig(cPages, 0, VmPhysAddrHigh, uAlignment, 0);
+ if (pPages)
+ break;
+ vm_contig_grow_cache(cTries, 0, VmPhysAddrHigh);
+ cTries++;
+ }
+
+ if (!pPages)
+ return pPages;
+ VM_OBJECT_WLOCK(pObject);
+ for (vm_pindex_t iPage = 0; iPage < cPages; iPage++)
+ {
+ vm_page_t pPage = pPages + iPage;
+ vm_page_insert(pPage, pObject, iPIndex + iPage);
+ pPage->valid = VM_PAGE_BITS_ALL;
+ if (fWire)
+ {
+ pPage->wire_count = 1;
+ atomic_add_int(&cnt.v_wire_count, 1);
+ }
+ }
+ VM_OBJECT_WUNLOCK(pObject);
+ return pPages;
+#endif
+}
+
+static int rtR0MemObjFreeBSDPhysAllocHelper(vm_object_t pObject, u_long cPages,
+ vm_paddr_t VmPhysAddrHigh, u_long uAlignment,
+ bool fContiguous, bool fWire, int rcNoMem)
+{
+ if (fContiguous)
+ {
+ if (rtR0MemObjFreeBSDContigPhysAllocHelper(pObject, 0, cPages, VmPhysAddrHigh,
+ uAlignment, fWire) != NULL)
+ return VINF_SUCCESS;
+ return rcNoMem;
+ }
+
+ for (vm_pindex_t iPage = 0; iPage < cPages; iPage++)
+ {
+ vm_page_t pPage = rtR0MemObjFreeBSDContigPhysAllocHelper(pObject, iPage, 1, VmPhysAddrHigh,
+ uAlignment, fWire);
+ if (!pPage)
+ {
+ /* Free all allocated pages */
+ VM_OBJECT_WLOCK(pObject);
+ while (iPage-- > 0)
+ {
+ pPage = vm_page_lookup(pObject, iPage);
+#if __FreeBSD_version < 1000000
+ vm_page_lock_queues();
+#endif
+ if (fWire)
+ vm_page_unwire(pPage, 0);
+ vm_page_free(pPage);
+#if __FreeBSD_version < 1000000
+ vm_page_unlock_queues();
+#endif
+ }
+ VM_OBJECT_WUNLOCK(pObject);
+ return rcNoMem;
+ }
+ }
+ return VINF_SUCCESS;
+}
+
+static int rtR0MemObjFreeBSDAllocHelper(PRTR0MEMOBJFREEBSD pMemFreeBSD, bool fExecutable,
+ vm_paddr_t VmPhysAddrHigh, bool fContiguous, int rcNoMem)
+{
+ vm_offset_t MapAddress = vm_map_min(kernel_map);
+ size_t cPages = atop(pMemFreeBSD->Core.cb);
+ int rc;
+
+ pMemFreeBSD->pObject = vm_object_allocate(OBJT_PHYS, cPages);
+
+ /* No additional object reference for auto-deallocation upon unmapping. */
+#if __FreeBSD_version >= 1000055
+ rc = vm_map_find(kernel_map, pMemFreeBSD->pObject, 0,
+ &MapAddress, pMemFreeBSD->Core.cb, 0, VMFS_ANY_SPACE,
+ fExecutable ? VM_PROT_ALL : VM_PROT_RW, VM_PROT_ALL, 0);
+#else
+ rc = vm_map_find(kernel_map, pMemFreeBSD->pObject, 0,
+ &MapAddress, pMemFreeBSD->Core.cb, VMFS_ANY_SPACE,
+ fExecutable ? VM_PROT_ALL : VM_PROT_RW, VM_PROT_ALL, 0);
+#endif
+
+ if (rc == KERN_SUCCESS)
+ {
+ rc = rtR0MemObjFreeBSDPhysAllocHelper(pMemFreeBSD->pObject, cPages,
+ VmPhysAddrHigh, PAGE_SIZE, fContiguous,
+ false, rcNoMem);
+ if (RT_SUCCESS(rc))
+ {
+ vm_map_wire(kernel_map, MapAddress, MapAddress + pMemFreeBSD->Core.cb,
+ VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
+
+ /* Store start address */
+ pMemFreeBSD->Core.pv = (void *)MapAddress;
+ return VINF_SUCCESS;
+ }
+
+ vm_map_remove(kernel_map, MapAddress, MapAddress + pMemFreeBSD->Core.cb);
+ }
+ else
+ {
+ rc = rcNoMem; /** @todo fix translation (borrow from darwin) */
+ vm_object_deallocate(pMemFreeBSD->pObject);
+ }
+
+ rtR0MemObjDelete(&pMemFreeBSD->Core);
+ return rc;
+}
+DECLHIDDEN(int) rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
+{
+ PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)rtR0MemObjNew(sizeof(*pMemFreeBSD),
+ RTR0MEMOBJTYPE_PAGE, NULL, cb);
+ if (!pMemFreeBSD)
+ return VERR_NO_MEMORY;
+
+ int rc = rtR0MemObjFreeBSDAllocHelper(pMemFreeBSD, fExecutable, ~(vm_paddr_t)0, false, VERR_NO_MEMORY);
+ if (RT_FAILURE(rc))
+ {
+ rtR0MemObjDelete(&pMemFreeBSD->Core);
+ return rc;
+ }
+
+ *ppMem = &pMemFreeBSD->Core;
+ return rc;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
+{
+ PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)rtR0MemObjNew(sizeof(*pMemFreeBSD),
+ RTR0MEMOBJTYPE_LOW, NULL, cb);
+ if (!pMemFreeBSD)
+ return VERR_NO_MEMORY;
+
+ int rc = rtR0MemObjFreeBSDAllocHelper(pMemFreeBSD, fExecutable, _4G - 1, false, VERR_NO_LOW_MEMORY);
+ if (RT_FAILURE(rc))
+ {
+ rtR0MemObjDelete(&pMemFreeBSD->Core);
+ return rc;
+ }
+
+ *ppMem = &pMemFreeBSD->Core;
+ return rc;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
+{
+ PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)rtR0MemObjNew(sizeof(*pMemFreeBSD),
+ RTR0MEMOBJTYPE_CONT, NULL, cb);
+ if (!pMemFreeBSD)
+ return VERR_NO_MEMORY;
+
+ int rc = rtR0MemObjFreeBSDAllocHelper(pMemFreeBSD, fExecutable, _4G - 1, true, VERR_NO_CONT_MEMORY);
+ if (RT_FAILURE(rc))
+ {
+ rtR0MemObjDelete(&pMemFreeBSD->Core);
+ return rc;
+ }
+
+ pMemFreeBSD->Core.u.Cont.Phys = vtophys(pMemFreeBSD->Core.pv);
+ *ppMem = &pMemFreeBSD->Core;
+ return rc;
+}
+
+
+static int rtR0MemObjFreeBSDAllocPhysPages(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJTYPE enmType,
+ size_t cb,
+ RTHCPHYS PhysHighest, size_t uAlignment,
+ bool fContiguous, int rcNoMem)
+{
+ uint32_t cPages = atop(cb);
+ vm_paddr_t VmPhysAddrHigh;
+
+ /* create the object. */
+ PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)rtR0MemObjNew(sizeof(*pMemFreeBSD),
+ enmType, NULL, cb);
+ if (!pMemFreeBSD)
+ return VERR_NO_MEMORY;
+
+ pMemFreeBSD->pObject = vm_object_allocate(OBJT_PHYS, atop(cb));
+
+ if (PhysHighest != NIL_RTHCPHYS)
+ VmPhysAddrHigh = PhysHighest;
+ else
+ VmPhysAddrHigh = ~(vm_paddr_t)0;
+
+ int rc = rtR0MemObjFreeBSDPhysAllocHelper(pMemFreeBSD->pObject, cPages, VmPhysAddrHigh,
+ uAlignment, fContiguous, true, rcNoMem);
+ if (RT_SUCCESS(rc))
+ {
+ if (fContiguous)
+ {
+ Assert(enmType == RTR0MEMOBJTYPE_PHYS);
+ VM_OBJECT_WLOCK(pMemFreeBSD->pObject);
+ pMemFreeBSD->Core.u.Phys.PhysBase = VM_PAGE_TO_PHYS(vm_page_find_least(pMemFreeBSD->pObject, 0));
+ VM_OBJECT_WUNLOCK(pMemFreeBSD->pObject);
+ pMemFreeBSD->Core.u.Phys.fAllocated = true;
+ }
+
+ *ppMem = &pMemFreeBSD->Core;
+ }
+ else
+ {
+ vm_object_deallocate(pMemFreeBSD->pObject);
+ rtR0MemObjDelete(&pMemFreeBSD->Core);
+ }
+
+ return rc;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment)
+{
+ return rtR0MemObjFreeBSDAllocPhysPages(ppMem, RTR0MEMOBJTYPE_PHYS, cb, PhysHighest, uAlignment, true, VERR_NO_MEMORY);
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeAllocPhysNC(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest)
+{
+ return rtR0MemObjFreeBSDAllocPhysPages(ppMem, RTR0MEMOBJTYPE_PHYS_NC, cb, PhysHighest, PAGE_SIZE, false, VERR_NO_PHYS_MEMORY);
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy)
+{
+ AssertReturn(uCachePolicy == RTMEM_CACHE_POLICY_DONT_CARE, VERR_NOT_SUPPORTED);
+
+ /* create the object. */
+ PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)rtR0MemObjNew(sizeof(*pMemFreeBSD), RTR0MEMOBJTYPE_PHYS, NULL, cb);
+ if (!pMemFreeBSD)
+ return VERR_NO_MEMORY;
+
+ /* there is no allocation here, it needs to be mapped somewhere first. */
+ pMemFreeBSD->Core.u.Phys.fAllocated = false;
+ pMemFreeBSD->Core.u.Phys.PhysBase = Phys;
+ pMemFreeBSD->Core.u.Phys.uCachePolicy = uCachePolicy;
+ *ppMem = &pMemFreeBSD->Core;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Worker locking the memory in either kernel or user maps.
+ */
+static int rtR0MemObjNativeLockInMap(PPRTR0MEMOBJINTERNAL ppMem, vm_map_t pVmMap,
+ vm_offset_t AddrStart, size_t cb, uint32_t fAccess,
+ RTR0PROCESS R0Process, int fFlags)
+{
+ int rc;
+ NOREF(fAccess);
+
+ /* create the object. */
+ PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)rtR0MemObjNew(sizeof(*pMemFreeBSD), RTR0MEMOBJTYPE_LOCK, (void *)AddrStart, cb);
+ if (!pMemFreeBSD)
+ return VERR_NO_MEMORY;
+
+ /*
+ * We could've used vslock here, but we don't wish to be subject to
+ * resource usage restrictions, so we'll call vm_map_wire directly.
+ */
+ rc = vm_map_wire(pVmMap, /* the map */
+ AddrStart, /* start */
+ AddrStart + cb, /* end */
+ fFlags); /* flags */
+ if (rc == KERN_SUCCESS)
+ {
+ pMemFreeBSD->Core.u.Lock.R0Process = R0Process;
+ *ppMem = &pMemFreeBSD->Core;
+ return VINF_SUCCESS;
+ }
+ rtR0MemObjDelete(&pMemFreeBSD->Core);
+ return VERR_NO_MEMORY;/** @todo fix mach -> vbox error conversion for freebsd. */
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess, RTR0PROCESS R0Process)
+{
+ return rtR0MemObjNativeLockInMap(ppMem,
+ &((struct proc *)R0Process)->p_vmspace->vm_map,
+ (vm_offset_t)R3Ptr,
+ cb,
+ fAccess,
+ R0Process,
+ VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES);
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, uint32_t fAccess)
+{
+ return rtR0MemObjNativeLockInMap(ppMem,
+ kernel_map,
+ (vm_offset_t)pv,
+ cb,
+ fAccess,
+ NIL_RTR0PROCESS,
+ VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
+}
+
+
+/**
+ * Worker for the two virtual address space reservers.
+ *
+ * We're leaning on the examples provided by mmap and vm_mmap in vm_mmap.c here.
+ */
+static int rtR0MemObjNativeReserveInMap(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment, RTR0PROCESS R0Process, vm_map_t pMap)
+{
+ int rc;
+
+ /*
+ * The pvFixed address range must be within the VM space when specified.
+ */
+ if ( pvFixed != (void *)-1
+ && ( (vm_offset_t)pvFixed < vm_map_min(pMap)
+ || (vm_offset_t)pvFixed + cb > vm_map_max(pMap)))
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * Check that the specified alignment is supported.
+ */
+ if (uAlignment > PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+
+ /*
+ * Create the object.
+ */
+ PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)rtR0MemObjNew(sizeof(*pMemFreeBSD), RTR0MEMOBJTYPE_RES_VIRT, NULL, cb);
+ if (!pMemFreeBSD)
+ return VERR_NO_MEMORY;
+
+ vm_offset_t MapAddress = pvFixed != (void *)-1
+ ? (vm_offset_t)pvFixed
+ : vm_map_min(pMap);
+ if (pvFixed != (void *)-1)
+ vm_map_remove(pMap,
+ MapAddress,
+ MapAddress + cb);
+
+ rc = vm_map_find(pMap, /* map */
+ NULL, /* object */
+ 0, /* offset */
+ &MapAddress, /* addr (IN/OUT) */
+ cb, /* length */
+#if __FreeBSD_version >= 1000055
+ 0, /* max addr */
+#endif
+ pvFixed == (void *)-1 ? VMFS_ANY_SPACE : VMFS_NO_SPACE,
+ /* find_space */
+ VM_PROT_NONE, /* protection */
+ VM_PROT_ALL, /* max(_prot) ?? */
+ 0); /* cow (copy-on-write) */
+ if (rc == KERN_SUCCESS)
+ {
+ if (R0Process != NIL_RTR0PROCESS)
+ {
+ rc = vm_map_inherit(pMap,
+ MapAddress,
+ MapAddress + cb,
+ VM_INHERIT_SHARE);
+ AssertMsg(rc == KERN_SUCCESS, ("%#x\n", rc));
+ }
+ pMemFreeBSD->Core.pv = (void *)MapAddress;
+ pMemFreeBSD->Core.u.ResVirt.R0Process = R0Process;
+ *ppMem = &pMemFreeBSD->Core;
+ return VINF_SUCCESS;
+ }
+
+ rc = VERR_NO_MEMORY; /** @todo fix translation (borrow from darwin) */
+ rtR0MemObjDelete(&pMemFreeBSD->Core);
+ return rc;
+
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment)
+{
+ return rtR0MemObjNativeReserveInMap(ppMem, pvFixed, cb, uAlignment, NIL_RTR0PROCESS, kernel_map);
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, RTR0PROCESS R0Process)
+{
+ return rtR0MemObjNativeReserveInMap(ppMem, (void *)R3PtrFixed, cb, uAlignment, R0Process,
+ &((struct proc *)R0Process)->p_vmspace->vm_map);
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment,
+ unsigned fProt, size_t offSub, size_t cbSub)
+{
+// AssertMsgReturn(!offSub && !cbSub, ("%#x %#x\n", offSub, cbSub), VERR_NOT_SUPPORTED);
+ AssertMsgReturn(pvFixed == (void *)-1, ("%p\n", pvFixed), VERR_NOT_SUPPORTED);
+
+ /*
+ * Check that the specified alignment is supported.
+ */
+ if (uAlignment > PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+ Assert(!offSub || cbSub);
+
+ int rc;
+ PRTR0MEMOBJFREEBSD pMemToMapFreeBSD = (PRTR0MEMOBJFREEBSD)pMemToMap;
+
+ /* calc protection */
+ vm_prot_t ProtectionFlags = 0;
+ if ((fProt & RTMEM_PROT_NONE) == RTMEM_PROT_NONE)
+ ProtectionFlags = VM_PROT_NONE;
+ if ((fProt & RTMEM_PROT_READ) == RTMEM_PROT_READ)
+ ProtectionFlags |= VM_PROT_READ;
+ if ((fProt & RTMEM_PROT_WRITE) == RTMEM_PROT_WRITE)
+ ProtectionFlags |= VM_PROT_WRITE;
+ if ((fProt & RTMEM_PROT_EXEC) == RTMEM_PROT_EXEC)
+ ProtectionFlags |= VM_PROT_EXECUTE;
+
+ vm_offset_t Addr = vm_map_min(kernel_map);
+ if (cbSub == 0)
+ cbSub = pMemToMap->cb - offSub;
+
+ vm_object_reference(pMemToMapFreeBSD->pObject);
+ rc = vm_map_find(kernel_map, /* Map to insert the object in */
+ pMemToMapFreeBSD->pObject, /* Object to map */
+ offSub, /* Start offset in the object */
+ &Addr, /* Start address IN/OUT */
+ cbSub, /* Size of the mapping */
+#if __FreeBSD_version >= 1000055
+ 0, /* Upper bound of mapping */
+#endif
+ VMFS_ANY_SPACE, /* Whether a suitable address should be searched for first */
+ ProtectionFlags, /* protection flags */
+ VM_PROT_ALL, /* Maximum protection flags */
+ 0); /* copy-on-write and similar flags */
+
+ if (rc == KERN_SUCCESS)
+ {
+ rc = vm_map_wire(kernel_map, Addr, Addr + cbSub, VM_MAP_WIRE_SYSTEM|VM_MAP_WIRE_NOHOLES);
+ AssertMsg(rc == KERN_SUCCESS, ("%#x\n", rc));
+
+ PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)rtR0MemObjNew(sizeof(RTR0MEMOBJFREEBSD),
+ RTR0MEMOBJTYPE_MAPPING,
+ (void *)Addr,
+ cbSub);
+ if (pMemFreeBSD)
+ {
+ Assert((vm_offset_t)pMemFreeBSD->Core.pv == Addr);
+ pMemFreeBSD->Core.u.Mapping.R0Process = NIL_RTR0PROCESS;
+ *ppMem = &pMemFreeBSD->Core;
+ return VINF_SUCCESS;
+ }
+ rc = vm_map_remove(kernel_map, Addr, Addr + cbSub);
+ AssertMsg(rc == KERN_SUCCESS, ("Deleting mapping failed\n"));
+ }
+ else
+ vm_object_deallocate(pMemToMapFreeBSD->pObject);
+
+ return VERR_NO_MEMORY;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, RTR3PTR R3PtrFixed, size_t uAlignment,
+ unsigned fProt, RTR0PROCESS R0Process, size_t offSub, size_t cbSub)
+{
+ /*
+ * Check for unsupported stuff.
+ */
+ AssertMsgReturn(R0Process == RTR0ProcHandleSelf(), ("%p != %p\n", R0Process, RTR0ProcHandleSelf()), VERR_NOT_SUPPORTED);
+ if (uAlignment > PAGE_SIZE)
+ return VERR_NOT_SUPPORTED;
+ Assert(!offSub || cbSub);
+
+ int rc;
+ PRTR0MEMOBJFREEBSD pMemToMapFreeBSD = (PRTR0MEMOBJFREEBSD)pMemToMap;
+ struct proc *pProc = (struct proc *)R0Process;
+ struct vm_map *pProcMap = &pProc->p_vmspace->vm_map;
+
+ /* calc protection */
+ vm_prot_t ProtectionFlags = 0;
+ if ((fProt & RTMEM_PROT_NONE) == RTMEM_PROT_NONE)
+ ProtectionFlags = VM_PROT_NONE;
+ if ((fProt & RTMEM_PROT_READ) == RTMEM_PROT_READ)
+ ProtectionFlags |= VM_PROT_READ;
+ if ((fProt & RTMEM_PROT_WRITE) == RTMEM_PROT_WRITE)
+ ProtectionFlags |= VM_PROT_WRITE;
+ if ((fProt & RTMEM_PROT_EXEC) == RTMEM_PROT_EXEC)
+ ProtectionFlags |= VM_PROT_EXECUTE;
+
+ /* calc mapping address */
+ vm_offset_t AddrR3;
+ if (R3PtrFixed == (RTR3PTR)-1)
+ {
+ /** @todo is this needed?. */
+ PROC_LOCK(pProc);
+ AddrR3 = round_page((vm_offset_t)pProc->p_vmspace->vm_daddr + MY_LIM_MAX_PROC(pProc, RLIMIT_DATA));
+ PROC_UNLOCK(pProc);
+ }
+ else
+ AddrR3 = (vm_offset_t)R3PtrFixed;
+
+ if (cbSub == 0)
+ cbSub = pMemToMap->cb - offSub;
+
+ /* Insert the pObject in the map. */
+ vm_object_reference(pMemToMapFreeBSD->pObject);
+ rc = vm_map_find(pProcMap, /* Map to insert the object in */
+ pMemToMapFreeBSD->pObject, /* Object to map */
+ offSub, /* Start offset in the object */
+ &AddrR3, /* Start address IN/OUT */
+ cbSub, /* Size of the mapping */
+#if __FreeBSD_version >= 1000055
+ 0, /* Upper bound of the mapping */
+#endif
+ R3PtrFixed == (RTR3PTR)-1 ? VMFS_ANY_SPACE : VMFS_NO_SPACE,
+ /* Whether a suitable address should be searched for first */
+ ProtectionFlags, /* protection flags */
+ VM_PROT_ALL, /* Maximum protection flags */
+ 0); /* copy-on-write and similar flags */
+
+ if (rc == KERN_SUCCESS)
+ {
+ rc = vm_map_wire(pProcMap, AddrR3, AddrR3 + pMemToMap->cb, VM_MAP_WIRE_USER|VM_MAP_WIRE_NOHOLES);
+ AssertMsg(rc == KERN_SUCCESS, ("%#x\n", rc));
+
+ rc = vm_map_inherit(pProcMap, AddrR3, AddrR3 + pMemToMap->cb, VM_INHERIT_SHARE);
+ AssertMsg(rc == KERN_SUCCESS, ("%#x\n", rc));
+
+ /*
+ * Create a mapping object for it.
+ */
+ PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)rtR0MemObjNew(sizeof(RTR0MEMOBJFREEBSD),
+ RTR0MEMOBJTYPE_MAPPING,
+ (void *)AddrR3,
+ pMemToMap->cb);
+ if (pMemFreeBSD)
+ {
+ Assert((vm_offset_t)pMemFreeBSD->Core.pv == AddrR3);
+ pMemFreeBSD->Core.u.Mapping.R0Process = R0Process;
+ *ppMem = &pMemFreeBSD->Core;
+ return VINF_SUCCESS;
+ }
+
+ rc = vm_map_remove(pProcMap, AddrR3, AddrR3 + pMemToMap->cb);
+ AssertMsg(rc == KERN_SUCCESS, ("Deleting mapping failed\n"));
+ }
+ else
+ vm_object_deallocate(pMemToMapFreeBSD->pObject);
+
+ return VERR_NO_MEMORY;
+}
+
+
+DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
+{
+ vm_prot_t ProtectionFlags = 0;
+ vm_offset_t AddrStart = (uintptr_t)pMem->pv + offSub;
+ vm_offset_t AddrEnd = AddrStart + cbSub;
+ vm_map_t pVmMap = rtR0MemObjFreeBSDGetMap(pMem);
+
+ if (!pVmMap)
+ return VERR_NOT_SUPPORTED;
+
+ if ((fProt & RTMEM_PROT_NONE) == RTMEM_PROT_NONE)
+ ProtectionFlags = VM_PROT_NONE;
+ if ((fProt & RTMEM_PROT_READ) == RTMEM_PROT_READ)
+ ProtectionFlags |= VM_PROT_READ;
+ if ((fProt & RTMEM_PROT_WRITE) == RTMEM_PROT_WRITE)
+ ProtectionFlags |= VM_PROT_WRITE;
+ if ((fProt & RTMEM_PROT_EXEC) == RTMEM_PROT_EXEC)
+ ProtectionFlags |= VM_PROT_EXECUTE;
+
+ int krc = vm_map_protect(pVmMap, AddrStart, AddrEnd, ProtectionFlags, FALSE);
+ if (krc == KERN_SUCCESS)
+ return VINF_SUCCESS;
+
+ return VERR_NOT_SUPPORTED;
+}
+
+
+DECLHIDDEN(RTHCPHYS) rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, size_t iPage)
+{
+ PRTR0MEMOBJFREEBSD pMemFreeBSD = (PRTR0MEMOBJFREEBSD)pMem;
+
+ switch (pMemFreeBSD->Core.enmType)
+ {
+ case RTR0MEMOBJTYPE_LOCK:
+ {
+ if ( pMemFreeBSD->Core.u.Lock.R0Process != NIL_RTR0PROCESS
+ && pMemFreeBSD->Core.u.Lock.R0Process != (RTR0PROCESS)curproc)
+ {
+ /* later */
+ return NIL_RTHCPHYS;
+ }
+
+ vm_offset_t pb = (vm_offset_t)pMemFreeBSD->Core.pv + ptoa(iPage);
+
+ struct proc *pProc = (struct proc *)pMemFreeBSD->Core.u.Lock.R0Process;
+ struct vm_map *pProcMap = &pProc->p_vmspace->vm_map;
+ pmap_t pPhysicalMap = vm_map_pmap(pProcMap);
+
+ return pmap_extract(pPhysicalMap, pb);
+ }
+
+ case RTR0MEMOBJTYPE_MAPPING:
+ {
+ vm_offset_t pb = (vm_offset_t)pMemFreeBSD->Core.pv + ptoa(iPage);
+
+ if (pMemFreeBSD->Core.u.Mapping.R0Process != NIL_RTR0PROCESS)
+ {
+ struct proc *pProc = (struct proc *)pMemFreeBSD->Core.u.Mapping.R0Process;
+ struct vm_map *pProcMap = &pProc->p_vmspace->vm_map;
+ pmap_t pPhysicalMap = vm_map_pmap(pProcMap);
+
+ return pmap_extract(pPhysicalMap, pb);
+ }
+ return vtophys(pb);
+ }
+
+ case RTR0MEMOBJTYPE_PAGE:
+ case RTR0MEMOBJTYPE_LOW:
+ case RTR0MEMOBJTYPE_PHYS_NC:
+ {
+ RTHCPHYS addr;
+
+ VM_OBJECT_WLOCK(pMemFreeBSD->pObject);
+ addr = VM_PAGE_TO_PHYS(vm_page_lookup(pMemFreeBSD->pObject, iPage));
+ VM_OBJECT_WUNLOCK(pMemFreeBSD->pObject);
+ return addr;
+ }
+
+ case RTR0MEMOBJTYPE_PHYS:
+ return pMemFreeBSD->Core.u.Cont.Phys + ptoa(iPage);
+
+ case RTR0MEMOBJTYPE_CONT:
+ return pMemFreeBSD->Core.u.Phys.PhysBase + ptoa(iPage);
+
+ case RTR0MEMOBJTYPE_RES_VIRT:
+ default:
+ return NIL_RTHCPHYS;
+ }
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/memuserkernel-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/memuserkernel-r0drv-freebsd.c
new file mode 100644
index 00000000..078c548e
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/memuserkernel-r0drv-freebsd.c
@@ -0,0 +1,83 @@
+/* $Id: memuserkernel-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - User & Kernel Memory, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Copyright (C) 2009-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+
+#include <iprt/mem.h>
+#include <iprt/errcore.h>
+
+
+RTR0DECL(int) RTR0MemUserCopyFrom(void *pvDst, RTR3PTR R3PtrSrc, size_t cb)
+{
+ int rc = copyin((const void *)R3PtrSrc, pvDst, cb);
+ if (RT_LIKELY(rc == 0))
+ return VINF_SUCCESS;
+ return VERR_ACCESS_DENIED;
+}
+
+
+RTR0DECL(int) RTR0MemUserCopyTo(RTR3PTR R3PtrDst, void const *pvSrc, size_t cb)
+{
+ int rc = copyout(pvSrc, (void *)R3PtrDst, cb);
+ if (RT_LIKELY(rc == 0))
+ return VINF_SUCCESS;
+ return VERR_ACCESS_DENIED;
+}
+
+
+RTR0DECL(bool) RTR0MemUserIsValidAddr(RTR3PTR R3Ptr)
+{
+ return R3Ptr < VM_MAXUSER_ADDRESS;
+}
+
+
+RTR0DECL(bool) RTR0MemKernelIsValidAddr(void *pv)
+{
+ return (uintptr_t)pv >= VM_MAXUSER_ADDRESS;
+}
+
+
+RTR0DECL(bool) RTR0MemAreKrnlAndUsrDifferent(void)
+{
+ return true;
+}
+
+
+RTR0DECL(int) RTR0MemKernelCopyFrom(void *pvDst, void const *pvSrc, size_t cb)
+{
+ return VERR_NOT_SUPPORTED;
+}
+
+
+RTR0DECL(int) RTR0MemKernelCopyTo(void *pvDst, void const *pvSrc, size_t cb)
+{
+ return VERR_NOT_SUPPORTED;
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/mp-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/mp-r0drv-freebsd.c
new file mode 100644
index 00000000..e8b86960
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/mp-r0drv-freebsd.c
@@ -0,0 +1,312 @@
+/* $Id: mp-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Multiprocessor, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Copyright (C) 2008-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+
+#include <iprt/mp.h>
+#include <iprt/err.h>
+#include <iprt/asm.h>
+#include <iprt/cpuset.h>
+#include "r0drv/mp-r0drv.h"
+
+
+#if __FreeBSD_version < 1200028
+# define smp_no_rendezvous_barrier smp_no_rendevous_barrier
+#endif
+
+RTDECL(RTCPUID) RTMpCpuId(void)
+{
+ return curcpu;
+}
+
+
+RTDECL(int) RTMpCurSetIndex(void)
+{
+ return curcpu;
+}
+
+
+RTDECL(int) RTMpCurSetIndexAndId(PRTCPUID pidCpu)
+{
+ return *pidCpu = curcpu;
+}
+
+
+RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
+{
+ return idCpu < RTCPUSET_MAX_CPUS && idCpu <= mp_maxid ? (int)idCpu : -1;
+}
+
+
+RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
+{
+ return (unsigned)iCpu <= mp_maxid ? (RTCPUID)iCpu : NIL_RTCPUID;
+}
+
+
+RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
+{
+ return mp_maxid;
+}
+
+
+RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
+{
+ return idCpu <= mp_maxid;
+}
+
+
+RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
+{
+ RTCPUID idCpu;
+
+ RTCpuSetEmpty(pSet);
+ idCpu = RTMpGetMaxCpuId();
+ do
+ {
+ if (RTMpIsCpuPossible(idCpu))
+ RTCpuSetAdd(pSet, idCpu);
+ } while (idCpu-- > 0);
+ return pSet;
+}
+
+
+RTDECL(RTCPUID) RTMpGetCount(void)
+{
+ return mp_maxid + 1;
+}
+
+
+RTDECL(RTCPUID) RTMpGetCoreCount(void)
+{
+ return mp_maxid + 1;
+}
+
+RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
+{
+ return idCpu <= mp_maxid
+ && !CPU_ABSENT(idCpu);
+}
+
+
+RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
+{
+ RTCPUID idCpu;
+
+ RTCpuSetEmpty(pSet);
+ idCpu = RTMpGetMaxCpuId();
+ do
+ {
+ if (RTMpIsCpuOnline(idCpu))
+ RTCpuSetAdd(pSet, idCpu);
+ } while (idCpu-- > 0);
+
+ return pSet;
+}
+
+
+RTDECL(RTCPUID) RTMpGetOnlineCount(void)
+{
+ return mp_ncpus;
+}
+
+
+/**
+ * Wrapper between the native FreeBSD per-cpu callback and PFNRTWORKER
+ * for the RTMpOnAll API.
+ *
+ * @param pvArg Pointer to the RTMPARGS package.
+ */
+static void rtmpOnAllFreeBSDWrapper(void *pvArg)
+{
+ PRTMPARGS pArgs = (PRTMPARGS)pvArg;
+ pArgs->pfnWorker(curcpu, pArgs->pvUser1, pArgs->pvUser2);
+}
+
+
+RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ RTMPARGS Args;
+ Args.pfnWorker = pfnWorker;
+ Args.pvUser1 = pvUser1;
+ Args.pvUser2 = pvUser2;
+ Args.idCpu = NIL_RTCPUID;
+ Args.cHits = 0;
+ smp_rendezvous(NULL, rtmpOnAllFreeBSDWrapper, smp_no_rendezvous_barrier, &Args);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Wrapper between the native FreeBSD per-cpu callback and PFNRTWORKER
+ * for the RTMpOnOthers API.
+ *
+ * @param pvArg Pointer to the RTMPARGS package.
+ */
+static void rtmpOnOthersFreeBSDWrapper(void *pvArg)
+{
+ PRTMPARGS pArgs = (PRTMPARGS)pvArg;
+ RTCPUID idCpu = curcpu;
+ if (pArgs->idCpu != idCpu)
+ pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
+}
+
+
+RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ /* Will panic if no rendezvousing cpus, so check up front. */
+ if (RTMpGetOnlineCount() > 1)
+ {
+#if __FreeBSD_version >= 900000
+ cpuset_t Mask;
+#elif __FreeBSD_version >= 700000
+ cpumask_t Mask;
+#endif
+ RTMPARGS Args;
+
+ Args.pfnWorker = pfnWorker;
+ Args.pvUser1 = pvUser1;
+ Args.pvUser2 = pvUser2;
+ Args.idCpu = RTMpCpuId();
+ Args.cHits = 0;
+#if __FreeBSD_version >= 700000
+# if __FreeBSD_version >= 900000
+ Mask = all_cpus;
+ CPU_CLR(curcpu, &Mask);
+# else
+ Mask = ~(cpumask_t)curcpu;
+# endif
+ smp_rendezvous_cpus(Mask, NULL, rtmpOnOthersFreeBSDWrapper, smp_no_rendezvous_barrier, &Args);
+#else
+ smp_rendezvous(NULL, rtmpOnOthersFreeBSDWrapper, NULL, &Args);
+#endif
+ }
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Wrapper between the native FreeBSD per-cpu callback and PFNRTWORKER
+ * for the RTMpOnSpecific API.
+ *
+ * @param pvArg Pointer to the RTMPARGS package.
+ */
+static void rtmpOnSpecificFreeBSDWrapper(void *pvArg)
+{
+ PRTMPARGS pArgs = (PRTMPARGS)pvArg;
+ RTCPUID idCpu = curcpu;
+ if (pArgs->idCpu == idCpu)
+ {
+ pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
+ ASMAtomicIncU32(&pArgs->cHits);
+ }
+}
+
+
+RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+#if __FreeBSD_version >= 900000
+ cpuset_t Mask;
+#elif __FreeBSD_version >= 700000
+ cpumask_t Mask;
+#endif
+ RTMPARGS Args;
+
+ /* Will panic if no rendezvousing cpus, so make sure the cpu is online. */
+ if (!RTMpIsCpuOnline(idCpu))
+ return VERR_CPU_NOT_FOUND;
+
+ Args.pfnWorker = pfnWorker;
+ Args.pvUser1 = pvUser1;
+ Args.pvUser2 = pvUser2;
+ Args.idCpu = idCpu;
+ Args.cHits = 0;
+#if __FreeBSD_version >= 700000
+# if __FreeBSD_version >= 900000
+ CPU_SETOF(idCpu, &Mask);
+# else
+ Mask = (cpumask_t)1 << idCpu;
+# endif
+ smp_rendezvous_cpus(Mask, NULL, rtmpOnSpecificFreeBSDWrapper, smp_no_rendezvous_barrier, &Args);
+#else
+ smp_rendezvous(NULL, rtmpOnSpecificFreeBSDWrapper, NULL, &Args);
+#endif
+ return Args.cHits == 1
+ ? VINF_SUCCESS
+ : VERR_CPU_NOT_FOUND;
+}
+
+
+#if __FreeBSD_version >= 700000
+/**
+ * Dummy callback for RTMpPokeCpu.
+ * @param pvArg Ignored
+ */
+static void rtmpFreeBSDPokeCallback(void *pvArg)
+{
+ NOREF(pvArg);
+}
+
+
+RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
+{
+#if __FreeBSD_version >= 900000
+ cpuset_t Mask;
+#elif __FreeBSD_version >= 700000
+ cpumask_t Mask;
+#endif
+
+ /* Will panic if no rendezvousing cpus, so make sure the cpu is online. */
+ if (!RTMpIsCpuOnline(idCpu))
+ return VERR_CPU_NOT_FOUND;
+
+# if __FreeBSD_version >= 900000
+ CPU_SETOF(idCpu, &Mask);
+# else
+ Mask = (cpumask_t)1 << idCpu;
+# endif
+ smp_rendezvous_cpus(Mask, NULL, rtmpFreeBSDPokeCallback, smp_no_rendezvous_barrier, NULL);
+
+ return VINF_SUCCESS;
+}
+
+#else /* < 7.0 */
+RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
+{
+ return VERR_NOT_SUPPORTED;
+}
+#endif /* < 7.0 */
+
+
+RTDECL(bool) RTMpOnAllIsConcurrentSafe(void)
+{
+ return true;
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/process-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/process-r0drv-freebsd.c
new file mode 100644
index 00000000..a00cf566
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/process-r0drv-freebsd.c
@@ -0,0 +1,75 @@
+/* $Id: process-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Process Management, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+
+#include <iprt/process.h>
+
+
+RTDECL(RTPROCESS) RTProcSelf(void)
+{
+ struct proc *pSelf = curproc;
+ return pSelf->p_pid;
+}
+
+
+RTR0DECL(RTR0PROCESS) RTR0ProcHandleSelf(void)
+{
+ return (RTR0PROCESS)curproc;
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/semevent-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/semevent-r0drv-freebsd.c
new file mode 100644
index 00000000..bd208a93
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/semevent-r0drv-freebsd.c
@@ -0,0 +1,280 @@
+/* $Id: semevent-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Single Release Event Semaphores, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define RTSEMEVENT_WITHOUT_REMAPPING
+#include "the-freebsd-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/semaphore.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/lockvalidator.h>
+#include <iprt/mem.h>
+
+#include "sleepqueue-r0drv-freebsd.h"
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * FreeBSD event semaphore.
+ */
+typedef struct RTSEMEVENTINTERNAL
+{
+ /** Magic value (RTSEMEVENT_MAGIC). */
+ uint32_t volatile u32Magic;
+ /** The object status - !0 when signaled and 0 when reset. */
+ uint32_t volatile fState;
+ /** Reference counter. */
+ uint32_t volatile cRefs;
+} RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
+
+
+RTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem)
+{
+ return RTSemEventCreateEx(phEventSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
+}
+
+
+RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...)
+{
+ AssertCompile(sizeof(RTSEMEVENTINTERNAL) > sizeof(void *));
+ AssertReturn(!(fFlags & ~(RTSEMEVENT_FLAGS_NO_LOCK_VAL | RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)), VERR_INVALID_PARAMETER);
+ Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL));
+ AssertPtrReturn(phEventSem, VERR_INVALID_POINTER);
+
+ PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)RTMemAllocZ(sizeof(*pThis));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ pThis->u32Magic = RTSEMEVENT_MAGIC;
+ pThis->cRefs = 1;
+ pThis->fState = 0;
+
+ *phEventSem = pThis;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Retains a reference to the event semaphore.
+ *
+ * @param pThis The event semaphore.
+ */
+DECLINLINE(void) rtR0SemEventBsdRetain(PRTSEMEVENTINTERNAL pThis)
+{
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ Assert(cRefs < 100000); NOREF(cRefs);
+}
+
+
+/**
+ * Releases a reference to the event semaphore.
+ *
+ * @param pThis The event semaphore.
+ */
+DECLINLINE(void) rtR0SemEventBsdRelease(PRTSEMEVENTINTERNAL pThis)
+{
+ if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
+ RTMemFree(pThis);
+}
+
+
+RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)
+{
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTINTERNAL pThis = hEventSem;
+ if (pThis == NIL_RTSEMEVENT)
+ return VINF_SUCCESS;
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+ Assert(pThis->cRefs > 0);
+
+ /*
+ * Invalidate it and signal the object just in case.
+ */
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENT_MAGIC);
+ ASMAtomicWriteU32(&pThis->fState, 0);
+ rtR0SemBsdBroadcast(pThis);
+ rtR0SemEventBsdRelease(pThis);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
+{
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
+ rtR0SemEventBsdRetain(pThis);
+
+ /*
+ * Signal the event object.
+ */
+ ASMAtomicWriteU32(&pThis->fState, 1);
+ rtR0SemBsdSignal(pThis);
+ rtR0SemEventBsdRelease(pThis);
+ return VINF_SUCCESS;
+}
+
+/**
+ * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug.
+ *
+ * @returns VBox status code.
+ * @param pThis The event semaphore.
+ * @param fFlags See RTSemEventWaitEx.
+ * @param uTimeout See RTSemEventWaitEx.
+ * @param pSrcPos The source code position of the wait.
+ */
+static int rtR0SemEventWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
+ PCRTLOCKVALSRCPOS pSrcPos)
+{
+ int rc;
+
+ /*
+ * Validate the input.
+ */
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
+ rtR0SemEventBsdRetain(pThis);
+
+ /*
+ * Try grab the event without setting up the wait.
+ */
+ if (ASMAtomicCmpXchgU32(&pThis->fState, 0, 1))
+ rc = VINF_SUCCESS;
+ else
+ {
+ /*
+ * We have to wait.
+ */
+ RTR0SEMBSDSLEEP Wait;
+ rc = rtR0SemBsdWaitInit(&Wait, fFlags, uTimeout, pThis);
+ if (RT_SUCCESS(rc))
+ {
+ for (;;)
+ {
+ /* The destruction test. */
+ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC))
+ rc = VERR_SEM_DESTROYED;
+ else
+ {
+ rtR0SemBsdWaitPrepare(&Wait);
+
+ /* Check the exit conditions. */
+ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENT_MAGIC))
+ rc = VERR_SEM_DESTROYED;
+ else if (ASMAtomicCmpXchgU32(&pThis->fState, 0, 1))
+ rc = VINF_SUCCESS;
+ else if (rtR0SemBsdWaitHasTimedOut(&Wait))
+ rc = VERR_TIMEOUT;
+ else if (rtR0SemBsdWaitWasInterrupted(&Wait))
+ rc = VERR_INTERRUPTED;
+ else
+ {
+ /* Do the wait and then recheck the conditions. */
+ rtR0SemBsdWaitDoIt(&Wait);
+ continue;
+ }
+ }
+ break;
+ }
+
+ rtR0SemBsdWaitDelete(&Wait);
+ }
+ }
+
+ rtR0SemEventBsdRelease(pThis);
+ return rc;
+}
+
+
+RTDECL(int) RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout)
+{
+#ifndef RTSEMEVENT_STRICT
+ return rtR0SemEventWait(hEventSem, fFlags, uTimeout, NULL);
+#else
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+ return rtR0SemEventWait(hEventSem, fFlags, uTimeout, &SrcPos);
+#endif
+}
+RT_EXPORT_SYMBOL(RTSemEventWaitEx);
+
+
+RTDECL(int) RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
+ RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+ return rtR0SemEventWait(hEventSem, fFlags, uTimeout, &SrcPos);
+}
+RT_EXPORT_SYMBOL(RTSemEventWaitExDebug);
+
+
+RTDECL(uint32_t) RTSemEventGetResolution(void)
+{
+ return 1000000000 / hz;
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/semeventmulti-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/semeventmulti-r0drv-freebsd.c
new file mode 100644
index 00000000..56a5ef14
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/semeventmulti-r0drv-freebsd.c
@@ -0,0 +1,344 @@
+/* $Id: semeventmulti-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define RTSEMEVENTMULTI_WITHOUT_REMAPPING
+#include "the-freebsd-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/semaphore.h>
+
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/lockvalidator.h>
+
+#include "sleepqueue-r0drv-freebsd.h"
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** @name fStateAndGen values
+ * @{ */
+/** The state bit number. */
+#define RTSEMEVENTMULTIBSD_STATE_BIT 0
+/** The state mask. */
+#define RTSEMEVENTMULTIBSD_STATE_MASK RT_BIT_32(RTSEMEVENTMULTIBSD_STATE_BIT)
+/** The generation mask. */
+#define RTSEMEVENTMULTIBSD_GEN_MASK ~RTSEMEVENTMULTIBSD_STATE_MASK
+/** The generation shift. */
+#define RTSEMEVENTMULTIBSD_GEN_SHIFT 1
+/** The initial variable value. */
+#define RTSEMEVENTMULTIBSD_STATE_GEN_INIT UINT32_C(0xfffffffc)
+/** @} */
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * FreeBSD multiple release event semaphore.
+ */
+typedef struct RTSEMEVENTMULTIINTERNAL
+{
+ /** Magic value (RTSEMEVENTMULTI_MAGIC). */
+ uint32_t volatile u32Magic;
+ /** The object state bit and generation counter.
+ * The generation counter is incremented every time the object is
+ * signalled. */
+ uint32_t volatile fStateAndGen;
+ /** Reference counter. */
+ uint32_t volatile cRefs;
+} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
+
+
+RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
+{
+ return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
+}
+
+
+RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
+ const char *pszNameFmt, ...)
+{
+ PRTSEMEVENTMULTIINTERNAL pThis;
+
+ AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
+ pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
+ if (pThis)
+ {
+ pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
+ pThis->fStateAndGen = RTSEMEVENTMULTIBSD_STATE_GEN_INIT;
+ pThis->cRefs = 1;
+
+ *phEventMultiSem = pThis;
+ return VINF_SUCCESS;
+ }
+ return VERR_NO_MEMORY;
+}
+
+
+/**
+ * Retain a reference to the semaphore.
+ *
+ * @param pThis The semaphore.
+ */
+DECLINLINE(void) rtR0SemEventMultiBsdRetain(PRTSEMEVENTMULTIINTERNAL pThis)
+{
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ Assert(cRefs && cRefs < 100000);
+}
+
+
+/**
+ * Release a reference, destroy the thing if necessary.
+ *
+ * @param pThis The semaphore.
+ */
+DECLINLINE(void) rtR0SemEventMultiBsdRelease(PRTSEMEVENTMULTIINTERNAL pThis)
+{
+ if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
+ {
+ Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
+ RTMemFree(pThis);
+ }
+}
+
+
+RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
+{
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
+ if (pThis == NIL_RTSEMEVENTMULTI)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ Assert(pThis->cRefs > 0);
+
+ /*
+ * Invalidate it and signal the object just in case.
+ */
+ ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC);
+ ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTIBSD_GEN_MASK);
+ rtR0SemBsdBroadcast(pThis);
+ rtR0SemEventMultiBsdRelease(pThis);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
+{
+ uint32_t fNew;
+ uint32_t fOld;
+
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
+ if (!pThis)
+ return VERR_INVALID_PARAMETER;
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ rtR0SemEventMultiBsdRetain(pThis);
+
+ /*
+ * Signal the event object. The cause of the parnoia here is racing to try
+ * deal with racing RTSemEventMultiSignal calls (should probably be
+ * forbidden, but it's relatively easy to handle).
+ */
+ do
+ {
+ fNew = fOld = ASMAtomicUoReadU32(&pThis->fStateAndGen);
+ fNew += 1 << RTSEMEVENTMULTIBSD_GEN_SHIFT;
+ fNew |= RTSEMEVENTMULTIBSD_STATE_MASK;
+ }
+ while (!ASMAtomicCmpXchgU32(&pThis->fStateAndGen, fNew, fOld));
+
+ rtR0SemBsdBroadcast(pThis);
+ rtR0SemEventMultiBsdRelease(pThis);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
+{
+ /*
+ * Validate input.
+ */
+ PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
+ if (!pThis)
+ return VERR_INVALID_PARAMETER;
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ rtR0SemEventMultiBsdRetain(pThis);
+
+ /*
+ * Reset it.
+ */
+ ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTIBSD_STATE_MASK);
+
+ rtR0SemEventMultiBsdRelease(pThis);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
+ *
+ * @returns VBox status code.
+ * @param pThis The event semaphore.
+ * @param fFlags See RTSemEventMultiWaitEx.
+ * @param uTimeout See RTSemEventMultiWaitEx.
+ * @param pSrcPos The source code position of the wait.
+ */
+static int rtR0SemEventMultiBsdWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
+ PCRTLOCKVALSRCPOS pSrcPos)
+{
+ uint32_t fOrgStateAndGen;
+ int rc;
+
+ /*
+ * Validate the input.
+ */
+ AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
+ AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
+ rtR0SemEventMultiBsdRetain(pThis);
+
+ /*
+ * Is the event already signalled or do we have to wait?
+ */
+ fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
+ if (fOrgStateAndGen & RTSEMEVENTMULTIBSD_STATE_MASK)
+ rc = VINF_SUCCESS;
+ else
+ {
+ /*
+ * We have to wait.
+ */
+ RTR0SEMBSDSLEEP Wait;
+ rc = rtR0SemBsdWaitInit(&Wait, fFlags, uTimeout, pThis);
+ if (RT_SUCCESS(rc))
+ {
+ for (;;)
+ {
+ /* The destruction test. */
+ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
+ rc = VERR_SEM_DESTROYED;
+ else
+ {
+ rtR0SemBsdWaitPrepare(&Wait);
+
+ /* Check the exit conditions. */
+ if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
+ rc = VERR_SEM_DESTROYED;
+ else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
+ rc = VINF_SUCCESS;
+ else if (rtR0SemBsdWaitHasTimedOut(&Wait))
+ rc = VERR_TIMEOUT;
+ else if (rtR0SemBsdWaitWasInterrupted(&Wait))
+ rc = VERR_INTERRUPTED;
+ else
+ {
+ /* Do the wait and then recheck the conditions. */
+ rtR0SemBsdWaitDoIt(&Wait);
+ continue;
+ }
+ }
+ break;
+ }
+
+ rtR0SemBsdWaitDelete(&Wait);
+ }
+ }
+
+ rtR0SemEventMultiBsdRelease(pThis);
+ return rc;
+}
+
+
+RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
+{
+#ifndef RTSEMEVENT_STRICT
+ return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, NULL);
+#else
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
+ return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
+#endif
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiWaitEx);
+
+
+RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
+ RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
+ return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiWaitExDebug);
+
+
+RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
+{
+ return rtR0SemBsdWaitGetResolution();
+}
+RT_EXPORT_SYMBOL(RTSemEventMultiGetResolution);
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/semfastmutex-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/semfastmutex-r0drv-freebsd.c
new file mode 100644
index 00000000..53035200
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/semfastmutex-r0drv-freebsd.c
@@ -0,0 +1,139 @@
+/* $Id: semfastmutex-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Fast Mutex Semaphores, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+
+#include <iprt/semaphore.h>
+#include <iprt/errcore.h>
+#include <iprt/alloc.h>
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Wrapper for the FreeBSD (sleep) mutex.
+ */
+typedef struct RTSEMFASTMUTEXINTERNAL
+{
+ /** Magic value (RTSEMFASTMUTEX_MAGIC). */
+ uint32_t u32Magic;
+ /** The FreeBSD shared/exclusive lock mutex. */
+ struct sx SxLock;
+} RTSEMFASTMUTEXINTERNAL, *PRTSEMFASTMUTEXINTERNAL;
+
+
+RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx)
+{
+ AssertCompile(sizeof(RTSEMFASTMUTEXINTERNAL) > sizeof(void *));
+ AssertPtrReturn(phFastMtx, VERR_INVALID_POINTER);
+
+ PRTSEMFASTMUTEXINTERNAL pThis = (PRTSEMFASTMUTEXINTERNAL)RTMemAllocZ(sizeof(*pThis));
+ if (pThis)
+ {
+ pThis->u32Magic = RTSEMFASTMUTEX_MAGIC;
+ sx_init_flags(&pThis->SxLock, "IPRT Fast Mutex Semaphore", SX_DUPOK);
+
+ *phFastMtx = pThis;
+ return VINF_SUCCESS;
+ }
+ return VERR_NO_MEMORY;
+}
+
+
+RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx)
+{
+ PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
+ if (pThis == NIL_RTSEMFASTMUTEX)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ ASMAtomicWriteU32(&pThis->u32Magic, RTSEMFASTMUTEX_MAGIC_DEAD);
+ sx_destroy(&pThis->SxLock);
+ RTMemFree(pThis);
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx)
+{
+ PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ sx_xlock(&pThis->SxLock);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx)
+{
+ PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ sx_xunlock(&pThis->SxLock);
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/semmutex-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/semmutex-r0drv-freebsd.c
new file mode 100644
index 00000000..ec6ac89d
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/semmutex-r0drv-freebsd.c
@@ -0,0 +1,219 @@
+/* $Id: semmutex-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Mutex Semaphores, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Copyright (C) 2010-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define RTSEMMUTEX_WITHOUT_REMAPPING
+#include "the-freebsd-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/semaphore.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/mem.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Wrapper for the FreeBSD (sleep) mutex.
+ */
+typedef struct RTSEMMUTEXINTERNAL
+{
+ /** Magic value (RTSEMMUTEX_MAGIC). */
+ uint32_t u32Magic;
+ /** The FreeBSD shared/exclusive lock mutex. */
+ struct sx SxLock;
+} RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL;
+
+
+RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMutexSem)
+{
+ AssertCompile(sizeof(RTSEMMUTEXINTERNAL) > sizeof(void *));
+ AssertPtrReturn(phMutexSem, VERR_INVALID_POINTER);
+
+ PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)RTMemAllocZ(sizeof(*pThis));
+ if (pThis)
+ {
+ pThis->u32Magic = RTSEMMUTEX_MAGIC;
+ sx_init_flags(&pThis->SxLock, "IPRT Mutex Semaphore", SX_RECURSE);
+
+ *phMutexSem = pThis;
+ return VINF_SUCCESS;
+ }
+ return VERR_NO_MEMORY;
+}
+
+
+RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMutexSem;
+ if (pThis == NIL_RTSEMMUTEX)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE);
+
+ sx_destroy(&pThis->SxLock);
+ RTMemFree(pThis);
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMutexSem;
+ int rc;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ if (cMillies == RT_INDEFINITE_WAIT)
+ {
+ sx_xlock(&pThis->SxLock);
+ rc = VINF_SUCCESS;
+ }
+ else if (!cMillies)
+ {
+ if (sx_try_xlock(&pThis->SxLock))
+ rc = VINF_SUCCESS;
+ else
+ rc = VERR_TIMEOUT;
+ }
+ /*
+ * GROSS HACK: poll implementation of timeout.
+ */
+ /** @todo Implement timeouts in RTSemMutexRequest. */
+ else if (sx_try_xlock(&pThis->SxLock))
+ rc = VINF_SUCCESS;
+ else
+ {
+ uint64_t StartTS = RTTimeSystemMilliTS();
+ rc = VERR_TIMEOUT;
+ do
+ {
+ RTThreadSleep(1);
+ if (sx_try_xlock(&pThis->SxLock))
+ {
+ rc = VINF_SUCCESS;
+ break;
+ }
+ } while (RTTimeSystemMilliTS() - StartTS < cMillies);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ return RTSemMutexRequest(hMutexSem, cMillies);
+}
+
+
+RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMutexSem;
+ int rc;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ if (cMillies == RT_INDEFINITE_WAIT)
+ {
+ if (!sx_xlock_sig(&pThis->SxLock))
+ rc = VINF_SUCCESS;
+ else
+ rc = VERR_INTERRUPTED;
+ }
+ else if (!cMillies)
+ {
+ if (sx_try_xlock(&pThis->SxLock))
+ rc = VINF_SUCCESS;
+ else
+ rc = VERR_TIMEOUT;
+ }
+ /*
+ * GROSS HACK: poll implementation of timeout.
+ */
+ /** @todo Implement timeouts and interrupt checks in
+ * RTSemMutexRequestNoResume. */
+ else if (sx_try_xlock(&pThis->SxLock))
+ rc = VINF_SUCCESS;
+ else
+ {
+ uint64_t StartTS = RTTimeSystemMilliTS();
+ rc = VERR_TIMEOUT;
+ do
+ {
+ RTThreadSleep(1);
+ if (sx_try_xlock(&pThis->SxLock))
+ {
+ rc = VINF_SUCCESS;
+ break;
+ }
+ } while (RTTimeSystemMilliTS() - StartTS < cMillies);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+ return RTSemMutexRequestNoResume(hMutexSem, cMillies);
+}
+
+
+RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMutexSem;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
+
+ sx_xunlock(&pThis->SxLock);
+ return VINF_SUCCESS;
+}
+
+
+
+RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
+{
+ PRTSEMMUTEXINTERNAL pThis = hMutexSem;
+ AssertPtrReturn(pThis, false);
+ AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), false);
+
+ return sx_xlocked(&pThis->SxLock);
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h b/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h
new file mode 100644
index 00000000..dd13d487
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h
@@ -0,0 +1,334 @@
+/* $Id: sleepqueue-r0drv-freebsd.h $ */
+/** @file
+ * IPRT - FreeBSD Ring-0 Driver Helpers for Abstracting Sleep Queues,
+ */
+
+/*
+ * Copyright (C) 2006-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef IPRT_INCLUDED_SRC_r0drv_freebsd_sleepqueue_r0drv_freebsd_h
+#define IPRT_INCLUDED_SRC_r0drv_freebsd_sleepqueue_r0drv_freebsd_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include "the-freebsd-kernel.h"
+
+#include <iprt/asm-math.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include <iprt/time.h>
+
+/**
+ * Kernel mode FreeBSD wait state structure.
+ */
+typedef struct RTR0SEMBSDSLEEP
+{
+ /** The absolute timeout given as nano seconds since the start of the
+ * monotonic clock. */
+ uint64_t uNsAbsTimeout;
+ /** The timeout in ticks. Updated after waiting. */
+ int iTimeout;
+ /** Set if it's an indefinite wait. */
+ bool fIndefinite;
+ /** Set if we've already timed out.
+ * Set by rtR0SemBsdWaitDoIt and read by rtR0SemBsdWaitHasTimedOut. */
+ bool fTimedOut;
+ /** Flag whether the wait was interrupted. */
+ bool fInterrupted;
+ /** flag whether the wait is interruptible or not. */
+ bool fInterruptible;
+ /** Opaque wait channel id. */
+ void *pvWaitChan;
+} RTR0SEMBSDSLEEP;
+/** Pointer to a FreeBSD wait state. */
+typedef RTR0SEMBSDSLEEP *PRTR0SEMBSDSLEEP;
+
+
+/**
+ * Updates the timeout of the FreeBSD wait.
+ *
+ * @returns RTSEMWAIT_FLAGS_INDEFINITE if the timeout value is too big.
+ * 0 otherwise
+ * @param pWait The wait structure.
+ * @param uTimeout The relative timeout in nanoseconds.
+ */
+DECLINLINE(uint32_t) rtR0SemBsdWaitUpdateTimeout(PRTR0SEMBSDSLEEP pWait, uint64_t uTimeout)
+{
+#if 0
+ struct timeval tv;
+
+ tv.tv_sec = uTimeout / UINT64_C(1000000000);
+ tv.tv_usec = (uTimeout % UINT64_C(1000000000)) / UINT64_C(1000);
+
+ pWait->iTimeout = tvtohz(&tv);
+#else
+ uint64_t cTicks = ASMMultU64ByU32DivByU32(uTimeout, hz, UINT32_C(1000000000));
+ if (cTicks >= INT_MAX)
+ return RTSEMWAIT_FLAGS_INDEFINITE;
+ else
+ pWait->iTimeout = (int)cTicks;
+#endif
+
+ return 0;
+}
+
+/**
+ * Initializes a wait.
+ *
+ * The caller MUST check the wait condition BEFORE calling this function or the
+ * timeout logic will be flawed.
+ *
+ * @returns VINF_SUCCESS or VERR_TIMEOUT.
+ * @param pWait The wait structure.
+ * @param fFlags The wait flags.
+ * @param uTimeout The timeout.
+ * @param pvWaitChan The opaque wait channel.
+ */
+DECLINLINE(int) rtR0SemBsdWaitInit(PRTR0SEMBSDSLEEP pWait, uint32_t fFlags, uint64_t uTimeout,
+ void *pvWaitChan)
+{
+ pWait->iTimeout = 0;
+ pWait->uNsAbsTimeout = 0; /* shut up gcc */
+
+ /*
+ * Process the flags and timeout.
+ */
+ if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
+ {
+/** @todo optimize: millisecs -> nanosecs -> millisec -> jiffies */
+ if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
+ uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
+ ? uTimeout * UINT32_C(1000000)
+ : UINT64_MAX;
+ if (uTimeout == UINT64_MAX)
+ fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
+ else
+ {
+ uint64_t u64Now;
+ if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
+ {
+ if (uTimeout == 0)
+ return VERR_TIMEOUT;
+
+ u64Now = RTTimeSystemNanoTS();
+ if (u64Now + uTimeout < u64Now) /* overflow */
+ fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
+ else
+ pWait->uNsAbsTimeout = u64Now + uTimeout;
+ }
+ else
+ {
+ u64Now = RTTimeSystemNanoTS();
+ if (u64Now >= uTimeout)
+ return VERR_TIMEOUT;
+
+ pWait->uNsAbsTimeout = uTimeout;
+ uTimeout -= u64Now; /* Get a relative value. */
+ }
+ }
+ }
+
+ if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
+ {
+ pWait->fIndefinite = false;
+ fFlags |= rtR0SemBsdWaitUpdateTimeout(pWait, uTimeout);
+ }
+
+ if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
+ {
+ pWait->fIndefinite = true;
+ pWait->iTimeout = INT_MAX;
+ pWait->uNsAbsTimeout = UINT64_MAX;
+ }
+
+ pWait->fTimedOut = false;
+
+ /*
+ * Initialize the wait queue related bits.
+ */
+ pWait->fInterruptible = fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE
+ ? true : false;
+ pWait->pvWaitChan = pvWaitChan;
+ pWait->fInterrupted = false;
+
+ return VINF_SUCCESS;
+}
+
+/**
+ * Prepares the next wait.
+ *
+ * This must be called before rtR0SemBsdWaitDoIt, and the caller should check
+ * the exit conditions inbetween the two calls.
+ *
+ * @param pWait The wait structure.
+ */
+DECLINLINE(void) rtR0SemBsdWaitPrepare(PRTR0SEMBSDSLEEP pWait)
+{
+ /* Lock the queues. */
+ sleepq_lock(pWait->pvWaitChan);
+}
+
+/**
+ * Do the actual wait.
+ *
+ * @param pWait The wait structure.
+ */
+DECLINLINE(void) rtR0SemBsdWaitDoIt(PRTR0SEMBSDSLEEP pWait)
+{
+ int rcBsd;
+ int fSleepqFlags = SLEEPQ_CONDVAR;
+
+ if (pWait->fInterruptible)
+ fSleepqFlags |= SLEEPQ_INTERRUPTIBLE;
+
+ sleepq_add(pWait->pvWaitChan, NULL, "VBoxIS", fSleepqFlags, 0);
+
+ if (!pWait->fIndefinite)
+ {
+ sleepq_set_timeout(pWait->pvWaitChan, pWait->iTimeout);
+
+ if (pWait->fInterruptible)
+ rcBsd = SLEEPQ_TIMEDWAIT_SIG(pWait->pvWaitChan);
+ else
+ rcBsd = SLEEPQ_TIMEDWAIT(pWait->pvWaitChan);
+ }
+ else
+ {
+ if (pWait->fInterruptible)
+ rcBsd = SLEEPQ_WAIT_SIG(pWait->pvWaitChan);
+ else
+ {
+ rcBsd = 0;
+ SLEEPQ_WAIT(pWait->pvWaitChan);
+ }
+ }
+
+ switch (rcBsd)
+ {
+ case 0:
+ break;
+ case ERESTART:
+ {
+ if (!pWait->fIndefinite)
+ {
+ /* Recalc timeout. */
+ uint64_t u64Now = RTTimeSystemNanoTS();
+ if (u64Now >= pWait->uNsAbsTimeout)
+ pWait->fTimedOut = true;
+ else
+ {
+ u64Now = pWait->uNsAbsTimeout - u64Now;
+ rtR0SemBsdWaitUpdateTimeout(pWait, u64Now);
+ }
+ }
+ break;
+ }
+ case EWOULDBLOCK:
+ pWait->fTimedOut = true;
+ break;
+ case EINTR:
+ Assert(pWait->fInterruptible);
+ pWait->fInterrupted = true;
+ break;
+ default:
+ AssertMsgFailed(("sleepq_* -> %d\n", rcBsd));
+ break;
+ }
+}
+
+
+/**
+ * Checks if a FreeBSD wait was interrupted.
+ *
+ * @returns true / false
+ * @param pWait The wait structure.
+ * @remarks This shall be called before the first rtR0SemBsdWaitDoIt().
+ */
+DECLINLINE(bool) rtR0SemBsdWaitWasInterrupted(PRTR0SEMBSDSLEEP pWait)
+{
+ return pWait->fInterrupted;
+}
+
+
+/**
+ * Checks if a FreeBSD wait has timed out.
+ *
+ * @returns true / false
+ * @param pWait The wait structure.
+ */
+DECLINLINE(bool) rtR0SemBsdWaitHasTimedOut(PRTR0SEMBSDSLEEP pWait)
+{
+ return pWait->fTimedOut;
+}
+
+
+/**
+ * Deletes a FreeBSD wait.
+ *
+ * @param pWait The wait structure.
+ */
+DECLINLINE(void) rtR0SemBsdWaitDelete(PRTR0SEMBSDSLEEP pWait)
+{
+ sleepq_release(pWait->pvWaitChan);
+}
+
+
+/**
+ * Signals the wait channel.
+ *
+ * @param pvWaitChan The opaque wait channel handle.
+ */
+DECLINLINE(void) rtR0SemBsdSignal(void *pvWaitChan)
+{
+ sleepq_lock(pvWaitChan);
+ int fWakeupSwapProc = sleepq_signal(pvWaitChan, SLEEPQ_CONDVAR, 0, 0);
+ sleepq_release(pvWaitChan);
+ if (fWakeupSwapProc)
+ kick_proc0();
+}
+
+/**
+ * Wakes up all waiters on the wait channel.
+ *
+ * @param pvWaitChan The opaque wait channel handle.
+ */
+DECLINLINE(void) rtR0SemBsdBroadcast(void *pvWaitChan)
+{
+ sleepq_lock(pvWaitChan);
+ sleepq_broadcast(pvWaitChan, SLEEPQ_CONDVAR, 0, 0);
+#if __FreeBSD_version >= 800000 /* Broadcast releases the sleep queue lock on FreeBSD 7.x */
+ sleepq_release(pvWaitChan);
+#endif
+}
+
+/**
+ * Gets the max resolution of the timeout machinery.
+ *
+ * @returns Resolution specified in nanoseconds.
+ */
+DECLINLINE(uint32_t) rtR0SemBsdWaitGetResolution(void)
+{
+ return 1000000000 / hz; /* ns */
+}
+
+#endif /* !IPRT_INCLUDED_SRC_r0drv_freebsd_sleepqueue_r0drv_freebsd_h */
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/spinlock-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/spinlock-r0drv-freebsd.c
new file mode 100644
index 00000000..d5d56188
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/spinlock-r0drv-freebsd.c
@@ -0,0 +1,234 @@
+/* $Id: spinlock-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Spinlocks, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+#include "internal/iprt.h"
+
+#include <iprt/spinlock.h>
+#include <iprt/errcore.h>
+#include <iprt/alloc.h>
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/asm-amd64-x86.h>
+#include <iprt/thread.h>
+#include <iprt/mp.h>
+
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Wrapper for the struct mtx type.
+ */
+typedef struct RTSPINLOCKINTERNAL
+{
+ /** Spinlock magic value (RTSPINLOCK_MAGIC). */
+ uint32_t volatile u32Magic;
+ /** The spinlock. */
+ uint32_t volatile fLocked;
+ /** Saved interrupt flag. */
+ uint32_t volatile fIntSaved;
+ /** The spinlock creation flags. */
+ uint32_t fFlags;
+#ifdef RT_MORE_STRICT
+ /** The idAssertCpu variable before acquring the lock for asserting after
+ * releasing the spinlock. */
+ RTCPUID volatile idAssertCpu;
+ /** The CPU that owns the lock. */
+ RTCPUID volatile idCpuOwner;
+#endif
+} RTSPINLOCKINTERNAL, *PRTSPINLOCKINTERNAL;
+
+
+RTDECL(int) RTSpinlockCreate(PRTSPINLOCK pSpinlock, uint32_t fFlags, const char *pszName)
+{
+ RT_ASSERT_PREEMPTIBLE();
+ AssertReturn(fFlags == RTSPINLOCK_FLAGS_INTERRUPT_SAFE || fFlags == RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, VERR_INVALID_PARAMETER);
+
+ /*
+ * Allocate.
+ */
+ AssertCompile(sizeof(RTSPINLOCKINTERNAL) > sizeof(void *));
+ PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)RTMemAllocZ(sizeof(*pThis));
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ /*
+ * Initialize & return.
+ */
+ pThis->u32Magic = RTSPINLOCK_MAGIC;
+ pThis->fLocked = 0;
+ pThis->fFlags = fFlags;
+ pThis->fIntSaved = 0;
+
+ *pSpinlock = pThis;
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTSpinlockDestroy(RTSPINLOCK Spinlock)
+{
+ /*
+ * Validate input.
+ */
+ RT_ASSERT_INTS_ON();
+ PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)Spinlock;
+ if (!pThis)
+ return VERR_INVALID_PARAMETER;
+ AssertMsgReturn(pThis->u32Magic == RTSPINLOCK_MAGIC,
+ ("Invalid spinlock %p magic=%#x\n", pThis, pThis->u32Magic),
+ VERR_INVALID_PARAMETER);
+
+ /*
+ * Make the lock invalid and release the memory.
+ */
+ ASMAtomicIncU32(&pThis->u32Magic);
+ RTMemFree(pThis);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock)
+{
+ PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)Spinlock;
+ RT_ASSERT_PREEMPT_CPUID_VAR();
+ AssertPtr(pThis);
+ Assert(pThis->u32Magic == RTSPINLOCK_MAGIC);
+
+ if (pThis->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE)
+ {
+ for (;;)
+ {
+ uint32_t fIntSaved = ASMIntDisableFlags();
+ critical_enter();
+
+ int c = 50;
+ for (;;)
+ {
+ if (ASMAtomicCmpXchgU32(&pThis->fLocked, 1, 0))
+ {
+ RT_ASSERT_PREEMPT_CPUID_SPIN_ACQUIRED(pThis);
+ pThis->fIntSaved = fIntSaved;
+ return;
+ }
+ if (--c <= 0)
+ break;
+ cpu_spinwait();
+ }
+
+ /* Enable interrupts while we sleep. */
+ ASMSetFlags(fIntSaved);
+ critical_exit();
+ DELAY(1);
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ critical_enter();
+
+ int c = 50;
+ for (;;)
+ {
+ if (ASMAtomicCmpXchgU32(&pThis->fLocked, 1, 0))
+ {
+ RT_ASSERT_PREEMPT_CPUID_SPIN_ACQUIRED(pThis);
+ return;
+ }
+ if (--c <= 0)
+ break;
+ cpu_spinwait();
+ }
+
+ critical_exit();
+ DELAY(1);
+ }
+ }
+}
+
+
+RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock)
+{
+ PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)Spinlock;
+ RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE_VARS();
+
+ AssertPtr(pThis);
+ Assert(pThis->u32Magic == RTSPINLOCK_MAGIC);
+ RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE(pThis);
+
+ if (pThis->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE)
+ {
+ uint32_t fIntSaved = pThis->fIntSaved;
+ pThis->fIntSaved = 0;
+ if (ASMAtomicCmpXchgU32(&pThis->fLocked, 0, 1))
+ ASMSetFlags(fIntSaved);
+ else
+ AssertMsgFailed(("Spinlock %p was not locked!\n", pThis));
+ }
+ else
+ {
+ if (!ASMAtomicCmpXchgU32(&pThis->fLocked, 0, 1))
+ AssertMsgFailed(("Spinlock %p was not locked!\n", pThis));
+ }
+
+ critical_exit();
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/the-freebsd-kernel.h b/src/VBox/Runtime/r0drv/freebsd/the-freebsd-kernel.h
new file mode 100644
index 00000000..01d89963
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/the-freebsd-kernel.h
@@ -0,0 +1,160 @@
+/* $Id: the-freebsd-kernel.h $ */
+/** @file
+ * IPRT - Ring-0 Driver, The FreeBSD Kernel Headers.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef IPRT_INCLUDED_SRC_r0drv_freebsd_the_freebsd_kernel_h
+#define IPRT_INCLUDED_SRC_r0drv_freebsd_the_freebsd_kernel_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/types.h>
+
+/* Deal with conflicts first. */
+#include <sys/param.h>
+#undef PVM
+#include <sys/bus.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/uio.h>
+#include <sys/libkern.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/limits.h>
+#include <sys/unistd.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#if __FreeBSD_version >= 1000030
+#include <sys/rwlock.h>
+#endif
+#include <sys/mutex.h>
+#include <sys/sched.h>
+#include <sys/callout.h>
+#include <sys/cpu.h>
+#include <sys/smp.h>
+#include <sys/sleepqueue.h>
+#include <sys/sx.h>
+#include <vm/vm.h>
+#include <vm/pmap.h> /* for vtophys */
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_param.h> /* KERN_SUCCESS ++ */
+#include <vm/vm_page.h>
+#include <vm/vm_phys.h> /* vm_phys_alloc_* */
+#include <vm/vm_extern.h> /* kmem_alloc_attr */
+#include <vm/vm_pageout.h> /* vm_contig_grow_cache */
+#include <sys/vmmeter.h> /* cnt */
+#include <sys/resourcevar.h>
+#include <machine/cpu.h>
+
+/**
+ * Wrappers around the sleepq_ KPI.
+ */
+#if __FreeBSD_version >= 800026
+# define SLEEPQ_TIMEDWAIT(EventInt) sleepq_timedwait(EventInt, 0)
+# define SLEEPQ_TIMEDWAIT_SIG(EventInt) sleepq_timedwait_sig(EventInt, 0)
+# define SLEEPQ_WAIT(EventInt) sleepq_wait(EventInt, 0)
+# define SLEEPQ_WAIT_SIG(EventInt) sleepq_wait_sig(EventInt, 0)
+#else
+# define SLEEPQ_TIMEDWAIT(EventInt) sleepq_timedwait(EventInt)
+# define SLEEPQ_TIMEDWAIT_SIG(EventInt) sleepq_timedwait_sig(EventInt)
+# define SLEEPQ_WAIT(EventInt) sleepq_wait(EventInt)
+# define SLEEPQ_WAIT_SIG(EventInt) sleepq_wait_sig(EventInt)
+#endif
+
+/**
+ * Our pmap_enter version
+ */
+#if __FreeBSD_version >= 701105
+# define MY_PMAP_ENTER(pPhysMap, AddrR3, pPage, fProt, fWired) \
+ pmap_enter(pPhysMap, AddrR3, VM_PROT_NONE, pPage, fProt, fWired)
+#else
+# define MY_PMAP_ENTER(pPhysMap, AddrR3, pPage, fProt, fWired) \
+ pmap_enter(pPhysMap, AddrR3, pPage, fProt, fWired)
+#endif
+
+/**
+ * The VM object lock/unlock wrappers for older kernels.
+ */
+#if __FreeBSD_version < 1000030
+# define VM_OBJECT_WLOCK(a_pObject) VM_OBJECT_LOCK((a_pObject))
+# define VM_OBJECT_WUNLOCK(a_pObject) VM_OBJECT_UNLOCK((a_pObject))
+#endif
+
+#if __FreeBSD_version >= 1100077
+# define MY_LIM_MAX_PROC(a_pProc, a_Limit) lim_max_proc((a_pProc), (a_Limit))
+#else
+# define MY_LIM_MAX_PROC(a_pProc, a_Limit) lim_max((a_pProc), (a_Limit))
+#endif
+
+/**
+ * Check whether we can use kmem_alloc_attr for low allocs.
+ */
+#if (__FreeBSD_version >= 900011) \
+ || (__FreeBSD_version < 900000 && __FreeBSD_version >= 800505) \
+ || (__FreeBSD_version < 800000 && __FreeBSD_version >= 703101)
+# define USE_KMEM_ALLOC_ATTR
+#endif
+
+/**
+ * Check whether we can use kmem_alloc_prot.
+ */
+#if 0 /** @todo Not available yet. */
+# define USE_KMEM_ALLOC_PROT
+#endif
+
+#endif /* !IPRT_INCLUDED_SRC_r0drv_freebsd_the_freebsd_kernel_h */
diff --git a/src/VBox/Runtime/r0drv/freebsd/thread-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/thread-r0drv-freebsd.c
new file mode 100644
index 00000000..cbae13fa
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/thread-r0drv-freebsd.c
@@ -0,0 +1,186 @@
+/* $Id: thread-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Threads (Part 1), Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+#include "internal/iprt.h"
+#include <iprt/thread.h>
+
+#include <iprt/asm.h>
+#include <iprt/asm-amd64-x86.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mp.h>
+#include "internal/thread.h"
+
+
+RTDECL(RTNATIVETHREAD) RTThreadNativeSelf(void)
+{
+ return (RTNATIVETHREAD)curthread;
+}
+
+
+static int rtR0ThreadFbsdSleepCommon(RTMSINTERVAL cMillies)
+{
+ int rc;
+ int cTicks;
+
+ /*
+ * 0 ms sleep -> yield.
+ */
+ if (!cMillies)
+ {
+ RTThreadYield();
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Translate milliseconds into ticks and go to sleep.
+ */
+ if (cMillies != RT_INDEFINITE_WAIT)
+ {
+ if (hz == 1000)
+ cTicks = cMillies;
+ else if (hz == 100)
+ cTicks = cMillies / 10;
+ else
+ {
+ int64_t cTicks64 = ((uint64_t)cMillies * hz) / 1000;
+ cTicks = (int)cTicks64;
+ if (cTicks != cTicks64)
+ cTicks = INT_MAX;
+ }
+ }
+ else
+ cTicks = 0; /* requires giant lock! */
+
+ rc = tsleep((void *)RTThreadSleep,
+ PZERO | PCATCH,
+ "iprtsl", /* max 6 chars */
+ cTicks);
+ switch (rc)
+ {
+ case 0:
+ return VINF_SUCCESS;
+ case EWOULDBLOCK:
+ return VERR_TIMEOUT;
+ case EINTR:
+ case ERESTART:
+ return VERR_INTERRUPTED;
+ default:
+ AssertMsgFailed(("%d\n", rc));
+ return VERR_NO_TRANSLATION;
+ }
+}
+
+
+RTDECL(int) RTThreadSleep(RTMSINTERVAL cMillies)
+{
+ return rtR0ThreadFbsdSleepCommon(cMillies);
+}
+
+
+RTDECL(int) RTThreadSleepNoLog(RTMSINTERVAL cMillies)
+{
+ return rtR0ThreadFbsdSleepCommon(cMillies);
+}
+
+
+RTDECL(bool) RTThreadYield(void)
+{
+#if __FreeBSD_version >= 900032
+ kern_yield(curthread->td_user_pri);
+#else
+ uio_yield();
+#endif
+ return false; /** @todo figure this one ... */
+}
+
+
+RTDECL(bool) RTThreadPreemptIsEnabled(RTTHREAD hThread)
+{
+ Assert(hThread == NIL_RTTHREAD);
+
+ return curthread->td_critnest == 0
+ && ASMIntAreEnabled(); /** @todo is there a native freebsd function/macro for this? */
+}
+
+
+RTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread)
+{
+ Assert(hThread == NIL_RTTHREAD);
+
+ return curthread->td_owepreempt == 1;
+}
+
+
+RTDECL(bool) RTThreadPreemptIsPendingTrusty(void)
+{
+ /* yes, RTThreadPreemptIsPending is reliable. */
+ return true;
+}
+
+
+RTDECL(bool) RTThreadPreemptIsPossible(void)
+{
+ /* yes, kernel preemption is possible. */
+ return true;
+}
+
+
+RTDECL(void) RTThreadPreemptDisable(PRTTHREADPREEMPTSTATE pState)
+{
+ AssertPtr(pState);
+ Assert(pState->u32Reserved == 0);
+ pState->u32Reserved = 42;
+
+ critical_enter();
+ RT_ASSERT_PREEMPT_CPUID_DISABLE(pState);
+}
+
+
+RTDECL(void) RTThreadPreemptRestore(PRTTHREADPREEMPTSTATE pState)
+{
+ AssertPtr(pState);
+ Assert(pState->u32Reserved == 42);
+ pState->u32Reserved = 0;
+
+ RT_ASSERT_PREEMPT_CPUID_RESTORE(pState);
+ critical_exit();
+}
+
+
+RTDECL(bool) RTThreadIsInInterrupt(RTTHREAD hThread)
+{
+ Assert(hThread == NIL_RTTHREAD); NOREF(hThread);
+ /** @todo FreeBSD: Implement RTThreadIsInInterrupt. Required for guest
+ * additions! */
+ return !ASMIntAreEnabled();
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/thread2-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/thread2-r0drv-freebsd.c
new file mode 100644
index 00000000..d46f1d61
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/thread2-r0drv-freebsd.c
@@ -0,0 +1,179 @@
+/* $Id: thread2-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Threads (Part 2), Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+
+#include <iprt/thread.h>
+#include <iprt/errcore.h>
+#include <iprt/assert.h>
+
+#include "internal/thread.h"
+
+
+DECLHIDDEN(int) rtThreadNativeInit(void)
+{
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(RTTHREAD) RTThreadSelf(void)
+{
+ return rtThreadGetByNative(RTThreadNativeSelf());
+}
+
+
+DECLHIDDEN(int) rtThreadNativeSetPriority(PRTTHREADINT pThread, RTTHREADTYPE enmType)
+{
+ int iPriority;
+
+ switch (enmType)
+ {
+ case RTTHREADTYPE_INFREQUENT_POLLER: iPriority = PZERO + 8; break;
+ case RTTHREADTYPE_EMULATION: iPriority = PZERO + 4; break;
+ case RTTHREADTYPE_DEFAULT: iPriority = PZERO; break;
+ case RTTHREADTYPE_MSG_PUMP: iPriority = PZERO - 4; break;
+ case RTTHREADTYPE_IO: iPriority = PRIBIO; break;
+ case RTTHREADTYPE_TIMER: iPriority = PRI_MIN_KERN; break;
+ default:
+ AssertMsgFailed(("enmType=%d\n", enmType));
+ return VERR_INVALID_PARAMETER;
+ }
+
+#if __FreeBSD_version < 700000
+ /* Do like they're doing in subr_ntoskrnl.c... */
+ mtx_lock_spin(&sched_lock);
+#else
+ thread_lock(curthread);
+#endif
+ sched_prio(curthread, iPriority);
+#if __FreeBSD_version < 600000
+ curthread->td_base_pri = iPriority;
+#endif
+#if __FreeBSD_version < 700000
+ mtx_unlock_spin(&sched_lock);
+#else
+ thread_unlock(curthread);
+#endif
+
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
+{
+ NOREF(pThread);
+ /* There is nothing special that needs doing here, but the
+ user really better know what he's cooking. */
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(void) rtThreadNativeWaitKludge(PRTTHREADINT pThread)
+{
+ /** @todo fix RTThreadWait/RTR0Term race on freebsd. */
+ RTThreadSleep(1);
+}
+
+
+DECLHIDDEN(void) rtThreadNativeDestroy(PRTTHREADINT pThread)
+{
+ NOREF(pThread);
+}
+
+
+/**
+ * Native thread main function.
+ *
+ * @param pvThreadInt The thread structure.
+ */
+static void rtThreadNativeMain(void *pvThreadInt)
+{
+ const struct thread *Self = curthread;
+ PRTTHREADINT pThreadInt = (PRTTHREADINT)pvThreadInt;
+ int rc;
+
+ rc = rtThreadMain(pThreadInt, (RTNATIVETHREAD)Self, &pThreadInt->szName[0]);
+
+#if __FreeBSD_version >= 800002
+ kproc_exit(rc);
+#else
+ kthread_exit(rc);
+#endif
+}
+
+
+DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThreadInt, PRTNATIVETHREAD pNativeThread)
+{
+ int rc;
+ struct proc *pProc;
+
+#if __FreeBSD_version >= 800002
+ rc = kproc_create(rtThreadNativeMain, pThreadInt, &pProc, RFHIGHPID, 0, "%s", pThreadInt->szName);
+#else
+ rc = kthread_create(rtThreadNativeMain, pThreadInt, &pProc, RFHIGHPID, 0, "%s", pThreadInt->szName);
+#endif
+ if (!rc)
+ {
+ *pNativeThread = (RTNATIVETHREAD)FIRST_THREAD_IN_PROC(pProc);
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = RTErrConvertFromErrno(rc);
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/time-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/time-r0drv-freebsd.c
new file mode 100644
index 00000000..21a17733
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/time-r0drv-freebsd.c
@@ -0,0 +1,98 @@
+/* $Id: time-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Time, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+#define RTTIME_INCL_TIMESPEC
+
+#include <iprt/time.h>
+
+
+RTDECL(uint64_t) RTTimeNanoTS(void)
+{
+ struct timespec tsp;
+ nanouptime(&tsp);
+ return tsp.tv_sec * RT_NS_1SEC_64
+ + tsp.tv_nsec;
+}
+
+
+RTDECL(uint64_t) RTTimeMilliTS(void)
+{
+ return RTTimeNanoTS() / RT_NS_1MS;
+}
+
+
+RTDECL(uint64_t) RTTimeSystemNanoTS(void)
+{
+ return RTTimeNanoTS();
+}
+
+
+RTDECL(uint64_t) RTTimeSystemMilliTS(void)
+{
+ return RTTimeMilliTS();
+}
+
+
+RTDECL(PRTTIMESPEC) RTTimeNow(PRTTIMESPEC pTime)
+{
+ struct timespec tsp;
+ nanotime(&tsp);
+ return RTTimeSpecSetTimespec(pTime, &tsp);
+}
+
diff --git a/src/VBox/Runtime/r0drv/freebsd/timer-r0drv-freebsd.c b/src/VBox/Runtime/r0drv/freebsd/timer-r0drv-freebsd.c
new file mode 100644
index 00000000..80f99373
--- /dev/null
+++ b/src/VBox/Runtime/r0drv/freebsd/timer-r0drv-freebsd.c
@@ -0,0 +1,310 @@
+/* $Id: timer-r0drv-freebsd.c $ */
+/** @file
+ * IPRT - Memory Allocation, Ring-0 Driver, FreeBSD.
+ */
+
+/*
+ * Contributed by knut st. osmundsen.
+ *
+ * Copyright (C) 2007-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ * --------------------------------------------------------------------
+ *
+ * This code is based on:
+ *
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-freebsd-kernel.h"
+
+#include <iprt/timer.h>
+#include <iprt/time.h>
+#include <iprt/spinlock.h>
+#include <iprt/err.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/alloc.h>
+
+#include "internal/magics.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * The internal representation of an FreeBSD timer handle.
+ */
+typedef struct RTTIMER
+{
+ /** Magic.
+ * This is RTTIMER_MAGIC, but changes to something else before the timer
+ * is destroyed to indicate clearly that thread should exit. */
+ uint32_t volatile u32Magic;
+ /** Flag indicating that the timer is suspended. */
+ uint8_t volatile fSuspended;
+ /** Whether the timer must run on a specific CPU or not. */
+ uint8_t fSpecificCpu;
+ /** The CPU it must run on if fSpecificCpu is set. */
+ uint32_t iCpu;
+ /** The FreeBSD callout structure. */
+ struct callout Callout;
+ /** Callback. */
+ PFNRTTIMER pfnTimer;
+ /** User argument. */
+ void *pvUser;
+ /** The timer interval. 0 if one-shot. */
+ uint64_t u64NanoInterval;
+ /** The start of the current run.
+ * This is used to calculate when the timer ought to fire the next time. */
+ uint64_t volatile u64StartTS;
+ /** The start of the current run.
+ * This is used to calculate when the timer ought to fire the next time. */
+ uint64_t volatile u64NextTS;
+ /** The current tick number (since u64StartTS). */
+ uint64_t volatile iTick;
+} RTTIMER;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static void rtTimerFreeBSDCallback(void *pvTimer);
+
+
+
+RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
+{
+ *ppTimer = NULL;
+
+ /*
+ * Validate flags.
+ */
+ if (!RTTIMER_FLAGS_ARE_VALID(fFlags))
+ return VERR_INVALID_PARAMETER;
+ if ( (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
+ && (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL
+ && (fFlags & RTTIMER_FLAGS_CPU_MASK) > mp_maxid)
+ return VERR_CPU_NOT_FOUND;
+
+ /*
+ * Allocate and initialize the timer handle.
+ */
+ PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
+ if (!pTimer)
+ return VERR_NO_MEMORY;
+
+ pTimer->u32Magic = RTTIMER_MAGIC;
+ pTimer->fSuspended = true;
+ pTimer->fSpecificCpu = !!(fFlags & RTTIMER_FLAGS_CPU_SPECIFIC);
+ pTimer->iCpu = fFlags & RTTIMER_FLAGS_CPU_MASK;
+ pTimer->pfnTimer = pfnTimer;
+ pTimer->pvUser = pvUser;
+ pTimer->u64NanoInterval = u64NanoInterval;
+ pTimer->u64StartTS = 0;
+ callout_init(&pTimer->Callout, CALLOUT_MPSAFE);
+
+ *ppTimer = pTimer;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Validates the timer handle.
+ *
+ * @returns true if valid, false if invalid.
+ * @param pTimer The handle.
+ */
+DECLINLINE(bool) rtTimerIsValid(PRTTIMER pTimer)
+{
+ AssertReturn(VALID_PTR(pTimer), false);
+ AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, false);
+ return true;
+}
+
+
+RTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
+{
+ /* It's ok to pass NULL pointer. */
+ if (pTimer == /*NIL_RTTIMER*/ NULL)
+ return VINF_SUCCESS;
+ if (!rtTimerIsValid(pTimer))
+ return VERR_INVALID_HANDLE;
+
+ /*
+ * Free the associated resources.
+ */
+ pTimer->u32Magic++;
+ callout_stop(&pTimer->Callout);
+ RTMemFree(pTimer);
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
+{
+ struct timeval tv;
+
+ if (!rtTimerIsValid(pTimer))
+ return VERR_INVALID_HANDLE;
+ if (!pTimer->fSuspended)
+ return VERR_TIMER_ACTIVE;
+ if ( pTimer->fSpecificCpu
+ && !RTMpIsCpuOnline(RTMpCpuIdFromSetIndex(pTimer->iCpu)))
+ return VERR_CPU_OFFLINE;
+
+ /*
+ * Calc when it should start firing.
+ */
+ u64First += RTTimeNanoTS();
+
+ pTimer->fSuspended = false;
+ pTimer->iTick = 0;
+ pTimer->u64StartTS = u64First;
+ pTimer->u64NextTS = u64First;
+
+ tv.tv_sec = u64First / 1000000000;
+ tv.tv_usec = (u64First % 1000000000) / 1000;
+ callout_reset(&pTimer->Callout, tvtohz(&tv), rtTimerFreeBSDCallback, pTimer);
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTTimerStop(PRTTIMER pTimer)
+{
+ if (!rtTimerIsValid(pTimer))
+ return VERR_INVALID_HANDLE;
+ if (pTimer->fSuspended)
+ return VERR_TIMER_SUSPENDED;
+
+ /*
+ * Suspend the timer.
+ */
+ pTimer->fSuspended = true;
+ callout_stop(&pTimer->Callout);
+
+ return VINF_SUCCESS;
+}
+
+
+RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
+{
+ if (!rtTimerIsValid(pTimer))
+ return VERR_INVALID_HANDLE;
+ return VERR_NOT_SUPPORTED;
+}
+
+
+/**
+ * smp_rendezvous action callback.
+ *
+ * This will perform the timer callback if we're on the right CPU.
+ *
+ * @param pvTimer The timer.
+ */
+static void rtTimerFreeBSDIpiAction(void *pvTimer)
+{
+ PRTTIMER pTimer = (PRTTIMER)pvTimer;
+ if ( pTimer->iCpu == RTTIMER_FLAGS_CPU_MASK
+ || (u_int)pTimer->iCpu == curcpu)
+ pTimer->pfnTimer(pTimer, pTimer->pvUser, pTimer->iTick);
+}
+
+
+static void rtTimerFreeBSDCallback(void *pvTimer)
+{
+ PRTTIMER pTimer = (PRTTIMER)pvTimer;
+
+ /* calculate and set the next timeout */
+ pTimer->iTick++;
+ if (!pTimer->u64NanoInterval)
+ {
+ pTimer->fSuspended = true;
+ callout_stop(&pTimer->Callout);
+ }
+ else
+ {
+ struct timeval tv;
+ const uint64_t u64NanoTS = RTTimeNanoTS();
+ pTimer->u64NextTS = pTimer->u64StartTS + pTimer->iTick * pTimer->u64NanoInterval;
+ if (pTimer->u64NextTS < u64NanoTS)
+ pTimer->u64NextTS = u64NanoTS + RTTimerGetSystemGranularity() / 2;
+
+ tv.tv_sec = pTimer->u64NextTS / 1000000000;
+ tv.tv_usec = (pTimer->u64NextTS % 1000000000) / 1000;
+ callout_reset(&pTimer->Callout, tvtohz(&tv), rtTimerFreeBSDCallback, pTimer);
+ }
+
+ /* callback */
+ if ( !pTimer->fSpecificCpu
+ || pTimer->iCpu == curcpu)
+ pTimer->pfnTimer(pTimer, pTimer->pvUser, pTimer->iTick);
+ else
+ smp_rendezvous(NULL, rtTimerFreeBSDIpiAction, NULL, pvTimer);
+}
+
+
+RTDECL(uint32_t) RTTimerGetSystemGranularity(void)
+{
+ return 1000000000 / hz; /* ns */
+}
+
+
+RTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted)
+{
+ return VERR_NOT_SUPPORTED;
+}
+
+
+RTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted)
+{
+ return VERR_NOT_SUPPORTED;
+}
+
+
+RTDECL(bool) RTTimerCanDoHighResolution(void)
+{
+ return false;
+}
+