v0.1.0 - Hypervisor refactoring

@add
* create hypervisor module
* refacto hypervisor interface (hyp builtin)

@update
* ELF scanning: check ELF header validity instead of file extension
* improve ELF scanning
This commit is contained in:
Yatis 2021-01-29 19:46:54 +01:00
parent 95333b656d
commit 63db69e784
31 changed files with 5544 additions and 14 deletions

View File

@ -6,5 +6,6 @@
extern int mnt_main(int argc, char **argv);
extern int ls_main(int argc, char **argv);
extern int hyp_main(int argc, char **argv);
#endif /*__FXBOOT_BUILTIN_H__*/

4026
include/fxBoot/elf.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@ extern struct smemfs_superblock smemfs_superblock;
//---
extern struct smemfs_inode *smemfs_mount(void);
extern ssize_t smemfs_read(struct smemfs_inode *inode,
extern ssize_t smemfs_pread(struct smemfs_inode *inode,
void *buf, size_t count, off_t pos);
extern struct smemfs_inode *smemfs_alloc_inode(void);

107
include/fxBoot/hypervisor.h Normal file
View File

@ -0,0 +1,107 @@
#ifndef __FXBOOT_LOADER_H__
# define __FXBOOT_LOADER_H__
#include <stddef.h>
#include <stdint.h>
/* define smemfs_*() pirmitive */
#include "fxBoot/fs/smemfs.h"
#define HYPERVISOR_BSS __attribute__((section(".hypervisor.bss")))
//---
// World switch structure
// TODO: move me !
//--
/* Define the SuperH CPU hardware context */
struct cpuctx {
uint32_t reg[16];
uint32_t gbr;
uint32_t macl;
uint32_t mach;
uint32_t ssr;
uint32_t spc;
uint32_t pr;
};
struct hworld {
/* hardware context */
struct {
struct cpuctx cpu;
} context;
/* memory information */
struct {
struct {
void *start;
size_t size;
} program;
} memory;
/* private information (used by the hypeviseur) */
struct {
struct smemfs_inode *inode;
struct worldctx *next;
} private;
};
struct himage {
const char *name;
void *private;
struct himage *next;
};
//---
// Loader interface
//---
/* hypervisor_loader(): Load the IMAGE into memory.
The loader will relocalise the IMAGE that is an ELF program compiled in PIE.
The fact that if the image use Gint as a shared librarie then the loader
will automatically resolve missing symbols.
Note that the hypervisor does not support shared libraries "on-calc" because
GCC cannot generate shared libraries for the SuperH archtiecture. Gint is
only possible because the hypervisor known where is located the kernel and
all of these symbols name is hardcoded to allow symbols resolving.
@params
(in) image hypervisor image that can be get using the
"hypervisor_loader_list()" function
@return
0 if successfully loaded
negative if error occur */
extern int hypervisor_loader(struct himage *image);
/* hypervisor_loader_list(): Generate the list all loadable image
The hypervisor will scan all files into the SMEM storage memory and will
check if the file is an ELF format with PIE encoding.
Note that the generated list should be destroyed using the
"hypervisor_loader_list_destroy()" function.
@param
(out) list list that will be generated
@return
possitive The number of valid file
0 No file can be loadable
negative if error occur */
extern int hypervisor_loader_list(struct himage **list);
/* hypervisor_loader_list_destroy(): Destroy the image list
This function will destroy the list generates by the
"hypervisor_loader_list()" function.
@params
(out) list List that will be destroyed and set to NULL */
extern void hypervisor_loader_list_destroy(struct himage **list);
#endif /*__FXBOOT_LOADER_H__*/

View File

@ -57,8 +57,8 @@ CFLAGS += -Wall -Wextra -Wno-missing-field-initializers -Os
# be able to include files with #include<>. The Makefile provides a variable
# GCC_INCLUDE_FX/GCC_INCLUDE_CG that represents the default include folder,
# which is useful for some libraries such as OpenLibm.
INCLUDE_FX = -I include
INCLUDE_CG = -I include
INCLUDE_FX = -I include -I.
INCLUDE_CG = -I include -I.
# Libraries. Add one -l option for each library you are using, and also
# suitable -L options if you have library files in custom folders. To use

242
src/builtin/hyp.c Normal file
View File

@ -0,0 +1,242 @@
//---
// fxBoot:builtin:hyp - Hypervisor utility
//---
#include "fxBoot/builtin.h"
#include "fxBoot/terminal.h"
#include "fxBoot/fs/smemfs.h"
#include "fxBoot/hypervisor.h"
#include <gint/std/string.h>
#include <gint/std/stdlib.h>
#include <gint/gint.h>
/* internal structiure used to handle the hypervisor module */
#define HYP_INFO_WATERMARK (0xdeadbeef)
struct {
struct himage *images;
uint32_t watermark;
uint32_t installed;
} hypinfo;
#if 0
//---
// SMEM abstraction
//---
static void smemfs_find(struct smemfs_inode *inode, char *buffer, int *counter)
{
const char *ext;
if (inode == NULL)
return;
smemfs_find(inode->child, buffer, counter);
ext = strrchr(inode->name, '.');
if (ext != NULL) {
if (strcmp(ext, ".elf") == 0) {
terminal_write("[%d] %s\n", *counter, inode->name);
*counter += 1;
}
}
smemfs_find(inode->sibling, buffer, counter);
}
static struct smemfs_inode *smemfs_get(struct smemfs_inode *inode,
int *counter, int id)
{
struct smemfs_inode *file;
const char *ext;
if (inode == NULL)
return (NULL);
file = smemfs_get(inode->child, counter, id);
if (file != NULL)
return (file);
ext = strrchr(inode->name, '.');
if (ext != NULL) {
if (strcmp(ext, ".elf") == 0) {
if (*counter == id)
return (inode);
*counter += 1;
}
}
return (smemfs_get(inode->sibling, counter, id));
}
#endif
//---
// Module management
//---
static int hyp_img_module(int argc, char **argv)
{
if (argc < 2)
goto error;
if (strcmp(argv[2], "ls") == 0) {
int counter = 0;
struct himage *img = hypinfo.images;
while (img != NULL) {
terminal_write("[%d] %s\n", counter, img->name);
counter = counter + 1;
img = img->next;
}
return (0);
}
#if 0
if (strcmp(argv[2], "load") == 0) {
if (argc < 3) {
terminal_write("image ID missing\n");
return (84);
}
int id = 0;
struct smemfs_inode *file;
int counter = 0;
id = atoi(argv[3]);
file = smemfs_get(smemfs_superblock.root_inode,
&counter, id);
if (file == NULL) {
terminal_write("image ID invalid\n");
return (84);
}
struct worldctx *worldctx = calloc(sizeof(struct worldctx), 1);
if (hypervisor_loader(worldctx, file) != 0)
return (84);
worldctx->private.next = hyp_info.os_list;
hyp_info.os_list = worldctx;
terminal_write("image successfully loaded\n");
return (0);
}
#endif
error:
terminal_write("\"hyp img\" requires at least 1 argument\n");
terminal_write("\n");
terminal_write("Manage image\n");
terminal_write("\n");
terminal_write("commands:\n");
terminal_write(" ls List images available on the device\n");
terminal_write(" load Load image on memory\n");
return (1);
}
#if 0
static int hyp_os_module(int argc, char **argv)
{
if (argc < 2)
goto error;
if (strcmp(argv[2], "ls") == 0) {
int counter = 0;
struct worldctx *worldctx = hyp_info.os_list;
while (worldctx != NULL) {
terminal_write("[%d] - %s\n", counter, worldctx->private.file->name);
terminal_write("|-- cpu context:\n");
for (int i = 0; i < 16; ++i)
terminal_write("| |-- r%d: %p\n", i, worldctx->context.cpu.reg[i]);
terminal_write("| |-- gbr: %p\n", worldctx->context.cpu.gbr);
terminal_write("| |-- macl: %p\n", worldctx->context.cpu.macl);
terminal_write("| |-- mach: %p\n", worldctx->context.cpu.mach);
terminal_write("| |-- ssr: %p\n", worldctx->context.cpu.ssr);
terminal_write("| |-- spc: %p\n", worldctx->context.cpu.spc);
terminal_write("| `-- pr: %p\n", worldctx->context.cpu.pr);
terminal_write("`-- memory:\n");
terminal_write(" |-- entry: %p\n", worldctx->memory.program.start);
terminal_write(" `-- size : %do\n", worldctx->memory.program.size);
worldctx = worldctx->private.next;
counter = counter + 1;
}
return (0);
}
if (strcmp(argv[2], "run") == 0) {
if (argc < 3) {
terminal_write("OS ID missing\n");
return (84);
}
int id = atoi(argv[3]);
int counter = 0;
struct worldctx *worldctx = hyp_info.os_list;
while (worldctx != NULL) {
if (counter == id)
break;
worldctx = worldctx->private.next;
counter = counter + 1;
}
if (worldctx == NULL) {
terminal_write("OS ID invalid\n");
return (84);
}
/* Switch from gint to the OS after a short wait */
gint_switch_to_casio();
/* call Casio's specific code */
((void(*)(void))(uintptr_t)worldctx->context.cpu.spc)();
/* Then switch back to gint once the OS finishes working */
gint_switch_to_gint();
return (0);
}
error:
terminal_write("\"hyp os\" requiere at least 1 argument\n");
terminal_write("\n");
terminal_write("Manage image\n");
terminal_write("\n");
terminal_write("commands:\n");
terminal_write(" ls List images available on the device\n");
terminal_write(" run Run image (you cannot return to fxBoot)\n");
return (1);
}
/* install the hypervisor */
static int hyp_install(void)
{
/* extern void *bhyp_rom;
extern void *bhyp_ram;
extern void *zhyp;
// check if the hypervisor is already installed.
if (hyp_info.installed == 0xdeb0cad0) {
terminal_write("hypervisor already installed\n");
return (1);
}
// install the hypervisor
if (hyperisor_install() != 0) {
terminal_write("hypervisor installation fail :(\n");
return (84);
}*/
return (0);
}
#endif
//---
// Entry
//---
/* hyp_main(): hypervisor helper */
int hyp_main(int argc, char **argv)
{
/* initialize the buildtin (TODO: better way) */
if (hypinfo.watermark != HYP_INFO_WATERMARK) {
hypinfo.watermark = HYP_INFO_WATERMARK;
hypervisor_loader_list(&hypinfo.images);
}
/* handle arguments */
if (argc > 1) {
if (strcmp(argv[1], "img") == 0)
return (hyp_img_module(argc, argv));
//if (strcmp(argv[1], "os") == 0)
// return (hyp_os_module(argc, argv));
//if (strcmp(argv[1], "install") == 0)
// return (hyp_install());
}
/* error or helper */
terminal_write("Usage: hyp [OPTION] commands\n");
terminal_write("\n");
terminal_write("Manage image loading\n");
terminal_write("\n");
terminal_write("commands:\n");
terminal_write(" img Image management\n");
terminal_write(" os OS loading management\n");
terminal_write(" install Hypervisor installation\n");
return (0);
}

View File

@ -4,8 +4,39 @@
#include "fxBoot/builtin.h"
#include "fxBoot/terminal.h"
#include "fxBoot/fs/smemfs.h"
#include <gint/std/string.h>
#include <gint/bfile.h>
static void smemfs_generate_path(volatile char **path,
struct smemfs_inode *inode)
{
if (inode == NULL)
return;
smemfs_generate_path(path, inode->parent);
size_t length = strlen(inode->name);
memcpy((void*)*path, inode->name, length);
(*path)[length] = '\0';
*path = &(*path)[length];
}
static void smemfs_find(struct smemfs_inode *inode, char *buffer)
{
const char *ext;
if (inode == NULL)
return;
smemfs_find(inode->child, buffer);
ext = strrchr(inode->name, '.');
if (ext != NULL) {
if (strcmp(ext, ".elf") == 0) {
smemfs_generate_path((volatile char **)&buffer, inode);
/* TODO: check ELF validity */
terminal_write("(%x) %s\n", inode->type, inode->name);
}
}
smemfs_find(inode->sibling, buffer);
}
static void smemfs_walk(struct smemfs_inode *inode, int level, uint32_t bitmap)
{
const char *records;
@ -22,13 +53,13 @@ static void smemfs_walk(struct smemfs_inode *inode, int level, uint32_t bitmap)
}
/* handle file name and sibling dependencies */
records = "|-- %s";
records = "|-- (%x) %s";
bitmap |= 1 << level;
if (inode->sibling == NULL) {
records = "`-- %s";
records = "`-- (%x) %s";
bitmap &= ~(1 << level);
}
terminal_write(records, inode->name);
terminal_write(records, inode->type, inode->name);
/* handle file type */
if (inode->type == BFile_Type_Directory) {
@ -43,13 +74,16 @@ static void smemfs_walk(struct smemfs_inode *inode, int level, uint32_t bitmap)
int ls_main(int argc, char **argv)
{
(void)argc;
(void)argv;
if (smemfs_superblock.fake_root_inode != SMEMFS_FAKE_ROOT_INODE) {
terminal_write("smemfs not mounted !\n");
return (84);
}
terminal_write("/\n");
if (argc > 1 && strcmp(argv[1], "-elf") == 0) {
char buffer[512];
smemfs_find(smemfs_superblock.root_inode, buffer);
return (0);
}
terminal_write("/:\n");
smemfs_walk(smemfs_superblock.root_inode, 0, 0x00000000);
return (0);
}

View File

@ -35,7 +35,6 @@ static void dump_smem_level(struct smemfs_inode *parent,
struct smemfs_inode *inode;
uint16_t buffer[32];
int handle;
int i;
/* Generate searching path:
This format is used by the `Bfile_Find*()` syscall */
@ -53,7 +52,6 @@ static void dump_smem_level(struct smemfs_inode *parent,
tricky way to save some stack space. */
if (BFile_FindFirst(path, &handle, buffer, &file_info) != 0)
return;
i = 0;
inode = NULL;
do {
/* Try to alloc new inode */
@ -62,9 +60,8 @@ static void dump_smem_level(struct smemfs_inode *parent,
break;
/* Save the first inode (used after for directories checking) */
if (i == 0)
if (inode == NULL)
inode = *sibling;
i = 1;
/* Convert wide char to ASCII */
wide_char_convert((*sibling)->name, buffer);

View File

@ -39,7 +39,7 @@ static void generate_absolute_path(uint16_t *pathname,
/* bfile_abstract(): */
/* smemfs_read(): Read primitive */
ssize_t smemfs_read(struct smemfs_inode *inode,
ssize_t smemfs_pread(struct smemfs_inode *inode,
void *buf, size_t count, off_t pos)
{
uint16_t pathname[64];

16
src/hypervisor/config.c Normal file
View File

@ -0,0 +1,16 @@
//---
// fxBoot:hypervisor:config - Configuration interface
//---
#include "fxBoot/hypervisor.h"
//---
// User API
//---
/* hypervisor_wswitch_config(): Try to configure the hypervisor wswitch part */
int hypervisor_config(int config, ...)
{
//TODO: key remap.
//TODO: return behvious to hypervisor interface.
//TODO: remap hypervisor interface key combos
(void)config;
}

35
src/hypervisor/install.S Normal file
View File

@ -0,0 +1,35 @@
#if 0
.section .hypervisor.text, "ax"
.global _hypervisor_install
.align 2
_hypervisor_install:
/* check if the hypervisor is installed */
stc vbr, r0
mov.l hypervisor_vbr, r1
cmp/eq r1, r0
bf install
rts
mov #-1, r0
install:
/* Block all interrupts by setting IMASK=15 */
mov #0xf, r0
shll2 r0
shll2 r0
stc sr, r2
or r2, r0
ldc r0, sr
/* install the hypervisor */
ldc r1, vbr
/* restore VBR then exit */
ldc r2, sr
rts
xor r0, r0
.align 4
hypervisor_vbr:
.long _hypervisor_vbr
#endif

14
src/hypervisor/install.c Normal file
View File

@ -0,0 +1,14 @@
//---
// hypervisor:install - Hypervisor installation
//---
#include "fxBoot/hypervisor.h"
//---
// User API
//---
/* hypervisor_install(): Install the hypervisor */
int hypervisor_install(void)
{
//TODO:generate the world context for the interface
//TODO: switch VBR
}

View File

@ -0,0 +1,67 @@
#ifndef __HYPERVISOR_INTERNAL_H__
# define __HYPERVISOR_INTERNAL_H__
#include <stddef.h>
#include <stdint.h>
#include "fxBoot/fs/smemfs.h"
#include "fxBoot/elf.h"
//---
// Error helpers
//---
struct hel_error_db {
const int id;
const char *strerror;
};
extern int hypervisor_elf_loader_error(const struct hel_error_db *db,
const char *prefix, int errnum);
//---
// ELF Header helpers
//---
enum {
hel_header_valid = 0,
hel_header_size_error = -1,
hel_header_magic_error = -2,
hel_header_class_error = -3,
hel_header_indent_error = -4,
hel_header_type_error = -5,
hel_header_machine_error = -6,
hel_header_version_error = -7,
};
extern int hypervisor_elf_loader_header_get(struct smemfs_inode*,Elf32_Ehdr*);
extern int hypervisor_elf_loader_header_check(struct smemfs_inode *inode);
extern int hypervisor_elf_loader_header_error(int errnum);
//---
// ELF image helpers
//---
enum {
hel_image_success = 0,
hel_image_size_error = -1,
hel_image_type_error = -2,
hel_image_mem_error = -3,
};
extern int hypervisor_elf_loader_image_load(struct hworld *world,
struct smemfs_inode *inode, Elf32_Ehdr *header);
extern int hypervisor_elf_loader_image_error(int errnum);
//---
// ELF symbols relocatlisation helpers
//---
enum {
hel_reloc_success = 0,
hel_reloc_size_error = -1,
hel_reloc_error = -2,
};
extern int hypervisor_elf_loader_reloc_sym(struct hworld *world,
struct smemfs_inode *inode, Elf32_Ehdr *header);
extern int hypervisor_elf_loader_reloc_error(int errnum);
#endif /*__HYPERVISOR_INTERNAL_H__*/

View File

@ -0,0 +1,52 @@
//---
// fxBoot:hypervisor:loader:entry - ELF Loader entry
//---
#include "fxBoot/hypervisor.h"
#include "fxBoot/terminal.h"
#include "fxBoot/fs/smemfs.h"
#include "fxBoot/elf.h"
/* internal header */
#include "../src/hypervisor/internal/elf.h"
/* loader_entry(): Load a ELF programm (PIE) */
int hypervisor_elf_loader(struct hworld *world, struct smemfs_inode *inode)
{
Elf32_Ehdr header;
int err;
if (world == NULL)
return (-1);
/* save private information */
terminal_write("hypervisor:\n");
terminal_write("- load the inode \"%s\"\n", inode->name);
world->private.inode = inode;
/* Try to get the ELF header information */
terminal_write("- check header information\n");
err = hypervisor_elf_loader_header_get(inode, &header);
if (err != 0)
return (-2);
/* Get / Check program validity */
terminal_write("- load image\n");
err = hypervisor_elf_loader_image_load(world, inode, &header);
if (err != 0)
return (-3);
/* Relocalise sections / symbols */
terminal_write("- relocalise static symbols\n");
err = hypervisor_elf_loader_reloc_sym(world, inode, &header);
if (err != 0)
return (-4);
#if 0
/* Relocalise Gint symbols */
terminal_write("- relocalise shared symbols\n");
err = hypervisor_elf_loader_reloc_gint(world, inode, &header);
if (err != 0)
return (-5);
#endif
return (0);
}

View File

@ -0,0 +1,18 @@
//---
// elf/error - error engine
//---
#include "fxBoot/terminal.h"
#include "./src/hypervisor/internal/elf.h"
/* hypervisor_elf_loader_error(): Display error information */
int hypervisor_elf_loader_error(const struct hel_error_db *db,
const char *prefix, int errnum)
{
for (int i = 0; db[i].strerror != NULL; ++i) {
if (db[i].id != errnum)
continue;
terminal_write("%s %s\n", prefix, db[i].strerror);
return (0);
}
return (-1);
}

View File

@ -0,0 +1,74 @@
//---
// fxBoot:loader:header - Check ELF header
//---
#include "fxBoot/hypervisor.h"
#include "fxBoot/terminal.h"
#include "fxBoot/fs/smemfs.h"
#include "fxBoot/elf.h"
#include "./src/hypervisor/internal/elf.h"
/* error string list */
const struct hel_error_db header_error_db[] = {
{.id = hel_header_valid, .strerror = "valid"},
{.id = hel_header_size_error, .strerror = "size error"},
{.id = hel_header_magic_error, .strerror = "magic error"},
{.id = hel_header_class_error, .strerror = "class error"},
{.id = hel_header_indent_error, .strerror = "indent error"},
{.id = hel_header_type_error, .strerror = "type error"},
{.id = hel_header_machine_error, .strerror = "machine error"},
{.id = hel_header_version_error, .strerror = "version error"},
{.id = 0xdeb0cad0, .strerror = NULL},
};
/* hypervisor_elf_loader_header_error(): Display header error information */
int hypervisor_elf_loader_header_error(int errnum)
{
return (hypervisor_elf_loader_error(header_error_db,
"ELF header", errnum));
}
/* hypervisor_elf_loader_header_get(): Get ELF header and check validity */
int hypervisor_elf_loader_header_get(struct smemfs_inode *inode,
Elf32_Ehdr *header)
{
/* try to read the ELF header */
if (smemfs_pread(inode, header, sizeof(*header), 0) != sizeof(*header))
return (hel_header_size_error);
/* Check magic number */
if (header->e_ident[EI_MAG0] != ELFMAG0
|| header->e_ident[EI_MAG1] != ELFMAG1
|| header->e_ident[EI_MAG2] != ELFMAG2
|| header->e_ident[EI_MAG3] != ELFMAG3) {
return (hel_header_magic_error);
}
/* Check class */
if (header->e_ident[EI_CLASS] != ELFCLASS32)
return (hel_header_class_error);
/* Check data encoding */
if (header->e_ident[EI_DATA] != ELFDATA2MSB)
return (hel_header_indent_error);
/* Check ELF type */
if (header->e_type != ET_DYN)
return (hel_header_type_error);
/* Check ELF specifique instruction */
if (header->e_machine != EM_SH)
return (hel_header_machine_error);
/* Check ELF version */
if (header->e_version != EV_CURRENT)
return (hel_header_version_error);
return (hel_header_valid);
}
/* hypervisor_elf_loader_header_check(): Check ELF header validity */
int hypervisor_elf_loader_header_check(struct smemfs_inode *inode)
{
Elf32_Ehdr header;
return (hypervisor_elf_loader_header_get(inode, &header));
}

View File

@ -0,0 +1,80 @@
//---
// fxBoot:loader:entry - ELF Loader entry
//---
#include "fxBoot/hypervisor.h"
#include "fxBoot/fs/smemfs.h"
#include "fxBoot/elf.h"
#include <gint/std/stdlib.h>
#include <gint/std/string.h>
#include "./src/hypervisor/internal/elf.h"
/* error string list */
const struct hel_error_db image_error_db[] = {
{.id = hel_image_success, .strerror = "valid"},
{.id = hel_image_size_error, .strerror = "size error"},
{.id = hel_image_type_error, .strerror = "type error"},
{.id = hel_image_mem_error, .strerror = "out of memory error"},
{.id = 0xdeb0cad0, .strerror = NULL},
};
/* hypervisor_elf_loader_image_error(): Display image error information */
int hypervisor_elf_loader_image_error(int errnum)
{
return (hypervisor_elf_loader_error(image_error_db,
"ELF image ", errnum));
}
/* loader_load_image() - Load the program into Virtual Memory */
int hypervisor_elf_loader_image_load(struct hworld *world,
struct smemfs_inode *inode, Elf32_Ehdr *header)
{
Elf32_Phdr program;
void *paddress;
off_t offset;
uint16_t i;
/* Walk one time to get the entier program size and check ELF
validity. */
i = -1;
world->memory.program.size = 0;
while (++i < header->e_phnum) {
offset = header->e_phoff + (i * sizeof(Elf32_Phdr));
if (smemfs_pread(inode, &program, sizeof(Elf32_Phdr), offset)
!= sizeof(Elf32_Phdr)) {
return (hel_image_size_error);
}
if (program.p_type != PT_LOAD)
return (hel_image_type_error);
world->memory.program.size += program.p_memsz;
}
/* Allocate programe memory */
world->memory.program.start = calloc(world->memory.program.size, 1);
if (world->memory.program.start == NULL)
return (hel_image_mem_error);
/* Now, load all program section into physical memory. To do this, we
read each program header, generate the "real" physical address of
the segment then dump data.
Nota that the p_inodesz can be smaller than p_memsz so, we need to
wipe the segment area before the dump. */
i = -1;
while (++i < header->e_phnum) {
offset = header->e_phoff + (i * sizeof(Elf32_Phdr));
smemfs_pread(inode, &program, sizeof(Elf32_Phdr), offset);
paddress = program.p_vaddr + world->memory.program.start;
memset(paddress, 0, program.p_memsz);
smemfs_pread(inode, paddress,
program.p_filesz, program.p_offset);
}
/* Generate program entry address */
world->context.cpu.spc = (uint32_t)header->e_entry;
world->context.cpu.spc += (uintptr_t)world->memory.program.start;
return (hel_image_success);
}

View File

@ -0,0 +1,60 @@
//---
// fxBoot:loader:entry - ELF Loader entry
//---
#include "fxBoot/hypervisor.h"
#include "fxBoot/fs/smemfs.h"
#include "fxBoot/elf.h"
#include "./src/hypervisor/internal/elf.h"
//---
// Internal helpers
//---
/* reloc_section(): Relocalise section's symbols */
static int reloc_section(struct hworld *world,
struct smemfs_inode *inode, Elf32_Shdr *shdr)
{
Elf32_Rela rela;
uint32_t *prog;
off_t offset;
/* List symbols */
prog = (void*)world->memory.program.start;
for (uint32_t i = 0 ; i < shdr->sh_size / shdr->sh_entsize ; ++i) {
/* Get relocatable symbol information */
offset = shdr->sh_offset + (i * shdr->sh_entsize);
if (smemfs_pread(inode, &rela, shdr->sh_entsize, offset)
!= (ssize_t)shdr->sh_entsize) {
return (hel_reloc_size_error);
}
/* Relocalise the symbol */
prog[rela.r_offset >> 2] +=
(uintptr_t)world->memory.program.start;
}
return (hel_reloc_success);
}
//---
// Public helpers
//---
/* loader_reloc_sym(): Relocalise all symbols */
int hypervisor_elf_loader_reloc_sym(struct hworld *world,
struct smemfs_inode *inode, Elf32_Ehdr *header)
{
Elf32_Shdr shdr;
off_t offset;
for (int i = 1 ; i < header->e_shnum ; ++i) {
offset = header->e_shoff + (i * header->e_shentsize);
if (smemfs_pread(inode, &shdr, header->e_shentsize, offset)
!= header->e_shentsize) {
return (hel_reloc_size_error);
}
if (shdr.sh_type != SHT_RELA)
continue;
if (reloc_section(world, inode, &shdr) != hel_reloc_success)
return (hel_reloc_error);
}
return (hel_reloc_success);
}

View File

@ -0,0 +1,21 @@
#ifndef _SRC_HYPERVISOR_LOADER_LOADER_H__
# define _SRC_HYPERVISOR_LOADER_LOADER_H__
#include <stddef.h>
#include <stdint.h>
/* internal definition */
#include "fxBoot/fs/smemfs.h"
#include "fxBoot/elf.h"
//---
// Internal primitive
//---
extern int loader_get_header(struct smemfs_inode *file, Elf32_Ehdr *header);
extern int loader_load_image(struct worldctx *worldctx,
struct smemfs_inode *file, Elf32_Ehdr *header);
extern int loader_reloc_sym(struct worldctx *worldctx,
struct smemfs_inode *file, Elf32_Ehdr *header);
#endif /*_SRC_HYPERVISOR_LOADER_LOADER_H__*/

70
src/hypervisor/loader.c Normal file
View File

@ -0,0 +1,70 @@
//---
// fxBoot:hypervisor:loader - ELF loader interface
//---
#include "fxBoot/hypervisor.h"
#include "fxBoot/fs/smemfs.h"
#include "fxBoot/terminal.h"
#include "./src/hypervisor/internal/elf.h"
#include <gint/std/stdlib.h>
#include <gint/bfile.h>
//---
// Internal helpers
//---
/* hypervisor_get_image_list(): Dump all ELF file stored into the SMEM */
static int hypervisor_get_img_list(struct himage ***image,
struct smemfs_inode *inode)
{
if (inode == NULL)
return (0);
int counter = 0;
if (inode->type != BFile_Type_Archived) {
counter += hypervisor_get_img_list(image, inode->child);
goto anchor;
}
if (hypervisor_elf_loader_header_check(inode) == hel_header_valid) {
(**image) = calloc(sizeof(struct himage), 1);
if ((**image) == NULL) {
terminal_write("hypervisor: out of memory :(\n");
goto anchor;
}
(**image)->name = inode->name;
(**image)->private = inode;
*image = &((**image)->next);
}
anchor:
return (hypervisor_get_img_list(image, inode->sibling) + counter);
}
//---
// User API
//---
/* hypervisor_loader(): Load a ELF (must be PIE) and start it */
int hypervisor_loader(struct himage *image)
{
(void)image;
//TODO: create a new world context
//TODO: try to load the image
//TODO: link the new world context
//TODO: perform a world switch.
return (0);
}
/* hypervisor_loader_list(): Return a list of all supported file on SMEM */
int hypervisor_loader_list(struct himage **list)
{
return (hypervisor_get_img_list(&list, smemfs_superblock.root_inode));
}
/* hypervisor_loader_list_destroy(): Destroy the image image list */
void hypervisor_loader_list_destroy(struct himage **list)
{
if (list == NULL || *list == NULL)
return;
hypervisor_loader_list_destroy(&(*list)->next);
free(*list);
*list = NULL;
}

59
src/hypervisor/vbr.S Normal file
View File

@ -0,0 +1,59 @@
#if 0
.section .hypervisor.interrupt, "ax"
.global _hypervisor_inth
.align 2
_hypervisor_inth:
/* save interrupt related information */
sts.l mach, @-r15
sts.l macl, @-r15
stc.l gbr, @-r15
stc.l spc, @-r15
stc.l ssr, @-r15
sts.l pr, @-r15
/* check manually the keyboard status to see if the we need to
perform a world switch */
mov.l hypervisor_wswitch_check, r0
jsr @r0
nop
mov.l r0, @-r15
/* involve the "real" vbr handler */
mov.l hypervisor_inth_second_part, r0
ldc r0, vbr
mov.l hypervisor_current_vbr, r0
mov.l @r0, r0
mov #0x06, r1
shll8 r1
add r1, r0
jsr @r0
nop
hypervisor_inth_prologue:
/* check if world switch is requested */
mov.l @r15+, r0
tst r0, r0
bf.s hypervisor_inth_exit
mov.l hypervisor_wswitch, r0
jsr @r0
nop
hypervisor_inth_exit:
/* restore the saved information */
lds.l @r15+, pr
ldc.l @r15+, ssr
ldc.l @r15+, spc
ldc.l @r15+, gbr
lds.l @r15+, macl
rte
lds.l @r15+, mach
.align 4
hypervisor_wswitch_check: .long _hypervisor_worldswitch_check
hypervisor_wswitch: .long _hypervisor_worldswitch
hypervisor_current_vbr: .long _hypervisor_current_vbr
hypervisor_vbr: .long _hypervisor_vbr
hypervisor_inth_second_part: .long hypervisor_inth_prologue
#endif

24
src/hypervisor/wswitch.c Normal file
View File

@ -0,0 +1,24 @@
//---
// hypervisor:wsiwtch - hypervisor world switch
//---
#include "fxBoot/hypervisor.h"
/* internal globals information */
HYPERVISOR_BSS void *hypervisor_current_vbr = NULL;
HYPERVISOR_BSS struct hworld *hypervisor_world_queue = NULL;
//---
// User API
//---
/* hypervisor_wswitch_check(): Check if a world switch is needed */
int hypervisor_wswitch_check(void)
{
//TODO: scan the KEYSC registers
}
/* hypervisor_wswitch(): Perform a world switch */
int hypervisor_wswitch(void)
{
//TODO: display menu
//TODO: perform a world switch woth the next world context
}

View File

@ -1,6 +1,8 @@
#include "fxBoot/terminal.h"
#include "fxBoot/parser.h"
#include "fxBoot/builtin.h"
#include "fxBoot/fs/smemfs.h"
#include <gint/std/string.h>
#include <gint/keyboard.h>
#include <gint/display.h>
@ -12,6 +14,7 @@ struct {
} cmd_list[] = {
{.name = "mnt", &mnt_main},
{.name = "ls", &ls_main},
{.name = "hyp", &hyp_main},
{.name = NULL, NULL}
};
@ -37,6 +40,10 @@ int main(void)
int argc;
int ret;
/* automated hook */
/* TODO: better way to execute early command */
smemfs_mount();
ret = 0;
terminal_open();
terminal_write("Welcome to fxBoot!\n");

101
tests/Makefile Normal file
View File

@ -0,0 +1,101 @@
#!/usr/bin/make -f
## ---
## Project: PIE executable
## Author: yann.magnin@epitech.eu
## ---
##---
## Static variables
##--
HEADER := -I./include
NAME := test
EXEC := $(NAME).elf
LDFLAG := -T $(NAME).ld
MEMORY_MAP := $(NAME).map
BUILD := build
# Tools
COMPILER := sh-elf-
CC := $(COMPILER)gcc
LD := $(COMPILER)ld
OBJCOPY := $(COMPILER)objcopy
OBJDUMP := $(COMPILER)objdump
WRAPPER := g1a-wrapper
# Flags
CFLAGS := -Werror -Wall -W -Wextra -std=c18 -m3 -mb -mrenesas \
-ffreestanding -nostdlib -fstrict-volatile-bitfields \
-Wno-unused-const-variable -Wno-unused-function \
-Wno-unused-variable -Wno-unused-but-set-variable \
-Wno-unused-parameter -Wno-pointer-to-int-cast
# Colors
red := \033[1;31m
green := \033[1;32m
blue := \033[1;34m
white := \033[1;37m
nocolor := \033[1;0m
##---
## Automated variables
##---
SRC := $(wildcard src/*.[csS])
OBJ := $(patsubst %,$(BUILD)/%.o,\
$(subst /,_,$(subst src/,,$(basename $(SRC)))))
##---
## General rules
##---
all: $(EXEC)
$(EXEC): $(OBJ) | $(DEBUG)
$(CC) -pie -Wl,-M $(LDFLAG) $(CFLAGS) -o $@ $(OBJ) $(HEADER) > $(MEMORY_MAP)
check:
@ echo 'src: $(SRC)'
@ echo 'obj: $(OBJ)'
$(BUILD):
mkdir -p $@
##---
## Automated rules
##---
define rule-src
$(patsubst %,$(BUILD)/%.o,$(subst /,_,$(subst src/,,$(basename $1)))): $1 | $(BUILD)
@ printf "compiling $(white)$$<$(nocolor)..."
@ $(CC) -pie -DFXCG50 $(CFLAGS) -o $$@ -c $$< $(HEADER) -lgcc
@ printf "$(green)[ok]$(nocolor)\n"
endef
$(foreach source,$(SRC),$(eval \
$(call rule-src,$(source))) \
)
##---
## Cleaning rules
##---
clean:
rm -rf $(BUILD)
fclean: clean
rm -f $(EXEC)
re: fclean all
.PHONY: re fclean clean all install

75
tests/include/syscalls.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef __CASIO_H__
# define __CASIO_H__
#include <stdint.h>
#include <stddef.h>
// Internal Casio datat structure
struct rect
{
int left;
int top;
int right;
int bottom;
};
//
// Casio prototypes.
//
/* Bdisp_putDisp_DD - display Casio's VRAM */
void casio_Bdisp_PutDisp_DD(void);
/* GetKey() - display Casio's VRAM and wait keyboard input. */
void casio_GetKey(unsigned int *key);
/* Bdisp_AllClr_VRAM() - clear entirely the Casio's VRAM */
void casio_Bdisp_AllClr_VRAM(void);
/* Bdisp_AreaClr_VRAM() - clear only VRAM area. */
void casio_Bdisp_AreaClr_VRAM(const struct rect *buf);
/* PrintMini() - print string in Casio's VRAM (and display on screen ?) */
void casio_PrintMini(size_t x, size_t y, char const *str, int mode);
/* Bdisp_DrawLine_VRAM() - draw line in Casio's VRAM. */
void casio_Bdisp_DrawLine_VRAM(int x1, int y1, int x2, int y2);
/* Bdisp_AreaReverseVRAM() - reverse area in Casio's VRAM */
void casio_Bdisp_AreaReverseVRAM(int x0, int y0, int x1, int y1);
/* RestoreDisp() - restore saved screen. */
void casio_RestoreDisp(unsigned char page);
/* SaveDisp() - save the content of the screen. */
void casio_SaveDisp(unsigned char page);
/* Malloc() - malloc syscall */
void *casio_Malloc(size_t size);
/* Free() - free syscall */
void *casio_Free(void *ptr);
int casio_Bfile_CreateFile(const uint16_t *name, int type, size_t *size);
int casio_Bfile_OpenFile(const uint16_t *name, int useless_flags);
int casio_Bfile_WriteFile(int handle, const void *buf, size_t size);
int casio_Bfile_ReadFile(int handle, void *buf, size_t size, int cursorpos);
int casio_Bfile_CloseFile(int handle);
// Internal casio abstraction.
static inline void dclear_area(int x1, int y1, int x2, int y2)
{
struct rect area = {.left = x1, .top = y1, .right = x2, .bottom = y2};
casio_Bdisp_AreaClr_VRAM(&area);
}
#define print(x, y, str) casio_PrintMini(x, y, str, 0)
#define getkey casio_GetKey
#define dline_horizontal(y, x1, x2) casio_Bdisp_DrawLine_VRAM(x1, y, x2, y)
#define dreverse_area casio_Bdisp_AreaReverseVRAM
#define dclear casio_Bdisp_AllClr_VRAM
#define display casio_Bdisp_PutDisp_DD
#define save_window casio_SaveDisp
#define restore_window casio_RestoreDisp
#define malloc casio_Malloc
#define free casio_Free
#endif /*__CASIO_H__*/

14
tests/src/main.c Normal file
View File

@ -0,0 +1,14 @@
#include "syscalls.h"
int main(void)
{
casio_Bdisp_AllClr_VRAM();
casio_PrintMini(0, 0, "PIE executable test", 0);
casio_PrintMini(0, 10, "press [EXIT] key...", 0);
casio_Bdisp_PutDisp_DD();
unsigned int key;
while (1) {
casio_GetKey(&key);
}
}

150
tests/src/syscalls.S Normal file
View File

@ -0,0 +1,150 @@
.global _casio_GetKey
.global _casio_PrintMini
.global _casio_Bdisp_PutDisp_DD
.global _casio_Bdisp_AllClr_VRAM
.global _casio_Bdisp_DrawLine_VRAM
.global _casio_Bdisp_AreaReverseVRAM
.global _casio_Bdisp_AreaClr_VRAM
.global _casio_RestoreDisp
.global _casio_SaveDisp
.global _casio_Malloc
.global _casio_Free
.type _casio_GetKey, @function
.type _casio_PrintMini, @function
.type _casio_Bdisp_PutDisp_DD, @function
.type _casio_Bdisp_AllClr_VRAM, @function
.type _casio_Bdisp_DrawLine_VRAM, @function
.type _casio_Bdisp_AreaReverseVRAM, @function
.type _casio_Bdisp_AreaClr_VRAM, @function
.type _casio_RestoreDisp, @function
.type _casio_SaveDisp, @function
.type _casio_Malloc, @function
.type _casio_Free, @function
.global _casio_Bfile_CreateFile
.global _casio_Bfile_OpenFile
.global _casio_Bfile_ReadFile
.global _casio_Bfile_WriteFile
.global _casio_Bfile_CloseFile
.type _casio_Bfile_CreateFile, @function
.type _casio_Bfile_OpenFile, @function
.type _casio_Bfile_ReadFile, @function
.type _casio_Bfile_WriteFile, @function
.type _casio_Bfile_CloseFile, @function
#define syscall_(id, syscall_table) \
mov.l syscall_table, r2 ;\
mov.l 1f, r0 ;\
jmp @r2 ;\
nop ;\
.align 4 ;\
1: .long id
#define syscall(id) syscall_(id, syscall_table)
#ifdef FX9860G
_casio_GetKey:
syscall(0x90f)
_casio_PrintMini:
syscall(0xc4f)
_casio_Bdisp_AllClr_VRAM:
syscall(0x143)
_casio_Bdisp_PutDisp_DD:
syscall(0x028)
_casio_Bdisp_DrawLine_VRAM:
syscall(0x030)
_casio_Bdisp_AreaClr_VRAM:
syscall(0x14b)
_casio_Bdisp_AreaReverseVRAM:
syscall(0x14d)
_casio_Malloc:
syscall(0xacd)
_casio_Free:
syscall(0xacc)
_casio_Bfile_CreateFile:
syscall(0x434)
_casio_Bfile_OpenFile:
syscall(0x42c)
_casio_Bfile_WriteFile:
syscall(0x435)
_casio_Bfile_ReadFile:
syscall(0x432)
_casio_Bfile_CloseFile:
syscall(0x42d)
syscall_table:
.long 0x80010070
#endif /* FXCG9860G */
#ifdef FXCG50
_casio_GetKey:
syscall(0x0eab)
_casio_PrintMini:
sts.l pr, @-r15
! fxcg50 prototype:
! void PrintMinit(int *x, int *y, void *str, int mode, int color, int mode2)
mov.l r4, @-r15
mov r15, r4 ! x position
mov.l r5, @-r15
mov r15, r5 ! y posiition
mov #0, r7 ! mode
mov #0, r0 ! color
mov #0, r1 ! mode2
mov.l r0, @-r15
mov.l r1, @-r15
! syscall
mov.l syscall_table, r2
mov.l 1f, r0
jsr @r2
nop
! restore stack
add #16, r15
lds.l @r15+, pr
rts
nop
.align 4
1: .long 0x021b
_casio_Bdisp_AllClr_VRAM:
syscall(0x272)
_casio_Bdisp_PutDisp_DD:
syscall(0x025f)
_casio_Bfile_CreateFile:
syscall(0x1dae)
_casio_Bfile_OpenFile:
mov #0, r6
syscall(0x1da3)
_casio_Bfile_CloseFile:
syscall(0x1da4)
_casio_Bfile_WriteFile:
syscall(0x1daf)
_casio_Bfile_ReadFile:
syscall(0x1dac)
_casio_Malloc:
syscall(0x1f44)
_casio_Free:
syscall(0x1f42)
syscall_table:
.long 0x80020070
#endif /* FXCG50 */
.end

BIN
tests/test-fxcg50-anykey.elf Executable file

Binary file not shown.

BIN
tests/test-fxcg50.elf Executable file

Binary file not shown.

84
tests/test.ld Normal file
View File

@ -0,0 +1,84 @@
OUTPUT_FORMAT("elf32-sh", "elf32-sh", "elf32-sh")
OUTPUT_ARCH(sh3)
ENTRY(_main)
/*
** Linker script for user executables.
*/
MEMORY
{
/* virtual memory, read-write segment */
userram (WX) : o = 0x00000000, l = 256k
}
SECTIONS
{
/* Read-only sections */
.text : {
/* Code */
*(.text);
*(.text.*);
/* Read-Only data */
*(.rodata);
*(.rodata.*);
/* Dynamic symbols */
*(.hash)
*(.dynsym)
*(.dynstr)
*(.dynbss)
*(.dynamic)
/* Procedure Linkage Table */
*(.plt)
/* GLobal Offset Table */
*(.got.plt)
*(.got.*)
*(.got)
/* ???? */
*(.rofixup)
} > userram
/* Relocatable sections */
.rela.dyn : {
*(.rela.plt)
*(.rela.got)
*(.rela.got.*)
*(.rela.*)
*(.rela.text)
*(.real.data)
} > userram
/* readable / writable data */
.data ALIGN(4) : {
/* Data sections */
*(.data);
*(.data.*);
/* bss section included to avoid missaligned segment */
*(.bss);
*(.bss.*);
*(COMMON);
} > userram
/* unwanted section */
/DISCARD/ : {
*(.gnu.*)
*(.debug_info)
*(.debug_abbrev)
*(.debug_loc)
*(.debug_aranges)
*(.debug_ranges)
*(.debug_line)
*(.debug_str)
*(.jcr)
*(.eh_frame_hdr)
*(.eh_frame)
*(.comment)
*(.interp)
}
}

102
tests/test.map Normal file
View File

@ -0,0 +1,102 @@
build/main.o: dynamic relocation in read-only section `.text'
Discarded input sections
.comment 0x0000000000000000 0x13 build/main.o
Memory Configuration
Name Origin Length Attributes
userram 0x0000000000000000 0x0000000000040000 xw
*default* 0x0000000000000000 0xffffffffffffffff
Linker script and memory map
LOAD build/main.o
LOAD build/syscalls.o
.text 0x0000000000000000 0x230
*(.text)
.text 0x0000000000000000 0x68 build/main.o
0x0000000000000000 _main
*fill* 0x0000000000000068 0x8
.text 0x0000000000000070 0xe0 build/syscalls.o
0x0000000000000070 _casio_GetKey
0x0000000000000084 _casio_PrintMini
0x00000000000000b4 _casio_Bdisp_AllClr_VRAM
0x00000000000000c4 _casio_Bdisp_PutDisp_DD
0x00000000000000d4 _casio_Bfile_CreateFile
0x00000000000000e4 _casio_Bfile_OpenFile
0x00000000000000f4 _casio_Bfile_CloseFile
0x0000000000000104 _casio_Bfile_WriteFile
0x0000000000000114 _casio_Bfile_ReadFile
0x0000000000000124 _casio_Malloc
0x0000000000000134 _casio_Free
*(.text.*)
*(.rodata)
.rodata 0x0000000000000150 0x25 build/main.o
*(.rodata.*)
*(.hash)
*fill* 0x0000000000000175 0x3
.hash 0x0000000000000178 0x10 build/main.o
*(.dynsym)
.dynsym 0x0000000000000188 0x10 build/main.o
*(.dynstr)
.dynstr 0x0000000000000198 0x1 build/main.o
*(.dynbss)
.dynbss 0x0000000000000199 0x0 build/main.o
*(.dynamic)
*fill* 0x0000000000000199 0x3
.dynamic 0x000000000000019c 0x88 build/main.o
0x000000000000019c _DYNAMIC
*(.plt)
.plt 0x0000000000000224 0x0 build/main.o
*(.got.plt)
.got.plt 0x0000000000000224 0xc build/main.o
0x0000000000000224 _GLOBAL_OFFSET_TABLE_
*(.got.*)
.got.funcdesc 0x0000000000000230 0x0 build/main.o
*(.got)
.got 0x0000000000000230 0x0 build/main.o
*(.rofixup)
.rofixup 0x0000000000000230 0x0 build/main.o
.rela.dyn 0x0000000000000230 0x48
*(.rela.plt)
.rela.plt 0x0000000000000230 0x0 build/main.o
*(.rela.got)
.rela.got 0x0000000000000230 0x0 build/main.o
*(.rela.got.*)
.rela.got.funcdesc
0x0000000000000230 0x0 build/main.o
*(.rela.*)
.rela.text 0x0000000000000230 0x48 build/main.o
*(.rela.text)
*(.real.data)
.data 0x0000000000000278 0x0
*(.data)
.data 0x0000000000000278 0x0 build/main.o
.data 0x0000000000000278 0x0 build/syscalls.o
*(.data.*)
*(.bss)
.bss 0x0000000000000278 0x0 build/main.o
.bss 0x0000000000000278 0x0 build/syscalls.o
*(.bss.*)
*(COMMON)
/DISCARD/
*(.gnu.*)
*(.debug_info)
*(.debug_abbrev)
*(.debug_loc)
*(.debug_aranges)
*(.debug_ranges)
*(.debug_line)
*(.debug_str)
*(.jcr)
*(.eh_frame_hdr)
*(.eh_frame)
*(.comment)
*(.interp)
OUTPUT(test.elf elf32-sh)