diff --git a/scripts/patch_kernel_img.py b/scripts/patch_kernel_img.py new file mode 100644 index 0000000..d91d9bf --- /dev/null +++ b/scripts/patch_kernel_img.py @@ -0,0 +1,30 @@ +""" +patch kernel image for the Raspberry Pi Imager +""" +import os +import sys + +#--- +# Public +#--- + +if len(sys.argv) != 3: + print("./script ") + +if os.path.exists(sys.argv[2]): + yes = input("output file already exists, overwrite? [Yn]") + if yes and yes not in ['y', 'Y', 'yes']: + print("output file already exists, abord", file=sys.stderr) + sys.exit(84) + os.remove(sys.argv[2]) + +with open(sys.argv[2], "xb") as patch: + with open(sys.argv[1], "rb") as kernel: + content = kernel.read() + patch.write(content) + kernel_size = len(content) + if kernel_size % 512: + for _ in range(0, 512 - (kernel_size % 512)): + patch.write(0x00.to_bytes(1)) + +print(f"{sys.argv[2]}: patched and generated") diff --git a/scripts/vxdev/core/build/aslr.py b/scripts/vxdev/core/build/aslr.py index c5e53ed..e3663ac 100644 --- a/scripts/vxdev/core/build/aslr.py +++ b/scripts/vxdev/core/build/aslr.py @@ -37,7 +37,7 @@ def _fetch_sectab(binpath): """ """ ret = subprocess.run( - f"readelf -S {binpath}".split(), + f"readelf --sections --wide {binpath}".split(), capture_output=True, check=False ) diff --git a/scripts/vxdev/core/build/bootloader.py b/scripts/vxdev/core/build/bootloader.py index f8a7f2b..53ff6ed 100644 --- a/scripts/vxdev/core/build/bootloader.py +++ b/scripts/vxdev/core/build/bootloader.py @@ -46,7 +46,11 @@ def bootloader_configure(build, version): cmd += f"{prefix}/assets " cmd += f"{prefix}/../../.vxsdk/{build.target}/converter/bootloader " cmd += f"--filter={','.join(compiles.assets)} " - cmd += '--bootloader' + cmd += '--bootloader ' + if compiles.toolchain_endian == 'little': + cmd += '--little-endian' + else: + cmd += '--big-endian' proc = subprocess.run(cmd.split(), capture_output=True, check=False) if proc.returncode != 0: log.emergency( diff --git a/scripts/vxdev/core/build/compiles.py b/scripts/vxdev/core/build/compiles.py index d077aef..1fc14a8 100644 --- a/scripts/vxdev/core/build/compiles.py +++ b/scripts/vxdev/core/build/compiles.py @@ -19,6 +19,7 @@ class CompilesInfo(): """ board compilation information """ toolchain_prefix = '' toolchain_processor = '' + toolchain_endian = '' cflags = [] ldflags = [] libs = [] @@ -36,11 +37,13 @@ def compiles_fetch(filename): check = 'VXDEV_TOOLCHAIN_PREFIX' in board_info check += 'VXDEV_TOOLCHAIN_PROCESSOR' in board_info - if check == 1: - log.emergency(f"{filename}: missing toolchaine information, abord") - if check == 2: - info.toolchain_prefix = board_info['VXDEV_TOOLCHAIN_PREFIX'] - info.toolchain_processor = board_info['VXDEV_TOOLCHAIN_PROCESSOR'] + check += 'VXDEV_TOOLCHAIN_ENDIANNESS' in board_info + if check != 3: + log.emergency(f"{filename}: missing toolchain information, abord") + + info.toolchain_prefix = board_info['VXDEV_TOOLCHAIN_PREFIX'] + info.toolchain_processor = board_info['VXDEV_TOOLCHAIN_PROCESSOR'] + info.toolchain_endian = board_info['VXDEV_TOOLCHAIN_ENDIANNESS'] if 'VXDEV_CFLAGS' in board_info: info.cflags = board_info['VXDEV_CFLAGS'] if 'VXDEV_LDFLAGS' in board_info: diff --git a/sdk/converter/cli/assets.py b/sdk/converter/cli/assets.py index a2b85d6..35eb1a0 100644 --- a/sdk/converter/cli/assets.py +++ b/sdk/converter/cli/assets.py @@ -2,6 +2,7 @@ cli.conv.assets - Vhex asset converter user interface """ import os +import dataclasses from core.logger import log from core import assets_generate @@ -37,9 +38,21 @@ OPTIONS: --bootloader Generate bootloader font encoding --kernel Generate kernel font encoding --os Generate OS font encoding (default) + --little-endian Encode assets information in little endian format + --big-endian Encode assets information in big endian format -h, --help Display this help """ +@dataclasses.dataclass +class _ConvertAssetInfo(): + """ Assets converter information """ + force = False + endianness = 'little' + generator = 'os' + prefix_output = '' + prefix_assets = '' + assets_filter = [] + #--- # Public #--- @@ -52,39 +65,37 @@ def assets_conv_cli(argv): return 0 # fetch user indication - force = False - generator = 'os' - prefix_output = '' - prefix_assets = '' - assets_filter = [] + info = _ConvertAssetInfo() for arg in argv: if arg in ['-f', '--force']: - force = True + info.force = True continue if arg == '--bootloader': - generator = 'bootloader' + info.generator = 'bootloader' continue - if not prefix_assets: - prefix_assets = arg + if arg == '--little-endian': + info.endianness = 'little' + continue + if arg == '--big-endian': + info.endianness = 'big' + continue + if not info.prefix_assets: + info.prefix_assets = arg continue if arg.find('--filter=') == 0: - assets_filter = arg[9:].split(',') + info.assets_filter = arg[9:].split(',') continue - if prefix_output: - log.warn(f"previous output path ({prefix_output}) dropped") - prefix_output = arg + if info.prefix_output: + log.warn(f"previous output path ({info.prefix_output}) dropped") + info.prefix_output = arg # check indication - if not prefix_assets: + if not info.prefix_assets: log.emergency('missing assets prefix') - if not prefix_assets: + if not info.prefix_assets: log.emergency('missing output prefix') + info.prefix_assets = os.path.abspath(info.prefix_assets) + info.prefix_output = os.path.abspath(info.prefix_output) # generate assets information - return assets_generate( - os.path.abspath(prefix_assets), - os.path.abspath(prefix_output), - generator, - assets_filter, - force - ) + return assets_generate(info) diff --git a/sdk/converter/core/assets.py b/sdk/converter/core/assets.py index a703303..e0d8591 100644 --- a/sdk/converter/core/assets.py +++ b/sdk/converter/core/assets.py @@ -93,44 +93,47 @@ class _VxAsset(): # Public method #--- - def generate_source_file(self, prefix_output, generator, force_generate): + def generate_source_file( + self, + prefix_output, + generator, + endianness, + force_generate + ): """generate source file """ function = font_generate if self.type == 'font' else image_generate - return function(self, prefix_output, generator, force_generate) + return function( + self, + prefix_output, + generator, + endianness, + force_generate + ) #--- # Public #--- -def assets_generate( - prefix_assets, - prefix_output, - generator, - assets_filter, - force_generate -): +def assets_generate(info): """ 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 + > info (dataclass) - contains all information about the conversion @return > a list of all generated sources pathname """ - if not os.path.exists(prefix_output): - os.makedirs(prefix_output) - for root, _, files in os.walk(prefix_assets): + if not os.path.exists(info.prefix_output): + os.makedirs(info.prefix_output) + for root, _, files in os.walk(info.prefix_assets): if 'vxconv.toml' not in files: continue 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 + if info.assets_filter: + if asset_name not in info.assets_filter: + continue log.debug(f"converting {asset_name}...") log.user( _VxAsset( @@ -138,9 +141,10 @@ def assets_generate( asset_name, content[asset_name] ).generate_source_file( - prefix_output, - generator, - force_generate + info.prefix_output, + info.generator, + info.endianness, + info.force ) ) return 0 diff --git a/sdk/converter/core/font/__init__.py b/sdk/converter/core/font/__init__.py index 6ea227b..c0e0b7e 100644 --- a/sdk/converter/core/font/__init__.py +++ b/sdk/converter/core/font/__init__.py @@ -16,13 +16,14 @@ __all__ = [ # Public #--- -def font_generate(asset, prefix_output, generator, force_generate): +def font_generate(asset, prefix_output, generator, endian, force_generate): """ Convert an image asset to a C source file @args > asset (_VxAsset) - minimal asset information > prefix_output (str) - prefix for source file generation > generator (str) - selected generator for C file content + > endian (str) - selected endianness encoding > force_generate (bool) - force generate the source file @return @@ -41,7 +42,7 @@ def font_generate(asset, prefix_output, generator, force_generate): return '' # create the source file - content = font_generate_source_file(asset, font_info, generator) + content = font_generate_source_file(asset, font_info, generator, endian) with open(asset_src, "w", encoding='utf8') as file: file.write(content) log.debug(f"source file generated at {asset_src}") diff --git a/sdk/converter/core/font/generator/__init__.py b/sdk/converter/core/font/generator/__init__.py index 9087945..d664281 100644 --- a/sdk/converter/core/font/generator/__init__.py +++ b/sdk/converter/core/font/generator/__init__.py @@ -9,20 +9,27 @@ from core.font.generator.bootloader import font_generate_bootloader_source_file # Public #--- -def font_generate_source_file(asset, font_info, generator): +def font_generate_source_file(asset, font_info, generator, endianness): """ return the C source file based on the selected generator @args > asset (_VxAsset) - minimal asset information > font_info (dict) - font information > generator (str) - selected generator for C file content + > endianness (str) - selected endianness encoding @return > file content (str) """ if generator not in ['bootloader', 'kernel', 'os']: log.emergency(f"not supported generator '{generator}'") + if generator == 'bootloader': - return font_generate_bootloader_source_file(asset, font_info) + return font_generate_bootloader_source_file( + asset, + font_info, + endianness + ) + log.emergency(f"generator '{generator}' not implemented yet o(x_x)o") return '' diff --git a/sdk/converter/core/font/generator/bootloader.py b/sdk/converter/core/font/generator/bootloader.py index 3664ca1..839e38f 100644 --- a/sdk/converter/core/font/generator/bootloader.py +++ b/sdk/converter/core/font/generator/bootloader.py @@ -12,11 +12,26 @@ __all__ = [ # Internals #--- -def _font_generate_normal_source(asset, font_info): +def _u32_conv_little_endian(x32): +# return ((x32 & 0xff000000) >> 24) \ +# | ((x32 & 0x00ff0000) >> 8) \ +# | ((x32 & 0x0000ff00) << 8) \ +# | ((x32 & 0x000000ff) << 24) + return x32 + +def _u32_conv_big_endian(x32): + return x32 + +def _font_generate_normal_source(asset, font_info, endianness): """ Print chaset is a image file - Generate a C font file content based on bootloader font internal structure - and header declaration. + Generate a C font file content based on bootloader font internal + structure and header declaration. + + @args + > asset (VxAsset) - asset information + > info (dict) - hold font information + > endianness (str) - selected endianness encoding @return > complet font file content @@ -29,6 +44,11 @@ def _font_generate_normal_source(asset, font_info): content += 'converter */\n' content += f"struct font const {asset.name} = " + "{\n" + # handle endianness + u32 = _u32_conv_little_endian + if endianness != 'little': + u32 = _u32_conv_big_endian + # encode font bitmap line = 0 log.debug(f"data = {font_info['data']}") @@ -38,7 +58,7 @@ def _font_generate_normal_source(asset, font_info): content += ' ' if line >= 1: content += ' ' - content += f"{pixel:#010x}," + content += f"{u32(pixel):#010x}," if (line := line + 1) == 6: content += '\n' line = 0 @@ -61,12 +81,13 @@ def _font_generate_normal_source(asset, font_info): # Public #--- -def font_generate_bootloader_source_file(asset, font_info): +def font_generate_bootloader_source_file(asset, font_info, endianness): """ Generate font source file content @args - > asset (VxAsset) - asset information - > info (dict) - hold font information + > asset (VxAsset) - asset information + > info (dict) - hold font information + > endianness (str) - selected endianness encoding @return > file C content string @@ -78,4 +99,4 @@ def font_generate_bootloader_source_file(asset, font_info): log.emergency(f"{asset.name}: unsupported unicode font") # generate file content - return _font_generate_normal_source(asset, font_info) + return _font_generate_normal_source(asset, font_info, endianness) diff --git a/vxgos/boards/fxcg50/g3a_generator.py b/vxgos/boards/fxcg50/g3a_generator.py index 1731c59..a390a01 100644 --- a/vxgos/boards/fxcg50/g3a_generator.py +++ b/vxgos/boards/fxcg50/g3a_generator.py @@ -131,8 +131,8 @@ def _main(argv): addin = bytearray(0x7000) _generate_standar_header(addin) _generate_addin_subheader(addin) - _generate_addin_icon(addin, 0x1000, argv[2]) - _generate_addin_icon(addin, 0x4000, argv[3]) + _generate_addin_icon(addin, 0x1000, argv[3]) + _generate_addin_icon(addin, 0x4000, argv[2]) addin += rawbin addin += bytearray(4) _generate_checksums(addin) diff --git a/vxgos/boards/raspi3b/generate.py b/vxgos/boards/raspi3b/generate.py index d410edb..df5b046 100644 --- a/vxgos/boards/raspi3b/generate.py +++ b/vxgos/boards/raspi3b/generate.py @@ -10,11 +10,27 @@ __all__ = [ '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), 8): + print(f" > reloc GOT entry {got_base_addr+i:016x}...") + symfile.write((got_base_addr + i).to_bytes(8, 'little')) + break + #--- # Public #--- -def generate_aslr_blob(binpath, symtab, _): +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 @@ -45,50 +61,57 @@ def generate_aslr_blob(binpath, symtab, _): print('- generate raw symtab...') if os.path.exists(f"{binpath}.symtab"): os.remove(f"{binpath}.symtab") - #need_patch_got = False + 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 + # direct 64bits address if sym[2] == 'R_AARCH64_ABS64': - print(f" > [{i}] reloc {sym[2]} not implemented o(x_x)o") + print(f" > reloc 'R_AARCH64_ABS64' sym at {sym[0]}") + symfile.write(int(sym[0], base=16).to_bytes(8, 'little')) + continue + + # need GOT patch + if sym[2] == 'R_AARCH64_ADR_GOT': need_patch_got = True continue - if sym[2] in [ - 'R_AARCH64_ADR_PRE', - 'R_AARCH64_ADD_ABS', - 'R_AARCH64_ADR_GOT', - 'R_AARCH64_LD64_GO', - ]: - print(f" > [{i}] reloc {sym[2]} not tested yet o(x_x)o") + if sym[2] == 'R_AARCH64_LD64_GO': continue - if sym[2] not in [ + + # PC-related TAG + if sym[2] in [ 'R_AARCH64_JUMP26', 'R_AARCH64_CALL26', 'R_AARCH64_ADR_PRE', 'R_AARCH64_ADD_ABS', - 'R_AARCH64_ABS64', - 'R_AARCH64_ADR_GOT', - 'R_AARCH64_LD64_GO', + 'R_AARCH64_LDST32_', ]: - 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(8, 'big')) + continue + + # unsupported TAG, aboard + print(f" > [{i}] reloc {sym[2]} not supported") + sys.exit(84) + + # patch GOT if needed + if need_patch_got: + _patch_got_section(symfile, sectab) + symfile.write(int('0000000000000000', base=16).to_bytes(8, 'little')) print('- generate the full bootloader...') if os.path.exists(f"{binpath}.bzImage"): os.remove(f"{binpath}.bzImage") + image_size = 0 with open(f"{binpath}.bzImage", 'xb') as bzimgfile: with open(f"{binpath}.raw", 'rb') as rawbinfile: - bzimgfile.write(rawbinfile.read()) + content = rawbinfile.read() + bzimgfile.write(content) + image_size += len(content) with open(f"{binpath}.symtab", 'rb') as symtabfile: - bzimgfile.write(symtabfile.read()) + content = symtabfile.read() + bzimgfile.write(content) + image_size += len(content) + if image_size % 512: + for _ in range(0, 512 - (image_size % 512)): + bzimgfile.write(0x00.to_bytes(1)) return f"{binpath}.bzImage" diff --git a/vxgos/bootloader/boards/fxcg50/compiles.toml b/vxgos/bootloader/boards/fxcg50/compiles.toml index 892d6ab..93a169a 100644 --- a/vxgos/bootloader/boards/fxcg50/compiles.toml +++ b/vxgos/bootloader/boards/fxcg50/compiles.toml @@ -1,5 +1,6 @@ -VXDEV_TOOLCHAIN_PREFIX = 'sh-elf-vhex-' -VXDEV_TOOLCHAIN_PROCESSOR = 'sh' +VXDEV_TOOLCHAIN_PREFIX = 'sh-elf-vhex-' +VXDEV_TOOLCHAIN_PROCESSOR = 'sh' +VXDEV_TOOLCHAIN_ENDIANNESS = 'big' VXDEV_CFLAGS = [ '-Wall', '-Wextra', @@ -7,7 +8,7 @@ VXDEV_CFLAGS = [ '-ffreestanding', '-nostdlib', '-fPIE', - '-O1', + '-O3', '-mb', '-m4-nofpu', '-fstrict-volatile-bitfields', diff --git a/vxgos/bootloader/boards/raspi3b/compiles.toml b/vxgos/bootloader/boards/raspi3b/compiles.toml index 236eaed..c57b7a1 100644 --- a/vxgos/bootloader/boards/raspi3b/compiles.toml +++ b/vxgos/bootloader/boards/raspi3b/compiles.toml @@ -1,5 +1,6 @@ -VXDEV_TOOLCHAIN_PREFIX = 'aarch64-linux-gnu-' -VXDEV_TOOLCHAIN_PROCESSOR = 'aarch64' +VXDEV_TOOLCHAIN_PREFIX = 'aarch64-linux-gnu-' +VXDEV_TOOLCHAIN_PROCESSOR = 'aarch64' +VXDEV_TOOLCHAIN_ENDIANNESS = 'little' VXDEV_CFLAGS = [ '-Wall', '-Wextra', @@ -7,7 +8,9 @@ VXDEV_CFLAGS = [ '-ffreestanding', '-nostdlib', '-fPIE', - '-O1', + '-O3', + '-mlittle-endian', + '-march=armv8-a', '-fstrict-volatile-bitfields', ] VXDEV_LDFLAGS = [ @@ -16,3 +19,6 @@ VXDEV_LDFLAGS = [ '-Wl,--build-id=none', '-Wl,--emit-relocs', ] +VXDEV_ASSETS = [ + 'font8x12', +] diff --git a/vxgos/bootloader/boards/raspi3b/include/raspi3b/board.h b/vxgos/bootloader/boards/raspi3b/include/raspi3b/board.h new file mode 100644 index 0000000..48a2376 --- /dev/null +++ b/vxgos/bootloader/boards/raspi3b/include/raspi3b/board.h @@ -0,0 +1,11 @@ +#ifndef VXGOS_BOOTLOADER_RASPI3B_BOARD_H +#define VXGOS_BOOTLOADER_RASPI3B_BOARD_H + +//--- +// Public API +//--- + +/* board_init() : initialize board information */ +extern int board_init(void); + +#endif /* VXGOS_BOOTLOADER_RASPI3B_BOARD_H */ diff --git a/vxgos/bootloader/boards/raspi3b/include/raspi3b/framebuffer.h b/vxgos/bootloader/boards/raspi3b/include/raspi3b/framebuffer.h new file mode 100644 index 0000000..182c660 --- /dev/null +++ b/vxgos/bootloader/boards/raspi3b/include/raspi3b/framebuffer.h @@ -0,0 +1,43 @@ +#ifndef VXGOS_BOOTLOADER_RASPI3B_FRAMEBUFFER_H +#define VXGOS_BOOTLOADER_RASPI3B_FRAMEBUFFER_H + +#include +#include + +//--- +// Public API +//--- + +#define FRAMEBUFFER_WATERMARK 0xdeb0cad0 + +/* frambuffer - internal framebuffer information */ +struct framebuffer +{ + uint32_t watermark; + struct { + uintptr_t gpu; + uintptr_t cpu; + size_t size; + int pitch; + int align; + } vram; + struct { + size_t width; + size_t height; + } phys; + struct { + size_t width; + size_t height; + } virt; +}; + +/* framebuffer_init() : initialize framebuffer */ +extern int framebuffer_init(void); + +/* framebuffer_get() : fetch the framebuffer information if available */ +extern int framebuffer_get(struct framebuffer **framebuffer_out); + +/* framebuffer_debug() : display framebuffer information */ +extern void framebuffer_debug(void); + +#endif /* VXGOS_BOOTLOADER_RASPI3B_FRAMEBUFFER_H */ diff --git a/vxgos/bootloader/boards/raspi3b/include/raspi3b/mailbox.h b/vxgos/bootloader/boards/raspi3b/include/raspi3b/mailbox.h new file mode 100644 index 0000000..a1f6a59 --- /dev/null +++ b/vxgos/bootloader/boards/raspi3b/include/raspi3b/mailbox.h @@ -0,0 +1,184 @@ +#ifndef VXGOS_BOOTLOADER_RASPI3B_MAILBOX_H +#define VXGOS_BOOTLOADER_RASPI3B_MAILBOX_H + +#include "raspi3b/utils.h" + +//--- +// Public API +//--- + +/* MBOX_REQUEST_* : mailbox request tag */ +enum { + MBOX_REQUEST_CODE = 0x00000000, + MBOX_REQUEST_SUCCEED = 0x80000000, + MBOX_REQUEST_FAILED = 0x80000001, +}; + +/* MBOX_TAG_* : mailbox supported tags + * @note + * <> some obscure TAG are missing + * <> some obscure TAG can change with other raspi board + * */ +enum { + // Request + MBOX_TAG_END = 0x00000000, + + // Video Core + MBOX_TAG_GET_FIRMWARE_REV = 0x00000001, + + // Hardware + MBOX_TAG_GET_BOARD_MODEL = 0x00010001, + MBOX_TAG_GET_BOARD_REV = 0x00010002, + MBOX_TAG_GET_BOARD_MAC = 0x00010003, + MBOX_TAG_GET_BOARD_SERIAL = 0x00010004, + MBOX_TAG_GET_ARM_MEMORY = 0x00010005, + MBOX_TAG_GET_VC_MEMORY = 0x00010006, + MBOX_TAG_GET_CLOCKS = 0x00010007, + + // Config + MBOX_TAG_GET_CMDLINE = 0x00050001, + + // Shared Ressource Management + MBOX_TAG_GET_DMA_CHANNELS = 0x00060001, + + // Power + MBOX_TAG_GET_POWER_STATE = 0x00020001, + MBOX_TAG_SET_POWER_STATE = 0x00028001, + MBOX_TAG_GET_POWER_TIMING = 0x00020002, + + // Clocks + MBOX_TAG_GET_CLOCK_STATE = 0x00030001, + MBOX_TAG_SET_CLOCK_STATE = 0x00038001, + MBOX_TAG_GET_CLOCK_RATE = 0x00030002, + MBOX_TAG_SET_CLOCK_RATE = 0x00038002, + MBOX_TAG_GET_CLOCK_RATE_MAX = 0x00030004, + MBOX_TAG_GET_CLOCK_RATE_MIN = 0x00030007, + MBOX_TAG_GET_CLOCK_RATE_REAL = 0x00030047, + MBOX_TAG_GET_TURBO = 0x00030009, + MBOX_TAG_SET_TURBO = 0x00038009, + + // Leds + MBOX_TAG_GET_BOARD_LED_STATUS = 0x00030041, + MBOX_TAG_TEST_BOARD_LED_STATUS = 0x00034041, + MBOX_TAG_SET_BOARD_LED_STATUS = 0x00038041, + + // Voltage + MBOX_TAG_GET_VOLTAGE = 0x00030003, + MBOX_TAG_SET_VOLTAGE = 0x00038003, + MBOX_TAG_GET_VOLTAGE_MAX = 0x00030005, + MBOX_TAG_GET_VOLTAGE_MIN = 0x00030008, + + // Temperature + MBOX_TAG_GET_TEMPERATURE = 0x00030006, + MBOX_TAG_GET_TEMPERATURE_MAX = 0x0003000a, + + // Memory management + MBOX_TAG_MEMORY_ALLOC = 0x0003000c, + MBOX_TAG_MEMORY_LOCK = 0x0003000d, + MBOX_TAG_MEMORY_UNLOCK = 0x0003000e, + MBOX_TAG_MEMORY_FREE = 0x0003000f, + + // Screen (HDMI/DVI) + MBOX_TAG_SCREEN_BUFF_ALLOC = 0x00040001, + MBOX_TAG_SCREEN_BUFF_FREE = 0x00048001, + MBOX_TAG_SCREEN_BLINK = 0x00040002, + MBOX_TAG_SCREEN_GET_PHYS_SIZE = 0x00040003, + MBOX_TAG_SCREEN_SET_PHYS_SIZE = 0x00048003, + MBOX_TAG_SCREEN_TEST_PHYS_SIZE = 0x00044003, + MBOX_TAG_SCREEN_GET_VIRT_SIZE = 0x00040004, + MBOX_TAG_SCREEN_SET_VIRT_SIZE = 0x00048004, + MBOX_TAG_SCREEN_TEST_VIRT_SIZE = 0x00044004, + MBOX_TAG_SCREEN_GET_PIXEL_DEPTH = 0x00040005, + MBOX_TAG_SCREEN_SET_PHYS_DEPTH = 0x00048005, + MBOX_TAG_SCREEN_TEST_PIXEL_DEPTH = 0x00044005, + MBOX_TAG_SCREEN_GET_PIXEL_ORDER = 0x00040006, + MBOX_TAG_SCREEN_SET_PIXEL_ORDER = 0x00048006, + MBOX_TAG_SCREEN_TEST_PIXEL_ORDER = 0x00044006, + MBOX_TAG_SCREEN_GET_PIXEL_ALPHA_MODE = 0x00040007, + MBOX_TAG_SCREEN_SET_PIXEL_ALPHA_MODE = 0x00048007, + MBOX_TAG_SCREEN_TEST_PIXEL_ALPHA_MODE = 0x00044007, + MBOX_TAG_SCREEN_GET_PITCH = 0x00040008, + MBOX_TAG_SCREEN_GET_VIRTUAL_OFFSET = 0x00040009, + MBOX_TAG_SCREEN_SET_VIRTUAL_OFFSET = 0x00048009, + MBOX_TAG_SCREEN_TEST_VIRTUAL_OFFSET = 0x00044009, + MBOX_TAG_SCREEN_GET_OVERSCAN = 0x0004000a, + MBOX_TAG_SCREEN_SET_OVERSCAN = 0x0004800a, + MBOX_TAG_SCREEN_TEST_OVERSCAN = 0x0004400a, + MBOX_TAG_SCREEN_GET_PALETTE = 0x0004000b, + MBOX_TAG_SCREEN_SET_PALETTE = 0x0004800b, + MBOX_TAG_SCREEN_TEST_PALETTE = 0x0004400b, + MBOX_TAG_SCREEN_SET_CURSOR_INFO = 0x00008010, + MBOX_TAG_SCREEN_SET_CURSOR_STATE = 0x00008011, + MBOX_TAG_SCREEN_SET_GAMMA = 0x00008012, +}; + +/* MBOX_CHANNEL_* : mailbox channel ID */ +enum { + MBOX_CHANNEL_POWER = 0, + MBOX_CHANNEL_FRAMEBUFFER = 1, + MBOX_CHANNEL_VUART = 2, + MBOX_CHANNEL_VCHIQ = 3, + MBOX_CHANNEL_LEDS = 4, + MBOX_CHANNEL_BTNS = 5, + MBOX_CHANNEL_TOUCH = 6, + MBOX_CHANNEL_COUNT = 7, + MBOX_CHANNEL_PROP = 8, +}; + +/* mailbox_get() : return the mailbox request buffer */ +extern int mailbox_get(volatile uint32_t **mbox); + +/* mailbox_send() : send request to the mailbox */ +extern int mailbox_send(int channel); + +//--- +// Mailbox mecanism +// +// @note +// <> mailbox seems to be the only way to communicate with the VideoCore +// firmware which seems to contains a lot of critical primitive. The +// firmware is in closed source, so all information written here are +// glanned using multiple source: +// +// - https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes +// - https://github.com/bztsrc/raspi3-tutorial +// - https://github.com/raspberrypi/firmware/blob/master/hardfp/opt/vc/bin/vcmailbox +// - https://www.rpi4os.com/part5-framebuffer/ +//--- + +/* __bcm2837_mailbox : mailbox module structure */ +struct __bcm2837_mailbox +{ + /* [0x0020b880] Read "register" */ + u32_union(MBOX_READ, + uint32_t CHANNEL :4; + uint32_t DATA :28; + ); + pad(0x0c); + + /* [0x0020b890] Unknown register (rpi4os.com/part5-framebuffer) */ + const uint32_t MBOX_POLL; + /* [0x0020b894] Unknown register (rpi4os.com/part5-framebuffer) */ + const uint32_t MBOX_SENDER; + + /* [0x0020b898] Status regsiter */ + u32_union(MBOX_STATUS, + uint32_t :24; + uint32_t EMPTY :1; /* indicate if the MBOX is empty */ + uint32_t FULL :1; /* indicate if the MBOX is full */ + ); + + /* [0x0020b89c] Configuration register */ + //TODO : bitfields + uint32_t MBOX_CONFIG; + + /* [0x0020b8a0] Write register */ + u32_union(MBOX_WRITE, + uint32_t CHANNEL :4; + uint32_t DATA :28; + ); +} VPACKED(4); + +#define BCM2837_MAILBOX (*((volatile struct __bcm2837_mailbox*)0x3f00b880)) + +#endif /* VXGOS_BOOTLOADER_RASPI3B_MAILBOX_H */ diff --git a/vxgos/bootloader/boards/raspi3b/include/raspi3b/memory.h b/vxgos/bootloader/boards/raspi3b/include/raspi3b/memory.h new file mode 100644 index 0000000..af8edef --- /dev/null +++ b/vxgos/bootloader/boards/raspi3b/include/raspi3b/memory.h @@ -0,0 +1,28 @@ +#ifndef VXGOS_BOOTLOADER_RASPI3B_MEMORY_H +#define VXGOS_BOOTLOADER_RASPI3B_MEMORY_H + +#include +#include + +//--- +// Public API +//--- + +enum { + MEM_FLAG_DISCARDABLE = 1 << 0, + MEM_FLAG_NORMAL = 0 << 2, + MEM_FLAG_DIRECT = 1 << 2, + MEM_FLAG_COHERENT = 2 << 2, + MEM_FLAG_L1_NONALLOCATING = (MEM_FLAG_DIRECT | MEM_FLAG_COHERENT), + MEM_FLAG_ZERO = 1 << 4, + MEM_FLAG_NO_INIT = 1 << 5, + MEM_FLAG_HINT_PERMALOCK = 1 << 6, +}; + +/* memory_alloc() : malloc using GPU firmware request */ +extern void *memory_alloc(size_t size, int align, int flags); + +/* memory_free() : free using GPU firmware request */ +extern void memory_free(void *ptr); + +#endif /* VXGOS_BOOTLOADER_RASPI3B_MEMORY_H */ diff --git a/vxgos/bootloader/boards/raspi3b/include/raspi3b/uart.h b/vxgos/bootloader/boards/raspi3b/include/raspi3b/uart.h new file mode 100644 index 0000000..ad6346f --- /dev/null +++ b/vxgos/bootloader/boards/raspi3b/include/raspi3b/uart.h @@ -0,0 +1,17 @@ +#ifndef VXGOS_BOOTLOADER_RASPI3B_UART_H +#define VXGOS_BOOTLOADER_RASPI3B_UART_H + +//--- +// Public API +//--- + +/* uart_init() : initilize UART driver */ +extern void uart_init(void); + +/* uart_puts() : send string through the UART line (convert new line) */ +extern void uart_puts(char const * const s); + +/* uart_putf() : printf-like puts */ +extern void uart_putf(char const * const format, ...); + +#endif /* VXGOS_BOOTLOADER_RASPI3B_UART_H */ diff --git a/vxgos/bootloader/boards/raspi3b/src/bios/dfont.c b/vxgos/bootloader/boards/raspi3b/src/bios/dfont.c index af8d175..500ee83 100644 --- a/vxgos/bootloader/boards/raspi3b/src/bios/dfont.c +++ b/vxgos/bootloader/boards/raspi3b/src/bios/dfont.c @@ -8,7 +8,10 @@ /* _bios_dfont_get() : get font information */ int _bios_dfont_get(struct font **font) { - if (*font != NULL) - font = NULL; - return -1; + extern struct font font8x12; + + if (font == NULL) + return -1; + *font = &font8x12; + return 0; } diff --git a/vxgos/bootloader/boards/raspi3b/src/bios/dinfo.c b/vxgos/bootloader/boards/raspi3b/src/bios/dinfo.c index 5b1dbf2..f2cc95f 100644 --- a/vxgos/bootloader/boards/raspi3b/src/bios/dinfo.c +++ b/vxgos/bootloader/boards/raspi3b/src/bios/dinfo.c @@ -1,4 +1,5 @@ #include "bootloader/bios.h" +#include "raspi3b/framebuffer.h" //--- // Public @@ -7,8 +8,12 @@ /* _bios_dinfo() : get display information */ void _bios_dinfo(size_t *width, size_t *height) { + struct framebuffer *framebuffer; + + if (framebuffer_get(&framebuffer) != 0) + return; if (width != NULL) - *width = 0; + *width = framebuffer->phys.width; if (height != NULL) - *height = 0; + *height = framebuffer->phys.height; } diff --git a/vxgos/bootloader/boards/raspi3b/src/bios/dpixel.c b/vxgos/bootloader/boards/raspi3b/src/bios/dpixel.c index f0a5151..0250775 100644 --- a/vxgos/bootloader/boards/raspi3b/src/bios/dpixel.c +++ b/vxgos/bootloader/boards/raspi3b/src/bios/dpixel.c @@ -1,4 +1,6 @@ #include "bootloader/bios.h" +#include "bootloader/display.h" +#include "raspi3b/framebuffer.h" //--- // Public @@ -7,7 +9,24 @@ /* _bios_dpixel() : dpixel wrapper */ void _bios_dpixel(int x, int y, int color) { - (void)x; - (void)y; - (void)color; + struct framebuffer *framebuffer; + uint32_t *vram; + + if (framebuffer_get(&framebuffer) != 0) + return; + if ((unsigned)x >= framebuffer->phys.width) + return; + if ((unsigned)y >= framebuffer->phys.height) + return; + + vram = (void *)framebuffer->vram.cpu; + switch (color) + { + case C_WHITE: + vram[(y * framebuffer->phys.width) + x] = 0xffffffff; + break; + case C_BLACK: + vram[(y * framebuffer->phys.width) + x] = 0x00000000; + break; + } } diff --git a/vxgos/bootloader/boards/raspi3b/src/bios/free.c b/vxgos/bootloader/boards/raspi3b/src/bios/free.c index 089ba56..9ef2107 100644 --- a/vxgos/bootloader/boards/raspi3b/src/bios/free.c +++ b/vxgos/bootloader/boards/raspi3b/src/bios/free.c @@ -1,4 +1,5 @@ #include "bootloader/bios.h" +#include "raspi3b/memory.h" //--- // Public @@ -7,5 +8,5 @@ /* _bios_free() : free allocated memory */ void _bios_free(void *ptr) { - (void)ptr; + memory_free(ptr); } diff --git a/vxgos/bootloader/boards/raspi3b/src/bios/malloc.c b/vxgos/bootloader/boards/raspi3b/src/bios/malloc.c index b7ebb16..d39cf89 100644 --- a/vxgos/bootloader/boards/raspi3b/src/bios/malloc.c +++ b/vxgos/bootloader/boards/raspi3b/src/bios/malloc.c @@ -1,4 +1,5 @@ #include "bootloader/bios.h" +#include "raspi3b/memory.h" //--- // Public @@ -7,6 +8,9 @@ /* _bios_malloc() : memory allocator */ void *_bios_malloc(size_t size) { - (void)size; - return NULL; + return memory_alloc( + size, + 4, + MEM_FLAG_NO_INIT | MEM_FLAG_NORMAL + ); } diff --git a/vxgos/bootloader/boards/raspi3b/src/board.c b/vxgos/bootloader/boards/raspi3b/src/board.c new file mode 100644 index 0000000..d1f10bb --- /dev/null +++ b/vxgos/bootloader/boards/raspi3b/src/board.c @@ -0,0 +1,63 @@ +#include +#include + +#include "raspi3b/board.h" +#include "raspi3b/uart.h" +#include "raspi3b/mailbox.h" + +//--- +// Internals +//--- + +/* board_get_generic_u32() : generic mailbox call for u32 response */ +static uint32_t board_get_generic_u32(uint32_t tag) +{ + volatile uint32_t *mbox; + + if (mailbox_get(&mbox) != 0) + return 0x55555555; + + mbox[0] = 7 * 4; + mbox[1] = MBOX_REQUEST_CODE; + mbox[2] = tag; + mbox[3] = 4; + mbox[4] = MBOX_REQUEST_CODE; + mbox[5] = 0; + mbox[6] = MBOX_TAG_END; + + if (mailbox_send(MBOX_CHANNEL_PROP) == 0) + return 0x77777777; + + return mbox[5]; +} + +/* board_get_revision() : request the board revision */ +static uint32_t board_get_revision(void) +{ + return board_get_generic_u32(MBOX_TAG_GET_BOARD_REV); +} + +/* board_get_model() : request the board model */ +static uint32_t board_get_model(void) +{ + return board_get_generic_u32(MBOX_TAG_GET_BOARD_MODEL); +} + +/* board_get_firmware_ver() : request the GPU firmware revision */ +static uint32_t board_get_firmware_ver(void) +{ + return board_get_generic_u32(MBOX_TAG_GET_FIRMWARE_REV); +} + +//--- +// Public +//--- + +/* board_init() : initialize board information */ +int board_init(void) +{ + uart_putf("- board model = %p\n", board_get_model()); + uart_putf("- board revision = %p\n", board_get_revision()); + uart_putf("- GPU firmware version = %p\n", board_get_firmware_ver()); + return 0; +} diff --git a/vxgos/bootloader/boards/raspi3b/src/console/keysc.c b/vxgos/bootloader/boards/raspi3b/src/console/keysc.c index 991fadc..fca78fc 100644 --- a/vxgos/bootloader/boards/raspi3b/src/console/keysc.c +++ b/vxgos/bootloader/boards/raspi3b/src/console/keysc.c @@ -6,5 +6,8 @@ /* console_key_get() : small one-shot key waiter */ int console_key_get(void) { + while(1) { + _asm__ volatile ("nop"); + } return -1; } diff --git a/vxgos/bootloader/boards/raspi3b/src/fake_entry.c b/vxgos/bootloader/boards/raspi3b/src/fake_entry.c index 809db71..784799b 100644 --- a/vxgos/bootloader/boards/raspi3b/src/fake_entry.c +++ b/vxgos/bootloader/boards/raspi3b/src/fake_entry.c @@ -1,151 +1,50 @@ #include -#include +#include -#include "raspi3b/auxiliary.h" -#include "raspi3b/gpio.h" +#include "raspi3b/uart.h" +#include "raspi3b/mailbox.h" +#include "raspi3b/framebuffer.h" +#include "raspi3b/board.h" - -//--- -// Internals -//--- - -// driver-level primitives - -/* uart_init() : initialize the MiniUART1 module */ -static void uart_init(void) -{ - /* initialize UART - * - * @note - * <> disalbe UART interruption - * <> enable UART module - * <> clear Tx and Rx FIFOs - * <> setup to 115200 baud - * baudrate = system_clk_freq / (8 * (baud_reg + 1)) - * baud_reg = ((system_clk_freq / baudrate) / 8) - 1 */ - BCM2837_AUXILIARY.AUX_ENABLE.MiniUART = 1; - - /* disable as soon as possible Tx and Rx */ - BCM2837_AUXILIARY.AUX_MU_CNTL.RE = 0; - BCM2837_AUXILIARY.AUX_MU_CNTL.TE = 0; - - /* disable Tx or Rx interrupts */ - BCM2837_AUXILIARY.AUX_MU_IER.TIE = 0; - BCM2837_AUXILIARY.AUX_MU_IER.RIE = 0; - - /* clear FIFOs (FIFOs are always enabled) */ - //FIXME : be sure to not force enable FIFO channels - BCM2837_AUXILIARY.AUX_MU_IIR.TXFLUSH = 1; - BCM2837_AUXILIARY.AUX_MU_IIR.RXFLUSH = 1; - - /* Configure data format */ - BCM2837_AUXILIARY.AUX_MU_LCR.DLAB = 0; - BCM2837_AUXILIARY.AUX_MU_LCR.BREAK = 0; - BCM2837_AUXILIARY.AUX_MU_LCR.CHR = 0b11; - BCM2837_AUXILIARY.AUX_MU_MCR.RTS = 0; - - /* Configure extra features */ - BCM2837_AUXILIARY.AUX_MU_CNTL.ERAF = 0; - BCM2837_AUXILIARY.AUX_MU_CNTL.ETAF = 0; - BCM2837_AUXILIARY.AUX_MU_CNTL.RTS_AUTO = 0b00; - BCM2837_AUXILIARY.AUX_MU_CNTL.RTS_ASSERT = 0; - BCM2837_AUXILIARY.AUX_MU_CNTL.CTS_ASSERT = 0; - - /* Setup baudrate */ - //FIXME : find module freq, for now assum that is 250MHz - BCM2837_AUXILIARY.AUX_MU_LCR.DLAB = 1; - BCM2837_AUXILIARY.AUX_MU_BAUD.BAUD = 270; - BCM2837_AUXILIARY.AUX_MU_LCR.DLAB = 0; - - /* map UART1 to GPOI pins - * - * @note - * <> map GPIO15 to alternate function 5 (RXD1 UART1 Transmit Data) - * <> map GPIO14 to alternate function 5 (TXD1 UART1 Receive Data) - * <> alternante function 5 is the only way to map the UART1 - * */ - BCM2837_GPIO.GPFSEL1.FSEL15 = 0b011; - BCM2837_GPIO.GPFSEL1.FSEL14 = 0b011; - - /* link GPIO15 and GPIO14 pins to the UART1 - * - * Now, we want the GPIO15 and GPIO14 to be completly controlled by the - * UART1 module. So, we shall "disable" the current pins behaviour to - * avoid conflict with the module. - * - * @note - * <> we first need to disable pull-up/down for all GPIO pins - * <> we MUST wait at least 150 cycles (CPPUDCLKn, page 101) - * <> specify that only GPIO14 and GPIO15 must be modified - * <> we MUST wait at least 150 cycles (CPPUDCLKn, page 101) - * <> reset PUD (in our case, we already in reset mode) - * <> reset CLK to "flush" the "new" GPIO configuration - * */ - BCM2837_GPIO.GPPUD.PUD = 0b00; - UTIL_SPINWAIT_CYCLES(150); - BCM2837_GPIO.GPPUDCLK0.PIN14 = 1; - BCM2837_GPIO.GPPUDCLK0.PIN15 = 1; - UTIL_SPINWAIT_CYCLES(150); - BCM2837_GPIO.GPPUDCLK0.lword = 0x00000000; - UTIL_SPINWAIT_CYCLES(150); - - /* enable Tx and disable Rx */ - BCM2837_AUXILIARY.AUX_MU_CNTL.RE = 0; - BCM2837_AUXILIARY.AUX_MU_CNTL.TE = 1; -} - -/* uart_send() : send a 8-bit information (char in our case) */ -static void uart_send(unsigned int c) -{ - /* wait until we can send */ - do{ - __asm__ volatile("nop"); - } while(BCM2837_AUXILIARY.AUX_MU_LSR.TDFE == 0); - - /* write the character to the buffer */ - BCM2837_AUXILIARY.AUX_MU_IO.DATA = c; -} - -// high-level primtives - -/* uart_puts() : send string through the UART line (convert new line) */ -static void uart_puts(char const * s) -{ - while(s[0] != '\0') - { - if(s[0] == '\n') - uart_send('\r'); - uart_send(s[0]); - s = &s[1]; - } -} - -/* uart_putf() : printf-like puts */ -static void uart_putf(char *format, ...) -{ - char buffer[128]; - va_list ap; - - va_start(ap, format); - vsnprintf(buffer, 64, format, ap); - va_end(ap); - - uart_puts(buffer); -} +#include "bootloader/display.h" //--- // Public //--- +/* bootloader_main() : "real" bootloader entry */ +extern int bootloader_main(uintptr_t image_base_addr, size_t image_size); + /* bootloader_fake_entry() : debug / fake bootloader entry */ -void bootloader_fake_entry(void) +void bootloader_fake_entry(uintptr_t image_base_addr, size_t image_size) { + uart_init(); - uart_puts("vxGOS fake bootloader entry!!\n"); - uart_putf("AUX_IRQ = %p\n", &BCM2837_AUXILIARY.AUX_IRQ); - uart_putf("AUX_ENABLE = %p\n", &BCM2837_AUXILIARY.AUX_ENABLE); - uart_putf("AUX_MU_IO = %p\n", &BCM2837_AUXILIARY.AUX_MU_IO); - uart_putf("AUX_MU_ENB = %p\n", BCM2837_AUXILIARY.AUX_ENABLE.lword); - uart_putf("AUX_MU_IER = %p\n", BCM2837_AUXILIARY.AUX_MU_IER.lword); - while (1) { } + uart_puts("vxGOS fake bootloader entry!!\n\n"); + + uart_puts("[+] bootstrap information:\n"); + uart_putf("- image base address = %p\n", image_base_addr); + uart_putf("- image size = %d\n", image_size); + + uart_puts("[+] initialize boards\n"); + board_init(); + + uart_puts("[+] initilize framebuffer\n"); + framebuffer_init(); + framebuffer_debug(); + + struct font *font; + uart_puts("[+] font information:\n"); + if (dfont_get(&font) != 0) { + uart_puts("- font not found :(\n"); + } else { + uart_putf("- font struct = %p\n", font); + uart_putf("- font data = %p\n", font->data); + } + + bootloader_main(image_base_addr, image_size); + + while (1) { + __asm__ volatile ("nop"); + } } diff --git a/vxgos/bootloader/boards/raspi3b/src/framebuffer.c b/vxgos/bootloader/boards/raspi3b/src/framebuffer.c new file mode 100644 index 0000000..0e96717 --- /dev/null +++ b/vxgos/bootloader/boards/raspi3b/src/framebuffer.c @@ -0,0 +1,193 @@ +#include "raspi3b/framebuffer.h" +#include "raspi3b/mailbox.h" +#include "raspi3b/uart.h" + +//--- +// Internals +//--- + +/* frambuffer - internal framebuffer information */ +static struct framebuffer framebuffer = { + .watermark = 0x00000000, + .vram = { + .gpu = (uintptr_t)NULL, + .cpu = (uintptr_t)NULL, + .size = 0, + .pitch = 0, + .align = 0, + }, + .phys = { + .width = 0, + .height = 0, + }, + .virt = { + .width = 0, + .height = 0, + }, +}; + +/* framebuffer_setup_request() : perpare mailbox request */ +static void framebuffer_setup_prepare(volatile uint32_t *mbox) +{ + /* prepare mailbox request + * @note + * <> 1024x768 + * <> 32bits per pixel (TODO: palette ?) + * <> start offset at x=0 and y=0 + * */ + mbox[0] = 35*4; + mbox[1] = MBOX_REQUEST_CODE; + + /* set the physical screen size + * @note + * <> 1024x768 + * <> mbox[5] = FrameBufferInfo.width + * <> mbox[6] = FrameBufferInfo.height + * */ + mbox[2] = MBOX_TAG_SCREEN_SET_PHYS_SIZE; + mbox[3] = 8; + mbox[4] = 8; + mbox[5] = 1024; + mbox[6] = 768; + + /* set the virtual screen size + * @note + * <> 1024x768 + * <> mbox[10] = FrameBufferInfo.virtual_width + * <> mbox[11] = FrameBufferInfo.virtual_height + * */ + mbox[7] = MBOX_TAG_SCREEN_SET_VIRT_SIZE; + mbox[8] = 8; + mbox[9] = 8; + mbox[10] = 1024; + mbox[11] = 768; + + /* set the virtual X/Y offset + * @note + * <> x=0 and y=0 + * <> mbox[14] = FrameBufferInfo.x_offset + * <> mbox[15] = FrameBufferInfo.y_offset + * */ + mbox[12] = MBOX_TAG_SCREEN_SET_VIRTUAL_OFFSET; + mbox[13] = 8; + mbox[14] = 8; + mbox[15] = 0; + mbox[16] = 0; + + /* set the pixel depth (bits per pixels) + * @note + * <> for now, use classic RGB(A?) 32bits encoding + * <> mbox[20] = FrameBufferInfo.depth + * */ + mbox[17] = MBOX_TAG_SCREEN_SET_PHYS_DEPTH; + mbox[18] = 4; + mbox[19] = 4; + mbox[20] = 32; + + /* set pixel order (BGR or RGB) + * <> use RGB + * <> mbox[24] = FrameBufferInfo. + * */ + mbox[21] = MBOX_TAG_SCREEN_SET_PIXEL_ORDER; + mbox[22] = 4; + mbox[23] = 4; + mbox[24] = 1; + + /* request a framebuffer + * @note + * <> mbox[28] = request buffer alignement to 4k + * <> mbox[28] = FrameBufferInfo.addr + * <> mbox[29] = FramebufferInfo.size + * */ + mbox[25] = MBOX_TAG_SCREEN_BUFF_ALLOC; + mbox[26] = 8; + mbox[27] = 8; + mbox[28] = 4096; + mbox[29] = 0; + + /* get pixel pitch (number of pixel per line) + * @note + * <> mbox[33] = FrameBufferInfo.pitch + * */ + mbox[30] = MBOX_TAG_SCREEN_GET_PITCH; + mbox[31] = 4; + mbox[32] = 4; + mbox[33] = 0; + + /* indicate the end of the request */ + mbox[34] = MBOX_TAG_END; +} + +/* framebuffer_setup_request() : perform mailbox request and fetch info */ +static int framebuffer_setup_request(volatile uint32_t *mbox) +{ + if (framebuffer.watermark == FRAMEBUFFER_WATERMARK) + return -1; + + framebuffer_setup_prepare(mbox); + if (mailbox_send(MBOX_CHANNEL_PROP) == 0) + return -2; + + framebuffer.vram.gpu = mbox[28]; + framebuffer.vram.cpu = mbox[28] & 0x3fffffff; + framebuffer.vram.size = mbox[29]; + framebuffer.vram.pitch = mbox[33]; + framebuffer.vram.align = 4096; + framebuffer.phys.width = mbox[5]; + framebuffer.phys.height = mbox[6]; + framebuffer.virt.width = mbox[10]; + framebuffer.virt.height = mbox[11]; + + if (framebuffer.vram.gpu == (uintptr_t)NULL) + return -3; + + framebuffer.watermark = FRAMEBUFFER_WATERMARK; + return 0; +} + +//--- +// Public +//--- + +/* framebuffer_init() : initialize framebuffer */ +int framebuffer_init(void) +{ + volatile uint32_t *mbox; + + if (mailbox_get(&mbox) != 0) + return -1; + if (framebuffer_setup_request(mbox) != 0) + return -2; + uart_puts("- OK\n"); + return 0; +} + +/* framebuffer_get() : fetch the framebuffer information if available */ +int framebuffer_get(struct framebuffer **framebuffer_out) +{ + if (framebuffer_out == NULL) + return -1; + if (framebuffer.watermark != FRAMEBUFFER_WATERMARK) + return -2; + *framebuffer_out = &framebuffer; + return 0; +} + +/* framebuffer_debug() : display framebuffer information */ +void framebuffer_debug(void) +{ + uart_puts("[+] debug framebuffer information:\n"); + if (framebuffer.watermark != FRAMEBUFFER_WATERMARK) { + uart_puts("- not initialized\n"); + return; + } + uart_putf("- VRAM GPU address : %p\n", framebuffer.vram.gpu); + uart_putf("- VRAM CPU address : %p\n", framebuffer.vram.cpu); + uart_putf("- VRAM size : %d\n", framebuffer.vram.size); + uart_putf("- VRAM pitch : %d\n", framebuffer.vram.pitch); + uart_putf("- VRAM align : %d\n", framebuffer.vram.align); + uart_putf("- SCREEN phys. width : %d\n", framebuffer.phys.width); + uart_putf("- SCREEN phys. height : %d\n", framebuffer.phys.height); + uart_putf("- SCREEN virt. width : %d\n", framebuffer.virt.width); + uart_putf("- SCREEN virt. height : %d\n", framebuffer.virt.height); +} diff --git a/vxgos/bootloader/boards/raspi3b/src/mailbox.c b/vxgos/bootloader/boards/raspi3b/src/mailbox.c new file mode 100644 index 0000000..88b42aa --- /dev/null +++ b/vxgos/bootloader/boards/raspi3b/src/mailbox.c @@ -0,0 +1,51 @@ +#include "raspi3b/mailbox.h" + +//--- +// Internals +//--- + +/* mbox : mailbox request information (MUST be 16-aligned) */ +__attribute__((aligned(16))) +volatile uint32_t mailbox_buffer[36]; + +//--- +// Public +//--- + +/* mailbox_get() : return the mailbox request buffer */ +int mailbox_get(volatile uint32_t **mbox) +{ + if (mbox == NULL) + return -1; + *mbox = mailbox_buffer; + return 0; +} + +/* mailbox_send() : mailbox wrapper */ +int mailbox_send(int channel) +{ + uintptr_t watermark_request; + + /* wait until we can write to the mailbox */ + do{ + __asm__ volatile("nop"); + } while(BCM2837_MAILBOX.MBOX_STATUS.FULL); + + /* Indicate a new request */ + watermark_request = (uintptr_t)mailbox_buffer | (channel & 0x0f); + BCM2837_MAILBOX.MBOX_WRITE.lword = watermark_request; + + /* now wait for the response */ + while(1) + { + /* is there a response? */ + do{ + __asm__ volatile("nop"); + } while(BCM2837_MAILBOX.MBOX_STATUS.EMPTY); + + /* check if the GPU responded to us */ + if (BCM2837_MAILBOX.MBOX_READ.lword == watermark_request) + return mailbox_buffer[1] == 0x80000000; + } + return 0; +} diff --git a/vxgos/bootloader/boards/raspi3b/src/memory.c b/vxgos/bootloader/boards/raspi3b/src/memory.c new file mode 100644 index 0000000..b046dd9 --- /dev/null +++ b/vxgos/bootloader/boards/raspi3b/src/memory.c @@ -0,0 +1,96 @@ +#include "raspi3b/memory.h" +#include "raspi3b/mailbox.h" +#include "raspi3b/uart.h" + +//--- +// Internals +//--- + +/* memory_alloc_reserve() : reserve a memory area */ +static int memory_alloc_reserve( + uint32_t *handle, + volatile uint32_t *mbox, + size_t size, + int align, + int flags +) { + /* request memory area + * @note + * <> mbox[5] = handle + * */ + mbox[0] = 9 * 4; + mbox[1] = MBOX_REQUEST_CODE; + mbox[2] = MBOX_TAG_MEMORY_ALLOC; + mbox[3] = 12; + mbox[4] = 12; + mbox[5] = size; + mbox[6] = align; + mbox[7] = flags; + mbox[8] = MBOX_TAG_END; + + if (mailbox_send(MBOX_CHANNEL_PROP) == 0) + return -1; + + *handle = mbox[5]; + return 0; +} + +/* memory_alloc_lock() : lock the reserved area and fetch its address */ +static int memory_alloc_lock( + uintptr_t *ptr, + volatile uint32_t *mbox, + uint32_t handle +) { + /* request memory area + * @note + * <> mbox[5] = handle + * */ + mbox[0] = 7 * 4; + mbox[1] = MBOX_REQUEST_CODE; + mbox[2] = MBOX_TAG_MEMORY_LOCK; + mbox[3] = 4; + mbox[4] = 4; + mbox[5] = handle; + mbox[6] = MBOX_TAG_END; + + if (mailbox_send(MBOX_CHANNEL_PROP) == 0) + return -1; + + *ptr = mbox[5]; + return 0; +} + +//--- +// Public API +//--- + +/* memory_alloc() : malloc using GPU firmware request */ +void *memory_alloc(size_t size, int align, int flags) +{ + volatile uint32_t *mbox; + uint32_t handle; + uintptr_t ptr; + + if (mailbox_get(&mbox) != 0) { + uart_puts("[GPU]: memory_alloc: unable to fetch mbox\n"); + return NULL; + } + + if (memory_alloc_reserve(&handle, mbox, size, align, flags) != 0) { + uart_puts("[GPU]: memory_alloc: unable to fetch mbox\n"); + return NULL; + } + if (memory_alloc_lock(&ptr, mbox, handle) != 0) { + uart_puts("[GPU]: memory_alloc: unable to fetch mbox\n"); + return NULL; + } + + return (void *)ptr; +} + +/* memory_free() : free using GPU firmware request */ +void memory_free(void *ptr) +{ + uart_puts("[GPU] : FIXME : memory_free not implemented yet!\n"); + (void)ptr; +} diff --git a/vxgos/bootloader/boards/raspi3b/src/start.S b/vxgos/bootloader/boards/raspi3b/src/start.S index dee1142..afa54cc 100644 --- a/vxgos/bootloader/boards/raspi3b/src/start.S +++ b/vxgos/bootloader/boards/raspi3b/src/start.S @@ -107,21 +107,24 @@ patch_aslr_symbols: // since its content is based on the linker script provided address // 0x00000000000000000 adr x4, ___bootloader_code_end - add x4, x4, ram_base_addr _aslr_symbol_patch_loop: ldr x5, [x4], #8 cbz x5, stack_setup + add x5, x5, ram_base_addr ldr x6, [x5] add x6, x6, ram_base_addr str x6, [x5] - b patch_aslr_symbols + b _aslr_symbol_patch_loop // --- // RAM translation // --- + // TODO : relocation trampoline mecanism + // TODO : self-RAM translation // FIXME : invalidate cache - // TODO : jump to the relocalized RAM + // TODO : erease trampoline mecanism + // TODO : jump to the relocalized RAM // --- // Setup stack @@ -129,8 +132,6 @@ _aslr_symbol_patch_loop: stack_setup: adr x4, __bootloader_stack - sub x4, x4, rom_base_addr - add x4, x4, ram_base_addr mov sp, x4 // --- @@ -138,6 +139,9 @@ stack_setup: // --- high_level_bootloader_entry: + mov x2, ram_base_addr + mov x1, image_size + mov x0, x2 b bootloader_fake_entry // TODO diff --git a/vxgos/bootloader/boards/raspi3b/src/uart.c b/vxgos/bootloader/boards/raspi3b/src/uart.c new file mode 100644 index 0000000..a1dbd5b --- /dev/null +++ b/vxgos/bootloader/boards/raspi3b/src/uart.c @@ -0,0 +1,140 @@ +#include +#include + +#include "raspi3b/uart.h" +#include "raspi3b/auxiliary.h" +#include "raspi3b/gpio.h" +#include "raspi3b/mailbox.h" + +//--- +// Internals +//--- + +/* bcm2837_uart1_init() : initialize the MiniUART1 module */ +static void bcm2837_uart1_init(void) +{ + /* initialize UART + * + * @note + * <> disalbe UART interruption + * <> enable UART module + * <> clear Tx and Rx FIFOs + * <> setup to 115200 baud + * baudrate = system_clk_freq / (8 * (baud_reg + 1)) + * baud_reg = ((system_clk_freq / baudrate) / 8) - 1 */ + BCM2837_AUXILIARY.AUX_ENABLE.MiniUART = 1; + + /* disable as soon as possible Tx and Rx */ + BCM2837_AUXILIARY.AUX_MU_CNTL.RE = 0; + BCM2837_AUXILIARY.AUX_MU_CNTL.TE = 0; + + /* disable Tx or Rx interrupts */ + BCM2837_AUXILIARY.AUX_MU_IER.TIE = 0; + BCM2837_AUXILIARY.AUX_MU_IER.RIE = 0; + + /* clear FIFOs (FIFOs are always enabled) */ + //FIXME : be sure to not force enable FIFO channels + BCM2837_AUXILIARY.AUX_MU_IIR.TXFLUSH = 1; + BCM2837_AUXILIARY.AUX_MU_IIR.RXFLUSH = 1; + + /* Configure data format */ + BCM2837_AUXILIARY.AUX_MU_LCR.DLAB = 0; + BCM2837_AUXILIARY.AUX_MU_LCR.BREAK = 0; + BCM2837_AUXILIARY.AUX_MU_LCR.CHR = 0b11; + BCM2837_AUXILIARY.AUX_MU_MCR.RTS = 0; + + /* Configure extra features */ + BCM2837_AUXILIARY.AUX_MU_CNTL.ERAF = 0; + BCM2837_AUXILIARY.AUX_MU_CNTL.ETAF = 0; + BCM2837_AUXILIARY.AUX_MU_CNTL.RTS_AUTO = 0b00; + BCM2837_AUXILIARY.AUX_MU_CNTL.RTS_ASSERT = 0; + BCM2837_AUXILIARY.AUX_MU_CNTL.CTS_ASSERT = 0; + + /* Setup baudrate */ + //FIXME : find module freq, for now assum that is 250MHz + BCM2837_AUXILIARY.AUX_MU_LCR.DLAB = 1; + BCM2837_AUXILIARY.AUX_MU_BAUD.BAUD = 270; + BCM2837_AUXILIARY.AUX_MU_LCR.DLAB = 0; + + /* map UART1 to GPOI pins + * + * @note + * <> map GPIO15 to alternate function 5 (RXD1 UART1 Transmit Data) + * <> map GPIO14 to alternate function 5 (TXD1 UART1 Receive Data) + * <> alternante function 5 is the only way to map the UART1 + * */ + BCM2837_GPIO.GPFSEL1.FSEL15 = 0b011; + BCM2837_GPIO.GPFSEL1.FSEL14 = 0b011; + + /* link GPIO15 and GPIO14 pins to the UART1 + * + * Now, we want the GPIO15 and GPIO14 to be completly controlled by the + * UART1 module. So, we shall "disable" the current pins behaviour to + * avoid conflict with the module. + * + * @note + * <> we first need to disable pull-up/down for all GPIO pins + * <> we MUST wait at least 150 cycles (CPPUDCLKn, page 101) + * <> specify that only GPIO14 and GPIO15 must be modified + * <> we MUST wait at least 150 cycles (CPPUDCLKn, page 101) + * <> reset PUD (in our case, we already in reset mode) + * <> reset CLK to "flush" the "new" GPIO configuration + * */ + BCM2837_GPIO.GPPUD.PUD = 0b00; + UTIL_SPINWAIT_CYCLES(150); + BCM2837_GPIO.GPPUDCLK0.PIN14 = 1; + BCM2837_GPIO.GPPUDCLK0.PIN15 = 1; + UTIL_SPINWAIT_CYCLES(150); + BCM2837_GPIO.GPPUDCLK0.lword = 0x00000000; + UTIL_SPINWAIT_CYCLES(150); + + /* enable Tx and disable Rx */ + BCM2837_AUXILIARY.AUX_MU_CNTL.RE = 0; + BCM2837_AUXILIARY.AUX_MU_CNTL.TE = 1; +} + +/* bcm2837_uart1_send() : send a 8-bit information (char in our case) */ +static void bcm2837_uart1_send(unsigned int c) +{ + /* wait until we can send */ + do{ + __asm__ volatile("nop"); + } while(BCM2837_AUXILIARY.AUX_MU_LSR.TDFE == 0); + + /* write the character to the buffer */ + BCM2837_AUXILIARY.AUX_MU_IO.DATA = c; +} + +//--- +// Public +//--- + +/* uart_init() : initilize UART driver */ +void uart_init(void) +{ + bcm2837_uart1_init(); +} + +/* uart_puts() : send string through the UART line (convert new line) */ +void uart_puts(char const * const s) +{ + for(int i = 0 ; s[i] != '\0' ; i++) + { + if(s[i] == '\n') + bcm2837_uart1_send('\r'); + bcm2837_uart1_send(s[i]); + } +} + +/* uart_putf() : printf-like puts */ +void uart_putf(char const * const format, ...) +{ + char buffer[128]; + va_list ap; + + va_start(ap, format); + vsnprintf(buffer, 64, format, ap); + va_end(ap); + + uart_puts(buffer); +}