From nobody Mon Feb 9 18:00:14 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1582179479; cv=none; d=zohomail.com; s=zohoarc; b=NWqvVOtWTyBvCC6exgkI9u0lNiCRDKUY69WK0e7mhEVoqdwoFrauTbk0sXBrH33t5DyAQIQ3PE7Yn0giH20fx5DHxHKYOsY1iFsIscfT5B15TNZ6i4HpJpZqo2le+QjvU80ON55VJhcvrcHhRE7noXoQQtKXZiirTBsAcBE4KZo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1582179479; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=WYDLfFDXsBCTKyHfVYis7NnKhR4eg4I2I5WOGLQHMGc=; b=U34qkmTgf6YxwvXhqVNcmOT7qxQkbNhGgjNq4PuM62rV4pzoiPvYg8fOU/6yVpbL9VBYb/hMioqM/EIpz1um/KJvoLvxV1AthApjHbfbdQ+Td1BI52Ap+DdX1OiSJ5+bhyu34Jr8y0s+m0LtTE62VfThMpR3JOZDmDMhQdlHd1s= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1582179478991274.83841112268067; Wed, 19 Feb 2020 22:17:58 -0800 (PST) Received: from localhost ([::1]:36672 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j4f9p-0001FI-L7 for importer@patchew.org; Thu, 20 Feb 2020 01:17:57 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:56328) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j4f8c-0007wP-26 for qemu-devel@nongnu.org; Thu, 20 Feb 2020 01:16:45 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1j4f8Y-00058A-IC for qemu-devel@nongnu.org; Thu, 20 Feb 2020 01:16:41 -0500 Received: from [107.174.27.60] (port=52534 helo=ozlabs.ru) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1j4f8Y-00057Q-61; Thu, 20 Feb 2020 01:16:38 -0500 Received: from fstn1-p1.ozlabs.ibm.com (localhost [IPv6:::1]) by ozlabs.ru (Postfix) with ESMTP id 42C2DAE80017; Thu, 20 Feb 2020 01:15:04 -0500 (EST) From: Alexey Kardashevskiy To: qemu-devel@nongnu.org Subject: [PATCH qemu v7 5/5] spapr/vof: Add basic support for MBR/GPT/GRUB Date: Thu, 20 Feb 2020 17:16:22 +1100 Message-Id: <20200220061622.15064-6-aik@ozlabs.ru> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200220061622.15064-1-aik@ozlabs.ru> References: <20200220061622.15064-1-aik@ozlabs.ru> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 107.174.27.60 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Alexey Kardashevskiy , Paolo Bonzini , qemu-ppc@nongnu.org, David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This hooks up disks to block backends so vof.bin can read MBR/GPT, find a bootloader and run it. This bypasses the device drivers and goes straight to the backend. This implements basic support for 32bit big endian bootloader; tested on GRUB. Signed-off-by: Alexey Kardashevskiy --- pc-bios/vof/Makefile | 2 +- pc-bios/vof/vof.h | 15 +++ hw/ppc/spapr_of_client.c | 64 +++++++++ pc-bios/vof/bootblock.c | 242 ++++++++++++++++++++++++++++++++++ pc-bios/vof/ci.c | 11 ++ pc-bios/vof/elf32.c | 273 +++++++++++++++++++++++++++++++++++++++ pc-bios/vof/main.c | 1 + hw/ppc/trace-events | 4 + pc-bios/vof.bin | Bin 4272 -> 9180 bytes 9 files changed, 611 insertions(+), 1 deletion(-) create mode 100644 pc-bios/vof/bootblock.c create mode 100644 pc-bios/vof/elf32.c diff --git a/pc-bios/vof/Makefile b/pc-bios/vof/Makefile index 49f7e240eeff..7e4227bb2cc6 100644 --- a/pc-bios/vof/Makefile +++ b/pc-bios/vof/Makefile @@ -8,7 +8,7 @@ build-all: vof.bin %.o: %.c cc -m32 -mbig-endian -c -fno-stack-protector -Wno-builtin-declaration-mis= match -o $@ $< =20 -vof.elf: entry.o main.o libc.o ci.o bootmem.o +vof.elf: entry.o main.o libc.o ci.o bootmem.o bootblock.o elf32.o ld -nostdlib -e_start -Tl.lds -EB -o $@ $^ =20 %.bin: %.elf diff --git a/pc-bios/vof/vof.h b/pc-bios/vof/vof.h index 738b2539aa19..b16270b289b7 100644 --- a/pc-bios/vof/vof.h +++ b/pc-bios/vof/vof.h @@ -37,6 +37,8 @@ phandle ci_finddevice(const char *path); uint32_t ci_getprop(phandle ph, const char *propname, void *prop, int len); ihandle ci_open(const char *path); void ci_close(ihandle ih); +uint32_t ci_block_size(ihandle ih); +uint32_t ci_seek(ihandle ih, uint64_t offset); uint32_t ci_read(ihandle ih, void *buf, int len); uint32_t ci_write(ihandle ih, const void *buf, int len); void ci_stdout(const char *buf); @@ -44,5 +46,18 @@ void ci_stdoutn(const char *buf, int len); void *ci_claim(void *virt, uint32_t size, uint32_t align); uint32_t ci_release(void *virt, uint32_t size); =20 +/* ELF */ +int elf_load_file(void *file_addr, uint32_t *entry, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)); + +/* booting from blockdev */ +void boot_block(void); + /* booting from -kernel */ void boot_from_memory(uint64_t initrd, uint64_t initrdsize); + +/* bswap */ +#define le16_to_cpu(x) __builtin_bswap16(x) +#define le32_to_cpu(x) __builtin_bswap32(x) +#define le64_to_cpu(x) __builtin_bswap64(x) diff --git a/hw/ppc/spapr_of_client.c b/hw/ppc/spapr_of_client.c index 4c476e138e60..a36b32487349 100644 --- a/hw/ppc/spapr_of_client.c +++ b/hw/ppc/spapr_of_client.c @@ -43,6 +43,9 @@ typedef struct { typedef struct { DeviceState *dev; CharBackend *cbe; + BlockBackend *blk; + uint64_t blk_pos; + uint16_t blk_physical_block_size; char *params; char *path; /* the path used to open the instance */ uint32_t phandle; @@ -494,6 +497,8 @@ static uint32_t spapr_of_client_open(SpaprMachineState = *spapr, const char *path) if (inst->dev) { const char *cdevstr =3D object_property_get_str(OBJECT(inst->dev), "chardev", NULL); + const char *blkstr =3D object_property_get_str(OBJECT(inst->dev), + "drive", NULL); =20 if (cdevstr) { Chardev *cdev =3D qemu_chr_find(cdevstr); @@ -501,6 +506,13 @@ static uint32_t spapr_of_client_open(SpaprMachineState= *spapr, const char *path) if (cdev) { inst->cbe =3D cdev->be; } + } else if (blkstr) { + BlockConf conf =3D { 0 }; + + inst->blk =3D blk_by_name(blkstr); + conf.blk =3D inst->blk; + blkconf_blocksizes(&conf); + inst->blk_physical_block_size =3D conf.physical_block_size; } } =20 @@ -602,6 +614,8 @@ static uint32_t of_client_write(SpaprMachineState *spap= r, uint32_t ihandle, if (inst->cbe) { toprint =3D qemu_chr_fe_write_all(inst->cbe, (uint8_t *) t= mp, toprint); + } else if (inst->blk) { + trace_spapr_of_client_blk_write(ihandle, len); } } else { /* We normally open stdout so this is fallback */ @@ -636,6 +650,17 @@ static uint32_t of_client_read(SpaprMachineState *spap= r, uint32_t ihandle, SpaprVioDevice *sdev =3D VIO_SPAPR_DEVICE(inst->dev); =20 ret =3D vty_getchars(sdev, buf, len); /* qemu_chr_fe_read_= all? */ + } else if (inst->blk) { + int rc =3D blk_pread(inst->blk, inst->blk_pos, buf, len); + + if (rc > 0) { + ret =3D rc; + } + trace_spapr_of_client_blk_read(ihandle, inst->blk_pos, len, + ret); + if (rc > 0) { + inst->blk_pos +=3D rc; + } } } } @@ -643,6 +668,25 @@ static uint32_t of_client_read(SpaprMachineState *spap= r, uint32_t ihandle, return ret; } =20 +static uint32_t of_client_seek(SpaprMachineState *spapr, uint32_t ihandle, + uint32_t hi, uint32_t lo) +{ + uint32_t ret =3D -1; + uint64_t pos =3D ((uint64_t) hi << 32) | lo; + SpaprOfInstance *inst =3D (SpaprOfInstance *) + g_hash_table_lookup(spapr->of_instances, GINT_TO_POINTER(ihandle)); + + if (inst) { + if (inst->blk) { + inst->blk_pos =3D pos; + ret =3D 1; + trace_spapr_of_client_blk_seek(ihandle, pos, ret); + } + } + + return ret; +} + static void of_client_clamed_dump(GArray *claimed) { #ifdef DEBUG @@ -797,6 +841,20 @@ static uint32_t of_client_call_method(SpaprMachineStat= e *spapr, /* do not bother about colors now */ ret =3D 0; } + } else if (inst->blk) { + if (strcmp(method, "block-size") =3D=3D 0) { + ret =3D 0; + *ret2 =3D inst->blk_physical_block_size; + } else if (strcmp(method, "#blocks") =3D=3D 0) { + ret =3D 0; + *ret2 =3D blk_getlength(inst->blk) / inst->blk_physical_block_= size; + } + } else if (inst->dev) { + if (strcmp(method, "vscsi-report-luns") =3D=3D 0) { + /* TODO: Not implemented yet, not clear when it is really need= ed */ + ret =3D -1; + *ret2 =3D 1; + } } else { trace_spapr_of_client_error_unknown_method(method); } @@ -934,6 +992,12 @@ static target_ulong spapr_h_of_client(PowerPCCPU *cpu,= SpaprMachineState *spapr, be32_to_cpu(pargs.args[0]), be32_to_cpu(pargs.args[1]), be32_to_cpu(pargs.args[2])); + } else if (cmpserv("seek", 3, 1)) { + pargs.args[nargs] =3D + of_client_seek(spapr, + be32_to_cpu(pargs.args[0]), + be32_to_cpu(pargs.args[1]), + be32_to_cpu(pargs.args[2])); } else if (cmpserv("claim", 3, 1)) { pargs.args[nargs] =3D of_client_claim(spapr, diff --git a/pc-bios/vof/bootblock.c b/pc-bios/vof/bootblock.c new file mode 100644 index 000000000000..cbf585746734 --- /dev/null +++ b/pc-bios/vof/bootblock.c @@ -0,0 +1,242 @@ +#include "vof.h" + +#define UUID_FMT_LEN 36 +#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-" \ + "%02hhx%02hhx-%02hhx%02hhx-" \ + "%02hhx%02hhx-" \ + "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" + +typedef struct { + union { + unsigned char data[16]; + struct { + /* Generated in BE endian, can be swapped with qemu_uuid_bswap= . */ + uint32_t time_low; + uint16_t time_mid; + uint16_t time_high_and_version; + uint8_t clock_seq_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; + } fields; + }; +} UUID; + +struct gpt_header { + char signature[8]; + char revision[4]; + uint32_t header_size; + uint32_t crc; + uint32_t reserved; + uint64_t current_lba; + uint64_t backup_lba; + uint64_t first_usable_lba; + uint64_t last_usable_lba; + char guid[16]; + uint64_t partition_entries_lba; + uint32_t nr_partition_entries; + uint32_t size_partition_entry; + uint32_t crc_partitions; +}; + +#define GPT_SIGNATURE "EFI PART" +#define GPT_REVISION "\0\0\1\0" /* revision 1.0 */ + +struct gpt_entry { + char partition_type_guid[16]; + char unique_guid[16]; + uint64_t first_lba; + uint64_t last_lba; + uint64_t attributes; + char name[72]; /* UTF-16LE */ +}; + +#define GPT_MIN_PARTITIONS 128 +#define GPT_PT_ENTRY_SIZE 128 +#define SECTOR_SIZE 512 + +static int find_prep_partition_on_gpt(ihandle blk, uint8_t *lba01, + uint64_t *offset, uint64_t *size) +{ + unsigned long i, partnum, partentrysize; + int ret; + struct gpt_header *hdr =3D (struct gpt_header *) (lba01 + SECTOR_SIZE); + UUID prep_uuid =3D { .fields =3D + { 0x9e1a2d38, 0xc612, 0x4316, 0xaa, 0x26, + { 0x8b, 0x49, 0x52, 0x1e, 0x5a, 0x8b} } }; + + if (memcmp(hdr, "EFI PART", 8)) + return -1; + + partnum =3D le32_to_cpu(hdr->nr_partition_entries); + partentrysize =3D le32_to_cpu(hdr->size_partition_entry); + + if (partentrysize < 128 || partentrysize > 512) { + return -1; + } + + for (i =3D 0; i < partnum; ++i) { + uint8_t partdata[partentrysize]; + struct gpt_entry *entry =3D (struct gpt_entry *) partdata; + uint64_t first, last; + UUID parttype; + char uuid[UUID_FMT_LEN + 1]; + + ci_seek(blk, 2 * SECTOR_SIZE + i * partentrysize); + ret =3D ci_read(blk, partdata, sizeof(partdata)); + if (ret < 0) + return ret; + else if (!ret) + return -1; + + memcpy(parttype.data, entry->partition_type_guid, 16); + first =3D le64_to_cpu(entry->first_lba); + last =3D le64_to_cpu(entry->last_lba); + + if (!memcmp(&parttype, &prep_uuid, sizeof(parttype))) { + *offset =3D first * SECTOR_SIZE; + *size =3D (last - first) * SECTOR_SIZE; + } + } + + if (*offset) + return 0; + + return -1; +} + +struct partition_record { + uint8_t bootable; + uint8_t start_head; + uint32_t start_cylinder; + uint8_t start_sector; + uint8_t system; + uint8_t end_head; + uint8_t end_cylinder; + uint8_t end_sector; + uint32_t start_sector_abs; + uint32_t nb_sectors_abs; +}; + +static void read_partition(uint8_t *p, struct partition_record *r) +{ + r->bootable =3D p[0]; + r->start_head =3D p[1]; + r->start_cylinder =3D p[3] | ((p[2] << 2) & 0x0300); + r->start_sector =3D p[2] & 0x3f; + r->system =3D p[4]; + r->end_head =3D p[5]; + r->end_cylinder =3D p[7] | ((p[6] << 2) & 0x300); + r->end_sector =3D p[6] & 0x3f; + r->start_sector_abs =3D le32_to_cpu(*(uint32_t *)(p + 8)); + r->nb_sectors_abs =3D le32_to_cpu(*(uint32_t *)(p + 12)); +} + +static int find_prep_partition(ihandle blk, uint64_t *offset, uint64_t *si= ze) +{ + uint8_t lba01[SECTOR_SIZE * 2]; + int i; + int ret =3D -1; + + ci_seek(blk, 0); + ret =3D ci_read(blk, lba01, sizeof(lba01)); + if (ret < 0) + return ret; + + if (lba01[510] !=3D 0x55 || lba01[511] !=3D 0xaa) + return find_prep_partition_on_gpt(blk, lba01, offset, size); + + for (i =3D 0; i < 4; i++) { + struct partition_record part; + + read_partition(&lba01[446 + 16 * i], &part); + + if (!part.system || !part.nb_sectors_abs) { + continue; + } + + /* 0xEE =3D=3D GPT */ + if (part.system =3D=3D 0xEE) { + ret =3D find_prep_partition_on_gpt(blk, lba01, offset, size); + } + /* 0x41 =3D=3D PReP */ + if (part.system =3D=3D 0x41) { + *offset =3D part.start_sector_abs; + *offset <<=3D 9; + *size =3D (uint64_t)part.nb_sectors_abs << 9; + ret =3D 0; + } + } + + return ret; +} + +static int elf_pre_load(void *destaddr, long size) +{ + void *ret =3D ci_claim(destaddr, size, 0); + + return (ret =3D=3D destaddr) ? 0 : -1; +} + +static void try_boot_block_device(ihandle blk, const char *path) +{ + uint32_t rc, elf_addr =3D 0; + uint64_t offset =3D 0, size =3D 0; + void *grub; + int ret; + + if (find_prep_partition(blk, &offset, &size)) + return; + + grub =3D ci_claim((void*)0x20000000, size, 0); + if (!grub) + return; + + ci_seek(blk, offset); + rc =3D ci_read(blk, grub, size); + if (rc <=3D 0) { + ci_release(grub, size); + return; + } + + ret =3D elf_load_file(grub, &elf_addr, elf_pre_load, NULL); + ci_release(grub, size); + if (ret < 0) + return; + + ci_stdout("** Booting from "); + ci_stdout(path); + ci_stdout("\n"); + do_boot(elf_addr, 0, 0); +} + +void boot_block(void) +{ + char bootlist[2048], *cur, *next; + uint32_t cb, blk; + phandle chosen =3D ci_finddevice("/chosen"); + + cb =3D ci_getprop(chosen, "qemu,boot-list", bootlist, + sizeof(bootlist) - 1); + bootlist[sizeof(bootlist) - 1] =3D '\0'; + + if (strlen(bootlist) =3D=3D 0) + return; + + for (cur =3D bootlist; cb > 0; cur =3D next + 1) { + for (next =3D cur; cb > 0; --cb) { + if (*next =3D=3D '\n') { + *next =3D '\0'; + ++next; + --cb; + break; + } + } + + blk =3D ci_open(cur); + if (!blk) + continue; + + try_boot_block_device(blk, cur); + ci_close(blk); + } +} diff --git a/pc-bios/vof/ci.c b/pc-bios/vof/ci.c index 143676421984..584776b2ff5b 100644 --- a/pc-bios/vof/ci.c +++ b/pc-bios/vof/ci.c @@ -96,6 +96,17 @@ void ci_close(ihandle ih) call_prom("close", 1, 0, ih); } =20 +uint32_t ci_block_size(ihandle ih) +{ + return 512; +} + +uint32_t ci_seek(ihandle ih, uint64_t offset) +{ + return call_prom("seek", 3, 1, ih, (prom_arg_t)(offset >> 32), + (prom_arg_t)(offset & 0xFFFFFFFFUL)); +} + uint32_t ci_read(ihandle ih, void *buf, int len) { return call_prom("read", 3, 1, ih, buf, len); diff --git a/pc-bios/vof/elf32.c b/pc-bios/vof/elf32.c new file mode 100644 index 000000000000..8e0623557d3f --- /dev/null +++ b/pc-bios/vof/elf32.c @@ -0,0 +1,273 @@ +/*************************************************************************= ***** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *************************************************************************= ****/ + +/* + * 32-bit ELF loader + */ +#include "vof.h" + +/* ELF object file types */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ + +/* ELF object endian */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ + +struct ehdr32 { + uint32_t ei_ident; + uint8_t ei_class; + uint8_t ei_data; + uint8_t ei_version; + uint8_t ei_pad[9]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +}; + +struct phdr32 { + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; +}; + +static inline void bswap_16p (uint16_t *x) +{ + *x =3D __builtin_bswap16(*x); +} + +static inline void bswap_32p (uint32_t *x) +{ + *x =3D __builtin_bswap32(*x); +} + +static inline void bswap_64p (uint64_t *x) +{ + *x =3D __builtin_bswap64(*x); +} + +static struct phdr32* +get_phdr32(void *file_addr) +{ + return (struct phdr32 *) (((unsigned char *)file_addr) + + ((struct ehdr32 *)file_addr)->e_phoff); +} + +static void +load_segment(void *file_addr, struct phdr32 *phdr, signed long offset, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)) +{ + unsigned long src =3D phdr->p_offset + (unsigned long) file_addr; + unsigned long destaddr; + + destaddr =3D (unsigned long)phdr->p_paddr; + destaddr =3D destaddr + offset; + + /* check if we're allowed to copy */ + if (pre_load !=3D NULL) { + if (pre_load((void*)destaddr, phdr->p_memsz) !=3D 0) + return; + } + + /* copy into storage */ + memmove((void *)destaddr, (void *)src, phdr->p_filesz); + + /* clear bss */ + memset((void *)(destaddr + phdr->p_filesz), 0, + phdr->p_memsz - phdr->p_filesz); + + if (phdr->p_memsz && post_load) { + post_load((void*)destaddr, phdr->p_memsz); + } +} + +unsigned int +elf_load_segments32(void *file_addr, signed long offset, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)) +{ + struct ehdr32 *ehdr =3D (struct ehdr32 *) file_addr; + /* Calculate program header address */ + struct phdr32 *phdr =3D get_phdr32(file_addr); + int i; + + /* loop e_phnum times */ + for (i =3D 0; i <=3D ehdr->e_phnum; i++) { + /* PT_LOAD ? */ + if (phdr->p_type =3D=3D 1) { + if (phdr->p_paddr !=3D phdr->p_vaddr) { + return 0; + } + + /* copy segment */ + load_segment(file_addr, phdr, offset, pre_load, + post_load); + } + /* step to next header */ + phdr =3D (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize); + } + + /* Entry point is always a virtual address, so translate it + * to physical before returning it */ + return ehdr->e_entry; +} + +/** + * Return the base address for loading (i.e. the address of the first PT_L= OAD + * segment) + * @param file_addr pointer to the ELF file in memory + * @return the base address + */ +long +elf_get_base_addr32(void *file_addr) +{ + struct ehdr32 *ehdr =3D (struct ehdr32 *) file_addr; + struct phdr32 *phdr =3D get_phdr32(file_addr); + int i; + + /* loop e_phnum times */ + for (i =3D 0; i <=3D ehdr->e_phnum; i++) { + /* PT_LOAD ? */ + if (phdr->p_type =3D=3D 1) { + return phdr->p_paddr; + } + /* step to next header */ + phdr =3D (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize); + } + + return 0; +} + +uint32_t elf_get_eflags_32(void *file_addr) +{ + struct ehdr32 *ehdr =3D (struct ehdr32 *) file_addr; + + return ehdr->e_flags; +} + +void +elf_byteswap_header32(void *file_addr) +{ + struct ehdr32 *ehdr =3D (struct ehdr32 *) file_addr; + struct phdr32 *phdr; + int i; + + bswap_16p(&ehdr->e_type); + bswap_16p(&ehdr->e_machine); + bswap_32p(&ehdr->e_version); + bswap_32p(&ehdr->e_entry); + bswap_32p(&ehdr->e_phoff); + bswap_32p(&ehdr->e_shoff); + bswap_32p(&ehdr->e_flags); + bswap_16p(&ehdr->e_ehsize); + bswap_16p(&ehdr->e_phentsize); + bswap_16p(&ehdr->e_phnum); + bswap_16p(&ehdr->e_shentsize); + bswap_16p(&ehdr->e_shnum); + bswap_16p(&ehdr->e_shstrndx); + + phdr =3D get_phdr32(file_addr); + + /* loop e_phnum times */ + for (i =3D 0; i <=3D ehdr->e_phnum; i++) { + bswap_32p(&phdr->p_type); + bswap_32p(&phdr->p_offset); + bswap_32p(&phdr->p_vaddr); + bswap_32p(&phdr->p_paddr); + bswap_32p(&phdr->p_filesz); + bswap_32p(&phdr->p_memsz); + bswap_32p(&phdr->p_flags); + bswap_32p(&phdr->p_align); + + /* step to next header */ + phdr =3D (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize); + } +} + +/** + * elf_check_file tests if the file at file_addr is + * a correct endian, ELF PPC executable + * @param file_addr pointer to the start of the ELF file + * @return the class (1 for 32 bit, 2 for 64 bit) + * -1 if it is not an ELF file + * -2 if it has the wrong endianness + * -3 if it is not an ELF executable + * -4 if it is not for PPC + */ +static int +elf_check_file(unsigned long *file_addr) +{ + struct ehdr32 *ehdr =3D (struct ehdr32 *) file_addr; + + /* check if it is an ELF image at all */ + if (ehdr->ei_ident !=3D 0x7f454c46) + return -1; + + if (ELFDATA2MSB !=3D ehdr->ei_data) { + switch (ehdr->ei_class) { + case 1: + elf_byteswap_header32(file_addr); + break; + } + } + + /* check if it is an ELF executable ... and also + * allow DYN files, since this is specified by ePAPR */ + if (ehdr->e_type !=3D ET_EXEC && ehdr->e_type !=3D ET_DYN) + return -3; + + /* check if it is a PPC ELF executable */ + if (ehdr->e_machine !=3D 0x14 && ehdr->e_machine !=3D 0x15) + return -4; + + return ehdr->ei_class; +} + +int elf_load_file(void *file_addr, uint32_t *entry, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)) +{ + int type =3D elf_check_file(file_addr); + struct ehdr32 *ehdr =3D (struct ehdr32 *) file_addr; + + switch (type) { + case 1: + *entry =3D elf_load_segments32(file_addr, 0, pre_load, pos= t_load); + if (ehdr->ei_data !=3D ELFDATA2MSB) { + type =3D 5; /* LE32 ABIv1 */ + } + break; + } + if (*entry =3D=3D 0) + type =3D 0; + + return type; +} diff --git a/pc-bios/vof/main.c b/pc-bios/vof/main.c index eb9aa8b78a8f..d0935e78edd8 100644 --- a/pc-bios/vof/main.c +++ b/pc-bios/vof/main.c @@ -19,5 +19,6 @@ void entry_c(void) =20 ci_stdout("*** Virtual Open Firmware ***\n"); boot_from_memory(initrd, initrdsize); + boot_block(); ci_panic("*** No boot target ***\n"); } diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 640d0649394d..9405d7fb2b84 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -38,6 +38,10 @@ spapr_of_client_getproplen(uint32_t ph, const char *prop= , uint32_t ret) "ph=3D0x%x spapr_of_client_setprop(uint32_t ph, const char *prop, const char *val, ui= nt32_t ret) "ph=3D0x%x \"%s\" [%s] =3D> len=3D%d" spapr_of_client_open(const char *path, uint32_t ph, uint32_t ih) "%s ph=3D= 0x%x =3D> ih=3D0x%x" spapr_of_client_interpret(const char *cmd, uint32_t param1, uint32_t param= 2, uint32_t ret, uint32_t ret2) "[%s] 0x%x 0x%x =3D> 0x%x 0x%x" +spapr_of_client_blk_write(uint32_t ih, uint32_t len) "0x%x =3D> len=3D%d" +spapr_of_client_blk_read(uint32_t ih, uint64_t pos, uint32_t len, uint32_t= ret) "ih=3D0x%x @0x%"PRIx64" size=3D%d =3D> %d" +spapr_of_client_blk_seek(uint32_t ih, uint64_t pos, uint32_t ret) "ih=3D0x= %x 0x%"PRIx64" =3D> %d" +spapr_of_client_blk_bootloader_read(uint64_t offset, uint64_t size) "0x%"P= RIx64" size=3D0x%"PRIx64 spapr_of_client_package_to_path(uint32_t ph, const char *tmp, uint32_t ret= ) "ph=3D0x%x =3D> %s len=3D%d" spapr_of_client_instance_to_path(uint32_t ih, uint32_t ph, const char *tmp= , uint32_t ret) "ih=3D0x%x ph=3D0x%x =3D> %s len=3D%d" spapr_of_client_instance_to_package(uint32_t ih, uint32_t ph) "ih=3D0x%x = =3D> ph=3D0x%x" diff --git a/pc-bios/vof.bin b/pc-bios/vof.bin index 152d86a094ce376ee8962c3f26afeccc9e7cae58..2c6629d2c72d5d1657c5e6791c1= 5dabbc7aecb48 100755 GIT binary patch literal 9180 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 delta 501 zcmYk$F-Tis5C`!4PBHJr^u0$>P?1)AdaF=3DB|`=3D~6j}(V(4j+zP&%Z9l3q|thaVhw-+lM5&6b8s4~2Ul zOn_=3DM2Jm8f9~#50gXRsSGT-sYgsv3|i6rh-C@)^)-V!P3>z$D2V8|=3Dzkr_~A5nLv? ztg?yjPTW<>sjdZq+b4AD@Q78qcFf?mS@tXQLVTt*^^LZbv)gOTgpRk=3DP!qT{NQ=3D%S zZt{|I9XG=3Di?M`B@N{8K3RCM=3DJ$)#Z~MHeoQ8l3w$o{hJfpQ!Hi{Tpu7c{nPb|KFV4 zSmQ%|b`b`xNg1{R08e%RVg>NZbs34b{`9wlL@uCHp2@H*$Y?th_g}W((~k!UEqi^R zHQxI5l@_&Un0-$lG@lx~&GGw&YT5!?4GQT)>eIXC3Z*$*M)wR@RsO)w8G`mXgzPH_ z^KIb#kLgq&z~(#pqL1Ov04au-{3Cg)jLa@Ug1pqT&w --=20 2.17.1