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