feat(ram): Add flat ELF loading capabilities (#485)
This adds the ELF format as an additional pre-loadable file format.
This commit is contained in:
parent
2047043435
commit
c1a64aec62
6
Makefile
6
Makefile
|
@ -166,6 +166,12 @@ else
|
|||
SIM_LDFLAGS += -lzstd
|
||||
endif
|
||||
|
||||
# Elf image support
|
||||
IMAGE_ELF ?= 1
|
||||
ifeq ($(IMAGE_ELF),0)
|
||||
SIM_CXXFLAGS += -DNO_IMAGE_ELF
|
||||
endif
|
||||
|
||||
# spike-dasm plugin
|
||||
WITH_SPIKE_DASM ?= 1
|
||||
ifeq ($(WITH_SPIKE_DASM),1)
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2024 Axelera AI
|
||||
*
|
||||
* DiffTest is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include "elfloader.h"
|
||||
|
||||
void ElfBinary::load() {
|
||||
assert(size >= sizeof(Elf64_Ehdr));
|
||||
eh64 = (const Elf64_Ehdr *)raw;
|
||||
assert(IS_ELF32(*eh64) || IS_ELF64(*eh64));
|
||||
|
||||
if (IS_ELF32(*eh64))
|
||||
parse(data32);
|
||||
else
|
||||
parse(data64);
|
||||
}
|
||||
|
||||
template <typename ehdr_t, typename phdr_t, typename shdr_t, typename sym_t>
|
||||
void ElfBinary::parse(ElfBinaryData<ehdr_t, phdr_t, shdr_t, sym_t> &data) {
|
||||
data.eh = (const ehdr_t *)raw;
|
||||
data.ph = (const phdr_t *)(raw + data.eh->e_phoff);
|
||||
entry = data.eh->e_entry;
|
||||
assert(size >= data.eh->e_phoff + data.eh->e_phnum * sizeof(*data.ph));
|
||||
for (unsigned i = 0; i < data.eh->e_phnum; i++) {
|
||||
if (data.ph[i].p_type == PT_LOAD && data.ph[i].p_memsz) {
|
||||
if (data.ph[i].p_filesz) {
|
||||
assert(size >= data.ph[i].p_offset + data.ph[i].p_filesz);
|
||||
sections.push_back({
|
||||
.data_src = (const uint8_t *)raw + data.ph[i].p_offset,
|
||||
.data_dst = data.ph[i].p_paddr,
|
||||
.data_len = data.ph[i].p_filesz,
|
||||
.zero_dst = data.ph[i].p_paddr + data.ph[i].p_filesz,
|
||||
.zero_len = data.ph[i].p_memsz - data.ph[i].p_filesz,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ElfBinaryFile::ElfBinaryFile(const char *filename) : filename(filename) {
|
||||
int fd = open(filename, O_RDONLY);
|
||||
struct stat s;
|
||||
assert(fd != -1);
|
||||
assert(fstat(fd, &s) >= 0);
|
||||
size = s.st_size;
|
||||
|
||||
raw = (uint8_t *)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
assert(raw != MAP_FAILED);
|
||||
close(fd);
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
ElfBinaryFile::~ElfBinaryFile() {
|
||||
if (raw)
|
||||
munmap((void *)raw, size);
|
||||
}
|
||||
|
||||
bool isElfFile(const char *filename) {
|
||||
int fd = -1;
|
||||
|
||||
#ifdef NO_IMAGE_ELF
|
||||
return false;
|
||||
#endif
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
assert(fd);
|
||||
|
||||
uint8_t buf[4];
|
||||
|
||||
size_t sz = read(fd, buf, 4);
|
||||
if (!IS_ELF(*((const Elf64_Ehdr *)buf))) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
long readFromElf(void *ptr, const char *file_name, long buf_size) {
|
||||
auto elf_file = ElfBinaryFile(file_name);
|
||||
|
||||
if (elf_file.sections.size() < 1) {
|
||||
printf("The requested elf '%s' contains zero sections\n", file_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t len_written = 0;
|
||||
auto base_addr = elf_file.sections[0].data_dst;
|
||||
|
||||
if (base_addr != PMEM_BASE) {
|
||||
printf(
|
||||
"The first address in the elf does not match the base of the physical memory. It is likely that execution "
|
||||
"leads to unexpected behaviour.");
|
||||
}
|
||||
|
||||
for (auto section: elf_file.sections) {
|
||||
auto len = section.data_len + section.zero_len;
|
||||
auto offset = section.data_dst - base_addr;
|
||||
|
||||
if (offset + len > buf_size) {
|
||||
printf("The size (%ld bytes) of the section at address 0x%lx is larger than buf_size!\n", len, section.data_dst);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Loading %ld bytes at address 0x%lx at offset 0x%lx\n", len, section.data_dst, offset);
|
||||
std::memset((uint8_t *)ptr + offset, 0, len);
|
||||
std::memcpy((uint8_t *)ptr + offset, section.data_src, section.data_len);
|
||||
len_written += len;
|
||||
}
|
||||
return len_written;
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2024 Axelera AI
|
||||
*
|
||||
* DiffTest is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#ifndef __ELFLOADER_H
|
||||
#define __ELFLOADER_H
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
#define IS_ELF(hdr) \
|
||||
((hdr).e_ident[0] == 0x7f && (hdr).e_ident[1] == 'E' && (hdr).e_ident[2] == 'L' && (hdr).e_ident[3] == 'F')
|
||||
|
||||
#define IS_ELF32(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 1)
|
||||
#define IS_ELF64(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 2)
|
||||
|
||||
#define PT_LOAD 1
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_PROGBITS 0x1
|
||||
#define SHT_GROUP 0x11
|
||||
|
||||
typedef struct {
|
||||
uint8_t e_ident[16];
|
||||
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;
|
||||
} Elf32_Ehdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t sh_name;
|
||||
uint32_t sh_type;
|
||||
uint32_t sh_flags;
|
||||
uint32_t sh_addr;
|
||||
uint32_t sh_offset;
|
||||
uint32_t sh_size;
|
||||
uint32_t sh_link;
|
||||
uint32_t sh_info;
|
||||
uint32_t sh_addralign;
|
||||
uint32_t sh_entsize;
|
||||
} Elf32_Shdr;
|
||||
|
||||
typedef struct {
|
||||
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;
|
||||
} Elf32_Phdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t st_name;
|
||||
uint32_t st_value;
|
||||
uint32_t st_size;
|
||||
uint8_t st_info;
|
||||
uint8_t st_other;
|
||||
uint16_t st_shndx;
|
||||
} Elf32_Sym;
|
||||
|
||||
typedef struct {
|
||||
uint8_t e_ident[16];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint64_t e_entry;
|
||||
uint64_t e_phoff;
|
||||
uint64_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;
|
||||
} Elf64_Ehdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t sh_name;
|
||||
uint32_t sh_type;
|
||||
uint64_t sh_flags;
|
||||
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;
|
||||
} Elf64_Shdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t p_type;
|
||||
uint32_t p_flags;
|
||||
uint64_t p_offset;
|
||||
uint64_t p_vaddr;
|
||||
uint64_t p_paddr;
|
||||
uint64_t p_filesz;
|
||||
uint64_t p_memsz;
|
||||
uint64_t p_align;
|
||||
} Elf64_Phdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t st_name;
|
||||
uint8_t st_info;
|
||||
uint8_t st_other;
|
||||
uint16_t st_shndx;
|
||||
uint64_t st_value;
|
||||
uint64_t st_size;
|
||||
} Elf64_Sym;
|
||||
|
||||
template <typename ehdr_t, typename phdr_t, typename shdr_t, typename sym_t> struct ElfBinaryData {
|
||||
const ehdr_t *eh = nullptr;
|
||||
const phdr_t *ph = nullptr;
|
||||
};
|
||||
|
||||
struct ElfSection {
|
||||
const uint8_t *data_src;
|
||||
uint64_t data_dst;
|
||||
size_t data_len;
|
||||
uint64_t zero_dst;
|
||||
size_t zero_len;
|
||||
};
|
||||
|
||||
struct ElfBinary {
|
||||
const uint8_t *raw = nullptr;
|
||||
size_t size = 0;
|
||||
|
||||
const Elf64_Ehdr *eh64 = nullptr;
|
||||
ElfBinaryData<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym> data32;
|
||||
ElfBinaryData<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym> data64;
|
||||
|
||||
uint64_t entry;
|
||||
std::vector<ElfSection> sections;
|
||||
|
||||
void load();
|
||||
|
||||
template <typename ehdr_t, typename phdr_t, typename shdr_t, typename sym_t>
|
||||
void parse(ElfBinaryData<ehdr_t, phdr_t, shdr_t, sym_t> &data);
|
||||
};
|
||||
|
||||
struct ElfBinaryFile : public ElfBinary {
|
||||
const std::string filename;
|
||||
|
||||
ElfBinaryFile(const char *filename);
|
||||
|
||||
~ElfBinaryFile();
|
||||
};
|
||||
|
||||
// Is the file at the given path an Elf file
|
||||
bool isElfFile(const char *filename);
|
||||
// load binary content at `file_name` into ptr. Returns the number of bytes
|
||||
// written.
|
||||
long readFromElf(void *ptr, const char *file_name, long buf_size);
|
||||
|
||||
#endif // __ELFLOADER_H
|
|
@ -17,6 +17,7 @@
|
|||
#include "ram.h"
|
||||
#include "common.h"
|
||||
#include "compress.h"
|
||||
#include "elfloader.h"
|
||||
#include <iostream>
|
||||
#include <sys/mman.h>
|
||||
#ifdef CONFIG_DIFFTEST_PERFCNT
|
||||
|
@ -284,6 +285,10 @@ MmapMemory::MmapMemory(const char *image, uint64_t n_bytes) : SimMemory(n_bytes)
|
|||
Info("Zstd file detected and loading image from extracted zstd file\n");
|
||||
img_size = readFromZstd(ram, image, memory_size, LOAD_RAM);
|
||||
assert(img_size >= 0);
|
||||
} else if (isElfFile(image)) {
|
||||
Info("ELF file detected and loading image from extracted elf file\n");
|
||||
img_size = readFromElf(ram, image, memory_size);
|
||||
assert(img_size >= 0);
|
||||
} else {
|
||||
InputReader *reader = createInputReader(image);
|
||||
img_size = reader->read_all(ram, memory_size);
|
||||
|
|
Loading…
Reference in New Issue