1 /******************************************************************************
2 * xc_kexec.c
3 *
4 * API for loading and executing kexec images.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation;
9 * version 2.1 of the License.
10 *
11 * Copyright (C) 2013 Citrix Systems R&D Ltd.
12 */
13 #include "xc_private.h"
14
xc_kexec_exec(xc_interface * xch,int type)15 int xc_kexec_exec(xc_interface *xch, int type)
16 {
17 DECLARE_HYPERCALL_BUFFER(xen_kexec_exec_t, exec);
18 int ret = -1;
19
20 exec = xc_hypercall_buffer_alloc(xch, exec, sizeof(*exec));
21 if ( exec == NULL )
22 {
23 PERROR("Could not alloc bounce buffer for kexec_exec hypercall");
24 goto out;
25 }
26
27 exec->type = type;
28
29 ret = xencall2(xch->xcall, __HYPERVISOR_kexec_op,
30 KEXEC_CMD_kexec,
31 HYPERCALL_BUFFER_AS_ARG(exec));
32
33 out:
34 xc_hypercall_buffer_free(xch, exec);
35
36 return ret;
37 }
38
xc_kexec_get_range(xc_interface * xch,int range,int nr,uint64_t * size,uint64_t * start)39 int xc_kexec_get_range(xc_interface *xch, int range, int nr,
40 uint64_t *size, uint64_t *start)
41 {
42 DECLARE_HYPERCALL_BUFFER(xen_kexec_range_t, get_range);
43 int ret = -1;
44
45 get_range = xc_hypercall_buffer_alloc(xch, get_range, sizeof(*get_range));
46 if ( get_range == NULL )
47 {
48 PERROR("Could not alloc bounce buffer for kexec_get_range hypercall");
49 goto out;
50 }
51
52 get_range->range = range;
53 get_range->nr = nr;
54
55 ret = xencall2(xch->xcall, __HYPERVISOR_kexec_op,
56 KEXEC_CMD_kexec_get_range,
57 HYPERCALL_BUFFER_AS_ARG(get_range));
58
59 *size = get_range->size;
60 *start = get_range->start;
61
62 out:
63 xc_hypercall_buffer_free(xch, get_range);
64
65 return ret;
66 }
67
xc_kexec_load(xc_interface * xch,uint8_t type,uint16_t arch,uint64_t entry_maddr,uint32_t nr_segments,xen_kexec_segment_t * segments)68 int xc_kexec_load(xc_interface *xch, uint8_t type, uint16_t arch,
69 uint64_t entry_maddr,
70 uint32_t nr_segments, xen_kexec_segment_t *segments)
71 {
72 int ret = -1;
73 DECLARE_HYPERCALL_BOUNCE(segments, sizeof(*segments) * nr_segments,
74 XC_HYPERCALL_BUFFER_BOUNCE_IN);
75 DECLARE_HYPERCALL_BUFFER(xen_kexec_load_t, load);
76
77 if ( xc_hypercall_bounce_pre(xch, segments) )
78 {
79 PERROR("Could not allocate bounce buffer for kexec load hypercall");
80 goto out;
81 }
82 load = xc_hypercall_buffer_alloc(xch, load, sizeof(*load));
83 if ( load == NULL )
84 {
85 PERROR("Could not allocate buffer for kexec load hypercall");
86 goto out;
87 }
88
89 load->type = type;
90 load->arch = arch;
91 load->entry_maddr = entry_maddr;
92 load->nr_segments = nr_segments;
93 set_xen_guest_handle(load->segments.h, segments);
94
95 ret = xencall2(xch->xcall, __HYPERVISOR_kexec_op,
96 KEXEC_CMD_kexec_load,
97 HYPERCALL_BUFFER_AS_ARG(load));
98
99 out:
100 xc_hypercall_buffer_free(xch, load);
101 xc_hypercall_bounce_post(xch, segments);
102
103 return ret;
104 }
105
xc_kexec_unload(xc_interface * xch,int type)106 int xc_kexec_unload(xc_interface *xch, int type)
107 {
108 DECLARE_HYPERCALL_BUFFER(xen_kexec_unload_t, unload);
109 int ret = -1;
110
111 unload = xc_hypercall_buffer_alloc(xch, unload, sizeof(*unload));
112 if ( unload == NULL )
113 {
114 PERROR("Could not alloc buffer for kexec unload hypercall");
115 goto out;
116 }
117
118 unload->type = type;
119
120 ret = xencall2(xch->xcall, __HYPERVISOR_kexec_op,
121 KEXEC_CMD_kexec_unload,
122 HYPERCALL_BUFFER_AS_ARG(unload));
123
124 out:
125 xc_hypercall_buffer_free(xch, unload);
126
127 return ret;
128 }
129
xc_kexec_status(xc_interface * xch,int type)130 int xc_kexec_status(xc_interface *xch, int type)
131 {
132 DECLARE_HYPERCALL_BUFFER(xen_kexec_status_t, status);
133 int ret = -1;
134
135 status = xc_hypercall_buffer_alloc(xch, status, sizeof(*status));
136 if ( status == NULL )
137 {
138 PERROR("Could not alloc buffer for kexec status hypercall");
139 goto out;
140 }
141
142 status->type = type;
143
144 ret = xencall2(xch->xcall, __HYPERVISOR_kexec_op,
145 KEXEC_CMD_kexec_status,
146 HYPERCALL_BUFFER_AS_ARG(status));
147
148 out:
149 xc_hypercall_buffer_free(xch, status);
150
151 return ret;
152 }
153