1 #include <xenevtchn.h>
2 #include <xenctrl.h>
3 #include <xc_private.h>
4 #include <xc_core.h>
5 #include <xenstore.h>
6 #include <unistd.h>
7 
8 static xc_interface *xch;
9 
show_help(void)10 void show_help(void)
11 {
12     fprintf(stderr,
13             "xen-hptool: Xen CPU/memory hotplug tool\n"
14             "Usage: xen-hptool <command> [args]\n"
15             "Commands:\n"
16             "  help                     display this help\n"
17             "  cpu-online    <cpuid>    online CPU <cpuid>\n"
18             "  cpu-offline   <cpuid>    offline CPU <cpuid>\n"
19             "  mem-online    <mfn>      online MEMORY <mfn>\n"
20             "  mem-offline   <mfn>      offline MEMORY <mfn>\n"
21             "  mem-status    <mfn>      query Memory status<mfn>\n"
22             "  smt-enable               onlines all SMT threads\n"
23             "  smt-disable              offlines all SMT threads\n"
24            );
25 }
26 
27 /* wrapper function */
help_func(int argc,char * argv[])28 static int help_func(int argc, char *argv[])
29 {
30     show_help();
31     return 0;
32 }
33 
hp_mem_online_func(int argc,char * argv[])34 static int hp_mem_online_func(int argc, char *argv[])
35 {
36     uint32_t status;
37     int ret;
38     unsigned long mfn;
39 
40     if (argc != 1)
41     {
42         show_help();
43         return -1;
44     }
45 
46     sscanf(argv[0], "%lx", &mfn);
47     printf("Prepare to online MEMORY mfn %lx\n", mfn);
48 
49     ret = xc_mark_page_online(xch, mfn, mfn, &status);
50 
51     if (ret < 0)
52         fprintf(stderr, "Onlining page mfn %lx failed, error %x", mfn, errno);
53     else if (status & (PG_ONLINE_FAILED |PG_ONLINE_BROKEN)) {
54         fprintf(stderr, "Onlining page mfn %lx is broken, "
55                         "Memory online failed\n", mfn);
56         ret = -1;
57 	}
58     else if (status & PG_ONLINE_ONLINED)
59         printf("Memory mfn %lx onlined successfully\n", mfn);
60     else
61         printf("Memory is already onlined!\n");
62 
63     return ret;
64 }
65 
hp_mem_query_func(int argc,char * argv[])66 static int hp_mem_query_func(int argc, char *argv[])
67 {
68     uint32_t status;
69     int ret;
70     unsigned long mfn;
71 
72     if (argc != 1)
73     {
74         show_help();
75         return -1;
76     }
77 
78     sscanf(argv[0], "%lx", &mfn);
79     printf("Querying MEMORY mfn %lx status\n", mfn);
80     ret = xc_query_page_offline_status(xch, mfn, mfn, &status);
81 
82     if (ret < 0)
83         fprintf(stderr, "Querying page mfn %lx failed, error %x", mfn, errno);
84     else
85     {
86 		printf("Memory Status %x: [", status);
87         if ( status & PG_OFFLINE_STATUS_OFFLINE_PENDING)
88             printf(" PAGE_OFFLINE_PENDING ");
89         if ( status & PG_OFFLINE_STATUS_BROKEN )
90             printf(" PAGE_BROKEND  ");
91         if ( status & PG_OFFLINE_STATUS_OFFLINED )
92             printf(" PAGE_OFFLINED ");
93 		else
94             printf(" PAGE_ONLINED ");
95         printf("]\n");
96     }
97 
98     return ret;
99 }
100 
suspend_guest(xc_interface * xch,xenevtchn_handle * xce,int domid,int * evtchn,int * lockfd)101 static int suspend_guest(xc_interface *xch, xenevtchn_handle *xce, int domid,
102                          int *evtchn, int *lockfd)
103 {
104     int port, rc, suspend_evtchn = -1;
105 
106     *lockfd = -1;
107 
108     if (!evtchn)
109         return -1;
110 
111     port = xs_suspend_evtchn_port(domid);
112     if (port < 0)
113     {
114         fprintf(stderr, "DOM%d: No suspend port, try live migration\n", domid);
115         goto failed;
116     }
117     suspend_evtchn = xc_suspend_evtchn_init_exclusive(xch, xce, domid,
118                                                       port, lockfd);
119     if (suspend_evtchn < 0)
120     {
121         fprintf(stderr, "Suspend evtchn initialization failed\n");
122         goto failed;
123     }
124     *evtchn = suspend_evtchn;
125 
126     rc = xenevtchn_notify(xce, suspend_evtchn);
127     if (rc < 0)
128     {
129         fprintf(stderr, "Failed to notify suspend channel: errno %d\n", rc);
130         goto failed;
131     }
132     if (xc_await_suspend(xch, xce, suspend_evtchn) < 0)
133     {
134         fprintf(stderr, "Suspend Failed\n");
135         goto failed;
136     }
137     return 0;
138 
139 failed:
140     if (suspend_evtchn != -1)
141         xc_suspend_evtchn_release(xch, xce, domid,
142                                   suspend_evtchn, lockfd);
143 
144     return -1;
145 }
146 
hp_mem_offline_func(int argc,char * argv[])147 static int hp_mem_offline_func(int argc, char *argv[])
148 {
149     uint32_t status, domid;
150     int ret;
151     unsigned long mfn;
152 
153     if (argc != 1)
154     {
155         show_help();
156         return -1;
157     }
158 
159     sscanf(argv[0], "%lx", &mfn);
160     printf("Prepare to offline MEMORY mfn %lx\n", mfn);
161     ret = xc_mark_page_offline(xch, mfn, mfn, &status);
162     if (ret < 0) {
163         fprintf(stderr, "Offlining page mfn %lx failed, error %x\n", mfn, errno);
164         if (status & (PG_OFFLINE_XENPAGE | PG_OFFLINE_FAILED))
165             fprintf(stderr, "XEN_PAGE is not permitted be offlined\n");
166         else if (status & (PG_OFFLINE_FAILED | PG_OFFLINE_NOT_CONV_RAM))
167             fprintf(stderr, "RESERVED RAM is not permitted to be offlined\n");
168     }
169     else
170     {
171         switch(status & PG_OFFLINE_STATUS_MASK)
172         {
173             case PG_OFFLINE_OFFLINED:
174             {
175                 printf("Memory mfn %lx offlined successfully, current state is"
176                        " [PG_OFFLINE_OFFLINED]\n", mfn);
177                 if (status & PG_OFFLINE_BROKEN)
178                     printf("And this offlined PAGE is already marked broken"
179                         " before!\n");
180                 break;
181             }
182             case PG_OFFLINE_FAILED:
183             {
184                 fprintf(stderr, "Memory mfn %lx offline failed\n", mfn);
185                 if ( status & PG_OFFLINE_ANONYMOUS)
186                     fprintf(stderr, "the memory is an anonymous page!\n");
187                 ret = -1;
188                 break;
189             }
190             case PG_OFFLINE_PENDING:
191             {
192                 if (status & PG_OFFLINE_XENPAGE) {
193                     ret = -1;
194                     fprintf(stderr, "Memory mfn %lx offlined succssefully,"
195                             "this page is xen page, current state is"
196                             " [PG_OFFLINE_PENDING, PG_OFFLINE_XENPAGE]\n", mfn);
197                 }
198                 else if (status & PG_OFFLINE_OWNED)
199                 {
200                     int result, suspend_evtchn = -1, suspend_lockfd = -1;
201                     xenevtchn_handle *xce;
202                     xce = xenevtchn_open(NULL, 0);
203 
204                     if (xce == NULL)
205                     {
206                         fprintf(stderr, "When exchange page, fail"
207                                 " to open evtchn\n");
208                         return -1;
209                     }
210 
211                     domid = status >> PG_OFFLINE_OWNER_SHIFT;
212                     if (suspend_guest(xch, xce, domid,
213                                       &suspend_evtchn, &suspend_lockfd))
214                     {
215                         fprintf(stderr, "Failed to suspend guest %d for"
216                                 " mfn %lx\n", domid, mfn);
217                         xenevtchn_close(xce);
218                         return -1;
219                     }
220 
221                     result = xc_exchange_page(xch, domid, mfn);
222 
223                     /* Exchange page successfully */
224                     if (result == 0)
225                         printf("Memory mfn %lx offlined successfully, this "
226                                 "page is DOM%d page and being swapped "
227                                 "successfully, current state is "
228                                 "[PG_OFFLINE_OFFLINED, PG_OFFLINE_OWNED]\n",
229                                 mfn, domid);
230                     else {
231                         ret = -1;
232                         fprintf(stderr, "Memory mfn %lx offlined successfully"
233                                 " , this page is DOM%d page yet failed to be "
234                                 "exchanged. current state is "
235                                 "[PG_OFFLINE_PENDING, PG_OFFLINE_OWNED]\n",
236                                 mfn, domid);
237                     }
238                     xc_domain_resume(xch, domid, 1);
239                     xc_suspend_evtchn_release(xch, xce, domid,
240                                               suspend_evtchn, &suspend_lockfd);
241                     xenevtchn_close(xce);
242                 }
243                 break;
244             }
245         }//end of switch
246     }//end of if
247 
248     return ret;
249 }
250 
exec_cpu_hp_fn(int (* hp_fn)(xc_interface *,int),int cpu)251 static int exec_cpu_hp_fn(int (*hp_fn)(xc_interface *, int), int cpu)
252 {
253     int ret;
254 
255     for ( ; ; )
256     {
257         ret = (*hp_fn)(xch, cpu);
258         if ( (ret >= 0) || (errno != EBUSY) )
259             break;
260         usleep(100000); /* 100ms */
261     }
262 
263     return ret;
264 }
265 
hp_cpu_online_func(int argc,char * argv[])266 static int hp_cpu_online_func(int argc, char *argv[])
267 {
268     int cpu, ret;
269 
270     if ( argc != 1 )
271     {
272         show_help();
273         return -1;
274     }
275 
276     cpu = atoi(argv[0]);
277     printf("Prepare to online CPU %d\n", cpu);
278     ret = exec_cpu_hp_fn(xc_cpu_online, cpu);
279     if (ret < 0)
280         fprintf(stderr, "CPU %d online failed (error %d: %s)\n",
281                 cpu, errno, strerror(errno));
282     else
283         printf("CPU %d onlined successfully\n", cpu);
284 
285     return ret;
286 
287 }
hp_cpu_offline_func(int argc,char * argv[])288 static int hp_cpu_offline_func(int argc, char *argv[])
289 {
290     int cpu, ret;
291 
292     if (argc != 1 )
293     {
294         show_help();
295         return -1;
296     }
297     cpu = atoi(argv[0]);
298     printf("Prepare to offline CPU %d\n", cpu);
299     ret = exec_cpu_hp_fn(xc_cpu_offline, cpu);
300     if (ret < 0)
301         fprintf(stderr, "CPU %d offline failed (error %d: %s)\n",
302                 cpu, errno, strerror(errno));
303     else
304         printf("CPU %d offlined successfully\n", cpu);
305 
306     return ret;
307 }
308 
main_smt_enable(int argc,char * argv[])309 static int main_smt_enable(int argc, char *argv[])
310 {
311     int ret;
312 
313     if ( argc )
314     {
315         show_help();
316         return -1;
317     }
318 
319     for ( ;; )
320     {
321         ret = xc_smt_enable(xch);
322         if ( (ret >= 0) || (errno != EBUSY) )
323             break;
324     }
325 
326     if ( ret < 0 )
327         fprintf(stderr, "Unable to enable SMT: errno %d, %s\n",
328                 errno, strerror(errno));
329     else
330         printf("Enabled SMT\n");
331 
332     return ret;
333 }
334 
main_smt_disable(int argc,char * argv[])335 static int main_smt_disable(int argc, char *argv[])
336 {
337     int ret;
338 
339     if ( argc )
340     {
341         show_help();
342         return -1;
343     }
344 
345     for ( ;; )
346     {
347         ret = xc_smt_disable(xch);
348         if ( (ret >= 0) || (errno != EBUSY) )
349             break;
350     }
351 
352     if ( ret < 0 )
353         fprintf(stderr, "Unable to disable SMT: errno %d, %s\n",
354                 errno, strerror(errno));
355     else
356         printf("Disabled SMT\n");
357 
358     return ret;
359 }
360 
361 struct {
362     const char *name;
363     int (*function)(int argc, char *argv[]);
364 } main_options[] = {
365     { "help", help_func },
366     { "cpu-online", hp_cpu_online_func },
367     { "cpu-offline", hp_cpu_offline_func },
368     { "mem-status", hp_mem_query_func},
369     { "mem-online", hp_mem_online_func},
370     { "mem-offline", hp_mem_offline_func},
371     { "smt-enable", main_smt_enable },
372     { "smt-disable", main_smt_disable },
373 };
374 
375 
main(int argc,char * argv[])376 int main(int argc, char *argv[])
377 {
378     int i, ret;
379 
380     if (argc < 2)
381     {
382         show_help();
383         return 0;
384     }
385 
386     xch = xc_interface_open(0,0,0);
387     if ( !xch )
388     {
389         fprintf(stderr, "failed to get the handler\n");
390         return 0;
391     }
392 
393     for ( i = 0; i < ARRAY_SIZE(main_options); i++ )
394         if (!strncmp(main_options[i].name, argv[1], strlen(argv[1])))
395             break;
396     if ( i == ARRAY_SIZE(main_options) )
397     {
398         fprintf(stderr, "Unrecognised command '%s' -- try "
399                 "'xen-hptool help'\n", argv[1]);
400         return 1;
401     }
402 
403     ret = main_options[i].function(argc -2, argv + 2);
404 
405     xc_interface_close(xch);
406 
407     return !!ret;
408 }
409