Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
obj-y += lib/ kernel/ mm/
# for cleaning
subdir- += boot
+265
View File
@@ -0,0 +1,265 @@
# SPDX-License-Identifier: GPL-2.0
#
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/kconfig-language.rst.
#
config OPENRISC
def_bool y
select ARCH_32BIT_OFF_T
select ARCH_HAS_DMA_SET_UNCACHED
select ARCH_HAS_DMA_CLEAR_UNCACHED
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select GENERIC_BUILTIN_DTB
select COMMON_CLK
select OF
select OF_EARLY_FLATTREE
select IRQ_DOMAIN
select GPIOLIB
select HAVE_ARCH_TRACEHOOK
select SPARSE_IRQ
select GENERIC_IRQ_CHIP
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
select GENERIC_PCI_IOMAP
select GENERIC_IOREMAP
select GENERIC_CPU_DEVICES
select HAVE_ARCH_JUMP_LABEL
select HAVE_ARCH_JUMP_LABEL_RELATIVE
select HAVE_PCI
select HAVE_UID16
select HAVE_PAGE_SIZE_8KB
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_RSEQ
select GENERIC_ATOMIC64
select GENERIC_CLOCKEVENTS_BROADCAST
select GENERIC_SMP_IDLE_THREAD
select MODULES_USE_ELF_RELA
select HAVE_DEBUG_STACKOVERFLOW
select OR1K_PIC
select CPU_NO_EFFICIENT_FFS if !OPENRISC_HAVE_INST_FF1
select ARCH_USE_QUEUED_RWLOCKS
select OMPIC if SMP
select PCI_DOMAINS_GENERIC if PCI
select PCI_MSI if PCI
select ARCH_WANT_FRAME_POINTERS
select GENERIC_IRQ_MULTI_HANDLER
select MMU_GATHER_NO_RANGE if MMU
select TRACE_IRQFLAGS_SUPPORT
config CPU_BIG_ENDIAN
def_bool y
config MMU
def_bool y
config GENERIC_HWEIGHT
def_bool y
config NO_IOPORT_MAP
def_bool y
# For now, use generic checksum functions
#These can be reimplemented in assembly later if so inclined
config GENERIC_CSUM
def_bool y
config STACKTRACE_SUPPORT
def_bool y
config LOCKDEP_SUPPORT
def_bool y
config FIX_EARLYCON_MEM
def_bool y
menu "Processor type and features"
choice
prompt "Subarchitecture"
default OR1K_1200
config OR1K_1200
bool "OR1200"
help
Generic OpenRISC 1200 architecture
endchoice
config DCACHE_WRITETHROUGH
bool "Have write through data caches"
default n
help
Select this if your implementation features write through data caches.
Selecting 'N' here will allow the kernel to force flushing of data
caches at relevant times. Most OpenRISC implementations support write-
through data caches.
If unsure say N here
config BUILTIN_DTB_NAME
string "Builtin DTB"
default ""
menu "Class II Instructions"
config OPENRISC_HAVE_INST_FF1
bool "Have instruction l.ff1"
default y
help
Select this if your implementation has the Class II instruction l.ff1
config OPENRISC_HAVE_INST_FL1
bool "Have instruction l.fl1"
default y
help
Select this if your implementation has the Class II instruction l.fl1
config OPENRISC_HAVE_INST_MUL
bool "Have instruction l.mul for hardware multiply"
default y
help
Select this if your implementation has a hardware multiply instruction
config OPENRISC_HAVE_INST_DIV
bool "Have instruction l.div for hardware divide"
default y
help
Select this if your implementation has a hardware divide instruction
config OPENRISC_HAVE_INST_CMOV
bool "Have instruction l.cmov for conditional move"
default n
help
This config enables gcc to generate l.cmov instructions when compiling
the kernel which in general will improve performance and reduce the
binary size.
Select this if your implementation has support for the Class II
l.cmov conistional move instruction.
Say N if you are unsure.
config OPENRISC_HAVE_INST_ROR
bool "Have instruction l.ror for rotate right"
default n
help
This config enables gcc to generate l.ror instructions when compiling
the kernel which in general will improve performance and reduce the
binary size.
Select this if your implementation has support for the Class II
l.ror rotate right instruction.
Say N if you are unsure.
config OPENRISC_HAVE_INST_RORI
bool "Have instruction l.rori for rotate right with immediate"
default n
help
This config enables gcc to generate l.rori instructions when compiling
the kernel which in general will improve performance and reduce the
binary size.
Select this if your implementation has support for the Class II
l.rori rotate right with immediate instruction.
Say N if you are unsure.
config OPENRISC_HAVE_INST_SEXT
bool "Have instructions l.ext* for sign extension"
default n
help
This config enables gcc to generate l.ext* instructions when compiling
the kernel which in general will improve performance and reduce the
binary size.
Select this if your implementation has support for the Class II
l.exths, l.extbs, l.exthz and l.extbz size extend instructions.
Say N if you are unsure.
endmenu
config NR_CPUS
int "Maximum number of CPUs (2-32)"
range 2 32
depends on SMP
default "2"
config SMP
bool "Symmetric Multi-Processing support"
help
This enables support for systems with more than one CPU. If you have
a system with only one CPU, say N. If you have a system with more
than one CPU, say Y.
If you don't know what to do here, say N.
config FPU
bool "FPU support"
default y
help
Say N here if you want to disable all floating-point related procedures
in the kernel and reduce binary size.
If you don't know what to do here, say Y.
source "kernel/Kconfig.hz"
config OPENRISC_NO_SPR_SR_DSX
bool "use SPR_SR_DSX software emulation" if OR1K_1200
default y
help
SPR_SR_DSX bit is status register bit indicating whether
the last exception has happened in delay slot.
OpenRISC architecture makes it optional to have it implemented
in hardware and the OR1200 does not have it.
Say N here if you know that your OpenRISC processor has
SPR_SR_DSX bit implemented. Say Y if you are unsure.
config OPENRISC_HAVE_SHADOW_GPRS
bool "Support for shadow gpr files" if !SMP
default y if SMP
help
Say Y here if your OpenRISC processor features shadowed
register files. They will in such case be used as a
scratch reg storage on exception entry.
On SMP systems, this feature is mandatory.
On a unicore system it's safe to say N here if you are unsure.
config CMDLINE
string "Default kernel command string"
default ""
help
On some architectures there is currently no way for the boot loader
to pass arguments to the kernel. For these architectures, you should
supply some command-line options at build time by entering them
here.
menu "Debugging options"
config JUMP_UPON_UNHANDLED_EXCEPTION
bool "Try to die gracefully"
default y
help
Now this puts kernel into infinite loop after first oops. Till
your kernel crashes this doesn't have any influence.
Say Y if you are unsure.
config OPENRISC_ESR_EXCEPTION_BUG_CHECK
bool "Check for possible ESR exception bug"
default n
help
This option enables some checks that might expose some problems
in kernel.
Say N if you are unsure.
endmenu
endmenu
+2
View File
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
# dummy file, do not delete
+63
View File
@@ -0,0 +1,63 @@
# BK Id: %F% %I% %G% %U% %#%
#
# This file is included by the global makefile so that you can add your own
# architecture-specific flags and dependencies.
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
# Copyright (C) 1994 by Linus Torvalds
# Modifications for the OpenRISC architecture:
# Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
# Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
#
# Based on:
# arch/i386/Makefile
KBUILD_DEFCONFIG := or1ksim_defconfig
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
KBUILD_CFLAGS += -pipe -ffixed-r10 -D__linux__
KBUILD_CFLAGS += -msfimm -mshftimm
all: vmlinux.bin
boot := arch/$(ARCH)/boot
ifeq ($(CONFIG_OPENRISC_HAVE_INST_MUL),y)
KBUILD_CFLAGS += $(call cc-option,-mhard-mul)
else
KBUILD_CFLAGS += $(call cc-option,-msoft-mul)
endif
ifeq ($(CONFIG_OPENRISC_HAVE_INST_DIV),y)
KBUILD_CFLAGS += $(call cc-option,-mhard-div)
else
KBUILD_CFLAGS += $(call cc-option,-msoft-div)
endif
ifeq ($(CONFIG_OPENRISC_HAVE_INST_CMOV),y)
KBUILD_CFLAGS += $(call cc-option,-mcmov)
endif
ifeq ($(CONFIG_OPENRISC_HAVE_INST_ROR),y)
KBUILD_CFLAGS += $(call cc-option,-mror)
endif
ifeq ($(CONFIG_OPENRISC_HAVE_INST_RORI),y)
KBUILD_CFLAGS += $(call cc-option,-mrori)
endif
ifeq ($(CONFIG_OPENRISC_HAVE_INST_SEXT),y)
KBUILD_CFLAGS += $(call cc-option,-msext)
endif
libs-y += $(LIBGCC)
PHONY += vmlinux.bin
vmlinux.bin: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
vmlinux.bin
+10
View File
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for bootable kernel images
#
targets += vmlinux.bin
OBJCOPYFLAGS_vmlinux.bin := -O binary
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
@@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
dtb-y += $(addsuffix .dtb, $(CONFIG_BUILTIN_DTB_NAME))
#DTC_FLAGS ?= -p 1024
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: GPL-2.0
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
/ {
leds0: leds {
compatible = "gpio-leds";
led-heartbeat {
gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_HEARTBEAT;
linux,default-trigger = "heartbeat";
label = "heartbeat";
};
};
memory@0 {
device_type = "memory";
reg = <0x00000000 0x02000000>;
};
/* 8 Green LEDs */
gpio0: gpio@91000000 {
compatible = "opencores,gpio";
reg = <0x91000000 0x1>, <0x91000001 0x1>;
reg-names = "dat", "dirout";
gpio-controller;
#gpio-cells = <2>;
};
/* 4 DIP Switches */
gpio1: gpio@92000000 {
compatible = "opencores,gpio";
reg = <0x92000000 0x1>, <0x92000001 0x1>;
reg-names = "dat", "dirout";
gpio-controller;
#gpio-cells = <2>;
status = "disabled";
};
};
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: GPL-2.0
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
/dts-v1/;
#include "simple-smp.dtsi"
#include "de0-nano-common.dtsi"
/ {
model = "Terasic DE0 Nano - Multicore";
};
&cpu0 {
clock-frequency = <50000000>;
};
&cpu1 {
clock-frequency = <50000000>;
};
&serial0 {
clock-frequency = <50000000>;
};
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include "de0-nano-common.dtsi"
/ {
model = "Terasic DE0 Nano";
compatible = "opencores,or1ksim";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&pic>;
aliases {
uart0 = &serial0;
};
chosen {
stdout-path = "uart0:115200";
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "opencores,or1200-rtlsvn481";
reg = <0>;
clock-frequency = <50000000>;
};
};
/*
* OR1K PIC is built into CPU and accessed via special purpose
* registers. It is not addressable and, hence, has no 'reg'
* property.
*/
pic: pic {
compatible = "opencores,or1k-pic";
#interrupt-cells = <1>;
interrupt-controller;
};
serial0: serial@90000000 {
compatible = "opencores,uart16550-rtlsvn105", "ns16550a";
reg = <0x90000000 0x100>;
interrupts = <2>;
clock-frequency = <50000000>;
};
};
&gpio1 {
status = "okay";
};
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-2.0
/*
* LiteX-based System on Chip
*
* Copyright (C) 2019 Antmicro <www.antmicro.com>
*/
/dts-v1/;
/ {
compatible = "opencores,or1ksim";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&pic>;
aliases {
serial0 = &serial0;
};
chosen {
bootargs = "console=liteuart";
};
memory@0 {
device_type = "memory";
reg = <0x00000000 0x10000000>;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "opencores,or1200-rtlsvn481";
reg = <0>;
clock-frequency = <100000000>;
};
};
pic: pic {
compatible = "opencores,or1k-pic";
#interrupt-cells = <1>;
interrupt-controller;
};
serial0: serial@e0006800 {
device_type = "serial";
compatible = "litex,liteuart";
reg = <0xe0006800 0x100>;
};
soc_ctrl0: soc_controller@e0000000 {
compatible = "litex,soc-controller";
reg = <0xe0000000 0xc>;
status = "okay";
};
ethernet@e0001000 {
compatible = "litex,liteeth";
reg = <0xe0001000 0x7c>,
<0xe0001800 0x0a>,
<0x80000000 0x2000>;
reg-names = "mac", "mdio", "buffer";
interrupts = <2>;
};
};
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/ {
compatible = "opencores,or1ksim";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&pic>;
aliases {
uart0 = &serial0;
};
chosen {
bootargs = "earlycon";
stdout-path = "uart0:115200";
};
memory@0 {
device_type = "memory";
reg = <0x00000000 0x02000000>;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "opencores,or1200-rtlsvn481";
reg = <0>;
clock-frequency = <20000000>;
};
};
/*
* OR1K PIC is built into CPU and accessed via special purpose
* registers. It is not addressable and, hence, has no 'reg'
* property.
*/
pic: pic {
compatible = "opencores,or1k-pic";
#interrupt-cells = <1>;
interrupt-controller;
};
serial0: serial@90000000 {
compatible = "opencores,uart16550-rtlsvn105", "ns16550a";
reg = <0x90000000 0x100>;
interrupts = <2>;
clock-frequency = <20000000>;
};
enet0: ethoc@92000000 {
compatible = "opencores,ethoc";
reg = <0x92000000 0x800>;
interrupts = <4>;
big-endian;
};
};
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include "simple-smp.dtsi"
/ {
model = "Simple SMP Board";
};
&cpu0 {
clock-frequency = <20000000>;
};
&cpu1 {
clock-frequency = <20000000>;
};
&enet0 {
status = "okay";
};
&serial0 {
clock-frequency = <20000000>;
};
@@ -0,0 +1,68 @@
/ {
compatible = "opencores,or1ksim";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&pic>;
aliases {
uart0 = &serial0;
};
chosen {
bootargs = "earlycon";
stdout-path = "uart0:115200";
};
memory@0 {
device_type = "memory";
reg = <0x00000000 0x02000000>;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
compatible = "opencores,or1200-rtlsvn481";
reg = <0>;
};
cpu1: cpu@1 {
compatible = "opencores,or1200-rtlsvn481";
reg = <1>;
};
};
ompic: ompic@98000000 {
compatible = "openrisc,ompic";
reg = <0x98000000 16>;
interrupt-controller;
#interrupt-cells = <0>;
interrupts = <1>;
};
/*
* OR1K PIC is built into CPU and accessed via special purpose
* registers. It is not addressable and, hence, has no 'reg'
* property.
*/
pic: pic {
compatible = "opencores,or1k-pic-level";
#interrupt-cells = <1>;
interrupt-controller;
};
serial0: serial@90000000 {
compatible = "opencores,uart16550-rtlsvn105", "ns16550a";
reg = <0x90000000 0x100>;
interrupts = <2>;
};
enet0: ethoc@92000000 {
compatible = "opencores,ethoc";
reg = <0x92000000 0x800>;
interrupts = <4>;
big-endian;
status = "disabled";
};
};
@@ -0,0 +1,79 @@
CONFIG_SYSVIPC=y
CONFIG_NO_HZ=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
# CONFIG_RD_LZMA is not set
# CONFIG_RD_LZO is not set
# CONFIG_RD_LZ4 is not set
# CONFIG_RD_ZSTD is not set
CONFIG_EXPERT=y
# CONFIG_EPOLL is not set
# CONFIG_TIMERFD is not set
# CONFIG_EVENTFD is not set
# CONFIG_AIO is not set
CONFIG_BUILTIN_DTB_NAME="de0-nano"
# CONFIG_FPU is not set
CONFIG_HZ_100=y
# CONFIG_BLOCK is not set
CONFIG_SLUB_TINY=y
# CONFIG_COMPAT_BRK is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_NET=y
CONFIG_UNIX=y
CONFIG_UNIX_DIAG=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_INET_UDP_DIAG=y
CONFIG_INET_RAW_DIAG=y
CONFIG_INET_DIAG_DESTROY=y
# CONFIG_IPV6 is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
CONFIG_PPS=y
CONFIG_GPIO_SYSFS=y
# CONFIG_GPIO_SYSFS_LEGACY is not set
CONFIG_GPIO_GENERIC_PLATFORM=y
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_ONESHOT=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_CPU=y
CONFIG_LEDS_TRIGGER_ACTIVITY=y
CONFIG_LEDS_TRIGGER_GPIO=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_LEDS_TRIGGER_TRANSIENT=y
CONFIG_LEDS_TRIGGER_PANIC=y
CONFIG_LEDS_TRIGGER_NETDEV=y
CONFIG_LEDS_TRIGGER_PATTERN=y
CONFIG_LEDS_TRIGGER_TTY=y
# CONFIG_VIRTIO_MENU is not set
# CONFIG_VHOST_MENU is not set
# CONFIG_DNOTIFY is not set
CONFIG_TMPFS=y
# CONFIG_XZ_DEC_X86 is not set
# CONFIG_XZ_DEC_POWERPC is not set
# CONFIG_XZ_DEC_ARM is not set
# CONFIG_XZ_DEC_ARMTHUMB is not set
# CONFIG_XZ_DEC_ARM64 is not set
# CONFIG_XZ_DEC_SPARC is not set
# CONFIG_XZ_DEC_RISCV is not set
CONFIG_PRINTK_TIME=y
# CONFIG_DEBUG_MISC is not set
# CONFIG_FTRACE is not set
# CONFIG_RUNTIME_TESTING_MENU is not set
@@ -0,0 +1,92 @@
CONFIG_LOCALVERSION="-de0nano-smp"
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_NO_HZ=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
# CONFIG_RD_BZIP2 is not set
# CONFIG_RD_LZMA is not set
# CONFIG_RD_XZ is not set
# CONFIG_RD_LZO is not set
# CONFIG_RD_LZ4 is not set
CONFIG_EXPERT=y
# CONFIG_EPOLL is not set
# CONFIG_TIMERFD is not set
# CONFIG_EVENTFD is not set
# CONFIG_AIO is not set
CONFIG_KALLSYMS_ALL=y
CONFIG_DCACHE_WRITETHROUGH=y
CONFIG_BUILTIN_DTB_NAME="de0-nano-multicore"
CONFIG_OPENRISC_HAVE_INST_CMOV=y
CONFIG_SMP=y
CONFIG_HZ_100=y
CONFIG_JUMP_LABEL=y
# CONFIG_BLOCK is not set
CONFIG_SLUB_TINY=y
# CONFIG_COMPAT_BRK is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_UNIX_DIAG=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_TCP_CONG_ADVANCED=y
# CONFIG_TCP_CONG_BIC is not set
# CONFIG_TCP_CONG_CUBIC is not set
# CONFIG_TCP_CONG_WESTWOOD is not set
# CONFIG_TCP_CONG_HTCP is not set
# CONFIG_IPV6 is not set
# CONFIG_WIRELESS is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
CONFIG_NETDEVICES=y
CONFIG_ETHOC=y
CONFIG_MICREL_PHY=y
# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
CONFIG_GPIO_SYSFS=y
# CONFIG_GPIO_CDEV_V1 is not set
CONFIG_GPIO_GENERIC_PLATFORM=y
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_ONESHOT=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_CPU=y
CONFIG_LEDS_TRIGGER_ACTIVITY=y
CONFIG_LEDS_TRIGGER_GPIO=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_LEDS_TRIGGER_TRANSIENT=y
CONFIG_LEDS_TRIGGER_PANIC=y
CONFIG_LEDS_TRIGGER_NETDEV=y
CONFIG_LEDS_TRIGGER_PATTERN=y
CONFIG_LEDS_TRIGGER_TTY=y
# CONFIG_DNOTIFY is not set
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
CONFIG_XZ_DEC=y
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
CONFIG_GDB_SCRIPTS=y
CONFIG_VMLINUX_MAP=y
CONFIG_HARDLOCKUP_DETECTOR=y
CONFIG_WQ_WATCHDOG=y
CONFIG_WQ_CPU_INTENSIVE_REPORT=y
CONFIG_STACKTRACE=y
CONFIG_RCU_CPU_STALL_CPUTIME=y
# CONFIG_RCU_TRACE is not set
@@ -0,0 +1,56 @@
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_CGROUPS=y
CONFIG_NAMESPACES=y
CONFIG_USER_NS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SGETMASK_SYSCALL=y
CONFIG_EXPERT=y
CONFIG_BUILTIN_DTB_NAME="or1klitex"
CONFIG_HZ_100=y
CONFIG_OPENRISC_HAVE_SHADOW_GPRS=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_PACKET_DIAG=y
CONFIG_UNIX=y
CONFIG_UNIX_DIAG=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_INET_UDP_DIAG=y
CONFIG_INET_RAW_DIAG=y
# CONFIG_WIRELESS is not set
# CONFIG_ETHTOOL_NETLINK is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_OF_OVERLAY=y
CONFIG_NETDEVICES=y
CONFIG_LITEX_LITEETH=y
# CONFIG_WLAN is not set
CONFIG_SERIAL_LITEUART=y
CONFIG_SERIAL_LITEUART_CONSOLE=y
CONFIG_TTY_PRINTK=y
# CONFIG_GPIO_CDEV is not set
CONFIG_MMC=y
CONFIG_MMC_LITEX=y
# CONFIG_VHOST_MENU is not set
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_LITEX_SOC_CONTROLLER=y
CONFIG_EXT2_FS=y
CONFIG_EXT4_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_EXFAT_FS=y
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,bpf"
CONFIG_PRINTK_TIME=y
CONFIG_PANIC_ON_OOPS=y
CONFIG_SOFTLOCKUP_DETECTOR=y
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=1
CONFIG_BUG_ON_DATA_CORRUPTION=y
@@ -0,0 +1,51 @@
CONFIG_NO_HZ=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
CONFIG_EXPERT=y
# CONFIG_EPOLL is not set
# CONFIG_TIMERFD is not set
# CONFIG_EVENTFD is not set
# CONFIG_AIO is not set
# CONFIG_KALLSYMS is not set
CONFIG_BUILTIN_DTB_NAME="or1ksim"
CONFIG_HZ_100=y
CONFIG_JUMP_LABEL=y
CONFIG_MODULES=y
# CONFIG_BLOCK is not set
CONFIG_SLUB_TINY=y
# CONFIG_COMPAT_BRK is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_INET_DIAG is not set
CONFIG_TCP_CONG_ADVANCED=y
# CONFIG_TCP_CONG_BIC is not set
# CONFIG_TCP_CONG_CUBIC is not set
# CONFIG_TCP_CONG_WESTWOOD is not set
# CONFIG_TCP_CONG_HTCP is not set
# CONFIG_IPV6 is not set
# CONFIG_WIRELESS is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
CONFIG_NETDEVICES=y
CONFIG_ETHOC=y
CONFIG_MICREL_PHY=y
# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_DNOTIFY is not set
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
@@ -0,0 +1,65 @@
CONFIG_LOCALVERSION="-simple-smp"
CONFIG_NO_HZ=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
# CONFIG_RD_BZIP2 is not set
# CONFIG_RD_LZMA is not set
# CONFIG_RD_XZ is not set
# CONFIG_RD_LZO is not set
# CONFIG_RD_LZ4 is not set
CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_EPOLL is not set
# CONFIG_TIMERFD is not set
# CONFIG_EVENTFD is not set
# CONFIG_AIO is not set
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLUB=y
CONFIG_SLUB_TINY=y
CONFIG_MODULES=y
# CONFIG_BLOCK is not set
CONFIG_BUILTIN_DTB_NAME="simple-smp"
CONFIG_SMP=y
CONFIG_HZ_100=y
CONFIG_OPENRISC_HAVE_SHADOW_GPRS=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_DIAG is not set
CONFIG_TCP_CONG_ADVANCED=y
# CONFIG_TCP_CONG_BIC is not set
# CONFIG_TCP_CONG_CUBIC is not set
# CONFIG_TCP_CONG_WESTWOOD is not set
# CONFIG_TCP_CONG_HTCP is not set
# CONFIG_IPV6 is not set
# CONFIG_WIRELESS is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
CONFIG_NETDEVICES=y
CONFIG_ETHOC=y
CONFIG_MICREL_PHY=y
# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_DNOTIFY is not set
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
CONFIG_XZ_DEC=y
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_RCU_TRACE is not set
@@ -0,0 +1,108 @@
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_NO_HZ_IDLE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_CGROUPS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_OPENRISC_HAVE_INST_CMOV=y
CONFIG_OPENRISC_HAVE_INST_ROR=y
CONFIG_OPENRISC_HAVE_INST_RORI=y
CONFIG_OPENRISC_HAVE_INST_SEXT=y
CONFIG_NR_CPUS=8
CONFIG_SMP=y
CONFIG_HZ_100=y
# CONFIG_OPENRISC_NO_SPR_SR_DSX is not set
CONFIG_JUMP_LABEL=y
# CONFIG_COMPAT_BRK is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_INET_DIAG is not set
CONFIG_TCP_CONG_ADVANCED=y
# CONFIG_TCP_CONG_BIC is not set
# CONFIG_TCP_CONG_CUBIC is not set
# CONFIG_TCP_CONG_WESTWOOD is not set
# CONFIG_TCP_CONG_HTCP is not set
# CONFIG_IPV6 is not set
# CONFIG_WIRELESS is not set
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCI_HOST_GENERIC=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NBD=y
CONFIG_VIRTIO_BLK=y
CONFIG_NETDEVICES=y
CONFIG_VIRTIO_NET=y
CONFIG_ETHOC=y
CONFIG_MICREL_PHY=y
# CONFIG_WLAN is not set
CONFIG_INPUT_MOUSEDEV=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_VIRTIO_CONSOLE=y
# CONFIG_HW_RANDOM is not set
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_POWER_RESET_SYSCON_POWEROFF=y
CONFIG_SYSCON_REBOOT_MODE=y
# CONFIG_HWMON is not set
CONFIG_DRM=y
# CONFIG_DRM_FBDEV_EMULATION is not set
CONFIG_DRM_VIRTIO_GPU=y
CONFIG_FB=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
CONFIG_LOGO=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_INTEL8X0=y
CONFIG_SND_INTEL8X0M=y
CONFIG_SND_SOC=y
CONFIG_SND_VIRTIO=y
# CONFIG_HID_A4TECH is not set
# CONFIG_HID_BELKIN is not set
# CONFIG_HID_CHERRY is not set
# CONFIG_HID_CHICONY is not set
# CONFIG_HID_CYPRESS is not set
# CONFIG_HID_EZKEY is not set
# CONFIG_HID_ITE is not set
# CONFIG_HID_KENSINGTON is not set
# CONFIG_HID_REDRAGON is not set
# CONFIG_HID_MICROSOFT is not set
# CONFIG_HID_MONTEREY is not set
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_PLATFORM=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
CONFIG_USB_SERIAL=y
CONFIG_USB_GADGET=y
CONFIG_TYPEC=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GOLDFISH=y
CONFIG_VIRT_DRIVERS=y
CONFIG_VIRTIO_PCI=y
# CONFIG_VIRTIO_PCI_LEGACY is not set
CONFIG_VIRTIO_INPUT=y
CONFIG_VIRTIO_MMIO=y
CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
# CONFIG_DNOTIFY is not set
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_EXFAT_FS=y
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
CONFIG_UNICODE=y
CONFIG_PRINTK_TIME=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_FTRACE=y
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
syscall-y += syscall_table_32.h
generic-y += extable.h
generic-y += kvm_para.h
generic-y += parport.h
generic-y += spinlock_types.h
generic-y += spinlock.h
generic-y += qrwlock_types.h
generic-y += qrwlock.h
generic-y += ring_buffer.h
generic-y += user.h
@@ -0,0 +1 @@
#include <generated/asm-offsets.h>
@@ -0,0 +1,133 @@
/*
* Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#ifndef __ASM_OPENRISC_ATOMIC_H
#define __ASM_OPENRISC_ATOMIC_H
#include <linux/types.h>
/* Atomically perform op with v->counter and i */
#define ATOMIC_OP(op) \
static inline void arch_atomic_##op(int i, atomic_t *v) \
{ \
int tmp; \
\
__asm__ __volatile__( \
"1: l.lwa %0,0(%1) \n" \
" l." #op " %0,%0,%2 \n" \
" l.swa 0(%1),%0 \n" \
" l.bnf 1b \n" \
" l.nop \n" \
: "=&r"(tmp) \
: "r"(&v->counter), "r"(i) \
: "cc", "memory"); \
}
/* Atomically perform op with v->counter and i, return the result */
#define ATOMIC_OP_RETURN(op) \
static inline int arch_atomic_##op##_return(int i, atomic_t *v) \
{ \
int tmp; \
\
__asm__ __volatile__( \
"1: l.lwa %0,0(%1) \n" \
" l." #op " %0,%0,%2 \n" \
" l.swa 0(%1),%0 \n" \
" l.bnf 1b \n" \
" l.nop \n" \
: "=&r"(tmp) \
: "r"(&v->counter), "r"(i) \
: "cc", "memory"); \
\
return tmp; \
}
/* Atomically perform op with v->counter and i, return orig v->counter */
#define ATOMIC_FETCH_OP(op) \
static inline int arch_atomic_fetch_##op(int i, atomic_t *v) \
{ \
int tmp, old; \
\
__asm__ __volatile__( \
"1: l.lwa %0,0(%2) \n" \
" l." #op " %1,%0,%3 \n" \
" l.swa 0(%2),%1 \n" \
" l.bnf 1b \n" \
" l.nop \n" \
: "=&r"(old), "=&r"(tmp) \
: "r"(&v->counter), "r"(i) \
: "cc", "memory"); \
\
return old; \
}
ATOMIC_OP_RETURN(add)
ATOMIC_OP_RETURN(sub)
ATOMIC_FETCH_OP(add)
ATOMIC_FETCH_OP(sub)
ATOMIC_FETCH_OP(and)
ATOMIC_FETCH_OP(or)
ATOMIC_FETCH_OP(xor)
ATOMIC_OP(add)
ATOMIC_OP(sub)
ATOMIC_OP(and)
ATOMIC_OP(or)
ATOMIC_OP(xor)
#undef ATOMIC_FETCH_OP
#undef ATOMIC_OP_RETURN
#undef ATOMIC_OP
#define arch_atomic_add_return arch_atomic_add_return
#define arch_atomic_sub_return arch_atomic_sub_return
#define arch_atomic_fetch_add arch_atomic_fetch_add
#define arch_atomic_fetch_sub arch_atomic_fetch_sub
#define arch_atomic_fetch_and arch_atomic_fetch_and
#define arch_atomic_fetch_or arch_atomic_fetch_or
#define arch_atomic_fetch_xor arch_atomic_fetch_xor
#define arch_atomic_add arch_atomic_add
#define arch_atomic_sub arch_atomic_sub
#define arch_atomic_and arch_atomic_and
#define arch_atomic_or arch_atomic_or
#define arch_atomic_xor arch_atomic_xor
/*
* Atomically add a to v->counter as long as v is not already u.
* Returns the original value at v->counter.
*
* This is often used through atomic_inc_not_zero()
*/
static inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
{
int old, tmp;
__asm__ __volatile__(
"1: l.lwa %0, 0(%2) \n"
" l.sfeq %0, %4 \n"
" l.bf 2f \n"
" l.add %1, %0, %3 \n"
" l.swa 0(%2), %1 \n"
" l.bnf 1b \n"
" l.nop \n"
"2: \n"
: "=&r"(old), "=&r" (tmp)
: "r"(&v->counter), "r"(a), "r"(u)
: "cc", "memory");
return old;
}
#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
#define arch_atomic_read(v) READ_ONCE((v)->counter)
#define arch_atomic_set(v,i) WRITE_ONCE((v)->counter, (i))
#include <asm/cmpxchg.h>
#endif /* __ASM_OPENRISC_ATOMIC_H */
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_BARRIER_H
#define __ASM_BARRIER_H
#define mb() asm volatile ("l.msync" ::: "memory")
#define nop() asm volatile ("l.nop")
#include <asm-generic/barrier.h>
#endif /* __ASM_BARRIER_H */
@@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_BITOPS_H
#define __ASM_OPENRISC_BITOPS_H
/*
* Where we haven't written assembly versions yet, we fall back to the
* generic implementations. Otherwise, we pull in our (hopefully)
* optimized versions.
*/
#include <linux/irqflags.h>
#include <linux/compiler.h>
#include <asm/barrier.h>
#include <asm/bitops/__ffs.h>
#include <asm-generic/bitops/ffz.h>
#include <asm/bitops/fls.h>
#include <asm/bitops/__fls.h>
#include <asm-generic/bitops/fls64.h>
#ifndef _LINUX_BITOPS_H
#error only <linux/bitops.h> can be included directly
#endif
#include <asm-generic/bitops/sched.h>
#include <asm/bitops/ffs.h>
#include <asm-generic/bitops/hweight.h>
#include <asm-generic/bitops/lock.h>
#include <asm/bitops/atomic.h>
#include <asm-generic/bitops/non-atomic.h>
#include <asm-generic/bitops/le.h>
#include <asm-generic/bitops/ext2-atomic.h>
#endif /* __ASM_GENERIC_BITOPS_H */
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#ifndef __ASM_OPENRISC___FFS_H
#define __ASM_OPENRISC___FFS_H
#ifdef CONFIG_OPENRISC_HAVE_INST_FF1
static inline __attribute_const__ unsigned long __ffs(unsigned long x)
{
int ret;
__asm__ ("l.ff1 %0,%1"
: "=r" (ret)
: "r" (x));
return ret-1;
}
#else
#include <asm-generic/bitops/__ffs.h>
#endif
#endif /* __ASM_OPENRISC___FFS_H */
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#ifndef __ASM_OPENRISC___FLS_H
#define __ASM_OPENRISC___FLS_H
#ifdef CONFIG_OPENRISC_HAVE_INST_FL1
static inline __attribute_const__ unsigned long __fls(unsigned long x)
{
int ret;
__asm__ ("l.fl1 %0,%1"
: "=r" (ret)
: "r" (x));
return ret-1;
}
#else
#include <asm-generic/bitops/__fls.h>
#endif
#endif /* __ASM_OPENRISC___FLS_H */
@@ -0,0 +1,123 @@
/*
* Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#ifndef __ASM_OPENRISC_BITOPS_ATOMIC_H
#define __ASM_OPENRISC_BITOPS_ATOMIC_H
static inline void set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long tmp;
__asm__ __volatile__(
"1: l.lwa %0,0(%1) \n"
" l.or %0,%0,%2 \n"
" l.swa 0(%1),%0 \n"
" l.bnf 1b \n"
" l.nop \n"
: "=&r"(tmp)
: "r"(p), "r"(mask)
: "cc", "memory");
}
static inline void clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long tmp;
__asm__ __volatile__(
"1: l.lwa %0,0(%1) \n"
" l.and %0,%0,%2 \n"
" l.swa 0(%1),%0 \n"
" l.bnf 1b \n"
" l.nop \n"
: "=&r"(tmp)
: "r"(p), "r"(~mask)
: "cc", "memory");
}
static inline void change_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long tmp;
__asm__ __volatile__(
"1: l.lwa %0,0(%1) \n"
" l.xor %0,%0,%2 \n"
" l.swa 0(%1),%0 \n"
" l.bnf 1b \n"
" l.nop \n"
: "=&r"(tmp)
: "r"(p), "r"(mask)
: "cc", "memory");
}
static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long old;
unsigned long tmp;
__asm__ __volatile__(
"1: l.lwa %0,0(%2) \n"
" l.or %1,%0,%3 \n"
" l.swa 0(%2),%1 \n"
" l.bnf 1b \n"
" l.nop \n"
: "=&r"(old), "=&r"(tmp)
: "r"(p), "r"(mask)
: "cc", "memory");
return (old & mask) != 0;
}
static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long old;
unsigned long tmp;
__asm__ __volatile__(
"1: l.lwa %0,0(%2) \n"
" l.and %1,%0,%3 \n"
" l.swa 0(%2),%1 \n"
" l.bnf 1b \n"
" l.nop \n"
: "=&r"(old), "=&r"(tmp)
: "r"(p), "r"(~mask)
: "cc", "memory");
return (old & mask) != 0;
}
static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
unsigned long old;
unsigned long tmp;
__asm__ __volatile__(
"1: l.lwa %0,0(%2) \n"
" l.xor %1,%0,%3 \n"
" l.swa 0(%2),%1 \n"
" l.bnf 1b \n"
" l.nop \n"
: "=&r"(old), "=&r"(tmp)
: "r"(p), "r"(mask)
: "cc", "memory");
return (old & mask) != 0;
}
#endif /* __ASM_OPENRISC_BITOPS_ATOMIC_H */
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#ifndef __ASM_OPENRISC_FFS_H
#define __ASM_OPENRISC_FFS_H
#ifdef CONFIG_OPENRISC_HAVE_INST_FF1
static inline __attribute_const__ int ffs(int x)
{
int ret;
__asm__ ("l.ff1 %0,%1"
: "=r" (ret)
: "r" (x));
return ret;
}
#else
#include <asm-generic/bitops/ffs.h>
#endif
#endif /* __ASM_OPENRISC_FFS_H */
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#ifndef __ASM_OPENRISC_FLS_H
#define __ASM_OPENRISC_FLS_H
#ifdef CONFIG_OPENRISC_HAVE_INST_FL1
static inline __attribute_const__ int fls(unsigned int x)
{
int ret;
__asm__ ("l.fl1 %0,%1"
: "=r" (ret)
: "r" (x));
return ret;
}
#else
#include <asm-generic/bitops/fls.h>
#endif
#endif /* __ASM_OPENRISC_FLS_H */
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __ASM_OPENRISC_BUG_H
#define __ASM_OPENRISC_BUG_H
#include <asm-generic/bug.h>
struct pt_regs;
void __noreturn die(const char *str, struct pt_regs *regs, long err);
#endif /* __ASM_OPENRISC_BUG_H */
@@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_CACHE_H
#define __ASM_OPENRISC_CACHE_H
/* FIXME: How can we replace these with values from the CPU...
* they shouldn't be hard-coded!
*/
#define __ro_after_init __read_mostly
#define L1_CACHE_BYTES 16
#define L1_CACHE_SHIFT 4
#endif /* __ASM_OPENRISC_CACHE_H */
@@ -0,0 +1,100 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) Jan Henrik Weinstock <jan.weinstock@rwth-aachen.de>
* et al.
*/
#ifndef __ASM_CACHEFLUSH_H
#define __ASM_CACHEFLUSH_H
#include <linux/mm.h>
/*
* Helper function for flushing or invalidating entire pages from data
* and instruction caches. SMP needs a little extra work, since we need
* to flush the pages on all cpus.
*/
extern void local_dcache_page_flush(struct page *page);
extern void local_icache_page_inv(struct page *page);
extern void local_dcache_range_flush(unsigned long start, unsigned long end);
extern void local_dcache_range_inv(unsigned long start, unsigned long end);
extern void local_icache_range_inv(unsigned long start, unsigned long end);
extern void local_icache_all_inv(void);
/*
* Data cache flushing always happen on the local cpu. Instruction cache
* invalidations need to be broadcasted to all other cpu in the system in
* case of SMP configurations.
*/
#ifndef CONFIG_SMP
#define dcache_page_flush(page) local_dcache_page_flush(page)
#define icache_page_inv(page) local_icache_page_inv(page)
#define icache_all_inv() local_icache_all_inv()
#else /* CONFIG_SMP */
#define dcache_page_flush(page) local_dcache_page_flush(page)
#define icache_page_inv(page) smp_icache_page_inv(page)
#define icache_all_inv() smp_icache_all_inv()
extern void smp_icache_page_inv(struct page *page);
extern void smp_icache_all_inv(void);
#endif /* CONFIG_SMP */
/*
* Even if the actual block size is larger than L1_CACHE_BYTES, paddr
* can be incremented by L1_CACHE_BYTES. When paddr is written to the
* invalidate register, the entire cache line encompassing this address
* is invalidated. Each subsequent reference to the same cache line will
* not affect the invalidation process.
*/
#define local_dcache_block_flush(addr) \
local_dcache_range_flush(addr, addr + L1_CACHE_BYTES)
#define local_dcache_block_inv(addr) \
local_dcache_range_inv(addr, addr + L1_CACHE_BYTES)
#define local_icache_block_inv(addr) \
local_icache_range_inv(addr, addr + L1_CACHE_BYTES)
/*
* Synchronizes caches. Whenever a cpu writes executable code to memory, this
* should be called to make sure the processor sees the newly written code.
*/
static inline void sync_icache_dcache(struct page *page)
{
if (!IS_ENABLED(CONFIG_DCACHE_WRITETHROUGH))
dcache_page_flush(page);
icache_page_inv(page);
}
/*
* Pages with this bit set need not be flushed/invalidated, since
* they have not changed since last flush. New pages start with
* PG_arch_1 not set and are therefore dirty by default.
*/
#define PG_dc_clean PG_arch_1
static inline void flush_dcache_folio(struct folio *folio)
{
clear_bit(PG_dc_clean, &folio->flags.f);
}
#define flush_dcache_folio flush_dcache_folio
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
static inline void flush_dcache_page(struct page *page)
{
flush_dcache_folio(page_folio(page));
}
#define flush_icache_user_page(vma, page, addr, len) \
do { \
if (vma->vm_flags & VM_EXEC) \
sync_icache_dcache(page); \
} while (0)
#include <asm-generic/cacheflush.h>
#endif /* __ASM_CACHEFLUSH_H */
@@ -0,0 +1,171 @@
/*
* 1,2 and 4 byte cmpxchg and xchg implementations for OpenRISC.
*
* Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
* Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*
* Note:
* The portable implementations of 1 and 2 byte xchg and cmpxchg using a 4
* byte cmpxchg is sourced heavily from the sh and mips implementations.
*/
#ifndef __ASM_OPENRISC_CMPXCHG_H
#define __ASM_OPENRISC_CMPXCHG_H
#include <linux/bits.h>
#include <linux/compiler.h>
#include <linux/types.h>
#define __HAVE_ARCH_CMPXCHG 1
static inline unsigned long cmpxchg_u32(volatile void *ptr,
unsigned long old, unsigned long new)
{
__asm__ __volatile__(
"1: l.lwa %0, 0(%1) \n"
" l.sfeq %0, %2 \n"
" l.bnf 2f \n"
" l.nop \n"
" l.swa 0(%1), %3 \n"
" l.bnf 1b \n"
" l.nop \n"
"2: \n"
: "=&r"(old)
: "r"(ptr), "r"(old), "r"(new)
: "cc", "memory");
return old;
}
static inline unsigned long xchg_u32(volatile void *ptr,
unsigned long val)
{
__asm__ __volatile__(
"1: l.lwa %0, 0(%1) \n"
" l.swa 0(%1), %2 \n"
" l.bnf 1b \n"
" l.nop \n"
: "=&r"(val)
: "r"(ptr), "r"(val)
: "cc", "memory");
return val;
}
static inline u32 cmpxchg_small(volatile void *ptr, u32 old, u32 new,
int size)
{
int off = (unsigned long)ptr % sizeof(u32);
volatile u32 *p = ptr - off;
#ifdef __BIG_ENDIAN
int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
#else
int bitoff = off * BITS_PER_BYTE;
#endif
u32 bitmask = ((0x1 << size * BITS_PER_BYTE) - 1) << bitoff;
u32 load32, old32, new32;
u32 ret;
load32 = READ_ONCE(*p);
while (true) {
ret = (load32 & bitmask) >> bitoff;
if (old != ret)
return ret;
old32 = (load32 & ~bitmask) | (old << bitoff);
new32 = (load32 & ~bitmask) | (new << bitoff);
/* Do 32 bit cmpxchg */
load32 = cmpxchg_u32(p, old32, new32);
if (load32 == old32)
return old;
}
}
/* xchg */
static inline u32 xchg_small(volatile void *ptr, u32 x, int size)
{
int off = (unsigned long)ptr % sizeof(u32);
volatile u32 *p = ptr - off;
#ifdef __BIG_ENDIAN
int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
#else
int bitoff = off * BITS_PER_BYTE;
#endif
u32 bitmask = ((0x1 << size * BITS_PER_BYTE) - 1) << bitoff;
u32 oldv, newv;
u32 ret;
do {
oldv = READ_ONCE(*p);
ret = (oldv & bitmask) >> bitoff;
newv = (oldv & ~bitmask) | (x << bitoff);
} while (cmpxchg_u32(p, oldv, newv) != oldv);
return ret;
}
/*
* This function doesn't exist, so you'll get a linker error
* if something tries to do an invalid cmpxchg().
*/
extern unsigned long __cmpxchg_called_with_bad_pointer(void)
__compiletime_error("Bad argument size for cmpxchg");
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long new, int size)
{
switch (size) {
case 1:
case 2:
return cmpxchg_small(ptr, old, new, size);
case 4:
return cmpxchg_u32(ptr, old, new);
default:
return __cmpxchg_called_with_bad_pointer();
}
}
#define arch_cmpxchg(ptr, o, n) \
({ \
(__typeof__(*(ptr))) __cmpxchg((ptr), \
(unsigned long)(o), \
(unsigned long)(n), \
sizeof(*(ptr))); \
})
/*
* This function doesn't exist, so you'll get a linker error if
* something tries to do an invalidly-sized xchg().
*/
extern unsigned long __xchg_called_with_bad_pointer(void)
__compiletime_error("Bad argument size for xchg");
static inline unsigned long
__arch_xchg(volatile void *ptr, unsigned long with, int size)
{
switch (size) {
case 1:
case 2:
return xchg_small(ptr, with, size);
case 4:
return xchg_u32(ptr, with);
default:
return __xchg_called_with_bad_pointer();
}
}
#define arch_xchg(ptr, with) \
({ \
(__typeof__(*(ptr))) __arch_xchg((ptr), \
(unsigned long)(with), \
sizeof(*(ptr))); \
})
#endif /* __ASM_OPENRISC_CMPXCHG_H */
@@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_CPUINFO_H
#define __ASM_OPENRISC_CPUINFO_H
#include <asm/spr.h>
#include <asm/spr_defs.h>
struct cache_desc {
u32 size;
u32 sets;
u32 block_size;
u32 ways;
};
struct cpuinfo_or1k {
u32 clock_frequency;
struct cache_desc icache;
struct cache_desc dcache;
u16 coreid;
};
extern struct cpuinfo_or1k cpuinfo_or1k[NR_CPUS];
extern void setup_cpuinfo(void);
/*
* Check if the cache component exists.
*/
extern bool cpu_cache_is_present(const unsigned int cache_type);
#endif /* __ASM_OPENRISC_CPUINFO_H */
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#ifndef __ASM_OPENRISC_DELAY_H
#define __ASM_OPENRISC_DELAY_H
#include <asm-generic/delay.h>
extern unsigned long loops_per_jiffy;
#endif
@@ -0,0 +1,61 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_ELF_H
#define __ASM_OPENRISC_ELF_H
#include <linux/types.h>
#include <uapi/asm/elf.h>
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch(x) \
(((x)->e_machine == EM_OR32) || ((x)->e_machine == EM_OPENRISC))
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
use of this is to invoke "./ld.so someprog" to test out a new version of
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */
#define ELF_ET_DYN_BASE (0x08000000)
/*
* Enable dump using regset.
* This covers all of general/DSP/FPU regs.
*/
#define CORE_DUMP_USE_REGSET
#define ELF_EXEC_PAGESIZE 8192
extern void dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt);
#define ELF_CORE_COPY_REGS(dest, regs) dump_elf_thread(dest, regs);
/* This yields a mask that user programs can use to figure out what
instruction set this cpu supports. This could be done in userspace,
but it's not easy, and we've already done it here. */
#define ELF_HWCAP (0)
/* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in
intent than poking at uname or /proc/cpuinfo.
For the moment, we have only optimizations for the Intel generations,
but that could change... */
#define ELF_PLATFORM (NULL)
#endif
@@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_FIXMAP_H
#define __ASM_OPENRISC_FIXMAP_H
/* Why exactly do we need 2 empty pages between the top of the fixed
* addresses and the top of virtual memory? Something is using that
* memory space but not sure what right now... If you find it, leave
* a comment here.
*/
#define FIXADDR_TOP ((unsigned long) (-2*PAGE_SIZE))
#include <linux/kernel.h>
#include <linux/bug.h>
#include <asm/page.h>
enum fixed_addresses {
FIX_EARLYCON_MEM_BASE,
FIX_TEXT_POKE0,
__end_of_fixed_addresses
};
#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
/* FIXADDR_BOTTOM might be a better name here... */
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
#define FIXMAP_PAGE_IO PAGE_KERNEL_NOCACHE
extern void __set_fixmap(enum fixed_addresses idx,
phys_addr_t phys, pgprot_t flags);
#include <asm-generic/fixmap.h>
#endif
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_OPENRISC_FPU_H
#define __ASM_OPENRISC_FPU_H
struct task_struct;
#ifdef CONFIG_FPU
static inline void save_fpu(struct task_struct *task)
{
task->thread.fpcsr = mfspr(SPR_FPCSR);
}
static inline void restore_fpu(struct task_struct *task)
{
mtspr(SPR_FPCSR, task->thread.fpcsr);
}
#else
#define save_fpu(tsk) do { } while (0)
#define restore_fpu(tsk) do { } while (0)
#endif
#endif /* __ASM_OPENRISC_FPU_H */
@@ -0,0 +1,104 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_OPENRISC_FUTEX_H
#define __ASM_OPENRISC_FUTEX_H
#ifdef __KERNEL__
#include <linux/futex.h>
#include <linux/uaccess.h>
#include <asm/errno.h>
#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
({ \
__asm__ __volatile__ ( \
"1: l.lwa %0, %2 \n" \
insn "\n" \
"2: l.swa %2, %1 \n" \
" l.bnf 1b \n" \
" l.ori %1, r0, 0 \n" \
"3: \n" \
".section .fixup,\"ax\" \n" \
"4: l.j 3b \n" \
" l.addi %1, r0, %3 \n" \
".previous \n" \
".section __ex_table,\"a\" \n" \
".word 1b,4b,2b,4b \n" \
".previous \n" \
: "=&r" (oldval), "=&r" (ret), "+m" (*uaddr) \
: "i" (-EFAULT), "r" (oparg) \
: "cc", "memory" \
); \
})
static inline int
arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
{
int oldval = 0, ret;
if (!access_ok(uaddr, sizeof(u32)))
return -EFAULT;
switch (op) {
case FUTEX_OP_SET:
__futex_atomic_op("l.or %1,%4,%4", ret, oldval, uaddr, oparg);
break;
case FUTEX_OP_ADD:
__futex_atomic_op("l.add %1,%0,%4", ret, oldval, uaddr, oparg);
break;
case FUTEX_OP_OR:
__futex_atomic_op("l.or %1,%0,%4", ret, oldval, uaddr, oparg);
break;
case FUTEX_OP_ANDN:
__futex_atomic_op("l.and %1,%0,%4", ret, oldval, uaddr, ~oparg);
break;
case FUTEX_OP_XOR:
__futex_atomic_op("l.xor %1,%0,%4", ret, oldval, uaddr, oparg);
break;
default:
ret = -ENOSYS;
}
if (!ret)
*oval = oldval;
return ret;
}
static inline int
futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
u32 oldval, u32 newval)
{
int ret = 0;
u32 prev;
if (!access_ok(uaddr, sizeof(u32)))
return -EFAULT;
__asm__ __volatile__ ( \
"1: l.lwa %1, %2 \n" \
" l.sfeq %1, %3 \n" \
" l.bnf 3f \n" \
" l.nop \n" \
"2: l.swa %2, %4 \n" \
" l.bnf 1b \n" \
" l.nop \n" \
"3: \n" \
".section .fixup,\"ax\" \n" \
"4: l.j 3b \n" \
" l.addi %0, r0, %5 \n" \
".previous \n" \
".section __ex_table,\"a\" \n" \
".word 1b,4b,2b,4b \n" \
".previous \n" \
: "+r" (ret), "=&r" (prev), "+m" (*uaddr) \
: "r" (oldval), "r" (newval), "i" (-EFAULT) \
: "cc", "memory" \
);
*uval = prev;
return ret;
}
#endif /* __KERNEL__ */
#endif /* __ASM_OPENRISC_FUTEX_H */
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2025 Chen Miao
*/
#ifndef __ASM_OPENRISC_INSN_DEF_H
#define __ASM_OPENRISC_INSN_DEF_H
/* or1k instructions are always 32 bits. */
#define OPENRISC_INSN_SIZE 4
/* or1k nop instruction code */
#define OPENRISC_INSN_NOP 0x15000000U
#endif /* __ASM_OPENRISC_INSN_DEF_H */
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_IO_H
#define __ASM_OPENRISC_IO_H
#include <linux/types.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
/*
* PCI: We do not use IO ports in OpenRISC
*/
#define IO_SPACE_LIMIT 0
/* OpenRISC has no port IO */
#define HAVE_ARCH_PIO_SIZE 1
#define PIO_RESERVED 0X0UL
#define PIO_OFFSET 0
#define PIO_MASK 0
/*
* I/O memory mapping functions.
*/
#define _PAGE_IOREMAP (pgprot_val(PAGE_KERNEL) | _PAGE_CI)
#include <asm-generic/io.h>
#endif
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_IRQ_H__
#define __ASM_OPENRISC_IRQ_H__
#define NR_IRQS 32
#include <asm-generic/irq.h>
#define NO_IRQ (-1)
#endif /* __ASM_OPENRISC_IRQ_H__ */
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef ___ASM_OPENRISC_IRQFLAGS_H
#define ___ASM_OPENRISC_IRQFLAGS_H
#include <asm/spr_defs.h>
#define ARCH_IRQ_DISABLED 0x00
#define ARCH_IRQ_ENABLED (SPR_SR_IEE|SPR_SR_TEE)
#include <asm-generic/irqflags.h>
#endif /* ___ASM_OPENRISC_IRQFLAGS_H */
@@ -0,0 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2025 Chen Miao
*
* Based on arch/arm/include/asm/jump_label.h
*/
#ifndef __ASM_OPENRISC_JUMP_LABEL_H
#define __ASM_OPENRISC_JUMP_LABEL_H
#ifndef __ASSEMBLER__
#include <linux/types.h>
#include <asm/insn-def.h>
#define HAVE_JUMP_LABEL_BATCH
#define JUMP_LABEL_NOP_SIZE OPENRISC_INSN_SIZE
/**
* JUMP_TABLE_ENTRY - Create a jump table entry
* @key: Jump key identifier (typically a symbol address)
* @label: Target label address
*
* This macro creates a jump table entry in the dedicated kernel section (__jump_table).
* Each entry contains the following information:
* Offset from current instruction to jump instruction (1b - .)
* Offset from current instruction to target label (label - .)
* Offset from current instruction to key identifier (key - .)
*/
#define JUMP_TABLE_ENTRY(key, label) \
".pushsection __jump_table, \"aw\" \n\t" \
".align 4 \n\t" \
".long 1b - ., " label " - . \n\t" \
".long " key " - . \n\t" \
".popsection \n\t"
#define ARCH_STATIC_BRANCH_ASM(key, label) \
".align 4 \n\t" \
"1: l.nop \n\t" \
" l.nop \n\t" \
JUMP_TABLE_ENTRY(key, label)
static __always_inline bool arch_static_branch(struct static_key *const key,
const bool branch)
{
asm goto (ARCH_STATIC_BRANCH_ASM("%0", "%l[l_yes]")
::"i"(&((char *)key)[branch])::l_yes);
return false;
l_yes:
return true;
}
#define ARCH_STATIC_BRANCH_JUMP_ASM(key, label) \
".align 4 \n\t" \
"1: l.j " label " \n\t" \
" l.nop \n\t" \
JUMP_TABLE_ENTRY(key, label)
static __always_inline bool
arch_static_branch_jump(struct static_key *const key, const bool branch)
{
asm goto (ARCH_STATIC_BRANCH_JUMP_ASM("%0", "%l[l_yes]")
::"i"(&((char *)key)[branch])::l_yes);
return false;
l_yes:
return true;
}
#endif /* __ASSEMBLER__ */
#endif /* __ASM_OPENRISC_JUMP_LABEL_H */
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_LINKAGE_H
#define __ASM_OPENRISC_LINKAGE_H
#define __ALIGN .align 0
#define __ALIGN_STR ".align 0"
#endif /* __ASM_OPENRISC_LINKAGE_H */
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_MMU_H
#define __ASM_OPENRISC_MMU_H
#ifndef __ASSEMBLER__
typedef unsigned long mm_context_t;
#endif
#endif
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_MMU_CONTEXT_H
#define __ASM_OPENRISC_MMU_CONTEXT_H
#include <asm-generic/mm_hooks.h>
#define init_new_context init_new_context
extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
#define destroy_context destroy_context
extern void destroy_context(struct mm_struct *mm);
extern void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk);
#define activate_mm(prev, next) switch_mm((prev), (next), NULL)
/* current active pgd - this is similar to other processors pgd
* registers like cr3 on the i386
*/
extern volatile pgd_t *current_pgd[]; /* defined in arch/openrisc/mm/fault.c */
#include <asm-generic/mmu_context.h>
#endif
@@ -0,0 +1,80 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_PAGE_H
#define __ASM_OPENRISC_PAGE_H
#include <vdso/page.h>
#define PAGE_OFFSET 0xc0000000
#define KERNELBASE PAGE_OFFSET
/* This is not necessarily the right place for this, but it's needed by
* drivers/of/fdt.c
*/
#include <asm/setup.h>
#ifndef __ASSEMBLER__
#define clear_page(page) memset((page), 0, PAGE_SIZE)
#define copy_page(to, from) memcpy((to), (from), PAGE_SIZE)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
/*
* These are used to make use of C type-checking..
*/
typedef struct {
unsigned long pte;
} pte_t;
typedef struct {
unsigned long pgd;
} pgd_t;
typedef struct {
unsigned long pgprot;
} pgprot_t;
typedef struct page *pgtable_t;
#define pte_val(x) ((x).pte)
#define pgd_val(x) ((x).pgd)
#define pgprot_val(x) ((x).pgprot)
#define __pte(x) ((pte_t) { (x) })
#define __pgd(x) ((pgd_t) { (x) })
#define __pgprot(x) ((pgprot_t) { (x) })
#endif /* !__ASSEMBLER__ */
#ifndef __ASSEMBLER__
#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET)
static inline unsigned long virt_to_pfn(const void *kaddr)
{
return __pa(kaddr) >> PAGE_SHIFT;
}
#define virt_to_page(addr) \
(mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
#define virt_addr_valid(kaddr) (pfn_valid(virt_to_pfn(kaddr)))
#endif /* __ASSEMBLER__ */
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
#endif /* __ASM_OPENRISC_PAGE_H */
@@ -0,0 +1,70 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_PGALLOC_H
#define __ASM_OPENRISC_PGALLOC_H
#include <asm/page.h>
#include <linux/threads.h>
#include <linux/mm.h>
#include <linux/memblock.h>
#define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL
#include <asm-generic/pgalloc.h>
extern int mem_init_done;
#define pmd_populate_kernel(mm, pmd, pte) \
set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte)))
static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
struct page *pte)
{
set_pmd(pmd, __pmd(_KERNPG_TABLE +
((unsigned long)page_to_pfn(pte) <<
(unsigned long) PAGE_SHIFT)));
}
/*
* Allocate and free page tables.
*/
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
pgd_t *ret = __pgd_alloc(mm, 0);
if (ret)
memcpy(ret + USER_PTRS_PER_PGD,
swapper_pg_dir + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
return ret;
}
#if 0
/* FIXME: This seems to be the preferred style, but we are using
* current_pgd (from mm->pgd) to load kernel pages so we need it
* initialized. This needs to be looked into.
*/
extern inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
return (pgd_t *)get_zeroed_page(GFP_KERNEL);
}
#endif
extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm);
#define __pte_free_tlb(tlb, pte, addr) \
tlb_remove_ptdesc((tlb), page_ptdesc(pte))
#endif
@@ -0,0 +1,413 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
/* or1k pgtable.h - macros and functions to manipulate page tables
*
* Based on:
* include/asm-cris/pgtable.h
*/
#ifndef __ASM_OPENRISC_PGTABLE_H
#define __ASM_OPENRISC_PGTABLE_H
#include <asm-generic/pgtable-nopmd.h>
#ifndef __ASSEMBLER__
#include <asm/mmu.h>
#include <asm/fixmap.h>
/*
* The Linux memory management assumes a three-level page table setup. On
* or1k, we use that, but "fold" the mid level into the top-level page
* table. Since the MMU TLB is software loaded through an interrupt, it
* supports any page table structure, so we could have used a three-level
* setup, but for the amounts of memory we normally use, a two-level is
* probably more efficient.
*
* This file contains the functions and defines necessary to modify and use
* the or1k page table tree.
*/
extern void paging_init(void);
/* Certain architectures need to do special things when pte's
* within a page table are directly modified. Thus, the following
* hook is made available.
*/
#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
/*
* (pmds are folded into pgds so this doesn't get actually called,
* but the define is needed for a generic inline function.)
*/
#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
#define PGDIR_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-2))
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
/*
* entries per page directory level: we use a two-level, so
* we don't really have any PMD directory physically.
* pointers are 4 bytes so we can use the page size and
* divide it by 4 (shift by 2).
*/
#define PTRS_PER_PTE (1UL << (PAGE_SHIFT-2))
#define PTRS_PER_PGD (1UL << (32-PGDIR_SHIFT))
/* calculate how many PGD entries a user-level program can use
* the first mappable virtual address is 0
* (TASK_SIZE is the maximum virtual address space)
*/
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
/*
* Kernels own virtual memory area.
*/
/*
* The size and location of the vmalloc area are chosen so that modules
* placed in this area aren't more than a 28-bit signed offset from any
* kernel functions that they may need. This greatly simplifies handling
* of the relocations for l.j and l.jal instructions as we don't need to
* introduce any trampolines for reaching "distant" code.
*
* 64 MB of vmalloc area is comparable to what's available on other arches.
*/
#define VMALLOC_START (PAGE_OFFSET-0x04000000UL)
#define VMALLOC_END (PAGE_OFFSET)
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
/* Define some higher level generic page attributes.
*
* If you change _PAGE_CI definition be sure to change it in
* io.h for ioremap() too.
*/
/*
* An OR32 PTE looks like this:
*
* | 31 ... 10 | 9 | 8 ... 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* Phys pg.num L PP Index D A WOM WBC CI CC
*
* L : link
* PPI: Page protection index
* D : Dirty
* A : Accessed
* WOM: Weakly ordered memory
* WBC: Write-back cache
* CI : Cache inhibit
* CC : Cache coherent
*
* The protection bits below should correspond to the layout of the actual
* PTE as per above
*/
#define _PAGE_CC 0x001 /* software: pte contains a translation */
#define _PAGE_CI 0x002 /* cache inhibit */
#define _PAGE_WBC 0x004 /* write back cache */
#define _PAGE_WOM 0x008 /* weakly ordered memory */
#define _PAGE_A 0x010 /* accessed */
#define _PAGE_D 0x020 /* dirty */
#define _PAGE_URE 0x040 /* user read enable */
#define _PAGE_UWE 0x080 /* user write enable */
#define _PAGE_SRE 0x100 /* superuser read enable */
#define _PAGE_SWE 0x200 /* superuser write enable */
#define _PAGE_EXEC 0x400 /* software: page is executable */
#define _PAGE_U_SHARED 0x800 /* software: page is shared in user space */
/* 0x001 is cache coherency bit, which should always be set to
* 1 - for SMP (when we support it)
* 0 - otherwise
*
* we just reuse this bit in software for _PAGE_PRESENT and
* force it to 0 when loading it into TLB.
*/
#define _PAGE_PRESENT _PAGE_CC
#define _PAGE_USER _PAGE_URE
#define _PAGE_WRITE (_PAGE_UWE | _PAGE_SWE)
#define _PAGE_DIRTY _PAGE_D
#define _PAGE_ACCESSED _PAGE_A
#define _PAGE_NO_CACHE _PAGE_CI
#define _PAGE_SHARED _PAGE_U_SHARED
#define _PAGE_READ (_PAGE_URE | _PAGE_SRE)
#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED)
#define _PAGE_ALL (_PAGE_PRESENT | _PAGE_ACCESSED)
#define _KERNPG_TABLE \
(_PAGE_BASE | _PAGE_SRE | _PAGE_SWE | _PAGE_ACCESSED | _PAGE_DIRTY)
/* We borrow bit 11 to store the exclusive marker in swap PTEs. */
#define _PAGE_SWP_EXCLUSIVE _PAGE_U_SHARED
#define PAGE_NONE __pgprot(_PAGE_ALL)
#define PAGE_READONLY __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE)
#define PAGE_READONLY_X __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_EXEC)
#define PAGE_SHARED \
__pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_UWE | _PAGE_SWE \
| _PAGE_SHARED)
#define PAGE_SHARED_X \
__pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_UWE | _PAGE_SWE \
| _PAGE_SHARED | _PAGE_EXEC)
#define PAGE_COPY __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE)
#define PAGE_COPY_X __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_EXEC)
#define PAGE_KERNEL \
__pgprot(_PAGE_ALL | _PAGE_SRE | _PAGE_SWE \
| _PAGE_SHARED | _PAGE_DIRTY | _PAGE_EXEC)
#define PAGE_KERNEL_RO \
__pgprot(_PAGE_ALL | _PAGE_SRE \
| _PAGE_SHARED | _PAGE_DIRTY | _PAGE_EXEC)
#define PAGE_KERNEL_NOCACHE \
__pgprot(_PAGE_ALL | _PAGE_SRE | _PAGE_SWE \
| _PAGE_SHARED | _PAGE_DIRTY | _PAGE_EXEC | _PAGE_CI)
#define pte_none(x) (!pte_val(x))
#define pte_present(x) (pte_val(x) & _PAGE_PRESENT)
#define pte_clear(mm, addr, xp) do { pte_val(*(xp)) = 0; } while (0)
#define pmd_none(x) (!pmd_val(x))
#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK)) != _KERNPG_TABLE)
#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
#define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0)
/*
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; }
static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; }
static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; }
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline pte_t pte_wrprotect(pte_t pte)
{
pte_val(pte) &= ~(_PAGE_WRITE);
return pte;
}
static inline pte_t pte_rdprotect(pte_t pte)
{
pte_val(pte) &= ~(_PAGE_READ);
return pte;
}
static inline pte_t pte_exprotect(pte_t pte)
{
pte_val(pte) &= ~(_PAGE_EXEC);
return pte;
}
static inline pte_t pte_mkclean(pte_t pte)
{
pte_val(pte) &= ~(_PAGE_DIRTY);
return pte;
}
static inline pte_t pte_mkold(pte_t pte)
{
pte_val(pte) &= ~(_PAGE_ACCESSED);
return pte;
}
static inline pte_t pte_mkwrite_novma(pte_t pte)
{
pte_val(pte) |= _PAGE_WRITE;
return pte;
}
static inline pte_t pte_mkread(pte_t pte)
{
pte_val(pte) |= _PAGE_READ;
return pte;
}
static inline pte_t pte_mkexec(pte_t pte)
{
pte_val(pte) |= _PAGE_EXEC;
return pte;
}
static inline pte_t pte_mkdirty(pte_t pte)
{
pte_val(pte) |= _PAGE_DIRTY;
return pte;
}
static inline pte_t pte_mkyoung(pte_t pte)
{
pte_val(pte) |= _PAGE_ACCESSED;
return pte;
}
/*
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
*/
/* What actually goes as arguments to the various functions is less than
* obvious, but a rule of thumb is that struct page's goes as struct page *,
* really physical DRAM addresses are unsigned long's, and DRAM "virtual"
* addresses (the 0xc0xxxxxx's) goes as void *'s.
*/
static inline pte_t __mk_pte(void *page, pgprot_t pgprot)
{
pte_t pte;
/* the PTE needs a physical address */
pte_val(pte) = __pa(page) | pgprot_val(pgprot);
return pte;
}
#define mk_pte_phys(physpage, pgprot) \
({ \
pte_t __pte; \
\
pte_val(__pte) = (physpage) + pgprot_val(pgprot); \
__pte; \
})
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
return pte;
}
/*
* pte_val refers to a page in the 0x0xxxxxxx physical DRAM interval
* __pte_page(pte_val) refers to the "virtual" DRAM interval
* pte_pagenr refers to the page-number counted starting from the virtual
* DRAM start
*/
static inline unsigned long __pte_page(pte_t pte)
{
/* the PTE contains a physical address */
return (unsigned long)__va(pte_val(pte) & PAGE_MASK);
}
#define pte_pagenr(pte) ((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT)
/* permanent address of a page */
#define __page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
#define pte_page(pte) (mem_map+pte_pagenr(pte))
/*
* only the pte's themselves need to point to physical DRAM (see above)
* the pagetable links are purely handled within the kernel SW and thus
* don't need the __pa and __va transformations.
*/
static inline void pmd_set(pmd_t *pmdp, pte_t *ptep)
{
pmd_val(*pmdp) = _KERNPG_TABLE | (unsigned long) ptep;
}
#define pmd_pfn(pmd) (pmd_val(pmd) >> PAGE_SHIFT)
#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
static inline unsigned long pmd_page_vaddr(pmd_t pmd)
{
return ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK));
}
#define __pmd_offset(address) \
(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
#define PFN_PTE_SHIFT PAGE_SHIFT
#define pte_pfn(x) ((unsigned long)(((x).pte)) >> PAGE_SHIFT)
#define pfn_pte(pfn, prot) __pte((((pfn) << PAGE_SHIFT)) | pgprot_val(prot))
#define pte_ERROR(e) \
printk(KERN_ERR "%s:%d: bad pte %p(%08lx).\n", \
__FILE__, __LINE__, &(e), pte_val(e))
#define pgd_ERROR(e) \
printk(KERN_ERR "%s:%d: bad pgd %p(%08lx).\n", \
__FILE__, __LINE__, &(e), pgd_val(e))
extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */
struct vm_area_struct;
static inline void update_tlb(struct vm_area_struct *vma,
unsigned long address, pte_t *pte)
{
}
extern void update_cache(struct vm_area_struct *vma,
unsigned long address, pte_t *pte);
static inline void update_mmu_cache_range(struct vm_fault *vmf,
struct vm_area_struct *vma, unsigned long address,
pte_t *ptep, unsigned int nr)
{
update_tlb(vma, address, ptep);
update_cache(vma, address, ptep);
}
#define update_mmu_cache(vma, addr, ptep) \
update_mmu_cache_range(NULL, vma, addr, ptep, 1)
/* __PHX__ FIXME, SWAP, this probably doesn't work */
/*
* Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that
* are !pte_none() && !pte_present().
*
* Format of swap PTEs:
*
* 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* <-------------- offset ---------------> E <- type --> 0 0 0 0 0
*
* E is the exclusive marker that is not stored in swap entries.
* The zero'ed bits include _PAGE_PRESENT.
*/
#define __swp_type(x) (((x).val >> 5) & 0x3f)
#define __swp_offset(x) ((x).val >> 12)
#define __swp_entry(type, offset) \
((swp_entry_t) { (((type) & 0x3f) << 5) | ((offset) << 12) })
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
static inline bool pte_swp_exclusive(pte_t pte)
{
return pte_val(pte) & _PAGE_SWP_EXCLUSIVE;
}
static inline pte_t pte_swp_mkexclusive(pte_t pte)
{
pte_val(pte) |= _PAGE_SWP_EXCLUSIVE;
return pte;
}
static inline pte_t pte_swp_clear_exclusive(pte_t pte)
{
pte_val(pte) &= ~_PAGE_SWP_EXCLUSIVE;
return pte;
}
typedef pte_t *pte_addr_t;
#endif /* __ASSEMBLER__ */
#endif /* __ASM_OPENRISC_PGTABLE_H */
@@ -0,0 +1,84 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_PROCESSOR_H
#define __ASM_OPENRISC_PROCESSOR_H
#include <asm/spr_defs.h>
#include <asm/page.h>
#include <asm/ptrace.h>
#define STACK_TOP TASK_SIZE
#define STACK_TOP_MAX STACK_TOP
/* Kernel and user SR register setting */
#define KERNEL_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_ICE \
| SPR_SR_DCE | SPR_SR_SM)
#define USER_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_ICE \
| SPR_SR_DCE | SPR_SR_IEE | SPR_SR_TEE)
/* SR bits user space may change via sigreturn, the rest stay kernel owned */
#define SPR_SR_USER_MASK (SPR_SR_F | SPR_SR_CY | SPR_SR_OV)
/*
* User space process size. This is hardcoded into a few places,
* so don't change it unless you know what you are doing.
*/
#define TASK_SIZE (0x80000000UL)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
#define TASK_UNMAPPED_BASE (TASK_SIZE / 8 * 3)
#ifndef __ASSEMBLER__
struct task_struct;
struct thread_struct {
long fpcsr; /* Floating point control status register. */
};
/*
* At user->kernel entry, the pt_regs struct is stacked on the top of the
* kernel-stack. This macro allows us to find those regs for a task.
* Notice that subsequent pt_regs stackings, like recursive interrupts
* occurring while we're in the kernel, won't affect this - only the first
* user->kernel transition registers are reached by this (i.e. not regs
* for running signal handler)
*/
#define user_regs(thread_info) (((struct pt_regs *)((unsigned long)(thread_info) + THREAD_SIZE - STACK_FRAME_OVERHEAD)) - 1)
/*
* Dito but for the currently running task
*/
#define task_pt_regs(task) user_regs(task_thread_info(task))
#define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack)
#define INIT_THREAD { }
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
#define KSTK_ESP(tsk) (task_pt_regs(tsk)->sp)
void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp);
unsigned long __get_wchan(struct task_struct *p);
void show_registers(struct pt_regs *regs);
#define cpu_relax() barrier()
#endif /* __ASSEMBLER__ */
#endif /* __ASM_OPENRISC_PROCESSOR_H */
@@ -0,0 +1,190 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_PTRACE_H
#define __ASM_OPENRISC_PTRACE_H
#include <asm/spr_defs.h>
#include <uapi/asm/ptrace.h>
#include <linux/compiler.h>
/*
* Make kernel PTrace/register structures opaque to userspace... userspace can
* access thread state via the regset mechanism. This allows us a bit of
* flexibility in how we order the registers on the stack, permitting some
* optimizations like packing call-clobbered registers together so that
* they share a cacheline (not done yet, though... future optimization).
*/
#ifndef __ASSEMBLER__
/*
* This struct describes how the registers are laid out on the kernel stack
* during a syscall or other kernel entry.
*
* This structure should always be cacheline aligned on the stack.
* FIXME: I don't think that's the case right now. The alignment is
* taken care of elsewhere... head.S, process.c, etc.
*/
struct pt_regs {
union {
struct {
/* Named registers */
long sr; /* Stored in place of r0 */
long sp; /* r1 */
long gpr2;
long gpr3;
long gpr4;
long gpr5;
long gpr6;
long gpr7;
long gpr8;
long gpr9;
long gpr10;
long gpr11;
long gpr12;
long gpr13;
long gpr14;
long gpr15;
long gpr16;
long gpr17;
long gpr18;
long gpr19;
long gpr20;
long gpr21;
long gpr22;
long gpr23;
long gpr24;
long gpr25;
long gpr26;
long gpr27;
long gpr28;
long gpr29;
long gpr30;
long gpr31;
};
struct {
/* Old style */
long offset[2];
long gprs[30];
};
struct {
/* New style */
long gpr[32];
};
};
long pc;
/* For restarting system calls:
* Set to syscall number for syscall exceptions,
* -1 for all other exceptions.
*/
long orig_gpr11; /* For restarting system calls */
long dummy; /* Cheap alignment fix */
long dummy2; /* Cheap alignment fix */
};
/* TODO: Rename this to REDZONE because that's what it is */
#define STACK_FRAME_OVERHEAD 128 /* size of minimum stack frame */
#define MAX_REG_OFFSET offsetof(struct pt_regs, orig_gpr11)
/* Helpers for working with the instruction pointer */
static inline unsigned long instruction_pointer(struct pt_regs *regs)
{
return (unsigned long)regs->pc;
}
static inline void instruction_pointer_set(struct pt_regs *regs,
unsigned long val)
{
regs->pc = val;
}
#define user_mode(regs) (((regs)->sr & SPR_SR_SM) == 0)
#define user_stack_pointer(regs) ((unsigned long)(regs)->sp)
#define profile_pc(regs) instruction_pointer(regs)
/* Valid only for Kernel mode traps. */
static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
{
return (unsigned long)regs->sp;
}
static inline long regs_return_value(struct pt_regs *regs)
{
return regs->gpr[11];
}
extern int regs_query_register_offset(const char *name);
extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
unsigned int n);
/**
* regs_get_register() - get register value from its offset
* @regs: pt_regs from which register value is gotten
* @offset: offset of the register.
*
* regs_get_register returns the value of a register whose offset from @regs.
* The @offset is the offset of the register in struct pt_regs.
* If @offset is bigger than MAX_REG_OFFSET, this returns 0.
*/
static inline unsigned long regs_get_register(struct pt_regs *regs,
unsigned int offset)
{
if (unlikely(offset > MAX_REG_OFFSET))
return 0;
return *(unsigned long *)((unsigned long)regs + offset);
}
#endif /* __ASSEMBLER__ */
/*
* Offsets used by 'ptrace' system call interface.
*/
#define PT_SR 0
#define PT_SP 4
#define PT_GPR2 8
#define PT_GPR3 12
#define PT_GPR4 16
#define PT_GPR5 20
#define PT_GPR6 24
#define PT_GPR7 28
#define PT_GPR8 32
#define PT_GPR9 36
#define PT_GPR10 40
#define PT_GPR11 44
#define PT_GPR12 48
#define PT_GPR13 52
#define PT_GPR14 56
#define PT_GPR15 60
#define PT_GPR16 64
#define PT_GPR17 68
#define PT_GPR18 72
#define PT_GPR19 76
#define PT_GPR20 80
#define PT_GPR21 84
#define PT_GPR22 88
#define PT_GPR23 92
#define PT_GPR24 96
#define PT_GPR25 100
#define PT_GPR26 104
#define PT_GPR27 108
#define PT_GPR28 112
#define PT_GPR29 116
#define PT_GPR30 120
#define PT_GPR31 124
#define PT_PC 128
#define PT_ORIG_GPR11 132
#endif /* __ASM_OPENRISC_PTRACE_H */
@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_SERIAL_H
#define __ASM_OPENRISC_SERIAL_H
#ifdef __KERNEL__
#include <asm/cpuinfo.h>
/* There's a generic version of this file, but it assumes a 1.8MHz UART clk...
* this, on the other hand, assumes the UART clock is tied to the system
* clock... 8250_early.c (early 8250 serial console) actually uses this, so
* it needs to be correct to get the early console working.
*/
#define BASE_BAUD (cpuinfo_or1k[smp_processor_id()].clock_frequency/16)
#endif /* __KERNEL__ */
#endif /* __ASM_OPENRISC_SERIAL_H */
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2021 Stafford Horne
*/
#ifndef _ASM_OR1K_SETUP_H
#define _ASM_OR1K_SETUP_H
#include <linux/init.h>
#include <asm-generic/setup.h>
#ifndef __ASSEMBLER__
void __init or1k_early_setup(void *fdt);
#endif
#endif /* _ASM_OR1K_SETUP_H */
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#ifndef __ASM_OPENRISC_SMP_H
#define __ASM_OPENRISC_SMP_H
#include <asm/spr.h>
#include <asm/spr_defs.h>
#define raw_smp_processor_id() (current_thread_info()->cpu)
#define hard_smp_processor_id() mfspr(SPR_COREID)
extern void smp_init_cpus(void);
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int),
unsigned int irq);
extern void handle_IPI(unsigned int ipi_msg);
#endif /* __ASM_OPENRISC_SMP_H */
@@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#ifndef __ASM_OPENRISC_SPR_H
#define __ASM_OPENRISC_SPR_H
#define mtspr(_spr, _val) __asm__ __volatile__ ( \
"l.mtspr r0,%1,%0" \
: : "K" (_spr), "r" (_val))
#define mtspr_off(_spr, _off, _val) __asm__ __volatile__ ( \
"l.mtspr %0,%1,%2" \
: : "r" (_off), "r" (_val), "K" (_spr))
static inline unsigned long mfspr(unsigned long add)
{
unsigned long ret;
__asm__ __volatile__ ("l.mfspr %0,r0,%1" : "=r" (ret) : "K" (add));
return ret;
}
static inline unsigned long mfspr_off(unsigned long add, unsigned long offset)
{
unsigned long ret;
__asm__ __volatile__ ("l.mfspr %0,%1,%2" : "=r" (ret)
: "r" (offset), "K" (add));
return ret;
}
#endif
@@ -0,0 +1,614 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* SPR Definitions
*
* Copyright (C) 2000 Damjan Lampret
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2008, 2010 Embecosm Limited
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*
* This file is part of OpenRISC 1000 Architectural Simulator.
*/
#ifndef SPR_DEFS__H
#define SPR_DEFS__H
/* Definition of special-purpose registers (SPRs). */
#define MAX_GRPS (32)
#define MAX_SPRS_PER_GRP_BITS (11)
#define MAX_SPRS_PER_GRP (1 << MAX_SPRS_PER_GRP_BITS)
#define MAX_SPRS (0x10000)
/* Base addresses for the groups */
#define SPRGROUP_SYS (0 << MAX_SPRS_PER_GRP_BITS)
#define SPRGROUP_DMMU (1 << MAX_SPRS_PER_GRP_BITS)
#define SPRGROUP_IMMU (2 << MAX_SPRS_PER_GRP_BITS)
#define SPRGROUP_DC (3 << MAX_SPRS_PER_GRP_BITS)
#define SPRGROUP_IC (4 << MAX_SPRS_PER_GRP_BITS)
#define SPRGROUP_MAC (5 << MAX_SPRS_PER_GRP_BITS)
#define SPRGROUP_D (6 << MAX_SPRS_PER_GRP_BITS)
#define SPRGROUP_PC (7 << MAX_SPRS_PER_GRP_BITS)
#define SPRGROUP_PM (8 << MAX_SPRS_PER_GRP_BITS)
#define SPRGROUP_PIC (9 << MAX_SPRS_PER_GRP_BITS)
#define SPRGROUP_TT (10 << MAX_SPRS_PER_GRP_BITS)
#define SPRGROUP_FP (11 << MAX_SPRS_PER_GRP_BITS)
/* System control and status group */
#define SPR_VR (SPRGROUP_SYS + 0)
#define SPR_UPR (SPRGROUP_SYS + 1)
#define SPR_CPUCFGR (SPRGROUP_SYS + 2)
#define SPR_DMMUCFGR (SPRGROUP_SYS + 3)
#define SPR_IMMUCFGR (SPRGROUP_SYS + 4)
#define SPR_DCCFGR (SPRGROUP_SYS + 5)
#define SPR_ICCFGR (SPRGROUP_SYS + 6)
#define SPR_DCFGR (SPRGROUP_SYS + 7)
#define SPR_PCCFGR (SPRGROUP_SYS + 8)
#define SPR_VR2 (SPRGROUP_SYS + 9)
#define SPR_AVR (SPRGROUP_SYS + 10)
#define SPR_EVBAR (SPRGROUP_SYS + 11)
#define SPR_AECR (SPRGROUP_SYS + 12)
#define SPR_AESR (SPRGROUP_SYS + 13)
#define SPR_NPC (SPRGROUP_SYS + 16) /* CZ 21/06/01 */
#define SPR_SR (SPRGROUP_SYS + 17) /* CZ 21/06/01 */
#define SPR_PPC (SPRGROUP_SYS + 18) /* CZ 21/06/01 */
#define SPR_FPCSR (SPRGROUP_SYS + 20) /* CZ 21/06/01 */
#define SPR_EPCR_BASE (SPRGROUP_SYS + 32) /* CZ 21/06/01 */
#define SPR_EPCR_LAST (SPRGROUP_SYS + 47) /* CZ 21/06/01 */
#define SPR_EEAR_BASE (SPRGROUP_SYS + 48)
#define SPR_EEAR_LAST (SPRGROUP_SYS + 63)
#define SPR_ESR_BASE (SPRGROUP_SYS + 64)
#define SPR_ESR_LAST (SPRGROUP_SYS + 79)
#define SPR_COREID (SPRGROUP_SYS + 128)
#define SPR_NUMCORES (SPRGROUP_SYS + 129)
#define SPR_GPR_BASE (SPRGROUP_SYS + 1024)
/* Data MMU group */
#define SPR_DMMUCR (SPRGROUP_DMMU + 0)
#define SPR_DTLBEIR (SPRGROUP_DMMU + 2)
#define SPR_DTLBMR_BASE(WAY) (SPRGROUP_DMMU + 0x200 + (WAY) * 0x100)
#define SPR_DTLBMR_LAST(WAY) (SPRGROUP_DMMU + 0x27f + (WAY) * 0x100)
#define SPR_DTLBTR_BASE(WAY) (SPRGROUP_DMMU + 0x280 + (WAY) * 0x100)
#define SPR_DTLBTR_LAST(WAY) (SPRGROUP_DMMU + 0x2ff + (WAY) * 0x100)
/* Instruction MMU group */
#define SPR_IMMUCR (SPRGROUP_IMMU + 0)
#define SPR_ITLBEIR (SPRGROUP_IMMU + 2)
#define SPR_ITLBMR_BASE(WAY) (SPRGROUP_IMMU + 0x200 + (WAY) * 0x100)
#define SPR_ITLBMR_LAST(WAY) (SPRGROUP_IMMU + 0x27f + (WAY) * 0x100)
#define SPR_ITLBTR_BASE(WAY) (SPRGROUP_IMMU + 0x280 + (WAY) * 0x100)
#define SPR_ITLBTR_LAST(WAY) (SPRGROUP_IMMU + 0x2ff + (WAY) * 0x100)
/* Data cache group */
#define SPR_DCCR (SPRGROUP_DC + 0)
#define SPR_DCBPR (SPRGROUP_DC + 1)
#define SPR_DCBFR (SPRGROUP_DC + 2)
#define SPR_DCBIR (SPRGROUP_DC + 3)
#define SPR_DCBWR (SPRGROUP_DC + 4)
#define SPR_DCBLR (SPRGROUP_DC + 5)
#define SPR_DCR_BASE(WAY) (SPRGROUP_DC + 0x200 + (WAY) * 0x200)
#define SPR_DCR_LAST(WAY) (SPRGROUP_DC + 0x3ff + (WAY) * 0x200)
/* Instruction cache group */
#define SPR_ICCR (SPRGROUP_IC + 0)
#define SPR_ICBPR (SPRGROUP_IC + 1)
#define SPR_ICBIR (SPRGROUP_IC + 2)
#define SPR_ICBLR (SPRGROUP_IC + 3)
#define SPR_ICR_BASE(WAY) (SPRGROUP_IC + 0x200 + (WAY) * 0x200)
#define SPR_ICR_LAST(WAY) (SPRGROUP_IC + 0x3ff + (WAY) * 0x200)
/* MAC group */
#define SPR_MACLO (SPRGROUP_MAC + 1)
#define SPR_MACHI (SPRGROUP_MAC + 2)
/* Debug group */
#define SPR_DVR(N) (SPRGROUP_D + (N))
#define SPR_DCR(N) (SPRGROUP_D + 8 + (N))
#define SPR_DMR1 (SPRGROUP_D + 16)
#define SPR_DMR2 (SPRGROUP_D + 17)
#define SPR_DWCR0 (SPRGROUP_D + 18)
#define SPR_DWCR1 (SPRGROUP_D + 19)
#define SPR_DSR (SPRGROUP_D + 20)
#define SPR_DRR (SPRGROUP_D + 21)
/* Performance counters group */
#define SPR_PCCR(N) (SPRGROUP_PC + (N))
#define SPR_PCMR(N) (SPRGROUP_PC + 8 + (N))
/* Power management group */
#define SPR_PMR (SPRGROUP_PM + 0)
/* PIC group */
#define SPR_PICMR (SPRGROUP_PIC + 0)
#define SPR_PICPR (SPRGROUP_PIC + 1)
#define SPR_PICSR (SPRGROUP_PIC + 2)
/* Tick Timer group */
#define SPR_TTMR (SPRGROUP_TT + 0)
#define SPR_TTCR (SPRGROUP_TT + 1)
/*
* Bit definitions for the Version Register
*
*/
#define SPR_VR_VER 0xff000000 /* Processor version */
#define SPR_VR_CFG 0x00ff0000 /* Processor configuration */
#define SPR_VR_RES 0x0000ffc0 /* Reserved */
#define SPR_VR_REV 0x0000003f /* Processor revision */
#define SPR_VR_UVRP 0x00000040 /* Updated Version Registers Present */
#define SPR_VR_VER_OFF 24
#define SPR_VR_CFG_OFF 16
#define SPR_VR_REV_OFF 0
/*
* Bit definitions for the Version Register 2
*/
#define SPR_VR2_CPUID 0xff000000 /* Processor ID */
#define SPR_VR2_VER 0x00ffffff /* Processor version */
/*
* Bit definitions for the Unit Present Register
*
*/
#define SPR_UPR_UP 0x00000001 /* UPR present */
#define SPR_UPR_DCP 0x00000002 /* Data cache present */
#define SPR_UPR_ICP 0x00000004 /* Instruction cache present */
#define SPR_UPR_DMP 0x00000008 /* Data MMU present */
#define SPR_UPR_IMP 0x00000010 /* Instruction MMU present */
#define SPR_UPR_MP 0x00000020 /* MAC present */
#define SPR_UPR_DUP 0x00000040 /* Debug unit present */
#define SPR_UPR_PCUP 0x00000080 /* Performance counters unit present */
#define SPR_UPR_PICP 0x00000100 /* PIC present */
#define SPR_UPR_PMP 0x00000200 /* Power management present */
#define SPR_UPR_TTP 0x00000400 /* Tick timer present */
#define SPR_UPR_RES 0x00fe0000 /* Reserved */
#define SPR_UPR_CUP 0xff000000 /* Context units present */
/*
* JPB: Bit definitions for the CPU configuration register
*
*/
#define SPR_CPUCFGR_NSGF 0x0000000f /* Number of shadow GPR files */
#define SPR_CPUCFGR_CGF 0x00000010 /* Custom GPR file */
#define SPR_CPUCFGR_OB32S 0x00000020 /* ORBIS32 supported */
#define SPR_CPUCFGR_OB64S 0x00000040 /* ORBIS64 supported */
#define SPR_CPUCFGR_OF32S 0x00000080 /* ORFPX32 supported */
#define SPR_CPUCFGR_OF64S 0x00000100 /* ORFPX64 supported */
#define SPR_CPUCFGR_OV64S 0x00000200 /* ORVDX64 supported */
#define SPR_CPUCFGR_RES 0xfffffc00 /* Reserved */
/*
* JPB: Bit definitions for the Debug configuration register and other
* constants.
*
*/
#define SPR_DCFGR_NDP 0x00000007 /* Number of matchpoints mask */
#define SPR_DCFGR_NDP1 0x00000000 /* One matchpoint supported */
#define SPR_DCFGR_NDP2 0x00000001 /* Two matchpoints supported */
#define SPR_DCFGR_NDP3 0x00000002 /* Three matchpoints supported */
#define SPR_DCFGR_NDP4 0x00000003 /* Four matchpoints supported */
#define SPR_DCFGR_NDP5 0x00000004 /* Five matchpoints supported */
#define SPR_DCFGR_NDP6 0x00000005 /* Six matchpoints supported */
#define SPR_DCFGR_NDP7 0x00000006 /* Seven matchpoints supported */
#define SPR_DCFGR_NDP8 0x00000007 /* Eight matchpoints supported */
#define SPR_DCFGR_WPCI 0x00000008 /* Watchpoint counters implemented */
#define MATCHPOINTS_TO_NDP(n) (1 == n ? SPR_DCFGR_NDP1 : \
2 == n ? SPR_DCFGR_NDP2 : \
3 == n ? SPR_DCFGR_NDP3 : \
4 == n ? SPR_DCFGR_NDP4 : \
5 == n ? SPR_DCFGR_NDP5 : \
6 == n ? SPR_DCFGR_NDP6 : \
7 == n ? SPR_DCFGR_NDP7 : SPR_DCFGR_NDP8)
#define MAX_MATCHPOINTS 8
#define MAX_WATCHPOINTS (MAX_MATCHPOINTS + 2)
/*
* Bit definitions for the Supervision Register
*
*/
#define SPR_SR_SM 0x00000001 /* Supervisor Mode */
#define SPR_SR_TEE 0x00000002 /* Tick timer Exception Enable */
#define SPR_SR_IEE 0x00000004 /* Interrupt Exception Enable */
#define SPR_SR_DCE 0x00000008 /* Data Cache Enable */
#define SPR_SR_ICE 0x00000010 /* Instruction Cache Enable */
#define SPR_SR_DME 0x00000020 /* Data MMU Enable */
#define SPR_SR_IME 0x00000040 /* Instruction MMU Enable */
#define SPR_SR_LEE 0x00000080 /* Little Endian Enable */
#define SPR_SR_CE 0x00000100 /* CID Enable */
#define SPR_SR_F 0x00000200 /* Condition Flag */
#define SPR_SR_CY 0x00000400 /* Carry flag */
#define SPR_SR_OV 0x00000800 /* Overflow flag */
#define SPR_SR_OVE 0x00001000 /* Overflow flag Exception */
#define SPR_SR_DSX 0x00002000 /* Delay Slot Exception */
#define SPR_SR_EPH 0x00004000 /* Exception Prefix High */
#define SPR_SR_FO 0x00008000 /* Fixed one */
#define SPR_SR_SUMRA 0x00010000 /* Supervisor SPR read access */
#define SPR_SR_RES 0x0ffe0000 /* Reserved */
#define SPR_SR_CID 0xf0000000 /* Context ID */
/*
* Bit definitions for the Data MMU Control Register
*
*/
#define SPR_DMMUCR_P2S 0x0000003e /* Level 2 Page Size */
#define SPR_DMMUCR_P1S 0x000007c0 /* Level 1 Page Size */
#define SPR_DMMUCR_VADDR_WIDTH 0x0000f800 /* Virtual ADDR Width */
#define SPR_DMMUCR_PADDR_WIDTH 0x000f0000 /* Physical ADDR Width */
/*
* Bit definitions for the Instruction MMU Control Register
*
*/
#define SPR_IMMUCR_P2S 0x0000003e /* Level 2 Page Size */
#define SPR_IMMUCR_P1S 0x000007c0 /* Level 1 Page Size */
#define SPR_IMMUCR_VADDR_WIDTH 0x0000f800 /* Virtual ADDR Width */
#define SPR_IMMUCR_PADDR_WIDTH 0x000f0000 /* Physical ADDR Width */
/*
* Bit definitions for the Data TLB Match Register
*
*/
#define SPR_DTLBMR_V 0x00000001 /* Valid */
#define SPR_DTLBMR_PL1 0x00000002 /* Page Level 1 (if 0 then PL2) */
#define SPR_DTLBMR_CID 0x0000003c /* Context ID */
#define SPR_DTLBMR_LRU 0x000000c0 /* Least Recently Used */
#define SPR_DTLBMR_VPN 0xfffff000 /* Virtual Page Number */
/*
* Bit definitions for the Data TLB Translate Register
*
*/
#define SPR_DTLBTR_CC 0x00000001 /* Cache Coherency */
#define SPR_DTLBTR_CI 0x00000002 /* Cache Inhibit */
#define SPR_DTLBTR_WBC 0x00000004 /* Write-Back Cache */
#define SPR_DTLBTR_WOM 0x00000008 /* Weakly-Ordered Memory */
#define SPR_DTLBTR_A 0x00000010 /* Accessed */
#define SPR_DTLBTR_D 0x00000020 /* Dirty */
#define SPR_DTLBTR_URE 0x00000040 /* User Read Enable */
#define SPR_DTLBTR_UWE 0x00000080 /* User Write Enable */
#define SPR_DTLBTR_SRE 0x00000100 /* Supervisor Read Enable */
#define SPR_DTLBTR_SWE 0x00000200 /* Supervisor Write Enable */
#define SPR_DTLBTR_PPN 0xfffff000 /* Physical Page Number */
/*
* Bit definitions for the Instruction TLB Match Register
*
*/
#define SPR_ITLBMR_V 0x00000001 /* Valid */
#define SPR_ITLBMR_PL1 0x00000002 /* Page Level 1 (if 0 then PL2) */
#define SPR_ITLBMR_CID 0x0000003c /* Context ID */
#define SPR_ITLBMR_LRU 0x000000c0 /* Least Recently Used */
#define SPR_ITLBMR_VPN 0xfffff000 /* Virtual Page Number */
/*
* Bit definitions for the Instruction TLB Translate Register
*
*/
#define SPR_ITLBTR_CC 0x00000001 /* Cache Coherency */
#define SPR_ITLBTR_CI 0x00000002 /* Cache Inhibit */
#define SPR_ITLBTR_WBC 0x00000004 /* Write-Back Cache */
#define SPR_ITLBTR_WOM 0x00000008 /* Weakly-Ordered Memory */
#define SPR_ITLBTR_A 0x00000010 /* Accessed */
#define SPR_ITLBTR_D 0x00000020 /* Dirty */
#define SPR_ITLBTR_SXE 0x00000040 /* User Read Enable */
#define SPR_ITLBTR_UXE 0x00000080 /* User Write Enable */
#define SPR_ITLBTR_PPN 0xfffff000 /* Physical Page Number */
/*
* Bit definitions for Data Cache Control register
*
*/
#define SPR_DCCR_EW 0x000000ff /* Enable ways */
/*
* Bit definitions for Insn Cache Control register
*
*/
#define SPR_ICCR_EW 0x000000ff /* Enable ways */
/*
* Bit definitions for Data Cache Configuration Register
*
*/
#define SPR_DCCFGR_NCW 0x00000007
#define SPR_DCCFGR_NCS 0x00000078
#define SPR_DCCFGR_CBS 0x00000080
#define SPR_DCCFGR_CWS 0x00000100
#define SPR_DCCFGR_CCRI 0x00000200
#define SPR_DCCFGR_CBIRI 0x00000400
#define SPR_DCCFGR_CBPRI 0x00000800
#define SPR_DCCFGR_CBLRI 0x00001000
#define SPR_DCCFGR_CBFRI 0x00002000
#define SPR_DCCFGR_CBWBRI 0x00004000
#define SPR_DCCFGR_NCW_OFF 0
#define SPR_DCCFGR_NCS_OFF 3
#define SPR_DCCFGR_CBS_OFF 7
/*
* Bit definitions for Instruction Cache Configuration Register
*
*/
#define SPR_ICCFGR_NCW 0x00000007
#define SPR_ICCFGR_NCS 0x00000078
#define SPR_ICCFGR_CBS 0x00000080
#define SPR_ICCFGR_CCRI 0x00000200
#define SPR_ICCFGR_CBIRI 0x00000400
#define SPR_ICCFGR_CBPRI 0x00000800
#define SPR_ICCFGR_CBLRI 0x00001000
#define SPR_ICCFGR_NCW_OFF 0
#define SPR_ICCFGR_NCS_OFF 3
#define SPR_ICCFGR_CBS_OFF 7
/*
* Bit definitions for Data MMU Configuration Register
*
*/
#define SPR_DMMUCFGR_NTW 0x00000003
#define SPR_DMMUCFGR_NTS 0x0000001C
#define SPR_DMMUCFGR_NAE 0x000000E0
#define SPR_DMMUCFGR_CRI 0x00000100
#define SPR_DMMUCFGR_PRI 0x00000200
#define SPR_DMMUCFGR_TEIRI 0x00000400
#define SPR_DMMUCFGR_HTR 0x00000800
#define SPR_DMMUCFGR_NTW_OFF 0
#define SPR_DMMUCFGR_NTS_OFF 2
/*
* Bit definitions for Instruction MMU Configuration Register
*
*/
#define SPR_IMMUCFGR_NTW 0x00000003
#define SPR_IMMUCFGR_NTS 0x0000001C
#define SPR_IMMUCFGR_NAE 0x000000E0
#define SPR_IMMUCFGR_CRI 0x00000100
#define SPR_IMMUCFGR_PRI 0x00000200
#define SPR_IMMUCFGR_TEIRI 0x00000400
#define SPR_IMMUCFGR_HTR 0x00000800
#define SPR_IMMUCFGR_NTW_OFF 0
#define SPR_IMMUCFGR_NTS_OFF 2
/*
* Bit definitions for Debug Control registers
*
*/
#define SPR_DCR_DP 0x00000001 /* DVR/DCR present */
#define SPR_DCR_CC 0x0000000e /* Compare condition */
#define SPR_DCR_SC 0x00000010 /* Signed compare */
#define SPR_DCR_CT 0x000000e0 /* Compare to */
/* Bit results with SPR_DCR_CC mask */
#define SPR_DCR_CC_MASKED 0x00000000
#define SPR_DCR_CC_EQUAL 0x00000002
#define SPR_DCR_CC_LESS 0x00000004
#define SPR_DCR_CC_LESSE 0x00000006
#define SPR_DCR_CC_GREAT 0x00000008
#define SPR_DCR_CC_GREATE 0x0000000a
#define SPR_DCR_CC_NEQUAL 0x0000000c
/* Bit results with SPR_DCR_CT mask */
#define SPR_DCR_CT_DISABLED 0x00000000
#define SPR_DCR_CT_IFEA 0x00000020
#define SPR_DCR_CT_LEA 0x00000040
#define SPR_DCR_CT_SEA 0x00000060
#define SPR_DCR_CT_LD 0x00000080
#define SPR_DCR_CT_SD 0x000000a0
#define SPR_DCR_CT_LSEA 0x000000c0
#define SPR_DCR_CT_LSD 0x000000e0
/* SPR_DCR_CT_LSD doesn't seem to be implemented anywhere in or1ksim. 2004-1-30 HP */
/*
* Bit definitions for Debug Mode 1 register
*
*/
#define SPR_DMR1_CW 0x000fffff /* Chain register pair data */
#define SPR_DMR1_CW0_AND 0x00000001
#define SPR_DMR1_CW0_OR 0x00000002
#define SPR_DMR1_CW0 (SPR_DMR1_CW0_AND | SPR_DMR1_CW0_OR)
#define SPR_DMR1_CW1_AND 0x00000004
#define SPR_DMR1_CW1_OR 0x00000008
#define SPR_DMR1_CW1 (SPR_DMR1_CW1_AND | SPR_DMR1_CW1_OR)
#define SPR_DMR1_CW2_AND 0x00000010
#define SPR_DMR1_CW2_OR 0x00000020
#define SPR_DMR1_CW2 (SPR_DMR1_CW2_AND | SPR_DMR1_CW2_OR)
#define SPR_DMR1_CW3_AND 0x00000040
#define SPR_DMR1_CW3_OR 0x00000080
#define SPR_DMR1_CW3 (SPR_DMR1_CW3_AND | SPR_DMR1_CW3_OR)
#define SPR_DMR1_CW4_AND 0x00000100
#define SPR_DMR1_CW4_OR 0x00000200
#define SPR_DMR1_CW4 (SPR_DMR1_CW4_AND | SPR_DMR1_CW4_OR)
#define SPR_DMR1_CW5_AND 0x00000400
#define SPR_DMR1_CW5_OR 0x00000800
#define SPR_DMR1_CW5 (SPR_DMR1_CW5_AND | SPR_DMR1_CW5_OR)
#define SPR_DMR1_CW6_AND 0x00001000
#define SPR_DMR1_CW6_OR 0x00002000
#define SPR_DMR1_CW6 (SPR_DMR1_CW6_AND | SPR_DMR1_CW6_OR)
#define SPR_DMR1_CW7_AND 0x00004000
#define SPR_DMR1_CW7_OR 0x00008000
#define SPR_DMR1_CW7 (SPR_DMR1_CW7_AND | SPR_DMR1_CW7_OR)
#define SPR_DMR1_CW8_AND 0x00010000
#define SPR_DMR1_CW8_OR 0x00020000
#define SPR_DMR1_CW8 (SPR_DMR1_CW8_AND | SPR_DMR1_CW8_OR)
#define SPR_DMR1_CW9_AND 0x00040000
#define SPR_DMR1_CW9_OR 0x00080000
#define SPR_DMR1_CW9 (SPR_DMR1_CW9_AND | SPR_DMR1_CW9_OR)
#define SPR_DMR1_RES1 0x00300000 /* Reserved */
#define SPR_DMR1_ST 0x00400000 /* Single-step trace*/
#define SPR_DMR1_BT 0x00800000 /* Branch trace */
#define SPR_DMR1_RES2 0xff000000 /* Reserved */
/*
* Bit definitions for Debug Mode 2 register. AWTC and WGB corrected by JPB
*
*/
#define SPR_DMR2_WCE0 0x00000001 /* Watchpoint counter 0 enable */
#define SPR_DMR2_WCE1 0x00000002 /* Watchpoint counter 0 enable */
#define SPR_DMR2_AWTC 0x00000ffc /* Assign watchpoints to counters */
#define SPR_DMR2_AWTC_OFF 2 /* Bit offset to AWTC field */
#define SPR_DMR2_WGB 0x003ff000 /* Watchpoints generating breakpoint */
#define SPR_DMR2_WGB_OFF 12 /* Bit offset to WGB field */
#define SPR_DMR2_WBS 0xffc00000 /* JPB: Watchpoint status */
#define SPR_DMR2_WBS_OFF 22 /* Bit offset to WBS field */
/*
* Bit definitions for Debug watchpoint counter registers
*
*/
#define SPR_DWCR_COUNT 0x0000ffff /* Count */
#define SPR_DWCR_MATCH 0xffff0000 /* Match */
#define SPR_DWCR_MATCH_OFF 16 /* Match bit offset */
/*
* Bit definitions for Debug stop register
*
*/
#define SPR_DSR_RSTE 0x00000001 /* Reset exception */
#define SPR_DSR_BUSEE 0x00000002 /* Bus error exception */
#define SPR_DSR_DPFE 0x00000004 /* Data Page Fault exception */
#define SPR_DSR_IPFE 0x00000008 /* Insn Page Fault exception */
#define SPR_DSR_TTE 0x00000010 /* Tick Timer exception */
#define SPR_DSR_AE 0x00000020 /* Alignment exception */
#define SPR_DSR_IIE 0x00000040 /* Illegal Instruction exception */
#define SPR_DSR_IE 0x00000080 /* Interrupt exception */
#define SPR_DSR_DME 0x00000100 /* DTLB miss exception */
#define SPR_DSR_IME 0x00000200 /* ITLB miss exception */
#define SPR_DSR_RE 0x00000400 /* Range exception */
#define SPR_DSR_SCE 0x00000800 /* System call exception */
#define SPR_DSR_FPE 0x00001000 /* Floating Point Exception */
#define SPR_DSR_TE 0x00002000 /* Trap exception */
/*
* Bit definitions for Debug reason register
*
*/
#define SPR_DRR_RSTE 0x00000001 /* Reset exception */
#define SPR_DRR_BUSEE 0x00000002 /* Bus error exception */
#define SPR_DRR_DPFE 0x00000004 /* Data Page Fault exception */
#define SPR_DRR_IPFE 0x00000008 /* Insn Page Fault exception */
#define SPR_DRR_TTE 0x00000010 /* Tick Timer exception */
#define SPR_DRR_AE 0x00000020 /* Alignment exception */
#define SPR_DRR_IIE 0x00000040 /* Illegal Instruction exception */
#define SPR_DRR_IE 0x00000080 /* Interrupt exception */
#define SPR_DRR_DME 0x00000100 /* DTLB miss exception */
#define SPR_DRR_IME 0x00000200 /* ITLB miss exception */
#define SPR_DRR_RE 0x00000400 /* Range exception */
#define SPR_DRR_SCE 0x00000800 /* System call exception */
#define SPR_DRR_FPE 0x00001000 /* Floating Point Exception */
#define SPR_DRR_TE 0x00002000 /* Trap exception */
/*
* Bit definitions for Performance counters mode registers
*
*/
#define SPR_PCMR_CP 0x00000001 /* Counter present */
#define SPR_PCMR_UMRA 0x00000002 /* User mode read access */
#define SPR_PCMR_CISM 0x00000004 /* Count in supervisor mode */
#define SPR_PCMR_CIUM 0x00000008 /* Count in user mode */
#define SPR_PCMR_LA 0x00000010 /* Load access event */
#define SPR_PCMR_SA 0x00000020 /* Store access event */
#define SPR_PCMR_IF 0x00000040 /* Instruction fetch event*/
#define SPR_PCMR_DCM 0x00000080 /* Data cache miss event */
#define SPR_PCMR_ICM 0x00000100 /* Insn cache miss event */
#define SPR_PCMR_IFS 0x00000200 /* Insn fetch stall event */
#define SPR_PCMR_LSUS 0x00000400 /* LSU stall event */
#define SPR_PCMR_BS 0x00000800 /* Branch stall event */
#define SPR_PCMR_DTLBM 0x00001000 /* DTLB miss event */
#define SPR_PCMR_ITLBM 0x00002000 /* ITLB miss event */
#define SPR_PCMR_DDS 0x00004000 /* Data dependency stall event */
#define SPR_PCMR_WPE 0x03ff8000 /* Watchpoint events */
/*
* Bit definitions for the Power management register
*
*/
#define SPR_PMR_SDF 0x0000000f /* Slow down factor */
#define SPR_PMR_DME 0x00000010 /* Doze mode enable */
#define SPR_PMR_SME 0x00000020 /* Sleep mode enable */
#define SPR_PMR_DCGE 0x00000040 /* Dynamic clock gating enable */
#define SPR_PMR_SUME 0x00000080 /* Suspend mode enable */
/*
* Bit definitions for PICMR
*
*/
#define SPR_PICMR_IUM 0xfffffffc /* Interrupt unmask */
/*
* Bit definitions for PICPR
*
*/
#define SPR_PICPR_IPRIO 0xfffffffc /* Interrupt priority */
/*
* Bit definitions for PICSR
*
*/
#define SPR_PICSR_IS 0xffffffff /* Interrupt status */
/*
* Bit definitions for Tick Timer Control Register
*
*/
#define SPR_TTCR_CNT 0xffffffff /* Count, time period */
#define SPR_TTMR_TP 0x0fffffff /* Time period */
#define SPR_TTMR_IP 0x10000000 /* Interrupt Pending */
#define SPR_TTMR_IE 0x20000000 /* Interrupt Enable */
#define SPR_TTMR_DI 0x00000000 /* Disabled */
#define SPR_TTMR_RT 0x40000000 /* Restart tick */
#define SPR_TTMR_SR 0x80000000 /* Single run */
#define SPR_TTMR_CR 0xc0000000 /* Continuous run */
#define SPR_TTMR_M 0xc0000000 /* Tick mode */
/*
* Bit definitions for the FP Control Status Register
*
*/
#define SPR_FPCSR_FPEE 0x00000001 /* Floating Point Exception Enable */
#define SPR_FPCSR_RM 0x00000006 /* Rounding Mode */
#define SPR_FPCSR_OVF 0x00000008 /* Overflow Flag */
#define SPR_FPCSR_UNF 0x00000010 /* Underflow Flag */
#define SPR_FPCSR_SNF 0x00000020 /* SNAN Flag */
#define SPR_FPCSR_QNF 0x00000040 /* QNAN Flag */
#define SPR_FPCSR_ZF 0x00000080 /* Zero Flag */
#define SPR_FPCSR_IXF 0x00000100 /* Inexact Flag */
#define SPR_FPCSR_IVF 0x00000200 /* Invalid Flag */
#define SPR_FPCSR_INF 0x00000400 /* Infinity Flag */
#define SPR_FPCSR_DZF 0x00000800 /* Divide By Zero Flag */
#define SPR_FPCSR_ALLF (SPR_FPCSR_OVF | SPR_FPCSR_UNF | SPR_FPCSR_SNF | \
SPR_FPCSR_QNF | SPR_FPCSR_ZF | SPR_FPCSR_IXF | \
SPR_FPCSR_IVF | SPR_FPCSR_INF | SPR_FPCSR_DZF)
#define FPCSR_RM_RN (0<<1)
#define FPCSR_RM_RZ (1<<1)
#define FPCSR_RM_RIP (2<<1)
#define FPCSR_RM_RIN (3<<1)
/*
* l.nop constants
*
*/
#define NOP_NOP 0x0000 /* Normal nop instruction */
#define NOP_EXIT 0x0001 /* End of simulation */
#define NOP_REPORT 0x0002 /* Simple report */
/*#define NOP_PRINTF 0x0003 Simprintf instruction (obsolete)*/
#define NOP_PUTC 0x0004 /* JPB: Simputc instruction */
#define NOP_CNT_RESET 0x0005 /* Reset statistics counters */
#define NOP_GET_TICKS 0x0006 /* JPB: Get # ticks running */
#define NOP_GET_PS 0x0007 /* JPB: Get picosecs/cycle */
#define NOP_REPORT_FIRST 0x0400 /* Report with number */
#define NOP_REPORT_LAST 0x03ff /* Report with number */
#endif /* SPR_DEFS__H */
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_OPENRISC_STRING_H
#define __ASM_OPENRISC_STRING_H
#define __HAVE_ARCH_MEMSET
extern void *memset(void *s, int c, __kernel_size_t n);
#define __HAVE_ARCH_MEMCPY
extern void *memcpy(void *dest, __const void *src, __kernel_size_t n);
#endif /* __ASM_OPENRISC_STRING_H */
@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_SYSCALL_H__
#define __ASM_OPENRISC_SYSCALL_H__
#include <uapi/linux/audit.h>
#include <linux/err.h>
#include <linux/sched.h>
static inline int
syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
return regs->orig_gpr11;
}
static inline void
syscall_set_nr(struct task_struct *task, struct pt_regs *regs, int nr)
{
regs->orig_gpr11 = nr;
}
static inline void
syscall_rollback(struct task_struct *task, struct pt_regs *regs)
{
regs->gpr[11] = regs->orig_gpr11;
}
static inline long
syscall_get_error(struct task_struct *task, struct pt_regs *regs)
{
return IS_ERR_VALUE(regs->gpr[11]) ? regs->gpr[11] : 0;
}
static inline long
syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
{
return regs->gpr[11];
}
static inline void
syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
int error, long val)
{
regs->gpr[11] = (long) error ?: val;
}
static inline void
syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
unsigned long *args)
{
memcpy(args, &regs->gpr[3], 6 * sizeof(args[0]));
}
static inline void
syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
const unsigned long *args)
{
memcpy(&regs->gpr[3], args, 6 * sizeof(args[0]));
}
static inline int syscall_get_arch(struct task_struct *task)
{
return AUDIT_ARCH_OPENRISC;
}
#endif
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_SYSCALLS_H
#define __ASM_OPENRISC_SYSCALLS_H
asmlinkage long sys_or1k_atomic(unsigned long type, unsigned long *v1,
unsigned long *v2);
#include <asm-generic/syscalls.h>
asmlinkage long __sys_clone(unsigned long clone_flags, unsigned long newsp,
void __user *parent_tid, void __user *child_tid, int tls);
asmlinkage long __sys_clone3(struct clone_args __user *uargs, size_t size);
asmlinkage long __sys_fork(void);
#endif /* __ASM_OPENRISC_SYSCALLS_H */
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2025 Chen Miao
*/
#ifndef _ASM_OPENRISC_PATCHING_H
#define _ASM_OPENRISC_PATCHING_H
#include <linux/types.h>
int patch_insn_write(void *addr, u32 insn);
#endif /* _ASM_OPENRISC_PATCHING_H */
@@ -0,0 +1,116 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef _ASM_THREAD_INFO_H
#define _ASM_THREAD_INFO_H
#ifdef __KERNEL__
#ifndef __ASSEMBLER__
#include <asm/types.h>
#include <asm/processor.h>
#endif
/* THREAD_SIZE is the size of the task_struct/kernel_stack combo.
* normally, the stack is found by doing something like p + THREAD_SIZE
* in or1k, a page is 8192 bytes, which seems like a sane size
*/
#define THREAD_SIZE_ORDER 0
#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
/*
* low level task data that entry.S needs immediate access to
* - this struct should fit entirely inside of one cache line
* - this struct shares the supervisor stack pages
* - if the contents of this structure are changed, the assembly constants
* must also be changed
*/
#ifndef __ASSEMBLER__
struct thread_info {
struct task_struct *task; /* main task structure */
unsigned long flags; /* low level flags */
__u32 cpu; /* current CPU */
__s32 preempt_count; /* 0 => preemptable, <0 => BUG */
__u8 supervisor_stack[0];
/* saved context data */
unsigned long ksp;
};
#endif
/*
* macros/functions for gaining access to the thread information structure
*
* preempt_count needs to be 1 initially, until the scheduler is functional.
*/
#ifndef __ASSEMBLER__
#define INIT_THREAD_INFO(tsk) \
{ \
.task = &tsk, \
.flags = 0, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
.ksp = 0, \
}
/* how to get the thread information struct from C */
register struct thread_info *current_thread_info_reg asm("r10");
#define current_thread_info() (current_thread_info_reg)
#define get_thread_info(ti) get_task_struct((ti)->task)
#define put_thread_info(ti) put_task_struct((ti)->task)
#endif /* !__ASSEMBLER__ */
/*
* thread information flags
* these are process state flags that various assembly files may need to
* access
* - pending work-to-be-done flags are in LSW
* - other flags in MSW
*/
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_SINGLESTEP 4 /* restore singlestep on return to user
* mode
*/
#define TIF_NOTIFY_SIGNAL 5 /* signal notifications exist */
#define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */
#define TIF_RESTORE_SIGMASK 9
#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling * TIF_NEED_RESCHED
*/
#define TIF_MEMDIE 17
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
#define _TIF_NOTIFY_SIGNAL (1<<TIF_NOTIFY_SIGNAL)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
/* Work to do when returning from interrupt/exception */
/* For OpenRISC, this is anything in the LSW other than syscall trace */
#define _TIF_WORK_MASK (0xff & ~(_TIF_SYSCALL_TRACE|_TIF_SINGLESTEP))
#endif /* __KERNEL__ */
#endif /* _ASM_THREAD_INFO_H */
@@ -0,0 +1,23 @@
/*
* OpenRISC timer API
*
* Copyright (C) 2017 by Stafford Horne (shorne@gmail.com)
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#ifndef __ASM_OR1K_TIME_H
#define __ASM_OR1K_TIME_H
extern void openrisc_clockevent_init(void);
extern void openrisc_timer_set(unsigned long count);
extern void openrisc_timer_set_next(unsigned long delta);
#ifdef CONFIG_SMP
extern void synchronise_count_master(int cpu);
extern void synchronise_count_slave(int cpu);
#endif
#endif /* __ASM_OR1K_TIME_H */
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#ifndef __ASM_OPENRISC_TIMEX_H
#define __ASM_OPENRISC_TIMEX_H
#define get_cycles get_cycles
#include <asm-generic/timex.h>
#include <asm/spr.h>
#include <asm/spr_defs.h>
static inline cycles_t get_cycles(void)
{
return mfspr(SPR_TTCR);
}
#define get_cycles get_cycles
/* This isn't really used any more */
#define CLOCK_TICK_RATE 1000
#define ARCH_HAS_READ_CURRENT_TIMER
#endif
@@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_TLB_H__
#define __ASM_OPENRISC_TLB_H__
/*
* OpenRISC doesn't have an efficient flush_tlb_range() so use flush_tlb_mm()
* for everything.
*/
#include <linux/pagemap.h>
#include <asm-generic/tlb.h>
#endif /* __ASM_OPENRISC_TLB_H__ */
@@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_TLBFLUSH_H
#define __ASM_OPENRISC_TLBFLUSH_H
#include <linux/mm.h>
#include <asm/processor.h>
#include <asm/current.h>
#include <linux/sched.h>
/*
* - flush_tlb() flushes the current mm struct TLBs
* - flush_tlb_all() flushes all processes TLBs
* - flush_tlb_mm(mm) flushes the specified mm context TLB's
* - flush_tlb_page(vma, vmaddr) flushes one page
* - flush_tlb_range(vma, start, end) flushes a range of pages
*/
extern void local_flush_tlb_all(void);
extern void local_flush_tlb_mm(struct mm_struct *mm);
extern void local_flush_tlb_page(struct vm_area_struct *vma,
unsigned long addr);
extern void local_flush_tlb_range(struct vm_area_struct *vma,
unsigned long start,
unsigned long end);
#ifndef CONFIG_SMP
#define flush_tlb_all local_flush_tlb_all
#define flush_tlb_mm local_flush_tlb_mm
#define flush_tlb_page local_flush_tlb_page
#define flush_tlb_range local_flush_tlb_range
#else
extern void flush_tlb_all(void);
extern void flush_tlb_mm(struct mm_struct *mm);
extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr);
extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end);
#endif
static inline void flush_tlb(void)
{
flush_tlb_mm(current->mm);
}
static inline void flush_tlb_kernel_range(unsigned long start,
unsigned long end)
{
flush_tlb_range(NULL, start, end);
}
#endif /* __ASM_OPENRISC_TLBFLUSH_H */
@@ -0,0 +1,237 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*/
#ifndef __ASM_OPENRISC_UACCESS_H
#define __ASM_OPENRISC_UACCESS_H
/*
* User space memory access functions
*/
#include <linux/prefetch.h>
#include <linux/string.h>
#include <asm/page.h>
#include <asm/extable.h>
#include <asm-generic/access_ok.h>
/*
* These are the main single-value transfer routines. They automatically
* use the right size if we just have the right pointer type.
*
* This gets kind of ugly. We want to return _two_ values in "get_user()"
* and yet we don't want to do any pointers, because that is too much
* of a performance impact. Thus we have a few rather ugly macros here,
* and hide all the uglyness from the user.
*
* The "__xxx" versions of the user access functions are versions that
* do not verify the address space, that must have been done previously
* with a separate "access_ok()" call (this is used when we do multiple
* accesses to the same area of user memory).
*
* As we use the same address space for kernel and user data on the
* PowerPC, we can just do these as direct assignments. (Of course, the
* exception handling means that it's no longer "just"...)
*/
#define get_user(x, ptr) \
__get_user_check((x), (ptr), sizeof(*(ptr)))
#define put_user(x, ptr) \
__put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
#define __get_user(x, ptr) \
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
#define __put_user(x, ptr) \
__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
extern long __put_user_bad(void);
#define __put_user_nocheck(x, ptr, size) \
({ \
long __pu_err; \
__put_user_size((x), (ptr), (size), __pu_err); \
__pu_err; \
})
#define __put_user_check(x, ptr, size) \
({ \
long __pu_err = -EFAULT; \
__typeof__(*(ptr)) __user *__pu_addr = (ptr); \
if (access_ok(__pu_addr, size)) \
__put_user_size((x), __pu_addr, (size), __pu_err); \
__pu_err; \
})
#define __put_user_size(x, ptr, size, retval) \
do { \
retval = 0; \
switch (size) { \
case 1: __put_user_asm(x, ptr, retval, "l.sb"); break; \
case 2: __put_user_asm(x, ptr, retval, "l.sh"); break; \
case 4: __put_user_asm(x, ptr, retval, "l.sw"); break; \
case 8: __put_user_asm2(x, ptr, retval); break; \
default: __put_user_bad(); \
} \
} while (0)
struct __large_struct {
unsigned long buf[100];
};
#define __m(x) (*(struct __large_struct *)(x))
/*
* We don't tell gcc that we are accessing memory, but this is OK
* because we do not write to any memory gcc knows about, so there
* are no aliasing issues.
*/
#define __put_user_asm(x, addr, err, op) \
__asm__ __volatile__( \
"1: "op" 0(%2),%1\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: l.addi %0,r0,%3\n" \
" l.j 2b\n" \
" l.nop\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 2\n" \
" .long 1b,3b\n" \
".previous" \
: "=r"(err) \
: "r"(x), "r"(addr), "i"(-EFAULT), "0"(err))
#define __put_user_asm2(x, addr, err) \
__asm__ __volatile__( \
"1: l.sw 0(%2),%1\n" \
"2: l.sw 4(%2),%H1\n" \
"3:\n" \
".section .fixup,\"ax\"\n" \
"4: l.addi %0,r0,%3\n" \
" l.j 3b\n" \
" l.nop\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 2\n" \
" .long 1b,4b\n" \
" .long 2b,4b\n" \
".previous" \
: "=r"(err) \
: "r"(x), "r"(addr), "i"(-EFAULT), "0"(err))
#define __get_user_nocheck(x, ptr, size) \
({ \
long __gu_err; \
__get_user_size((x), (ptr), (size), __gu_err); \
__gu_err; \
})
#define __get_user_check(x, ptr, size) \
({ \
long __gu_err = -EFAULT; \
const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
if (access_ok(__gu_addr, size)) \
__get_user_size((x), __gu_addr, (size), __gu_err); \
else \
(x) = (__typeof__(*(ptr))) 0; \
__gu_err; \
})
extern long __get_user_bad(void);
#define __get_user_size(x, ptr, size, retval) \
do { \
retval = 0; \
switch (size) { \
case 1: __get_user_asm(x, ptr, retval, "l.lbz"); break; \
case 2: __get_user_asm(x, ptr, retval, "l.lhz"); break; \
case 4: __get_user_asm(x, ptr, retval, "l.lwz"); break; \
case 8: __get_user_asm2(x, ptr, retval); break; \
default: (x) = (__typeof__(*(ptr)))__get_user_bad(); \
} \
} while (0)
#define __get_user_asm(x, addr, err, op) \
{ \
unsigned long __gu_tmp; \
__asm__ __volatile__( \
"1: "op" %1,0(%2)\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: l.addi %0,r0,%3\n" \
" l.addi %1,r0,0\n" \
" l.j 2b\n" \
" l.nop\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 2\n" \
" .long 1b,3b\n" \
".previous" \
: "=r"(err), "=r"(__gu_tmp) \
: "r"(addr), "i"(-EFAULT), "0"(err)); \
(x) = (__typeof__(*(addr)))__gu_tmp; \
}
#define __get_user_asm2(x, addr, err) \
{ \
unsigned long long __gu_tmp; \
__asm__ __volatile__( \
"1: l.lwz %1,0(%2)\n" \
"2: l.lwz %H1,4(%2)\n" \
"3:\n" \
".section .fixup,\"ax\"\n" \
"4: l.addi %0,r0,%3\n" \
" l.addi %1,r0,0\n" \
" l.addi %H1,r0,0\n" \
" l.j 3b\n" \
" l.nop\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 2\n" \
" .long 1b,4b\n" \
" .long 2b,4b\n" \
".previous" \
: "=r"(err), "=&r"(__gu_tmp) \
: "r"(addr), "i"(-EFAULT), "0"(err)); \
(x) = (__typeof__(*(addr)))( \
(__typeof__((x)-(x)))__gu_tmp); \
}
/* more complex routines */
extern unsigned long __must_check
__copy_tofrom_user(void *to, const void *from, unsigned long size);
static inline unsigned long
raw_copy_from_user(void *to, const void __user *from, unsigned long size)
{
return __copy_tofrom_user(to, (__force const void *)from, size);
}
static inline unsigned long
raw_copy_to_user(void __user *to, const void *from, unsigned long size)
{
return __copy_tofrom_user((__force void *)to, from, size);
}
#define INLINE_COPY_USER
extern unsigned long __clear_user(void __user *addr, unsigned long size);
static inline __must_check unsigned long
clear_user(void __user *addr, unsigned long size)
{
if (likely(access_ok(addr, size)))
size = __clear_user(addr, size);
return size;
}
extern long strncpy_from_user(char *dest, const char __user *src, long count);
extern __must_check long strnlen_user(const char __user *str, long n);
#endif /* __ASM_OPENRISC_UACCESS_H */
@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
#define __ARCH_WANT_STAT64
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_CLONE
#define __ARCH_WANT_TIME32_SYSCALLS
#include <uapi/asm/unistd.h>
@@ -0,0 +1,20 @@
/*
* OpenRISC unwinder.h
*
* Architecture API for unwinding stacks.
*
* Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#ifndef __ASM_OPENRISC_UNWINDER_H
#define __ASM_OPENRISC_UNWINDER_H
void unwind_stack(void *data, unsigned long *stack,
void (*trace)(void *data, unsigned long addr,
int reliable));
#endif /* __ASM_OPENRISC_UNWINDER_H */
@@ -0,0 +1,4 @@
#ifndef _ASM_OPENRISC_VMALLOC_H
#define _ASM_OPENRISC_VMALLOC_H
#endif /* _ASM_OPENRISC_VMALLOC_H */
@@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
syscall-y += unistd_32.h
generic-y += ucontext.h
@@ -0,0 +1 @@
#include <linux/byteorder/big_endian.h>
@@ -0,0 +1,125 @@
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef _UAPI__ASM_OPENRISC_ELF_H
#define _UAPI__ASM_OPENRISC_ELF_H
/*
* This files is partially exported to userspace. This allows us to keep
* the ELF bits in one place which should assist in keeping the kernel and
* userspace in sync.
*/
/*
* ELF register definitions..
*/
/* for struct user_regs_struct definition */
#include <asm/ptrace.h>
/* The OR1K relocation types... not all relevant for module loader */
#define R_OR1K_NONE 0
#define R_OR1K_32 1
#define R_OR1K_16 2
#define R_OR1K_8 3
#define R_OR1K_LO_16_IN_INSN 4
#define R_OR1K_HI_16_IN_INSN 5
#define R_OR1K_INSN_REL_26 6
#define R_OR1K_GNU_VTENTRY 7
#define R_OR1K_GNU_VTINHERIT 8
#define R_OR1K_32_PCREL 9
#define R_OR1K_16_PCREL 10
#define R_OR1K_8_PCREL 11
#define R_OR1K_GOTPC_HI16 12
#define R_OR1K_GOTPC_LO16 13
#define R_OR1K_GOT16 14
#define R_OR1K_PLT26 15
#define R_OR1K_GOTOFF_HI16 16
#define R_OR1K_GOTOFF_LO16 17
#define R_OR1K_COPY 18
#define R_OR1K_GLOB_DAT 19
#define R_OR1K_JMP_SLOT 20
#define R_OR1K_RELATIVE 21
#define R_OR1K_TLS_GD_HI16 22
#define R_OR1K_TLS_GD_LO16 23
#define R_OR1K_TLS_LDM_HI16 24
#define R_OR1K_TLS_LDM_LO16 25
#define R_OR1K_TLS_LDO_HI16 26
#define R_OR1K_TLS_LDO_LO16 27
#define R_OR1K_TLS_IE_HI16 28
#define R_OR1K_TLS_IE_LO16 29
#define R_OR1K_TLS_LE_HI16 30
#define R_OR1K_TLS_LE_LO16 31
#define R_OR1K_TLS_TPOFF 32
#define R_OR1K_TLS_DTPOFF 33
#define R_OR1K_TLS_DTPMOD 34
#define R_OR1K_AHI16 35
#define R_OR1K_GOTOFF_AHI16 36
#define R_OR1K_TLS_IE_AHI16 37
#define R_OR1K_TLS_LE_AHI16 38
#define R_OR1K_SLO16 39
#define R_OR1K_GOTOFF_SLO16 40
#define R_OR1K_TLS_LE_SLO16 41
#define R_OR1K_PCREL_PG21 42
#define R_OR1K_GOT_PG21 43
#define R_OR1K_TLS_GD_PG21 44
#define R_OR1K_TLS_LDM_PG21 45
#define R_OR1K_TLS_IE_PG21 46
#define R_OR1K_LO13 47
#define R_OR1K_GOT_LO13 48
#define R_OR1K_TLS_GD_LO13 49
#define R_OR1K_TLS_LDM_LO13 50
#define R_OR1K_TLS_IE_LO13 51
#define R_OR1K_SLO13 52
#define R_OR1K_PLTA26 53
#define R_OR1K_GOT_AHI16 54
/* Old relocation names */
#define R_OR32_NONE R_OR1K_NONE
#define R_OR32_32 R_OR1K_32
#define R_OR32_16 R_OR1K_16
#define R_OR32_8 R_OR1K_8
#define R_OR32_CONST R_OR1K_LO_16_IN_INSN
#define R_OR32_CONSTH R_OR1K_HI_16_IN_INSN
#define R_OR32_JUMPTARG R_OR1K_INSN_REL_26
#define R_OR32_VTENTRY R_OR1K_GNU_VTENTRY
#define R_OR32_VTINHERIT R_OR1K_GNU_VTINHERIT
typedef unsigned long elf_greg_t;
/*
* Note that NGREG is defined to ELF_NGREG in include/linux/elfcore.h, and is
* thus exposed to user-space.
*/
#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef struct __or1k_fpu_state elf_fpregset_t;
/* EM_OPENRISC is defined in linux/elf-em.h */
#define EM_OR32 0x8472
/*
* These are used to set parameters in the core dumps.
*/
#define ELF_ARCH EM_OR32
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2MSB
#endif /* _UAPI__ASM_OPENRISC_ELF_H */
@@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __ASM_OPENRISC_PARAM_H
#define __ASM_OPENRISC_PARAM_H
#define EXEC_PAGESIZE 8192
#include <asm-generic/param.h>
#endif /* __ASM_OPENRISC_PARAM_H */
@@ -0,0 +1,40 @@
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef _UAPI__ASM_OPENRISC_PTRACE_H
#define _UAPI__ASM_OPENRISC_PTRACE_H
#ifndef __ASSEMBLER__
/*
* This is the layout of the regset returned by the GETREGSET ptrace call
*/
struct user_regs_struct {
/* GPR R0-R31... */
unsigned long gpr[32];
unsigned long pc;
unsigned long sr;
};
struct __or1k_fpu_state {
unsigned long fpcsr;
};
#endif
#endif /* _UAPI__ASM_OPENRISC_PTRACE_H */
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __ASM_OPENRISC_SIGCONTEXT_H
#define __ASM_OPENRISC_SIGCONTEXT_H
#include <asm/ptrace.h>
/* This struct is saved by setup_frame in signal.c, to keep the current
context while a signal handler is executed. It's restored by sys_sigreturn.
*/
struct sigcontext {
struct user_regs_struct regs; /* needs to be first */
union {
unsigned long fpcsr;
unsigned long oldmask; /* unused */
};
};
#endif /* __ASM_OPENRISC_SIGCONTEXT_H */
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <asm/unistd_32.h>
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
vmlinux.lds
+19
View File
@@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the linux kernel.
#
always-$(KBUILD_BUILTIN) := vmlinux.lds
obj-y := head.o setup.o or32_ksyms.o process.o dma.o \
traps.o time.o irq.o entry.o ptrace.o signal.o \
sys_call_table.o unwinder.o cacheinfo.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
obj-$(CONFIG_SMP) += smp.o sync-timer.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_OF) += prom.o
obj-y += patching.o
clean:
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
syscall_abis_32 += or1k time32 stat64 rlimit renameat
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC asm-offsets.c
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* Modifications for the OpenRISC architecture:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*
* This program is used to generate definitions needed by
* assembly language modules.
*
* We use the technique used in the OSF Mach kernel code:
* generate asm statements containing #defines,
* compile this file to assembler, and then extract the
* #defines from the assembly-language output.
*/
#define COMPILE_OFFSETS
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/thread_info.h>
#include <linux/kbuild.h>
#include <asm/page.h>
#include <asm/processor.h>
int main(void)
{
/* offsets into the task_struct */
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
/* offsets into thread_info */
DEFINE(TI_TASK, offsetof(struct thread_info, task));
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
DEFINE(TI_KSP, offsetof(struct thread_info, ksp));
DEFINE(PT_SIZE, sizeof(struct pt_regs));
/* Interrupt register frame */
DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
DEFINE(NUM_USER_SEGMENTS, TASK_SIZE >> 28);
return 0;
}
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC cacheinfo support
*
* Based on work done for MIPS and LoongArch. All original copyrights
* apply as per the original source declaration.
*
* OpenRISC implementation:
* Copyright (C) 2025 Sahil Siddiq <sahilcdq@proton.me>
*/
#include <linux/cacheinfo.h>
#include <asm/cpuinfo.h>
#include <asm/spr.h>
#include <asm/spr_defs.h>
static inline void ci_leaf_init(struct cacheinfo *this_leaf, enum cache_type type,
unsigned int level, struct cache_desc *cache, int cpu)
{
this_leaf->type = type;
this_leaf->level = level;
this_leaf->coherency_line_size = cache->block_size;
this_leaf->number_of_sets = cache->sets;
this_leaf->ways_of_associativity = cache->ways;
this_leaf->size = cache->size;
cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
}
int init_cache_level(unsigned int cpu)
{
struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[smp_processor_id()];
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
int leaves = 0, levels = 0;
unsigned long upr = mfspr(SPR_UPR);
unsigned long iccfgr, dccfgr;
if (!(upr & SPR_UPR_UP)) {
printk(KERN_INFO
"-- no UPR register... unable to detect configuration\n");
return -ENOENT;
}
if (cpu_cache_is_present(SPR_UPR_DCP)) {
dccfgr = mfspr(SPR_DCCFGR);
cpuinfo->dcache.ways = 1 << (dccfgr & SPR_DCCFGR_NCW);
cpuinfo->dcache.sets = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3);
cpuinfo->dcache.block_size = 16 << ((dccfgr & SPR_DCCFGR_CBS) >> 7);
cpuinfo->dcache.size =
cpuinfo->dcache.sets * cpuinfo->dcache.ways * cpuinfo->dcache.block_size;
leaves += 1;
printk(KERN_INFO
"-- dcache: %d bytes total, %d bytes/line, %d set(s), %d way(s)\n",
cpuinfo->dcache.size, cpuinfo->dcache.block_size,
cpuinfo->dcache.sets, cpuinfo->dcache.ways);
} else
printk(KERN_INFO "-- dcache disabled\n");
if (cpu_cache_is_present(SPR_UPR_ICP)) {
iccfgr = mfspr(SPR_ICCFGR);
cpuinfo->icache.ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
cpuinfo->icache.sets = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3);
cpuinfo->icache.block_size = 16 << ((iccfgr & SPR_ICCFGR_CBS) >> 7);
cpuinfo->icache.size =
cpuinfo->icache.sets * cpuinfo->icache.ways * cpuinfo->icache.block_size;
leaves += 1;
printk(KERN_INFO
"-- icache: %d bytes total, %d bytes/line, %d set(s), %d way(s)\n",
cpuinfo->icache.size, cpuinfo->icache.block_size,
cpuinfo->icache.sets, cpuinfo->icache.ways);
} else
printk(KERN_INFO "-- icache disabled\n");
if (!leaves)
return -ENOENT;
levels = 1;
this_cpu_ci->num_leaves = leaves;
this_cpu_ci->num_levels = levels;
return 0;
}
int populate_cache_leaves(unsigned int cpu)
{
struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[smp_processor_id()];
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
struct cacheinfo *this_leaf = this_cpu_ci->info_list;
int level = 1;
if (cpu_cache_is_present(SPR_UPR_DCP)) {
ci_leaf_init(this_leaf, CACHE_TYPE_DATA, level, &cpuinfo->dcache, cpu);
this_leaf->attributes = ((mfspr(SPR_DCCFGR) & SPR_DCCFGR_CWS) >> 8) ?
CACHE_WRITE_BACK : CACHE_WRITE_THROUGH;
this_leaf++;
}
if (cpu_cache_is_present(SPR_UPR_ICP))
ci_leaf_init(this_leaf, CACHE_TYPE_INST, level, &cpuinfo->icache, cpu);
this_cpu_ci->cpu_map_populated = true;
return 0;
}
+115
View File
@@ -0,0 +1,115 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC Linux
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* Modifications for the OpenRISC architecture:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*
* DMA mapping callbacks...
*/
#include <linux/dma-map-ops.h>
#include <linux/pagewalk.h>
#include <asm/cpuinfo.h>
#include <asm/cacheflush.h>
#include <asm/spr_defs.h>
#include <asm/tlbflush.h>
static int
page_set_nocache(pte_t *pte, unsigned long addr,
unsigned long next, struct mm_walk *walk)
{
pte_val(*pte) |= _PAGE_CI;
/*
* Flush the page out of the TLB so that the new page flags get
* picked up next time there's an access
*/
flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
/* Flush page out of dcache */
local_dcache_range_flush(__pa(addr), __pa(next));
return 0;
}
static const struct mm_walk_ops set_nocache_walk_ops = {
.pte_entry = page_set_nocache,
};
static int
page_clear_nocache(pte_t *pte, unsigned long addr,
unsigned long next, struct mm_walk *walk)
{
pte_val(*pte) &= ~_PAGE_CI;
/*
* Flush the page out of the TLB so that the new page flags get
* picked up next time there's an access
*/
flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
return 0;
}
static const struct mm_walk_ops clear_nocache_walk_ops = {
.pte_entry = page_clear_nocache,
};
void *arch_dma_set_uncached(void *cpu_addr, size_t size)
{
unsigned long va = (unsigned long)cpu_addr;
int error;
/*
* We need to iterate through the pages, clearing the dcache for
* them and setting the cache-inhibit bit.
*/
mmap_write_lock(&init_mm);
error = walk_kernel_page_table_range(va, va + size,
&set_nocache_walk_ops, NULL, NULL);
mmap_write_unlock(&init_mm);
if (error)
return ERR_PTR(error);
return cpu_addr;
}
void arch_dma_clear_uncached(void *cpu_addr, size_t size)
{
unsigned long va = (unsigned long)cpu_addr;
mmap_write_lock(&init_mm);
/* walk_page_range shouldn't be able to fail here */
WARN_ON(walk_kernel_page_table_range(va, va + size,
&clear_nocache_walk_ops, NULL, NULL));
mmap_write_unlock(&init_mm);
}
void arch_sync_dma_for_device(phys_addr_t addr, size_t size,
enum dma_data_direction dir)
{
switch (dir) {
case DMA_TO_DEVICE:
/* Flush the dcache for the requested range */
local_dcache_range_flush(addr, addr + size);
break;
case DMA_FROM_DEVICE:
/* Invalidate the dcache for the requested range */
local_dcache_range_inv(addr, addr + size);
break;
default:
/*
* NOTE: If dir == DMA_BIDIRECTIONAL then there's no need to
* flush nor invalidate the cache here as the area will need
* to be manually synced anyway.
*/
break;
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+38
View File
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC irq.c
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* Modifications for the OpenRISC architecture:
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/ftrace.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/export.h>
#include <linux/irqflags.h>
/* read interrupt enabled status */
unsigned long arch_local_save_flags(void)
{
return mfspr(SPR_SR) & (SPR_SR_IEE|SPR_SR_TEE);
}
EXPORT_SYMBOL(arch_local_save_flags);
/* set interrupt enabled status */
void arch_local_irq_restore(unsigned long flags)
{
mtspr(SPR_SR, ((mfspr(SPR_SR) & ~(SPR_SR_IEE|SPR_SR_TEE)) | flags));
}
EXPORT_SYMBOL(arch_local_irq_restore);
void __init init_IRQ(void)
{
irqchip_init();
}
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2025 Chen Miao
*
* Based on arch/arm/kernel/jump_label.c
*/
#include <linux/jump_label.h>
#include <linux/kernel.h>
#include <linux/memory.h>
#include <asm/bug.h>
#include <asm/cacheflush.h>
#include <asm/text-patching.h>
bool arch_jump_label_transform_queue(struct jump_entry *entry,
enum jump_label_type type)
{
void *addr = (void *)jump_entry_code(entry);
u32 insn;
if (type == JUMP_LABEL_JMP) {
long offset;
offset = jump_entry_target(entry) - jump_entry_code(entry);
/*
* The actual maximum range of the l.j instruction's offset is -134,217,728
* ~ 134,217,724 (sign 26-bit imm).
* For the original jump range, we need to right-shift N by 2 to obtain the
* instruction's offset.
*/
WARN_ON_ONCE(offset < -134217728 || offset > 134217724);
/* 26bit imm mask */
offset = (offset >> 2) & 0x03ffffff;
insn = offset;
} else {
insn = OPENRISC_INSN_NOP;
}
if (early_boot_irqs_disabled)
copy_to_kernel_nofault(addr, &insn, sizeof(insn));
else
patch_insn_write(addr, insn);
return true;
}
void arch_jump_label_transform_apply(void)
{
icache_all_inv();
}
+80
View File
@@ -0,0 +1,80 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC module.c
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* Modifications for the OpenRISC architecture:
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#include <linux/moduleloader.h>
#include <linux/elf.h>
int apply_relocate_add(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
unsigned int i;
Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
Elf32_Sym *sym;
uint32_t *location;
uint32_t value;
pr_debug("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset;
/* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM(rel[i].r_info);
value = sym->st_value + rel[i].r_addend;
switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_OR1K_32:
*location = value;
break;
case R_OR1K_LO_16_IN_INSN:
*((uint16_t *)location + 1) = value;
break;
case R_OR1K_HI_16_IN_INSN:
*((uint16_t *)location + 1) = value >> 16;
break;
case R_OR1K_INSN_REL_26:
value -= (uint32_t)location;
value >>= 2;
value &= 0x03ffffff;
value |= *location & 0xfc000000;
*location = value;
break;
case R_OR1K_32_PCREL:
value -= (uint32_t)location;
*location = value;
break;
case R_OR1K_AHI16:
/* Adjust the operand to match with a signed LO16. */
value += 0x8000;
*((uint16_t *)location + 1) = value >> 16;
break;
case R_OR1K_SLO16:
/* Split value lower 16-bits. */
value = ((value & 0xf800) << 10) | (value & 0x7ff);
*location = (*location & ~0x3e007ff) | value;
break;
default:
pr_err("module %s: Unknown relocation: %u\n",
me->name, ELF32_R_TYPE(rel[i].r_info));
break;
}
}
return 0;
}
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC or32_ksyms.c
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* Modifications for the OpenRISC architecture:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#include <linux/export.h>
#include <linux/elfcore.h>
#include <linux/sched.h>
#include <linux/in6.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
#include <linux/semaphore.h>
#include <linux/pgtable.h>
#include <asm/processor.h>
#include <linux/uaccess.h>
#include <asm/checksum.h>
#include <asm/io.h>
#include <asm/hardirq.h>
#include <asm/delay.h>
#define DECLARE_EXPORT(name) extern void name(void); EXPORT_SYMBOL(name)
/* compiler generated symbols */
DECLARE_EXPORT(__udivsi3);
DECLARE_EXPORT(__divsi3);
DECLARE_EXPORT(__umodsi3);
DECLARE_EXPORT(__modsi3);
DECLARE_EXPORT(__muldi3);
DECLARE_EXPORT(__ashrdi3);
DECLARE_EXPORT(__ashldi3);
DECLARE_EXPORT(__lshrdi3);
DECLARE_EXPORT(__ucmpdi2);
EXPORT_SYMBOL(__copy_tofrom_user);
EXPORT_SYMBOL(__clear_user);
EXPORT_SYMBOL(memset);
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2020 SiFive
* Copyright (C) 2025 Chen Miao
*/
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <asm/insn-def.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <asm/fixmap.h>
#include <asm/text-patching.h>
#include <asm/sections.h>
static DEFINE_RAW_SPINLOCK(patch_lock);
static __always_inline void *patch_map(void *addr, int fixmap)
{
uintptr_t uaddr = (uintptr_t) addr;
phys_addr_t phys;
if (core_kernel_text(uaddr)) {
phys = __pa_symbol(addr);
} else {
struct page *page = vmalloc_to_page(addr);
BUG_ON(!page);
phys = page_to_phys(page) + offset_in_page(addr);
}
return (void *)set_fixmap_offset(fixmap, phys);
}
static void patch_unmap(int fixmap)
{
clear_fixmap(fixmap);
}
static int __patch_insn_write(void *addr, u32 insn)
{
void *waddr = addr;
unsigned long flags = 0;
int ret;
raw_spin_lock_irqsave(&patch_lock, flags);
waddr = patch_map(addr, FIX_TEXT_POKE0);
ret = copy_to_kernel_nofault(waddr, &insn, OPENRISC_INSN_SIZE);
if (!IS_ENABLED(CONFIG_DCACHE_WRITETHROUGH))
local_dcache_range_flush((unsigned long)waddr,
(unsigned long)waddr + OPENRISC_INSN_SIZE);
local_icache_range_inv((unsigned long)waddr,
(unsigned long)waddr + OPENRISC_INSN_SIZE);
patch_unmap(FIX_TEXT_POKE0);
raw_spin_unlock_irqrestore(&patch_lock, flags);
return ret;
}
/*
* patch_insn_write - Write a single instruction to a specified memory location
* This API provides a single-instruction patching, primarily used for runtime
* code modification.
* By the way, the insn size must be 4 bytes.
*/
int patch_insn_write(void *addr, u32 insn)
{
u32 *tp = addr;
int ret;
if ((uintptr_t) tp & 0x3)
return -EINVAL;
ret = __patch_insn_write(tp, insn);
return ret;
}
+288
View File
@@ -0,0 +1,288 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC process.c
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* Modifications for the OpenRISC architecture:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*
* This file handles the architecture-dependent parts of process handling...
*/
#define __KERNEL_SYSCALLS__
#include <linux/cpu.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/sched/task.h>
#include <linux/sched/task_stack.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/elfcore.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/init_task.h>
#include <linux/mqueue.h>
#include <linux/fs.h>
#include <linux/reboot.h>
#include <linux/uaccess.h>
#include <asm/fpu.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/spr_defs.h>
#include <asm/switch_to.h>
#include <linux/smp.h>
/*
* Pointer to Current thread info structure.
*
* Used at user space -> kernel transitions.
*/
struct thread_info *current_thread_info_set[NR_CPUS] = { &init_thread_info, };
void machine_restart(char *cmd)
{
do_kernel_restart(cmd);
__asm__("l.nop 13");
/* Give a grace period for failure to restart of 1s */
mdelay(1000);
/* Whoops - the platform was unable to reboot. Tell the user! */
pr_emerg("Reboot failed -- System halted\n");
while (1);
}
/*
* This is used if a sys-off handler was not set by a power management
* driver, in this case we can assume we are on a simulator. On
* OpenRISC simulators l.nop 1 will trigger the simulator exit.
*/
static void default_power_off(void)
{
__asm__("l.nop 1");
}
/*
* Similar to machine_power_off, but don't shut off power. Add code
* here to freeze the system for e.g. post-mortem debug purpose when
* possible. This halt has nothing to do with the idle halt.
*/
void machine_halt(void)
{
printk(KERN_INFO "*** MACHINE HALT ***\n");
__asm__("l.nop 1");
}
/* If or when software power-off is implemented, add code here. */
void machine_power_off(void)
{
printk(KERN_INFO "*** MACHINE POWER OFF ***\n");
do_kernel_power_off();
default_power_off();
}
/*
* Send the doze signal to the cpu if available.
* Make sure, that all interrupts are enabled
*/
void arch_cpu_idle(void)
{
raw_local_irq_enable();
if (mfspr(SPR_UPR) & SPR_UPR_PMP)
mtspr(SPR_PMR, mfspr(SPR_PMR) | SPR_PMR_DME);
raw_local_irq_disable();
}
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
/*
* When a process does an "exec", machine state like FPU and debug
* registers need to be reset. This is a hook function for that.
* Currently we don't have any such state to reset, so this is empty.
*/
void flush_thread(void)
{
}
void show_regs(struct pt_regs *regs)
{
show_regs_print_info(KERN_DEFAULT);
/* __PHX__ cleanup this mess */
show_registers(regs);
}
/*
* Copy the thread-specific (arch specific) info from the current
* process to the new one p
*/
extern asmlinkage void ret_from_fork(void);
/*
* copy_thread
* @clone_flags: flags
* @usp: user stack pointer or fn for kernel thread
* @arg: arg to fn for kernel thread; always NULL for userspace thread
* @p: the newly created task
* @tls: the Thread Local Storage pointer for the new process
*
* At the top of a newly initialized kernel stack are two stacked pt_reg
* structures. The first (topmost) is the userspace context of the thread.
* The second is the kernelspace context of the thread.
*
* A kernel thread will not be returning to userspace, so the topmost pt_regs
* struct can be uninitialized; it _does_ need to exist, though, because
* a kernel thread can become a userspace thread by doing a kernel_execve, in
* which case the topmost context will be initialized and used for 'returning'
* to userspace.
*
* The second pt_reg struct needs to be initialized to 'return' to
* ret_from_fork. A kernel thread will need to set r20 to the address of
* a function to call into (with arg in r22); userspace threads need to set
* r20 to NULL in which case ret_from_fork will just continue a return to
* userspace.
*
* A kernel thread 'fn' may return; this is effectively what happens when
* kernel_execve is called. In that case, the userspace pt_regs must have
* been initialized (which kernel_execve takes care of, see start_thread
* below); ret_from_fork will then continue its execution causing the
* 'kernel thread' to return to userspace as a userspace thread.
*/
int
copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
u64 clone_flags = args->flags;
unsigned long usp = args->stack;
unsigned long tls = args->tls;
struct pt_regs *userregs;
struct pt_regs *kregs;
unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
unsigned long top_of_kernel_stack;
top_of_kernel_stack = sp;
/* Locate userspace context on stack... */
sp -= STACK_FRAME_OVERHEAD; /* redzone */
sp -= sizeof(struct pt_regs);
userregs = (struct pt_regs *) sp;
/* ...and kernel context */
sp -= STACK_FRAME_OVERHEAD; /* redzone */
sp -= sizeof(struct pt_regs);
kregs = (struct pt_regs *)sp;
if (unlikely(args->fn)) {
memset(kregs, 0, sizeof(struct pt_regs));
kregs->gpr[20] = (unsigned long)args->fn;
kregs->gpr[22] = (unsigned long)args->fn_arg;
} else {
*userregs = *current_pt_regs();
if (usp)
userregs->sp = usp;
/*
* For CLONE_SETTLS set "tp" (r10) to the TLS pointer.
*/
if (clone_flags & CLONE_SETTLS)
userregs->gpr[10] = tls;
userregs->gpr[11] = 0; /* Result from fork() */
kregs->gpr[20] = 0; /* Userspace thread */
}
/*
* _switch wants the kernel stack page in pt_regs->sp so that it
* can restore it to thread_info->ksp... see _switch for details.
*/
kregs->sp = top_of_kernel_stack;
kregs->gpr[9] = (unsigned long)ret_from_fork;
task_thread_info(p)->ksp = (unsigned long)kregs;
return 0;
}
/*
* Set up a thread for executing a new program
*/
void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp)
{
unsigned long sr = mfspr(SPR_SR) & ~SPR_SR_SM;
memset(regs, 0, sizeof(struct pt_regs));
regs->pc = pc;
regs->sr = sr;
regs->sp = sp;
}
extern struct thread_info *_switch(struct thread_info *old_ti,
struct thread_info *new_ti);
extern int lwa_flag;
struct task_struct *__switch_to(struct task_struct *old,
struct task_struct *new)
{
struct task_struct *last;
struct thread_info *new_ti, *old_ti;
unsigned long flags;
local_irq_save(flags);
save_fpu(current);
/* current_set is an array of saved current pointers
* (one for each cpu). we need them at user->kernel transition,
* while we save them at kernel->user transition
*/
new_ti = new->stack;
old_ti = old->stack;
lwa_flag = 0;
current_thread_info_set[smp_processor_id()] = new_ti;
last = (_switch(old_ti, new_ti))->task;
restore_fpu(current);
local_irq_restore(flags);
return last;
}
/*
* Write out registers in core dump format, as defined by the
* struct user_regs_struct
*/
void dump_elf_thread(elf_greg_t *dest, struct pt_regs* regs)
{
dest[0] = 0; /* r0 */
memcpy(dest+1, regs->gpr+1, 31*sizeof(unsigned long));
dest[32] = regs->pc;
dest[33] = regs->sr;
dest[34] = 0;
dest[35] = 0;
}
unsigned long __get_wchan(struct task_struct *p)
{
/* TODO */
return 0;
}
+27
View File
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC prom.c
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* Modifications for the OpenRISC architecture:
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*
* Architecture specific procedures for creating, accessing and
* interpreting the device tree.
*/
#include <linux/init.h>
#include <linux/types.h>
#include <linux/memblock.h>
#include <linux/of_fdt.h>
#include <asm/page.h>
void __init early_init_devtree(void *params)
{
early_init_dt_scan(params, __pa(params));
memblock_allow_resize();
}
+319
View File
@@ -0,0 +1,319 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC ptrace.c
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* Modifications for the OpenRISC architecture:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2005 Gyorgy Jeney <nog@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/audit.h>
#include <linux/regset.h>
#include <linux/elf.h>
#include <asm/thread_info.h>
#include <asm/page.h>
asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
asmlinkage void do_syscall_trace_leave(struct pt_regs *regs);
/*
* Copy the thread state to a regset that can be interpreted by userspace.
*
* It doesn't matter what our internal pt_regs structure looks like. The
* important thing is that we export a consistent view of the thread state
* to userspace. As such, we need to make sure that the regset remains
* ABI compatible as defined by the struct user_regs_struct:
*
* (Each item is a 32-bit word)
* r0 = 0 (exported for clarity)
* 31 GPRS r1-r31
* PC (Program counter)
* SR (Supervision register)
*/
static int genregs_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
const struct pt_regs *regs = task_pt_regs(target);
/* r0 */
membuf_zero(&to, 4);
membuf_write(&to, regs->gpr + 1, 31 * 4);
membuf_store(&to, regs->pc);
return membuf_store(&to, regs->sr);
}
/*
* Set the thread state from a regset passed in via ptrace
*/
static int genregs_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user * ubuf)
{
struct pt_regs *regs = task_pt_regs(target);
int ret;
/* ignore r0 */
user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, 4);
/* r1 - r31 */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
regs->gpr+1, 4, 4*32);
/* PC */
if (!ret)
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&regs->pc, 4*32, 4*33);
/*
* Skip SR and padding... userspace isn't allowed to changes bits in
* the Supervision register
*/
if (!ret)
user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 4*33, -1);
return ret;
}
#ifdef CONFIG_FPU
/*
* As OpenRISC shares GPRs and floating point registers we don't need to export
* the floating point registers again. So here we only export the fpcsr special
* purpose register.
*/
static int fpregs_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
return membuf_store(&to, target->thread.fpcsr);
}
static int fpregs_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
/* FPCSR */
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&target->thread.fpcsr, 0, 4);
}
#endif
/*
* Define the register sets available on OpenRISC under Linux
*/
enum or1k_regset {
REGSET_GENERAL,
#ifdef CONFIG_FPU
REGSET_FPU,
#endif
};
static const struct user_regset or1k_regsets[] = {
[REGSET_GENERAL] = {
USER_REGSET_NOTE_TYPE(PRSTATUS),
.n = ELF_NGREG,
.size = sizeof(long),
.align = sizeof(long),
.regset_get = genregs_get,
.set = genregs_set,
},
#ifdef CONFIG_FPU
[REGSET_FPU] = {
USER_REGSET_NOTE_TYPE(PRFPREG),
.n = sizeof(struct __or1k_fpu_state) / sizeof(long),
.size = sizeof(long),
.align = sizeof(long),
.regset_get = fpregs_get,
.set = fpregs_set,
},
#endif
};
static const struct user_regset_view user_or1k_native_view = {
.name = "or1k",
.e_machine = EM_OPENRISC,
.regsets = or1k_regsets,
.n = ARRAY_SIZE(or1k_regsets),
};
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
return &user_or1k_native_view;
}
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
*/
struct pt_regs_offset {
const char *name;
int offset;
};
#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
#define REG_OFFSET_END {.name = NULL, .offset = 0}
static const struct pt_regs_offset regoffset_table[] = {
REG_OFFSET_NAME(sr),
REG_OFFSET_NAME(sp),
REG_OFFSET_NAME(gpr2),
REG_OFFSET_NAME(gpr3),
REG_OFFSET_NAME(gpr4),
REG_OFFSET_NAME(gpr5),
REG_OFFSET_NAME(gpr6),
REG_OFFSET_NAME(gpr7),
REG_OFFSET_NAME(gpr8),
REG_OFFSET_NAME(gpr9),
REG_OFFSET_NAME(gpr10),
REG_OFFSET_NAME(gpr11),
REG_OFFSET_NAME(gpr12),
REG_OFFSET_NAME(gpr13),
REG_OFFSET_NAME(gpr14),
REG_OFFSET_NAME(gpr15),
REG_OFFSET_NAME(gpr16),
REG_OFFSET_NAME(gpr17),
REG_OFFSET_NAME(gpr18),
REG_OFFSET_NAME(gpr19),
REG_OFFSET_NAME(gpr20),
REG_OFFSET_NAME(gpr21),
REG_OFFSET_NAME(gpr22),
REG_OFFSET_NAME(gpr23),
REG_OFFSET_NAME(gpr24),
REG_OFFSET_NAME(gpr25),
REG_OFFSET_NAME(gpr26),
REG_OFFSET_NAME(gpr27),
REG_OFFSET_NAME(gpr28),
REG_OFFSET_NAME(gpr29),
REG_OFFSET_NAME(gpr30),
REG_OFFSET_NAME(gpr31),
REG_OFFSET_NAME(pc),
REG_OFFSET_NAME(orig_gpr11),
REG_OFFSET_END,
};
/**
* regs_query_register_offset() - query register offset from its name
* @name: the name of a register
*
* regs_query_register_offset() returns the offset of a register in struct
* pt_regs from its name. If the name is invalid, this returns -EINVAL;
*/
int regs_query_register_offset(const char *name)
{
const struct pt_regs_offset *roff;
for (roff = regoffset_table; roff->name != NULL; roff++)
if (!strcmp(roff->name, name))
return roff->offset;
return -EINVAL;
}
/**
* regs_within_kernel_stack() - check the address in the stack
* @regs: pt_regs which contains kernel stack pointer.
* @addr: address which is checked.
*
* regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
* If @addr is within the kernel stack, it returns true. If not, returns false.
*/
static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
{
return (addr & ~(THREAD_SIZE - 1)) ==
(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1));
}
/**
* regs_get_kernel_stack_nth() - get Nth entry of the stack
* @regs: pt_regs which contains kernel stack pointer.
* @n: stack entry number.
*
* regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
* is specified by @regs. If the @n th entry is NOT in the kernel stack,
* this returns 0.
*/
unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
{
unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
addr += n;
if (regs_within_kernel_stack(regs, (unsigned long)addr))
return *addr;
else
return 0;
}
/*
* Called by kernel/ptrace.c when detaching..
*
* Make sure the single step bit is not set.
*/
void ptrace_disable(struct task_struct *child)
{
pr_debug("ptrace_disable(): TODO\n");
user_disable_single_step(child);
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}
long arch_ptrace(struct task_struct *child, long request, unsigned long addr,
unsigned long data)
{
int ret;
switch (request) {
default:
ret = ptrace_request(child, request, addr, data);
break;
}
return ret;
}
/*
* Notification of system call entry/exit
* - triggered by current->work.syscall_trace
*/
asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
{
long ret = 0;
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
ptrace_report_syscall_entry(regs))
/*
* Tracing decided this syscall should not happen.
* We'll return a bogus call number to get an ENOSYS
* error, but leave the original number in <something>.
*/
ret = -1L;
audit_syscall_entry(regs->gpr[11], regs->gpr[3], regs->gpr[4],
regs->gpr[5], regs->gpr[6]);
return ret ? : regs->gpr[11];
}
asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
{
int step;
audit_syscall_exit(regs);
step = test_thread_flag(TIF_SINGLESTEP);
if (step || test_thread_flag(TIF_SYSCALL_TRACE))
ptrace_report_syscall_exit(regs, step);
}
+340
View File
@@ -0,0 +1,340 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC setup.c
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* Modifications for the OpenRISC architecture:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*
* This file handles the architecture-dependent parts of initialization
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/memblock.h>
#include <linux/seq_file.h>
#include <linux/serial.h>
#include <linux/initrd.h>
#include <linux/of_fdt.h>
#include <linux/of.h>
#include <linux/device.h>
#include <asm/sections.h>
#include <asm/types.h>
#include <asm/setup.h>
#include <asm/io.h>
#include <asm/cpuinfo.h>
#include <asm/delay.h>
#include "vmlinux.h"
static void __init setup_memory(void)
{
unsigned long ram_start_pfn;
unsigned long ram_end_pfn;
phys_addr_t memory_start, memory_end;
memory_end = memory_start = 0;
/* Find main memory where is the kernel, we assume its the only one */
memory_start = memblock_start_of_DRAM();
memory_end = memblock_end_of_DRAM();
if (!memory_end) {
panic("No memory!");
}
ram_start_pfn = PFN_UP(memory_start);
ram_end_pfn = PFN_DOWN(memblock_end_of_DRAM());
/* setup bootmem globals (we use no_bootmem, but mm still depends on this) */
min_low_pfn = ram_start_pfn;
max_low_pfn = ram_end_pfn;
max_pfn = ram_end_pfn;
/*
* initialize the boot-time allocator (with low memory only).
*
* This makes the memory from the end of the kernel to the end of
* RAM usable.
*/
memblock_reserve(__pa(_stext), _end - _stext);
#ifdef CONFIG_BLK_DEV_INITRD
/* Then reserve the initrd, if any */
if (initrd_start && (initrd_end > initrd_start)) {
unsigned long aligned_start = ALIGN_DOWN(initrd_start, PAGE_SIZE);
unsigned long aligned_end = ALIGN(initrd_end, PAGE_SIZE);
memblock_reserve(__pa(aligned_start), aligned_end - aligned_start);
}
#endif /* CONFIG_BLK_DEV_INITRD */
early_init_fdt_reserve_self();
early_init_fdt_scan_reserved_mem();
memblock_dump_all();
}
struct cpuinfo_or1k cpuinfo_or1k[NR_CPUS];
static void print_cpuinfo(void)
{
unsigned long upr = mfspr(SPR_UPR);
unsigned long vr = mfspr(SPR_VR);
unsigned int version;
unsigned int revision;
struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[smp_processor_id()];
version = (vr & SPR_VR_VER) >> 24;
revision = (vr & SPR_VR_REV);
printk(KERN_INFO "CPU: OpenRISC-%x (revision %d) @%d MHz\n",
version, revision, cpuinfo->clock_frequency / 1000000);
if (!(upr & SPR_UPR_UP)) {
printk(KERN_INFO
"-- no UPR register... unable to detect configuration\n");
return;
}
if (upr & SPR_UPR_DMP)
printk(KERN_INFO "-- dmmu: %4d entries, %lu way(s)\n",
1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2),
1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW));
if (upr & SPR_UPR_IMP)
printk(KERN_INFO "-- immu: %4d entries, %lu way(s)\n",
1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2),
1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW));
printk(KERN_INFO "-- additional features:\n");
if (upr & SPR_UPR_DUP)
printk(KERN_INFO "-- debug unit\n");
if (upr & SPR_UPR_PCUP)
printk(KERN_INFO "-- performance counters\n");
if (upr & SPR_UPR_PMP)
printk(KERN_INFO "-- power management\n");
if (upr & SPR_UPR_PICP)
printk(KERN_INFO "-- PIC\n");
if (upr & SPR_UPR_TTP)
printk(KERN_INFO "-- timer\n");
if (upr & SPR_UPR_CUP)
printk(KERN_INFO "-- custom unit(s)\n");
}
void __init setup_cpuinfo(void)
{
struct device_node *cpu;
int cpu_id = smp_processor_id();
struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[cpu_id];
cpu = of_get_cpu_node(cpu_id, NULL);
if (!cpu)
panic("Couldn't find CPU%d in device tree...\n", cpu_id);
if (of_property_read_u32(cpu, "clock-frequency",
&cpuinfo->clock_frequency)) {
printk(KERN_WARNING
"Device tree missing CPU 'clock-frequency' parameter."
"Assuming frequency 25MHZ"
"This is probably not what you want.");
}
cpuinfo->coreid = mfspr(SPR_COREID);
of_node_put(cpu);
print_cpuinfo();
}
/**
* or1k_early_setup
* @fdt: pointer to the start of the device tree in memory or NULL
*
* Handles the pointer to the device tree that this kernel is to use
* for establishing the available platform devices.
*
* Falls back on built-in device tree in case null pointer is passed.
*/
void __init or1k_early_setup(void *fdt)
{
if (fdt)
pr_info("FDT at %p\n", fdt);
else {
fdt = __dtb_start;
pr_info("Compiled-in FDT at %p\n", fdt);
}
early_init_devtree(fdt);
}
static inline unsigned long extract_value_bits(unsigned long reg,
short bit_nr, short width)
{
return (reg >> bit_nr) & (0 << width);
}
static inline unsigned long extract_value(unsigned long reg, unsigned long mask)
{
while (!(mask & 0x1)) {
reg = reg >> 1;
mask = mask >> 1;
}
return mask & reg;
}
/*
* calibrate_delay
*
* Lightweight calibrate_delay implementation that calculates loops_per_jiffy
* from the clock frequency passed in via the device tree
*
*/
void calibrate_delay(void)
{
const int *val;
struct device_node *cpu = of_get_cpu_node(smp_processor_id(), NULL);
val = of_get_property(cpu, "clock-frequency", NULL);
if (!val)
panic("no cpu 'clock-frequency' parameter in device tree");
loops_per_jiffy = *val / HZ;
pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
loops_per_jiffy / (500000 / HZ),
(loops_per_jiffy / (5000 / HZ)) % 100, loops_per_jiffy);
of_node_put(cpu);
}
void __init setup_arch(char **cmdline_p)
{
/* setup memblock allocator */
setup_memory();
unflatten_and_copy_device_tree();
setup_cpuinfo();
#ifdef CONFIG_SMP
smp_init_cpus();
#endif
/* process 1's initial memory region is the kernel code/data */
setup_initial_init_mm(_stext, _etext, _edata, _end);
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start == initrd_end) {
printk(KERN_INFO "Initial ramdisk not found\n");
initrd_start = 0;
initrd_end = 0;
} else {
printk(KERN_INFO "Initial ramdisk at: 0x%p (%lu bytes)\n",
(void *)(initrd_start), initrd_end - initrd_start);
initrd_below_start_ok = 1;
}
#endif
/* perform jump_table sorting before paging_init locks down read only memory */
jump_label_init();
/* paging_init() sets up the MMU and marks all pages as reserved */
paging_init();
*cmdline_p = boot_command_line;
printk(KERN_INFO "OpenRISC Linux -- http://openrisc.io\n");
}
static int show_cpuinfo(struct seq_file *m, void *v)
{
unsigned int vr, cpucfgr;
unsigned int avr;
unsigned int version;
#ifdef CONFIG_SMP
struct cpuinfo_or1k *cpuinfo = v;
seq_printf(m, "processor\t\t: %d\n", cpuinfo->coreid);
#endif
vr = mfspr(SPR_VR);
cpucfgr = mfspr(SPR_CPUCFGR);
if (vr & SPR_VR_UVRP) {
vr = mfspr(SPR_VR2);
version = vr & SPR_VR2_VER;
avr = mfspr(SPR_AVR);
seq_printf(m, "cpu architecture\t: "
"OpenRISC 1000 (%d.%d-rev%d)\n",
(avr >> 24) & 0xff,
(avr >> 16) & 0xff,
(avr >> 8) & 0xff);
seq_printf(m, "cpu implementation id\t: 0x%x\n",
(vr & SPR_VR2_CPUID) >> 24);
seq_printf(m, "cpu version\t\t: 0x%x\n", version);
} else {
version = (vr & SPR_VR_VER) >> 24;
seq_printf(m, "cpu\t\t\t: OpenRISC-%x\n", version);
seq_printf(m, "revision\t\t: %d\n", vr & SPR_VR_REV);
}
seq_printf(m, "frequency\t\t: %ld\n", loops_per_jiffy * HZ);
seq_printf(m, "immu\t\t\t: %d entries, %lu ways\n",
1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2),
1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW));
seq_printf(m, "dmmu\t\t\t: %d entries, %lu ways\n",
1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2),
1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW));
seq_printf(m, "bogomips\t\t: %lu.%02lu\n",
(loops_per_jiffy * HZ) / 500000,
((loops_per_jiffy * HZ) / 5000) % 100);
seq_puts(m, "features\t\t: ");
seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OB32S ? "orbis32" : "");
seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OB64S ? "orbis64" : "");
seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OF32S ? "orfpx32" : "");
seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OF64S ? "orfpx64" : "");
seq_printf(m, "%s ", cpucfgr & SPR_CPUCFGR_OV64S ? "orvdx64" : "");
seq_puts(m, "\n");
seq_puts(m, "\n");
return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
{
*pos = cpumask_next(*pos - 1, cpu_online_mask);
if ((*pos) < nr_cpu_ids)
return &cpuinfo_or1k[*pos];
return NULL;
}
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
(*pos)++;
return c_start(m, pos);
}
static void c_stop(struct seq_file *m, void *v)
{
}
const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
.show = show_cpuinfo,
};
+361
View File
@@ -0,0 +1,361 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC signal.c
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* Modifications for the OpenRISC architecture:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/resume_user_mode.h>
#include <asm/fpu.h>
#include <asm/processor.h>
#include <asm/syscall.h>
#include <asm/ucontext.h>
#include <linux/uaccess.h>
struct rt_sigframe {
struct siginfo info;
struct ucontext uc;
unsigned char retcode[16]; /* trampoline code */
};
asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs);
asmlinkage int do_work_pending(struct pt_regs *regs, unsigned int thread_flags,
int syscall);
#ifdef CONFIG_FPU
static long restore_fp_state(struct sigcontext __user *sc)
{
long err;
err = __copy_from_user(&current->thread.fpcsr, &sc->fpcsr, sizeof(unsigned long));
if (unlikely(err))
return err;
/* Restore the FPU state */
restore_fpu(current);
return 0;
}
static long save_fp_state(struct sigcontext __user *sc)
{
long err;
/* Sync the user FPU state so we can copy to sigcontext */
save_fpu(current);
err = __copy_to_user(&sc->fpcsr, &current->thread.fpcsr, sizeof(unsigned long));
return err;
}
#else
#define save_fp_state(sc) (0)
#define restore_fp_state(sc) (0)
#endif
static int restore_sigcontext(struct pt_regs *regs,
struct sigcontext __user *sc)
{
unsigned long old_sr = regs->sr;
int err = 0;
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
/*
* Restore the regs from &sc->regs.
* (sc is already checked since the sigframe was
* checked in sys_sigreturn previously)
*/
err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long));
err |= __copy_from_user(&regs->pc, &sc->regs.pc, sizeof(unsigned long));
err |= __copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long));
err |= restore_fp_state(sc);
/* keep the privileged SR bits kernel owned, restore only user flags */
regs->sr = (old_sr & ~SPR_SR_USER_MASK) | (regs->sr & SPR_SR_USER_MASK);
regs->orig_gpr11 = -1; /* Avoid syscall restart checks */
/* TODO: the other ports use regs->orig_XX to disable syscall checks
* after this completes, but we don't use that mechanism. maybe we can
* use it now ?
*/
return err;
}
asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->sp;
sigset_t set;
/*
* Since we stacked the signal on a dword boundary,
* then frame should be dword aligned here. If it's
* not, then the user is trying to mess with us.
*/
if (((unsigned long)frame) & 3)
goto badframe;
if (!access_ok(frame, sizeof(*frame)))
goto badframe;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return regs->gpr[11];
badframe:
force_sig(SIGSEGV);
return 0;
}
/*
* Set up a signal frame.
*/
static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
{
int err = 0;
/* copy the regs */
/* There should be no need to save callee-saved registers here...
* ...but we save them anyway. Revisit this
*/
err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long));
err |= __copy_to_user(&sc->regs.pc, &regs->pc, sizeof(unsigned long));
err |= __copy_to_user(&sc->regs.sr, &regs->sr, sizeof(unsigned long));
err |= save_fp_state(sc);
return err;
}
static inline unsigned long align_sigframe(unsigned long sp)
{
return sp & ~3UL;
}
/*
* Work out where the signal frame should go. It's either on the user stack
* or the alternate stack.
*/
static inline void __user *get_sigframe(struct ksignal *ksig,
struct pt_regs *regs, size_t frame_size)
{
unsigned long sp = regs->sp;
/* redzone */
sp -= STACK_FRAME_OVERHEAD;
sp = sigsp(sp, ksig);
sp = align_sigframe(sp - frame_size);
return (void __user *)sp;
}
/* grab and setup a signal frame.
*
* basically we stack a lot of state info, and arrange for the
* user-mode program to return to the kernel using either a
* trampoline which performs the syscall sigreturn, or a provided
* user-mode trampoline.
*/
static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
unsigned long return_ip;
int err = 0;
frame = get_sigframe(ksig, regs, sizeof(*frame));
if (!access_ok(frame, sizeof(*frame)))
return -EFAULT;
/* Create siginfo. */
if (ksig->ka.sa.sa_flags & SA_SIGINFO)
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(NULL, &frame->uc.uc_link);
err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
err |= setup_sigcontext(regs, &frame->uc.uc_mcontext);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
return -EFAULT;
/* trampoline - the desired return ip is the retcode itself */
return_ip = (unsigned long)&frame->retcode;
/* This is:
l.ori r11,r0,__NR_sigreturn
l.sys 1
*/
err |= __put_user(0xa960, (short __user *)(frame->retcode + 0));
err |= __put_user(__NR_rt_sigreturn, (short __user *)(frame->retcode + 2));
err |= __put_user(0x20000001, (unsigned long __user *)(frame->retcode + 4));
err |= __put_user(0x15000000, (unsigned long __user *)(frame->retcode + 8));
if (err)
return -EFAULT;
/* Set up registers for signal handler */
regs->pc = (unsigned long)ksig->ka.sa.sa_handler; /* what we enter NOW */
regs->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
regs->gpr[3] = (unsigned long)ksig->sig; /* arg 1: signo */
regs->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
regs->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
/* actually move the usp to reflect the stacked frame */
regs->sp = (unsigned long)frame;
return 0;
}
static inline void
handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
int ret;
rseq_signal_deliver(ksig, regs);
ret = setup_rt_frame(ksig, sigmask_to_save(), regs);
signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
}
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*
* Also note that the regs structure given here as an argument, is the latest
* pushed pt_regs. It may or may not be the same as the first pushed registers
* when the initial usermode->kernelmode transition took place. Therefore
* we can use user_mode(regs) to see if we came directly from kernel or user
* mode below.
*/
static int do_signal(struct pt_regs *regs, int syscall)
{
struct ksignal ksig;
unsigned long continue_addr = 0;
unsigned long restart_addr = 0;
unsigned long retval = 0;
int restart = 0;
if (syscall) {
continue_addr = regs->pc;
restart_addr = continue_addr - 4;
retval = regs->gpr[11];
/*
* Setup syscall restart here so that a debugger will
* see the already changed PC.
*/
switch (retval) {
case -ERESTART_RESTARTBLOCK:
restart = -2;
fallthrough;
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
restart++;
regs->gpr[11] = regs->orig_gpr11;
regs->pc = restart_addr;
break;
}
}
/*
* Get the signal to deliver. During the call to get_signal the
* debugger may change all our registers so we may need to revert
* the decision to restart the syscall; specifically, if the PC is
* changed, don't restart the syscall.
*/
if (get_signal(&ksig)) {
if (unlikely(restart) && regs->pc == restart_addr) {
if (retval == -ERESTARTNOHAND ||
retval == -ERESTART_RESTARTBLOCK
|| (retval == -ERESTARTSYS
&& !(ksig.ka.sa.sa_flags & SA_RESTART))) {
/* No automatic restart */
regs->gpr[11] = -EINTR;
regs->pc = continue_addr;
}
}
handle_signal(&ksig, regs);
} else {
/* no handler */
restore_saved_sigmask();
/*
* Restore pt_regs PC as syscall restart will be handled by
* kernel without return to userspace
*/
if (unlikely(restart) && regs->pc == restart_addr) {
regs->pc = continue_addr;
return restart;
}
}
return 0;
}
asmlinkage int
do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
{
do {
if (likely(thread_flags & _TIF_NEED_RESCHED)) {
schedule();
} else {
if (unlikely(!user_mode(regs)))
return 0;
local_irq_enable();
if (thread_flags & (_TIF_SIGPENDING|_TIF_NOTIFY_SIGNAL)) {
int restart = do_signal(regs, syscall);
if (unlikely(restart)) {
/*
* Restart without handlers.
* Deal with it without leaving
* the kernel space.
*/
return restart;
}
syscall = 0;
} else {
resume_user_mode_work(regs);
}
}
local_irq_disable();
thread_flags = read_thread_flags();
} while (thread_flags & _TIF_WORK_MASK);
return 0;
}
+369
View File
@@ -0,0 +1,369 @@
/*
* Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
* Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
*
* Based on arm64 and arc implementations
* Copyright (C) 2013 ARM Ltd.
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/smp.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/sched/mm.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <asm/cpuinfo.h>
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
#include <asm/time.h>
asmlinkage __init void secondary_start_kernel(void);
static unsigned int ipi_irq __ro_after_init;
static void (*smp_cross_call)(const struct cpumask *, unsigned int);
unsigned long secondary_release = -1;
struct thread_info *secondary_thread_info;
enum ipi_msg_type {
IPI_WAKEUP,
IPI_RESCHEDULE,
IPI_CALL_FUNC,
IPI_CALL_FUNC_SINGLE,
};
static DEFINE_SPINLOCK(boot_lock);
static void or1k_ipi_enable(void)
{
if (WARN_ON_ONCE(!ipi_irq))
return;
enable_percpu_irq(ipi_irq, 0);
}
static void boot_secondary(unsigned int cpu, struct task_struct *idle)
{
/*
* set synchronisation state between this boot processor
* and the secondary one
*/
spin_lock(&boot_lock);
secondary_release = cpu;
smp_cross_call(cpumask_of(cpu), IPI_WAKEUP);
/*
* now the secondary core is starting up let it run its
* calibrations, then wait for it to finish
*/
spin_unlock(&boot_lock);
}
void __init smp_init_cpus(void)
{
struct device_node *cpu;
u32 cpu_id;
for_each_of_cpu_node(cpu) {
cpu_id = of_get_cpu_hwid(cpu, 0);
if (cpu_id < NR_CPUS)
set_cpu_possible(cpu_id, true);
}
}
void __init smp_prepare_cpus(unsigned int max_cpus)
{
unsigned int cpu;
/*
* Initialise the present map, which describes the set of CPUs
* actually populated at the present time.
*/
for_each_possible_cpu(cpu) {
if (cpu < max_cpus)
set_cpu_present(cpu, true);
}
}
void __init smp_cpus_done(unsigned int max_cpus)
{
}
static DECLARE_COMPLETION(cpu_running);
int __cpu_up(unsigned int cpu, struct task_struct *idle)
{
if (smp_cross_call == NULL) {
pr_warn("CPU%u: failed to start, IPI controller missing",
cpu);
return -EIO;
}
secondary_thread_info = task_thread_info(idle);
current_pgd[cpu] = init_mm.pgd;
boot_secondary(cpu, idle);
if (!wait_for_completion_timeout(&cpu_running,
msecs_to_jiffies(1000))) {
pr_crit("CPU%u: failed to start\n", cpu);
return -EIO;
}
synchronise_count_master(cpu);
return 0;
}
asmlinkage __init void secondary_start_kernel(void)
{
struct mm_struct *mm = &init_mm;
unsigned int cpu = smp_processor_id();
/*
* All kernel threads share the same mm context; grab a
* reference and switch to it.
*/
mmgrab(mm);
current->active_mm = mm;
cpumask_set_cpu(cpu, mm_cpumask(mm));
pr_info("CPU%u: Booted secondary processor\n", cpu);
setup_cpuinfo();
openrisc_clockevent_init();
notify_cpu_starting(cpu);
/*
* OK, now it's safe to let the boot CPU continue
*/
complete(&cpu_running);
synchronise_count_slave(cpu);
or1k_ipi_enable();
set_cpu_online(cpu, true);
local_irq_enable();
/*
* OK, it's off to the idle thread for us
*/
cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
}
void handle_IPI(unsigned int ipi_msg)
{
unsigned int cpu = smp_processor_id();
switch (ipi_msg) {
case IPI_WAKEUP:
break;
case IPI_RESCHEDULE:
scheduler_ipi();
break;
case IPI_CALL_FUNC:
generic_smp_call_function_interrupt();
break;
case IPI_CALL_FUNC_SINGLE:
generic_smp_call_function_single_interrupt();
break;
default:
WARN(1, "CPU%u: Unknown IPI message 0x%x\n", cpu, ipi_msg);
break;
}
}
void arch_smp_send_reschedule(int cpu)
{
smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
}
static void stop_this_cpu(void *dummy)
{
/* Remove this CPU */
set_cpu_online(smp_processor_id(), false);
local_irq_disable();
/* CPU Doze */
if (mfspr(SPR_UPR) & SPR_UPR_PMP)
mtspr(SPR_PMR, mfspr(SPR_PMR) | SPR_PMR_DME);
/* If that didn't work, infinite loop */
while (1)
;
}
void smp_send_stop(void)
{
smp_call_function(stop_this_cpu, NULL, 0);
}
void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int),
unsigned int irq)
{
if (WARN_ON(ipi_irq))
return;
smp_cross_call = fn;
ipi_irq = irq;
/* Enabled IPIs for boot CPU immediately */
or1k_ipi_enable();
}
void arch_send_call_function_single_ipi(int cpu)
{
smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
}
void arch_send_call_function_ipi_mask(const struct cpumask *mask)
{
smp_cross_call(mask, IPI_CALL_FUNC);
}
/* TLB flush operations - Performed on each CPU*/
static inline void ipi_flush_tlb_all(void *ignored)
{
local_flush_tlb_all();
}
static inline void ipi_flush_tlb_mm(void *info)
{
struct mm_struct *mm = (struct mm_struct *)info;
local_flush_tlb_mm(mm);
}
static void smp_flush_tlb_mm(struct cpumask *cmask, struct mm_struct *mm)
{
unsigned int cpuid;
if (cpumask_empty(cmask))
return;
cpuid = get_cpu();
if (cpumask_any_but(cmask, cpuid) >= nr_cpu_ids) {
/* local cpu is the only cpu present in cpumask */
local_flush_tlb_mm(mm);
} else {
on_each_cpu_mask(cmask, ipi_flush_tlb_mm, mm, 1);
}
put_cpu();
}
struct flush_tlb_data {
unsigned long addr1;
unsigned long addr2;
};
static inline void ipi_flush_tlb_page(void *info)
{
struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
local_flush_tlb_page(NULL, fd->addr1);
}
static inline void ipi_flush_tlb_range(void *info)
{
struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
local_flush_tlb_range(NULL, fd->addr1, fd->addr2);
}
static void smp_flush_tlb_range(const struct cpumask *cmask, unsigned long start,
unsigned long end)
{
unsigned int cpuid;
if (cpumask_empty(cmask))
return;
cpuid = get_cpu();
if (cpumask_any_but(cmask, cpuid) >= nr_cpu_ids) {
/* local cpu is the only cpu present in cpumask */
if ((end - start) <= PAGE_SIZE)
local_flush_tlb_page(NULL, start);
else
local_flush_tlb_range(NULL, start, end);
} else {
struct flush_tlb_data fd;
fd.addr1 = start;
fd.addr2 = end;
if ((end - start) <= PAGE_SIZE)
on_each_cpu_mask(cmask, ipi_flush_tlb_page, &fd, 1);
else
on_each_cpu_mask(cmask, ipi_flush_tlb_range, &fd, 1);
}
put_cpu();
}
void flush_tlb_all(void)
{
on_each_cpu(ipi_flush_tlb_all, NULL, 1);
}
void flush_tlb_mm(struct mm_struct *mm)
{
smp_flush_tlb_mm(mm_cpumask(mm), mm);
}
void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
{
smp_flush_tlb_range(mm_cpumask(vma->vm_mm), uaddr, uaddr + PAGE_SIZE);
}
void flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
const struct cpumask *cmask = vma ? mm_cpumask(vma->vm_mm)
: cpu_online_mask;
smp_flush_tlb_range(cmask, start, end);
}
/* Instruction cache invalidate - performed on each cpu */
static void ipi_icache_page_inv(void *arg)
{
struct page *page = arg;
local_icache_page_inv(page);
}
void smp_icache_page_inv(struct page *page)
{
on_each_cpu(ipi_icache_page_inv, page, 1);
}
EXPORT_SYMBOL(smp_icache_page_inv);
static void ipi_icache_all_inv(void *arg)
{
local_icache_all_inv();
}
void smp_icache_all_inv(void)
{
if (num_online_cpus() < 2) {
local_icache_all_inv();
return;
}
/*
* Ensure stores complete before we request remote icaches
* to invalidate.
*/
mb();
on_each_cpu(ipi_icache_all_inv, NULL, 1);
}
@@ -0,0 +1,100 @@
/*
* Stack trace utility for OpenRISC
*
* Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*
* Losely based on work from sh and powerpc.
*/
#include <linux/export.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/sched/task_stack.h>
#include <linux/stacktrace.h>
#include <asm/processor.h>
#include <asm/unwinder.h>
/*
* Save stack-backtrace addresses into a stack_trace buffer.
*/
static void
save_stack_address(void *data, unsigned long addr, int reliable)
{
struct stack_trace *trace = data;
if (!reliable)
return;
if (trace->skip > 0) {
trace->skip--;
return;
}
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = addr;
}
void save_stack_trace(struct stack_trace *trace)
{
unwind_stack(trace, (unsigned long *) &trace, save_stack_address);
}
EXPORT_SYMBOL_GPL(save_stack_trace);
static void
save_stack_address_nosched(void *data, unsigned long addr, int reliable)
{
struct stack_trace *trace = (struct stack_trace *)data;
if (!reliable)
return;
if (in_sched_functions(addr))
return;
if (trace->skip > 0) {
trace->skip--;
return;
}
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = addr;
}
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
unsigned long *sp = NULL;
if (!try_get_task_stack(tsk))
return;
if (tsk == current)
sp = (unsigned long *) &sp;
else {
unsigned long ksp;
/* Locate stack from kernel context */
ksp = task_thread_info(tsk)->ksp;
ksp += STACK_FRAME_OVERHEAD; /* redzone */
ksp += sizeof(struct pt_regs);
sp = (unsigned long *) ksp;
}
unwind_stack(trace, sp, save_stack_address_nosched);
put_task_stack(tsk);
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
void
save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
{
unwind_stack(trace, (unsigned long *) regs->sp,
save_stack_address_nosched);
}
EXPORT_SYMBOL_GPL(save_stack_trace_regs);
@@ -0,0 +1,120 @@
/*
* OR1K timer synchronisation
*
* Based on work from MIPS implementation.
*
* All CPUs will have their count registers synchronised to the CPU0 next time
* value. This can cause a small timewarp for CPU0. All other CPU's should
* not have done anything significant (but they may have had interrupts
* enabled briefly - prom_smp_finish() should not be responsible for enabling
* interrupts...)
*/
#include <linux/kernel.h>
#include <linux/irqflags.h>
#include <linux/cpumask.h>
#include <asm/time.h>
#include <asm/timex.h>
#include <linux/atomic.h>
#include <asm/barrier.h>
#include <asm/spr.h>
static unsigned int initcount;
static atomic_t count_count_start = ATOMIC_INIT(0);
static atomic_t count_count_stop = ATOMIC_INIT(0);
#define COUNTON 100
#define NR_LOOPS 3
void synchronise_count_master(int cpu)
{
int i;
unsigned long flags;
pr_info("Synchronize counters for CPU %u: ", cpu);
local_irq_save(flags);
/*
* We loop a few times to get a primed instruction cache,
* then the last pass is more or less synchronised and
* the master and slaves each set their cycle counters to a known
* value all at once. This reduces the chance of having random offsets
* between the processors, and guarantees that the maximum
* delay between the cycle counters is never bigger than
* the latency of information-passing (cachelines) between
* two CPUs.
*/
for (i = 0; i < NR_LOOPS; i++) {
/* slaves loop on '!= 2' */
while (atomic_read(&count_count_start) != 1)
mb();
atomic_set(&count_count_stop, 0);
smp_wmb();
/* Let the slave writes its count register */
atomic_inc(&count_count_start);
/* Count will be initialised to current timer */
if (i == 1)
initcount = get_cycles();
/*
* Everyone initialises count in the last loop:
*/
if (i == NR_LOOPS-1)
openrisc_timer_set(initcount);
/*
* Wait for slave to leave the synchronization point:
*/
while (atomic_read(&count_count_stop) != 1)
mb();
atomic_set(&count_count_start, 0);
smp_wmb();
atomic_inc(&count_count_stop);
}
/* Arrange for an interrupt in a short while */
openrisc_timer_set_next(COUNTON);
local_irq_restore(flags);
/*
* i386 code reported the skew here, but the
* count registers were almost certainly out of sync
* so no point in alarming people
*/
pr_cont("done.\n");
}
void synchronise_count_slave(int cpu)
{
int i;
/*
* Not every cpu is online at the time this gets called,
* so we first wait for the master to say everyone is ready
*/
for (i = 0; i < NR_LOOPS; i++) {
atomic_inc(&count_count_start);
while (atomic_read(&count_count_start) != 2)
mb();
/*
* Everyone initialises count in the last loop:
*/
if (i == NR_LOOPS-1)
openrisc_timer_set(initcount);
atomic_inc(&count_count_stop);
while (atomic_read(&count_count_stop) != 2)
mb();
}
/* Arrange for an interrupt in a short while */
openrisc_timer_set_next(COUNTON);
}
#undef NR_LOOPS
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* OpenRISC sys_call_table.c
*
* Linux architectural port borrowing liberally from similar works of
* others. All original copyrights apply as per the original source
* declaration.
*
* Modifications for the OpenRISC architecture:
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
*/
#include <linux/syscalls.h>
#include <linux/signal.h>
#include <linux/unistd.h>
#include <asm/syscalls.h>
#define __SYSCALL(nr, call) [nr] = (call),
#define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, native)
#define sys_mmap2 sys_mmap_pgoff
#define sys_clone __sys_clone
#define sys_clone3 __sys_clone3
#define sys_fork __sys_fork
void *sys_call_table[__NR_syscalls] = {
#include <asm/syscall_table_32.h>
};

Some files were not shown because too many files have changed in this diff Show More