class VM(IOCTL): __slots__ = ('vcpus_struct') KVM_NITRO_ATTACH_VCPUS = IOR(KVMIO, 0xE2, NitroVCPUs) KVM_NITRO_SET_SYSCALL_TRAP = IOW(KVMIO, 0xE3, c_bool) KVM_NITRO_ADD_SYSCALL_FILTER = IOR(KVMIO, 0xEB, c_ulonglong) KVM_NITRO_REMOVE_SYSCALL_FILTER = IOR(KVMIO, 0xEC, c_ulonglong) def __init__(self, vm_fd): super().__init__() self.fd = vm_fd self.vcpus_struct = NitroVCPUs() def attach_vcpus(self): logging.debug('attach_vcpus') r = self.make_ioctl(self.KVM_NITRO_ATTACH_VCPUS, byref(self.vcpus_struct)) if r != 0: raise RuntimeError('Error: fail to attach to vcpus') vcpus = [ VCPU(i, self.vcpus_struct.fds[i]) for i in range(self.vcpus_struct.num_vcpus) ] return vcpus def set_syscall_trap(self, enabled): logging.debug('set_syscall_trap %s', enabled) c_enabled = c_bool(enabled) r = self.make_ioctl(self.KVM_NITRO_SET_SYSCALL_TRAP, byref(c_enabled)) return r def add_syscall_filter(self, syscall_nb): logging.debug('adding syscall filter on %s' % (syscall_nb)) c_syscall_nb = c_ulonglong(syscall_nb) r = self.make_ioctl(self.KVM_NITRO_ADD_SYSCALL_FILTER, byref(c_syscall_nb)) if r != 0: raise RuntimeError('Error: fail to add syscall filter') return r def remove_syscall_filter(self, syscall_nb): logging.debug('removing syscall filter on %s' % (syscall_nb)) c_syscall_nb = c_ulonglong(syscall_nb) r = self.make_ioctl(self.KVM_NITRO_REMOVE_SYSCALL_FILTER, byref(c_syscall_nb)) if r != 0: raise RuntimeError('Error: fail to remove syscall filter') return r
class VM(IOCTL): __slots__ = ('vcpus_struct') KVM_NITRO_ATTACH_VCPUS = IOR(KVMIO, 0xE2, NitroVCPUs) KVM_NITRO_SET_SYSCALL_TRAP = IOW(KVMIO, 0xE3, c_bool) def __init__(self, vm_fd): super().__init__() self.fd = vm_fd self.vcpus_struct = NitroVCPUs() def attach_vcpus(self): logging.debug('attach_vcpus') r = self.make_ioctl(self.KVM_NITRO_ATTACH_VCPUS, byref(self.vcpus_struct)) if r != 0: raise RuntimeError('Error: fail to attach to vcpus') vcpus = [ VCPU(i, self.vcpus_struct.fds[i]) for i in range(self.vcpus_struct.num_vcpus) ] return vcpus def set_syscall_trap(self, enabled): logging.debug('set_syscall_trap {}'.format(enabled)) c_enabled = c_bool(enabled) r = self.make_ioctl(self.KVM_NITRO_SET_SYSCALL_TRAP, byref(c_enabled)) return r
class VCPU(IOCTL): __slots__ = ('vcpu_nb', ) KVM_NITRO_GET_EVENT = IOR(KVMIO, 0xE5, NitroEventStr) KVM_NITRO_CONTINUE = IO(KVMIO, 0xE6) KVM_NITRO_GET_REGS = IOR(KVMIO, 0xE7, Regs) KVM_NITRO_SET_REGS = IOW(KVMIO, 0xE8, Regs) KVM_NITRO_GET_SREGS = IOR(KVMIO, 0xE9, SRegs) KVM_NITRO_SET_SREGS = IOW(KVMIO, 0xEA, SRegs) def __init__(self, vcpu_nb, vcpu_fd): super().__init__() self.vcpu_nb = vcpu_nb self.fd = vcpu_fd def get_event(self): # logging.debug('get_event %s, self.vcpu_nb) nitro_ev = NitroEventStr() ret = self.make_ioctl(self.KVM_NITRO_GET_EVENT, byref(nitro_ev)) if ret != 0: logging.error("get_event failed (vcpu: %d; returned: %d)", self.vcpu_nb, ret) raise ValueError("get_event failed") return nitro_ev def continue_vm(self): # logging.debug('continue_vm %s', self.vcpu_nb) return self.make_ioctl(self.KVM_NITRO_CONTINUE, 0) def get_regs(self): regs = Regs() self.make_ioctl(self.KVM_NITRO_GET_REGS, byref(regs)) return regs def get_sregs(self): sregs = SRegs() self.make_ioctl(self.KVM_NITRO_GET_SREGS, byref(sregs)) return sregs def set_regs(self, regs): ret = self.make_ioctl(self.KVM_NITRO_SET_REGS, byref(regs)) return ret def set_sregs(self, sregs): ret = self.make_ioctl(self.KVM_NITRO_SET_SREGS, byref(sregs)) return ret
class VCPU(IOCTL): KVM_NITRO_GET_EVENT = IOR(KVMIO, 0xE5, NitroEventStr) KVM_NITRO_CONTINUE = IO(KVMIO, 0xE6) def __init__(self, vcpu_nb, vcpu_fd): super().__init__() self.vcpu_nb = vcpu_nb self.fd = vcpu_fd def get_event(self): # logging.debug('get_event {}'.format(self.vcpu_nb)) nitro_ev = NitroEventStr() self.make_ioctl(self.KVM_NITRO_GET_EVENT, byref(nitro_ev)) return nitro_ev def continue_vm(self): # logging.debug('continue_vm {}'.format(self.vcpu_nb)) return self.make_ioctl(self.KVM_NITRO_CONTINUE, None)
class VCPU(IOCTL): """Class that allows controlling and inspecting the state of an individual virtual CPU.""" __slots__ = ( 'vcpu_nb', ) #: Request for retrieving event KVM_NITRO_GET_EVENT = IOR(KVMIO, 0xE5, NitroEventStr) #: Request to continue KVM_NITRO_CONTINUE = IO(KVMIO, 0xE6) #: Request to get register state KVM_NITRO_GET_REGS = IOR(KVMIO, 0xE7, Regs) #: Request to set register state KVM_NITRO_SET_REGS = IOW(KVMIO, 0xE8, Regs) #: Request to get special registers KVM_NITRO_GET_SREGS = IOR(KVMIO, 0xE9, SRegs) #: Request to set special registers KVM_NITRO_SET_SREGS = IOW(KVMIO, 0xEA, SRegs) def __init__(self, vcpu_nb, vcpu_fd): super().__init__() self.vcpu_nb = vcpu_nb self.fd = vcpu_fd def get_event(self): """ Retrieve event from the virtual machine :rtype: NitroEventStr """ # logging.debug('get_event %s, self.vcpu_nb) nitro_ev = NitroEventStr() ret = self.make_ioctl(self.KVM_NITRO_GET_EVENT, byref(nitro_ev)) if ret != 0: raise ValueError("get_event failed on vcpu %d (%d)".format(self.vcpu_nb, ret)) return nitro_ev def continue_vm(self): """Continue virtual machine execution""" # logging.debug('continue_vm %s', self.vcpu_nb) return self.make_ioctl(self.KVM_NITRO_CONTINUE, 0) def get_regs(self): """ Get registers from the virtual machine. :rtype: Regs """ regs = Regs() self.make_ioctl(self.KVM_NITRO_GET_REGS, byref(regs)) return regs def get_sregs(self): """ Get special registers from the virtual machine. :rtype: SRegs """ sregs = SRegs() self.make_ioctl(self.KVM_NITRO_GET_SREGS, byref(sregs)) return sregs def set_regs(self, regs): """ Set registers for the virtual machine. :param Regs regs: Values for registers """ ret = self.make_ioctl(self.KVM_NITRO_SET_REGS, byref(regs)) return ret def set_sregs(self, sregs): """ Set special registers for the virtual machine. :param SRegs sregs: Values for special registers """ ret = self.make_ioctl(self.KVM_NITRO_SET_SREGS, byref(sregs)) return ret
class VM(IOCTL): """Class that allows low-level control of KVM virtual machines. VM makes it possible to attach to machine's virtual CPUs and add system call filters. """ __slots__ = ( 'vcpus_struct', 'syscall_filters' ) #: Reguest for attaching to a virtual CPU KVM_NITRO_ATTACH_VCPUS = IOR(KVMIO, 0xE2, NitroVCPUs) #: Request for setting system call trap KVM_NITRO_SET_SYSCALL_TRAP = IOW(KVMIO, 0xE3, c_bool) #: Request for adding system call filter KVM_NITRO_ADD_SYSCALL_FILTER = IOR(KVMIO, 0xEB, c_ulonglong) #: Request for removing system call filter KVM_NITRO_REMOVE_SYSCALL_FILTER = IOR(KVMIO, 0xEC, c_ulonglong) def __init__(self, vm_fd): super().__init__() self.fd = vm_fd self.vcpus_struct = NitroVCPUs() self.syscall_filters = set() def attach_vcpus(self): """ Attach to virtual CPUs :rtype: List of VCPUs """ logging.debug('attach_vcpus') r = self.make_ioctl(self.KVM_NITRO_ATTACH_VCPUS, byref(self.vcpus_struct)) if r != 0: raise RuntimeError('Error: fail to attach to vcpus') vcpus = [VCPU(i, self.vcpus_struct.fds[i]) for i in range(self.vcpus_struct.num_vcpus)] return vcpus def set_syscall_trap(self, enabled): logging.debug('set_syscall_trap %s', enabled) c_enabled = c_bool(enabled) r = self.make_ioctl(self.KVM_NITRO_SET_SYSCALL_TRAP, byref(c_enabled)) return r def add_syscall_filter(self, syscall_nb): logging.debug('adding syscall filter on %s' % (hex(syscall_nb))) c_syscall_nb = c_ulonglong(syscall_nb) r = self.make_ioctl(self.KVM_NITRO_ADD_SYSCALL_FILTER, byref(c_syscall_nb)) if r != 0: raise RuntimeError('Error: fail to add syscall filter') self.syscall_filters.add(syscall_nb) return r def remove_syscall_filter(self, syscall_nb): logging.debug('removing syscall filter on %s' % (hex(syscall_nb))) c_syscall_nb = c_ulonglong(syscall_nb) r = self.make_ioctl(self.KVM_NITRO_REMOVE_SYSCALL_FILTER, byref(c_syscall_nb)) if r != 0: raise RuntimeError('Error: fail to remove syscall filter') self.syscall_filters.remove(syscall_nb) return r
import ctypes, fcntl from ioctl_opt import IOR, IOC, IOC_READ, IOC_WRITE class hidraw_devinfo(ctypes.Structure): _fields_ = [ ('bustype', ctypes.c_uint), ('vendor', ctypes.c_short), ('product', ctypes.c_short), ] HIDIOCGRAWINFO = IOR(ord('H'), 0x03, hidraw_devinfo) HIDIOCGRAWNAME = lambda length: IOC(IOC_READ, ord('H'), 0x04, length) def get_device_name(fd, length=1024): name = (ctypes.c_char * length)() actual_length = fcntl.ioctl(fd, HIDIOCGRAWNAME(length), name, True) if actual_length < 0: raise OSError(-actual_length) if name[actual_length - 1] == b'\x00': actual_length -= 1 return name[:actual_length] def get_device_id(fd, length=1024): device_id = hidraw_devinfo() actual_length = fcntl.ioctl(fd, HIDIOCGRAWINFO, device_id, True) if actual_length < 0: raise OSError(-actual_length)
class raw_vcsm_cma(raw): ''' Methods and constants for the VCSM-CMA kernel driver. Copyright (c) 2019 Raspberry Pi (Trading) Ltd. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Copyright (c) 2012 Broadcom Europe Ltd. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. * 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. References: - https://github.com/raspberrypi/linux/blob/rpi-5.10.y/drivers/staging/vc04_services/include/linux/broadcom/vc_sm_cma_ioctl.h - https://github.com/raspberrypi/userland/blob/master/host_applications/linux/libs/sm/user-vcsm.c ''' __MAGIC = ord('J') __CMD_ALLOC = 0x5a __CMD_CLEAN_INVALID2 = 0x5c class __st_alloc(Structure): _fields_ = [ # user -> kernel ('size', c_uint32), ('num', c_uint32), ('cached', c_uint32), ('pad', c_uint32), ('name', c_char * 32), # kernel -> user ('handle', c_int32), ('vc_handle', c_uint32), ('dma_addr', c_uint64), ] class __st_clean_invalid2(Structure): class st_clean_invalid_block(Structure): _fields_ = [ ('invalidate_mode', c_uint32), ('block_count', c_uint32), ('start_address', c_void_p), ('block_size', c_uint32), ('inter_block_stride', c_uint32), ] _fields_ = [ # user -> kernel ('op_count', c_uint32), # Must be 1 for now. ('pad', c_uint32), ('s', st_clean_invalid_block), ] __IOCTL_ALLOC = IOR(__MAGIC, __CMD_ALLOC, __st_alloc) __IOCTL_CLEAN_INVALID2 = IOR(__MAGIC, __CMD_CLEAN_INVALID2, __st_clean_invalid2) def __ioctl_alloc(self, *, size, num, cached, pad, name): s = self.__st_alloc(size=size, num=num, cached=cached, pad=pad, name=name) ioctl(self.__fd, self.__IOCTL_ALLOC, s) return s.handle, s.vc_handle, s.dma_addr def __init__(self, *, path=None): if path is None: path = '/dev/vcsm-cma' self.__fd = os.open(path, os.O_NONBLOCK | os.O_RDWR) def close(self): os.close(self.__fd) del self.__fd def alloc(self, *, size, cached, name): size_aligned = self.align(size, resource.getpagesize()) name = bytes(name, 'ascii') handle, vc_handle, bus_ptr = self.__ioctl_alloc(size=size_aligned, num=1, cached=cached, pad=0, name=name) assert 0 <= bus_ptr < 2**32 usr_buf = mmap.mmap(fileno=handle, length=size, flags=mmap.MAP_SHARED, prot=mmap.PROT_READ | mmap.PROT_WRITE, offset=0) dma_buf.ioctl_sync(fd=handle, flags=dma_buf.SYNC_START | dma_buf.SYNC_RW) # The reference to this intermediate buffer is immediately removed, but # as long as the usr_buf is living, the memory address does not change. usr_ptr = addressof(c_byte.from_buffer(usr_buf)) return handle, bus_ptr, usr_ptr, usr_buf def free(self, *, handle, usr_buf): dma_buf.ioctl_sync(fd=handle, flags=dma_buf.SYNC_END | dma_buf.SYNC_RW) usr_buf.close() os.close(handle) def clean_invalid(self, *, op, handle): if op == CACHE_OP_NOP: return elif op == CACHE_OP_INVALIDATE: flags = dma_buf.SYNC_START | dma_buf.SYNC_RW elif op == CACHE_OP_CLEAN or op == CACHE_OP_FLUSH: flags = dma_buf.SYNC_END | dma_buf.SYNC_RW dma_buf.ioctl_sync(fd=handle, flags=flags)
class raw_vcsm(raw): ''' Methods and constants for the plain (non-CMA) VCSM kernel driver. Copyright (c) 2011 Broadcom Corporation. All rights reserved. Unless you and Broadcom execute a separate written software license agreement governing use of this software, this software is licensed to you under the terms of the GNU General Public License version 2, available at http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). Notwithstanding the above, under no circumstances may you combine this software in any way with any other Broadcom software provided under a license other than the GPL, without Broadcom's express prior written consent. Copyright (c) 2012 Broadcom Europe Ltd. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. * 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. References: - https://github.com/raspberrypi/linux/blob/rpi-5.8.y/include/linux/broadcom/vmcs_sm_ioctl.h - https://github.com/raspberrypi/userland/blob/master/host_applications/linux/libs/sm/user-vcsm.c ''' __MAGIC = ord('I') __CMD_ALLOC = 0x5a __CMD_LOCK = 0x5c __CMD_UNLOCK = 0x5e __CMD_FREE = 0x61 __CMD_MAPPED_VC_ADDR_FROM_HDL = 0x6a __CMD_CLEAN_INVALID2 = 0x70 class __st_alloc(Structure): _fields_ = [ # user -> kernel ('size', c_uint), ('num', c_uint), ('cached', c_uint), ('name', c_char * 32), # kernel -> user ('handle', c_uint), ] class __st_free(Structure): _fields_ = [ # user -> kernel ('handle', c_uint), ] class __st_lock_unlock(Structure): _fields_ = [ # user -> kernel ('handle', c_uint), # kernel -> user ('addr', c_uint), ] class __st_map(Structure): _fields_ = [ # user -> kernel ('pid', c_uint), ('handle', c_uint), ('addr', c_uint), # kernel -> user ('size', c_uint), ] class __st_clean_invalid2(Structure): class st_clean_invalid_block(Structure): _fields_ = [ ('invalidate_mode', c_uint16), ('block_count', c_uint16), ('start_address', c_void_p), ('block_size', c_uint32), ('inter_block_stride', c_uint32), ] _fields_ = [ # user -> kernel ('op_count', c_uint8), # Must be 1 for now. ('zero', c_uint8 * 3), ('s', st_clean_invalid_block), ] __IOCTL_ALLOC = IOR(__MAGIC, __CMD_ALLOC, __st_alloc) __IOCTL_LOCK = IOR(__MAGIC, __CMD_LOCK, __st_lock_unlock) __IOCTL_UNLOCK = IOR(__MAGIC, __CMD_UNLOCK, __st_lock_unlock) __IOCTL_FREE = IOR(__MAGIC, __CMD_FREE, __st_free) __IOCTL_MAP_VC_ADDR_FR_HDL = IOR(__MAGIC, __CMD_MAPPED_VC_ADDR_FROM_HDL, __st_map) __IOCTL_CLEAN_INVALID2 = IOR(__MAGIC, __CMD_CLEAN_INVALID2, __st_clean_invalid2) def __ioctl_alloc(self, *, size, num, cached, name): s = self.__st_alloc(size=size, num=num, cached=cached, name=name) ioctl(self.__fd, self.__IOCTL_ALLOC, s) return s.handle def __ioctl_lock(self, *, handle): s = self.__st_lock_unlock(handle=handle) ioctl(self.__fd, self.__IOCTL_LOCK, s) return s.addr def __ioctl_unlock(self, *, handle): s = self.__st_lock_unlock(handle=handle) ioctl(self.__fd, self.__IOCTL_UNLOCK, s) return s.addr def __ioctl_free(self, *, handle): s = self.__st_free(handle=handle) ioctl(self.__fd, self.__IOCTL_FREE, s) def __ioctl_map_vc_addr_fr_hdl(self, *, pid, handle): s = self.__st_map(pid=pid, handle=handle) ioctl(self.__fd, self.__IOCTL_MAP_VC_ADDR_FR_HDL, s) return s.addr def __ioctl_clean_invalid2(self, *, invalidate_mode, block_count, start_address, block_size, inter_block_stride): s = self.__st_clean_invalid2( op_count=1, s=self.__st_clean_invalid2.st_clean_invalid_block( invalidate_mode=invalidate_mode, block_count=block_count, start_address=start_address, block_size=block_size, inter_block_stride=inter_block_stride)) ioctl(self.__fd, self.__IOCTL_CLEAN_INVALID2, s) def __init__(self, *, path=None): if path is None: path = '/dev/vcsm' self.__fd = os.open(path, os.O_NONBLOCK | os.O_RDWR) def close(self): os.close(self.__fd) del self.__fd def alloc(self, *, size, cached, name): size = self.align(size, resource.getpagesize()) name = bytes(name, 'ascii') handle = self.__ioctl_alloc(size=size, num=1, cached=cached, name=name) usr_buf = mmap.mmap(fileno=self.__fd, length=size, flags=mmap.MAP_SHARED, prot=mmap.PROT_READ | mmap.PROT_WRITE, offset=handle) usr_ptr = self.__ioctl_lock(handle=handle) bus_ptr = self.__ioctl_map_vc_addr_fr_hdl(pid=os.getpid(), handle=handle) return handle, bus_ptr, usr_ptr, usr_buf def free(self, *, handle, usr_buf): usr_buf.close() self.__ioctl_unlock(handle=handle) self.__ioctl_free(handle=handle) def clean_invalid(self, *, op, usr_ptr, size): self.__ioctl_clean_invalid2(invalidate_mode=op, block_count=1, start_address=usr_ptr, block_size=size, inter_block_stride=0)
class raw(object): MAGIC = ord('I') CMD_ALLOC = 0x5a CMD_LOCK = 0x5c CMD_UNLOCK = 0x5e CMD_FREE = 0x61 CMD_MAPPED_VC_ADDR_FROM_HDL = 0x6a CMD_CLEAN_INVALID2 = 0x70 OP_NOP = 0 OP_INVALIDATE = 1 OP_CLEAN = 2 OP_CLEAN_INVALIDATE = 3 class st_alloc(Structure): _fields_ = [ # user -> kernel ('size', c_uint), ('num', c_uint), ('cached', c_uint), ('name', c_char * 32), # kernel -> user ('handle', c_uint), ] pass class st_free(Structure): _fields_ = [ # user -> kernel ('handle', c_uint), ] pass class st_lock_unlock(Structure): _fields_ = [ # user -> kernel ('handle', c_uint), # kernel -> user ('addr', c_uint), ] pass class st_size(Structure): _fields_ = [ # user -> kernel ('handle', c_uint), # kernel -> user ('size', c_uint), ] pass class st_map(Structure): _fields_ = [ # user -> kernel ('pid', c_uint), ('handle', c_uint), ('addr', c_uint), # kernel -> user ('size', c_uint), ] pass class st_clean_invalid2(Structure): class st_clean_invalid_block(Structure): _fields_ = [ ('invalidate_mode', c_uint16), ('block_count', c_uint16), ('start_address', c_void_p), ('block_size', c_uint32), ('inter_block_stride', c_uint32), ] pass _fields_ = [ # user -> kernel ('op_count', c_uint8), # Must be 1 for now... Sigh... ('zero', c_uint8 * 3), ('s', st_clean_invalid_block), ] pass IOCTL_ALLOC = IOR(MAGIC, CMD_ALLOC, st_alloc) IOCTL_LOCK = IOR(MAGIC, CMD_LOCK, st_lock_unlock) IOCTL_UNLOCK = IOR(MAGIC, CMD_UNLOCK, st_lock_unlock) IOCTL_FREE = IOR(MAGIC, CMD_FREE, st_free) IOCTL_MAP_VC_ADDR_FR_HDL = IOR(MAGIC, CMD_MAPPED_VC_ADDR_FROM_HDL, st_map) # Dirty hack! No more zero-sized arrays I hope! IOCTL_CLEAN_INVALID2 = IOR(MAGIC, CMD_CLEAN_INVALID2, c_uint8 * 4) def __init__(self): self.fd = os.open('/dev/vcsm', os.O_NONBLOCK | os.O_RDWR) def close(self): if self.fd: os.close(self.fd) self.fd = None def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): self.close() return exc_value is None def alloc(self, size, num, cached, name): if sys.version_info >= (3, 0): name = bytes(name, 'ascii') else: name = bytes(name).encode('ascii') s = self.st_alloc(size=size, num=num, cached=cached, name=name) ioctl(self.fd, self.IOCTL_ALLOC, s) return s.handle def lock(self, handle): s = self.st_lock_unlock(handle=handle) ioctl(self.fd, self.IOCTL_LOCK, s) return s.addr def unlock(self, handle): s = self.st_lock_unlock(handle=handle) ioctl(self.fd, self.IOCTL_UNLOCK, s) def free(self, handle): s = self.st_free(handle=handle) ioctl(self.fd, self.IOCTL_FREE, s) def map_vc_addr_fr_hdl(self, handle): s = self.st_map(pid=os.getpid(), handle=handle) ioctl(self.fd, self.IOCTL_MAP_VC_ADDR_FR_HDL, s) return s.addr def clean_invalid2(self, op, usr_ptr, block_count, block_size, stride): s = self.st_clean_invalid2( op_count=1, s=self.st_clean_invalid2.st_clean_invalid_block( invalidate_mode=op, block_count=block_count, start_address=usr_ptr, block_size=block_size, inter_block_stride=stride)) ioctl(self.fd, self.IOCTL_CLEAN_INVALID2, s)
# KVM IOCTLs KVM_GET_API_VERSION = IO(KVMIO, 0x00) KVM_CREATE_VM = IO(KVMIO, 0x01) KVM_CHECK_EXTENSION = IO(KVMIO, 0x03) KVM_GET_VCPU_MMAP_SIZE = IO(KVMIO, 0x04) # KVM VM IOCTLs KVM_CREATE_VCPU = IO(KVMIO, 0x41) KVM_SET_TSS_ADDR = IO(KVMIO, 0x47) KVM_SET_USER_MEMORY_REGION = IOW(KVMIO, 0x46, KVMUserSpaceMemoryRegion) # KVM CPU IOCTLs KVM_RUN = IO(KVMIO, 0x80) KVM_GET_REGS = IOR(KVMIO, 0x81, KVMRegs) KVM_SET_REGS = IOW(KVMIO, 0x82, KVMRegs) KVM_GET_SREGS = IOR(KVMIO, 0x83, KVMSRegs) KVM_SET_SREGS = IOW(KVMIO, 0x84, KVMSRegs) ######################################################################################### # The KVM structures and APIs below are not part of the standard KVM interface. # They are part of the KVM extensions for symbolic execution by S2E (http://s2e.systems). # Available with KVM_CAP_MEM_FIXED_REGION class KVMFixedRegion(Structure): _fields_ = [ ('name', c_char_p), ('host_address', c_uint64), ('size', c_uint64),