vxGOS - v0.7.0-14 : RaspberryPi3b FrameBuffer and ASLR
*add* > [scripts] | [patch_kernel_img] a small tool used to "patch" kernel image to a 512 bytes-aligned image size. This is required for the RaspberryPi Imager > [boards] | [common] add endianness information | [raspi3b] add GOT section patching | [raspi3b] add default font assets | [raspi3b] add GPU board information dumping routine at startup | [raspi3b] add GPU framebuffer (physical HDMI seems not work) support | [raspi3b] add GPU mailbox support | [raspi3b] add GPU memory allocator support *update* > [scripts] | [vxdev] now support endian handling using VXDEV_TOOLCHAIN_ENDIANNESS > [sdk] | [converter] support endian encoding selection (LSB, MSB) > [boards] | [raspi3b] proper link common display interface with framebuffer interface | [raspi3b] proper link fake entry with real entry | [raspr3b] proper send relocation information to the bootloader entry | [raspi3b] proper isolate the MiniUART driver *fix* > [scripts] | [vxdev] force ELF section displayed in "wide" format > [boards] | [fxcg50] swap selected and unselected icon | [raspi3b] proper support relocation TAG | [raspi3b] proper generate 512 bytes-aligned image | [raspi3b] fix bootstrap ALSR patching mechanism
This commit is contained in:
parent
b316b98004
commit
49508b417c
|
@ -0,0 +1,30 @@
|
|||
"""
|
||||
patch kernel image for the Raspberry Pi Imager
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
#---
|
||||
# Public
|
||||
#---
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print("./script <kernel_original> <output>")
|
||||
|
||||
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")
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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 ''
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
]
|
||||
|
|
|
@ -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 */
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef VXGOS_BOOTLOADER_RASPI3B_FRAMEBUFFER_H
|
||||
#define VXGOS_BOOTLOADER_RASPI3B_FRAMEBUFFER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
//---
|
||||
// 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 */
|
|
@ -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 */
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef VXGOS_BOOTLOADER_RASPI3B_MEMORY_H
|
||||
#define VXGOS_BOOTLOADER_RASPI3B_MEMORY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
//---
|
||||
// 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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -6,5 +6,8 @@
|
|||
/* console_key_get() : small one-shot key waiter */
|
||||
int console_key_get(void)
|
||||
{
|
||||
while(1) {
|
||||
_asm__ volatile ("nop");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -1,151 +1,50 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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);
|
||||
}
|
Loading…
Reference in New Issue