1da0c48c4Sopenharmony_ci/* Linux kernel image support for libdwfl. 2da0c48c4Sopenharmony_ci Copyright (C) 2009-2011 Red Hat, Inc. 3da0c48c4Sopenharmony_ci Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org> 4da0c48c4Sopenharmony_ci This file is part of elfutils. 5da0c48c4Sopenharmony_ci 6da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 7da0c48c4Sopenharmony_ci it under the terms of either 8da0c48c4Sopenharmony_ci 9da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 10da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 11da0c48c4Sopenharmony_ci your option) any later version 12da0c48c4Sopenharmony_ci 13da0c48c4Sopenharmony_ci or 14da0c48c4Sopenharmony_ci 15da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 16da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 17da0c48c4Sopenharmony_ci your option) any later version 18da0c48c4Sopenharmony_ci 19da0c48c4Sopenharmony_ci or both in parallel, as here. 20da0c48c4Sopenharmony_ci 21da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 22da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 23da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24da0c48c4Sopenharmony_ci General Public License for more details. 25da0c48c4Sopenharmony_ci 26da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 27da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 28da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 29da0c48c4Sopenharmony_ci 30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 31da0c48c4Sopenharmony_ci# include <config.h> 32da0c48c4Sopenharmony_ci#endif 33da0c48c4Sopenharmony_ci 34da0c48c4Sopenharmony_ci#include "libdwflP.h" 35da0c48c4Sopenharmony_ci 36da0c48c4Sopenharmony_ci#if BYTE_ORDER == LITTLE_ENDIAN 37da0c48c4Sopenharmony_ci# define LE16(x) (x) 38da0c48c4Sopenharmony_ci#else 39da0c48c4Sopenharmony_ci# define LE16(x) bswap_16 (x) 40da0c48c4Sopenharmony_ci#endif 41da0c48c4Sopenharmony_ci 42da0c48c4Sopenharmony_ci/* See Documentation/x86/boot.txt in Linux kernel sources 43da0c48c4Sopenharmony_ci for an explanation of these format details. */ 44da0c48c4Sopenharmony_ci 45da0c48c4Sopenharmony_ci#define MAGIC1 0xaa55 46da0c48c4Sopenharmony_ci#define MAGIC2 0x53726448 /* "HdrS" little-endian */ 47da0c48c4Sopenharmony_ci#define MIN_VERSION 0x0208 48da0c48c4Sopenharmony_ci 49da0c48c4Sopenharmony_ci#define H_START (H_SETUP_SECTS & -4) 50da0c48c4Sopenharmony_ci#define H_SETUP_SECTS 0x1f1 51da0c48c4Sopenharmony_ci#define H_MAGIC1 0x1fe 52da0c48c4Sopenharmony_ci#define H_MAGIC2 0x202 53da0c48c4Sopenharmony_ci#define H_VERSION 0x206 54da0c48c4Sopenharmony_ci#define H_PAYLOAD_OFFSET 0x248 55da0c48c4Sopenharmony_ci#define H_PAYLOAD_LENGTH 0x24c 56da0c48c4Sopenharmony_ci#define H_END 0x250 57da0c48c4Sopenharmony_ci#define H_READ_SIZE (H_END - H_START) 58da0c48c4Sopenharmony_ci 59da0c48c4Sopenharmony_ciDwfl_Error 60da0c48c4Sopenharmony_ciinternal_function 61da0c48c4Sopenharmony_ci__libdw_image_header (int fd, off_t *start_offset, 62da0c48c4Sopenharmony_ci void *mapped, size_t mapped_size) 63da0c48c4Sopenharmony_ci{ 64da0c48c4Sopenharmony_ci if (likely (mapped_size > H_END)) 65da0c48c4Sopenharmony_ci { 66da0c48c4Sopenharmony_ci const void *header = mapped; 67da0c48c4Sopenharmony_ci char header_buffer[H_READ_SIZE]; 68da0c48c4Sopenharmony_ci if (header == NULL) 69da0c48c4Sopenharmony_ci { 70da0c48c4Sopenharmony_ci ssize_t n = pread_retry (fd, header_buffer, H_READ_SIZE, 71da0c48c4Sopenharmony_ci *start_offset + H_START); 72da0c48c4Sopenharmony_ci if (n < 0) 73da0c48c4Sopenharmony_ci return DWFL_E_ERRNO; 74da0c48c4Sopenharmony_ci if (n < H_READ_SIZE) 75da0c48c4Sopenharmony_ci return DWFL_E_BADELF; 76da0c48c4Sopenharmony_ci 77da0c48c4Sopenharmony_ci header = header_buffer - H_START; 78da0c48c4Sopenharmony_ci } 79da0c48c4Sopenharmony_ci 80da0c48c4Sopenharmony_ci uint16_t magic1; 81da0c48c4Sopenharmony_ci uint32_t magic2; 82da0c48c4Sopenharmony_ci uint16_t version; 83da0c48c4Sopenharmony_ci memcpy (&magic1, header + H_MAGIC1, sizeof (uint16_t)); 84da0c48c4Sopenharmony_ci memcpy (&magic2, header + H_MAGIC2, sizeof (uint32_t)); 85da0c48c4Sopenharmony_ci memcpy (&version, header + H_VERSION, sizeof (uint16_t)); 86da0c48c4Sopenharmony_ci if (magic1 == LE16 (MAGIC1) && magic2 == LE32 (MAGIC2) 87da0c48c4Sopenharmony_ci && LE16 (version) >= MIN_VERSION) 88da0c48c4Sopenharmony_ci { 89da0c48c4Sopenharmony_ci /* The magic numbers match and the version field is sufficient. 90da0c48c4Sopenharmony_ci Extract the payload bounds. */ 91da0c48c4Sopenharmony_ci 92da0c48c4Sopenharmony_ci uint32_t offset; 93da0c48c4Sopenharmony_ci uint32_t length; 94da0c48c4Sopenharmony_ci uint8_t sects; 95da0c48c4Sopenharmony_ci memcpy (&offset, header + H_PAYLOAD_OFFSET, sizeof (uint32_t)); 96da0c48c4Sopenharmony_ci memcpy (&length, header + H_PAYLOAD_LENGTH, sizeof (uint32_t)); 97da0c48c4Sopenharmony_ci memcpy (§s, header + H_SETUP_SECTS, sizeof (uint8_t)); 98da0c48c4Sopenharmony_ci offset = LE32 (offset); 99da0c48c4Sopenharmony_ci length = LE32 (length); 100da0c48c4Sopenharmony_ci 101da0c48c4Sopenharmony_ci offset += ((sects ?: 4) + 1) * 512; 102da0c48c4Sopenharmony_ci 103da0c48c4Sopenharmony_ci if (offset > H_END && offset < mapped_size 104da0c48c4Sopenharmony_ci && mapped_size - offset >= length) 105da0c48c4Sopenharmony_ci { 106da0c48c4Sopenharmony_ci /* It looks kosher. Use it! */ 107da0c48c4Sopenharmony_ci *start_offset += offset; 108da0c48c4Sopenharmony_ci return DWFL_E_NOERROR; 109da0c48c4Sopenharmony_ci } 110da0c48c4Sopenharmony_ci } 111da0c48c4Sopenharmony_ci } 112da0c48c4Sopenharmony_ci return DWFL_E_BADELF; 113da0c48c4Sopenharmony_ci} 114