first commit
This commit is contained in:
commit
8f27b1a576
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
**/.cross_build
|
||||
cross
|
||||
*.dtb
|
||||
*.dts
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# ROVO
|
||||
|
||||
An hobby operating system for RISC-V platforms
|
6
ROADMAP
Normal file
6
ROADMAP
Normal file
@ -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
|
283
build_cross_toolchain.sh
Executable file
283
build_cross_toolchain.sh
Executable file
@ -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
kernel/-kernel
Normal file
0
kernel/-kernel
Normal file
4
kernel/.gitignore
vendored
Normal file
4
kernel/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
**/*.o
|
||||
*.img
|
||||
*.elf
|
||||
compile_commands.json
|
39
kernel/Makefile
Normal file
39
kernel/Makefile
Normal file
@ -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
|
190
kernel/clock.h
Normal file
190
kernel/clock.h
Normal file
@ -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
|
27
kernel/crt0.S
Normal file
27
kernel/crt0.S
Normal file
@ -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
|
BIN
kernel/kernel
Executable file
BIN
kernel/kernel
Executable file
Binary file not shown.
12
kernel/kernel.c
Normal file
12
kernel/kernel.c
Normal file
@ -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
|
||||
}
|
10
kernel/macro.h
Normal file
10
kernel/macro.h
Normal file
@ -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
|
26
kernel/platform/FU740/clock.c
Normal file
26
kernel/platform/FU740/clock.c
Normal file
@ -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;
|
||||
}
|
BIN
kernel/platform/FU740/doc/FU740_errata_20210205.pdf
Normal file
BIN
kernel/platform/FU740/doc/FU740_errata_20210205.pdf
Normal file
Binary file not shown.
BIN
kernel/platform/FU740/doc/fu740-c000-manual-v1p6.pdf
Normal file
BIN
kernel/platform/FU740/doc/fu740-c000-manual-v1p6.pdf
Normal file
Binary file not shown.
62
kernel/platform/FU740/uart.c
Normal file
62
kernel/platform/FU740/uart.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
170
kernel/platform/FU740/uart.h
Normal file
170
kernel/platform/FU740/uart.h
Normal file
@ -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
|
263
kernel/rv64-sifive_u.ld
Normal file
263
kernel/rv64-sifive_u.ld
Normal file
@ -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_*) }
|
||||
}
|
44
qemu_run.sh
Executable file
44
qemu_run.sh
Executable file
@ -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
Block a user