From patchwork Tue Jan 27 18:00:12 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Whitehorn X-Patchwork-Id: 433593 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 0D48B1401F6 for ; Wed, 28 Jan 2015 05:00:31 +1100 (AEDT) Received: from ozlabs.org (ozlabs.org [103.22.144.67]) by lists.ozlabs.org (Postfix) with ESMTP id F25E81A0627 for ; Wed, 28 Jan 2015 05:00:30 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from c.mail.sonic.net (c.mail.sonic.net [64.142.111.80]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 76D011A051F for ; Wed, 28 Jan 2015 05:00:26 +1100 (AEDT) Received: from comporellon.tachypleus.net (polaris.tachypleus.net [75.101.50.44]) (authenticated bits=0) by c.mail.sonic.net (8.15.1/8.15.1) with ESMTPSA id t0RI0C9n005509 (version=TLSv1.2 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT); Tue, 27 Jan 2015 10:00:13 -0800 Message-ID: <54C7D22C.5040202@freebsd.org> Date: Tue, 27 Jan 2015 10:00:12 -0800 From: Nathan Whitehorn User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 To: Benjamin Herrenschmidt References: <54BFD7A5.5080603@freebsd.org> <1421946125.4949.72.camel@kernel.crashing.org> <54C7D1FC.6090902@freebsd.org> In-Reply-To: <54C7D1FC.6090902@freebsd.org> X-Sonic-CAuth: UmFuZG9tSVaanMHI6eSSjz2UQ/prgQppT1vFvi69fSw7stw2xiCfJ702O4kqi4116urFzOVN7k9wyQ4cyi+3StOhw04YWy92xEpKyO71yeA= X-Sonic-ID: C;qjr9Vk6m5BG4panrCx1YGw== M;4pNhV06m5BG4panrCx1YGw== X-Spam-Flag: No X-Sonic-Spam-Details: 0.0/5.0 by cerberusd Cc: skiboot list Subject: Re: [Skiboot] [PATCH] Load ELF64 binaries correctly X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" On 01/27/15 09:59, Nathan Whitehorn wrote: > On 01/22/15 09:02, Benjamin Herrenschmidt wrote: >> On Wed, 2015-01-21 at 08:45 -0800, Nathan Whitehorn wrote: >>> The attached patch fixes the big-endian ELF64 loader in skiboot to >>> handle the fact that the ELF entry point is specified to point to a >>> function descriptor describing the entry point rather than the entry >>> point itself. (I haven't set it up to load the TOC base pointer though) >>> This is required to load the FreeBSD kernel as a skiboot payload. The >>> patch does not touch the little-endian loader since I'm not sure if the >>> ELFv2 spec still has function descriptors or not. >> An additional problem is that the Linux 64-bit BE kernel vmlinux doesn't >> have a correct function descriptor as an entry point :-( So that patch >> breaks loading a raw BE vmlinux... We probably need a quirk to recognize >> such an image, possibly via the fact that the value that would be in the >> function descriptor cannot possibly be a valid entry point as part of >> the image. > > Here's a second version of the patch that can load both Linux and > FreeBSD. It iterates through the ELF section table and, if the entry > point points to an executable section, treats the entry point as the > first instruction to run. Otherwise, it treats it as a function > descriptor. > -Nathan Sorry, missed a file in the patch. Here's the right one. -Nathan diff --git a/core/init.c b/core/init.c index 2c7e30c..e75b5a3 100644 --- a/core/init.c +++ b/core/init.c @@ -111,6 +111,7 @@ static bool try_load_elf64(struct elf_hdr *header) struct elf64_hdr *kh = (struct elf64_hdr *)header; uint64_t load_base = (uint64_t)kh; struct elf64_phdr *ph; + struct elf64_shdr *sh; unsigned int i; /* Check it's a ppc64 LE ELF */ @@ -152,6 +153,27 @@ static bool try_load_elf64(struct elf_hdr *header) prerror("INIT: Failed to find kernel entry !\n"); return false; } + + /* For the normal big-endian ELF ABI, the kernel entry points + * to a function descriptor in the data section. Linux instead + * has it point directly to code. Test whether it is pointing + * into an executable section or not to figure this out. Default + * to assuming it obeys the ABI. + */ + sh = (struct elf64_shdr *)(load_base + kh->e_shoff); + for (i = 0; i < kh->e_shnum; i++, sh++) { + if (sh->sh_addr > kh->e_entry || + (sh->sh_addr + sh->sh_size) <= kh->e_entry) + continue; + + break; + } + + if (i == kh->e_shnum || !(sh->sh_flags & ELF_SFLAGS_X)) { + kernel_entry = *(uint64_t *)(kernel_entry + load_base); + kernel_entry = kernel_entry - ph->p_vaddr + ph->p_offset; + } + kernel_entry += load_base; kernel_32bit = false; diff --git a/include/elf.h b/include/elf.h index 0a52f3e..c600f7f 100644 --- a/include/elf.h +++ b/include/elf.h @@ -76,6 +76,23 @@ struct elf64_phdr { uint64_t p_align; }; +/* 64-bit ELF section header */ +struct elf64_shdr { + uint32_t sh_name; + uint32_t sh_type; + uint64_t sh_flags; +#define ELF_SFLAGS_X 0x4 +#define ELF_SFLAGS_A 0x2 +#define ELF_SFLAGS_W 0x1 + uint64_t sh_addr; + uint64_t sh_offset; + uint64_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint64_t sh_addralign; + uint64_t sh_entsize; +}; + /* Some relocation related stuff used in relocate.c */ struct elf64_dyn { int64_t d_tag;