Implement loading of test signatures
This commit is contained in:
parent
89d9ca3814
commit
40179ed237
6 changed files with 167 additions and 29 deletions
141
src/elf.cpp
141
src/elf.cpp
|
@ -57,29 +57,38 @@ struct Elf32Section {
|
||||||
uint32_t sh_entsize; // Entry size if section holds table
|
uint32_t sh_entsize; // Entry size if section holds table
|
||||||
};
|
};
|
||||||
|
|
||||||
bool should_load_section(const Elf32Section& section_header) {
|
struct Elf32Sym {
|
||||||
// Check if the section has the SHF_ALLOC flag, which indicates
|
uint32_t st_name; // Symbol name (index into string table)
|
||||||
// the section should be loaded into memory
|
uint32_t st_value; // Symbol value (address or offset)
|
||||||
if (section_header.sh_flags & SHF_ALLOC) {
|
uint32_t st_size; // Size of the symbol
|
||||||
// Further filter out sections that shouldn't be loaded
|
uint8_t st_info; // Symbol type and binding attributes
|
||||||
switch (section_header.sh_type) {
|
uint8_t st_other; // Symbol visibility
|
||||||
case SHT_PROGBITS: // Typically contains code or data
|
uint16_t st_shndx; // Section header index related to this symbol
|
||||||
case SHT_INIT_ARRAY: // Initialization function pointers
|
};
|
||||||
case SHT_FINI_ARRAY: // Termination function pointers
|
|
||||||
case SHT_NOBITS: // .bss section (uninitialized data)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Exclude debug and other non-loadable sections
|
bool should_load_section(const Elf32Section& section_header) {
|
||||||
case SHT_SYMTAB: // Symbol table
|
// Check if the section has the SHF_ALLOC flag, which indicates
|
||||||
case SHT_STRTAB: // String table
|
// the section should be loaded into memory
|
||||||
case SHT_RELA: // Relocation entries
|
if (section_header.sh_flags & SHF_ALLOC) {
|
||||||
case SHT_DYNAMIC: // Dynamic linking information
|
// Further filter out sections that shouldn't be loaded
|
||||||
case SHT_NOTE: // Note section
|
switch (section_header.sh_type) {
|
||||||
default:
|
case SHT_PROGBITS: // Typically contains code or data
|
||||||
return false;
|
case SHT_INIT_ARRAY: // Initialization function pointers
|
||||||
}
|
case SHT_FINI_ARRAY: // Termination function pointers
|
||||||
|
case SHT_NOBITS: // .bss section (uninitialized data)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Exclude debug and other non-loadable sections
|
||||||
|
case SHT_SYMTAB: // Symbol table
|
||||||
|
case SHT_STRTAB: // String table
|
||||||
|
case SHT_RELA: // Relocation entries
|
||||||
|
case SHT_DYNAMIC: // Dynamic linking information
|
||||||
|
case SHT_NOTE: // Note section
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> load_elf(const std::string& filename, size_t memory_size) {
|
std::vector<uint8_t> load_elf(const std::string& filename, size_t memory_size) {
|
||||||
|
@ -143,7 +152,7 @@ std::vector<uint8_t> load_elf(const std::string& filename, size_t memory_size) {
|
||||||
throw std::runtime_error("No loadable sections found");
|
throw std::runtime_error("No loadable sections found");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> loadedData(memoryEnd-memoryStart, 0);
|
std::vector<uint8_t> loadedData(memoryEnd - memoryStart, 0);
|
||||||
|
|
||||||
// Load .text and .sdata sections
|
// Load .text and .sdata sections
|
||||||
for (const Elf32Section& shdr : sectionHeaders) {
|
for (const Elf32Section& shdr : sectionHeaders) {
|
||||||
|
@ -153,8 +162,9 @@ std::vector<uint8_t> load_elf(const std::string& filename, size_t memory_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
file.seekg(shdr.sh_offset);
|
file.seekg(shdr.sh_offset);
|
||||||
file.read(reinterpret_cast<char*>(&loadedData[shdr.sh_addr-memoryStart]),
|
file.read(
|
||||||
shdr.sh_size);
|
reinterpret_cast<char*>(&loadedData[shdr.sh_addr - memoryStart]),
|
||||||
|
shdr.sh_size);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw std::runtime_error("Failed to read section data");
|
throw std::runtime_error("Failed to read section data");
|
||||||
}
|
}
|
||||||
|
@ -163,3 +173,86 @@ std::vector<uint8_t> load_elf(const std::string& filename, size_t memory_size) {
|
||||||
|
|
||||||
return loadedData;
|
return loadedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::tuple<uint32_t, uint32_t> elf_get_signature(const std::string& filename) {
|
||||||
|
std::ifstream file(filename, std::ios::binary);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
throw std::runtime_error("Failed to open ELF file");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the ELF header
|
||||||
|
Elf32Header ehdr;
|
||||||
|
file.read(reinterpret_cast<char*>(&ehdr), sizeof(ehdr));
|
||||||
|
if (!file) {
|
||||||
|
throw std::runtime_error("Failed to read ELF header");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate ELF magic and basic properties
|
||||||
|
if (std::memcmp(ehdr.e_ident, ELF_MAGIC, sizeof(ELF_MAGIC)) != 0) {
|
||||||
|
throw std::runtime_error("Invalid ELF magic number");
|
||||||
|
}
|
||||||
|
if (ehdr.e_ident[4] != ELF_CLASS_32 || ehdr.e_ident[5] != ELF_LITTLE_ENDIAN) {
|
||||||
|
throw std::runtime_error("Unsupported ELF class or endianness");
|
||||||
|
}
|
||||||
|
if (ehdr.e_type != ELF_TYPE_EXECUTABLE ||
|
||||||
|
ehdr.e_machine != ELF_MACHINE_RISCV) {
|
||||||
|
throw std::runtime_error("Unsupported ELF type or machine");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read section headers
|
||||||
|
file.seekg(ehdr.e_shoff);
|
||||||
|
std::vector<Elf32Section> sectionHeaders(ehdr.e_shnum);
|
||||||
|
for (size_t i = 0; i < ehdr.e_shnum; ++i) {
|
||||||
|
file.read(reinterpret_cast<char*>(§ionHeaders[i]),
|
||||||
|
sizeof(Elf32Section));
|
||||||
|
if (!file) {
|
||||||
|
throw std::runtime_error("Failed to read section headers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load symbols
|
||||||
|
std::vector<Elf32Sym> sectionSymTable;
|
||||||
|
std::vector<char> sectionStrTable;
|
||||||
|
|
||||||
|
for (const Elf32Section& shdr : sectionHeaders) {
|
||||||
|
if (shdr.sh_type == SHT_SYMTAB) {
|
||||||
|
size_t symbol_count = shdr.sh_size / shdr.sh_entsize;
|
||||||
|
sectionSymTable = std::vector<Elf32Sym>(symbol_count);
|
||||||
|
|
||||||
|
file.seekg(shdr.sh_offset);
|
||||||
|
file.read(reinterpret_cast<char*>(sectionSymTable.data()), shdr.sh_size);
|
||||||
|
if (!file) {
|
||||||
|
throw std::runtime_error("Failed to read section symbol table");
|
||||||
|
}
|
||||||
|
|
||||||
|
const Elf32Section& strtab_shdr = sectionHeaders[shdr.sh_link];
|
||||||
|
|
||||||
|
sectionStrTable = std::vector<char>(strtab_shdr.sh_size);
|
||||||
|
file.seekg(strtab_shdr.sh_offset);
|
||||||
|
file.read(sectionStrTable.data(), strtab_shdr.sh_size);
|
||||||
|
if (!file) {
|
||||||
|
throw std::runtime_error("Failed to read section symbol string table");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t begin_signature = 0;
|
||||||
|
uint32_t end_signature = 0;
|
||||||
|
|
||||||
|
for (const Elf32Sym sym : sectionSymTable) {
|
||||||
|
const char* name = §ionStrTable[sym.st_name];
|
||||||
|
|
||||||
|
if (std::strcmp(name, "begin_signature") == 0) {
|
||||||
|
begin_signature = sym.st_value;
|
||||||
|
}
|
||||||
|
if (std::strcmp(name, "end_signature") == 0) {
|
||||||
|
end_signature = sym.st_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end_signature == 0 || begin_signature >= end_signature) {
|
||||||
|
return std::make_tuple<uint32_t, uint32_t>(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_tuple(begin_signature, end_signature);
|
||||||
|
}
|
||||||
|
|
|
@ -5,3 +5,5 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
std::vector<uint8_t> load_elf(const std::string& filename, size_t memory_size);
|
std::vector<uint8_t> load_elf(const std::string& filename, size_t memory_size);
|
||||||
|
|
||||||
|
std::tuple<uint32_t, uint32_t> elf_get_signature(const std::string& filename);
|
||||||
|
|
40
src/rve.cpp
40
src/rve.cpp
|
@ -14,12 +14,19 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
bool debug = false;
|
bool debug = false;
|
||||||
std::string program_filename = "";
|
std::string program_filename = "";
|
||||||
|
std::string signature_filename = "";
|
||||||
|
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (int i = 1; i < argc; ++i) {
|
||||||
if (std::string(argv[i]) == "--debug")
|
if (std::string(argv[i]) == "--debug") {
|
||||||
debug = true;
|
debug = true;
|
||||||
else
|
} else if (std::string(argv[i]) == "--signature") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
signature_filename = argv[i + 1];
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
program_filename = std::filesystem::absolute(argv[i]);
|
program_filename = std::filesystem::absolute(argv[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (program_filename == "") {
|
if (program_filename == "") {
|
||||||
std::cerr << "Expected filename of program to execute" << std::endl;
|
std::cerr << "Expected filename of program to execute" << std::endl;
|
||||||
|
@ -27,14 +34,17 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> memory;
|
std::vector<uint8_t> memory;
|
||||||
|
std::tuple<uint32_t, uint32_t> signature;
|
||||||
try {
|
try {
|
||||||
memory = load_elf(program_filename, MEMORY_SIZE);
|
memory = load_elf(program_filename, MEMORY_SIZE);
|
||||||
|
|
||||||
|
signature = elf_get_signature(program_filename);
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cerr << e.what() << std::endl;
|
std::cerr << e.what() << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memory.resize(MEMORY_SIZE, 0);
|
memory.resize(std::max(memory.size(), MEMORY_SIZE), 0);
|
||||||
|
|
||||||
VM vm(memory, program_filename);
|
VM vm(memory, program_filename);
|
||||||
|
|
||||||
|
@ -46,6 +56,30 @@ int main(int argc, char *argv[]) {
|
||||||
std::cerr << "Emulator error: " << e.what() << std::endl;
|
std::cerr << "Emulator error: " << e.what() << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (signature_filename.size() > 0) {
|
||||||
|
uint32_t signature_begin = std::get<0>(signature) + 4;
|
||||||
|
uint32_t signature_end = std::get<1>(signature);
|
||||||
|
|
||||||
|
std::vector<uint8_t> mem =
|
||||||
|
vm.read_memory(signature_begin, signature_end - signature_begin);
|
||||||
|
|
||||||
|
std::ofstream file(signature_filename);
|
||||||
|
if (!file) {
|
||||||
|
throw std::runtime_error("Failed to open signature file for writing");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mem.size() / 4; i++) {
|
||||||
|
uint32_t val = *reinterpret_cast<uint32_t *>(&mem[i * 4]);
|
||||||
|
file << std::hex << std::setfill('0') << std::setw(8) << val << std::dec
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
if (!file) {
|
||||||
|
throw std::runtime_error("Error occurred while writing to file");
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// to debug, do: "set debug remote 1" in gdb
|
// to debug, do: "set debug remote 1" in gdb
|
||||||
// and then "target remote :1234"
|
// and then "target remote :1234"
|
||||||
|
|
|
@ -47,6 +47,7 @@ void VM::setreg(int regnum, uint32_t value) {
|
||||||
|
|
||||||
std::vector<uint8_t> VM::read_memory(size_t start, size_t size) {
|
std::vector<uint8_t> VM::read_memory(size_t start, size_t size) {
|
||||||
if (start >= PROGRAM_ADDR) {
|
if (start >= PROGRAM_ADDR) {
|
||||||
|
start -= PROGRAM_ADDR;
|
||||||
if (start + size > memory_.size()) {
|
if (start + size > memory_.size()) {
|
||||||
return std::vector<uint8_t>(size, 0);
|
return std::vector<uint8_t>(size, 0);
|
||||||
}
|
}
|
||||||
|
@ -172,6 +173,13 @@ void VM::step() {
|
||||||
int32_t imm;
|
int32_t imm;
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
|
case 0x0F: {
|
||||||
|
if (instr == 0xff0000f) { // fence iorw, iorw
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Unknown fence instruction");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 0x33: { // R-type
|
case 0x33: { // R-type
|
||||||
if (funct7 == 0x00) {
|
if (funct7 == 0x00) {
|
||||||
if (funct3 == 0x0) { // ADD
|
if (funct3 == 0x0) { // ADD
|
||||||
|
|
3
test/rve/env/model_test.h
vendored
3
test/rve/env/model_test.h
vendored
|
@ -15,6 +15,7 @@
|
||||||
li x1, 1; \
|
li x1, 1; \
|
||||||
write_tohost: \
|
write_tohost: \
|
||||||
sw x1, tohost, t5; \
|
sw x1, tohost, t5; \
|
||||||
|
ebreak
|
||||||
j write_tohost;
|
j write_tohost;
|
||||||
|
|
||||||
#define RVMODEL_BOOT
|
#define RVMODEL_BOOT
|
||||||
|
@ -28,7 +29,7 @@
|
||||||
//RV_COMPLIANCE_DATA_END
|
//RV_COMPLIANCE_DATA_END
|
||||||
#define RVMODEL_DATA_END \
|
#define RVMODEL_DATA_END \
|
||||||
.align 4;\
|
.align 4;\
|
||||||
.global end_signature; end_signature:
|
.global end_signature; end_signature:
|
||||||
|
|
||||||
//RVTEST_IO_INIT
|
//RVTEST_IO_INIT
|
||||||
#define RVMODEL_IO_INIT
|
#define RVMODEL_IO_INIT
|
||||||
|
|
|
@ -145,7 +145,7 @@ class rve(pluginTemplate):
|
||||||
# echo statement.
|
# echo statement.
|
||||||
if self.target_run:
|
if self.target_run:
|
||||||
# set up the simulation command. Template is for spike. Please change.
|
# set up the simulation command. Template is for spike. Please change.
|
||||||
simcmd = self.dut_exe + ' {0}'.format(elf)
|
simcmd = self.dut_exe + ' --signature {0} {1}'.format(sig_file, elf)
|
||||||
else:
|
else:
|
||||||
simcmd = 'echo "NO RUN"'
|
simcmd = 'echo "NO RUN"'
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue