0768d01522
new experimental stripped-down version of plex86, which is now a user-code-only VM. I ripped out all the fancy stuff in plex86, such that under that right conditions, user-code (protection level 3) can run at near native speeds inside the plex86 VM. The general idea is that bochs emulates all the initial real-mode code, and guest kernel code (protection level 0). When it senses the right conditions (like the context switches to user-code), a shim is called to execute the guest inside the plex86 VM. All guest-generated faults/exceptions are then forwarded back to bochs to be handled in the emulator. Actually, I'm not yet adding the mods to the bochs code (other than the shim code which is in a separate file), until I hear that we're back in a more development mode with bochs after the 2.0 release. The plex86 subdirectory is really a separate project. It's just more convenient to co-develop it with bochs for now. Both projects are currently LGPL, but each should be taken to be a separate project, and have their own license file. Plex86 (it's only a kernel driver now) could ultimately be used with other projects, as it's modular. I talked with Bryce, and we both agreed it's OK to keep plex86 as a subdir in bochs for now.
220 lines
4.0 KiB
C
220 lines
4.0 KiB
C
#include <Drivers.h>
|
|
#include <KernelExport.h>
|
|
#include <OS.h>
|
|
#include <SupportDefs.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#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;
|
|
}
|
|
|