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