Commit f0735fd0 authored by Charlie Jacobsen's avatar Charlie Jacobsen Committed by Vikram Narayanan

Driver code and interface for loading a blob in an lcd (untested).

User code calls ioctl with LCD_RUN_BLOB ioctl number and
lcd_blob_info (containing userspace address of blob and
blob order) -- defined in public include/linux/lcd-domains.h.

The blob must be N pages, and N must be a power of 2 (for
easy driver code). blob_order = log2(N). The blob consists
of machine instructions that are loaded in the lcd and
executed. The machine instructions cannot access any memory,
including the stack (for now, until gv paging is in place).

-- Added lcd_arch_set_pc for setting the lcd's program counter.
-- Added driver code in lcd-domains.c for handling the ioctl
   request, loading the blob from user space into a fresh lcd,
   and running the lcd (in a loop).
parent e0ca0ea1
......@@ -184,6 +184,11 @@ int lcd_arch_ept_map_gpa_to_hpa(struct lcd_arch *vcpu, u64 gpa, u64 hpa,
* Simple routine combinding ept walk and get.
*/
int lcd_arch_ept_gpa_to_hpa(struct lcd_arch *vcpu, u64 gpa, u64 *hpa_out);
/**
* Set the lcd's program counter to the guest physical address
* gpa.
*/
int lcd_arch_set_pc(struct lcd_arch *vcpu, u64 gpa);
/*
* GDT Layout
......
......@@ -2590,6 +2590,13 @@ int lcd_arch_run(struct lcd_arch *vcpu)
return ret;
}
/* LCD RUNTIME ENV -------------------------------------------------- */
int lcd_arch_set_pc(struct lcd_arch *vcpu, u64 gpa)
{
vcpu->regs[LCD_ARCH_REGS_RIP] = gpa;
}
/* EXPORTS -------------------------------------------------- */
EXPORT_SYMBOL(lcd_arch_init);
......@@ -2602,6 +2609,7 @@ EXPORT_SYMBOL(lcd_arch_ept_set);
EXPORT_SYMBOL(lcd_arch_ept_hpa);
EXPORT_SYMBOL(lcd_arch_ept_map_gpa_to_hpa);
EXPORT_SYMBOL(lcd_arch_ept_gpa_to_hpa);
EXPORT_SYMBOL(lcd_arch_set_pc);
/* DEBUGGING -------------------------------------------------- */
......
......@@ -2,11 +2,11 @@
#define LCD_DOMAINS_H
/*
* lcd.h - interface to LCD domains
*
* Author: Anton Burtsev
* lcd-domains.h - public header for LCD support
*/
#include <linux/types.h>
/*
* IOCTL interface
*/
......@@ -14,10 +14,16 @@
/* FIXME: this must be reserved in miscdevice.h */
#define LCD_MINOR 234
#define LCD_LOAD_PV_KERNEL _IOR(LCD_MINOR, 0x01, struct lcd_pv_kernel_config)
struct lcd_pv_kernel_config {
char *file;
} __attribute__((packed));
struct lcd_blob_info {
unsigned char *blob;
unsigned int blob_order;
} __attribute__((packed));
#define LCD_LOAD_PV_KERNEL _IOR(LCD_MINOR, 0x01, struct lcd_pv_kernel_config)
#define LCD_RUN_BLOB _IOR(LCD_MINOR, 0x02, struct lcd_blob_info)
#endif /* LCD_DOMAINS_H */
......@@ -21,33 +21,243 @@
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("LCD driver");
/* run blob -------------------------------------------------- */
static int lcd_do_run_blob_once(struct lcd *lcd)
{
int r;
r = lcd_arch_run(lcd->lcd_arch);
if (r < 0) {
printk(KERN_ERR "lcd_do_run_blob_once: error running blob\n");
goto out;
}
switch(r) {
case LCD_ARCH_STATUS_PAGE_FAULT:
/*
* Paging shouldn't be needed for blob (blob shouldn't
* use instructions that access memory, for now)
*/
printk(KERN_ERR "lcd_run_blob: page fault\n");
r = -EIO;
goto out;
break;
case LCD_ARCH_STATUS_EXT_INTR:
/*
* Continue
*/
printk(KERN_ERR "lcd_run_blob: got external intr\n");
r = 0;
goto out;
case LCD_ARCH_STATUS_EPT_FAULT:
/*
* EPT should everything mapped the blob needs, so
* there's a problem. Quit.
*/
printk(KERN_ERR "lcd_run_blob: ept fault\n");
r = -EIO;
goto out;
case LCD_ARCH_STATUS_CR3_ACCESS:
/*
* %cr3 shouldn't be accessed for simple blobs (for
* now). Quit.
*/
printk(KERN_ERR "lcd_run_blob: cr3 access\n");
r = -EIO;
goto out;
case LCD_ARCH_STATUS_SYSCALL:
/*
* Only allow yield syscalls for now
*/
syscall_id = LCD_ARCH_GET_SYSCALL_NUM(lcd->lcd_arch);
printk(KERN_ERR "lcd_run_blob: handling syscall %d\n",
syscall_id);
if (syscall_id != LCD_SYSCALL_YIELD) {
printk(KERN_ERR "lcd_run_blob: unexpected syscall id %d\n",
syscall_id);
r = -EIO;
goto out;
} else {
printk(KERN_ERR "lcd_run_blob: lcd yielded, exiting lcd...\n");
r = 0;
goto out;
}
}
out:
return r;
}
static int lcd_do_run_blob(struct lcd *lcd)
{
int r;
while (1) {
r = lcd_do_run_blob_once(lcd);
if (r)
return r;
}
}
static int lcd_load_blob(struct lcd *lcd, unsigned char *blob,
unsigned int blob_order)
{
u64 blob_hpa_base;
u64 blob_gpa_base;
u64 off;
unsigned int blob_size;
/*
* Map blob in lcd, starting at LCD_ARCH_FREE
*/
blob_size = 1 << blob_order;
blob_hpa_base = __pa((u64)blob);
blob_gpa_base = LCD_ARCH_FREE;
for (off = 0; off < blob_size; off += PAGE_SIZE) {
if (lcd_arch_ept_map_gpa_to_hpa(lcd->lcd_arch,
/* gpa */
blob_gpa_base + off,
/* hpa */
blob_hpa_base + off,
/* create */
1,
/* no overwrite */
0)) {
printk(KERN_ERR "lcd_load_blob: error mapping blob at offset %lx\n",
off);
return -EIO;
}
}
/*
* Set program counter to start of free mem
*/
if (lcd_arch_set_pc(lcd->lcd_arch, LCD_ARCH_FREE)) {
printk(KERN_ERR "lcd_load_blob: error setting prgm ctr.\n");
return -EIO;
}
}
static int lcd_run_blob(struct lcd_blob_info *bi)
{
struct lcd *lcd;
int r;
unsigned char *blob;
int syscall_id;
/*
* Sanity check blob order
*/
if (bi->blob_order > 4) {
printk(KERN_ERR "lcd_run_blob: blob is bigger than 16 pgs\n");
r = -EINVAL;
goto fail1;
}
/*
* Load blob mem
*/
blob = (unsigned char *)__get_free_pages(GFP_KERNEL, bi->blob_order);
if (!blob) {
printk(KERN_ERR "lcd_run_blob: couldn't alloc mem for blob\n");
r = -ENOMEM;
goto fail2;
}
/*
* Copy blob
*/
r = copy_from_user(blob, (void __user *)bi->blob, (1 << bi->order));
if (r) {
printk(KERN_ERR "lcd_run_blob: error copying blob\n");
goto fail3;
}
/*
* Alloc and init lcd
*/
lcd = (struct lcd *)kmalloc(sizeof(*lcd), GFP_KERNEL);
if (!lcd) {
printk(KERN_ERR "lcd_run_blob: error alloc'ing lcd\n");
r = -ENOMEM;
goto fail4;
}
lcd->lcd_arch = lcd_arch_create();
if(!lcd->lcd_arch) {
printk(KERN_ERR "lcd_run_blob: error alloc'ing lcd_arch\n");
r = -ENOMEM;
goto fail5;
}
/*
* Load blob in lcd
*/
r = lcd_load_blob(lcd, blob);
if (r) {
printk(KERN_ERR "lcd_run_blob: error loading blob in lcd\n");
r = -EIO;
goto fail6;
}
/*
* Run blob until it yields or fails
*/
r = lcd_do_run_blob(lcd);
goto done;
done:
fail7:
fail6:
lcd_arch_destroy(lcd->lcd_arch);
fail5:
kfree(lcd);
fail4:
fail3:
free_pages((u64)blob, bi->order);
fail2:
fail1:
return r;
}
/* ioctl -------------------------------------------------- */
static long lcd_dev_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
long r = -EINVAL;
//struct lcd_pv_kernel_config conf;
struct lcd_pv_kernel_config conf;
struct lcd_blob_info bi;
switch (ioctl) {
case LCD_LOAD_PV_KERNEL:
//r = copy_from_user(&conf, (int __user *) arg,
// sizeof(conf));
//if (r) {
// r = -EIO;
// goto out;
//}
case LCD_LOAD_PV_KERNEL:
/* r = copy_from_user(&conf, (int __user *) arg, */
/* sizeof(struct lcd_pv_kernel_config)); */
if (r) {
r = -EIO;
goto out;
}
/* create LCD with a PV Linux kernel */
return r;
goto out;
break;
case LCD_RUN_BLOB:
r = copy_from_user(&bi, (void __user *)arg, sizeof(*bi));
if (r) {
printk(KERN_ERR "lcd: error loading blob info\n");
r = -EIO;
goto out;
}
r = lcd_run_blob(&bi);
if (r) {
printk(KERN_ERR "lcd: error running blob\n");
goto out;
}
r = 0;
goto out;
default:
return -ENOTTY;
}
//out:
// return r;
out:
return r;
}
static const struct file_operations lcd_chardev_ops = {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment