/root/src/xen/xen/common/multicall.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * multicall.c |
3 | | */ |
4 | | |
5 | | #include <xen/types.h> |
6 | | #include <xen/lib.h> |
7 | | #include <xen/mm.h> |
8 | | #include <xen/sched.h> |
9 | | #include <xen/event.h> |
10 | | #include <xen/multicall.h> |
11 | | #include <xen/guest_access.h> |
12 | | #include <xen/perfc.h> |
13 | | #include <xen/trace.h> |
14 | | #include <asm/current.h> |
15 | | #include <asm/hardirq.h> |
16 | | |
17 | | #ifndef COMPAT |
18 | | typedef long ret_t; |
19 | | #define xlat_multicall_entry(mcs) |
20 | | |
21 | | static void __trace_multicall_call(multicall_entry_t *call) |
22 | 0 | { |
23 | 0 | __trace_hypercall(TRC_PV_HYPERCALL_SUBCALL, call->op, call->args); |
24 | 0 | } |
25 | | #endif |
26 | | |
27 | | static void trace_multicall_call(multicall_entry_t *call) |
28 | 0 | { |
29 | 0 | if ( !tb_init_done ) |
30 | 0 | return; |
31 | 0 |
|
32 | 0 | __trace_multicall_call(call); |
33 | 0 | } |
34 | | |
35 | | ret_t |
36 | | do_multicall( |
37 | | XEN_GUEST_HANDLE_PARAM(multicall_entry_t) call_list, uint32_t nr_calls) |
38 | 0 | { |
39 | 0 | struct vcpu *curr = current; |
40 | 0 | struct mc_state *mcs = &curr->mc_state; |
41 | 0 | uint32_t i; |
42 | 0 | int rc = 0; |
43 | 0 | enum mc_disposition disp = mc_continue; |
44 | 0 |
|
45 | 0 | if ( unlikely(__test_and_set_bit(_MCSF_in_multicall, &mcs->flags)) ) |
46 | 0 | { |
47 | 0 | gdprintk(XENLOG_INFO, "Multicall reentry is disallowed.\n"); |
48 | 0 | return -EINVAL; |
49 | 0 | } |
50 | 0 |
|
51 | 0 | if ( unlikely(!guest_handle_okay(call_list, nr_calls)) ) |
52 | 0 | rc = -EFAULT; |
53 | 0 |
|
54 | 0 | for ( i = 0; !rc && disp == mc_continue && i < nr_calls; i++ ) |
55 | 0 | { |
56 | 0 | if ( i && hypercall_preempt_check() ) |
57 | 0 | goto preempted; |
58 | 0 |
|
59 | 0 | if ( unlikely(__copy_from_guest(&mcs->call, call_list, 1)) ) |
60 | 0 | { |
61 | 0 | rc = -EFAULT; |
62 | 0 | break; |
63 | 0 | } |
64 | 0 |
|
65 | 0 | trace_multicall_call(&mcs->call); |
66 | 0 |
|
67 | 0 | disp = arch_do_multicall_call(mcs); |
68 | 0 |
|
69 | 0 | #ifndef NDEBUG |
70 | 0 | { |
71 | 0 | /* |
72 | 0 | * Deliberately corrupt the contents of the multicall structure. |
73 | 0 | * The caller must depend only on the 'result' field on return. |
74 | 0 | */ |
75 | 0 | struct multicall_entry corrupt; |
76 | 0 | memset(&corrupt, 0xAA, sizeof(corrupt)); |
77 | 0 | (void)__copy_to_guest(call_list, &corrupt, 1); |
78 | 0 | } |
79 | 0 | #endif |
80 | 0 |
|
81 | 0 | if ( unlikely(disp == mc_exit) ) |
82 | 0 | { |
83 | 0 | if ( __copy_field_to_guest(call_list, &mcs->call, result) ) |
84 | 0 | /* nothing, best effort only */; |
85 | 0 | rc = mcs->call.result; |
86 | 0 | } |
87 | 0 | else if ( unlikely(__copy_field_to_guest(call_list, &mcs->call, |
88 | 0 | result)) ) |
89 | 0 | rc = -EFAULT; |
90 | 0 | else if ( curr->hcall_preempted ) |
91 | 0 | { |
92 | 0 | /* Translate sub-call continuation to guest layout */ |
93 | 0 | xlat_multicall_entry(mcs); |
94 | 0 |
|
95 | 0 | /* Copy the sub-call continuation. */ |
96 | 0 | if ( likely(!__copy_to_guest(call_list, &mcs->call, 1)) ) |
97 | 0 | goto preempted; |
98 | 0 | else |
99 | 0 | hypercall_cancel_continuation(curr); |
100 | 0 | rc = -EFAULT; |
101 | 0 | } |
102 | 0 | else |
103 | 0 | guest_handle_add_offset(call_list, 1); |
104 | 0 | } |
105 | 0 |
|
106 | 0 | if ( unlikely(disp == mc_preempt) && i < nr_calls ) |
107 | 0 | goto preempted; |
108 | 0 |
|
109 | 0 | perfc_incr(calls_to_multicall); |
110 | 0 | perfc_add(calls_from_multicall, i); |
111 | 0 | mcs->flags = 0; |
112 | 0 | return rc; |
113 | 0 |
|
114 | 0 | preempted: |
115 | 0 | perfc_add(calls_from_multicall, i); |
116 | 0 | mcs->flags = 0; |
117 | 0 | return hypercall_create_continuation( |
118 | 0 | __HYPERVISOR_multicall, "hi", call_list, nr_calls-i); |
119 | 0 | } Unexecuted instantiation: do_multicall Unexecuted instantiation: compat_multicall |
120 | | |
121 | | /* |
122 | | * Local variables: |
123 | | * mode: C |
124 | | * c-file-style: "BSD" |
125 | | * c-basic-offset: 4 |
126 | | * tab-width: 4 |
127 | | * indent-tabs-mode: nil |
128 | | * End: |
129 | | */ |