lguest_user.c revision d7e28ffe6c74416b54345d6004fd0964c115b12c
1d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell/* Userspace control of the guest, via /dev/lguest. */ 2d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell#include <linux/uaccess.h> 3d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell#include <linux/miscdevice.h> 4d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell#include <linux/fs.h> 5d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell#include "lg.h" 6d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 7d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellstatic void setup_regs(struct lguest_regs *regs, unsigned long start) 8d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell{ 9d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell /* Write out stack in format lguest expects, so we can switch to it. */ 10d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL; 11d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell regs->cs = __KERNEL_CS|GUEST_PL; 12d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell regs->eflags = 0x202; /* Interrupts enabled. */ 13d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell regs->eip = start; 14d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell /* esi points to our boot information (physical address 0) */ 15d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell} 16d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 17d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell/* + addr */ 18d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellstatic long user_get_dma(struct lguest *lg, const u32 __user *input) 19d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell{ 20d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell unsigned long key, udma, irq; 21d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 22d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (get_user(key, input) != 0) 23d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -EFAULT; 24d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell udma = get_dma_buffer(lg, key, &irq); 25d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (!udma) 26d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -ENOENT; 27d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 28d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell /* We put irq number in udma->used_len. */ 29d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lgwrite_u32(lg, udma + offsetof(struct lguest_dma, used_len), irq); 30d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return udma; 31d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell} 32d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 33d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell/* To force the Guest to stop running and return to the Launcher, the 34d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest. The 35d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell * Launcher then writes LHREQ_BREAK and "0" to release the Waker. */ 36d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellstatic int break_guest_out(struct lguest *lg, const u32 __user *input) 37d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell{ 38d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell unsigned long on; 39d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 40d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell /* Fetch whether they're turning break on or off.. */ 41d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (get_user(on, input) != 0) 42d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -EFAULT; 43d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 44d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (on) { 45d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg->break_out = 1; 46d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell /* Pop it out (may be running on different CPU) */ 47d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell wake_up_process(lg->tsk); 48d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell /* Wait for them to reset it */ 49d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return wait_event_interruptible(lg->break_wq, !lg->break_out); 50d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell } else { 51d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg->break_out = 0; 52d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell wake_up(&lg->break_wq); 53d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return 0; 54d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell } 55d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell} 56d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 57d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell/* + irq */ 58d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellstatic int user_send_irq(struct lguest *lg, const u32 __user *input) 59d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell{ 60d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell u32 irq; 61d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 62d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (get_user(irq, input) != 0) 63d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -EFAULT; 64d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (irq >= LGUEST_IRQS) 65d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -EINVAL; 66d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell set_bit(irq, lg->irqs_pending); 67d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return 0; 68d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell} 69d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 70d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellstatic ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o) 71d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell{ 72d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell struct lguest *lg = file->private_data; 73d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 74d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (!lg) 75d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -EINVAL; 76d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 77d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell /* If you're not the task which owns the guest, go away. */ 78d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (current != lg->tsk) 79d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -EPERM; 80d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 81d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (lg->dead) { 82d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell size_t len; 83d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 84d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (IS_ERR(lg->dead)) 85d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return PTR_ERR(lg->dead); 86d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 87d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell len = min(size, strlen(lg->dead)+1); 88d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (copy_to_user(user, lg->dead, len) != 0) 89d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -EFAULT; 90d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return len; 91d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell } 92d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 93d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (lg->dma_is_pending) 94d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg->dma_is_pending = 0; 95d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 96d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return run_guest(lg, (unsigned long __user *)user); 97d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell} 98d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 99d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell/* Take: pfnlimit, pgdir, start, pageoffset. */ 100d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellstatic int initialize(struct file *file, const u32 __user *input) 101d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell{ 102d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell struct lguest *lg; 103d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell int err, i; 104d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell u32 args[4]; 105d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 106d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell /* We grab the Big Lguest lock, which protects the global array 107d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell * "lguests" and multiple simultaneous initializations. */ 108d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell mutex_lock(&lguest_lock); 109d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 110d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (file->private_data) { 111d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell err = -EBUSY; 112d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell goto unlock; 113d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell } 114d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 115d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (copy_from_user(args, input, sizeof(args)) != 0) { 116d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell err = -EFAULT; 117d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell goto unlock; 118d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell } 119d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 120d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell i = find_free_guest(); 121d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (i < 0) { 122d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell err = -ENOSPC; 123d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell goto unlock; 124d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell } 125d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg = &lguests[i]; 126d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg->guestid = i; 127d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg->pfn_limit = args[0]; 128d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg->page_offset = args[3]; 129d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg->regs_page = get_zeroed_page(GFP_KERNEL); 130d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (!lg->regs_page) { 131d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell err = -ENOMEM; 132d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell goto release_guest; 133d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell } 134d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg->regs = (void *)lg->regs_page + PAGE_SIZE - sizeof(*lg->regs); 135d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 136d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell err = init_guest_pagetable(lg, args[1]); 137d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (err) 138d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell goto free_regs; 139d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 140d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell setup_regs(lg->regs, args[2]); 141d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell setup_guest_gdt(lg); 142d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell init_clockdev(lg); 143d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg->tsk = current; 144d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg->mm = get_task_mm(lg->tsk); 145d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell init_waitqueue_head(&lg->break_wq); 146d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell lg->last_pages = NULL; 147d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell file->private_data = lg; 148d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 149d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell mutex_unlock(&lguest_lock); 150d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 151d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return sizeof(args); 152d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 153d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellfree_regs: 154d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell free_page(lg->regs_page); 155d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellrelease_guest: 156d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell memset(lg, 0, sizeof(*lg)); 157d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellunlock: 158d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell mutex_unlock(&lguest_lock); 159d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return err; 160d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell} 161d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 162d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellstatic ssize_t write(struct file *file, const char __user *input, 163d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell size_t size, loff_t *off) 164d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell{ 165d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell struct lguest *lg = file->private_data; 166d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell u32 req; 167d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 168d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (get_user(req, input) != 0) 169d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -EFAULT; 170d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell input += sizeof(req); 171d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 172d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (req != LHREQ_INITIALIZE && !lg) 173d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -EINVAL; 174d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (lg && lg->dead) 175d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -ENOENT; 176d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 177d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell /* If you're not the task which owns the Guest, you can only break */ 178d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (lg && current != lg->tsk && req != LHREQ_BREAK) 179d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -EPERM; 180d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 181d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell switch (req) { 182d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell case LHREQ_INITIALIZE: 183d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return initialize(file, (const u32 __user *)input); 184d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell case LHREQ_GETDMA: 185d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return user_get_dma(lg, (const u32 __user *)input); 186d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell case LHREQ_IRQ: 187d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return user_send_irq(lg, (const u32 __user *)input); 188d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell case LHREQ_BREAK: 189d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return break_guest_out(lg, (const u32 __user *)input); 190d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell default: 191d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return -EINVAL; 192d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell } 193d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell} 194d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 195d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellstatic int close(struct inode *inode, struct file *file) 196d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell{ 197d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell struct lguest *lg = file->private_data; 198d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 199d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (!lg) 200d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return 0; 201d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 202d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell mutex_lock(&lguest_lock); 203d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */ 204d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell hrtimer_cancel(&lg->hrt); 205d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell release_all_dma(lg); 206d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell free_guest_pagetable(lg); 207d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell mmput(lg->mm); 208d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell if (!IS_ERR(lg->dead)) 209d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell kfree(lg->dead); 210d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell free_page(lg->regs_page); 211d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell memset(lg, 0, sizeof(*lg)); 212d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell mutex_unlock(&lguest_lock); 213d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return 0; 214d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell} 215d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 216d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellstatic struct file_operations lguest_fops = { 217d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell .owner = THIS_MODULE, 218d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell .release = close, 219d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell .write = write, 220d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell .read = read, 221d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell}; 222d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellstatic struct miscdevice lguest_dev = { 223d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell .minor = MISC_DYNAMIC_MINOR, 224d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell .name = "lguest", 225d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell .fops = &lguest_fops, 226d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell}; 227d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 228d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellint __init lguest_device_init(void) 229d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell{ 230d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell return misc_register(&lguest_dev); 231d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell} 232d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell 233d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russellvoid __exit lguest_device_remove(void) 234d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell{ 235d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell misc_deregister(&lguest_dev); 236d7e28ffe6c74416b54345d6004fd0964c115b12cRusty Russell} 237