18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * QEMU Executable loader 38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2006 Fabrice Bellard 58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Permission is hereby granted, free of charge, to any person obtaining a copy 78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * of this software and associated documentation files (the "Software"), to deal 88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * in the Software without restriction, including without limitation the rights 98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * copies of the Software, and to permit persons to whom the Software is 118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * furnished to do so, subject to the following conditions: 128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The above copyright notice and this permission notice shall be included in 148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * all copies or substantial portions of the Software. 158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE. 235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Gunzip functionality in this file is derived from u-boot: 255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * (C) Copyright 2008 Semihalf 275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * (C) Copyright 2000-2005 295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * This program is free software; you can redistribute it and/or 325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * modify it under the terms of the GNU General Public License as 335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * published by the Free Software Foundation; either version 2 of 345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the License, or (at your option) any later version. 355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * This program is distributed in the hope that it will be useful, 375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * but WITHOUT ANY WARRANTY; without even the implied warranty of 385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * GNU General Public License for more details. 405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * You should have received a copy of the GNU General Public License along 425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * with this program; if not, write to the Free Software Foundation, Inc., 435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-common.h" 478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "disas.h" 488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "sysemu.h" 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "uboot_image.h" 508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <zlib.h> 525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* return the size or -1 if error */ 548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint get_image_size(const char *filename) 558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int fd, size; 578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fd = open(filename, O_RDONLY | O_BINARY); 588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (fd < 0) 598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size = lseek(fd, 0, SEEK_END); 618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project close(fd); 628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return size; 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* return the size or -1 if error */ 668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* deprecated, because caller does not specify buffer size! */ 678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint load_image(const char *filename, uint8_t *addr) 688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int fd, size; 708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fd = open(filename, O_RDONLY | O_BINARY); 718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (fd < 0) 728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size = lseek(fd, 0, SEEK_END); 748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project lseek(fd, 0, SEEK_SET); 758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (read(fd, addr, size) != size) { 768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project close(fd); 778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project close(fd); 808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return size; 818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* return the amount read, just like fread. 0 may mean error or eof */ 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f) 858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t buf[4096]; 878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project target_phys_addr_t dst_begin = dst_addr; 888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size_t want, did; 898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while (nbytes) { 918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes; 928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project did = fread(buf, 1, want, f); 938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_physical_memory_write_rom(dst_addr, buf, did); 958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dst_addr += did; 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nbytes -= did; 975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (did != want) 985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return dst_addr - dst_begin; 1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* returns 0 on error, 1 if ok */ 1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f) 1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return fread_targphys(dst_addr, nbytes, f) == nbytes; 1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* read()-like version */ 1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes) 1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t buf[4096]; 1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project target_phys_addr_t dst_begin = dst_addr; 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size_t want, did; 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project while (nbytes) { 1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes; 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project did = read(fd, buf, want); 1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (did != want) break; 1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_physical_memory_write_rom(dst_addr, buf, did); 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project dst_addr += did; 1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nbytes -= did; 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return dst_addr - dst_begin; 1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* return the size or -1 if error */ 1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint load_image_targphys(const char *filename, 1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project target_phys_addr_t addr, int max_sz) 1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project FILE *f; 1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size_t got; 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project f = fopen(filename, "rb"); 1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (!f) return -1; 1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project got = fread_targphys(addr, max_sz, f); 1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (ferror(f)) { fclose(f); return -1; } 1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fclose(f); 1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return got; 1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid pstrcpy_targphys(target_phys_addr_t dest, int buf_size, 1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const char *source) 1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project static const uint8_t nul_byte = 0; 1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const char *nulp; 1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (buf_size <= 0) return; 1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project nulp = memchr(source, 0, buf_size); 1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (nulp) { 1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_physical_memory_write_rom(dest, (uint8_t *)source, 1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (nulp - source) + 1); 1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_physical_memory_write_rom(dest, (uint8_t *)source, buf_size - 1); 1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_physical_memory_write_rom(dest, &nul_byte, 1); 1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* A.OUT loader */ 1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct exec 1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t a_info; /* Use macros N_MAGIC, etc for access */ 1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t a_text; /* length of text, in bytes */ 1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t a_data; /* length of data, in bytes */ 1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t a_bss; /* length of uninitialized data area, in bytes */ 1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t a_syms; /* length of symbol table data in file, in bytes */ 1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t a_entry; /* start address */ 1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t a_trsize; /* length of relocation info for text, in bytes */ 1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t a_drsize; /* length of relocation info for data, in bytes */ 1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}; 1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef BSWAP_NEEDED 1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void bswap_ahdr(struct exec *e) 1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&e->a_info); 1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&e->a_text); 1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&e->a_data); 1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&e->a_bss); 1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&e->a_syms); 1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&e->a_entry); 1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&e->a_trsize); 1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&e->a_drsize); 1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define bswap_ahdr(x) do { } while (0) 1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define N_MAGIC(exec) ((exec).a_info & 0xffff) 1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OMAGIC 0407 1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define NMAGIC 0410 1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ZMAGIC 0413 1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define QMAGIC 0314 1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define _N_HDROFF(x) (1024 - sizeof (struct exec)) 1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define N_TXTOFF(x) \ 1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ 2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) 2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0) 2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1)) 2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) 2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define N_DATADDR(x) \ 2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ 2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) 2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint load_aout(const char *filename, target_phys_addr_t addr, int max_sz) 2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int fd, size, ret; 2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project struct exec e; 2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint32_t magic; 2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fd = open(filename, O_RDONLY | O_BINARY); 2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (fd < 0) 2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size = read(fd, &e, sizeof(e)); 2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (size < 0) 2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap_ahdr(&e); 2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project magic = N_MAGIC(e); 2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (magic) { 2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case ZMAGIC: 2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case QMAGIC: 2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case OMAGIC: 2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (e.a_text + e.a_data > max_sz) 2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project lseek(fd, N_TXTOFF(e), SEEK_SET); 2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size = read_targphys(fd, addr, e.a_text + e.a_data); 2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (size < 0) 2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case NMAGIC: 2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (N_DATADDR(e) + e.a_data > max_sz) 2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project lseek(fd, N_TXTOFF(e), SEEK_SET); 2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size = read_targphys(fd, addr, e.a_text); 2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (size < 0) 2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ret = read_targphys(fd, addr + N_DATADDR(e), e.a_data); 2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (ret < 0) 2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size += ret; 2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project break; 2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: 2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project close(fd); 2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return size; 2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fail: 2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project close(fd); 2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* ELF loader */ 2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void *load_at(int fd, int offset, int size) 2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project void *ptr; 2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (lseek(fd, offset, SEEK_SET) < 0) 2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return NULL; 2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ptr = qemu_malloc(size); 2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (read(fd, ptr, size) != size) { 2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_free(ptr); 2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return NULL; 2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return ptr; 2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ELF_CLASS ELFCLASS32 2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "elf.h" 2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SZ 32 2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define elf_word uint32_t 2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define elf_sword int32_t 2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define bswapSZs bswap32s 2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "elf_ops.h" 2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef elfhdr 2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef elf_phdr 2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef elf_shdr 2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef elf_sym 2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef elf_note 2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef elf_word 2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef elf_sword 2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef bswapSZs 2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef SZ 2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define elfhdr elf64_hdr 2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define elf_phdr elf64_phdr 2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define elf_note elf64_note 2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define elf_shdr elf64_shdr 2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define elf_sym elf64_sym 3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define elf_word uint64_t 3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define elf_sword int64_t 3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define bswapSZs bswap64s 3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SZ 64 3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "elf_ops.h" 3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* return < 0 if error, otherwise the number of bytes loaded in memory */ 3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint load_elf(const char *filename, int64_t address_offset, 3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr) 3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int fd, data_order, host_data_order, must_swab, ret; 3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t e_ident[EI_NIDENT]; 3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fd = open(filename, O_RDONLY | O_BINARY); 3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (fd < 0) { 3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project perror(filename); 3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 3178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident)) 3198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 3208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (e_ident[0] != ELFMAG0 || 3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project e_ident[1] != ELFMAG1 || 3228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project e_ident[2] != ELFMAG2 || 3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project e_ident[3] != ELFMAG3) 3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto fail; 32520894ae3fa98f82da925fbeb72e616eef509758aDavid 'Digit' Turner#ifdef HOST_WORDS_BIGENDIAN 3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project data_order = ELFDATA2MSB; 3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project data_order = ELFDATA2LSB; 3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project must_swab = data_order != e_ident[EI_DATA]; 3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef TARGET_WORDS_BIGENDIAN 3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project host_data_order = ELFDATA2MSB; 3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else 3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project host_data_order = ELFDATA2LSB; 3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (host_data_order != e_ident[EI_DATA]) 3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project lseek(fd, 0, SEEK_SET); 3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (e_ident[EI_CLASS] == ELFCLASS64) { 3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = load_elf64(fd, address_offset, must_swab, pentry, 3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project lowaddr, highaddr); 3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = load_elf32(fd, address_offset, must_swab, pentry, 3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project lowaddr, highaddr); 3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project close(fd); 3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return ret; 3518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fail: 3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project close(fd); 3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void bswap_uboot_header(uboot_image_header_t *hdr) 3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 35920894ae3fa98f82da925fbeb72e616eef509758aDavid 'Digit' Turner#ifndef HOST_WORDS_BIGENDIAN 3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&hdr->ih_magic); 3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&hdr->ih_hcrc); 3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&hdr->ih_time); 3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&hdr->ih_size); 3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&hdr->ih_load); 3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&hdr->ih_ep); 3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap32s(&hdr->ih_dcrc); 3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif 3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define ZALLOC_ALIGNMENT 16 3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void *zalloc(void *x, unsigned items, unsigned size) 3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *p; 3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size *= items; 3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1); 3795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner p = qemu_malloc(size); 3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return (p); 3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void zfree(void *x, void *addr) 3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(addr); 3885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define HEAD_CRC 2 3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define EXTRA_FIELD 4 3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define ORIG_NAME 8 3945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define COMMENT 0x10 3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define RESERVED 0xe0 3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define DEFLATED 8 3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* This is the maximum in uboot, so if a uImage overflows this, it would 4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * overflow on real hardware too. */ 4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define UBOOT_MAX_GUNZIP_BYTES 0x800000 4025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, 4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size_t srclen) 4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 4065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner z_stream s; 4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ssize_t dstbytes; 4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int r, i, flags; 4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* skip header */ 4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner i = 10; 4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner flags = src[3]; 4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (src[2] != DEFLATED || (flags & RESERVED) != 0) { 4145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner puts ("Error: Bad gzipped data\n"); 4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((flags & EXTRA_FIELD) != 0) 4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner i = 12 + src[10] + (src[11] << 8); 4195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((flags & ORIG_NAME) != 0) 4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (src[i++] != 0) 4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ; 4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((flags & COMMENT) != 0) 4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (src[i++] != 0) 4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ; 4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((flags & HEAD_CRC) != 0) 4265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner i += 2; 4275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (i >= srclen) { 4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner puts ("Error: gunzip out of data in header\n"); 4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s.zalloc = zalloc; 4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s.zfree = zfree; 4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r = inflateInit2(&s, -MAX_WBITS); 4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (r != Z_OK) { 4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner printf ("Error: inflateInit2() returned %d\n", r); 4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return (-1); 4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s.next_in = src + i; 4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s.avail_in = srclen - i; 4425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s.next_out = dst; 4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s.avail_out = dstlen; 4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner r = inflate(&s, Z_FINISH); 4455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (r != Z_OK && r != Z_STREAM_END) { 4465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner printf ("Error: inflate() returned %d\n", r); 4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -1; 4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner dstbytes = s.next_out - (unsigned char *) dst; 4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner inflateEnd(&s); 4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return dstbytes; 4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Load a U-Boot image. */ 4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint load_uimage(const char *filename, target_ulong *ep, target_ulong *loadaddr, 4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int *is_linux) 4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int fd; 4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int size; 4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uboot_image_header_t h; 4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uboot_image_header_t *hdr = &h; 4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uint8_t *data = NULL; 4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int ret = -1; 4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fd = open(filename, O_RDONLY | O_BINARY); 4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (fd < 0) 4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project size = read(fd, hdr, sizeof(uboot_image_header_t)); 4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (size < 0) 4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project bswap_uboot_header(hdr); 4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (hdr->ih_magic != IH_MAGIC) 4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: Implement other image types. */ 4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hdr->ih_type != IH_TYPE_KERNEL) { 4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Can only load u-boot image type \"kernel\"\n"); 4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (hdr->ih_comp) { 4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case IH_COMP_NONE: 4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case IH_COMP_GZIP: 4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 4905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, 4915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Unable to load u-boot images with compression type %d\n", 4925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hdr->ih_comp); 4935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* TODO: Check CPU type. */ 4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (is_linux) { 4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hdr->ih_os == IH_OS_LINUX) 4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *is_linux = 1; 5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else 5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *is_linux = 0; 5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *ep = hdr->ih_ep; 5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project data = qemu_malloc(hdr->ih_size); 5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (read(fd, data, hdr->ih_size) != hdr->ih_size) { 5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fprintf(stderr, "Error reading file\n"); 5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hdr->ih_comp == IH_COMP_GZIP) { 5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t *compressed_data; 5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner size_t max_bytes; 5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ssize_t bytes; 5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner compressed_data = data; 5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner max_bytes = UBOOT_MAX_GUNZIP_BYTES; 5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner data = qemu_malloc(max_bytes); 5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size); 5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(compressed_data); 5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bytes < 0) { 5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "Unable to decompress gzipped image!\n"); 5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto out; 5265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hdr->ih_size = bytes; 5288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 5298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size); 5318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (loadaddr) 5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *loadaddr = hdr->ih_load; 5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ret = hdr->ih_size; 5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout: 5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (data) 5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_free(data); 5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project close(fd); 5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return ret; 5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 543