vxGOS - v0.7.0-13 : RaspberryPi3b bootstrap and MiniUART driver

*add*
> [boards]
  | [raspi3b] add auxiliary hardware module bitfields (power, IRQ and UART1)
  | [raspi3b] add gpio hardware module bitfields
  | [raspi3b] add bootloader fake entry (test entry)
  | [raspi3b] add bootloader stack

*fix*
> [boards]
  | [raspi3b] patch missing image size in image header
  | [raspi3b] add missing "dfont()" BIOS build request
> [bootloader]
  | [linker] move bootloader stack
This commit is contained in:
Yann MAGNIN 2023-06-10 13:33:11 +02:00
parent 4ea5758074
commit b316b98004
9 changed files with 582 additions and 13 deletions

View File

@ -8,6 +8,7 @@ let g:ale_cpp_gcc_executable = 'sh-elf-vhex-gcc'
let s:_hdrflags = [
\ '-I./vxgos/bootloader/include',
\ '-I./vxgos/bootloader/boards/fxcg50/include/',
\ '-I./vxgos/bootloader/boards/raspi3b/include/',
\ ]
let s:_cflags = [
\ '-DFXCG50',

View File

@ -106,7 +106,6 @@ def generate_image(prefix_build, bootloader_path, _):
# (todo) os/kernel
image_size = len(image)
print(image_size)
mov0 = 0xd2800000 | (((image_size & 0x000000000000ffff) >> 0) << 5)
mov1 = 0xf2a00000 | (((image_size & 0x00000000ffff0000) >> 16) << 5)
mov2 = 0xf2c00000 | (((image_size & 0x0000ffff00000000) >> 32) << 5)
@ -117,6 +116,8 @@ def generate_image(prefix_build, bootloader_path, _):
image[0x48:0x4c] = mov2.to_bytes(4, 'little')
image[0x4c:0x50] = mov3.to_bytes(4, 'little')
image[0x0c:0x14] = image_size.to_bytes(8, 'little')
bzimage = f"{prefix_build}/vxgos.bzImage"
if os.path.exists(bzimage):
os.remove(bzimage)

View File

@ -0,0 +1,130 @@
#ifndef VXGOS_BOOTLOADER_RASPI3B_AUXILIARY_H
#define VXGOS_BOOTLOADER_RASPI3B_AUXILIARY_H
#include "raspi3b/utils.h"
//---
// BCM2837 Auxiliary peripheral
//
// @note
// <> all of theses bits is based on the documentation on
// https://cs140e.sergio.bz/docs/BCM2837-ARM-Peripherals.pdf
// <> we use MSB instead of LSB packed struct because of the architecture
// note that this cannot be modified with compiler flags.
//---
struct __bcm2837_aux
{
/* [0x00215000] pending interrupt flags */
const u32_union(AUX_IRQ,
uint32_t MiniUART :1; /* Enable Mini UART */
uint32_t SPI1 :1; /* Enable SPI1 */
uint32_t SPI2 :1; /* Enable SPI2 */
uint32_t :29;
);
/* [0x00215004] enable auxialiary modules */
u32_union(AUX_ENABLE,
uint32_t MiniUART :1; /* Enable Mini UART */
uint32_t SPI1 :1; /* Enable SPI1 */
uint32_t SPI2 :1; /* Enable SPI2 */
uint32_t :29;
);
pad(0x38);
//---
// Mini UART register
//---
/* [0x00215040] used to write or write data from the FIFOs. */
u32_union(AUX_MU_IO,
uint32_t DATA : 8;
uint32_t :24;
);
/* [0x00215044] used to enable interrupts */
u32_union(AUX_MU_IER,
uint32_t RIE :1; /* Receive Interrupt Enable */
uint32_t TIE :1; /* Transmit Interrupt Enable */
uint32_t :30;
);
/* [0x00215048] Interrupt Status */
u32_union(AUX_MU_IIR,
uint32_t PENDING :1; /* =0 if pending interrupts */
uint32_t TXFLUSH :1; /* Receiver holds valid byte */
uint32_t RXFLUSH :1; /* Transmit holding register empty */
uint32_t :3;
uint32_t FIFO :2; /* FIFO enabled (TODO: check RX/TX) */
uint32_t :24;
);
/* [0x0021504c] Control Line Data */
u32_union(AUX_MU_LCR,
uint32_t CHR :2; /* Character Length */
uint32_t :4;
uint32_t BREAK :1; /* Pull down the UART1_TX line */
uint32_t DLAB :1; /* Give access to the Baudrate reg */
uint32_t :24;
);
/* [0x00215050] Control the 'modem' signals */
u32_union(AUX_MU_MCR,
uint32_t :1;
uint32_t RTS :1; /* Pull down the UART1_RTS line */
uint32_t :30;
);
/* [0x00215054] Data Status */
const u32_union(AUX_MU_LSR,
uint32_t DRIE :1; /* Received Data Ready */
uint32_t ORER :1; /* Overrrun Error */
uint32_t :3;
uint32_t TDFE :1; /* Transmitter Empty */
uint32_t TDFI :1; /* Transmitter Idle */
uint32_t :25;
);
/* [0x00215058] Data 'modem' status */
const u32_union(AUX_MU_MSR,
uint32_t :4;
uint32_t CTS :1; /* Inverse of the UART1_CTS input */
uint32_t :27;
);
/* [0x0021505c] Single Byte Storage */
u32_union(AUX_MU_SCRATCH,
uint32_t SCRATCH :8; /* SDC byte extra */
uint32_t :24;
);
/* [0x00215060] Access to Extra features */
u32_union(AUX_MU_CNTL,
uint32_t RE :1; /* Receiver Enable */
uint32_t TE :1; /* Transmitter Enable */
uint32_t ERAF :1; /* Enable Rx Auto Flow-control */
uint32_t ETAF :1; /* Enable Tx Auto Flow-control */
uint32_t RTS_AUTO :2; /* Rx Auto Flow Level */
uint32_t RTS_ASSERT :1; /* Rx RTS invert */
uint32_t CTS_ASSERT :1; /* CTS invert */
uint32_t :24;
);
/* [0x00215064] Internal Status */
const u32_union(AUX_MU_STAT,
uint32_t SYMA :1; /* Symbol Available */
uint32_t SPCA :1; /* Tx can accept a least one byte */
uint32_t RII :1; /* Rx is idle */
uint32_t TII :1; /* Tx is idle */
uint32_t ROVRE :1; /* Rx overrun */
uint32_t TDFF :1; /* Tx FIFO is full */
uint32_t RTS :1; /* status of the UART1_RTS line */
uint32_t CTS :1; /* status of the UART1_CTS line */
uint32_t TDFE :1; /* Tx FIFO is empty */
uint32_t TEND :1; /* Tx End */
uint32_t :6;
uint32_t RFFL :4; /* Rx FIFO fill level */
uint32_t :4;
uint32_t TFFL :4; /* Tx FIFO fill level */
uint32_t :4;
);
/* [0x00215068] baudrate counter */
u32_union(AUX_MU_BAUD,
uint32_t BAUD :16; /* Baudrate */
uint32_t :16;
);
} VPACKED(4);
#define BCM2837_AUXILIARY (*((volatile struct __bcm2837_aux *)0x3f215000))
#endif /* VXGOS_BOOTLOADER_RASPI3B_AUXILIARY_H */

View File

@ -0,0 +1,227 @@
#ifndef VXGOS_BOOTLOADER_RASPI3B_GPIO_H
#define VXGOS_BOOTLOADER_RASPI3B_GPIO_H
#include "raspi3b/utils.h"
//---
// Macros helpers
//---
#define u32_pin0(name) \
u32_union(name, \
uint32_t PIN0 :1; \
uint32_t PIN1 :1; \
uint32_t PIN2 :1; \
uint32_t PIN3 :1; \
uint32_t PIN4 :1; \
uint32_t PIN5 :1; \
uint32_t PIN6 :1; \
uint32_t PIN7 :1; \
uint32_t PIN8 :1; \
uint32_t PIN9 :1; \
uint32_t PIN10 :1; \
uint32_t PIN11 :1; \
uint32_t PIN12 :1; \
uint32_t PIN13 :1; \
uint32_t PIN14 :1; \
uint32_t PIN15 :1; \
uint32_t PIN16 :1; \
uint32_t PIN17 :1; \
uint32_t PIN18 :1; \
uint32_t PIN19 :1; \
uint32_t PIN20 :1; \
uint32_t PIN21 :1; \
uint32_t PIN22 :1; \
uint32_t PIN23 :1; \
uint32_t PIN24 :1; \
uint32_t PIN25 :1; \
uint32_t PIN26 :1; \
uint32_t PIN27 :1; \
uint32_t PIN28 :1; \
uint32_t PIN29 :1; \
uint32_t PIN30 :1; \
uint32_t PIN31 :1; \
);
#define u32_pin1(name) \
u32_union(name, \
uint32_t PIN32 :1; \
uint32_t PIN33 :1; \
uint32_t PIN34 :1; \
uint32_t PIN35 :1; \
uint32_t PIN36 :1; \
uint32_t PIN37 :1; \
uint32_t PIN38 :1; \
uint32_t PIN39 :1; \
uint32_t PIN40 :1; \
uint32_t PIN41 :1; \
uint32_t PIN42 :1; \
uint32_t PIN43 :1; \
uint32_t PIN44 :1; \
uint32_t PIN45 :1; \
uint32_t PIN46 :1; \
uint32_t PIN47 :1; \
uint32_t PIN48 :1; \
uint32_t PIN49 :1; \
uint32_t PIN50 :1; \
uint32_t PIN51 :1; \
uint32_t PIN52 :1; \
uint32_t PIN53 :1; \
uint32_t :10;\
);
//---
//
//---
struct __bcm2837_gpio
{
/* [0x00200000-0x00200014] GPIO Function Selection */
u32_union(GPFSEL0,
uint32_t FSEL0 :3;
uint32_t FSEL1 :3;
uint32_t FSEL2 :3;
uint32_t FSEL3 :3;
uint32_t FSEL4 :3;
uint32_t FSEL5 :3;
uint32_t FSEL6 :3;
uint32_t FSEL7 :3;
uint32_t FSEL8 :3;
uint32_t FSEL9 :3;
uint32_t :2;
);
u32_union(GPFSEL1,
uint32_t FSEL10 :3;
uint32_t FSEL11 :3;
uint32_t FSEL12 :3;
uint32_t FSEL13 :3;
uint32_t FSEL14 :3;
uint32_t FSEL15 :3;
uint32_t FSEL16 :3;
uint32_t FSEL17 :3;
uint32_t FSEL18 :3;
uint32_t FSEL19 :3;
uint32_t :2;
);
u32_union(GPFSEL2,
uint32_t FSEL20 :3;
uint32_t FSEL21 :3;
uint32_t FSEL22 :3;
uint32_t FSEL23 :3;
uint32_t FSEL24 :3;
uint32_t FSEL25 :3;
uint32_t FSEL26 :3;
uint32_t FSEL27 :3;
uint32_t FSEL28 :3;
uint32_t FSEL29 :3;
uint32_t :2;
);
u32_union(GPFSEL3,
uint32_t FSEL30 :3;
uint32_t FSEL31 :3;
uint32_t FSEL32 :3;
uint32_t FSEL33 :3;
uint32_t FSEL34 :3;
uint32_t FSEL35 :3;
uint32_t FSEL36 :3;
uint32_t FSEL37 :3;
uint32_t FSEL38 :3;
uint32_t FSEL39 :3;
uint32_t :2;
);
u32_union(GPFSEL4,
uint32_t FSEL40 :3;
uint32_t FSEL41 :3;
uint32_t FSEL42 :3;
uint32_t FSEL43 :3;
uint32_t FSEL44 :3;
uint32_t FSEL45 :3;
uint32_t FSEL46 :3;
uint32_t FSEL47 :3;
uint32_t FSEL48 :3;
uint32_t FSEL49 :3;
uint32_t :2;
);
u32_union(GPFSEL5,
uint32_t FSEL50 :3;
uint32_t FSEL51 :3;
uint32_t FSEL52 :3;
uint32_t FSEL53 :3;
uint32_t FSEL54 :3;
uint32_t FSEL55 :3;
uint32_t FSEL56 :3;
uint32_t FSEL57 :3;
uint32_t FSEL58 :3;
uint32_t FSEL59 :3;
uint32_t :2;
);
pad(0x04);
/* [0x0020001c-0x00200020] Pin Output Set Register */
u32_pin0(GPSET0);
u32_pin1(GPSET1);
pad(0x04);
/* [0x00200028-0x0020030] Pin Output Clear */
u32_pin0(GPCLR0);
u32_pin1(GPCLR1);
pad(0x04);
/* [0x00200034-0x00200038] Pin Level */
const u32_pin0(GPLEV0);
const u32_pin1(GPLEV1);
pad(0x04);
/* [0x00200040-0x00200040] Pin Event Detect Status */
u32_pin0(GPEDS0);
u32_pin1(GPEDS1);
pad(0x04);
/* [0x0020004c-0x00200050] Pin Rising Edge Detect Enable */
u32_pin0(GPREN0);
u32_pin1(GPREN1);
pad(0x04);
/* [0x00200058-0x0020005c] Pin Falling Edge Detect Enable */
u32_pin0(GPFEN0);
u32_pin1(GPFEN1);
pad(0x04);
/* [0x00200064-0x00200068] Pin High Detect Enable */
u32_pin0(GPHEN0);
u32_pin1(GPHEN1);
pad(0x04);
/* [0x00200070-0x00200074] Pin Low Detect Enable */
u32_pin0(GPLEN0);
u32_pin1(GPLEN1);
pad(0x04);
/* [0x0020007c-0x00200080] Pin Async. Rising Edge Detect */
u32_pin0(GPAREN0);
u32_pin1(GPAREN1);
pad(0x04);
/* [0x00200088-0x0020008c] Pin Async. Rising Edge Detect */
u32_pin0(GPAFEN0);
u32_pin1(GPAFEN1);
pad(0x04);
/* [0x00200094] GPIO Pin Pull-up/down Enable */
u32_union(GPPUD,
uint32_t PUD :2; /* GPIO Pin Pull-up/down */
uint32_t :30;
);
/* [0x00200098-0x0020009c] Pin Pull-up/down Enable Clock */
u32_pin0(GPPUDCLK0);
u32_pin1(GPPUDCLK1);
pad(0x14);
/* [0x002000b0] Test (unknown) */
uint32_t _test;
} VPACKED(4);
#define BCM2837_GPIO (*((volatile struct __bcm2837_gpio*)0x3f200000))
#endif /* VXGOS_BOOTLOADER_RASPI3B_GPIO_H */

View File

@ -0,0 +1,37 @@
#ifndef VXGOS_BOOTLOADER_RASPI3B_UTILS_H
#define VXGOS_BOOTLOADER_RASPI3B_UTILS_H
#include <stdint.h>
#include <stddef.h>
//---
// macros helpers
//---
/* Giving a type to padding bytes is misguiding, let's hide it in a macro */
#define pad_nam2(c) _ ## c
#define pad_name(c) pad_nam2(c)
#define pad(bytes) uint8_t pad_name(__COUNTER__)[bytes]
/* Packed structures.
* I require explicit alignment because if it's unspecified, GCC cannot
* optimize access size, and reads to memory-mapped I/O with invalid access
* sizes silently fail - honestly you don't want this to happen */
#define VPACKED(x) __attribute__((packed, aligned(x)))
/* uint32_t union helper */
#define u32_union(name, fields) \
union { \
uint32_t lword; \
struct { fields } VPACKED(4); \
} VPACKED(4) name
/* UTIL_SPINWAIT_CYCLES() : wait at least X cycles */
//TODO : handle superscalar behaviour
//TODO : handle over/under clock
#define UTIL_SPINWAIT_CYCLES(x) \
for(int r = x ; r > 0 ; r--) { \
__asm__ volatile ("nop"); \
}
#endif /* VXGOS_BOOTLOADER_RASPI3B_UTILS_H */

View File

@ -0,0 +1,14 @@
#include "bootloader/display.h"
#include "bootloader/bios.h"
//---
// Public
//---
/* _bios_dfont_get() : get font information */
int _bios_dfont_get(struct font **font)
{
if (*font != NULL)
font = NULL;
return -1;
}

View File

@ -0,0 +1,151 @@
#include <stdarg.h>
#include <stdio.h>
#include "raspi3b/auxiliary.h"
#include "raspi3b/gpio.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);
}
//---
// Public
//---
/* bootloader_fake_entry() : debug / fake bootloader entry */
void bootloader_fake_entry(void)
{
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) { }
}

