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
);