Cleaned up host-linux.c.

Moved more logic into monitor-host, which is host neutral.
This commit is contained in:
Kevin Lawton 2003-01-03 20:02:54 +00:00
parent 9ca28db2ab
commit d4a8cf56d6
4 changed files with 464 additions and 392 deletions

View File

@ -48,7 +48,7 @@
/************************************************************************/
/* Compatibility macros for older kernels */
/* Compatibility macros & convenience functions for older kernels */
/************************************************************************/
#ifndef EXPORT_NO_SYMBOLS
@ -66,27 +66,30 @@
#endif
#if LINUX_VERSION_CODE < VERSION_CODE(2,1,0)
static inline unsigned long copy_from_user(void *to, const void *from, unsigned long n)
static inline unsigned long
copy_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;
int i;
if ( (i = verify_area(VERIFY_READ, from, n)) != 0 )
return i;
memcpy_fromfs(to, from, n);
return 0;
}
static inline unsigned long copy_to_user(void *to, const void *from, unsigned long n)
static inline unsigned long
copy_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;
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 ... */
* but the THIS_MODULE #define was introduced much later ...
*/
#define THIS_MODULE (&__this_module)
#endif
@ -103,7 +106,7 @@ MODULE_PARM(plex_major, "i");
MODULE_PARM_DESC(plex_major, "major number (default " __MODULE_STRING(PLEX86_MAJOR) ")");
#endif
/* The kernel segment base */
/* The kernel segment base. */
#if LINUX_VERSION_CODE < VERSION_CODE(2,1,0)
# define KERNEL_OFFSET 0xc0000000
#else
@ -111,26 +114,28 @@ MODULE_PARM_DESC(plex_major, "major number (default " __MODULE_STRING(PLEX86_MAJ
#endif
/* File operations */
static int plex86_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
/* 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 *);
static int plex86_release(struct inode *, struct file *);
#else
static void plex86_release(struct inode *, struct file *);
static 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);
static int plex86_mmap(struct file * file, struct vm_area_struct * vma);
#else
static int plex86_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);
static 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 */
/* New License scheme. */
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL"); /* Close enough. */
MODULE_LICENSE("GPL"); /* Close enough. Keeps kernel from complaining. */
#endif
#endif
@ -140,12 +145,12 @@ MODULE_LICENSE("GPL"); /* Close enough. */
/* Structures / Variables */
/************************************************************************/
static int retrieve_vm_pages(Bit32u *page, int max_pages, void *addr, unsigned size);
static unsigned retrieve_phy_pages(Bit32u *page, int max_pages, void *addr, unsigned size);
static int retrieve_vm_pages(Bit32u *page, int max_pages, void *addr,
unsigned size);
static unsigned retrieve_phy_pages(Bit32u *page, int max_pages, void *addr,
unsigned size);
static int retrieve_monitor_pages(void);
monitor_pages_t monitor_pages;
extern unsigned intRedirCount[];
static struct file_operations plex86_fops = {
@ -173,14 +178,14 @@ int plex86_read_procmem(char *, char **, off_t, int, int);
#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 */
};
0, /* dynamic inode */
6, "driver/plex86", /* len, name */
S_IFREG | S_IRUGO, /* mode */
1, 0, 0,
0,
NULL,
&plex86_read_procmem, /* read function */
};
#endif
@ -191,95 +196,95 @@ static struct proc_dir_entry plex86_proc_entry = {
int
init_module(void)
{
int err;
int err;
/* clear uninitialised structures */
memset(&monitor_pages, 0, sizeof(monitor_pages));
/* Clear uninitialised structures. */
memset(&monitor_pages, 0, sizeof(monitor_pages));
/* 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 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 */
/* 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");
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);
proc_register_dynamic(&proc_root, &plex86_proc_entry);
#endif
#endif
/* register /dev/misc/plex86 with devfs */
/* 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");
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 (!retrieve_monitor_pages()) {
printk(KERN_ERR "plex86: retrieve_monitor_pages returned error\n");
err = -EINVAL;
goto fail_retrieve_pages;
}
/* Retrieve the monitor physical pages. */
if ( !retrieve_monitor_pages() ) {
printk(KERN_ERR "plex86: retrieve_monitor_pages returned error\n");
err = -EINVAL;
goto fail_retrieve_pages;
}
/* Kernel independent code to be run when kernel module is loaded. */
if ( !genericModuleInit() ) {
printk(KERN_ERR "plex86: genericModuleInit returned error\n");
err = -EINVAL;
goto fail_cpu_capabilities;
}
/* Kernel independent code to be run when kernel module is loaded. */
if ( !genericModuleInit() ) {
printk(KERN_ERR "plex86: genericModuleInit returned error\n");
err = -EINVAL;
goto fail_cpu_capabilities;
}
/* success */
EXPORT_NO_SYMBOLS;
return(0);
/* Success. */
EXPORT_NO_SYMBOLS;
return(0);
fail_cpu_capabilities:
fail_retrieve_pages:
/* unregister /proc entry */
/* Unregister /proc entry. */
#ifdef CONFIG_PROC_FS
#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
remove_proc_entry("driver/plex86", NULL);
remove_proc_entry("driver/plex86", NULL);
#else
proc_unregister(&proc_root, plex86_proc_entry.low_ino);
proc_unregister(&proc_root, plex86_proc_entry.low_ino);
#endif
#endif
/* unregister device */
unregister_chrdev(plex_major, "plex86");
return err;
/* Unregister device. */
unregister_chrdev(plex_major, "plex86");
return err;
}
void
void
cleanup_module(void)
{
/* unregister device */
unregister_chrdev(plex_major, "plex86");
/* Unregister device. */
unregister_chrdev(plex_major, "plex86");
/* unregister /proc entry */
/* Unregister /proc entry. */
#ifdef CONFIG_PROC_FS
#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
remove_proc_entry("driver/plex86", NULL);
remove_proc_entry("driver/plex86", NULL);
#else
proc_unregister(&proc_root, plex86_proc_entry.low_ino);
proc_unregister(&proc_root, plex86_proc_entry.low_ino);
#endif
#endif
#ifdef CONFIG_DEVFS_FS
devfs_unregister(my_devfs_entry);
devfs_unregister(my_devfs_entry);
#endif
}
@ -298,7 +303,7 @@ plex86_open(struct inode *inode, struct file *filp)
#endif
/* Allocate a VM structure. */
if ( (vm = vmalloc(sizeof(vm_t))) == NULL )
if ( (vm = hostAllocZeroedMem(sizeof(vm_t))) == NULL )
return -ENOMEM;
filp->private_data = vm;
@ -316,28 +321,27 @@ plex86_open(struct inode *inode, struct file *filp)
#endif
plex86_release(struct inode *inode, struct file *filp)
{
vm_t *vm = (vm_t *)filp->private_data;
filp->private_data = NULL;
vm_t *vm = (vm_t *)filp->private_data;
filp->private_data = NULL;
/* Free the virtual memory. */
hostUnreserveGuestPages( vm );
unallocVmPages( vm );
/* Free the virtual memory. */
unreserveGuestPhyPages(vm);
unallocVmPages( vm );
/* Free the VM structure. */
memset( vm, 0, sizeof(*vm) );
vfree( 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;
MOD_DEC_USE_COUNT;
#endif
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,31)
return(0);
return(0);
#endif
}
int
plex86_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
@ -359,116 +363,98 @@ plex86_ioctl(struct inode *inode, struct file *filp,
}
int
int
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)
plex86_mmap(struct file * file, struct vm_area_struct * vma)
#else
plex86_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
#endif
{
vm_t *vm = (vm_t *)file->private_data;
int i, firstpage, nr_pages;
Bit32u *pagesArray;
unsigned stateMask;
vm_t *vm = (vm_t *)file->private_data;
int firstpage, pagesN;
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)
void *inode = NULL; /* Not used; for consistency of passing args. */
#endif
int ret;
/* Must have memory allocated */
if (!vm->pages.guest_n_pages) {
printk(KERN_WARNING "plex86: device not initialized\n");
return -EACCES;
}
/* Private mappings make no sense ... */
if ( !(vma->vm_flags & VM_SHARED) ) {
printk(KERN_WARNING "plex86: private mapping\n");
return -EINVAL;
}
/* Private mappings make no sense ... */
if ( !(vma->vm_flags & VM_SHARED) ) {
printk(KERN_WARNING "plex86: private mapping\n");
return -EINVAL;
}
#if LINUX_VERSION_CODE < VERSION_CODE(2,3,25)
/* To simplify things, allow only page-aligned offsets */
if ( vma->vm_offset & (PAGE_SIZE - 1) ) {
printk(KERN_WARNING "plex86: unaligned offset %08lx\n", vma->vm_offset);
return -EINVAL;
}
/* To simplify things, allow only page-aligned offsets */
if ( vma->vm_offset & (PAGE_SIZE - 1) ) {
printk(KERN_WARNING "plex86: unaligned offset %08lx\n", vma->vm_offset);
return -EINVAL;
}
#endif
/* Map all requested pages in ... */
#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
firstpage = vma->vm_pgoff;
firstpage = vma->vm_pgoff;
#else
firstpage = vma->vm_offset >> PAGE_SHIFT;
firstpage = vma->vm_offset >> PAGE_SHIFT;
#endif
nr_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
pagesN = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
/* The memory map:
* guest physical memory (guest_n_pages)
* log_buffer (1)
* guest_cpu (1)
*/
if ( firstpage == 0 ) {
if (nr_pages != vm->pages.guest_n_pages) {
printk(KERN_WARNING "plex86: mmap of guest phy mem, "
"nr_pages of %u != guest_n_pages of %u\n",
nr_pages, vm->pages.guest_n_pages);
return -EINVAL;
}
/* printk(KERN_WARNING "plex86: found mmap of guest phy memory.\n"); */
pagesArray = &vm->pages.guest[0];
stateMask = VMStateMMapPhyMem;
}
else if ( firstpage == (vm->pages.guest_n_pages+0) ) {
if (nr_pages != 1) {
printk(KERN_WARNING "plex86: mmap of log_buffer, pages>1.\n");
return -EINVAL;
}
/* printk(KERN_WARNING "plex86: found mmap of log_buffer.\n"); */
pagesArray = &vm->pages.log_buffer[0];
stateMask = VMStateMMapPrintBuffer;
}
else if ( firstpage == (vm->pages.guest_n_pages+1) ) {
if (nr_pages != 1) {
printk(KERN_WARNING "plex86: mmap of guest_cpu, pages>1.\n");
return -EINVAL;
}
/* printk(KERN_WARNING "plex86: found mmap of guest_cpu.\n"); */
pagesArray = &vm->pages.guest_cpu;
stateMask = VMStateMMapGuestCPU;
}
else {
printk(KERN_WARNING "plex86: mmap with firstpage of 0x%x.\n", firstpage);
return -EINVAL;
}
ret = genericMMap(vm, inode, file, vma, firstpage, pagesN);
return( - hostConvertPlex86Errno(ret) );
}
/* Sanity check */
int
hostMMap(vm_t *vm, void *iV, void *fV, void *vmaV,
unsigned pagesN, Bit32u *pagesArray)
{
#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)
void *inode = NULL;
#else
struct inode * inode = (struct inode *) iV;
#endif
struct file * file = (struct file *) fV;
struct vm_area_struct * vma = (struct vm_area_struct *) vmaV;
unsigned i;
UNUSED(file);
/* Note: this function returns Plex86Errno style errors, since
* it reports to the hostOS-independent logic.
*/
/* Sanity check. */
#if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
if ( ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) > nr_pages ) {
printk(KERN_WARNING "plex86: mmap sanity checks failed.\n");
return -EINVAL;
}
if ( ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) > pagesN ) {
printk(KERN_WARNING "plex86: mmap sanity checks failed.\n");
return Plex86ErrnoEINVAL;
}
#else
if ( (vma->vm_end - vma->vm_start) > (nr_pages << PAGE_SHIFT) ) {
printk(KERN_WARNING "plex86: mmap sanity checks failed.\n");
return -EINVAL;
}
if ( (vma->vm_end - vma->vm_start) > (pagesN << PAGE_SHIFT) ) {
printk(KERN_WARNING "plex86: mmap sanity checks failed.\n");
return Plex86ErrnoEINVAL;
}
#endif
for ( i = 0; i < nr_pages; i++ ) {
if ( remap_page_range(vma->vm_start + (i << PAGE_SHIFT),
pagesArray[i] << 12,
PAGE_SIZE,
vma->vm_page_prot ) )
/* xxx What about fixing partial remaps? */
return -EAGAIN;
}
for (i = 0; i < pagesN; i++) {
if ( remap_page_range(vma->vm_start + (i << PAGE_SHIFT),
pagesArray[i] << 12,
PAGE_SIZE,
vma->vm_page_prot) )
/* xxx What about fixing partial remaps? */
return Plex86ErrnoEAGAIN;
}
#if LINUX_VERSION_CODE < VERSION_CODE(2,1,0)
/* Enter our inode into the VMA; no need to change the default ops */
vma->vm_inode = inode;
if (!inode->i_count)
inode->i_count++;
/* Enter our inode into the VMA; no need to change the default ops. */
vma->vm_inode = inode;
if (!inode->i_count)
inode->i_count++;
#else
UNUSED(inode);
#endif
vm->vmState |= stateMask;
return 0;
return 0; /* OK. */
}
@ -480,235 +466,220 @@ plex86_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vm
int
plex86_read_procmem(char *buf, char **start, off_t offset,
#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
int len
int len
#else
int len, int unused
int len, int unused
#endif
)
)
{
unsigned i;
len = 0;
len += sprintf(buf, "monitor-->host interrupt reflection counts\n");
for (i=0; i<256; i++) {
unsigned i;
len = 0;
len += sprintf(buf, "monitor-->host interrupt reflection counts\n");
for (i=0; i<256; i++) {
if (intRedirCount[i])
len += sprintf(buf+len, " 0x%2x:%10u\n", i, intRedirCount[i]);
len += sprintf(buf+len, " 0x%2x:%10u\n", i, intRedirCount[i]);
}
return(len);
return(len);
}
#warning "Consolidate retrieve_XYZ() functions?"
int
retrieve_monitor_pages(void)
{
/*
* Retrieve start address and size of this module.
*
* Note that with old kernels, we cannot access the module info (size),
* hence we rely on the fact that Linux lets at least one page of
* virtual address space unused after the end of the module.
*/
#ifdef THIS_MODULE
void *start_addr = THIS_MODULE;
unsigned size = THIS_MODULE->size;
#else
void *start_addr = &mod_use_count_;
unsigned size = 0x10000000; /* Actual size determined below */
#endif
int n_pages;
n_pages = retrieve_vm_pages(monitor_pages.page, PLEX86_MAX_MONITOR_PAGES,
start_addr, size);
if (n_pages == 0) {
printk(KERN_ERR "plex86: retrieve_vm_pages returned error.\n");
return( 0 ); /* Error. */
}
printk(KERN_WARNING "plex86: %u monitor pages located\n", n_pages);
monitor_pages.startOffset = (Bit32u)start_addr;
monitor_pages.startOffsetPageAligned = monitor_pages.startOffset & 0xfffff000;
monitor_pages.n_pages = n_pages;
return( n_pages );
}
int
retrieve_vm_pages(Bit32u *page, int max_pages, void *addr, unsigned size)
{
/*
* Grrr. There doesn't seem to be an exported mechanism to retrieve
* the physical pages underlying a vmalloc()'ed area. We do it the
* hard way ...
*/
pageEntry_t *host_pgd;
Bit32u host_cr3;
Bit32u start_addr;
int n_pages;
int i;
/*
* Grrr. There doesn't seem to be an exported mechanism to retrieve
* the physical pages underlying a vmalloc()'ed area. We do it the
* hard way ...
*/
pageEntry_t *host_pgd;
Bit32u host_cr3;
Bit32u start_addr;
int n_pages;
int i;
start_addr = ((Bit32u)addr) & 0xfffff000;
n_pages = BytesToPages( (((Bit32u)addr) - start_addr) + size );
start_addr = ((Bit32u)addr) & 0xfffff000;
n_pages = BytesToPages( (((Bit32u)addr) - start_addr) + size );
if (!addr) {
printk(KERN_WARNING "plex86: retrieve_vm_pages: addr NULL!\n");
return 0;
}
if ( n_pages > max_pages ) {
printk(KERN_WARNING "plex86: retrieve_vm_pages: not enough pages!\n");
printk(KERN_WARNING "plex86: npages(%u) > max_pages(%u)\n",
n_pages, max_pages);
return 0;
}
asm volatile ("movl %%cr3, %0" : "=r" (host_cr3));
host_pgd = (pageEntry_t *)(phys_to_virt(host_cr3 & ~0xfff));
for (i = 0; i < n_pages; i++)
{
Bit32u virt_addr = start_addr + i*PAGESIZE + KERNEL_OFFSET;
pageEntry_t *pde = host_pgd + (virt_addr >> 22);
pageEntry_t *pte = (pageEntry_t *)phys_to_virt(pde->fields.base << 12)
+ ((virt_addr >> 12) & 0x3ff);
/* If page isn't present, assume end of area */
if ( !pde->fields.P || ! pte->fields.P )
{
n_pages = i;
break;
}
/* Abort if our page list is too small */
if (i >= max_pages)
{
printk(KERN_WARNING "plex86: page list is too small!\n");
printk(KERN_WARNING "plex86: n_pages=%u, max_pages=%u\n",
n_pages, max_pages);
return 0;
}
page[i] = pte->fields.base;
if (!addr) {
printk(KERN_WARNING "plex86: retrieve_vm_pages: addr NULL!\n");
return 0;
}
return n_pages;
}
if ( n_pages > max_pages ) {
printk(KERN_WARNING "plex86: retrieve_vm_pages: not enough pages!\n");
printk(KERN_WARNING "plex86: npages(%u) > max_pages(%u)\n",
n_pages, max_pages);
return 0;
}
int
retrieve_monitor_pages(void)
{
/*
* Retrieve start address and size of this module.
*
* Note that with old kernels, we cannot access the module info (size),
* hence we rely on the fact that Linux lets at least one page of
* virtual address space unused after the end of the module.
*/
#ifdef THIS_MODULE
void *start_addr = THIS_MODULE;
unsigned size = THIS_MODULE->size;
#else
void *start_addr = &mod_use_count_;
unsigned size = 0x10000000; /* Actual size determined below */
#endif
asm volatile ("movl %%cr3, %0" : "=r" (host_cr3));
host_pgd = (pageEntry_t *)(phys_to_virt(host_cr3 & ~0xfff));
int n_pages;
for (i = 0; i < n_pages; i++) {
Bit32u virt_addr = start_addr + i*PAGESIZE + KERNEL_OFFSET;
pageEntry_t *pde = host_pgd + (virt_addr >> 22);
pageEntry_t *pte = (pageEntry_t *)phys_to_virt(pde->fields.base << 12)
+ ((virt_addr >> 12) & 0x3ff);
n_pages = retrieve_vm_pages(monitor_pages.page, PLEX86_MAX_MONITOR_PAGES,
start_addr, size);
if (n_pages == 0) {
printk(KERN_ERR "plex86: retrieve_vm_pages returned error.\n");
return( 0 ); /* Error. */
/* If page isn't present, assume end of area. */
if ( !pde->fields.P || ! pte->fields.P ) {
n_pages = i;
break;
}
/* Abort if our page list is too small */
if (i >= max_pages) {
printk(KERN_WARNING "plex86: page list is too small!\n");
printk(KERN_WARNING "plex86: n_pages=%u, max_pages=%u\n",
n_pages, max_pages);
return 0;
}
printk(KERN_WARNING "plex86: %u monitor pages located\n", n_pages);
monitor_pages.startOffset = (Bit32u)start_addr;
monitor_pages.startOffsetPageAligned =
monitor_pages.startOffset & 0xfffff000;
monitor_pages.n_pages = n_pages;
return( n_pages );
page[i] = pte->fields.base;
}
return n_pages;
}
void
hostReserveGuestPages(vm_t *vm)
{
vm_pages_t *pg = &vm->pages;
unsigned p;
/*
* As we want to map these pages to user space, we need to mark
* them as 'reserved' pages by setting the PG_reserved bit.
*
* This has the effect that:
* - remap_page_range accepts them as candidates for remapping
* - the swapper does *not* try to swap these pages out, even
* after they are mapped to user space
*/
#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
for (p = 0; p < pg->guest_n_pages; p++)
set_bit(PG_reserved, &((mem_map + pg->guest[p])->flags));
set_bit(PG_reserved, &((mem_map + pg->log_buffer[0])->flags));
set_bit(PG_reserved, &((mem_map + pg->guest_cpu)->flags));
#else
for (p = 0; p < pg->guest_n_pages; p++)
mem_map_reserve(pg->guest[p]);
mem_map_reserve(pg->log_buffer[0]);
mem_map_reserve(pg->guest_cpu);
#endif
}
void
hostUnreserveGuestPages(vm_t *vm)
{
vm_pages_t *pg = &vm->pages;
unsigned p;
/* Remove the PG_reserved flags before returning the pages */
#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
for (p = 0; p < pg->guest_n_pages; p++)
clear_bit(PG_reserved, &((mem_map + pg->guest[p])->flags));
clear_bit(PG_reserved, &((mem_map + pg->log_buffer[0])->flags));
clear_bit(PG_reserved, &((mem_map + pg->guest_cpu)->flags));
#else
for (p = 0; p < pg->guest_n_pages; p++)
mem_map_unreserve(pg->guest[p]);
mem_map_unreserve(pg->log_buffer[0]);
mem_map_unreserve(pg->guest_cpu);
#endif
}
unsigned
retrieve_phy_pages(Bit32u *page, int max_pages, void *addr_v, unsigned size)
{
/*
* Grrr. There doesn't seem to be an exported mechanism to retrieve
* the physical pages underlying a vmalloc()'ed area. We do it the
* hard way ...
*/
pageEntry_t *host_pgd;
Bit32u host_cr3;
/*Bit32u start_addr = (Bit32u)addr & ~(PAGESIZE-1); */
/*int n_pages = ((Bit32u)addr + size - start_addr + PAGESIZE-1) >> 12; */
int i;
Bit8u *addr;
unsigned n_pages;
/*
* Grrr. There doesn't seem to be an exported mechanism to retrieve
* the physical pages underlying a vmalloc()'ed area. We do it the
* hard way ...
*/
pageEntry_t *host_pgd;
Bit32u host_cr3;
/*Bit32u start_addr = (Bit32u)addr & ~(PAGESIZE-1); */
/*int n_pages = ((Bit32u)addr + size - start_addr + PAGESIZE-1) >> 12; */
int i;
Bit8u *addr;
unsigned n_pages;
addr = (Bit8u *) addr_v;
if ( ((Bit32u)addr) & 0xfff ) {
printk(KERN_ERR "plex86: retrieve_phy_pages: not aligned!\n");
addr = (Bit8u *) addr_v;
if ( ((Bit32u)addr) & 0xfff ) {
printk(KERN_ERR "plex86: retrieve_phy_pages: not aligned!\n");
return 0;
}
n_pages = BytesToPages(size);
if (!addr) {
printk(KERN_ERR "plex86: retrieve_phy_pages: addr NULL!\n");
return 0;
}
if ( n_pages > max_pages ) {
printk(KERN_ERR "plex86: retrieve_phy_pages: n=%u > max=%u\n",
n_pages, max_pages);
return 0;
}
asm volatile ("movl %%cr3, %0" : "=r" (host_cr3));
host_pgd = (pageEntry_t *)(phys_to_virt(host_cr3 & ~0xfff));
for (i = 0; i < n_pages; i++) {
Bit32u laddr;
pageEntry_t *pde;
pageEntry_t *pte;
laddr = KERNEL_OFFSET + ((Bit32u) addr);
pde = host_pgd + (laddr >> 22);
pte = ((pageEntry_t *)phys_to_virt(pde->fields.base << 12))
+ ((laddr >> 12) & 0x3ff);
if ( !pde->fields.P ) {
printk(KERN_ERR "plex86: retrieve_phy_pages: "
"PDE.P==0: i=%u, n=%u laddr=0x%x\n", i, n_pages, laddr);
return 0;
}
n_pages = BytesToPages(size);
if (!addr) {
printk(KERN_ERR "plex86: retrieve_phy_pages: addr NULL!\n");
if ( !pte->fields.P ) {
printk(KERN_ERR "plex86: retrieve_phy_pages: "
"PTE.P==0: i=%u, n=%u laddr=0x%x\n", i, n_pages, laddr);
return 0;
}
if ( n_pages > max_pages ) {
printk(KERN_ERR "plex86: retrieve_phy_pages: n=%u > max=%u\n",
n_pages, max_pages);
return 0;
}
asm volatile ("movl %%cr3, %0" : "=r" (host_cr3));
host_pgd = (pageEntry_t *)(phys_to_virt(host_cr3 & ~0xfff));
for (i = 0; i < n_pages; i++) {
Bit32u laddr;
pageEntry_t *pde;
pageEntry_t *pte;
laddr = KERNEL_OFFSET + ((Bit32u) addr);
pde = host_pgd + (laddr >> 22);
pte = ((pageEntry_t *)phys_to_virt(pde->fields.base << 12))
+ ((laddr >> 12) & 0x3ff);
if ( !pde->fields.P ) {
printk(KERN_ERR "plex86: retrieve_phy_pages: PDE.P==0: i=%u, n=%u laddr=0x%x\n",
i, n_pages, laddr);
return 0;
}
if ( !pte->fields.P ) {
printk(KERN_ERR "plex86: retrieve_phy_pages: PTE.P==0: i=%u, n=%u laddr=0x%x\n",
i, n_pages, laddr);
return 0;
}
page[i] = pte->fields.base;
addr += 4096;
}
return(n_pages);
page[i] = pte->fields.base;
addr += 4096;
}
return(n_pages);
}
/************************************************************************/
/* The requisite host-specific functions. */
/************************************************************************/
/************************************************************************
* The requisite host-specific functions. An implementation of each of
* these functions needs to be offered for each host-XYZ.c file.
************************************************************************/
void
hostReservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages)
{
unsigned p;
/*
* As we want to map these pages to user space, we need to mark
* them as 'reserved' pages by setting the PG_reserved bit.
*
* This has the effect that:
* - remap_page_range accepts them as candidates for remapping
* - the swapper does *not* try to swap these pages out, even
* after they are mapped to user space
*/
for (p = 0; p < nPages; p++)
#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
set_bit(PG_reserved, &((mem_map + hostPhyPages[p])->flags));
#else
mem_map_reserve(hostPhyPages[p]);
#endif
}
void
hostUnreservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages)
{
unsigned p;
/* Remove the PG_reserved flags before returning the pages. */
for (p = 0; p < nPages; p++)
#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
clear_bit(PG_reserved, &((mem_map + hostPhyPages[p])->flags));
#else
mem_map_unreserve(hostPhyPages[p]);
#endif
}
unsigned
hostIdle(void)
@ -800,6 +771,8 @@ hostConvertPlex86Errno(unsigned ret)
case Plex86ErrnoENOMEM: return(ENOMEM);
case Plex86ErrnoEFAULT: return(EFAULT);
case Plex86ErrnoEINVAL: return(EINVAL);
case Plex86ErrnoEACCES: return(EACCES);
case Plex86ErrnoEAGAIN: return(EAGAIN);
default:
printk(KERN_ERR "plex86: ioctlAllocVPhys: case %u\n", ret);
return(EINVAL);

View File

@ -56,12 +56,12 @@ main(int argc, char *argv[])
}
void
hostReserveGuestPages(vm_t *vm)
hostReservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages)
{
}
void
hostUnreserveGuestPages(vm_t *vm)
hostUnreservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages)
{
}

