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
This commit is contained in:
Yann MAGNIN 2022-01-08 11:49:29 +01:00
commit f38bea7024
20 changed files with 1420 additions and 0 deletions

11
board/fx9860g/board.ini Normal file
View File

@ -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

88
board/fx9860g/fx9860g.ld Normal file
View File

@ -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)
}
}

View File

@ -0,0 +1,10 @@
#include <stdint.h>
/* for now, just involve the main routine */
void initialize(void)
{
extern int main(void);
main();
while(1) { __asm__ volatile ("sleep"::); }
}

13
board/fxcg50/_Exit.c Normal file
View File

@ -0,0 +1,13 @@
#include <setjmp.h>
/* 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);
}

11
board/fxcg50/board.ini Normal file
View File

@ -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

113
board/fxcg50/fxcg50.ld Normal file
View File

@ -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)
}
}

66
board/fxcg50/hardware.c Normal file
View File

@ -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);
}

129
board/fxcg50/initialize.c Normal file
View File

@ -0,0 +1,129 @@
//---
// fxcg50:initialize - Kernel initialization and C runtime
//---
#include "vhex/hardware.h"
#include "vhex/kernel.h"
#include <stdint.h>
#include <stdlib.h>
#include <setjmp.h>
/* 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
}

227
config Executable file
View File

@ -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()

View File

@ -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__*/

View File

@ -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__*/

50
include/vhex/defs/types.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef __VHEX_DEFS_TYPES__
# define __VHEX_DEFS_TYPES__
#include <vhex/defs/attributes.h>
/* For size_t, mainly */
#include <stddef.h>
/* For all fixed-width integer types */
#include <stdint.h>
/* For human-readable boolean types */
#include <stdbool.h>
/* Common system types: ssize_t, off_t, etc. */
#include <sys/types.h>
/* 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__*/

27
include/vhex/hardware.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef __VHEX_HARDWARE_H__
# define __VHEX_HARDWARE_H__
#include <vhex/defs/types.h>
/* 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__*/

10
include/vhex/kernel.h Normal file
View File

@ -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__*/

16
include/vhex/mmu.h Normal file
View File

@ -0,0 +1,16 @@
//---
// vhex:mmu - Memory Management Unit
//---
#ifndef __VHEX_MMU__
# define __VHEX_MMU__
#include <vhex/defs/types.h>
/* 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__*/

View File

@ -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 <vhex/mmu.h>.
//---
#ifndef __VHEX_MPU_SH7305_MMU__
# define __VHEX_MPU_SH7305_MMU__
#include <vhex/defs/attributes.h>
//---
// 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__*/

View File

@ -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 <vhex/defs/attributes.h>
#include <vhex/defs/types.h>
//---
// 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__*/

336
make/Makefile Normal file
View File

@ -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
# |-- <board_name>/:
# | |-- <format>/:
# | | |-- obj/:
# | | | |-- main.o
# ...
# | | | `-- initialize.o
# | | `-- map
# | |-- <board_name>.ld
# | `-- libvxkernel-<format>.[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 <libname>-install and <libname>-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

View File

@ -0,0 +1,43 @@
//---
// vhex:mmu:mmu - MMU driver definition and context management
//---
#include <vhex/mmu.h>
#include <vhex/mpu/sh7305/mmu.h>
#include <vhex/defs/attributes.h>
/* 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;
}

20
src/kernel/kernel.c Normal file
View File

@ -0,0 +1,20 @@
#include <vhex/kernel.h>
//---
// 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
}