diff --git a/core/include/config.h b/core/include/config.h index afaea13f..56dda6e5 100644 --- a/core/include/config.h +++ b/core/include/config.h @@ -65,7 +65,13 @@ struct config_t { }; #define HAX_MAX_VCPUS 16 + +#ifdef HAX_PLATFORM_NETBSD +// TODO: Handle 64 VMs +#define HAX_MAX_VMS 8 +#else // Matches the number of bits in vm_mid_bits (see vm.c) #define HAX_MAX_VMS 64 +#endif #endif // HAX_CORE_CONFIG_H_ diff --git a/include/hax.h b/include/hax.h index 444bcd2b..bde01262 100644 --- a/include/hax.h +++ b/include/hax.h @@ -269,6 +269,9 @@ int hax_em64t_enabled(void); #ifdef HAX_PLATFORM_LINUX #include "linux/hax_linux.h" #endif +#ifdef HAX_PLATFORM_NETBSD +#include "netbsd/hax_netbsd.h" +#endif #ifdef HAX_PLATFORM_WINDOWS #include "windows/hax_windows.h" #endif diff --git a/include/hax_interface.h b/include/hax_interface.h index 41efd2ba..5dd15d94 100644 --- a/include/hax_interface.h +++ b/include/hax_interface.h @@ -45,6 +45,9 @@ #ifdef HAX_PLATFORM_LINUX #include "linux/hax_interface_linux.h" #endif +#ifdef HAX_PLATFORM_NETBSD +#include "netbsd/hax_interface_netbsd.h" +#endif #ifdef HAX_PLATFORM_WINDOWS #include "windows/hax_interface_windows.h" #endif diff --git a/include/hax_types.h b/include/hax_types.h index 28dd6ffc..ed0f5108 100644 --- a/include/hax_types.h +++ b/include/hax_types.h @@ -78,6 +78,10 @@ #elif defined(__linux__) #define HAX_PLATFORM_LINUX #include "linux/hax_types_linux.h" +// NetBSD +#elif defined(__NetBSD__) +#define HAX_PLATFORM_NETBSD +#include "netbsd/hax_types_netbsd.h" // Windows #elif defined(_WIN32) #define HAX_PLATFORM_WINDOWS diff --git a/include/netbsd/hax_interface_netbsd.h b/include/netbsd/hax_interface_netbsd.h new file mode 100644 index 00000000..08bdb643 --- /dev/null +++ b/include/netbsd/hax_interface_netbsd.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2011 Intel Corporation + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAX_NETBSD_HAX_INTERFACE_NETBSD_H_ +#define HAX_NETBSD_HAX_INTERFACE_NETBSD_H_ + +#include +#include +#include +#include + +/* The mac specific interface to qemu because of mac's + * special handling like hax tunnel allocation etc */ +/* HAX model level ioctl */ +#define HAX_IOCTL_VERSION _IOWR(0, 0x20, struct hax_module_version) +#define HAX_IOCTL_CREATE_VM _IOWR(0, 0x21, uint32_t) +#define HAX_IOCTL_DESTROY_VM _IOW(0, 0x22, uint32_t) +#define HAX_IOCTL_CAPABILITY _IOR(0, 0x23, struct hax_capabilityinfo) +#define HAX_IOCTL_SET_MEMLIMIT _IOWR(0, 0x24, struct hax_set_memlimit) + +// Only for backward compatibility with old Qemu. +#define HAX_VM_IOCTL_VCPU_CREATE_ORIG _IOR(0, 0x80, int) + +#define HAX_VM_IOCTL_VCPU_CREATE _IOWR(0, 0x80, uint32_t) +#define HAX_VM_IOCTL_ALLOC_RAM _IOWR(0, 0x81, struct hax_alloc_ram_info) +#define HAX_VM_IOCTL_SET_RAM _IOWR(0, 0x82, struct hax_set_ram_info) +#define HAX_VM_IOCTL_VCPU_DESTROY _IOR(0, 0x83, uint32_t) +#define HAX_VM_IOCTL_ADD_RAMBLOCK _IOW(0, 0x85, struct hax_ramblock_info) +#define HAX_VM_IOCTL_SET_RAM2 _IOWR(0, 0x86, struct hax_set_ram_info2) +#define HAX_VM_IOCTL_PROTECT_RAM _IOWR(0, 0x87, struct hax_protect_ram_info) + +#define HAX_VCPU_IOCTL_RUN _IO(0, 0xc0) +#define HAX_VCPU_IOCTL_SET_MSRS _IOWR(0, 0xc1, struct hax_msr_data) +#define HAX_VCPU_IOCTL_GET_MSRS _IOWR(0, 0xc2, struct hax_msr_data) + +#define HAX_VCPU_IOCTL_SET_FPU _IOW(0, 0xc3, struct fx_layout) +#define HAX_VCPU_IOCTL_GET_FPU _IOR(0, 0xc4, struct fx_layout) + +#define HAX_VCPU_IOCTL_SETUP_TUNNEL _IOWR(0, 0xc5, struct hax_tunnel_info) +#define HAX_VCPU_IOCTL_INTERRUPT _IOWR(0, 0xc6, uint32_t) +#define HAX_VCPU_SET_REGS _IOWR(0, 0xc7, struct vcpu_state_t) +#define HAX_VCPU_GET_REGS _IOWR(0, 0xc8, struct vcpu_state_t) + +/* API 2.0 */ +#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION _IOW(0, 0x84, struct hax_qemu_version) + +#define HAX_IOCTL_VCPU_DEBUG _IOW(0, 0xc9, struct hax_debug_t) + +#ifdef _KERNEL +#define HAX_KERNEL64_CS 0x80 +#define HAX_KERNEL32_CS 0x08 + +#define is_compatible() 0 + +struct hax_vm_netbsd_t; + +struct hax_vm_softc { + device_t sc_dev; + struct hax_vm_netbsd_t *vm; +}; + +struct hax_vcpu_netbsd_t; + +struct hax_vcpu_softc { + device_t sc_dev; + struct hax_vcpu_netbsd_t *vcpu; +}; + +struct vm_t; + +typedef struct hax_vm_netbsd_t { + struct vm_t *cvm; + int id; +} hax_vm_netbsd_t; + +struct vcpu_t; + +typedef struct hax_vcpu_netbsd_t { + struct vcpu_t *cvcpu; + struct hax_vm_netbsd_t *vm; + int id; +} hax_vcpu_netbsd_t; + +#define unit2vmmid(u) (__SHIFTOUT(u, __BITS(4,6))) +#define unit2vcpuid(u) (__SHIFTOUT(u, __BITS(0,3))) + +#define vmvcpu2unit(vm,vcpu) (__SHIFTIN(vm, __BITS(4,6)) | vcpu) +#endif + +#endif // HAX_NETBSD_HAX_INTERFACE_NETBSD_H_ diff --git a/include/netbsd/hax_netbsd.h b/include/netbsd/hax_netbsd.h new file mode 100644 index 00000000..e333e2fd --- /dev/null +++ b/include/netbsd/hax_netbsd.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2011 Intel Corporation + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAX_NETBSD_HAX_NETBSD_H_ +#define HAX_NETBSD_HAX_NETBSD_H_ + +#define HAX_RAM_ENTRY_SIZE 0x4000000 + +hax_spinlock *hax_spinlock_alloc_init(void); +void hax_spinlock_free(hax_spinlock *lock); +void hax_spin_lock(hax_spinlock *lock); +void hax_spin_unlock(hax_spinlock *lock); + +hax_mutex hax_mutex_alloc_init(void); +void hax_mutex_lock(hax_mutex lock); +void hax_mutex_unlock(hax_mutex lock); +void hax_mutex_free(hax_mutex lock); + +/* Return true if the bit is set already */ +int hax_test_and_set_bit(int bit, uint64_t *memory); + +/* Return true if the bit is cleared already */ +int hax_test_and_clear_bit(int bit, uint64_t *memory); + +/* Don't care for the big endian situation */ +static inline bool hax_test_bit(int bit, uint64_t *memory) +{ + int byte = bit / 8; + unsigned char *p; + int offset = bit % 8; + + p = (unsigned char *)memory + byte; + return !!(*p & (1 << offset)); +} + +// memcpy_s() is part of the optional Bounds Checking Interfaces specified in +// Annex K of the C11 standard: +// http://en.cppreference.com/w/c/string/byte/memcpy +// However, it is not implemented by Clang: +// https://stackoverflow.com/questions/40829032/how-to-install-c11-compiler-on-mac-os-with-optional-string-functions-included +// Provide a simplified implementation here so memcpy_s() can be used instead of +// memcpy() everywhere else, which helps reduce the number of Klocwork warnings. +static inline int memcpy_s(void *dest, size_t destsz, const void *src, + size_t count) +{ + char *dest_start = (char *)dest; + char *dest_end = (char *)dest + destsz; + char *src_start = (char *)src; + char *src_end = (char *)src + count; + bool overlap; + + if (count == 0) + return 0; + + if (!dest || destsz == 0) + return -EINVAL; + + overlap = src_start < dest_start + ? dest_start < src_end : src_start < dest_end; + if (!src || count > destsz || overlap) { + memset(dest, 0, destsz); + return -EINVAL; + } + + memcpy(dest, src, count); + return 0; +} + +bool hax_cmpxchg32(uint32_t old_val, uint32_t new_val, volatile uint32_t *addr); +bool hax_cmpxchg64(uint64_t old_val, uint64_t new_val, volatile uint64_t *addr); + +static inline bool cpu_is_online(int cpu) +{ + if (cpu < 0 || cpu >= max_cpus) + return 0; + return !!(((mword)1 << cpu) & cpu_online_map); +} + +int hax_notify_host_event(enum hax_notify_event event, uint32_t *param, + uint32_t size); + +extern int default_hax_log_level; + +void hax_error(char *fmt, ...); +void hax_warning(char *fmt, ...); +void hax_info(char *fmt, ...); +void hax_debug(char *fmt, ...); +void hax_log(char *fmt, ...); + +#define hax_log hax_info + +#define hax_panic panic + +#define hax_assert(condition) KASSERT(condition) + +#endif // HAX_NETBSD_HAX_NETBSD_H_ diff --git a/include/netbsd/hax_types_netbsd.h b/include/netbsd/hax_types_netbsd.h new file mode 100644 index 00000000..599fd54c --- /dev/null +++ b/include/netbsd/hax_types_netbsd.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011 Intel Corporation + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAX_NETBSD_HAX_TYPES_NETBSD_H_ +#define HAX_NETBSD_HAX_TYPES_NETBSD_H_ + +#include +#include + +// Signed Types +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; + +// Unsigned Types +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned long ulong_t; + +#if defined(__i386__) +typedef uint32_t mword; +#endif +#if defined (__x86_64__) +typedef uint64_t mword; +#endif +typedef mword HAX_VADDR_T; + +#include "../hax_list.h" +struct hax_page { + void *kva; + struct vm_page *page; + struct pglist *pglist; + uint64_t pa; + uint32_t order; + uint32_t flags; + struct hax_link_list list; + size_t size; +}; + +typedef struct hax_memdesc_user { + vaddr_t uva; + vsize_t size; +} hax_memdesc_user; + +typedef struct hax_kmap_user { + vaddr_t kva; + vsize_t size; +} hax_kmap_user; + +typedef struct hax_memdesc_phys { + struct vm_page *page; +} hax_memdesc_phys; + +typedef struct hax_kmap_phys { + vaddr_t kva; +} hax_kmap_phys; + +typedef struct hax_spinlock hax_spinlock; + +typedef int hax_cpumap_t; + +static inline hax_cpumap_t cpu2cpumap(int cpu) +{ + return (0x1 << cpu); +} + +/* Remove this later */ +#define is_leaf(x) 1 + +typedef mword preempt_flag; +typedef kmutex_t *hax_mutex; +typedef uint32_t hax_atomic_t; + +/* Return the value before add */ +hax_atomic_t hax_atomic_add(volatile hax_atomic_t *atom, uint32_t value); + +/* Return the value before the increment */ +hax_atomic_t hax_atomic_inc(volatile hax_atomic_t *atom); + +/* Return the value before the decrement */ +hax_atomic_t hax_atomic_dec(volatile hax_atomic_t *atom); + +void hax_smp_mb(void); + +#endif // HAX_NETBSD_HAX_TYPES_NETBSD_H_ diff --git a/platforms/netbsd/.gitignore b/platforms/netbsd/.gitignore new file mode 100644 index 00000000..7f3794db --- /dev/null +++ b/platforms/netbsd/.gitignore @@ -0,0 +1,8 @@ +# Build +*.kmod.map +*.kmod +*~ +amd64 +i386 +machine +x86 diff --git a/platforms/netbsd/Makefile b/platforms/netbsd/Makefile new file mode 100644 index 00000000..09cf9e3f --- /dev/null +++ b/platforms/netbsd/Makefile @@ -0,0 +1,56 @@ +S?= /usr/src/sys + +KMOD= haxm + +# toplevel +SRCS+= components.c +SRCS+= hax_entry.c +SRCS+= hax_entry_hax.c +SRCS+= hax_entry_vcpu.c +SRCS+= hax_entry_vm.c +SRCS+= hax_event.c +SRCS+= hax_host_mem.c +SRCS+= hax_mem_alloc.c +SRCS+= hax_mm.c +SRCS+= hax_wrapper.c + +# core +.PATH: ../../core +SRCS+= chunk.c +SRCS+= cpu.c +SRCS+= cpuid.c +SRCS+= dump.c +SRCS+= emulate.c +SRCS+= ept.c +SRCS+= ept2.c +SRCS+= ept_tree.c +SRCS+= gpa_space.c +SRCS+= hax.c +SRCS+= ia32.c +SRCS+= intr_exc.c +SRCS+= memory.c +SRCS+= memslot.c +SRCS+= name.c +SRCS+= page_walker.c +SRCS+= ramblock.c +SRCS+= vcpu.c +SRCS+= vm.c +SRCS+= vmx.c +SRCS+= vtlb.c + +.if ${MACHINE} == "amd64" +TARGET_ELF= elf64 +.else +.error Not supported +.endif + +.SUFFIXES: .asm .o +.PATH.asm: ../../core +.asm.o: + nasm -f ${TARGET_ELF} -o ${.TARGET} ${.IMPSRC} + +SRCS+= emulate_ops.asm +SRCS+= ia32_ops.asm +SRCS+= vmx_ops.asm + +.include diff --git a/platforms/netbsd/components.c b/platforms/netbsd/components.c new file mode 100644 index 00000000..90122909 --- /dev/null +++ b/platforms/netbsd/components.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include +#include +#include + +#include "../../core/include/hax_core_interface.h" +#include "../../core/include/config.h" + +extern struct cfdriver hax_vm_cd; +extern struct cfdriver hax_vcpu_cd; + +/* Component management */ + +static hax_vcpu_netbsd_t *hax_vcpu_create_netbsd(struct vcpu_t *cvcpu, + hax_vm_netbsd_t *vm, + int vcpu_id) +{ + hax_vcpu_netbsd_t *vcpu; + + if (!cvcpu || !vm) + return NULL; + + vcpu = kmem_zalloc(sizeof(hax_vcpu_netbsd_t), KM_SLEEP); + vcpu->cvcpu = cvcpu; + vcpu->id = vcpu_id; + vcpu->vm = vm; + set_vcpu_host(cvcpu, vcpu); + return vcpu; +} + +static void hax_vcpu_destroy_netbsd(hax_vcpu_netbsd_t *vcpu) +{ + struct vcpu_t *cvcpu; + + if (!vcpu) + return; + + cvcpu = vcpu->cvcpu; + hax_vcpu_destroy_hax_tunnel(cvcpu); + set_vcpu_host(cvcpu, NULL); + vcpu->cvcpu = NULL; + kmem_free(vcpu, sizeof(hax_vcpu_netbsd_t)); +} + +int hax_vcpu_create_host(struct vcpu_t *cvcpu, void *vm_host, int vm_id, + int vcpu_id) +{ + int err; + hax_vcpu_netbsd_t *vcpu; + hax_vm_netbsd_t *vm; + struct hax_vcpu_softc *sc; + devminor_t minor; + + minor = vmvcpu2unit(vm_id, vcpu_id); + sc = device_lookup_private(&hax_vcpu_cd, minor); + if (!sc) { + hax_error("device lookup for hax_vcpu failed (minor %u)\n", minor); + return -1; + } + + vm = (hax_vm_netbsd_t *)vm_host; + vcpu = hax_vcpu_create_netbsd(cvcpu, vm, vcpu_id); + if (!vcpu) + return -1; + + vcpu->id = vcpu_id; + sc->vcpu = vcpu; + + hax_info("Created HAXM-VCPU device 'hax_vm%02d/vcpu%02d'\n", vm_id, vcpu_id); + return 0; +} + +int hax_vcpu_destroy_host(struct vcpu_t *cvcpu, void *vcpu_host) +{ + hax_vcpu_netbsd_t *vcpu; + struct hax_vcpu_softc *sc; + devminor_t minor; + + vcpu = (hax_vcpu_netbsd_t *)vcpu_host; + + minor = vmvcpu2unit(vcpu->vm->id, vcpu->id); + sc = device_lookup_private(&hax_vcpu_cd, minor); + if (!sc) { + hax_error("device lookup for hax_vcpu failed (minor %u)\n", minor); + return -1; + } + + hax_vcpu_destroy_netbsd(vcpu); + + sc->vcpu = NULL; + + return 0; +} + +static hax_vm_netbsd_t *hax_vm_create_netbsd(struct vm_t *cvm, int vm_id) +{ + hax_vm_netbsd_t *vm; + + if (!cvm) + return NULL; + + vm = kmem_zalloc(sizeof(hax_vm_netbsd_t), KM_SLEEP); + vm->cvm = cvm; + vm->id = vm_id; + set_vm_host(cvm, vm); + return vm; +} + +static void hax_vm_destroy_netbsd(hax_vm_netbsd_t *vm) +{ + struct vm_t *cvm; + struct hax_vm_softc *sc; + devminor_t minor; + + minor = vm->id; + sc = device_lookup_private(&hax_vm_cd, minor); + if (!sc) { + hax_error("device lookup for hax_vm failed (minor %u)\n", minor); + return; + } + + if (!vm) + return; + + cvm = vm->cvm; + set_vm_host(cvm, NULL); + vm->cvm = NULL; + hax_vm_free_all_ram(cvm); + kmem_free(vm, sizeof(hax_vm_netbsd_t)); + + sc->vm = NULL; +} + +int hax_vm_create_host(struct vm_t *cvm, int vm_id) +{ + int err; + hax_vm_netbsd_t *vm; + struct hax_vm_softc *sc; + devminor_t minor; + + minor = vm_id; + sc = device_lookup_private(&hax_vm_cd, minor); + if (!sc) { + hax_error("device lookup for hax_vm failed (minor %u)\n", minor); + return -1; + } + + vm = hax_vm_create_netbsd(cvm, vm_id); + if (!vm) + return -1; + + sc->vm = vm; + + hax_info("Created HAXM-VM device 'hax_vm/vm%02d'\n", vm_id); + return 0; +} + +/* When coming here, all vcpus should have been destroyed already. */ +int hax_vm_destroy_host(struct vm_t *cvm, void *vm_host) +{ + hax_vm_netbsd_t *vm; + + vm = (hax_vm_netbsd_t *)vm_host; + hax_vm_destroy_netbsd(vm); + + return 0; +} + +/* No corresponding function in netbsd side, it can be cleaned later. */ +int hax_destroy_host_interface(void) +{ + return 0; +} diff --git a/platforms/netbsd/hax_entry.c b/platforms/netbsd/hax_entry.c new file mode 100644 index 00000000..0a92da37 --- /dev/null +++ b/platforms/netbsd/hax_entry.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "../../core/include/config.h" +#include "../../core/include/hax_core_interface.h" +#include "../../include/hax.h" +#include "../../include/hax_interface.h" + +#define HAX_DEVICE_NAME "HAX" +#define HAX_VM_DEVICE_NAME "hax_vm" +#define HAX_VCPU_DEVICE_NAME "hax_vcpu" + +static int hax_cmajor = 220, hax_bmajor = -1; +static int hax_vm_cmajor = 222, hax_vm_bmajor = -1; +static int hax_vcpu_cmajor = 221, hax_vcpu_bmajor = -1; + +extern struct cdevsw hax_cdevsw; +extern struct cdevsw hax_vm_cdevsw; +extern struct cdevsw hax_vcpu_cdevsw; + +static int hax_vm_match(device_t, cfdata_t, void *); +static void hax_vm_attach(device_t, device_t, void *); +static int hax_vm_detach(device_t, int); + +CFATTACH_DECL_NEW(hax_vm, sizeof(struct hax_vm_softc), + hax_vm_match, hax_vm_attach, hax_vm_detach, NULL); + +static int hax_vcpu_match(device_t, cfdata_t, void *); +static void hax_vcpu_attach(device_t, device_t, void *); +static int hax_vcpu_detach(device_t, int); + +CFATTACH_DECL_NEW(hax_vcpu, sizeof(struct hax_vcpu_softc), + hax_vcpu_match, hax_vcpu_attach, hax_vcpu_detach, NULL); + +static int +hax_vm_match(device_t parent, cfdata_t match, void *aux) +{ + return 1; +} + +static void +hax_vm_attach(device_t parent, device_t self, void *aux) +{ + struct hax_vm_softc *sc; + int unit; + + sc = device_private(self); + if (sc == NULL) { + hax_error("device_private() for hax_vm failed\n"); + return; + } + + unit = device_unit(self); + + sc->sc_dev = self; + sc->vm = NULL; + + snprintf(self->dv_xname, sizeof self->dv_xname, "hax_vm/vm%02d", unit); + + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, "couldn't establish power handler\n"); +} + +static int +hax_vm_detach(device_t self, int flags) +{ + struct hax_vm_softc *sc; + + sc = device_private(self); + if (sc == NULL) { + hax_error("device_private() for hax_vm failed\n"); + return -ENODEV; + } + pmf_device_deregister(self); + + return 0; +} + +static int +hax_vcpu_match(device_t parent, cfdata_t match, void *aux) +{ + return 1; +} + +static void +hax_vcpu_attach(device_t parent, device_t self, void *aux) +{ + struct hax_vcpu_softc *sc; + int unit, vm_id, cpu_id; + + sc = device_private(self); + if (sc == NULL) { + hax_error("device_private() for hax_vcpu failed\n"); + return; + } + + unit = device_unit(self); + vm_id = unit2vmmid(unit); + cpu_id = unit2vcpuid(unit); + + sc->sc_dev = self; + sc->vcpu = NULL; + + snprintf(self->dv_xname, sizeof self->dv_xname, "hax_vm%02d/vcpu%02d", + vm_id, cpu_id); + + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, "couldn't establish power handler\n"); +} + +static int +hax_vcpu_detach(device_t self, int flags) +{ + struct hax_vcpu_softc *sc; + + sc = device_private(self); + if (sc == NULL) { + hax_error("device_private() for hax_vcpu failed\n"); + return -ENODEV; + } + pmf_device_deregister(self); + + return 0; +} + +static const struct cfiattrdata haxbus_iattrdata = { + "haxbus", 0, { { NULL, NULL, 0 },} +}; + +static const struct cfiattrdata *const hax_vm_attrs[] = { + &haxbus_iattrdata, NULL +}; + +CFDRIVER_DECL(hax_vm, DV_DULL, hax_vm_attrs); +extern struct cfattach hax_vm_ca; +static int hax_vmloc[] = { + -1, + -1, + -1 +}; + +static struct cfdata hax_vm_cfdata[] = { + { + .cf_name = "hax_vm", + .cf_atname = "hax_vm", + .cf_unit = 0, + .cf_fstate = FSTATE_STAR, + .cf_loc = hax_vmloc, + .cf_flags = 0, + .cf_pspec = NULL, + }, + { NULL, NULL, 0, FSTATE_NOTFOUND, NULL, 0, NULL } +}; + +static const struct cfiattrdata *const hax_vcpu_attrs[] = { + &haxbus_iattrdata, NULL +}; + +CFDRIVER_DECL(hax_vcpu, DV_DULL, hax_vcpu_attrs); +extern struct cfattach hax_vcpu_ca; +static int hax_vcpuloc[] = { + -1, + -1, + -1 +}; + +static struct cfdata hax_vcpu_cfdata[] = { + { + .cf_name = "hax_vcpu", + .cf_atname = "hax_vcpu", + .cf_unit = 0, + .cf_fstate = FSTATE_STAR, + .cf_loc = hax_vcpuloc, + .cf_flags = 0, + .cf_pspec = NULL, + }, + { NULL, NULL, 0, FSTATE_NOTFOUND, NULL, 0, NULL } +}; + +MODULE(MODULE_CLASS_MISC, haxm, NULL); + +static int +haxm_modcmd(modcmd_t cmd, void *arg __unused) +{ + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + int err; + size_t i; + + switch (cmd) { + case MODULE_CMD_INIT: { + // Initialization + max_cpus = 0; + + ci = NULL; + + for (CPU_INFO_FOREACH(cii, ci)) { + ++max_cpus; + if (!ISSET(ci->ci_schedstate.spc_flags, SPCF_OFFLINE)) { + cpu_online_map |= __BIT(ci->ci_cpuid); + } + } + + // Register hax_vm + err = config_cfdriver_attach(&hax_vm_cd); + if (err) { + hax_error("Unable to register cfdriver hax_vm\n"); + goto init_err1; + } + + err = config_cfattach_attach(hax_vm_cd.cd_name, &hax_vm_ca); + if (err) { + hax_error("Unable to register cfattch hax_vm\n"); + goto init_err2; + } + + err = config_cfdata_attach(hax_vm_cfdata, 1); + if (err) { + hax_error("Unable to register cfdata hax_vm\n"); + goto init_err3; + } + + // Register hax_vcpu + err = config_cfdriver_attach(&hax_vcpu_cd); + if (err) { + hax_error("Unable to register cfdriver hax_vcpu\n"); + goto init_err4; + } + + err = config_cfattach_attach(hax_vcpu_cd.cd_name, &hax_vcpu_ca); + if (err) { + hax_error("Unable to register cfattch hax_vcpu\n"); + goto init_err5; + } + + err = config_cfdata_attach(hax_vcpu_cfdata, 1); + if (err) { + hax_error("Unable to register cfdata hax_vcpu\n"); + goto init_err6; + } + + // Register device entries + err = devsw_attach(HAX_DEVICE_NAME, NULL, &hax_bmajor, &hax_cdevsw, + &hax_cmajor); + if (err) { + hax_error("Failed to register HAXM device\n"); + goto init_err7; + } + err = devsw_attach(HAX_VM_DEVICE_NAME, NULL, &hax_vm_bmajor, &hax_vm_cdevsw, + &hax_vm_cmajor); + if (err) { + hax_error("Failed to register HAXM VM device\n"); + goto init_err8; + } + err = devsw_attach(HAX_VCPU_DEVICE_NAME, NULL, &hax_vcpu_bmajor, &hax_vcpu_cdevsw, + &hax_vcpu_cmajor); + if (err) { + hax_error("Failed to register HAXM VCPU device\n"); + goto init_err9; + } + + for (i = 0; i < HAX_MAX_VMS; i++) + config_attach_pseudo(hax_vm_cfdata); + + for (i = 0; i < (HAX_MAX_VMS * HAX_MAX_VCPUS); i++) + config_attach_pseudo(hax_vcpu_cfdata); + + // Initialize HAXM + if (hax_module_init() < 0) { + hax_error("Failed to initialize HAXM module\n"); + goto init_err10; + } + + hax_info("Created HAXM device\n"); + return 0; + +init_err10: + devsw_detach(NULL, &hax_vcpu_cdevsw); +init_err9: + devsw_detach(NULL, &hax_vm_cdevsw); +init_err8: + devsw_detach(NULL, &hax_cdevsw); +init_err7: + config_cfdata_detach(hax_vcpu_cfdata); +init_err6: + config_cfattach_detach(hax_vcpu_cd.cd_name, &hax_vcpu_ca); +init_err5: + config_cfdriver_detach(&hax_vcpu_cd); +init_err4: + config_cfdata_detach(hax_vm_cfdata); +init_err3: + config_cfattach_detach(hax_vm_cd.cd_name, &hax_vm_ca); +init_err2: + config_cfdriver_detach(&hax_vm_cd); +init_err1: + return ENXIO; + } + case MODULE_CMD_FINI: { + if (hax_module_exit() < 0) { + hax_error("Failed to finalize HAXM module\n"); + return EBUSY; + } + + devsw_detach(NULL, &hax_vcpu_cdevsw); + devsw_detach(NULL, &hax_vm_cdevsw); + devsw_detach(NULL, &hax_cdevsw); + + config_cfdata_detach(hax_vcpu_cfdata); + config_cfattach_detach(hax_vcpu_cd.cd_name, &hax_vcpu_ca); + config_cfdriver_detach(&hax_vcpu_cd); + + config_cfdata_detach(hax_vm_cfdata); + config_cfattach_detach(hax_vm_cd.cd_name, &hax_vm_ca); + config_cfdriver_detach(&hax_vm_cd); + + hax_info("Removed HAXM device\n"); + return 0; + } + default: + return ENOTTY; + } +} diff --git a/platforms/netbsd/hax_entry_hax.c b/platforms/netbsd/hax_entry_hax.c new file mode 100644 index 00000000..630e2719 --- /dev/null +++ b/platforms/netbsd/hax_entry_hax.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../include/hax.h" +#include "../../include/hax_interface.h" +#include "../../include/hax_release_ver.h" +#include "../../core/include/hax_core_interface.h" +#include "../../core/include/config.h" + +dev_type_open(hax_open); +dev_type_close(hax_close); +dev_type_ioctl(hax_ioctl); + +struct cdevsw hax_cdevsw = { + .d_open = hax_open, + .d_close = hax_close, + .d_read = noread, + .d_write = nowrite, + .d_ioctl = hax_ioctl, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = nommap, + .d_kqfilter = nokqfilter, + .d_discard = nodiscard, + .d_flag = D_OTHER +}; + +int hax_open(dev_t dev __unused, int flags __unused, int mode __unused, + struct lwp *l __unused) +{ + hax_log_level(HAX_LOGI, "HAX module opened\n"); + return 0; +} + +int hax_close(dev_t self __unused, int flag __unused, int mode __unused, + struct lwp *l __unused) +{ + hax_log_level(HAX_LOGI, "hax_close\n"); + return 0; +} + +int hax_ioctl(dev_t self __unused, u_long cmd, void *data, int flag, + struct lwp *l) +{ + int ret = 0; + + switch (cmd) { + case HAX_IOCTL_VERSION: { + struct hax_module_version *version; + version = (struct hax_module_version *)data; + version->cur_version = HAX_CUR_VERSION; + version->compat_version = HAX_COMPAT_VERSION; + break; + } + case HAX_IOCTL_CAPABILITY: { + struct hax_capabilityinfo *capab; + capab = (struct hax_capabilityinfo *)data; + hax_get_capability(capab, sizeof(*capab), NULL); + break; + } + case HAX_IOCTL_SET_MEMLIMIT: { + struct hax_set_memlimit *memlimit; + memlimit = (struct hax_set_memlimit *)data; + ret = hax_set_memlimit(memlimit, sizeof(*memlimit), NULL); + break; + } + case HAX_IOCTL_CREATE_VM: { + int vm_id; + struct vm_t *cvm; + + cvm = hax_create_vm(&vm_id); + if (!cvm) { + hax_log_level(HAX_LOGE, "Failed to create the HAX VM\n"); + ret = -ENOMEM; + break; + } + + *((uint32_t *)data) = vm_id; + break; + } + default: + hax_error("Unknown ioctl %#lx, pid=%d ('%s')\n", cmd, + l->l_proc->p_pid, l->l_proc->p_comm); + ret = -ENOSYS; + break; + } + return ret; +} diff --git a/platforms/netbsd/hax_entry_vcpu.c b/platforms/netbsd/hax_entry_vcpu.c new file mode 100644 index 00000000..c1b83b4e --- /dev/null +++ b/platforms/netbsd/hax_entry_vcpu.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "../../core/include/hax_core_interface.h" + +extern struct cfdriver hax_vcpu_cd; + +dev_type_open(hax_vcpu_open); +dev_type_close(hax_vcpu_close); +dev_type_ioctl(hax_vcpu_ioctl); + +struct cdevsw hax_vcpu_cdevsw = { + .d_open = hax_vcpu_open, + .d_close = hax_vcpu_close, + .d_read = noread, + .d_write = nowrite, + .d_ioctl = hax_vcpu_ioctl, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = nommap, + .d_kqfilter = nokqfilter, + .d_discard = nodiscard, + .d_flag = D_OTHER +}; + +/* VCPU operations */ + +int hax_vcpu_open(dev_t self, int flag __unused, int mode __unused, + struct lwp *l __unused) +{ + struct hax_vcpu_softc *sc; + struct vcpu_t *cvcpu; + struct hax_vcpu_netbsd_t *vcpu; + int ret; + int unit, vm_id, vcpu_id; + + sc = device_lookup_private(&hax_vcpu_cd, minor(self)); + if (sc == NULL) { + hax_error("device_lookup_private() for hax_vcpu failed\n"); + return -ENODEV; + } + + vcpu = sc->vcpu; + + unit = device_unit(sc->sc_dev); + vm_id = unit2vmmid(unit); + vcpu_id = unit2vcpuid(unit); + + if (!vcpu) { + hax_error("HAX VCPU 'hax_vm%02d/vcpu%02d' is not ready\n", vm_id, vcpu_id); + return -ENODEV; + } + + hax_assert(vcpu->vm->id == vm_id); + hax_assert(vcpu->id == vcpu_id); + + cvcpu = hax_get_vcpu(vcpu->vm->id, vcpu->id, 1); + + hax_log_level(HAX_LOGD, "HAX VM%02d vcpu%02d open called\n", vcpu->vm->id, vcpu->id); + if (!cvcpu) + return -ENODEV; + + ret = hax_vcpu_core_open(cvcpu); + if (ret) + hax_error("Failed to open core vcpu\n"); + hax_put_vcpu(cvcpu); + return ret; +} + +int hax_vcpu_close(dev_t self, int flag __unused, int mode __unused, + struct lwp *l __unused) +{ + struct hax_vcpu_softc *sc; + struct vcpu_t *cvcpu; + struct hax_vcpu_netbsd_t *vcpu; + + sc = device_lookup_private(&hax_vcpu_cd, minor(self)); + if (sc == NULL) { + hax_error("device_lookup_private() for hax_vcpu failed\n"); + return -ENODEV; + } + vcpu = sc->vcpu; + cvcpu = hax_get_vcpu(vcpu->vm->id, vcpu->id, 1); + + hax_log_level(HAX_LOGD, "HAX VM%02d vcpu%02d close called\n", vcpu->vm->id, vcpu->id); + if (!cvcpu) { + hax_error("Failed to find the vcpu, is it closed already?\n"); + return 0; + } + + /* put the one for vcpu create */ + hax_put_vcpu(cvcpu); + /* put the one just held */ + hax_put_vcpu(cvcpu); + + return 0; +} + +int hax_vcpu_ioctl(dev_t self, u_long cmd, void *data, int flag, + struct lwp *l __unused) +{ + int ret = 0; + struct hax_vcpu_softc *sc; + struct vcpu_t *cvcpu; + struct hax_vcpu_netbsd_t *vcpu; + + sc = device_lookup_private(&hax_vcpu_cd, minor(self)); + if (sc == NULL) { + hax_error("device_lookup_private() for hax_vcpu failed\n"); + return -ENODEV; + } + vcpu = sc->vcpu; + cvcpu = hax_get_vcpu(vcpu->vm->id, vcpu->id, 1); + + if (!cvcpu) + return -ENODEV; + + switch (cmd) { + case HAX_VCPU_IOCTL_RUN: + ret = vcpu_execute(cvcpu); + break; + case HAX_VCPU_IOCTL_SETUP_TUNNEL: { + struct hax_tunnel_info *info; + info = (struct hax_tunnel_info *)data; + ret = hax_vcpu_setup_hax_tunnel(cvcpu, info); + break; + } + case HAX_VCPU_IOCTL_SET_MSRS: { + struct hax_msr_data *msrs; + msrs = (struct hax_msr_data *)data; + struct vmx_msr *msr; + int i, fail; + + msr = msrs->entries; + /* nr_msr needs to be verified */ + if (msrs->nr_msr >= 0x20) { + hax_error("MSRS invalid!\n"); + ret = -EFAULT; + break; + } + for (i = 0; i < msrs->nr_msr; i++, msr++) { + fail = vcpu_set_msr(cvcpu, msr->entry, msr->value); + if (fail) { + break; + } + } + msrs->done = i; + break; + } + case HAX_VCPU_IOCTL_GET_MSRS: { + struct hax_msr_data *msrs; + msrs = (struct hax_msr_data *)data; + struct vmx_msr *msr; + int i, fail; + + msr = msrs->entries; + if(msrs->nr_msr >= 0x20) { + hax_error("MSRS invalid!\n"); + ret = -EFAULT; + break; + } + for (i = 0; i < msrs->nr_msr; i++, msr++) { + fail = vcpu_get_msr(cvcpu, msr->entry, &msr->value); + if (fail) { + break; + } + } + msrs->done = i; + break; + } + case HAX_VCPU_IOCTL_SET_FPU: { + struct fx_layout *fl; + fl = (struct fx_layout *)data; + ret = vcpu_put_fpu(cvcpu, fl); + break; + } + case HAX_VCPU_IOCTL_GET_FPU: { + struct fx_layout *fl; + fl = (struct fx_layout *)data; + ret = vcpu_get_fpu(cvcpu, fl); + break; + } + case HAX_VCPU_SET_REGS: { + struct vcpu_state_t *vc_state; + vc_state = (struct vcpu_state_t *)data; + ret = vcpu_set_regs(cvcpu, vc_state); + break; + } + case HAX_VCPU_GET_REGS: { + struct vcpu_state_t *vc_state; + vc_state = (struct vcpu_state_t *)data; + ret = vcpu_get_regs(cvcpu, vc_state); + break; + } + case HAX_VCPU_IOCTL_INTERRUPT: { + uint8_t *vector; + vector = (uint8_t *)data; + vcpu_interrupt(cvcpu, *vector); + break; + } + case HAX_IOCTL_VCPU_DEBUG: { + struct hax_debug_t *hax_debug; + hax_debug = (struct hax_debug_t *)data; + vcpu_debug(cvcpu, hax_debug); + break; + } + default: + // TODO: Print information about the process that sent the ioctl. + hax_error("Unknown VCPU IOCTL %#lx, pid=%d ('%s')\n", cmd, + l->l_proc->p_pid, l->l_proc->p_comm); + ret = -ENOSYS; + break; + } + hax_put_vcpu(cvcpu); + return ret; +} diff --git a/platforms/netbsd/hax_entry_vm.c b/platforms/netbsd/hax_entry_vm.c new file mode 100644 index 00000000..007e2d61 --- /dev/null +++ b/platforms/netbsd/hax_entry_vm.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "../../core/include/hax_core_interface.h" + +extern struct cfdriver hax_vm_cd; + +dev_type_open(hax_vm_open); +dev_type_close(hax_vm_close); +dev_type_ioctl(hax_vm_ioctl); + +struct cdevsw hax_vm_cdevsw = { + .d_open = hax_vm_open, + .d_close = hax_vm_close, + .d_read = noread, + .d_write = nowrite, + .d_ioctl = hax_vm_ioctl, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = nommap, + .d_kqfilter = nokqfilter, + .d_discard = nodiscard, + .d_flag = D_OTHER +}; + +int hax_vm_open(dev_t self, int flag __unused, int mode __unused, + struct lwp *l __unused) +{ + struct hax_vm_softc *sc; + struct vm_t *cvm; + struct hax_vm_netbsd_t *vm; + int unit; + int ret; + + sc = device_lookup_private(&hax_vm_cd, minor(self)); + if (sc == NULL) { + hax_error("device_lookup_private() for hax_vm failed\n"); + return -ENODEV; + } + + vm = sc->vm; + + unit = device_unit(sc->sc_dev); + + if (!vm) { + hax_error("HAX VM 'hax_vm/vm%02d' is not ready\n", unit); + return -ENODEV; + } + + hax_assert(unit == vm->id); + + cvm = hax_get_vm(vm->id, 1); + if (!cvm) + return -ENODEV; + + ret = hax_vm_core_open(cvm); + hax_put_vm(cvm); + hax_log_level(HAX_LOGI, "Open VM%02d\n", vm->id); + return ret; +} + +int hax_vm_close(dev_t self __unused, int flag __unused, int mode __unused, + struct lwp *l __unused) +{ + struct hax_vm_softc *sc; + struct vm_t *cvm; + struct hax_vm_netbsd_t *vm; + + sc = device_lookup_private(&hax_vm_cd, minor(self)); + if (sc == NULL) { + hax_error("device_lookup_private() for hax_vm failed\n"); + return -ENODEV; + } + + vm = sc->vm; + cvm = hax_get_vm(vm->id, 1); + + hax_log_level(HAX_LOGI, "Close VM%02d\n", vm->id); + if (cvm) { + /* put the ref get just now */ + hax_put_vm(cvm); + hax_put_vm(cvm); + } + return 0; +} + +int hax_vm_ioctl(dev_t self __unused, u_long cmd, void *data, int flag, + struct lwp *l __unused) +{ + int ret = 0; + struct vm_t *cvm; + struct hax_vm_netbsd_t *vm; + struct hax_vm_softc *sc; + + sc = device_lookup_private(&hax_vm_cd, minor(self)); + if (sc == NULL) { + hax_error("device_lookup_private() for hax_vm failed\n"); + return -ENODEV; + } + vm = sc->vm; + cvm = hax_get_vm(vm->id, 1); + if (!cvm) + return -ENODEV; + + switch (cmd) { + case HAX_VM_IOCTL_VCPU_CREATE: + case HAX_VM_IOCTL_VCPU_CREATE_ORIG: { + uint32_t *vcpu_id, vm_id; + vcpu_id = (uint32_t *)data; + struct vcpu_t *cvcpu; + + vm_id = vm->id; + cvcpu = vcpu_create(cvm, vm, *vcpu_id); + if (!cvcpu) { + hax_error("Failed to create vcpu %x on vm %x\n", *vcpu_id, vm_id); + ret = -EINVAL; + break; + } + break; + } + case HAX_VM_IOCTL_ALLOC_RAM: { + struct hax_alloc_ram_info *info; + info = (struct hax_alloc_ram_info *)data; + hax_info("IOCTL_ALLOC_RAM: vm_id=%d, va=0x%llx, size=0x%x, pad=0x%x\n", + vm->id, info->va, info->size, info->pad); + ret = hax_vm_add_ramblock(cvm, info->va, info->size); + break; + } + case HAX_VM_IOCTL_ADD_RAMBLOCK: { + struct hax_ramblock_info *info; + info = (struct hax_ramblock_info *)data; + if (info->reserved) { + hax_error("IOCTL_ADD_RAMBLOCK: vm_id=%d, reserved=0x%llx\n", + vm->id, info->reserved); + ret = -EINVAL; + break; + } + hax_info("IOCTL_ADD_RAMBLOCK: vm_id=%d, start_va=0x%llx, size=0x%llx\n", + vm->id, info->start_va, info->size); + ret = hax_vm_add_ramblock(cvm, info->start_va, info->size); + break; + } + case HAX_VM_IOCTL_SET_RAM: { + struct hax_set_ram_info *info; + info = (struct hax_set_ram_info *)data; + ret = hax_vm_set_ram(cvm, info); + break; + } +#ifdef CONFIG_HAX_EPT2 + case HAX_VM_IOCTL_SET_RAM2: { + struct hax_set_ram_info2 *info; + info = (struct hax_set_ram_info2 *)data; + if (info->reserved1 || info->reserved2) { + hax_error("IOCTL_SET_RAM2: vm_id=%d, reserved1=0x%x reserved2=0x%llx\n", + vm->id, info->reserved1, info->reserved2); + ret = -EINVAL; + break; + } + ret = hax_vm_set_ram2(cvm, info); + break; + } + case HAX_VM_IOCTL_PROTECT_RAM: { + struct hax_protect_ram_info *info; + info = (struct hax_protect_ram_info *)data; + if (info->reserved) { + hax_error("IOCTL_PROTECT_RAM: vm_id=%d, reserved=0x%x\n", + vm->id, info->reserved); + ret = -EINVAL; + break; + } + ret = hax_vm_protect_ram(cvm, info); + break; + } +#endif + case HAX_VM_IOCTL_NOTIFY_QEMU_VERSION: { + struct hax_qemu_version *info; + info = (struct hax_qemu_version *)data; + // TODO: Print information about the process that sent the ioctl. + ret = hax_vm_set_qemuversion(cvm, info); + break; + } + default: + // TODO: Print information about the process that sent the ioctl. + hax_error("Unknown VM IOCTL %#lx, pid=%d ('%s')\n", cmd, + l->l_proc->p_pid, l->l_proc->p_comm); + break; + } + hax_put_vm(cvm); + return ret; +} diff --git a/platforms/netbsd/hax_event.c b/platforms/netbsd/hax_event.c new file mode 100644 index 00000000..885c771c --- /dev/null +++ b/platforms/netbsd/hax_event.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "../../include/hax.h" + +int hax_notify_host_event(enum hax_notify_event event, uint32_t *param, + uint32_t size) +{ + return 0; +} diff --git a/platforms/netbsd/hax_host_mem.c b/platforms/netbsd/hax_host_mem.c new file mode 100644 index 00000000..d408f845 --- /dev/null +++ b/platforms/netbsd/hax_host_mem.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define __HAVE_DIRECT_MAP + +#include +#include +#include +#include +#include + +#include "../../include/hax_host_mem.h" +#include "../../core/include/paging.h" + +int hax_pin_user_pages(uint64_t start_uva, uint64_t size, hax_memdesc_user *memdesc) +{ + if (start_uva & PAGE_MASK) { + hax_error("Failed 'start_uva & ~PAGE_MASK', start_uva=%llx\n", start_uva); + return -EINVAL; + } + if (!size) { + hax_error("Failed '!size'\n"); + return -EINVAL; + } + + uvm_vslock(curproc->p_vmspace, (void *)start_uva, size, VM_PROT_READ | VM_PROT_WRITE); + + memdesc->uva = start_uva; + memdesc->size = size; + return 0; +} + +int hax_unpin_user_pages(hax_memdesc_user *memdesc) +{ + vsize_t size; + vaddr_t uva; + + if (!memdesc) + return -EINVAL; + if (!memdesc->size) + return -EINVAL; + if (!memdesc->uva) + return -EINVAL; + + size = memdesc->size; + uva = memdesc->uva; + + uvm_vsunlock(curproc->p_vmspace, (void *)uva, size); + + return 0; +} + +uint64_t hax_get_pfn_user(hax_memdesc_user *memdesc, uint64_t uva_offset) +{ + struct vm_map *map; + vsize_t size; + vaddr_t uva; + paddr_t pa; + + if (!memdesc) + return -EINVAL; + if (!memdesc->size) + return -EINVAL; + if (!memdesc->uva) + return -EINVAL; + + size = memdesc->size; + uva = memdesc->uva; + + if (uva_offset > size) + return -EINVAL; + + map = &curproc->p_vmspace->vm_map; + + if (!pmap_extract(map->pmap, uva + uva_offset, &pa)) + return -EINVAL; + + return (pa >> PAGE_SHIFT); +} + +void * hax_map_user_pages(hax_memdesc_user *memdesc, uint64_t uva_offset, + uint64_t size, hax_kmap_user *kmap) +{ + struct vm_map *map; + struct vm_page *page; + vaddr_t uva, va, va2, end_va; + vaddr_t kva; + paddr_t pa; + int err; + + if (!memdesc) + return NULL; + if (!memdesc->size) + return NULL; + if (!memdesc->uva) + return NULL; + if (!kmap) + return NULL; + if (!size) + return NULL; + if (size + uva_offset > memdesc->size) + return NULL; + + uva = trunc_page(memdesc->uva + uva_offset); + size = round_page(size); + + map = &curproc->p_vmspace->vm_map; + + kva = uvm_km_alloc(kernel_map, size, PAGE_SIZE, UVM_KMF_VAONLY|UVM_KMF_WAITVA); + + for (va = uva, end_va = uva + size, va2 = kva; va < end_va; va += PAGE_SIZE, va2 += PAGE_SIZE) { + if (!pmap_extract(map->pmap, va, &pa)) + break; + pmap_kenter_pa(va2, pa, VM_PROT_READ | VM_PROT_WRITE, PMAP_WIRED); + } + pmap_update(pmap_kernel()); + + kmap->kva = kva; + kmap->size = size; + return (void *)kva; +} + +int hax_unmap_user_pages(hax_kmap_user *kmap) +{ + vaddr_t kva; + vsize_t size; + + if (!kmap) + return -EINVAL; + if (!kmap->kva) + return -EINVAL; + if (!kmap->size) + return -EINVAL; + + kva = kmap->kva; + size = kmap->size; + + pmap_kremove(kva, size); + pmap_update(pmap_kernel()); + + uvm_km_free(kernel_map, kva, size, UVM_KMF_VAONLY); + + return 0; +} + +int hax_alloc_page_frame(uint8_t flags, hax_memdesc_phys *memdesc) +{ + if (!memdesc) + return -EINVAL; + + // TODO: Support HAX_PAGE_ALLOC_BELOW_4G + if (flags & HAX_PAGE_ALLOC_BELOW_4G) { + hax_warning("%s: HAX_PAGE_ALLOC_BELOW_4G is ignored\n", __func__); + } + + memdesc->page = uvm_pagealloc(NULL, 0, NULL, ISSET(flags, HAX_PAGE_ALLOC_ZEROED) ? UVM_PGA_ZERO : 0); + + return 0; +} + +int hax_free_page_frame(hax_memdesc_phys *memdesc) +{ + if (!memdesc) + return -EINVAL; + if (!memdesc->page) + return -EINVAL; + + uvm_pagefree(memdesc->page); + + memdesc->page = NULL; + + return 0; +} + +uint64_t hax_get_pfn_phys(hax_memdesc_phys *memdesc) +{ + if (!memdesc) + return INVALID_PFN; + if (!memdesc->page) + return INVALID_PFN; + + return VM_PAGE_TO_PHYS(memdesc->page) >> PAGE_SHIFT; +} + +void * hax_get_kva_phys(hax_memdesc_phys *memdesc) +{ + if (!memdesc) + return NULL; + if (!memdesc->page) + return NULL; + + return (void *)(PMAP_MAP_POOLPAGE(VM_PAGE_TO_PHYS(memdesc->page))); +} + +void * hax_map_page_frame(uint64_t pfn, hax_kmap_phys *kmap) +{ + vaddr_t kva; + paddr_t pa; + struct vm_page *ppage; + + if (!kmap) + return NULL; + + kva = uvm_km_alloc(kernel_map, PAGE_SIZE, PAGE_SIZE, UVM_KMF_VAONLY|UVM_KMF_WAITVA); + + pa = pfn << PAGE_SHIFT; + + pmap_kenter_pa(kva, pa, VM_PROT_READ | VM_PROT_WRITE, PMAP_WIRED); + pmap_update(pmap_kernel()); + + kmap->kva = kva; + return (void *)kva; +} + +int hax_unmap_page_frame(hax_kmap_phys *kmap) +{ + if (!kmap) + return -EINVAL; + if (!kmap->kva) + return -EINVAL; + + pmap_kremove(kmap->kva, PAGE_SIZE); + pmap_update(pmap_kernel()); + + uvm_km_free(kernel_map, kmap->kva, PAGE_SIZE, UVM_KMF_VAONLY); + + return 0; +} diff --git a/platforms/netbsd/hax_mem_alloc.c b/platforms/netbsd/hax_mem_alloc.c new file mode 100644 index 00000000..e6a97b94 --- /dev/null +++ b/platforms/netbsd/hax_mem_alloc.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "../../include/hax.h" + +void * hax_vmalloc(uint32_t size, uint32_t flags) +{ + vaddr_t kva; + uvm_flag_t flag; + + if (size == 0) + return NULL; + +#if 0 + if (flags & HAX_MEM_PAGABLE) + flag = UVM_KMF_PAGEABLE; + else if (flags & HAX_MEM_NONPAGE) +#endif + flag = UVM_KMF_WIRED | UVM_KMF_ZERO; + + flag |= UVM_KMF_WAITVA; + + kva = uvm_km_alloc(kernel_map, size, PAGE_SIZE, flag); + + return (void *)kva; +} + +void hax_vfree_flags(void *va, uint32_t size, uint32_t flags) +{ + uvm_flag_t flag; + +#if 0 + if (flags & HAX_MEM_PAGABLE) + flag = UVM_KMF_PAGEABLE; + else if (flags & HAX_MEM_NONPAGE) +#endif + flag = UVM_KMF_WIRED; + + uvm_km_free(kernel_map, (vaddr_t)va, size, flag); +} + +void hax_vfree(void *va, uint32_t size) +{ + uint32_t flags = HAX_MEM_NONPAGE; + + hax_vfree_flags(va, size, flags); +} + +void hax_vfree_aligned(void *va, uint32_t size, uint32_t alignment, + uint32_t flags) +{ + hax_vfree_flags(va, size, flags); +} + +void * hax_vmap(hax_pa_t pa, uint32_t size) +{ + vaddr_t kva; + vaddr_t va, end_va; + unsigned long offset; + + offset = pa & PAGE_MASK; + pa = trunc_page(pa); + size = round_page(size + offset); + + kva = uvm_km_alloc(kernel_map, size, PAGE_SIZE, UVM_KMF_VAONLY|UVM_KMF_WAITVA); + + for (va = kva, end_va = kva + size; va < end_va; va += PAGE_SIZE, pa += PAGE_SIZE) { + pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE, PMAP_WIRED); + } + pmap_update(pmap_kernel()); + + return (void *)(kva + offset); +} + +void hax_vunmap(void *addr, uint32_t size) +{ + unsigned long offset; + vaddr_t kva = (vaddr_t)addr; + + offset = kva & PAGE_MASK; + size = round_page(size + offset); + kva = trunc_page(kva); + + pmap_kremove(kva, size); + pmap_update(pmap_kernel()); + + uvm_km_alloc(kernel_map, kva, size, UVM_KMF_VAONLY); +} + +hax_pa_t hax_pa(void *va) +{ + bool success; + paddr_t pa; + + success = pmap_extract(pmap_kernel(), (vaddr_t)va, &pa); + + KASSERT(success); + + return pa; +} + +struct hax_page * hax_alloc_pages(int order, uint32_t flags, bool vmap) +{ + struct hax_page *ppage; + struct vm_page *page; + paddr_t pa; + vaddr_t kva, va; + size_t size; + int rv; + + ppage = kmem_zalloc(sizeof(struct hax_page), KM_SLEEP); + + // TODO: Support HAX_MEM_LOW_4G + if (flags & HAX_MEM_LOW_4G) { + hax_warning("%s: HAX_MEM_LOW_4G is ignored\n", __func__); + } + + ppage->pglist = kmem_zalloc(sizeof(struct pglist), KM_SLEEP); + + size = PAGE_SIZE << order; + + rv = uvm_pglistalloc(size, 0, ~0UL, PAGE_SIZE, 0, ppage->pglist, 1, 1); + if (rv) { + kmem_free(ppage->pglist, sizeof(struct pglist)); + kmem_free(ppage, sizeof(struct hax_page)); + return NULL; + } + + kva = uvm_km_alloc(kernel_map, size, PAGE_SIZE, UVM_KMF_VAONLY); + if (kva == 0) { + uvm_pglistfree(ppage->pglist); + kmem_free(ppage->pglist, sizeof(struct pglist)); + kmem_free(ppage, sizeof(struct hax_page)); + return NULL; + } + + va = kva; + TAILQ_FOREACH(page, ppage->pglist, pageq.queue) { + pa = VM_PAGE_TO_PHYS(page); + pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE, PMAP_WRITE_BACK); + va += PAGE_SIZE; + } + pmap_update(pmap_kernel()); + + ppage->page = TAILQ_FIRST(ppage->pglist); + ppage->pa = VM_PAGE_TO_PHYS(ppage->page); + ppage->kva = (void *)kva; + ppage->flags = flags; + ppage->order = order; + return ppage; +} + +void hax_free_pages(struct hax_page *pages) +{ + size_t size; + + if (!pages) + return; + + size = PAGE_SIZE << pages->order; + + pmap_kremove((vaddr_t)pages->kva, size); + pmap_update(pmap_kernel()); + uvm_km_free(kernel_map, (vaddr_t)pages->kva, size, UVM_KMF_VAONLY); + uvm_pglistfree(pages->pglist); + kmem_free(pages->pglist, sizeof(struct pglist)); + kmem_free(pages, sizeof(struct hax_page)); +} + +void * hax_map_page(struct hax_page *page) +{ + if (!page) + return NULL; + + return page->kva; +} + +void hax_unmap_page(struct hax_page *page) +{ + return; +} + +hax_pfn_t hax_page2pfn(struct hax_page *page) +{ + if (!page) + return 0; + + return page->pa >> PAGE_SHIFT; +} + +void hax_clear_page(struct hax_page *page) +{ + memset((void *)page->kva, 0, PAGE_SIZE); +} + +void hax_set_page(struct hax_page *page) +{ + memset((void *)page->kva, 0xFF, PAGE_SIZE); +} + +/* Initialize memory allocation related structures */ +int hax_malloc_init(void) +{ + return 0; +} + +void hax_malloc_exit(void) +{ +} diff --git a/platforms/netbsd/hax_mm.c b/platforms/netbsd/hax_mm.c new file mode 100644 index 00000000..8b377f3e --- /dev/null +++ b/platforms/netbsd/hax_mm.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "../../include/hax.h" + +struct hax_vcpu_mem_hinfo_t { + struct uvm_object *uao; + int flags; +}; + +int hax_clear_vcpumem(struct hax_vcpu_mem *mem) +{ + struct hax_vcpu_mem_hinfo_t *hinfo; + struct vm_map *map; + vaddr_t uva, kva; + vsize_t size; + + if (!mem) + return -EINVAL; + + hinfo = mem->hinfo; + + uva = mem->uva; + kva = (vaddr_t)mem->kva; + size = mem->size; + + if (!ISSET(hinfo->flags, HAX_VCPUMEM_VALIDVA)) { + map = &curproc->p_vmspace->vm_map; + uvm_unmap(map, uva, uva + size); + } + + uvm_unmap(kernel_map, kva, kva + size); + + if (!ISSET(hinfo->flags, HAX_VCPUMEM_VALIDVA)) { + uao_detach(hinfo->uao); + } + + kmem_free(hinfo, sizeof(struct hax_vcpu_mem_hinfo_t)); + + return 0; +} + +int hax_setup_vcpumem(struct hax_vcpu_mem *mem, uint64_t uva, uint32_t size, + int flags) +{ + struct proc *p; + struct uvm_object *uao; + struct vm_map *map; + int err; + struct hax_vcpu_mem_hinfo_t *hinfo = NULL; + vaddr_t kva, kva2; + vaddr_t va, end_va; + paddr_t pa; + unsigned offset; + + if (!mem || !size) + return -EINVAL; + + offset = uva & PAGE_MASK; + size = round_page(size + offset); + uva = trunc_page(uva); + + hinfo = kmem_zalloc(sizeof(struct hax_vcpu_mem_hinfo_t), KM_SLEEP); + hinfo->flags = flags; + + p = curproc; + map = &p->p_vmspace->vm_map; + + if (!ISSET(flags, HAX_VCPUMEM_VALIDVA)) { + // Map to user + uao = uao_create(size, 0); + uao_reference(uao); + va = p->p_emul->e_vm_default_addr(p, (vaddr_t)p->p_vmspace->vm_daddr, size, map->flags & VM_MAP_TOPDOWN); + err = uvm_map(map, &va, size, uao, 0, 0, + UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_NONE, + UVM_ADV_RANDOM, 0)); + uao_reference(uao); + if (err) { + hax_error("Failed to map into user\n"); + uao_detach(uao); + kmem_free(hinfo, sizeof(struct hax_vcpu_mem_hinfo_t)); + return -ENOMEM; + } + hinfo->uao = uao; + uva = va; + } + + err = uvm_map_extract(map, uva, size, kernel_map, &kva, UVM_EXTRACT_QREF | UVM_EXTRACT_CONTIG | UVM_EXTRACT_FIXPROT); + if (err) { + hax_error("Failed to map into kernel\n"); + if (!ISSET(flags, HAX_VCPUMEM_VALIDVA)) { + uvm_unmap(map, uva, uva + size); + uao_detach(uao); + kmem_free(hinfo, sizeof(struct hax_vcpu_mem_hinfo_t)); + } + } + + mem->uva = uva; + mem->kva = (void *)kva; + mem->hinfo = hinfo; + mem->size = size; + return 0; +} + +uint64_t hax_get_memory_threshold(void) +{ +#ifdef CONFIG_HAX_EPT2 + // Since there is no memory cap, just return a sufficiently large value + return 1ULL << 48; // PHYSADDR_MAX + 1 +#else // !CONFIG_HAX_EPT2 + return 0; +#endif // CONFIG_HAX_EPT2 +} diff --git a/platforms/netbsd/hax_wrapper.c b/platforms/netbsd/hax_wrapper.c new file mode 100644 index 00000000..46c29341 --- /dev/null +++ b/platforms/netbsd/hax_wrapper.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2018 Kamil Rytarowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "../../include/hax.h" +#include "../../core/include/hax_core_interface.h" +#include "../../core/include/ia32.h" + +int default_hax_log_level = HAX_LOG_DEFAULT; +int max_cpus; +hax_cpumap_t cpu_online_map; + +int hax_log_level(int level, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + if (level >= default_hax_log_level) { + printf("haxm: "); + vprintf(fmt, args); + } + va_end(args); + return 0; +} + +uint32_t hax_cpuid(void) +{ + return curcpu()->ci_cpuid; +} + +typedef struct smp_call_parameter { + void (*func)(void *); + void *param; + hax_cpumap_t *cpus; +} smp_call_parameter; + +static void smp_cfunction(void *a1, void *a2 __unused) +{ + struct smp_call_parameter *info = a1; + hax_cpumap_t *cpus; + uint32_t cpuid; + + cpus = info->cpus; + cpuid = hax_cpuid(); + if (*cpus & (0x1 << cpuid)) + info->func(info->param); +} + +int hax_smp_call_function(hax_cpumap_t *cpus, void (*scfunc)(void *), + void *param) +{ + smp_call_parameter info; + uint64_t xc; + + info.func = scfunc; + info.param = param; + info.cpus = cpus; + xc = xc_broadcast(XC_HIGHPRI, smp_cfunction, &info, NULL); + xc_wait(xc); + return 0; +} + +/* XXX */ +int proc_event_pending(struct vcpu_t *vcpu) +{ + return vcpu_event_pending(vcpu); +} + +void hax_disable_preemption(preempt_flag *eflags) +{ + kpreempt_disable(); +} + +void hax_enable_preemption(preempt_flag *eflags) +{ + kpreempt_enable(); +} + +void hax_enable_irq(void) +{ + x86_enable_intr(); +} + +void hax_disable_irq(void) +{ + x86_disable_intr(); +} + +void hax_error(char *fmt, ...) +{ + va_list args; + + if (HAX_LOGE < default_hax_log_level) + return; + + va_start(args, fmt); + printf("haxm_error: "); + vprintf(fmt, args); + va_end(args); +} + +void hax_warning(char *fmt, ...) +{ + va_list args; + + if (HAX_LOGW < default_hax_log_level) + return; + + va_start(args, fmt); + printf("haxm_warning: "); + vprintf(fmt, args); + va_end(args); +} + +void hax_info(char *fmt, ...) +{ + va_list args; + + if (HAX_LOGI < default_hax_log_level) + return; + + va_start(args, fmt); + printf("haxm_info: "); + vprintf(fmt, args); + va_end(args); +} + +void hax_debug(char *fmt, ...) +{ + va_list args; + + if (HAX_LOGD < default_hax_log_level) + return; + + va_start(args, fmt); + printf("haxm_debug: "); + vprintf(fmt, args); + va_end(args); +} + +void hax_panic_vcpu(struct vcpu_t *v, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + printf("haxm_panic: "); + vprintf(fmt, args); + va_end(args); + + vcpu_set_panic(v); +} + +/* Misc */ +void hax_smp_mb(void) +{ + membar_sync(); +} + +/* Compare-Exchange */ +bool hax_cmpxchg32(uint32_t old_val, uint32_t new_val, volatile uint32_t *addr) +{ + hax_atomic_t rv; + + membar_exit(); + rv = atomic_cas_32(addr, old_val, new_val); + membar_enter(); + + return rv == old_val; +} + +bool hax_cmpxchg64(uint64_t old_val, uint64_t new_val, volatile uint64_t *addr) +{ + hax_atomic_t rv; + + membar_exit(); + rv = atomic_cas_64(addr, old_val, new_val); + membar_enter(); + + return rv == old_val; +} + +/* Atomics */ +hax_atomic_t hax_atomic_add(volatile hax_atomic_t *atom, uint32_t value) +{ + hax_atomic_t rv; + + membar_exit(); + rv = atomic_add_32_nv(atom, value) - value; + membar_enter(); + + return rv; +} + +hax_atomic_t hax_atomic_inc(volatile hax_atomic_t *atom) +{ + hax_atomic_t rv; + + membar_exit(); + rv = atomic_inc_32_nv(atom) - 1; + membar_enter(); + + return rv; +} + +hax_atomic_t hax_atomic_dec(volatile hax_atomic_t *atom) +{ + hax_atomic_t rv; + + membar_exit(); + rv = atomic_dec_32_nv(atom) + 1; + membar_enter(); + + return rv; +} + +int hax_test_and_set_bit(int bit, uint64_t *memory) +{ + volatile uint64_t *val; + uint64_t mask, old; + + val = (volatile uint64_t *)memory; + mask = 1 << bit; + + do { + old = *val; + if ((old & mask) != 0) + break; + } while (atomic_cas_64(val, old, old | mask) != old); + + return !!(old & mask); +} + +int hax_test_and_clear_bit(int bit, uint64_t *memory) +{ + volatile uint64_t *val; + uint64_t mask, old; + + val = (volatile uint64_t *)memory; + mask = 1 << bit; + + do { + old = *val; + if ((old & mask) != 0) + break; + } while (atomic_cas_64(val, old, old & ~mask) != old); + + return !!(old & mask); +} + +/* Spinlock */ +struct hax_spinlock { + kmutex_t lock; +}; + +hax_spinlock *hax_spinlock_alloc_init(void) +{ + struct hax_spinlock *lock; + + lock = kmem_alloc(sizeof(struct hax_spinlock), KM_SLEEP); + if (!lock) { + hax_error("Could not allocate spinlock\n"); + return NULL; + } + mutex_init(&lock->lock, MUTEX_DEFAULT, IPL_VM); + + return lock; +} + +void hax_spinlock_free(hax_spinlock *lock) +{ + if (!lock) + return; + + mutex_destroy(&lock->lock); + kmem_free(lock, sizeof(struct hax_spinlock)); +} + +void hax_spin_lock(hax_spinlock *lock) +{ + mutex_spin_enter(&lock->lock); +} + +void hax_spin_unlock(hax_spinlock *lock) +{ + mutex_spin_exit(&lock->lock); +} + +/* Mutex */ +hax_mutex hax_mutex_alloc_init(void) +{ + kmutex_t *lock; + + lock = kmem_alloc(sizeof(kmutex_t), KM_SLEEP); + if (!lock) { + hax_error("Could not allocate mutex\n"); + return NULL; + } + mutex_init(lock, MUTEX_DEFAULT, IPL_NONE); + return lock; +} + +void hax_mutex_lock(hax_mutex lock) +{ + if (!lock) + return; + + mutex_enter(lock); +} + +void hax_mutex_unlock(hax_mutex lock) +{ + if (!lock) + return; + + mutex_exit(lock); +} + +void hax_mutex_free(hax_mutex lock) +{ + if (!lock) + return; + + mutex_destroy(lock); + kmem_free(lock, sizeof(kmutex_t)); +}