ia64/xen-unstable

view tools/libxc/ia64/xc_ia64_hvm_build.c @ 15333:634b7f7f8584

[IA64] When a domU is destroyed, it will fall into NVRAM saving
path. But if there is no NVRAM file for the domU, the save operation
would fail. Then domU blocked by Xend's exception. This patch fixs
that issue.

Signed-off-by: Zhang Xin <xing.z.zhang@intel.com>
author kfraser@localhost.localdomain
date Tue Jun 12 11:32:03 2007 +0100 (2007-06-12)
parents 17f6163ae930
children 96617c4f19aa
line source
1 #include "xg_private.h"
2 #include "xenguest.h"
3 #include "xc_private.h"
4 #include "xc_elf.h"
5 #include <stdlib.h>
6 #include <zlib.h>
7 #include "xen/arch-ia64.h"
8 #include <xen/hvm/ioreq.h>
9 #include <xen/hvm/params.h>
11 static int
12 xc_ia64_copy_to_domain_pages(int xc_handle, uint32_t domid, void* src_page,
13 unsigned long dst_pfn, int nr_pages)
14 {
15 // N.B. gva should be page aligned
16 int i;
18 for (i = 0; i < nr_pages; i++) {
19 if (xc_copy_to_domain_page(xc_handle, domid, dst_pfn + i,
20 src_page + (i << PAGE_SHIFT)))
21 return -1;
22 }
24 return 0;
25 }
27 int
28 xc_set_hvm_param(int handle, domid_t dom, int param, unsigned long value)
29 {
30 DECLARE_HYPERCALL;
31 xen_hvm_param_t arg;
32 int rc;
34 hypercall.op = __HYPERVISOR_hvm_op;
35 hypercall.arg[0] = HVMOP_set_param;
36 hypercall.arg[1] = (unsigned long)&arg;
38 arg.domid = dom;
39 arg.index = param;
40 arg.value = value;
42 if (mlock(&arg, sizeof(arg)) != 0)
43 return -1;
45 rc = do_xen_hypercall(handle, &hypercall);
46 safe_munlock(&arg, sizeof(arg));
48 return rc;
49 }
51 int
52 xc_get_hvm_param(int handle, domid_t dom, int param, unsigned long *value)
53 {
54 DECLARE_HYPERCALL;
55 xen_hvm_param_t arg;
56 int rc;
58 hypercall.op = __HYPERVISOR_hvm_op;
59 hypercall.arg[0] = HVMOP_get_param;
60 hypercall.arg[1] = (unsigned long)&arg;
62 arg.domid = dom;
63 arg.index = param;
65 if (mlock(&arg, sizeof(arg)) != 0)
66 return -1;
68 rc = do_xen_hypercall(handle, &hypercall);
69 safe_munlock(&arg, sizeof(arg));
71 *value = arg.value;
72 return rc;
73 }
75 #define HOB_SIGNATURE 0x3436474953424f48 // "HOBSIG64"
76 #define GFW_HOB_START ((4UL<<30)-(14UL<<20)) // 4G - 14M
77 #define GFW_HOB_SIZE (1UL<<20) // 1M
79 typedef struct {
80 unsigned long signature;
81 unsigned int type;
82 unsigned int length;
83 } HOB_GENERIC_HEADER;
85 /*
86 * INFO HOB is the first data data in one HOB list
87 * it contains the control information of the HOB list
88 */
89 typedef struct {
90 HOB_GENERIC_HEADER header;
91 unsigned long length; // current length of hob
92 unsigned long cur_pos; // current poisiton of hob
93 unsigned long buf_size; // size of hob buffer
94 } HOB_INFO;
96 typedef struct{
97 unsigned long start;
98 unsigned long size;
99 } hob_mem_t;
101 typedef enum {
102 HOB_TYPE_INFO=0,
103 HOB_TYPE_TERMINAL,
104 HOB_TYPE_MEM,
105 HOB_TYPE_PAL_BUS_GET_FEATURES_DATA,
106 HOB_TYPE_PAL_CACHE_SUMMARY,
107 HOB_TYPE_PAL_MEM_ATTRIB,
108 HOB_TYPE_PAL_CACHE_INFO,
109 HOB_TYPE_PAL_CACHE_PROT_INFO,
110 HOB_TYPE_PAL_DEBUG_INFO,
111 HOB_TYPE_PAL_FIXED_ADDR,
112 HOB_TYPE_PAL_FREQ_BASE,
113 HOB_TYPE_PAL_FREQ_RATIOS,
114 HOB_TYPE_PAL_HALT_INFO,
115 HOB_TYPE_PAL_PERF_MON_INFO,
116 HOB_TYPE_PAL_PROC_GET_FEATURES,
117 HOB_TYPE_PAL_PTCE_INFO,
118 HOB_TYPE_PAL_REGISTER_INFO,
119 HOB_TYPE_PAL_RSE_INFO,
120 HOB_TYPE_PAL_TEST_INFO,
121 HOB_TYPE_PAL_VM_SUMMARY,
122 HOB_TYPE_PAL_VM_INFO,
123 HOB_TYPE_PAL_VM_PAGE_SIZE,
124 HOB_TYPE_NR_VCPU,
125 HOB_TYPE_NVRAM,
126 HOB_TYPE_MAX
127 } hob_type_t;
129 static int hob_init(void *buffer ,unsigned long buf_size);
130 static int add_pal_hob(void* hob_buf);
131 static int add_mem_hob(void* hob_buf, unsigned long dom_mem_size);
132 static int add_vcpus_hob(void* hob_buf, unsigned long nr_vcpu);
133 static int add_nvram_hob(void* hob_buf, unsigned long nvram_addr);
134 static int build_hob(void* hob_buf, unsigned long hob_buf_size,
135 unsigned long dom_mem_size, unsigned long vcpus,
136 unsigned long nvram_addr);
137 static int load_hob(int xc_handle,uint32_t dom, void *hob_buf,
138 unsigned long dom_mem_size);
140 static int
141 xc_ia64_build_hob(int xc_handle, uint32_t dom,
142 unsigned long memsize, unsigned long vcpus,
143 unsigned long nvram_addr)
144 {
145 char *hob_buf;
147 hob_buf = malloc(GFW_HOB_SIZE);
148 if (hob_buf == NULL) {
149 PERROR("Could not allocate hob");
150 return -1;
151 }
153 if (build_hob(hob_buf, GFW_HOB_SIZE, memsize, vcpus, nvram_addr) < 0) {
154 free(hob_buf);
155 PERROR("Could not build hob");
156 return -1;
157 }
159 if (load_hob(xc_handle, dom, hob_buf, memsize) < 0) {
160 free(hob_buf);
161 PERROR("Could not load hob");
162 return -1;
163 }
164 free(hob_buf);
165 return 0;
167 }
169 static int
170 hob_init(void *buffer, unsigned long buf_size)
171 {
172 HOB_INFO *phit;
173 HOB_GENERIC_HEADER *terminal;
175 if (sizeof(HOB_INFO) + sizeof(HOB_GENERIC_HEADER) > buf_size) {
176 // buffer too small
177 return -1;
178 }
180 phit = (HOB_INFO*)buffer;
181 phit->header.signature = HOB_SIGNATURE;
182 phit->header.type = HOB_TYPE_INFO;
183 phit->header.length = sizeof(HOB_INFO);
184 phit->length = sizeof(HOB_INFO) + sizeof(HOB_GENERIC_HEADER);
185 phit->cur_pos = 0;
186 phit->buf_size = buf_size;
188 terminal = (HOB_GENERIC_HEADER*)(buffer + sizeof(HOB_INFO));
189 terminal->signature = HOB_SIGNATURE;
190 terminal->type = HOB_TYPE_TERMINAL;
191 terminal->length = sizeof(HOB_GENERIC_HEADER);
193 return 0;
194 }
196 /*
197 * Add a new HOB to the HOB List.
198 *
199 * hob_start - start address of hob buffer
200 * type - type of the hob to be added
201 * data - data of the hob to be added
202 * data_size - size of the data
203 */
204 static int
205 hob_add(void* hob_start, int type, void* data, int data_size)
206 {
207 HOB_INFO *phit;
208 HOB_GENERIC_HEADER *newhob, *tail;
210 phit = (HOB_INFO*)hob_start;
212 if (phit->length + data_size > phit->buf_size) {
213 // no space for new hob
214 return -1;
215 }
217 //append new HOB
218 newhob = (HOB_GENERIC_HEADER*)(hob_start + phit->length -
219 sizeof(HOB_GENERIC_HEADER));
220 newhob->signature = HOB_SIGNATURE;
221 newhob->type = type;
222 newhob->length = data_size + sizeof(HOB_GENERIC_HEADER);
223 memcpy((void*)newhob + sizeof(HOB_GENERIC_HEADER), data, data_size);
225 // append terminal HOB
226 tail = (HOB_GENERIC_HEADER*)(hob_start + phit->length + data_size);
227 tail->signature = HOB_SIGNATURE;
228 tail->type = HOB_TYPE_TERMINAL;
229 tail->length = sizeof(HOB_GENERIC_HEADER);
231 // adjust HOB list length
232 phit->length += sizeof(HOB_GENERIC_HEADER) + data_size;
234 return 0;
235 }
237 static int
238 get_hob_size(void* hob_buf)
239 {
240 HOB_INFO *phit = (HOB_INFO*)hob_buf;
242 if (phit->header.signature != HOB_SIGNATURE) {
243 PERROR("xc_get_hob_size:Incorrect signature");
244 return -1;
245 }
246 return phit->length;
247 }
249 static int
250 build_hob(void* hob_buf, unsigned long hob_buf_size,
251 unsigned long dom_mem_size, unsigned long vcpus,
252 unsigned long nvram_addr)
253 {
254 //Init HOB List
255 if (hob_init(hob_buf, hob_buf_size) < 0) {
256 PERROR("buffer too small");
257 goto err_out;
258 }
260 if (add_mem_hob(hob_buf,dom_mem_size) < 0) {
261 PERROR("Add memory hob failed, buffer too small");
262 goto err_out;
263 }
265 if (add_vcpus_hob(hob_buf, vcpus) < 0) {
266 PERROR("Add NR_VCPU hob failed, buffer too small");
267 goto err_out;
268 }
270 if (add_pal_hob( hob_buf ) < 0) {
271 PERROR("Add PAL hob failed, buffer too small");
272 goto err_out;
273 }
275 if (add_nvram_hob( hob_buf, nvram_addr ) < 0) {
276 PERROR("Add nvram hob failed, buffer too small");
277 goto err_out;
278 }
280 return 0;
282 err_out:
283 return -1;
284 }
286 static int
287 load_hob(int xc_handle, uint32_t dom, void *hob_buf,
288 unsigned long dom_mem_size)
289 {
290 // hob_buf should be page aligned
291 int hob_size;
292 int nr_pages;
294 hob_size = get_hob_size(hob_buf);
295 if (hob_size < 0) {
296 PERROR("Invalid hob data");
297 return -1;
298 }
300 if (hob_size > GFW_HOB_SIZE) {
301 PERROR("No enough memory for hob data");
302 return -1;
303 }
305 nr_pages = (hob_size + PAGE_SIZE -1) >> PAGE_SHIFT;
307 return xc_ia64_copy_to_domain_pages(xc_handle, dom, hob_buf,
308 GFW_HOB_START >> PAGE_SHIFT, nr_pages);
309 }
311 #define MIN(x, y) ((x) < (y)) ? (x) : (y)
312 static int
313 add_mem_hob(void* hob_buf, unsigned long dom_mem_size)
314 {
315 hob_mem_t memhob;
317 // less than 3G
318 memhob.start = 0;
319 memhob.size = MIN(dom_mem_size, 0xC0000000);
321 if (hob_add(hob_buf, HOB_TYPE_MEM, &memhob, sizeof(memhob)) < 0)
322 return -1;
324 if (dom_mem_size > 0xC0000000) {
325 // 4G ~ 4G+remain
326 memhob.start = 0x100000000; //4G
327 memhob.size = dom_mem_size - 0xC0000000;
328 if (hob_add(hob_buf, HOB_TYPE_MEM, &memhob, sizeof(memhob)) < 0)
329 return -1;
330 }
331 return 0;
332 }
334 static int
335 add_vcpus_hob(void* hob_buf, unsigned long vcpus)
336 {
337 return hob_add(hob_buf, HOB_TYPE_NR_VCPU, &vcpus, sizeof(vcpus));
338 }
340 static int
341 add_nvram_hob(void *hob_buf, unsigned long nvram_addr)
342 {
343 return hob_add(hob_buf, HOB_TYPE_NVRAM, &nvram_addr, sizeof(nvram_addr));
344 }
346 static const unsigned char config_pal_bus_get_features_data[24] = {
347 0, 0, 0, 32, 0, 0, 240, 189, 0, 0, 0, 0, 0, 0,
348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
349 };
351 static const unsigned char config_pal_cache_summary[16] = {
352 3, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0
353 };
355 static const unsigned char config_pal_mem_attrib[8] = {
356 241, 0, 0, 0, 0, 0, 0, 0
357 };
359 static const unsigned char config_pal_cache_info[152] = {
360 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
361 6, 4, 6, 7, 255, 1, 0, 1, 0, 64, 0, 0, 12, 12,
362 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 7, 0, 1,
363 0, 1, 0, 64, 0, 0, 12, 12, 49, 0, 0, 0, 0, 0, 0,
364 0, 0, 0, 6, 8, 7, 7, 255, 7, 0, 11, 0, 0, 16, 0,
365 12, 17, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7,
366 7, 7, 5, 9, 11, 0, 0, 4, 0, 12, 15, 49, 0, 254, 255,
367 255, 255, 255, 255, 255, 255, 2, 8, 7, 7, 7, 5, 9,
368 11, 0, 0, 4, 0, 12, 15, 49, 0, 0, 0, 0, 0, 0, 0, 0,
369 0, 3, 12, 7, 7, 7, 14, 1, 3, 0, 0, 192, 0, 12, 20, 49, 0
370 };
372 static const unsigned char config_pal_cache_prot_info[200] = {
373 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
374 45, 0, 16, 8, 0, 76, 12, 64, 0, 0, 0, 0, 0, 0, 0,
375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
376 8, 0, 16, 4, 0, 76, 44, 68, 0, 0, 0, 0, 0, 0, 0, 0,
377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32,
378 0, 16, 8, 0, 81, 44, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0,
379 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0,
380 112, 12, 0, 79, 124, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
381 0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255,
382 32, 0, 112, 12, 0, 79, 124, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 160,
384 12, 0, 84, 124, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
385 0, 0, 0
386 };
388 static const unsigned char config_pal_debug_info[16] = {
389 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0
390 };
392 static const unsigned char config_pal_fixed_addr[8] = {
393 0, 0, 0, 0, 0, 0, 0, 0
394 };
396 static const unsigned char config_pal_freq_base[8] = {
397 109, 219, 182, 13, 0, 0, 0, 0
398 };
400 static const unsigned char config_pal_freq_ratios[24] = {
401 11, 1, 0, 0, 77, 7, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 4,
402 0, 0, 0, 7, 0, 0, 0
403 };
405 static const unsigned char config_pal_halt_info[64] = {
406 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0,
407 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
408 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
409 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
410 };
412 static const unsigned char config_pal_perf_mon_info[136] = {
413 12, 47, 18, 8, 0, 0, 0, 0, 241, 255, 0, 0, 255, 7, 0, 0,
414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
415 0, 0, 0, 0, 0, 0, 0, 0, 241, 255, 0, 0, 223, 0, 255, 255,
416 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
417 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 0, 0, 0, 0, 0, 0,
418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
419 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 0, 0, 0, 0, 0, 0,
420 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
421 0, 0, 0, 0, 0, 0, 0, 0
422 };
424 static const unsigned char config_pal_proc_get_features[104] = {
425 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
426 0, 0, 0, 0, 64, 6, 64, 49, 0, 0, 0, 0, 64, 6, 0, 0,
427 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,
428 231, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0, 0,
429 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0,
430 63, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0,
431 0, 0, 0, 0, 0, 0, 0, 0
432 };
434 static const unsigned char config_pal_ptce_info[24] = {
435 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
436 0, 0, 0, 0, 0, 0, 0, 0
437 };
439 static const unsigned char config_pal_register_info[64] = {
440 255, 0, 47, 127, 17, 17, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0,
441 255, 208, 128, 238, 238, 0, 0, 248, 255, 255, 255, 255, 255, 0, 0, 7, 3,
442 251, 3, 0, 0, 0, 0, 255, 7, 3, 0, 0, 0, 0, 0, 248, 252, 4,
443 252, 255, 255, 255, 255, 2, 248, 252, 255, 255, 255, 255, 255
444 };
446 static const unsigned char config_pal_rse_info[16] = {
447 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
448 };
450 static const unsigned char config_pal_test_info[48] = {
451 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
452 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
453 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
454 };
456 static const unsigned char config_pal_vm_summary[16] = {
457 101, 18, 15, 2, 7, 7, 4, 2, 59, 18, 0, 0, 0, 0, 0, 0
458 };
460 static const unsigned char config_pal_vm_info[104] = {
461 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
462 32, 32, 0, 0, 0, 0, 0, 0, 112, 85, 21, 0, 0, 0, 0, 0, 0,
463 0, 0, 0, 0, 0, 0, 1, 32, 32, 0, 0, 0, 0, 0, 0, 112, 85,
464 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 128, 128, 0,
465 4, 0, 0, 0, 0, 112, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
466 0, 0, 0, 1, 128, 128, 0, 4, 0, 0, 0, 0, 112, 85, 0, 0, 0, 0, 0
467 };
469 static const unsigned char config_pal_vm_page_size[16] = {
470 0, 112, 85, 21, 0, 0, 0, 0, 0, 112, 85, 21, 0, 0, 0, 0
471 };
473 typedef struct{
474 hob_type_t type;
475 void* data;
476 unsigned long size;
477 } hob_batch_t;
479 static const hob_batch_t hob_batch[]={
480 { HOB_TYPE_PAL_BUS_GET_FEATURES_DATA,
481 &config_pal_bus_get_features_data,
482 sizeof(config_pal_bus_get_features_data)
483 },
484 { HOB_TYPE_PAL_CACHE_SUMMARY,
485 &config_pal_cache_summary,
486 sizeof(config_pal_cache_summary)
487 },
488 { HOB_TYPE_PAL_MEM_ATTRIB,
489 &config_pal_mem_attrib,
490 sizeof(config_pal_mem_attrib)
491 },
492 { HOB_TYPE_PAL_CACHE_INFO,
493 &config_pal_cache_info,
494 sizeof(config_pal_cache_info)
495 },
496 { HOB_TYPE_PAL_CACHE_PROT_INFO,
497 &config_pal_cache_prot_info,
498 sizeof(config_pal_cache_prot_info)
499 },
500 { HOB_TYPE_PAL_DEBUG_INFO,
501 &config_pal_debug_info,
502 sizeof(config_pal_debug_info)
503 },
504 { HOB_TYPE_PAL_FIXED_ADDR,
505 &config_pal_fixed_addr,
506 sizeof(config_pal_fixed_addr)
507 },
508 { HOB_TYPE_PAL_FREQ_BASE,
509 &config_pal_freq_base,
510 sizeof(config_pal_freq_base)
511 },
512 { HOB_TYPE_PAL_FREQ_RATIOS,
513 &config_pal_freq_ratios,
514 sizeof(config_pal_freq_ratios)
515 },
516 { HOB_TYPE_PAL_HALT_INFO,
517 &config_pal_halt_info,
518 sizeof(config_pal_halt_info)
519 },
520 { HOB_TYPE_PAL_PERF_MON_INFO,
521 &config_pal_perf_mon_info,
522 sizeof(config_pal_perf_mon_info)
523 },
524 { HOB_TYPE_PAL_PROC_GET_FEATURES,
525 &config_pal_proc_get_features,
526 sizeof(config_pal_proc_get_features)
527 },
528 { HOB_TYPE_PAL_PTCE_INFO,
529 &config_pal_ptce_info,
530 sizeof(config_pal_ptce_info)
531 },
532 { HOB_TYPE_PAL_REGISTER_INFO,
533 &config_pal_register_info,
534 sizeof(config_pal_register_info)
535 },
536 { HOB_TYPE_PAL_RSE_INFO,
537 &config_pal_rse_info,
538 sizeof(config_pal_rse_info)
539 },
540 { HOB_TYPE_PAL_TEST_INFO,
541 &config_pal_test_info,
542 sizeof(config_pal_test_info)
543 },
544 { HOB_TYPE_PAL_VM_SUMMARY,
545 &config_pal_vm_summary,
546 sizeof(config_pal_vm_summary)
547 },
548 { HOB_TYPE_PAL_VM_INFO,
549 &config_pal_vm_info,
550 sizeof(config_pal_vm_info)
551 },
552 { HOB_TYPE_PAL_VM_PAGE_SIZE,
553 &config_pal_vm_page_size,
554 sizeof(config_pal_vm_page_size)
555 },
556 };
558 static int
559 add_pal_hob(void* hob_buf)
560 {
561 int i;
562 for (i = 0; i < sizeof(hob_batch)/sizeof(hob_batch_t); i++) {
563 if (hob_add(hob_buf, hob_batch[i].type, hob_batch[i].data,
564 hob_batch[i].size) < 0)
565 return -1;
566 }
567 return 0;
568 }
570 // The most significant bit of nvram file descriptor:
571 // 1: valid; 0: invalid
572 #define VALIDATE_NVRAM_FD(x) ((1UL<<(sizeof(x)*8 - 1)) | x)
573 #define IS_VALID_NVRAM_FD(x) ((uint64_t)x >> (sizeof(x)*8 - 1))
574 static uint64_t
575 nvram_init(const char *nvram_path)
576 {
577 uint64_t fd = 0;
578 fd = open(nvram_path, O_CREAT|O_RDWR, 0666);
580 if ( fd < 0 )
581 {
582 PERROR("Nvram open failed at %s. Guest will boot without"
583 " nvram support!\n", nvram_path);
584 return -1;
585 }
587 return VALIDATE_NVRAM_FD(fd);
588 }
590 static int
591 copy_from_nvram_to_GFW(int xc_handle, uint32_t dom, int nvram_fd)
592 {
593 unsigned int nr_pages = NVRAM_SIZE >> PAGE_SHIFT;
594 struct stat file_stat;
595 char buf[NVRAM_SIZE] = {0};
597 if ( fstat(nvram_fd, &file_stat) < 0 )
598 {
599 PERROR("Cannot get Nvram file info! Guest will boot without "
600 "nvram support!\n");
601 return -1;
602 }
604 if ( 0 == file_stat.st_size )
605 {
606 DPRINTF("Nvram file create successful!\n");
607 return 0;
608 }
610 if ( read(nvram_fd, buf, NVRAM_SIZE) != NVRAM_SIZE )
611 {
612 PERROR("Load nvram fail. guest will boot without"
613 " nvram support!\n");
614 return -1;
615 }
617 return xc_ia64_copy_to_domain_pages(xc_handle, dom, buf,
618 NVRAM_START >> PAGE_SHIFT,
619 nr_pages);
620 }
623 /*
624 * GFW use 4k page. when doing foreign map, we should 16k align
625 * the address and map one more page to guarantee all 64k nvram data
626 * can be got.
627 */
628 static int
629 copy_from_GFW_to_nvram(int xc_handle, uint32_t dom, int nvram_fd)
630 {
631 xen_pfn_t *pfn_list = NULL;
632 char *tmp_ptr = NULL;
633 unsigned int nr_pages = 0;
634 uint64_t addr_from_GFW_4k_align = 0;
635 uint32_t offset = 0;
636 uint64_t nvram_base_addr = 0;
637 char buf[NVRAM_SIZE] = {0};
638 int i;
641 // map one more page
642 nr_pages = (NVRAM_SIZE + PAGE_SIZE) >> PAGE_SHIFT;
643 pfn_list = (xen_pfn_t *)malloc(sizeof(xen_pfn_t) * nr_pages);
644 if ( NULL == pfn_list )
645 {
646 PERROR("Cannot allocate memory for nvram save!\n");
647 close(nvram_fd);
648 return -1;
649 }
651 /*
652 * GFW allocate memory dynamicly to save nvram data
653 * and save address of the dynamic memory at NVRAM_START.
654 * To save nvram data to file, we must get the dynamic
655 * memory address first.
656 */
657 pfn_list[0] = NVRAM_START >> PAGE_SHIFT;
658 tmp_ptr = (char *)xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
659 PROT_READ | PROT_WRITE, pfn_list[0]);
661 if ( NULL == tmp_ptr )
662 {
663 PERROR("Cannot get nvram data from GFW!\n");
664 free(pfn_list);
665 close(nvram_fd);
666 return -1;
667 }
669 addr_from_GFW_4k_align = *((uint64_t *)tmp_ptr);
670 munmap(tmp_ptr, PAGE_SIZE);
672 // align address to 16k
673 offset = addr_from_GFW_4k_align % ( 16 * MEM_K );
674 addr_from_GFW_4k_align = addr_from_GFW_4k_align - offset;
675 for ( i=0; i<nr_pages; i++ )
676 pfn_list[i] = (addr_from_GFW_4k_align >> PAGE_SHIFT) + i;
678 tmp_ptr = (char *)xc_map_foreign_batch(xc_handle, dom,
679 PROT_READ | PROT_WRITE, pfn_list, nr_pages);
680 if ( NULL == tmp_ptr )
681 {
682 PERROR("Cannot get nvram data from GFW!\n");
683 free(pfn_list);
684 close(nvram_fd);
685 return -1;
686 }
688 // calculate nvram data base addrees
689 nvram_base_addr = (uint64_t)(tmp_ptr + offset);
691 memcpy(buf, (void *)nvram_base_addr, NVRAM_SIZE);
692 free(pfn_list);
693 munmap(tmp_ptr, NVRAM_SIZE + PAGE_SIZE);
695 lseek(nvram_fd, 0, SEEK_SET);
696 if ( write(nvram_fd, buf, NVRAM_SIZE) != NVRAM_SIZE )
697 {
698 PERROR("Save to nvram fail!\n");
699 return -1;
700 }
702 close(nvram_fd);
704 DPRINTF("Nvram save successful!\n");
706 return 0;
707 }
709 int xc_ia64_save_to_nvram(int xc_handle, uint32_t dom)
710 {
711 uint64_t nvram_fd = 0;
712 xc_get_hvm_param(xc_handle, dom, HVM_PARAM_NVRAM_FD, &nvram_fd);
714 if ( !IS_VALID_NVRAM_FD(nvram_fd) )
715 PERROR("Nvram not be initialized. Nvram save fail!\n");
716 else
717 copy_from_GFW_to_nvram(xc_handle, dom, (int)nvram_fd);
719 // although save to nvram maybe fail, we don't return any error number
720 // to Xend. This is quite logical because damage of NVRAM on native would
721 // not block OS's executive path. Return error number will cause an exception
722 // of Xend and block XenU when it destroy.
723 return 0;
724 }
726 #define NVRAM_FILE_PATH "/usr/lib/xen/boot/nvram_"
727 int xc_ia64_nvram_init(int xc_handle, char *dom_name, uint32_t dom)
728 {
729 int file_path_len = strlen(NVRAM_FILE_PATH);
730 uint64_t nvram_fd = 0;
731 char nvram_path[100] = {0};
733 strncpy(nvram_path, NVRAM_FILE_PATH, file_path_len);
734 if ( file_path_len + strlen(dom_name) + 1 > sizeof(nvram_path) )
735 {
736 PERROR("Nvram file path is too long!\n");
737 return -1;
738 }
739 strcpy(nvram_path + file_path_len, dom_name);
741 nvram_fd = nvram_init(nvram_path);
742 if ( nvram_fd == (uint64_t)(-1) )
743 {
744 xc_set_hvm_param(xc_handle, dom, HVM_PARAM_NVRAM_FD, 0);
745 return -1;
746 }
748 xc_set_hvm_param(xc_handle, dom, HVM_PARAM_NVRAM_FD, nvram_fd);
749 return 0;
750 }
752 #define GFW_PAGES (GFW_SIZE >> PAGE_SHIFT)
753 #define VGA_START_PAGE (VGA_IO_START >> PAGE_SHIFT)
754 #define VGA_END_PAGE ((VGA_IO_START + VGA_IO_SIZE) >> PAGE_SHIFT)
755 /*
756 * In this function, we will allocate memory and build P2M/M2P table for VTI
757 * guest. Frist, a pfn list will be initialized discontiguous, normal memory
758 * begins with 0, GFW memory and other three pages at their place defined in
759 * xen/include/public/arch-ia64.h xc_domain_memory_populate_physmap() called
760 * three times, to set parameter 'extent_order' to different value, this is
761 * convenient to allocate discontiguous memory with different size.
762 */
763 static int
764 setup_guest(int xc_handle, uint32_t dom, unsigned long memsize,
765 char *image, unsigned long image_size, vcpu_guest_context_t *ctxt)
766 {
767 xen_pfn_t *pfn_list;
768 shared_iopage_t *sp;
769 void *ioreq_buffer_page;
770 void *pio_buffer_page;
771 unsigned long dom_memsize = memsize << 20;
772 unsigned long nr_pages = memsize << (20 - PAGE_SHIFT);
773 unsigned long vcpus;
774 unsigned long nvram_start = NVRAM_START, nvram_fd = 0;
775 int rc;
776 long i;
777 DECLARE_DOMCTL;
780 if ((image_size > 12 * MEM_M) || (image_size & (PAGE_SIZE - 1))) {
781 PERROR("Guest firmware size is incorrect [%ld]?", image_size);
782 return -1;
783 }
785 pfn_list = malloc(nr_pages * sizeof(xen_pfn_t));
786 if (pfn_list == NULL) {
787 PERROR("Could not allocate memory.\n");
788 return -1;
789 }
791 // Allocate pfn for normal memory
792 for (i = 0; i < dom_memsize >> PAGE_SHIFT; i++)
793 pfn_list[i] = i;
795 // If normal memory > 3G. Reserve 3G ~ 4G for MMIO, GFW and others.
796 for (i = (MMIO_START >> PAGE_SHIFT); i < (dom_memsize >> PAGE_SHIFT); i++)
797 pfn_list[i] += ((1 * MEM_G) >> PAGE_SHIFT);
799 // Allocate memory for VTI guest, up to VGA hole from 0xA0000-0xC0000.
800 rc = xc_domain_memory_populate_physmap(xc_handle, dom,
801 (nr_pages > VGA_START_PAGE) ?
802 VGA_START_PAGE : nr_pages,
803 0, 0, &pfn_list[0]);
805 // We're not likely to attempt to create a domain with less than
806 // 640k of memory, but test for completeness
807 if (rc == 0 && nr_pages > VGA_END_PAGE)
808 rc = xc_domain_memory_populate_physmap(xc_handle, dom,
809 nr_pages - VGA_END_PAGE,
810 0, 0, &pfn_list[VGA_END_PAGE]);
811 if (rc != 0) {
812 PERROR("Could not allocate normal memory for Vti guest.\n");
813 goto error_out;
814 }
816 // We allocate additional pfn for GFW and other three pages, so
817 // the pfn_list is not contiguous. Due to this we must support
818 // old interface xc_ia64_get_pfn_list().
819 for (i = 0; i < GFW_PAGES; i++)
820 pfn_list[i] = (GFW_START >> PAGE_SHIFT) + i;
822 rc = xc_domain_memory_populate_physmap(xc_handle, dom, GFW_PAGES,
823 0, 0, &pfn_list[0]);
824 if (rc != 0) {
825 PERROR("Could not allocate GFW memory for Vti guest.\n");
826 goto error_out;
827 }
829 pfn_list[0] = IO_PAGE_START >> PAGE_SHIFT;
830 pfn_list[1] = STORE_PAGE_START >> PAGE_SHIFT;
831 pfn_list[2] = BUFFER_IO_PAGE_START >> PAGE_SHIFT;
832 pfn_list[3] = BUFFER_PIO_PAGE_START >> PAGE_SHIFT;
834 rc = xc_domain_memory_populate_physmap(xc_handle, dom, 4,
835 0, 0, &pfn_list[0]);
836 if (rc != 0) {
837 PERROR("Could not allocate IO page or store page or buffer io page.\n");
838 goto error_out;
839 }
841 domctl.u.arch_setup.flags = XEN_DOMAINSETUP_hvm_guest;
842 domctl.u.arch_setup.bp = 0;
843 domctl.u.arch_setup.maxmem = 0;
844 domctl.cmd = XEN_DOMCTL_arch_setup;
845 domctl.domain = (domid_t)dom;
846 if (xc_domctl(xc_handle, &domctl))
847 goto error_out;
849 // Load guest firmware
850 if (xc_ia64_copy_to_domain_pages(xc_handle, dom, image,
851 (GFW_START + GFW_SIZE - image_size) >> PAGE_SHIFT,
852 image_size >> PAGE_SHIFT)) {
853 PERROR("Could not load guest firmware into domain");
854 goto error_out;
855 }
857 domctl.cmd = XEN_DOMCTL_getdomaininfo;
858 domctl.domain = (domid_t)dom;
859 if (xc_domctl(xc_handle, &domctl) < 0) {
860 PERROR("Could not get info on domain");
861 goto error_out;
862 }
864 xc_get_hvm_param(xc_handle, dom, HVM_PARAM_NVRAM_FD, &nvram_fd);
865 if ( !IS_VALID_NVRAM_FD(nvram_fd) )
866 nvram_start = 0;
867 else
868 if ( copy_from_nvram_to_GFW(xc_handle, dom, (int)nvram_fd ) == -1 )
869 {
870 nvram_start = 0;
871 close(nvram_fd);
872 }
874 vcpus = domctl.u.getdomaininfo.max_vcpu_id + 1;
876 // Hand-off state passed to guest firmware
877 if (xc_ia64_build_hob(xc_handle, dom, dom_memsize, vcpus, nvram_start) < 0) {
878 PERROR("Could not build hob\n");
879 goto error_out;
880 }
882 xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, pfn_list[1]);
884 // Retrieve special pages like io, xenstore, etc.
885 sp = (shared_iopage_t *)xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
886 PROT_READ | PROT_WRITE,
887 pfn_list[0]);
888 if (sp == 0)
889 goto error_out;
891 memset(sp, 0, PAGE_SIZE);
892 munmap(sp, PAGE_SIZE);
893 ioreq_buffer_page = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
894 PROT_READ | PROT_WRITE,
895 pfn_list[2]);
896 memset(ioreq_buffer_page,0,PAGE_SIZE);
897 munmap(ioreq_buffer_page, PAGE_SIZE);
899 pio_buffer_page = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
900 PROT_READ | PROT_WRITE,
901 pfn_list[3]);
902 memset(pio_buffer_page,0,PAGE_SIZE);
903 munmap(pio_buffer_page, PAGE_SIZE);
904 free(pfn_list);
905 return 0;
907 error_out:
908 return -1;
909 }
911 int
912 xc_hvm_build(int xc_handle, uint32_t domid, int memsize, const char *image_name)
913 {
914 struct xen_domctl launch_domctl;
915 int rc;
916 vcpu_guest_context_t st_ctxt, *ctxt = &st_ctxt;
917 char *image = NULL;
918 unsigned long image_size;
919 unsigned long nr_pages;
921 nr_pages = xc_get_max_pages(xc_handle, domid);
922 if (nr_pages < 0) {
923 PERROR("Could not find total pages for domain");
924 goto error_out;
925 }
927 image = xc_read_image(image_name, &image_size);
928 if (image == NULL) {
929 PERROR("Could not read guest firmware image %s", image_name);
930 goto error_out;
931 }
933 image_size = (image_size + PAGE_SIZE - 1) & PAGE_MASK;
935 if (mlock(&st_ctxt, sizeof(st_ctxt))) {
936 PERROR("Unable to mlock ctxt");
937 return 1;
938 }
940 memset(ctxt, 0, sizeof(*ctxt));
942 if (setup_guest(xc_handle, domid, (unsigned long)memsize, image,
943 image_size, ctxt) < 0) {
944 ERROR("Error constructing guest OS");
945 goto error_out;
946 }
948 free(image);
950 ctxt->regs.ip = 0x80000000ffffffb0UL;
952 memset(&launch_domctl, 0, sizeof(launch_domctl));
954 launch_domctl.domain = (domid_t)domid;
955 launch_domctl.u.vcpucontext.vcpu = 0;
956 set_xen_guest_handle(launch_domctl.u.vcpucontext.ctxt, ctxt);
958 launch_domctl.cmd = XEN_DOMCTL_setvcpucontext;
959 rc = do_domctl(xc_handle, &launch_domctl);
960 return rc;
962 error_out:
963 free(image);
964 return -1;
965 }
967 /*
968 * Local variables:
969 * mode: C
970 * c-set-style: "BSD"
971 * c-basic-offset: 4
972 * tab-width: 4
973 * indent-tabs-mode: nil
974 * End:
975 */