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