host-freebsd.c

来自「bochs : one pc simulator.」· C语言 代码 · 共 570 行

C
570
字号
/* * plex86: run multiple x86 operating systems concurrently *  * Copyright (C) 2000 Frank van der Linden (fvdl@wasabisystems.com) * Copyright (C) 2000 Alexander Langer <alex@big.endian.de> *  * 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 */#define DIAGNOSTIC 1#define CDEV_MAJOR	20#define timer_t __bsd_timer_t#define write_eflags __freebsd_write_eflags#define read_eflags __freebsd_read_eflags/* XXX recheck, which includes are needed */#include <sys/param.h>#include <sys/types.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/conf.h>#include <sys/exec.h>#include <sys/malloc.h>#include <sys/syslog.h>#include <sys/queue.h>#include <sys/signalvar.h>#include <sys/mman.h>#include <sys/kernel.h>#include <sys/linker.h>#include <sys/sysproto.h>#include <sys/module.h>#include <vm/vm.h>#include <machine/cpu.h>#undef timer_t#undef write_eflags#undef read_eflags#include "plex86.h"#define IN_HOST_SPACE#include "monitor.h"static          MALLOC_DEFINE(M_PLEX86, "plex86", "Plex86 mem");static d_open_t plex86_open;static d_close_t plex86_close;static d_mmap_t plex86_mmap;static d_ioctl_t plex86_ioctl;static unsigned retrieve_phy_pages(Bit32u *, int, void *, unsigned, int);static vm_t    *find_vm(struct proc * p);static void     register_vm(vm_t * vm, struct proc * p);static void     unregister_all(struct proc * p);static struct cdevsw plex86_cdevsw = {    /* open */	plex86_open,    /* close */	plex86_close,    /* read */	noread,    /* write */	nowrite,    /* ioctl */	plex86_ioctl,    /* poll */	nopoll,    /* mmap */	plex86_mmap,    /* strat */	nostrategy,    /* name */	"plex86",    /* major */	CDEV_MAJOR,    /* dump */	nodump,    /* psize */	nopsize,    /* flags */	0,    /* bmaj */	-1};/* For use with make_dev/destroy_dev */static dev_t    plex86_dev;static struct plex86_softc {    int             sc_open;}               plex86sc;monitor_pages_t monitor_pages;/* * Hash table stuff to maintain proc <-> vm mapping. 23 entries should be * plenty.. unless someone plans to run more than 23 guest OSs.. *  * Note that a process can only open the device once with this scheme. */LIST_HEAD(plex86_hashhead, plex86_vmentry);struct plex86_vmentry {    pid_t           vm_pid;    vm_t           *vm_vm;    LIST_ENTRY(plex86_vmentry) vm_entry;};struct plex86_hashhead *plex86_hashtbl;u_long          plex86_hashmask;#define PLEX86_VMHASHSIZE	23#define PLEX86_VMHASH(p)	((u_long)((p)->p_pid) & plex86_hashmask)static intplex86_open(dev_t dev, int flags, int fmt, struct proc * p){    vm_t           *vm;    if (suser_xxx(p->p_ucred, p, p->p_acflag) != 0)	return (EPERM);    vm = find_vm(p);    if (vm == NULL) {	vm = malloc(sizeof(vm_t), M_PLEX86, M_WAITOK);	if (vm == NULL)	    return EIO;	memset(vm, 0, sizeof(vm_t));	register_vm(vm, p);	plex86sc.sc_open++;    } else	return (EBUSY);  /* Kernel independent device open code. */  hostDeviceOpenInit(vm);#ifdef FREEBSD_PLEX86_DEBUG    printf("plex86: pid %u opened device, vm %p\n", p->p_pid, vm);#endif    return (0);}intplex86_close(dev_t dev, int flags, int fmt, struct proc * p){    unregister_all(p);    plex86sc.sc_open = 0;#ifdef FREEBSD_PLEX86_DEBUG    printf("plex86: pid %u closed device\n", p->p_pid);#endif    return (0);}intplex86_mmap(dev_t dev, vm_offset_t offset, int nprot){    struct proc    *p = curproc;    int             page;    vm_offset_t     endguestoff;    vm_t           *vm;    vm = find_vm(p);    if (vm == NULL)	return (ENXIO);#warning "kludge to mmap message buffer"    endguestoff = (vm_offset_t) (vm->pages.guest_n_megs * 1024 * 1024);    if (offset >= endguestoff && nprot == PROT_READ) {	page = (offset - endguestoff) / PAGE_SIZE;	return (vm->pages.log_buffer[page]);    }    page = offset / PAGE_SIZE;    if (page < 0 || page > vm->pages.guest_n_pages) {	log(LOG_WARNING, "plex86: mmap: offset %lx out of range\n",	    (unsigned long) offset);	return -1;    }    return vm->pages.guest[page];}intplex86_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags,	     struct proc * p){    int             error;    vm_t           *vm;    vm = find_vm(p);    if (vm == NULL)	return EINVAL;    switch (cmd) {    case PLEX86_ALLOCVPHYS:	{	    unsigned        arg = *((unsigned *) data);	    guest_cpu_t     guest_cpu;	    if (vm->mon_state != MON_STATE_UNINITIALIZED ||		vm->pages.guest_n_megs != 0)		return EBUSY;	    if (arg > PLEX86_MAX_PHY_MEGS || arg < 4 || (arg & ~0x3) != arg)		return EINVAL;	    /* Allocate memory */	    error = allocVmPages(vm, arg);	    if (error != 0) {		log(LOG_WARNING, "plex86: allocVmPages failed (%d)\n",		    error);		return ENOMEM;	    }	    if (init_guest_phy_mem(vm) != 0) {		log(LOG_ERR, "plex86: init_guest_phy_mem failed\n");		unallocVmPages(vm);		return EFAULT;	    }	    getCpuResetValues(&guest_cpu);	    log(LOG_WARNING, "plex86: cpu.cr0 = 0x%x\n", guest_cpu.cr0);	    if (!init_monitor(vm, 0, 0, &guest_cpu) ||		!setGuestCPU(vm, 0, &guest_cpu) ||		!mapMonitor(vm, guest_cpu.eflags, 0)) {		log(LOG_ERR, "plex86: init_monitor failed\n");		unallocVmPages(vm);		return EFAULT;	    }	    break;	}    case PLEX86_TEARDOWN:	unallocVmPages(vm);	break;    case PLEX86_ALLOCINT:	return EINVAL;    case PLEX86_RELEASEINT:	return EINVAL;    case PLEX86_PRESCANDEPTH:	{	    unsigned long   arg = *(unsigned long *) data;	    if ((arg < PrescanDepthMin) || (arg > PrescanDepthMax)) {		log(LOG_WARNING, "plex86: Requested prescan depth %lu"		    " out of range [%u..%u]\n", arg, PrescanDepthMin,		    PrescanDepthMax);		return EINVAL;	    }	    vm->prescanDepth = (unsigned) arg;	    break;	}    case PLEX86_SETINTR:	ioctlSetIntr(vm, *(unsigned long *) data);	break;    case PLEX86_SET_A20:	{	    unsigned long   arg = *(unsigned long *) data;	    if (!ioctlSetA20E(vm, arg))		return EINVAL;	    break;	}    case PLEX86_MESSAGEQ:	{	    vm_messages_t   msg;	    if (vm->mon_state != MON_STATE_RUNNABLE)		return EINVAL;	    error = copyin(*(void **) data, &msg.header, sizeof msg.header);	    if (error != 0)		return error;	    if ((msg.header.msg_len + sizeof(msg.header)) > sizeof(msg))		return EINVAL;	    if (msg.header.msg_len != 0) {		error = copyin(&((vm_messages_t *) * (void **) data)->msg,			       &msg.msg, msg.header.msg_len);		if (error != 0)		    return error;	    }	    if (ioctlMessageQ(vm, &msg)) {		log(LOG_WARNING, "plex86: ioctlMessageQ failed\n");		return EINVAL;	    }	    error = copyout(&msg, *(void **) data,			    sizeof(msg.header) + msg.header.msg_len);	    return error;	}    case PLEX86_RESET:	break;    case PLEX86_PHYMEM_MOD:	break;    case PLEX86_FORCE_INT:	if (vm->mon_state != MON_STATE_RUNNABLE)	    return -EINVAL;	vm->dbg_force_int = 0x100 | (unsigned) data;	break;    case PLEX86_PRESCANRING3:	{	    unsigned long   arg = *(unsigned long *) data;	    if (arg > PrescanRing3On) {		log(LOG_WARNING,		    "plex86: Requested PrescanRing3 val(%lu) OOB\n",		    arg);		return EINVAL;	    }	    vm->prescanRing3 = arg;	    break;	}    default:	log(LOG_WARNING, "plex86: unknown ioctl %lx\n", cmd);	return EINVAL;    }    return 0;}static voidregister_vm(vm_t * vm, struct proc * p){    struct plex86_hashhead *php;    struct plex86_vmentry *vhp;    php = &plex86_hashtbl[PLEX86_VMHASH(p)];#if DIAGNOSTIC    for (vhp = php->lh_first; vhp != NULL; vhp = vhp->vm_entry.le_next) {	if (vhp->vm_pid == p->p_pid)	    panic("plex86: vm already registered, pid %u\n",		  p->p_pid);    }#endif    vhp = malloc(sizeof(struct plex86_vmentry), M_PLEX86, M_WAITOK);    vhp->vm_pid = p->p_pid;    vhp->vm_vm = vm;    LIST_INSERT_HEAD(php, vhp, vm_entry);}static voidunregister_vm(vm_t * vm, struct proc * p){    struct plex86_hashhead *php;    struct plex86_vmentry *vhp;    php = &plex86_hashtbl[PLEX86_VMHASH(p)];    for (vhp = php->lh_first; vhp != NULL; vhp = vhp->vm_entry.le_next) {	if (vhp->vm_pid == p->p_pid) {	    LIST_REMOVE(vhp, vm_entry);	    free(vhp->vm_vm, M_PLEX86);	    free(vhp, M_PLEX86);	    break;	}    }}static voidunregister_all(struct proc * p){    int             i;    struct plex86_hashhead *php;    struct plex86_vmentry *vhp;    php = &plex86_hashtbl[PLEX86_VMHASH(p)];    if (php == NULL)	return;    for (vhp = php->lh_first; vhp != NULL;	 vhp = vhp->vm_entry.le_next) {#ifdef FREEBSD_PLEX86_DEBUG	printf("plex86: unregister vm %p, pid %u\n",	       vhp->vm_vm, vhp->vm_pid);#endif	LIST_REMOVE(vhp, vm_entry);	if (vhp->vm_vm != NULL)	    free(vhp->vm_vm, M_PLEX86);	if (vhp != NULL)	    free(vhp, M_PLEX86);    }}static vm_t    *find_vm(struct proc * p){    struct plex86_hashhead *php;    struct plex86_vmentry *vhp;    php = &plex86_hashtbl[PLEX86_VMHASH(p)];    for (vhp = php->lh_first; vhp != NULL; vhp = vhp->vm_entry.le_next) {	if (vhp->vm_pid == p->p_pid)	    return vhp->vm_vm;    }    return NULL;}static unsignedretrieve_phy_pages(Bit32u * page, int max_pages, void *addr_v, unsigned size,		   int aligned){    Bit32u          start_addr;    unsigned        n_pages, i;    if (!aligned)	start_addr = (Bit32u) addr_v & ~(PAGE_SIZE - 1);    else {	start_addr = (Bit32u) addr_v;	if (start_addr & (PAGE_SIZE - 1)) {	    log(LOG_WARNING, "plex86: retrieve_phy_pages: address "		"%p not aligned\n", addr_v);	    return 0;	}    }    n_pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;    if (n_pages > max_pages) {	log(LOG_WARNING, "plex86: retrieve_phy_pages: page list "	    "too small\n");	return (0);    }    for (i = 0; i < n_pages; i++) {	page[i] = kvtop((vm_offset_t) start_addr) / PAGE_SIZE;	start_addr += PAGE_SIZE;    }    return n_pages;}unsignedhost_idle(void){#if defined(want_resched)    if (want_resched) {#endif	yield(curproc, NULL); /* XXX */	need_resched(); /* XXX */#if defined(want_resched)    }#endif    printf("resched done\n");    return (CURSIG(curproc) == 0);}void           *host_alloc(unsigned long size){    /*     * XXX - it wants this page-aligned apparently.	 */    if (size <= (PAGE_SIZE / 2))	size = PAGE_SIZE;    return (malloc(size, M_PLEX86, M_WAITOK));}voidhost_free(void *ptr){    free(ptr, M_PLEX86);}unsignedhost_map(Bit32u * page, int max_pages, void *ptr, unsigned size){    return retrieve_phy_pages(page, max_pages, ptr, size, 1);}void           *host_alloc_page(void){    return malloc(PAGE_SIZE, M_PLEX86, M_WAITOK);}voidhost_free_page(void *ptr){    return free(ptr, M_PLEX86);}Bit32uhost_map_page(void *ptr){    Bit32u          u;    if (ptr == NULL)	return 0;    u = kvtop(ptr) / PAGE_SIZE;#if FREEBSD_PLEX86_DEBUG    printf("host_map_page(%p) -> %x\n", ptr, u);#endif    return u;}voidhostprint(char *fmt,...){    va_list         args;    int             ret;    unsigned char   buffer[256];    va_start(args, fmt);    ret = vsnprintf(buffer, 256, fmt, args);    if (ret == -1)	log(LOG_WARNING,	    "plex86: hostprint: vsnprintf returns error.\n");    else	log(LOG_WARNING, "plex86: %s\n", buffer);}static intplex86_modevent(module_t mod, int type, void *data){    linker_file_t   lf;    int             error = 0;    switch (type) {    case MOD_LOAD:	plex86_hashtbl = NULL;	lf = linker_find_file_by_name("plex86");	if (lf == NULL) {	    printf("plex86: can't find linker_file 'plex86'\n");	    return (ENXIO);	}	monitor_pages.startOffset = lf->address;  monitor_pages.startOffsetPageAligned =      monitor_pages.startOffset & 0xfffff000;	if ((monitor_pages.n_pages = retrieve_phy_pages(monitor_pages.page,							PLEX86_MAX_MONITOR_PAGES,							lf->address,							lf->size,							0)) == 0) {	    log(LOG_WARNING, "plex86: could not store physical "		"addresses for monitor pages\n");	    return (ENXIO);	}	plex86_hashtbl = hashinit(PLEX86_VMHASHSIZE,				  M_PLEX86, &plex86_hashmask);	if (!hostModuleInit()) {	    log(LOG_WARNING, "hostModuleInit error\n");	    error = EINVAL;	}	plex86_dev = make_dev(&plex86_cdevsw, 0 /* minor */ , UID_ROOT,			      GID_WHEEL, 0600, "plex86");	printf("plex86: Module loaded.\n");	return (0);	break;    case MOD_UNLOAD:	if (plex86sc.sc_open != 0)	    return (EBUSY);	destroy_dev(plex86_dev);	if (plex86_hashtbl != NULL) {	    free(plex86_hashtbl, M_PLEX86);	}	printf("plex86: Module unloaded.\n");	break;    default:	error = ENXIO;	break;    }    return (error);}MODULE_VERSION(plex86, 1);DEV_MODULE(plex86, plex86_modevent, 0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?