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:
Yann MAGNIN 2023-06-17 14:14:17 +02:00
parent b316b98004
commit 49508b417c
31 changed files with 1128 additions and 253 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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',
]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,5 +6,8 @@
/* console_key_get() : small one-shot key waiter */
int console_key_get(void)
{
while(1) {
_asm__ volatile ("nop");
}
return -1;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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