vxGOS - v0.7.0-11 : add fx9860 support
*add* > [vxgos] | [fx9860] add vxsdk build entry | [fx9860] add G1A file generation | [fx9860] add ASLR support | [fx9860] add bios primitives | [fx9860] add new 3x5 font | [fx9860] add custom GCC toolchain dependency for vxSDK > [sdk] | [converter] support assets filter *update* > [scripts] | [vxdev] proper support "per board" assets requirements declaration > [bootloader] | [display] proper font BIOS-dependant (board-specific) interface *fix* > [sdk] | [converter] fix default font border size | [converter] remove useless core function exposition > [bootloader] | [assets] fix font8x9 to font8x12 (the real size) > [scripts] | [vxdev] convert assets only if needed
This commit is contained in:
parent
cefccb8bb1
commit
d596c74634
|
@ -38,17 +38,22 @@ def bootloader_configure(build, version):
|
|||
"(compiles.toml)"
|
||||
)
|
||||
|
||||
log.debug('- generate assets sources files...')
|
||||
cmd = '/usr/bin/env python3 '
|
||||
cmd += f"{prefix}/../../sdk/converter conv-assets "
|
||||
cmd += f"{prefix}/assets "
|
||||
cmd += f"{prefix}/../../.vxsdk/{build.target}/converter/bootloader "
|
||||
cmd += '--bootloader'
|
||||
proc = subprocess.run(cmd.split(), capture_output=True, check=False)
|
||||
if proc.returncode != 0:
|
||||
log.emergency(f"unable to convert bootloader assets : {proc.stderr}")
|
||||
assets_src = proc.stdout.decode('utf8').split()
|
||||
log.debug(f"> assets src = {assets_src}")
|
||||
assets_src = []
|
||||
if compiles.assets:
|
||||
log.debug('- generate assets sources files...')
|
||||
cmd = '/usr/bin/env python3 '
|
||||
cmd += f"{prefix}/../../sdk/converter conv-assets "
|
||||
cmd += f"{prefix}/assets "
|
||||
cmd += f"{prefix}/../../.vxsdk/{build.target}/converter/bootloader "
|
||||
cmd += f"--filter={','.join(compiles.assets)} "
|
||||
cmd += '--bootloader'
|
||||
proc = subprocess.run(cmd.split(), capture_output=True, check=False)
|
||||
if proc.returncode != 0:
|
||||
log.emergency(
|
||||
f"unable to convert bootloader assets : {proc.stderr}"
|
||||
)
|
||||
assets_src = proc.stdout.decode('utf8').split()
|
||||
log.debug(f"> assets src = {assets_src}")
|
||||
|
||||
common_src = f"{prefix}/src/**/*.[csS]"
|
||||
common_src = glob.glob(common_src, recursive=True)
|
||||
|
|
|
@ -22,6 +22,7 @@ class CompilesInfo():
|
|||
cflags = []
|
||||
ldflags = []
|
||||
libs = []
|
||||
assets = []
|
||||
|
||||
#---
|
||||
# Public
|
||||
|
@ -46,5 +47,7 @@ def compiles_fetch(filename):
|
|||
info.ldflags = board_info['VXDEV_LDFLAGS']
|
||||
if 'VXDEV_LIBS' in board_info:
|
||||
info.libs = board_info['VXDEV_LIBS']
|
||||
if 'VXDEV_ASSETS' in board_info:
|
||||
info.assets = board_info['VXDEV_ASSETS']
|
||||
|
||||
return info
|
||||
|
|
|
@ -56,6 +56,7 @@ def assets_conv_cli(argv):
|
|||
generator = 'os'
|
||||
prefix_output = ''
|
||||
prefix_assets = ''
|
||||
assets_filter = []
|
||||
for arg in argv:
|
||||
if arg in ['-f', '--force']:
|
||||
force = True
|
||||
|
@ -66,6 +67,9 @@ def assets_conv_cli(argv):
|
|||
if not prefix_assets:
|
||||
prefix_assets = arg
|
||||
continue
|
||||
if arg.find('--filter=') == 0:
|
||||
assets_filter = arg[9:].split(',')
|
||||
continue
|
||||
if prefix_output:
|
||||
log.warn(f"previous output path ({prefix_output}) dropped")
|
||||
prefix_output = arg
|
||||
|
@ -81,5 +85,6 @@ def assets_conv_cli(argv):
|
|||
os.path.abspath(prefix_assets),
|
||||
os.path.abspath(prefix_output),
|
||||
generator,
|
||||
assets_filter,
|
||||
force
|
||||
)
|
||||
|
|
|
@ -1,72 +1,4 @@
|
|||
"""
|
||||
core.conv - Vhex converter module
|
||||
"""
|
||||
|
||||
from core.assets import assets_generate
|
||||
|
||||
__all__ = [
|
||||
'generate_assets'
|
||||
]
|
||||
|
||||
#---
|
||||
# Public
|
||||
#---
|
||||
|
||||
def generate_assets(prefix_assets, prefix_src, force_generate=True):
|
||||
"""Generate Vhex assets.
|
||||
|
||||
This function abstract the asset convertion for the Vhex Operating System.
|
||||
It will walk througt the `<source_prefix>` folder and will try to find some
|
||||
files named 'vxconv.txt' wich discribe assets information of a potential
|
||||
project. Then it will use them to convert assets into an appropriate source
|
||||
file in C without using any Vhex-specific function (so, you can use this
|
||||
converter for other project).
|
||||
|
||||
The vxconv.txt file is structured like basic key/value file:
|
||||
|
||||
```
|
||||
<exposed_symbols_name>:
|
||||
type: <image type> (font, bitmap) - required
|
||||
path: <image path> - required
|
||||
...
|
||||
|
||||
<next_exposed_symbols_name>:
|
||||
...
|
||||
```
|
||||
|
||||
Each asset file description should have at least type and name information,
|
||||
and each type have potentially its own requierements.
|
||||
|
||||
type = bitmap:
|
||||
================================== ========================================
|
||||
Keys name and value type Description
|
||||
================================== ========================================
|
||||
profile: <name> Select the bitmap pixel profile
|
||||
| rgb4 | RGB 4 (indexed)
|
||||
| rgb4a | RGBA 4 (indexed)
|
||||
| rgb8 | RGB 8 (indexed)
|
||||
| rgb8a | RGBA 8 (indexed)
|
||||
| rgb16 | RGB 16 (5:R, 6:G, 5:B)
|
||||
| rgb16a | RGBA 16 (5:R, 5:G, 5:B, 1:A)
|
||||
================================== ========================================
|
||||
|
||||
type = font:
|
||||
================================== ========================================
|
||||
Keys name and value type Description
|
||||
================================== ========================================
|
||||
grid.size: 8x9 (widthxheight) caracter size in pixel
|
||||
grid.padding: <pixel> space between caracter
|
||||
grig.border: <pixel> space around grid
|
||||
proportional: <true,false> caracter are cropped
|
||||
line_height: <pixel> caracter line alignement
|
||||
charset: <print,unicode> charset specification
|
||||
================================== ========================================
|
||||
|
||||
@args:
|
||||
> path (str) - the path to find assets
|
||||
> source_prefix (str) - the path to generate image source file
|
||||
|
||||
@return:
|
||||
> a list of string which represents all assets sources files path
|
||||
"""
|
||||
return assets_generate(prefix_assets, prefix_src, force_generate)
|
||||
|
|
|
@ -102,13 +102,20 @@ class _VxAsset():
|
|||
# Public
|
||||
#---
|
||||
|
||||
def assets_generate(prefix_assets, prefix_output, generator, force_generate):
|
||||
def assets_generate(
|
||||
prefix_assets,
|
||||
prefix_output,
|
||||
generator,
|
||||
assets_filter,
|
||||
force_generate
|
||||
):
|
||||
""" Walk through the assets prefix and generate all source file
|
||||
|
||||
@args
|
||||
> prefix_asset (str) - prefix used for recursivly search for asset info
|
||||
> prefix_output (str) - prefix used for the output of generated file
|
||||
> generator (str) - selected generator
|
||||
> assets_filter (list) - assets filter
|
||||
> force_generate (bool) - force generate the source file
|
||||
|
||||
@return
|
||||
|
@ -122,6 +129,8 @@ def assets_generate(prefix_assets, prefix_output, generator, force_generate):
|
|||
with open(f"{root}/vxconv.toml", 'r', encoding='utf-8') as inf:
|
||||
content = toml.loads(inf.read())
|
||||
for asset_name in content:
|
||||
if assets_filter and asset_name not in assets_filter:
|
||||
continue
|
||||
log.debug(f"converting {asset_name}...")
|
||||
log.user(
|
||||
_VxAsset(
|
||||
|
|
|
@ -28,7 +28,7 @@ def font_meta_fetch(asset):
|
|||
'grid_size_x' : 0,
|
||||
'grid_size_y' : 0,
|
||||
'grid_padding' : 1,
|
||||
'grid_border' : 1,
|
||||
'grid_border' : 0,
|
||||
'is_proportional' : False,
|
||||
'line_height' : 0,
|
||||
'char_spacing' : 1,
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
"""
|
||||
g3a_generator - Casio G1A file generator
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
#---
|
||||
# Internals
|
||||
#---
|
||||
|
||||
def _u32(ptr, idx, data):
|
||||
""" unsigned 32bits wrapper """
|
||||
ptr[idx + 0] = (data & 0xff000000) >> 24
|
||||
ptr[idx + 1] = (data & 0x00ff0000) >> 16
|
||||
ptr[idx + 2] = (data & 0x0000ff00) >> 8
|
||||
ptr[idx + 3] = (data & 0x000000ff) >> 0
|
||||
|
||||
def _u16(ptr, idx, data):
|
||||
""" unsigned 16bits injection """
|
||||
ptr[idx + 0] = (data & 0xff00) >> 8
|
||||
ptr[idx + 1] = (data & 0x00ff) >> 0
|
||||
|
||||
def _u08(ptr, idx, data):
|
||||
""" unsigned 8bits injection """
|
||||
ptr[idx + 0] = (data & 0xff) >> 0
|
||||
|
||||
def _str(ptr, idx, data):
|
||||
""" string copy """
|
||||
for i, j in enumerate(data):
|
||||
_u08(ptr, idx + i, ord(j))
|
||||
|
||||
def _generate_standar_header(addin):
|
||||
""" generate Casio file standard header """
|
||||
_str(addin, 0x000, "USBPower") # watermark
|
||||
_u08(addin, 0x008, 0xf3) # addin file type
|
||||
_u08(addin, 0x009, 0x00) # watermark
|
||||
_u08(addin, 0x00a, 0x01) # watermark
|
||||
_u08(addin, 0x00b, 0x00) # watermark
|
||||
_u08(addin, 0x00c, 0x01) # watermark
|
||||
_u08(addin, 0x00d, 0x00) # watermark
|
||||
_u08(addin, 0x00e, 0x00) # LSB of file size + 0x41 (post)
|
||||
_u08(addin, 0x00f, 0x01) # watermark
|
||||
_u32(addin, 0x010, 0x00000000) # file size (MSB) (post)
|
||||
_u08(addin, 0x014, 0x00) # LSB of file size + 0xb8 (post)
|
||||
_u16(addin, 0x016, 0x0000) # sum of 8 words starting at 0x7100
|
||||
|
||||
def _generate_addin_subheader(addin):
|
||||
""" generate the g1a addin subheader """
|
||||
_str(addin, 0x020, "@VXGOS ") # checksum (post)
|
||||
_u08(addin, 0x02b, 0x00) # number of estrips
|
||||
_str(addin, 0x030, "01.00.0000") # addin version
|
||||
_str(addin, 0x03c, "2012.0903.1652") # addin date
|
||||
|
||||
for i in range(0, 44):
|
||||
_u08(addin, 0x03c + i, 0x00) # icon
|
||||
|
||||
_str(addin, 0x1d4, "VXGOS ") # add name
|
||||
_u32(addin, 0x002e, 0x00000000) # filesize (post)
|
||||
|
||||
def _generate_checksums(addin):
|
||||
""" generate all checksums requested for the g3a format """
|
||||
filesize = len(addin)
|
||||
|
||||
# standard header checksum
|
||||
_u08(addin, 0x010, (filesize & 0xff000000) >> 24)
|
||||
_u08(addin, 0x011, (filesize & 0x00ff0000) >> 16)
|
||||
_u08(addin, 0x012, (filesize & 0x0000ff00) >> 8)
|
||||
_u08(addin, 0x013, (filesize & 0x000000ff) >> 0)
|
||||
_u08(addin, 0x00e, addin[0x013] + 0x41)
|
||||
_u08(addin, 0x014, addin[0x013] + 0xb8)
|
||||
checksum = 0x00000
|
||||
for i in range(0, 8):
|
||||
checksum += int(
|
||||
addin[0x300 + (i * 2) : 0x302 + (i * 2)].hex(),
|
||||
base=16
|
||||
)
|
||||
_u16(addin, 0x016, checksum)
|
||||
|
||||
# addin-specific header checksum
|
||||
_u08(addin, 0x1f0, (filesize & 0xff000000) >> 24)
|
||||
_u08(addin, 0x1f1, (filesize & 0x00ff0000) >> 16)
|
||||
_u08(addin, 0x1f2, (filesize & 0x0000ff00) >> 8)
|
||||
_u08(addin, 0x1f3, (filesize & 0x000000ff) >> 0)
|
||||
|
||||
def _main(argv):
|
||||
""" main entry of the project """
|
||||
if len(argv) != 2:
|
||||
print('missing <rawbin> or <output>')
|
||||
sys.exit(84)
|
||||
|
||||
rawbin = b''
|
||||
with open(argv[0], 'rb') as rawfile:
|
||||
rawbin = rawfile.read()
|
||||
|
||||
addin = bytearray(0x200)
|
||||
_generate_standar_header(addin)
|
||||
_generate_addin_subheader(addin)
|
||||
addin += rawbin
|
||||
_generate_checksums(addin)
|
||||
|
||||
if os.path.exists(argv[1]):
|
||||
os.remove(argv[1])
|
||||
with open(argv[1], 'xb') as addinfile:
|
||||
addinfile.write(addin)
|
||||
return 0
|
||||
|
||||
#---
|
||||
# Public
|
||||
#---
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(_main(sys.argv[1:]))
|
|
@ -0,0 +1,137 @@
|
|||
"""
|
||||
generate - post-build script used to generate bootlaoder blob with ASLR
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
__all__ = [
|
||||
'generate_aslr_blob',
|
||||
'generate_image'
|
||||
]
|
||||
|
||||
#---
|
||||
# Internals
|
||||
#---
|
||||
|
||||
def _patch_got_section(symfile, section):
|
||||
""" fetch all address of the GOT table
|
||||
"""
|
||||
for sec in section:
|
||||
if sec[0] != '.got':
|
||||
continue
|
||||
got_base_addr = int(sec[2], base=16)
|
||||
for i in range(0, int(sec[4], base=16), 4):
|
||||
print(f" > reloc GOT entry {got_base_addr+i:08x}...")
|
||||
symfile.write((got_base_addr + i).to_bytes(4, 'big'))
|
||||
break
|
||||
|
||||
#---
|
||||
# Public
|
||||
#---
|
||||
|
||||
def generate_aslr_blob(binpath, symtab, sectab):
|
||||
""" generate bootloader final blob with ASLR
|
||||
|
||||
The objectif of this script is to generate the final bootloader blob with
|
||||
ASLR. To performs this, we will performs 3 steps:
|
||||
|
||||
* generate the raw binary file of the bootloader (objcpy)
|
||||
* generate the raw ALSR symbols table
|
||||
* generate the complet blootloader image
|
||||
|
||||
@args
|
||||
> binpath (str) - binary file
|
||||
> symtab (list) - list of all reloc information (readelf -r binpath)
|
||||
> sectab (list) - list of all sections information (readelf -S binpath)
|
||||
|
||||
@return
|
||||
> Nothings
|
||||
"""
|
||||
print('- generate raw binary...')
|
||||
if os.path.exists(f"{binpath}.raw"):
|
||||
os.remove(f"{binpath}.raw")
|
||||
cmd = f"sh-elf-vhex-objcopy -O binary -R .bss {binpath} {binpath}.raw"
|
||||
subprocess.run(
|
||||
cmd.split(),
|
||||
capture_output=False,
|
||||
check=False
|
||||
)
|
||||
|
||||
print('- generate raw symtab...')
|
||||
if os.path.exists(f"{binpath}.symtab"):
|
||||
os.remove(f"{binpath}.symtab")
|
||||
need_patch_got = False
|
||||
with open(f"{binpath}.symtab", 'xb') as symfile:
|
||||
for i, sym in enumerate(symtab):
|
||||
# direct 32bits address
|
||||
if sym[2] == 'R_SH_DIR32':
|
||||
print(f" > reloc 'R_SH_DIR32' sym at {sym[0]}")
|
||||
symfile.write(int(sym[0], base=16).to_bytes(4, 'big'))
|
||||
continue
|
||||
# GOT related jump
|
||||
if sym[2] == 'R_SH_GOT32':
|
||||
need_patch_got = True
|
||||
continue
|
||||
# Other
|
||||
if sym[2] not in [
|
||||
'R_SH_PLT32',
|
||||
'R_SH_GOT32',
|
||||
'R_SH_GOTPC',
|
||||
'R_SH_GOTOFF'
|
||||
]:
|
||||
print(f" > [{i}] reloc {sym[2]} not supported")
|
||||
sys.exit(84)
|
||||
if need_patch_got:
|
||||
_patch_got_section(symfile, sectab)
|
||||
symfile.write(int('00000000', base=16).to_bytes(4, 'big'))
|
||||
|
||||
print('- generate the full bootloader...')
|
||||
if os.path.exists(f"{binpath}.bzImage"):
|
||||
os.remove(f"{binpath}.bzImage")
|
||||
with open(f"{binpath}.bzImage", 'xb') as bzimgfile:
|
||||
with open(f"{binpath}.raw", 'rb') as rawbinfile:
|
||||
bzimgfile.write(rawbinfile.read())
|
||||
with open(f"{binpath}.symtab", 'rb') as symtabfile:
|
||||
bzimgfile.write(symtabfile.read())
|
||||
return f"{binpath}.bzImage"
|
||||
|
||||
def generate_image(prefix_build, bootloader_path, _):
|
||||
""" generate complet image (g3a) file
|
||||
|
||||
TODO
|
||||
"""
|
||||
|
||||
image = bytearray(0)
|
||||
with open(bootloader_path, 'rb') as bootloaderfile:
|
||||
image += bootloaderfile.read()
|
||||
# (todo) os/kernel
|
||||
image_size = len(image)
|
||||
|
||||
# patch first two instruction of the image (see <vxgos/bootloader>)
|
||||
image[0] = 0b00000000 # (MSB) nop
|
||||
image[1] = 0b00001001 # (LSB) nop
|
||||
image[2] = 0b11010000 # (MSB) mov.l @(1*, PC), r0
|
||||
image[3] = 0b00000001 # (LSB) mov.l @(1*, PC), r0
|
||||
image[8] = (image_size & 0xff000000) >> 24
|
||||
image[9] = (image_size & 0x00ff0000) >> 16
|
||||
image[10] = (image_size & 0x0000ff00) >> 8
|
||||
image[11] = (image_size & 0x000000ff) >> 0
|
||||
|
||||
bzimage = f"{prefix_build}/vxgos.bzImage"
|
||||
if os.path.exists(bzimage):
|
||||
os.remove(bzimage)
|
||||
with open(bzimage, 'xb') as bzimage:
|
||||
bzimage.write(image)
|
||||
prefix = os.path.dirname(__file__)
|
||||
subprocess.run(
|
||||
[
|
||||
'/usr/bin/env',
|
||||
'python3',
|
||||
f"{prefix}/g1a_generator.py",
|
||||
f"{prefix_build}/vxgos.bzImage",
|
||||
f"{prefix_build}/vxgos.g1a",
|
||||
],
|
||||
capture_output=False,
|
||||
check=False
|
||||
)
|
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
@ -1,7 +1,16 @@
|
|||
[font8x9]
|
||||
path = 'font8x9.png'
|
||||
[font8x12]
|
||||
path = 'font8x12.png'
|
||||
type = 'font'
|
||||
grid_size = '8x12'
|
||||
grid_padding = 1
|
||||
grid_border = 1
|
||||
proportional = false
|
||||
line_height = 9
|
||||
|
||||
[font3x5]
|
||||
path = 'font3x5.png'
|
||||
type = 'font'
|
||||
grid_size = '3x5'
|
||||
grid_padding = 1
|
||||
proportional = false
|
||||
line_height = 6
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
VXDEV_TOOLCHAIN_PREFIX = 'sh-elf-vhex-'
|
||||
VXDEV_TOOLCHAIN_PROCESSOR = 'sh'
|
||||
VXDEV_CFLAGS = [
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-D__SUPPORT_FX9860__',
|
||||
'-ffreestanding',
|
||||
'-nostdlib',
|
||||
'-fPIE',
|
||||
'-O1',
|
||||
'-mb',
|
||||
'-m4-nofpu',
|
||||
'-fstrict-volatile-bitfields',
|
||||
]
|
||||
VXDEV_LDFLAGS = [
|
||||
'-static',
|
||||
'-Wl,-Map=map',
|
||||
'-Wl,--build-id=none',
|
||||
'-Wl,--emit-relocs',
|
||||
]
|
||||
VXDEV_LIBS = [
|
||||
'-lgcc',
|
||||
]
|
||||
VXDEV_ASSETS = [
|
||||
'font3x5',
|
||||
]
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef FXCG50_BOOTLOADER_ASM_UTILS_H
|
||||
#define FXCG50_BOOTLOADER_ASM_UTILS_H 1
|
||||
|
||||
/* function() : define a function using special indication
|
||||
*
|
||||
* - the function's name must start with a '_'
|
||||
* - the function should start in a 4-aligned address in order to benefit from
|
||||
* the ILP (Instruction Level Parallelism) */
|
||||
#define function(name) \
|
||||
.balign 4 ;\
|
||||
.global _ ## name ;\
|
||||
_ ## name
|
||||
|
||||
/* FX9860_SYSCALL_TRAMPOLINE - Casio's syscall trampoline address */
|
||||
#define FX9860_SYSCALL_TRAMPOLINE 0x80010070
|
||||
|
||||
/* syscall() : helper used to quickly define Casio syscall invokation
|
||||
*
|
||||
* - the syscall trampoline code is common for all syscall
|
||||
* - r0 contain the syscall ID */
|
||||
#define syscall(id) \
|
||||
mov.l 1f, r2 ;\
|
||||
mov.l 2f, r0 ;\
|
||||
jmp @r2 ;\
|
||||
nop ;\
|
||||
.balign 4 ;\
|
||||
1: .long FX9860_SYSCALL_TRAMPOLINE ;\
|
||||
2: .long id
|
||||
|
||||
#endif /* FXCG50_BOOTLOADER_ASM_UTILS_H */
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef FXCG50_KEYCODE_H
|
||||
#define FXCG50_KEYCODE_H
|
||||
|
||||
/* KEYSCODE_GEN() : generate keycode */
|
||||
#define KEYCODE_GEN(row, column) \
|
||||
(((row & 0x0f) << 4) | ((column & 0x0f) << 0))
|
||||
|
||||
/* Define all keycode */
|
||||
typedef enum
|
||||
{
|
||||
KEY_F1 = 0x41,
|
||||
KEY_F2 = 0x42,
|
||||
KEY_F3 = 0x43,
|
||||
KEY_F4 = 0x44,
|
||||
KEY_F5 = 0x45,
|
||||
KEY_F6 = 0x46,
|
||||
|
||||
KEY_SHIFT = 0x49,
|
||||
KEY_OPTN = 0x4a,
|
||||
KEY_VARS = 0x4b,
|
||||
KEY_MENU = 0x4c,
|
||||
KEY_LEFT = 0x4d,
|
||||
KEY_UP = 0x4e,
|
||||
|
||||
KEY_ALPHA = 0x31,
|
||||
KEY_SQUARE = 0x32,
|
||||
KEY_POWER = 0x33,
|
||||
KEY_EXIT = 0x34,
|
||||
KEY_DOWN = 0x35,
|
||||
KEY_RIGHT = 0x36,
|
||||
|
||||
KEY_XOT = 0x39,
|
||||
KEY_LOG = 0x3a,
|
||||
KEY_LN = 0x3b,
|
||||
KEY_SIN = 0x3c,
|
||||
KEY_COS = 0x3d,
|
||||
KEY_TAN = 0x3e,
|
||||
|
||||
KEY_FRAC = 0x21,
|
||||
KEY_FD = 0x22,
|
||||
KEY_LEFTP = 0x23,
|
||||
KEY_RIGHTP = 0x24,
|
||||
KEY_COMMA = 0x25,
|
||||
KEY_ARROW = 0x26,
|
||||
|
||||
KEY_7 = 0x29,
|
||||
KEY_8 = 0x2a,
|
||||
KEY_9 = 0x2b,
|
||||
KEY_DEL = 0x2c,
|
||||
|
||||
KEY_4 = 0x11,
|
||||
KEY_5 = 0x12,
|
||||
KEY_6 = 0x13,
|
||||
KEY_MUL = 0x14,
|
||||
KEY_DIV = 0x15,
|
||||
|
||||
KEY_1 = 0x19,
|
||||
KEY_2 = 0x1a,
|
||||
KEY_3 = 0x1b,
|
||||
KEY_PLUS = 0x1c,
|
||||
KEY_MINUS = 0x1d,
|
||||
|
||||
KEY_0 = 0x01,
|
||||
KEY_DOT = 0x02,
|
||||
KEY_EXP = 0x03,
|
||||
KEY_NEG = 0x04,
|
||||
KEY_EXE = 0x05,
|
||||
|
||||
KEY_UNUSED = 0xff,
|
||||
KEY_NONE = 0xfe,
|
||||
} KEY_t;
|
||||
|
||||
#endif /* FXCG50_KEYCODE_H */
|
|
@ -0,0 +1,17 @@
|
|||
#include "bootloader/display.h"
|
||||
#include "bootloader/bios.h"
|
||||
|
||||
//---
|
||||
// Public
|
||||
//---
|
||||
|
||||
/* _bios_dfont_get() : get font information */
|
||||
int _bios_dfont_get(struct font **font)
|
||||
{
|
||||
extern struct font font3x5;
|
||||
|
||||
if (font == NULL)
|
||||
return -1;
|
||||
*font = &font3x5;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#include "bootloader/bios.h"
|
||||
|
||||
//---
|
||||
// Public
|
||||
//---
|
||||
|
||||
/* _bios_dinfo() : get display information */
|
||||
void _bios_dinfo(size_t *width, size_t *height)
|
||||
{
|
||||
if (width != NULL)
|
||||
*width = 128;
|
||||
if (height != NULL)
|
||||
*height = 64;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bootloader/bios.h"
|
||||
#include "bootloader/display.h"
|
||||
|
||||
//---
|
||||
// Public
|
||||
//---
|
||||
|
||||
/* _bios_dpixel() : dpixel wrapper */
|
||||
void _bios_dpixel(int x, int y, int color)
|
||||
{
|
||||
extern uint8_t vram[];
|
||||
int mask;
|
||||
int indx;
|
||||
|
||||
if ((unsigned)x >= 128 || (unsigned)y >= 64)
|
||||
return;
|
||||
|
||||
indx = ((y * 128) + x) / 8;
|
||||
mask = 0x80 >> (x & 7);
|
||||
|
||||
switch (color) {
|
||||
case C_BLACK:
|
||||
vram[indx] |= mask;
|
||||
break;
|
||||
case C_WHITE:
|
||||
vram[indx] &= ~mask;
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
#include <stdint.h>
|
||||
|
||||
//---
|
||||
// Internals
|
||||
//---
|
||||
|
||||
// Device specification sheet
|
||||
|
||||
/* This version number is 1 for the old T6K11 (T6K73A (2005-11-30)) everyone
|
||||
* knows, and 2 for the newer one found in the Graph 35+E II (ML9801A
|
||||
* (2018-07-05)).
|
||||
* Documentation is available only for the T6K11 (version 1 is close).
|
||||
* Dumps of Bdisp_PutDisp_DD() are used to drive version 2. */
|
||||
static int t6k11_version = -1;
|
||||
|
||||
/* Screen registers on the original T6K11. Registers 8..11 and 13..15 are test
|
||||
registers and must not be used! */
|
||||
enum {
|
||||
reg_display = 0,
|
||||
reg_counter = 1,
|
||||
reg_analog = 2,
|
||||
reg_alternate = 3,
|
||||
|
||||
reg_yaddr = 4, /* These two use the same register */
|
||||
reg_xaddr = 4, /* (interpretation depends on count mode) */
|
||||
|
||||
reg_zaddr = 5,
|
||||
reg_contrast = 6,
|
||||
reg_data = 7,
|
||||
reg_daconv = 12,
|
||||
};
|
||||
|
||||
/* Automatic counter increment during read/write */
|
||||
enum {
|
||||
cnt_ydown = 0,
|
||||
cnt_yup = 1,
|
||||
cnt_xdown = 2,
|
||||
cnt_xup = 3,
|
||||
};
|
||||
|
||||
// Device communication primitives
|
||||
|
||||
/* I/O may be performed either with RS = 0 or RS = 1.
|
||||
* The memory-mapping of the device I/O maps bit 16 of the address to pin RS.
|
||||
* There may be other mapped pins in the address. (?) */
|
||||
|
||||
/* RS = 0: Register selection */
|
||||
static volatile uint8_t *sel = (void *)0xb4000000;
|
||||
/* RS = 1: Command data or vram data */
|
||||
static volatile uint8_t *cmd = (void *)0xb4010000;
|
||||
|
||||
/* command() - send a command to set the value of a register
|
||||
@reg Register number
|
||||
@data Value to set in reg */
|
||||
static void command(uint8_t reg, uint8_t data)
|
||||
{
|
||||
*sel = reg;
|
||||
*cmd = data;
|
||||
}
|
||||
|
||||
/* write_row() - send 16 bytes to the display driver
|
||||
@buf Buffer to take data from */
|
||||
static void write_row(const uint8_t *buf)
|
||||
{
|
||||
/* Unroll the loop for more speed */
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
*cmd = *buf++;
|
||||
}
|
||||
|
||||
// Driver functions
|
||||
|
||||
/* t6k11_display() - send vram data to the LCD device */
|
||||
static void t6k11_display_t6k73(const void *vram)
|
||||
{
|
||||
for(int y = 0; y < 64; y++)
|
||||
{
|
||||
/* Set the X-address register for this row */
|
||||
command(reg_xaddr, y | 0xc0);
|
||||
/* Use Y-Up mode */
|
||||
command(reg_counter, cnt_yup);
|
||||
/* Start counting Y from 0 */
|
||||
command(reg_yaddr, 0);
|
||||
|
||||
/* Send the row's data to the device */
|
||||
*sel = reg_data;
|
||||
write_row(vram);
|
||||
vram += 128 / 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* t6k11_display() - send vram data to the LCD device */
|
||||
static void t6k11_display_ml9801(const void *vram)
|
||||
{
|
||||
for(int y = 0; y < 64; y++)
|
||||
{
|
||||
command(8, y | 0x80);
|
||||
command(8, 4);
|
||||
|
||||
*sel = 10;
|
||||
write_row(vram);
|
||||
vram += 128 / 8;
|
||||
}
|
||||
}
|
||||
|
||||
//---
|
||||
// Public
|
||||
//---
|
||||
|
||||
/* expose VRAM here */
|
||||
uint8_t vram[(128 * 64) / 8];
|
||||
|
||||
/* _bios_dupdate() : small T6K73A and ML9801A driver */
|
||||
void _bios_dupdate(void)
|
||||
{
|
||||
extern uint8_t vram[];
|
||||
extern int t6k11_version;
|
||||
|
||||
/* Tell Graph 35+E II from OS version (this is accurate unless someone
|
||||
* tweaks an OS file enough to de-correlate the version of the OS and
|
||||
* the version of the display and storage memory drivers, which, let's
|
||||
* be real, is enough for now. */
|
||||
if (t6k11_version == -1) {
|
||||
char *version = (void *)0x80010020;
|
||||
t6k11_version = (version[1] == '3') ? 2 : 1;
|
||||
}
|
||||
|
||||
/* branch to the real driver */
|
||||
if(t6k11_version == 1) t6k11_display_t6k73(vram);
|
||||
if(t6k11_version == 2) t6k11_display_ml9801(vram);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#include "fx9860/asm_utils.h"
|
||||
|
||||
.text
|
||||
|
||||
!---
|
||||
! Public
|
||||
!---
|
||||
|
||||
/* _bios_free() (free) : free allocated memory */
|
||||
function(_bios_free):
|
||||
syscall(0xacc)
|
|
@ -0,0 +1,11 @@
|
|||
#include "fx9860/asm_utils.h"
|
||||
|
||||
.text
|
||||
|
||||
!---
|
||||
! Public
|
||||
!---
|
||||
|
||||
/* _bios_malloc() (malloc) : allocate memory */
|
||||
function(_bios_malloc):
|
||||
syscall(0xacd)
|
|
@ -0,0 +1,89 @@
|
|||
#include "bootloader/console.h"
|
||||
#include "fx9860/keycode.h"
|
||||
|
||||
//---
|
||||
// Public
|
||||
//---
|
||||
|
||||
/* console_key_handle_special() : handle special key handling */
|
||||
// TODO
|
||||
// - F_UP -> history
|
||||
// - F_DOWN -> history
|
||||
int console_key_handle_special(struct console *console, int key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case KEY_SHIFT:
|
||||
console->input.mode.shift ^= 1;
|
||||
return 1;
|
||||
case KEY_ALPHA:
|
||||
console->input.mode.maj ^= 1;
|
||||
return 1;
|
||||
case KEY_OPTN:
|
||||
console->input.mode.ctrl ^= 1;
|
||||
return 1;
|
||||
case KEY_DOT:
|
||||
console_buffer_in_insert(console, ' ');
|
||||
return 1;
|
||||
case KEY_DEL:
|
||||
console_buffer_in_remove(console);
|
||||
return 1;
|
||||
case KEY_EXE:
|
||||
console->input.mode.exit = 1;
|
||||
return 1;
|
||||
case KEY_LEFT:
|
||||
console_buffer_in_cursor_move(console, -1);
|
||||
return 1;
|
||||
case KEY_RIGHT:
|
||||
console_buffer_in_cursor_move(console, 1);
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* console_key_handle(): Update the internal buffer with the given key code */
|
||||
int console_key_handle(struct console *console, int key)
|
||||
{
|
||||
static const uint8_t keylist_alpha[] = {
|
||||
KEY_XOT, KEY_LOG, KEY_LN, KEY_SIN, KEY_COS, KEY_TAN,
|
||||
KEY_FRAC, KEY_FD, KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_ARROW,
|
||||
KEY_7, KEY_8, KEY_9,
|
||||
KEY_4, KEY_5, KEY_6, KEY_MUL, KEY_DIV,
|
||||
KEY_1, KEY_2, KEY_3, KEY_PLUS, KEY_MINUS,
|
||||
KEY_0, 0xff
|
||||
};
|
||||
static const uint8_t keylist_num[] = {
|
||||
KEY_0, KEY_1, KEY_2, KEY_3, KEY_4,
|
||||
KEY_5, KEY_6, KEY_7, KEY_8, KEY_9,
|
||||
KEY_PLUS, KEY_MINUS, KEY_MUL, KEY_DIV,
|
||||
KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_POWER,
|
||||
KEY_DOT, KEY_FD, KEY_ARROW, 0xff
|
||||
};
|
||||
static const char keylist_num_char[] = "0123456789+-x/(),^.|_";
|
||||
const uint8_t *keycode_list;
|
||||
char character;
|
||||
int i;
|
||||
|
||||
/* Get the appropriate key list */
|
||||
keycode_list = keylist_alpha;
|
||||
if (console->input.mode.shift == 1)
|
||||
keycode_list = keylist_num;
|
||||
|
||||
/* Try to find the pressed key. */
|
||||
i = -1;
|
||||
while (keycode_list[++i] != 0xff && keycode_list[i] != key);
|
||||
if (keycode_list[i] != key)
|
||||
return 0;
|
||||
|
||||
/* handle mode then update the buffer */
|
||||
if (console->input.mode.shift == 0) {
|
||||
character = 'a' + i;
|
||||
if (console->input.mode.maj == 1)
|
||||
character = 'A' + i;
|
||||
} else {
|
||||
character = keylist_num_char[i];
|
||||
}
|
||||
console_buffer_in_insert(console, character);
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#include "bootloader/console.h"
|
||||
#include "fx9860/keycode.h"
|
||||
|
||||
//---
|
||||
// Internlas
|
||||
//---
|
||||
|
||||
/* keysc_fetch() : scan the KEYSC hardware module */
|
||||
static int keysc_fetch(void)
|
||||
{
|
||||
uint16_t volatile *SH7305_KEYSC = (void*)0xa44b0000;
|
||||
int column;
|
||||
int key;
|
||||
int row;
|
||||
int registered;
|
||||
uint16_t udata;
|
||||
|
||||
/* update the keycache */
|
||||
row = 6;
|
||||
key = 0x5f;
|
||||
registered = 0x0000;
|
||||
while (--row >= 0)
|
||||
{
|
||||
column = 16;
|
||||
udata = SH7305_KEYSC[row];
|
||||
if (registered != 0x0000)
|
||||
continue;
|
||||
while (--column >= 0)
|
||||
{
|
||||
if ((udata & (0x8000 >> column)) != 0) {
|
||||
registered = KEYCODE_GEN(row, column);
|
||||
break;
|
||||
}
|
||||
key -= 1;
|
||||
}
|
||||
}
|
||||
return registered;
|
||||
}
|
||||
|
||||
//---
|
||||
// Public
|
||||
//---
|
||||
|
||||
/* console_key_get() : small one-shot key waiter */
|
||||
int console_key_get(void)
|
||||
{
|
||||
static uint16_t prev_key = 0xffff;
|
||||
|
||||
if (prev_key != 0xffff) {
|
||||
while (1) {
|
||||
if (prev_key != keysc_fetch())
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (1) {
|
||||
prev_key = keysc_fetch();
|
||||
if (prev_key != 0x0000)
|
||||
break;
|
||||
}
|
||||
return prev_key;
|
||||
}
|
|
@ -0,0 +1,297 @@
|
|||
#include "fx9860/asm_utils.h"
|
||||
|
||||
.section .bootloader.pre_text, "ax"
|
||||
|
||||
/* ___fxcg50_initialize() : bootstrap routine
|
||||
|
||||
We are currently virtualized as a common program (addin) at 0x00300000, but the
|
||||
code currently executed is physically fragmented through the ROM. So, we cannot
|
||||
perform ASLR self-relocation here.
|
||||
|
||||
The first thing we need to do is find the "user" RAM allocated by Casio (by
|
||||
analyzing the TLB) and then performs a "self-translation" into this place.
|
||||
After that, we will be able to perform ASLR self-relocation and classic
|
||||
"kernel" bootstrapping.. */
|
||||
|
||||
function(__fxcg50_primary_bootloader):
|
||||
|
||||
! ---
|
||||
! *CRITICAL*
|
||||
!
|
||||
! The next two instructions will be patched *DURING COMPILE TIME* with the
|
||||
! complete image size (bootloader, ASLR, kernel, OS,...) as follows:
|
||||
! > mov.l complet_image_size, r0
|
||||
! > nop
|
||||
! If not patched, the code will just return and indicate to Casio not to
|
||||
! restart the application.
|
||||
! ---
|
||||
|
||||
rts
|
||||
mov #1, r0
|
||||
bra translation_entry
|
||||
nop
|
||||
.long 0x00000000
|
||||
|
||||
translation_entry:
|
||||
|
||||
! ---
|
||||
! prepare alias
|
||||
!
|
||||
! We don't need to setup the stack because we are loaded from CasioABS
|
||||
! (Casio OS) as a simple program (addin) with a given stack, which we will
|
||||
! not use even if we use "special" registers such as r8, r9, ... as we will
|
||||
! be careful to never return from here.
|
||||
!
|
||||
! @note
|
||||
! - r0 is reused
|
||||
! - r1 is reused
|
||||
! - r2 is reused
|
||||
! - r7 is reused
|
||||
! - r14 is reused
|
||||
! ---
|
||||
|
||||
#define counter r0
|
||||
#define utlb_addr_val r1
|
||||
#define utlb_data_val r2
|
||||
#define uram_phys_addr r3
|
||||
#define rom_base_addr r4
|
||||
#define rom_image_size r5
|
||||
#define utlb_data_ptr r6
|
||||
#define utlb_addr_ptr r7
|
||||
#define uram_virt_ptr r8
|
||||
#define uram_phys_size r9
|
||||
#define utlb_valid_bit r10
|
||||
#define utlb_data_ptr_saved r11
|
||||
#define utlb_magic_array r12
|
||||
#define utlb_addr_ptr_saved r13
|
||||
#define utlb_data_ppn_mask r14
|
||||
|
||||
! ---
|
||||
! Save critical information
|
||||
!
|
||||
! Calculate the runtime loaded address of the addin and save the
|
||||
! compile-time image size information
|
||||
! ---
|
||||
|
||||
! save image size
|
||||
mov r0, rom_image_size
|
||||
|
||||
! precalculate runtime loaded address
|
||||
mova utlb_fetch_uram_info, r0
|
||||
add #(___fxcg50_primary_bootloader - utlb_fetch_uram_info), r0
|
||||
mov r0, rom_base_addr
|
||||
|
||||
! ---
|
||||
! Configure cache
|
||||
!
|
||||
! This is a critical part because we will move to the URAM and perform
|
||||
! self-patching symbols during our execution. So, we need to have a
|
||||
! consistent cache behavior to help the MPU follow our instructions.
|
||||
!
|
||||
! The SH7305 has a special register for that called Cache Control Register
|
||||
! (CCR), and it seems tobe the same as SH7724 (except that no official POC
|
||||
! or information can invalidate the instruction Cache (IC) without causing
|
||||
! the machine to crash):
|
||||
!
|
||||
! - Indicate that P1 area use the "Write-back" method
|
||||
! - Indicate that P0/P3 areas use the "Write-through" method
|
||||
! - Enable Operand Cache (OC)
|
||||
! - Enable Instruction Cache (IC)
|
||||
! - Invalidate all Operand Cache (OC) entries
|
||||
! ---
|
||||
|
||||
mov.l ccr_register_addr, r0
|
||||
mov.l ccr_register_data, r1
|
||||
mov.l r1, @r0
|
||||
synco
|
||||
|
||||
! ---
|
||||
! UTLB scan to find URAM information
|
||||
!
|
||||
! As explained above, we first need to find the user RAM given by Casio for
|
||||
! our application, as we know that is an unused and stable space for us.
|
||||
!
|
||||
! We will scan each TLB entry to find the user's RAM. The memory is
|
||||
! virtually mapped by Casio using the same historical virtual address:
|
||||
! 0x08100000. Also, all the given RAM is entierly (?) mapped by the
|
||||
! operating system. Thus, we walk through the TLB until we don't find the
|
||||
! next memory fragment; this will allow us to find the size of the RAM
|
||||
! (which varies between models and emulators).
|
||||
!
|
||||
! We will also take advantage of the fact that Casio *MAP* the virtual
|
||||
! address 0x00000000 (NULL) for no valid reason. So, if we find this
|
||||
! mapping, we will invalidate it to be sure that a NULL manipulated pointer
|
||||
! will cause a TLBmiss exception.
|
||||
!
|
||||
! TODO : invalidate NULL page
|
||||
! ---
|
||||
|
||||
utlb_fetch_uram_info:
|
||||
|
||||
! fetch external information
|
||||
mov.l data_00000100, utlb_valid_bit
|
||||
mov.l data_08100000, uram_virt_ptr
|
||||
mov.l data_f6000000, utlb_addr_ptr
|
||||
mov.l data_14100c0a, utlb_magic_array
|
||||
mov.l data_1ffffc00, utlb_data_ppn_mask
|
||||
mov.l data_f7000000, utlb_data_ptr
|
||||
|
||||
! prepare internal vars
|
||||
mov #0, counter
|
||||
mov #-1, uram_phys_addr
|
||||
mov #0, uram_phys_size
|
||||
mov utlb_data_ptr, utlb_data_ptr_saved
|
||||
mov utlb_addr_ptr, utlb_addr_ptr_saved
|
||||
|
||||
utlb_walk_loop:
|
||||
! validity check
|
||||
! @note
|
||||
! - check the validity bit for each UTLB data and address entry
|
||||
! - both data and address entry have the same Valid bit position
|
||||
mov.l @utlb_addr_ptr, utlb_addr_val
|
||||
tst utlb_valid_bit, utlb_addr_val
|
||||
bt utlb_walk_cond_check
|
||||
mov.l @utlb_data_ptr, utlb_data_val
|
||||
tst utlb_valid_bit, utlb_data_val
|
||||
bt.s utlb_walk_cond_check
|
||||
|
||||
! check VPN validity
|
||||
! @note
|
||||
! - "UTLB Address Array" (p239) - Figure 7.14
|
||||
! - we need to clear the first 10 bits of the fetched UTLB data to get the
|
||||
! the "real" virtual address (eliminate ASID, Dirty and Valid bits)
|
||||
shlr8 utlb_addr_val
|
||||
shlr2 utlb_addr_val
|
||||
shll8 utlb_addr_val
|
||||
shll2 utlb_addr_val
|
||||
cmp/eq uram_virt_ptr, utlb_addr_val
|
||||
bf.s utlb_walk_cond_check
|
||||
|
||||
! fetch the page size
|
||||
! @note
|
||||
! - "Unified TLB (UTLB) Configuration"(p221)
|
||||
! - page size is weird to calculate for many hardware reasons, and this code
|
||||
! is the literal translation of :
|
||||
! > size = ((data->SZ1 << 1) | data->SZ2) << 3;
|
||||
! > size = 1 << ((0x14100c0a >> size) & 0xff);
|
||||
mov #-1, r1
|
||||
mov utlb_data_val, r0
|
||||
tst #128, r0
|
||||
mov #-1, r7
|
||||
negc r1, r1
|
||||
tst #16, r0
|
||||
add r1, r1
|
||||
negc r7, r7
|
||||
or r7, r1
|
||||
mov utlb_magic_array,r7
|
||||
shll2 r1
|
||||
add r1, r1
|
||||
neg r1, r1
|
||||
shad r1, r7
|
||||
extu.b r7, r1
|
||||
mov #1, r7
|
||||
shld r1, r7
|
||||
|
||||
! update counter / information
|
||||
add r7, uram_phys_size
|
||||
add r7, uram_virt_ptr
|
||||
|
||||
! check if the URAM physical address is already set
|
||||
mov uram_phys_addr,r0
|
||||
cmp/eq #-1,r0
|
||||
bf utlb_page_found_restart
|
||||
|
||||
! calculate the physical address of the page (URAM)
|
||||
! @note
|
||||
! - "UTLB Data Array"(p240) - Figure 7.15
|
||||
! - to fetch the Physical Address, we just need to isolate the PPN
|
||||
and utlb_data_ppn_mask, utlb_data_val
|
||||
shlr8 utlb_data_val
|
||||
shlr2 utlb_data_val
|
||||
mov utlb_data_val, uram_phys_addr
|
||||
shll8 uram_phys_addr
|
||||
shll2 uram_phys_addr
|
||||
|
||||
utlb_page_found_restart:
|
||||
mov r13, utlb_addr_ptr
|
||||
mov r11, utlb_data_ptr
|
||||
bra utlb_walk_loop
|
||||
mov #0, counter
|
||||
|
||||
utlb_walk_cond_check:
|
||||
! update internal counter
|
||||
! @notes
|
||||
! - only 64 UTLB entry
|
||||
! - UTLB entry (for data and address) gap is 0x100
|
||||
mov.l data_00000100, r1
|
||||
add #1, counter
|
||||
cmp/eq #64, counter
|
||||
add r1, utlb_addr_ptr
|
||||
bf.s utlb_walk_loop
|
||||
add r1, utlb_data_ptr
|
||||
|
||||
! ---
|
||||
! Self-translation to URAM
|
||||
!
|
||||
! Now that we have the user RAM entry address (uram_phys_addr) and its size
|
||||
! (uram_phys_size), we can self-translate to this location using a dummy
|
||||
! byte-per-byte copy.
|
||||
!
|
||||
! Note that, for now, no random installation offset is performed since
|
||||
! predicting uncertain behavior is complex to choose for now.
|
||||
! ---
|
||||
|
||||
self_translation:
|
||||
! fetch bootloader ROM geometry information
|
||||
mov rom_base_addr, r0
|
||||
mov rom_image_size, r2
|
||||
|
||||
! generate uncachable P2 URAM address
|
||||
! TODO
|
||||
! - random offset
|
||||
! - check oversize
|
||||
mov.l data_a0000000, r1
|
||||
or uram_phys_addr, r1
|
||||
|
||||
! dump the complet image into URAM
|
||||
self_dump_uram:
|
||||
mov.b @r0, r14
|
||||
mov.b r14, @r1
|
||||
dt r2
|
||||
add #1, r0
|
||||
add #1, r1
|
||||
bf.s self_dump_uram
|
||||
nop
|
||||
|
||||
! Prepare the self-translation by calculating the new PC position using a
|
||||
! P1 address to allow caching to be performed.
|
||||
! @note
|
||||
! - ___fxcg50_bootloader_start is a global symbol compiled with NULL as the
|
||||
! base address. So, we don't have to calculate the gap between the start
|
||||
! of the ROM and the symbol.
|
||||
mov.l data_80000000, r1
|
||||
or uram_phys_addr, r1
|
||||
mov.l real_bootloader_start, r0
|
||||
add r1, r0
|
||||
|
||||
! self-translation
|
||||
mov rom_image_size, r6
|
||||
mov uram_phys_addr, r5
|
||||
mov rom_base_addr, r4
|
||||
jmp @r0
|
||||
nop
|
||||
|
||||
.balign 4
|
||||
|
||||
data_08100000: .long 0x08100000 ! Casio addin load virtual address
|
||||
data_f6000000: .long 0xf6000000 ! SH7305 UTLB Address address
|
||||
data_f7000000: .long 0xf7000000 ! SH7305 UTLB Data addresss
|
||||
data_14100c0a: .long 0x14100c0a ! Magic UTLB page size table
|
||||
data_1ffffc00: .long 0x1ffffc00 ! UTLB Address PPN mask
|
||||
data_00000100: .long 0x00000100 ! UTLB entry gap and UTLB validity bit
|
||||
data_a0000000: .long 0xa0000000 ! P2 base address
|
||||
data_80000000: .long 0x80000000 ! P1 base address
|
||||
ccr_register_addr: .long 0xff00001c ! SH7305.CACHE.CCR register address
|
||||
ccr_register_data: .long 0x0000010f ! CCR configuration
|
||||
real_bootloader_start:
|
||||
.long ___fxcg50_bootloader_start
|
|
@ -0,0 +1,130 @@
|
|||
#include "fx9860/asm_utils.h"
|
||||
|
||||
.section .bootloader.text, "ax"
|
||||
|
||||
/* ___fxcg50_bootloader_start() : real bootstrap entry
|
||||
|
||||
Now we are in the URAM we can performs ASLR patching, setup stack and involve
|
||||
the first high-level C code which will perform kernel setup.
|
||||
|
||||
The primary (fake) bootloader (previous operations) have setup some arg:
|
||||
- r4 = ROM relocation base address
|
||||
- r5 = RAM relocation base address (physical)
|
||||
- r6 = image size */
|
||||
|
||||
function(__fxcg50_bootloader_start):
|
||||
|
||||
! ---
|
||||
! prepare alias
|
||||
! ---
|
||||
|
||||
#define rom_reloc_base r4
|
||||
#define ram_reloc_base r5
|
||||
#define image_size r6
|
||||
|
||||
! ---
|
||||
! ASLR application
|
||||
!
|
||||
! perform ASLR patch by using the symbols table information injected
|
||||
! during bootloader build steps at the end of the bootloader code marked
|
||||
! with ___bootloader_code_end.
|
||||
!
|
||||
! The content of the table has been generated during post-compiling script
|
||||
! ---
|
||||
|
||||
! The table symbol is not aready resolved (its our job), we must manually
|
||||
! calculate the real address of the symbols table
|
||||
mov.l bootloader_code_end, r0
|
||||
mov.l p1_addr_base, r1
|
||||
mov.l p2_addr_base, r2
|
||||
or ram_reloc_base, r2
|
||||
or ram_reloc_base, r1
|
||||
add r2, r0
|
||||
|
||||
! walk trough the symbols table and patch all location
|
||||
! @note
|
||||
! - we MUST perform patching using P2 (uncachable) area to avoid
|
||||
! inconsistancy behaviour with the cache.
|
||||
! - symbols are relocalize through P1 (cachable) area
|
||||
aslr_symbol_patch_loop:
|
||||
mov.l @r0, r8
|
||||
tst r8, r8
|
||||
bt aslr_commit
|
||||
add r2, r8
|
||||
mov.l @r8, r9
|
||||
add r1, r9
|
||||
mov.l r9, @r8
|
||||
mov.l r8, @r0
|
||||
add #4, r0
|
||||
bra aslr_symbol_patch_loop
|
||||
nop
|
||||
|
||||
aslr_commit:
|
||||
! Now that ASLR symbols has been updated using uncachable area (P2), we
|
||||
! need to invalitate all Operands Cache entry that the MPU have possibly
|
||||
! setup to avoid inconsistant `mov.x` behaviour
|
||||
! @note
|
||||
! - CCR.OCI = 1 -> Operand Cache Invalidation (self-cleared to 0)
|
||||
mov.l ccr_reg_addr, r1
|
||||
mov.l @r1, r0
|
||||
or #0x08, r0
|
||||
mov.l r0, @r1
|
||||
synco
|
||||
|
||||
setup_stack:
|
||||
! TODO : watermark stack area for statistics
|
||||
! TODO : stack switch
|
||||
! TODO : stack canary
|
||||
|
||||
bootloader_c_invokation:
|
||||
mov.l p2_addr_base, r2
|
||||
mov ram_reloc_base, r4
|
||||
mov image_size, r5
|
||||
mov.l bootloader_main, r0
|
||||
jsr @r0
|
||||
or r2, r4
|
||||
|
||||
! ---
|
||||
! bootloader panic
|
||||
!
|
||||
! As we have probably wierdly restored hadware information, if the
|
||||
! bootloader main routine return we simply display black screen. You can
|
||||
! uncomment following instruction to allows getkey() to return to the menu
|
||||
! (debug only)
|
||||
! ---
|
||||
|
||||
bootloader_paniktamer:
|
||||
mov.l syscall_trampoline, r8
|
||||
mov #0x4a, r4
|
||||
mov #3, r5
|
||||
mov.l syscall_id, r0
|
||||
jsr @r8
|
||||
nop
|
||||
test1:
|
||||
! add #-4, r15
|
||||
! mov r15, r4 ! column
|
||||
! add #-4, r15
|
||||
! mov r15, r5 ! row
|
||||
! add #-4, r15
|
||||
! mov r15, r1 ! keycode
|
||||
! mov #0, r6 ! type of waiting (KEYWAIT_HALTON_TIMEOFF)
|
||||
! mov #0, r7 ! timeout period
|
||||
! mov.l r1, @-r15 ! keycode
|
||||
! mov #0, r2
|
||||
! mov.l r2, @-r15 ! [menu] key return to menu
|
||||
! mov.l getkey_id, r0
|
||||
! jsr @r8
|
||||
! nop
|
||||
bra test1
|
||||
nop
|
||||
|
||||
.balign 4
|
||||
|
||||
bootloader_main: .long _bootloader_main
|
||||
bootloader_code_end: .long ___bootloader_code_end
|
||||
syscall_trampoline: .long 0x80020070
|
||||
syscall_id: .long 0x0276
|
||||
p2_addr_base: .long 0xa0000000
|
||||
p1_addr_base: .long 0x80000000
|
||||
getkey_id: .long 0x000012bf ! GetKeyWait_OS syscall ID
|
||||
ccr_reg_addr: .long 0xff00001c ! SH7305.CACHE.CCR register address
|
|
@ -21,3 +21,6 @@ VXDEV_LDFLAGS = [
|
|||
VXDEV_LIBS = [
|
||||
'-lgcc',
|
||||
]
|
||||
VXDEV_ASSETS = [
|
||||
'font8x12',
|
||||
]
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#include "bootloader/display.h"
|
||||
#include "bootloader/bios.h"
|
||||
|
||||
//---
|
||||
// Public
|
||||
//---
|
||||
|
||||
/* _bios_dfont_get() : get font information */
|
||||
int _bios_dfont_get(struct font **font)
|
||||
{
|
||||
extern struct font font8x12;
|
||||
|
||||
if (font == NULL)
|
||||
return -1;
|
||||
*font = &font8x12;
|
||||
return 0;
|
||||
}
|
|
@ -4,9 +4,15 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// opaque definition of font struct
|
||||
struct font;
|
||||
|
||||
/* _bios_dinfo() : get display information */
|
||||
extern void _bios_dinfo(size_t *width, size_t *height);
|
||||
|
||||
/* _bios_dfont_get() : get font information */
|
||||
extern int _bios_dfont_get(struct font **font);
|
||||
|
||||
/* _bios_dpixel() : draw pixel */
|
||||
extern void _bios_dpixel(int x, int y, int color);
|
||||
|
||||
|
|
|
@ -8,10 +8,5 @@
|
|||
/* dfont_get() : get font information */
|
||||
int dfont_get(struct font **font)
|
||||
{
|
||||
extern struct font font8x9;
|
||||
|
||||
if (font == NULL)
|
||||
return -1;
|
||||
*font = &font8x9;
|
||||
return 0;
|
||||
return _bios_dfont_get(font);
|
||||
}
|
||||
|
|
|
@ -3,11 +3,17 @@ name = 'vxkernel'
|
|||
version = '0.7.0'
|
||||
target = [
|
||||
'fxcg50',
|
||||
'fx9860',
|
||||
'raspi3b',
|
||||
]
|
||||
|
||||
|
||||
[build]
|
||||
build = '/usr/bin/env python3 ./scripts/vxdev build --verbose'
|
||||
build = '/usr/bin/env python3 ./scripts/vxdev build'
|
||||
|
||||
|
||||
[fxcg50.dependencies]
|
||||
sh-elf-vhex = 'master@superh'
|
||||
|
||||
[fx9860.dependencies]
|
||||
sh-elf-vhex = 'master@superh'
|
||||
|
|
Loading…
Reference in New Issue