Initial commit

Added base code, can run ELF files and simulate RV32I instructions
This commit is contained in:
2023-10-04 21:28:18 +02:00
commit 981c35584c
17 changed files with 1280 additions and 0 deletions

101
src/bootloader/elf/elf.c Normal file
View File

@@ -0,0 +1,101 @@
#include "elf.h"
#include "memory/memory.h"
#include "vriscv.h"
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
uint32_t elf_32_load(void* file)
{
// Parse/verify the header
elf_header_32_t* header = file;
// Verify magic number
uint8_t* m = header->ELF;
if((m[0] != 0x7F) || (m[1] != 'E') || (m[2] != 'L') || (m[3] != 'F'))
{
fprintf(stderr, "Not a valid ELF file (wrong magic)\n");
exit(EXIT_FAILURE);
}
// Verify architecture
if(header->instruction_set != INSTRUCTION_SET_RISCV)
{
switch(header->instruction_set)
{
case INSTRUCTION_SET_X86:
fprintf(stderr, "Provided ELF file targets x86 ; perhaps you forgot to cross-compile ? Please provide a RISC-V ELF\n");
break;
case INSTRUCTION_SET_X86_64:
fprintf(stderr, "Provided ELF file targets x86_64; perhaps you forgot to cross-compile ? Please provide a RISC-V ELF\n");
break;
default:
fprintf(stderr, "Provided ELF file is for an unknown instruction set architecture (0x%x), please provide a RISC-V ELF\n", header->instruction_set);
break;
}
exit(EXIT_FAILURE);
}
// Verify bit count
if(header->bits != BITS_32)
{
switch(header->bits)
{
case BITS_64:
fprintf(stderr, "Provided ELF file targets RISC-V 64 bits ; please provide a 32-bits ELF\n");
break;
default:
fprintf(stderr, "Provided ELF file targets an unknown bit count (not 32 bits) ; please provide a 32-bits ELF\n");
break;
}
exit(EXIT_FAILURE);
}
// Verify endianness
if(header->endianness != ELF_LITTLE_ENDIAN)
{
fprintf(stderr, "Provided ELF file is encoded in big endian ; please provide a little endian ELF\n");
exit(EXIT_FAILURE);
}
// File should be correct ; now load it, using program header table
elf_program_header_32_t* program_header = (elf_program_header_32_t*) (((uint8_t*) file) + header->program_header_table_32);
size_t program_header_count = header->program_entry_amount;
for(size_t i = 0; i < program_header_count; i++)
{
elf_program_header_32_t current = program_header[i];
// Check segment type
if(current.segment_type != SEGMENT_TYPE_LOAD)
{
fprintf(stderr, "WARNING: Unknown segment type %u in ELF file ; skipping\n", current.segment_type);
continue;
}
// Check memory size
size_t memsz = current.segment_memory_size;
if(!memsz)
{
fprintf(stderr, "WARNING: LOAD segment with null size in ELF file ; skipping\n");
continue;
}
// Map the segment : first the part in the file, then the zeros
if(memory_size < (current.virtual_address + memsz))
{
fprintf(stderr, "FATAL: Not enough memory while loading ELF file\n");
exit(EXIT_FAILURE);
}
if(current.segment_file_size != 0)
{
memcpy(&memory[current.virtual_address], ((uint8_t*) file) + current.segment_offset, current.segment_file_size);
}
if(memsz > current.segment_file_size)
{
memset(&memory[current.virtual_address] + current.segment_file_size, 0, memsz - current.segment_file_size);
}
}
return header->entry_32;
}

83
src/bootloader/elf/elf.h Normal file
View File

@@ -0,0 +1,83 @@
#ifndef ELF_H
#define ELF_H
/*
* ELF handling
* Valentin HAUDIQUET
* Sources are :
* - https://refspecs.linuxfoundation.org/elf/elf.pdf (ELF Reference)
* - https://wiki.osdev.org/ELF (OSDev)
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
typedef struct ELF_HEADER_32
{
uint8_t ELF[4];
uint8_t bits; // 1 = 32bits, 2 = 64bits
uint8_t endianness; // 1 = little, 2 = big
uint8_t header_version;
uint8_t abi;
uint8_t padding0[8];
uint16_t exec_type; // 1 = relocatable, 2 = executable, 3 = shared, 4 = core
uint16_t instruction_set;
uint32_t elf_version;
uint32_t entry_32;
uint32_t program_header_table_32;
uint32_t section_table_32;
uint32_t flags;
uint16_t header_size;
uint16_t program_entry_size;
uint16_t program_entry_amount;
uint16_t section_entry_size;
uint16_t section_entry_amount;
uint16_t section_str_index; // Index of string table associated with section names
} __attribute__((packed)) elf_header_32_t;
#define ELF_LITTLE_ENDIAN 1
#define ELF_BIG_ENDIAN 2
#define BITS_32 1
#define BITS_64 2
#define INSTRUCTION_SET_X86 0x3
#define INSTRUCTION_SET_X86_64 0x3E
#define INSTRUCTION_SET_RISCV 0xF3
typedef struct ELF_SECTION_HEADER_32
{
uint16_t section_name;
uint16_t section_type;
uint16_t section_flags;
uint32_t section_addr_32;
uint32_t section_offset_32;
uint16_t section_size;
uint16_t section_link;
uint16_t section_info;
uint16_t section_addralign;
uint16_t section_entrysize;
} __attribute__((packed)) elf_section_header_32_t;
typedef struct ELF_PROGRAM_HEADER_32
{
uint32_t segment_type;
uint32_t segment_offset;
uint32_t virtual_address;
uint32_t undefined;
uint32_t segment_file_size;
uint32_t segment_memory_size;
uint32_t flags;
uint32_t align;
} __attribute__((packed)) elf_program_header_32_t;
#define SEGMENT_TYPE_NULL 0
#define SEGMENT_TYPE_LOAD 1
#define SEGMENT_TYPE_DYNAMIC 2
#define SEGMENT_TYPE_INTERP 3
#define SEGMENT_TYPE_NOTE 4
uint32_t elf_32_load(void* file);
#endif