summaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2017-03-04 03:03:02 +0100
committerWaldemar Brodkorb <wbx@openadk.org>2017-03-04 03:03:02 +0100
commit9c7797245138ee0e411f2bae618e05a375e1f06f (patch)
tree45d47b510cd0417db2c13424102cdda416dc3cb1 /target
parentf139fafceb3d6f6fc9211146b2bdea4af4508dac (diff)
riscv: add experimental linux/glibc support
Diffstat (limited to 'target')
-rw-r--r--target/config/Config.in.cpu2
-rw-r--r--target/config/Config.in.kernelversion15
-rw-r--r--target/config/Config.in.libc9
-rw-r--r--target/linux/patches/4.6.2/riscv-04032017.patch9424
4 files changed, 9448 insertions, 2 deletions
diff --git a/target/config/Config.in.cpu b/target/config/Config.in.cpu
index d7132e1ef..962942528 100644
--- a/target/config/Config.in.cpu
+++ b/target/config/Config.in.cpu
@@ -1012,6 +1012,8 @@ config ADK_TARGET_CPU_PPC64_POWER8
# riscv
config ADK_TARGET_CPU_RISCV
bool "riscv"
+ select ADK_TARGET_SUPPORTS_THREADS
+ select ADK_TARGET_SUPPORTS_NPTL
select ADK_TARGET_WITH_MMU
depends on ADK_TARGET_ARCH_RISCV
diff --git a/target/config/Config.in.kernelversion b/target/config/Config.in.kernelversion
index 7a6ac8fab..b2353f839 100644
--- a/target/config/Config.in.kernelversion
+++ b/target/config/Config.in.kernelversion
@@ -12,12 +12,14 @@ default ADK_TARGET_KERNEL_VERSION_GIT if ADK_TARGET_SYSTEM_KINETIS_K70
default ADK_TARGET_KERNEL_VERSION_GIT if ADK_TARGET_ARCH_LM32
default ADK_TARGET_KERNEL_VERSION_4_4 if ADK_TARGET_ARCH_CRIS
default ADK_TARGET_KERNEL_VERSION_4_4 if ADK_TARGET_ARCH_METAG
+default ADK_TARGET_KERNEL_VERSION_4_6 if ADK_TARGET_ARCH_RISCV
default ADK_TARGET_KERNEL_VERSION_4_4 if ADK_TARGET_SYSTEM_QEMU_ARM_VERSATILEPB_NOMMU
default ADK_TARGET_KERNEL_VERSION_4_9
config ADK_TARGET_KERNEL_VERSION_GIT
bool "git"
depends on !ADK_TARGET_ARCH_NDS32
+ depends on !ADK_TARGET_ARCH_RISCV
select ADK_HOST_NEED_LZOP if ADK_TARGET_SYSTEM_SOLIDRUN_IMX6
select ADK_HOST_NEED_LZOP if ADK_TARGET_SYSTEM_BEAGLEBONE_BLACK
select ADK_TARGET_KERNEL_IMAGE if ADK_TARGET_SYSTEM_SOLIDRUN_IMX6
@@ -28,13 +30,19 @@ config ADK_TARGET_KERNEL_VERSION_4_9
depends on !ADK_TARGET_ARCH_CRIS
depends on !ADK_TARGET_ARCH_METAG
depends on !ADK_TARGET_ARCH_NDS32
+ depends on !ADK_TARGET_ARCH_RISCV
depends on !ADK_TARGET_SYSTEM_QEMU_ARM_VERSATILEPB_NOMMU
+config ADK_TARGET_KERNEL_VERSION_4_6
+ bool "4.6.2"
+ depends on ADK_TARGET_ARCH_RISCV
+
config ADK_TARGET_KERNEL_VERSION_4_4
bool "4.4.50"
depends on !ADK_TARGET_ARCH_NDS32
depends on !ADK_TARGET_ARCH_NIOS2
depends on !ADK_TARGET_ARCH_OR1K
+ depends on !ADK_TARGET_ARCH_RISCV
depends on !ADK_TARGET_CPU_MIPS_MIPS32R6
depends on !ADK_TARGET_CPU_MIPS64_MIPS64R6
depends on !ADK_TARGET_SYSTEM_NUMATO_MIMASV2
@@ -48,6 +56,7 @@ config ADK_TARGET_KERNEL_VERSION_4_1
depends on !ADK_TARGET_ARCH_NDS32
depends on !ADK_TARGET_ARCH_OR1K
depends on !ADK_TARGET_ARCH_SPARC
+ depends on !ADK_TARGET_ARCH_RISCV
depends on !ADK_TARGET_SYSTEM_KINETIS_K70
depends on !ADK_TARGET_SYSTEM_QEMU_M68K_MCF5208
depends on !ADK_TARGET_SYSTEM_QEMU_ARM_VERSATILEPB_NOMMU
@@ -62,6 +71,7 @@ config ADK_TARGET_KERNEL_VERSION_3_18
depends on !ADK_TARGET_ARCH_NDS32
depends on !ADK_TARGET_ARCH_NIOS2
depends on !ADK_TARGET_ARCH_OR1K
+ depends on !ADK_TARGET_ARCH_RISCV
depends on !ADK_TARGET_ARCH_SPARC
depends on !ADK_TARGET_BOARD_ATH79
depends on !ADK_TARGET_BOARD_BCM28XX
@@ -82,6 +92,7 @@ config ADK_TARGET_KERNEL_VERSION_3_12
depends on !ADK_TARGET_ARCH_NDS32
depends on !ADK_TARGET_ARCH_NIOS2
depends on !ADK_TARGET_ARCH_OR1K
+ depends on !ADK_TARGET_ARCH_RISCV
depends on !ADK_TARGET_ARCH_SPARC
depends on !ADK_TARGET_BOARD_ATH79
depends on !ADK_TARGET_BOARD_BCM28XX
@@ -101,6 +112,7 @@ config ADK_TARGET_KERNEL_VERSION_3_10
depends on !ADK_TARGET_ARCH_NDS32
depends on !ADK_TARGET_ARCH_NIOS2
depends on !ADK_TARGET_ARCH_OR1K
+ depends on !ADK_TARGET_ARCH_RISCV
depends on !ADK_TARGET_ARCH_SPARC
depends on !ADK_TARGET_BOARD_ATH79
depends on !ADK_TARGET_BOARD_BCM28XX
@@ -122,6 +134,7 @@ config ADK_TARGET_KERNEL_VERSION_3_4
depends on !ADK_TARGET_ARCH_NDS32
depends on !ADK_TARGET_ARCH_NIOS2
depends on !ADK_TARGET_ARCH_OR1K
+ depends on !ADK_TARGET_ARCH_RISCV
depends on !ADK_TARGET_ARCH_SPARC
depends on !ADK_TARGET_BOARD_ATH79
depends on !ADK_TARGET_BOARD_BCM28XX
@@ -146,6 +159,7 @@ config ADK_TARGET_KERNEL_VERSION_3_2
depends on !ADK_TARGET_ARCH_NDS32
depends on !ADK_TARGET_ARCH_NIOS2
depends on !ADK_TARGET_ARCH_OR1K
+ depends on !ADK_TARGET_ARCH_RISCV
depends on !ADK_TARGET_ARCH_SPARC
depends on !ADK_TARGET_BOARD_ATH79
depends on !ADK_TARGET_BOARD_BCM28XX
@@ -166,6 +180,7 @@ config ADK_TARGET_KERNEL_VERSION_2_6_32
depends on !ADK_TARGET_ARCH_NDS32
depends on !ADK_TARGET_ARCH_NIOS2
depends on !ADK_TARGET_ARCH_OR1K
+ depends on !ADK_TARGET_ARCH_RISCV
depends on !ADK_TARGET_ARCH_SPARC
depends on !ADK_TARGET_BOARD_ATH79
depends on !ADK_TARGET_BOARD_BCM28XX
diff --git a/target/config/Config.in.libc b/target/config/Config.in.libc
index 83439d76b..7157c214c 100644
--- a/target/config/Config.in.libc
+++ b/target/config/Config.in.libc
@@ -79,6 +79,7 @@ config ADK_TARGET_LIB_GLIBC
ADK_TARGET_CPU_SH_SH4A || \
ADK_TARGET_ARCH_SPARC64 || \
ADK_TARGET_ARCH_TILE || \
+ ADK_TARGET_ARCH_RISCV || \
ADK_TARGET_ARCH_X86 || \
ADK_TARGET_ARCH_X86_64) && ADK_TARGET_OS_LINUX
help
@@ -137,11 +138,15 @@ config ADK_TARGET_LIB_UCLIBC_NG_GIT
config ADK_TARGET_LIB_GLIBC_2_25
bool "2.25"
- depends on ADK_TARGET_LIB_GLIBC
+ depends on ADK_TARGET_LIB_GLIBC && !ADK_TARGET_ARCH_RISCV
+
+config ADK_TARGET_LIB_GLIBC_RISCV
+ bool "riscv"
+ depends on ADK_TARGET_LIB_GLIBC && ADK_TARGET_ARCH_RISCV
config ADK_TARGET_LIB_GLIBC_GIT
bool "git"
- depends on ADK_TARGET_LIB_GLIBC
+ depends on ADK_TARGET_LIB_GLIBC && !ADK_TARGET_ARCH_RISCV
config ADK_TARGET_LIB_MUSL_1_1_16
bool "1.1.16"
diff --git a/target/linux/patches/4.6.2/riscv-04032017.patch b/target/linux/patches/4.6.2/riscv-04032017.patch
new file mode 100644
index 000000000..019ee3173
--- /dev/null
+++ b/target/linux/patches/4.6.2/riscv-04032017.patch
@@ -0,0 +1,9424 @@
+diff -Nur linux-4.6.2/arch/.gitignore linux-4.6.2.riscv/arch/.gitignore
+--- linux-4.6.2/arch/.gitignore 2016-06-08 03:23:53.000000000 +0200
++++ linux-4.6.2.riscv/arch/.gitignore 2017-03-04 02:48:34.162887952 +0100
+@@ -1,2 +1,3 @@
+-i386
+-x86_64
++# In ../, we ignored everything, so suppress that.
++!riscv/
++
+diff -Nur linux-4.6.2/arch/riscv/configs/riscv64_qemu linux-4.6.2.riscv/arch/riscv/configs/riscv64_qemu
+--- linux-4.6.2/arch/riscv/configs/riscv64_qemu 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/configs/riscv64_qemu 2017-03-04 02:48:34.162887952 +0100
+@@ -0,0 +1,64 @@
++# CONFIG_COMPACTION is not set
++# CONFIG_CROSS_MEMORY_ATTACH is not set
++CONFIG_HZ_100=y
++CONFIG_CROSS_COMPILE="riscv64-unknown-linux-gnu-"
++CONFIG_DEFAULT_HOSTNAME="ucbvax"
++CONFIG_NAMESPACES=y
++CONFIG_EMBEDDED=y
++# CONFIG_BLK_DEV_BSG is not set
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_IOSCHED_DEADLINE is not set
++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_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_WIRELESS is not set
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++# CONFIG_BLK_DEV is not set
++CONFIG_SCSI=y
++CONFIG_BLK_DEV_SD=y
++CONFIG_SCSI_VIRTIO=y
++CONFIG_NETDEVICES=y
++CONFIG_VIRTIO_NET=y
++# CONFIG_ETHERNET is not set
++# CONFIG_WLAN is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_VT is not set
++CONFIG_SERIAL_8250=y
++# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=1
++CONFIG_SERIAL_8250_RUNTIME_UARTS=1
++CONFIG_VIRTIO_CONSOLE=y
++# CONFIG_HW_RANDOM is not set
++# CONFIG_HWMON is not set
++CONFIG_FB=y
++# CONFIG_USB_SUPPORT is not set
++CONFIG_VIRTIO_MMIO=y
++CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
++# CONFIG_IOMMU_SUPPORT is not set
++CONFIG_EXT4_FS=y
++# CONFIG_FILE_LOCKING is not set
++# CONFIG_DNOTIFY is not set
++# CONFIG_INOTIFY_USER is not set
++# CONFIG_PROC_PAGE_MONITOR is not set
++CONFIG_TMPFS=y
++# CONFIG_MISC_FILESYSTEMS is not set
++# CONFIG_NETWORK_FILESYSTEMS is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="virtio_mmio.device=0x200@0x400:1 virtio_mmio.device=0x200@0x600:2 virtio_mmio.device=0x200@0x800:3 lpj=100000"
++CONFIG_CMDLINE_OVERRIDE=y
++CONFIG_PRINTK_TIME=y
++CONFIG_DEBUG_SECTION_MISMATCH=y
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_HW is not set
+diff -Nur linux-4.6.2/arch/riscv/configs/riscv64_spike linux-4.6.2.riscv/arch/riscv/configs/riscv64_spike
+--- linux-4.6.2/arch/riscv/configs/riscv64_spike 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/configs/riscv64_spike 2017-03-04 02:48:34.162887952 +0100
+@@ -0,0 +1,929 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/riscv 3.14.29 Kernel Configuration
++#
++CONFIG_RISCV=y
++CONFIG_MMU=y
++CONFIG_PCI=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_BUG=y
++CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_CSUM=y
++CONFIG_GENERIC_HWEIGHT=y
++
++#
++# Platform type
++#
++CONFIG_CPU_RV_ROCKET=y
++# CONFIG_CPU_RV_GENERIC is not set
++CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
++CONFIG_RV_ATOMIC=y
++# CONFIG_RV_SYSRISCV_ATOMIC is not set
++CONFIG_SBI_CONSOLE=y
++
++#
++# Kernel type
++#
++CONFIG_64BIT=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++CONFIG_PHYS_ADDR_T_64BIT=y
++CONFIG_ZONE_DMA_FLAG=0
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CROSS_MEMORY_ATTACH is not set
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++# CONFIG_CMA is not set
++# CONFIG_ZBUD is not set
++# CONFIG_ZSMALLOC is not set
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ_100=y
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++# CONFIG_SCHED_HRTICK is not set
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="riscv64-unknown-linux-gnu-"
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_DEFAULT_HOSTNAME="ucbvax"
++CONFIG_SWAP=y
++# CONFIG_SYSVIPC is not set
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_FHANDLE is not set
++# CONFIG_AUDIT is not set
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++
++#
++# Timers subsystem
++#
++CONFIG_HZ_PERIODIC=y
++# CONFIG_NO_HZ_IDLE is not set
++# CONFIG_NO_HZ is not set
++# CONFIG_HIGH_RES_TIMERS is not set
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_RCU_STALL_COMMON is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++# CONFIG_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_SYSCTL_EXCEPTION_TRACE=y
++CONFIG_EXPERT=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_64BIT_ALIGNED_ACCESS=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_CLONE_BACKWARDS=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++# CONFIG_MODULES is not set
++CONFIG_BLOCK=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++# CONFIG_BLK_CMDLINE_PARSER is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++# CONFIG_SYSV68_PARTITION is not set
++# CONFIG_CMDLINE_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++# CONFIG_IOSCHED_DEADLINE is not set
++CONFIG_IOSCHED_CFQ=y
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
++CONFIG_INLINE_READ_UNLOCK=y
++CONFIG_INLINE_READ_UNLOCK_IRQ=y
++CONFIG_INLINE_WRITE_UNLOCK=y
++CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
++# CONFIG_FREEZER is not set
++
++#
++# Executable file formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++# CONFIG_XFRM_USER is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_NET_IP_TUNNEL is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++# 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_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++# CONFIG_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_NET_MPLS_GSO is not set
++# CONFIG_HSR is not set
++CONFIG_NET_RX_BUSY_POLL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++# CONFIG_WIRELESS is not set
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_EXTRA_FIRMWARE=""
++CONFIG_FW_LOADER_USER_HELPER=y
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++CONFIG_GENERIC_CPU_DEVICES=y
++# CONFIG_DMA_SHARED_BUFFER is not set
++
++#
++# Bus devices
++#
++# CONFIG_CONNECTOR is not set
++# CONFIG_MTD is not set
++# CONFIG_PARPORT is not set
++# CONFIG_BLK_DEV is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_DUMMY_IRQ is not set
++# CONFIG_ATMEL_SSC is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_93CX6 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++
++#
++# Altera FPGA firmware download module
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_DMA is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_NETDEVICES is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=256
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_SCCNXP is not set
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_RTC is not set
++# CONFIG_GEN_RTC is not set
++# CONFIG_R3964 is not set
++
++#
++# PCMCIA character devices
++#
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_I2C is not set
++# CONFIG_SPI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++# CONFIG_PTP_1588_CLOCK is not set
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_SYSCON is not set
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++# CONFIG_FB_TILEBLITTING is not set
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_EXYNOS_VIDEO is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_AUREAL 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_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO_TPKBD is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MAGICMOUSE is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TIVO is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SUPPORT is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_RTC_CLASS is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++# CONFIG_MAILBOX is not set
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers
++#
++
++#
++# Rpmsg drivers
++#
++# CONFIG_PM_DEVFREQ is not set
++# CONFIG_EXTCON is not set
++# CONFIG_MEMORY is not set
++# CONFIG_IIO is not set
++# CONFIG_PWM is not set
++# CONFIG_IPACK_BUS is not set
++# CONFIG_RESET_CONTROLLER is not set
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++# CONFIG_GENERIC_PHY is not set
++# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set
++# CONFIG_POWERCAP is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XIP is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_FILE_LOCKING is not set
++# CONFIG_FSNOTIFY is not set
++# CONFIG_DNOTIFY is not set
++# CONFIG_INOTIFY_USER is not set
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++# CONFIG_MSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++# CONFIG_PROC_KCORE is not set
++CONFIG_PROC_SYSCTL=y
++# CONFIG_PROC_PAGE_MONITOR is not set
++# CONFIG_SYSFS is not set
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++# CONFIG_MISC_FILESYSTEMS is not set
++# CONFIG_NETWORK_FILESYSTEMS is not set
++# CONFIG_NLS is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_CMDLINE_BOOL is not set
++# CONFIG_EARLY_PRINTK is not set
++
++#
++# printk and dmesg options
++#
++CONFIG_PRINTK_TIME=y
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++
++#
++# Compile-time checks and compiler options
++#
++# CONFIG_DEBUG_INFO is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=2048
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_ARCH_WANT_FRAME_POINTERS=y
++# CONFIG_FRAME_POINTER is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_MAGIC_SYSRQ is not set
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_DEBUG_PAGEALLOC is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_TIMER_STATS is not set
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++
++#
++# RCU Debugging
++#
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++
++#
++# Runtime Testing
++#
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_SAMPLES is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++# CONFIG_CRYPTO_MANAGER is not set
++# CONFIG_CRYPTO_MANAGER2 is not set
++# CONFIG_CRYPTO_USER is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++# CONFIG_CRYPTO_ECB is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_CMAC is not set
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRCT10DIF is not set
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=y
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++# CONFIG_CRYPTO_HW is not set
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_IO=y
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC32_SELFTEST is not set
++CONFIG_CRC32_SLICEBY8=y
++# CONFIG_CRC32_SLICEBY4 is not set
++# CONFIG_CRC32_SARWATE is not set
++# CONFIG_CRC32_BIT is not set
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++# CONFIG_RANDOM32_SELFTEST is not set
++# CONFIG_XZ_DEC is not set
++# CONFIG_XZ_DEC_BCJ is not set
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
+diff -Nur linux-4.6.2/arch/riscv/.gitignore linux-4.6.2.riscv/arch/riscv/.gitignore
+--- linux-4.6.2/arch/riscv/.gitignore 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/.gitignore 2017-03-04 02:48:34.162887952 +0100
+@@ -0,0 +1,35 @@
++# Now un-ignore all files.
++!*
++
++# But then re-ignore the files listed in the Linux .gitignore
++# Normal rules
++#
++.*
++*.o
++*.o.*
++*.a
++*.s
++*.ko
++*.so
++*.so.dbg
++*.mod.c
++*.i
++*.lst
++*.symtypes
++*.order
++modules.builtin
++*.elf
++*.bin
++*.gz
++*.bz2
++*.lzma
++*.xz
++*.lzo
++*.patch
++*.gcno
++
++include/generated
++kernel/vmlinux.lds
++
++# Then reinclude .gitignore.
++!.gitignore
+diff -Nur linux-4.6.2/arch/riscv/include/asm/asm.h linux-4.6.2.riscv/arch/riscv/include/asm/asm.h
+--- linux-4.6.2/arch/riscv/include/asm/asm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/asm.h 2017-03-04 02:48:34.162887952 +0100
+@@ -0,0 +1,51 @@
++#ifndef _ASM_RISCV_ASM_H
++#define _ASM_RISCV_ASM_H
++
++#ifdef __ASSEMBLY__
++#define __ASM_STR(x) x
++#else
++#define __ASM_STR(x) #x
++#endif
++
++#if __riscv_xlen == 64
++#define __REG_SEL(a,b) __ASM_STR(a)
++#elif __riscv_xlen == 32
++#define __REG_SEL(a,b) __ASM_STR(b)
++#else
++#error "Unexpected __riscv_xlen"
++#endif
++
++#define REG_L __REG_SEL(ld, lw)
++#define REG_S __REG_SEL(sd, sw)
++#define SZREG __REG_SEL(8, 4)
++#define LGREG __REG_SEL(3, 2)
++
++#if __SIZEOF_POINTER__ == 8
++#define __PTR_SEL(a,b) __ASM_STR(a)
++#elif __SIZEOF_POINTER__ == 4
++#define __PTR_SEL(a,b) __ASM_STR(b)
++#else
++#error "Unexpected __SIZEOF_POINTER__"
++#endif
++
++#define PTR __PTR_SEL(.dword, .word)
++#define SZPTR __PTR_SEL(8, 4)
++#define LGPTR __PTR_SEL(3, 2)
++
++#if (__SIZEOF_INT__ == 4)
++#define INT __ASM_STR(.word)
++#define SZINT __ASM_STR(4)
++#define LGINT __ASM_STR(2)
++#else
++#error "Unexpected __SIZEOF_INT__"
++#endif
++
++#if (__SIZEOF_SHORT__ == 2)
++#define SHORT __ASM_STR(.half)
++#define SZSHORT __ASM_STR(2)
++#define LGSHORT __ASM_STR(1)
++#else
++#error "Unexpected __SIZEOF_SHORT__"
++#endif
++
++#endif /* _ASM_RISCV_ASM_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/asm-offsets.h linux-4.6.2.riscv/arch/riscv/include/asm/asm-offsets.h
+--- linux-4.6.2/arch/riscv/include/asm/asm-offsets.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/asm-offsets.h 2017-03-04 02:48:34.162887952 +0100
+@@ -0,0 +1 @@
++#include <generated/asm-offsets.h>
+diff -Nur linux-4.6.2/arch/riscv/include/asm/atomic64.h linux-4.6.2.riscv/arch/riscv/include/asm/atomic64.h
+--- linux-4.6.2/arch/riscv/include/asm/atomic64.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/atomic64.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,287 @@
++#ifndef _ASM_RISCV_ATOMIC64_H
++#define _ASM_RISCV_ATOMIC64_H
++
++#ifdef CONFIG_GENERIC_ATOMIC64
++#include <asm-generic/atomic64.h>
++#else /* !CONFIG_GENERIC_ATOMIC64 */
++
++#include <linux/types.h>
++
++#define ATOMIC64_INIT(i) { (i) }
++
++/**
++ * atomic64_read - read atomic64 variable
++ * @v: pointer of type atomic64_t
++ *
++ * Atomically reads the value of @v.
++ */
++static inline s64 atomic64_read(const atomic64_t *v)
++{
++ return *((volatile long *)(&(v->counter)));
++}
++
++/**
++ * atomic64_set - set atomic64 variable
++ * @v: pointer to type atomic64_t
++ * @i: required value
++ *
++ * Atomically sets the value of @v to @i.
++ */
++static inline void atomic64_set(atomic64_t *v, s64 i)
++{
++ v->counter = i;
++}
++
++/**
++ * atomic64_add - add integer to atomic64 variable
++ * @i: integer value to add
++ * @v: pointer to type atomic64_t
++ *
++ * Atomically adds @i to @v.
++ */
++static inline void atomic64_add(s64 a, atomic64_t *v)
++{
++ __asm__ __volatile__ (
++ "amoadd.d zero, %1, %0"
++ : "+A" (v->counter)
++ : "r" (a));
++}
++
++/**
++ * atomic64_sub - subtract the atomic64 variable
++ * @i: integer value to subtract
++ * @v: pointer to type atomic64_t
++ *
++ * Atomically subtracts @i from @v.
++ */
++static inline void atomic64_sub(s64 a, atomic64_t *v)
++{
++ atomic64_add(-a, v);
++}
++
++/**
++ * atomic64_add_return - add and return
++ * @i: integer value to add
++ * @v: pointer to type atomic64_t
++ *
++ * Atomically adds @i to @v and returns @i + @v
++ */
++static inline s64 atomic64_add_return(s64 a, atomic64_t *v)
++{
++ register s64 c;
++ __asm__ __volatile__ (
++ "amoadd.d %0, %2, %1"
++ : "=r" (c), "+A" (v->counter)
++ : "r" (a));
++ return (c + a);
++}
++
++static inline s64 atomic64_sub_return(s64 a, atomic64_t *v)
++{
++ return atomic64_add_return(-a, v);
++}
++
++/**
++ * atomic64_inc - increment atomic64 variable
++ * @v: pointer to type atomic64_t
++ *
++ * Atomically increments @v by 1.
++ */
++static inline void atomic64_inc(atomic64_t *v)
++{
++ atomic64_add(1L, v);
++}
++
++/**
++ * atomic64_dec - decrement atomic64 variable
++ * @v: pointer to type atomic64_t
++ *
++ * Atomically decrements @v by 1.
++ */
++static inline void atomic64_dec(atomic64_t *v)
++{
++ atomic64_add(-1L, v);
++}
++
++static inline s64 atomic64_inc_return(atomic64_t *v)
++{
++ return atomic64_add_return(1L, v);
++}
++
++static inline s64 atomic64_dec_return(atomic64_t *v)
++{
++ return atomic64_add_return(-1L, v);
++}
++
++/**
++ * atomic64_inc_and_test - increment and test
++ * @v: pointer to type atomic64_t
++ *
++ * Atomically increments @v by 1
++ * and returns true if the result is zero, or false for all
++ * other cases.
++ */
++static inline int atomic64_inc_and_test(atomic64_t *v)
++{
++ return (atomic64_inc_return(v) == 0);
++}
++
++/**
++ * atomic64_dec_and_test - decrement and test
++ * @v: pointer to type atomic64_t
++ *
++ * Atomically decrements @v by 1 and
++ * returns true if the result is 0, or false for all other
++ * cases.
++ */
++static inline int atomic64_dec_and_test(atomic64_t *v)
++{
++ return (atomic64_dec_return(v) == 0);
++}
++
++/**
++ * atomic64_sub_and_test - subtract value from variable and test result
++ * @a: integer value to subtract
++ * @v: pointer to type atomic64_t
++ *
++ * Atomically subtracts @a from @v and returns
++ * true if the result is zero, or false for all
++ * other cases.
++ */
++static inline int atomic64_sub_and_test(s64 a, atomic64_t *v)
++{
++ return (atomic64_sub_return(a, v) == 0);
++}
++
++/**
++ * atomic64_add_negative - add and test if negative
++ * @a: integer value to add
++ * @v: pointer to type atomic64_t
++ *
++ * Atomically adds @a to @v and returns true
++ * if the result is negative, or false when
++ * result is greater than or equal to zero.
++ */
++static inline int atomic64_add_negative(s64 a, atomic64_t *v)
++{
++ return (atomic64_add_return(a, v) < 0);
++}
++
++
++static inline s64 atomic64_xchg(atomic64_t *v, s64 n)
++{
++ register s64 c;
++ __asm__ __volatile__ (
++ "amoswap.d %0, %2, %1"
++ : "=r" (c), "+A" (v->counter)
++ : "r" (n));
++ return c;
++}
++
++static inline s64 atomic64_cmpxchg(atomic64_t *v, s64 o, s64 n)
++{
++ return cmpxchg(&(v->counter), o, n);
++}
++
++/*
++ * atomic64_dec_if_positive - decrement by 1 if old value positive
++ * @v: pointer of type atomic_t
++ *
++ * The function returns the old value of *v minus 1, even if
++ * the atomic variable, v, was not decremented.
++ */
++static inline s64 atomic64_dec_if_positive(atomic64_t *v)
++{
++ register s64 prev, rc;
++ __asm__ __volatile__ (
++ "0:"
++ "lr.d %0, %2\n"
++ "add %0, %0, -1\n"
++ "bltz %0, 1f\n"
++ "sc.w %1, %0, %2\n"
++ "bnez %1, 0b\n"
++ "1:"
++ : "=&r" (prev), "=r" (rc), "+A" (v->counter));
++ return prev;
++}
++
++/**
++ * atomic64_add_unless - add unless the number is a given value
++ * @v: pointer of type atomic64_t
++ * @a: the amount to add to v...
++ * @u: ...unless v is equal to u.
++ *
++ * Atomically adds @a to @v, so long as it was not @u.
++ * Returns true if the addition occurred and false otherwise.
++ */
++static inline int atomic64_add_unless(atomic64_t *v, s64 a, s64 u)
++{
++ register s64 tmp;
++ register int rc = 1;
++
++ __asm__ __volatile__ (
++ "0:"
++ "lr.d %0, %2\n"
++ "beq %0, %z4, 1f\n"
++ "add %0, %0, %3\n"
++ "sc.d %1, %0, %2\n"
++ "bnez %1, 0b\n"
++ "1:"
++ : "=&r" (tmp), "=&r" (rc), "+A" (v->counter)
++ : "rI" (a), "rJ" (u));
++ return !rc;
++}
++
++static inline int atomic64_inc_not_zero(atomic64_t *v)
++{
++ return atomic64_add_unless(v, 1, 0);
++}
++
++/**
++ * atomic64_and - Atomically clear bits in atomic variable
++ * @mask: Mask of the bits to be retained
++ * @v: pointer of type atomic_t
++ *
++ * Atomically retains the bits set in @mask from @v
++ */
++static inline void atomic64_and(s64 mask, atomic64_t *v)
++{
++ __asm__ __volatile__ (
++ "amoand.d zero, %1, %0"
++ : "+A" (v->counter)
++ : "r" (mask));
++}
++
++/**
++ * atomic64_or - Atomically set bits in atomic variable
++ * @mask: Mask of the bits to be set
++ * @v: pointer of type atomic_t
++ *
++ * Atomically sets the bits set in @mask in @v
++ */
++static inline void atomic64_or(s64 mask, atomic64_t *v)
++{
++ __asm__ __volatile__ (
++ "amoor.d zero, %1, %0"
++ : "+A" (v->counter)
++ : "r" (mask));
++}
++
++/**
++ * atomic64_xor - Atomically flips bits in atomic variable
++ * @mask: Mask of the bits to be flipped
++ * @v: pointer of type atomic_t
++ *
++ * Atomically flips the bits set in @mask in @v
++ */
++static inline void atomic64_xor(s64 mask, atomic64_t *v)
++{
++ __asm__ __volatile__ (
++ "amoxor.d zero, %1, %0"
++ : "+A" (v->counter)
++ : "r" (mask));
++}
++
++#endif /* CONFIG_GENERIC_ATOMIC64 */
++
++#endif /* _ASM_RISCV_ATOMIC64_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/atomic.h linux-4.6.2.riscv/arch/riscv/include/asm/atomic.h
+--- linux-4.6.2/arch/riscv/include/asm/atomic.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/atomic.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,276 @@
++#ifndef _ASM_RISCV_ATOMIC_H
++#define _ASM_RISCV_ATOMIC_H
++
++#ifdef CONFIG_RV_ATOMIC
++
++#include <asm/cmpxchg.h>
++#include <asm/barrier.h>
++
++#define ATOMIC_INIT(i) { (i) }
++
++/**
++ * atomic_read - read atomic variable
++ * @v: pointer of type atomic_t
++ *
++ * Atomically reads the value of @v.
++ */
++static inline int atomic_read(const atomic_t *v)
++{
++ return *((volatile int *)(&(v->counter)));
++}
++
++/**
++ * atomic_set - set atomic variable
++ * @v: pointer of type atomic_t
++ * @i: required value
++ *
++ * Atomically sets the value of @v to @i.
++ */
++static inline void atomic_set(atomic_t *v, int i)
++{
++ v->counter = i;
++}
++
++/**
++ * atomic_add - add integer to atomic variable
++ * @i: integer value to add
++ * @v: pointer of type atomic_t
++ *
++ * Atomically adds @i to @v.
++ */
++static inline void atomic_add(int i, atomic_t *v)
++{
++ __asm__ __volatile__ (
++ "amoadd.w zero, %1, %0"
++ : "+A" (v->counter)
++ : "r" (i));
++}
++
++/**
++ * atomic_sub - subtract integer from atomic variable
++ * @i: integer value to subtract
++ * @v: pointer of type atomic_t
++ *
++ * Atomically subtracts @i from @v.
++ */
++static inline void atomic_sub(int i, atomic_t *v)
++{
++ atomic_add(-i, v);
++}
++
++/**
++ * atomic_add_return - add integer to atomic variable
++ * @i: integer value to add
++ * @v: pointer of type atomic_t
++ *
++ * Atomically adds @i to @v and returns the result
++ */
++static inline int atomic_add_return(int i, atomic_t *v)
++{
++ register int c;
++ __asm__ __volatile__ (
++ "amoadd.w %0, %2, %1"
++ : "=r" (c), "+A" (v->counter)
++ : "r" (i));
++ return (c + i);
++}
++
++/**
++ * atomic_sub_return - subtract integer from atomic variable
++ * @i: integer value to subtract
++ * @v: pointer of type atomic_t
++ *
++ * Atomically subtracts @i from @v and returns the result
++ */
++static inline int atomic_sub_return(int i, atomic_t *v)
++{
++ return atomic_add_return(-i, v);
++}
++
++/**
++ * atomic_inc - increment atomic variable
++ * @v: pointer of type atomic_t
++ *
++ * Atomically increments @v by 1.
++ */
++static inline void atomic_inc(atomic_t *v)
++{
++ atomic_add(1, v);
++}
++
++/**
++ * atomic_dec - decrement atomic variable
++ * @v: pointer of type atomic_t
++ *
++ * Atomically decrements @v by 1.
++ */
++static inline void atomic_dec(atomic_t *v)
++{
++ atomic_add(-1, v);
++}
++
++static inline int atomic_inc_return(atomic_t *v)
++{
++ return atomic_add_return(1, v);
++}
++
++static inline int atomic_dec_return(atomic_t *v)
++{
++ return atomic_sub_return(1, v);
++}
++
++/**
++ * atomic_sub_and_test - subtract value from variable and test result
++ * @i: integer value to subtract
++ * @v: pointer of type atomic_t
++ *
++ * Atomically subtracts @i from @v and returns
++ * true if the result is zero, or false for all
++ * other cases.
++ */
++static inline int atomic_sub_and_test(int i, atomic_t *v)
++{
++ return (atomic_sub_return(i, v) == 0);
++}
++
++/**
++ * atomic_inc_and_test - increment and test
++ * @v: pointer of type atomic_t
++ *
++ * Atomically increments @v by 1
++ * and returns true if the result is zero, or false for all
++ * other cases.
++ */
++static inline int atomic_inc_and_test(atomic_t *v)
++{
++ return (atomic_inc_return(v) == 0);
++}
++
++/**
++ * atomic_dec_and_test - decrement and test
++ * @v: pointer of type atomic_t
++ *
++ * Atomically decrements @v by 1 and
++ * returns true if the result is 0, or false for all other
++ * cases.
++ */
++static inline int atomic_dec_and_test(atomic_t *v)
++{
++ return (atomic_dec_return(v) == 0);
++}
++
++/**
++ * atomic_add_negative - add and test if negative
++ * @i: integer value to add
++ * @v: pointer of type atomic_t
++ *
++ * Atomically adds @i to @v and returns true
++ * if the result is negative, or false when
++ * result is greater than or equal to zero.
++ */
++static inline int atomic_add_negative(int i, atomic_t *v)
++{
++ return (atomic_add_return(i, v) < 0);
++}
++
++
++static inline int atomic_xchg(atomic_t *v, int n)
++{
++ register int c;
++ __asm__ __volatile__ (
++ "amoswap.w %0, %2, %1"
++ : "=r" (c), "+A" (v->counter)
++ : "r" (n));
++ return c;
++}
++
++static inline int atomic_cmpxchg(atomic_t *v, int o, int n)
++{
++ return cmpxchg(&(v->counter), o, n);
++}
++
++/**
++ * __atomic_add_unless - add unless the number is already a given value
++ * @v: pointer of type atomic_t
++ * @a: the amount to add to v...
++ * @u: ...unless v is equal to u.
++ *
++ * Atomically adds @a to @v, so long as @v was not already @u.
++ * Returns the old value of @v.
++ */
++static inline int __atomic_add_unless(atomic_t *v, int a, int u)
++{
++ register int prev, rc;
++ __asm__ __volatile__ (
++ "0:"
++ "lr.w %0, %2\n"
++ "beq %0, %4, 1f\n"
++ "add %1, %0, %3\n"
++ "sc.w %1, %1, %2\n"
++ "bnez %1, 0b\n"
++ "1:"
++ : "=&r" (prev), "=&r" (rc), "+A" (v->counter)
++ : "r" (a), "r" (u));
++ return prev;
++}
++
++/**
++ * atomic_and - Atomically clear bits in atomic variable
++ * @mask: Mask of the bits to be retained
++ * @v: pointer of type atomic_t
++ *
++ * Atomically retains the bits set in @mask from @v
++ */
++static inline void atomic_and(unsigned int mask, atomic_t *v)
++{
++ __asm__ __volatile__ (
++ "amoand.w zero, %1, %0"
++ : "+A" (v->counter)
++ : "r" (mask));
++}
++
++/**
++ * atomic_or - Atomically set bits in atomic variable
++ * @mask: Mask of the bits to be set
++ * @v: pointer of type atomic_t
++ *
++ * Atomically sets the bits set in @mask in @v
++ */
++static inline void atomic_or(unsigned int mask, atomic_t *v)
++{
++ __asm__ __volatile__ (
++ "amoor.w zero, %1, %0"
++ : "+A" (v->counter)
++ : "r" (mask));
++}
++
++/**
++ * atomic_xor - Atomically flips bits in atomic variable
++ * @mask: Mask of the bits to be flipped
++ * @v: pointer of type atomic_t
++ *
++ * Atomically flips the bits set in @mask in @v
++ */
++static inline void atomic_xor(unsigned int mask, atomic_t *v)
++{
++ __asm__ __volatile__ (
++ "amoxor.w zero, %1, %0"
++ : "+A" (v->counter)
++ : "r" (mask));
++}
++
++/* Assume that atomic operations are already serializing */
++#define smp_mb__before_atomic_dec() barrier()
++#define smp_mb__after_atomic_dec() barrier()
++#define smp_mb__before_atomic_inc() barrier()
++#define smp_mb__after_atomic_inc() barrier()
++
++#else /* !CONFIG_RV_ATOMIC */
++
++#include <asm-generic/atomic.h>
++
++#endif /* CONFIG_RV_ATOMIC */
++
++#include <asm/atomic64.h>
++
++#endif /* _ASM_RISCV_ATOMIC_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/barrier.h linux-4.6.2.riscv/arch/riscv/include/asm/barrier.h
+--- linux-4.6.2/arch/riscv/include/asm/barrier.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/barrier.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,14 @@
++#ifndef _ASM_RISCV_BARRIER_H
++#define _ASM_RISCV_BARRIER_H
++
++#ifndef __ASSEMBLY__
++
++#define nop() __asm__ __volatile__ ("nop")
++
++#define mb() __asm__ __volatile__ ("fence" : : : "memory")
++
++#include <asm-generic/barrier.h>
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* _ASM_RISCV_BARRIER_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/bitops.h linux-4.6.2.riscv/arch/riscv/include/asm/bitops.h
+--- linux-4.6.2/arch/riscv/include/asm/bitops.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/bitops.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,271 @@
++#ifndef _ASM_RISCV_BITOPS_H
++#define _ASM_RISCV_BITOPS_H
++
++#ifndef _LINUX_BITOPS_H
++#error "Only <linux/bitops.h> can be included directly"
++#endif /* _LINUX_BITOPS_H */
++
++#ifdef __KERNEL__
++
++#include <linux/compiler.h>
++#include <linux/irqflags.h>
++#include <asm/barrier.h>
++#include <asm/bitsperlong.h>
++
++#ifdef CONFIG_RV_ATOMIC
++
++#ifndef smp_mb__before_clear_bit
++#define smp_mb__before_clear_bit() smp_mb()
++#define smp_mb__after_clear_bit() smp_mb()
++#endif /* smp_mb__before_clear_bit */
++
++/**
++ * __ffs - find first bit in word.
++ * @word: The word to search
++ *
++ * Undefined if no bit exists, so code should check against 0 first.
++ */
++/*
++static __always_inline unsigned long __ffs(unsigned long word)
++{
++ return 0;
++}
++*/
++#include <asm-generic/bitops/__ffs.h>
++
++#include <asm-generic/bitops/ffz.h>
++
++/**
++ * fls - find last (most-significant) bit set
++ * @x: the word to search
++ *
++ * This is defined the same way as ffs.
++ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
++ */
++/*
++static __always_inline int fls(int x)
++{
++ return 0;
++}
++*/
++#include <asm-generic/bitops/fls.h>
++
++/**
++ * __fls - find last (most-significant) set bit in a long word
++ * @word: the word to search
++ *
++ * Undefined if no set bit exists, so code should check against 0 first.
++ */
++/*
++static __always_inline unsigned long __fls(unsigned long word)
++{
++ return 0;
++}
++*/
++#include <asm-generic/bitops/__fls.h>
++
++#include <asm-generic/bitops/fls64.h>
++#include <asm-generic/bitops/find.h>
++#include <asm-generic/bitops/sched.h>
++
++/**
++ * ffs - find first bit set
++ * @x: the word to search
++ *
++ * This is defined the same way as
++ * the libc and compiler builtin ffs routines, therefore
++ * differs in spirit from the above ffz (man ffs).
++ */
++/*
++static __always_inline int ffs(int x)
++{
++ return 0;
++}
++*/
++#include <asm-generic/bitops/ffs.h>
++
++#include <asm-generic/bitops/hweight.h>
++
++#if (BITS_PER_LONG == 64)
++#define __AMO(op) "amo" #op ".d"
++#elif (BITS_PER_LONG == 32)
++#define __AMO(op) "amo" #op ".w"
++#else
++#error "Unexpected BITS_PER_LONG"
++#endif
++
++#define __test_and_op_bit(op, mod, nr, addr) \
++({ \
++ unsigned long __res, __mask; \
++ __mask = BIT_MASK(nr); \
++ __asm__ __volatile__ ( \
++ __AMO(op) " %0, %2, %1" \
++ : "=r" (__res), "+A" (addr[BIT_WORD(nr)]) \
++ : "r" (mod(__mask))); \
++ ((__res & __mask) != 0); \
++})
++
++#define __op_bit(op, mod, nr, addr) \
++ __asm__ __volatile__ ( \
++ __AMO(op) " zero, %1, %0" \
++ : "+A" (addr[BIT_WORD(nr)]) \
++ : "r" (mod(BIT_MASK(nr))))
++
++/* Bitmask modifiers */
++#define __NOP(x) (x)
++#define __NOT(x) (~(x))
++
++/**
++ * test_and_set_bit - Set a bit and return its old value
++ * @nr: Bit to set
++ * @addr: Address to count from
++ *
++ * This operation is atomic and cannot be reordered.
++ * It may be reordered on other architectures than x86.
++ * It also implies a memory barrier.
++ */
++static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
++{
++ return __test_and_op_bit(or, __NOP, nr, addr);
++}
++
++/**
++ * test_and_clear_bit - Clear a bit and return its old value
++ * @nr: Bit to clear
++ * @addr: Address to count from
++ *
++ * This operation is atomic and cannot be reordered.
++ * It can be reordered on other architectures other than x86.
++ * It also implies a memory barrier.
++ */
++static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
++{
++ return __test_and_op_bit(and, __NOT, nr, addr);
++}
++
++/**
++ * test_and_change_bit - Change a bit and return its old value
++ * @nr: Bit to change
++ * @addr: Address to count from
++ *
++ * This operation is atomic and cannot be reordered.
++ * It also implies a memory barrier.
++ */
++static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
++{
++ return __test_and_op_bit(xor, __NOP, nr, addr);
++}
++
++/**
++ * set_bit - Atomically set a bit in memory
++ * @nr: the bit to set
++ * @addr: the address to start counting from
++ *
++ * This function is atomic and may not be reordered. See __set_bit()
++ * if you do not require the atomic guarantees.
++ *
++ * Note: there are no guarantees that this function will not be reordered
++ * on non x86 architectures, so if you are writing portable code,
++ * make sure not to rely on its reordering guarantees.
++ *
++ * Note that @nr may be almost arbitrarily large; this function is not
++ * restricted to acting on a single-word quantity.
++ */
++static inline void set_bit(int nr, volatile unsigned long *addr)
++{
++ __op_bit(or, __NOP, nr, addr);
++}
++
++/**
++ * clear_bit - Clears a bit in memory
++ * @nr: Bit to clear
++ * @addr: Address to start counting from
++ *
++ * clear_bit() is atomic and may not be reordered. However, it does
++ * not contain a memory barrier, so if it is used for locking purposes,
++ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
++ * in order to ensure changes are visible on other processors.
++ */
++static inline void clear_bit(int nr, volatile unsigned long *addr)
++{
++ __op_bit(and, __NOT, nr, addr);
++}
++
++/**
++ * change_bit - Toggle a bit in memory
++ * @nr: Bit to change
++ * @addr: Address to start counting from
++ *
++ * change_bit() is atomic and may not be reordered. It may be
++ * reordered on other architectures than x86.
++ * Note that @nr may be almost arbitrarily large; this function is not
++ * restricted to acting on a single-word quantity.
++ */
++static inline void change_bit(int nr, volatile unsigned long *addr)
++{
++ __op_bit(xor, __NOP, nr, addr);
++}
++
++/**
++ * test_and_set_bit_lock - Set a bit and return its old value, for lock
++ * @nr: Bit to set
++ * @addr: Address to count from
++ *
++ * This operation is atomic and provides acquire barrier semantics.
++ * It can be used to implement bit locks.
++ */
++static inline int test_and_set_bit_lock(
++ unsigned long nr, volatile unsigned long *addr)
++{
++ return test_and_set_bit(nr, addr);
++}
++
++/**
++ * clear_bit_unlock - Clear a bit in memory, for unlock
++ * @nr: the bit to set
++ * @addr: the address to start counting from
++ *
++ * This operation is atomic and provides release barrier semantics.
++ */
++static inline void clear_bit_unlock(
++ unsigned long nr, volatile unsigned long *addr)
++{
++ clear_bit(nr, addr);
++}
++
++/**
++ * __clear_bit_unlock - Clear a bit in memory, for unlock
++ * @nr: the bit to set
++ * @addr: the address to start counting from
++ *
++ * This operation is like clear_bit_unlock, however it is not atomic.
++ * It does provide release barrier semantics so it can be used to unlock
++ * a bit lock, however it would only be used if no other CPU can modify
++ * any bits in the memory until the lock is released (a good example is
++ * if the bit lock itself protects access to the other bits in the word).
++ */
++static inline void __clear_bit_unlock(
++ unsigned long nr, volatile unsigned long *addr)
++{
++ clear_bit(nr, addr);
++}
++
++#undef __test_and_op_bit
++#undef __op_bit
++#undef __NOP
++#undef __NOT
++#undef __AMO
++
++#include <asm-generic/bitops/non-atomic.h>
++#include <asm-generic/bitops/le.h>
++#include <asm-generic/bitops/ext2-atomic.h>
++
++#else /* !CONFIG_RV_ATOMIC */
++
++#include <asm-generic/bitops.h>
++
++#endif /* CONFIG_RV_ATOMIC */
++
++#endif /* __KERNEL__ */
++
++#endif /* _ASM_RISCV_BITOPS_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/bug.h linux-4.6.2.riscv/arch/riscv/include/asm/bug.h
+--- linux-4.6.2/arch/riscv/include/asm/bug.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/bug.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,67 @@
++#ifndef _ASM_RISCV_BUG_H
++#define _ASM_RISCV_BUG_H
++
++#include <linux/compiler.h>
++#include <linux/const.h>
++#include <linux/types.h>
++
++#include <asm/asm.h>
++
++#ifdef CONFIG_GENERIC_BUG
++#define __BUG_INSN _AC(0x00100073,UL) /* sbreak */
++
++#ifndef __ASSEMBLY__
++typedef u32 bug_insn_t;
++
++#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
++#define __BUG_ENTRY_ADDR INT " 1b - 2b"
++#define __BUG_ENTRY_FILE INT " %0 - 2b"
++#else
++#define __BUG_ENTRY_ADDR PTR " 1b"
++#define __BUG_ENTRY_FILE PTR " %0"
++#endif
++
++#ifdef CONFIG_DEBUG_BUGVERBOSE
++#define __BUG_ENTRY \
++ __BUG_ENTRY_ADDR "\n\t" \
++ __BUG_ENTRY_FILE "\n\t" \
++ SHORT " %1"
++#else
++#define __BUG_ENTRY \
++ __BUG_ENTRY_ADDR
++#endif
++
++#define BUG() \
++do { \
++ __asm__ __volatile__ ( \
++ "1:\n\t" \
++ "sbreak\n" \
++ ".pushsection __bug_table,\"a\"\n\t" \
++ "2:\n\t" \
++ __BUG_ENTRY "\n\t" \
++ ".org 2b + %2\n\t" \
++ ".popsection" \
++ : \
++ : "i" (__FILE__), "i" (__LINE__), \
++ "i" (sizeof(struct bug_entry))); \
++ unreachable(); \
++} while (0)
++
++#define HAVE_ARCH_BUG
++#endif /* !__ASSEMBLY__ */
++#endif /* CONFIG_GENERIC_BUG */
++
++#include <asm-generic/bug.h>
++
++#ifndef __ASSEMBLY__
++
++struct pt_regs;
++struct task_struct;
++
++extern void die(struct pt_regs *regs, const char *str);
++extern void do_trap(struct pt_regs *regs, int signo, int code,
++ unsigned long addr, struct task_struct *tsk);
++
++#endif /* !__ASSEMBLY__ */
++
++#endif /* _ASM_RISCV_BUG_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/cacheflush.h linux-4.6.2.riscv/arch/riscv/include/asm/cacheflush.h
+--- linux-4.6.2/arch/riscv/include/asm/cacheflush.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/cacheflush.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,26 @@
++#ifndef _ASM_RISCV_CACHEFLUSH_H
++#define _ASM_RISCV_CACHEFLUSH_H
++
++#include <asm-generic/cacheflush.h>
++
++#undef flush_icache_range
++#undef flush_icache_user_range
++
++static inline void local_flush_icache_all(void)
++{
++ asm volatile ("fence.i" ::: "memory");
++}
++
++#ifndef CONFIG_SMP
++
++#define flush_icache_range(start, end) local_flush_icache_all()
++#define flush_icache_user_range(vma, pg, addr, len) local_flush_icache_all()
++
++#else /* CONFIG_SMP */
++
++#define flush_icache_range(start, end) sbi_remote_fence_i(0)
++#define flush_icache_user_range(vma, pg, addr, len) sbi_remote_fence_i(0)
++
++#endif /* CONFIG_SMP */
++
++#endif /* _ASM_RISCV_CACHEFLUSH_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/cache.h linux-4.6.2.riscv/arch/riscv/include/asm/cache.h
+--- linux-4.6.2/arch/riscv/include/asm/cache.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/cache.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,12 @@
++#ifndef _ASM_RISCV_CACHE_H
++#define _ASM_RISCV_CACHE_H
++
++#if defined(CONFIG_CPU_RV_ROCKET)
++#define L1_CACHE_SHIFT 6
++#else
++#define L1_CACHE_SHIFT 5
++#endif
++
++#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++
++#endif /* _ASM_RISCV_CACHE_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/cmpxchg.h linux-4.6.2.riscv/arch/riscv/include/asm/cmpxchg.h
+--- linux-4.6.2/arch/riscv/include/asm/cmpxchg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/cmpxchg.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,111 @@
++#ifndef _ASM_RISCV_CMPXCHG_H
++#define _ASM_RISCV_CMPXCHG_H
++
++#include <linux/bug.h>
++
++#ifdef CONFIG_RV_ATOMIC
++
++#include <asm/barrier.h>
++
++#define __xchg(new, ptr, size) \
++({ \
++ __typeof__(ptr) __ptr = (ptr); \
++ __typeof__(new) __new = (new); \
++ __typeof__(*(ptr)) __ret; \
++ switch (size) { \
++ case 4: \
++ __asm__ __volatile__ ( \
++ "amoswap.w %0, %2, %1" \
++ : "=r" (__ret), "+A" (*__ptr) \
++ : "r" (__new)); \
++ break; \
++ case 8: \
++ __asm__ __volatile__ ( \
++ "amoswap.d %0, %2, %1" \
++ : "=r" (__ret), "+A" (*__ptr) \
++ : "r" (__new)); \
++ break; \
++ default: \
++ BUILD_BUG(); \
++ } \
++ __ret; \
++})
++
++#define xchg(ptr, x) (__xchg((x), (ptr), sizeof(*(ptr))))
++
++
++/*
++ * Atomic compare and exchange. Compare OLD with MEM, if identical,
++ * store NEW in MEM. Return the initial value in MEM. Success is
++ * indicated by comparing RETURN with OLD.
++ */
++#define __cmpxchg(ptr, old, new, size) \
++({ \
++ __typeof__(ptr) __ptr = (ptr); \
++ __typeof__(old) __old = (old); \
++ __typeof__(new) __new = (new); \
++ __typeof__(*(ptr)) __ret; \
++ register unsigned int __rc; \
++ switch (size) { \
++ case 4: \
++ __asm__ __volatile__ ( \
++ "0:" \
++ "lr.w %0, %2\n" \
++ "bne %0, %z3, 1f\n" \
++ "sc.w %1, %z4, %2\n" \
++ "bnez %1, 0b\n" \
++ "1:" \
++ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
++ : "rJ" (__old), "rJ" (__new)); \
++ break; \
++ case 8: \
++ __asm__ __volatile__ ( \
++ "0:" \
++ "lr.d %0, %2\n" \
++ "bne %0, %z3, 1f\n" \
++ "sc.d %1, %z4, %2\n" \
++ "bnez %1, 0b\n" \
++ "1:" \
++ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
++ : "rJ" (__old), "rJ" (__new)); \
++ break; \
++ default: \
++ BUILD_BUG(); \
++ } \
++ __ret; \
++})
++
++#define __cmpxchg_mb(ptr, old, new, size) \
++({ \
++ __typeof__(*(ptr)) __ret; \
++ smp_mb(); \
++ __ret = __cmpxchg((ptr), (old), (new), (size)); \
++ smp_mb(); \
++ __ret; \
++})
++
++#define cmpxchg(ptr, o, n) \
++ (__cmpxchg_mb((ptr), (o), (n), sizeof(*(ptr))))
++
++#define cmpxchg_local(ptr, o, n) \
++ (__cmpxchg((ptr), (o), (n), sizeof(*(ptr))))
++
++#define cmpxchg64(ptr, o, n) \
++({ \
++ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
++ cmpxchg((ptr), (o), (n)); \
++})
++
++#define cmpxchg64_local(ptr, o, n) \
++({ \
++ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
++ cmpxchg_local((ptr), (o), (n)); \
++})
++
++#else /* !CONFIG_RV_ATOMIC */
++
++#include <asm-generic/cmpxchg.h>
++
++#endif /* CONFIG_RV_ATOMIC */
++
++#endif /* _ASM_RISCV_CMPXCHG_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/csr.h linux-4.6.2.riscv/arch/riscv/include/asm/csr.h
+--- linux-4.6.2/arch/riscv/include/asm/csr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/csr.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,137 @@
++#ifndef _ASM_RISCV_CSR_H
++#define _ASM_RISCV_CSR_H
++
++#include <linux/const.h>
++
++/* Status register flags */
++#define SR_IE _AC(0x00000002,UL) /* Interrupt Enable */
++#define SR_PIE _AC(0x00000020,UL) /* Previous IE */
++#define SR_PS _AC(0x00000100,UL) /* Previously Supervisor */
++#define SR_PUM _AC(0x00040000,UL) /* Protect User Memory */
++
++#define SR_FS _AC(0x00006000,UL) /* Floating-point Status */
++#define SR_FS_OFF _AC(0x00000000,UL)
++#define SR_FS_INITIAL _AC(0x00002000,UL)
++#define SR_FS_CLEAN _AC(0x00004000,UL)
++#define SR_FS_DIRTY _AC(0x00006000,UL)
++
++#define SR_XS _AC(0x00018000,UL) /* Extension Status */
++#define SR_XS_OFF _AC(0x00000000,UL)
++#define SR_XS_INITIAL _AC(0x00008000,UL)
++#define SR_XS_CLEAN _AC(0x00010000,UL)
++#define SR_XS_DIRTY _AC(0x00018000,UL)
++
++#ifndef CONFIG_64BIT
++#define SR_SD _AC(0x80000000,UL) /* FS/XS dirty */
++#else
++#define SR_SD _AC(0x8000000000000000,UL) /* FS/XS dirty */
++#endif
++
++/* Interrupt Enable and Interrupt Pending flags */
++#define SIE_SSIE _AC(0x00000002,UL) /* Software Interrupt Enable */
++#define SIE_STIE _AC(0x00000020,UL) /* Timer Interrupt Enable */
++
++#define EXC_INST_MISALIGNED 0
++#define EXC_INST_ACCESS 1
++#define EXC_BREAKPOINT 3
++#define EXC_LOAD_ACCESS 5
++#define EXC_STORE_ACCESS 7
++#define EXC_SYSCALL 8
++
++#ifndef __ASSEMBLY__
++
++#define CSR_ZIMM(val) \
++ (__builtin_constant_p(val) && ((unsigned long)(val) < 0x20))
++
++#define csr_swap(csr,val) \
++({ \
++ unsigned long __v = (unsigned long)(val); \
++ if (CSR_ZIMM(__v)) { \
++ __asm__ __volatile__ ( \
++ "csrrw %0, " #csr ", %1" \
++ : "=r" (__v) : "i" (__v)); \
++ } else { \
++ __asm__ __volatile__ ( \
++ "csrrw %0, " #csr ", %1" \
++ : "=r" (__v) : "r" (__v)); \
++ } \
++ __v; \
++})
++
++#define csr_read(csr) \
++({ \
++ register unsigned long __v; \
++ __asm__ __volatile__ ( \
++ "csrr %0, " #csr : "=r" (__v)); \
++ __v; \
++})
++
++#define csr_write(csr,val) \
++({ \
++ unsigned long __v = (unsigned long)(val); \
++ if (CSR_ZIMM(__v)) { \
++ __asm__ __volatile__ ( \
++ "csrw " #csr ", %0" : : "i" (__v)); \
++ } else { \
++ __asm__ __volatile__ ( \
++ "csrw " #csr ", %0" : : "r" (__v)); \
++ } \
++})
++
++#define csr_read_set(csr,val) \
++({ \
++ unsigned long __v = (unsigned long)(val); \
++ if (CSR_ZIMM(val)) { \
++ __asm__ __volatile__ ( \
++ "csrrs %0, " #csr ", %1" \
++ : "=r" (__v) : "i" (__v)); \
++ } else { \
++ __asm__ __volatile__ ( \
++ "csrrs %0, " #csr ", %1" \
++ : "=r" (__v) : "r" (__v)); \
++ } \
++ __v; \
++})
++
++#define csr_set(csr,val) \
++({ \
++ unsigned long __v = (unsigned long)(val); \
++ if (CSR_ZIMM(__v)) { \
++ __asm__ __volatile__ ( \
++ "csrs " #csr ", %0" : : "i" (__v)); \
++ } else { \
++ __asm__ __volatile__ ( \
++ "csrs " #csr ", %0" : : "r" (__v)); \
++ } \
++})
++
++#define csr_read_clear(csr,val) \
++({ \
++ unsigned long __v = (unsigned long)(val); \
++ if (CSR_ZIMM(__v)) { \
++ __asm__ __volatile__ ( \
++ "csrrc %0, " #csr ", %1" \
++ : "=r" (__v) : "i" (__v)); \
++ } else { \
++ __asm__ __volatile__ ( \
++ "csrrc %0, " #csr ", %1" \
++ : "=r" (__v) : "r" (__v)); \
++ } \
++ __v; \
++})
++
++#define csr_clear(csr,val) \
++({ \
++ unsigned long __v = (unsigned long)(val); \
++ if (CSR_ZIMM(__v)) { \
++ __asm__ __volatile__ ( \
++ "csrc " #csr ", %0" : : "i" (__v)); \
++ } else { \
++ __asm__ __volatile__ ( \
++ "csrc " #csr ", %0" : : "r" (__v)); \
++ } \
++})
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* _ASM_RISCV_CSR_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/current.h linux-4.6.2.riscv/arch/riscv/include/asm/current.h
+--- linux-4.6.2/arch/riscv/include/asm/current.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/current.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,16 @@
++#ifndef _ASM_RISCV_CURRENT_H
++#define _ASM_RISCV_CURRENT_H
++
++#include <asm/csr.h>
++
++struct task_struct;
++
++static inline struct task_struct *get_current(void)
++{
++ register struct task_struct * tp asm("tp");
++ return tp;
++}
++
++#define current (get_current())
++
++#endif /* _ASM_RISCV_CURRENT_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/delay.h linux-4.6.2.riscv/arch/riscv/include/asm/delay.h
+--- linux-4.6.2/arch/riscv/include/asm/delay.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/delay.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,14 @@
++#ifndef _ASM_RISCV_DELAY_H
++#define _ASM_RISCV_DELAY_H
++
++extern unsigned long timebase;
++
++#define udelay udelay
++extern void udelay(unsigned long usecs);
++
++#define ndelay ndelay
++extern void ndelay(unsigned long nsecs);
++
++extern void __delay(unsigned long cycles);
++
++#endif /* _ASM_RISCV_DELAY_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/device.h linux-4.6.2.riscv/arch/riscv/include/asm/device.h
+--- linux-4.6.2/arch/riscv/include/asm/device.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/device.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,13 @@
++#ifndef _ASM_RISCV_DEVICE_H
++#define _ASM_RISCV_DEVICE_H
++
++#include <linux/sysfs.h>
++
++struct dev_archdata {
++ struct dma_map_ops *dma_ops;
++};
++
++struct pdev_archdata {
++};
++
++#endif /* _ASM_RISCV_DEVICE_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/dma-mapping.h linux-4.6.2.riscv/arch/riscv/include/asm/dma-mapping.h
+--- linux-4.6.2/arch/riscv/include/asm/dma-mapping.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/dma-mapping.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,63 @@
++/*
++ * Copyright (C) 2003-2004 Hewlett-Packard Co
++ * David Mosberger-Tang <davidm@hpl.hp.com>
++ * Copyright (C) 2012 ARM Ltd.
++ * Copyright (C) 2016 SiFive, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++#ifndef __ASM_RISCV_DMA_MAPPING_H
++#define __ASM_RISCV_DMA_MAPPING_H
++
++#ifdef __KERNEL__
++
++/* Use ops->dma_mapping_error (if it exists) or assume success */
++// #undef DMA_ERROR_CODE
++
++static inline struct dma_map_ops *get_dma_ops(struct device *dev)
++{
++ if (unlikely(dev->archdata.dma_ops))
++ return dev->archdata.dma_ops;
++ else
++ return &dma_noop_ops;
++}
++
++static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
++{
++ if (!dev->dma_mask)
++ return false;
++
++ return addr + size - 1 <= *dev->dma_mask;
++}
++
++static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
++{
++ return (dma_addr_t)paddr;
++}
++
++static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
++{
++ return (phys_addr_t)dev_addr;
++}
++
++static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction dir)
++{
++ /*
++ * RISC-V is cache-coherent, so this is mostly a no-op. However, we do need to
++ * ensure that dma_cache_sync() enforces order, hence the mb().
++ */
++ mb();
++}
++
++#endif /* __KERNEL__ */
++#endif /* __ASM_RISCV_DMA_MAPPING_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/elf.h linux-4.6.2.riscv/arch/riscv/include/asm/elf.h
+--- linux-4.6.2/arch/riscv/include/asm/elf.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/elf.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,72 @@
++#ifndef _ASM_RISCV_ELF_H
++#define _ASM_RISCV_ELF_H
++
++#include <uapi/asm/elf.h>
++#include <asm/auxvec.h>
++#include <asm/byteorder.h>
++
++/* TODO: Move definition into include/uapi/linux/elf-em.h */
++#define EM_RISCV 0xF3
++
++/*
++ * These are used to set parameters in the core dumps.
++ */
++#define ELF_ARCH EM_RISCV
++
++#ifdef CONFIG_64BIT
++#define ELF_CLASS ELFCLASS64
++#else
++#define ELF_CLASS ELFCLASS32
++#endif
++
++#if defined(__LITTLE_ENDIAN)
++#define ELF_DATA ELFDATA2LSB
++#elif defined(__BIG_ENDIAN)
++#define ELF_DATA ELFDATA2MSB
++#else
++#error "Unknown endianness"
++#endif
++
++/*
++ * This is used to ensure we don't load something for the wrong architecture.
++ */
++#define elf_check_arch(x) ((x)->e_machine == EM_RISCV)
++
++#define CORE_DUMP_USE_REGSET
++#define ELF_EXEC_PAGESIZE (PAGE_SIZE)
++
++/*
++ * 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 ((TASK_SIZE / 3) * 2)
++
++/*
++ * This yields a mask that user programs can use to figure out what
++ * instruction set this CPU supports. This could be done in user space,
++ * 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.
++ */
++#define ELF_PLATFORM (NULL)
++
++#define ARCH_DLINFO \
++do { \
++ NEW_AUX_ENT(AT_SYSINFO_EHDR, \
++ (elf_addr_t)current->mm->context.vdso); \
++} while (0)
++
++
++#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
++struct linux_binprm;
++extern int arch_setup_additional_pages(struct linux_binprm *bprm,
++ int uses_interp);
++
++#endif /* _ASM_RISCV_ELF_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/io.h linux-4.6.2.riscv/arch/riscv/include/asm/io.h
+--- linux-4.6.2/arch/riscv/include/asm/io.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/io.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,63 @@
++#ifndef _ASM_RISCV_IO_H
++#define _ASM_RISCV_IO_H
++
++#include <asm-generic/io.h>
++
++#ifdef __KERNEL__
++
++#ifdef CONFIG_MMU
++
++extern void __iomem *ioremap(phys_addr_t offset, unsigned long size);
++
++/*
++ * ioremap_nocache - map bus memory into CPU space
++ * @offset: bus address of the memory
++ * @size: size of the resource to map
++ *
++ * ioremap_nocache performs a platform specific sequence of operations to
++ * make bus memory CPU accessible via the readb/readw/readl/writeb/
++ * writew/writel functions and the other mmio helpers. The returned
++ * address is not guaranteed to be usable directly as a virtual
++ * address.
++ *
++ * This version of ioremap ensures that the memory is marked uncachable
++ * on the CPU as well as honouring existing caching rules from things like
++ * the PCI bus. Note that there are other caches and buffers on many
++ * busses. In particular driver authors should read up on PCI writes.
++ *
++ * It's useful if some control registers are in such an area and
++ * write combining or read caching is not desirable.
++ *
++ * Must be freed with iounmap.
++ */
++static inline void __iomem *ioremap_nocache(
++ phys_addr_t offset, unsigned long size)
++{
++ return ioremap(offset, size);
++}
++
++/**
++ * ioremap_wc - map memory into CPU space write combined
++ * @offset: bus address of the memory
++ * @size: size of the resource to map
++ *
++ * This version of ioremap ensures that the memory is marked write combining.
++ * Write combining allows faster writes to some hardware devices.
++ *
++ * Must be freed with iounmap.
++ */
++static inline void __iomem *ioremap_wc(
++ phys_addr_t offset, unsigned long size)
++{
++ return ioremap(offset, size);
++}
++
++#define ioremap_wt ioremap_nocache
++
++extern void iounmap(void __iomem *addr);
++
++#endif /* CONFIG_MMU */
++
++#endif /* __KERNEL__ */
++
++#endif /* _ASM_RISCV_IO_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/irqflags.h linux-4.6.2.riscv/arch/riscv/include/asm/irqflags.h
+--- linux-4.6.2/arch/riscv/include/asm/irqflags.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/irqflags.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,49 @@
++#ifndef _ASM_RISCV_IRQFLAGS_H
++#define _ASM_RISCV_IRQFLAGS_H
++
++#include <asm/processor.h>
++#include <asm/csr.h>
++
++/* read interrupt enabled status */
++static inline unsigned long arch_local_save_flags(void)
++{
++ return csr_read(sstatus);
++}
++
++/* unconditionally enable interrupts */
++static inline void arch_local_irq_enable(void)
++{
++ csr_set(sstatus, SR_IE);
++}
++
++/* unconditionally disable interrupts */
++static inline void arch_local_irq_disable(void)
++{
++ csr_clear(sstatus, SR_IE);
++}
++
++/* get status and disable interrupts */
++static inline unsigned long arch_local_irq_save(void)
++{
++ return csr_read_clear(sstatus, SR_IE);
++}
++
++/* test flags */
++static inline int arch_irqs_disabled_flags(unsigned long flags)
++{
++ return !(flags & SR_IE);
++}
++
++/* test hardware interrupt enable bit */
++static inline int arch_irqs_disabled(void)
++{
++ return arch_irqs_disabled_flags(arch_local_save_flags());
++}
++
++/* set interrupt enabled status */
++static inline void arch_local_irq_restore(unsigned long flags)
++{
++ csr_set(sstatus, flags & SR_IE);
++}
++
++#endif /* _ASM_RISCV_IRQFLAGS_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/irq.h linux-4.6.2.riscv/arch/riscv/include/asm/irq.h
+--- linux-4.6.2/arch/riscv/include/asm/irq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/irq.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,14 @@
++#ifndef _ASM_RISCV_IRQ_H
++#define _ASM_RISCV_IRQ_H
++
++#define NR_IRQS 0
++
++#define INTERRUPT_CAUSE_SOFTWARE 1
++#define INTERRUPT_CAUSE_TIMER 5
++#define INTERRUPT_CAUSE_EXTERNAL 9
++
++void riscv_timer_interrupt(void);
++
++#include <asm-generic/irq.h>
++
++#endif /* _ASM_RISCV_IRQ_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/Kbuild linux-4.6.2.riscv/arch/riscv/include/asm/Kbuild
+--- linux-4.6.2/arch/riscv/include/asm/Kbuild 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/Kbuild 2017-03-04 02:48:34.162887952 +0100
+@@ -0,0 +1,59 @@
++generic-y += bugs.h
++generic-y += cacheflush.h
++generic-y += checksum.h
++generic-y += clkdev.h
++generic-y += cputime.h
++generic-y += div64.h
++generic-y += dma.h
++generic-y += emergency-restart.h
++generic-y += errno.h
++generic-y += exec.h
++generic-y += fb.h
++generic-y += fcntl.h
++generic-y += ftrace.h
++generic-y += futex.h
++generic-y += hardirq.h
++generic-y += hash.h
++generic-y += hw_irq.h
++generic-y += ioctl.h
++generic-y += ioctls.h
++generic-y += ipcbuf.h
++generic-y += irq_regs.h
++generic-y += irq_work.h
++generic-y += kdebug.h
++generic-y += kmap_types.h
++generic-y += kvm_para.h
++generic-y += local.h
++generic-y += mm-arch-hooks.h
++generic-y += mman.h
++generic-y += module.h
++generic-y += msgbuf.h
++generic-y += mutex.h
++generic-y += param.h
++generic-y += percpu.h
++generic-y += poll.h
++generic-y += posix_types.h
++generic-y += preempt.h
++generic-y += resource.h
++generic-y += scatterlist.h
++generic-y += sections.h
++generic-y += sembuf.h
++generic-y += shmbuf.h
++generic-y += shmparam.h
++generic-y += signal.h
++generic-y += socket.h
++generic-y += sockios.h
++generic-y += stat.h
++generic-y += statfs.h
++generic-y += swab.h
++generic-y += termbits.h
++generic-y += termios.h
++generic-y += topology.h
++generic-y += trace_clock.h
++generic-y += types.h
++generic-y += ucontext.h
++generic-y += unaligned.h
++generic-y += user.h
++generic-y += vga.h
++generic-y += vmlinux.lds.h
++generic-y += xor.h
+diff -Nur linux-4.6.2/arch/riscv/include/asm/linkage.h linux-4.6.2.riscv/arch/riscv/include/asm/linkage.h
+--- linux-4.6.2/arch/riscv/include/asm/linkage.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/linkage.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,7 @@
++#ifndef _ASM_RISCV_LINKAGE_H
++#define _ASM_RISCV_LINKAGE_H
++
++#define __ALIGN .balign 4
++#define __ALIGN_STR ".balign 4"
++
++#endif /* _ASM_RISCV_LINKAGE_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/mmu_context.h linux-4.6.2.riscv/arch/riscv/include/asm/mmu_context.h
+--- linux-4.6.2/arch/riscv/include/asm/mmu_context.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/mmu_context.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,46 @@
++#ifndef _ASM_RISCV_MMU_CONTEXT_H
++#define _ASM_RISCV_MMU_CONTEXT_H
++
++#include <asm-generic/mm_hooks.h>
++
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <asm/tlbflush.h>
++
++static inline void enter_lazy_tlb(struct mm_struct *mm,
++ struct task_struct *task)
++{
++}
++
++/* Initialize context-related info for a new mm_struct */
++static inline int init_new_context(struct task_struct *task,
++ struct mm_struct *mm)
++{
++ return 0;
++}
++
++static inline void destroy_context(struct mm_struct *mm)
++{
++}
++
++static inline void switch_mm(struct mm_struct *prev,
++ struct mm_struct *next, struct task_struct *task)
++{
++ if (likely(prev != next)) {
++ csr_write(sptbr, virt_to_pfn(next->pgd));
++ local_flush_tlb_all();
++ }
++}
++
++static inline void activate_mm(struct mm_struct *prev,
++ struct mm_struct *next)
++{
++ switch_mm(prev, next, NULL);
++}
++
++static inline void deactivate_mm(struct task_struct *task,
++ struct mm_struct *mm)
++{
++}
++
++#endif /* _ASM_RISCV_MMU_CONTEXT_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/mmu.h linux-4.6.2.riscv/arch/riscv/include/asm/mmu.h
+--- linux-4.6.2/arch/riscv/include/asm/mmu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/mmu.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,12 @@
++#ifndef _ASM_RISCV_MMU_H
++#define _ASM_RISCV_MMU_H
++
++#ifndef __ASSEMBLY__
++
++typedef struct {
++ void *vdso;
++} mm_context_t;
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* _ASM_RISCV_MMU_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/page.h linux-4.6.2.riscv/arch/riscv/include/asm/page.h
+--- linux-4.6.2/arch/riscv/include/asm/page.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/page.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,119 @@
++#ifndef _ASM_RISCV_PAGE_H
++#define _ASM_RISCV_PAGE_H
++
++#include <linux/pfn.h>
++#include <linux/const.h>
++
++#define PAGE_SHIFT (12)
++#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
++#define PAGE_MASK (~(PAGE_SIZE - 1))
++
++#ifdef __KERNEL__
++
++/*
++ * PAGE_OFFSET -- the first address of the first page of memory.
++ * When not using MMU this corresponds to the first free page in
++ * physical memory (aligned on a page boundary).
++ */
++#ifdef CONFIG_64BIT
++#define PAGE_OFFSET _AC(0xffffffff80000000,UL)
++#else
++#define PAGE_OFFSET _AC(0xc0000000,UL)
++#endif
++
++#ifndef __ASSEMBLY__
++
++#define PAGE_UP(addr) (((addr)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1)))
++#define PAGE_DOWN(addr) ((addr)&(~((PAGE_SIZE)-1)))
++
++/* align addr on a size boundary - adjust address up/down if needed */
++#define _ALIGN_UP(addr, size) (((addr)+((size)-1))&(~((size)-1)))
++#define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1)))
++
++/* align addr on a size boundary - adjust address up if needed */
++#define _ALIGN(addr, size) _ALIGN_UP(addr, size)
++
++#define clear_page(pgaddr) memset((pgaddr), 0, PAGE_SIZE)
++#define copy_page(to, from) memcpy((to), (from), PAGE_SIZE)
++
++#define clear_user_page(pgaddr, vaddr, page) memset((pgaddr), 0, PAGE_SIZE)
++#define copy_user_page(vto, vfrom, vaddr, topg) \
++ memcpy((vto), (vfrom), PAGE_SIZE)
++
++/*
++ * Use struct definitions to apply C type checking
++ */
++
++/* Page Global Directory entry */
++typedef struct {
++ unsigned long pgd;
++} pgd_t;
++
++/* Page Table entry */
++typedef struct {
++ unsigned long pte;
++} pte_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) })
++
++#ifdef CONFIG_64BITS
++#define PTE_FMT "%016lx"
++#else
++#define PTE_FMT "%08lx"
++#endif
++
++extern unsigned long va_pa_offset;
++extern unsigned long pfn_base;
++
++extern unsigned long max_low_pfn;
++extern unsigned long min_low_pfn;
++
++#define __pa(x) ((unsigned long)(x) - va_pa_offset)
++#define __va(x) ((void *)((unsigned long) (x) + va_pa_offset))
++
++#define phys_to_pfn(phys) (PFN_DOWN(phys))
++#define pfn_to_phys(pfn) (PFN_PHYS(pfn))
++
++#define virt_to_pfn(vaddr) (phys_to_pfn(__pa(vaddr)))
++#define pfn_to_virt(pfn) (__va(pfn_to_phys(pfn)))
++
++#define virt_to_page(vaddr) (pfn_to_page(virt_to_pfn(vaddr)))
++#define page_to_virt(page) (pfn_to_virt(page_to_pfn(page)))
++
++#define page_to_phys(page) (pfn_to_phys(page_to_pfn(page)))
++#define page_to_bus(page) (page_to_phys(page))
++#define phys_to_page(paddr) (pfn_to_page(phys_to_pfn(paddr)))
++
++#define pfn_valid(pfn) (((pfn) >= pfn_base) && (((pfn)-pfn_base) < max_mapnr))
++
++#define ARCH_PFN_OFFSET (pfn_base)
++
++#endif /* __ASSEMBLY__ */
++
++#define virt_addr_valid(vaddr) (pfn_valid(virt_to_pfn(vaddr)))
++
++#endif /* __KERNEL__ */
++
++#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
++ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
++
++#include <asm-generic/memory_model.h>
++#include <asm-generic/getorder.h>
++
++/* vDSO support */
++/* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */
++#define __HAVE_ARCH_GATE_AREA
++
++#endif /* _ASM_RISCV_PAGE_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/pci.h linux-4.6.2.riscv/arch/riscv/include/asm/pci.h
+--- linux-4.6.2/arch/riscv/include/asm/pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/pci.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,37 @@
++#ifndef __ASM_RISCV_PCI_H
++#define __ASM_RISCV_PCI_H
++#ifdef __KERNEL__
++
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/io.h>
++
++#define PCIBIOS_MIN_IO 0x1000
++#define PCIBIOS_MIN_MEM 0
++
++/* RISC-V shim does not initialize PCI bus */
++#define pcibios_assign_all_busses() 1
++
++/* RISC-V TileLink and PCIe share the share address space */
++#define PCI_DMA_BUS_IS_PHYS 1
++
++extern int isa_dma_bridge_buggy;
++
++#ifdef CONFIG_PCI
++static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
++{
++ /* no legacy IRQ on risc-v */
++ return -ENODEV;
++}
++
++static inline int pci_proc_domain(struct pci_bus *bus)
++{
++ /* always show the domain in /proc */
++ return 1;
++}
++#endif /* CONFIG_PCI */
++
++#endif /* __KERNEL__ */
++#endif /* __ASM_PCI_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/pgalloc.h linux-4.6.2.riscv/arch/riscv/include/asm/pgalloc.h
+--- linux-4.6.2/arch/riscv/include/asm/pgalloc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/pgalloc.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,107 @@
++#ifndef _ASM_RISCV_PGALLOC_H
++#define _ASM_RISCV_PGALLOC_H
++
++#include <linux/mm.h>
++#include <asm/tlb.h>
++
++static inline void pmd_populate_kernel(struct mm_struct *mm,
++ pmd_t *pmd, pte_t *pte)
++{
++ unsigned long pfn = virt_to_pfn(pte);
++ set_pmd(pmd, __pmd((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
++}
++
++static inline void pmd_populate(struct mm_struct *mm,
++ pmd_t *pmd, pgtable_t pte)
++{
++ unsigned long pfn = virt_to_pfn(page_address(pte));
++ set_pmd(pmd, __pmd((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
++}
++
++#ifndef __PAGETABLE_PMD_FOLDED
++static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
++{
++ unsigned long pfn = virt_to_pfn(pmd);
++ set_pud(pud, __pud((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
++}
++#endif /* __PAGETABLE_PMD_FOLDED */
++
++#define pmd_pgtable(pmd) pmd_page(pmd)
++
++static inline pgd_t *pgd_alloc(struct mm_struct *mm)
++{
++ pgd_t *pgd;
++
++ pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
++ if (likely(pgd != NULL)) {
++ memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
++ /* Copy kernel mappings */
++ memcpy(pgd + USER_PTRS_PER_PGD,
++ init_mm.pgd + USER_PTRS_PER_PGD,
++ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
++ }
++ return pgd;
++}
++
++static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
++{
++ free_page((unsigned long)pgd);
++}
++
++#ifndef __PAGETABLE_PMD_FOLDED
++
++static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
++{
++ return (pmd_t *)__get_free_page(
++ GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
++}
++
++static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
++{
++ free_page((unsigned long)pmd);
++}
++
++#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
++
++#endif /* __PAGETABLE_PMD_FOLDED */
++
++static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
++ unsigned long address)
++{
++ return (pte_t *)__get_free_page(
++ GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
++}
++
++static inline struct page *pte_alloc_one(struct mm_struct *mm,
++ unsigned long address)
++{
++ struct page *pte;
++ pte = alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
++ if (likely(pte != NULL)) {
++ pgtable_page_ctor(pte);
++ }
++ return pte;
++}
++
++static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
++{
++ free_page((unsigned long)pte);
++}
++
++static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
++{
++ pgtable_page_dtor(pte);
++ __free_page(pte);
++}
++
++#define __pte_free_tlb(tlb, pte, buf) \
++do { \
++ pgtable_page_dtor(pte); \
++ tlb_remove_page((tlb), pte); \
++} while (0)
++
++static inline void check_pgt_cache(void)
++{
++}
++
++#endif /* _ASM_RISCV_PGALLOC_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/pgtable-32.h linux-4.6.2.riscv/arch/riscv/include/asm/pgtable-32.h
+--- linux-4.6.2/arch/riscv/include/asm/pgtable-32.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/pgtable-32.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,12 @@
++#ifndef _ASM_RISCV_PGTABLE_32_H
++#define _ASM_RISCV_PGTABLE_32_H
++
++#include <asm-generic/pgtable-nopmd.h>
++#include <linux/const.h>
++
++/* Size of region mapped by a page global directory */
++#define PGDIR_SHIFT 22
++#define PGDIR_SIZE (_AC(1,UL) << PGDIR_SHIFT)
++#define PGDIR_MASK (~(PGDIR_SIZE - 1))
++
++#endif /* _ASM_RISCV_PGTABLE_32_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/pgtable-64.h linux-4.6.2.riscv/arch/riscv/include/asm/pgtable-64.h
+--- linux-4.6.2/arch/riscv/include/asm/pgtable-64.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/pgtable-64.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,66 @@
++#ifndef _ASM_RISCV_PGTABLE_64_H
++#define _ASM_RISCV_PGTABLE_64_H
++
++#include <linux/const.h>
++
++#define PGDIR_SHIFT 30
++/* Size of region mapped by a page global directory */
++#define PGDIR_SIZE (_AC(1,UL) << PGDIR_SHIFT)
++#define PGDIR_MASK (~(PGDIR_SIZE - 1))
++
++#define PMD_SHIFT 21
++/* Size of region mapped by a page middle directory */
++#define PMD_SIZE (_AC(1,UL) << PMD_SHIFT)
++#define PMD_MASK (~(PMD_SIZE - 1))
++
++/* Page Middle Directory entry */
++typedef struct {
++ unsigned long pmd;
++} pmd_t;
++
++#define pmd_val(x) ((x).pmd)
++#define __pmd(x) ((pmd_t) { (x) })
++
++#define PTRS_PER_PMD (PAGE_SIZE / sizeof(pmd_t))
++
++static inline int pud_present(pud_t pud)
++{
++ return (pud_val(pud) & _PAGE_PRESENT);
++}
++
++static inline int pud_none(pud_t pud)
++{
++ return (pud_val(pud) == 0);
++}
++
++static inline int pud_bad(pud_t pud)
++{
++ return !pud_present(pud);
++}
++
++static inline void set_pud(pud_t *pudp, pud_t pud)
++{
++ *pudp = pud;
++}
++
++static inline void pud_clear(pud_t *pudp)
++{
++ set_pud(pudp, __pud(0));
++}
++
++static inline unsigned long pud_page_vaddr(pud_t pud)
++{
++ return (unsigned long)pfn_to_virt(pud_val(pud) >> _PAGE_PFN_SHIFT);
++}
++
++#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
++
++static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
++{
++ return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr);
++}
++
++#define pmd_ERROR(e) \
++ pr_err("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e))
++
++#endif /* _ASM_RISCV_PGTABLE_64_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/pgtable-bits.h linux-4.6.2.riscv/arch/riscv/include/asm/pgtable-bits.h
+--- linux-4.6.2/arch/riscv/include/asm/pgtable-bits.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/pgtable-bits.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,37 @@
++#ifndef _ASM_RISCV_PGTABLE_BITS_H
++#define _ASM_RISCV_PGTABLE_BITS_H
++
++/*
++ * RV32Sv32 page table entry:
++ * | 31 10 | 9 7 | 6 | 5 | 4 1 | 0
++ * PFN reserved for SW D R TYPE V
++ *
++ * RV64Sv39 / RV64Sv48 page table entry:
++ * | 63 48 | 47 10 | 9 7 | 6 | 5 | 4 1 | 0
++ * reserved for HW PFN reserved for SW D R TYPE V
++ */
++
++#define _PAGE_PRESENT (1 << 0)
++#define _PAGE_READ (1 << 1) /* Readable */
++#define _PAGE_WRITE (1 << 2) /* Writable */
++#define _PAGE_EXEC (1 << 3) /* Executable */
++#define _PAGE_USER (1 << 4) /* User */
++#define _PAGE_GLOBAL (1 << 5) /* Global */
++#define _PAGE_ACCESSED (1 << 6) /* Set by hardware on any access */
++#define _PAGE_DIRTY (1 << 7) /* Set by hardware on any write */
++#define _PAGE_SOFT (1 << 8) /* Reserved for software */
++
++#define _PAGE_SPECIAL _PAGE_SOFT
++#define _PAGE_TABLE _PAGE_PRESENT
++
++#define _PAGE_PFN_SHIFT 10
++
++/* Set of bits to preserve across pte_modify() */
++#define _PAGE_CHG_MASK (~(unsigned long)(_PAGE_PRESENT | _PAGE_READ | \
++ _PAGE_WRITE | _PAGE_EXEC | \
++ _PAGE_USER | _PAGE_GLOBAL))
++
++/* Advertise support for _PAGE_SPECIAL */
++#define __HAVE_ARCH_PTE_SPECIAL
++
++#endif /* _ASM_RISCV_PGTABLE_BITS_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/pgtable.h linux-4.6.2.riscv/arch/riscv/include/asm/pgtable.h
+--- linux-4.6.2/arch/riscv/include/asm/pgtable.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/pgtable.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,329 @@
++#ifndef _ASM_RISCV_PGTABLE_H
++#define _ASM_RISCV_PGTABLE_H
++
++#include <linux/mmzone.h>
++
++#include <asm/pgtable-bits.h>
++
++#ifndef __ASSEMBLY__
++
++#ifdef CONFIG_MMU
++
++/* Page Upper Directory not used in RISC-V */
++#include <asm-generic/pgtable-nopud.h>
++#include <asm/page.h>
++#include <linux/mm_types.h>
++
++#ifdef CONFIG_64BIT
++#include <asm/pgtable-64.h>
++#else
++#include <asm/pgtable-32.h>
++#endif /* CONFIG_64BIT */
++
++/* Number of entries in the page global directory */
++#define PTRS_PER_PGD (PAGE_SIZE / sizeof(pgd_t))
++/* Number of entries in the page table */
++#define PTRS_PER_PTE (PAGE_SIZE / sizeof(pte_t))
++
++/* Number of PGD entries that a user-mode program can use */
++#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
++#define FIRST_USER_ADDRESS 0
++
++/* Page protection bits */
++#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER)
++
++#define PAGE_NONE __pgprot(0)
++#define PAGE_READ __pgprot(_PAGE_BASE | _PAGE_READ)
++#define PAGE_WRITE __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_WRITE)
++#define PAGE_EXEC __pgprot(_PAGE_BASE | _PAGE_EXEC)
++#define PAGE_READ_EXEC __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC)
++#define PAGE_WRITE_EXEC __pgprot(_PAGE_BASE | _PAGE_READ | \
++ _PAGE_EXEC | _PAGE_WRITE)
++
++#define PAGE_COPY PAGE_READ
++#define PAGE_COPY_EXEC PAGE_EXEC
++#define PAGE_COPY_READ_EXEC PAGE_READ_EXEC
++#define PAGE_SHARED PAGE_WRITE
++#define PAGE_SHARED_EXEC PAGE_WRITE_EXEC
++
++#define PAGE_KERNEL __pgprot(_PAGE_READ | _PAGE_WRITE | \
++ _PAGE_PRESENT | _PAGE_ACCESSED)
++
++#define swapper_pg_dir NULL
++
++/* MAP_PRIVATE permissions: xwr (copy-on-write) */
++#define __P000 PAGE_NONE
++#define __P001 PAGE_READ
++#define __P010 PAGE_COPY
++#define __P011 PAGE_COPY
++#define __P100 PAGE_EXEC
++#define __P101 PAGE_READ_EXEC
++#define __P110 PAGE_COPY_EXEC
++#define __P111 PAGE_COPY_READ_EXEC
++
++/* MAP_SHARED permissions: xwr */
++#define __S000 PAGE_NONE
++#define __S001 PAGE_READ
++#define __S010 PAGE_SHARED
++#define __S011 PAGE_SHARED
++#define __S100 PAGE_EXEC
++#define __S101 PAGE_READ_EXEC
++#define __S110 PAGE_SHARED_EXEC
++#define __S111 PAGE_SHARED_EXEC
++
++/*
++ * ZERO_PAGE is a global shared page that is always zero,
++ * used for zero-mapped memory areas, etc.
++ */
++extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
++#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
++
++static inline int pmd_present(pmd_t pmd)
++{
++ return (pmd_val(pmd) & _PAGE_PRESENT);
++}
++
++static inline int pmd_none(pmd_t pmd)
++{
++ return (pmd_val(pmd) == 0);
++}
++
++static inline int pmd_bad(pmd_t pmd)
++{
++ return !pmd_present(pmd);
++}
++
++static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
++{
++ *pmdp = pmd;
++}
++
++static inline void pmd_clear(pmd_t *pmdp)
++{
++ set_pmd(pmdp, __pmd(0));
++}
++
++
++#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
++
++/* Locate an entry in the page global directory */
++static inline pgd_t *pgd_offset(const struct mm_struct *mm, unsigned long addr)
++{
++ return mm->pgd + pgd_index(addr);
++}
++/* Locate an entry in the kernel page global directory */
++#define pgd_offset_k(addr) pgd_offset(&init_mm, (addr))
++
++static inline struct page *pmd_page(pmd_t pmd)
++{
++ return pfn_to_page(pmd_val(pmd) >> _PAGE_PFN_SHIFT);
++}
++
++static inline unsigned long pmd_page_vaddr(pmd_t pmd)
++{
++ return (unsigned long)pfn_to_virt(pmd_val(pmd) >> _PAGE_PFN_SHIFT);
++}
++
++/* Yields the page frame number (PFN) of a page table entry */
++static inline unsigned long pte_pfn(pte_t pte)
++{
++ return (pte_val(pte) >> _PAGE_PFN_SHIFT);
++}
++
++#define pte_page(x) pfn_to_page(pte_pfn(x))
++
++/* Constructs a page table entry */
++static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot)
++{
++ return __pte((pfn << _PAGE_PFN_SHIFT) | pgprot_val(prot));
++}
++
++static inline pte_t mk_pte(struct page *page, pgprot_t prot)
++{
++ return pfn_pte(page_to_pfn(page), prot);
++}
++
++#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
++
++static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long addr)
++{
++ return (pte_t *)pmd_page_vaddr(*pmd) + pte_index(addr);
++}
++
++#define pte_offset_map(dir, addr) pte_offset_kernel((dir), (addr))
++#define pte_unmap(pte) ((void)(pte))
++
++/*
++ * Certain architectures need to do special things when PTEs within
++ * a page table are directly modified. Thus, the following hook is
++ * made available.
++ */
++static inline void set_pte(pte_t *ptep, pte_t pteval)
++{
++ *ptep = pteval;
++}
++
++static inline void set_pte_at(struct mm_struct *mm,
++ unsigned long addr, pte_t *ptep, pte_t pteval)
++{
++ set_pte(ptep, pteval);
++}
++
++static inline void pte_clear(struct mm_struct *mm,
++ unsigned long addr, pte_t *ptep)
++{
++ set_pte_at(mm, addr, ptep, __pte(0));
++}
++
++static inline int pte_present(pte_t pte)
++{
++ return (pte_val(pte) & _PAGE_PRESENT);
++}
++
++static inline int pte_none(pte_t pte)
++{
++ return (pte_val(pte) == 0);
++}
++
++/* static inline int pte_read(pte_t pte) */
++
++static inline int pte_write(pte_t pte)
++{
++ return pte_val(pte) & _PAGE_WRITE;
++}
++
++static inline int pte_huge(pte_t pte)
++{
++ return pte_present(pte)
++ && (pte_val(pte) & (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC));
++}
++
++/* static inline int pte_exec(pte_t pte) */
++
++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 int pte_special(pte_t pte)
++{
++ return pte_val(pte) & _PAGE_SPECIAL;
++}
++
++/* static inline pte_t pte_rdprotect(pte_t pte) */
++
++static inline pte_t pte_wrprotect(pte_t pte)
++{
++ return __pte(pte_val(pte) & ~(_PAGE_WRITE));
++}
++
++/* static inline pte_t pte_mkread(pte_t pte) */
++
++static inline pte_t pte_mkwrite(pte_t pte)
++{
++ return __pte(pte_val(pte) | _PAGE_WRITE);
++}
++
++/* static inline pte_t pte_mkexec(pte_t pte) */
++
++static inline pte_t pte_mkdirty(pte_t pte)
++{
++ return __pte(pte_val(pte) | _PAGE_DIRTY);
++}
++
++static inline pte_t pte_mkclean(pte_t pte)
++{
++ return __pte(pte_val(pte) & ~(_PAGE_DIRTY));
++}
++
++static inline pte_t pte_mkyoung(pte_t pte)
++{
++ return __pte(pte_val(pte) & ~(_PAGE_ACCESSED));
++}
++
++static inline pte_t pte_mkold(pte_t pte)
++{
++ return __pte(pte_val(pte) | _PAGE_ACCESSED);
++}
++
++static inline pte_t pte_mkspecial(pte_t pte)
++{
++ return __pte(pte_val(pte) | _PAGE_SPECIAL);
++}
++
++/* Modify page protection bits */
++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
++{
++ return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot));
++}
++
++#define pgd_ERROR(e) \
++ pr_err("%s:%d: bad pgd " PTE_FMT ".\n", __FILE__, __LINE__, pgd_val(e))
++
++
++/* Commit new configuration to MMU hardware */
++static inline void update_mmu_cache(struct vm_area_struct *vma,
++ unsigned long address, pte_t *ptep)
++{
++}
++
++/*
++ * Encode and decode a swap entry
++ *
++ * Format of swap PTE:
++ * bit 0: _PAGE_PRESENT (zero)
++ * bit 1: reserved for future use (zero)
++ * bits 2 to 6: swap type
++ * bits 7 to XLEN-1: swap offset
++ */
++#define __SWP_TYPE_SHIFT 2
++#define __SWP_TYPE_BITS 5
++#define __SWP_TYPE_MASK ((1UL << __SWP_TYPE_BITS) - 1)
++#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
++
++#define MAX_SWAPFILES_CHECK() \
++ BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)
++
++#define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
++#define __swp_offset(x) ((x).val >> __SWP_OFFSET_SHIFT)
++#define __swp_entry(type, offset) ((swp_entry_t) \
++ { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })
++
++#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
++#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
++
++#ifdef CONFIG_FLATMEM
++#define kern_addr_valid(addr) (1) /* FIXME */
++#endif
++
++extern void paging_init(void);
++
++static inline void pgtable_cache_init(void)
++{
++ /* No page table caches to initialize */
++}
++
++#endif /* CONFIG_MMU */
++
++#define VMALLOC_SIZE _AC(0x8000000,UL)
++#define VMALLOC_END (PAGE_OFFSET - 1)
++#define VMALLOC_START (PAGE_OFFSET - VMALLOC_SIZE)
++
++/* Task size is 0x40000000000 for RV64 or 0xb800000 for RV32.
++ Note that PGDIR_SIZE must evenly divide TASK_SIZE. */
++#ifdef CONFIG_64BIT
++#define TASK_SIZE (PGDIR_SIZE * PTRS_PER_PGD / 2)
++#else
++#define TASK_SIZE VMALLOC_START
++#endif
++
++#include <asm-generic/pgtable.h>
++
++#endif /* !__ASSEMBLY__ */
++
++#endif /* _ASM_RISCV_PGTABLE_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/processor.h linux-4.6.2.riscv/arch/riscv/include/asm/processor.h
+--- linux-4.6.2/arch/riscv/include/asm/processor.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/processor.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,87 @@
++#ifndef _ASM_RISCV_PROCESSOR_H
++#define _ASM_RISCV_PROCESSOR_H
++
++#include <linux/const.h>
++
++#include <asm/ptrace.h>
++
++/*
++ * This decides where the kernel will search for a free chunk of vm
++ * space during mmap's.
++ */
++#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE >> 1)
++
++#ifdef __KERNEL__
++#define STACK_TOP TASK_SIZE
++#define STACK_TOP_MAX STACK_TOP
++#endif /* __KERNEL__ */
++
++#ifndef __ASSEMBLY__
++
++struct task_struct;
++struct pt_regs;
++
++/*
++ * Default implementation of macro that returns current
++ * instruction pointer ("program counter").
++ */
++#define current_text_addr() ({ __label__ _l; _l: &&_l;})
++
++/* CPU-specific state of a task */
++struct thread_struct {
++ /* Callee-saved registers */
++ unsigned long ra;
++ unsigned long sp; /* Kernel mode stack */
++ unsigned long s[12]; /* s[0]: frame pointer */
++ struct user_fpregs_struct fstate;
++};
++
++#define INIT_THREAD { \
++ .sp = sizeof(init_stack) + (long)&init_stack, \
++}
++
++/* Return saved (kernel) PC of a blocked thread. */
++#define thread_saved_pc(t) ((t)->thread.ra)
++#define thread_saved_sp(t) ((t)->thread.sp)
++#define thread_saved_fp(t) ((t)->thread.s[0])
++
++#define task_pt_regs(tsk) \
++ ((struct pt_regs *)(task_stack_page(tsk) + THREAD_SIZE) - 1)
++
++#define KSTK_EIP(tsk) (task_pt_regs(tsk)->sepc)
++#define KSTK_ESP(tsk) (task_pt_regs(tsk)->sp)
++
++
++/* Do necessary setup to start up a newly executed thread. */
++extern void start_thread(struct pt_regs *regs,
++ unsigned long pc, unsigned long sp);
++
++/* Free all resources held by a thread. */
++static inline void release_thread(struct task_struct *dead_task)
++{
++}
++
++/* Free current thread data structures, etc. */
++static inline void exit_thread(void)
++{
++}
++
++extern unsigned long get_wchan(struct task_struct *p);
++
++
++static inline void cpu_relax(void)
++{
++ int dummy;
++ /* In lieu of a halt instruction, induce a long-latency stall. */
++ __asm__ __volatile__ ("div %0, %0, zero" : "=r" (dummy));
++ barrier();
++}
++
++static inline void wait_for_interrupt(void)
++{
++ __asm__ __volatile__ ("wfi");
++}
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* _ASM_RISCV_PROCESSOR_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/ptrace.h linux-4.6.2.riscv/arch/riscv/include/asm/ptrace.h
+--- linux-4.6.2/arch/riscv/include/asm/ptrace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/ptrace.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,103 @@
++#ifndef _ASM_RISCV_PTRACE_H
++#define _ASM_RISCV_PTRACE_H
++
++#include <uapi/asm/ptrace.h>
++#include <asm/csr.h>
++
++#ifndef __ASSEMBLY__
++
++struct pt_regs {
++ unsigned long sepc;
++ unsigned long ra;
++ unsigned long sp;
++ unsigned long gp;
++ unsigned long tp;
++ unsigned long t0;
++ unsigned long t1;
++ unsigned long t2;
++ unsigned long s0;
++ unsigned long s1;
++ unsigned long a0;
++ unsigned long a1;
++ unsigned long a2;
++ unsigned long a3;
++ unsigned long a4;
++ unsigned long a5;
++ unsigned long a6;
++ unsigned long a7;
++ unsigned long s2;
++ unsigned long s3;
++ unsigned long s4;
++ unsigned long s5;
++ unsigned long s6;
++ unsigned long s7;
++ unsigned long s8;
++ unsigned long s9;
++ unsigned long s10;
++ unsigned long s11;
++ unsigned long t3;
++ unsigned long t4;
++ unsigned long t5;
++ unsigned long t6;
++ /* Supervisor CSRs */
++ unsigned long sstatus;
++ unsigned long sbadaddr;
++ unsigned long scause;
++};
++
++#ifdef CONFIG_64BIT
++#define REG_FMT "%016lx"
++#else
++#define REG_FMT "%08lx"
++#endif
++
++#define user_mode(regs) (((regs)->sstatus & SR_PS) == 0)
++
++
++/* Helpers for working with the instruction pointer */
++#define GET_IP(regs) ((regs)->sepc)
++#define SET_IP(regs, val) (GET_IP(regs) = (val))
++
++static inline unsigned long instruction_pointer(struct pt_regs *regs)
++{
++ return GET_IP(regs);
++}
++static inline void instruction_pointer_set(struct pt_regs *regs,
++ unsigned long val)
++{
++ SET_IP(regs, val);
++}
++
++#define profile_pc(regs) instruction_pointer(regs)
++
++/* Helpers for working with the user stack pointer */
++#define GET_USP(regs) ((regs)->sp)
++#define SET_USP(regs, val) (GET_USP(regs) = (val))
++
++static inline unsigned long user_stack_pointer(struct pt_regs *regs)
++{
++ return GET_USP(regs);
++}
++static inline void user_stack_pointer_set(struct pt_regs *regs,
++ unsigned long val)
++{
++ SET_USP(regs, val);
++}
++
++/* Helpers for working with the frame pointer */
++#define GET_FP(regs) ((regs)->s0)
++#define SET_FP(regs, val) (GET_FP(regs) = (val))
++
++static inline unsigned long frame_pointer(struct pt_regs *regs)
++{
++ return GET_FP(regs);
++}
++static inline void frame_pointer_set(struct pt_regs *regs,
++ unsigned long val)
++{
++ SET_FP(regs, val);
++}
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* _ASM_RISCV_PTRACE_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/sbi-con.h linux-4.6.2.riscv/arch/riscv/include/asm/sbi-con.h
+--- linux-4.6.2/arch/riscv/include/asm/sbi-con.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/sbi-con.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,8 @@
++#ifndef _ASM_RISCV_SBI_CON_H
++#define _ASM_RISCV_SBI_CON_H
++
++#include <linux/irqreturn.h>
++
++irqreturn_t sbi_console_isr(void);
++
++#endif /* _ASM_RISCV_SBI_CON_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/sbi.h linux-4.6.2.riscv/arch/riscv/include/asm/sbi.h
+--- linux-4.6.2/arch/riscv/include/asm/sbi.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/sbi.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,30 @@
++#ifndef _ASM_RISCV_SBI_H
++#define _ASM_RISCV_SBI_H
++
++typedef struct {
++ unsigned long base;
++ unsigned long size;
++ unsigned long node_id;
++} memory_block_info;
++
++unsigned long sbi_query_memory(unsigned long id, memory_block_info *p);
++
++unsigned long sbi_hart_id(void);
++unsigned long sbi_num_harts(void);
++unsigned long sbi_timebase(void);
++void sbi_set_timer(unsigned long long stime_value);
++void sbi_send_ipi(unsigned long hart_id);
++unsigned long sbi_clear_ipi(void);
++void sbi_shutdown(void);
++
++void sbi_console_putchar(unsigned char ch);
++int sbi_console_getchar(void);
++
++void sbi_remote_sfence_vm(unsigned long hart_mask_ptr, unsigned long asid);
++void sbi_remote_sfence_vm_range(unsigned long hart_mask_ptr, unsigned long asid, unsigned long start, unsigned long size);
++void sbi_remote_fence_i(unsigned long hart_mask_ptr);
++
++unsigned long sbi_mask_interrupt(unsigned long which);
++unsigned long sbi_unmask_interrupt(unsigned long which);
++
++#endif
+diff -Nur linux-4.6.2/arch/riscv/include/asm/serial.h linux-4.6.2.riscv/arch/riscv/include/asm/serial.h
+--- linux-4.6.2/arch/riscv/include/asm/serial.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/serial.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,29 @@
++#ifndef _ASM_RISCV_SERIAL_H
++#define _ASM_RISCV_SERIAL_H
++
++/*
++ * FIXME: interim serial support for riscv-qemu
++ *
++ * Currently requires that the emulator itself create a hole at addresses
++ * 0x3f8 - 0x3ff without looking through page tables.
++ *
++ * This assumes you have a 1.8432 MHz clock for your UART.
++ */
++#define BASE_BAUD ( 1843200 / 16 )
++
++/* Standard COM flags */
++#ifdef CONFIG_SERIAL_DETECT_IRQ
++#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
++#else
++#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
++#endif
++
++#define SERIAL_PORT_DFNS \
++ { /* ttyS0 */ \
++ .baud_base = BASE_BAUD, \
++ .port = 0x3F8, \
++ .irq = 4, \
++ .flags = STD_COM_FLAGS, \
++ },
++
++#endif /* _ASM_RISCV_SERIAL_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/setup.h linux-4.6.2.riscv/arch/riscv/include/asm/setup.h
+--- linux-4.6.2/arch/riscv/include/asm/setup.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/setup.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,6 @@
++#ifndef _ASM_RISCV_SETUP_H
++#define _ASM_RISCV_SETUP_H
++
++#include <asm-generic/setup.h>
++
++#endif /* _ASM_RISCV_SETUP_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/smp.h linux-4.6.2.riscv/arch/riscv/include/asm/smp.h
+--- linux-4.6.2/arch/riscv/include/asm/smp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/smp.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,28 @@
++#ifndef _ASM_RISCV_SMP_H
++#define _ASM_RISCV_SMP_H
++
++#include <linux/cpumask.h>
++#include <linux/irqreturn.h>
++
++#ifdef CONFIG_SMP
++
++/* SMP initialization hook for setup_arch */
++void __init init_clockevent(void);
++
++/* SMP initialization hook for setup_arch */
++void __init setup_smp(void);
++
++/* Hook for the generic smp_call_function_many() routine. */
++void arch_send_call_function_ipi_mask(struct cpumask *mask);
++
++/* Hook for the generic smp_call_function_single() routine. */
++void arch_send_call_function_single_ipi(int cpu);
++
++#define raw_smp_processor_id() (current_thread_info()->cpu)
++
++/* Interprocessor interrupt handler */
++irqreturn_t handle_ipi(void);
++
++#endif /* CONFIG_SMP */
++
++#endif /* _ASM_RISCV_SMP_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/spinlock.h linux-4.6.2.riscv/arch/riscv/include/asm/spinlock.h
+--- linux-4.6.2/arch/riscv/include/asm/spinlock.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/spinlock.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,142 @@
++#ifndef _ASM_RISCV_SPINLOCK_H
++#define _ASM_RISCV_SPINLOCK_H
++
++#include <linux/kernel.h>
++#include <asm/current.h>
++
++/*
++ * Simple spin lock operations. These provide no fairness guarantees.
++ */
++
++#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
++#define arch_spin_is_locked(x) ((x)->lock != 0)
++#define arch_spin_unlock_wait(x) \
++ do { cpu_relax(); } while ((x)->lock)
++
++static inline void arch_spin_unlock(arch_spinlock_t *lock)
++{
++ __asm__ __volatile__ (
++ "amoswap.w.rl x0, x0, %0"
++ : "=A" (lock->lock)
++ :: "memory");
++}
++
++static inline int arch_spin_trylock(arch_spinlock_t *lock)
++{
++ int tmp = 1, busy;
++
++ __asm__ __volatile__ (
++ "amoswap.w.aq %0, %2, %1"
++ : "=r" (busy), "+A" (lock->lock)
++ : "r" (tmp)
++ : "memory");
++
++ return !busy;
++}
++
++static inline void arch_spin_lock(arch_spinlock_t *lock)
++{
++ while (1) {
++ if (arch_spin_is_locked(lock))
++ continue;
++
++ if (arch_spin_trylock(lock))
++ break;
++ }
++}
++
++/***********************************************************/
++
++static inline int arch_read_can_lock(arch_rwlock_t *lock)
++{
++ return lock->lock >= 0;
++}
++
++static inline int arch_write_can_lock(arch_rwlock_t *lock)
++{
++ return lock->lock == 0;
++}
++
++static inline void arch_read_lock(arch_rwlock_t *lock)
++{
++ int tmp;
++
++ __asm__ __volatile__(
++ "1: lr.w %1, %0\n"
++ " bltz %1, 1b\n"
++ " addi %1, %1, 1\n"
++ " sc.w.aq %1, %1, %0\n"
++ " bnez %1, 1b\n"
++ : "+A" (lock->lock), "=&r" (tmp)
++ :: "memory");
++}
++
++static inline void arch_write_lock(arch_rwlock_t *lock)
++{
++ int tmp;
++
++ __asm__ __volatile__(
++ "1: lr.w %1, %0\n"
++ " bnez %1, 1b\n"
++ " li %1, -1\n"
++ " sc.w.aq %1, %1, %0\n"
++ " bnez %1, 1b\n"
++ : "+A" (lock->lock), "=&r" (tmp)
++ :: "memory");
++}
++
++static inline int arch_read_trylock(arch_rwlock_t * lock)
++{
++ int busy;
++
++ __asm__ __volatile__(
++ "1: lr.w %1, %0\n"
++ " bltz %1, 1f\n"
++ " addi %1, %1, 1\n"
++ " sc.w.aq %1, %1, %0\n"
++ " bnez %1, 1b\n"
++ "1:\n"
++ : "+A" (lock->lock), "=&r" (busy)
++ :: "memory");
++
++ return !busy;
++}
++
++static inline int arch_write_trylock(arch_rwlock_t * lock)
++{
++ int busy;
++
++ __asm__ __volatile__(
++ "1: lr.w %1, %0\n"
++ " bnez %1, 1f\n"
++ " li %1, -1\n"
++ " sc.w.aq %1, %1, %0\n"
++ " bnez %1, 1b\n"
++ "1:\n"
++ : "+A" (lock->lock), "=&r" (busy)
++ :: "memory");
++
++ return !busy;
++}
++
++static inline void arch_read_unlock(arch_rwlock_t * lock)
++{
++ __asm__ __volatile__(
++ "amoadd.w.rl x0, %1, %0"
++ : "+A" (lock->lock)
++ : "r" (-1)
++ : "memory");
++}
++
++static inline void arch_write_unlock(arch_rwlock_t * lock)
++{
++ __asm__ __volatile__ (
++ "amoswap.w.rl x0, x0, %0"
++ : "=A" (lock->lock)
++ :: "memory");
++}
++
++#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
++#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
++
++#endif /* _ASM_RISCV_SPINLOCK_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/spinlock_types.h linux-4.6.2.riscv/arch/riscv/include/asm/spinlock_types.h
+--- linux-4.6.2/arch/riscv/include/asm/spinlock_types.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/spinlock_types.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,20 @@
++#ifndef _ASM_RISCV_SPINLOCK_TYPES_H
++#define _ASM_RISCV_SPINLOCK_TYPES_H
++
++#ifndef __LINUX_SPINLOCK_TYPES_H
++# error "please don't include this file directly"
++#endif
++
++typedef struct {
++ volatile unsigned int lock;
++} arch_spinlock_t;
++
++#define __ARCH_SPIN_LOCK_UNLOCKED { 0 }
++
++typedef struct {
++ volatile unsigned int lock;
++} arch_rwlock_t;
++
++#define __ARCH_RW_LOCK_UNLOCKED { 0 }
++
++#endif
+diff -Nur linux-4.6.2/arch/riscv/include/asm/string.h linux-4.6.2.riscv/arch/riscv/include/asm/string.h
+--- linux-4.6.2/arch/riscv/include/asm/string.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/string.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,17 @@
++#ifndef _ASM_RISCV_STRING_H
++#define _ASM_RISCV_STRING_H
++
++#ifdef __KERNEL__
++
++#include <linux/types.h>
++#include <linux/linkage.h>
++
++#define __HAVE_ARCH_MEMSET
++extern asmlinkage void *memset(void *, int, size_t);
++
++#define __HAVE_ARCH_MEMCPY
++extern asmlinkage void *memcpy(void *, const void *, size_t);
++
++#endif /* __KERNEL__ */
++
++#endif /* _ASM_RISCV_STRING_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/switch_to.h linux-4.6.2.riscv/arch/riscv/include/asm/switch_to.h
+--- linux-4.6.2/arch/riscv/include/asm/switch_to.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/switch_to.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,57 @@
++#ifndef _ASM_RISCV_SWITCH_TO_H
++#define _ASM_RISCV_SWITCH_TO_H
++
++#include <asm/processor.h>
++#include <asm/ptrace.h>
++#include <asm/csr.h>
++
++extern void __fstate_save(struct task_struct *);
++extern void __fstate_restore(struct task_struct *);
++
++static inline void __fstate_clean(struct pt_regs *regs)
++{
++ regs->sstatus |= (regs->sstatus & ~(SR_FS)) | SR_FS_CLEAN;
++}
++
++static inline void fstate_save(struct task_struct *task,
++ struct pt_regs *regs)
++{
++ if ((regs->sstatus & SR_FS) == SR_FS_DIRTY) {
++ __fstate_save(task);
++ __fstate_clean(regs);
++ }
++}
++
++static inline void fstate_restore(struct task_struct *task,
++ struct pt_regs *regs)
++{
++ if ((regs->sstatus & SR_FS) != SR_FS_OFF) {
++ __fstate_restore(task);
++ __fstate_clean(regs);
++ }
++}
++
++static inline void __switch_to_aux(struct task_struct *prev,
++ struct task_struct *next)
++{
++ struct pt_regs *regs;
++
++ regs = task_pt_regs(prev);
++ if (unlikely(regs->sstatus & SR_SD)) {
++ fstate_save(prev, regs);
++ }
++ fstate_restore(next, task_pt_regs(next));
++}
++
++extern struct task_struct *__switch_to(struct task_struct *,
++ struct task_struct *);
++
++#define switch_to(prev, next, last) \
++do { \
++ struct task_struct *__prev = (prev); \
++ struct task_struct *__next = (next); \
++ __switch_to_aux(__prev, __next); \
++ ((last) = __switch_to(__prev, __next)); \
++} while (0)
++
++#endif /* _ASM_RISCV_SWITCH_TO_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/syscall.h linux-4.6.2.riscv/arch/riscv/include/asm/syscall.h
+--- linux-4.6.2/arch/riscv/include/asm/syscall.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/syscall.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,90 @@
++/*
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright 2010 Tilera Corporation. All Rights Reserved.
++ * Copyright 2015 Regents of the University of California, Berkeley
++ *
++ * 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, version 2.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
++ * NON INFRINGEMENT. See the GNU General Public License for
++ * more details.
++ *
++ * See asm-generic/syscall.h for descriptions of what we must do here.
++ */
++
++#ifndef _ASM_RISCV_SYSCALL_H
++#define _ASM_RISCV_SYSCALL_H
++
++#include <linux/sched.h>
++#include <linux/err.h>
++
++/* The array of function pointers for syscalls. */
++extern void *sys_call_table[];
++
++/*
++ * Only the low 32 bits of orig_r0 are meaningful, so we return int.
++ * This importantly ignores the high bits on 64-bit, so comparisons
++ * sign-extend the low 32 bits.
++ */
++static inline int syscall_get_nr(struct task_struct *task,
++ struct pt_regs *regs)
++{
++ return regs->a7;
++}
++
++static inline void syscall_set_nr(struct task_struct *task,
++ struct pt_regs *regs,
++ int sysno)
++{
++ regs->a7 = sysno;
++}
++
++static inline void syscall_rollback(struct task_struct *task,
++ struct pt_regs *regs)
++{
++ /* FIXME: We can't do this... */
++}
++
++static inline long syscall_get_error(struct task_struct *task,
++ struct pt_regs *regs)
++{
++ unsigned long error = regs->a0;
++ return IS_ERR_VALUE(error) ? error : 0;
++}
++
++static inline long syscall_get_return_value(struct task_struct *task,
++ struct pt_regs *regs)
++{
++ return regs->a0;
++}
++
++static inline void syscall_set_return_value(struct task_struct *task,
++ struct pt_regs *regs,
++ int error, long val)
++{
++ regs->a0 = (long) error ?: val;
++}
++
++static inline void syscall_get_arguments(struct task_struct *task,
++ struct pt_regs *regs,
++ unsigned int i, unsigned int n,
++ unsigned long *args)
++{
++ BUG_ON(i + n > 6);
++ memcpy(args, &regs->a0 + i * sizeof(regs->a0), n * sizeof(args[0]));
++}
++
++static inline void syscall_set_arguments(struct task_struct *task,
++ struct pt_regs *regs,
++ unsigned int i, unsigned int n,
++ const unsigned long *args)
++{
++ BUG_ON(i + n > 6);
++ memcpy(&regs->a0 + i * sizeof(regs->a0), args, n * sizeof(regs->a0));
++}
++
++#endif /* _ASM_TILE_SYSCALL_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/syscalls.h linux-4.6.2.riscv/arch/riscv/include/asm/syscalls.h
+--- linux-4.6.2/arch/riscv/include/asm/syscalls.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/syscalls.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,12 @@
++#ifndef _ASM_RISCV_SYSCALLS_H
++#define _ASM_RISCV_SYSCALLS_H
++
++#include <linux/linkage.h>
++
++#include <asm-generic/syscalls.h>
++
++/* kernel/sys_riscv.c */
++asmlinkage long sys_sysriscv(unsigned long, unsigned long,
++ unsigned long, unsigned long);
++
++#endif /* _ASM_RISCV_SYSCALLS_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/thread_info.h linux-4.6.2.riscv/arch/riscv/include/asm/thread_info.h
+--- linux-4.6.2/arch/riscv/include/asm/thread_info.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/thread_info.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,89 @@
++#ifndef _ASM_RISCV_THREAD_INFO_H
++#define _ASM_RISCV_THREAD_INFO_H
++
++#ifdef __KERNEL__
++
++#include <asm/page.h>
++#include <linux/const.h>
++
++/* thread information allocation */
++#define THREAD_SIZE_ORDER (1)
++#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
++
++#ifndef __ASSEMBLY__
++
++#include <asm/processor.h>
++#include <asm/csr.h>
++
++typedef unsigned long mm_segment_t;
++
++/*
++ * low level task data that entry.S needs immediate access to
++ * - this struct should fit entirely inside of one cache line
++ * - this struct resides at the bottom of the supervisor stack
++ * - if the members of this struct changes, the assembly constants
++ * in asm-offsets.c must be updated accordingly
++ */
++struct thread_info {
++ struct task_struct *task; /* main task structure */
++ unsigned long flags; /* low level flags */
++ __u32 cpu; /* current CPU */
++ int preempt_count; /* 0 => preemptable, <0 => BUG */
++ mm_segment_t addr_limit;
++};
++
++/*
++ * macros/functions for gaining access to the thread information structure
++ *
++ * preempt_count needs to be 1 initially, until the scheduler is functional.
++ */
++#define INIT_THREAD_INFO(tsk) \
++{ \
++ .task = &tsk, \
++ .flags = 0, \
++ .cpu = 0, \
++ .preempt_count = INIT_PREEMPT_COUNT, \
++ .addr_limit = KERNEL_DS, \
++}
++
++#define init_thread_info (init_thread_union.thread_info)
++#define init_stack (init_thread_union.stack)
++
++/*
++ * Pointer to the thread_info struct of the current process
++ * Assumes that the kernel mode stack (thread_union) is THREAD_SIZE-aligned
++ */
++static inline struct thread_info *current_thread_info(void)
++{
++ register unsigned long sp __asm__ ("sp");
++ return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
++}
++
++#endif /* !__ASSEMBLY__ */
++
++/*
++ * thread information flags
++ * - these are process state flags that various assembly files may need to
++ * access
++ * - pending work-to-be-done flags are in lowest half-word
++ * - other flags in upper half-word(s)
++ */
++#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
++#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
++#define TIF_SIGPENDING 2 /* signal pending */
++#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
++#define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */
++#define TIF_MEMDIE 5 /* is terminating due to OOM killer */
++#define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */
++
++#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_WORK_MASK \
++ (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED)
++
++#endif /* __KERNEL__ */
++
++#endif /* _ASM_RISCV_THREAD_INFO_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/timex.h linux-4.6.2.riscv/arch/riscv/include/asm/timex.h
+--- linux-4.6.2/arch/riscv/include/asm/timex.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/timex.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,39 @@
++#ifndef _ASM_RISCV_TIMEX_H
++#define _ASM_RISCV_TIMEX_H
++
++#include <asm/param.h>
++
++#define CLOCK_TICK_RATE (HZ * 100UL)
++
++typedef unsigned long cycles_t;
++
++static inline cycles_t get_cycles(void)
++{
++#if __riscv_xlen >= 64
++ cycles_t n;
++ __asm__ __volatile__ (
++ "rdtime %0"
++ : "=r" (n));
++ return n;
++#else
++ u32 lo, hi, tmp;
++ __asm__ __volatile__ (
++ "1:\n"
++ "rdtimeh %0\n"
++ "rdtime %1\n"
++ "rdtimeh %2\n"
++ "bne %0, %2, 1b"
++ : "=&r" (hi), "=&r" (lo), "=&r" (tmp));
++ return ((u64)hi << 32) | lo;
++#endif
++}
++
++#define ARCH_HAS_READ_CURRENT_TIMER
++
++static inline int read_current_timer(unsigned long *timer_val)
++{
++ *timer_val = get_cycles();
++ return 0;
++}
++
++#endif /* _ASM_RISCV_TIMEX_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/tlbflush.h linux-4.6.2.riscv/arch/riscv/include/asm/tlbflush.h
+--- linux-4.6.2/arch/riscv/include/asm/tlbflush.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/tlbflush.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,84 @@
++#ifndef _ASM_RISCV_TLBFLUSH_H
++#define _ASM_RISCV_TLBFLUSH_H
++
++#ifdef CONFIG_MMU
++
++#include <linux/mm.h>
++#include <linux/bug.h>
++#include <asm/csr.h>
++
++/* Flush entire local TLB */
++static inline void local_flush_tlb_all(void)
++{
++ __asm__ __volatile__ ("sfence.vm");
++}
++
++/* Flush one page from local TLB */
++static inline void local_flush_tlb_page(unsigned long addr)
++{
++ __asm__ __volatile__ ("sfence.vm %0" : : "r" (addr));
++}
++
++#ifndef CONFIG_SMP
++
++#define flush_tlb_all() local_flush_tlb_all()
++#define flush_tlb_page(vma, addr) local_flush_tlb_page(addr)
++#define flush_tlb_range(vma, start, end) local_flush_tlb_all()
++
++#else /* CONFIG_SMP */
++
++#include <asm/sbi.h>
++
++#define flush_tlb_all() sbi_remote_sfence_vm(0, 0)
++#define flush_tlb_page(vma, addr) flush_tlb_range(vma, (addr), (addr) + 1)
++#define flush_tlb_range(vma, start, end) \
++ sbi_remote_sfence_vm_range(0, 0, (start), (end) - (start))
++
++#endif /* CONFIG_SMP */
++
++/* Flush the TLB entries of the specified mm context */
++static inline void flush_tlb_mm(struct mm_struct *mm)
++{
++ flush_tlb_all();
++}
++
++/* Flush a range of kernel pages */
++static inline void flush_tlb_kernel_range(unsigned long start,
++ unsigned long end)
++{
++ flush_tlb_all();
++}
++
++#else /* !CONFIG_MMU */
++
++static inline void flush_tlb_all(void)
++{
++ BUG();
++}
++
++static inline void flush_tlb_mm(struct mm_struct *mm)
++{
++ BUG();
++}
++
++static inline void flush_tlb_page(struct vm_area_struct *vma,
++ unsigned long addr)
++{
++ BUG();
++}
++
++static inline void flush_tlb_range(struct vm_area_struct *vma,
++ unsigned long start, unsigned long end)
++{
++ BUG();
++}
++
++static inline void flush_tlb_kernel_range(unsigned long start,
++ unsigned long end)
++{
++ BUG();
++}
++
++#endif /* CONFIG_MMU */
++
++#endif /* _ASM_RISCV_TLBFLUSH_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/tlb.h linux-4.6.2.riscv/arch/riscv/include/asm/tlb.h
+--- linux-4.6.2/arch/riscv/include/asm/tlb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/tlb.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,11 @@
++#ifndef _ASM_RISCV_TLB_H
++#define _ASM_RISCV_TLB_H
++
++#include <asm-generic/tlb.h>
++
++static inline void tlb_flush(struct mmu_gather *tlb)
++{
++ flush_tlb_mm(tlb->mm);
++}
++
++#endif /* _ASM_RISCV_TLB_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/uaccess.h linux-4.6.2.riscv/arch/riscv/include/asm/uaccess.h
+--- linux-4.6.2/arch/riscv/include/asm/uaccess.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/uaccess.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,460 @@
++#ifndef _ASM_RISCV_UACCESS_H
++#define _ASM_RISCV_UACCESS_H
++
++/*
++ * User space memory access functions
++ */
++#include <linux/errno.h>
++#include <linux/compiler.h>
++#include <linux/thread_info.h>
++#include <asm/byteorder.h>
++#include <asm/asm.h>
++
++#ifdef CONFIG_RV_PUM
++#define __enable_user_access() \
++ __asm__ __volatile__ ("csrc sstatus, %0" : : "r" (SR_PUM))
++#define __disable_user_access() \
++ __asm__ __volatile__ ("csrs sstatus, %0" : : "r" (SR_PUM))
++#else
++#define __enable_user_access()
++#define __disable_user_access()
++#endif
++
++/*
++ * The fs value determines whether argument validity checking should be
++ * performed or not. If get_fs() == USER_DS, checking is performed, with
++ * get_fs() == KERNEL_DS, checking is bypassed.
++ *
++ * For historical reasons, these macros are grossly misnamed.
++ */
++
++#define KERNEL_DS (~0UL)
++#define USER_DS (TASK_SIZE)
++
++#define get_ds() (KERNEL_DS)
++#define get_fs() (current_thread_info()->addr_limit)
++
++static inline void set_fs(mm_segment_t fs)
++{
++ current_thread_info()->addr_limit = fs;
++}
++
++#define segment_eq(a, b) ((a) == (b))
++
++#define user_addr_max() (get_fs())
++
++
++#define VERIFY_READ 0
++#define VERIFY_WRITE 1
++
++/**
++ * access_ok: - Checks if a user space pointer is valid
++ * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that
++ * %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
++ * to write to a block, it is always safe to read from it.
++ * @addr: User space pointer to start of block to check
++ * @size: Size of block to check
++ *
++ * Context: User context only. This function may sleep.
++ *
++ * Checks if a pointer to a block of memory in user space is valid.
++ *
++ * Returns true (nonzero) if the memory block may be valid, false (zero)
++ * if it is definitely invalid.
++ *
++ * Note that, depending on architecture, this function probably just
++ * checks that the pointer is in the user space range - after calling
++ * this function, memory access functions may still return -EFAULT.
++ */
++#define access_ok(type, addr, size) ({ \
++ __chk_user_ptr(addr); \
++ likely(__access_ok((unsigned long __force)(addr), (size))); \
++})
++
++/* Ensure that the range [addr, addr+size) is within the process's
++ * address space
++ */
++static inline int __access_ok(unsigned long addr, unsigned long size)
++{
++ const mm_segment_t fs = get_fs();
++ return (size <= fs) && (addr <= (fs - size));
++}
++
++/*
++ * The exception table consists of pairs of addresses: the first is the
++ * address of an instruction that is allowed to fault, and the second is
++ * the address at which the program should continue. No registers are
++ * modified, so it is entirely up to the continuation code to figure out
++ * what to do.
++ *
++ * All the routines below use bits of fixup code that are out of line
++ * with the main instruction path. This means when everything is well,
++ * we don't even have to jump over them. Further, they do not intrude
++ * on our cache or tlb entries.
++ */
++
++struct exception_table_entry {
++ unsigned long insn, fixup;
++};
++
++extern int fixup_exception(struct pt_regs *);
++
++#if defined(__LITTLE_ENDIAN)
++#define __MSW 1
++#define __LSW 0
++#elif defined(__BIG_ENDIAN)
++#define __MSW 0
++#define __LSW 1
++#else
++#error "Unknown endianness"
++#endif
++
++/*
++ * The "__xxx" versions of the user access functions do not verify the address
++ * space - it must have been done previously with a separate "access_ok()"
++ * call.
++ */
++
++#ifdef CONFIG_MMU
++#define __get_user_asm(insn, x, ptr, err) \
++do { \
++ uintptr_t __tmp; \
++ __enable_user_access(); \
++ __asm__ __volatile__ ( \
++ "1:\n" \
++ " " insn " %1, %3\n" \
++ "2:\n" \
++ " .section .fixup,\"ax\"\n" \
++ " .balign 4\n" \
++ "3:\n" \
++ " li %0, %4\n" \
++ " li %1, 0\n" \
++ " jump 2b, %2\n" \
++ " .previous\n" \
++ " .section __ex_table,\"a\"\n" \
++ " .balign " SZPTR "\n" \
++ " " PTR " 1b, 3b\n" \
++ " .previous" \
++ : "+r" (err), "=&r" (x), "=r" (__tmp) \
++ : "m" (*(ptr)), "i" (-EFAULT)); \
++ __disable_user_access(); \
++} while (0)
++#else /* !CONFIG_MMU */
++#define __get_user_asm(insn, x, ptr, err) \
++ __asm__ __volatile__ ( \
++ insn " %0, %1" \
++ : "=r" (x) \
++ : "m" (*(ptr)))
++#endif /* CONFIG_MMU */
++
++
++#ifdef CONFIG_64BIT
++#define __get_user_8(x, ptr, err) \
++ __get_user_asm("ld", x, ptr, err)
++#else /* !CONFIG_64BIT */
++#ifdef CONFIG_MMU
++#define __get_user_8(x, ptr, err) \
++do { \
++ u32 __user *__ptr = (u32 __user *)(ptr); \
++ u32 __lo, __hi; \
++ uintptr_t __tmp; \
++ __enable_user_access(); \
++ __asm__ __volatile__ ( \
++ "1:\n" \
++ " lw %1, %4\n" \
++ "2:\n" \
++ " lw %2, %5\n" \
++ "3:\n" \
++ " .section .fixup,\"ax\"\n" \
++ " .balign 4\n" \
++ "4:\n" \
++ " li %0, %6\n" \
++ " li %1, 0\n" \
++ " li %2, 0\n" \
++ " jump 3b, %3\n" \
++ " .previous\n" \
++ " .section __ex_table,\"a\"\n" \
++ " .balign " SZPTR "\n" \
++ " " PTR " 1b, 4b\n" \
++ " " PTR " 2b, 4b\n" \
++ " .previous" \
++ : "+r" (err), "=&r" (__lo), "=r" (__hi), \
++ "=r" (__tmp) \
++ : "m" (__ptr[__LSW]), "m" (__ptr[__MSW]), \
++ "i" (-EFAULT)); \
++ __disable_user_access(); \
++ (x) = (__typeof__(x))((__typeof__((x)-(x)))( \
++ (((u64)__hi << 32) | __lo))); \
++} while (0)
++#else /* !CONFIG_MMU */
++#define __get_user_8(x, ptr, err) \
++ (x) = (__typeof__(x))(*((u64 __user *)(ptr)))
++#endif /* CONFIG_MMU */
++#endif /* CONFIG_64BIT */
++
++
++/**
++ * __get_user: - Get a simple variable from user space, with less checking.
++ * @x: Variable to store result.
++ * @ptr: Source address, in user space.
++ *
++ * Context: User context only. This function may sleep.
++ *
++ * This macro copies a single simple variable from user space to kernel
++ * space. It supports simple types like char and int, but not larger
++ * data types like structures or arrays.
++ *
++ * @ptr must have pointer-to-simple-variable type, and the result of
++ * dereferencing @ptr must be assignable to @x without a cast.
++ *
++ * Caller must check the pointer with access_ok() before calling this
++ * function.
++ *
++ * Returns zero on success, or -EFAULT on error.
++ * On error, the variable @x is set to zero.
++ */
++#define __get_user(x, ptr) \
++({ \
++ register int __gu_err = 0; \
++ const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
++ __chk_user_ptr(__gu_ptr); \
++ switch (sizeof(*__gu_ptr)) { \
++ case 1: \
++ __get_user_asm("lb", (x), __gu_ptr, __gu_err); \
++ break; \
++ case 2: \
++ __get_user_asm("lh", (x), __gu_ptr, __gu_err); \
++ break; \
++ case 4: \
++ __get_user_asm("lw", (x), __gu_ptr, __gu_err); \
++ break; \
++ case 8: \
++ __get_user_8((x), __gu_ptr, __gu_err); \
++ break; \
++ default: \
++ BUILD_BUG(); \
++ } \
++ __gu_err; \
++})
++
++/**
++ * get_user: - Get a simple variable from user space.
++ * @x: Variable to store result.
++ * @ptr: Source address, in user space.
++ *
++ * Context: User context only. This function may sleep.
++ *
++ * This macro copies a single simple variable from user space to kernel
++ * space. It supports simple types like char and int, but not larger
++ * data types like structures or arrays.
++ *
++ * @ptr must have pointer-to-simple-variable type, and the result of
++ * dereferencing @ptr must be assignable to @x without a cast.
++ *
++ * Returns zero on success, or -EFAULT on error.
++ * On error, the variable @x is set to zero.
++ */
++#define get_user(x, ptr) \
++({ \
++ const __typeof__(*(ptr)) __user *__p = (ptr); \
++ might_fault(); \
++ access_ok(VERIFY_READ, __p, sizeof(*__p)) ? \
++ __get_user((x), __p) : \
++ ((x) = 0, -EFAULT); \
++})
++
++
++#ifdef CONFIG_MMU
++#define __put_user_asm(insn, x, ptr, err) \
++do { \
++ uintptr_t __tmp; \
++ __typeof__(*(ptr)) __x = x; \
++ __enable_user_access(); \
++ __asm__ __volatile__ ( \
++ "1:\n" \
++ " " insn " %z3, %2\n" \
++ "2:\n" \
++ " .section .fixup,\"ax\"\n" \
++ " .balign 4\n" \
++ "3:\n" \
++ " li %0, %4\n" \
++ " jump 2b, %1\n" \
++ " .previous\n" \
++ " .section __ex_table,\"a\"\n" \
++ " .balign " SZPTR "\n" \
++ " " PTR " 1b, 3b\n" \
++ " .previous" \
++ : "+r" (err), "=r" (__tmp), "=m" (*(ptr)) \
++ : "rJ" (__x), "i" (-EFAULT)); \
++ __disable_user_access(); \
++} while (0)
++#else /* !CONFIG_MMU */
++#define __put_user_asm(insn, x, ptr, err) \
++ __asm__ __volatile__ ( \
++ insn " %z1, %0" \
++ : "=m" (*(ptr)) \
++ : "rJ" ((__typeof__(*(ptr))) x))
++#endif /* CONFIG_MMU */
++
++
++#ifdef CONFIG_64BIT
++#define __put_user_8(x, ptr, err) \
++ __put_user_asm("sd", x, ptr, err)
++#else /* !CONFIG_64BIT */
++#ifdef CONFIG_MMU
++#define __put_user_8(x, ptr, err) \
++do { \
++ u32 __user *__ptr = (u32 __user *)(ptr); \
++ u64 __x = (__typeof__((x)-(x)))(x); \
++ uintptr_t __tmp; \
++ __enable_user_access(); \
++ __asm__ __volatile__ ( \
++ "1:\n" \
++ " sw %z4, %2\n" \
++ "2:\n" \
++ " sw %z5, %3\n" \
++ "3:\n" \
++ " .section .fixup,\"ax\"\n" \
++ " .balign 4\n" \
++ "4:\n" \
++ " li %0, %6\n" \
++ " jump 2b, %1\n" \
++ " .previous\n" \
++ " .section __ex_table,\"a\"\n" \
++ " .balign " SZPTR "\n" \
++ " " PTR " 1b, 4b\n" \
++ " " PTR " 2b, 4b\n" \
++ " .previous" \
++ : "+r" (err), "=r" (__tmp), \
++ "=m" (__ptr[__LSW]), \
++ "=m" (__ptr[__MSW]) \
++ : "rJ" (__x), "rJ" (__x >> 32), "i" (-EFAULT)); \
++ __disable_user_access(); \
++} while (0)
++#else /* !CONFIG_MMU */
++#define __put_user_8(x, ptr, err) \
++ *((u64 __user *)(ptr)) = (u64)(x)
++#endif /* CONFIG_MMU */
++#endif /* CONFIG_64BIT */
++
++
++/**
++ * __put_user: - Write a simple value into user space, with less checking.
++ * @x: Value to copy to user space.
++ * @ptr: Destination address, in user space.
++ *
++ * Context: User context only. This function may sleep.
++ *
++ * This macro copies a single simple value from kernel space to user
++ * space. It supports simple types like char and int, but not larger
++ * data types like structures or arrays.
++ *
++ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
++ * to the result of dereferencing @ptr.
++ *
++ * Caller must check the pointer with access_ok() before calling this
++ * function.
++ *
++ * Returns zero on success, or -EFAULT on error.
++ */
++#define __put_user(x, ptr) \
++({ \
++ register int __pu_err = 0; \
++ __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
++ __chk_user_ptr(__gu_ptr); \
++ switch (sizeof(*__gu_ptr)) { \
++ case 1: \
++ __put_user_asm("sb", (x), __gu_ptr, __pu_err); \
++ break; \
++ case 2: \
++ __put_user_asm("sh", (x), __gu_ptr, __pu_err); \
++ break; \
++ case 4: \
++ __put_user_asm("sw", (x), __gu_ptr, __pu_err); \
++ break; \
++ case 8: \
++ __put_user_8((x), __gu_ptr, __pu_err); \
++ break; \
++ default: \
++ BUILD_BUG(); \
++ } \
++ __pu_err; \
++})
++
++/**
++ * put_user: - Write a simple value into user space.
++ * @x: Value to copy to user space.
++ * @ptr: Destination address, in user space.
++ *
++ * Context: User context only. This function may sleep.
++ *
++ * This macro copies a single simple value from kernel space to user
++ * space. It supports simple types like char and int, but not larger
++ * data types like structures or arrays.
++ *
++ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
++ * to the result of dereferencing @ptr.
++ *
++ * Returns zero on success, or -EFAULT on error.
++ */
++#define put_user(x, ptr) \
++({ \
++ __typeof__(*(ptr)) __user *__p = (ptr); \
++ might_fault(); \
++ access_ok(VERIFY_WRITE, __p, sizeof(*__p)) ? \
++ __put_user((x), __p) : \
++ -EFAULT; \
++})
++
++
++extern unsigned long __must_check __copy_user(void __user *to,
++ const void __user *from, unsigned long n);
++
++static inline long __must_check __copy_from_user(void *to,
++ const void __user *from, unsigned long n)
++{
++ return __copy_user(to, from, n);
++}
++
++static inline long __must_check __copy_to_user(void __user *to,
++ const void *from, unsigned long n)
++{
++ return __copy_user(to, from, n);
++}
++
++#define __copy_from_user_inatomic(to, from, n) \
++ __copy_from_user((to), (from), (n))
++#define __copy_to_user_inatomic(to, from, n) \
++ __copy_to_user((to), (from), (n))
++
++static inline long copy_from_user(void *to,
++ const void __user * from, unsigned long n)
++{
++ might_fault();
++ return access_ok(VERIFY_READ, from, n) ?
++ __copy_from_user(to, from, n) : n;
++}
++
++static inline long copy_to_user(void __user *to,
++ const void *from, unsigned long n)
++{
++ might_fault();
++ return access_ok(VERIFY_WRITE, to, n) ?
++ __copy_to_user(to, from, n) : n;
++}
++
++extern long strncpy_from_user(char *dest, const char __user *src, long count);
++
++extern long __must_check strlen_user(const char __user *str);
++extern long __must_check strnlen_user(const char __user *str, long n);
++
++extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
++
++static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
++{
++ might_fault();
++ return access_ok(VERIFY_WRITE, to, n) ?
++ __clear_user(to, n) : n;
++}
++
++#endif /* _ASM_RISCV_UACCESS_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/unistd.h linux-4.6.2.riscv/arch/riscv/include/asm/unistd.h
+--- linux-4.6.2/arch/riscv/include/asm/unistd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/unistd.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,3 @@
++#define __ARCH_HAVE_MMU
++#define __ARCH_WANT_SYS_CLONE
++#include <uapi/asm/unistd.h>
+diff -Nur linux-4.6.2/arch/riscv/include/asm/vdso.h linux-4.6.2.riscv/arch/riscv/include/asm/vdso.h
+--- linux-4.6.2/arch/riscv/include/asm/vdso.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/vdso.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,15 @@
++#ifndef _ASM_RISCV_VDSO_H
++#define _ASM_RISCV_VDSO_H
++
++#include <linux/types.h>
++
++struct vdso_data {
++};
++
++#define VDSO_SYMBOL(base, name) \
++({ \
++ extern const char __vdso_##name[]; \
++ (void __user *)((unsigned long)(base) + __vdso_##name); \
++})
++
++#endif /* _ASM_RISCV_VDSO_H */
+diff -Nur linux-4.6.2/arch/riscv/include/asm/word-at-a-time.h linux-4.6.2.riscv/arch/riscv/include/asm/word-at-a-time.h
+--- linux-4.6.2/arch/riscv/include/asm/word-at-a-time.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/asm/word-at-a-time.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,42 @@
++#ifndef _ASM_RISCV_WORD_AT_A_TIME_H
++#define _ASM_RISCV_WORD_AT_A_TIME_H
++
++/* Derived from arch/x86/include/asm/word-at-a-time.h */
++
++#include <linux/kernel.h>
++
++struct word_at_a_time {
++ const unsigned long one_bits, high_bits;
++};
++
++#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
++
++static inline unsigned long has_zero(unsigned long val,
++ unsigned long *bits, const struct word_at_a_time *c)
++{
++ unsigned long mask = ((val - c->one_bits) & ~val) & c->high_bits;
++ *bits = mask;
++ return mask;
++}
++
++static inline unsigned long prep_zero_mask(unsigned long val,
++ unsigned long bits, const struct word_at_a_time *c)
++{
++ return bits;
++}
++
++static inline unsigned long create_zero_mask(unsigned long bits)
++{
++ bits = (bits - 1) & ~bits;
++ return bits >> 7;
++}
++
++static inline unsigned long find_zero(unsigned long mask)
++{
++ return fls64(mask) >> 3;
++}
++
++/* The mask we created is directly usable as a bytemask */
++#define zero_bytemask(mask) (mask)
++
++#endif /* _ASM_RISCV_WORD_AT_A_TIME_H */
+diff -Nur linux-4.6.2/arch/riscv/include/uapi/asm/auxvec.h linux-4.6.2.riscv/arch/riscv/include/uapi/asm/auxvec.h
+--- linux-4.6.2/arch/riscv/include/uapi/asm/auxvec.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/uapi/asm/auxvec.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,7 @@
++#ifndef _UAPI_ASM_RISCV_AUXVEC_H
++#define _UAPI_ASM_RISCV_AUXVEC_H
++
++/* vDSO location */
++#define AT_SYSINFO_EHDR 33
++
++#endif /* _UAPI_ASM_RISCV_AUXVEC_H */
+diff -Nur linux-4.6.2/arch/riscv/include/uapi/asm/bitsperlong.h linux-4.6.2.riscv/arch/riscv/include/uapi/asm/bitsperlong.h
+--- linux-4.6.2/arch/riscv/include/uapi/asm/bitsperlong.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/uapi/asm/bitsperlong.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,8 @@
++#ifndef _UAPI_ASM_RISCV_BITSPERLONG_H
++#define _UAPI_ASM_RISCV_BITSPERLONG_H
++
++#define __BITS_PER_LONG (__SIZEOF_POINTER__ * 8)
++
++#include <asm-generic/bitsperlong.h>
++
++#endif /* _UAPI_ASM_RISCV_BITSPERLONG_H */
+diff -Nur linux-4.6.2/arch/riscv/include/uapi/asm/byteorder.h linux-4.6.2.riscv/arch/riscv/include/uapi/asm/byteorder.h
+--- linux-4.6.2/arch/riscv/include/uapi/asm/byteorder.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/uapi/asm/byteorder.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,6 @@
++#ifndef _UAPI_ASM_RISCV_BYTEORDER_H
++#define _UAPI_ASM_RISCV_BYTEORDER_H
++
++#include <linux/byteorder/little_endian.h>
++
++#endif /* _UAPI_ASM_RISCV_BYTEORDER_H */
+diff -Nur linux-4.6.2/arch/riscv/include/uapi/asm/elf.h linux-4.6.2.riscv/arch/riscv/include/uapi/asm/elf.h
+--- linux-4.6.2/arch/riscv/include/uapi/asm/elf.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/uapi/asm/elf.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,64 @@
++#ifndef _UAPI_ASM_ELF_H
++#define _UAPI_ASM_ELF_H
++
++#include <asm/ptrace.h>
++
++/* ELF register definitions */
++typedef unsigned long elf_greg_t;
++typedef struct user_regs_struct elf_gregset_t;
++#define ELF_NGREG (sizeof(elf_gregset_t) / sizeof(elf_greg_t))
++
++typedef struct user_fpregs_struct elf_fpregset_t;
++
++
++/*
++ * RISC-V relocation types
++ */
++
++/* Relocation types used by the dynamic linker */
++#define R_RISCV_NONE 0
++#define R_RISCV_32 1
++#define R_RISCV_64 2
++#define R_RISCV_RELATIVE 3
++#define R_RISCV_COPY 4
++#define R_RISCV_JUMP_SLOT 5
++#define R_RISCV_TLS_DTPMOD32 6
++#define R_RISCV_TLS_DTPMOD64 7
++#define R_RISCV_TLS_DTPREL32 8
++#define R_RISCV_TLS_DTPREL64 9
++#define R_RISCV_TLS_TPREL32 10
++#define R_RISCV_TLS_TPREL64 11
++
++/* Relocation types not used by the dynamic linker */
++#define R_RISCV_BRANCH 16
++#define R_RISCV_JAL 17
++#define R_RISCV_CALL 18
++#define R_RISCV_CALL_PLT 19
++#define R_RISCV_GOT_HI20 20
++#define R_RISCV_TLS_GOT_HI20 21
++#define R_RISCV_TLS_GD_HI20 22
++#define R_RISCV_PCREL_HI20 23
++#define R_RISCV_PCREL_LO12_I 24
++#define R_RISCV_PCREL_LO12_S 25
++#define R_RISCV_HI20 26
++#define R_RISCV_LO12_I 27
++#define R_RISCV_LO12_S 28
++#define R_RISCV_TPREL_HI20 29
++#define R_RISCV_TPREL_LO12_I 30
++#define R_RISCV_TPREL_LO12_S 31
++#define R_RISCV_TPREL_ADD 32
++#define R_RISCV_ADD8 33
++#define R_RISCV_ADD16 34
++#define R_RISCV_ADD32 35
++#define R_RISCV_ADD64 36
++#define R_RISCV_SUB8 37
++#define R_RISCV_SUB16 38
++#define R_RISCV_SUB32 39
++#define R_RISCV_SUB64 40
++#define R_RISCV_GNU_VTINHERIT 41
++#define R_RISCV_GNU_VTENTRY 42
++#define R_RISCV_ALIGN 43
++#define R_RISCV_RVC_BRANCH 44
++#define R_RISCV_RVC_JUMP 45
++
++#endif /* _UAPI_ASM_ELF_H */
+diff -Nur linux-4.6.2/arch/riscv/include/uapi/asm/Kbuild linux-4.6.2.riscv/arch/riscv/include/uapi/asm/Kbuild
+--- linux-4.6.2/arch/riscv/include/uapi/asm/Kbuild 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/uapi/asm/Kbuild 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,10 @@
++# UAPI Header export list
++include include/uapi/asm-generic/Kbuild.asm
++
++header-y += auxvec.h
++header-y += bitsperlong.h
++header-y += byteorder.h
++header-y += ptrace.h
++header-y += sigcontext.h
++header-y += siginfo.h
++header-y += unistd.h
+diff -Nur linux-4.6.2/arch/riscv/include/uapi/asm/ptrace.h linux-4.6.2.riscv/arch/riscv/include/uapi/asm/ptrace.h
+--- linux-4.6.2/arch/riscv/include/uapi/asm/ptrace.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/uapi/asm/ptrace.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,55 @@
++#ifndef _UAPI_ASM_RISCV_PTRACE_H
++#define _UAPI_ASM_RISCV_PTRACE_H
++
++#ifndef __ASSEMBLY__
++
++#include <linux/types.h>
++
++/* User-mode register state for core dumps, ptrace, sigcontext
++ *
++ * This decouples struct pt_regs from the userspace ABI.
++ * struct user_regs_struct must form a prefix of struct pt_regs.
++ */
++struct user_regs_struct {
++ unsigned long pc;
++ unsigned long ra;
++ unsigned long sp;
++ unsigned long gp;
++ unsigned long tp;
++ unsigned long t0;
++ unsigned long t1;
++ unsigned long t2;
++ unsigned long s0;
++ unsigned long s1;
++ unsigned long a0;
++ unsigned long a1;
++ unsigned long a2;
++ unsigned long a3;
++ unsigned long a4;
++ unsigned long a5;
++ unsigned long a6;
++ unsigned long a7;
++ unsigned long s2;
++ unsigned long s3;
++ unsigned long s4;
++ unsigned long s5;
++ unsigned long s6;
++ unsigned long s7;
++ unsigned long s8;
++ unsigned long s9;
++ unsigned long s10;
++ unsigned long s11;
++ unsigned long t3;
++ unsigned long t4;
++ unsigned long t5;
++ unsigned long t6;
++};
++
++struct user_fpregs_struct {
++ __u64 f[32];
++ __u32 fcsr;
++};
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* _UAPI_ASM_RISCV_PTRACE_H */
+diff -Nur linux-4.6.2/arch/riscv/include/uapi/asm/sigcontext.h linux-4.6.2.riscv/arch/riscv/include/uapi/asm/sigcontext.h
+--- linux-4.6.2/arch/riscv/include/uapi/asm/sigcontext.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/uapi/asm/sigcontext.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,16 @@
++#ifndef _UAPI_ASM_RISCV_SIGCONTEXT_H
++#define _UAPI_ASM_RISCV_SIGCONTEXT_H
++
++#include <asm/ptrace.h>
++
++/* Signal context structure
++ *
++ * This contains the context saved before a signal handler is invoked;
++ * it is restored by sys_sigreturn / sys_rt_sigreturn.
++ */
++struct sigcontext {
++ struct user_regs_struct sc_regs;
++ struct user_fpregs_struct sc_fpregs;
++};
++
++#endif /* _UAPI_ASM_RISCV_SIGCONTEXT_H */
+diff -Nur linux-4.6.2/arch/riscv/include/uapi/asm/siginfo.h linux-4.6.2.riscv/arch/riscv/include/uapi/asm/siginfo.h
+--- linux-4.6.2/arch/riscv/include/uapi/asm/siginfo.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/uapi/asm/siginfo.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,24 @@
++/*
++ * Copyright (C) 2012 ARM Ltd.
++ * Copyright (C) 2016 SiFive, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++#ifndef __ASM_SIGINFO_H
++#define __ASM_SIGINFO_H
++
++#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
++
++#include <asm-generic/siginfo.h>
++
++#endif
+diff -Nur linux-4.6.2/arch/riscv/include/uapi/asm/unistd.h linux-4.6.2.riscv/arch/riscv/include/uapi/asm/unistd.h
+--- linux-4.6.2/arch/riscv/include/uapi/asm/unistd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/include/uapi/asm/unistd.h 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,9 @@
++#include <asm-generic/unistd.h>
++
++#define __NR_sysriscv __NR_arch_specific_syscall
++#ifndef __riscv_atomic
++__SYSCALL(__NR_sysriscv, sys_sysriscv)
++#endif
++
++#define RISCV_ATOMIC_CMPXCHG 1
++#define RISCV_ATOMIC_CMPXCHG64 2
+diff -Nur linux-4.6.2/arch/riscv/initramfs.txt linux-4.6.2.riscv/arch/riscv/initramfs.txt
+--- linux-4.6.2/arch/riscv/initramfs.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/initramfs.txt 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,9 @@
++dir /bin 755 0 0
++file /bin/busybox tmp/bin/busybox 755 0 0
++dir /etc 755 0 0
++file /etc/inittab tmp/etc/inittab 755 0 0
++
++dir /dev 755 0 0
++nod /dev/console 644 0 0 c 5 1
++nod /dev/null 644 0 0 c 1 3
++slink /init /bin/busybox 755 0 0
+diff -Nur linux-4.6.2/arch/riscv/Kconfig linux-4.6.2.riscv/arch/riscv/Kconfig
+--- linux-4.6.2/arch/riscv/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/Kconfig 2017-03-04 02:48:34.162887952 +0100
+@@ -0,0 +1,284 @@
++#
++# For a description of the syntax of this configuration file,
++# see Documentation/kbuild/kconfig-language.txt.
++#
++
++config RISCV
++ def_bool y
++ select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
++ select ARCH_WANT_FRAME_POINTERS
++ select CLONE_BACKWARDS
++ select COMMON_CLK
++ select GENERIC_CLOCKEVENTS
++ select GENERIC_CPU_DEVICES
++ select GENERIC_IRQ_SHOW
++ select GENERIC_PCI_IOMAP
++ select GENERIC_STRNCPY_FROM_USER
++ select GENERIC_STRNLEN_USER
++ select GENERIC_SMP_IDLE_THREAD
++ select GENERIC_ATOMIC64 if !64BIT || !RV_ATOMIC
++ select ARCH_WANT_OPTIONAL_GPIOLIB
++ select HAVE_MEMBLOCK
++ select HAVE_MEMBLOCK_NODE_MAP
++ select HAVE_DMA_API_DEBUG
++ select HAVE_DMA_CONTIGUOUS
++ select HAVE_GENERIC_DMA_COHERENT
++ select IRQ_DOMAIN
++ select NO_BOOTMEM
++ select RV_ATOMIC if SMP
++ select RV_SYSRISCV_ATOMIC if !RV_ATOMIC
++ select SPARSE_IRQ
++ select SYSCTL_EXCEPTION_TRACE
++ select HAVE_ARCH_TRACEHOOK
++
++config MMU
++ def_bool y
++
++# even on 32-bit, physical (and DMA) addresses are > 32-bits
++config ARCH_PHYS_ADDR_T_64BIT
++ def_bool y
++
++config ARCH_DMA_ADDR_T_64BIT
++ def_bool y
++
++config STACKTRACE_SUPPORT
++ def_bool y
++
++config RWSEM_GENERIC_SPINLOCK
++ def_bool y
++
++config GENERIC_BUG
++ def_bool y
++ depends on BUG
++ select GENERIC_BUG_RELATIVE_POINTERS if 64BIT
++
++config GENERIC_BUG_RELATIVE_POINTERS
++ bool
++
++config GENERIC_CALIBRATE_DELAY
++ def_bool y
++
++config GENERIC_CSUM
++ def_bool y
++
++config GENERIC_HWEIGHT
++ def_bool y
++
++config PGTABLE_LEVELS
++ int
++ default 3 if 64BIT
++ default 2
++
++menu "Platform type"
++
++config SMP
++ bool "Symmetric Multi-Processing"
++ help
++ This enables support for systems with more than one CPU. If
++ you say N here, the kernel will run on single and
++ multiprocessor machines, but will use only one CPU of a
++ multiprocessor machine. If you say Y here, the kernel will run
++ on many, but not all, single processor machines. On a single
++ processor machine, the kernel will run faster if you say N
++ here.
++
++ If you don't know what to do here, say N.
++
++config NR_CPUS
++ int "Maximum number of CPUs (2-32)"
++ range 2 32
++ depends on SMP
++ default "8"
++
++choice
++ prompt "CPU selection"
++ default CPU_RV_ROCKET
++
++config CPU_RV_ROCKET
++ bool "Rocket"
++ select CPU_SUPPORTS_64BIT_KERNEL
++
++config CPU_RV_GENERIC
++ bool "Generic RISC-V"
++ select CPU_SUPPORTS_32BIT_KERNEL
++ select CPU_SUPPORTS_64BIT_KERNEL
++
++endchoice
++
++config CPU_SUPPORTS_32BIT_KERNEL
++ bool
++config CPU_SUPPORTS_64BIT_KERNEL
++ bool
++
++config SBI_CONSOLE
++ tristate "SBI console support"
++ select TTY
++ default y
++
++config RVC
++ bool "Use compressed instructions (RV32C or RV64C)"
++ default n
++
++config RV_ATOMIC
++ bool "Use atomic memory instructions (RV32A or RV64A)"
++ default y
++
++config RV_SYSRISCV_ATOMIC
++ bool "Include support for atomic operation syscalls"
++ default n
++ help
++ If atomic memory instructions are present, i.e.,
++ CONFIG_RV_ATOMIC, this includes support for the syscall that
++ provides atomic accesses. This is only useful to run
++ binaries that require atomic access but were compiled with
++ -mno-atomic.
++
++ If CONFIG_RV_ATOMIC is unset, this option is mandatory.
++
++config RV_PUM
++ def_bool y
++ prompt "Protect User Memory" if EXPERT
++ ---help---
++ Protect User Memory (PUM) prevents the kernel from inadvertently
++ accessing user-space memory. There is a small performance cost
++ and kernel size increase if this is enabled.
++
++ If unsure, say Y.
++
++endmenu
++
++menu "Kernel type"
++
++choice
++ prompt "Kernel code model"
++ default 64BIT
++
++config 32BIT
++ bool "32-bit kernel"
++ depends on CPU_SUPPORTS_32BIT_KERNEL
++ help
++ Select this option to build a 32-bit kernel.
++
++config 64BIT
++ bool "64-bit kernel"
++ depends on CPU_SUPPORTS_64BIT_KERNEL
++ help
++ Select this option to build a 64-bit kernel.
++
++endchoice
++
++source "mm/Kconfig"
++
++source "kernel/Kconfig.preempt"
++
++source "kernel/Kconfig.hz"
++
++endmenu
++
++menu "Bus support"
++
++config PCI
++ bool "PCI support"
++ select PCI_MSI
++ help
++ This feature enables support for PCI bus system. If you say Y
++ here, the kernel will include drivers and infrastructure code
++ to support PCI bus devices.
++
++config PCI_DOMAINS
++ def_bool PCI
++
++config PCI_DOMAINS_GENERIC
++ def_bool PCI
++
++config PCI_SYSCALL
++ def_bool PCI
++
++source "drivers/pci/Kconfig"
++
++endmenu
++
++source "init/Kconfig"
++
++source "kernel/Kconfig.freezer"
++
++menu "Executable file formats"
++
++source "fs/Kconfig.binfmt"
++
++endmenu
++
++menu "Power management options"
++
++source kernel/power/Kconfig
++
++endmenu
++
++source "net/Kconfig"
++
++source "drivers/Kconfig"
++
++source "fs/Kconfig"
++
++menu "Kernel hacking"
++
++config CMDLINE_BOOL
++ bool "Built-in kernel command line"
++ default n
++ help
++ For most platforms, it is firmware or second stage bootloader
++ that by default specifies the kernel command line options.
++ However, it might be necessary or advantageous to either override
++ the default kernel command line or add a few extra options to it.
++ For such cases, this option allows hardcoding command line options
++ directly into the kernel.
++
++ For that, choose 'Y' here and fill in the extra boot parameters
++ in CONFIG_CMDLINE.
++
++ The built-in options will be concatenated to the default command
++ line if CMDLINE_OVERRIDE is set to 'N'. Otherwise, the default
++ command line will be ignored and replaced by the built-in string.
++
++config CMDLINE
++ string "Built-in kernel command string"
++ depends on CMDLINE_BOOL
++ default ""
++ help
++ Supply command-line options at build time by entering them here.
++
++config CMDLINE_OVERRIDE
++ bool "Built-in command line overrides bootloader arguments"
++ default n
++ depends on CMDLINE_BOOL
++ help
++ Set this option to 'Y' to have the kernel ignore the bootloader
++ or firmware command line. Instead, the built-in command line
++ will be used exclusively.
++
++config EARLY_PRINTK
++ bool "Early printk"
++ default n
++ help
++ This option enables special console drivers which allow the kernel
++ to print messages very early in the bootup process.
++
++ This is useful for kernel debugging when your machine crashes very
++ early before the console code is initialized. For normal operation
++ it is not recommended because it looks ugly and doesn't cooperate
++ with klogd/syslogd or the X server. You should normally N here,
++ unless you want to debug such a crash.
++
++
++source "lib/Kconfig.debug"
++
++config CMDLINE_BOOL
++ bool
++endmenu
++
++source "security/Kconfig"
++
++source "crypto/Kconfig"
++
++source "lib/Kconfig"
++
+diff -Nur linux-4.6.2/arch/riscv/kernel/asm-offsets.c linux-4.6.2.riscv/arch/riscv/kernel/asm-offsets.c
+--- linux-4.6.2/arch/riscv/kernel/asm-offsets.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/asm-offsets.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,99 @@
++#include <linux/kbuild.h>
++#include <linux/sched.h>
++#include <asm/thread_info.h>
++#include <asm/ptrace.h>
++
++void asm_offsets(void)
++{
++ OFFSET(TASK_THREAD_INFO, task_struct, stack);
++ OFFSET(THREAD_RA, task_struct, thread.ra);
++ OFFSET(THREAD_SP, task_struct, thread.sp);
++ OFFSET(THREAD_S0, task_struct, thread.s[0]);
++ OFFSET(THREAD_S1, task_struct, thread.s[1]);
++ OFFSET(THREAD_S2, task_struct, thread.s[2]);
++ OFFSET(THREAD_S3, task_struct, thread.s[3]);
++ OFFSET(THREAD_S4, task_struct, thread.s[4]);
++ OFFSET(THREAD_S5, task_struct, thread.s[5]);
++ OFFSET(THREAD_S6, task_struct, thread.s[6]);
++ OFFSET(THREAD_S7, task_struct, thread.s[7]);
++ OFFSET(THREAD_S8, task_struct, thread.s[8]);
++ OFFSET(THREAD_S9, task_struct, thread.s[9]);
++ OFFSET(THREAD_S10, task_struct, thread.s[10]);
++ OFFSET(THREAD_S11, task_struct, thread.s[11]);
++ OFFSET(THREAD_SP, task_struct, thread.sp);
++ OFFSET(TI_TASK, thread_info, task);
++ OFFSET(TI_FLAGS, thread_info, flags);
++ OFFSET(TI_CPU, thread_info, cpu);
++
++ OFFSET(THREAD_F0, task_struct, thread.fstate.f[0]);
++ OFFSET(THREAD_F1, task_struct, thread.fstate.f[1]);
++ OFFSET(THREAD_F2, task_struct, thread.fstate.f[2]);
++ OFFSET(THREAD_F3, task_struct, thread.fstate.f[3]);
++ OFFSET(THREAD_F4, task_struct, thread.fstate.f[4]);
++ OFFSET(THREAD_F5, task_struct, thread.fstate.f[5]);
++ OFFSET(THREAD_F6, task_struct, thread.fstate.f[6]);
++ OFFSET(THREAD_F7, task_struct, thread.fstate.f[7]);
++ OFFSET(THREAD_F8, task_struct, thread.fstate.f[8]);
++ OFFSET(THREAD_F9, task_struct, thread.fstate.f[9]);
++ OFFSET(THREAD_F10, task_struct, thread.fstate.f[10]);
++ OFFSET(THREAD_F11, task_struct, thread.fstate.f[11]);
++ OFFSET(THREAD_F12, task_struct, thread.fstate.f[12]);
++ OFFSET(THREAD_F13, task_struct, thread.fstate.f[13]);
++ OFFSET(THREAD_F14, task_struct, thread.fstate.f[14]);
++ OFFSET(THREAD_F15, task_struct, thread.fstate.f[15]);
++ OFFSET(THREAD_F16, task_struct, thread.fstate.f[16]);
++ OFFSET(THREAD_F17, task_struct, thread.fstate.f[17]);
++ OFFSET(THREAD_F18, task_struct, thread.fstate.f[18]);
++ OFFSET(THREAD_F19, task_struct, thread.fstate.f[19]);
++ OFFSET(THREAD_F20, task_struct, thread.fstate.f[20]);
++ OFFSET(THREAD_F21, task_struct, thread.fstate.f[21]);
++ OFFSET(THREAD_F22, task_struct, thread.fstate.f[22]);
++ OFFSET(THREAD_F23, task_struct, thread.fstate.f[23]);
++ OFFSET(THREAD_F24, task_struct, thread.fstate.f[24]);
++ OFFSET(THREAD_F25, task_struct, thread.fstate.f[25]);
++ OFFSET(THREAD_F26, task_struct, thread.fstate.f[26]);
++ OFFSET(THREAD_F27, task_struct, thread.fstate.f[27]);
++ OFFSET(THREAD_F28, task_struct, thread.fstate.f[28]);
++ OFFSET(THREAD_F29, task_struct, thread.fstate.f[29]);
++ OFFSET(THREAD_F30, task_struct, thread.fstate.f[30]);
++ OFFSET(THREAD_F31, task_struct, thread.fstate.f[31]);
++ OFFSET(THREAD_FCSR, task_struct, thread.fstate.fcsr);
++
++ DEFINE(PT_SIZE, sizeof(struct pt_regs));
++ OFFSET(PT_SEPC, pt_regs, sepc);
++ OFFSET(PT_RA, pt_regs, ra);
++ OFFSET(PT_FP, pt_regs, s0);
++ OFFSET(PT_S0, pt_regs, s0);
++ OFFSET(PT_S1, pt_regs, s1);
++ OFFSET(PT_S2, pt_regs, s2);
++ OFFSET(PT_S3, pt_regs, s3);
++ OFFSET(PT_S4, pt_regs, s4);
++ OFFSET(PT_S5, pt_regs, s5);
++ OFFSET(PT_S6, pt_regs, s6);
++ OFFSET(PT_S7, pt_regs, s7);
++ OFFSET(PT_S8, pt_regs, s8);
++ OFFSET(PT_S9, pt_regs, s9);
++ OFFSET(PT_S10, pt_regs, s10);
++ OFFSET(PT_S11, pt_regs, s11);
++ OFFSET(PT_SP, pt_regs, sp);
++ OFFSET(PT_TP, pt_regs, tp);
++ OFFSET(PT_A0, pt_regs, a0);
++ OFFSET(PT_A1, pt_regs, a1);
++ OFFSET(PT_A2, pt_regs, a2);
++ OFFSET(PT_A3, pt_regs, a3);
++ OFFSET(PT_A4, pt_regs, a4);
++ OFFSET(PT_A5, pt_regs, a5);
++ OFFSET(PT_A6, pt_regs, a6);
++ OFFSET(PT_A7, pt_regs, a7);
++ OFFSET(PT_T0, pt_regs, t0);
++ OFFSET(PT_T1, pt_regs, t1);
++ OFFSET(PT_T2, pt_regs, t2);
++ OFFSET(PT_T3, pt_regs, t3);
++ OFFSET(PT_T4, pt_regs, t4);
++ OFFSET(PT_T5, pt_regs, t5);
++ OFFSET(PT_T6, pt_regs, t6);
++ OFFSET(PT_GP, pt_regs, gp);
++ OFFSET(PT_SSTATUS, pt_regs, sstatus);
++ OFFSET(PT_SBADADDR, pt_regs, sbadaddr);
++ OFFSET(PT_SCAUSE, pt_regs, scause);
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/cpu.c linux-4.6.2.riscv/arch/riscv/kernel/cpu.c
+--- linux-4.6.2/arch/riscv/kernel/cpu.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/cpu.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,41 @@
++#include <linux/init.h>
++#include <linux/seq_file.h>
++
++#ifdef CONFIG_PROC_FS
++
++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 (void *)(uintptr_t)(1 + *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)
++{
++}
++
++static int c_show(struct seq_file *m, void *v)
++{
++ unsigned long hart_id = (unsigned long)v - 1;
++
++ seq_printf(m, "hart\t: %lu\n", hart_id);
++ seq_printf(m, "isa\t: RV%zuG\n", sizeof(void *) * 8);
++ seq_printf(m, "\n");
++ return 0;
++}
++
++const struct seq_operations cpuinfo_op = {
++ .start = c_start,
++ .next = c_next,
++ .stop = c_stop,
++ .show = c_show
++};
++
++#endif /* CONFIG_PROC_FS */
+diff -Nur linux-4.6.2/arch/riscv/kernel/entry.S linux-4.6.2.riscv/arch/riscv/kernel/entry.S
+--- linux-4.6.2/arch/riscv/kernel/entry.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/entry.S 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,399 @@
++#include <linux/init.h>
++#include <linux/linkage.h>
++
++#include <asm/asm.h>
++#include <asm/csr.h>
++#include <asm/unistd.h>
++#include <asm/thread_info.h>
++#include <asm/asm-offsets.h>
++
++ .text
++ .altmacro
++ .macro SAVE_ALL
++ LOCAL _restore_kernel_sp
++ LOCAL _save_context
++
++ /* If coming from userspace, preserve the user stack pointer and load
++ the kernel stack pointer. If we came from the kernel, sscratch
++ will contain 0, and we should continue on the current stack. */
++ csrrw sp, sscratch, sp
++ bnez sp, _save_context
++
++_restore_kernel_sp:
++ csrr sp, sscratch
++_save_context:
++ addi sp, sp, -(PT_SIZE)
++ REG_S x1, PT_RA(sp)
++ REG_S x3, PT_GP(sp)
++ REG_S x4, PT_TP(sp)
++ REG_S x5, PT_T0(sp)
++ REG_S x6, PT_T1(sp)
++ REG_S x7, PT_T2(sp)
++ REG_S x8, PT_S0(sp)
++ REG_S x9, PT_S1(sp)
++ REG_S x10, PT_A0(sp)
++ REG_S x11, PT_A1(sp)
++ REG_S x12, PT_A2(sp)
++ REG_S x13, PT_A3(sp)
++ REG_S x14, PT_A4(sp)
++ REG_S x15, PT_A5(sp)
++ REG_S x16, PT_A6(sp)
++ REG_S x17, PT_A7(sp)
++ REG_S x18, PT_S2(sp)
++ REG_S x19, PT_S3(sp)
++ REG_S x20, PT_S4(sp)
++ REG_S x21, PT_S5(sp)
++ REG_S x22, PT_S6(sp)
++ REG_S x23, PT_S7(sp)
++ REG_S x24, PT_S8(sp)
++ REG_S x25, PT_S9(sp)
++ REG_S x26, PT_S10(sp)
++ REG_S x27, PT_S11(sp)
++ REG_S x28, PT_T3(sp)
++ REG_S x29, PT_T4(sp)
++ REG_S x30, PT_T5(sp)
++ REG_S x31, PT_T6(sp)
++
++ /* Disable FPU to detect illegal usage of
++ floating point in kernel space */
++ li t0, SR_FS
++
++ csrr s0, sscratch
++ csrrc s1, sstatus, t0
++ csrr s2, sepc
++ csrr s3, sbadaddr
++ csrr s4, scause
++ REG_S s0, PT_SP(sp)
++ REG_S s1, PT_SSTATUS(sp)
++ REG_S s2, PT_SEPC(sp)
++ REG_S s3, PT_SBADADDR(sp)
++ REG_S s4, PT_SCAUSE(sp)
++ .endm
++
++ .macro RESTORE_ALL
++ REG_L a0, PT_SSTATUS(sp)
++ REG_L a2, PT_SEPC(sp)
++ csrw sstatus, a0
++ csrw sepc, a2
++
++ REG_L x1, PT_RA(sp)
++ REG_L x3, PT_GP(sp)
++ REG_L x4, PT_TP(sp)
++ REG_L x5, PT_T0(sp)
++ REG_L x6, PT_T1(sp)
++ REG_L x7, PT_T2(sp)
++ REG_L x8, PT_S0(sp)
++ REG_L x9, PT_S1(sp)
++ REG_L x10, PT_A0(sp)
++ REG_L x11, PT_A1(sp)
++ REG_L x12, PT_A2(sp)
++ REG_L x13, PT_A3(sp)
++ REG_L x14, PT_A4(sp)
++ REG_L x15, PT_A5(sp)
++ REG_L x16, PT_A6(sp)
++ REG_L x17, PT_A7(sp)
++ REG_L x18, PT_S2(sp)
++ REG_L x19, PT_S3(sp)
++ REG_L x20, PT_S4(sp)
++ REG_L x21, PT_S5(sp)
++ REG_L x22, PT_S6(sp)
++ REG_L x23, PT_S7(sp)
++ REG_L x24, PT_S8(sp)
++ REG_L x25, PT_S9(sp)
++ REG_L x26, PT_S10(sp)
++ REG_L x27, PT_S11(sp)
++ REG_L x28, PT_T3(sp)
++ REG_L x29, PT_T4(sp)
++ REG_L x30, PT_T5(sp)
++ REG_L x31, PT_T6(sp)
++
++ REG_L x2, PT_SP(sp)
++ .endm
++
++ENTRY(handle_exception)
++ SAVE_ALL
++
++ /* Set sscratch register to 0, so that if a recursive exception
++ occurs, the exception vector knows it came from the kernel */
++ csrw sscratch, x0
++
++ /* Compute address of current thread_info */
++ li tp, ~(THREAD_SIZE-1)
++ and tp, tp, sp
++ /* Set current pointer */
++ REG_L tp, TI_TASK(tp)
++
++1: auipc gp, %pcrel_hi(_gp)
++ addi gp, gp, %pcrel_lo(1b)
++
++ la ra, ret_from_exception
++ /* MSB of cause differentiates between
++ interrupts and exceptions */
++ bge s4, zero, 1f
++
++ /* Handle interrupts */
++ slli a0, s4, 1
++ srli a0, a0, 1
++ move a1, sp /* pt_regs */
++ tail do_IRQ
++1:
++ /* Handle syscalls */
++ li t0, EXC_SYSCALL
++ beq s4, t0, handle_syscall
++
++ /* Handle other exceptions */
++ slli t0, s4, LGPTR
++ la t1, excp_vect_table
++ la t2, excp_vect_table_end
++ move a0, sp /* pt_regs */
++ add t0, t1, t0
++ /* Check if exception code lies within bounds */
++ bgeu t0, t2, 1f
++ REG_L t0, 0(t0)
++ jr t0
++1:
++ tail do_trap_unknown
++
++handle_syscall:
++ /* Advance SEPC to avoid executing the original
++ scall instruction on sret */
++ addi s2, s2, 0x4
++ REG_S s2, PT_SEPC(sp)
++ /* System calls run with interrupts enabled */
++ csrs sstatus, SR_IE
++ /* Trace syscalls, but only if requested by the user. */
++ REG_L t0, TASK_THREAD_INFO(tp)
++ REG_L t0, TI_FLAGS(t0)
++ andi t0, t0, _TIF_SYSCALL_TRACE
++ bnez t0, handle_syscall_trace_enter
++check_syscall_nr:
++ /* Check to make sure we don't jump to a bogus syscall number. */
++ li t0, __NR_syscalls
++ la s0, sys_ni_syscall
++ /* Syscall number held in a7 */
++ bgeu a7, t0, 1f
++ la s0, sys_call_table
++ slli t0, a7, LGPTR
++ add s0, s0, t0
++ REG_L s0, 0(s0)
++1:
++ jalr s0
++
++ret_from_syscall:
++ /* Set user a0 to kernel a0 */
++ REG_S a0, PT_A0(sp)
++ /* Trace syscalls, but only if requested by the user. */
++ REG_L t0, TASK_THREAD_INFO(tp)
++ REG_L t0, TI_FLAGS(t0)
++ andi t0, t0, _TIF_SYSCALL_TRACE
++ bnez t0, handle_syscall_trace_exit
++
++ret_from_exception:
++ REG_L s0, PT_SSTATUS(sp)
++ csrc sstatus, SR_IE
++ andi s0, s0, SR_PS
++ bnez s0, restore_all
++
++resume_userspace:
++ /* Interrupts must be disabled here so flags are checked atomically */
++ REG_L s0, TASK_THREAD_INFO(tp)
++ REG_L s0, TI_FLAGS(s0) /* current_thread_info->flags */
++ andi s1, s0, _TIF_WORK_MASK
++ bnez s1, work_pending
++
++ /* Save unwound kernel stack pointer in sscratch */
++ addi s0, sp, PT_SIZE
++ csrw sscratch, s0
++restore_all:
++ RESTORE_ALL
++ sret
++
++work_pending:
++ /* Enter slow path for supplementary processing */
++ la ra, ret_from_exception
++ andi s1, s0, _TIF_NEED_RESCHED
++ bnez s1, work_resched
++work_notifysig:
++ /* Handle pending signals and notify-resume requests */
++ csrs sstatus, SR_IE /* Enable interrupts for do_notify_resume() */
++ move a0, sp /* pt_regs */
++ move a1, s0 /* current_thread_info->flags */
++ tail do_notify_resume
++work_resched:
++ tail schedule
++
++/* Slow paths for ptrace. */
++handle_syscall_trace_enter:
++ move a0, sp
++ call do_syscall_trace_enter
++ REG_L a0, PT_A0(sp)
++ REG_L a1, PT_A1(sp)
++ REG_L a2, PT_A2(sp)
++ REG_L a3, PT_A3(sp)
++ REG_L a4, PT_A4(sp)
++ REG_L a5, PT_A5(sp)
++ REG_L a6, PT_A6(sp)
++ REG_L a7, PT_A7(sp)
++ j check_syscall_nr
++handle_syscall_trace_exit:
++ move a0, sp
++ call do_syscall_trace_exit
++ j ret_from_exception
++
++END(handle_exception)
++
++ENTRY(ret_from_fork)
++ la ra, ret_from_exception
++ tail schedule_tail
++ENDPROC(ret_from_fork)
++
++ENTRY(ret_from_kernel_thread)
++ call schedule_tail
++ /* Call fn(arg) */
++ la ra, ret_from_exception
++ move a0, s1
++ jr s0
++ENDPROC(ret_from_kernel_thread)
++
++
++/*
++ * Integer register context switch
++ * The callee-saved registers must be saved and restored.
++ *
++ * a0: previous task_struct (must be preserved across the switch)
++ * a1: next task_struct
++ */
++ENTRY(__switch_to)
++ /* Save context into prev->thread */
++ REG_S ra, THREAD_RA(a0)
++ REG_S sp, THREAD_SP(a0)
++ REG_S s0, THREAD_S0(a0)
++ REG_S s1, THREAD_S1(a0)
++ REG_S s2, THREAD_S2(a0)
++ REG_S s3, THREAD_S3(a0)
++ REG_S s4, THREAD_S4(a0)
++ REG_S s5, THREAD_S5(a0)
++ REG_S s6, THREAD_S6(a0)
++ REG_S s7, THREAD_S7(a0)
++ REG_S s8, THREAD_S8(a0)
++ REG_S s9, THREAD_S9(a0)
++ REG_S s10, THREAD_S10(a0)
++ REG_S s11, THREAD_S11(a0)
++ /* Restore context from next->thread */
++ REG_L ra, THREAD_RA(a1)
++ REG_L sp, THREAD_SP(a1)
++ REG_L s0, THREAD_S0(a1)
++ REG_L s1, THREAD_S1(a1)
++ REG_L s2, THREAD_S2(a1)
++ REG_L s3, THREAD_S3(a1)
++ REG_L s4, THREAD_S4(a1)
++ REG_L s5, THREAD_S5(a1)
++ REG_L s6, THREAD_S6(a1)
++ REG_L s7, THREAD_S7(a1)
++ REG_L s8, THREAD_S8(a1)
++ REG_L s9, THREAD_S9(a1)
++ REG_L s10, THREAD_S10(a1)
++ REG_L s11, THREAD_S11(a1)
++ mv tp, a1 /* Next current pointer */
++ ret
++ENDPROC(__switch_to)
++
++ENTRY(__fstate_save)
++ li t1, SR_FS
++ csrs sstatus, t1
++ frcsr t0
++ fsd f0, THREAD_F0(a0)
++ fsd f1, THREAD_F1(a0)
++ fsd f2, THREAD_F2(a0)
++ fsd f3, THREAD_F3(a0)
++ fsd f4, THREAD_F4(a0)
++ fsd f5, THREAD_F5(a0)
++ fsd f6, THREAD_F6(a0)
++ fsd f7, THREAD_F7(a0)
++ fsd f8, THREAD_F8(a0)
++ fsd f9, THREAD_F9(a0)
++ fsd f10, THREAD_F10(a0)
++ fsd f11, THREAD_F11(a0)
++ fsd f12, THREAD_F12(a0)
++ fsd f13, THREAD_F13(a0)
++ fsd f14, THREAD_F14(a0)
++ fsd f15, THREAD_F15(a0)
++ fsd f16, THREAD_F16(a0)
++ fsd f17, THREAD_F17(a0)
++ fsd f18, THREAD_F18(a0)
++ fsd f19, THREAD_F19(a0)
++ fsd f20, THREAD_F20(a0)
++ fsd f21, THREAD_F21(a0)
++ fsd f22, THREAD_F22(a0)
++ fsd f23, THREAD_F23(a0)
++ fsd f24, THREAD_F24(a0)
++ fsd f25, THREAD_F25(a0)
++ fsd f26, THREAD_F26(a0)
++ fsd f27, THREAD_F27(a0)
++ fsd f28, THREAD_F28(a0)
++ fsd f29, THREAD_F29(a0)
++ fsd f30, THREAD_F30(a0)
++ fsd f31, THREAD_F31(a0)
++ sw t0, THREAD_FCSR(a0)
++ csrc sstatus, t1
++ ret
++ENDPROC(__fstate_save)
++
++ENTRY(__fstate_restore)
++ li t1, SR_FS
++ lw t0, THREAD_FCSR(a0)
++ csrs sstatus, t1
++ fld f0, THREAD_F0(a0)
++ fld f1, THREAD_F1(a0)
++ fld f2, THREAD_F2(a0)
++ fld f3, THREAD_F3(a0)
++ fld f4, THREAD_F4(a0)
++ fld f5, THREAD_F5(a0)
++ fld f6, THREAD_F6(a0)
++ fld f7, THREAD_F7(a0)
++ fld f8, THREAD_F8(a0)
++ fld f9, THREAD_F9(a0)
++ fld f10, THREAD_F10(a0)
++ fld f11, THREAD_F11(a0)
++ fld f12, THREAD_F12(a0)
++ fld f13, THREAD_F13(a0)
++ fld f14, THREAD_F14(a0)
++ fld f15, THREAD_F15(a0)
++ fld f16, THREAD_F16(a0)
++ fld f17, THREAD_F17(a0)
++ fld f18, THREAD_F18(a0)
++ fld f19, THREAD_F19(a0)
++ fld f20, THREAD_F20(a0)
++ fld f21, THREAD_F21(a0)
++ fld f22, THREAD_F22(a0)
++ fld f23, THREAD_F23(a0)
++ fld f24, THREAD_F24(a0)
++ fld f25, THREAD_F25(a0)
++ fld f26, THREAD_F26(a0)
++ fld f27, THREAD_F27(a0)
++ fld f28, THREAD_F28(a0)
++ fld f29, THREAD_F29(a0)
++ fld f30, THREAD_F30(a0)
++ fld f31, THREAD_F31(a0)
++ fscsr t0
++ csrc sstatus, t1
++ ret
++ENDPROC(__fstate_restore)
++
++
++ .section ".rodata"
++ /* Exception vector table */
++ENTRY(excp_vect_table)
++ PTR do_trap_insn_misaligned
++ PTR do_page_fault
++ PTR do_trap_insn_illegal
++ PTR do_trap_unknown
++ PTR do_trap_unknown
++ PTR do_page_fault
++ PTR do_trap_amo_misaligned
++ PTR do_page_fault
++ PTR 0 /* handle_syscall */
++ PTR do_trap_break
++excp_vect_table_end:
++END(excp_vect_table)
++
+diff -Nur linux-4.6.2/arch/riscv/kernel/head.S linux-4.6.2.riscv/arch/riscv/kernel/head.S
+--- linux-4.6.2/arch/riscv/kernel/head.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/head.S 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,77 @@
++#include <asm/thread_info.h>
++#include <asm/asm-offsets.h>
++#include <asm/asm.h>
++#include <linux/init.h>
++#include <linux/linkage.h>
++#include <asm/thread_info.h>
++#include <asm/page.h>
++#include <asm/csr.h>
++
++__INIT
++ENTRY(_start)
++ /* Load the global pointer (before any use of la) */
++1: auipc gp, %pcrel_hi(_gp)
++ addi gp, gp, %pcrel_lo(1b)
++
++ /* Disable FPU to detect illegal usage of
++ floating point in kernel space */
++ li t0, SR_FS
++ csrc sstatus, t0
++
++#ifdef CONFIG_RV_PUM
++ /* Prevent inadvertent access to user memory */
++ li t0, SR_PUM
++ csrs sstatus, t0
++#endif
++
++ /* See if we're the main hart */
++ call sbi_hart_id
++ bnez a0, .Lsecondary_start
++
++ /* Clear the .bss segment */
++ la a0, __bss_start
++ li a1, 0
++ la a2, __bss_stop
++ sub a2, a2, a0
++ call memset
++
++ /* Initialize stack pointer */
++ la sp, init_thread_union + THREAD_SIZE
++ /* Initialize current task_struct pointer */
++ la tp, init_task
++
++ tail start_kernel
++
++.Lsecondary_start:
++#ifdef CONFIG_SMP
++ li a1, CONFIG_NR_CPUS
++ bgeu a0, a1, .Lsecondary_park
++
++ la a1, __cpu_up_stack_pointer
++ slli a0, a0, LGREG
++ add a0, a0, a1
++
++.Lwait_for_cpu_up:
++ REG_L sp, (a0)
++ beqz sp, .Lwait_for_cpu_up
++
++ /* Initialize task_struct pointer */
++ li tp, -THREAD_SIZE
++ add tp, tp, sp
++ REG_L tp, (tp)
++
++ tail smp_callin
++#endif
++
++.Lsecondary_park:
++ /* We lack SMP support or have too many harts, so park this hart */
++ wfi
++ j .Lsecondary_park
++END(_start)
++
++__PAGE_ALIGNED_BSS
++ /* Empty zero page */
++ .balign PAGE_SIZE
++ENTRY(empty_zero_page)
++ .fill (empty_zero_page + PAGE_SIZE) - ., 1, 0x00
++END(empty_zero_page)
+diff -Nur linux-4.6.2/arch/riscv/kernel/irq.c linux-4.6.2.riscv/arch/riscv/kernel/irq.c
+--- linux-4.6.2/arch/riscv/kernel/irq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/irq.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,102 @@
++#include <linux/interrupt.h>
++#include <linux/ftrace.h>
++#include <linux/seq_file.h>
++
++#include <asm/ptrace.h>
++#include <asm/sbi.h>
++#include <asm/sbi-con.h>
++#include <asm/smp.h>
++
++struct plic_context {
++ volatile int priority_threshold;
++ volatile int claim;
++};
++
++static DEFINE_PER_CPU(struct plic_context *, plic_context);
++static DEFINE_PER_CPU(unsigned int, irq_in_progress);
++
++static void riscv_software_interrupt(void)
++{
++ irqreturn_t ret;
++
++#ifdef CONFIG_SMP
++ ret = handle_ipi();
++ if (ret != IRQ_NONE)
++ return;
++#endif
++
++ ret = sbi_console_isr();
++ if (ret != IRQ_NONE)
++ return;
++
++ BUG();
++}
++
++static void plic_interrupt(void)
++{
++ unsigned int cpu = smp_processor_id();
++ unsigned int irq = per_cpu(plic_context, cpu)->claim;
++
++ BUG_ON(per_cpu(irq_in_progress, cpu) != 0);
++
++ if (irq) {
++ per_cpu(irq_in_progress, cpu) = irq;
++ generic_handle_irq(irq);
++ }
++}
++
++asmlinkage void __irq_entry do_IRQ(unsigned int cause, struct pt_regs *regs)
++{
++ struct pt_regs *old_regs = set_irq_regs(regs);
++ irq_enter();
++
++ /* There are three classes of interrupt: timer, software, and
++ external devices. We dispatch between them here. External
++ device interrupts use the generic IRQ mechanisms. */
++ switch (cause) {
++ case INTERRUPT_CAUSE_TIMER:
++ riscv_timer_interrupt();
++ break;
++ case INTERRUPT_CAUSE_SOFTWARE:
++ riscv_software_interrupt();
++ break;
++ case INTERRUPT_CAUSE_EXTERNAL:
++ plic_interrupt();
++ break;
++ default:
++ BUG();
++ }
++
++ irq_exit();
++ set_irq_regs(old_regs);
++}
++
++static void plic_irq_mask(struct irq_data *d)
++{
++ unsigned int cpu = smp_processor_id();
++
++ BUG_ON(d->irq != per_cpu(irq_in_progress, cpu));
++}
++
++static void plic_irq_unmask(struct irq_data *d)
++{
++ unsigned int cpu = smp_processor_id();
++
++ BUG_ON(d->irq != per_cpu(irq_in_progress, cpu));
++
++ per_cpu(plic_context, cpu)->claim = per_cpu(irq_in_progress, cpu);
++ per_cpu(irq_in_progress, cpu) = 0;
++}
++
++struct irq_chip plic_irq_chip = {
++ .name = "riscv",
++ .irq_mask = plic_irq_mask,
++ .irq_mask_ack = plic_irq_mask,
++ .irq_unmask = plic_irq_unmask,
++};
++
++void __init init_IRQ(void)
++{
++ /* Enable software interrupts (and disable the others) */
++ csr_write(sie, SIE_SSIE);
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/Makefile linux-4.6.2.riscv/arch/riscv/kernel/Makefile
+--- linux-4.6.2/arch/riscv/kernel/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/Makefile 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,15 @@
++#
++# Makefile for the RISC-V Linux kernel
++#
++
++extra-y := head.o vmlinux.lds
++
++obj-y := cpu.o entry.o irq.o process.o ptrace.o reset.o setup.o \
++ sbi.o signal.o syscall_table.o sys_riscv.o time.o traps.o \
++ stacktrace.o vdso.o vdso/
++
++obj-$(CONFIG_SMP) += smpboot.o smp.o
++obj-$(CONFIG_SBI_CONSOLE) += sbi-con.o
++obj-$(CONFIG_PCI) += pci.o
++
++clean:
+diff -Nur linux-4.6.2/arch/riscv/kernel/pci.c linux-4.6.2.riscv/arch/riscv/kernel/pci.c
+--- linux-4.6.2/arch/riscv/kernel/pci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/pci.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,23 @@
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++
++/*
++ * Called after each bus is probed, but before its children are examined
++ */
++void pcibios_fixup_bus(struct pci_bus *bus)
++{
++ /* nothing to do, expected to be removed in the future */
++}
++
++/*
++ * We don't have to worry about legacy ISA devices, so nothing to do here
++ */
++resource_size_t pcibios_align_resource(void *data, const struct resource *res,
++ resource_size_t size, resource_size_t align)
++{
++ return res->start;
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/process.c linux-4.6.2.riscv/arch/riscv/kernel/process.c
+--- linux-4.6.2/arch/riscv/kernel/process.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/process.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,106 @@
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/tick.h>
++#include <linux/ptrace.h>
++
++#include <asm/unistd.h>
++#include <asm/uaccess.h>
++#include <asm/processor.h>
++#include <asm/csr.h>
++#include <asm/string.h>
++#include <asm/switch_to.h>
++
++extern asmlinkage void ret_from_fork(void);
++extern asmlinkage void ret_from_kernel_thread(void);
++
++void arch_cpu_idle(void)
++{
++ wait_for_interrupt();
++ local_irq_enable();
++}
++
++void show_regs(struct pt_regs *regs)
++{
++ show_regs_print_info(KERN_DEFAULT);
++
++ printk("sepc: " REG_FMT " ra : " REG_FMT " sp : " REG_FMT "\n",
++ regs->sepc, regs->ra, regs->sp);
++ printk(" gp : " REG_FMT " tp : " REG_FMT " t0 : " REG_FMT "\n",
++ regs->gp, regs->tp, regs->t0);
++ printk(" t1 : " REG_FMT " t2 : " REG_FMT " s0 : " REG_FMT "\n",
++ regs->t1, regs->t2, regs->s0);
++ printk(" s1 : " REG_FMT " a0 : " REG_FMT " a1 : " REG_FMT "\n",
++ regs->s1, regs->a0, regs->a1);
++ printk(" a2 : " REG_FMT " a3 : " REG_FMT " a4 : " REG_FMT "\n",
++ regs->a2, regs->a3, regs->a4);
++ printk(" a5 : " REG_FMT " a6 : " REG_FMT " a7 : " REG_FMT "\n",
++ regs->a5, regs->a6, regs->a7);
++ printk(" s2 : " REG_FMT " s3 : " REG_FMT " s4 : " REG_FMT "\n",
++ regs->s2, regs->s3, regs->s4);
++ printk(" s5 : " REG_FMT " s6 : " REG_FMT " s7 : " REG_FMT "\n",
++ regs->s5, regs->s6, regs->s7);
++ printk(" s8 : " REG_FMT " s9 : " REG_FMT " s10: " REG_FMT "\n",
++ regs->s8, regs->s9, regs->s10);
++ printk(" s11: " REG_FMT " t3 : " REG_FMT " t4 : " REG_FMT "\n",
++ regs->s11, regs->t3, regs->t4);
++ printk(" t5 : " REG_FMT " t6 : " REG_FMT "\n",
++ regs->t5, regs->t6);
++
++ printk("sstatus: " REG_FMT " sbadaddr: " REG_FMT " scause: " REG_FMT "\n",
++ regs->sstatus, regs->sbadaddr, regs->scause);
++}
++
++void start_thread(struct pt_regs *regs, unsigned long pc,
++ unsigned long sp)
++{
++ regs->sstatus = SR_PIE /* User mode, irqs on */ | SR_FS_INITIAL;
++ regs->sepc = pc;
++ regs->sp = sp;
++ set_fs(USER_DS);
++}
++
++void flush_thread(void)
++{
++ /* Reset FPU context
++ * frm: round to nearest, ties to even (IEEE default)
++ * fflags: accrued exceptions cleared
++ */
++ memset(&current->thread.fstate, 0,
++ sizeof(struct user_fpregs_struct));
++}
++
++int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
++{
++ fstate_save(src, task_pt_regs(src));
++ *dst = *src;
++ return 0;
++}
++
++int copy_thread(unsigned long clone_flags, unsigned long usp,
++ unsigned long arg, struct task_struct *p)
++{
++ struct pt_regs *childregs = task_pt_regs(p);
++
++ /* p->thread holds context to be restored by __switch_to() */
++ if (unlikely(p->flags & PF_KTHREAD)) {
++ /* Kernel thread */
++ const register unsigned long gp __asm__ ("gp");
++ memset(childregs, 0, sizeof(struct pt_regs));
++ childregs->gp = gp;
++ childregs->sstatus = SR_PS | SR_PIE; /* Supervisor, irqs on */
++
++ p->thread.ra = (unsigned long)ret_from_kernel_thread;
++ p->thread.s[0] = usp; /* fn */
++ p->thread.s[1] = arg;
++ } else {
++ *childregs = *(current_pt_regs());
++ if (usp) /* User fork */
++ childregs->sp = usp;
++ if (clone_flags & CLONE_SETTLS)
++ childregs->tp = childregs->a5;
++ childregs->a0 = 0; /* Return value of fork() */
++ p->thread.ra = (unsigned long)ret_from_fork;
++ }
++ p->thread.sp = (unsigned long)childregs; /* kernel sp */
++ return 0;
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/ptrace.c linux-4.6.2.riscv/arch/riscv/kernel/ptrace.c
+--- linux-4.6.2/arch/riscv/kernel/ptrace.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/ptrace.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,128 @@
++#include <asm/ptrace.h>
++#include <asm/syscall.h>
++#include <asm/thread_info.h>
++#include <linux/ptrace.h>
++#include <linux/elf.h>
++#include <linux/regset.h>
++#include <linux/tracehook.h>
++#include <trace/events/syscalls.h>
++
++enum riscv_regset {
++ REGSET_X,
++};
++
++/*
++ * Get registers from task and ready the result for userspace.
++ */
++static char *getregs(struct task_struct *child, struct pt_regs *uregs)
++{
++ *uregs = *task_pt_regs(child);
++ return (char *)uregs;
++}
++
++/* Put registers back to task. */
++static void putregs(struct task_struct *child, struct pt_regs *uregs)
++{
++ struct pt_regs *regs = task_pt_regs(child);
++ *regs = *uregs;
++}
++
++static int riscv_gpr_get(struct task_struct *target,
++ const struct user_regset *regset,
++ unsigned int pos, unsigned int count,
++ void *kbuf, void __user *ubuf)
++{
++ struct pt_regs regs;
++
++ getregs(target, &regs);
++
++ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &regs, 0,
++ sizeof(regs));
++}
++
++static int riscv_gpr_set(struct task_struct *target,
++ const struct user_regset *regset,
++ unsigned int pos, unsigned int count,
++ const void *kbuf, const void __user *ubuf)
++{
++ int ret;
++ struct pt_regs regs;
++
++ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &regs, 0,
++ sizeof(regs));
++ if (ret)
++ return ret;
++
++ putregs(target, &regs);
++
++ return 0;
++}
++
++
++static const struct user_regset riscv_user_regset[] = {
++ [REGSET_X] = {
++ .core_note_type = NT_PRSTATUS,
++ .n = ELF_NGREG,
++ .size = sizeof(elf_greg_t),
++ .align = sizeof(elf_greg_t),
++ .get = &riscv_gpr_get,
++ .set = &riscv_gpr_set,
++ },
++};
++
++static const struct user_regset_view riscv_user_native_view = {
++ .name = "riscv",
++ .e_machine = EM_RISCV,
++ .regsets = riscv_user_regset,
++ .n = ARRAY_SIZE(riscv_user_regset),
++};
++
++const struct user_regset_view *task_user_regset_view(struct task_struct *task)
++{
++ return &riscv_user_native_view;
++}
++
++void ptrace_disable(struct task_struct *child)
++{
++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++}
++
++long arch_ptrace(struct task_struct *child, long request,
++ unsigned long addr, unsigned long data)
++{
++ long ret = -EIO;
++
++ switch (request) {
++ default:
++ ret = ptrace_request(child, request, addr, data);
++ break;
++ }
++
++ return ret;
++}
++
++/* Allows PTRACE_SYSCALL to work. These are called from entry.S in
++ * {handle,ret_from}_syscall. */
++void do_syscall_trace_enter(struct pt_regs *regs)
++{
++ if (test_thread_flag(TIF_SYSCALL_TRACE)) {
++ if (tracehook_report_syscall_entry(regs))
++ syscall_set_nr(current, regs, -1);
++ }
++
++#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
++ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
++ trace_sys_enter(regs, syscall_get_nr(current, regs));
++#endif
++}
++
++void do_syscall_trace_exit(struct pt_regs *regs)
++{
++ if (test_thread_flag(TIF_SYSCALL_TRACE))
++ tracehook_report_syscall_exit(regs, 0);
++
++#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
++ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
++ trace_sys_exit(regs, regs->regs[0]);
++#endif
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/reset.c linux-4.6.2.riscv/arch/riscv/kernel/reset.c
+--- linux-4.6.2/arch/riscv/kernel/reset.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/reset.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,19 @@
++#include <linux/reboot.h>
++#include <linux/export.h>
++#include <asm/sbi.h>
++
++void (*pm_power_off)(void) = machine_power_off;
++EXPORT_SYMBOL(pm_power_off);
++
++void machine_restart(char *cmd)
++{
++}
++
++void machine_halt(void)
++{
++}
++
++void machine_power_off(void)
++{
++ sbi_shutdown();
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/sbi-con.c linux-4.6.2.riscv/arch/riscv/kernel/sbi-con.c
+--- linux-4.6.2/arch/riscv/kernel/sbi-con.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/sbi-con.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,155 @@
++#include <linux/init.h>
++#include <linux/console.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/tty_driver.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++
++#include <asm/sbi.h>
++
++static DEFINE_SPINLOCK(sbi_tty_port_lock);
++static struct tty_port sbi_tty_port;
++static struct tty_driver *sbi_tty_driver;
++
++irqreturn_t sbi_console_isr(void)
++{
++ int ch = sbi_console_getchar();
++ if (ch < 0)
++ return IRQ_NONE;
++
++ spin_lock(&sbi_tty_port_lock);
++ tty_insert_flip_char(&sbi_tty_port, ch, TTY_NORMAL);
++ tty_flip_buffer_push(&sbi_tty_port);
++ spin_unlock(&sbi_tty_port_lock);
++
++ return IRQ_HANDLED;
++}
++
++static int sbi_tty_open(struct tty_struct *tty, struct file *filp)
++{
++ return 0;
++}
++
++static int sbi_tty_write(struct tty_struct *tty,
++ const unsigned char *buf, int count)
++{
++ const unsigned char *end;
++
++ for (end = buf + count; buf < end; buf++) {
++ sbi_console_putchar(*buf);
++ }
++ return count;
++}
++
++static int sbi_tty_write_room(struct tty_struct *tty)
++{
++ return 1024; /* arbitrary */
++}
++
++static const struct tty_operations sbi_tty_ops = {
++ .open = sbi_tty_open,
++ .write = sbi_tty_write,
++ .write_room = sbi_tty_write_room,
++};
++
++
++static void sbi_console_write(struct console *co, const char *buf, unsigned n)
++{
++ for ( ; n > 0; n--, buf++) {
++ if (*buf == '\n')
++ sbi_console_putchar('\r');
++ sbi_console_putchar(*buf);
++ }
++}
++
++static struct tty_driver *sbi_console_device(struct console *co, int *index)
++{
++ *index = co->index;
++ return sbi_tty_driver;
++}
++
++static int sbi_console_setup(struct console *co, char *options)
++{
++ return co->index != 0 ? -ENODEV : 0;
++}
++
++static struct console sbi_console = {
++ .name = "sbi_console",
++ .write = sbi_console_write,
++ .device = sbi_console_device,
++ .setup = sbi_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1
++};
++
++static int __init sbi_console_init(void)
++{
++ int ret;
++
++ register_console(&sbi_console);
++
++ sbi_tty_driver = tty_alloc_driver(1,
++ TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
++ if (unlikely(IS_ERR(sbi_tty_driver)))
++ return PTR_ERR(sbi_tty_driver);
++
++ sbi_tty_driver->driver_name = "sbi";
++ sbi_tty_driver->name = "ttySBI";
++ sbi_tty_driver->major = TTY_MAJOR;
++ sbi_tty_driver->minor_start = 0;
++ sbi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
++ sbi_tty_driver->subtype = SERIAL_TYPE_NORMAL;
++ sbi_tty_driver->init_termios = tty_std_termios;
++ tty_set_operations(sbi_tty_driver, &sbi_tty_ops);
++
++ tty_port_init(&sbi_tty_port);
++ tty_port_link_device(&sbi_tty_port, sbi_tty_driver, 0);
++
++ ret = tty_register_driver(sbi_tty_driver);
++ if (unlikely(ret))
++ goto out_tty_put;
++
++ /* Poll the console once, which will trigger future interrupts */
++ sbi_console_isr();
++
++ return ret;
++
++out_tty_put:
++ put_tty_driver(sbi_tty_driver);
++ return ret;
++}
++
++static void __exit sbi_console_exit(void)
++{
++ tty_unregister_driver(sbi_tty_driver);
++ put_tty_driver(sbi_tty_driver);
++}
++
++module_init(sbi_console_init);
++module_exit(sbi_console_exit);
++
++MODULE_DESCRIPTION("RISC-V SBI console driver");
++MODULE_LICENSE("GPL");
++
++#ifdef CONFIG_EARLY_PRINTK
++
++static struct console early_console_dev __initdata = {
++ .name = "early",
++ .write = sbi_console_write,
++ .flags = CON_PRINTBUFFER | CON_BOOT,
++ .index = -1
++};
++
++static int __init setup_early_printk(char *str)
++{
++ if (early_console == NULL) {
++ early_console = &early_console_dev;
++ register_console(early_console);
++ }
++ return 0;
++}
++
++early_param("earlyprintk", setup_early_printk);
++
++#endif
+diff -Nur linux-4.6.2/arch/riscv/kernel/sbi.S linux-4.6.2.riscv/arch/riscv/kernel/sbi.S
+--- linux-4.6.2/arch/riscv/kernel/sbi.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/sbi.S 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,15 @@
++.globl sbi_hart_id; sbi_hart_id = -2048
++.globl sbi_num_harts; sbi_num_harts = -2032
++.globl sbi_query_memory; sbi_query_memory = -2016
++.globl sbi_console_putchar; sbi_console_putchar = -2000
++.globl sbi_console_getchar; sbi_console_getchar = -1984
++.globl sbi_send_ipi; sbi_send_ipi = -1952
++.globl sbi_clear_ipi; sbi_clear_ipi = -1936
++.globl sbi_timebase; sbi_timebase = -1920
++.globl sbi_shutdown; sbi_shutdown = -1904
++.globl sbi_set_timer; sbi_set_timer = -1888
++.globl sbi_mask_interrupt; sbi_mask_interrupt = -1872
++.globl sbi_unmask_interrupt; sbi_unmask_interrupt = -1856
++.globl sbi_remote_sfence_vm; sbi_remote_sfence_vm = -1840
++.globl sbi_remote_sfence_vm_range; sbi_remote_sfence_vm_range = -1824
++.globl sbi_remote_fence_i; sbi_remote_fence_i = -1808
+diff -Nur linux-4.6.2/arch/riscv/kernel/setup.c linux-4.6.2.riscv/arch/riscv/kernel/setup.c
+--- linux-4.6.2/arch/riscv/kernel/setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/setup.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,161 @@
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/memblock.h>
++#include <linux/sched.h>
++#include <linux/initrd.h>
++#include <linux/console.h>
++#include <linux/screen_info.h>
++
++#include <asm/setup.h>
++#include <asm/sections.h>
++#include <asm/pgtable.h>
++#include <asm/smp.h>
++#include <asm/sbi.h>
++
++#ifdef CONFIG_DUMMY_CONSOLE
++struct screen_info screen_info = {
++ .orig_video_lines = 30,
++ .orig_video_cols = 80,
++ .orig_video_mode = 0,
++ .orig_video_ega_bx = 0,
++ .orig_video_isVGA = 1,
++ .orig_video_points = 8
++};
++#endif
++
++static char __initdata command_line[COMMAND_LINE_SIZE];
++#ifdef CONFIG_CMDLINE_BOOL
++static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
++#endif /* CONFIG_CMDLINE_BOOL */
++
++unsigned long va_pa_offset;
++unsigned long pfn_base;
++
++#ifdef CONFIG_BLK_DEV_INITRD
++static void __init setup_initrd(void)
++{
++ extern char __initramfs_start[];
++ extern unsigned long __initramfs_size;
++ unsigned long size;
++
++ if (__initramfs_size > 0) {
++ initrd_start = (unsigned long)(&__initramfs_start);
++ initrd_end = initrd_start + __initramfs_size;
++ }
++
++ if (initrd_start >= initrd_end) {
++ printk(KERN_INFO "initrd not found or empty");
++ goto disable;
++ }
++ if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) {
++ printk(KERN_ERR "initrd extends beyond end of memory");
++ goto disable;
++ }
++
++ size = initrd_end - initrd_start;
++ memblock_reserve(__pa(initrd_start), size);
++ initrd_below_start_ok = 1;
++
++ printk(KERN_INFO "Initial ramdisk at: 0x%p (%lu bytes)\n",
++ (void *)(initrd_start), size);
++ return;
++disable:
++ printk(KERN_CONT " - disabling initrd\n");
++ initrd_start = 0;
++ initrd_end = 0;
++}
++#endif /* CONFIG_BLK_DEV_INITRD */
++
++static resource_size_t __initdata mem_size;
++
++/* Parse "mem=nn[KkMmGg]" */
++static int __init early_mem(char *p)
++{
++ if (!p)
++ return -EINVAL;
++ mem_size = memparse(p, &p) & PMD_MASK;
++ if (mem_size == 0)
++ return -EINVAL;
++ return 0;
++}
++early_param("mem", early_mem);
++
++static void __init reserve_boot_page_table(pte_t *table)
++{
++ unsigned long i;
++
++ memblock_reserve(__pa(table), PAGE_SIZE);
++
++ for (i = 0; i < PTRS_PER_PTE; i++) {
++ if (pte_present(table[i]) && !pte_huge(table[i]))
++ reserve_boot_page_table(pfn_to_virt(pte_pfn(table[i])));
++ }
++}
++
++static void __init setup_bootmem(void)
++{
++ unsigned long ret;
++ memory_block_info info;
++
++ ret = sbi_query_memory(0, &info);
++ BUG_ON(ret != 0);
++ BUG_ON((info.base & ~PMD_MASK) != 0);
++ BUG_ON((info.size & ~PMD_MASK) != 0);
++ pr_info("Available physical memory: %ldMB\n", info.size >> 20);
++
++ /* The kernel image is mapped at VA=PAGE_OFFSET and PA=info.base */
++ va_pa_offset = PAGE_OFFSET - info.base;
++ pfn_base = PFN_DOWN(info.base);
++
++ if ((mem_size != 0) && (mem_size < info.size)) {
++ memblock_enforce_memory_limit(mem_size);
++ info.size = mem_size;
++ pr_notice("Physical memory usage limited to %lluMB\n",
++ (unsigned long long)(mem_size >> 20));
++ }
++ set_max_mapnr(PFN_DOWN(info.size));
++ max_low_pfn = PFN_DOWN(info.base + info.size);
++
++#ifdef CONFIG_BLK_DEV_INITRD
++ setup_initrd();
++#endif /* CONFIG_BLK_DEV_INITRD */
++
++ memblock_reserve(info.base, __pa(_end) - info.base);
++ reserve_boot_page_table(pfn_to_virt(csr_read(sptbr)));
++ memblock_allow_resize();
++}
++
++void __init setup_arch(char **cmdline_p)
++{
++#ifdef CONFIG_CMDLINE_BOOL
++#ifdef CONFIG_CMDLINE_OVERRIDE
++ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
++#else
++ if (builtin_cmdline[0] != '\0') {
++ /* Append bootloader command line to built-in */
++ strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
++ strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
++ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
++ }
++#endif /* CONFIG_CMDLINE_OVERRIDE */
++#endif /* CONFIG_CMDLINE_BOOL */
++ strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
++ *cmdline_p = command_line;
++
++ parse_early_param();
++
++ init_mm.start_code = (unsigned long) _stext;
++ init_mm.end_code = (unsigned long) _etext;
++ init_mm.end_data = (unsigned long) _edata;
++ init_mm.brk = (unsigned long) _end;
++
++ setup_bootmem();
++#ifdef CONFIG_SMP
++ setup_smp();
++#endif
++ paging_init();
++
++#ifdef CONFIG_DUMMY_CONSOLE
++ conswitchp = &dummy_con;
++#endif
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/signal.c linux-4.6.2.riscv/arch/riscv/kernel/signal.c
+--- linux-4.6.2/arch/riscv/kernel/signal.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/signal.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,236 @@
++#include <linux/signal.h>
++#include <linux/uaccess.h>
++#include <linux/syscalls.h>
++#include <linux/tracehook.h>
++#include <linux/linkage.h>
++
++#include <asm/ucontext.h>
++#include <asm/vdso.h>
++#include <asm/switch_to.h>
++#include <asm/csr.h>
++
++#define DEBUG_SIG 0
++
++struct rt_sigframe {
++ struct siginfo info;
++ struct ucontext uc;
++};
++
++static long restore_sigcontext(struct pt_regs *regs,
++ struct sigcontext __user *sc)
++{
++ struct task_struct *task = current;
++ long err;
++ /* sc_regs is structured the same as the start of pt_regs */
++ err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
++ err |= __copy_from_user(&task->thread.fstate, &sc->sc_fpregs,
++ sizeof(sc->sc_fpregs));
++ if (likely(!err))
++ fstate_restore(task, regs);
++ return err;
++}
++
++SYSCALL_DEFINE0(rt_sigreturn)
++{
++ struct pt_regs *regs = current_pt_regs();
++ struct rt_sigframe __user *frame;
++ struct task_struct *task;
++ sigset_t set;
++
++ /* Always make any pending restarted system calls return -EINTR */
++ current->restart_block.fn = do_no_restart_syscall;
++
++ frame = (struct rt_sigframe __user *)regs->sp;
++
++ if (!access_ok(VERIFY_READ, 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->a0;
++
++badframe:
++ task = current;
++ if (show_unhandled_signals) {
++ pr_info_ratelimited("%s[%d]: bad frame in %s: "
++ "frame=%p pc=%p sp=%p\n",
++ task->comm, task_pid_nr(task), __func__,
++ frame, (void *)regs->sepc, (void *)regs->sp);
++ }
++ force_sig(SIGSEGV, task);
++ return 0;
++}
++
++static long setup_sigcontext(struct sigcontext __user *sc,
++ struct pt_regs *regs)
++{
++ struct task_struct *task = current;
++ long err;
++ /* sc_regs is structured the same as the start of pt_regs */
++ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
++ fstate_save(task, regs);
++ err |= __copy_to_user(&sc->sc_fpregs, &task->thread.fstate,
++ sizeof(sc->sc_fpregs));
++ return err;
++}
++
++static inline void __user *get_sigframe(struct ksignal *ksig,
++ struct pt_regs *regs, size_t framesize)
++{
++ unsigned long sp;
++ /* Default to using normal stack */
++ sp = regs->sp;
++
++ /*
++ * If we are on the alternate signal stack and would overflow it, don't.
++ * Return an always-bogus address instead so we will die with SIGSEGV.
++ */
++ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
++ return (void __user __force *)(-1UL);
++
++ /* This is the X/Open sanctioned signal stack switching. */
++ sp = sigsp(sp, ksig) - framesize;
++
++ /* Align the stack frame. */
++ sp &= ~0xfUL;
++
++ return (void __user *)sp;
++}
++
++
++static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
++ struct pt_regs *regs)
++{
++ struct rt_sigframe __user *frame;
++ long err = 0;
++
++ frame = get_sigframe(ksig, regs, sizeof(*frame));
++ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
++ return -EFAULT;
++
++ 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(&frame->uc.uc_mcontext, regs);
++ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
++ if (err)
++ return -EFAULT;
++
++ /* Set up to return from userspace. */
++ regs->ra = (unsigned long)VDSO_SYMBOL(
++ current->mm->context.vdso, rt_sigreturn);
++
++ /*
++ * Set up registers for signal handler.
++ * Registers that we don't modify keep the value they had from
++ * user-space at the time we took the signal.
++ * We always pass siginfo and mcontext, regardless of SA_SIGINFO,
++ * since some things rely on this (e.g. glibc's debug/segfault.c).
++ */
++ regs->sepc = (unsigned long)ksig->ka.sa.sa_handler;
++ regs->sp = (unsigned long)frame;
++ regs->a0 = ksig->sig; /* a0: signal number */
++ regs->a1 = (unsigned long)(&frame->info); /* a1: siginfo pointer */
++ regs->a2 = (unsigned long)(&frame->uc); /* a2: ucontext pointer */
++
++#if DEBUG_SIG
++ pr_info("SIG deliver (%s:%d): sig=%d pc=%p ra=%p sp=%p\n",
++ current->comm, task_pid_nr(current), ksig->sig,
++ (void *)regs->sepc, (void *)regs->ra, frame);
++#endif
++
++ return 0;
++}
++
++static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
++{
++ sigset_t *oldset = sigmask_to_save();
++ int ret;
++
++ /* Are we from a system call? */
++ if (regs->scause == EXC_SYSCALL) {
++ /* If so, check system call restarting.. */
++ switch (regs->a0) {
++ case -ERESTART_RESTARTBLOCK:
++ case -ERESTARTNOHAND:
++ regs->a0 = -EINTR;
++ break;
++
++ case -ERESTARTSYS:
++ if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
++ regs->a0 = -EINTR;
++ break;
++ }
++ /* fallthrough */
++ case -ERESTARTNOINTR:
++ regs->sepc -= 0x4;
++ break;
++ }
++ }
++
++ /* Set up the stack frame */
++ ret = setup_rt_frame(ksig, oldset, regs);
++
++ signal_setup_done(ret, ksig, 0);
++}
++
++static void do_signal(struct pt_regs *regs)
++{
++ struct ksignal ksig;
++
++ if (get_signal(&ksig)) {
++ /* Actually deliver the signal */
++ handle_signal(&ksig, regs);
++ return;
++ }
++
++ /* Did we come from a system call? */
++ if (regs->scause == EXC_SYSCALL) {
++ /* Restart the system call - no handlers present */
++ switch (regs->a0) {
++ case -ERESTARTNOHAND:
++ case -ERESTARTSYS:
++ case -ERESTARTNOINTR:
++ regs->sepc -= 0x4;
++ break;
++ case -ERESTART_RESTARTBLOCK:
++ regs->a7 = __NR_restart_syscall;
++ regs->sepc -= 0x4;
++ break;
++ }
++ }
++
++ /* If there is no signal to deliver, we just put the saved
++ sigmask back. */
++ restore_saved_sigmask();
++}
++
++/*
++ * notification of userspace execution resumption
++ * - triggered by the _TIF_WORK_MASK flags
++ */
++asmlinkage void do_notify_resume(struct pt_regs *regs,
++ unsigned long thread_info_flags)
++{
++ /* Handle pending signal delivery */
++ if (thread_info_flags & _TIF_SIGPENDING) {
++ do_signal(regs);
++ }
++
++ if (thread_info_flags & _TIF_NOTIFY_RESUME) {
++ clear_thread_flag(TIF_NOTIFY_RESUME);
++ tracehook_notify_resume(regs);
++ }
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/smpboot.c linux-4.6.2.riscv/arch/riscv/kernel/smpboot.c
+--- linux-4.6.2/arch/riscv/kernel/smpboot.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/smpboot.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,72 @@
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/kernel_stat.h>
++#include <linux/notifier.h>
++#include <linux/cpu.h>
++#include <linux/percpu.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/irq.h>
++#include <asm/mmu_context.h>
++#include <asm/tlbflush.h>
++#include <asm/sections.h>
++#include <asm/sbi.h>
++
++void *__cpu_up_stack_pointer[NR_CPUS];
++
++void __init smp_prepare_boot_cpu(void)
++{
++}
++
++void __init smp_prepare_cpus(unsigned int max_cpus)
++{
++}
++
++void __init setup_smp(void)
++{
++ int i, num_cpus = sbi_num_harts();
++
++ for (i = 0; i < min(num_cpus, NR_CPUS); i++) {
++ set_cpu_possible(i, true);
++ set_cpu_present(i, true);
++ }
++}
++
++int __cpu_up(unsigned int cpu, struct task_struct *tidle)
++{
++ /* Signal cpu to start */
++ __cpu_up_stack_pointer[cpu] = task_stack_page(tidle) + THREAD_SIZE;
++
++ while (!cpu_online(cpu))
++ ;
++
++ return 0;
++}
++
++void __init smp_cpus_done(unsigned int max_cpus)
++{
++}
++
++/*
++ * C entry point for a secondary processor.
++ */
++asmlinkage void __init smp_callin(void)
++{
++ struct mm_struct *mm = &init_mm;
++
++ /* All kernel threads share the same mm context. */
++ atomic_inc(&mm->mm_count);
++ current->active_mm = mm;
++
++ trap_init();
++ init_clockevent();
++ notify_cpu_starting(smp_processor_id());
++ set_cpu_online(smp_processor_id(), 1);
++ local_flush_tlb_all();
++ local_irq_enable();
++ preempt_disable();
++ cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/smp.c linux-4.6.2.riscv/arch/riscv/kernel/smp.c
+--- linux-4.6.2/arch/riscv/kernel/smp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/smp.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,85 @@
++#include <linux/interrupt.h>
++#include <linux/smp.h>
++#include <linux/sched.h>
++
++#include <asm/sbi.h>
++#include <asm/tlbflush.h>
++#include <asm/cacheflush.h>
++
++/* A collection of single bit ipi messages. */
++static struct {
++ unsigned long bits ____cacheline_aligned;
++} ipi_data[NR_CPUS] __cacheline_aligned;
++
++enum ipi_message_type {
++ IPI_RESCHEDULE,
++ IPI_CALL_FUNC,
++ IPI_MAX
++};
++
++irqreturn_t handle_ipi(void)
++{
++ unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
++ unsigned long ops;
++
++ /* Clear pending IPI */
++ if (!sbi_clear_ipi())
++ return IRQ_NONE;
++
++ mb(); /* Order interrupt and bit testing. */
++ while ((ops = xchg(pending_ipis, 0)) != 0) {
++ mb(); /* Order bit clearing and data access. */
++
++ if (ops & (1 << IPI_RESCHEDULE))
++ scheduler_ipi();
++
++ if (ops & (1 << IPI_CALL_FUNC))
++ generic_smp_call_function_interrupt();
++
++ BUG_ON((ops >> IPI_MAX) != 0);
++
++ mb(); /* Order data access and bit testing. */
++ }
++
++ return IRQ_HANDLED;
++}
++
++static void
++send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
++{
++ int i;
++
++ mb();
++ for_each_cpu(i, to_whom)
++ set_bit(operation, &ipi_data[i].bits);
++
++ mb();
++ for_each_cpu(i, to_whom)
++ sbi_send_ipi(i);
++}
++
++void arch_send_call_function_ipi_mask(struct cpumask *mask)
++{
++ send_ipi_message(mask, IPI_CALL_FUNC);
++}
++
++void arch_send_call_function_single_ipi(int cpu)
++{
++ send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC);
++}
++
++static void ipi_stop(void *unused)
++{
++ while (1)
++ wait_for_interrupt();
++}
++
++void smp_send_stop(void)
++{
++ on_each_cpu(ipi_stop, NULL, 1);
++}
++
++void smp_send_reschedule(int cpu)
++{
++ send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/stacktrace.c linux-4.6.2.riscv/arch/riscv/kernel/stacktrace.c
+--- linux-4.6.2/arch/riscv/kernel/stacktrace.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/stacktrace.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,163 @@
++#include <linux/export.h>
++#include <linux/kallsyms.h>
++#include <linux/sched.h>
++#include <linux/stacktrace.h>
++
++#ifdef CONFIG_FRAME_POINTER
++
++struct stackframe {
++ unsigned long fp;
++ unsigned long ra;
++};
++
++static void notrace walk_stackframe(struct task_struct *task,
++ struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg)
++{
++ unsigned long fp, sp, pc;
++
++ if (regs) {
++ fp = GET_FP(regs);
++ sp = GET_USP(regs);
++ pc = GET_IP(regs);
++ } else if (task == NULL || task == current) {
++ const register unsigned long current_sp __asm__ ("sp");
++ fp = (unsigned long)__builtin_frame_address(0);
++ sp = current_sp;
++ pc = (unsigned long)walk_stackframe;
++ } else {
++ /* task blocked in __switch_to */
++ fp = task->thread.s[0];
++ sp = task->thread.sp;
++ pc = task->thread.ra;
++ }
++
++ for (;;) {
++ unsigned long low, high;
++ struct stackframe *frame;
++
++ if (unlikely(!__kernel_text_address(pc) || fn(pc, arg)))
++ break;
++
++ /* Validate frame pointer */
++ low = sp + sizeof(struct stackframe);
++ high = ALIGN(sp, THREAD_SIZE);
++ if (unlikely(fp < low || fp > high || fp & 0x7))
++ break;
++ /* Unwind stack frame */
++ frame = (struct stackframe *)fp - 1;
++ sp = fp;
++ fp = frame->fp;
++ pc = frame->ra - 0x4;
++ }
++}
++
++#else /* !CONFIG_FRAME_POINTER */
++
++static void notrace walk_stackframe(struct task_struct *task,
++ struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg)
++{
++ unsigned long sp, pc;
++ unsigned long *ksp;
++
++ if (regs) {
++ sp = GET_USP(regs);
++ pc = GET_IP(regs);
++ } else if (task == NULL || task == current) {
++ const register unsigned long current_sp __asm__ ("sp");
++ sp = current_sp;
++ pc = (unsigned long)walk_stackframe;
++ } else {
++ /* task blocked in __switch_to */
++ sp = task->thread.sp;
++ pc = task->thread.ra;
++ }
++
++ if (unlikely(sp & 0x7))
++ return;
++
++ ksp = (unsigned long *)sp;
++ while (!kstack_end(ksp)) {
++ if (__kernel_text_address(pc) && unlikely(fn(pc, arg))) {
++ break;
++ }
++ pc = (*ksp++) - 0x4;
++ }
++}
++
++#endif /* CONFIG_FRAME_POINTER */
++
++
++static bool print_trace_address(unsigned long pc, void *arg)
++{
++ print_ip_sym(pc);
++ return false;
++}
++
++void show_stack(struct task_struct *task, unsigned long *sp)
++{
++ printk("Call Trace:\n");
++ walk_stackframe(task, NULL, print_trace_address, NULL);
++}
++
++
++static bool save_wchan(unsigned long pc, void *arg)
++{
++ if (!in_sched_functions(pc)) {
++ unsigned long *p = arg;
++ *p = pc;
++ return true;
++ }
++ return false;
++}
++
++unsigned long get_wchan(struct task_struct *task)
++{
++ unsigned long pc;
++ pc = 0;
++ if (likely(task && task != current && task->state != TASK_RUNNING)) {
++ walk_stackframe(task, NULL, save_wchan, &pc);
++ }
++ return pc;
++}
++
++
++#ifdef CONFIG_STACKTRACE
++
++static bool __save_trace(unsigned long pc, void *arg, bool nosched)
++{
++ struct stack_trace *trace = arg;
++
++ if (unlikely(nosched && in_sched_functions(pc)))
++ return false;
++ if (unlikely(trace->skip > 0)) {
++ trace->skip--;
++ return false;
++ }
++
++ trace->entries[trace->nr_entries++] = pc;
++ return (trace->nr_entries >= trace->max_entries);
++}
++
++static bool save_trace(unsigned long pc, void *arg)
++{
++ return __save_trace(pc, arg, false);
++}
++
++/*
++ * Save stack-backtrace addresses into a stack_trace buffer.
++ */
++void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
++{
++ walk_stackframe(tsk, NULL, save_trace, trace);
++ if (trace->nr_entries < trace->max_entries)
++ trace->entries[trace->nr_entries++] = ULONG_MAX;
++}
++EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
++
++void save_stack_trace(struct stack_trace *trace)
++{
++ save_stack_trace_tsk(NULL, trace);
++}
++EXPORT_SYMBOL_GPL(save_stack_trace);
++
++#endif /* CONFIG_STACKTRACE */
+diff -Nur linux-4.6.2/arch/riscv/kernel/syscall_table.c linux-4.6.2.riscv/arch/riscv/kernel/syscall_table.c
+--- linux-4.6.2/arch/riscv/kernel/syscall_table.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/syscall_table.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,10 @@
++#include <linux/syscalls.h>
++
++#include <asm/syscalls.h>
++
++#undef __SYSCALL
++#define __SYSCALL(nr, call) [nr] = (call),
++
++void *sys_call_table[__NR_syscalls] = {
++#include <asm/unistd.h>
++};
+diff -Nur linux-4.6.2/arch/riscv/kernel/sys_riscv.c linux-4.6.2.riscv/arch/riscv/kernel/sys_riscv.c
+--- linux-4.6.2/arch/riscv/kernel/sys_riscv.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/sys_riscv.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,70 @@
++#include <linux/syscalls.h>
++#include <asm/unistd.h>
++
++SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
++ unsigned long, prot, unsigned long, flags,
++ unsigned long, fd, off_t, offset)
++{
++ if (unlikely(offset & (~PAGE_MASK)))
++ return -EINVAL;
++ return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
++}
++
++#ifndef CONFIG_64BIT
++SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
++ unsigned long, prot, unsigned long, flags,
++ unsigned long, fd, off_t, offset)
++{
++ /* Note that the shift for mmap2 is constant (12),
++ regardless of PAGE_SIZE */
++ if (unlikely(offset & (~PAGE_MASK >> 12)))
++ return -EINVAL;
++ return sys_mmap_pgoff(addr, len, prot, flags, fd,
++ offset >> (PAGE_SHIFT - 12));
++}
++#endif /* !CONFIG_64BIT */
++
++#ifdef CONFIG_RV_SYSRISCV_ATOMIC
++SYSCALL_DEFINE4(sysriscv, unsigned long, cmd, unsigned long, arg1,
++ unsigned long, arg2, unsigned long, arg3)
++{
++ unsigned long flags;
++ unsigned long prev;
++ unsigned int *ptr;
++ unsigned int err;
++
++ switch (cmd) {
++ case RISCV_ATOMIC_CMPXCHG:
++ ptr = (unsigned int *)arg1;
++ if (!access_ok(VERIFY_WRITE, ptr, sizeof(unsigned int)))
++ return -EFAULT;
++
++ preempt_disable();
++ raw_local_irq_save(flags);
++ err = __get_user(prev, ptr);
++ if (likely(!err && prev == arg2))
++ err = __put_user(arg3, ptr);
++ raw_local_irq_restore(flags);
++ preempt_enable();
++
++ return unlikely(err) ? err : prev;
++
++ case RISCV_ATOMIC_CMPXCHG64:
++ ptr = (unsigned int *)arg1;
++ if (!access_ok(VERIFY_WRITE, ptr, sizeof(unsigned long)))
++ return -EFAULT;
++
++ preempt_disable();
++ raw_local_irq_save(flags);
++ err = __get_user(prev, ptr);
++ if (likely(!err && prev == arg2))
++ err = __put_user(arg3, ptr);
++ raw_local_irq_restore(flags);
++ preempt_enable();
++
++ return unlikely(err) ? err : prev;
++ }
++
++ return -EINVAL;
++}
++#endif /* CONFIG_RV_SYSRISCV_ATOMIC */
+diff -Nur linux-4.6.2/arch/riscv/kernel/time.c linux-4.6.2.riscv/arch/riscv/kernel/time.c
+--- linux-4.6.2/arch/riscv/kernel/time.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/time.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,88 @@
++#include <linux/clocksource.h>
++#include <linux/clockchips.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/delay.h>
++
++#include <asm/irq.h>
++#include <asm/csr.h>
++#include <asm/sbi.h>
++#include <asm/delay.h>
++
++unsigned long timebase;
++
++static DEFINE_PER_CPU(struct clock_event_device, clock_event);
++
++static int riscv_timer_set_next_event(unsigned long delta,
++ struct clock_event_device *evdev)
++{
++ sbi_set_timer(get_cycles() + delta);
++ return 0;
++}
++
++static int riscv_timer_set_oneshot(struct clock_event_device *evt)
++{
++ /* no-op; only one mode */
++ return 0;
++}
++
++static int riscv_timer_set_shutdown(struct clock_event_device *evt)
++{
++ /* can't stop the clock! */
++ return 0;
++}
++
++static cycle_t riscv_rdtime(struct clocksource *cs)
++{
++ return get_cycles();
++}
++
++static struct clocksource riscv_clocksource = {
++ .name = "riscv_clocksource",
++ .rating = 300,
++ .read = riscv_rdtime,
++#ifdef CONFIG_64BITS
++ .mask = CLOCKSOURCE_MASK(64),
++#else
++ .mask = CLOCKSOURCE_MASK(32),
++#endif /* CONFIG_64BITS */
++ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
++};
++
++void riscv_timer_interrupt(void)
++{
++ int cpu = smp_processor_id();
++ struct clock_event_device *evdev = &per_cpu(clock_event, cpu);
++ evdev->event_handler(evdev);
++}
++
++void __init init_clockevent(void)
++{
++ int cpu = smp_processor_id();
++ struct clock_event_device *ce = &per_cpu(clock_event, cpu);
++
++ *ce = (struct clock_event_device){
++ .name = "riscv_timer_clockevent",
++ .features = CLOCK_EVT_FEAT_ONESHOT,
++ .rating = 300,
++ .cpumask = cpumask_of(cpu),
++ .set_next_event = riscv_timer_set_next_event,
++ .set_state_oneshot = riscv_timer_set_oneshot,
++ .set_state_shutdown = riscv_timer_set_shutdown,
++ };
++
++ clockevents_config_and_register(ce, sbi_timebase(), 100, 0x7fffffff);
++}
++
++void __init time_init(void)
++{
++ timebase = sbi_timebase();
++ lpj_fine = timebase;
++ do_div(lpj_fine, HZ);
++
++ clocksource_register_hz(&riscv_clocksource, timebase);
++ init_clockevent();
++
++ /* Enable timer interrupts. */
++ csr_set(sie, SIE_STIE);
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/traps.c linux-4.6.2.riscv/arch/riscv/kernel/traps.c
+--- linux-4.6.2/arch/riscv/kernel/traps.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/traps.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,146 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/kdebug.h>
++#include <linux/uaccess.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++
++#include <asm/processor.h>
++#include <asm/ptrace.h>
++#include <asm/csr.h>
++
++int show_unhandled_signals = 1;
++
++extern asmlinkage void handle_exception(void);
++
++static DEFINE_SPINLOCK(die_lock);
++
++void die(struct pt_regs *regs, const char *str)
++{
++ static int die_counter;
++ int ret;
++
++ oops_enter();
++
++ spin_lock_irq(&die_lock);
++ console_verbose();
++ bust_spinlocks(1);
++
++ pr_emerg("%s [#%d]\n", str, ++die_counter);
++ print_modules();
++ show_regs(regs);
++
++ ret = notify_die(DIE_OOPS, str, regs, 0, regs->scause, SIGSEGV);
++
++ bust_spinlocks(0);
++ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
++ spin_unlock_irq(&die_lock);
++ oops_exit();
++
++ if (in_interrupt())
++ panic("Fatal exception in interrupt");
++ if (panic_on_oops)
++ panic("Fatal exception");
++ if (ret != NOTIFY_STOP)
++ do_exit(SIGSEGV);
++}
++
++static inline void do_trap_siginfo(int signo, int code,
++ unsigned long addr, struct task_struct *tsk)
++{
++ siginfo_t info;
++
++ info.si_signo = signo;
++ info.si_errno = 0;
++ info.si_code = code;
++ info.si_addr = (void __user *)addr;
++ force_sig_info(signo, &info, tsk);
++}
++
++void do_trap(struct pt_regs *regs, int signo, int code,
++ unsigned long addr, struct task_struct *tsk)
++{
++ if (show_unhandled_signals && unhandled_signal(tsk, signo)
++ && printk_ratelimit()) {
++ pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x" REG_FMT,
++ tsk->comm, task_pid_nr(tsk), signo, code, addr);
++ print_vma_addr(KERN_CONT " in ", GET_IP(regs));
++ pr_cont("\n");
++ show_regs(regs);
++ }
++
++ do_trap_siginfo(signo, code, addr, tsk);
++}
++
++static void do_trap_error(struct pt_regs *regs, int signo, int code,
++ unsigned long addr, const char *str)
++{
++ if (user_mode(regs)) {
++ do_trap(regs, signo, code, addr, current);
++ } else {
++ if (!fixup_exception(regs))
++ die(regs, str);
++ }
++}
++
++#define DO_ERROR_INFO(name, signo, code, str) \
++asmlinkage void name(struct pt_regs *regs) \
++{ \
++ do_trap_error(regs, signo, code, regs->sepc, "Oops - " str); \
++}
++
++DO_ERROR_INFO(do_trap_unknown,
++ SIGILL, ILL_ILLTRP, "unknown exception");
++DO_ERROR_INFO(do_trap_amo_misaligned,
++ SIGBUS, BUS_ADRALN, "AMO address misaligned");
++DO_ERROR_INFO(do_trap_insn_misaligned,
++ SIGBUS, BUS_ADRALN, "instruction address misaligned");
++DO_ERROR_INFO(do_trap_insn_illegal,
++ SIGILL, ILL_ILLOPC, "illegal instruction");
++
++asmlinkage void do_trap_break(struct pt_regs *regs)
++{
++#ifdef CONFIG_GENERIC_BUG
++ if (!user_mode(regs)) {
++ enum bug_trap_type type;
++
++ type = report_bug(regs->sepc, regs);
++ switch (type) {
++ case BUG_TRAP_TYPE_NONE:
++ break;
++ case BUG_TRAP_TYPE_WARN:
++ regs->sepc += sizeof(bug_insn_t);
++ return;
++ case BUG_TRAP_TYPE_BUG:
++ die(regs, "Kernel BUG");
++ }
++ }
++#endif /* CONFIG_GENERIC_BUG */
++
++ do_trap_siginfo(SIGTRAP, TRAP_BRKPT, regs->sepc, current);
++ regs->sepc += 0x4;
++}
++
++#ifdef CONFIG_GENERIC_BUG
++int is_valid_bugaddr(unsigned long pc)
++{
++ bug_insn_t insn;
++
++ if (pc < PAGE_OFFSET)
++ return 0;
++ if (probe_kernel_address((bug_insn_t __user *)pc, insn))
++ return 0;
++ return (insn == __BUG_INSN);
++}
++#endif /* CONFIG_GENERIC_BUG */
++
++void __init trap_init(void)
++{
++ /* Set sup0 scratch register to 0, indicating to exception vector
++ that we are presently executing in the kernel */
++ csr_write(sscratch, 0);
++ /* Set the exception vector address */
++ csr_write(stvec, &handle_exception);
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/vdso/.gitignore linux-4.6.2.riscv/arch/riscv/kernel/vdso/.gitignore
+--- linux-4.6.2/arch/riscv/kernel/vdso/.gitignore 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/vdso/.gitignore 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1 @@
++vdso.lds
+diff -Nur linux-4.6.2/arch/riscv/kernel/vdso/Makefile linux-4.6.2.riscv/arch/riscv/kernel/vdso/Makefile
+--- linux-4.6.2/arch/riscv/kernel/vdso/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/vdso/Makefile 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,61 @@
++# Derived from arch/{arm64,tile}/kernel/vdso/Makefile
++
++obj-vdso := sigreturn.o
++
++# Build rules
++targets := $(obj-vdso) vdso.so vdso.so.dbg
++obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
++
++#ccflags-y := -shared -fno-common -fno-builtin
++#ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \
++ $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
++
++CFLAGS_vdso.so = $(c_flags)
++CFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \
++ $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
++CFLAGS_vdso_syms.o = -r
++
++obj-y += vdso.o
++
++# We also create a special relocatable object that should mirror the symbol
++# table and layout of the linked DSO. With ld -R we can then refer to
++# these symbols in the kernel code rather than hand-coded addresses.
++extra-y += vdso.lds vdso-syms.o
++$(obj)/built-in.o: $(obj)/vdso-syms.o
++$(obj)/built-in.o: ld_flags += -R $(obj)/vdso-syms.o
++
++CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
++
++# Force dependency
++$(obj)/vdso.o : $(obj)/vdso.so
++
++# Link rule for the *.so file; *.lds must be first
++$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso)
++ $(call if_changed,vdsold)
++$(obj)/vdso-syms.o: $(src)/vdso.lds $(obj-vdso)
++ $(call if_changed,vdsold)
++
++# Strip rule for the *.so file
++$(obj)/%.so: OBJCOPYFLAGS := -S
++$(obj)/%.so: $(obj)/%.so.dbg FORCE
++ $(call if_changed,objcopy)
++
++# Assembly rules for the *.S files
++$(obj-vdso): %.o: %.S
++ $(call if_changed_dep,vdsoas)
++
++# Actual build commands
++quiet_cmd_vdsold = VDSOLD $@
++ cmd_vdsold = $(CC) $(c_flags) -nostdlib $(CFLAGS_$(@F)) -Wl,-n -Wl,-T $^ -o $@
++quiet_cmd_vdsoas = VDSOAS $@
++ cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $<
++
++# Install commands for the unstripped file
++quiet_cmd_vdso_install = INSTALL $@
++ cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
++
++vdso.so: $(obj)/vdso.so.dbg
++ @mkdir -p $(MODLIB)/vdso
++ $(call cmd,vdso_install)
++
++vdso_install: vdso.so
+diff -Nur linux-4.6.2/arch/riscv/kernel/vdso/sigreturn.S linux-4.6.2.riscv/arch/riscv/kernel/vdso/sigreturn.S
+--- linux-4.6.2/arch/riscv/kernel/vdso/sigreturn.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/vdso/sigreturn.S 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,11 @@
++#include <linux/linkage.h>
++#include <asm/unistd.h>
++
++ .text
++ENTRY(__vdso_rt_sigreturn)
++ .cfi_startproc
++ .cfi_signal_frame
++ li a7, __NR_rt_sigreturn
++ scall
++ .cfi_endproc
++ENDPROC(__vdso_rt_sigreturn)
+diff -Nur linux-4.6.2/arch/riscv/kernel/vdso/vdso.lds.S linux-4.6.2.riscv/arch/riscv/kernel/vdso/vdso.lds.S
+--- linux-4.6.2/arch/riscv/kernel/vdso/vdso.lds.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/vdso/vdso.lds.S 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,63 @@
++OUTPUT_ARCH(riscv)
++
++SECTIONS
++{
++ . = SIZEOF_HEADERS;
++
++ .hash : { *(.hash) } :text
++ .gnu.hash : { *(.gnu.hash) }
++ .dynsym : { *(.dynsym) }
++ .dynstr : { *(.dynstr) }
++ .gnu.version : { *(.gnu.version) }
++ .gnu.version_d : { *(.gnu.version_d) }
++ .gnu.version_r : { *(.gnu.version_r) }
++
++ .note : { *(.note.*) } :text :note
++ .dynamic : { *(.dynamic) } :text :dynamic
++
++ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
++ .eh_frame : { KEEP (*(.eh_frame)) } :text
++
++ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
++
++ /*
++ * This linker script is used both with -r and with -shared.
++ * For the layouts to match, we need to skip more than enough
++ * space for the dynamic symbol table, etc. If this amount is
++ * insufficient, ld -shared will error; simply increase it here.
++ */
++ . = 0x800;
++ .text : { *(.text .text.*) } :text
++
++ .data : {
++ *(.got.plt) *(.got)
++ *(.data .data.* .gnu.linkonce.d.*)
++ *(.dynbss)
++ *(.bss .bss.* .gnu.linkonce.b.*)
++ }
++}
++
++/*
++ * We must supply the ELF program headers explicitly to get just one
++ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
++ */
++PHDRS
++{
++ text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
++ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
++ note PT_NOTE FLAGS(4); /* PF_R */
++ eh_frame_hdr PT_GNU_EH_FRAME;
++}
++
++/*
++ * This controls what symbols we export from the DSO.
++ */
++VERSION
++{
++ LINUX_2.6 {
++ global:
++ __vdso_rt_sigreturn;
++ local: *;
++ };
++}
++
+diff -Nur linux-4.6.2/arch/riscv/kernel/vdso/vdso.S linux-4.6.2.riscv/arch/riscv/kernel/vdso/vdso.S
+--- linux-4.6.2/arch/riscv/kernel/vdso/vdso.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/vdso/vdso.S 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,14 @@
++#include <linux/init.h>
++#include <linux/linkage.h>
++#include <asm/page.h>
++
++ __PAGE_ALIGNED_DATA
++
++ .globl vdso_start, vdso_end
++ .balign PAGE_SIZE
++vdso_start:
++ .incbin "arch/riscv/kernel/vdso/vdso.so"
++ .balign PAGE_SIZE
++vdso_end:
++
++ .previous
+diff -Nur linux-4.6.2/arch/riscv/kernel/vdso.c linux-4.6.2.riscv/arch/riscv/kernel/vdso.c
+--- linux-4.6.2/arch/riscv/kernel/vdso.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/vdso.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,106 @@
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/binfmts.h>
++#include <linux/err.h>
++
++#include <asm/vdso.h>
++
++extern char vdso_start[], vdso_end[];
++
++static unsigned int vdso_pages;
++static struct page **vdso_pagelist;
++
++/*
++ * The vDSO data page.
++ */
++static union {
++ struct vdso_data data;
++ u8 page[PAGE_SIZE];
++} vdso_data_store __page_aligned_data;
++struct vdso_data *vdso_data = &vdso_data_store.data;
++
++static int __init vdso_init(void)
++{
++ unsigned int i;
++
++ vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT;
++ vdso_pagelist = kzalloc(sizeof(struct page *) * (vdso_pages + 1), GFP_KERNEL);
++ if (unlikely(vdso_pagelist == NULL)) {
++ pr_err("vdso: pagelist allocation failed\n");
++ return -ENOMEM;
++ }
++
++ for (i = 0; i < vdso_pages; i++) {
++ struct page *pg;
++ pg = virt_to_page(vdso_start + (i << PAGE_SHIFT));
++ ClearPageReserved(pg);
++ vdso_pagelist[i] = pg;
++ }
++ vdso_pagelist[i] = virt_to_page(vdso_data);
++
++ return 0;
++}
++arch_initcall(vdso_init);
++
++int arch_setup_additional_pages(struct linux_binprm *bprm,
++ int uses_interp)
++{
++ struct mm_struct *mm = current->mm;
++ unsigned long vdso_base, vdso_len;
++ int ret;
++
++ vdso_len = (vdso_pages + 1) << PAGE_SHIFT;
++
++ down_write(&mm->mmap_sem);
++ vdso_base = get_unmapped_area(NULL, 0, vdso_len, 0, 0);
++ if (unlikely(IS_ERR_VALUE(vdso_base))) {
++ ret = vdso_base;
++ goto end;
++ }
++
++ /*
++ * Put vDSO base into mm struct. We need to do this before calling
++ * install_special_mapping or the perf counter mmap tracking code
++ * will fail to recognise it as a vDSO (since arch_vma_name fails).
++ */
++ mm->context.vdso = (void *)vdso_base;
++
++ ret = install_special_mapping(mm, vdso_base, vdso_len,
++ (VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC),
++ vdso_pagelist);
++
++ if (unlikely(ret)) {
++ mm->context.vdso = NULL;
++ }
++
++end:
++ up_write(&mm->mmap_sem);
++ return ret;
++}
++
++const char *arch_vma_name(struct vm_area_struct *vma)
++{
++ if (vma->vm_mm && (vma->vm_start == (long)vma->vm_mm->context.vdso)) {
++ return "[vdso]";
++ }
++ return NULL;
++}
++
++/*
++ * Function stubs to prevent linker errors when AT_SYSINFO_EHDR is defined
++ */
++
++int in_gate_area_no_mm(unsigned long addr)
++{
++ return 0;
++}
++
++int in_gate_area(struct mm_struct *mm, unsigned long addr)
++{
++ return 0;
++}
++
++struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
++{
++ return NULL;
++}
+diff -Nur linux-4.6.2/arch/riscv/kernel/vmlinux.lds.S linux-4.6.2.riscv/arch/riscv/kernel/vmlinux.lds.S
+--- linux-4.6.2/arch/riscv/kernel/vmlinux.lds.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/kernel/vmlinux.lds.S 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,75 @@
++#define LOAD_OFFSET PAGE_OFFSET
++#include <asm/vmlinux.lds.h>
++#include <asm/page.h>
++#include <asm/cache.h>
++#include <asm/thread_info.h>
++
++OUTPUT_ARCH(riscv)
++ENTRY(_start)
++
++jiffies = jiffies_64;
++
++SECTIONS
++{
++ /* Beginning of code and text segment */
++ . = LOAD_OFFSET;
++ _start = .;
++ __init_begin = .;
++ HEAD_TEXT_SECTION
++ INIT_TEXT_SECTION(PAGE_SIZE)
++ INIT_DATA_SECTION(16)
++ /* we have to discard exit text and such at runtime, not link time */
++ .exit.text :
++ {
++ EXIT_TEXT
++ }
++ .exit.data :
++ {
++ EXIT_DATA
++ }
++ PERCPU_SECTION(L1_CACHE_BYTES)
++ __init_end = .;
++
++ .text : {
++ _text = .;
++ _stext = .;
++ TEXT_TEXT
++ SCHED_TEXT
++ LOCK_TEXT
++ KPROBES_TEXT
++ ENTRY_TEXT
++ IRQENTRY_TEXT
++ *(.fixup)
++ _etext = .;
++ }
++
++ /* Start of data section */
++ _sdata = .;
++ RO_DATA_SECTION(PAGE_SIZE)
++ RW_DATA_SECTION(0x40, PAGE_SIZE, THREAD_SIZE)
++ .sdata : {
++ _gp = . + 0x800;
++ *(.sdata*)
++ }
++ .srodata : {
++ *(.srodata*)
++ }
++ /* End of data section */
++ _edata = .;
++
++ BSS_SECTION(0x20, 0, 0x20)
++
++ EXCEPTION_TABLE(0x10)
++ NOTES
++
++ .rel.dyn : {
++ *(.rel.dyn*)
++ }
++
++ _end = .;
++
++ STABS_DEBUG
++ DWARF_DEBUG
++
++ DISCARDS
++}
+diff -Nur linux-4.6.2/arch/riscv/lib/ashldi3.c linux-4.6.2.riscv/arch/riscv/lib/ashldi3.c
+--- linux-4.6.2/arch/riscv/lib/ashldi3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/lib/ashldi3.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,28 @@
++#include <linux/export.h>
++
++#include "libgcc.h"
++
++long long __ashldi3(long long u, word_type b)
++{
++ DWunion uu, w;
++ word_type bm;
++
++ if (b == 0)
++ return u;
++
++ uu.ll = u;
++ bm = 32 - b;
++
++ if (bm <= 0) {
++ w.s.low = 0;
++ w.s.high = (unsigned int) uu.s.low << -bm;
++ } else {
++ const unsigned int carries = (unsigned int) uu.s.low >> bm;
++
++ w.s.low = (unsigned int) uu.s.low << b;
++ w.s.high = ((unsigned int) uu.s.high << b) | carries;
++ }
++
++ return w.ll;
++}
++EXPORT_SYMBOL(__ashldi3);
+diff -Nur linux-4.6.2/arch/riscv/lib/ashrdi3.c linux-4.6.2.riscv/arch/riscv/lib/ashrdi3.c
+--- linux-4.6.2/arch/riscv/lib/ashrdi3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/lib/ashrdi3.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,30 @@
++#include <linux/export.h>
++
++#include "libgcc.h"
++
++long long __ashrdi3(long long u, word_type b)
++{
++ DWunion uu, w;
++ word_type bm;
++
++ if (b == 0)
++ return u;
++
++ uu.ll = u;
++ bm = 32 - b;
++
++ if (bm <= 0) {
++ /* w.s.high = 1..1 or 0..0 */
++ w.s.high =
++ uu.s.high >> 31;
++ w.s.low = uu.s.high >> -bm;
++ } else {
++ const unsigned int carries = (unsigned int) uu.s.high << bm;
++
++ w.s.high = uu.s.high >> b;
++ w.s.low = ((unsigned int) uu.s.low >> b) | carries;
++ }
++
++ return w.ll;
++}
++EXPORT_SYMBOL(__ashrdi3);
+diff -Nur linux-4.6.2/arch/riscv/lib/delay.c linux-4.6.2.riscv/arch/riscv/lib/delay.c
+--- linux-4.6.2/arch/riscv/lib/delay.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/lib/delay.c 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,24 @@
++#include <linux/delay.h>
++#include <linux/param.h>
++#include <linux/timex.h>
++#include <linux/export.h>
++
++void __delay(unsigned long cycles)
++{
++ cycle_t t0 = get_cycles();
++ while ((unsigned long)(get_cycles() - t0) < cycles)
++ cpu_relax();
++}
++
++void udelay(unsigned long usecs)
++{
++ __delay((unsigned long)(((u64)usecs * timebase) / 1000000UL));
++
++}
++EXPORT_SYMBOL(udelay);
++
++void ndelay(unsigned long nsecs)
++{
++ __delay((unsigned long)(((u64)nsecs * timebase) / 1000000000UL));
++}
++EXPORT_SYMBOL(ndelay);
+diff -Nur linux-4.6.2/arch/riscv/lib/libgcc.h linux-4.6.2.riscv/arch/riscv/lib/libgcc.h
+--- linux-4.6.2/arch/riscv/lib/libgcc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/lib/libgcc.h 2017-03-04 02:48:34.170888098 +0100
+@@ -0,0 +1,32 @@
++#ifndef __ASM_LIBGCC_H
++#define __ASM_LIBGCC_H
++
++#include <asm/byteorder.h>
++
++typedef int word_type __attribute__ ((mode (__word__)));
++
++#ifdef __BIG_ENDIAN
++struct DWstruct {
++ int high, low;
++};
++#elif defined(__LITTLE_ENDIAN)
++struct DWstruct {
++ int low, high;
++};
++#else
++#error I feel sick.
++#endif
++
++typedef union {
++ struct DWstruct s;
++ long long ll;
++} DWunion;
++
++extern long long __ashldi3(long long u, word_type b);
++extern long long __ashrdi3(long long u, word_type b);
++extern word_type __cmpdi2(long long a, long long b);
++extern long long __lshrdi3(long long u, word_type b);
++extern long long __muldi3(long long u, long long v);
++extern word_type __ucmpdi2(unsigned long long a, unsigned long long b);
++
++#endif /* __ASM_LIBGCC_H */
+diff -Nur linux-4.6.2/arch/riscv/lib/lshrdi3.c linux-4.6.2.riscv/arch/riscv/lib/lshrdi3.c
+--- linux-4.6.2/arch/riscv/lib/lshrdi3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/lib/lshrdi3.c 2017-03-04 02:48:34.170888098 +0100
+@@ -0,0 +1,28 @@
++#include <linux/export.h>
++
++#include "libgcc.h"
++
++long long __lshrdi3(long long u, word_type b)
++{
++ DWunion uu, w;
++ word_type bm;
++
++ if (b == 0)
++ return u;
++
++ uu.ll = u;
++ bm = 32 - b;
++
++ if (bm <= 0) {
++ w.s.high = 0;
++ w.s.low = (unsigned int) uu.s.high >> -bm;
++ } else {
++ const unsigned int carries = (unsigned int) uu.s.high << bm;
++
++ w.s.high = (unsigned int) uu.s.high >> b;
++ w.s.low = ((unsigned int) uu.s.low >> b) | carries;
++ }
++
++ return w.ll;
++}
++EXPORT_SYMBOL(__lshrdi3);
+diff -Nur linux-4.6.2/arch/riscv/lib/Makefile linux-4.6.2.riscv/arch/riscv/lib/Makefile
+--- linux-4.6.2/arch/riscv/lib/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/lib/Makefile 2017-03-04 02:48:34.166888015 +0100
+@@ -0,0 +1,5 @@
++lib-y := delay.o memcpy.o memset.o uaccess.o
++
++ifeq ($(CONFIG_64BIT),)
++lib-y += ashldi3.o ashrdi3.o lshrdi3.o
++endif
+diff -Nur linux-4.6.2/arch/riscv/lib/memcpy.S linux-4.6.2.riscv/arch/riscv/lib/memcpy.S
+--- linux-4.6.2/arch/riscv/lib/memcpy.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/lib/memcpy.S 2017-03-04 02:48:34.170888098 +0100
+@@ -0,0 +1,85 @@
++#include <linux/linkage.h>
++#include <asm/asm.h>
++
++/* void *memcpy(void *, const void *, size_t) */
++ENTRY(memcpy)
++ move t6, a0 /* Preserve return value */
++
++ /* Defer to byte-oriented copy for small sizes */
++ sltiu a3, a2, 128
++ bnez a3, 4f
++ /* Use word-oriented copy only if low-order bits match */
++ andi a3, t6, SZREG-1
++ andi a4, a1, SZREG-1
++ bne a3, a4, 4f
++
++ beqz a3, 2f /* Skip if already aligned */
++ /* Round to nearest double word-aligned address
++ greater than or equal to start address */
++ andi a3, a1, ~(SZREG-1)
++ addi a3, a3, SZREG
++ /* Handle initial misalignment */
++ sub a4, a3, a1
++1:
++ lb a5, 0(a1)
++ addi a1, a1, 1
++ sb a5, 0(t6)
++ addi t6, t6, 1
++ bltu a1, a3, 1b
++ sub a2, a2, a4 /* Update count */
++
++2:
++ andi a4, a2, ~((16*SZREG)-1)
++ beqz a4, 4f
++ add a3, a1, a4
++3:
++ REG_L a4, 0(a1)
++ REG_L a5, SZREG(a1)
++ REG_L a6, 2*SZREG(a1)
++ REG_L a7, 3*SZREG(a1)
++ REG_L t0, 4*SZREG(a1)
++ REG_L t1, 5*SZREG(a1)
++ REG_L t2, 6*SZREG(a1)
++ REG_L t3, 7*SZREG(a1)
++ REG_L t4, 8*SZREG(a1)
++ REG_L t5, 9*SZREG(a1)
++ REG_S a4, 0(t6)
++ REG_S a5, SZREG(t6)
++ REG_S a6, 2*SZREG(t6)
++ REG_S a7, 3*SZREG(t6)
++ REG_S t0, 4*SZREG(t6)
++ REG_S t1, 5*SZREG(t6)
++ REG_S t2, 6*SZREG(t6)
++ REG_S t3, 7*SZREG(t6)
++ REG_S t4, 8*SZREG(t6)
++ REG_S t5, 9*SZREG(t6)
++ REG_L a4, 10*SZREG(a1)
++ REG_L a5, 11*SZREG(a1)
++ REG_L a6, 12*SZREG(a1)
++ REG_L a7, 13*SZREG(a1)
++ REG_L t0, 14*SZREG(a1)
++ REG_L t1, 15*SZREG(a1)
++ addi a1, a1, 16*SZREG
++ REG_S a4, 10*SZREG(t6)
++ REG_S a5, 11*SZREG(t6)
++ REG_S a6, 12*SZREG(t6)
++ REG_S a7, 13*SZREG(t6)
++ REG_S t0, 14*SZREG(t6)
++ REG_S t1, 15*SZREG(t6)
++ addi t6, t6, 16*SZREG
++ bltu a1, a3, 3b
++ andi a2, a2, (16*SZREG)-1 /* Update count */
++
++4:
++ /* Handle trailing misalignment */
++ beqz a2, 6f
++ add a3, a1, a2
++5:
++ lb a4, 0(a1)
++ addi a1, a1, 1
++ sb a4, 0(t6)
++ addi t6, t6, 1
++ bltu a1, a3, 5b
++6:
++ ret
++END(memcpy)
+diff -Nur linux-4.6.2/arch/riscv/lib/memset.S linux-4.6.2.riscv/arch/riscv/lib/memset.S
+--- linux-4.6.2/arch/riscv/lib/memset.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/lib/memset.S 2017-03-04 02:48:34.170888098 +0100
+@@ -0,0 +1,104 @@
++#include <linux/linkage.h>
++#include <asm/asm.h>
++
++/* void *memset(void *, int, size_t) */
++ENTRY(memset)
++ move t0, a0 /* Preserve return value */
++
++ /* Defer to byte-oriented fill for small sizes */
++ sltiu a3, a2, 16
++ bnez a3, 4f
++
++ /* Round to nearest XLEN-aligned address
++ greater than or equal to start address */
++ addi a3, t0, SZREG-1
++ andi a3, a3, ~(SZREG-1)
++ beq a3, t0, 2f /* Skip if already aligned */
++ /* Handle initial misalignment */
++ sub a4, a3, t0
++1:
++ sb a1, 0(t0)
++ addi t0, t0, 1
++ bltu t0, a3, 1b
++ sub a2, a2, a4 /* Update count */
++
++2: /* Duff's device with 32 XLEN stores per iteration */
++ /* Broadcast value into all bytes */
++ andi a1, a1, 0xff
++ slli a3, a1, 8
++ or a1, a3, a1
++ slli a3, a1, 16
++ or a1, a3, a1
++#ifdef CONFIG_64BIT
++ slli a3, a1, 32
++ or a1, a3, a1
++#endif
++
++ /* Calculate end address */
++ andi a4, a2, ~(SZREG-1)
++ add a3, t0, a4
++
++ andi a4, a4, 31*SZREG /* Calculate remainder */
++ beqz a4, 3f /* Shortcut if no remainder */
++ neg a4, a4
++ addi a4, a4, 32*SZREG /* Calculate initial offset */
++
++ /* Adjust start address with offset */
++ sub t0, t0, a4
++
++ /* Jump into loop body */
++ /* Assumes 32-bit instruction lengths */
++ la a5, 3f
++#ifdef CONFIG_64BIT
++ srli a4, a4, 1
++#endif
++ add a5, a5, a4
++ jr a5
++3:
++ REG_S a1, 0(t0)
++ REG_S a1, SZREG(t0)
++ REG_S a1, 2*SZREG(t0)
++ REG_S a1, 3*SZREG(t0)
++ REG_S a1, 4*SZREG(t0)
++ REG_S a1, 5*SZREG(t0)
++ REG_S a1, 6*SZREG(t0)
++ REG_S a1, 7*SZREG(t0)
++ REG_S a1, 8*SZREG(t0)
++ REG_S a1, 9*SZREG(t0)
++ REG_S a1, 10*SZREG(t0)
++ REG_S a1, 11*SZREG(t0)
++ REG_S a1, 12*SZREG(t0)
++ REG_S a1, 13*SZREG(t0)
++ REG_S a1, 14*SZREG(t0)
++ REG_S a1, 15*SZREG(t0)
++ REG_S a1, 16*SZREG(t0)
++ REG_S a1, 17*SZREG(t0)
++ REG_S a1, 18*SZREG(t0)
++ REG_S a1, 19*SZREG(t0)
++ REG_S a1, 20*SZREG(t0)
++ REG_S a1, 21*SZREG(t0)
++ REG_S a1, 22*SZREG(t0)
++ REG_S a1, 23*SZREG(t0)
++ REG_S a1, 24*SZREG(t0)
++ REG_S a1, 25*SZREG(t0)
++ REG_S a1, 26*SZREG(t0)
++ REG_S a1, 27*SZREG(t0)
++ REG_S a1, 28*SZREG(t0)
++ REG_S a1, 29*SZREG(t0)
++ REG_S a1, 30*SZREG(t0)
++ REG_S a1, 31*SZREG(t0)
++ addi t0, t0, 32*SZREG
++ bltu t0, a3, 3b
++ andi a2, a2, SZREG-1 /* Update count */
++
++4:
++ /* Handle trailing misalignment */
++ beqz a2, 6f
++ add a3, t0, a2
++5:
++ sb a1, 0(t0)
++ addi t0, t0, 1
++ bltu t0, a3, 5b
++6:
++ ret
++END(memset)
+diff -Nur linux-4.6.2/arch/riscv/lib/uaccess.S linux-4.6.2.riscv/arch/riscv/lib/uaccess.S
+--- linux-4.6.2/arch/riscv/lib/uaccess.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/lib/uaccess.S 2017-03-04 02:48:34.170888098 +0100
+@@ -0,0 +1,125 @@
++#include <linux/linkage.h>
++#include <asm/asm.h>
++#include <asm/csr.h>
++
++ .altmacro
++ .macro fixup op reg addr lbl
++ LOCAL _epc
++_epc:
++ \op \reg, \addr
++ .section __ex_table,"a"
++ .balign SZPTR
++ PTR _epc, \lbl
++ .previous
++ .endm
++
++ENTRY(__copy_user)
++
++#ifdef CONFIG_RV_PUM
++ /* Enable access to user memory */
++ li t6, SR_PUM
++ csrc sstatus, t6
++#endif
++
++ add a3, a1, a2
++ /* Use word-oriented copy only if low-order bits match */
++ andi t0, a0, SZREG-1
++ andi t1, a1, SZREG-1
++ bne t0, t1, 2f
++
++ addi t0, a1, SZREG-1
++ andi t1, a3, ~(SZREG-1)
++ andi t0, t0, ~(SZREG-1)
++ /* a3: terminal address of source region
++ * t0: lowest XLEN-aligned address in source
++ * t1: highest XLEN-aligned address in source
++ */
++ bgeu t0, t1, 2f
++ bltu a1, t0, 4f
++1:
++ fixup REG_L, t2, (a1), 10f
++ fixup REG_S, t2, (a0), 10f
++ addi a1, a1, SZREG
++ addi a0, a0, SZREG
++ bltu a1, t1, 1b
++2:
++ bltu a1, a3, 5f
++
++3:
++#ifdef CONFIG_RV_PUM
++ /* Disable access to user memory */
++ csrs sstatus, t6
++#endif
++ li a0, 0
++ ret
++4: /* Edge case: unalignment */
++ fixup lbu, t2, (a1), 10f
++ fixup sb, t2, (a0), 10f
++ addi a1, a1, 1
++ addi a0, a0, 1
++ bltu a1, t0, 4b
++ j 1b
++5: /* Edge case: remainder */
++ fixup lbu, t2, (a1), 10f
++ fixup sb, t2, (a0), 10f
++ addi a1, a1, 1
++ addi a0, a0, 1
++ bltu a1, a3, 5b
++ j 3b
++ENDPROC(__copy_user)
++
++
++ENTRY(__clear_user)
++
++#ifdef CONFIG_RV_PUM
++ /* Enable access to user memory */
++ li t6, SR_PUM
++ csrc sstatus, t6
++#endif
++
++ add a3, a0, a1
++ addi t0, a0, SZREG-1
++ andi t1, a3, ~(SZREG-1)
++ andi t0, t0, ~(SZREG-1)
++ /* a3: terminal address of target region
++ * t0: lowest doubleword-aligned address in target region
++ * t1: highest doubleword-aligned address in target region
++ */
++ bgeu t0, t1, 2f
++ bltu a0, t0, 4f
++1:
++ fixup REG_S, zero, (a0), 10f
++ addi a0, a0, SZREG
++ bltu a0, t1, 1b
++2:
++ bltu a0, a3, 5f
++
++3:
++#ifdef CONFIG_RV_PUM
++ /* Disable access to user memory */
++ csrs sstatus, t6
++#endif
++ li a0, 0
++ ret
++4: /* Edge case: unalignment */
++ fixup sb, zero, (a0), 10f
++ addi a0, a0, 1
++ bltu a0, t0, 4b
++ j 1b
++5: /* Edge case: remainder */
++ fixup sb, zero, (a0), 10f
++ addi a0, a0, 1
++ bltu a0, a3, 5b
++ j 3b
++ENDPROC(__clear_user)
++
++ .section .fixup,"ax"
++ .balign 4
++10:
++#ifdef CONFIG_RV_PUM
++ /* Disable access to user memory */
++ csrs sstatus, t6
++#endif
++ sub a0, a3, a0
++ ret
++ .previous
+diff -Nur linux-4.6.2/arch/riscv/Makefile linux-4.6.2.riscv/arch/riscv/Makefile
+--- linux-4.6.2/arch/riscv/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/Makefile 2017-03-04 02:48:34.162887952 +0100
+@@ -0,0 +1,70 @@
++# 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. Remember to do have actions
++# for "archclean" and "archdep" for cleaning up and making dependencies for
++# this architecture
++#
++# 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 RISC-V architecture:
++# Quan Nguyen <quannguyen@eecs.berkeley.edu>
++# Albert Ou <a_ou@eecs.berkeley.edu>
++#
++# Based on:
++# arch/score/Makefile
++
++LDFLAGS :=
++OBJCOPYFLAGS := -O binary
++LDFLAGS_vmlinux :=
++
++ifeq ($(ARCH),riscv)
++ KBUILD_DEFCONFIG = riscv64_spike
++else
++ KBUILD_DEFCONFIG = $(ARCH)_spike
++endif
++
++export BITS
++ifeq ($(CONFIG_64BIT),y)
++ BITS := 64
++ UTS_MACHINE := riscv64
++
++ KBUILD_CFLAGS += -mabi=lp64
++ KBUILD_AFLAGS += -mabi=lp64
++ KBUILD_MARCH = rv64im
++ LDFLAGS += -melf64lriscv
++else
++ BITS := 32
++ UTS_MACHINE := riscv32
++
++ KBUILD_CFLAGS += -mabi=ilp32
++ KBUILD_AFLAGS += -mabi=ilp32
++ KBUILD_MARCH = rv32im
++ LDFLAGS += -melf32lriscv
++endif
++
++ifeq ($(CONFIG_RV_ATOMIC),y)
++ KBUILD_RV_ATOMIC = a
++endif
++
++KBUILD_CFLAGS += -Wall
++
++ifeq ($(CONFIG_RVC),y)
++ KBUILD_RVC = c
++endif
++
++KBUILD_AFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_RV_ATOMIC)fd$(KBUILD_RVC)
++
++KBUILD_CFLAGS += -march=$(KBUILD_MARCH)$(KBUILD_RV_ATOMIC)$(KBUILD_RVC)
++KBUILD_CFLAGS += -mno-save-restore
++
++head-y := arch/riscv/kernel/head.o
++
++core-y += arch/riscv/kernel/ arch/riscv/mm/
++
++libs-y += arch/riscv/lib/
++
++all: vmlinux
+diff -Nur linux-4.6.2/arch/riscv/mm/extable.c linux-4.6.2.riscv/arch/riscv/mm/extable.c
+--- linux-4.6.2/arch/riscv/mm/extable.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/mm/extable.c 2017-03-04 02:48:34.170888098 +0100
+@@ -0,0 +1,14 @@
++#include <linux/module.h>
++#include <linux/uaccess.h>
++
++int fixup_exception(struct pt_regs *regs)
++{
++ const struct exception_table_entry *fixup;
++
++ fixup = search_exception_tables(regs->sepc);
++ if (fixup) {
++ regs->sepc = fixup->fixup;
++ return 1;
++ }
++ return 0;
++}
+diff -Nur linux-4.6.2/arch/riscv/mm/fault.c linux-4.6.2.riscv/arch/riscv/mm/fault.c
+--- linux-4.6.2/arch/riscv/mm/fault.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/mm/fault.c 2017-03-04 02:48:34.170888098 +0100
+@@ -0,0 +1,250 @@
++#include <linux/mm.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/perf_event.h>
++#include <linux/signal.h>
++#include <linux/uaccess.h>
++
++#include <asm/pgalloc.h>
++#include <asm/ptrace.h>
++#include <asm/uaccess.h>
++
++/*
++ * This routine handles page faults. It determines the address and the
++ * problem, and then passes it off to one of the appropriate routines.
++ */
++asmlinkage void do_page_fault(struct pt_regs *regs)
++{
++ struct task_struct *tsk;
++ struct vm_area_struct *vma;
++ struct mm_struct *mm;
++ unsigned long addr, cause;
++ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
++ int fault, code = SEGV_MAPERR;
++
++ cause = regs->scause;
++ addr = regs->sbadaddr;
++
++ tsk = current;
++ mm = tsk->mm;
++
++ /*
++ * Fault-in kernel-space virtual memory on-demand.
++ * The 'reference' page table is init_mm.pgd.
++ *
++ * NOTE! We MUST NOT take any locks for this case. We may
++ * be in an interrupt or a critical region, and should
++ * only copy the information from the master page table,
++ * nothing more.
++ */
++ if (unlikely((addr >= VMALLOC_START) && (addr <= VMALLOC_END)))
++ goto vmalloc_fault;
++
++ /* Enable interrupts if they were enabled in the parent context. */
++ if (likely(regs->sstatus & SR_PIE))
++ local_irq_enable();
++
++ /*
++ * If we're in an interrupt, have no user context, or are running
++ * in an atomic region, then we must not take the fault.
++ */
++ if (unlikely(faulthandler_disabled() || !mm))
++ goto no_context;
++
++ if (user_mode(regs))
++ flags |= FAULT_FLAG_USER;
++
++ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
++
++retry:
++ down_read(&mm->mmap_sem);
++ vma = find_vma(mm, addr);
++ if (unlikely(!vma))
++ goto bad_area;
++ if (likely(vma->vm_start <= addr))
++ goto good_area;
++ if (unlikely(!(vma->vm_flags & VM_GROWSDOWN)))
++ goto bad_area;
++ if (unlikely(expand_stack(vma, addr)))
++ goto bad_area;
++
++ /*
++ * Ok, we have a good vm_area for this memory access, so
++ * we can handle it.
++ */
++good_area:
++ code = SEGV_ACCERR;
++
++ switch (cause) {
++ case EXC_INST_ACCESS:
++ if (!(vma->vm_flags & VM_EXEC))
++ goto bad_area;
++ break;
++ case EXC_LOAD_ACCESS:
++ if (!(vma->vm_flags & VM_READ))
++ goto bad_area;
++ break;
++ case EXC_STORE_ACCESS:
++ if (!(vma->vm_flags & VM_WRITE))
++ goto bad_area;
++ flags |= FAULT_FLAG_WRITE;
++ break;
++ default:
++ panic("%s: unhandled cause %lu", __func__, cause);
++ }
++
++ /*
++ * If for any reason at all we could not handle the fault,
++ * make sure we exit gracefully rather than endlessly redo
++ * the fault.
++ */
++ fault = handle_mm_fault(mm, vma, addr, flags);
++
++ /*
++ * If we need to retry but a fatal signal is pending, handle the
++ * signal first. We do not need to release the mmap_sem because it
++ * would already be released in __lock_page_or_retry in mm/filemap.c.
++ */
++ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(tsk))
++ return;
++
++ if (unlikely(fault & VM_FAULT_ERROR)) {
++ if (fault & VM_FAULT_OOM)
++ goto out_of_memory;
++ else if (fault & VM_FAULT_SIGBUS)
++ goto do_sigbus;
++ BUG();
++ }
++
++ /*
++ * Major/minor page fault accounting is only done on the
++ * initial attempt. If we go through a retry, it is extremely
++ * likely that the page will be found in page cache at that point.
++ */
++ if (flags & FAULT_FLAG_ALLOW_RETRY) {
++ if (fault & VM_FAULT_MAJOR) {
++ tsk->maj_flt++;
++ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, addr);
++ } else {
++ tsk->min_flt++;
++ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, addr);
++ }
++ if (fault & VM_FAULT_RETRY) {
++ /*
++ * Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
++ * of starvation.
++ */
++ flags &= ~(FAULT_FLAG_ALLOW_RETRY);
++ flags |= FAULT_FLAG_TRIED;
++
++ /*
++ * No need to up_read(&mm->mmap_sem) as we would
++ * have already released it in __lock_page_or_retry
++ * in mm/filemap.c.
++ */
++ goto retry;
++ }
++ }
++
++ up_read(&mm->mmap_sem);
++ return;
++
++ /*
++ * Something tried to access memory that isn't in our memory map.
++ * Fix it, but check if it's kernel or user first.
++ */
++bad_area:
++ up_read(&mm->mmap_sem);
++ /* User mode accesses just cause a SIGSEGV */
++ if (user_mode(regs)) {
++ do_trap(regs, SIGSEGV, code, addr, tsk);
++ return;
++ }
++
++no_context:
++ /* Are we prepared to handle this kernel fault? */
++ if (fixup_exception(regs)) {
++ return;
++ }
++
++ /*
++ * Oops. The kernel tried to access some bad page. We'll have to
++ * terminate things with extreme prejudice.
++ */
++ bust_spinlocks(1);
++ pr_alert("Unable to handle kernel %s at virtual address " REG_FMT "\n",
++ (addr < PAGE_SIZE) ? "NULL pointer dereference" :
++ "paging request", addr);
++ die(regs, "Oops");
++ do_exit(SIGKILL);
++
++ /*
++ * We ran out of memory, call the OOM killer, and return the userspace
++ * (which will retry the fault, or kill us if we got oom-killed).
++ */
++out_of_memory:
++ up_read(&mm->mmap_sem);
++ if (!user_mode(regs))
++ goto no_context;
++ pagefault_out_of_memory();
++ return;
++
++do_sigbus:
++ up_read(&mm->mmap_sem);
++ /* Kernel mode? Handle exceptions or die */
++ if (!user_mode(regs))
++ goto no_context;
++ do_trap(regs, SIGBUS, BUS_ADRERR, addr, tsk);
++ return;
++
++vmalloc_fault:
++ {
++ pgd_t *pgd, *pgd_k;
++ pud_t *pud, *pud_k;
++ pmd_t *pmd, *pmd_k;
++ pte_t *pte_k;
++ int index;
++
++ if (user_mode(regs))
++ goto bad_area;
++
++ /*
++ * Synchronize this task's top level page-table
++ * with the 'reference' page table.
++ *
++ * Do _not_ use "tsk->active_mm->pgd" here.
++ * We might be inside an interrupt in the middle
++ * of a task switch.
++ */
++ index = pgd_index(addr);
++ pgd = (pgd_t *)pfn_to_virt(csr_read(sptbr)) + index;
++ pgd_k = init_mm.pgd + index;
++
++ if (!pgd_present(*pgd_k))
++ goto no_context;
++ set_pgd(pgd, *pgd_k);
++
++ pud = pud_offset(pgd, addr);
++ pud_k = pud_offset(pgd_k, addr);
++ if (!pud_present(*pud_k))
++ goto no_context;
++
++ /* Since the vmalloc area is global, it is unnecessary
++ to copy individual PTEs */
++ pmd = pmd_offset(pud, addr);
++ pmd_k = pmd_offset(pud_k, addr);
++ if (!pmd_present(*pmd_k))
++ goto no_context;
++ set_pmd(pmd, *pmd_k);
++
++ /* Make sure the actual PTE exists as well to
++ * catch kernel vmalloc-area accesses to non-mapped
++ * addresses. If we don't do this, this will just
++ * silently loop forever.
++ */
++ pte_k = pte_offset_kernel(pmd_k, addr);
++ if (!pte_present(*pte_k))
++ goto no_context;
++ return;
++ }
++}
+diff -Nur linux-4.6.2/arch/riscv/mm/init.c linux-4.6.2.riscv/arch/riscv/mm/init.c
+--- linux-4.6.2/arch/riscv/mm/init.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/mm/init.c 2017-03-04 02:48:34.170888098 +0100
+@@ -0,0 +1,84 @@
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/bootmem.h>
++#include <linux/initrd.h>
++#include <linux/memblock.h>
++#include <linux/swap.h>
++
++#include <asm/tlbflush.h>
++#include <asm/sections.h>
++#include <asm/pgtable.h>
++#include <asm/io.h>
++
++#ifdef CONFIG_NUMA
++static void __init zone_sizes_init(void)
++{
++ unsigned long zones_size[MAX_NR_ZONES];
++ int nid;
++
++ memset(zones_size, 0, sizeof(zones_size));
++
++ for_each_online_node(nid) {
++ pg_data_t *pgdat;
++ unsigned long start_pfn, end_pfn;
++
++ pgdat = NODE_DATA(nid);
++ start_pfn = pgdat->bdata->node_min_pfn;
++ end_pfn = pgdat->bdata->node_low_pfn;
++ memblock_add_node(start_pfn,
++ PFN_PHYS(end_pfn - start_pfn), nid);
++ }
++
++ zones_size[ZONE_NORMAL] = pfn_base + max_mapnr;
++ free_area_init_nodes(zones_size);
++}
++#else
++static void __init zone_sizes_init(void)
++{
++ unsigned long zones_size[MAX_NR_ZONES];
++
++ memset(zones_size, 0, sizeof(zones_size));
++ memblock_add_node(PFN_PHYS(pfn_base), PFN_PHYS(max_mapnr), 0);
++ zones_size[ZONE_NORMAL] = pfn_base + max_mapnr;
++ free_area_init_nodes(zones_size);
++}
++#endif /* CONFIG_NUMA */
++
++void setup_zero_page(void)
++{
++ memset((void *)empty_zero_page, 0, PAGE_SIZE);
++}
++
++void __init paging_init(void)
++{
++ init_mm.pgd = (pgd_t *)pfn_to_virt(csr_read(sptbr));
++
++ setup_zero_page();
++ local_flush_tlb_all();
++ zone_sizes_init();
++}
++
++void __init mem_init(void)
++{
++#ifdef CONFIG_FLATMEM
++ BUG_ON(!mem_map);
++#endif /* CONFIG_FLATMEM */
++
++ high_memory = (void *)(__va(PFN_PHYS(max_low_pfn)));
++ free_all_bootmem();
++
++ mem_init_print_info(NULL);
++}
++
++void free_initmem(void)
++{
++ free_initmem_default(0);
++}
++
++#ifdef CONFIG_BLK_DEV_INITRD
++void free_initrd_mem(unsigned long start, unsigned long end)
++{
++// free_reserved_area(start, end, 0, "initrd");
++}
++#endif /* CONFIG_BLK_DEV_INITRD */
++
+diff -Nur linux-4.6.2/arch/riscv/mm/ioremap.c linux-4.6.2.riscv/arch/riscv/mm/ioremap.c
+--- linux-4.6.2/arch/riscv/mm/ioremap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/mm/ioremap.c 2017-03-04 02:48:34.170888098 +0100
+@@ -0,0 +1,81 @@
++#include <linux/export.h>
++#include <linux/mm.h>
++#include <linux/vmalloc.h>
++#include <linux/io.h>
++
++#include <asm/pgtable.h>
++
++/*
++ * Remap an arbitrary physical address space into the kernel virtual
++ * address space. Needed when the kernel wants to access high addresses
++ * directly.
++ *
++ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
++ * have to convert them into an offset in a page-aligned mapping, but the
++ * caller shouldn't need to know that small detail.
++ */
++static void __iomem *__ioremap_caller(phys_addr_t addr, size_t size,
++ pgprot_t prot, void *caller)
++{
++ phys_addr_t last_addr;
++ unsigned long offset, vaddr;
++ struct vm_struct *area;
++
++ /* Disallow wrap-around or zero size */
++ last_addr = addr + size - 1;
++ if (!size || last_addr < addr) {
++ return NULL;
++ }
++
++ /* Page-align mappings */
++ offset = addr & (~PAGE_MASK);
++ addr &= PAGE_MASK;
++ size = PAGE_ALIGN(size + offset);
++
++ area = get_vm_area_caller(size, VM_IOREMAP, caller);
++ if (!area) {
++ return NULL;
++ }
++ vaddr = (unsigned long)area->addr;
++
++ if (ioremap_page_range(vaddr, vaddr + size, addr, prot)) {
++ free_vm_area(area);
++ return NULL;
++ }
++
++ return (void __iomem *)(vaddr + offset);
++}
++
++/*
++ * ioremap - map bus memory into CPU space
++ * @offset: bus address of the memory
++ * @size: size of the resource to map
++ *
++ * ioremap performs a platform specific sequence of operations to
++ * make bus memory CPU accessible via the readb/readw/readl/writeb/
++ * writew/writel functions and the other mmio helpers. The returned
++ * address is not guaranteed to be usable directly as a virtual
++ * address.
++ *
++ * Must be freed with iounmap.
++ */
++void __iomem *ioremap(phys_addr_t offset, unsigned long size)
++{
++ return __ioremap_caller(offset, size, PAGE_KERNEL,
++ __builtin_return_address(0));
++}
++EXPORT_SYMBOL(ioremap);
++
++
++/**
++ * iounmap - Free a IO remapping
++ * @addr: virtual address from ioremap_*
++ *
++ * Caller must ensure there is only one unmapping for the same pointer.
++ */
++void iounmap(void __iomem *addr)
++{
++ vunmap((void *)((unsigned long)addr & PAGE_MASK));
++}
++EXPORT_SYMBOL(iounmap);
++
+diff -Nur linux-4.6.2/arch/riscv/mm/Makefile linux-4.6.2.riscv/arch/riscv/mm/Makefile
+--- linux-4.6.2/arch/riscv/mm/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/arch/riscv/mm/Makefile 2017-03-04 02:48:34.170888098 +0100
+@@ -0,0 +1 @@
++obj-y := init.o fault.o extable.o ioremap.o
+diff -Nur linux-4.6.2/.gitignore linux-4.6.2.riscv/.gitignore
+--- linux-4.6.2/.gitignore 2016-06-08 03:23:53.000000000 +0200
++++ linux-4.6.2.riscv/.gitignore 2017-03-04 02:48:34.162887952 +0100
+@@ -1,114 +1,11 @@
+-#
+-# NOTE! Don't add files that are generated in specific
+-# subdirectories here. Add them in the ".gitignore" file
+-# in that subdirectory instead.
+-#
+-# NOTE! Please use 'git ls-files -i --exclude-standard'
+-# command after changing this file, to see if there are
+-# any tracked files which get ignored after the change.
+-#
+-# Normal rules
+-#
+-.*
+-*.o
+-*.o.*
+-*.a
+-*.s
+-*.ko
+-*.so
+-*.so.dbg
+-*.mod.c
+-*.i
+-*.lst
+-*.symtypes
+-*.order
+-*.elf
+-*.bin
+-*.tar
+-*.gz
+-*.bz2
+-*.lzma
+-*.xz
+-*.lz4
+-*.lzo
+-*.patch
+-*.gcno
+-modules.builtin
+-Module.symvers
+-*.dwo
+-*.su
++# Ignore everything...
++*
+
+-#
+-# Top-level generic files
+-#
+-/tags
+-/TAGS
+-/linux
+-/vmlinux
+-/vmlinux.32
+-/vmlinux-gdb.py
+-/vmlinuz
+-/System.map
+-/Module.markers
+-
+-#
+-# Debian directory (make deb-pkg)
+-#
+-/debian/
+-
+-#
+-# tar directory (make tar*-pkg)
+-#
+-/tar-install/
+-
+-#
+-# git files that we don't want to ignore even it they are dot-files
+-#
++# Then include just this.
++!arch/
+ !.gitignore
+-!.mailmap
+-
+-#
+-# Generated include files
+-#
+-include/config
+-include/generated
+-arch/*/include/generated
+-
+-# stgit generated dirs
+-patches-*
+-
+-# quilt's files
+-patches
+-series
+-
+-# cscope files
+-cscope.*
+-ncscope.*
+-
+-# gnu global files
+-GPATH
+-GRTAGS
+-GSYMS
+-GTAGS
+-
+-# id-utils files
+-ID
+-
+-*.orig
+-*~
+-\#*#
+-
+-#
+-# Leavings from module signing
+-#
+-extra_certificates
+-signing_key.pem
+-signing_key.priv
+-signing_key.x509
+-x509.genkey
++!README.md
+
+-# Kconfig presets
+-all.config
++# The arch/.gitignore and arch/riscv/.gitignore have patterns to un-ignore the
++# appropriate files.
+
+-# Kdevelop4
+-*.kdev4
+diff -Nur linux-4.6.2/README.md linux-4.6.2.riscv/README.md
+--- linux-4.6.2/README.md 1970-01-01 01:00:00.000000000 +0100
++++ linux-4.6.2.riscv/README.md 2017-03-04 02:48:34.162887952 +0100
+@@ -0,0 +1,72 @@
++# Linux/RISC-V
++
++This is a port of Linux kernel for the [RISC-V](http://riscv.org/)
++instruction set architecture.
++Development is currently based on the
++[4.6 longterm branch](https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/log/?h=linux-4.6.y).
++
++
++## Obtaining kernel sources
++
++### Master
++
++Overlay the `riscv` architecture-specific subtree onto an upstream release:
++
++ $ curl -L https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.6.2.tar.xz | tar -xJ
++ $ cd linux-4.6.2
++ $ git init
++ $ git remote add -t master origin https://github.com/riscv/riscv-linux.git
++ $ git fetch
++ $ git checkout -f -t origin/master
++
++Note that the `-t <branch>` option minimizes the history fetched.
++To add another branch:
++
++ $ git remote set-branches --add origin <branch>
++ $ git fetch
++
++### Full kernel source trees
++
++For convenience, full kernel source trees are maintained on separate
++branches tracking
++[linux-stable](https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git):
++
++* `linux-4.6.y-riscv`
++* `linux-3.14.y-riscv` (historical)
++
++## Building the kernel image
++
++1. Create kernel configuration based on architecture defaults:
++
++ $ make ARCH=riscv defconfig
++
++1. Optionally edit the configuration via an ncurses interface:
++
++ $ make ARCH=riscv menuconfig
++
++1. Build the uncompressed kernel image:
++
++ $ make -j4 ARCH=riscv vmlinux
++
++1. Boot the kernel in the functional simulator, optionally specifying a
++ raw disk image for the root filesystem:
++
++ $ spike +disk=path/to/root.img bbl vmlinux
++
++ `bbl` (the Berkeley Boot Loader) is available from the
++ [riscv-pk](https://github.com/riscv/riscv-pk) repository.
++
++## Exporting kernel headers
++
++The `riscv-gnu-toolchain` repository includes a copy of the kernel header files.
++If the userspace API has changed, export the updated headers to the
++`riscv-gnu-toolchain` source directory:
++
++ $ make ARCH=riscv headers_check
++ $ make ARCH=riscv INSTALL_HDR_PATH=path/to/riscv-gnu-toolchain/linux-headers headers_install
++
++Rebuild `riscv64-unknown-linux-gnu-gcc` with the `linux` target:
++
++ $ cd path/to/riscv-gnu-toolchain
++ $ make linux
++