diff --git a/include/fxBoot/hypervisor.h b/include/fxBoot/hypervisor.h index cd34ac3..7836907 100644 --- a/include/fxBoot/hypervisor.h +++ b/include/fxBoot/hypervisor.h @@ -7,6 +7,8 @@ /* define smemfs_*() pirmitive */ #include "fxBoot/fs/smemfs.h" +/* define tsession */ +#include #define HYPERVISOR_BSS __attribute__((section(".hypervisor.bss"))) @@ -16,13 +18,13 @@ //-- /* 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; + uintptr_t reg[16]; + uintptr_t gbr; + uintptr_t macl; + uintptr_t mach; + uintptr_t ssr; + uintptr_t spc; + uintptr_t pr; }; #define HYPERVISOR_STACK_KERNEL_SIZE (2 * 1024) @@ -51,6 +53,10 @@ struct hworld { struct { void *start; size_t size; + struct { + uintptr_t vmin; + uintptr_t vmax; + } elf; } program; struct { void *kernel; @@ -76,6 +82,9 @@ struct hworld { HYPERVISOR_ENV_GINT = 0, HYPERVISOR_ENV_CASIO = 1, } env; + struct { + struct tsession *tracer; + } debug; } private; }; diff --git a/include/fxBoot/terminal.h b/include/fxBoot/terminal.h index 0476f71..a952c4a 100644 --- a/include/fxBoot/terminal.h +++ b/include/fxBoot/terminal.h @@ -65,6 +65,7 @@ extern struct terminal terminal; //--- extern int terminal_open(void); extern int terminal_write(const char *format, ...); +extern int terminal_error(const char *format, ...); extern int terminal_read(void *buffer, size_t nb); extern int terminal_close(void); diff --git a/project.cfg b/project.cfg index 2e4bbeb..d2287ab 100644 --- a/project.cfg +++ b/project.cfg @@ -63,8 +63,8 @@ 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 # fxlib, add libfx.a to the project directory and use "-L . -lfx". -LIBS_FX := -LIBS_CG := +LIBS_FX := -lgintrace-fx +LIBS_CG := -lgintrace-cg # Base linker flags for the fxSDK, you usually want to keep these. LDFLAGS_FX := -T fx9860g.ld -lgint-fx $(LIBS_FX) -lgint-fx -lgcc diff --git a/src/builtin/hyp.c b/src/builtin/hyp.c index 7ea6fbd..360a4ae 100644 --- a/src/builtin/hyp.c +++ b/src/builtin/hyp.c @@ -11,6 +11,10 @@ #include #include +#include + +#include "./src/hypervisor/internal/elf.h" + /* internal structiure used to handle the hypervisor module */ #define HYP_INFO_WATERMARK (0xdeadbeef) struct { @@ -19,6 +23,27 @@ struct { uint32_t installed; } hypinfo; +//--- +// Internal information +//--- +/* hyp_get_image(): return the image using its ID */ +static struct himage *hyp_get_image(int id) +{ + struct himage *img; + int counter; + + counter = 0; + img = hypinfo.images; + while (img != NULL) { + if (counter == id) + break; + counter = counter + 1; + img = img->next; + } + return (img); +} + + //--- // Module management //--- @@ -42,15 +67,7 @@ static int hyp_img_module(int argc, char **argv) terminal_write("image ID missing\n"); return (84); } - int counter = 0; - int id = atoi(argv[3]); - struct himage *img = hypinfo.images; - while (img != NULL) { - if (counter == id) - break; - counter = counter + 1; - img = img->next; - } + struct himage *img = hyp_get_image(atoi(argv[3])); if (img == NULL) { terminal_write("image ID invalid\n"); return (84); @@ -60,6 +77,18 @@ static int hyp_img_module(int argc, char **argv) terminal_write("image successfully loaded\n"); return (0); } + if (strcmp(argv[2], "dyn") == 0) { + if (argc < 3) { + terminal_write("image ID missing\n"); + return (84); + } + struct himage *img = hyp_get_image(atoi(argv[3])); + if (img == NULL) { + terminal_write("image ID invalid\n"); + return (84); + } + return (hypervisor_elf_loader_dynamic_check(img->private)); + } error: terminal_write("\"hyp img\" requires at least 1 argument\n"); @@ -75,6 +104,7 @@ error: /* hyp_os_module(): Handle argument for the os module part */ static int hyp_os_module(int argc, char **argv) { + if (argc < 2) goto error; if (strcmp(argv[2], "ls") == 0) { @@ -100,22 +130,40 @@ static int hyp_os_module(int argc, char **argv) } return (0); } + if (argc < 3) { + terminal_write("OS ID missing\n"); + return (84); + } + int counter = 0; + int id = atoi(argv[3]); + struct hworld *world = hypervisor_wswitch_queue_get(); + while (world != NULL) { + if (counter == id) + break; + counter = counter + 1; + world = world->private.next; + } + if (world == NULL) { + terminal_write("image ID invalid\n"); + return (84); + } if (strcmp(argv[2], "run") == 0) { - if (argc < 3) { - terminal_write("OS ID missing\n"); + //FIXME: indicate that the world is running ! + //FIXME: check if the world is already running ! + if (hypervisor_wswitch(world) != 0) return (84); - } - int counter = 0; - int id = atoi(argv[3]); - struct hworld *world = hypervisor_wswitch_queue_get(); - while (world != NULL) { - if (counter == id) - break; - counter = counter + 1; - world = world->private.next; - } - if (world == NULL) { - terminal_write("image ID invalid\n"); + return (0); + } + if (strcmp(argv[2], "trace") == 0) { + //FIXME: indicate that the world is running ! + //FIXME: check if the world is already running ! + world->private.debug.tracer = + tracer_create_session((void*)world->context.cpu.spc, + TRACER_DISASM + | TRACER_CONTEXT + | TRACER_HEXDUMP); + if (world->private.debug.tracer == NULL) { + terminal_write("tracer session error\n"); return (84); } if (hypervisor_wswitch(world) != 0) diff --git a/src/fs/smemfs/mount.c b/src/fs/smemfs/mount.c index 0c119e4..3b65f0f 100644 --- a/src/fs/smemfs/mount.c +++ b/src/fs/smemfs/mount.c @@ -6,7 +6,11 @@ #include #include #include -#include + +/* world information */ +extern void *kernel_env_casio; +extern void *kernel_env_gint; +extern void *gint_switch_to_world(void *buffctx); /* Define the super block information */ struct smemfs_superblock smemfs_superblock = { @@ -97,7 +101,7 @@ struct smemfs_inode *smemfs_mount(void) void *root_inode; /* switch to the Casio's OS */ - gint_switch_to_casio(); + gint_switch_to_world(kernel_env_casio); /* Check useless mount */ root_inode = smemfs_superblock.root_inode; @@ -117,7 +121,7 @@ struct smemfs_inode *smemfs_mount(void) } /* switch to the Gint kernel */ - gint_switch_to_gint(); + gint_switch_to_world(kernel_env_gint); /* Return the sector table to simulate the root inode. */ return (root_inode); diff --git a/src/fs/smemfs/pread.c b/src/fs/smemfs/pread.c index 48e45ab..b7f3f3c 100644 --- a/src/fs/smemfs/pread.c +++ b/src/fs/smemfs/pread.c @@ -9,6 +9,12 @@ /* external symbols */ extern uint32_t (*cpu_setVBR)(uint32_t vbr, void (*conf_intc)(int), int arg); +/* world information */ +extern void *kernel_env_casio; +extern void *kernel_env_gint; +extern void *gint_switch_to_world(void *buffctx); + + /* generate_abolute_path(): Generate abolute path This function will generate the absolute path of a file because Casio's open @@ -36,8 +42,6 @@ static void generate_absolute_path(uint16_t *pathname, pathname[*pos] = '\0'; } -/* bfile_abstract(): */ - /* smemfs_read(): Read primitive */ ssize_t smemfs_pread(struct smemfs_inode *inode, void *buf, size_t count, off_t pos) @@ -53,7 +57,7 @@ ssize_t smemfs_pread(struct smemfs_inode *inode, generate_absolute_path(pathname, inode, &handle); /* Switch from gint to the OS after a short wait */ - gint_switch_to_casio(); + gint_switch_to_world(kernel_env_casio); /* Open, read and close the file using Casio's OS syscall */ read = -1; @@ -64,7 +68,7 @@ ssize_t smemfs_pread(struct smemfs_inode *inode, } /* Then switch back to gint once the OS finishes working */ - gint_switch_to_gint(); + gint_switch_to_world(kernel_env_gint); /* return the number of byte readed */ return (read); diff --git a/src/hypervisor/gint.c b/src/gint.c similarity index 98% rename from src/hypervisor/gint.c rename to src/gint.c index 98b4a02..ebf4a48 100644 --- a/src/hypervisor/gint.c +++ b/src/gint.c @@ -1,6 +1,7 @@ //--- // fxBoot:hypervisor:gint - Gint workaround //--- +#if 0 #include "fxBoot/hypervisor.h" #include @@ -34,3 +35,4 @@ void gint_switch(void (*function)(void)) function(); gint_switch_to_gint(); } +#endif diff --git a/src/hypervisor/env.c b/src/hypervisor/env.c index a2a647f..32e8ee7 100644 --- a/src/hypervisor/env.c +++ b/src/hypervisor/env.c @@ -25,6 +25,6 @@ int hypervisor_env_set(struct hworld *world) default: return (-2); } - drivers_context_duplicate(world->context.drivers, env); + drivers_context_duplicate(&world->context.drivers, env); return (0); } diff --git a/src/hypervisor/internal/elf.h b/src/hypervisor/internal/elf.h index d7de71b..2db0630 100644 --- a/src/hypervisor/internal/elf.h +++ b/src/hypervisor/internal/elf.h @@ -8,6 +8,13 @@ #include "fxBoot/fs/smemfs.h" #include "fxBoot/elf.h" +/* internal gint symbols information structure */ +struct dyngint { + const char *name; + const void *addr; +}; +extern const struct dyngint gint_reloc[]; + //--- // Main API //--- @@ -70,4 +77,6 @@ enum { 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); + +extern int hypervisor_elf_loader_dynamic_check(struct smemfs_inode *inode); #endif /*__HYPERVISOR_INTERNAL_H__*/ diff --git a/src/hypervisor/internal/elf/dyn.c b/src/hypervisor/internal/elf/dyn.c new file mode 100644 index 0000000..737af79 --- /dev/null +++ b/src/hypervisor/internal/elf/dyn.c @@ -0,0 +1,156 @@ +//--- +// fxBoot:loader:entry - ELF Loader entry +//--- +#include "fxBoot/hypervisor.h" +#include "fxBoot/fs/smemfs.h" +#include "fxBoot/elf.h" +#include "fxBoot/terminal.h" + +#include +#include + +#include "./src/hypervisor/internal/elf.h" + +/* elf_dump_section(): Dump one section */ +static void *elf_dump_section(struct smemfs_inode *inode, Elf32_Shdr *shdr) +{ + void *section; + + section = malloc(shdr->sh_size); + if (section == NULL) + return (NULL); + if (smemfs_pread(inode, section, shdr->sh_size, shdr->sh_offset) + != (ssize_t)shdr->sh_size) { + free(section); + return (NULL); + } + return (section); +} + +/* elf_rela_check(): Check rela section */ +static void elf_rela_check(struct smemfs_inode *inode, Elf32_Shdr *shdr) +{ + Elf32_Rela rela; + Elf32_Word i; + off_t offset; + + for (i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i) { + offset = shdr->sh_offset + (i * shdr->sh_entsize); + if (smemfs_pread(inode, &rela, shdr->sh_entsize, offset) + != (ssize_t)shdr->sh_entsize) { + terminal_write("rela sectio size error\n"); + return; + } + terminal_write("%p %p %d %d %d\n", rela.r_offset, + rela.r_info, + ELF32_R_SYM(rela.r_info), + ELF32_R_TYPE(rela.r_info), + rela.r_addend); + } +} + +/* hypervisor_elf_loader_dynamic_check(): Display all .dynshr */ +int hypervisor_elf_loader_dynamic_check(struct smemfs_inode *inode) +{ + Elf32_Ehdr ehdr; + Elf32_Shdr shdr; + Elf32_Shdr dynamichdr; + Elf32_Dyn *dynamic; + char *shstrtab; + char *dynstr; + char *dynsym; + off_t offset; + void **tmp; + int err; + + /* Try to get the ELF header information */ + err = hypervisor_elf_loader_header_get(inode, &ehdr); + if (err != 0) + return (-2); + + /* get ELF section header string table */ + offset = ehdr.e_shoff + (ehdr.e_shstrndx * ehdr.e_shentsize); + if (smemfs_pread(inode, &shdr, ehdr.e_shentsize, offset) + != ehdr.e_shentsize) { + terminal_write("shdr size\n"); + return (-1); + } + shstrtab = elf_dump_section(inode, &shdr); + if (shstrtab == NULL) { + terminal_write("cannot get the shstrtab section\n"); + return (-2); + } + + /* get ELF information */ + dynstr = NULL; + dynamic = NULL; + for (int i = 1 ; i < ehdr.e_shnum ; ++i) { + offset = ehdr.e_shoff + (i * ehdr.e_shentsize); + if (smemfs_pread(inode, &shdr, ehdr.e_shentsize, offset) + != ehdr.e_shentsize) { + terminal_write("section %d size error\n", i); + continue; + } + if (shdr.sh_type == SHT_RELA) { + elf_rela_check(inode, &shdr); + continue; + } + tmp = NULL; + if (strcmp(".dynamic", &shstrtab[shdr.sh_name]) == 0) { + memcpy(&dynamichdr, &shdr, sizeof(Elf32_Shdr)); + tmp = (void*)&dynamic; + } + if (strcmp(".dynstr", &shstrtab[shdr.sh_name]) == 0) + tmp = (void*)&dynstr; + if (strcmp(".dynsym", &shstrtab[shdr.sh_name]) == 0) + tmp = (void*)&dynsym; + if (tmp == NULL) + continue; + *tmp = elf_dump_section(inode, &shdr); + if (*tmp == NULL) { + terminal_write("warning: '%s' dump error\n", + &shstrtab[shdr.sh_name]); + } + } + if (dynstr == NULL || dynamic == NULL) { + terminal_write(".dynstr or .dynamic not found\n"); + return (-3); + } + +#if 0 + /* display information */ + Elf32_Word i; + terminal_write("%10s %8s Name/Value\n", "TAG", "Type"); + for (i = 0; i < dynamichdr.sh_size / dynamichdr.sh_entsize; ++i) { + if (dynamic[i].d_tag == DT_NULL) { + terminal_write("%p %8s %d\n", + dynamic[i].d_tag, "NULL", + dynamic[i].d_un.d_val); + break; + } + if (dynamic[i].d_tag == DT_NEEDED) { + terminal_write("%p %8s %s\n", + dynamic[i].d_tag, "NEEDED", + &dynstr[dynamic[i].d_un.d_val]); + continue; + } + if (dynamic[i].d_tag == DT_STRTAB) { + terminal_write("%p %8s %p\n", + dynamic[i].d_tag, "STRTAB", + dynamic[i].d_un.d_ptr); + continue; + } + if (dynamic[i].d_tag == DT_SYMTAB) { + terminal_write("%x %8s %p\n", + dynamic[i].d_tag, "SYMTAB", + dynamic[i].d_un.d_ptr); + continue; + } + terminal_write("%p %8s %p\n", + dynamic[i].d_tag, type, + dynamic[i].d_un.d_val); + } + terminal_write("dynamic symbols - %d\n", i); +#endif + return (0); +} diff --git a/src/hypervisor/internal/elf/entry.c b/src/hypervisor/internal/elf/entry.c index 2400c8f..e30b6b3 100644 --- a/src/hypervisor/internal/elf/entry.c +++ b/src/hypervisor/internal/elf/entry.c @@ -19,8 +19,7 @@ int hypervisor_elf_loader(struct hworld *world, struct smemfs_inode *inode) return (-1); /* save private information */ - terminal_write("hypervisor:\n"); - terminal_write("- load the inode \"%s\"\n", inode->name); + terminal_write("- load ELF file \"%s\"\n", inode->name); world->private.inode = inode; /* Try to get the ELF header information */ @@ -36,17 +35,9 @@ int hypervisor_elf_loader(struct hworld *world, struct smemfs_inode *inode) return (-3); /* Relocalise sections / symbols */ - terminal_write("- relocalise static symbols\n"); + terminal_write("- relocalize 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); } diff --git a/src/hypervisor/internal/elf/gint.c b/src/hypervisor/internal/elf/gint.c new file mode 100644 index 0000000..e2514f4 --- /dev/null +++ b/src/hypervisor/internal/elf/gint.c @@ -0,0 +1,42 @@ +#include "./src/hypervisor/internal/elf.h" + +#include +#include + + +const struct dyngint gint_reloc[] = { + /* display symbols */ + {.name = "_dclear", .addr = (void*)&dclear}, + {.name = "_drect", .addr = (void*)&drect}, + {.name = "_drect_border", .addr = (void*)&drect_border}, + {.name = "_dpixel", .addr = (void*)&dpixel}, + {.name = "_dline", .addr = (void*)&dline}, + {.name = "_dhline", .addr = (void*)&dhline}, + {.name = "_dvline", .addr = (void*)&dvline}, + {.name = "_dfont", .addr = (void*)&dfont}, + {.name = "_dsize", .addr = (void*)&dsize}, + {.name = "_dtext_opt", .addr = (void*)&dtext_opt}, + {.name = "_dtext", .addr = (void*)&dtext}, + {.name = "_dprint_opt", .addr = (void*)&dprint_opt}, + {.name = "_dprint", .addr = (void*)&dprint}, + {.name = "_dimage", .addr = (void*)&dimage}, + {.name = "_dsubimage", .addr = (void*)&dsubimage}, + {.name = "_dupdate", .addr = (void*)&dupdate}, + + /* keyboard symbols */ + {.name = "_pollevent", .addr = (void*)&pollevent}, + {.name = "_waitevent", .addr = (void*)&waitevent}, + {.name = "_clearevants", .addr = (void*)&clearevents}, + {.name = "_keydown", .addr = (void*)&keydown}, + {.name = "_keydown_all", .addr = (void*)&keydown_all}, + {.name = "_keydown_any", .addr = (void*)&keydown_any}, + {.name = "_getkey", .addr = (void*)&getkey}, + {.name = "_getkey_opt", .addr = (void*)&getkey_opt}, + {.name = "_getkey_repeat", .addr = (void*)&getkey_repeat}, + {.name = "_getkey_repeat_filter",.addr = (void*)&getkey_repeat_filter}, + {.name = "_keycode_function", .addr = (void*)&keycode_function}, + {.name = "_keycode_digit", .addr = (void*)&keycode_digit}, + + /* end */ + {.name = NULL, .addr = (void*)NULL}, +}; diff --git a/src/hypervisor/internal/elf/header.c b/src/hypervisor/internal/elf/header.c index a3cdbf8..9a5bdeb 100644 --- a/src/hypervisor/internal/elf/header.c +++ b/src/hypervisor/internal/elf/header.c @@ -53,7 +53,7 @@ int hypervisor_elf_loader_header_get(struct smemfs_inode *inode, return (hel_header_indent_error); /* Check ELF type */ - if (header->e_type != ET_DYN) + if (header->e_type != ET_DYN && header->e_type != ET_EXEC) return (hel_header_type_error); /* Check ELF specifique instruction */ diff --git a/src/hypervisor/internal/elf/image.c b/src/hypervisor/internal/elf/image.c index 8ae8608..b31d5b6 100644 --- a/src/hypervisor/internal/elf/image.c +++ b/src/hypervisor/internal/elf/image.c @@ -31,13 +31,18 @@ int hypervisor_elf_loader_image_load(struct hworld *world, struct smemfs_inode *inode, Elf32_Ehdr *header) { Elf32_Phdr program; - void *paddress; + uintptr_t paddress; + uintptr_t vmin; + uintptr_t vmax; off_t offset; uint16_t i; + /* Walk one time to get the entier program size and check ELF validity. */ i = -1; + vmin = 0xffffffff; + vmax = 0x00000000; world->memory.program.size = 0; while (++i < header->e_phnum) { offset = header->e_phoff + (i * sizeof(Elf32_Phdr)); @@ -45,10 +50,14 @@ int hypervisor_elf_loader_image_load(struct hworld *world, != 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; + if (program.p_vaddr < vmin) + vmin = program.p_vaddr; + if (program.p_vaddr + program.p_memsz > vmax) + vmax = program.p_vaddr + program.p_memsz; } + world->memory.program.size = vmax - vmin; + world->memory.program.elf.vmin = vmin; + world->memory.program.elf.vmax = vmax; /* Allocate programe memory */ world->memory.program.start = calloc(world->memory.program.size, 1); @@ -59,22 +68,28 @@ int hypervisor_elf_loader_image_load(struct hworld *world, 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 + Note that the p_filesz 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; + paddress = (uintptr_t)program.p_vaddr - vmin; + paddress += (uintptr_t)world->memory.program.start; - memset(paddress, 0, program.p_memsz); - smemfs_pread(inode, paddress, + memset((void*)paddress, 0x00, program.p_memsz); + smemfs_pread(inode, (void*)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)header->e_entry - vmin; world->context.cpu.spc += (uintptr_t)world->memory.program.start; + terminal_write("- SPC: %p\n", world->context.cpu.spc); + + /* Generate other information */ + world->context.cpu.ssr = 0x40000000; + //TODO: PR register ! return (hel_image_success); } diff --git a/src/hypervisor/internal/elf/reloc.c b/src/hypervisor/internal/elf/reloc.c index 724c94f..c543f86 100644 --- a/src/hypervisor/internal/elf/reloc.c +++ b/src/hypervisor/internal/elf/reloc.c @@ -4,33 +4,146 @@ #include "fxBoot/hypervisor.h" #include "fxBoot/fs/smemfs.h" #include "fxBoot/elf.h" +#include "fxBoot/terminal.h" + +#include +#include #include "./src/hypervisor/internal/elf.h" //--- // Internal helpers //--- +/* relocinfo: Internal structure used to stoe all ELF information */ +struct relocinfo { + Elf32_Ehdr *ehdr; + Elf32_Shdr ehdr_dynamic; + Elf32_Dyn *dynamic; + Elf32_Sym *dynsym; + char *dynstr; + char *shstrtab; + struct smemfs_inode *inode; +}; + +/* reloc_dump_section(): Dump one section */ +static void *reloc_dump_section(struct smemfs_inode *inode, Elf32_Shdr *shdr) +{ + void *section; + + section = malloc(shdr->sh_size); + if (section == NULL) + return (NULL); + if (smemfs_pread(inode, section, shdr->sh_size, shdr->sh_offset) + != (ssize_t)shdr->sh_size) { + free(section); + return (NULL); + } + return (section); +} + +/* reloc_get_dynamic_info(): Dump all dynamic information */ +static int reloc_get_dynamic_info(struct relocinfo *elf) +{ + Elf32_Shdr shdr; + off_t offset; + void **tmp; + + /* get ELF section header string table */ + offset = elf->ehdr->e_shoff; + offset += elf->ehdr->e_shstrndx * elf->ehdr->e_shentsize; + if (smemfs_pread(elf->inode, &shdr, elf->ehdr->e_shentsize, offset) + != elf->ehdr->e_shentsize) { + return (-1); + } + elf->shstrtab = reloc_dump_section(elf->inode, &shdr); + if (elf->shstrtab == NULL) + return (-2); + + /* get ELF information */ + elf->dynstr = NULL; + elf->dynamic = NULL; + for (int i = 1 ; i < elf->ehdr->e_shnum ; ++i) { + offset = elf->ehdr->e_shoff + (i * elf->ehdr->e_shentsize); + if (smemfs_pread(elf->inode, &shdr, + elf->ehdr->e_shentsize, offset) + != elf->ehdr->e_shentsize) { + continue; + } + tmp = NULL; + if (strcmp(".dynamic", &elf->shstrtab[shdr.sh_name]) == 0) { + memcpy(&elf->ehdr_dynamic, &shdr, sizeof(Elf32_Shdr)); + tmp = (void*)&elf->dynamic; + } + if (strcmp(".dynstr", &elf->shstrtab[shdr.sh_name]) == 0) + tmp = (void*)&elf->dynstr; + if (strcmp(".dynsym", &elf->shstrtab[shdr.sh_name]) == 0) + tmp = (void*)&elf->dynsym; + if (tmp == NULL) + continue; + *tmp = reloc_dump_section(elf->inode, &shdr); + } + return (0); +} + +/* reloc_get_dynsym(): Try to find the dynamic symbol address */ +static void *reloc_get_dynsym(struct relocinfo *info, int symid) +{ + char *name; + + if (info->dynsym == NULL || info->dynstr == NULL) + return (NULL); + //FIXME: check symid validity ! + name = &info->dynstr[info->dynsym[symid].st_name]; + for (int i = 0; gint_reloc[i].name != NULL; ++i) { + if (strcmp(name, gint_reloc[i].name) != 0) + continue; + terminal_write(" * reloc '%s'\n", name); + return ((void*)gint_reloc[i].addr); + } + terminal_write("unknown '%s' symbols\n", name); + return (NULL); +} + /* reloc_section(): Relocalise section's symbols */ -static int reloc_section(struct hworld *world, - struct smemfs_inode *inode, Elf32_Shdr *shdr) +static int reloc_rela(struct hworld *world, + struct relocinfo *info, Elf32_Shdr *shdr) { Elf32_Rela rela; uint32_t *prog; off_t offset; + void *dyn; - /* List symbols */ + if (shdr->sh_size == 0 || shdr->sh_entsize == 0) { + terminal_write("empty section\n"); + return (0); + } 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) + if (smemfs_pread(info->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; + if (ELF32_R_TYPE(rela.r_info) == R_SH_RELATIVE) { + offset = rela.r_offset; + offset -= world->memory.program.elf.vmin; + prog[offset >> 2] -= world->memory.program.elf.vmin; + prog[offset >> 2] += + (uintptr_t)world->memory.program.start; + continue; + } + if (ELF32_R_TYPE(rela.r_info) == R_SH_JMP_SLOT) { + dyn = reloc_get_dynsym(info, ELF32_R_SYM(rela.r_info)); + if (dyn == NULL) + return (-1); + offset = rela.r_offset; + offset -= world->memory.program.elf.vmin; + prog[offset >> 2] = (uintptr_t)dyn; + world->private.env = HYPERVISOR_ENV_GINT; + continue; + } + terminal_write("unknown type %x\n", rela.r_info); + return (-1); } return (hel_reloc_success); } @@ -40,21 +153,35 @@ static int reloc_section(struct hworld *world, //--- /* loader_reloc_sym(): Relocalise all symbols */ int hypervisor_elf_loader_reloc_sym(struct hworld *world, - struct smemfs_inode *inode, Elf32_Ehdr *header) + struct smemfs_inode *inode, Elf32_Ehdr *ehdr) { + struct relocinfo info; 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) { + + /* get dynamic information */ + info.inode = inode; + info.ehdr = ehdr; + if (reloc_get_dynamic_info(&info) != 0) + return (-1); + + /* find all reloc section */ + //TODO : support SH_REL + //TODO : check if the GOT, PLT sections are relocalized ! + for (int i = 1 ; i < ehdr->e_shnum ; ++i) { + offset = ehdr->e_shoff + (i * ehdr->e_shentsize); + if (smemfs_pread(inode, &shdr, ehdr->e_shentsize, offset) + != ehdr->e_shentsize) { return (hel_reloc_size_error); } - if (shdr.sh_type != SHT_RELA) - continue; - if (reloc_section(world, inode, &shdr) != hel_reloc_success) + if (shdr.sh_type == SHT_RELA + && reloc_rela(world, &info, &shdr) != hel_reloc_success) return (hel_reloc_error); + if (shdr.sh_type == SHT_REL) { + terminal_write("SHT_REL not yet supported\n"); + return (hel_reloc_error); + } } return (hel_reloc_success); } diff --git a/src/hypervisor/kernel.S b/src/hypervisor/kernel.S index 8f27bdb..32008af 100644 --- a/src/hypervisor/kernel.S +++ b/src/hypervisor/kernel.S @@ -37,86 +37,139 @@ abi_error: abi_trapa_reg: .long 0xff000020 abi_syscall_table: - .long 0x00000000 ! _hypervisor_kernel_world_switch - .long 0x00000000 + .long _hypervisor_kernel_world_switch + .long 0x00000000 ! _hypervisor_kernel_schedule -#if 0 -/* hypervisor world_switch(): Performs a world switch */ +/* hypervisor world_switch(struct hworld *world): Performs a world switch + + This hypervisor call will check the world validity then it will save the + current world environment information, install the new world then perform + an world switch. */ _hypervisor_kernel_world_switch: + /* enable exception but block all interruption */ + mov.l sr_ws_config, r0 + stc sr, r1 + or r0, r1 + ldc r1, sr + /* check potential error */ + stc R4_BANK, r4 tst r4, r4 bt kernel_world_error + mov.l hypervisor_world_current, r5 + mov.l @r5, r5 tst r5, r5 bt kernel_world_error + /* switch stack (user -> kernel) */ + mov.l r15, @r5 + mov.l @(4, r5), r15 + /* save the current context */ sts.l pr, @-r15 mov.l r4, @-r15 mov.l r5, @-r15 mov.l drivers_context_save, r0 jsr @r0 - mov.l @r4, r4 + mov.l @(8, r5), r4 mov.l @r15+, r5 mov.l @r15+, r4 - ldc.l @r15+, pr + lds.l @r15+, pr + + /* switch stack (kernel -> user) */ + mov.l r15, @(4, r5) + mov.l @r5, r15 /* save cpu context */ - add #92, r4 - mov.l pr, @-r4 - stc.l spc, @-r4 - stc.l ssr, @-r4 - sts.l mach, @-r4 - sts.l macl, @-r4 - stc.l gbr, @-r4 - mov.l r15, @-r4 - mov.l r14, @-r4 - mov.l r13, @-r4 - mov.l r12, @-r4 - mov.l r11, @-r4 - mov.l r10, @-r4 - mov.l r9, @-r4 - mov.l r8, @-r4 - stc.l R7_BANK, @-r4 - stc.l R6_BANK, @-r4 - stc.l R5_BANK, @-r4 - stc.l R4_BANK, @-r4 - stc.l R3_BANK, @-r4 - stc.l R2_BANK, @-r4 - stc.l R1_BANK, @-r4 - stc.l R0_BANK, @-r4 + add #100, r5 + sts.l pr, @-r5 + stc.l spc, @-r5 + stc.l ssr, @-r5 + sts.l mach, @-r5 + sts.l macl, @-r5 + stc.l gbr, @-r5 + mov.l r15, @-r5 + mov.l r14, @-r5 + mov.l r13, @-r5 + mov.l r12, @-r5 + mov.l r11, @-r5 + mov.l r10, @-r5 + mov.l r9, @-r5 + mov.l r8, @-r5 + stc.l R7_BANK, @-r5 + stc.l R6_BANK, @-r5 + stc.l R5_BANK, @-r5 + stc.l R4_BANK, @-r5 + stc.l R3_BANK, @-r5 + stc.l R2_BANK, @-r5 + stc.l R1_BANK, @-r5 + stc.l R0_BANK, @-r5 /* restore cpu context */ - add #4, r5 - ldc.l @r5+, R0_BANK - ldc.l @r5+, R1_BANK - ldc.l @r5+, R2_BANK - ldc.l @r5+, R3_BANK - ldc.l @r5+, R4_BANK - ldc.l @r5+, R5_BANK - ldc.l @r5+, R6_BANK - ldc.l @r5+, R7_BANK - mov.l @r5+, r8 - mov.l @r5+, r9 - mov.l @r5+, r10 - mov.l @r5+, r11 - mov.l @r5+, r12 - mov.l @r5+, r13 - mov.l @r5+, r14 - mov.l @r5+, r15 - ldc.l @r5+, gbr - lds.l @r5+, macl - lds.l @r5+, mach - ldc.l @r5+, ssr - ldc.l @r5+, spc - lds.l @r5+, pr + add #12, r4 + ldc.l @r4+, R0_BANK + ldc.l @r4+, R1_BANK + ldc.l @r4+, R2_BANK + ldc.l @r4+, R3_BANK + ldc.l @r4+, R4_BANK + ldc.l @r4+, R5_BANK + ldc.l @r4+, R6_BANK + ldc.l @r4+, R7_BANK + mov.l @r4+, r8 + mov.l @r4+, r9 + mov.l @r4+, r10 + mov.l @r4+, r11 + mov.l @r4+, r12 + mov.l @r4+, r13 + mov.l @r4+, r14 + mov.l @r4+, r15 + ldc.l @r4+, gbr + lds.l @r4+, macl + lds.l @r4+, mach + ldc.l @r4+, ssr + ldc.l @r4+, spc + lds.l @r4+, pr - /* restore drivers context */ - /* TODO */ + /* switch stack (user -> kernel) */ + add #-100, r4 + mov.l r15, @r4 + mov.l @(4, r4), r15 - /* force install hypervisor */ - /* TODO */ + /* indicate that the world has changed */ + mov.l hypervisor_world_current, r0 + mov.l r4, @r0 + + /* save the current context + Note that the SR register can be restored. So, interruption / + exceptions can occur during this lack of time between JSR and the + resotoration of the SR register. */ + stc.l ssr, @-r15 + stc.l spc, @-r15 + sts.l pr, @-r15 + mov.l r4, @-r15 + stc.l sr, @-r15 + mov.l drivers_context_restore, r0 + jsr @r0 + mov.l @(8, r4), r4 + ldc.l @r15+, sr + mov.l @r15+, r4 + lds.l @r15+, pr + ldc.l @r15+, spc + ldc.l @r15+, ssr + + /* switch stack (kernel -> user) */ + mov.l r15, @(4, r4) + mov.l @r4, r15 + + /* force hypervisor VBR re-installation, because it possible that the + VBR has been changed during the handler */ + mov.l hypervisor_vbr_redirect, r0 + mov.l hypervisor_vbr, r1 + stc vbr, r2 + mov.l r2, @r0 + ldc.l @r1+, vbr /* perform the world switch */ rte @@ -125,4 +178,12 @@ _hypervisor_kernel_world_switch: kernel_world_error: rts mov #-2, r0 -#endif + +.align 4 +sr_ws_config: .long 0x600000f0 +!wswitch_debug: .long _wswitch_debug +hypervisor_vbr: .long _hypervisor_vbr +hypervisor_vbr_redirect: .long _hypervisor_vbr_redirect +hypervisor_world_current: .long _hypervisor_world_current +drivers_context_save: .long _drivers_save +drivers_context_restore: .long _drivers_restore diff --git a/src/hypervisor/wswitch.c b/src/hypervisor/wswitch.c index 7cb731f..511a7d5 100644 --- a/src/hypervisor/wswitch.c +++ b/src/hypervisor/wswitch.c @@ -2,6 +2,7 @@ // hypervisor:wsiwtch - hypervisor world switch //--- #include "fxBoot/hypervisor.h" +#include "fxBoot/terminal.h" #include #include @@ -10,6 +11,7 @@ /* internal globals information */ HYPERVISOR_BSS void *hypervisor_current_vbr = NULL; HYPERVISOR_BSS struct hworld *hypervisor_world_queue = NULL; +extern struct hworld *hypervisor_world_current; extern struct hworld *hypervisor_world; //--- @@ -57,10 +59,10 @@ struct hworld *hypervisor_wswitch_world_alloc(void) world->stack.user = world->memory.stack.user; world->stack.user += HYPERVISOR_STACK_USER_SIZE; world->stack.user = (void*)((uintptr_t)world->stack.user & ~3); + world->context.cpu.reg[15] = (uintptr_t)world->stack.user; return (world); } - /* hypervisor_wswitch_create(): Create a new world */ struct hworld *hypervisor_wswitch_create(void) { @@ -149,7 +151,15 @@ int hypervisor_wswitch(struct hworld *world) return (-1); if (world->private.status != HYPERVISOR_STATUS_INIT) return (-2); + int retval; hypervisor_install(); - //hypervisor_kernel_world_yield(hypervisor_world, world); - return (0); + tracer_set_session(world->private.debug.tracer); + terminal_error("world switch to:\ncurr: %p\nnext: %p\n", + hypervisor_world_current, world); + __asm__ volatile ( + "mov %0, r4;" + "trapa #0;" + "mov r0, %0;" + : "=r"(retval) : "r"(world) : "r4", "r0"); + return (retval); } diff --git a/src/terminal/write.c b/src/terminal/write.c index d8f535d..290b8ab 100644 --- a/src/terminal/write.c +++ b/src/terminal/write.c @@ -28,3 +28,25 @@ int terminal_write(const char *format, ...) dupdate(); return (nb); } + +/* terminal_write() - printf wrapper for the terminal device */ +int terminal_error(const char *format, ...) +{ + char buffer[1024]; + va_list ap; + int nb; + + /* process the format */ + va_start(ap, format); + nb = vsnprintf(buffer, 1024, format, ap); + va_end(ap); + + /* update the internal buffer */ + terminal_buffer_insert(buffer, nb); + + /* display the internal buffer */ + dclear(terminal.private.color.bg); + terminal_buffer_display(); + dupdate_noint(); + return (nb); +} diff --git a/tests/symboltest/compilation.sh b/tests/symboltest/compilation.sh new file mode 100644 index 0000000..1252111 --- /dev/null +++ b/tests/symboltest/compilation.sh @@ -0,0 +1,7 @@ +#! /usr/bin/bash + +#non#sh-elf-gcc -nostdlib -m3 -mb -mrenesas -ffreestanding -c test.c -o test.o -DFXCG50 +# @note: -mrenesas change the calling convention of varaiodic arguments + +sh-elf-gcc -fPIE -nostdlib -m3 -mb -ffreestanding -c test.c -o test.o -DFXCG50 +sh-elf-ld -pie test.o -o dyntest -L. -lgint-cg-dyn -T linker.ld diff --git a/tests/symboltest/dyntest b/tests/symboltest/dyntest new file mode 100755 index 0000000..acba994 Binary files /dev/null and b/tests/symboltest/dyntest differ diff --git a/tests/symboltest/libgint-cg-dyn.so b/tests/symboltest/libgint-cg-dyn.so new file mode 100755 index 0000000..0f98bae Binary files /dev/null and b/tests/symboltest/libgint-cg-dyn.so differ diff --git a/tests/symboltest/linker.ld b/tests/symboltest/linker.ld new file mode 100644 index 0000000..d24523a --- /dev/null +++ b/tests/symboltest/linker.ld @@ -0,0 +1,17 @@ +OUTPUT_ARCH(sh4) +OUTPUT_FORMAT(elf32-sh) +ENTRY(_main) + +SECTIONS +{ + . = SIZEOF_HEADERS; + .text : { + *(.text) + } + .data : { + *(.data) + } + .bss : { + *(.bss) + } +} diff --git a/tests/symboltest/test.c b/tests/symboltest/test.c new file mode 100644 index 0000000..b408db0 --- /dev/null +++ b/tests/symboltest/test.c @@ -0,0 +1,14 @@ +#include +#include + +int main(void) +{ + while (1) { + dclear(C_WHITE); + dtext(0, 0, C_BLACK, "Relocalized addin :D"); + dprint(0, 10, C_RED, "test %d", 10); + dupdate(); + getkey(); + } + return (0); +} diff --git a/tests/symboltest/user_dynlib_test.ld b/tests/symboltest/user_dynlib_test.ld new file mode 100644 index 0000000..2a2e9b3 --- /dev/null +++ b/tests/symboltest/user_dynlib_test.ld @@ -0,0 +1,87 @@ +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 +{ + /* Code */ + .text : { + *(.text); + *(.text.*); + + } > userram + + /* Read-only sections */ + .rodata : { + /* 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) + } +} diff --git a/tests/test.elf b/tests/test.elf new file mode 100755 index 0000000..81d7906 Binary files /dev/null and b/tests/test.elf differ diff --git a/tests/test.map b/tests/test.map index f64e4d8..d1a3b6f 100644 --- a/tests/test.map +++ b/tests/test.map @@ -15,73 +15,72 @@ Linker script and memory map LOAD build/main.o LOAD build/syscalls.o -.text 0x0000000000000000 0x230 +.text 0x0000000000000000 0x220 *(.text) - .text 0x0000000000000000 0x68 build/main.o + .text 0x0000000000000000 0x5c 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 + *fill* 0x000000000000005c 0x4 + .text 0x0000000000000060 0xe0 build/syscalls.o + 0x0000000000000060 _casio_GetKey + 0x0000000000000074 _casio_PrintMini + 0x00000000000000a4 _casio_Bdisp_AllClr_VRAM + 0x00000000000000b4 _casio_Bdisp_PutDisp_DD + 0x00000000000000c4 _casio_Bfile_CreateFile + 0x00000000000000d4 _casio_Bfile_OpenFile + 0x00000000000000e4 _casio_Bfile_CloseFile + 0x00000000000000f4 _casio_Bfile_WriteFile + 0x0000000000000104 _casio_Bfile_ReadFile + 0x0000000000000114 _casio_Malloc + 0x0000000000000124 _casio_Free *(.text.*) *(.rodata) - .rodata 0x0000000000000150 0x25 build/main.o + .rodata 0x0000000000000140 0x28 build/main.o *(.rodata.*) *(.hash) - *fill* 0x0000000000000175 0x3 - .hash 0x0000000000000178 0x10 build/main.o + .hash 0x0000000000000168 0x10 build/main.o *(.dynsym) - .dynsym 0x0000000000000188 0x10 build/main.o + .dynsym 0x0000000000000178 0x10 build/main.o *(.dynstr) - .dynstr 0x0000000000000198 0x1 build/main.o + .dynstr 0x0000000000000188 0x1 build/main.o *(.dynbss) - .dynbss 0x0000000000000199 0x0 build/main.o + .dynbss 0x0000000000000189 0x0 build/main.o *(.dynamic) - *fill* 0x0000000000000199 0x3 - .dynamic 0x000000000000019c 0x88 build/main.o - 0x000000000000019c _DYNAMIC + *fill* 0x0000000000000189 0x3 + .dynamic 0x000000000000018c 0x88 build/main.o + 0x000000000000018c _DYNAMIC *(.plt) - .plt 0x0000000000000224 0x0 build/main.o + .plt 0x0000000000000214 0x0 build/main.o *(.got.plt) - .got.plt 0x0000000000000224 0xc build/main.o - 0x0000000000000224 _GLOBAL_OFFSET_TABLE_ + .got.plt 0x0000000000000214 0xc build/main.o + 0x0000000000000214 _GLOBAL_OFFSET_TABLE_ *(.got.*) - .got.funcdesc 0x0000000000000230 0x0 build/main.o + .got.funcdesc 0x0000000000000220 0x0 build/main.o *(.got) - .got 0x0000000000000230 0x0 build/main.o + .got 0x0000000000000220 0x0 build/main.o *(.rofixup) - .rofixup 0x0000000000000230 0x0 build/main.o + .rofixup 0x0000000000000220 0x0 build/main.o -.rela.dyn 0x0000000000000230 0x48 +.rela.dyn 0x0000000000000220 0x48 *(.rela.plt) - .rela.plt 0x0000000000000230 0x0 build/main.o + .rela.plt 0x0000000000000220 0x0 build/main.o *(.rela.got) - .rela.got 0x0000000000000230 0x0 build/main.o + .rela.got 0x0000000000000220 0x0 build/main.o *(.rela.got.*) .rela.got.funcdesc - 0x0000000000000230 0x0 build/main.o + 0x0000000000000220 0x0 build/main.o *(.rela.*) - .rela.text 0x0000000000000230 0x48 build/main.o + .rela.text 0x0000000000000220 0x48 build/main.o *(.rela.text) *(.real.data) -.data 0x0000000000000278 0x0 +.data 0x0000000000000268 0x0 *(.data) - .data 0x0000000000000278 0x0 build/main.o - .data 0x0000000000000278 0x0 build/syscalls.o + .data 0x0000000000000268 0x0 build/main.o + .data 0x0000000000000268 0x0 build/syscalls.o *(.data.*) *(.bss) - .bss 0x0000000000000278 0x0 build/main.o - .bss 0x0000000000000278 0x0 build/syscalls.o + .bss 0x0000000000000268 0x0 build/main.o + .bss 0x0000000000000268 0x0 build/syscalls.o *(.bss.*) *(COMMON)