View File

@ -61,6 +61,7 @@ _primary_continue:
// - check if we are already in RAM
// - detect RAM geometry (size, start and end)
// - ramdom translation offset
// - request mailboxs hardware information
// ---
adr x3, patch_aslr_symbols
@ -68,7 +69,7 @@ _primary_continue:
mov rom_base_addr, x3
mov ram_base_addr, 0x00000000
// for now, assume that we will always be loaded in RAM
// FIXME : for now, assume that we will always be loaded in RAM
mov ram_base_addr, rom_base_addr
#if 0
@ -98,37 +99,46 @@ _ram_translation_validate:
// ---
patch_aslr_symbols:
// The table symbol is not aready resolved (its our job), we must manually
// calculate the real address of the symbols table
adr x4, __bootloader_code_end
add x4, ram_base_address
// @note
// <> the symbol is defined by the linker script
// <> this symbols don't need to perform ROM_BASE address subtraction
// 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, _bootloader_panik
cbz x5, stack_setup
ldr x6, [x5]
add x6, ram_base_address
add x6, x6, ram_base_addr
str x6, [x5]
b patch_aslr_symbols
// TODO
// ---
// RAM translation
// ---
// TODO : invalidate cache
// FIXME : invalidate cache
// TODO : jump to the relocalized RAM
// ---
// Setup stack
// ---
// TODO
stack_setup:
adr x4, __bootloader_stack
sub x4, x4, rom_base_addr
add x4, x4, ram_base_addr
mov sp, x4
// ---
// High-level bootloader invokation
// ---
high_level_bootloader_entry:
b bootloader_fake_entry
// TODO
// ---

View File

@ -40,10 +40,8 @@ SECTIONS
. = ALIGN(16) ;
__bootloader_stack = . ;
. = . + (16 * 1024) ;
. = ALIGN(16);
__bootloader_stack = ALIGN(16) ;
}
/* readable / writable data (must be 16-aligned) */