1 /******************************************************************************
2  * mem_access.c
3  *
4  * Memory access support.
5  *
6  * Copyright (c) 2011 Virtuata, Inc.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 
23 #include <xen/sched.h>
24 #include <xen/guest_access.h>
25 #include <xen/hypercall.h>
26 #include <xen/vm_event.h>
27 #include <xen/mem_access.h>
28 #include <public/memory.h>
29 #include <xsm/xsm.h>
30 
mem_access_memop(unsigned long cmd,XEN_GUEST_HANDLE_PARAM (xen_mem_access_op_t)arg)31 int mem_access_memop(unsigned long cmd,
32                      XEN_GUEST_HANDLE_PARAM(xen_mem_access_op_t) arg)
33 {
34     unsigned long start_iter = cmd & ~MEMOP_CMD_MASK;
35     long rc;
36     xen_mem_access_op_t mao;
37     struct domain *d;
38 
39     if ( copy_from_guest(&mao, arg, 1) )
40         return -EFAULT;
41 
42     rc = rcu_lock_live_remote_domain_by_id(mao.domid, &d);
43     if ( rc )
44         return rc;
45 
46     rc = -EINVAL;
47     if ( !p2m_mem_access_sanity_check(d) )
48         goto out;
49 
50     rc = xsm_mem_access(XSM_DM_PRIV, d);
51     if ( rc )
52         goto out;
53 
54     rc = -ENODEV;
55     if ( unlikely(!vm_event_check_ring(d->vm_event_monitor)) )
56         goto out;
57 
58     switch ( mao.op )
59     {
60 
61     case XENMEM_access_op_set_access:
62         rc = -EINVAL;
63         if ( (mao.pfn != ~0ull) &&
64              (mao.nr < start_iter ||
65               ((mao.pfn + mao.nr - 1) < mao.pfn) ||
66               ((mao.pfn + mao.nr - 1) > domain_get_maximum_gpfn(d))) )
67             break;
68 
69         rc = p2m_set_mem_access(d, _gfn(mao.pfn), mao.nr, start_iter,
70                                 MEMOP_CMD_MASK, mao.access, 0);
71         if ( rc > 0 )
72         {
73             ASSERT(!(rc & MEMOP_CMD_MASK));
74             rc = hypercall_create_continuation(__HYPERVISOR_memory_op, "lh",
75                                                XENMEM_access_op | rc, arg);
76         }
77         break;
78 
79     case XENMEM_access_op_set_access_multi:
80         rc = p2m_set_mem_access_multi(d, mao.pfn_list, mao.access_list, mao.nr,
81                                       start_iter, MEMOP_CMD_MASK, 0);
82         if ( rc > 0 )
83         {
84             ASSERT(!(rc & MEMOP_CMD_MASK));
85             rc = hypercall_create_continuation(__HYPERVISOR_memory_op, "lh",
86                                                XENMEM_access_op | rc, arg);
87         }
88         break;
89 
90     case XENMEM_access_op_get_access:
91     {
92         xenmem_access_t access;
93 
94         rc = -ENOSYS;
95         if ( unlikely(start_iter) )
96             break;
97 
98         rc = -EINVAL;
99         if ( (mao.pfn > domain_get_maximum_gpfn(d)) && mao.pfn != ~0ull )
100             break;
101 
102         rc = p2m_get_mem_access(d, _gfn(mao.pfn), &access, 0);
103         if ( rc != 0 )
104             break;
105 
106         mao.access = access;
107         rc = __copy_field_to_guest(arg, &mao, access) ? -EFAULT : 0;
108 
109         break;
110     }
111 
112     default:
113         rc = -ENOSYS;
114         break;
115     }
116 
117  out:
118     rcu_unlock_domain(d);
119     return rc;
120 }
121 
122 /*
123  * Local variables:
124  * mode: C
125  * c-file-style: "BSD"
126  * c-basic-offset: 4
127  * indent-tabs-mode: nil
128  * End:
129  */
130