View File

@ -36,6 +36,11 @@
#include "eflags.h"
#include "guest_context.h"
#ifndef UNUSED
# define UNUSED(x) ((void)(x))
#endif
/* Method1: push event info (CPU pushes error code before) */
typedef struct
{
@ -481,6 +486,7 @@ typedef struct {
extern monitor_pages_t monitor_pages;
extern cpuid_info_t cpuid_info;
extern unsigned intRedirCount[];
@ -566,6 +572,8 @@ vm_rdtsc(void) {
#define Plex86ErrnoENOMEM 2
#define Plex86ErrnoEFAULT 3
#define Plex86ErrnoEINVAL 4
#define Plex86ErrnoEACCES 5
#define Plex86ErrnoEAGAIN 6
#define vm_save_flags(x) \
asm volatile("pushfl ; popl %0": "=g" (x): :"memory")
@ -588,6 +596,10 @@ int ioctlGeneric(vm_t *vm, void *inode, void *filp,
int ioctlExecute(vm_t *vm, plex86IoctlExecute_t *executeMsg);
unsigned ioctlAllocVPhys(vm_t *vm, unsigned long arg);
void copyGuestStateToUserSpace(vm_t *vm);
void unreserveGuestPhyPages(vm_t *vm);
void reserveGuestPhyPages(vm_t *vm);
int genericMMap(vm_t *vm, void *inode, void *file, void *vma,
unsigned firstPage, unsigned pagesN);
/* These are the functions that the host-OS-specific file of the
* plex86 device driver must define.
@ -602,13 +614,15 @@ unsigned hostGetAllocedMemPhyPages(Bit32u *page, int max_pages, void *ptr,
Bit32u hostGetAllocedPagePhyPage(void *ptr);
void hostPrint(char *fmt, ...);
Bit32u hostKernelOffset(void);
void hostReserveGuestPages(vm_t *vm);
void hostUnreserveGuestPages(vm_t *vm);
void hostReservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages);
void hostUnreservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages);
int hostConvertPlex86Errno(unsigned ret);
unsigned hostMMapCheck(void *i, void *f);
void hostModuleCountReset(vm_t *vm, void *inode, void *filp);
unsigned long hostCopyFromUser(void *to, void *from, unsigned long len);
unsigned long hostCopyToUser(void *to, void *from, unsigned long len);
int hostMMap(vm_t *vm, void *iV, void *fV, void *vmaV,
unsigned pagesN, Bit32u *pagesArray);
#endif /* HOST Space */

View File

@ -25,14 +25,15 @@
#define IN_HOST_SPACE
#include "monitor.h"
monitor_pages_t monitor_pages;
/* Instrumentation of how many hardware interrupts were redirected
* to the host, while the VM was running.
*/
#warning "Check for SMP issues on these globals"
unsigned intRedirCount[256];
cpuid_info_t hostCpuIDInfo;
static int initIDTSlot(vm_t *vm, unsigned vec, int type);
static void mapMonPages(vm_t *vm, Bit32u *, unsigned, Bit32u *, page_t *,
unsigned user, unsigned writable, char *name);
@ -744,7 +745,8 @@ ioctlGeneric(vm_t *vm, void *inode, void *filp,
*/
vm->vmState &= ~VMStateMMapAll;
hostUnreserveGuestPages(vm);
#warning "Add check before calling unreserveGuestPhyPages()"
unreserveGuestPhyPages(vm);
unallocVmPages(vm);
/* Reset state to only FD opened. */
@ -769,6 +771,7 @@ ioctlGeneric(vm_t *vm, void *inode, void *filp,
return ret;
}
#warning "PLEX86_RESET should only conditionally compiled for debugging."
/*
* For debugging, when the module gets hosed, this is a way
* to reset the in-use count, so we can rmmod it.
@ -1262,11 +1265,11 @@ hostPrint("plex86: vm_t size is %u\n", sizeof(vm_t));
}
/* Mark guest pages as reserved (for mmap()). */
hostReserveGuestPages( vm );
reserveGuestPhyPages(vm);
/* Initialize the guests physical memory. */
if ( initGuestPhyMem(vm) ) {
hostUnreserveGuestPages(vm);
unreserveGuestPhyPages(vm);
unallocVmPages(vm);
return -Plex86ErrnoEFAULT;
}
@ -1274,7 +1277,7 @@ hostPrint("plex86: vm_t size is %u\n", sizeof(vm_t));
/* Initialize the monitor. */
if ( !initMonitor(vm) ||
!mapMonitor(vm) ) {
hostUnreserveGuestPages(vm);
unreserveGuestPhyPages(vm);
unallocVmPages(vm);
return -Plex86ErrnoEFAULT;
}
@ -1688,4 +1691,86 @@ initShadowPaging(vm_t *vm)
xxxpanic(vm, "monPagingRemap: BadUsage4PDir\n");
}
#endif
}
void
reserveGuestPhyPages(vm_t *vm)
{
/* Mark guest pages as reserved (for mmap()). */
hostReservePhyPages(vm, vm->pages.guest, vm->pages.guest_n_pages);
hostReservePhyPages(vm, vm->pages.log_buffer, LOG_BUFF_PAGES);
hostReservePhyPages(vm, &vm->pages.guest_cpu, 1);
}
void
unreserveGuestPhyPages(vm_t *vm)
{
hostUnreservePhyPages(vm, vm->pages.guest, vm->pages.guest_n_pages);
hostUnreservePhyPages(vm, vm->pages.log_buffer, LOG_BUFF_PAGES);
hostUnreservePhyPages(vm, &vm->pages.guest_cpu, 1);
}
int
genericMMap(vm_t *vm, void *inode, void *file, void *vma, unsigned firstPage,
unsigned pagesN)
{
unsigned stateMask;
Bit32u *pagesArray;
int ret;
/* The memory map:
* guest physical memory (guest_n_pages)
* log_buffer (1)
* guest_cpu (1)
*/
/* Must have memory allocated. */
if (!vm->pages.guest_n_pages) {
hostPrint("plex86: genericMMap: device not initialized\n");
return Plex86ErrnoEACCES;
}
if ( firstPage == 0 ) {
if (pagesN != vm->pages.guest_n_pages) {
hostPrint("plex86: mmap of guest phy mem, "
"pagesN of %u != guest_n_pages of %u\n",
pagesN, vm->pages.guest_n_pages);
return Plex86ErrnoEINVAL;
}
/* hostPrint("plex86: found mmap of guest phy memory.\n"); */
pagesArray = &vm->pages.guest[0];
stateMask = VMStateMMapPhyMem;
}
else if ( firstPage == (vm->pages.guest_n_pages+0) ) {
if (pagesN != 1) {
hostPrint("plex86: mmap of log_buffer, pages>1.\n");
return Plex86ErrnoEINVAL;
}
/* hostPrint("plex86: found mmap of log_buffer.\n"); */
pagesArray = &vm->pages.log_buffer[0];
stateMask = VMStateMMapPrintBuffer;
}
else if ( firstPage == (vm->pages.guest_n_pages+1) ) {
if (pagesN != 1) {
hostPrint("plex86: mmap of guest_cpu, pages>1.\n");
return Plex86ErrnoEINVAL;
}
/* hostPrint("plex86: found mmap of guest_cpu.\n"); */
pagesArray = &vm->pages.guest_cpu;
stateMask = VMStateMMapGuestCPU;
}
else {
hostPrint("plex86: mmap with firstPage of 0x%x.\n", firstPage);
return Plex86ErrnoEINVAL;
}
/* Call the hostOS-specific mmap code. */
ret = hostMMap(vm, inode, file, vma, pagesN, pagesArray);
if (ret != 0) {
/* Host-specific mmap code returned an error. Return that. */
return( ret );
}
vm->vmState |= stateMask;
return 0; /* OK. */
}