1 /*
2  * xc_resource.c
3  *
4  * Generic resource access API
5  *
6  * Copyright (C) 2014      Intel Corporation
7  * Author Dongxiao Xu <dongxiao.xu@intel.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU Lesser General Public License as published
11  * by the Free Software Foundation; version 2.1 only. with the special
12  * exception on linking described in file LICENSE.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License for more details.
18  */
19 
20 #include "xc_private.h"
21 
xc_resource_op_one(xc_interface * xch,xc_resource_op_t * op)22 static int xc_resource_op_one(xc_interface *xch, xc_resource_op_t *op)
23 {
24     int rc;
25     DECLARE_PLATFORM_OP;
26     DECLARE_NAMED_HYPERCALL_BOUNCE(entries, op->entries,
27                                 op->nr_entries * sizeof(*op->entries),
28                                 XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
29 
30     if ( xc_hypercall_bounce_pre(xch, entries) )
31         return -1;
32 
33     platform_op.cmd = XENPF_resource_op;
34     platform_op.u.resource_op.nr_entries = op->nr_entries;
35     platform_op.u.resource_op.cpu = op->cpu;
36     set_xen_guest_handle(platform_op.u.resource_op.entries, entries);
37 
38     rc = do_platform_op(xch, &platform_op);
39     op->result = rc;
40 
41     xc_hypercall_bounce_post(xch, entries);
42 
43     return rc;
44 }
45 
xc_resource_op_multi(xc_interface * xch,uint32_t nr_ops,xc_resource_op_t * ops)46 static int xc_resource_op_multi(xc_interface *xch, uint32_t nr_ops, xc_resource_op_t *ops)
47 {
48     int rc, i, entries_size;
49     xc_resource_op_t *op;
50     multicall_entry_t *call;
51     DECLARE_HYPERCALL_BUFFER(multicall_entry_t, call_list);
52     xc_hypercall_buffer_array_t *platform_ops, *entries_list = NULL;
53 
54     call_list = xc_hypercall_buffer_alloc(xch, call_list,
55                                           sizeof(*call_list) * nr_ops);
56     if ( !call_list )
57         return -1;
58 
59     platform_ops = xc_hypercall_buffer_array_create(xch, nr_ops);
60     if ( !platform_ops )
61     {
62         rc = -1;
63         goto out;
64     }
65 
66     entries_list = xc_hypercall_buffer_array_create(xch, nr_ops);
67     if ( !entries_list )
68     {
69         rc = -1;
70         goto out;
71     }
72 
73     for ( i = 0; i < nr_ops; i++ )
74     {
75         DECLARE_HYPERCALL_BUFFER(xen_platform_op_t, platform_op);
76         DECLARE_HYPERCALL_BUFFER(xc_resource_entry_t, entries);
77 
78         op = ops + i;
79 
80         platform_op = xc_hypercall_buffer_array_alloc(xch, platform_ops, i,
81                         platform_op, sizeof(xen_platform_op_t));
82         if ( !platform_op )
83         {
84             rc = -1;
85             goto out;
86         }
87 
88         entries_size = sizeof(xc_resource_entry_t) * op->nr_entries;
89         entries = xc_hypercall_buffer_array_alloc(xch, entries_list, i,
90                    entries, entries_size);
91         if ( !entries)
92         {
93             rc = -1;
94             goto out;
95         }
96         memcpy(entries, op->entries, entries_size);
97 
98         call = call_list + i;
99         call->op = __HYPERVISOR_platform_op;
100         call->args[0] = HYPERCALL_BUFFER_AS_ARG(platform_op);
101 
102         platform_op->interface_version = XENPF_INTERFACE_VERSION;
103         platform_op->cmd = XENPF_resource_op;
104         platform_op->u.resource_op.cpu = op->cpu;
105         platform_op->u.resource_op.nr_entries = op->nr_entries;
106         set_xen_guest_handle(platform_op->u.resource_op.entries, entries);
107     }
108 
109     rc = do_multicall_op(xch, HYPERCALL_BUFFER(call_list), nr_ops);
110 
111     for ( i = 0; i < nr_ops; i++ )
112     {
113         DECLARE_HYPERCALL_BUFFER(xc_resource_entry_t, entries);
114         op = ops + i;
115 
116         call = call_list + i;
117         op->result = call->result;
118 
119         entries_size = sizeof(xc_resource_entry_t) * op->nr_entries;
120         entries = xc_hypercall_buffer_array_get(xch, entries_list, i,
121                    entries, entries_size);
122         memcpy(op->entries, entries, entries_size);
123     }
124 
125 out:
126     xc_hypercall_buffer_array_destroy(xch, entries_list);
127     xc_hypercall_buffer_array_destroy(xch, platform_ops);
128     xc_hypercall_buffer_free(xch, call_list);
129     return rc;
130 }
131 
xc_resource_op(xc_interface * xch,uint32_t nr_ops,xc_resource_op_t * ops)132 int xc_resource_op(xc_interface *xch, uint32_t nr_ops, xc_resource_op_t *ops)
133 {
134     if ( nr_ops == 1 )
135         return xc_resource_op_one(xch, ops);
136     else if ( nr_ops > 1 )
137         return xc_resource_op_multi(xch, nr_ops, ops);
138     else
139         return -1;
140 }
141 
142 /*
143  * Local variables:
144  * mode: C
145  * c-file-style: "BSD"
146  * c-basic-offset: 4
147  * tab-width: 4
148  * indent-tabs-mode: nil
149  * End:
150  */
151