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 + -
显示快捷键?