commit
8f27b1a576
@ -0,0 +1,4 @@ |
|||||||
|
**/.cross_build |
||||||
|
cross |
||||||
|
*.dtb |
||||||
|
*.dts |
@ -0,0 +1,6 @@ |
|||||||
|
[ ] parse the dtb |
||||||
|
[ ] Fin the name of the board |
||||||
|
[ ] Find out how many cores the cpu has |
||||||
|
[ ] Find where the ram starts and how much memory is available |
||||||
|
[ ] Find the UART address |
||||||
|
[ ] Print the previous information to the serial console |
@ -0,0 +1,283 @@ |
|||||||
|
#!/bin/sh |
||||||
|
|
||||||
|
|
||||||
|
BUILD_GCC=true |
||||||
|
BUILD_BINUTILS=true |
||||||
|
BUILD_GDB=true |
||||||
|
START_SHELL=false |
||||||
|
|
||||||
|
PROJECT_ROOT="$(pwd)" |
||||||
|
CROSS_ROOT="$PROJECT_ROOT/cross" |
||||||
|
PREFIX="$CROSS_ROOT" |
||||||
|
CROSS_BUILD_DIR="$PROJECT_ROOT/.cross_build" |
||||||
|
|
||||||
|
TARGET='' |
||||||
|
CPUS=1 |
||||||
|
|
||||||
|
# Get the target arch |
||||||
|
if [ -z "$ARCH" ]; then |
||||||
|
ARCH="$1" |
||||||
|
shift |
||||||
|
if [ -z "$ARCH" ]; then |
||||||
|
echo "Must define an arch" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
fi |
||||||
|
|
||||||
|
case "$ARCH" in |
||||||
|
'x86_64-elf'|'x86_64'|'x64'|'amd64') |
||||||
|
TARGET='x86_64-elf' |
||||||
|
CONFIG_EXTRA_GCC="$CONFIG_EXTRA_GCC --enable-multilib" |
||||||
|
;; |
||||||
|
'i686-elf'|'i386'|'x32'|'386') |
||||||
|
TARGET='i686-elf' |
||||||
|
CONFIG_EXTRA_GCC="$CONFIG_EXTRA_GCC --enable-multilib" |
||||||
|
;; |
||||||
|
'riscv-64-elf'|'rv64'|'riscv64') |
||||||
|
TARGET='riscv-64-elf' |
||||||
|
;; |
||||||
|
*) |
||||||
|
echo "arch=$ARCH not implemented" |
||||||
|
exit 1 |
||||||
|
;; |
||||||
|
esac |
||||||
|
|
||||||
|
# Get the build target |
||||||
|
while [ "${1:-}" != "" ]; do |
||||||
|
case "$1" in |
||||||
|
"--no-gcc") |
||||||
|
BUILD_GCC=false |
||||||
|
;; |
||||||
|
"--no-binutils") |
||||||
|
BUILD_BINUTILS=false |
||||||
|
;; |
||||||
|
"--no-gdb") |
||||||
|
BUILD_GDB=false |
||||||
|
;; |
||||||
|
"--start-shell") |
||||||
|
START_SHELL=true |
||||||
|
BUILD_GCC=false |
||||||
|
BUILD_BINUTILS=false |
||||||
|
BUILD_GDB=false |
||||||
|
;; |
||||||
|
esac |
||||||
|
shift |
||||||
|
done |
||||||
|
|
||||||
|
# TODO: add some more options to speed up the build / disable unnecessary features |
||||||
|
# https://gitlab.archlinux.org/archlinux/packaging/packages/riscv64-linux-gnu-binutils/-/blob/main/PKGBUILD |
||||||
|
CONFIG_EXTRA_BINUTILS="\ |
||||||
|
--without-zstd \ |
||||||
|
--with-sysroot \ |
||||||
|
--enable-languages=c \ |
||||||
|
--disable-nls \ |
||||||
|
--disable-werror" |
||||||
|
|
||||||
|
# TODO: add some more options to speed up the build / disable unnecessary features |
||||||
|
# https://gitlab.archlinux.org/archlinux/packaging/packages/riscv64-linux-gnu-gcc/-/blob/main/PKGBUILD |
||||||
|
CONFIG_EXTRA_GCC="\ |
||||||
|
--without-zstd \ |
||||||
|
--disable-nls \ |
||||||
|
--enable-languages=c \ |
||||||
|
--without-headers" |
||||||
|
|
||||||
|
CONFIG_EXTRA_GDB="\ |
||||||
|
--with-sysroot \ |
||||||
|
--disable-nls \ |
||||||
|
--disable-werror \ |
||||||
|
--without-headers \ |
||||||
|
--enable-languages=c \ |
||||||
|
--enable-tui=yes \ |
||||||
|
--with-expat" |
||||||
|
|
||||||
|
#CONFIG_HOST="$(gcc -dumpmachine)" |
||||||
|
|
||||||
|
FTP_MIRROR="https://ftpmirror.gnu.org" |
||||||
|
|
||||||
|
gdb_version='13.1' |
||||||
|
gcc_version='12.2.0' |
||||||
|
binutils_version='2.37' |
||||||
|
|
||||||
|
gcc_url="$FTP_MIRROR/gcc/gcc-$gcc_version" |
||||||
|
binutils_url="$FTP_MIRROR/binutils" |
||||||
|
gdb_url="$FTP_MIRROR/gdb" |
||||||
|
|
||||||
|
gdb_build_log=gdb-log-"$(date +%F_%H-%M)".log |
||||||
|
gcc_build_log=gcc-log-"$(date +%F_%H-%M)".log |
||||||
|
binutils_build_log=binutils-log-"$(date +%F_%H-%M)".log |
||||||
|
|
||||||
|
# check if the user wants a particular version |
||||||
|
if [ -n "$GDB_VERSION" ]; then |
||||||
|
gdb_version="$GDB_VERSION" |
||||||
|
fi |
||||||
|
|
||||||
|
# sanity check |
||||||
|
if [ -z "$TARGET" ]; then |
||||||
|
echo "Target not specified, how'd you get this far?" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
# get the right number of cpus |
||||||
|
# and some extra fixes |
||||||
|
case $(uname) in |
||||||
|
'OpenBSD') |
||||||
|
CPUS="$(sysctl -n hw.ncpu)" |
||||||
|
CPUS=$((CPUS + 1)) |
||||||
|
CONFIG_EXTRA_GCC="$CONFIG_EXTRA_GCC --with-gmp=/usr/local" |
||||||
|
# use GNU make |
||||||
|
alias make=gmake |
||||||
|
;; |
||||||
|
'Linux') |
||||||
|
CPUS="$(nproc)" |
||||||
|
CPUS=$((CPUS + 1)) |
||||||
|
;; |
||||||
|
*) |
||||||
|
;; |
||||||
|
esac |
||||||
|
|
||||||
|
|
||||||
|
gpg_verify() { |
||||||
|
keyring="$1" |
||||||
|
pkg="$2" |
||||||
|
sig="$3" |
||||||
|
gpg --verify --keyring "$keyring" "$sig" "$pkg" |
||||||
|
return $? |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
download_sources() { |
||||||
|
pkg="$1" |
||||||
|
sig="$2" |
||||||
|
url="$3" |
||||||
|
wget -nv -O "$pkg" "$url/$pkg" || return $? |
||||||
|
wget -nv -O "$sig" "$url/$sig" || return $? |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
download_and_build() { |
||||||
|
|
||||||
|
pkg_name="$1" |
||||||
|
pkg_version="$2" |
||||||
|
pkg_config="$3" |
||||||
|
pkg_url="$4" |
||||||
|
pkg_ark="$pkg_name-$pkg_version.tar.xz" |
||||||
|
pkg_sig="$pkg_name-$pkg_version.tar.xz.sig" |
||||||
|
|
||||||
|
# Get the archives and signature if they are not already present |
||||||
|
if ! [ -e "$pkg_ark" ] || ! [ -e "$pkg_sig" ]; then |
||||||
|
download_sources "$pkg_ark" "$pkg_sig" "$pkg_url" || return 1 |
||||||
|
fi |
||||||
|
|
||||||
|
# Verify the archive |
||||||
|
if ! gpg_verify ./gnu-keyring.gpg "$pkg_ark" "$pkg_sig"; then |
||||||
|
echo "Package signature was incorrect, please remove the donwloaded sources and try again" |
||||||
|
return 1 |
||||||
|
fi |
||||||
|
|
||||||
|
# Extract the archive |
||||||
|
xz -k -d "$pkg_ark" |
||||||
|
tar -xf "$pkg_name-$pkg_version.tar" && rm -f "$pkg_name-$pkg_version.tar" |
||||||
|
|
||||||
|
# FIXME: this forces a comlete rebuild |
||||||
|
#if [ -d "build-$pkg_name-$TARGET" ]; then |
||||||
|
# rm -rf "build-$pkg_name-$TARGET" |
||||||
|
#fi |
||||||
|
mkdir -p "build-$pkg_name-$TARGET" |
||||||
|
cd "build-$pkg_name-$TARGET" || exit 1 |
||||||
|
|
||||||
|
oldpath="$PATH" |
||||||
|
export PATH="$PREFIX/bin:$PATH" |
||||||
|
# shellcheck disable=SC2086 |
||||||
|
../"$pkg_name-$pkg_version"/configure \ |
||||||
|
--target="$TARGET" \ |
||||||
|
$pkg_config \ |
||||||
|
--prefix="$PREFIX" || return 1 |
||||||
|
|
||||||
|
case "$pkg_name" in |
||||||
|
'gcc') |
||||||
|
make all-gcc || return 1 |
||||||
|
make all-target-libgcc || return 1 |
||||||
|
make install-gcc || return 1 |
||||||
|
make install-target-libgcc || return 1 |
||||||
|
;; |
||||||
|
'binutils') |
||||||
|
make -j$CPUS || return 1 |
||||||
|
make install || return 1 |
||||||
|
;; |
||||||
|
'gdb') |
||||||
|
make all-gdb || return 1 |
||||||
|
make install-gdb || return 1 |
||||||
|
;; |
||||||
|
esac |
||||||
|
|
||||||
|
export PATH="$oldpath" |
||||||
|
cd .. |
||||||
|
return 0 |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#set -x |
||||||
|
|
||||||
|
mkdir -p "$PREFIX" |
||||||
|
mkdir -p "$CROSS_BUILD_DIR/$TARGET" |
||||||
|
|
||||||
|
cd "$CROSS_BUILD_DIR/$TARGET" || exit 1 |
||||||
|
|
||||||
|
# get the gnu keyring, used to verify the archives |
||||||
|
if [ $BUILD_GCC = true ] || [ $BUILD_BINUTILS = true ] || [ $BUILD_GDB = true ]; then |
||||||
|
if ! [ -e gnu-keyring.gpg ]; then |
||||||
|
wget -O gnu-keyring.gpg https://ftp.gnu.org/gnu/gnu-keyring.gpg |
||||||
|
fi |
||||||
|
fi |
||||||
|
|
||||||
|
if [ $BUILD_BINUTILS = true ]; then |
||||||
|
echo "### BUILDING BINUTILS ###" |
||||||
|
|
||||||
|
download_and_build binutils "$binutils_version" "$CONFIG_EXTRA_BINUTILS" \ |
||||||
|
"$binutils_url" > ../"$binutils_build_log" 2>&1 |
||||||
|
res=$? |
||||||
|
|
||||||
|
if ! [ $res -eq 0 ]; then |
||||||
|
echo "Error building binutils, check $CROSS_BUILD_DIR/$binutils_build_log for more details" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
fi |
||||||
|
|
||||||
|
|
||||||
|
if [ $BUILD_GCC = true ]; then |
||||||
|
echo "### BUILDING GCC ###" |
||||||
|
|
||||||
|
download_and_build gcc "$gcc_version" "$CONFIG_EXTRA_GCC" \ |
||||||
|
"$gcc_url" > ../"$gcc_build_log" 2>&1 |
||||||
|
res=$? |
||||||
|
|
||||||
|
if ! [ $res -eq 0 ]; then |
||||||
|
echo "Error building gcc, check $CROSS_BUILD_DIR/$gcc_build_log for more details" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
fi |
||||||
|
|
||||||
|
|
||||||
|
if [ $BUILD_GDB = true ]; then |
||||||
|
echo "### BUILDING GDB ###" |
||||||
|
|
||||||
|
download_and_build gdb "$gdb_version" "$CONFIG_EXTRA_GDB" \ |
||||||
|
"$gdb_url" > ../"$gdb_build_log" 2>&1 |
||||||
|
res=$? |
||||||
|
|
||||||
|
if ! [ $res -eq 0 ]; then |
||||||
|
echo "Error building gdb, check $CROSS_BUILD_DIR/$gdb_build_log for more details" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
fi |
||||||
|
|
||||||
|
cd "$PROJECT_ROOT" || exit 1 |
||||||
|
|
||||||
|
if [ $START_SHELL = true ]; then |
||||||
|
PATH="$CROSS_ROOT/bin:$PATH" |
||||||
|
export PATH TARGET ARCH |
||||||
|
echo "### Starting $SHELL with correct PATH and TARGET ###" |
||||||
|
exec "$SHELL" || exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
# TODO: validate that all things are where they should |
@ -0,0 +1,4 @@ |
|||||||
|
**/*.o |
||||||
|
*.img |
||||||
|
*.elf |
||||||
|
compile_commands.json |
@ -0,0 +1,39 @@ |
|||||||
|
CC = $(TARGET)-gcc
|
||||||
|
LD = $(TARGET)-ld
|
||||||
|
AS = $(TARGET)-gcc
|
||||||
|
|
||||||
|
KERN_WARNINGS = -Wall -Wextra -Wpedantic -Wuninitialized -Wunused-result
|
||||||
|
KERN_FLAGS = -ffreestanding -nostartfiles -nostdlib -nodefaultlibs --std=gnu2x
|
||||||
|
MACHINE_FLAGS = -march=rv64gc -mabi=lp64 -mcmodel=medany
|
||||||
|
PATH_FLAGS = -I./
|
||||||
|
|
||||||
|
CFLAGS = ${MACHINE_FLAGS} -g -O0 ${KERN_WARNINGS} ${KERN_FLAGS} ${PATH_FLAGS}
|
||||||
|
LDFLAGS = -m elf64lriscv --gc-sections -T rv64-sifive_u.ld
|
||||||
|
ASFLAGS = ${CFLAGS}
|
||||||
|
|
||||||
|
.SUFFIXES: .c .o .S |
||||||
|
|
||||||
|
.c.o: |
||||||
|
${CC} ${CFLAGS} -o $@ -c $<
|
||||||
|
|
||||||
|
.S.o: |
||||||
|
${AS} ${ASFLAGS} -o $@ -c $<
|
||||||
|
|
||||||
|
kernel.elf: kernel.o crt0.o platform/FU740/uart.o platform/FU740/clock.o |
||||||
|
${LD} ${LDFLAGS} -o kernel.elf kernel.o crt0.o platform/FU740/uart.o platform/FU740/clock.o
|
||||||
|
|
||||||
|
kernel.o: kernel.c |
||||||
|
|
||||||
|
platform/FU740/uart.o: platform/FU740/uart.c |
||||||
|
|
||||||
|
platform/FU740/clock.o: platform/FU740/clock.c |
||||||
|
|
||||||
|
crt0.o: crt0.S |
||||||
|
|
||||||
|
.PHONY: all test clean |
||||||
|
all: kernel.img |
||||||
|
|
||||||
|
test: |
||||||
|
|
||||||
|
clean: |
||||||
|
rm -f kernel.elf kernel.o crt0.o platform/FU740/uart.o platform/FU740/clock.o
|
@ -0,0 +1,190 @@ |
|||||||
|
#ifndef _PLATFORM_CLOCK_H |
||||||
|
#define _PLATFORM_CLOCK_H |
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <macro.h> |
||||||
|
|
||||||
|
/* Clocking and reset is managed by the PRCI (Power Reset Clocking Interrupt)
|
||||||
|
* block (Figure 24) [77] |
||||||
|
* |
||||||
|
* FU740-C000 generates all internal clocks from 26 MHz hfclk driven from an |
||||||
|
* external oscillator (HFCLKIN) or crystal (HFOSCIN) input, selected by input |
||||||
|
* HFXSEL. All harts operate in a single clock domain (coreclk) supplied by |
||||||
|
* either corepll or dvfscorepll, which can be selected using the corepllsel |
||||||
|
* register. These PLLs step 26 MHz hfclk up to higher frequencies. |
||||||
|
* The recommended frequency of coreclk is 1.0GHz, however operation at up to |
||||||
|
* 1.5GHz is possible. |
||||||
|
* tlclk is a divided version of the coreclk and generates the clock for the L2 |
||||||
|
* cache. |
||||||
|
* The hfpclkpll generates the clock for peripherals such as SPI, UART, GPIO, |
||||||
|
* I2C, and PWM. |
||||||
|
* dvfs_core_pll enables the user to change the CPU frequency without dropping |
||||||
|
* down to the lower frequency hfclk. |
||||||
|
* The DDR, Ethernet and PCIe Subsystems operate asynchronously. |
||||||
|
* The PRCI contains two dedicated PLLs used to step 26 MHz hfclk up to the DDR |
||||||
|
* and Ethernet operating frequencies. |
||||||
|
* The PCIe Subsystem contains its own clock generation. |
||||||
|
* The PRCI contains memory-mapped registers that control the clock selection |
||||||
|
* and configuration of the PLLs. |
||||||
|
* On power-on, the default PRCI register settings start the harts running |
||||||
|
* directly from hfclk. |
||||||
|
* All additional clock management, for instance initializing the DDR PLL or |
||||||
|
* stepping the coreclk frequency, is performed through software reads and |
||||||
|
* writes to the memory-mapped PRCI control registers. |
||||||
|
* The CPU real time clock (rtcclk) runs at 1 MHz and is driven from input pin |
||||||
|
* RTCCLKIN. This should be connected to an external oscillator. |
||||||
|
* JTAG debug logic runs off of JTAG TCK as described in Chapter 26. |
||||||
|
* |
||||||
|
* Reset |
||||||
|
* The FU740-C000 has two external reset pins. |
||||||
|
* PORESET_N is an asynchonous active low power-on reset that should be |
||||||
|
* connected to an external power sequencing/supervisory circuit. ERESET_N is |
||||||
|
* an asynchonous active low reset that can be connected to a reset button. |
||||||
|
* There is internal debounce and stretch logic. The PRCI also contains hardware |
||||||
|
* to generate internal synchronous resets for coreclk, tlclk, and hfpclk |
||||||
|
* domains and handle reset to and from the debug module. Resets for the DDR, |
||||||
|
* Eth- ernet and PCIE Subsystems are performed through software reads and |
||||||
|
* writes to memory-mapped PRCI control registers. These registers are outlined |
||||||
|
* in Table 34 below. |
||||||
|
*/ |
||||||
|
|
||||||
|
/* Table 21: PRCI Memory Map
|
||||||
|
* Offset Name Description |
||||||
|
* 0x00 hfxosccfg Crystal Oscillator Configuration and Status |
||||||
|
* 0x04 core_pllcfg PLL Configuration and Status |
||||||
|
* 0x08 core_plloutdiv PLL Final Divide Configuration |
||||||
|
* 0x0C ddr_pllcfg PLL Configuration and Status |
||||||
|
* 0x10 ddr_plloutdiv PLL Final Divide Configuration |
||||||
|
* 0x1C gemgxl_pllcfg PLL Configuration and Status |
||||||
|
* 0x20 gemgxl_plloutdiv PLL Final Divide Configuration |
||||||
|
* 0x24 core_clk_sel_reg Select core clock source. 0: coreclkpll 1: external hfclk |
||||||
|
* 0x28 devices_reset_n Software controlled resets (active low) |
||||||
|
* 0x2C clk_mux_status Current selection of each clock mux |
||||||
|
* 0x38 dvfs_core_pllcfg PLL Configuration and Status |
||||||
|
* 0x3C dvfs_core_plloutdiv PLL Final Divide Configuration |
||||||
|
* 0x40 corepllsel Select which PLL output to use for core clock. 0: corepll 1: dvfscorepll |
||||||
|
* 0x50 hfpclk_pllcfg PLL Configuration and Status |
||||||
|
* 0x54 hfpclk_plloutdiv PLL Final Divide Configuration |
||||||
|
* 0x58 hfpclkpllsel Select source for Periphery Clock (pclk). 0: hfpclkpll 1: external hfclk |
||||||
|
* 0x5C hfpclk_div_reg HFPCLK PLL divider value |
||||||
|
* 0xE0 prci_plls Indicates presence of each PLL |
||||||
|
*/ |
||||||
|
|
||||||
|
#define HFCLK_FREQ_HZ 26000000L |
||||||
|
#define PRCI_MEMORY_BLOCK 0x10000000L |
||||||
|
|
||||||
|
|
||||||
|
struct S_PACKED prci_pllcfg { |
||||||
|
uint32_t pllr:6; // [RW, 0x1] PLL R Value
|
||||||
|
uint32_t pllf:9; // [RW, 0x1F] PLL F Value
|
||||||
|
uint32_t pllq:3; // [RW, 0x3] PLL Q Value
|
||||||
|
uint32_t pllrange:3; // [RW, 0x0] PLL Range Value
|
||||||
|
uint32_t reserved0:3; |
||||||
|
uint32_t pllbypass:1; // [RW, 0x1] PLL Bypass
|
||||||
|
uint32_t pllfsebypass:1; // [RW, 0x1] PLL FSE Bypass
|
||||||
|
uint32_t reserved1:5; |
||||||
|
uint32_t plllock:1; // [RO, X] PLL Lock
|
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
struct S_PACKED prci_plloutdiv { |
||||||
|
uint32_t reserved:31; |
||||||
|
uint32_t pllcke:1; // [RW, 0x0] PLL Clock Enable
|
||||||
|
}; |
||||||
|
|
||||||
|
struct S_PACKED prci_mem_map { |
||||||
|
// Offset 0x0
|
||||||
|
struct prci_hfxosccfg { |
||||||
|
uint32_t reserved:30; |
||||||
|
uint32_t hfxoscen:1; // [RW, 0x1] Crystal Oscillator Enable
|
||||||
|
uint32_t hfxoscrdy:1; // [RO, X] Crystal Oscillator Ready
|
||||||
|
} hfxosccfg; |
||||||
|
|
||||||
|
// Offset 0x4
|
||||||
|
struct prci_pllcfg core_pllcfg; |
||||||
|
|
||||||
|
// Offset 0x8
|
||||||
|
struct { uint32_t reserved; } core_plloutdiv; |
||||||
|
|
||||||
|
// Offset 0xC
|
||||||
|
struct prci_pllcfg ddr_pllcfg; |
||||||
|
|
||||||
|
// Offset 0x10
|
||||||
|
struct prci_plloutdiv ddr_plloutdiv; |
||||||
|
uint8_t off0[8]; |
||||||
|
|
||||||
|
// Offset 0x1C
|
||||||
|
struct prci_pllcfg gemgxl_pllcfg; |
||||||
|
|
||||||
|
// Offset 0x20
|
||||||
|
struct prci_plloutdiv gemgxl_plloutdiv; |
||||||
|
|
||||||
|
// Offset 0x24
|
||||||
|
uint32_t core_clk_sel_reg; |
||||||
|
|
||||||
|
// Offset 0x28
|
||||||
|
struct prci_devices_reset_n { |
||||||
|
uint32_t ddrctrl_reset_n:1; // [RW, 0x0] Active-Low ddrctrl reset
|
||||||
|
uint32_t ddraxi_reset_n:1; // [RW, 0x0] Active-Low ddraxi reset
|
||||||
|
uint32_t ddrahb_reset_n:1; // [RW, 0x0] Active-Low ddrahb reset
|
||||||
|
uint32_t ddrphy_reset_n:1; // [RW, 0x0] Active-Low ddrphy reset
|
||||||
|
uint32_t pcieaux_reset_n:1; // [RW, 0x0] Active-Low pcieaux reset
|
||||||
|
uint32_t gemgxl_reset_n:1; // [RW, 0x0] Active-Low gemgxl reset
|
||||||
|
uint32_t reserved:26; |
||||||
|
|
||||||
|
} devices_reset_n; |
||||||
|
|
||||||
|
// Offset 0x2C
|
||||||
|
struct prci_clk_mux_status { |
||||||
|
uint32_t coreclkpllsel:1; // [RO, X] Current setting of coreclkpllsel mux
|
||||||
|
uint32_t tlclksel:1; // [RO, X] Current setting of tlclksel mux
|
||||||
|
uint32_t rtcxsel:1; // [RO, X] Current setting of rtcxsel mux
|
||||||
|
uint32_t ddrctrlclksel:1; // [RO, X] Current setting of ddrctrlclksel mux
|
||||||
|
uint32_t ddrphyclksel:1; // [RO, X] Current setting of ddrphyclksel mux
|
||||||
|
uint32_t reserved0:1; // [RO, X] Current setting of reserved0 mux
|
||||||
|
uint32_t gemgxlclksel:1; // [RO, X] Current setting of gemgxlclksel mux
|
||||||
|
uint32_t mainmemclksel:1; // [RO, X] Current setting of mainmemclksel mux
|
||||||
|
uint32_t reserved:24; |
||||||
|
} clk_mux_status; |
||||||
|
uint8_t off1[8]; |
||||||
|
|
||||||
|
// Offset 0x38
|
||||||
|
struct prci_pllcfg dvfs_core_pllcfg; |
||||||
|
|
||||||
|
// Offset 0x3C
|
||||||
|
struct prci_plloutdiv dvfs_core_plloutdiv; |
||||||
|
|
||||||
|
// Offset 0x40
|
||||||
|
uint32_t corepllsel; |
||||||
|
uint8_t off2[12]; |
||||||
|
|
||||||
|
// Offset 0x50
|
||||||
|
struct prci_pllcfg hfpclk_pllcfg; |
||||||
|
|
||||||
|
// Offset 0x54
|
||||||
|
struct prci_plloutdiv hfpclk_plloutdiv; |
||||||
|
|
||||||
|
// Offset 0x58
|
||||||
|
uint32_t hfpclkpllsel; |
||||||
|
|
||||||
|
// Offset 0x5C
|
||||||
|
uint32_t hfpclk_div_reg; // [RW, 0x0] HFPCLK PLL divider value
|
||||||
|
uint8_t off3[128]; |
||||||
|
|
||||||
|
// Offset 0xE0
|
||||||
|
struct prci_prci_plls { |
||||||
|
uint32_t cltxpll:1; // [RO, X] Indicates presence of cltxpll
|
||||||
|
uint32_t gemgxlpll:1; // [RO, X] Indicates presence of gemgxlpll
|
||||||
|
uint32_t ddrpll:1; // [RO, X] Indicates presence of ddrpll
|
||||||
|
uint32_t hfpclkpll:1; // [RO, X] Indicates presence of hfpclkpll
|
||||||
|
uint32_t dvfscorepll:1; // [RO, X] Indicates presence of dvfscorepll
|
||||||
|
uint32_t corepll:1; // [RO, X] Indicates presence of corepll
|
||||||
|
uint32_t reserved:26; |
||||||
|
} prci_plls; |
||||||
|
}; |
||||||
|
static_assert((sizeof(struct prci_mem_map) == 0xE4), |
||||||
|
"prci_mem_map is not the right size"); |
||||||
|
|
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,27 @@ |
|||||||
|
# C runtime, modified from |
||||||
|
# https://twilco.github.io/riscv-from-scratch/2019/04/27/riscv-from-scratch-2.html#stop--hammertime-runtime |
||||||
|
|
||||||
|
# in the init section which is "allocatable" and "executable" |
||||||
|
.section .init, "ax" |
||||||
|
|
||||||
|
# entry point for the kernel |
||||||
|
.global _start
|
||||||
|
_start: |
||||||
|
.cfi_startproc |
||||||
|
.cfi_undefined ra
|
||||||
|
# initialize the global pointer register |
||||||
|
.option push
|
||||||
|
.option norelax
|
||||||
|
la gp, __global_pointer$ |
||||||
|
.option pop
|
||||||
|
# initialize the stack pointer and frame pointer registers |
||||||
|
# FIXME: when putting the stack at the end of RAM with system memory >2G |
||||||
|
# it fails to link with the error: relocation truncated to fit: |
||||||
|
# R_RISCV_HI20 against '__stack_top' |
||||||
|
la sp, __stack_top |
||||||
|
add s0, sp, zero |
||||||
|
# jump to main |
||||||
|
jal zero, main |
||||||
|
.cfi_endproc |
||||||
|
|
||||||
|
.end |
Binary file not shown.
@ -0,0 +1,12 @@ |
|||||||
|
#include "macro.h" |
||||||
|
#include "platform/FU740/uart.h" |
||||||
|
|
||||||
|
int F_NAKED main(void) |
||||||
|
{ |
||||||
|
(void)uart_init(UART0, DEFAULT_BAUD, 0); |
||||||
|
|
||||||
|
static char str[] = "Hello RISC-V!\n"; |
||||||
|
uart_tx_buf(UART0, str, sizeof(str)); |
||||||
|
|
||||||
|
while(1) asm volatile("nop"); // we should not be here
|
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
#ifndef _COMMON_MACROS_H |
||||||
|
#define _COMMON_MACROS_H |
||||||
|
|
||||||
|
#define F_NAKED __attribute__((noreturn)) |
||||||
|
#define F_INTERRUPT __attribute__((interrupt)) |
||||||
|
#define S_PACKED __attribute__((packed)) |
||||||
|
|
||||||
|
#define static_assert _Static_assert |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,26 @@ |
|||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
#include "clock.h" |
||||||
|
|
||||||
|
|
||||||
|
static struct prci_mem_map *const prci_mm = (struct prci_mem_map *const)PRCI_MEMORY_BLOCK; |
||||||
|
|
||||||
|
|
||||||
|
// Sets the hfpclkpll register to the appropriate value for the freqency, returns
|
||||||
|
// -1 on error
|
||||||
|
// TODO: for higher frequencies use the internal PLLs
|
||||||
|
int set_hfp_frequency(uint32_t f) |
||||||
|
{ |
||||||
|
// test if the correct register is present
|
||||||
|
if (!prci_mm->prci_plls.hfpclkpll) |
||||||
|
return -1; |
||||||
|
|
||||||
|
// make sure that the clock source is set to external
|
||||||
|
prci_mm->hfpclkpllsel = 1; |
||||||
|
|
||||||
|
// the external clock source is 26MHz, the formula for the baud rate is:
|
||||||
|
// f_baud = f_hfclk / (1 + hfpclk_div_reg)
|
||||||
|
prci_mm->hfpclk_div_reg = (HFCLK_FREQ_HZ/f + 1); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,62 @@ |
|||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
#include "uart.h" |
||||||
|
|
||||||
|
|
||||||
|
static struct uart_memory_map *const uart_mm[] = { |
||||||
|
(struct uart_memory_map *const)UART_0_ADDR, |
||||||
|
(struct uart_memory_map *const)UART_1_ADDR, |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// set the baudrate on the chosen uart, if the baud rate is incorrect or invalid
|
||||||
|
// then set it to the default value, return the set baudrate value
|
||||||
|
int uart_set_baudrate(uart_id id, int baud) |
||||||
|
{ |
||||||
|
// FIXME: actually set the baud rate, for now leave it as the default
|
||||||
|
(void)baud; |
||||||
|
(void)id; |
||||||
|
return 115200; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// initialize the uart registers for transmit and receive
|
||||||
|
// TODO: also initialize interrupts and thesholds
|
||||||
|
int uart_init(uart_id id, uint32_t baud, int stop_bits) |
||||||
|
{ |
||||||
|
// FIXME: check baud rate error and propagate it
|
||||||
|
(void)uart_set_baudrate(id, baud); |
||||||
|
|
||||||
|
// change the number of stop bits only if stop_bits > 0
|
||||||
|
if (stop_bits > 0) |
||||||
|
uart_mm[id]->txctrl.nstop = !!stop_bits; |
||||||
|
|
||||||
|
uart_mm[id]->txctrl.txen = 1; |
||||||
|
uart_mm[id]->rxctrl.rxen = 1; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// transmit a byte of data through a uart line
|
||||||
|
void uart_tx_byte(uart_id id, unsigned char b) |
||||||
|
{ |
||||||
|
uart_mm[id]->txdata.data = b; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// busy-wait until the uart buffer is cleared
|
||||||
|
void uart_tx_full(uart_id id) |
||||||
|
{ |
||||||
|
while (uart_mm[id]->txdata.full); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// send a buffer through uart
|
||||||
|
void uart_tx_buf(uart_id id, unsigned char *buf, unsigned int size) |
||||||
|
{ |
||||||
|
for (unsigned int i = 0; i < size; i++) { |
||||||
|
uart_tx_byte(id, buf[i]); |
||||||
|
uart_tx_full(id); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,170 @@ |
|||||||
|
#ifndef _PLATFORM_UART_H |
||||||
|
#define _PLATFORM_UART_H |
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <macro.h> |
||||||
|
|
||||||
|
|
||||||
|
// <Description> <[Doc Page]>
|
||||||
|
|
||||||
|
// UART Base Addesses [141]
|
||||||
|
#define UART_0_ADDR 0x10010000L |
||||||
|
#define UART_1_ADDR 0x10010000L |
||||||
|
|
||||||
|
// UART Control Register Offsets [142]
|
||||||
|
#define UART_TXDATA_OFF 0x00 // Transmit data register
|
||||||
|
#define UART_RXDATA_OFF 0x04 // Receive data register
|
||||||
|
#define UART_TXCTRL_OFF 0x08 // Transmit control register
|
||||||
|
#define UART_RXCTRL_OFF 0x0C // Receive control register
|
||||||
|
#define UART_IE_OFF 0x10 // UART interrupt enable
|
||||||
|
#define UART_IP_OFF 0x14 // UART interrupt pending
|
||||||
|
#define UART_DIV_OFF 0x18 // Baud rate divisor
|
||||||
|
|
||||||
|
#define UART_NUMBER 2 |
||||||
|
#define DEFAULT_BAUD 115200 |
||||||
|
|
||||||
|
|
||||||
|
// UART ids
|
||||||
|
typedef enum { |
||||||
|
UART0 = 0, |
||||||
|
UART1 = 1, |
||||||
|
} uart_id; |
||||||
|
|
||||||
|
|
||||||
|
/* Transmit Data Register (txdata) [142]
|
||||||
|
* Writing to the txdata register enqueues the character contained in the data |
||||||
|
* field to the transmit FIFO if the FIFO is able to accept new entries. Reading |
||||||
|
* from txdata returns the current value of the full flag and zero in the data |
||||||
|
* field. The full flag indicates whether the transmit FIFO is able to accept |
||||||
|
* new entries; when set, writes to data are ignored. A RISC‐V amoor.w |
||||||
|
* instruction can be used to both read the full status and attempt to enqueue |
||||||
|
* data, with a non-zero return value indicating the character was not accepted. |
||||||
|
*/ |
||||||
|
struct S_PACKED uart_txdata_reg { |
||||||
|
uint32_t data:8; |
||||||
|
uint32_t reserved:23; |
||||||
|
uint32_t full:1; |
||||||
|
}; |
||||||
|
static_assert((sizeof(struct uart_txdata_reg) == sizeof(uint32_t)), |
||||||
|
"uart_txdata_reg is not the right size"); |
||||||
|
|
||||||
|
/* Receive Data Register (rxdata) [143]
|
||||||
|
* Reading the rxdata register dequeues a character from the receive FIFO and |
||||||
|
* returns the value in the data field. The empty flag indicates if the receive |
||||||
|
* FIFO was empty; when set, the data field does not contain a valid character. |
||||||
|
* Writes to rxdata are ignored. |
||||||
|
*/ |
||||||
|
struct S_PACKED uart_rxdata_reg { |
||||||
|
uint32_t data:8; |
||||||
|
uint32_t reserved:23; |
||||||
|
uint32_t empty:1; |
||||||
|
}; |
||||||
|
static_assert((sizeof(struct uart_rxdata_reg) == sizeof(uint32_t)), |
||||||
|
"uart_rxdata_reg is not the right size"); |
||||||
|
|
||||||
|
/* Transmit Control Register (txctrl) [143]
|
||||||
|
* The read-write txctrl register controls the operation of the transmit channel. |
||||||
|
* The txen bit con- trols whether the Tx channel is active. When cleared, |
||||||
|
* transmission of Tx FIFO contents is suppressed, and the txd pin is driven |
||||||
|
* high. The nstop field specifies the number of stop bits: 0 for one stop bit |
||||||
|
* and 1 for two stop bits. The txcnt field specifies the threshold at which the |
||||||
|
* Tx FIFO watermark interrupt triggers. The txctrl register is reset to 0. |
||||||
|
*/ |
||||||
|
struct S_PACKED uart_txctrl_reg { |
||||||
|
uint32_t txen:1; |
||||||
|
uint32_t nstop:1; |
||||||
|
uint32_t reserved0:14; |
||||||
|
uint32_t txcnt:3; |
||||||
|
uint32_t reserved1:13; |
||||||
|
}; |
||||||
|
static_assert((sizeof(struct uart_txctrl_reg) == sizeof(uint32_t)), |
||||||
|
"uart_txctrl_reg is not the right size"); |
||||||
|
|
||||||
|
/* Receive Control Register (rxctrl) [144]
|
||||||
|
* The read-write rxctrl register controls the operation of the receive channel. |
||||||
|
* The rxen bit controls whether the Rx channel is active. When cleared, the |
||||||
|
* state of the rxd pin is ignored, and no characters will be enqueued into the |
||||||
|
* Rx FIFO. The rxcnt field specifies the threshold at which the Rx FIFO |
||||||
|
* watermark interrupt triggers. The rxctrl register is reset to 0. Characters |
||||||
|
* are enqueued when a zero (low) start bit is seen. |
||||||
|
*/ |
||||||
|
struct S_PACKED uart_rxctrl_reg { |
||||||
|
uint32_t rxen:1; |
||||||
|
uint32_t reserved0:15; |
||||||
|
uint32_t rxcnt:3; |
||||||
|
uint32_t reserved1:13; |
||||||
|
}; |
||||||
|
static_assert((sizeof(struct uart_rxctrl_reg) == sizeof(uint32_t)), |
||||||
|
"uart_rxctrl_reg is not the right size"); |
||||||
|
|
||||||
|
/* Interrupt Registers (ip and ie) [144]
|
||||||
|
* The ip register is a read-only register indicating the pending interrupt |
||||||
|
* conditions, and the read- write ie register controls which UART interrupts |
||||||
|
* are enabled. ie is reset to 0. The txwm condition becomes raised when the |
||||||
|
* number of entries in the transmit FIFO is strictly less than the count |
||||||
|
* specified by the txcnt field of the txctrl register. The pending bit is |
||||||
|
* cleared when sufficient entries have been enqueued to exceed the watermark. |
||||||
|
* The rxwm condition becomes raised when the number of entries in the receive |
||||||
|
* FIFO is strictly greater than the count specified by the rxcnt field of the |
||||||
|
* rxctrl register. The pending bit is cleared when sufficient entries have been |
||||||
|
* dequeued to fall below the watermark. |
||||||
|
*/ |
||||||
|
struct S_PACKED uart_ie_reg { |
||||||
|
uint32_t txwm:1; |
||||||
|
uint32_t rxwm:1; |
||||||
|
uint32_t reserved:30; |
||||||
|
}; |
||||||
|
static_assert((sizeof(struct uart_ie_reg) == sizeof(uint32_t)), |
||||||
|
"uart_ie_reg is not the right size"); |
||||||
|
|
||||||
|
struct S_PACKED uart_ip_reg { |
||||||
|
uint32_t txwm:1; |
||||||
|
uint32_t rxwm:1; |
||||||
|
uint32_t reserved:30; |
||||||
|
}; |
||||||
|
static_assert((sizeof(struct uart_ip_reg) == sizeof(uint32_t)), |
||||||
|
"uart_ip_reg is not the right size"); |
||||||
|
|
||||||
|
/* Baud Rate Divisor Register (div) [145]
|
||||||
|
* The read-write, div_width-bit div register specifies the divisor used by baud |
||||||
|
* rate generation for both Tx and Rx channels. The relationship between the |
||||||
|
* input clock and baud rate is given by the following formula: The input clock |
||||||
|
* is the bus clock pclk. The reset value of the register is set to div_init, |
||||||
|
* which is tuned to provide a 115200 baud output out of reset given the |
||||||
|
* expected frequency of pclk. Table 85 shows divisors for some common core |
||||||
|
* clock rates and commonly used baud rates. Note that the table shows the |
||||||
|
* divide ratios, which are one greater than the value stored in the div |
||||||
|
* register. The receive channel is sampled at 16× the baud rate, and a majority |
||||||
|
* vote over 3 neighboring bits is used to determine the received value. For |
||||||
|
* this reason, the divisor must be ≥16 for a receive channel. |
||||||
|
*/ |
||||||
|
struct S_PACKED uart_div_reg { |
||||||
|
uint32_t div:16; |
||||||
|
uint32_t reserved:16; |
||||||
|
}; |
||||||
|
static_assert((sizeof(struct uart_div_reg) == sizeof(uint32_t)), |
||||||
|
"uart_div_reg is not the right size"); |
||||||
|
|
||||||
|
|
||||||
|
struct S_PACKED uart_memory_map { |
||||||
|
struct uart_txdata_reg txdata; |
||||||
|
struct uart_rxdata_reg rxdata; |
||||||
|
struct uart_txctrl_reg txctrl; |
||||||
|
struct uart_rxctrl_reg rxctrl; |
||||||
|
struct uart_ie_reg ie; |
||||||
|
struct uart_ip_reg ip; |
||||||
|
struct uart_div_reg div; |
||||||
|
}; |
||||||
|
static_assert((sizeof(struct uart_memory_map) == sizeof(uint32_t[7])), |
||||||
|
"uart_memory_map is not the right size"); |
||||||
|
|
||||||
|
|
||||||
|
int uart_set_baudrate(uart_id id, int baud); |
||||||
|
int uart_init(uart_id id, uint32_t baud, int stop_bits); |
||||||
|
void uart_tx_byte(uart_id id, unsigned char b); |
||||||
|
void uart_tx_full(uart_id id); |
||||||
|
void uart_tx_buf(uart_id id, unsigned char *buf, unsigned int size); |
||||||
|
|
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,263 @@ |
|||||||
|
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv") |
||||||
|
OUTPUT_ARCH(riscv) |
||||||
|
|
||||||
|
|
||||||
|
SEARCH_DIR("=/home/ale/Documents/Projects/OS/rovo/cross/riscv-64-elf/lib") |
||||||
|
SEARCH_DIR("=/usr/local/lib") |
||||||
|
SEARCH_DIR("=/lib") |
||||||
|
SEARCH_DIR("=/usr/lib") |
||||||
|
|
||||||
|
|
||||||
|
MEMORY |
||||||
|
{ |
||||||
|
/* qemu-system-risc64 sifive_u machine */ |
||||||
|
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 1024M |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
ENTRY(_start) |
||||||
|
|
||||||
|
|
||||||
|
SECTIONS |
||||||
|
{ |
||||||
|
/* Read-only sections, merged into text segment: */ |
||||||
|
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x10000)); |
||||||
|
. = SEGMENT_START("text-segment", 0x10000) + SIZEOF_HEADERS; |
||||||
|
|
||||||
|
/* Provide the stack top positioned at the bottom of RAM */ |
||||||
|
PROVIDE (__stack_top = ORIGIN(RAM) + LENGTH(RAM)); |
||||||
|
|
||||||
|
.interp : { *(.interp) } |
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) } |
||||||
|
.hash : { *(.hash) } |
||||||
|
.gnu.hash : { *(.gnu.hash) } |
||||||
|
.dynsym : { *(.dynsym) } |
||||||
|
.dynstr : { *(.dynstr) } |
||||||
|
.gnu.version : { *(.gnu.version) } |
||||||
|
.gnu.version_d : { *(.gnu.version_d) } |
||||||
|
.gnu.version_r : { *(.gnu.version_r) } |
||||||
|
.rela.dyn : |
||||||
|
{ |
||||||
|
*(.rela.init) |
||||||
|
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) |
||||||
|
*(.rela.fini) |
||||||
|
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) |
||||||
|
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) |
||||||
|
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) |
||||||
|
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) |
||||||
|
*(.rela.ctors) |
||||||
|
*(.rela.dtors) |
||||||
|
*(.rela.got) |
||||||
|
*(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) |
||||||
|
*(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) |
||||||
|
*(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) |
||||||
|
*(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) |
||||||
|
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) |
||||||
|
*(.rela.ifunc) |
||||||
|
} |
||||||
|
.rela.plt : |
||||||
|
{ |
||||||
|
*(.rela.plt) |
||||||
|
PROVIDE_HIDDEN (__rela_iplt_start = .); |
||||||
|
*(.rela.iplt) |
||||||
|
PROVIDE_HIDDEN (__rela_iplt_end = .); |
||||||
|
} |
||||||
|
.init : |
||||||
|
{ |
||||||
|
KEEP (*(SORT_NONE(.init))) |
||||||
|
} |
||||||
|
.plt : { *(.plt) *(.iplt) } |
||||||
|
.text : |
||||||
|
{ |
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*) |
||||||
|
*(.text.exit .text.exit.*) |
||||||
|
*(.text.startup .text.startup.*) |
||||||
|
*(.text.hot .text.hot.*) |
||||||
|
*(SORT(.text.sorted.*)) |
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*) |
||||||
|
/* .gnu.warning sections are handled specially by elf.em. */ |
||||||
|
*(.gnu.warning) |
||||||
|
} |
||||||
|
.fini : |
||||||
|
{ |
||||||
|
KEEP (*(SORT_NONE(.fini))) |
||||||
|
} |
||||||
|
PROVIDE (__etext = .); |
||||||
|
PROVIDE (_etext = .); |
||||||
|
PROVIDE (etext = .); |
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } |
||||||
|
.rodata1 : { *(.rodata1) } |
||||||
|
.sdata2 : |
||||||
|
{ |
||||||
|
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*) |
||||||
|
} |
||||||
|
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } |
||||||
|
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } |
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } |
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } |
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } |
||||||
|
/* These sections are generated by the Sun/Oracle C++ compiler. */ |
||||||
|
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } |
||||||
|
/* Adjust the address for the data segment. We want to adjust up to |
||||||
|
the same address within the page on the next page up. */ |
||||||
|
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); |
||||||
|
/* Exception handling */ |
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } |
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) } |
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } |
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } |
||||||
|
/* Thread Local Storage sections */ |
||||||
|
.tdata : |
||||||
|
{ |
||||||
|
PROVIDE_HIDDEN (__tdata_start = .); |
||||||
|
*(.tdata .tdata.* .gnu.linkonce.td.*) |
||||||
|
} |
||||||
|
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } |
||||||
|
.preinit_array : |
||||||
|
{ |
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .); |
||||||
|
KEEP (*(.preinit_array)) |
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .); |
||||||
|
} |
||||||
|
.init_array : |
||||||
|
{ |
||||||
|
PROVIDE_HIDDEN (__init_array_start = .); |
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) |
||||||
|
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) |
||||||
|
PROVIDE_HIDDEN (__init_array_end = .); |
||||||
|
} |
||||||
|
.fini_array : |
||||||
|
{ |
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .); |
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) |
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) |
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .); |
||||||
|
} |
||||||
|
.ctors : |
||||||
|
{ |
||||||
|
/* gcc uses crtbegin.o to find the start of |
||||||
|
the constructors, so we make sure it is |
||||||
|
first. Because this is a wildcard, it |
||||||
|
doesn't matter if the user does not |
||||||
|
actually link against crtbegin.o; the |
||||||
|
linker won't look for a file to match a |
||||||
|
wildcard. The wildcard also means that it |
||||||
|
doesn't matter which directory crtbegin.o |
||||||
|
is in. */ |
||||||
|
KEEP (*crtbegin.o(.ctors)) |
||||||
|
KEEP (*crtbegin?.o(.ctors)) |
||||||
|
/* We don't want to include the .ctor section from |
||||||
|
the crtend.o file until after the sorted ctors. |
||||||
|
The .ctor section from the crtend file contains the |
||||||
|
end of ctors marker and it must be last */ |
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) |
||||||
|
KEEP (*(SORT(.ctors.*))) |
||||||
|
KEEP (*(.ctors)) |
||||||
|
} |
||||||
|
.dtors : |
||||||
|
{ |
||||||
|
KEEP (*crtbegin.o(.dtors)) |
||||||
|
KEEP (*crtbegin?.o(.dtors)) |
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) |
||||||
|
KEEP (*(SORT(.dtors.*))) |
||||||
|
KEEP (*(.dtors)) |
||||||
|
} |
||||||
|
.jcr : { KEEP (*(.jcr)) } |
||||||
|
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } |
||||||
|
.dynamic : { *(.dynamic) } |
||||||
|
. = DATA_SEGMENT_RELRO_END (0, .); |
||||||
|
.data : |
||||||
|
{ |
||||||
|
__DATA_BEGIN__ = .; |
||||||
|
*(.data .data.* .gnu.linkonce.d.*) |
||||||
|
SORT(CONSTRUCTORS) |
||||||
|
} |
||||||
|
.data1 : { *(.data1) } |
||||||
|
.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } |
||||||
|
/* We want the small data sections together, so single-instruction offsets |
||||||
|
can access them all, and initialized data all before uninitialized, so |
||||||
|
we can shorten the on-disk segment size. */ |
||||||
|
.sdata : |
||||||
|
{ |
||||||
|
__SDATA_BEGIN__ = .; |
||||||
|
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) |
||||||
|
*(.sdata .sdata.* .gnu.linkonce.s.*) |
||||||
|
} |
||||||
|
_edata = .; PROVIDE (edata = .); |
||||||
|
. = .; |
||||||
|
__bss_start = .; |
||||||
|
.sbss : |
||||||
|
{ |
||||||
|
*(.dynsbss) |
||||||
|
*(.sbss .sbss.* .gnu.linkonce.sb.*) |
||||||
|
*(.scommon) |
||||||
|
} |
||||||
|
.bss : |
||||||
|
{ |
||||||
|
*(.dynbss) |
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*) |
||||||
|
*(COMMON) |
||||||
|
/* Align here to ensure that the .bss section occupies space up to |
||||||
|
_end. Align after .bss to ensure correct alignment even if the |
||||||
|
.bss section disappears because there are no input sections. |
||||||
|
FIXME: Why do we need it? When there is no .bss section, we do not |
||||||
|
pad the .data section. */ |
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1); |
||||||
|
} |
||||||
|
. = ALIGN(64 / 8); |
||||||
|
. = SEGMENT_START("ldata-segment", .); |
||||||
|
. = ALIGN(64 / 8); |
||||||
|
__BSS_END__ = .; |
||||||
|
__global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800, |
||||||
|
MAX(__DATA_BEGIN__ + 0x800, __BSS_END__ - 0x800)); |
||||||
|
_end = .; PROVIDE (end = .); |
||||||
|
. = DATA_SEGMENT_END (.); |
||||||
|
/* Stabs debugging sections. */ |
||||||
|
.stab 0 : { *(.stab) } |
||||||
|
.stabstr 0 : { *(.stabstr) } |
||||||
|
.stab.excl 0 : { *(.stab.excl) } |
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) } |
||||||
|
.stab.index 0 : { *(.stab.index) } |
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) } |
||||||
|
.comment 0 : { *(.comment) } |
||||||
|
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } |
||||||
|
/* DWARF debug sections. |
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning |
||||||
|
of the section so we begin them at 0. */ |
||||||
|
/* DWARF 1. */ |
||||||
|
.debug 0 : { *(.debug) } |
||||||
|
.line 0 : { *(.line) } |
||||||
|
/* GNU DWARF 1 extensions. */ |
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) } |
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) } |
||||||
|
/* DWARF 1.1 and DWARF 2. */ |
||||||
|
.debug_aranges 0 : { *(.debug_aranges) } |
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) } |
||||||
|
/* DWARF 2. */ |
||||||
|
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } |
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) } |
||||||
|
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } |
||||||
|
.debug_frame 0 : { *(.debug_frame) } |
||||||
|
.debug_str 0 : { *(.debug_str) } |
||||||
|
.debug_loc 0 : { *(.debug_loc) } |
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) } |
||||||
|
/* SGI/MIPS DWARF 2 extensions. */ |
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) } |
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) } |
||||||
|
.debug_typenames 0 : { *(.debug_typenames) } |
||||||
|
.debug_varnames 0 : { *(.debug_varnames) } |
||||||
|
/* DWARF 3. */ |
||||||
|
.debug_pubtypes 0 : { *(.debug_pubtypes) } |
||||||
|
.debug_ranges 0 : { *(.debug_ranges) } |
||||||
|
/* DWARF 5. */ |
||||||
|
.debug_addr 0 : { *(.debug_addr) } |
||||||
|
.debug_line_str 0 : { *(.debug_line_str) } |
||||||
|
.debug_loclists 0 : { *(.debug_loclists) } |
||||||
|
.debug_macro 0 : { *(.debug_macro) } |
||||||
|
.debug_names 0 : { *(.debug_names) } |
||||||
|
.debug_rnglists 0 : { *(.debug_rnglists) } |
||||||
|
.debug_str_offsets 0 : { *(.debug_str_offsets) } |
||||||
|
.debug_sup 0 : { *(.debug_sup) } |
||||||
|
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } |
||||||
|
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
#!/bin/sh |
||||||
|
|
||||||
|
# https://www.qemu.org/docs/master/system/target-riscv.html#board-specific-documentation |
||||||
|
# This is similar to the JH7110 used in the PineTab-V |
||||||
|
EMU_MACHINE='sifive_u' |
||||||
|
EMU_MEMORY='1G' |
||||||
|
EMU_BIOS='none' |
||||||
|
EMU_PLATFORM="-machine $EMU_MACHINE -smp 5 -m $EMU_MEMORY" |
||||||
|
EMU_OPTIONS="-bios $EMU_BIOS -display none -serial stdio -gdb tcp::1234" |
||||||
|
EMU_EXTRA='' |
||||||
|
QEMU_BIN='qemu-system-riscv64' |
||||||
|
|
||||||
|
kern_img='' |
||||||
|
|
||||||
|
while [ "${1:-}" != "" ]; do |
||||||
|
case "$1" in |
||||||
|
"--debug") |
||||||
|
EMU_EXTRA='-D' |
||||||
|
;; |
||||||
|
"--dump-dts"|"--dump") |
||||||
|
# shellcheck disable=SC2086 |
||||||
|
QEMU_CMD="$QEMU_BIN $EMU_PLATFORM $EMU_OPTIONS" |
||||||
|
$QEMU_CMD -machine dumpdtb=riscv64-"$EMU_MACHINE".dtb |
||||||
|
dtc riscv64-"$EMU_MACHINE".dtb > riscv64-"$EMU_MACHINE".dts |
||||||
|
exit 0 |
||||||
|
;; |
||||||
|
*) |
||||||
|
kern_img="$1" |
||||||
|
;; |
||||||
|
esac |
||||||
|
shift |
||||||
|
done |
||||||
|
|
||||||
|
|
||||||
|
if ! [ "$kern_img" ]; then |
||||||
|
echo "Must provide kernel binary ($kern_img)" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
QEMU_CMD="$QEMU_BIN $EMU_PLATFORM $EMU_OPTIONS $EMU_EXTRA" |
||||||
|
|
||||||
|
echo "starting $QEMU_CMD" |
||||||
|
# shellcheck disable=SC2086 |
||||||
|
exec $QEMU_CMD -kernel "$kern_img" |
Loading…
Reference in new issue