kvm: libkvm: avoid losing errno if post_kvm_run() calls libc
[qemu-kvm/amd-iommu.git] / target-ia64 / firmware.c
blobb8259e051055baba4461b02d894e64fdd0551fcf
1 /*
2 * firmware.c : Firmware build logic for ia64 platform.
4 * Ported from Xen 3.0 Source.
5 * Copyright (c) 2007, Intel Corporation.
6 * Zhang Xiantao <xiantao.zhang@intel.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place - Suite 330, Boston, MA 02111-1307 USA.
22 #include <string.h>
23 #include <stdlib.h>
24 #include <zlib.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
29 #include "cpu.h"
31 #include "firmware.h"
33 typedef struct {
34 unsigned long signature;
35 unsigned int type;
36 unsigned int length;
37 } HOB_GENERIC_HEADER;
40 * INFO HOB is the first data data in one HOB list
41 * it contains the control information of the HOB list
43 typedef struct {
44 HOB_GENERIC_HEADER header;
45 unsigned long length; // current length of hob
46 unsigned long cur_pos; // current poisiton of hob
47 unsigned long buf_size; // size of hob buffer
48 } HOB_INFO;
50 typedef struct{
51 unsigned long start;
52 unsigned long size;
53 } hob_mem_t;
55 typedef enum {
56 HOB_TYPE_INFO=0,
57 HOB_TYPE_TERMINAL,
58 HOB_TYPE_MEM,
59 HOB_TYPE_PAL_BUS_GET_FEATURES_DATA,
60 HOB_TYPE_PAL_CACHE_SUMMARY,
61 HOB_TYPE_PAL_MEM_ATTRIB,
62 HOB_TYPE_PAL_CACHE_INFO,
63 HOB_TYPE_PAL_CACHE_PROT_INFO,
64 HOB_TYPE_PAL_DEBUG_INFO,
65 HOB_TYPE_PAL_FIXED_ADDR,
66 HOB_TYPE_PAL_FREQ_BASE,
67 HOB_TYPE_PAL_FREQ_RATIOS,
68 HOB_TYPE_PAL_HALT_INFO,
69 HOB_TYPE_PAL_PERF_MON_INFO,
70 HOB_TYPE_PAL_PROC_GET_FEATURES,
71 HOB_TYPE_PAL_PTCE_INFO,
72 HOB_TYPE_PAL_REGISTER_INFO,
73 HOB_TYPE_PAL_RSE_INFO,
74 HOB_TYPE_PAL_TEST_INFO,
75 HOB_TYPE_PAL_VM_SUMMARY,
76 HOB_TYPE_PAL_VM_INFO,
77 HOB_TYPE_PAL_VM_PAGE_SIZE,
78 HOB_TYPE_NR_VCPU,
79 HOB_TYPE_NR_NVRAM,
80 HOB_TYPE_MAX
81 } hob_type_t;
83 static int hob_init(void *buffer ,unsigned long buf_size);
84 static int add_pal_hob(void* hob_buf);
85 static int add_mem_hob(void* hob_buf, unsigned long dom_mem_size);
86 static int add_vcpus_hob(void* hob_buf, unsigned long nr_vcpu);
87 static int build_hob(void* hob_buf, unsigned long hob_buf_size,
88 unsigned long dom_mem_size, unsigned long vcpus);
89 static int load_hob(void *hob_buf,
90 unsigned long dom_mem_size, void* hob_start);
92 int
93 kvm_ia64_build_hob(unsigned long memsize,
94 unsigned long vcpus, uint8_t* fw_start)
96 char *hob_buf;
98 hob_buf = malloc(GFW_HOB_SIZE);
99 if (hob_buf == NULL) {
100 Hob_Output("Hob: Could not allocate hob");
101 return -1;
104 if (build_hob(hob_buf, GFW_HOB_SIZE, memsize, vcpus) < 0) {
105 free(hob_buf);
106 Hob_Output("Could not build hob");
107 return -1;
109 if (load_hob(hob_buf, memsize, fw_start + HOB_OFFSET) < 0) {
110 free(hob_buf);
111 Hob_Output("Could not load hob");
112 return -1;
114 free(hob_buf);
115 return 0;
119 static int
120 hob_init(void *buffer, unsigned long buf_size)
122 HOB_INFO *phit;
123 HOB_GENERIC_HEADER *terminal;
125 if (sizeof(HOB_INFO) + sizeof(HOB_GENERIC_HEADER) > buf_size) {
126 // buffer too small
127 return -1;
130 phit = (HOB_INFO*)buffer;
131 phit->header.signature = HOB_SIGNATURE;
132 phit->header.type = HOB_TYPE_INFO;
133 phit->header.length = sizeof(HOB_INFO);
134 phit->length = sizeof(HOB_INFO) + sizeof(HOB_GENERIC_HEADER);
135 phit->cur_pos = 0;
136 phit->buf_size = buf_size;
138 terminal = (HOB_GENERIC_HEADER*)(buffer + sizeof(HOB_INFO));
139 terminal->signature = HOB_SIGNATURE;
140 terminal->type = HOB_TYPE_TERMINAL;
141 terminal->length = sizeof(HOB_GENERIC_HEADER);
143 return 0;
147 * Add a new HOB to the HOB List.
149 * hob_start - start address of hob buffer
150 * type - type of the hob to be added
151 * data - data of the hob to be added
152 * data_size - size of the data
154 static int
155 hob_add(void* hob_start, int type, void* data, int data_size)
157 HOB_INFO *phit;
158 HOB_GENERIC_HEADER *newhob, *tail;
160 phit = (HOB_INFO*)hob_start;
162 if (phit->length + data_size > phit->buf_size) {
163 // no space for new hob
164 return -1;
167 //append new HOB
168 newhob = (HOB_GENERIC_HEADER*)(hob_start + phit->length -
169 sizeof(HOB_GENERIC_HEADER));
170 newhob->signature = HOB_SIGNATURE;
171 newhob->type = type;
172 newhob->length = data_size + sizeof(HOB_GENERIC_HEADER);
173 memcpy((void*)newhob + sizeof(HOB_GENERIC_HEADER), data, data_size);
175 // append terminal HOB
176 tail = (HOB_GENERIC_HEADER*)(hob_start + phit->length + data_size);
177 tail->signature = HOB_SIGNATURE;
178 tail->type = HOB_TYPE_TERMINAL;
179 tail->length = sizeof(HOB_GENERIC_HEADER);
181 // adjust HOB list length
182 phit->length += sizeof(HOB_GENERIC_HEADER) + data_size;
184 return 0;
187 static int
188 get_hob_size(void* hob_buf)
190 HOB_INFO *phit = (HOB_INFO*)hob_buf;
192 if (phit->header.signature != HOB_SIGNATURE) {
193 Hob_Output("xc_get_hob_size:Incorrect signature");
194 return -1;
196 return phit->length;
199 static int
200 add_max_hob_entry(void* hob_buf)
202 long max_hob = 0;
203 return hob_add(hob_buf, HOB_TYPE_MAX, &max_hob, sizeof(long));
206 static int
207 build_hob(void* hob_buf, unsigned long hob_buf_size,
208 unsigned long dom_mem_size, unsigned long vcpus)
210 //Init HOB List
211 if (hob_init(hob_buf, hob_buf_size) < 0) {
212 Hob_Output("buffer too small");
213 goto err_out;
216 if (add_mem_hob(hob_buf,dom_mem_size) < 0) {
217 Hob_Output("Add memory hob failed, buffer too small");
218 goto err_out;
221 if (add_vcpus_hob(hob_buf, vcpus) < 0) {
222 Hob_Output("Add NR_VCPU hob failed, buffer too small");
223 goto err_out;
226 if (add_pal_hob( hob_buf ) < 0) {
227 Hob_Output("Add PAL hob failed, buffer too small");
228 goto err_out;
231 if (add_max_hob_entry(hob_buf) < 0) {
232 Hob_Output("Add max hob entry failed, buffer too small");
233 goto err_out;
235 return 0;
237 err_out:
238 return -1;
240 static int
241 load_hob(void *hob_buf,
242 unsigned long dom_mem_size, void* hob_start)
244 int hob_size;
246 hob_size = get_hob_size(hob_buf);
247 if (hob_size < 0) {
248 Hob_Output("Invalid hob data");
249 return -1;
252 if (hob_size > GFW_HOB_SIZE) {
253 Hob_Output("No enough memory for hob data");
254 return -1;
256 memcpy (hob_start, hob_buf, hob_size);
257 return 0;
260 static int
261 add_mem_hob(void* hob_buf, unsigned long dom_mem_size)
263 hob_mem_t memhob;
265 // less than 3G
266 memhob.start = 0;
267 memhob.size = MIN(dom_mem_size, 0xC0000000);
269 if (hob_add(hob_buf, HOB_TYPE_MEM, &memhob, sizeof(memhob)) < 0)
270 return -1;
272 if (dom_mem_size > 0xC0000000) {
273 // 4G ~ 4G+remain
274 memhob.start = 0x100000000; //4G
275 memhob.size = dom_mem_size - 0xC0000000;
276 if (hob_add(hob_buf, HOB_TYPE_MEM, &memhob, sizeof(memhob)) < 0)
277 return -1;
279 return 0;
282 static int
283 add_vcpus_hob(void* hob_buf, unsigned long vcpus)
285 return hob_add(hob_buf, HOB_TYPE_NR_VCPU, &vcpus, sizeof(vcpus));
288 static const unsigned char config_pal_bus_get_features_data[24] = {
289 0, 0, 0, 32, 0, 0, 240, 189, 0, 0, 0, 0, 0, 0,
290 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
293 static const unsigned char config_pal_cache_summary[16] = {
294 3, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0
297 static const unsigned char config_pal_mem_attrib[8] = {
298 241, 0, 0, 0, 0, 0, 0, 0
301 static const unsigned char config_pal_cache_info[152] = {
302 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
303 6, 4, 6, 7, 255, 1, 0, 1, 0, 64, 0, 0, 12, 12,
304 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 7, 0, 1,
305 0, 1, 0, 64, 0, 0, 12, 12, 49, 0, 0, 0, 0, 0, 0,
306 0, 0, 0, 6, 8, 7, 7, 255, 7, 0, 11, 0, 0, 16, 0,
307 12, 17, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7,
308 7, 7, 5, 9, 11, 0, 0, 4, 0, 12, 15, 49, 0, 254, 255,
309 255, 255, 255, 255, 255, 255, 2, 8, 7, 7, 7, 5, 9,
310 11, 0, 0, 4, 0, 12, 15, 49, 0, 0, 0, 0, 0, 0, 0, 0,
311 0, 3, 12, 7, 7, 7, 14, 1, 3, 0, 0, 192, 0, 12, 20, 49, 0
314 static const unsigned char config_pal_cache_prot_info[200] = {
315 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
316 45, 0, 16, 8, 0, 76, 12, 64, 0, 0, 0, 0, 0, 0, 0,
317 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
318 8, 0, 16, 4, 0, 76, 44, 68, 0, 0, 0, 0, 0, 0, 0, 0,
319 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32,
320 0, 16, 8, 0, 81, 44, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0,
321 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0,
322 112, 12, 0, 79, 124, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
323 0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255,
324 32, 0, 112, 12, 0, 79, 124, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0,
325 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 160,
326 12, 0, 84, 124, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
327 0, 0, 0
330 static const unsigned char config_pal_debug_info[16] = {
331 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0
334 static const unsigned char config_pal_fixed_addr[8] = {
335 0, 0, 0, 0, 0, 0, 0, 0
338 static const unsigned char config_pal_freq_base[8] = {
339 109, 219, 182, 13, 0, 0, 0, 0
342 static const unsigned char config_pal_freq_ratios[24] = {
343 11, 1, 0, 0, 77, 7, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 4,
344 0, 0, 0, 7, 0, 0, 0
347 static const unsigned char config_pal_halt_info[64] = {
348 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0,
349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
354 static const unsigned char config_pal_perf_mon_info[136] = {
355 12, 47, 18, 8, 0, 0, 0, 0, 241, 255, 0, 0, 255, 7, 0, 0,
356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
357 0, 0, 0, 0, 0, 0, 0, 0, 241, 255, 0, 0, 223, 0, 255, 255,
358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
359 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 0, 0, 0, 0, 0, 0,
360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
361 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 0, 0, 0, 0, 0, 0,
362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
363 0, 0, 0, 0, 0, 0, 0, 0
366 static const unsigned char config_pal_proc_get_features[104] = {
367 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368 0, 0, 0, 0, 64, 6, 64, 49, 0, 0, 0, 0, 64, 6, 0, 0,
369 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,
370 231, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0, 0,
371 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0,
372 63, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0,
373 0, 0, 0, 0, 0, 0, 0, 0
376 static const unsigned char config_pal_ptce_info[24] = {
377 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
378 0, 0, 0, 0, 0, 0, 0, 0
381 static const unsigned char config_pal_register_info[64] = {
382 255, 0, 47, 127, 17, 17, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0,
383 255, 208, 128, 238, 238, 0, 0, 248, 255, 255, 255, 255, 255, 0, 0, 7, 3,
384 251, 3, 0, 0, 0, 0, 255, 7, 3, 0, 0, 0, 0, 0, 248, 252, 4,
385 252, 255, 255, 255, 255, 2, 248, 252, 255, 255, 255, 255, 255
388 static const unsigned char config_pal_rse_info[16] = {
389 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
392 static const unsigned char config_pal_test_info[48] = {
393 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
394 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
395 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
398 static const unsigned char config_pal_vm_summary[16] = {
399 101, 18, 15, 2, 7, 7, 4, 2, 59, 18, 0, 0, 0, 0, 0, 0
402 static const unsigned char config_pal_vm_info[104] = {
403 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
404 32, 32, 0, 0, 0, 0, 0, 0, 112, 85, 21, 0, 0, 0, 0, 0, 0,
405 0, 0, 0, 0, 0, 0, 1, 32, 32, 0, 0, 0, 0, 0, 0, 112, 85,
406 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 128, 128, 0,
407 4, 0, 0, 0, 0, 112, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
408 0, 0, 0, 1, 128, 128, 0, 4, 0, 0, 0, 0, 112, 85, 0, 0, 0, 0, 0
411 static const unsigned char config_pal_vm_page_size[16] = {
412 0, 112, 85, 21, 0, 0, 0, 0, 0, 112, 85, 21, 0, 0, 0, 0
415 typedef struct{
416 hob_type_t type;
417 void* data;
418 unsigned long size;
419 } hob_batch_t;
421 static const hob_batch_t hob_batch[]={
422 { HOB_TYPE_PAL_BUS_GET_FEATURES_DATA,
423 &config_pal_bus_get_features_data,
424 sizeof(config_pal_bus_get_features_data)
426 { HOB_TYPE_PAL_CACHE_SUMMARY,
427 &config_pal_cache_summary,
428 sizeof(config_pal_cache_summary)
430 { HOB_TYPE_PAL_MEM_ATTRIB,
431 &config_pal_mem_attrib,
432 sizeof(config_pal_mem_attrib)
434 { HOB_TYPE_PAL_CACHE_INFO,
435 &config_pal_cache_info,
436 sizeof(config_pal_cache_info)
438 { HOB_TYPE_PAL_CACHE_PROT_INFO,
439 &config_pal_cache_prot_info,
440 sizeof(config_pal_cache_prot_info)
442 { HOB_TYPE_PAL_DEBUG_INFO,
443 &config_pal_debug_info,
444 sizeof(config_pal_debug_info)
446 { HOB_TYPE_PAL_FIXED_ADDR,
447 &config_pal_fixed_addr,
448 sizeof(config_pal_fixed_addr)
450 { HOB_TYPE_PAL_FREQ_BASE,
451 &config_pal_freq_base,
452 sizeof(config_pal_freq_base)
454 { HOB_TYPE_PAL_FREQ_RATIOS,
455 &config_pal_freq_ratios,
456 sizeof(config_pal_freq_ratios)
458 { HOB_TYPE_PAL_HALT_INFO,
459 &config_pal_halt_info,
460 sizeof(config_pal_halt_info)
462 { HOB_TYPE_PAL_PERF_MON_INFO,
463 &config_pal_perf_mon_info,
464 sizeof(config_pal_perf_mon_info)
466 { HOB_TYPE_PAL_PROC_GET_FEATURES,
467 &config_pal_proc_get_features,
468 sizeof(config_pal_proc_get_features)
470 { HOB_TYPE_PAL_PTCE_INFO,
471 &config_pal_ptce_info,
472 sizeof(config_pal_ptce_info)
474 { HOB_TYPE_PAL_REGISTER_INFO,
475 &config_pal_register_info,
476 sizeof(config_pal_register_info)
478 { HOB_TYPE_PAL_RSE_INFO,
479 &config_pal_rse_info,
480 sizeof(config_pal_rse_info)
482 { HOB_TYPE_PAL_TEST_INFO,
483 &config_pal_test_info,
484 sizeof(config_pal_test_info)
486 { HOB_TYPE_PAL_VM_SUMMARY,
487 &config_pal_vm_summary,
488 sizeof(config_pal_vm_summary)
490 { HOB_TYPE_PAL_VM_INFO,
491 &config_pal_vm_info,
492 sizeof(config_pal_vm_info)
494 { HOB_TYPE_PAL_VM_PAGE_SIZE,
495 &config_pal_vm_page_size,
496 sizeof(config_pal_vm_page_size)
500 static int
501 add_pal_hob(void* hob_buf)
503 int i;
504 for (i = 0; i < sizeof(hob_batch)/sizeof(hob_batch_t); i++) {
505 if (hob_add(hob_buf, hob_batch[i].type, hob_batch[i].data,
506 hob_batch[i].size) < 0)
507 return -1;
509 return 0;
511 char *read_image(const char *filename, unsigned long *size)
513 int kernel_fd = -1;
514 gzFile kernel_gfd = NULL;
515 char *image = NULL, *tmp;
516 unsigned int bytes;
518 if ( (filename == NULL) || (size == NULL) )
519 return NULL;
521 kernel_fd = open(filename, O_RDONLY);
522 if (kernel_fd < 0)
524 Hob_Output("Could not open kernel image\n");
525 goto out_1;
528 if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
530 Hob_Output("Could not allocate decompression state for state file\n");
531 goto out_1;
534 *size = 0;
536 #define CHUNK 1*1024*1024
537 while(1)
539 if ( (tmp = realloc(image, *size + CHUNK)) == NULL )
541 Hob_Output("Could not allocate memory for kernel image");
542 free(image);
543 image = NULL;
544 goto out;
546 image = tmp;
548 bytes = gzread(kernel_gfd, image + *size, CHUNK);
549 switch (bytes)
551 case -1:
552 Hob_Output("Error reading kernel image");
553 free(image);
554 image = NULL;
555 goto out;
556 case 0: /* EOF */
557 goto out;
558 default:
559 *size += bytes;
560 break;
563 #undef CHUNK
565 out:
566 if ( *size == 0 )
568 Hob_Output("Could not read kernel image");
569 free(image);
570 image = NULL;
572 else if ( image )
574 /* Shrink allocation to fit image. */
575 tmp = realloc(image, *size);
576 if ( tmp )
577 image = tmp;
580 if ( kernel_gfd != NULL )
581 gzclose(kernel_gfd);
582 else if ( kernel_fd >= 0 )
583 close(kernel_fd);
584 return image;
586 out_1:
587 return NULL;
591 * Local variables:
592 * mode: C
593 * c-set-style: "BSD"
594 * c-basic-offset: 4
595 * tab-width: 4
596 * indent-tabs-mode: nil
597 * End: