From f38bea70243642b13ebf53eb44009e337e8b612d Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Sat, 8 Jan 2022 11:49:29 +0100 Subject: [PATCH] VxKernel - 0.1.0 : Base @add <> board/fx9860g/board : board description for the fx9860G device <> board/fx9860g/fx9860g.ld : linker script for the fx9860G device <> board/fx9860g/initialize : device-specific entry for the fx9860g device <> board/fxcg50/_Exit : define our own _Exit() function for the fxlibc <> board/fxcg50/board : board description for the fxcg50 device <> board/fxcg50/fxcg50.ld : linker script for the fxcg50 device <> board/fxcg50/hardware : hardware detection for the fxcg50 device <> board/fxcg50/initialize : device-specific entry for the fxcg50 device <> config : configuration script for the vxKernel build system <> make/Makefile : initial Makefile (must be used with the vxsdk) <> include/vhex/arch/fxcg50/hardware : hardware definition for the fxcg50 device <> include/vhex/defs/attributes : define common attributes macros <> include/vhex/defs/types : define all types information <> include/vhex/hardware : expose hardware "module" API <> include/vhex/kernel : expose kernel "module" API <> include/vhex/mmu : expose MMU "module" API <> include/vhex/mpu/sh7305/mmu : MMU hardware definition <> include/vhex/mpu/sh7305/pfc : PFC hardware definition <> src/drivers/mpu/sh/sh7305/mmu : MMU driver definition <> src/kernel/kernel : kinit() and kquit() definition --- board/fx9860g/board.ini | 11 + board/fx9860g/fx9860g.ld | 88 ++++++++ board/fx9860g/initialize.c | 10 + board/fxcg50/_Exit.c | 13 ++ board/fxcg50/board.ini | 11 + board/fxcg50/fxcg50.ld | 113 ++++++++++ board/fxcg50/hardware.c | 66 ++++++ board/fxcg50/initialize.c | 129 +++++++++++ config | 227 +++++++++++++++++++ include/vhex/arch/fxcg50/hardware.h | 12 + include/vhex/defs/attributes.h | 37 +++ include/vhex/defs/types.h | 50 +++++ include/vhex/hardware.h | 27 +++ include/vhex/kernel.h | 10 + include/vhex/mmu.h | 16 ++ include/vhex/mpu/sh7305/mmu.h | 123 ++++++++++ include/vhex/mpu/sh7305/pfc.h | 78 +++++++ make/Makefile | 336 ++++++++++++++++++++++++++++ src/drivers/mpu/sh/sh7305/mmu.c | 43 ++++ src/kernel/kernel.c | 20 ++ 20 files changed, 1420 insertions(+) create mode 100644 board/fx9860g/board.ini create mode 100644 board/fx9860g/fx9860g.ld create mode 100644 board/fx9860g/initialize.c create mode 100644 board/fxcg50/_Exit.c create mode 100644 board/fxcg50/board.ini create mode 100644 board/fxcg50/fxcg50.ld create mode 100644 board/fxcg50/hardware.c create mode 100644 board/fxcg50/initialize.c create mode 100755 config create mode 100644 include/vhex/arch/fxcg50/hardware.h create mode 100644 include/vhex/defs/attributes.h create mode 100644 include/vhex/defs/types.h create mode 100644 include/vhex/hardware.h create mode 100644 include/vhex/kernel.h create mode 100644 include/vhex/mmu.h create mode 100644 include/vhex/mpu/sh7305/mmu.h create mode 100644 include/vhex/mpu/sh7305/pfc.h create mode 100644 make/Makefile create mode 100644 src/drivers/mpu/sh/sh7305/mmu.c create mode 100644 src/kernel/kernel.c diff --git a/board/fx9860g/board.ini b/board/fx9860g/board.ini new file mode 100644 index 0000000..9f8c8ea --- /dev/null +++ b/board/fx9860g/board.ini @@ -0,0 +1,11 @@ +[meta] +description=Casio's Fx9860g calculator board description + +[drivers] +screen=T6K73A,ML9801 +mpu=sh7305 + +[toolchain] +prefix=sh-elf-vhex- +cflags=-DFX9860G,-m4-nofpu,-mb +libs=-lgcc diff --git a/board/fx9860g/fx9860g.ld b/board/fx9860g/fx9860g.ld new file mode 100644 index 0000000..542e420 --- /dev/null +++ b/board/fx9860g/fx9860g.ld @@ -0,0 +1,88 @@ +/* + Linker script for the fxcg50 platform. +*/ + +OUTPUT_FORMAT(elf32-sh) +OUTPUT_ARCH(sh3) +ENTRY(_initilize) + +/* +** 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) + } > 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/board/fx9860g/initialize.c b/board/fx9860g/initialize.c new file mode 100644 index 0000000..8ca5eed --- /dev/null +++ b/board/fx9860g/initialize.c @@ -0,0 +1,10 @@ +#include + +/* for now, just involve the main routine */ +void initialize(void) +{ + extern int main(void); + + main(); + while(1) { __asm__ volatile ("sleep"::); } +} diff --git a/board/fxcg50/_Exit.c b/board/fxcg50/_Exit.c new file mode 100644 index 0000000..685ae58 --- /dev/null +++ b/board/fxcg50/_Exit.c @@ -0,0 +1,13 @@ +#include + +/* Jumping there will properly unwind and leave the kernel */ +extern jmp_buf vhex_exitbuf; +/* Return value of main() */ +extern int vhex_exitcode; + +/* Standard _Exit, used by the fxlibc exit() to leave control */ +void _Exit(int rc) +{ + vhex_exitcode = rc; + longjmp(vhex_exitbuf, 1); +} diff --git a/board/fxcg50/board.ini b/board/fxcg50/board.ini new file mode 100644 index 0000000..b04f743 --- /dev/null +++ b/board/fxcg50/board.ini @@ -0,0 +1,11 @@ +[meta] +description=Casio's Fxcg50 calculator board description + +[drivers] +screen=R61524 +mpu=sh7305 + +[toolchain] +prefix=sh-elf-vhex- +cflags=-DFXCG50,-m4-nofpu,-mb +libs=-lgcc diff --git a/board/fxcg50/fxcg50.ld b/board/fxcg50/fxcg50.ld new file mode 100644 index 0000000..d2e925b --- /dev/null +++ b/board/fxcg50/fxcg50.ld @@ -0,0 +1,113 @@ +/* + Linker script for the fxcg50 platform. +*/ + +OUTPUT_FORMAT(elf32-sh) +OUTPUT_ARCH(sh4) +ENTRY(_initialize) + +/* +** Linker script for user executables. +*/ +MEMORY +{ + /* virtual memory, read-write segment */ + userram (WX) : o = 0x00000000, l = 256k +} + +SECTIONS +{ + /* Code */ + .text : { + *(.text); + *(.text.*); + + _bctors = . ; + *(.ctors .ctors.*) + _ectors = . ; + + _bdtors = . ; + *(.dtors .dtors.*) + _edtors = . ; + } > 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) + } > userram + + /* Relocatable sections */ + .rela.dyn : { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } > userram + .rela.plt : { + *(.rela.plt) + } > userram + + .plt : { *(.plt) } > userram + .iplt : { *(.iplt) } > 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/board/fxcg50/hardware.c b/board/fxcg50/hardware.c new file mode 100644 index 0000000..272ad59 --- /dev/null +++ b/board/fxcg50/hardware.c @@ -0,0 +1,66 @@ +//--- +// vhex:core:hardware - Platform information and hardware detection +//--- +#include "vhex/mpu/sh7305/pfc.h" +#include "vhex/arch/fxcg50/hardware.h" +#include "vhex/hardware.h" +#include "vhex/mmu.h" + + +/* Holds information about the current platform */ +uintptr_t vhex[HW_KEYS]; + +/* Processor Version Register */ +#define PVR (*((volatile uint32_t *)0xff000030)) +/* Product Register */ +#define PRR (*((volatile uint32_t *)0xff000044)) + + + +/* ram_get_size() : try to determine the RAM size */ +static ptrdiff_t ram_get_size(uintptr_t start_ram) +{ + volatile uint32_t *ptr = (void*)start_ram; + volatile uint32_t *tst = (void*)start_ram; + uintptr_t backup; + + //TODO: use UTLB page size information to walk through each pages + while (1) { + ptr = &ptr[4096]; + backup = ptr[0]; + ptr[0] = 0xdeadbeef; + if (ptr[0] != 0xdeadbeef || ptr[0] == tst[0]) break; + ptr[0] = backup; + } + ptr[0] = backup; + return ((ptrdiff_t)((uintptr_t)ptr - (uintptr_t)tst)); +} + + + +/* hw_detect(): Basic hardware detection */ +void hw_detect(void) +{ + /* get MPU and CPU information */ + vhex[HWMPU] = HWMPU_SH7305; + vhex[HWCPUVR] = PVR; + vhex[HWCPUPR] = PRR; + + /* We can differentiate the Prizm device from the fxcg50 device by + checking its stack */ + uintptr_t stack; + __asm__("mov r15, %0" : "=r"(stack)); + + /* detect the device type */ + vhex[HWDEVICE] = HWDEVICE_FXCG50; + if (stack < 0x8c000000) + vhex[HWDEVICE] = HWDEVICE_PRIZM; + if (PVR == 0x00000000) + vhex[HWDEVICE] = HWDEVICE_FXCG_MANAGER; + + /* detect the RAM geometry */ + uintptr_t uram = mmu_translate(0x08100000, NULL); + vhex[HWRAM_PHY_USER] = uram; + vhex[HWRAM_PHY_ORIGIN] = uram & 0xff000000; + vhex[HWRAM_PHY_SIZE] = ram_get_size(uram | 0xa0000000); +} diff --git a/board/fxcg50/initialize.c b/board/fxcg50/initialize.c new file mode 100644 index 0000000..9f91bb8 --- /dev/null +++ b/board/fxcg50/initialize.c @@ -0,0 +1,129 @@ +//--- +// fxcg50:initialize - Kernel initialization and C runtime +//--- + +#include "vhex/hardware.h" +#include "vhex/kernel.h" + +#include +#include +#include + + + +/* Constructor and destructor arrays */ +extern void (*bctors)(void), (*ectors)(void); +extern void (*bdtors)(void), (*edtors)(void); + +/* User-provided main() function */ +extern int main(void); + +/* Jumping there will properly unwind and leave the kernel */ +jmp_buf vhex_exitbuf; +/* Return value of main() */ +int vhex_exitcode; + + + +/* callarray(): Call an array of functions (constructors or destructors) */ +static void callarray(void (**f)(void), void (**l)(void)) +{ + while(f < l) (*(*f++))(); +} + + + +/* initialize() : Where it all starts + + We are currently in a RAM location at a non-constant address due to the + relocalization performed by the bootloader. Moreover, we are in privileged + mode with one golden rule: + + Do not disturb the operating system + + Why we should keep this rule in mind? Because, on this particular device, + none of all hardware and software information are documented. Vhex will + therefore involve Casio's syscall to perform some interaction, especially + concerning file manipulation. + + Note that we don't need to change the stack, the kernel will use the one + given by Casio because it's big enough to store the user-application + (mainly the vxOS) and the kernel code. However, we need to keep in mind + that for this device, a lot of hardware supposition will be performed here, + chiefly concerning the memory discovery. + + +---------------+ + | | + | | + | Reserved Area | + | | + | | + + - - - - - - - + <-- virtually mapped at 0x0810000 + | _vxKernel | + | + | + | _vxOS | + + - - - - - - - + <-- Provided by the vxKernel (variable) + | | + | Stack | + | | + + - - - - - - - + <-- end of the TLB information (variable) + | | + | | + | | + | | + | kmalloc() | + | | + | | + | | + | | + | | + | | + +---------------+ <-- variable + + We know that the "user RAM" is *constantly* mapped at 0x08100000 and all the + memory reserved for the user is completely loaded and all of this information + is stored at the end of the UTLB. Moreover, the stack provided by Casio start + at the end of the "user RAM". So, the memory layout is a bit exotic and look + like above. */ +void initialize(void) +{ + /* Detect hardware information : This part is important because it will + tell us if we are running in an emulator or on a real device. */ + hw_detect(); + + /* Install Vhex, switch VBR and initialize drivers */ + kinit(); + + //TODO: add area for the kmalloc() ? + + /* We are now running on our own in kernel mode. Since we have taken + control of interrupts, pretty much any interaction with the system + will break it. We'll limit our use of syscalls and do device driving + ourselves. (Hopefully we can add cool features in the process!) */ + + /* Now that we have initialized the kernel, we are ready to start the + hosted user application, which has its own constructors and + destructors to work with. */ + + /* Here, we use exit() to allow the standard library to do + what it wants in exit() after main() finishes executing */ + if(!setjmp(vhex_exitbuf)) { + callarray(&bctors, &ectors); + exit(main()); + } + else { + callarray(&bdtors, &edtors); + } + + /* Before leaving the kernel (which will return to the bootloader menu), + we need to clean everything we changed to hardware settings and + peripheral modules. The OS is bound to be confused (and hang, or + crash, or any other kind of giving up) if we don't restore them. */ + + /* Unload vhex and give back control to the system. Driver settings + will be restored while interrupts are disabled */ + kquit(); + + + //TODO: involve manualy the Casio's OS-menu +} diff --git a/config b/config new file mode 100755 index 0000000..611a671 --- /dev/null +++ b/config @@ -0,0 +1,227 @@ +#! /bin/python3 +import sys +import configparser +import os.path +import os +import shutil + + +help_string = f""" +usage: config [options...] + +Configuration script for the Vhex unikernel. You should build out-of-tree by +creating a build directory and configuring from there. + +Options: + -h,--help + display this message + + --verbose + display more information during the compilation step + + --format=FORMAT[,format[,...]] + select the format of the library generation. You can use two format: + <> static - generate a static library + <> dynamic - generate a dynamic library + <> all - same behaviour as "--format=static,dynamic" + By default, only "dynamic" is used. + + --board[=BOARD,board[,...]] + select boards. If no board name is given, a list of all available board + will be printed. + + --prefix=PATH + installation path for all generated libraries +""".strip() + +# +# create and apply the arguments parser +# + +def parse_arguments(): + """ + The objectif of this function is to generate the "arguments object" with + all arguments passed throuth this script correctly isolated. + """ + args = { + 'board' : [], + 'format' : [], + 'verbose': False, + 'prefix': '' + } + arg_name = [ + "-h", + "--help", + "--format", + "--verbose", + "--board", + "--prefix" + ] + for arg in sys.argv[1:]: + info = arg.split("=") + if (info[0] in arg_name) == False: + print("%s: unreconized option '%s'" % (sys.argv[0],info[0])) + print("Try '%s --help' for more information" % sys.argv[0]) + exit(84) + if (info[0] in ["-h", "--help"]) == True: + print(help_string) + exit(0) + if info[0] == "--verbose": + args["verbose"] = True + continue + if info[0] == "--prefix": + args["prefix"] = info[1] + continue + if len(info) > 1: + args[info[0][2:]] = info[1].split(",") + return args + + +# +# part handlers +# + +def board_check(file, board_list): + (boards,_,_) = os.walk('../board') + (archs,_,_) = os.walk('../src/drivers/mpu') + boards = boards[1] + archs = archs[1] + + if not board_list: + print('board available:') + for board in boards: + path = '../board/%s/board.ini' % board + if not os.path.exists(path): + print('board \'%s\' does not exists' % board) + continue + conf = configparser.ConfigParser() + conf.read(path) + if not ('meta' in conf) or not ('description' in conf['meta']): + print('<> %s\t\tNo description available' % board) + continue + print('<> %s\t\t%s' % (board, conf['meta']['description'])) + exit(0) + + + valid_board_list = [] + for board in board_list: + if not (board in boards): + print("board '%s' does not exist" % board) + continue + path = '../board/%s/board.ini' % board + if not os.path.exists(path): + print("board '%s' does not have INI descriptor file" % board) + continue + conf = configparser.ConfigParser() + conf.read(path) + if not ('drivers' in conf) or not ('mpu' in conf['drivers']): + print("board '%s' does not have MPU information" % board) + continue + arch = '' + mpu = conf['drivers']['mpu'] + for _arch in archs: + if not os.path.exists('../src/drivers/mpu/%s/%s' % (_arch,mpu)): + continue + arch = _arch + break + if not arch: + print("board '%s': unreconized MPU '%s'" % (board,mpu)) + continue + + pathlist = [ + '../board/%s' % board, + '../src/drivers/mpu/%s/%s' % (_arch,mpu) + ] + for driver in conf['drivers']: + if driver == 'mpu': + continue + dpath = '../src/drivers/%s' % driver + if not os.path.exists(dpath): + print("board '%s': unreconized driver \'%s\'" % (board, dpath)) + continue + for t in conf['drivers'][driver].split(','): + tpath = dpath + '/' + t + if not os.path.exists(tpath): + print("board '%s': unreconized driver \'%s\'" % (board, t)) + continue + pathlist.append(tpath) + tpath = tpath + '/target/' + arch + if os.path.exists(tpath): + pathlist.append(tpath) + for dirent in os.listdir('../src'): + if not (dirent in ['drivers', 'arch']): + pathlist.append('../src/' + dirent) + + ldflags,cflags,prefix,libs = [],[],[],[] + if 'toolchain' in conf: + if 'prefix' in conf['toolchain']: + prefix = conf['toolchain']['prefix'] + if 'cflags' in conf['toolchain']: + cflags = conf['toolchain']['cflags'].split(',') + if 'libs' in conf['toolchain']: + libs = conf['toolchain']['libs'].split(',') + + confstr = 'CONFIG.' + board; + file.write( + confstr + '.SRC-MODULE-PATH :=' + ' '.join(pathlist) + '\n' + + confstr + '.TOOLCHAIN.LDFLAGS :=' + ' '.join(ldflags) + '\n' + + confstr + '.TOOLCHAIN.CFLAGS :=' + ' '.join(cflags) + '\n' + + confstr + '.TOOLCHAIN.PREFIX :=' + prefix + '\n' + + confstr + '.LIBS :=' + ' '.join(libs) + '\n' + ) + + if not os.path.exists(board): + os.mkdir(board) + os.symlink( + '../../board/%s/%s.ld' % (board,board), + '%s/%s.ld' % (board,board) + ) + + valid_board_list.append(board) + + file.write('CONFIG.BOARD-LIST := ' + ' '.join(valid_board_list) + '\n') + +def format_check(file, format_list): + file.write('CONFIG.FORMAT-LIST :=') + for _format in format_list: + if not (_format in ["static", "dynamic", "all"]): + print("%s: unreconized format '%s'" % (sys.argv[0], _format)) + exit(84) + if _format == 'all': + file.write(' dynamic static\n') + return + file.write(' ' + _format) + if not format_list: + file.write(' dynamic') + file.write('\n') + +def prefix_check(file, prefix): + file.write('CONFIG.INSTALL-PREFIX :=' + prefix + '\n') + +def verbose_check(file, verbose): + file.write('CONFIG.VERBOSE :=\n') + +# +# "real" entry of the script +# + +def main(): + args = parse_arguments() + + if os.path.exists('../src') == False: + print('error: you should configure from a build directory, like this:') + print(' mkdir build && cd build && ../configure [options..]') + exit(84) + + file = open('kernel.cfg', 'w') + + board_check(file, args['board']) + format_check(file, args['format']) + prefix_check(file, args['prefix']) + verbose_check(file, args['prefix']) + + if os.path.exists('Makefile'): + os.remove('Makefile') + os.symlink('../make/Makefile', 'Makefile') + +main() diff --git a/include/vhex/arch/fxcg50/hardware.h b/include/vhex/arch/fxcg50/hardware.h new file mode 100644 index 0000000..72e81cc --- /dev/null +++ b/include/vhex/arch/fxcg50/hardware.h @@ -0,0 +1,12 @@ +#ifndef __VHEX_ARCH_FXCG50_HARDWARE__ +# define __VHEX_ARCH_FXCG50_HARDWARE__ + +/* define devices list */ +#define HWDEVICE_FXCG50 0 +#define HWDEVICE_PRIZM 1 +#define HWDEVICE_FXCG_MANAGER 2 + +/* define MPU list */ +#define HWMPU_SH7305 0 + +#endif /*__VHEX_ARCH_FXCG50_HARDWARE__*/ diff --git a/include/vhex/defs/attributes.h b/include/vhex/defs/attributes.h new file mode 100644 index 0000000..b7e37d3 --- /dev/null +++ b/include/vhex/defs/attributes.h @@ -0,0 +1,37 @@ +//--- +// vhex:defs:attributes - Macros for compiler-specific attributes +//--- + +#ifndef __VHEX_DEFS_ATTRIBUTES__ +# define __VHEX_DEFS_ATTRIBUTES__ + +/* Objects from specific sections */ +#define VSECTION(x) __attribute__((section(x))) + +/* Unused parameters or variables */ +#define VUNUSED __attribute__((unused)) +/* Functions that *must* be inlined */ +#define VINLINE __attribute__((always_inline)) inline + +/* Aligned variables */ +#define VALIGNED(x) __attribute__((aligned(x))) +/* Packed structures. I require explicit alignment because if it's unspecified, + GCC cannot optimize access size, and reads to memory-mapped I/O with invalid + access sizes silently fail - honestly you don't want this to happen */ +#define VPACKED(x) __attribute__((packed, aligned(x))) +/* Packed enumerations */ +#define VPACKEDENUM __attribute__((packed)) +/* Transparent unions */ +#define VTRANSPARENT __attribute__((transparent_union)) + +/* Weak symbols */ +#define VWEAK __attribute__((weak)) + +/* Constructors */ +#define VCONSTRUCTOR __attribute__((constructor)) +#define VDESTRUCTOR __attribute__((destructor)) + +/* Functions that do not return */ +#define VNORETURN __attribute__((noreturn)) + +#endif /*__VHEX_DEFS_ATTRIBUTES__*/ diff --git a/include/vhex/defs/types.h b/include/vhex/defs/types.h new file mode 100644 index 0000000..738e282 --- /dev/null +++ b/include/vhex/defs/types.h @@ -0,0 +1,50 @@ +#ifndef __VHEX_DEFS_TYPES__ +# define __VHEX_DEFS_TYPES__ + +#include + +/* For size_t, mainly */ +#include +/* For all fixed-width integer types */ +#include +/* For human-readable boolean types */ +#include +/* Common system types: ssize_t, off_t, etc. */ +#include + +/* Fixed-width types for bit fields are quite meaningless */ +typedef unsigned int uint; + +//--- +// Structure elements +//---- + +/* Giving a type to padding bytes is misguiding, let's hide it in a macro */ +#define pad_nam2(c) _ ## c +#define pad_name(c) pad_nam2(c) +#define pad(bytes) uint8_t pad_name(__COUNTER__)[bytes] + +/* byte_union() - union between an uint8_t 'byte' element and a bit field */ +#define byte_union(name, fields) \ + union { \ + uint8_t byte; \ + struct { fields } VPACKED(1); \ + } VPACKED(1) name + +/* word_union() - union between an uint16_t 'word' element and a bit field */ +#define word_union(name, fields) \ + union { \ + uint16_t word; \ + struct { fields } VPACKED(2); \ + } VPACKED(2) name + +/* lword_union() - union between an uint32_t 'lword' element and a bit field */ +#define lword_union(name, fields) \ + union { \ + uint32_t lword; \ + struct { fields } VPACKED(4); \ + } VPACKED(4) name + + + +#endif /*__VHEX_DEFS_TYPES__*/ diff --git a/include/vhex/hardware.h b/include/vhex/hardware.h new file mode 100644 index 0000000..1992d1f --- /dev/null +++ b/include/vhex/hardware.h @@ -0,0 +1,27 @@ +#ifndef __VHEX_HARDWARE_H__ +# define __VHEX_HARDWARE_H__ + +#include + +/* hw_detect(): Basic hardware detection */ +extern void hw_detect(void); + +/* Most of the information here is going to be stored in (key, value) pairs for + predetermined keys and 32-bits values that are often integers or a set of + flags. The data will be filled by vhex or its drivers. */ +#define HW_KEYS 16 +extern uintptr_t vhex[HW_KEYS]; + +/* +** Key list +*/ + +#define HWMPU 0 /* MPU type */ +#define HWCPUVR 1 /* CPU Version Register */ +#define HWCPUPR 2 /* CPU Product Register */ +#define HWDEVICE 3 /* Device model */ +#define HWRAM_PHY_USER 4 /* Physical RAM address (user) */ +#define HWRAM_PHY_ORIGIN 5 /* Physical RAM address (origin) */ +#define HWRAM_PHY_SIZE 6 /* Physical RAM size */ + +#endif /*__VHEX_HARDWARE_H__*/ diff --git a/include/vhex/kernel.h b/include/vhex/kernel.h new file mode 100644 index 0000000..e66197d --- /dev/null +++ b/include/vhex/kernel.h @@ -0,0 +1,10 @@ +#ifndef __VHEX_KERNEL_H__ +# define __VHEX_KERNEL_H__ + +/* kinit(): Install and start vhex */ +void kinit(void); + +/* kquit(): Quit vhex and give back control to the system */ +void kquit(void); + +#endif /*__VHEX_KERNEL_H__*/ diff --git a/include/vhex/mmu.h b/include/vhex/mmu.h new file mode 100644 index 0000000..8c25148 --- /dev/null +++ b/include/vhex/mmu.h @@ -0,0 +1,16 @@ +//--- +// vhex:mmu - Memory Management Unit +//--- + +#ifndef __VHEX_MMU__ +# define __VHEX_MMU__ + +#include + +/* mmu_translate(): Get the physical address for a virtual page + Looks for a translation with the specified virtual address as start, and + returns the corresponding physical address. Only works if the argument is + page-aligned. */ +extern uintptr_t mmu_translate(uintptr_t page, size_t *size); + +#endif /*__VHEX_MMU__*/ diff --git a/include/vhex/mpu/sh7305/mmu.h b/include/vhex/mpu/sh7305/mmu.h new file mode 100644 index 0000000..ea1922d --- /dev/null +++ b/include/vhex/mpu/sh7305/mmu.h @@ -0,0 +1,123 @@ +//--- +// vhex:mpu:mmu - Memory Management Unit +// +// The MMU mainly exposes the contents of the TLB for us to inspect. +// Functions to manipulate these are exposed by . +//--- + + +#ifndef __VHEX_MPU_SH7305_MMU__ +# define __VHEX_MPU_SH7305_MMU__ + +#include + +//--- +// SH7305 TLB. Refer to: +// "Renesas SH7724 User's Manual: Hardware" +// Section 7: "Memory Management Unit (MMU)" +//--- + +/* utlb_addr - address part of a UTLB entry */ +struct utlb_addr +{ + uint VPN :22; + uint D :1; + uint V :1; + uint ASID :8; + +} VPACKED(4); + +/* utlb_data - data part of a UTLB entry */ +struct utlb_data +{ + uint :3; + uint PPN :19; + uint :1; + uint V :1; + uint SZ1 :1; + uint PR :2; + uint SZ2 :1; + uint C :1; + uint D :1; + uint SH :1; + uint WT :1; + +} VPACKED(4); + +/* sh7305_mmu - MMU definition */ +struct sh7305_mmu +{ + lword_union(PTEH, + uint32_t VPN :22; /* Virtual Page Number */ + uint32_t :2; + uint32_t ASID :8; /* Address Space Identifier */ + ); + + lword_union(PTEL, + uint32_t :3; + uint32_t PPN :19; /* Phusical Page Number */ + uint32_t :1; + uint32_t V :1; /* Valid */ + uint32_t SZ1 :1; /* Size (bit 1) */ + uint32_t PR :2; /* Protection */ + uint32_t SZ0 :1; /* Size (bit 0) */ + uint32_t C :1; /* Cacheable */ + uint32_t D :1; /* Dirty */ + uint32_t SH :1; /* Shared */ + uint32_t WT :1; /* Write-through */ + ); + + uint32_t TTB; + uint32_t TEA; + + lword_union(MMUCR, + uint32_t LRUI :6; /* Least-Recently Used ITLB */ + uint32_t :2; + uint32_t URB :6; /* UTLB Replace Boundary */ + uint32_t :2; + uint32_t URC :6; /* UTLB Replace Counter */ + uint32_t :1; + uint32_t SV :1; /* Single Virtual Memory Mode */ + uint32_t ME :1; /* TLB Extended Mode */ + uint32_t :4; + uint32_t TI :1; /* TLB Invalidate */ + uint32_t :1; + uint32_t AT :1; /* Address Translation */ + ); + pad(0x20); + + lword_union(PTEA, + uint32_t :18; + uint32_t EPR :6; + uint32_t ESZ :4; + uint32_t :4; + ); + pad(0x38); + + lword_union(PASCR, + uint32_t :24; + uint32_t UBC :1; /* Control register area */ + uint32_t UB6 :1; /* Area 6 */ + uint32_t UB5 :1; /* Area 5 */ + uint32_t UB4 :1; /* Area 4 */ + uint32_t UB3 :1; /* Area 3 */ + uint32_t UB2 :1; /* Area 2 */ + uint32_t UB1 :1; /* Area 1 */ + uint32_t UB0 :1; /* Area 0 */ + ); + pad(4); + + lword_union(IRMCR, + uint32_t :27; + uint32_t R2 :1; /* Re-fetch after Register 2 change */ + uint32_t R1 :1; /* Re-fetch after Register 1 change */ + uint32_t LT :1; /* Re-fetch after LDTLB */ + uint32_t MT :1; /* Re-fetch after writing TLB */ + uint32_t MC :1; /* Re-fetch after writing insn cache */ + ); + +} VPACKED(4); + +#define SH7305_MMU (*(volatile struct sh7305_mmu *)0xff000000) + +#endif /*__VHEX_MPU_SH7305_MMU__*/ diff --git a/include/vhex/mpu/sh7305/pfc.h b/include/vhex/mpu/sh7305/pfc.h new file mode 100644 index 0000000..93c4d00 --- /dev/null +++ b/include/vhex/mpu/sh7305/pfc.h @@ -0,0 +1,78 @@ +//--- +// vhex:mpu:pfc - Pin Function Controller +// +// The Pin Function Controller has a simple register interface, the main +// difficulty is still understanding the role of its pins. +//--- + +#ifndef __VHEX_MPU_SH7305_PFC__ +# define __VHEX_MPU_SH7305_PFC__ + +#include +#include + +//--- +// SH7305 Pin Function Controller. Refer to: +// "Renesas SH7705 Group Hardware Manual" +// Section 19: "Pin Function Controller" +// +// Note that we don't have any reliable information concerning this module, this +// is why we don't havec any bitfields here. +//--- + +struct sh7305_pfc +{ + /* Control registers */ + uint16_t PACR; + uint16_t PBCR; + uint16_t PCCR; + uint16_t PDCR; + uint16_t PECR; + uint16_t PFCR; + uint16_t PGCR; + uint16_t PHCR; + uint16_t PJCR; + uint16_t PKCR; + uint16_t PLCR; + uint16_t SCPCR; /* Port SC control register */ + uint16_t PMCR; + uint16_t PNCR; + + pad(4); + + /* Data registers */ + uint8_t PADR; + pad(1); + uint8_t PBDR; + pad(1); + uint8_t PCDR; + pad(1); + uint8_t PDDR; + pad(1); + uint8_t PEDR; + pad(1); + uint8_t PFDR; + pad(1); + uint8_t PGDR; + pad(1); + uint8_t PHDR; + pad(1); + uint8_t PJDR; + pad(1); + uint8_t PKDR; + pad(1); + uint8_t PLDR; + pad(1); + uint8_t SCPDR; /* Port SC data register */ + pad(1); + uint8_t PMDR; + pad(1); + uint8_t PNDR; + pad(1); + +} VPACKED(4); + +#define SH7305_PFC (*((volatile struct sh7305_pfc *)0xa4000100)) + + +#endif /*__VHEX_MPU_SH7305_PFC__*/ diff --git a/make/Makefile b/make/Makefile new file mode 100644 index 0000000..c495a61 --- /dev/null +++ b/make/Makefile @@ -0,0 +1,336 @@ +#!/usr/bin/make -f +# --- +# Project: vxKernek - Vhex project kernel +# Author: yann.magnin@epitech.eu +# +# TODO: +# <> support header modification detection +# <> remove "target" folder on any directory +# <> installation rule +# <> uninstall rule +# --- + + +#--- +# Build rules +#--- + +# Make selects the first rule set when you type "make" but, in our case, we are +# going to generate most of the rules. So, we set a placeholder to force the +# "all" rule to be the "first" rule +first: all + +# display the library version +version: + @echo "$(VXSDK_PKG_VERSION)" + +# Display helper +help: + @ echo 'Rules listing:' + @ echo '... all the default, if no target is provided' + @ echo '... clean remove build object' + @ echo '... fclean remove all generated object' + @ echo '... re same as `make fclean all`' + @ echo '... version display version' + @ echo '... install install the library' + @ echo '... uninstall uninstall the library' + +.PHONY: help version first + + + + +#--- +# Check config step validity +#--- + +# Require configuration file +CONFIG := kernel.cfg +ifeq "$(wildcard $(CONFIG))" "" +$(error "config file $(CONFIG) does not exist (you should use `../configure`") +endif +include $(CONFIG) + + + + +#--- +# Variables definition +#--- + +# Many variables will be provided by the "kernel.cfg" file (generated during +# the configuration path). It will defines: +# <> BOARD - indicate the target board list +# <> {BOARD}-SRC-MODULE-PATH - list of all sources path for a specific board +# <> {BOARD}-TOOLCHAIN-PREFIX - toolchain prefix for a board (sh-elf, ...) +# <> FORMAT - format for the kernel (static, dynamic) + +# color definition, for swagg :D +red := \033[1;31m +green := \033[1;32m +blue := \033[1;34m +white := \033[1;37m +nocolor := \033[1;0m + + + +#--- +# Rules definition +#--- + +# The objectif is to generate a building this build tree: +# +# build/: +# |-- kernel.cfg +# |-- /: +# | |-- /: +# | | |-- obj/: +# | | | |-- main.o +# ... +# | | | `-- initialize.o +# | | `-- map +# | |-- .ld +# | `-- libvxkernel-.[so/a] +# `-- Makefile + +# Function that will generate a rule for one object file +# @param +# *1 - GCC name (with specific prefix if needed) +# *2 - CFLAGS list +# *3 - source file path +# *4 - build root directory path +# *5 - object file compilation rule list +# *6 - unique id (used to generate unique variable name (workaround)) +define generate-compile-file-rule + +# generate the object file path +# @note +# <> This is alse the generated rule name +# <> step: +# 1) ../board/path/file.c -> ../board/path/file +# 2) .._board_path_file -> board_path_file +# 3) board_path_file.o -> {build path}/board_path_file.o +tname := $(strip $6) +obj-$(tname)-name := $$(basename $3) +obj-$(tname)-name := $$(subst /,_,$$(obj-$(tname)-name)) +obj-$(tname)-name := $$(patsubst .._%,$4/%.o,$$(obj-$(tname)-name)) + +# generate the building rule + +$$(obj-$(tname)-name): $3 + @ mkdir -p $$(dir $$@) +ifeq ($(CONFIG.VERBOSE),) + @ printf "$(green)>$(nocolor) $(white)$$@$(nocolor)\n" + @ $1 $2 -o $$@ -c $$< +else + $1 $2 -o $$@ -c $$< +endif + +# register the buildinf rule + +$5 += $$(obj-$(tname)-name) + +endef + + + +# Function that will generate all rules for a specific board and format +# @params +# *1 - board name +# *2 - format name (static or dynamic) +# *3 - rules list variable name +define generate-target-lib + +# generate common information +# @note: +# Because we generate rule "on-the-fly" we need to create unique variable +# definition because make is not a "scoped" language. (therefore, when a +# variable is created, it will never be destroyed until the end of the script) +t-$1-$2-build := $(VXSDK_BUILD_PREFIX)/$1/$2 + +# generate compilation flags + +t-$1-$2-ar := $$(CONFIG.$1.TOOLCHAIN.PREFIX)ar +t-$1-$2-ld := $$(CONFIG.$1.TOOLCHAIN.PREFIX)ld +t-$1-$2-gcc := $$(CONFIG.$1.TOOLCHAIN.PREFIX)gcc +t-$1-$2-ldflags := $$(CONFIG.$1.TOOLCHAIN.LDFLAGS) +t-$1-$2-cflags := $$(CONFIG.$1.TOOLCHAIN.CFLAGS) +t-$1-$2-cflags += -fpic -ffreestanding -nostdlib -fstrict-volatile-bitfields + +# generate compiler information (used to find some library like libgcc.a) +t-$1-$2-gcc-base := $$(shell $$(CONFIG.$1.TOOLCHAIN.PREFIX)gcc --print-search-dirs | grep install | sed 's/install: //') +t-$1-$2-gcc-header := $$(t-$1-$2-gcc-base)/include +t-$1-$2-cflags += -I../include -I.. -I$$(t-$1-$2-gcc-header) +t-$1-$2-cflags += -L../lib -L.. -L$$(t-$1-$2-gcc-base) + + +# generate format-specific flags + +t-$1-$2-exec := +ifeq ($2,static) + t-$1-$2-exec := $1/libvhex-$1.a +endif +ifeq ($2,dynamic) + t-$1-$2-ldflags += -shared -T $1/$1.ld + t-$1-$2-ldflags += -soname=libvxkernel-$1-$(VXSDK_PKG_VERSION).so + t-$1-$2-ldflags += -Map=$$(t-$1-$2-build)/map + t-$1-$2-exec := $1/libvxkernel-$1.so +endif + +# generate file's sources list, based on the configuration step + +t-$1-$2-dir := $$(foreach module,$$(CONFIG.$1.SRC-MODULE-PATH),\ + $$(shell find $$(module) -type d)) +t-$1-$2-src := $$(foreach path,$$(t-$1-$2-dir),\ + $$(wildcard $$(path)/*.c) \ + $$(wildcard $$(path)/*.S) \ + $$(wildcard $$(path)/*.s)) + +# generate file's compilation rules and all object filename into an object +# list variable, this will be used by the `main` rule + +t-$1-$2-obj := +$$(foreach source,$$(t-$1-$2-src),$$(eval \ + $$(call generate-compile-file-rule,\ + $$(t-$1-$2-gcc),\ + $$(t-$1-$2-cflags),\ + $$(source),\ + $$(t-$1-$2-build),\ + t-$1-$2-obj,\ + $1-$2\ + ))\ +) + + +# generate the "main" rule for this lib + +$$(t-$1-$2-exec): $$(t-$1-$2-obj) + @ mkdir -p $$(dir $$@) + @ printf "$(blue)Create the library $(red)$$@$(nocolor)\n" +ifeq ($2,dynamic) + $$(t-$1-$2-gcc) -shared $$(t-$1-$2-gcc-libs) -o $$@ $$^ +else + $$(t-$1-$2-ar) crs $$@ $$^ +endif + +# register the "main" building rule for the lib + +$3 += $$(t-$1-$2-exec) + +endef + + +# Generate the "main" rules list +target-lib-list := +$(foreach board,$(CONFIG.BOARD-LIST),\ + $(foreach format,$(CONFIG.FORMAT-LIST),$(eval\ + $(call generate-target-lib,$(board),$(format),target-lib-list)\ + ))\ +) + + + +#--- +# Build rules +#--- +all: $(target-lib-list) + +.PHONY: all + + + +#--- +# Generate installation rules +#--- +# Common rules generated for the installation of each libraries. +# Basically, it will generate -install and -uninstall rules +# @note: +# *1 - library pathname +# *2 - variable name (installation rules list) +# *3 - variable name (uninstallation rules list) +define generate-install-rule + +# Generate the installation rule +$(basename $(notdir $1))-install: + install -d $(VXSDK_LIB_PREFIX) + install $1 -m 644 $(VXSDK_LIB_PREFIX) + +# Generate the uninstallation rule +$(basename $(notdir $1))-uninstall: + rm -f $(VXSDK_LIB_PREFIX)/$(notdir $1) + +# Register generated rules into their appropriate list +$2 += $(basename $(notdir $1))-install +$3 += $(basename $(notdir $1))-uninstall +endef + +# Common rules generated for the installation of board-specific linker script +# @note: +# $1 - board name +# $2 - variable name (installation rules list) +# $3 - variable name (uninstallation rules list) +define generate-board-install-rule + +$1-install: + install -d $(VXSDK_LIB_PREFIX) + install ../board/$(strip $1)/$(strip $1).ld -m 644 $(VXSDK_LIB_PREFIX) + +$1-uninstall: + rm -f $(VXSDK_LIB_PREFIX)/$(strip $1).ld + +$2 += $1-install +$3 += $1-uninstall + +endef + +# Generate all installation/uninstallation rules + +target-install-rules := +target-uninstall-rules := +$(foreach target,$(target-lib-list),$(eval \ + $(call generate-install-rule, \ + $(target), \ + target-install-rules, \ + target-uninstall-rules \ + ) \ +)) +$(foreach board,$(CONFIG.BOARD-LIST),$(eval \ + $(call generate-board-install-rule, \ + $(board), \ + target-install-rules, \ + target-uninstall-rules \ + ) \ +)) + +# Generate the path where include directory will be installed. +target-install-hdr-dir := $(VXSDK_LIB_PREFIX)/include/ +ifeq ($(wildcard $(target-install-header-dir)vhex/.*),) + target-install-hdr-dir := $(target-install-hdr-dir)vhex +endif + + + +#--- +# Installation rules +#--- +install: $(target-install-rules) + cp -r ../include/vhex $(target-install-hdr-dir) + +unsintall: $(target-uninstall_rules) + rm -rf $(VXSDK_LIB_PREFIX)/include/vhex + +.PHONY: install uninstall + + + +#--- +# cleaning rules +#--- +#clean: TODO: generate clean rule list + + +fclean: clean + rm -rf $(target-lib-list) +re: fclean all + +.PHONY: clean fclean re all diff --git a/src/drivers/mpu/sh/sh7305/mmu.c b/src/drivers/mpu/sh/sh7305/mmu.c new file mode 100644 index 0000000..88f2238 --- /dev/null +++ b/src/drivers/mpu/sh/sh7305/mmu.c @@ -0,0 +1,43 @@ +//--- +// vhex:mmu:mmu - MMU driver definition and context management +//--- +#include +#include +#include + +/* utlb_addr() - get the P4 address of a UTLB address entry */ +VINLINE const struct utlb_addr *utlb_addr(uint E) +{ + uintptr_t addr = 0xf6000000 | ((E & 0x3f) << 8); + return (void *)addr; +} + +/* utlb_data() - get the P4 address of a UTLB data entry */ +VINLINE const struct utlb_data *utlb_data(uint E) +{ + uintptr_t addr = 0xf7000000 | ((E & 0x3f) << 8); + return (void *)addr; +} + +/* mmu_translate(): Get the physical address for a virtual page */ +uintptr_t mmu_translate(uintptr_t page, size_t *size) +{ + for(int E = 0; E < 64; E++) + { + const struct utlb_addr *addr = utlb_addr(E); + const struct utlb_data *data = utlb_data(E); + if(!addr->V || !data->V) continue; + + if((uintptr_t)addr->VPN << 10 == page) + { + /* Magic formula to get the size without using an array + since this code is used even before global data is + posibly initialized */ + int sz = ((data->SZ1 << 1) | data->SZ2) << 3; + if(size) *size = 1 << ((0x14100c0a >> sz) & 0xff); + + return data->PPN << 10; + } + } + return -1; +} diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c new file mode 100644 index 0000000..0f38e0b --- /dev/null +++ b/src/kernel/kernel.c @@ -0,0 +1,20 @@ +#include + +//--- +// Initialization and unloading +//--- + +/* kinit(): Install and start vhex */ +void kinit(void) +{ + //TODO: initialize kmalloc() + //TODO: initialize hypervisor + //TODO: perform a world-switch "in" +} + +/* kquit(): Quit vhex and give back control to the system */ +void kquit(void) +{ + //TODO: perform a world-switch "out" + //TODO: free'd allocated world information +}