#include #include #include #include #include #include #include #include "plex86.h" #include "monitor.h" #define read_flags() ({ \ unsigned int __dummy; \ __asm__( \ "pushfl\n\t" \ "popl %0\n\t" \ :"=r" (__dummy)); \ __dummy; \ }) #define write_flags(x) \ __asm__("push %0\n\tpopfl\n\t": :"r" (x)) struct cookie { sem_id sem; int mon_ok; uint32 irq_cnt[17]; }; static status_t driver_open(const char *name, ulong flags, void **_cookie) { struct cookie *cookie; status_t err; cookie = calloc(sizeof(*cookie), 1); if (!cookie) return ENOMEM; cookie->sem = create_sem(1, "plex86 mutex"); if (cookie->sem < 0) { err = cookie->sem; goto err1; } *_cookie = cookie; return B_OK; err1: free(cookie); return err; } static status_t driver_close(void *cookie) { return B_OK; } static status_t driver_free(void *_cookie) { struct cookie *cookie = (struct cookie *)_cookie; delete_sem(cookie->sem); free(cookie); return B_OK; } static status_t driver_read(void *cookie, off_t pos, void *buf, size_t *count) { return B_OK; } static status_t driver_write(void *cookie, off_t pos, const void *buf, size_t *count) { return B_OK; } static status_t driver_ioctl(void *_cookie, ulong cmd, void *buf, size_t len) { struct cookie *cookie = (struct cookie *)_cookie; uint32 cr0, arg, eflags_orig; uchar soft_int_vector; status_t err; arg = *(uint32 *)buf; switch (cmd) { /* Allocate unpaged memory for the VM. */ /* arg is the number of megabytes to allocate */ /* Memory returned must not be pageable by the */ /* host OS, since the VM monitor will run in this */ /* memory as well. Perhaps later, we can let */ /* the guest OS run in paged memory and reflect */ /* the page faults back to the host OS. */ case 0x6b02: acquire_sem(cookie->sem); init_monitor(MASTER_PIC_BASE_VECTOR, SLAVE_PIC_BASE_VECTOR, IRQ16_BASE_VECTOR); cookie->mon_ok = 1; release_sem(cookie->sem); return B_OK; case 0x6b03: /* linux-specific hack, unnecessary under BeOS */ return B_OK; /* run guest context for a time slice */ case 0x6b04: { cpu_status ps; acquire_sem(cookie->sem); if (!cookie->mon_ok) { release_sem(cookie->sem); return EPERM; } ps = disable_interrupts(); /* clear NT/IF/TF */ eflags_orig = read_flags(); write_flags(eflags_orig & ~0x00004300); __host2guest(); write_flags(eflags_orig & ~0x00000200); restore_interrupts(ps); switch ( monitor_info.ret_because ) { case RET_BECAUSE_IRQ: /* reported vector is actually the IRQ# */ soft_int_vector = MASTER_PIC_BASE_VECTOR + monitor_info.vector; soft_int(soft_int_vector); cookie->irq_cnt[monitor_info.vector]++; dprintf("plex86: irq %u\n", monitor_info.vector); err = B_OK; break; case RET_BECAUSE_INT: dprintf("plex86: int %u\n", monitor_info.vector); err = EFAULT; break; case RET_BECAUSE_EXC: dprintf("plex86: exc %u\n", monitor_info.vector); err = EFAULT; break; case RET_BECAUSE_TEST: dprintf("plex86: test\n"); err = B_OK; break; default: dprintf("plex86: unknown ret_because\n"); err = B_OK; break; } release_sem(cookie->sem); return err; } case 0x6b05: /* tear down VM environment */ acquire_sem(cookie->sem); cookie->mon_ok = 0; release_sem(cookie->sem); return B_OK; } return ENOSYS; } device_hooks driver_device = { driver_open, driver_close, driver_free, driver_ioctl, driver_read, driver_write }; status_t init_driver (void) { return B_OK; } void uninit_driver(void) { } const char ** publish_devices(void) { static const char *driver_names[] = { "misc/plex86", NULL }; return (const char **)driver_names; } device_hooks * find_device(const char *name) { return &driver_device; }