| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * QEMU Executable loader | 
					
						
							| 
									
										
										
										
											2007-09-16 21:08:06 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |  * Copyright (c) 2006 Fabrice Bellard | 
					
						
							| 
									
										
										
										
											2007-09-16 21:08:06 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
					
						
							|  |  |  |  * of this software and associated documentation files (the "Software"), to deal | 
					
						
							|  |  |  |  * in the Software without restriction, including without limitation the rights | 
					
						
							|  |  |  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
					
						
							|  |  |  |  * copies of the Software, and to permit persons to whom the Software is | 
					
						
							|  |  |  |  * furnished to do so, subject to the following conditions: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The above copyright notice and this permission notice shall be included in | 
					
						
							|  |  |  |  * all copies or substantial portions of the Software. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
					
						
							|  |  |  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | 
					
						
							|  |  |  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
					
						
							|  |  |  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
					
						
							|  |  |  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
					
						
							|  |  |  |  * THE SOFTWARE. | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Gunzip functionality in this file is derived from u-boot: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * (C) Copyright 2008 Semihalf | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * (C) Copyright 2000-2005 | 
					
						
							|  |  |  |  * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License as | 
					
						
							|  |  |  |  * published by the Free Software Foundation; either version 2 of | 
					
						
							|  |  |  |  * the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2009-01-04 22:05:52 +00:00
										 |  |  |  * You should have received a copy of the GNU General Public License along | 
					
						
							| 
									
										
										
										
											2009-07-16 20:47:01 +00:00
										 |  |  |  * with this program; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-04 15:40:22 +01:00
										 |  |  | #include "hw/hw.h"
 | 
					
						
							| 
									
										
										
										
											2012-10-24 11:12:21 +02:00
										 |  |  | #include "disas/disas.h"
 | 
					
						
							| 
									
										
										
										
											2012-12-17 18:19:49 +01:00
										 |  |  | #include "monitor/monitor.h"
 | 
					
						
							| 
									
										
										
										
											2012-12-17 18:20:04 +01:00
										 |  |  | #include "sysemu/sysemu.h"
 | 
					
						
							| 
									
										
										
										
											2013-03-18 17:36:02 +01:00
										 |  |  | #include "uboot_image.h"
 | 
					
						
							| 
									
										
										
										
											2013-02-04 15:40:22 +01:00
										 |  |  | #include "hw/loader.h"
 | 
					
						
							| 
									
										
										
										
											2013-02-05 17:06:20 +01:00
										 |  |  | #include "hw/nvram/fw_cfg.h"
 | 
					
						
							| 
									
										
										
										
											2012-12-17 18:19:49 +01:00
										 |  |  | #include "exec/memory.h"
 | 
					
						
							|  |  |  | #include "exec/address-spaces.h"
 | 
					
						
							| 
									
										
										
										
											2015-12-01 20:58:08 -02:00
										 |  |  | #include "hw/boards.h"
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  | #include <zlib.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-11 18:17:24 +00:00
										 |  |  | static int roms_loaded; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | /* return the size or -1 if error */ | 
					
						
							|  |  |  | int get_image_size(const char *filename) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, size; | 
					
						
							|  |  |  |     fd = open(filename, O_RDONLY | O_BINARY); | 
					
						
							|  |  |  |     if (fd < 0) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     size = lseek(fd, 0, SEEK_END); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* return the size or -1 if error */ | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  | /* deprecated, because caller does not specify buffer size! */ | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | int load_image(const char *filename, uint8_t *addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, size; | 
					
						
							|  |  |  |     fd = open(filename, O_RDONLY | O_BINARY); | 
					
						
							|  |  |  |     if (fd < 0) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     size = lseek(fd, 0, SEEK_END); | 
					
						
							| 
									
										
										
										
											2014-11-15 18:06:43 +08:00
										 |  |  |     if (size == -1) { | 
					
						
							|  |  |  |         fprintf(stderr, "file %-20s: get size error: %s\n", | 
					
						
							|  |  |  |                 filename, strerror(errno)); | 
					
						
							|  |  |  |         close(fd); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |     lseek(fd, 0, SEEK_SET); | 
					
						
							|  |  |  |     if (read(fd, addr, size) != size) { | 
					
						
							|  |  |  |         close(fd); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-21 13:02:03 +10:00
										 |  |  | /* return the size or -1 if error */ | 
					
						
							|  |  |  | ssize_t load_image_size(const char *filename, void *addr, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd; | 
					
						
							|  |  |  |     ssize_t actsize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open(filename, O_RDONLY | O_BINARY); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     actsize = read(fd, addr, size); | 
					
						
							|  |  |  |     if (actsize < 0) { | 
					
						
							|  |  |  |         close(fd); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return actsize; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  | /* read()-like version */ | 
					
						
							| 
									
										
										
										
											2011-11-16 19:41:56 +01:00
										 |  |  | ssize_t read_targphys(const char *name, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                       int fd, hwaddr dst_addr, size_t nbytes) | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     uint8_t *buf; | 
					
						
							| 
									
										
										
										
											2011-11-16 19:41:56 +01:00
										 |  |  |     ssize_t did; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     buf = g_malloc(nbytes); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     did = read(fd, buf, nbytes); | 
					
						
							|  |  |  |     if (did > 0) | 
					
						
							|  |  |  |         rom_add_blob_fixed("read", buf, did, dst_addr); | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     g_free(buf); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     return did; | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* return the size or -1 if error */ | 
					
						
							|  |  |  | int load_image_targphys(const char *filename, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                         hwaddr addr, uint64_t max_sz) | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     int size; | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     size = get_image_size(filename); | 
					
						
							| 
									
										
										
										
											2012-01-11 19:46:20 +00:00
										 |  |  |     if (size > max_sz) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (size > 0) { | 
					
						
							| 
									
										
										
										
											2010-12-08 13:35:07 +02:00
										 |  |  |         rom_add_file_fixed(filename, addr, -1); | 
					
						
							| 
									
										
										
										
											2012-01-11 19:46:20 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     return size; | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size, | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  |                       const char *source) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const char *nulp; | 
					
						
							| 
									
										
										
										
											2009-10-07 13:37:06 +02:00
										 |  |  |     char *ptr; | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (buf_size <= 0) return; | 
					
						
							|  |  |  |     nulp = memchr(source, 0, buf_size); | 
					
						
							|  |  |  |     if (nulp) { | 
					
						
							| 
									
										
										
										
											2009-10-07 13:37:06 +02:00
										 |  |  |         rom_add_blob_fixed(name, source, (nulp - source) + 1, dest); | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2009-10-07 13:37:06 +02:00
										 |  |  |         rom_add_blob_fixed(name, source, buf_size, dest); | 
					
						
							|  |  |  |         ptr = rom_ptr(dest + buf_size - 1); | 
					
						
							|  |  |  |         *ptr = 0; | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | /* A.OUT loader */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct exec | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   uint32_t a_info;   /* Use macros N_MAGIC, etc for access */ | 
					
						
							|  |  |  |   uint32_t a_text;   /* length of text, in bytes */ | 
					
						
							|  |  |  |   uint32_t a_data;   /* length of data, in bytes */ | 
					
						
							|  |  |  |   uint32_t a_bss;    /* length of uninitialized data area, in bytes */ | 
					
						
							|  |  |  |   uint32_t a_syms;   /* length of symbol table data in file, in bytes */ | 
					
						
							|  |  |  |   uint32_t a_entry;  /* start address */ | 
					
						
							|  |  |  |   uint32_t a_trsize; /* length of relocation info for text, in bytes */ | 
					
						
							|  |  |  |   uint32_t a_drsize; /* length of relocation info for data, in bytes */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void bswap_ahdr(struct exec *e) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     bswap32s(&e->a_info); | 
					
						
							|  |  |  |     bswap32s(&e->a_text); | 
					
						
							|  |  |  |     bswap32s(&e->a_data); | 
					
						
							|  |  |  |     bswap32s(&e->a_bss); | 
					
						
							|  |  |  |     bswap32s(&e->a_syms); | 
					
						
							|  |  |  |     bswap32s(&e->a_entry); | 
					
						
							|  |  |  |     bswap32s(&e->a_trsize); | 
					
						
							|  |  |  |     bswap32s(&e->a_drsize); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define N_MAGIC(exec) ((exec).a_info & 0xffff)
 | 
					
						
							|  |  |  | #define OMAGIC 0407
 | 
					
						
							|  |  |  | #define NMAGIC 0410
 | 
					
						
							|  |  |  | #define ZMAGIC 0413
 | 
					
						
							|  |  |  | #define QMAGIC 0314
 | 
					
						
							|  |  |  | #define _N_HDROFF(x) (1024 - sizeof (struct exec))
 | 
					
						
							|  |  |  | #define N_TXTOFF(x)							\
 | 
					
						
							|  |  |  |     (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) :	\ | 
					
						
							|  |  |  |      (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) | 
					
						
							| 
									
										
										
										
											2009-09-20 14:58:02 +00:00
										 |  |  | #define N_TXTADDR(x, target_page_size) (N_MAGIC(x) == QMAGIC ? target_page_size : 0)
 | 
					
						
							|  |  |  | #define _N_SEGMENT_ROUND(x, target_page_size) (((x) + target_page_size - 1) & ~(target_page_size - 1))
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 14:58:02 +00:00
										 |  |  | #define _N_TXTENDADDR(x, target_page_size) (N_TXTADDR(x, target_page_size)+(x).a_text)
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 14:58:02 +00:00
										 |  |  | #define N_DATADDR(x, target_page_size) \
 | 
					
						
							|  |  |  |     (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x, target_page_size)) \ | 
					
						
							|  |  |  |      : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), target_page_size))) | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | int load_aout(const char *filename, hwaddr addr, int max_sz, | 
					
						
							|  |  |  |               int bswap_needed, hwaddr target_page_size) | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-16 19:41:56 +01:00
										 |  |  |     int fd; | 
					
						
							|  |  |  |     ssize_t size, ret; | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |     struct exec e; | 
					
						
							|  |  |  |     uint32_t magic; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open(filename, O_RDONLY | O_BINARY); | 
					
						
							|  |  |  |     if (fd < 0) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     size = read(fd, &e, sizeof(e)); | 
					
						
							|  |  |  |     if (size < 0) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 14:58:02 +00:00
										 |  |  |     if (bswap_needed) { | 
					
						
							|  |  |  |         bswap_ahdr(&e); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     magic = N_MAGIC(e); | 
					
						
							|  |  |  |     switch (magic) { | 
					
						
							|  |  |  |     case ZMAGIC: | 
					
						
							|  |  |  |     case QMAGIC: | 
					
						
							|  |  |  |     case OMAGIC: | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  |         if (e.a_text + e.a_data > max_sz) | 
					
						
							|  |  |  |             goto fail; | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 	lseek(fd, N_TXTOFF(e), SEEK_SET); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | 	size = read_targphys(filename, fd, addr, e.a_text + e.a_data); | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 	if (size < 0) | 
					
						
							|  |  |  | 	    goto fail; | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  |     case NMAGIC: | 
					
						
							| 
									
										
										
										
											2009-09-20 14:58:02 +00:00
										 |  |  |         if (N_DATADDR(e, target_page_size) + e.a_data > max_sz) | 
					
						
							| 
									
										
										
										
											2008-05-12 17:22:13 +00:00
										 |  |  |             goto fail; | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 	lseek(fd, N_TXTOFF(e), SEEK_SET); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | 	size = read_targphys(filename, fd, addr, e.a_text); | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 	if (size < 0) | 
					
						
							|  |  |  | 	    goto fail; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |         ret = read_targphys(filename, fd, addr + N_DATADDR(e, target_page_size), | 
					
						
							| 
									
										
										
										
											2009-09-20 14:58:02 +00:00
										 |  |  |                             e.a_data); | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 	if (ret < 0) | 
					
						
							|  |  |  | 	    goto fail; | 
					
						
							|  |  |  | 	size += ret; | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  | 	goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return size; | 
					
						
							|  |  |  |  fail: | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ELF loader */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-14 09:37:08 +01:00
										 |  |  | static void *load_at(int fd, off_t offset, size_t size) | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     void *ptr; | 
					
						
							|  |  |  |     if (lseek(fd, offset, SEEK_SET) < 0) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     ptr = g_malloc(size); | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |     if (read(fd, ptr, size) != size) { | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |         g_free(ptr); | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-18 13:10:12 +04:00
										 |  |  | #ifdef ELF_CLASS
 | 
					
						
							|  |  |  | #undef ELF_CLASS
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define ELF_CLASS   ELFCLASS32
 | 
					
						
							|  |  |  | #include "elf.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SZ		32
 | 
					
						
							|  |  |  | #define elf_word        uint32_t
 | 
					
						
							| 
									
										
										
										
											2007-10-17 23:07:31 +00:00
										 |  |  | #define elf_sword        int32_t
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | #define bswapSZs	bswap32s
 | 
					
						
							| 
									
										
										
										
											2013-02-04 15:40:22 +01:00
										 |  |  | #include "hw/elf_ops.h"
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #undef elfhdr
 | 
					
						
							|  |  |  | #undef elf_phdr
 | 
					
						
							|  |  |  | #undef elf_shdr
 | 
					
						
							|  |  |  | #undef elf_sym
 | 
					
						
							| 
									
										
										
										
											2015-03-09 11:12:52 +01:00
										 |  |  | #undef elf_rela
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | #undef elf_note
 | 
					
						
							|  |  |  | #undef elf_word
 | 
					
						
							| 
									
										
										
										
											2007-10-17 23:07:31 +00:00
										 |  |  | #undef elf_sword
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | #undef bswapSZs
 | 
					
						
							|  |  |  | #undef SZ
 | 
					
						
							|  |  |  | #define elfhdr		elf64_hdr
 | 
					
						
							|  |  |  | #define elf_phdr	elf64_phdr
 | 
					
						
							|  |  |  | #define elf_note	elf64_note
 | 
					
						
							|  |  |  | #define elf_shdr	elf64_shdr
 | 
					
						
							|  |  |  | #define elf_sym		elf64_sym
 | 
					
						
							| 
									
										
										
										
											2015-03-09 11:12:52 +01:00
										 |  |  | #define elf_rela        elf64_rela
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | #define elf_word        uint64_t
 | 
					
						
							| 
									
										
										
										
											2007-10-17 23:07:31 +00:00
										 |  |  | #define elf_sword        int64_t
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | #define bswapSZs	bswap64s
 | 
					
						
							|  |  |  | #define SZ		64
 | 
					
						
							| 
									
										
										
										
											2013-02-04 15:40:22 +01:00
										 |  |  | #include "hw/elf_ops.h"
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-04 15:04:18 +11:00
										 |  |  | const char *load_elf_strerror(int error) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch (error) { | 
					
						
							|  |  |  |     case 0: | 
					
						
							|  |  |  |         return "No error"; | 
					
						
							|  |  |  |     case ELF_LOAD_FAILED: | 
					
						
							|  |  |  |         return "Failed to load ELF"; | 
					
						
							|  |  |  |     case ELF_LOAD_NOT_ELF: | 
					
						
							|  |  |  |         return "The image is not ELF"; | 
					
						
							|  |  |  |     case ELF_LOAD_WRONG_ARCH: | 
					
						
							|  |  |  |         return "The image is from incompatible architecture"; | 
					
						
							|  |  |  |     case ELF_LOAD_WRONG_ENDIAN: | 
					
						
							|  |  |  |         return "The image has incorrect endianness"; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         return "Unknown error"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | /* return < 0 if error, otherwise the number of bytes loaded in memory */ | 
					
						
							| 
									
										
										
										
											2010-03-14 21:20:59 +01:00
										 |  |  | int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), | 
					
						
							|  |  |  |              void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, | 
					
						
							|  |  |  |              uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb) | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-04 15:04:18 +11:00
										 |  |  |     int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED; | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |     uint8_t e_ident[EI_NIDENT]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-05-07 18:06:27 +00:00
										 |  |  |     fd = open(filename, O_RDONLY | O_BINARY); | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         perror(filename); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident)) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							|  |  |  |     if (e_ident[0] != ELFMAG0 || | 
					
						
							|  |  |  |         e_ident[1] != ELFMAG1 || | 
					
						
							|  |  |  |         e_ident[2] != ELFMAG2 || | 
					
						
							| 
									
										
										
										
											2014-02-04 15:04:18 +11:00
										 |  |  |         e_ident[3] != ELFMAG3) { | 
					
						
							|  |  |  |         ret = ELF_LOAD_NOT_ELF; | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |         goto fail; | 
					
						
							| 
									
										
										
										
											2014-02-04 15:04:18 +11:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-07-27 16:13:06 +02:00
										 |  |  | #ifdef HOST_WORDS_BIGENDIAN
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |     data_order = ELFDATA2MSB; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     data_order = ELFDATA2LSB; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     must_swab = data_order != e_ident[EI_DATA]; | 
					
						
							| 
									
										
										
										
											2009-09-20 14:58:02 +00:00
										 |  |  |     if (big_endian) { | 
					
						
							|  |  |  |         target_data_order = ELFDATA2MSB; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         target_data_order = ELFDATA2LSB; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2006-12-23 14:18:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-12 19:48:57 +00:00
										 |  |  |     if (target_data_order != e_ident[EI_DATA]) { | 
					
						
							| 
									
										
										
										
											2014-02-04 15:04:18 +11:00
										 |  |  |         ret = ELF_LOAD_WRONG_ENDIAN; | 
					
						
							| 
									
										
										
										
											2011-01-12 19:48:57 +00:00
										 |  |  |         goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2006-12-23 14:18:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |     lseek(fd, 0, SEEK_SET); | 
					
						
							|  |  |  |     if (e_ident[EI_CLASS] == ELFCLASS64) { | 
					
						
							| 
									
										
										
										
											2010-03-14 21:20:59 +01:00
										 |  |  |         ret = load_elf64(filename, fd, translate_fn, translate_opaque, must_swab, | 
					
						
							|  |  |  |                          pentry, lowaddr, highaddr, elf_machine, clear_lsb); | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2010-03-14 21:20:59 +01:00
										 |  |  |         ret = load_elf32(filename, fd, translate_fn, translate_opaque, must_swab, | 
					
						
							|  |  |  |                          pentry, lowaddr, highaddr, elf_machine, clear_lsb); | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  fail: | 
					
						
							|  |  |  |     close(fd); | 
					
						
							| 
									
										
										
										
											2014-02-04 15:04:18 +11:00
										 |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2006-04-23 17:12:42 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:12:16 -05:00
										 |  |  | static void bswap_uboot_header(uboot_image_header_t *hdr) | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-07-27 16:13:06 +02:00
										 |  |  | #ifndef HOST_WORDS_BIGENDIAN
 | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  |     bswap32s(&hdr->ih_magic); | 
					
						
							|  |  |  |     bswap32s(&hdr->ih_hcrc); | 
					
						
							|  |  |  |     bswap32s(&hdr->ih_time); | 
					
						
							|  |  |  |     bswap32s(&hdr->ih_size); | 
					
						
							|  |  |  |     bswap32s(&hdr->ih_load); | 
					
						
							|  |  |  |     bswap32s(&hdr->ih_ep); | 
					
						
							|  |  |  |     bswap32s(&hdr->ih_dcrc); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define ZALLOC_ALIGNMENT	16
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void *zalloc(void *x, unsigned items, unsigned size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     void *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     size *= items; | 
					
						
							|  |  |  |     size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     p = g_malloc(size); | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return (p); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-09 23:36:03 +02:00
										 |  |  | static void zfree(void *x, void *addr) | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     g_free(addr); | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define HEAD_CRC	2
 | 
					
						
							|  |  |  | #define EXTRA_FIELD	4
 | 
					
						
							|  |  |  | #define ORIG_NAME	8
 | 
					
						
							|  |  |  | #define COMMENT		0x10
 | 
					
						
							|  |  |  | #define RESERVED	0xe0
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define DEFLATED	8
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-20 20:58:27 +02:00
										 |  |  | /* This is the usual maximum in uboot, so if a uImage overflows this, it would
 | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  |  * overflow on real hardware too. */ | 
					
						
							| 
									
										
										
										
											2012-06-20 20:58:27 +02:00
										 |  |  | #define UBOOT_MAX_GUNZIP_BYTES (64 << 20)
 | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, | 
					
						
							|  |  |  |                       size_t srclen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     z_stream s; | 
					
						
							|  |  |  |     ssize_t dstbytes; | 
					
						
							|  |  |  |     int r, i, flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* skip header */ | 
					
						
							|  |  |  |     i = 10; | 
					
						
							|  |  |  |     flags = src[3]; | 
					
						
							|  |  |  |     if (src[2] != DEFLATED || (flags & RESERVED) != 0) { | 
					
						
							|  |  |  |         puts ("Error: Bad gzipped data\n"); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((flags & EXTRA_FIELD) != 0) | 
					
						
							|  |  |  |         i = 12 + src[10] + (src[11] << 8); | 
					
						
							|  |  |  |     if ((flags & ORIG_NAME) != 0) | 
					
						
							|  |  |  |         while (src[i++] != 0) | 
					
						
							|  |  |  |             ; | 
					
						
							|  |  |  |     if ((flags & COMMENT) != 0) | 
					
						
							|  |  |  |         while (src[i++] != 0) | 
					
						
							|  |  |  |             ; | 
					
						
							|  |  |  |     if ((flags & HEAD_CRC) != 0) | 
					
						
							|  |  |  |         i += 2; | 
					
						
							|  |  |  |     if (i >= srclen) { | 
					
						
							|  |  |  |         puts ("Error: gunzip out of data in header\n"); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s.zalloc = zalloc; | 
					
						
							| 
									
										
										
										
											2009-06-09 23:36:03 +02:00
										 |  |  |     s.zfree = zfree; | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     r = inflateInit2(&s, -MAX_WBITS); | 
					
						
							|  |  |  |     if (r != Z_OK) { | 
					
						
							|  |  |  |         printf ("Error: inflateInit2() returned %d\n", r); | 
					
						
							|  |  |  |         return (-1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     s.next_in = src + i; | 
					
						
							|  |  |  |     s.avail_in = srclen - i; | 
					
						
							|  |  |  |     s.next_out = dst; | 
					
						
							|  |  |  |     s.avail_out = dstlen; | 
					
						
							|  |  |  |     r = inflate(&s, Z_FINISH); | 
					
						
							|  |  |  |     if (r != Z_OK && r != Z_STREAM_END) { | 
					
						
							|  |  |  |         printf ("Error: inflate() returned %d\n", r); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     dstbytes = s.next_out - (unsigned char *) dst; | 
					
						
							|  |  |  |     inflateEnd(&s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return dstbytes; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  | /* Load a U-Boot image.  */ | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  | static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, | 
					
						
							| 
									
										
										
										
											2014-10-19 07:42:22 +04:00
										 |  |  |                             int *is_linux, uint8_t image_type, | 
					
						
							|  |  |  |                             uint64_t (*translate_fn)(void *, uint64_t), | 
					
						
							|  |  |  |                             void *translate_opaque) | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int fd; | 
					
						
							|  |  |  |     int size; | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  |     hwaddr address; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:12:16 -05:00
										 |  |  |     uboot_image_header_t h; | 
					
						
							|  |  |  |     uboot_image_header_t *hdr = &h; | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  |     uint8_t *data = NULL; | 
					
						
							| 
									
										
										
										
											2008-11-20 22:02:56 +00:00
										 |  |  |     int ret = -1; | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  |     int do_uncompress = 0; | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     fd = open(filename, O_RDONLY | O_BINARY); | 
					
						
							|  |  |  |     if (fd < 0) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:12:16 -05:00
										 |  |  |     size = read(fd, hdr, sizeof(uboot_image_header_t)); | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  |     if (size < 0) | 
					
						
							| 
									
										
										
										
											2008-11-20 22:02:56 +00:00
										 |  |  |         goto out; | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     bswap_uboot_header(hdr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (hdr->ih_magic != IH_MAGIC) | 
					
						
							| 
									
										
										
										
											2008-11-20 22:02:56 +00:00
										 |  |  |         goto out; | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  |     if (hdr->ih_type != image_type) { | 
					
						
							|  |  |  |         fprintf(stderr, "Wrong image type %d, expected %d\n", hdr->ih_type, | 
					
						
							|  |  |  |                 image_type); | 
					
						
							| 
									
										
										
										
											2008-11-20 22:02:56 +00:00
										 |  |  |         goto out; | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  |     /* TODO: Implement other image types.  */ | 
					
						
							|  |  |  |     switch (hdr->ih_type) { | 
					
						
							|  |  |  |     case IH_TYPE_KERNEL: | 
					
						
							|  |  |  |         address = hdr->ih_load; | 
					
						
							| 
									
										
										
										
											2014-10-19 07:42:22 +04:00
										 |  |  |         if (translate_fn) { | 
					
						
							|  |  |  |             address = translate_fn(translate_opaque, address); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  |         if (loadaddr) { | 
					
						
							|  |  |  |             *loadaddr = hdr->ih_load; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (hdr->ih_comp) { | 
					
						
							|  |  |  |         case IH_COMP_NONE: | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case IH_COMP_GZIP: | 
					
						
							|  |  |  |             do_uncompress = 1; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             fprintf(stderr, | 
					
						
							|  |  |  |                     "Unable to load u-boot images with compression type %d\n", | 
					
						
							|  |  |  |                     hdr->ih_comp); | 
					
						
							|  |  |  |             goto out; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (ep) { | 
					
						
							|  |  |  |             *ep = hdr->ih_ep; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* TODO: Check CPU type.  */ | 
					
						
							|  |  |  |         if (is_linux) { | 
					
						
							|  |  |  |             if (hdr->ih_os == IH_OS_LINUX) { | 
					
						
							|  |  |  |                 *is_linux = 1; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 *is_linux = 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case IH_TYPE_RAMDISK: | 
					
						
							|  |  |  |         address = *loadaddr; | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  |         fprintf(stderr, "Unsupported u-boot image type %d\n", hdr->ih_type); | 
					
						
							| 
									
										
										
										
											2008-11-20 22:02:56 +00:00
										 |  |  |         goto out; | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     data = g_malloc(hdr->ih_size); | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (read(fd, data, hdr->ih_size) != hdr->ih_size) { | 
					
						
							|  |  |  |         fprintf(stderr, "Error reading file\n"); | 
					
						
							| 
									
										
										
										
											2008-11-20 22:02:56 +00:00
										 |  |  |         goto out; | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  |     if (do_uncompress) { | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  |         uint8_t *compressed_data; | 
					
						
							|  |  |  |         size_t max_bytes; | 
					
						
							|  |  |  |         ssize_t bytes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         compressed_data = data; | 
					
						
							|  |  |  |         max_bytes = UBOOT_MAX_GUNZIP_BYTES; | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |         data = g_malloc(max_bytes); | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size); | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |         g_free(compressed_data); | 
					
						
							| 
									
										
										
										
											2008-11-20 22:04:01 +00:00
										 |  |  |         if (bytes < 0) { | 
					
						
							|  |  |  |             fprintf(stderr, "Unable to decompress gzipped image!\n"); | 
					
						
							|  |  |  |             goto out; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         hdr->ih_size = bytes; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  |     rom_add_blob_fixed(filename, data, hdr->ih_size, address); | 
					
						
							| 
									
										
										
										
											2008-11-20 22:11:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-20 22:02:56 +00:00
										 |  |  |     ret = hdr->ih_size; | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-20 22:02:56 +00:00
										 |  |  | out: | 
					
						
							| 
									
										
										
										
											2015-08-26 12:17:18 +01:00
										 |  |  |     g_free(data); | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  |     close(fd); | 
					
						
							| 
									
										
										
										
											2008-11-20 22:02:56 +00:00
										 |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2007-03-06 23:52:01 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  | int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr, | 
					
						
							| 
									
										
										
										
											2014-10-19 07:42:22 +04:00
										 |  |  |                 int *is_linux, | 
					
						
							|  |  |  |                 uint64_t (*translate_fn)(void *, uint64_t), | 
					
						
							|  |  |  |                 void *translate_opaque) | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-10-19 07:42:22 +04:00
										 |  |  |     return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL, | 
					
						
							|  |  |  |                             translate_fn, translate_opaque); | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Load a ramdisk.  */ | 
					
						
							|  |  |  | int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-10-19 07:42:22 +04:00
										 |  |  |     return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK, | 
					
						
							|  |  |  |                             NULL, NULL); | 
					
						
							| 
									
										
										
										
											2013-07-08 15:40:01 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-22 13:11:43 +01:00
										 |  |  | /* Load a gzip-compressed kernel to a dynamically allocated buffer. */ | 
					
						
							|  |  |  | int load_image_gzipped_buffer(const char *filename, uint64_t max_sz, | 
					
						
							|  |  |  |                               uint8_t **buffer) | 
					
						
							| 
									
										
										
										
											2014-08-19 18:56:28 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     uint8_t *compressed_data = NULL; | 
					
						
							|  |  |  |     uint8_t *data = NULL; | 
					
						
							|  |  |  |     gsize len; | 
					
						
							|  |  |  |     ssize_t bytes; | 
					
						
							|  |  |  |     int ret = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!g_file_get_contents(filename, (char **) &compressed_data, &len, | 
					
						
							|  |  |  |                              NULL)) { | 
					
						
							|  |  |  |         goto out; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Is it a gzip-compressed file? */ | 
					
						
							|  |  |  |     if (len < 2 || | 
					
						
							|  |  |  |         compressed_data[0] != 0x1f || | 
					
						
							|  |  |  |         compressed_data[1] != 0x8b) { | 
					
						
							|  |  |  |         goto out; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (max_sz > LOAD_IMAGE_MAX_GUNZIP_BYTES) { | 
					
						
							|  |  |  |         max_sz = LOAD_IMAGE_MAX_GUNZIP_BYTES; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data = g_malloc(max_sz); | 
					
						
							|  |  |  |     bytes = gunzip(data, max_sz, compressed_data, len); | 
					
						
							|  |  |  |     if (bytes < 0) { | 
					
						
							|  |  |  |         fprintf(stderr, "%s: unable to decompress gzipped kernel file\n", | 
					
						
							|  |  |  |                 filename); | 
					
						
							|  |  |  |         goto out; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-22 13:11:43 +01:00
										 |  |  |     /* trim to actual size and return to caller */ | 
					
						
							|  |  |  |     *buffer = g_realloc(data, bytes); | 
					
						
							| 
									
										
										
										
											2014-08-19 18:56:28 +01:00
										 |  |  |     ret = bytes; | 
					
						
							| 
									
										
										
										
											2014-12-22 13:11:43 +01:00
										 |  |  |     /* ownership has been transferred to caller */ | 
					
						
							|  |  |  |     data = NULL; | 
					
						
							| 
									
										
										
										
											2014-08-19 18:56:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |  out: | 
					
						
							|  |  |  |     g_free(compressed_data); | 
					
						
							|  |  |  |     g_free(data); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-22 13:11:43 +01:00
										 |  |  | /* Load a gzip-compressed kernel. */ | 
					
						
							|  |  |  | int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int bytes; | 
					
						
							|  |  |  |     uint8_t *data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bytes = load_image_gzipped_buffer(filename, max_sz, &data); | 
					
						
							|  |  |  |     if (bytes != -1) { | 
					
						
							|  |  |  |         rom_add_blob_fixed(filename, data, bytes, addr); | 
					
						
							|  |  |  |         g_free(data); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return bytes; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Functions for reboot-persistent memory regions. | 
					
						
							|  |  |  |  *  - used for vga bios and option roms. | 
					
						
							|  |  |  |  *  - also linux kernel (-kernel / -initrd). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct Rom Rom; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct Rom { | 
					
						
							|  |  |  |     char *name; | 
					
						
							|  |  |  |     char *path; | 
					
						
							| 
									
										
										
										
											2013-02-19 04:41:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* datasize is the amount of memory allocated in "data". If datasize is less
 | 
					
						
							|  |  |  |      * than romsize, it means that the area from datasize to romsize is filled | 
					
						
							|  |  |  |      * with zeros. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     size_t romsize; | 
					
						
							| 
									
										
										
										
											2013-02-19 04:41:11 +00:00
										 |  |  |     size_t datasize; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     uint8_t *data; | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  |     MemoryRegion *mr; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     int isrom; | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:11 +01:00
										 |  |  |     char *fw_dir; | 
					
						
							|  |  |  |     char *fw_file; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |     hwaddr addr; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     QTAILQ_ENTRY(Rom) next; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:40 +01:00
										 |  |  | static FWCfgState *fw_cfg; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void rom_insert(Rom *rom) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Rom *item; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-11 18:17:24 +00:00
										 |  |  |     if (roms_loaded) { | 
					
						
							|  |  |  |         hw_error ("ROM images must be loaded at startup\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     /* list is ordered by load address */ | 
					
						
							|  |  |  |     QTAILQ_FOREACH(item, &roms, next) { | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:12 +01:00
										 |  |  |         if (rom->addr >= item->addr) | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |             continue; | 
					
						
							|  |  |  |         QTAILQ_INSERT_BEFORE(item, rom, next); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     QTAILQ_INSERT_TAIL(&roms, rom, next); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-17 07:51:50 +02:00
										 |  |  | static void fw_cfg_resized(const char *id, uint64_t length, void *host) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (fw_cfg) { | 
					
						
							|  |  |  |         fw_cfg_modify_file(fw_cfg, id + strlen("/rom@"), host, length); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  | static void *rom_set_mr(Rom *rom, Object *owner, const char *name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     void *data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rom->mr = g_malloc(sizeof(*rom->mr)); | 
					
						
							| 
									
										
										
										
											2014-11-17 07:51:50 +02:00
										 |  |  |     memory_region_init_resizeable_ram(rom->mr, owner, name, | 
					
						
							|  |  |  |                                       rom->datasize, rom->romsize, | 
					
						
							|  |  |  |                                       fw_cfg_resized, | 
					
						
							| 
									
										
										
										
											2015-09-11 16:51:44 +02:00
										 |  |  |                                       &error_fatal); | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  |     memory_region_set_readonly(rom->mr, true); | 
					
						
							|  |  |  |     vmstate_register_ram_global(rom->mr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data = memory_region_get_ram_ptr(rom->mr); | 
					
						
							|  |  |  |     memcpy(data, rom->data, rom->datasize); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return data; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  | int rom_add_file(const char *file, const char *fw_dir, | 
					
						
							| 
									
										
										
										
											2014-03-06 14:57:09 +02:00
										 |  |  |                  hwaddr addr, int32_t bootindex, | 
					
						
							|  |  |  |                  bool option_rom) | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-12-01 20:58:08 -02:00
										 |  |  |     MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     Rom *rom; | 
					
						
							|  |  |  |     int rc, fd = -1; | 
					
						
							| 
									
										
										
										
											2010-12-08 13:35:07 +02:00
										 |  |  |     char devpath[100]; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     rom = g_malloc0(sizeof(*rom)); | 
					
						
							|  |  |  |     rom->name = g_strdup(file); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     rom->path = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom->name); | 
					
						
							|  |  |  |     if (rom->path == NULL) { | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |         rom->path = g_strdup(file); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-10 19:02:40 +04:00
										 |  |  |     fd = open(rom->path, O_RDONLY | O_BINARY); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     if (fd == -1) { | 
					
						
							|  |  |  |         fprintf(stderr, "Could not open option rom '%s': %s\n", | 
					
						
							|  |  |  |                 rom->path, strerror(errno)); | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |     if (fw_dir) { | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |         rom->fw_dir  = g_strdup(fw_dir); | 
					
						
							|  |  |  |         rom->fw_file = g_strdup(file); | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-02-19 04:41:11 +00:00
										 |  |  |     rom->addr     = addr; | 
					
						
							|  |  |  |     rom->romsize  = lseek(fd, 0, SEEK_END); | 
					
						
							| 
									
										
										
										
											2014-11-15 18:06:43 +08:00
										 |  |  |     if (rom->romsize == -1) { | 
					
						
							|  |  |  |         fprintf(stderr, "rom: file %-20s: get size error: %s\n", | 
					
						
							|  |  |  |                 rom->name, strerror(errno)); | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-19 04:41:11 +00:00
										 |  |  |     rom->datasize = rom->romsize; | 
					
						
							|  |  |  |     rom->data     = g_malloc0(rom->datasize); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     lseek(fd, 0, SEEK_SET); | 
					
						
							| 
									
										
										
										
											2013-02-19 04:41:11 +00:00
										 |  |  |     rc = read(fd, rom->data, rom->datasize); | 
					
						
							|  |  |  |     if (rc != rom->datasize) { | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |         fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n", | 
					
						
							| 
									
										
										
										
											2013-02-19 04:41:11 +00:00
										 |  |  |                 rom->name, rc, rom->datasize); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |         goto err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     rom_insert(rom); | 
					
						
							| 
									
										
										
										
											2010-12-08 13:35:06 +02:00
										 |  |  |     if (rom->fw_file && fw_cfg) { | 
					
						
							|  |  |  |         const char *basename; | 
					
						
							| 
									
										
										
										
											2013-07-24 18:56:05 +03:00
										 |  |  |         char fw_file_name[FW_CFG_MAX_FILE_PATH]; | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  |         void *data; | 
					
						
							| 
									
										
										
										
											2010-12-08 13:35:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         basename = strrchr(rom->fw_file, '/'); | 
					
						
							|  |  |  |         if (basename) { | 
					
						
							|  |  |  |             basename++; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             basename = rom->fw_file; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s", rom->fw_dir, | 
					
						
							|  |  |  |                  basename); | 
					
						
							| 
									
										
										
										
											2010-12-08 13:35:07 +02:00
										 |  |  |         snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name); | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-01 20:58:08 -02:00
										 |  |  |         if ((!option_rom || mc->option_rom_has_mr) && mc->rom_file_has_mr) { | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  |             data = rom_set_mr(rom, OBJECT(fw_cfg), devpath); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             data = rom->data; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fw_cfg_add_file(fw_cfg, fw_file_name, data, rom->romsize); | 
					
						
							| 
									
										
										
										
											2010-12-08 13:35:07 +02:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr); | 
					
						
							| 
									
										
										
										
											2010-12-08 13:35:06 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-12-08 13:35:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     add_boot_device_path(bootindex, NULL, devpath); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | err: | 
					
						
							|  |  |  |     if (fd != -1) | 
					
						
							|  |  |  |         close(fd); | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     g_free(rom->data); | 
					
						
							|  |  |  |     g_free(rom->path); | 
					
						
							|  |  |  |     g_free(rom->name); | 
					
						
							|  |  |  |     g_free(rom); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 10:24:16 +01:00
										 |  |  | MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, | 
					
						
							| 
									
										
										
										
											2014-11-17 07:51:50 +02:00
										 |  |  |                    size_t max_len, hwaddr addr, const char *fw_file_name, | 
					
						
							| 
									
										
										
										
											2013-08-18 17:02:33 +03:00
										 |  |  |                    FWCfgReadCallback fw_callback, void *callback_opaque) | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-12-01 20:58:08 -02:00
										 |  |  |     MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     Rom *rom; | 
					
						
							| 
									
										
										
										
											2015-03-23 10:24:16 +01:00
										 |  |  |     MemoryRegion *mr = NULL; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-19 04:41:11 +00:00
										 |  |  |     rom           = g_malloc0(sizeof(*rom)); | 
					
						
							|  |  |  |     rom->name     = g_strdup(name); | 
					
						
							|  |  |  |     rom->addr     = addr; | 
					
						
							| 
									
										
										
										
											2014-11-17 07:51:50 +02:00
										 |  |  |     rom->romsize  = max_len ? max_len : len; | 
					
						
							| 
									
										
										
										
											2013-02-19 04:41:11 +00:00
										 |  |  |     rom->datasize = len; | 
					
						
							|  |  |  |     rom->data     = g_malloc0(rom->datasize); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     memcpy(rom->data, blob, len); | 
					
						
							|  |  |  |     rom_insert(rom); | 
					
						
							| 
									
										
										
										
											2013-08-18 17:02:33 +03:00
										 |  |  |     if (fw_file_name && fw_cfg) { | 
					
						
							|  |  |  |         char devpath[100]; | 
					
						
							| 
									
										
										
										
											2014-11-17 07:49:21 +02:00
										 |  |  |         void *data; | 
					
						
							| 
									
										
										
										
											2013-08-18 17:02:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-01 20:58:08 -02:00
										 |  |  |         if (mc->rom_file_has_mr) { | 
					
						
							| 
									
										
										
										
											2013-08-18 17:02:33 +03:00
										 |  |  |             data = rom_set_mr(rom, OBJECT(fw_cfg), devpath); | 
					
						
							| 
									
										
										
										
											2015-03-23 10:24:16 +01:00
										 |  |  |             mr = rom->mr; | 
					
						
							| 
									
										
										
										
											2013-08-18 17:02:33 +03:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             data = rom->data; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fw_cfg_add_file_callback(fw_cfg, fw_file_name, | 
					
						
							|  |  |  |                                  fw_callback, callback_opaque, | 
					
						
							| 
									
										
										
										
											2014-11-17 07:51:50 +02:00
										 |  |  |                                  data, rom->datasize); | 
					
						
							| 
									
										
										
										
											2013-08-18 17:02:33 +03:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-03-23 10:24:16 +01:00
										 |  |  |     return mr; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-19 04:41:11 +00:00
										 |  |  | /* This function is specific for elf program because we don't need to allocate
 | 
					
						
							|  |  |  |  * all the rom. We just allocate the first part and the rest is just zeros. This | 
					
						
							|  |  |  |  * is why romsize and datasize are different. Also, this function seize the | 
					
						
							|  |  |  |  * memory ownership of "data", so we don't have to allocate and copy the buffer. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int rom_add_elf_program(const char *name, void *data, size_t datasize, | 
					
						
							|  |  |  |                         size_t romsize, hwaddr addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Rom *rom; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rom           = g_malloc0(sizeof(*rom)); | 
					
						
							|  |  |  |     rom->name     = g_strdup(name); | 
					
						
							|  |  |  |     rom->addr     = addr; | 
					
						
							|  |  |  |     rom->datasize = datasize; | 
					
						
							|  |  |  |     rom->romsize  = romsize; | 
					
						
							|  |  |  |     rom->data     = data; | 
					
						
							|  |  |  |     rom_insert(rom); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-26 12:18:25 +01:00
										 |  |  | int rom_add_vga(const char *file) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-06 14:57:09 +02:00
										 |  |  |     return rom_add_file(file, "vgaroms", 0, -1, true); | 
					
						
							| 
									
										
										
										
											2009-10-26 12:18:25 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-08 13:35:07 +02:00
										 |  |  | int rom_add_option(const char *file, int32_t bootindex) | 
					
						
							| 
									
										
										
										
											2009-10-26 12:18:25 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-06 14:57:09 +02:00
										 |  |  |     return rom_add_file(file, "genroms", 0, bootindex, true); | 
					
						
							| 
									
										
										
										
											2009-10-26 12:18:25 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | static void rom_reset(void *unused) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Rom *rom; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_FOREACH(rom, &roms, next) { | 
					
						
							| 
									
										
										
										
											2009-12-22 11:57:02 +02:00
										 |  |  |         if (rom->fw_file) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |         if (rom->data == NULL) { | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |             continue; | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  |         if (rom->mr) { | 
					
						
							|  |  |  |             void *host = memory_region_get_ram_ptr(rom->mr); | 
					
						
							|  |  |  |             memcpy(host, rom->data, rom->datasize); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2013-12-13 16:28:52 +10:00
										 |  |  |             cpu_physical_memory_write_rom(&address_space_memory, | 
					
						
							|  |  |  |                                           rom->addr, rom->data, rom->datasize); | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |         if (rom->isrom) { | 
					
						
							|  |  |  |             /* rom needs to be written only once */ | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |             g_free(rom->data); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |             rom->data = NULL; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-12-11 14:17:44 +01:00
										 |  |  |         /*
 | 
					
						
							|  |  |  |          * The rom loader is really on the same level as firmware in the guest | 
					
						
							|  |  |  |          * shadowing a ROM into RAM. Such a shadowing mechanism needs to ensure | 
					
						
							|  |  |  |          * that the instruction cache for that new region is clear, so that the | 
					
						
							|  |  |  |          * CPU definitely fetches its instructions from the just written data. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         cpu_flush_icache_range(rom->addr, rom->datasize); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-16 17:07:54 +01:00
										 |  |  | int rom_check_and_register_reset(void) | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |     hwaddr addr = 0; | 
					
						
							| 
									
										
										
										
											2011-12-08 16:12:18 +02:00
										 |  |  |     MemoryRegionSection section; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     Rom *rom; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_FOREACH(rom, &roms, next) { | 
					
						
							| 
									
										
										
										
											2009-12-22 11:57:02 +02:00
										 |  |  |         if (rom->fw_file) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:12 +01:00
										 |  |  |         if (addr > rom->addr) { | 
					
						
							|  |  |  |             fprintf(stderr, "rom: requested regions overlap " | 
					
						
							|  |  |  |                     "(rom %s. free=0x" TARGET_FMT_plx | 
					
						
							|  |  |  |                     ", addr=0x" TARGET_FMT_plx ")\n", | 
					
						
							|  |  |  |                     rom->name, addr, rom->addr); | 
					
						
							|  |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:12 +01:00
										 |  |  |         addr  = rom->addr; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |         addr += rom->romsize; | 
					
						
							| 
									
										
										
										
											2011-12-08 16:12:18 +02:00
										 |  |  |         section = memory_region_find(get_system_memory(), rom->addr, 1); | 
					
						
							| 
									
										
										
										
											2013-05-27 10:08:27 +02:00
										 |  |  |         rom->isrom = int128_nz(section.size) && memory_region_is_rom(section.mr); | 
					
						
							| 
									
										
										
										
											2013-05-06 10:46:11 +02:00
										 |  |  |         memory_region_unref(section.mr); | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     qemu_register_reset(rom_reset, NULL); | 
					
						
							| 
									
										
										
										
											2013-07-24 18:56:08 +03:00
										 |  |  |     roms_loaded = 1; | 
					
						
							| 
									
										
										
										
											2015-06-16 17:07:54 +01:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2013-07-24 18:56:08 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-16 02:24:08 +02:00
										 |  |  | void rom_set_fw(FWCfgState *f) | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:11 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:40 +01:00
										 |  |  |     fw_cfg = f; | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:11 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static Rom *find_rom(hwaddr addr) | 
					
						
							| 
									
										
										
										
											2009-10-07 13:37:06 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     Rom *rom; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_FOREACH(rom, &roms, next) { | 
					
						
							| 
									
										
										
										
											2009-12-24 19:30:25 +01:00
										 |  |  |         if (rom->fw_file) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  |         if (rom->mr) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |         if (rom->addr > addr) { | 
					
						
							| 
									
										
										
										
											2009-10-07 13:37:06 +02:00
										 |  |  |             continue; | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (rom->addr + rom->romsize < addr) { | 
					
						
							| 
									
										
										
										
											2009-10-07 13:37:06 +02:00
										 |  |  |             continue; | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-10-07 13:37:06 +02:00
										 |  |  |         return rom; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-19 21:15:20 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copies memory from registered ROMs to dest. Any memory that is contained in | 
					
						
							|  |  |  |  * a ROM between addr and addr + size is copied. Note that this can involve | 
					
						
							|  |  |  |  * multiple ROMs, which need not start at addr and need not end at addr + size. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | int rom_copy(uint8_t *dest, hwaddr addr, size_t size) | 
					
						
							| 
									
										
										
										
											2009-11-12 21:53:11 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |     hwaddr end = addr + size; | 
					
						
							| 
									
										
										
										
											2009-11-12 21:53:11 +01:00
										 |  |  |     uint8_t *s, *d = dest; | 
					
						
							|  |  |  |     size_t l = 0; | 
					
						
							|  |  |  |     Rom *rom; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_FOREACH(rom, &roms, next) { | 
					
						
							| 
									
										
										
										
											2009-12-24 19:30:25 +01:00
										 |  |  |         if (rom->fw_file) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  |         if (rom->mr) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |         if (rom->addr + rom->romsize < addr) { | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:12 +01:00
										 |  |  |             continue; | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (rom->addr > end) { | 
					
						
							| 
									
										
										
										
											2009-11-12 21:53:11 +01:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-11-12 21:53:11 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:12 +01:00
										 |  |  |         d = dest + (rom->addr - addr); | 
					
						
							| 
									
										
										
										
											2009-11-12 21:53:11 +01:00
										 |  |  |         s = rom->data; | 
					
						
							| 
									
										
										
										
											2013-02-19 04:41:11 +00:00
										 |  |  |         l = rom->datasize; | 
					
						
							| 
									
										
										
										
											2009-11-12 21:53:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if ((d + l) > (dest + size)) { | 
					
						
							|  |  |  |             l = dest - d; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-06 20:45:39 +02:00
										 |  |  |         if (l > 0) { | 
					
						
							|  |  |  |             memcpy(d, s, l); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-19 04:41:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (rom->romsize > rom->datasize) { | 
					
						
							|  |  |  |             /* If datasize is less than romsize, it means that we didn't
 | 
					
						
							|  |  |  |              * allocate all the ROM because the trailing data are only zeros. | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             d += l; | 
					
						
							|  |  |  |             l = rom->romsize - rom->datasize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if ((d + l) > (dest + size)) { | 
					
						
							|  |  |  |                 /* Rom size doesn't fit in the destination area. Adjust to avoid
 | 
					
						
							|  |  |  |                  * overflow. | 
					
						
							|  |  |  |                  */ | 
					
						
							|  |  |  |                 l = dest - d; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (l > 0) { | 
					
						
							|  |  |  |                 memset(d, 0x0, l); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-11-12 21:53:11 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return (d + l) - dest; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | void *rom_ptr(hwaddr addr) | 
					
						
							| 
									
										
										
										
											2009-10-07 13:37:06 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     Rom *rom; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rom = find_rom(addr); | 
					
						
							|  |  |  |     if (!rom || !rom->data) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:12 +01:00
										 |  |  |     return rom->data + (addr - rom->addr); | 
					
						
							| 
									
										
										
										
											2009-10-07 13:37:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-06 14:18:24 +01:00
										 |  |  | void hmp_info_roms(Monitor *mon, const QDict *qdict) | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     Rom *rom; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_FOREACH(rom, &roms, next) { | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  |         if (rom->mr) { | 
					
						
							|  |  |  |             monitor_printf(mon, "%s" | 
					
						
							|  |  |  |                            " size=0x%06zx name=\"%s\"\n", | 
					
						
							| 
									
										
										
										
											2014-08-14 23:53:55 -07:00
										 |  |  |                            memory_region_name(rom->mr), | 
					
						
							| 
									
										
										
										
											2013-08-19 17:26:55 +03:00
										 |  |  |                            rom->romsize, | 
					
						
							|  |  |  |                            rom->name); | 
					
						
							|  |  |  |         } else if (!rom->fw_file) { | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:12 +01:00
										 |  |  |             monitor_printf(mon, "addr=" TARGET_FMT_plx | 
					
						
							| 
									
										
										
										
											2011-09-12 22:33:01 +02:00
										 |  |  |                            " size=0x%06zx mem=%s name=\"%s\"\n", | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:12 +01:00
										 |  |  |                            rom->addr, rom->romsize, | 
					
						
							|  |  |  |                            rom->isrom ? "rom" : "ram", | 
					
						
							|  |  |  |                            rom->name); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |             monitor_printf(mon, "fw=%s/%s" | 
					
						
							| 
									
										
										
										
											2011-09-12 22:33:01 +02:00
										 |  |  |                            " size=0x%06zx name=\"%s\"\n", | 
					
						
							| 
									
										
										
										
											2010-01-08 15:25:38 +01:00
										 |  |  |                            rom->fw_dir, | 
					
						
							| 
									
										
										
										
											2009-12-18 12:01:12 +01:00
										 |  |  |                            rom->fw_file, | 
					
						
							|  |  |  |                            rom->romsize, | 
					
						
							|  |  |  |                            rom->name); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-10-01 16:42:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } |