1 /* Userspace control of the guest, via /dev/lguest. */
2 #include <linux/uaccess.h>
3 #include <linux/miscdevice.h>
7 static void setup_regs(struct lguest_regs
*regs
, unsigned long start
)
9 /* Write out stack in format lguest expects, so we can switch to it. */
10 regs
->ds
= regs
->es
= regs
->ss
= __KERNEL_DS
|GUEST_PL
;
11 regs
->cs
= __KERNEL_CS
|GUEST_PL
;
12 regs
->eflags
= 0x202; /* Interrupts enabled. */
14 /* esi points to our boot information (physical address 0) */
18 static long user_get_dma(struct lguest
*lg
, const u32 __user
*input
)
20 unsigned long key
, udma
, irq
;
22 if (get_user(key
, input
) != 0)
24 udma
= get_dma_buffer(lg
, key
, &irq
);
28 /* We put irq number in udma->used_len. */
29 lgwrite_u32(lg
, udma
+ offsetof(struct lguest_dma
, used_len
), irq
);
33 /* To force the Guest to stop running and return to the Launcher, the
34 * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest. The
35 * Launcher then writes LHREQ_BREAK and "0" to release the Waker. */
36 static int break_guest_out(struct lguest
*lg
, const u32 __user
*input
)
40 /* Fetch whether they're turning break on or off.. */
41 if (get_user(on
, input
) != 0)
46 /* Pop it out (may be running on different CPU) */
47 wake_up_process(lg
->tsk
);
48 /* Wait for them to reset it */
49 return wait_event_interruptible(lg
->break_wq
, !lg
->break_out
);
52 wake_up(&lg
->break_wq
);
58 static int user_send_irq(struct lguest
*lg
, const u32 __user
*input
)
62 if (get_user(irq
, input
) != 0)
64 if (irq
>= LGUEST_IRQS
)
66 set_bit(irq
, lg
->irqs_pending
);
70 static ssize_t
read(struct file
*file
, char __user
*user
, size_t size
,loff_t
*o
)
72 struct lguest
*lg
= file
->private_data
;
77 /* If you're not the task which owns the guest, go away. */
78 if (current
!= lg
->tsk
)
85 return PTR_ERR(lg
->dead
);
87 len
= min(size
, strlen(lg
->dead
)+1);
88 if (copy_to_user(user
, lg
->dead
, len
) != 0)
93 if (lg
->dma_is_pending
)
94 lg
->dma_is_pending
= 0;
96 return run_guest(lg
, (unsigned long __user
*)user
);
99 /* Take: pfnlimit, pgdir, start, pageoffset. */
100 static int initialize(struct file
*file
, const u32 __user
*input
)
106 /* We grab the Big Lguest lock, which protects the global array
107 * "lguests" and multiple simultaneous initializations. */
108 mutex_lock(&lguest_lock
);
110 if (file
->private_data
) {
115 if (copy_from_user(args
, input
, sizeof(args
)) != 0) {
120 i
= find_free_guest();
127 lg
->pfn_limit
= args
[0];
128 lg
->page_offset
= args
[3];
129 lg
->regs_page
= get_zeroed_page(GFP_KERNEL
);
130 if (!lg
->regs_page
) {
134 lg
->regs
= (void *)lg
->regs_page
+ PAGE_SIZE
- sizeof(*lg
->regs
);
136 err
= init_guest_pagetable(lg
, args
[1]);
140 setup_regs(lg
->regs
, args
[2]);
144 lg
->mm
= get_task_mm(lg
->tsk
);
145 init_waitqueue_head(&lg
->break_wq
);
146 lg
->last_pages
= NULL
;
147 file
->private_data
= lg
;
149 mutex_unlock(&lguest_lock
);
154 free_page(lg
->regs_page
);
156 memset(lg
, 0, sizeof(*lg
));
158 mutex_unlock(&lguest_lock
);
162 static ssize_t
write(struct file
*file
, const char __user
*input
,
163 size_t size
, loff_t
*off
)
165 struct lguest
*lg
= file
->private_data
;
168 if (get_user(req
, input
) != 0)
170 input
+= sizeof(req
);
172 if (req
!= LHREQ_INITIALIZE
&& !lg
)
177 /* If you're not the task which owns the Guest, you can only break */
178 if (lg
&& current
!= lg
->tsk
&& req
!= LHREQ_BREAK
)
182 case LHREQ_INITIALIZE
:
183 return initialize(file
, (const u32 __user
*)input
);
185 return user_get_dma(lg
, (const u32 __user
*)input
);
187 return user_send_irq(lg
, (const u32 __user
*)input
);
189 return break_guest_out(lg
, (const u32 __user
*)input
);
195 static int close(struct inode
*inode
, struct file
*file
)
197 struct lguest
*lg
= file
->private_data
;
202 mutex_lock(&lguest_lock
);
203 /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
204 hrtimer_cancel(&lg
->hrt
);
206 free_guest_pagetable(lg
);
208 if (!IS_ERR(lg
->dead
))
210 free_page(lg
->regs_page
);
211 memset(lg
, 0, sizeof(*lg
));
212 mutex_unlock(&lguest_lock
);
216 static struct file_operations lguest_fops
= {
217 .owner
= THIS_MODULE
,
222 static struct miscdevice lguest_dev
= {
223 .minor
= MISC_DYNAMIC_MINOR
,
225 .fops
= &lguest_fops
,
228 int __init
lguest_device_init(void)
230 return misc_register(&lguest_dev
);
233 void __exit
lguest_device_remove(void)
235 misc_deregister(&lguest_dev
);