stuff
This commit is contained in:
BIN
TTOS/.DS_Store
vendored
Normal file
BIN
TTOS/.DS_Store
vendored
Normal file
Binary file not shown.
232
TTOS/include/elf.h
Normal file
232
TTOS/include/elf.h
Normal file
@@ -0,0 +1,232 @@
|
||||
#ifndef _ELF_H
|
||||
#define _ELF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "errorCode.h"
|
||||
|
||||
/* https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html */
|
||||
|
||||
/* ELF Data Types */
|
||||
typedef uint32_t Elf32_Addr;
|
||||
typedef uint32_t Elf32_Off;
|
||||
typedef uint16_t Elf32_Half;
|
||||
typedef uint32_t Elf32_Word;
|
||||
typedef int32_t Elf32_Sword;
|
||||
|
||||
typedef uint64_t Elf64_Addr;
|
||||
typedef uint64_t Elf64_Off;
|
||||
typedef uint16_t Elf64_Half;
|
||||
typedef uint32_t Elf64_Word;
|
||||
typedef int32_t Elf64_Sword;
|
||||
typedef uint64_t Elf64_Xword;
|
||||
typedef int64_t Elf64_Sxword;
|
||||
|
||||
/* ELF Magic */
|
||||
#define ELFMAG0 0x7f
|
||||
#define ELFMAG1 'E'
|
||||
#define ELFMAG2 'L'
|
||||
#define ELFMAG3 'F'
|
||||
|
||||
/* Class */
|
||||
#define ELFCLASSNONE 0
|
||||
#define ELFCLASS32 1
|
||||
#define ELFCLASS64 2
|
||||
|
||||
/* Data encoding */
|
||||
#define ELFDATANONE 0
|
||||
#define ELFDATA2LSB 1
|
||||
#define ELFDATA2MSB 2
|
||||
|
||||
/* Version */
|
||||
#define EV_NONE 0
|
||||
#define EV_CURRENT 1
|
||||
|
||||
/* Type */
|
||||
#define ET_NONE 0
|
||||
#define ET_REL 1
|
||||
#define ET_EXEC 2
|
||||
#define ET_DYN 3
|
||||
#define ET_CORE 4
|
||||
#define ET_LOOS 0xfe00
|
||||
#define ET_HIOS 0xfeff
|
||||
#define ET_LOPROC 0xff00
|
||||
#define ET_HIPROC 0xffff
|
||||
|
||||
#define EI_NIDENT 16
|
||||
|
||||
typedef struct {
|
||||
uint8_t e_ident[EI_NIDENT];
|
||||
Elf64_Half e_type;
|
||||
Elf64_Half e_machine;
|
||||
Elf64_Word e_version;
|
||||
Elf64_Addr e_entry;
|
||||
Elf64_Off e_phoff;
|
||||
Elf64_Off e_shoff;
|
||||
Elf64_Word e_flags;
|
||||
Elf64_Half e_ehsize;
|
||||
Elf64_Half e_phentsize;
|
||||
Elf64_Half e_phnum;
|
||||
Elf64_Half e_shentsize;
|
||||
Elf64_Half e_shnum;
|
||||
Elf64_Half e_shstrndx;
|
||||
} Elf64_Ehdr;
|
||||
|
||||
/* Program header types */
|
||||
#define PT_NULL 0
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define PT_INTERP 3
|
||||
#define PT_NOTE 4
|
||||
#define PT_SHLIB 5
|
||||
#define PT_PHDR 6
|
||||
#define PT_TLS 7
|
||||
#define PT_LOOS 0x60000000
|
||||
#define PT_HIOS 0x6fffffff
|
||||
#define PT_LOPROC 0x70000000
|
||||
#define PT_HIPROC 0x7fffffff
|
||||
|
||||
typedef struct {
|
||||
Elf64_Word p_type;
|
||||
Elf64_Word p_flags;
|
||||
Elf64_Off p_offset;
|
||||
Elf64_Addr p_vaddr;
|
||||
Elf64_Addr p_paddr;
|
||||
Elf64_Xword p_filesz;
|
||||
Elf64_Xword p_memsz;
|
||||
Elf64_Xword p_align;
|
||||
} Elf64_Phdr;
|
||||
|
||||
/* Section header type */
|
||||
#define SHT_NULL 0
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_HASH 5
|
||||
#define SHT_DYNAMIC 6
|
||||
#define SHT_NOTE 7
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
#define SHT_SHLIB 10
|
||||
#define SHT_DYNSYM 11
|
||||
#define SHT_INIT_ARRAY 14
|
||||
#define SHT_FINI_ARRAY 15
|
||||
#define SHT_PREINIT_ARRAY 16
|
||||
#define SHT_GROUP 17
|
||||
#define SHT_SYMTAB_SHNDX 18
|
||||
#define SHT_LOOS 0x60000000
|
||||
#define SHT_HIOS 0x6fffffff
|
||||
#define SHT_LOPROC 0x70000000
|
||||
#define SHT_HIPROC 0x7fffffff
|
||||
#define SHT_LOUSER 0x80000000
|
||||
#define SHT_HIUSER 0xffffffff
|
||||
|
||||
/* Section header name index */
|
||||
#define SHN_UNDEF 0
|
||||
#define SHN_LORESERVE 0xff00
|
||||
#define SHN_LOPROC 0xff00
|
||||
#define SHN_HIPROC 0xff1f
|
||||
#define SHN_ABS 0xfff1
|
||||
#define SHN_COMMON 0xfff2
|
||||
#define SHN_HIRESERVE 0xffff
|
||||
|
||||
/* Section header flags */
|
||||
#define SHF_WRITE 0x1
|
||||
#define SHF_ALLOC 0x2
|
||||
#define SHF_EXECINSTR 0x4
|
||||
#define SHF_MERGE 0x10
|
||||
#define SHF_STRINGS 0x20
|
||||
#define SHF_INFO_LINK 0x40
|
||||
#define SHF_LINK_ORDER 0x80
|
||||
#define SHF_OS_NONCONFORMING 0x100
|
||||
#define SHF_GROUP 0x200
|
||||
#define SHF_TLS 0x400
|
||||
#define SHF_MASKOS 0x0ff00000
|
||||
#define SHF_MASKPROC 0xf0000000
|
||||
|
||||
typedef struct {
|
||||
Elf64_Word sh_name;
|
||||
Elf64_Word sh_type;
|
||||
Elf64_Xword sh_flags;
|
||||
Elf64_Addr sh_addr;
|
||||
Elf64_Off sh_offset;
|
||||
Elf64_Xword sh_size;
|
||||
Elf64_Word sh_link;
|
||||
Elf64_Word sh_info;
|
||||
Elf64_Xword sh_addralign;
|
||||
Elf64_Xword sh_entsize;
|
||||
} Elf64_Shdr;
|
||||
|
||||
/* Symbol table index values */
|
||||
#define STN_UNDEF 0
|
||||
|
||||
typedef struct {
|
||||
Elf64_Word st_name;
|
||||
uint8_t st_info;
|
||||
uint8_t st_other;
|
||||
Elf64_Half st_shndx;
|
||||
Elf64_Addr st_value;
|
||||
Elf64_Xword st_size;
|
||||
} Elf64_Sym;
|
||||
|
||||
typedef struct {
|
||||
Elf64_Addr r_offset;
|
||||
Elf64_Xword r_info;
|
||||
} Elf64_Rel;
|
||||
|
||||
typedef struct {
|
||||
Elf64_Addr r_offset;
|
||||
Elf64_Xword r_info;
|
||||
Elf64_Sxword r_addend;
|
||||
} Elf64_Rela;
|
||||
|
||||
#define R_X86_64_NONE 0
|
||||
#define R_X86_64_64 1
|
||||
#define R_X86_64_PC32 2
|
||||
#define R_X86_64_GOT32 3
|
||||
#define R_X86_64_PLT32 4
|
||||
#define R_X86_64_COPY 5
|
||||
#define R_X86_64_GLOB_DAT 6
|
||||
#define R_X86_64_JUMP_SLOT 7
|
||||
#define R_X86_64_RELATIVE 8
|
||||
#define R_X86_64_GOTPCREL 9
|
||||
#define R_X86_64_32 10
|
||||
#define R_X86_64_32S 11
|
||||
#define R_X86_64_16 12
|
||||
#define R_X86_64_PC16 13
|
||||
#define R_X86_64_8 14
|
||||
#define R_X86_64_PC8 15
|
||||
#define R_X86_64_DPTMOD64 16
|
||||
#define R_X86_64_DTPOFF64 17
|
||||
#define R_X86_64_TPOFF64 18
|
||||
#define R_X86_64_TLSGD 19
|
||||
#define R_X86_64_TLSLD 20
|
||||
#define R_X86_64_DTPOFF32 21
|
||||
#define R_X86_64_GOTTPOFF 22
|
||||
#define R_X86_64_TPOFF32 23
|
||||
#define R_X86_64_PC64 24
|
||||
#define R_X86_64_GOTOFF64 25
|
||||
#define R_X86_64_GOTPC32 26
|
||||
#define R_X86_64_SIZE32 32
|
||||
#define R_X86_64_SIZE64 33
|
||||
|
||||
#define ELF64_R_SYM(i) ((i)>>32)
|
||||
#define ELF64_R_TYPE(i) ((i)&0xffffffffL)
|
||||
#define ELF64_R_INFO(s,t) (((s)<<32)+((t)&0xffffffffL))
|
||||
|
||||
typedef struct elf_file {
|
||||
int size;
|
||||
void* contents;
|
||||
Elf64_Ehdr* ehdr;
|
||||
Elf64_Phdr* phdr;
|
||||
Elf64_Shdr* shdr;
|
||||
} elf_file;
|
||||
|
||||
errorCode_t load_elf(const char* filename, elf_file* file);
|
||||
errorCode_t get_elf_proc_size(elf_file* file, uint64_t* size);
|
||||
errorCode_t populate_elf_proc(elf_file* file, void* tgt_addr);
|
||||
errorCode_t find_symbol(elf_file* file, const char* name, uint64_t* offset);
|
||||
errorCode_t free_elf(elf_file* file);
|
||||
|
||||
#endif
|
||||
15
TTOS/include/errorCode.h
Normal file
15
TTOS/include/errorCode.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _ERRORCODE_H
|
||||
#define _ERRORCODE_H
|
||||
|
||||
typedef int errorCode_t;
|
||||
|
||||
#define IS_ERROR(n) (n < SUCCESS)
|
||||
|
||||
#define SUCCESS 0
|
||||
#define EBADPARM -1
|
||||
#define ENOTFOUND -2
|
||||
#define EBADEXEC -3
|
||||
#define EMEMORY -4
|
||||
#define EFILESYS -5
|
||||
|
||||
#endif
|
||||
22
TTOS/include/fs/fs.h
Normal file
22
TTOS/include/fs/fs.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef _FS_H
|
||||
#define _FS_H
|
||||
|
||||
#include "errorCode.h"
|
||||
|
||||
/* fs_open flags */
|
||||
#define O_RDONLY 00000000
|
||||
#define O_WRONLY 00000001
|
||||
#define O_RDWR 00000002
|
||||
|
||||
/* fs_seek whence */
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_CUR 1
|
||||
#define SEEK_END 2
|
||||
|
||||
errorCode_t fs_open(const char* path, int flags, int* fd);
|
||||
errorCode_t fs_write(int fd, const void *buf, int count, int* bytes_written);
|
||||
errorCode_t fs_read(int fd, void *buf, int count, int* bytes_read);
|
||||
errorCode_t fs_seek(int fd, int offset, int whence, int* distance);
|
||||
errorCode_t fs_close(int fd);
|
||||
|
||||
#endif
|
||||
15
TTOS/include/memory.h
Normal file
15
TTOS/include/memory.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _MEMORY_H
|
||||
#define _MEMORY_H
|
||||
|
||||
#include "errorCode.h"
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_ALIGN(n) (n + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1)
|
||||
|
||||
errorCode_t allocate_user_memory(int size, void** addr);
|
||||
errorCode_t free_user_memory(void* addr, int size);
|
||||
|
||||
errorCode_t get_kernel_memory(int size, void** addr);
|
||||
errorCode_t free_kernel_memory(void* addr, int size);
|
||||
|
||||
#endif
|
||||
19
TTOS/include/process.h
Normal file
19
TTOS/include/process.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef _PROCESS_H
|
||||
#define _PROCESS_H
|
||||
|
||||
#define STACK_SIZE 8192
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
typedef struct process {
|
||||
void* entry_point;
|
||||
void* exec_start;
|
||||
void* stack_start;
|
||||
void* stack_end;
|
||||
int size;
|
||||
} process;
|
||||
|
||||
errorCode_t create_process(const char* file, process* proc);
|
||||
errorCode_t free_process(process* proc);
|
||||
|
||||
#endif
|
||||
6
TTOS/include/syscall.h
Normal file
6
TTOS/include/syscall.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef _SYSCALL_H
|
||||
#define _SYSCALL_H
|
||||
|
||||
long system_call(long n, ...);
|
||||
|
||||
#endif
|
||||
5
TTOS/ld.script
Normal file
5
TTOS/ld.script
Normal file
@@ -0,0 +1,5 @@
|
||||
ENTRY(main)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x000000; /* Image starts here */
|
||||
}
|
||||
16
TTOS/makefile
Normal file
16
TTOS/makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
CC=gcc
|
||||
CFLAGS=-g -Wall -Iinclude
|
||||
LFLAGS=
|
||||
|
||||
OBJS=$(patsubst %.c,%.o,$(wildcard src/*.c)) $(patsubst %.c,%.o,$(wildcard src/fs/*.c))
|
||||
|
||||
all: ttos
|
||||
|
||||
ttos: $(OBJS)
|
||||
$(CC) $(LFLAGS) -o ttos $(OBJS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) ttos
|
||||
307
TTOS/src/elf.c
Normal file
307
TTOS/src/elf.c
Normal file
@@ -0,0 +1,307 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "fs/fs.h"
|
||||
#include "syscall.h"
|
||||
#include "elf.h"
|
||||
#include "process.h"
|
||||
#include "memory.h"
|
||||
|
||||
static int validate_magic(uint8_t e_ident[EI_NIDENT]) {
|
||||
// ELF Magic must match
|
||||
if(e_ident[0] != ELFMAG0 || e_ident[1] != ELFMAG1 || e_ident[2] != ELFMAG2 || e_ident[3] != ELFMAG3) {
|
||||
return -1;
|
||||
}
|
||||
// Currently, only support 64 bit executables
|
||||
if(e_ident[4] != ELFCLASS64) {
|
||||
return -1;
|
||||
}
|
||||
// Currently, only support LSB byte order executables
|
||||
if(e_ident[5] != ELFDATA2LSB) {
|
||||
return -1;
|
||||
}
|
||||
// Currently, only support ELF current version
|
||||
if(e_ident[6] != EV_CURRENT) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errorCode_t get_file_data(const char* path, elf_file* file) {
|
||||
int rc;
|
||||
|
||||
// Open the file
|
||||
int fd = 0;
|
||||
rc = fs_open(path, O_RDONLY, &fd);
|
||||
if(IS_ERROR(rc)) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Seek to the beginning and then the end
|
||||
// to get the file size
|
||||
fs_seek(fd, 0, SEEK_SET, 0);
|
||||
rc = fs_seek(fd, 0, SEEK_END, &file->size);
|
||||
if(IS_ERROR(file->size) || file->size == 0) {
|
||||
return EBADEXEC;
|
||||
}
|
||||
|
||||
rc = get_kernel_memory(file->size, &file->contents);
|
||||
if(IS_ERROR(rc)) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Seek to the beginning and read the file data
|
||||
fs_seek(fd, 0, SEEK_SET, 0);
|
||||
int bytes_read = 0;
|
||||
rc = fs_read(fd, file->contents, file->size, &bytes_read);
|
||||
|
||||
// Check error if error use error code if one was returned
|
||||
if(IS_ERROR(rc)) {
|
||||
free_kernel_memory(file->contents, file->size);
|
||||
fs_close(fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Check error ELIBBAD if data read != size
|
||||
if(bytes_read != file->size) {
|
||||
free_kernel_memory(file->contents, file->size);
|
||||
fs_close(fd);
|
||||
return EBADEXEC;
|
||||
}
|
||||
|
||||
// Close the file and return
|
||||
fs_close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Elf64_Phdr* get_program_header(elf_file* file, int index) {
|
||||
return (Elf64_Phdr*)((char*)file->phdr + index * file->ehdr->e_phentsize);
|
||||
}
|
||||
|
||||
static Elf64_Shdr* get_section_header(elf_file* file, int index) {
|
||||
return (Elf64_Shdr*)((char*)file->shdr + index * file->ehdr->e_shentsize);
|
||||
}
|
||||
|
||||
static void* find_external_symbol(elf_file* file, Elf64_Shdr *symtbl_shdr, Elf64_Word st_name) {
|
||||
|
||||
if(symtbl_shdr->sh_link == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Elf64_Shdr* strtbl_hdr = get_section_header(file, symtbl_shdr->sh_link);
|
||||
char* strtbl = (char*)((uint8_t*)file->contents + strtbl_hdr->sh_offset);
|
||||
char* symbol_name = &(strtbl[st_name]);
|
||||
|
||||
if(strncmp(symbol_name, "system_call", 7) == 0) {
|
||||
return system_call;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errorCode_t relocate_symbols(elf_file* file, void* tgt_addr) {
|
||||
|
||||
for(int i = 0; i < file->ehdr->e_shnum; i++) {
|
||||
|
||||
Elf64_Shdr* shdr = get_section_header(file, i);
|
||||
|
||||
if(shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
|
||||
|
||||
// Retrieve the sections headers for the relocation section, linked symbol table, and target section
|
||||
Elf64_Shdr* rel_shdr = shdr;
|
||||
Elf64_Shdr *symtbl_shdr = get_section_header(file, rel_shdr->sh_link);
|
||||
Elf64_Shdr *tgt_shdr = get_section_header(file, rel_shdr->sh_info);
|
||||
|
||||
// Retrieve the linked symbol table
|
||||
Elf64_Sym* symtbl = (Elf64_Sym*)((uint8_t*)file->contents + symtbl_shdr->sh_offset);
|
||||
|
||||
// Loop through each relocation entry and update the target
|
||||
int entry_count = rel_shdr->sh_size / rel_shdr->sh_entsize;
|
||||
for (int j = 0; j < entry_count; j++) {
|
||||
|
||||
Elf64_Rela* relhdr = (Elf64_Rela*)((uint8_t*)file->contents + rel_shdr->sh_offset + j*rel_shdr->sh_entsize);
|
||||
Elf64_Xword symbol = ELF64_R_SYM(relhdr->r_info);
|
||||
Elf64_Xword type = ELF64_R_TYPE(relhdr->r_info);
|
||||
|
||||
// Symbol address
|
||||
// For relocatable files - start of the exec + offset to the section containing the symbol + offset to the symbol in the section (aka symbol value)
|
||||
// For all other files - start of the exec + symbol value (aka virtual address)
|
||||
// For undefined symbols - search for the symbol externally
|
||||
void* symbol_address = 0;
|
||||
if(file->ehdr->e_type == ET_REL) {
|
||||
symbol_address = (void*)((uint8_t*)tgt_addr + file->shdr[symtbl[symbol].st_shndx].sh_offset + symtbl[symbol].st_value);
|
||||
} else if(symtbl[symbol].st_shndx == STN_UNDEF) {
|
||||
symbol_address = find_external_symbol(file, symtbl_shdr, symtbl[symbol].st_name);
|
||||
} else {
|
||||
symbol_address = (void*)((uint8_t*)tgt_addr + symtbl[symbol].st_value);
|
||||
}
|
||||
if(symbol_address == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Location in section to patch
|
||||
// For relocatable files - start of exec + offset to patch section + offset in the section
|
||||
// For all other files - start of the exec + relocation offset value (aka virtual address)
|
||||
void* patch_location = file->ehdr->e_type == ET_REL ?
|
||||
(void*)((uint8_t*)tgt_addr + tgt_shdr->sh_offset + relhdr->r_offset) :
|
||||
(void*)((uint8_t*)tgt_addr + relhdr->r_offset);
|
||||
|
||||
// retrieve the addend, only applies to RELA entries
|
||||
Elf64_Sxword addend = file->shdr[i].sh_type == SHT_RELA ? relhdr->r_addend : 0;
|
||||
|
||||
// https://refspecs.linuxbase.org/elf/x86_64-abi-0.98.pdf page 69
|
||||
switch(type) {
|
||||
case R_X86_64_PC8:
|
||||
*(uint8_t*)patch_location = (uint8_t*)symbol_address + addend - (uint8_t*)patch_location;
|
||||
break;
|
||||
case R_X86_64_PC16:
|
||||
*(uint16_t*)patch_location = (uint8_t*)symbol_address + addend - (uint8_t*)patch_location;
|
||||
case R_X86_64_PC32:
|
||||
case R_X86_64_PLT32:
|
||||
*(uint32_t*)patch_location = (uint8_t*)symbol_address + addend - (uint8_t*)patch_location;
|
||||
break;
|
||||
case R_X86_64_PC64:
|
||||
*(uint64_t*)patch_location = (uint8_t*)symbol_address + addend - (uint8_t*)patch_location;
|
||||
break;
|
||||
case R_X86_64_GLOB_DAT:
|
||||
case R_X86_64_JUMP_SLOT:
|
||||
*(uint64_t*)patch_location = (uint64_t)symbol_address;
|
||||
break;
|
||||
}
|
||||
|
||||
// printf("%lX %lX %016lX %016lX\n", symbol, type, (uint64_t)symbol_address, (uint64_t)patch_location);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
errorCode_t load_elf(const char* path, elf_file* file) {
|
||||
if(file == 0 || path == 0) {
|
||||
return EBADPARM;
|
||||
}
|
||||
|
||||
// Initialize the file and retrieve the file data
|
||||
memset(file, 0x00, sizeof(elf_file));
|
||||
int rc = get_file_data(path, file);
|
||||
if(IS_ERROR(rc)) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Validate the file magic value
|
||||
if(validate_magic(file->contents) != 0) {
|
||||
free_elf(file);
|
||||
return EBADEXEC;
|
||||
}
|
||||
|
||||
file->ehdr = (Elf64_Ehdr*)file->contents;
|
||||
|
||||
/* Only support dynamic linked files */
|
||||
if(file->ehdr->e_type != ET_DYN) {
|
||||
free_elf(file);
|
||||
return EBADEXEC;
|
||||
}
|
||||
|
||||
if(file->ehdr->e_phoff == 0) {
|
||||
free_elf(file);
|
||||
return EBADEXEC;
|
||||
}
|
||||
file->phdr = (Elf64_Phdr*)((uint8_t*)file->contents + file->ehdr->e_phoff);
|
||||
|
||||
if(file->ehdr->e_shoff == 0) {;
|
||||
free_elf(file);
|
||||
return EBADEXEC;
|
||||
}
|
||||
file->shdr = (Elf64_Shdr*)((uint8_t*)file->contents + file->ehdr->e_shoff);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
errorCode_t get_elf_proc_size(elf_file* file, uint64_t* size) {
|
||||
|
||||
if(file == 0 || size == 0) {
|
||||
return EBADPARM;
|
||||
}
|
||||
|
||||
// Determine the size to allocate for the process
|
||||
// Determined by the highest address of any memory segment in the program header
|
||||
Elf64_Phdr* highest_header = 0;
|
||||
for(int i = 0; i < file->ehdr->e_phnum; i++) {
|
||||
Elf64_Phdr *phdr = get_program_header(file, i);
|
||||
if (phdr->p_type == PT_LOAD) {
|
||||
if (highest_header == 0 || highest_header->p_vaddr < phdr->p_vaddr) {
|
||||
highest_header = phdr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*size = (uint64_t)highest_header->p_vaddr + (uint64_t)highest_header->p_memsz;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
errorCode_t populate_elf_proc(elf_file* file, void* tgt_addr) {
|
||||
|
||||
if(file == 0 || tgt_addr == 0) {
|
||||
return EBADPARM;
|
||||
}
|
||||
|
||||
// Copy program sections into the process
|
||||
for(int i = 0; i < file->ehdr->e_shnum; i++) {
|
||||
Elf64_Shdr* shdr = get_section_header(file, i);
|
||||
if(shdr && (shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr > 0) {
|
||||
memcpy(((uint8_t*)tgt_addr) + shdr->sh_addr, ((uint8_t*)file->contents) + shdr->sh_offset, shdr->sh_size);
|
||||
}
|
||||
}
|
||||
|
||||
// Relocate symbols
|
||||
return relocate_symbols(file, tgt_addr);
|
||||
}
|
||||
|
||||
errorCode_t find_symbol(elf_file* file, const char* name, uint64_t* offset) {
|
||||
|
||||
if(offset == 0) {
|
||||
return EBADPARM;
|
||||
}
|
||||
|
||||
// Search for a symbol
|
||||
// Iterate through each section
|
||||
for(int i = 0; i < file->ehdr->e_shnum; i++) {
|
||||
|
||||
// Find a section that represents a symbol table
|
||||
Elf64_Shdr* shdr = get_section_header(file, i);
|
||||
if(shdr->sh_type == SHT_SYMTAB) {
|
||||
|
||||
// Retrieve the corresponding string table
|
||||
Elf64_Shdr* strtbl_hdr = get_section_header(file, shdr->sh_link);
|
||||
char* strtbl = (char*)((uint8_t*)file->contents + strtbl_hdr->sh_offset);
|
||||
|
||||
// Iterate through each entry searching for the symbol string
|
||||
int entry_count = shdr->sh_size / shdr->sh_entsize;
|
||||
for(int j = 0; j < entry_count; j++) {
|
||||
Elf64_Sym* symtbl = (Elf64_Sym*)((uint8_t*)file->contents + shdr->sh_offset + j*shdr->sh_entsize);
|
||||
char* symbol_name = &(strtbl[symtbl->st_name]);
|
||||
|
||||
// Check symbol name and return offset
|
||||
// For relocatable files - offset to symbol table + offset to the symbol (aka symbol value)
|
||||
// For all other files - symbol value (aka virtual address)
|
||||
if(strcmp(symbol_name, name) == 0) {
|
||||
if(file->ehdr->e_type == ET_REL) {
|
||||
*offset = file->shdr[symtbl->st_shndx].sh_offset + symtbl->st_value;
|
||||
} else {
|
||||
*offset = symtbl->st_value;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ENOTFOUND;
|
||||
}
|
||||
|
||||
errorCode_t free_elf(elf_file* file) {
|
||||
free_kernel_memory(file->contents, file->size);
|
||||
memset(file, 0x00, sizeof(elf_file));
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
57
TTOS/src/fs/fs.c
Normal file
57
TTOS/src/fs/fs.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "errorCode.h"
|
||||
|
||||
errorCode_t fs_open(const char* path, int flags, int* fd) {
|
||||
if(fd == 0) {
|
||||
return EBADPARM;
|
||||
}
|
||||
int rc = syscall(SYS_open, path, flags);
|
||||
if(rc == -1) {
|
||||
return EFILESYS;
|
||||
}
|
||||
*fd = rc;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
errorCode_t fs_write(int fd, const void *buf, int count, int* bytes_written) {
|
||||
int rc = syscall(SYS_write, fd, buf, count);
|
||||
if(rc == -1) {
|
||||
return EFILESYS;
|
||||
}
|
||||
if(bytes_written != 0) {
|
||||
*bytes_written = rc;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
errorCode_t fs_read(int fd, void *buf, int count, int* bytes_read) {
|
||||
int rc = syscall(SYS_read, fd, buf, count);
|
||||
if(rc == -1) {
|
||||
return EFILESYS;
|
||||
}
|
||||
if(bytes_read != 0) {
|
||||
*bytes_read = rc;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
errorCode_t fs_seek(int fd, int offset, int whence, int* distance) {
|
||||
int rc = syscall(SYS_lseek, fd, offset, whence);
|
||||
if(rc == -1) {
|
||||
return EFILESYS;
|
||||
}
|
||||
if(distance != 0) {
|
||||
*distance = rc;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
errorCode_t fs_close(int fd) {
|
||||
int rc = syscall(SYS_close, fd);
|
||||
if(rc == -1) {
|
||||
return EFILESYS;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
16
TTOS/src/main.c
Normal file
16
TTOS/src/main.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "process.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
process out;
|
||||
printf("%d\n", create_process("test", &out));
|
||||
|
||||
int (*main_exec)() = out.entry_point;
|
||||
int ret_val = main_exec();
|
||||
|
||||
printf("%d\n", ret_val);
|
||||
|
||||
free_process(&out);
|
||||
return 0;
|
||||
}
|
||||
52
TTOS/src/memory.c
Normal file
52
TTOS/src/memory.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "errorCode.h"
|
||||
#include "memory.h"
|
||||
|
||||
int allocate_user_memory(int size, void** addr) {
|
||||
if(addr == 0) {
|
||||
return EBADPARM;
|
||||
}
|
||||
|
||||
uint64_t aligned_size = PAGE_ALIGN(size);
|
||||
*addr = mmap(NULL, aligned_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if(*addr == MAP_FAILED) {
|
||||
*addr = 0;
|
||||
return EMEMORY;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int free_user_memory(void* addr, int size) {
|
||||
if(addr == 0) {
|
||||
return EBADPARM;
|
||||
}
|
||||
int rc = munmap(addr, size);
|
||||
if(rc == -1) {
|
||||
return EMEMORY;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int get_kernel_memory(int size, void** addr) {
|
||||
if(addr == 0) {
|
||||
return EBADPARM;
|
||||
}
|
||||
*addr = malloc(size);
|
||||
if(*addr == 0) {
|
||||
return EMEMORY;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int free_kernel_memory(void* addr, int size) {
|
||||
if(addr == 0) {
|
||||
return EBADPARM;
|
||||
}
|
||||
free(addr);
|
||||
return SUCCESS;
|
||||
}
|
||||
80
TTOS/src/process.c
Normal file
80
TTOS/src/process.c
Normal file
@@ -0,0 +1,80 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "errorCode.h"
|
||||
#include "elf.h"
|
||||
#include "process.h"
|
||||
#include "memory.h"
|
||||
|
||||
static errorCode_t allocate_process(int size, process* proc) {
|
||||
int aligned_size = PAGE_ALIGN(size);
|
||||
int rc = allocate_user_memory(aligned_size + STACK_SIZE, &(proc->exec_start));
|
||||
if(IS_ERROR(rc)) {
|
||||
return rc;
|
||||
}
|
||||
proc->stack_start = ((uint8_t*)(proc->exec_start) + aligned_size);
|
||||
proc->stack_end = ((uint8_t*)(proc->stack_start) + STACK_SIZE);
|
||||
proc->size = aligned_size + STACK_SIZE;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int create_process(const char* path, process* proc) {
|
||||
if(proc == 0) {
|
||||
return EBADPARM;
|
||||
}
|
||||
|
||||
// Load the executable file
|
||||
elf_file file;
|
||||
int rc = load_elf(path, &file);
|
||||
if(IS_ERROR(rc)) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Allocate the process address space
|
||||
uint64_t proc_size = 0;
|
||||
rc = get_elf_proc_size(&file, &proc_size);
|
||||
if(IS_ERROR(rc)) {
|
||||
free_elf(&file);
|
||||
return rc;
|
||||
}
|
||||
memset(proc, 0x00, sizeof(process));
|
||||
rc = allocate_process(proc_size, proc);
|
||||
if(IS_ERROR(rc)) {
|
||||
free_elf(&file);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Populate the process address space
|
||||
rc = populate_elf_proc(&file, proc->exec_start);
|
||||
if(IS_ERROR(rc)) {
|
||||
free_elf(&file);
|
||||
free_process(proc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Set the process entry point
|
||||
uint64_t offset_to_main = 0;
|
||||
rc = find_symbol(&file, "main", &offset_to_main);
|
||||
if(IS_ERROR(rc)) {
|
||||
free_elf(&file);
|
||||
free_process(proc);
|
||||
return rc;
|
||||
}
|
||||
proc->entry_point = (void*)((uint8_t*)proc->exec_start + offset_to_main);
|
||||
|
||||
// Free the executable - no longer needed since process has been created
|
||||
free_elf(&file);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
errorCode_t free_process(process* proc) {
|
||||
if(proc == 0) {
|
||||
return EBADPARM;
|
||||
}
|
||||
free_user_memory(proc->exec_start, proc->size);
|
||||
proc->exec_start = 0;
|
||||
proc->stack_start = 0;
|
||||
proc->stack_end = 0;
|
||||
proc->size = 0;
|
||||
return SUCCESS;
|
||||
}
|
||||
21
TTOS/src/syscall.c
Normal file
21
TTOS/src/syscall.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "fs/fs.h"
|
||||
|
||||
long system_call(long n, ...) {
|
||||
long rc = 0;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, n);
|
||||
|
||||
if(n == 1) {
|
||||
int fd = va_arg(ap, int);
|
||||
const char* buf = va_arg(ap, const char*);
|
||||
int count = va_arg(ap, int);
|
||||
int* bytes_written = va_arg(ap, int*);
|
||||
rc = fs_write(fd, buf, count, bytes_written);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
27
TTOS/test.c
Normal file
27
TTOS/test.c
Normal file
@@ -0,0 +1,27 @@
|
||||
//#include <stdio.h>
|
||||
|
||||
long system_call(long n, ...);
|
||||
|
||||
int j = 3;
|
||||
int i = 10;
|
||||
|
||||
int foo3(int b);
|
||||
|
||||
int foo2(int b) {
|
||||
return foo3(b) + 2;
|
||||
}
|
||||
|
||||
int foo1(int a) {
|
||||
return foo2(a) + 2 + i;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// printf("hi\n");
|
||||
// j = 10;
|
||||
system_call(1, 1, "abc\n", 4);
|
||||
int result = foo1(5 + j);
|
||||
system_call(1, 1, result, 4);
|
||||
system_call(1, 1, "\n", 1);
|
||||
return foo1(5 + j);
|
||||
// return foo1(5 + j);
|
||||
}
|
||||
3
TTOS/test2.c
Normal file
3
TTOS/test2.c
Normal file
@@ -0,0 +1,3 @@
|
||||
int foo3(int b) {
|
||||
return b + 3;
|
||||
}
|
||||
Reference in New Issue
Block a user