1 /*P:200 This contains all the /dev/lguest code, whereby the userspace launcher
2 * controls and communicates with the Guest. For example, the first write will
3 * tell us the memory size, pagetable, entry point and kernel address offset.
4 * A read will run the Guest until a signal is pending (-EINTR), or the Guest
5 * does a DMA out to the Launcher. Writes are also used to get a DMA buffer
6 * registered by the Guest and to send the Guest an interrupt. :*/
7 #include <linux/uaccess.h>
8 #include <linux/miscdevice.h>
12 static void setup_regs(struct lguest_regs *regs, unsigned long start)
14 /* Write out stack in format lguest expects, so we can switch to it. */
15 regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL;
16 regs->cs = __KERNEL_CS|GUEST_PL;
17 regs->eflags = 0x202; /* Interrupts enabled. */
19 /* esi points to our boot information (physical address 0) */
23 static long user_get_dma(struct lguest *lg, const u32 __user *input)
25 unsigned long key, udma, irq;
27 if (get_user(key, input) != 0)
29 udma = get_dma_buffer(lg, key, &irq);
33 /* We put irq number in udma->used_len. */
34 lgwrite_u32(lg, udma + offsetof(struct lguest_dma, used_len), irq);
38 /* To force the Guest to stop running and return to the Launcher, the
39 * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest. The
40 * Launcher then writes LHREQ_BREAK and "0" to release the Waker. */
41 static int break_guest_out(struct lguest *lg, const u32 __user *input)
45 /* Fetch whether they're turning break on or off.. */
46 if (get_user(on, input) != 0)
51 /* Pop it out (may be running on different CPU) */
52 wake_up_process(lg->tsk);
53 /* Wait for them to reset it */
54 return wait_event_interruptible(lg->break_wq, !lg->break_out);
57 wake_up(&lg->break_wq);
63 static int user_send_irq(struct lguest *lg, const u32 __user *input)
67 if (get_user(irq, input) != 0)
69 if (irq >= LGUEST_IRQS)
71 set_bit(irq, lg->irqs_pending);
75 static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
77 struct lguest *lg = file->private_data;
82 /* If you're not the task which owns the guest, go away. */
83 if (current != lg->tsk)
90 return PTR_ERR(lg->dead);
92 len = min(size, strlen(lg->dead)+1);
93 if (copy_to_user(user, lg->dead, len) != 0)
98 if (lg->dma_is_pending)
99 lg->dma_is_pending = 0;
101 return run_guest(lg, (unsigned long __user *)user);
104 /* Take: pfnlimit, pgdir, start, pageoffset. */
105 static int initialize(struct file *file, const u32 __user *input)
111 /* We grab the Big Lguest lock, which protects the global array
112 * "lguests" and multiple simultaneous initializations. */
113 mutex_lock(&lguest_lock);
115 if (file->private_data) {
120 if (copy_from_user(args, input, sizeof(args)) != 0) {
125 i = find_free_guest();
132 lg->pfn_limit = args[0];
133 lg->page_offset = args[3];
134 lg->regs_page = get_zeroed_page(GFP_KERNEL);
135 if (!lg->regs_page) {
139 lg->regs = (void *)lg->regs_page + PAGE_SIZE - sizeof(*lg->regs);
141 err = init_guest_pagetable(lg, args[1]);
145 setup_regs(lg->regs, args[2]);
149 lg->mm = get_task_mm(lg->tsk);
150 init_waitqueue_head(&lg->break_wq);
151 lg->last_pages = NULL;
152 file->private_data = lg;
154 mutex_unlock(&lguest_lock);
159 free_page(lg->regs_page);
161 memset(lg, 0, sizeof(*lg));
163 mutex_unlock(&lguest_lock);
167 static ssize_t write(struct file *file, const char __user *input,
168 size_t size, loff_t *off)
170 struct lguest *lg = file->private_data;
173 if (get_user(req, input) != 0)
175 input += sizeof(req);
177 if (req != LHREQ_INITIALIZE && !lg)
182 /* If you're not the task which owns the Guest, you can only break */
183 if (lg && current != lg->tsk && req != LHREQ_BREAK)
187 case LHREQ_INITIALIZE:
188 return initialize(file, (const u32 __user *)input);
190 return user_get_dma(lg, (const u32 __user *)input);
192 return user_send_irq(lg, (const u32 __user *)input);
194 return break_guest_out(lg, (const u32 __user *)input);
200 static int close(struct inode *inode, struct file *file)
202 struct lguest *lg = file->private_data;
207 mutex_lock(&lguest_lock);
208 /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
209 hrtimer_cancel(&lg->hrt);
211 free_guest_pagetable(lg);
213 if (!IS_ERR(lg->dead))
215 free_page(lg->regs_page);
216 memset(lg, 0, sizeof(*lg));
217 mutex_unlock(&lguest_lock);
221 static struct file_operations lguest_fops = {
222 .owner = THIS_MODULE,
227 static struct miscdevice lguest_dev = {
228 .minor = MISC_DYNAMIC_MINOR,
230 .fops = &lguest_fops,
233 int __init lguest_device_init(void)
235 return misc_register(&lguest_dev);
238 void __exit lguest_device_remove(void)
240 misc_deregister(&lguest_dev);