diff --git a/sys/conf/kern.mk b/sys/conf/kern.mk
index 1a1251f670e1..245f81e6ed71 100644
--- a/sys/conf/kern.mk
+++ b/sys/conf/kern.mk
@@ -1,334 +1,333 @@
# $FreeBSD$
#
# Warning flags for compiling the kernel and components of the kernel:
#
CWARNFLAGS?= -Wall -Wstrict-prototypes \
-Wmissing-prototypes -Wpointer-arith -Wcast-qual \
-Wundef -Wno-pointer-sign ${FORMAT_EXTENSIONS} \
-Wmissing-include-dirs -fdiagnostics-show-option \
-Wno-unknown-pragmas \
${CWARNEXTRA}
#
# The following flags are next up for working on:
# -Wextra
# Disable a few warnings for clang, since there are several places in the
# kernel where fixing them is more trouble than it is worth, or where there is
# a false positive.
.if ${COMPILER_TYPE} == "clang"
NO_WCONSTANT_CONVERSION= -Wno-error=constant-conversion
NO_WSHIFT_COUNT_NEGATIVE= -Wno-shift-count-negative
NO_WSHIFT_COUNT_OVERFLOW= -Wno-shift-count-overflow
NO_WSELF_ASSIGN= -Wno-self-assign
NO_WUNNEEDED_INTERNAL_DECL= -Wno-error=unneeded-internal-declaration
NO_WSOMETIMES_UNINITIALIZED= -Wno-error=sometimes-uninitialized
NO_WCAST_QUAL= -Wno-error=cast-qual
NO_WTAUTOLOGICAL_POINTER_COMPARE= -Wno-tautological-pointer-compare
.if ${COMPILER_VERSION} >= 100000
NO_WMISLEADING_INDENTATION= -Wno-misleading-indentation
.endif
.if ${COMPILER_VERSION} >= 130000
NO_WUNUSED_BUT_SET_VARIABLE= -Wno-unused-but-set-variable
.endif
.if ${COMPILER_VERSION} >= 140000
NO_WBITWISE_INSTEAD_OF_LOGICAL= -Wno-bitwise-instead-of-logical
.endif
.if ${COMPILER_VERSION} >= 150000
NO_WSTRICT_PROTOTYPES= -Wno-strict-prototypes
NO_WDEPRECATED_NON_PROTOTYPE= -Wno-deprecated-non-prototype
.endif
# Several other warnings which might be useful in some cases, but not severe
# enough to error out the whole kernel build. Display them anyway, so there is
# some incentive to fix them eventually.
CWARNEXTRA?= -Wno-error=tautological-compare -Wno-error=empty-body \
-Wno-error=parentheses-equality -Wno-error=unused-function \
-Wno-error=pointer-sign
CWARNEXTRA+= -Wno-error=shift-negative-value
CWARNEXTRA+= -Wno-address-of-packed-member
.if ${COMPILER_VERSION} >= 150000
# Clang 15 has much more aggressive diagnostics about
# mismatched prototypes and unused-but-set variables. Make these
# non-fatal for the time being.
CWARNEXTRA+= -Wno-error=strict-prototypes
CWARNEXTRA+= -Wno-error=unused-but-set-variable
.endif
.endif # clang
.if ${COMPILER_TYPE} == "gcc"
# Catch-all for all the things that are in our tree, but for which we're
# not yet ready for this compiler.
NO_WUNUSED_BUT_SET_VARIABLE=-Wno-unused-but-set-variable
CWARNEXTRA?= -Wno-error=address \
-Wno-error=aggressive-loop-optimizations \
-Wno-error=array-bounds \
-Wno-error=attributes \
-Wno-error=cast-qual \
-Wno-error=enum-compare \
-Wno-error=maybe-uninitialized \
-Wno-error=misleading-indentation \
-Wno-error=nonnull-compare \
-Wno-error=overflow \
-Wno-error=sequence-point \
-Wno-error=shift-overflow \
-Wno-error=tautological-compare \
-Wno-error=unused-function
.if ${COMPILER_VERSION} >= 70100
CWARNEXTRA+= -Wno-error=stringop-overflow
.endif
.if ${COMPILER_VERSION} >= 70200
CWARNEXTRA+= -Wno-error=memset-elt-size
.endif
.if ${COMPILER_VERSION} >= 80000
CWARNEXTRA+= -Wno-error=packed-not-aligned
.endif
.if ${COMPILER_VERSION} >= 90100
CWARNEXTRA+= -Wno-address-of-packed-member \
-Wno-error=alloca-larger-than=
.if ${COMPILER_VERSION} >= 120100
CWARNEXTRA+= -Wno-error=nonnull \
-Wno-dangling-pointer \
-Wno-zero-length-bounds
NO_WINFINITE_RECURSION= -Wno-infinite-recursion
NO_WSTRINGOP_OVERREAD= -Wno-stringop-overread
.endif
.endif
# GCC produces false positives for functions that switch on an
# enum (GCC bug 87950)
CWARNFLAGS+= -Wno-return-type
.endif # gcc
# This warning is utter nonsense
CWARNFLAGS+= -Wno-format-zero-length
# External compilers may not support our format extensions. Allow them
# to be disabled. WARNING: format checking is disabled in this case.
.if ${MK_FORMAT_EXTENSIONS} == "no"
FORMAT_EXTENSIONS= -Wno-format
.elif ${COMPILER_TYPE} == "clang" || \
(${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} >= 120100)
FORMAT_EXTENSIONS= -D__printf__=__freebsd_kprintf__
.else
FORMAT_EXTENSIONS= -fformat-extensions
.endif
#
# On i386, do not align the stack to 16-byte boundaries. Otherwise GCC 2.95
# and above adds code to the entry and exit point of every function to align the
# stack to 16-byte boundaries -- thus wasting approximately 12 bytes of stack
# per function call. While the 16-byte alignment may benefit micro benchmarks,
# it is probably an overall loss as it makes the code bigger (less efficient
# use of code cache tag lines) and uses more stack (less efficient use of data
# cache tag lines). Explicitly prohibit the use of FPU, SSE and other SIMD
# operations inside the kernel itself. These operations are exclusively
# reserved for user applications.
#
# gcc:
# Setting -mno-mmx implies -mno-3dnow
# Setting -mno-sse implies -mno-sse2, -mno-sse3 and -mno-ssse3
#
# clang:
# Setting -mno-mmx implies -mno-3dnow and -mno-3dnowa
# Setting -mno-sse implies -mno-sse2, -mno-sse3, -mno-ssse3, -mno-sse41 and -mno-sse42
#
.if ${MACHINE_CPUARCH} == "i386"
CFLAGS.gcc+= -mpreferred-stack-boundary=2
CFLAGS.clang+= -mno-aes -mno-avx
CFLAGS+= -mno-mmx -mno-sse -msoft-float
INLINE_LIMIT?= 8000
.endif
.if ${MACHINE_CPUARCH} == "arm"
INLINE_LIMIT?= 8000
.endif
.if ${MACHINE_CPUARCH} == "aarch64"
# We generally don't want fpu instructions in the kernel.
CFLAGS += -mgeneral-regs-only
# Reserve x18 for pcpu data
CFLAGS += -ffixed-x18
INLINE_LIMIT?= 8000
.endif
#
# For RISC-V we specify the soft-float ABI (lp64) to avoid the use of floating
-# point registers within the kernel. However, for kernels supporting hardware
-# float (FPE), we have to include that in the march so we can have limited
-# floating point support in context switching needed for that. This is different
-# than userland where we use a hard-float ABI (lp64d).
+# point registers within the kernel. However, we include the F and D extensions
+# in -march so we can have limited floating point support in context switching
+# code. This is different than userland where we use a hard-float ABI (lp64d).
#
# We also specify the "medium" code model, which generates code suitable for a
# 2GiB addressing range located at any offset, allowing modules to be located
# anywhere in the 64-bit address space. Note that clang and GCC refer to this
# code model as "medium" and "medany" respectively.
#
.if ${MACHINE_CPUARCH} == "riscv"
CFLAGS+= -march=rv64imafdc
CFLAGS+= -mabi=lp64
CFLAGS.clang+= -mcmodel=medium
CFLAGS.gcc+= -mcmodel=medany
INLINE_LIMIT?= 8000
.if ${LINKER_FEATURES:Mriscv-relaxations} == ""
CFLAGS+= -mno-relax
.endif
.endif
#
# For AMD64, we explicitly prohibit the use of FPU, SSE and other SIMD
# operations inside the kernel itself. These operations are exclusively
# reserved for user applications.
#
# gcc:
# Setting -mno-mmx implies -mno-3dnow
# Setting -mno-sse implies -mno-sse2, -mno-sse3, -mno-ssse3 and -mfpmath=387
#
# clang:
# Setting -mno-mmx implies -mno-3dnow and -mno-3dnowa
# Setting -mno-sse implies -mno-sse2, -mno-sse3, -mno-ssse3, -mno-sse41 and -mno-sse42
# (-mfpmath= is not supported)
#
.if ${MACHINE_CPUARCH} == "amd64"
CFLAGS.clang+= -mno-aes -mno-avx
CFLAGS+= -mcmodel=kernel -mno-red-zone -mno-mmx -mno-sse -msoft-float \
-fno-asynchronous-unwind-tables
INLINE_LIMIT?= 8000
.endif
#
# For PowerPC we tell gcc to use floating point emulation. This avoids using
# floating point registers for integer operations which it has a tendency to do.
# Also explicitly disable Altivec instructions inside the kernel.
#
.if ${MACHINE_CPUARCH} == "powerpc"
CFLAGS+= -mno-altivec -msoft-float
INLINE_LIMIT?= 15000
.endif
.if ${MACHINE_ARCH} == "powerpcspe"
CFLAGS.gcc+= -mno-spe
.endif
#
# Use dot symbols (or, better, the V2 ELF ABI) on powerpc64 to make
# DDB happy. ELFv2, if available, has some other efficiency benefits.
#
.if ${MACHINE_ARCH:Mpowerpc64*} != "" && \
${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} < 160000
CFLAGS+= -mabi=elfv2
.endif
#
# GCC 3.0 and above like to do certain optimizations based on the
# assumption that the program is linked against libc. Stop this.
#
CFLAGS+= -ffreestanding
#
# The C standard leaves signed integer overflow behavior undefined.
# gcc and clang opimizers take advantage of this. The kernel makes
# use of signed integer wraparound mechanics so we need the compiler
# to treat it as a wraparound and not take shortcuts.
#
CFLAGS+= -fwrapv
#
# GCC SSP support
#
.if ${MK_SSP} != "no"
CFLAGS+= -fstack-protector
.endif
#
# Retpoline speculative execution vulnerability mitigation (CVE-2017-5715)
#
.if defined(COMPILER_FEATURES) && ${COMPILER_FEATURES:Mretpoline} != "" && \
${MK_KERNEL_RETPOLINE} != "no"
CFLAGS+= -mretpoline
.endif
#
# Initialize stack variables on function entry
#
.if ${MK_INIT_ALL_ZERO} == "yes"
.if ${COMPILER_FEATURES:Minit-all}
CFLAGS+= -ftrivial-auto-var-init=zero \
-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang
.else
.warning InitAll (zeros) requested but not support by compiler
.endif
.elif ${MK_INIT_ALL_PATTERN} == "yes"
.if ${COMPILER_FEATURES:Minit-all}
CFLAGS+= -ftrivial-auto-var-init=pattern
.else
.warning InitAll (pattern) requested but not support by compiler
.endif
.endif
CFLAGS+= ${CWARNFLAGS:M*} ${CWARNFLAGS.${.IMPSRC:T}}
CFLAGS+= ${CWARNFLAGS.${COMPILER_TYPE}}
CFLAGS+= ${CFLAGS.${COMPILER_TYPE}} ${CFLAGS.${.IMPSRC:T}}
# Tell bmake not to mistake standard targets for things to be searched for
# or expect to ever be up-to-date.
PHONY_NOTMAIN = afterdepend afterinstall all beforedepend beforeinstall \
beforelinking build build-tools buildfiles buildincludes \
checkdpadd clean cleandepend cleandir cleanobj configure \
depend distclean distribute exe \
html includes install installfiles installincludes \
obj objlink objs objwarn \
realinstall regress \
tags whereobj
.PHONY: ${PHONY_NOTMAIN}
.NOTMAIN: ${PHONY_NOTMAIN}
CSTD= c99
.if ${CSTD} == "k&r"
CFLAGS+= -traditional
.elif ${CSTD} == "c89" || ${CSTD} == "c90"
CFLAGS+= -std=iso9899:1990
.elif ${CSTD} == "c94" || ${CSTD} == "c95"
CFLAGS+= -std=iso9899:199409
.elif ${CSTD} == "c99"
CFLAGS+= -std=iso9899:1999
.else # CSTD
CFLAGS+= -std=${CSTD}
.endif # CSTD
# Please keep this if in sync with bsd.sys.mk
.if ${LD} != "ld" && (${CC:[1]:H} != ${LD:[1]:H} || ${LD:[1]:T} != "ld")
# Add -fuse-ld=${LD} if $LD is in a different directory or not called "ld".
.if ${COMPILER_TYPE} == "clang"
# Note: Clang does not like relative paths for ld so we map ld.lld -> lld.
.if ${COMPILER_VERSION} >= 120000
CCLDFLAGS+= --ld-path=${LD:[1]:S/^ld.//1W}
.else
CCLDFLAGS+= -fuse-ld=${LD:[1]:S/^ld.//1W}
.endif
.else
# GCC does not support an absolute path for -fuse-ld so we just print this
# warning instead and let the user add the required symlinks.
# However, we can avoid this warning if -B is set appropriately (e.g. for
# CROSS_TOOLCHAIN=...-gcc).
.if !(${LD:[1]:T} == "ld" && ${CC:tw:M-B${LD:[1]:H}/})
.warning LD (${LD}) is not the default linker for ${CC} but -fuse-ld= is not supported
.endif
.endif
.endif
# Set target-specific linker emulation name.
LD_EMULATION_aarch64=aarch64elf
LD_EMULATION_amd64=elf_x86_64_fbsd
LD_EMULATION_arm=armelf_fbsd
LD_EMULATION_armv6=armelf_fbsd
LD_EMULATION_armv7=armelf_fbsd
LD_EMULATION_i386=elf_i386_fbsd
LD_EMULATION_powerpc= elf32ppc_fbsd
LD_EMULATION_powerpcspe= elf32ppc_fbsd
LD_EMULATION_powerpc64= elf64ppc_fbsd
LD_EMULATION_powerpc64le= elf64lppc_fbsd
LD_EMULATION_riscv64= elf64lriscv
LD_EMULATION=${LD_EMULATION_${MACHINE_ARCH}}
diff --git a/sys/conf/options.riscv b/sys/conf/options.riscv
index 9e48f73fba33..964a2f07173c 100644
--- a/sys/conf/options.riscv
+++ b/sys/conf/options.riscv
@@ -1,5 +1,4 @@
# $FreeBSD$
RISCV opt_global.h # For cpu RISCV to work
-FPE opt_global.h
INTRNG opt_global.h
diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC
index 49e3f07c0f96..04645ec9bf90 100644
--- a/sys/riscv/conf/GENERIC
+++ b/sys/riscv/conf/GENERIC
@@ -1,224 +1,223 @@
#
# GENERIC -- Generic kernel configuration file for FreeBSD/RISC-V
#
# For more information on this file, please read the config(5) manual page,
# and/or the handbook section on Kernel Configuration Files:
#
# https://docs.freebsd.org/en/books/handbook/kernelconfig/#kernelconfig-config
#
# The handbook is also available locally in /usr/share/doc/handbook
# if you've installed the doc distribution, otherwise always see the
# FreeBSD World Wide Web server (https://www.FreeBSD.org/) for the
# latest information.
#
# An exhaustive list of options and more detailed explanations of the
# device lines is also present in the ../../conf/NOTES and NOTES files.
# If you are in doubt as to the purpose or necessity of a line, check first
# in NOTES.
#
# $FreeBSD$
cpu RISCV
ident GENERIC
makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
makeoptions WITH_CTF=1 # Run ctfconvert(1) for DTrace support
options SCHED_ULE # ULE scheduler
options PREEMPTION # Enable kernel thread preemption
options VIMAGE # Subsystem virtualization, e.g. VNET
options INET # InterNETworking
options INET6 # IPv6 communications protocols
options TCP_HHOOK # hhook(9) framework for TCP
options IPSEC_SUPPORT # Allow kldload of ipsec and tcpmd5
options ROUTE_MPATH # Multipath routing support
options TCP_OFFLOAD # TCP offload
options TCP_BLACKBOX # Enhanced TCP event logging
options TCP_RFC7413 # TCP Fast Open
options SCTP_SUPPORT # Allow kldload of SCTP
options FFS # Berkeley Fast Filesystem
options SOFTUPDATES # Enable FFS soft updates support
options UFS_ACL # Support for access control lists
options UFS_DIRHASH # Improve performance on big directories
options UFS_GJOURNAL # Enable gjournal-based UFS journaling
options QUOTA # Enable disk quotas for UFS
options NFSCL # Network Filesystem Client
options NFSD # Network Filesystem Server
options NFSLOCKD # Network Lock Manager
options NFS_ROOT # NFS usable as /, requires NFSCL
options MSDOSFS # MSDOS Filesystem
options CD9660 # ISO 9660 Filesystem
options PROCFS # Process filesystem (requires PSEUDOFS)
options PSEUDOFS # Pseudo-filesystem framework
options TMPFS # Efficient memory filesystem
options GEOM_RAID # Soft RAID functionality.
options GEOM_LABEL # Provides labelization
options COMPAT_FREEBSD12 # Compatible with FreeBSD12
options COMPAT_FREEBSD13 # Compatible with FreeBSD13
options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
options KTRACE # ktrace(1) support
options STACK # stack(9) support
options SYSVSHM # SYSV-style shared memory
options SYSVMSG # SYSV-style message queues
options SYSVSEM # SYSV-style semaphores
options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions
options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed.
options KBD_INSTALL_CDEV # install a CDEV entry in /dev
# options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4)
options AUDIT # Security event auditing
options CAPABILITY_MODE # Capsicum capability mode
options CAPABILITIES # Capsicum capabilities
options MAC # TrustedBSD MAC Framework
options KDTRACE_FRAME # Ensure frames are compiled in
options KDTRACE_HOOKS # Kernel DTrace hooks
options DDB_CTF # Kernel ELF linker loads CTF data
-options FPE # Floating-point extension support
options RACCT # Resource accounting framework
options RACCT_DEFAULT_TO_DISABLED # Set kern.racct.enable=0 by default
options RCTL # Resource limits
options SMP
# RISC-V SBI console
device rcons
# pseudo devices
device clk
device hwreset
device syscon
device syscon_power
device riscv_syscon
# Bus drivers
device pci
# Block devices
device scbus
device da
# VirtIO support
device virtio # Generic VirtIO bus (required)
device virtio_pci # VirtIO PCI device
device vtnet # VirtIO Ethernet device
device virtio_blk # VirtIO Block device
device virtio_mmio # VirtIO MMIO bus
# NVM Express (NVMe) support
device nvme # base NVMe driver
options NVME_USE_NVD=0 # prefer the cam(4) based nda(4) driver
device nvd # expose NVMe namespaces as disks, depends on nvme
# USB support
options USB_DEBUG # enable debug msgs
device ohci # OHCI USB interface
device uhci # UHCI USB interface
device ehci # EHCI USB interface (USB 2.0)
device xhci # XHCI USB interface (USB 3.0)
device usb # USB Bus (required)
device ukbd # Keyboard
device umass # Disks/Mass storage - Requires scbus and da
# HID support
options HID_DEBUG # enable debug msgs
device hid # Generic HID support
# DTrace support
# device dtrace
# device dtrace_profile
# device dtrace_sdt
# device dtrace_fbt
# device dtrace_systrace
# device dtrace_prototype
# device dtraceall
# Serial (COM) ports
device uart # Generic UART driver
device uart_lowrisc # lowRISC UART driver
device uart_ns8250 # ns8250-type UART driver
# Console
device vt
device kbdmux
# RTC
device da9063_rtc # Dialog Semiconductor DA9063 RTC
device goldfish_rtc # QEMU RTC
# Ethernet drivers
device cgem # Cadence GEM Gigabit Ethernet device
device miibus # MII bus support
device xae # Xilinx AXI Ethernet MAC
# DMA support
device xdma # DMA interface
device axidma # Xilinx AXI DMA Controller
# GPIO
device gpio
# SPI
device spibus
device spigen
# Power management controllers
device da9063_pmic # Dialog Semiconductor DA9063 PMIC
# Uncomment for memory disk
# options MD_ROOT
# options MD_ROOT_SIZE=32768 # 32MB ram disk
# makeoptions MFS_IMAGE=/path/to/img
# options ROOTDEVNAME=\"ufs:/dev/md0\"
# Uncomment for virtio block device
# options ROOTDEVNAME=\"ufs:/dev/vtbd0\"
# Debugging support. Always need this:
options KDB # Enable kernel debugger support.
options KDB_TRACE # Print a stack trace for a panic.
# For full debugger support use (turn off in stable branch):
options DDB # Support DDB.
options GDB # Support remote GDB.
options DEADLKRES # Enable the deadlock resolver
options INVARIANTS # Enable calls of extra sanity checking
options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS
options WITNESS # Enable checks to detect deadlocks and cycles
options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed
options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones
options ALT_BREAK_TO_DEBUGGER # Enter debugger on keyboard escape sequence
# options EARLY_PRINTF
options VERBOSE_SYSINIT=0 # Support debug.verbose_sysinit, off by default
# Kernel dump features.
options ZSTDIO # zstd-compressed kernel and user dumps
# Pseudo devices.
device crypto # core crypto support
device loop # Network loopback
device ether # Ethernet support
device vlan # 802.1Q VLAN support
device tuntap # Packet tunnel.
device md # Memory "disks"
device gif # IPv6 and IPv4 tunneling
device firmware # firmware assist module
# The `bpf' device enables the Berkeley Packet Filter.
# Be aware of the administrative consequences of enabling this!
# Note that 'bpf' is required for DHCP.
device bpf # Berkeley packet filter
# Flattened Device Tree
options FDT
makeoptions MODULES_EXTRA+="dtb/sifive"
# I2C support
device iicbus # Bus support, required for iicoc below.
device iicoc # OpenCores I2C controller support
# Allwinner device drivers
device aw_wdog # Allwinner Watchdog
files "../allwinner/files.allwinner"
# SiFive device drivers
device fu740_pci_dw
device sifive_gpio
device sifive_spi
include "../sifive/std.sifive"
diff --git a/sys/riscv/conf/NOTES b/sys/riscv/conf/NOTES
index f36e6283433d..d3ff441a95d6 100644
--- a/sys/riscv/conf/NOTES
+++ b/sys/riscv/conf/NOTES
@@ -1,108 +1,107 @@
#
# NOTES -- Lines that can be cut/pasted into kernel and hints configs.
#
# This file contains machine dependent kernel configuration notes. For
# machine independent notes, look in /sys/conf/NOTES.
#
# $FreeBSD$
#
cpu RISCV
makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
makeoptions WITH_CTF=1 # Run ctfconvert(1) for DTrace support
options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed.
options KDTRACE_FRAME # Ensure frames are compiled in
options KDTRACE_HOOKS # Kernel DTrace hooks
options DDB_CTF # Kernel ELF linker loads CTF data
-options FPE # Floating-point extension support
options RACCT_DEFAULT_TO_DISABLED # Set kern.racct.enable=0 by default
# RISC-V SBI console
device rcons
# pseudo devices
device clk
device hwreset
device phy
device regulator
device syscon
device syscon_power
device riscv_syscon
# Backlight subsystem
device backlight
# VirtIO support
device virtio # Generic VirtIO bus (required)
device virtio_pci # VirtIO PCI device
device vtnet # VirtIO Ethernet device
device virtio_blk # VirtIO Block device
device virtio_mmio # VirtIO MMIO bus
device virtio_random # VirtIO Entropy device
# NVM Express (NVMe) support
device nvme # base NVMe driver
options NVME_USE_NVD=0 # prefer the cam(4) based nda(4) driver
device nvd # expose NVMe namespaces as disks, depends on nvme
# NOTE: dtrace introduces CDDL-licensed components into the kernel
device dtrace # dtrace core
device dtraceall # include all dtrace modules
# Serial (COM) ports
device uart_lowrisc # lowRISC UART driver
device uart_ns8250 # ns8250-type UART driver
# RTC
device da9063_rtc # Dialog Semiconductor DA9063 RTC
device goldfish_rtc # QEMU RTC
# Ethernet drivers
device xae # Xilinx AXI Ethernet MAC
# DMA support
device xdma # DMA interface
device axidma # Xilinx AXI DMA Controller
# SPI
device xilinx_spi # Xilinx AXI Quad-SPI Controller
# Power management controllers
device da9063_pmic # Dialog Semiconductor DA9063 PMIC
# SiFive device drivers
device fe310aon
device fu740_pci_dw
device sifive_gpio
device sifive_spi
files "../sifive/files.sifive"
# Flattened Device Tree
options FDT
makeoptions MODULES_EXTRA+="dtb/sifive"
# FreeBSD/riscv didn't exist for these releases
nooptions COMPAT_FREEBSD4
nooptions COMPAT_FREEBSD5
nooptions COMPAT_FREEBSD6
nooptions COMPAT_FREEBSD7
nooptions COMPAT_FREEBSD9
nooptions COMPAT_FREEBSD10
nooptions COMPAT_FREEBSD11
# riscv doesn't support inb/outb, so disable chipset probing which needs it
nooptions PPC_PROBE_CHIPSET
# Makes assumptions about bus tags that aren't true on riscv
nodevice snd_cmi
# Don't yet have hwpmc(4)
nodevice hwpmc
nooptions HWPMC_HOOKS
# riscv doesn't yet have atomic_testandset_int and atomic_testandclear_int.
nodevice ccr
nodevice cxgbe
nodevice cxgbev
diff --git a/sys/riscv/riscv/exec_machdep.c b/sys/riscv/riscv/exec_machdep.c
index ab79c0384eb3..e61bce628602 100644
--- a/sys/riscv/riscv/exec_machdep.c
+++ b/sys/riscv/riscv/exec_machdep.c
@@ -1,429 +1,416 @@
/*-
* Copyright (c) 2014 Andrew Turner
* Copyright (c) 2015-2017 Ruslan Bukin
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
* University of Cambridge Computer Laboratory under DARPA/AFRL contract
* FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
*
* Portions of this software were developed by the University of Cambridge
* Computer Laboratory as part of the CTSRD Project, with support from the
* UK Higher Education Innovation Fund (HEIF).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include
__FBSDID("$FreeBSD$");
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
-#ifdef FPE
-#include
-#endif
-
static void get_fpcontext(struct thread *td, mcontext_t *mcp);
static void set_fpcontext(struct thread *td, mcontext_t *mcp);
_Static_assert(sizeof(mcontext_t) == 864, "mcontext_t size incorrect");
_Static_assert(sizeof(ucontext_t) == 936, "ucontext_t size incorrect");
_Static_assert(sizeof(siginfo_t) == 80, "siginfo_t size incorrect");
int
fill_regs(struct thread *td, struct reg *regs)
{
struct trapframe *frame;
frame = td->td_frame;
regs->sepc = frame->tf_sepc;
regs->sstatus = frame->tf_sstatus;
regs->ra = frame->tf_ra;
regs->sp = frame->tf_sp;
regs->gp = frame->tf_gp;
regs->tp = frame->tf_tp;
memcpy(regs->t, frame->tf_t, sizeof(regs->t));
memcpy(regs->s, frame->tf_s, sizeof(regs->s));
memcpy(regs->a, frame->tf_a, sizeof(regs->a));
return (0);
}
int
set_regs(struct thread *td, struct reg *regs)
{
struct trapframe *frame;
frame = td->td_frame;
frame->tf_sepc = regs->sepc;
frame->tf_ra = regs->ra;
frame->tf_sp = regs->sp;
frame->tf_gp = regs->gp;
frame->tf_tp = regs->tp;
memcpy(frame->tf_t, regs->t, sizeof(frame->tf_t));
memcpy(frame->tf_s, regs->s, sizeof(frame->tf_s));
memcpy(frame->tf_a, regs->a, sizeof(frame->tf_a));
return (0);
}
int
fill_fpregs(struct thread *td, struct fpreg *regs)
{
-#ifdef FPE
struct pcb *pcb;
pcb = td->td_pcb;
if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
/*
* If we have just been running FPE instructions we will
* need to save the state to memcpy it below.
*/
if (td == curthread)
fpe_state_save(td);
memcpy(regs->fp_x, pcb->pcb_x, sizeof(regs->fp_x));
regs->fp_fcsr = pcb->pcb_fcsr;
} else
-#endif
memset(regs, 0, sizeof(*regs));
return (0);
}
int
set_fpregs(struct thread *td, struct fpreg *regs)
{
-#ifdef FPE
struct trapframe *frame;
struct pcb *pcb;
frame = td->td_frame;
pcb = td->td_pcb;
memcpy(pcb->pcb_x, regs->fp_x, sizeof(regs->fp_x));
pcb->pcb_fcsr = regs->fp_fcsr;
pcb->pcb_fpflags |= PCB_FP_STARTED;
frame->tf_sstatus &= ~SSTATUS_FS_MASK;
frame->tf_sstatus |= SSTATUS_FS_CLEAN;
-#endif
return (0);
}
int
fill_dbregs(struct thread *td, struct dbreg *regs)
{
panic("fill_dbregs");
}
int
set_dbregs(struct thread *td, struct dbreg *regs)
{
panic("set_dbregs");
}
void
exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
{
struct trapframe *tf;
struct pcb *pcb;
tf = td->td_frame;
pcb = td->td_pcb;
memset(tf, 0, sizeof(struct trapframe));
tf->tf_a[0] = stack;
tf->tf_sp = STACKALIGN(stack);
tf->tf_ra = imgp->entry_addr;
tf->tf_sepc = imgp->entry_addr;
pcb->pcb_fpflags &= ~PCB_FP_STARTED;
}
/* Sanity check these are the same size, they will be memcpy'd to and from */
CTASSERT(sizeof(((struct trapframe *)0)->tf_a) ==
sizeof((struct gpregs *)0)->gp_a);
CTASSERT(sizeof(((struct trapframe *)0)->tf_s) ==
sizeof((struct gpregs *)0)->gp_s);
CTASSERT(sizeof(((struct trapframe *)0)->tf_t) ==
sizeof((struct gpregs *)0)->gp_t);
CTASSERT(sizeof(((struct trapframe *)0)->tf_a) ==
sizeof((struct reg *)0)->a);
CTASSERT(sizeof(((struct trapframe *)0)->tf_s) ==
sizeof((struct reg *)0)->s);
CTASSERT(sizeof(((struct trapframe *)0)->tf_t) ==
sizeof((struct reg *)0)->t);
int
get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
{
struct trapframe *tf = td->td_frame;
memcpy(mcp->mc_gpregs.gp_t, tf->tf_t, sizeof(mcp->mc_gpregs.gp_t));
memcpy(mcp->mc_gpregs.gp_s, tf->tf_s, sizeof(mcp->mc_gpregs.gp_s));
memcpy(mcp->mc_gpregs.gp_a, tf->tf_a, sizeof(mcp->mc_gpregs.gp_a));
if (clear_ret & GET_MC_CLEAR_RET) {
mcp->mc_gpregs.gp_a[0] = 0;
mcp->mc_gpregs.gp_t[0] = 0; /* clear syscall error */
}
mcp->mc_gpregs.gp_ra = tf->tf_ra;
mcp->mc_gpregs.gp_sp = tf->tf_sp;
mcp->mc_gpregs.gp_gp = tf->tf_gp;
mcp->mc_gpregs.gp_tp = tf->tf_tp;
mcp->mc_gpregs.gp_sepc = tf->tf_sepc;
mcp->mc_gpregs.gp_sstatus = tf->tf_sstatus;
get_fpcontext(td, mcp);
return (0);
}
int
set_mcontext(struct thread *td, mcontext_t *mcp)
{
struct trapframe *tf;
tf = td->td_frame;
/*
* Permit changes to the USTATUS bits of SSTATUS.
*
* Ignore writes to read-only bits (SD, XS).
*
* Ignore writes to the FS field as set_fpcontext() will set
* it explicitly.
*/
if (((mcp->mc_gpregs.gp_sstatus ^ tf->tf_sstatus) &
~(SSTATUS_SD | SSTATUS_XS_MASK | SSTATUS_FS_MASK | SSTATUS_UPIE |
SSTATUS_UIE)) != 0)
return (EINVAL);
memcpy(tf->tf_t, mcp->mc_gpregs.gp_t, sizeof(tf->tf_t));
memcpy(tf->tf_s, mcp->mc_gpregs.gp_s, sizeof(tf->tf_s));
memcpy(tf->tf_a, mcp->mc_gpregs.gp_a, sizeof(tf->tf_a));
tf->tf_ra = mcp->mc_gpregs.gp_ra;
tf->tf_sp = mcp->mc_gpregs.gp_sp;
tf->tf_gp = mcp->mc_gpregs.gp_gp;
tf->tf_sepc = mcp->mc_gpregs.gp_sepc;
tf->tf_sstatus = mcp->mc_gpregs.gp_sstatus;
set_fpcontext(td, mcp);
return (0);
}
static void
get_fpcontext(struct thread *td, mcontext_t *mcp)
{
-#ifdef FPE
struct pcb *curpcb;
critical_enter();
curpcb = curthread->td_pcb;
KASSERT(td->td_pcb == curpcb, ("Invalid fpe pcb"));
if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
/*
* If we have just been running FPE instructions we will
* need to save the state to memcpy it below.
*/
fpe_state_save(td);
KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
("Non-userspace FPE flags set in get_fpcontext"));
memcpy(mcp->mc_fpregs.fp_x, curpcb->pcb_x,
sizeof(mcp->mc_fpregs.fp_x));
mcp->mc_fpregs.fp_fcsr = curpcb->pcb_fcsr;
mcp->mc_fpregs.fp_flags = curpcb->pcb_fpflags;
mcp->mc_flags |= _MC_FP_VALID;
}
critical_exit();
-#endif
}
static void
set_fpcontext(struct thread *td, mcontext_t *mcp)
{
-#ifdef FPE
struct pcb *curpcb;
-#endif
td->td_frame->tf_sstatus &= ~SSTATUS_FS_MASK;
td->td_frame->tf_sstatus |= SSTATUS_FS_OFF;
-#ifdef FPE
critical_enter();
if ((mcp->mc_flags & _MC_FP_VALID) != 0) {
curpcb = curthread->td_pcb;
/* FPE usage is enabled, override registers. */
memcpy(curpcb->pcb_x, mcp->mc_fpregs.fp_x,
sizeof(mcp->mc_fpregs.fp_x));
curpcb->pcb_fcsr = mcp->mc_fpregs.fp_fcsr;
curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags & PCB_FP_USERMASK;
td->td_frame->tf_sstatus |= SSTATUS_FS_CLEAN;
}
critical_exit();
-#endif
}
int
sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
{
ucontext_t uc;
int error;
if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
return (EFAULT);
error = set_mcontext(td, &uc.uc_mcontext);
if (error != 0)
return (error);
/* Restore signal mask. */
kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
return (EJUSTRETURN);
}
void
sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
{
struct sigframe *fp, frame;
struct sysentvec *sysent;
struct trapframe *tf;
struct sigacts *psp;
struct thread *td;
struct proc *p;
int onstack;
int sig;
td = curthread;
p = td->td_proc;
PROC_LOCK_ASSERT(p, MA_OWNED);
sig = ksi->ksi_signo;
psp = p->p_sigacts;
mtx_assert(&psp->ps_mtx, MA_OWNED);
tf = td->td_frame;
onstack = sigonstack(tf->tf_sp);
CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
catcher, sig);
/* Allocate and validate space for the signal handler context. */
if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack &&
SIGISMEMBER(psp->ps_sigonstack, sig)) {
fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
td->td_sigstk.ss_size);
} else {
fp = (struct sigframe *)td->td_frame->tf_sp;
}
/* Make room, keeping the stack aligned */
fp--;
fp = (struct sigframe *)STACKALIGN(fp);
/* Fill in the frame to copy out */
bzero(&frame, sizeof(frame));
get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
frame.sf_si = ksi->ksi_info;
frame.sf_uc.uc_sigmask = *mask;
frame.sf_uc.uc_stack = td->td_sigstk;
frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
(onstack ? SS_ONSTACK : 0) : SS_DISABLE;
mtx_unlock(&psp->ps_mtx);
PROC_UNLOCK(td->td_proc);
/* Copy the sigframe out to the user's stack. */
if (copyout(&frame, fp, sizeof(*fp)) != 0) {
/* Process has trashed its stack. Kill it. */
CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
PROC_LOCK(p);
sigexit(td, SIGILL);
}
tf->tf_a[0] = sig;
tf->tf_a[1] = (register_t)&fp->sf_si;
tf->tf_a[2] = (register_t)&fp->sf_uc;
tf->tf_sepc = (register_t)catcher;
tf->tf_sp = (register_t)fp;
sysent = p->p_sysent;
if (PROC_HAS_SHP(p))
tf->tf_ra = (register_t)PROC_SIGCODE(p);
else
tf->tf_ra = (register_t)(PROC_PS_STRINGS(p) -
*(sysent->sv_szsigcode));
CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_sepc,
tf->tf_sp);
PROC_LOCK(p);
mtx_lock(&psp->ps_mtx);
}
diff --git a/sys/riscv/riscv/identcpu.c b/sys/riscv/riscv/identcpu.c
index 5f10ec6358ae..c57a22c1b51a 100644
--- a/sys/riscv/riscv/identcpu.c
+++ b/sys/riscv/riscv/identcpu.c
@@ -1,368 +1,366 @@
/*-
* Copyright (c) 2015-2016 Ruslan Bukin
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
* University of Cambridge Computer Laboratory under DARPA/AFRL contract
* FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
*
* Portions of this software were developed by the University of Cambridge
* Computer Laboratory as part of the CTSRD Project, with support from the
* UK Higher Education Innovation Fund (HEIF).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "opt_platform.h"
#include
__FBSDID("$FreeBSD$");
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef FDT
#include
#include
#include
#endif
char machine[] = "riscv";
SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD | CTLFLAG_CAPRD, machine, 0,
"Machine class");
/* Hardware implementation info. These values may be empty. */
register_t mvendorid; /* The CPU's JEDEC vendor ID */
register_t marchid; /* The architecture ID */
register_t mimpid; /* The implementation ID */
struct cpu_desc {
u_int cpu_impl;
u_int cpu_part_num;
const char *cpu_impl_name;
const char *cpu_part_name;
};
struct cpu_desc cpu_desc[MAXCPU];
struct cpu_parts {
u_int part_id;
const char *part_name;
};
#define CPU_PART_NONE { -1, "Unknown Processor" }
struct cpu_implementers {
u_int impl_id;
const char *impl_name;
};
#define CPU_IMPLEMENTER_NONE { 0, "Unknown Implementer" }
/*
* CPU base
*/
static const struct cpu_parts cpu_parts_std[] = {
{ CPU_PART_RV32, "RV32" },
{ CPU_PART_RV64, "RV64" },
{ CPU_PART_RV128, "RV128" },
CPU_PART_NONE,
};
/*
* Implementers table.
*/
const struct cpu_implementers cpu_implementers[] = {
{ CPU_IMPL_UCB_ROCKET, "UC Berkeley Rocket" },
CPU_IMPLEMENTER_NONE,
};
/*
* The ISA string describes the complete set of instructions supported by a
* RISC-V CPU. The string begins with a small prefix (e.g. rv64) indicating the
* base ISA. It is followed first by single-letter ISA extensions, and then
* multi-letter ISA extensions.
*
* Underscores are used mainly to separate consecutive multi-letter extensions,
* but may optionally appear between any two extensions. An extension may be
* followed by a version number, in the form of 'Mpm', where M is the
* extension's major version number, and 'm' is the minor version number.
*
* The format is described in detail by the "ISA Extension Naming Conventions"
* chapter of the unprivileged spec.
*/
#define ISA_PREFIX ("rv" __XSTRING(__riscv_xlen))
#define ISA_PREFIX_LEN (sizeof(ISA_PREFIX) - 1)
static __inline int
parse_ext_s(char *isa, int idx, int len)
{
/*
* Proceed to the next multi-letter extension or the end of the
* string.
*
* TODO: parse these once we gain support
*/
while (isa[idx] != '_' && idx < len) {
idx++;
}
return (idx);
}
static __inline int
parse_ext_x(char *isa, int idx, int len)
{
/*
* Proceed to the next multi-letter extension or the end of the
* string.
*/
while (isa[idx] != '_' && idx < len) {
idx++;
}
return (idx);
}
static __inline int
parse_ext_z(char *isa, int idx, int len)
{
/*
* Proceed to the next multi-letter extension or the end of the
* string.
*
* TODO: parse some of these.
*/
while (isa[idx] != '_' && idx < len) {
idx++;
}
return (idx);
}
static __inline int
parse_ext_version(char *isa, int idx, u_int *majorp __unused,
u_int *minorp __unused)
{
/* Major version. */
while (isdigit(isa[idx]))
idx++;
if (isa[idx] != 'p')
return (idx);
else
idx++;
/* Minor version. */
while (isdigit(isa[idx]))
idx++;
return (idx);
}
/*
* Parse the ISA string, building up the set of HWCAP bits as they are found.
*/
static void
parse_riscv_isa(char *isa, int len, u_long *hwcapp)
{
u_long hwcap;
int i;
hwcap = 0;
i = ISA_PREFIX_LEN;
while (i < len) {
switch(isa[i]) {
case 'a':
case 'c':
-#ifdef FPE
case 'd':
case 'f':
-#endif
case 'i':
case 'm':
hwcap |= HWCAP_ISA_BIT(isa[i]);
i++;
break;
case 'g':
hwcap |= HWCAP_ISA_G;
i++;
break;
case 's':
/*
* XXX: older versions of this string erroneously
* indicated supervisor and user mode support as
* single-letter extensions. Detect and skip both 's'
* and 'u'.
*/
if (isa[i - 1] != '_' && isa[i + 1] == 'u') {
i += 2;
continue;
}
/*
* Supervisor-level extension namespace.
*/
i = parse_ext_s(isa, i, len);
break;
case 'x':
/*
* Custom extension namespace. For now, we ignore
* these.
*/
i = parse_ext_x(isa, i, len);
break;
case 'z':
/*
* Multi-letter standard extension namespace.
*/
i = parse_ext_z(isa, i, len);
break;
case '_':
i++;
continue;
default:
/* Unrecognized/unsupported. */
i++;
break;
}
i = parse_ext_version(isa, i, NULL, NULL);
}
if (hwcapp != NULL)
*hwcapp = hwcap;
}
#ifdef FDT
static void
fill_elf_hwcap(void *dummy __unused)
{
char isa[1024];
u_long hwcap;
phandle_t node;
ssize_t len;
node = OF_finddevice("/cpus");
if (node == -1) {
if (bootverbose)
printf("fill_elf_hwcap: Can't find cpus node\n");
return;
}
/*
* Iterate through the CPUs and examine their ISA string. While we
* could assign elf_hwcap to be whatever the boot CPU supports, to
* handle the (unusual) case of running a system with hetergeneous
* ISAs, keep only the extension bits that are common to all harts.
*/
for (node = OF_child(node); node > 0; node = OF_peer(node)) {
/* Skip any non-CPU nodes, such as cpu-map. */
if (!ofw_bus_node_is_compatible(node, "riscv"))
continue;
len = OF_getprop(node, "riscv,isa", isa, sizeof(isa));
KASSERT(len <= sizeof(isa), ("ISA string truncated"));
if (len == -1) {
if (bootverbose)
printf("fill_elf_hwcap: "
"Can't find riscv,isa property\n");
return;
} else if (strncmp(isa, ISA_PREFIX, ISA_PREFIX_LEN) != 0) {
if (bootverbose)
printf("fill_elf_hwcap: "
"Unsupported ISA string: %s\n", isa);
return;
}
/*
* The string is specified to be lowercase, but let's be
* certain.
*/
for (int i = 0; i < len; i++)
isa[i] = tolower(isa[i]);
parse_riscv_isa(isa, len, &hwcap);
if (elf_hwcap != 0)
elf_hwcap &= hwcap;
else
elf_hwcap = hwcap;
}
}
SYSINIT(identcpu, SI_SUB_CPU, SI_ORDER_ANY, fill_elf_hwcap, NULL);
#endif
void
identify_cpu(void)
{
const struct cpu_parts *cpu_partsp;
uint32_t part_id;
uint32_t impl_id;
uint64_t misa;
u_int cpu;
size_t i;
cpu_partsp = NULL;
/* TODO: can we get misa somewhere ? */
misa = 0;
cpu = PCPU_GET(cpuid);
impl_id = CPU_IMPL(mimpid);
for (i = 0; i < nitems(cpu_implementers); i++) {
if (impl_id == cpu_implementers[i].impl_id ||
cpu_implementers[i].impl_id == 0) {
cpu_desc[cpu].cpu_impl = impl_id;
cpu_desc[cpu].cpu_impl_name = cpu_implementers[i].impl_name;
cpu_partsp = cpu_parts_std;
break;
}
}
part_id = CPU_PART(misa);
for (i = 0; &cpu_partsp[i] != NULL; i++) {
if (part_id == cpu_partsp[i].part_id ||
cpu_partsp[i].part_id == -1) {
cpu_desc[cpu].cpu_part_num = part_id;
cpu_desc[cpu].cpu_part_name = cpu_partsp[i].part_name;
break;
}
}
/* Print details for boot CPU or if we want verbose output */
if (cpu == 0 || bootverbose) {
printf("CPU(%d): %s %s\n", cpu,
cpu_desc[cpu].cpu_impl_name,
cpu_desc[cpu].cpu_part_name);
}
}
diff --git a/sys/riscv/riscv/machdep.c b/sys/riscv/riscv/machdep.c
index 0821a29d11c1..6b8dcb647162 100644
--- a/sys/riscv/riscv/machdep.c
+++ b/sys/riscv/riscv/machdep.c
@@ -1,599 +1,596 @@
/*-
* Copyright (c) 2014 Andrew Turner
* Copyright (c) 2015-2017 Ruslan Bukin
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
* University of Cambridge Computer Laboratory under DARPA/AFRL contract
* FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
*
* Portions of this software were developed by the University of Cambridge
* Computer Laboratory as part of the CTSRD Project, with support from the
* UK Higher Education Innovation Fund (HEIF).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "opt_platform.h"
#include
__FBSDID("$FreeBSD$");
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
-#ifdef FPE
-#include
-#endif
-
#ifdef FDT
#include
#include
#include
#endif
struct pcpu __pcpu[MAXCPU];
static struct trapframe proc0_tf;
int early_boot = 1;
int cold = 1;
#define DTB_SIZE_MAX (1024 * 1024)
struct kva_md_info kmi;
int64_t dcache_line_size; /* The minimum D cache line size */
int64_t icache_line_size; /* The minimum I cache line size */
int64_t idcache_line_size; /* The minimum cache line size */
#define BOOT_HART_INVALID 0xffffffff
uint32_t boot_hart = BOOT_HART_INVALID; /* The hart we booted on. */
cpuset_t all_harts;
extern int *end;
static char static_kenv[PAGE_SIZE];
static void
cpu_startup(void *dummy)
{
sbi_print_version();
identify_cpu();
printf("real memory = %ju (%ju MB)\n", ptoa((uintmax_t)realmem),
ptoa((uintmax_t)realmem) / (1024 * 1024));
/*
* Display any holes after the first chunk of extended memory.
*/
if (bootverbose) {
int indx;
printf("Physical memory chunk(s):\n");
for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) {
vm_paddr_t size;
size = phys_avail[indx + 1] - phys_avail[indx];
printf(
"0x%016jx - 0x%016jx, %ju bytes (%ju pages)\n",
(uintmax_t)phys_avail[indx],
(uintmax_t)phys_avail[indx + 1] - 1,
(uintmax_t)size, (uintmax_t)size / PAGE_SIZE);
}
}
vm_ksubmap_init(&kmi);
printf("avail memory = %ju (%ju MB)\n",
ptoa((uintmax_t)vm_free_count()),
ptoa((uintmax_t)vm_free_count()) / (1024 * 1024));
if (bootverbose)
devmap_print_table();
bufinit();
vm_pager_bufferinit();
}
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
int
cpu_idle_wakeup(int cpu)
{
return (0);
}
void
cpu_idle(int busy)
{
spinlock_enter();
if (!busy)
cpu_idleclock();
if (!sched_runnable())
__asm __volatile(
"fence \n"
"wfi \n");
if (!busy)
cpu_activeclock();
spinlock_exit();
}
void
cpu_halt(void)
{
/*
* Try to power down using the HSM SBI extension and fall back to a
* simple wfi loop.
*/
intr_disable();
if (sbi_probe_extension(SBI_EXT_ID_HSM) != 0)
sbi_hsm_hart_stop();
for (;;)
__asm __volatile("wfi");
/* NOTREACHED */
}
/*
* Flush the D-cache for non-DMA I/O so that the I-cache can
* be made coherent later.
*/
void
cpu_flush_dcache(void *ptr, size_t len)
{
/* TBD */
}
/* Get current clock frequency for the given CPU ID. */
int
cpu_est_clockrate(int cpu_id, uint64_t *rate)
{
panic("cpu_est_clockrate");
}
void
cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size)
{
}
void
spinlock_enter(void)
{
struct thread *td;
register_t reg;
td = curthread;
if (td->td_md.md_spinlock_count == 0) {
reg = intr_disable();
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_sstatus_ie = reg;
critical_enter();
} else
td->td_md.md_spinlock_count++;
}
void
spinlock_exit(void)
{
struct thread *td;
register_t sstatus_ie;
td = curthread;
sstatus_ie = td->td_md.md_saved_sstatus_ie;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0) {
critical_exit();
intr_restore(sstatus_ie);
}
}
/*
* Construct a PCB from a trapframe. This is called from kdb_trap() where
* we want to start a backtrace from the function that caused us to enter
* the debugger. We have the context in the trapframe, but base the trace
* on the PCB. The PCB doesn't have to be perfect, as long as it contains
* enough for a backtrace.
*/
void
makectx(struct trapframe *tf, struct pcb *pcb)
{
memcpy(pcb->pcb_s, tf->tf_s, sizeof(tf->tf_s));
pcb->pcb_ra = tf->tf_sepc;
pcb->pcb_sp = tf->tf_sp;
pcb->pcb_gp = tf->tf_gp;
pcb->pcb_tp = tf->tf_tp;
}
static void
init_proc0(vm_offset_t kstack)
{
struct pcpu *pcpup;
pcpup = &__pcpu[0];
proc_linkup0(&proc0, &thread0);
thread0.td_kstack = kstack;
thread0.td_kstack_pages = kstack_pages;
thread0.td_pcb = (struct pcb *)(thread0.td_kstack +
thread0.td_kstack_pages * PAGE_SIZE) - 1;
thread0.td_pcb->pcb_fpflags = 0;
thread0.td_frame = &proc0_tf;
pcpup->pc_curpcb = thread0.td_pcb;
}
#ifdef FDT
static void
try_load_dtb(caddr_t kmdp)
{
vm_offset_t dtbp;
dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t);
#if defined(FDT_DTB_STATIC)
/*
* In case the device tree blob was not retrieved (from metadata) try
* to use the statically embedded one.
*/
if (dtbp == (vm_offset_t)NULL)
dtbp = (vm_offset_t)&fdt_static_dtb;
#endif
if (dtbp == (vm_offset_t)NULL) {
printf("ERROR loading DTB\n");
return;
}
if (OF_install(OFW_FDT, 0) == FALSE)
panic("Cannot install FDT");
if (OF_init((void *)dtbp) != 0)
panic("OF_init failed with the found device tree");
}
#endif
static void
cache_setup(void)
{
/* TODO */
dcache_line_size = 0;
icache_line_size = 0;
idcache_line_size = 0;
}
/*
* Fake up a boot descriptor table.
*/
static void
fake_preload_metadata(struct riscv_bootparams *rvbp)
{
static uint32_t fake_preload[48];
vm_offset_t lastaddr;
size_t fake_size, dtb_size;
#define PRELOAD_PUSH_VALUE(type, value) do { \
*(type *)((char *)fake_preload + fake_size) = (value); \
fake_size += sizeof(type); \
} while (0)
#define PRELOAD_PUSH_STRING(str) do { \
uint32_t ssize; \
ssize = strlen(str) + 1; \
PRELOAD_PUSH_VALUE(uint32_t, ssize); \
strcpy(((char *)fake_preload + fake_size), str); \
fake_size += ssize; \
fake_size = roundup(fake_size, sizeof(u_long)); \
} while (0)
fake_size = 0;
lastaddr = (vm_offset_t)&end;
PRELOAD_PUSH_VALUE(uint32_t, MODINFO_NAME);
PRELOAD_PUSH_STRING("kernel");
PRELOAD_PUSH_VALUE(uint32_t, MODINFO_TYPE);
PRELOAD_PUSH_STRING("elf kernel");
PRELOAD_PUSH_VALUE(uint32_t, MODINFO_ADDR);
PRELOAD_PUSH_VALUE(uint32_t, sizeof(vm_offset_t));
PRELOAD_PUSH_VALUE(uint64_t, KERNBASE);
PRELOAD_PUSH_VALUE(uint32_t, MODINFO_SIZE);
PRELOAD_PUSH_VALUE(uint32_t, sizeof(size_t));
PRELOAD_PUSH_VALUE(uint64_t, (size_t)((vm_offset_t)&end - KERNBASE));
/* Copy the DTB to KVA space. */
lastaddr = roundup(lastaddr, sizeof(int));
PRELOAD_PUSH_VALUE(uint32_t, MODINFO_METADATA | MODINFOMD_DTBP);
PRELOAD_PUSH_VALUE(uint32_t, sizeof(vm_offset_t));
PRELOAD_PUSH_VALUE(vm_offset_t, lastaddr);
dtb_size = fdt_totalsize(rvbp->dtbp_virt);
memmove((void *)lastaddr, (const void *)rvbp->dtbp_virt, dtb_size);
lastaddr = roundup(lastaddr + dtb_size, sizeof(int));
PRELOAD_PUSH_VALUE(uint32_t, MODINFO_METADATA | MODINFOMD_KERNEND);
PRELOAD_PUSH_VALUE(uint32_t, sizeof(vm_offset_t));
PRELOAD_PUSH_VALUE(vm_offset_t, lastaddr);
PRELOAD_PUSH_VALUE(uint32_t, MODINFO_METADATA | MODINFOMD_HOWTO);
PRELOAD_PUSH_VALUE(uint32_t, sizeof(int));
PRELOAD_PUSH_VALUE(int, RB_VERBOSE);
/* End marker */
PRELOAD_PUSH_VALUE(uint32_t, 0);
PRELOAD_PUSH_VALUE(uint32_t, 0);
preload_metadata = (caddr_t)fake_preload;
/* Check if bootloader clobbered part of the kernel with the DTB. */
KASSERT(rvbp->dtbp_phys + dtb_size <= rvbp->kern_phys ||
rvbp->dtbp_phys >= rvbp->kern_phys + (lastaddr - KERNBASE),
("FDT (%lx-%lx) and kernel (%lx-%lx) overlap", rvbp->dtbp_phys,
rvbp->dtbp_phys + dtb_size, rvbp->kern_phys,
rvbp->kern_phys + (lastaddr - KERNBASE)));
KASSERT(fake_size < sizeof(fake_preload),
("Too many fake_preload items"));
if (boothowto & RB_VERBOSE)
printf("FDT phys (%lx-%lx), kernel phys (%lx-%lx)\n",
rvbp->dtbp_phys, rvbp->dtbp_phys + dtb_size,
rvbp->kern_phys, rvbp->kern_phys + (lastaddr - KERNBASE));
}
/* Support for FDT configurations only. */
CTASSERT(FDT);
#ifdef FDT
static void
parse_fdt_bootargs(void)
{
char bootargs[512];
bootargs[sizeof(bootargs) - 1] = '\0';
if (fdt_get_chosen_bootargs(bootargs, sizeof(bootargs) - 1) == 0) {
boothowto |= boot_parse_cmdline(bootargs);
}
}
#endif
static vm_offset_t
parse_metadata(void)
{
caddr_t kmdp;
vm_offset_t lastaddr;
#ifdef DDB
vm_offset_t ksym_start, ksym_end;
#endif
char *kern_envp;
/* Find the kernel address */
kmdp = preload_search_by_type("elf kernel");
if (kmdp == NULL)
kmdp = preload_search_by_type("elf64 kernel");
KASSERT(kmdp != NULL, ("No preload metadata found!"));
/* Read the boot metadata */
boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
if (kern_envp != NULL)
init_static_kenv(kern_envp, 0);
else
init_static_kenv(static_kenv, sizeof(static_kenv));
#ifdef DDB
ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
db_fetch_ksymtab(ksym_start, ksym_end);
#endif
#ifdef FDT
try_load_dtb(kmdp);
if (kern_envp == NULL)
parse_fdt_bootargs();
#endif
return (lastaddr);
}
void
initriscv(struct riscv_bootparams *rvbp)
{
struct mem_region mem_regions[FDT_MEM_REGIONS];
struct pcpu *pcpup;
int mem_regions_sz;
vm_offset_t lastaddr;
vm_size_t kernlen;
#ifdef FDT
phandle_t chosen;
uint32_t hart;
#endif
char *env;
TSRAW(&thread0, TS_ENTER, __func__, NULL);
/* Set the pcpu data, this is needed by pmap_bootstrap */
pcpup = &__pcpu[0];
pcpu_init(pcpup, 0, sizeof(struct pcpu));
/* Set the pcpu pointer */
__asm __volatile("mv tp, %0" :: "r"(pcpup));
PCPU_SET(curthread, &thread0);
/* Initialize SBI interface. */
sbi_init();
/* Parse the boot metadata. */
if (rvbp->modulep != 0) {
preload_metadata = (caddr_t)rvbp->modulep;
} else {
fake_preload_metadata(rvbp);
}
lastaddr = parse_metadata();
#ifdef FDT
/*
* Look for the boot hart ID. This was either passed in directly from
* the SBI firmware and handled by locore, or was stored in the device
* tree by an earlier boot stage.
*/
chosen = OF_finddevice("/chosen");
if (OF_getencprop(chosen, "boot-hartid", &hart, sizeof(hart)) != -1) {
boot_hart = hart;
}
#endif
if (boot_hart == BOOT_HART_INVALID) {
panic("Boot hart ID was not properly set");
}
pcpup->pc_hart = boot_hart;
#ifdef FDT
/*
* Exclude reserved memory specified by the device tree. Typically,
* this contains an entry for memory used by the runtime SBI firmware.
*/
if (fdt_get_reserved_mem(mem_regions, &mem_regions_sz) == 0) {
physmem_exclude_regions(mem_regions, mem_regions_sz,
EXFLAG_NODUMP | EXFLAG_NOALLOC);
}
/* Grab physical memory regions information from device tree. */
if (fdt_get_mem_regions(mem_regions, &mem_regions_sz, NULL) != 0) {
panic("Cannot get physical memory regions");
}
physmem_hardware_regions(mem_regions, mem_regions_sz);
#endif
/* Do basic tuning, hz etc */
init_param1();
cache_setup();
/* Bootstrap enough of pmap to enter the kernel proper */
kernlen = (lastaddr - KERNBASE);
pmap_bootstrap(rvbp->kern_l1pt, rvbp->kern_phys, kernlen);
#ifdef FDT
/*
* XXX: Unconditionally exclude the lowest 2MB of physical memory, as
* this area is assumed to contain the SBI firmware. This is a little
* fragile, but it is consistent with the platforms we support so far.
*
* TODO: remove this when the all regular booting methods properly
* report their reserved memory in the device tree.
*/
physmem_exclude_region(mem_regions[0].mr_start, L2_SIZE,
EXFLAG_NODUMP | EXFLAG_NOALLOC);
#endif
physmem_init_kernel_globals();
/* Establish static device mappings */
devmap_bootstrap(0, NULL);
cninit();
/*
* Dump the boot metadata. We have to wait for cninit() since console
* output is required. If it's grossly incorrect the kernel will never
* make it this far.
*/
if (getenv_is_true("debug.dump_modinfo_at_boot"))
preload_dump();
init_proc0(rvbp->kern_stack);
msgbufinit(msgbufp, msgbufsize);
mutex_init();
init_param2(physmem);
kdb_init();
#ifdef KDB
if ((boothowto & RB_KDB) != 0)
kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
#endif
env = kern_getenv("kernelname");
if (env != NULL)
strlcpy(kernelname, env, sizeof(kernelname));
if (boothowto & RB_VERBOSE)
physmem_print_tables();
early_boot = 0;
TSEXIT();
}
diff --git a/sys/riscv/riscv/swtch.S b/sys/riscv/riscv/swtch.S
index d2e23784c994..5b878ae2fb30 100644
--- a/sys/riscv/riscv/swtch.S
+++ b/sys/riscv/riscv/swtch.S
@@ -1,473 +1,461 @@
/*-
* Copyright (c) 2015-2017 Ruslan Bukin
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
* University of Cambridge Computer Laboratory under DARPA/AFRL contract
* FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
*
* Portions of this software were developed by the University of Cambridge
* Computer Laboratory as part of the CTSRD Project, with support from the
* UK Higher Education Innovation Fund (HEIF).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "assym.inc"
#include "opt_sched.h"
#include
#include
#include
#include
__FBSDID("$FreeBSD$");
-#ifdef FPE
.macro __fpe_state_save p
/*
* Enable FPE usage in supervisor mode,
* so we can access registers.
*/
li t0, SSTATUS_FS_INITIAL
csrs sstatus, t0
/* Store registers */
frcsr t0
sd t0, (PCB_FCSR)(\p)
fsd f0, (PCB_X + 0 * 16)(\p)
fsd f1, (PCB_X + 1 * 16)(\p)
fsd f2, (PCB_X + 2 * 16)(\p)
fsd f3, (PCB_X + 3 * 16)(\p)
fsd f4, (PCB_X + 4 * 16)(\p)
fsd f5, (PCB_X + 5 * 16)(\p)
fsd f6, (PCB_X + 6 * 16)(\p)
fsd f7, (PCB_X + 7 * 16)(\p)
fsd f8, (PCB_X + 8 * 16)(\p)
fsd f9, (PCB_X + 9 * 16)(\p)
fsd f10, (PCB_X + 10 * 16)(\p)
fsd f11, (PCB_X + 11 * 16)(\p)
fsd f12, (PCB_X + 12 * 16)(\p)
fsd f13, (PCB_X + 13 * 16)(\p)
fsd f14, (PCB_X + 14 * 16)(\p)
fsd f15, (PCB_X + 15 * 16)(\p)
fsd f16, (PCB_X + 16 * 16)(\p)
fsd f17, (PCB_X + 17 * 16)(\p)
fsd f18, (PCB_X + 18 * 16)(\p)
fsd f19, (PCB_X + 19 * 16)(\p)
fsd f20, (PCB_X + 20 * 16)(\p)
fsd f21, (PCB_X + 21 * 16)(\p)
fsd f22, (PCB_X + 22 * 16)(\p)
fsd f23, (PCB_X + 23 * 16)(\p)
fsd f24, (PCB_X + 24 * 16)(\p)
fsd f25, (PCB_X + 25 * 16)(\p)
fsd f26, (PCB_X + 26 * 16)(\p)
fsd f27, (PCB_X + 27 * 16)(\p)
fsd f28, (PCB_X + 28 * 16)(\p)
fsd f29, (PCB_X + 29 * 16)(\p)
fsd f30, (PCB_X + 30 * 16)(\p)
fsd f31, (PCB_X + 31 * 16)(\p)
/* Disable FPE usage in supervisor mode. */
li t0, SSTATUS_FS_MASK
csrc sstatus, t0
.endm
.macro __fpe_state_load p
/*
* Enable FPE usage in supervisor mode,
* so we can access registers.
*/
li t0, SSTATUS_FS_INITIAL
csrs sstatus, t0
/* Restore registers */
ld t0, (PCB_FCSR)(\p)
fscsr t0
fld f0, (PCB_X + 0 * 16)(\p)
fld f1, (PCB_X + 1 * 16)(\p)
fld f2, (PCB_X + 2 * 16)(\p)
fld f3, (PCB_X + 3 * 16)(\p)
fld f4, (PCB_X + 4 * 16)(\p)
fld f5, (PCB_X + 5 * 16)(\p)
fld f6, (PCB_X + 6 * 16)(\p)
fld f7, (PCB_X + 7 * 16)(\p)
fld f8, (PCB_X + 8 * 16)(\p)
fld f9, (PCB_X + 9 * 16)(\p)
fld f10, (PCB_X + 10 * 16)(\p)
fld f11, (PCB_X + 11 * 16)(\p)
fld f12, (PCB_X + 12 * 16)(\p)
fld f13, (PCB_X + 13 * 16)(\p)
fld f14, (PCB_X + 14 * 16)(\p)
fld f15, (PCB_X + 15 * 16)(\p)
fld f16, (PCB_X + 16 * 16)(\p)
fld f17, (PCB_X + 17 * 16)(\p)
fld f18, (PCB_X + 18 * 16)(\p)
fld f19, (PCB_X + 19 * 16)(\p)
fld f20, (PCB_X + 20 * 16)(\p)
fld f21, (PCB_X + 21 * 16)(\p)
fld f22, (PCB_X + 22 * 16)(\p)
fld f23, (PCB_X + 23 * 16)(\p)
fld f24, (PCB_X + 24 * 16)(\p)
fld f25, (PCB_X + 25 * 16)(\p)
fld f26, (PCB_X + 26 * 16)(\p)
fld f27, (PCB_X + 27 * 16)(\p)
fld f28, (PCB_X + 28 * 16)(\p)
fld f29, (PCB_X + 29 * 16)(\p)
fld f30, (PCB_X + 30 * 16)(\p)
fld f31, (PCB_X + 31 * 16)(\p)
/* Disable FPE usage in supervisor mode. */
li t0, SSTATUS_FS_MASK
csrc sstatus, t0
.endm
/*
* void
* fpe_state_save(struct thread *td)
*/
ENTRY(fpe_state_save)
/* Get pointer to PCB */
ld a0, TD_PCB(a0)
__fpe_state_save a0
ret
END(fpe_state_save)
/*
* void
* fpe_state_clear(void)
*/
ENTRY(fpe_state_clear)
/*
* Enable FPE usage in supervisor mode,
* so we can access registers.
*/
li t0, SSTATUS_FS_INITIAL
csrs sstatus, t0
fscsr zero
fcvt.d.l f0, zero
fcvt.d.l f1, zero
fcvt.d.l f2, zero
fcvt.d.l f3, zero
fcvt.d.l f4, zero
fcvt.d.l f5, zero
fcvt.d.l f6, zero
fcvt.d.l f7, zero
fcvt.d.l f8, zero
fcvt.d.l f9, zero
fcvt.d.l f10, zero
fcvt.d.l f11, zero
fcvt.d.l f12, zero
fcvt.d.l f13, zero
fcvt.d.l f14, zero
fcvt.d.l f15, zero
fcvt.d.l f16, zero
fcvt.d.l f17, zero
fcvt.d.l f18, zero
fcvt.d.l f19, zero
fcvt.d.l f20, zero
fcvt.d.l f21, zero
fcvt.d.l f22, zero
fcvt.d.l f23, zero
fcvt.d.l f24, zero
fcvt.d.l f25, zero
fcvt.d.l f26, zero
fcvt.d.l f27, zero
fcvt.d.l f28, zero
fcvt.d.l f29, zero
fcvt.d.l f30, zero
fcvt.d.l f31, zero
/* Disable FPE usage in supervisor mode. */
li t0, SSTATUS_FS_MASK
csrc sstatus, t0
ret
END(fpe_state_clear)
-#endif /* FPE */
-
+
/*
* void cpu_throw(struct thread *old __unused, struct thread *new)
*/
ENTRY(cpu_throw)
/* Activate the new thread's pmap. */
mv s0, a1
mv a0, a1
call _C_LABEL(pmap_activate_sw)
mv a0, s0
/* Store the new curthread */
sd a0, PC_CURTHREAD(tp)
/* And the new pcb */
ld x13, TD_PCB(a0)
sd x13, PC_CURPCB(tp)
/* Load registers */
ld ra, (PCB_RA)(x13)
ld sp, (PCB_SP)(x13)
/* s[0-11] */
ld s0, (PCB_S + 0 * 8)(x13)
ld s1, (PCB_S + 1 * 8)(x13)
ld s2, (PCB_S + 2 * 8)(x13)
ld s3, (PCB_S + 3 * 8)(x13)
ld s4, (PCB_S + 4 * 8)(x13)
ld s5, (PCB_S + 5 * 8)(x13)
ld s6, (PCB_S + 6 * 8)(x13)
ld s7, (PCB_S + 7 * 8)(x13)
ld s8, (PCB_S + 8 * 8)(x13)
ld s9, (PCB_S + 9 * 8)(x13)
ld s10, (PCB_S + 10 * 8)(x13)
ld s11, (PCB_S + 11 * 8)(x13)
-#ifdef FPE
/* Is FPE enabled for new thread? */
ld t0, TD_FRAME(a0)
ld t1, (TF_SSTATUS)(t0)
li t2, SSTATUS_FS_MASK
and t3, t1, t2
beqz t3, 1f /* No, skip. */
/* Restore registers. */
__fpe_state_load x13
1:
-#endif
-
ret
END(cpu_throw)
/*
* void cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx)
*
* a0 = old
* a1 = new
* a2 = mtx
* x3 to x7, x16 and x17 are caller saved
*/
ENTRY(cpu_switch)
/* Store the new curthread */
sd a1, PC_CURTHREAD(tp)
/* And the new pcb */
ld x13, TD_PCB(a1)
sd x13, PC_CURPCB(tp)
/* Save the old context. */
ld x13, TD_PCB(a0)
/* Store ra, sp and the callee-saved registers */
sd ra, (PCB_RA)(x13)
sd sp, (PCB_SP)(x13)
/* s[0-11] */
sd s0, (PCB_S + 0 * 8)(x13)
sd s1, (PCB_S + 1 * 8)(x13)
sd s2, (PCB_S + 2 * 8)(x13)
sd s3, (PCB_S + 3 * 8)(x13)
sd s4, (PCB_S + 4 * 8)(x13)
sd s5, (PCB_S + 5 * 8)(x13)
sd s6, (PCB_S + 6 * 8)(x13)
sd s7, (PCB_S + 7 * 8)(x13)
sd s8, (PCB_S + 8 * 8)(x13)
sd s9, (PCB_S + 9 * 8)(x13)
sd s10, (PCB_S + 10 * 8)(x13)
sd s11, (PCB_S + 11 * 8)(x13)
-#ifdef FPE
/*
* Is FPE enabled and is it in dirty state
* for the old thread?
*/
ld t0, TD_FRAME(a0)
ld t1, (TF_SSTATUS)(t0)
li t2, SSTATUS_FS_MASK
and t3, t1, t2
li t2, SSTATUS_FS_DIRTY
bne t3, t2, 1f /* No, skip. */
/* Yes, mark FPE state clean and save registers. */
li t2, ~SSTATUS_FS_MASK
and t3, t1, t2
li t2, SSTATUS_FS_CLEAN
or t3, t3, t2
sd t3, (TF_SSTATUS)(t0)
__fpe_state_save x13
1:
-#endif
/* Activate the new thread's pmap */
mv s0, a0
mv s1, a1
mv s2, a2
mv a0, a1
call _C_LABEL(pmap_activate_sw)
mv a1, s1
/* Release the old thread */
sd s2, TD_LOCK(s0)
#if defined(SCHED_ULE) && defined(SMP)
/* Spin if TD_LOCK points to a blocked_lock */
la s2, _C_LABEL(blocked_lock)
1:
ld t0, TD_LOCK(a1)
beq t0, s2, 1b
#endif
/*
* Restore the saved context.
*/
ld x13, TD_PCB(a1)
/* Restore the registers */
ld ra, (PCB_RA)(x13)
ld sp, (PCB_SP)(x13)
/* s[0-11] */
ld s0, (PCB_S + 0 * 8)(x13)
ld s1, (PCB_S + 1 * 8)(x13)
ld s2, (PCB_S + 2 * 8)(x13)
ld s3, (PCB_S + 3 * 8)(x13)
ld s4, (PCB_S + 4 * 8)(x13)
ld s5, (PCB_S + 5 * 8)(x13)
ld s6, (PCB_S + 6 * 8)(x13)
ld s7, (PCB_S + 7 * 8)(x13)
ld s8, (PCB_S + 8 * 8)(x13)
ld s9, (PCB_S + 9 * 8)(x13)
ld s10, (PCB_S + 10 * 8)(x13)
ld s11, (PCB_S + 11 * 8)(x13)
-#ifdef FPE
/* Is FPE enabled for new thread? */
ld t0, TD_FRAME(a1)
ld t1, (TF_SSTATUS)(t0)
li t2, SSTATUS_FS_MASK
and t3, t1, t2
beqz t3, 1f /* No, skip. */
/* Restore registers. */
__fpe_state_load x13
1:
-#endif
-
ret
END(cpu_switch)
/*
* fork_exit(void (*callout)(void *, struct trapframe *), void *arg,
* struct trapframe *frame)
*/
ENTRY(fork_trampoline)
mv a0, s0
mv a1, s1
mv a2, sp
call _C_LABEL(fork_exit)
/* Restore sstatus */
ld t0, (TF_SSTATUS)(sp)
/* Ensure interrupts disabled */
li t1, ~SSTATUS_SIE
and t0, t0, t1
csrw sstatus, t0
/* Restore exception program counter */
ld t0, (TF_SEPC)(sp)
csrw sepc, t0
/* Restore the registers */
ld t0, (TF_T + 0 * 8)(sp)
ld t1, (TF_T + 1 * 8)(sp)
ld t2, (TF_T + 2 * 8)(sp)
ld t3, (TF_T + 3 * 8)(sp)
ld t4, (TF_T + 4 * 8)(sp)
ld t5, (TF_T + 5 * 8)(sp)
ld t6, (TF_T + 6 * 8)(sp)
ld s0, (TF_S + 0 * 8)(sp)
ld s1, (TF_S + 1 * 8)(sp)
ld s2, (TF_S + 2 * 8)(sp)
ld s3, (TF_S + 3 * 8)(sp)
ld s4, (TF_S + 4 * 8)(sp)
ld s5, (TF_S + 5 * 8)(sp)
ld s6, (TF_S + 6 * 8)(sp)
ld s7, (TF_S + 7 * 8)(sp)
ld s8, (TF_S + 8 * 8)(sp)
ld s9, (TF_S + 9 * 8)(sp)
ld s10, (TF_S + 10 * 8)(sp)
ld s11, (TF_S + 11 * 8)(sp)
ld a0, (TF_A + 0 * 8)(sp)
ld a1, (TF_A + 1 * 8)(sp)
ld a2, (TF_A + 2 * 8)(sp)
ld a3, (TF_A + 3 * 8)(sp)
ld a4, (TF_A + 4 * 8)(sp)
ld a5, (TF_A + 5 * 8)(sp)
ld a6, (TF_A + 6 * 8)(sp)
ld a7, (TF_A + 7 * 8)(sp)
/* Load user ra and gp */
ld ra, (TF_RA)(sp)
ld gp, (TF_GP)(sp)
/*
* Store our pcpup on stack, we will load it back
* on kernel mode trap.
*/
sd tp, (TF_SIZE)(sp)
ld tp, (TF_TP)(sp)
/* Save kernel stack so we can use it doing a user trap */
addi sp, sp, TF_SIZE
csrw sscratch, sp
/* Load user stack */
ld sp, (TF_SP - TF_SIZE)(sp)
sret
END(fork_trampoline)
ENTRY(savectx)
/* Store ra, sp and the callee-saved registers */
sd ra, (PCB_RA)(a0)
sd sp, (PCB_SP)(a0)
sd tp, (PCB_TP)(a0)
sd gp, (PCB_GP)(a0)
/* s[0-11] */
sd s0, (PCB_S + 0 * 8)(a0)
sd s1, (PCB_S + 1 * 8)(a0)
sd s2, (PCB_S + 2 * 8)(a0)
sd s3, (PCB_S + 3 * 8)(a0)
sd s4, (PCB_S + 4 * 8)(a0)
sd s5, (PCB_S + 5 * 8)(a0)
sd s6, (PCB_S + 6 * 8)(a0)
sd s7, (PCB_S + 7 * 8)(a0)
sd s8, (PCB_S + 8 * 8)(a0)
sd s9, (PCB_S + 9 * 8)(a0)
sd s10, (PCB_S + 10 * 8)(a0)
sd s11, (PCB_S + 11 * 8)(a0)
-#ifdef FPE
__fpe_state_save a0
-#endif
ret
END(savectx)
diff --git a/sys/riscv/riscv/trap.c b/sys/riscv/riscv/trap.c
index 39e0fbb1d5bd..11ecfa702054 100644
--- a/sys/riscv/riscv/trap.c
+++ b/sys/riscv/riscv/trap.c
@@ -1,425 +1,421 @@
/*-
* Copyright (c) 2015-2018 Ruslan Bukin
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
* University of Cambridge Computer Laboratory under DARPA/AFRL contract
* FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
*
* Portions of this software were developed by the University of Cambridge
* Computer Laboratory as part of the CTSRD Project, with support from the
* UK Higher Education Innovation Fund (HEIF).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include
__FBSDID("$FreeBSD$");
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef KDB
#include
#endif
#include
#include
#include
#include
#include
#include
-#ifdef FPE
#include
-#endif
#include
#include
#include
#include
#include
#ifdef KDTRACE_HOOKS
#include
#endif
int (*dtrace_invop_jump_addr)(struct trapframe *);
/* Called from exception.S */
void do_trap_supervisor(struct trapframe *);
void do_trap_user(struct trapframe *);
static __inline void
call_trapsignal(struct thread *td, int sig, int code, void *addr, int trapno)
{
ksiginfo_t ksi;
ksiginfo_init_trap(&ksi);
ksi.ksi_signo = sig;
ksi.ksi_code = code;
ksi.ksi_addr = addr;
ksi.ksi_trapno = trapno;
trapsignal(td, &ksi);
}
int
cpu_fetch_syscall_args(struct thread *td)
{
struct proc *p;
syscallarg_t *ap, *dst_ap;
struct syscall_args *sa;
p = td->td_proc;
sa = &td->td_sa;
ap = &td->td_frame->tf_a[0];
dst_ap = &sa->args[0];
sa->code = td->td_frame->tf_t[0];
sa->original_code = sa->code;
if (__predict_false(sa->code == SYS_syscall || sa->code == SYS___syscall)) {
sa->code = *ap++;
} else {
*dst_ap++ = *ap++;
}
if (__predict_false(sa->code >= p->p_sysent->sv_size))
sa->callp = &p->p_sysent->sv_table[0];
else
sa->callp = &p->p_sysent->sv_table[sa->code];
KASSERT(sa->callp->sy_narg <= nitems(sa->args),
("Syscall %d takes too many arguments", sa->code));
memcpy(dst_ap, ap, (NARGREG - 1) * sizeof(*dst_ap));
td->td_retval[0] = 0;
td->td_retval[1] = 0;
return (0);
}
#include "../../kern/subr_syscall.c"
static void
dump_regs(struct trapframe *frame)
{
int n;
int i;
n = nitems(frame->tf_t);
for (i = 0; i < n; i++)
printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]);
n = nitems(frame->tf_s);
for (i = 0; i < n; i++)
printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]);
n = nitems(frame->tf_a);
for (i = 0; i < n; i++)
printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]);
printf("ra == 0x%016lx\n", frame->tf_ra);
printf("sp == 0x%016lx\n", frame->tf_sp);
printf("gp == 0x%016lx\n", frame->tf_gp);
printf("tp == 0x%016lx\n", frame->tf_tp);
printf("sepc == 0x%016lx\n", frame->tf_sepc);
printf("sstatus == 0x%016lx\n", frame->tf_sstatus);
}
static void
ecall_handler(void)
{
struct thread *td;
td = curthread;
syscallenter(td);
syscallret(td);
}
static void
page_fault_handler(struct trapframe *frame, int usermode)
{
struct vm_map *map;
uint64_t stval;
struct thread *td;
struct pcb *pcb;
vm_prot_t ftype;
vm_offset_t va;
struct proc *p;
int error, sig, ucode;
#ifdef KDB
bool handled;
#endif
#ifdef KDB
if (kdb_active) {
kdb_reenter();
return;
}
#endif
td = curthread;
p = td->td_proc;
pcb = td->td_pcb;
stval = frame->tf_stval;
if (td->td_critnest != 0 || td->td_intr_nesting_level != 0 ||
WITNESS_CHECK(WARN_SLEEPOK | WARN_GIANTOK, NULL,
"Kernel page fault") != 0)
goto fatal;
if (usermode) {
if (!VIRT_IS_VALID(stval)) {
call_trapsignal(td, SIGSEGV, SEGV_MAPERR, (void *)stval,
frame->tf_scause & SCAUSE_CODE);
goto done;
}
map = &p->p_vmspace->vm_map;
} else {
/*
* Enable interrupts for the duration of the page fault. For
* user faults this was done already in do_trap_user().
*/
intr_enable();
if (stval >= VM_MIN_KERNEL_ADDRESS) {
map = kernel_map;
} else {
if (pcb->pcb_onfault == 0)
goto fatal;
map = &p->p_vmspace->vm_map;
}
}
va = trunc_page(stval);
if (frame->tf_scause == SCAUSE_STORE_PAGE_FAULT) {
ftype = VM_PROT_WRITE;
} else if (frame->tf_scause == SCAUSE_INST_PAGE_FAULT) {
ftype = VM_PROT_EXECUTE;
} else {
ftype = VM_PROT_READ;
}
if (VIRT_IS_VALID(va) && pmap_fault(map->pmap, va, ftype))
goto done;
error = vm_fault_trap(map, va, ftype, VM_FAULT_NORMAL, &sig, &ucode);
if (error != KERN_SUCCESS) {
if (usermode) {
call_trapsignal(td, sig, ucode, (void *)stval,
frame->tf_scause & SCAUSE_CODE);
} else {
if (pcb->pcb_onfault != 0) {
frame->tf_a[0] = error;
frame->tf_sepc = pcb->pcb_onfault;
return;
}
goto fatal;
}
}
done:
if (usermode)
userret(td, frame);
return;
fatal:
dump_regs(frame);
#ifdef KDB
if (debugger_on_trap) {
kdb_why = KDB_WHY_TRAP;
handled = kdb_trap(frame->tf_scause & SCAUSE_CODE, 0, frame);
kdb_why = KDB_WHY_UNSET;
if (handled)
return;
}
#endif
panic("Fatal page fault at %#lx: %#016lx", frame->tf_sepc, stval);
}
void
do_trap_supervisor(struct trapframe *frame)
{
uint64_t exception;
/* Ensure we came from supervisor mode, interrupts disabled */
KASSERT((csr_read(sstatus) & (SSTATUS_SPP | SSTATUS_SIE)) ==
SSTATUS_SPP, ("Came from S mode with interrupts enabled"));
KASSERT((csr_read(sstatus) & (SSTATUS_SUM)) == 0,
("Came from S mode with SUM enabled"));
exception = frame->tf_scause & SCAUSE_CODE;
if ((frame->tf_scause & SCAUSE_INTR) != 0) {
/* Interrupt */
riscv_cpu_intr(frame);
return;
}
#ifdef KDTRACE_HOOKS
if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
return;
#endif
CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p",
curthread, frame->tf_sepc, frame);
switch (exception) {
case SCAUSE_LOAD_ACCESS_FAULT:
case SCAUSE_STORE_ACCESS_FAULT:
case SCAUSE_INST_ACCESS_FAULT:
dump_regs(frame);
panic("Memory access exception at 0x%016lx\n", frame->tf_sepc);
break;
case SCAUSE_LOAD_MISALIGNED:
case SCAUSE_STORE_MISALIGNED:
case SCAUSE_INST_MISALIGNED:
dump_regs(frame);
panic("Misaligned address exception at %#016lx: %#016lx\n",
frame->tf_sepc, frame->tf_stval);
break;
case SCAUSE_STORE_PAGE_FAULT:
case SCAUSE_LOAD_PAGE_FAULT:
case SCAUSE_INST_PAGE_FAULT:
page_fault_handler(frame, 0);
break;
case SCAUSE_BREAKPOINT:
#ifdef KDTRACE_HOOKS
if (dtrace_invop_jump_addr != NULL &&
dtrace_invop_jump_addr(frame) == 0)
break;
#endif
#ifdef KDB
kdb_trap(exception, 0, frame);
#else
dump_regs(frame);
panic("No debugger in kernel.\n");
#endif
break;
case SCAUSE_ILLEGAL_INSTRUCTION:
dump_regs(frame);
panic("Illegal instruction at 0x%016lx\n", frame->tf_sepc);
break;
default:
dump_regs(frame);
panic("Unknown kernel exception %lx trap value %lx\n",
exception, frame->tf_stval);
}
}
void
do_trap_user(struct trapframe *frame)
{
uint64_t exception;
struct thread *td;
struct pcb *pcb;
td = curthread;
pcb = td->td_pcb;
KASSERT(td->td_frame == frame,
("%s: td_frame %p != frame %p", __func__, td->td_frame, frame));
/* Ensure we came from usermode, interrupts disabled */
KASSERT((csr_read(sstatus) & (SSTATUS_SPP | SSTATUS_SIE)) == 0,
("Came from U mode with interrupts enabled"));
KASSERT((csr_read(sstatus) & (SSTATUS_SUM)) == 0,
("Came from U mode with SUM enabled"));
exception = frame->tf_scause & SCAUSE_CODE;
if ((frame->tf_scause & SCAUSE_INTR) != 0) {
/* Interrupt */
riscv_cpu_intr(frame);
return;
}
intr_enable();
CTR3(KTR_TRAP, "do_trap_user: curthread: %p, sepc: %lx, frame: %p",
curthread, frame->tf_sepc, frame);
switch (exception) {
case SCAUSE_LOAD_ACCESS_FAULT:
case SCAUSE_STORE_ACCESS_FAULT:
case SCAUSE_INST_ACCESS_FAULT:
call_trapsignal(td, SIGBUS, BUS_ADRERR, (void *)frame->tf_sepc,
exception);
userret(td, frame);
break;
case SCAUSE_LOAD_MISALIGNED:
case SCAUSE_STORE_MISALIGNED:
case SCAUSE_INST_MISALIGNED:
call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_sepc,
exception);
userret(td, frame);
break;
case SCAUSE_STORE_PAGE_FAULT:
case SCAUSE_LOAD_PAGE_FAULT:
case SCAUSE_INST_PAGE_FAULT:
page_fault_handler(frame, 1);
break;
case SCAUSE_ECALL_USER:
frame->tf_sepc += 4; /* Next instruction */
ecall_handler();
break;
case SCAUSE_ILLEGAL_INSTRUCTION:
-#ifdef FPE
if ((pcb->pcb_fpflags & PCB_FP_STARTED) == 0) {
/*
* May be a FPE trap. Enable FPE usage
* for this thread and try again.
*/
fpe_state_clear();
frame->tf_sstatus &= ~SSTATUS_FS_MASK;
frame->tf_sstatus |= SSTATUS_FS_CLEAN;
pcb->pcb_fpflags |= PCB_FP_STARTED;
break;
}
-#endif
call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_sepc,
exception);
userret(td, frame);
break;
case SCAUSE_BREAKPOINT:
call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_sepc,
exception);
userret(td, frame);
break;
default:
dump_regs(frame);
panic("Unknown userland exception %lx, trap value %lx\n",
exception, frame->tf_stval);
}
}