?? host-linux.c
字號:
/* * plex86: run multiple x86 operating systems concurrently * Copyright (C) 1999-2003 Kevin P. Lawton * * host-linux.c: Linux specific VM host driver functionality * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "plex86.h"#define IN_HOST_SPACE#include "monitor.h"#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/proc_fs.h>#include <linux/wrapper.h>#include <linux/version.h>#include <asm/irq.h>#include <asm/atomic.h>#ifndef VERSION_CODE# define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) )#endif#if LINUX_VERSION_CODE < VERSION_CODE(2,4,20)/* I use get_user_pages() to find and pin physical pages of memory * underlying the guest physical memory malloc()'d from user space. * This became an exported symbol available for kernel modules * as of 2.4.20. You will have to recode some functions for * lesser kernels. */# error "Currently, you need Linux kernel 2.4.20 or above."#endif#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)# include <asm/uaccess.h>#endif#include <asm/io.h>/************************************************************************//* Compatibility macros & convenience functions for older kernels *//************************************************************************/#ifndef EXPORT_NO_SYMBOLS# define EXPORT_NO_SYMBOLS register_symtab(NULL)#endif#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,29)# define proc_register_dynamic proc_register#endif#if LINUX_VERSION_CODE < VERSION_CODE(2,2,0)#define NEED_RESCHED need_resched#else#define NEED_RESCHED current->need_resched#endif/* Instrumentation of how many hardware interrupts were redirected * to the host, while the VM monitor/guest was running. This can be * written to by multiple contexts, so it needs SMP protection. */static atomic_t interruptRedirCount[256];#if LINUX_VERSION_CODE < VERSION_CODE(2,1,0) static inline unsigned longcopy_from_user(void *to, const void *from, unsigned long n){ int i; if ( (i = verify_area(VERIFY_READ, from, n)) != 0 ) return i; memcpy_fromfs(to, from, n); return 0;} static inline unsigned longcopy_to_user(void *to, const void *from, unsigned long n){ int i; if ( (i = verify_area(VERIFY_WRITE, to, n)) != 0 ) return i; memcpy_tofs(to, from, n); return 0;}#endif#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,18) && !defined(THIS_MODULE)/* Starting with version 2.1.18, the __this_module symbol is present, * but the THIS_MODULE #define was introduced much later ... */#define THIS_MODULE (&__this_module)#endif/************************************************************************//* Declarations *//************************************************************************//* Use dynamic major number allocation. (Set non-zero for static allocation) */#define PLEX86_MAJOR 0static int plex_major = PLEX86_MAJOR;#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,18)MODULE_PARM(plex_major, "i");MODULE_PARM_DESC(plex_major, "major number (default " __MODULE_STRING(PLEX86_MAJOR) ")");#endif/* The kernel segment base. */#if LINUX_VERSION_CODE < VERSION_CODE(2,1,0)# define KERNEL_OFFSET 0xc0000000#else# define KERNEL_OFFSET 0x00000000#endif/* File operations. */static int plex86_ioctl(struct inode *, struct file *, unsigned int, unsigned long);static int plex86_open(struct inode *, struct file *);#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,31)static int plex86_release(struct inode *, struct file *);#elsestatic void plex86_release(struct inode *, struct file *);#endif#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)static int plex86_mmap(struct file * file, struct vm_area_struct * vma);#elsestatic int plex86_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)/* New License scheme. */#ifdef MODULE_LICENSEMODULE_LICENSE("GPL"); /* Close enough. Keeps kernel from complaining. */#endif#endif/************************************************************************//* Structures / Variables *//************************************************************************/static int retrieveKernelModulePages(void);static unsigned retrievePhyPages(Bit32u *page, int max_pages, void *addr, unsigned size);static struct file_operations plex86_fops = {#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0) owner: THIS_MODULE,#endif mmap: plex86_mmap, ioctl: plex86_ioctl, open: plex86_open, release: plex86_release, };#ifdef CONFIG_DEVFS_FS#include <linux/devfs_fs_kernel.h>devfs_handle_t my_devfs_entry;#endif/* For the /proc/driver/plex86 entry. */#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0) /* XXX - How far back? */int plex86_read_procmem(char *, char **, off_t, int);#elseint plex86_read_procmem(char *, char **, off_t, int, int);#endif#if LINUX_VERSION_CODE < VERSION_CODE(2,3,25)static struct proc_dir_entry plex86_proc_entry = { 0, /* dynamic inode */ 6, "driver/plex86", /* len, name */ S_IFREG | S_IRUGO, /* mode */ 1, 0, 0, 0, NULL, &plex86_read_procmem, /* read function */ };#endif#if CONFIG_X86_PAE# error "CONFIG_X86_PAE defined for this kernel, but unhandled in plex86"#endif/************************************************************************//* Main kernel module code *//************************************************************************/ intinit_module(void){ int err; /* Initialize structures which are not specific to each VM. These * are things which are set only once upon kernel module initialization. */ memset(&kernelModulePages, 0, sizeof(kernelModulePages)); memset(&interruptRedirCount, 0, sizeof(interruptRedirCount)); /* Register the device with the kernel. */ err = register_chrdev(plex_major, "plex86", &plex86_fops); if (err < 0) { printk(KERN_WARNING "plex86: can't get major %d\n", plex_major); return(err); } /* If this was a dynamic allocation, save the major for * the release code */ if(!plex_major) plex_major = err; /* Register the /proc entry. */#ifdef CONFIG_PROC_FS#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25) if (!create_proc_info_entry("driver/plex86", 0, NULL, plex86_read_procmem)) printk(KERN_ERR "plex86: registering /proc/driver/plex86 failed\n");#else proc_register_dynamic(&proc_root, &plex86_proc_entry);#endif#endif /* Register /dev/misc/plex86 with devfs. */#ifdef CONFIG_DEVFS_FS my_devfs_entry = devfs_register(NULL, "misc/plex86", DEVFS_FL_DEFAULT, plex_major, 0 /* minor mode*/, S_IFCHR | 0666, &plex86_fops, NULL /* "info" */); if (!my_devfs_entry) printk(KERN_ERR "plex86: registering misc/plex86 devfs entry failed\n");#endif /* Retrieve the monitor physical pages. */ if ( !retrieveKernelModulePages() ) { printk(KERN_ERR "plex86: retrieveKernelModulePages returned error\n"); err = -EINVAL; goto fail_retrieve_pages; } /* Kernel independent code to be run when kernel module is loaded. */ if ( !hostModuleInit() ) { printk(KERN_ERR "plex86: genericModuleInit returned error\n"); err = -EINVAL; goto fail_cpu_capabilities; } /* Success. */ EXPORT_NO_SYMBOLS; return(0);fail_cpu_capabilities:fail_retrieve_pages: /* Unregister /proc entry. */#ifdef CONFIG_PROC_FS#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25) remove_proc_entry("driver/plex86", NULL);#else proc_unregister(&proc_root, plex86_proc_entry.low_ino);#endif#endif /* Unregister device. */ unregister_chrdev(plex_major, "plex86"); return err;} voidcleanup_module(void){ /* Unregister device. */ unregister_chrdev(plex_major, "plex86"); /* Unregister /proc entry. */#ifdef CONFIG_PROC_FS#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25) remove_proc_entry("driver/plex86", NULL);#else proc_unregister(&proc_root, plex86_proc_entry.low_ino);#endif#endif#ifdef CONFIG_DEVFS_FS devfs_unregister(my_devfs_entry);#endif}/************************************************************************//* Open / Release a VM *//************************************************************************/ intplex86_open(struct inode *inode, struct file *filp){ vm_t *vm;#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0) MOD_INC_USE_COUNT;#endif /* Allocate a VM structure. */ if ( (vm = hostOSAllocZeroedMem(sizeof(vm_t))) == NULL ) return -ENOMEM; filp->private_data = vm; /* Kernel independent device open code. */ hostDeviceOpen(vm); return(0);}#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,31) int#else void#endifplex86_release(struct inode *inode, struct file *filp){ vm_t *vm = (vm_t *)filp->private_data; filp->private_data = NULL; /* Free the virtual memory. */ hostUnallocVmPages( vm ); /* Free the VM structure. */ memset( vm, 0, sizeof(*vm) ); vfree( vm );#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0) MOD_DEC_USE_COUNT;#endif#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,31) return(0);#endif} intplex86_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ vm_t *vm = (vm_t *)filp->private_data; int ret; /* Call non host-specific ioctl() code which calls back to this * module only when it needs host-specific features. */ ret = hostIoctlGeneric(vm, inode, filp, cmd, arg); /* Convert from plex86 errno codes to host-specific errno codes. Not * very exciting. */ if ( ret < 0 ) ret = - hostOSConvertPlex86Errno(- ret); return( ret );} int#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)plex86_mmap(struct file * file, struct vm_area_struct * vma)#elseplex86_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)#endif{ vm_t *vm = (vm_t *)file->private_data; UNUSED(vm); return -EINVAL;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -