This patchset adds core architecture support to Linux for Andestech's
N13, N15, D15, N10, D10 processor cores.
Based on the 16/32-bit AndeStar RISC-like architecture, we designed the
configurable AndesCore series of embedded processor families. AndesCores
range from highly performance-efficient small-footprint cores for
microcontrollers and deeply-embedded applications to 1GHz+ cores running
Linux, covering general-purpose N-series cores for a wide range of computing
need, DSP-capable D-series cores for digital signal control,
instruction-extensible E-series cores for application-specific acceleration,
and secure S-series cores for best protection of the most valuable.
The patches are based on v4.14-rc8, and can also be found in the
following git tree:
https://github.com/andestech/linux.git nds32-4.14-rc8
The build script and toolchain repositories are able to be found here:
https://github.com/andestech/build_script.git
Freely available instruction set and architecture overview documents can
be found on the following page:
http://www.andestech.com/product.php?cls=9
Vincent Ren-Wei Chen and I will maintain this port. Thanks to everyone who
helped us and contributed to it. :) Any feedback is welcome.
Greentime Hu (31):
nds32: Assembly macros and definitions
nds32: Kernel booting and initialization
nds32: Support early_printk
nds32: Exception handling
nds32: MMU definitions
nds32: MMU initialization
nds32: MMU fault handling and page table management
nds32: Cache and TLB routines
nds32: Process management
nds32: IRQ handling
nds32: Atomic operations
nds32: Device specific operations
nds32: DMA mapping API
nds32: ELF definitions
nds32: System calls handling
nds32: VDSO support
nds32: Signal handling support
nds32: Library functions
nds32: Debugging support
nds32: L2 cache support
nds32: Loadable modules
nds32: Generic timers support
nds32: Device tree support
nds32: Miscellaneous header files
nds32: defconfig
nds32: Build infrastructure
dt-bindings: interrupt-controller: Andestech Internal Vector
Interrupt Controller
irqchip: Andestech Internal Vector Interrupt Controller driver
MAINTAINERS: Add nds32
dt-bindings: nds32 CPU Bindings
net: faraday add nds32 support.
.../interrupt-controller/andestech,ativic32.txt | 27 +
Documentation/devicetree/bindings/nds32/cpus.txt | 33 +
MAINTAINERS | 9 +
arch/nds32/Kconfig | 107 +++
arch/nds32/Kconfig.cpu | 100 ++
arch/nds32/Kconfig.debug | 14 +
arch/nds32/Makefile | 60 ++
arch/nds32/boot/Makefile | 15 +
arch/nds32/boot/dts/Makefile | 8 +
arch/nds32/boot/dts/ae3xx.dts | 55 ++
arch/nds32/boot/dts/ag101p.dts | 60 ++
arch/nds32/configs/ae3xx_defconfig | 110 +++
arch/nds32/configs/ag101p_defconfig | 109 +++
arch/nds32/include/asm/Kbuild | 54 ++
arch/nds32/include/asm/assembler.h | 52 ++
arch/nds32/include/asm/bitfield.h | 982 ++++++++++++++++++++
arch/nds32/include/asm/cache.h | 25 +
arch/nds32/include/asm/cache_info.h | 26 +
arch/nds32/include/asm/cacheflush.h | 57 ++
arch/nds32/include/asm/current.h | 25 +
arch/nds32/include/asm/delay.h | 51 +
arch/nds32/include/asm/dma-mapping.h | 27 +
arch/nds32/include/asm/elf.h | 192 ++++
arch/nds32/include/asm/fixmap.h | 41 +
arch/nds32/include/asm/futex.h | 116 +++
arch/nds32/include/asm/highmem.h | 78 ++
arch/nds32/include/asm/io.h | 33 +
arch/nds32/include/asm/irqflags.h | 49 +
arch/nds32/include/asm/l2_cache.h | 158 ++++
arch/nds32/include/asm/linkage.h | 24 +
arch/nds32/include/asm/memory.h | 147 +++
arch/nds32/include/asm/mmu.h | 25 +
arch/nds32/include/asm/mmu_context.h | 81 ++
arch/nds32/include/asm/module.h | 24 +
arch/nds32/include/asm/nds32.h | 92 ++
arch/nds32/include/asm/page.h | 78 ++
arch/nds32/include/asm/pgalloc.h | 109 +++
arch/nds32/include/asm/pgtable.h | 426 +++++++++
arch/nds32/include/asm/proc-fns.h | 94 ++
arch/nds32/include/asm/processor.h | 116 +++
arch/nds32/include/asm/ptrace.h | 79 ++
arch/nds32/include/asm/shmparam.h | 33 +
arch/nds32/include/asm/spinlock.h | 178 ++++
arch/nds32/include/asm/string.h | 30 +
arch/nds32/include/asm/swab.h | 48 +
arch/nds32/include/asm/syscall.h | 203 ++++
arch/nds32/include/asm/syscalls.h | 27 +
arch/nds32/include/asm/thread_info.h | 91 ++
arch/nds32/include/asm/tlb.h | 41 +
arch/nds32/include/asm/tlbflush.h | 60 ++
arch/nds32/include/asm/uaccess.h | 385 ++++++++
arch/nds32/include/asm/unistd.h | 21 +
arch/nds32/include/asm/vdso.h | 35 +
arch/nds32/include/asm/vdso_datapage.h | 51 +
arch/nds32/include/uapi/asm/Kbuild | 26 +
arch/nds32/include/uapi/asm/auxvec.h | 25 +
arch/nds32/include/uapi/asm/byteorder.h | 26 +
arch/nds32/include/uapi/asm/cachectl.h | 19 +
arch/nds32/include/uapi/asm/param.h | 24 +
arch/nds32/include/uapi/asm/posix_types.h | 41 +
arch/nds32/include/uapi/asm/ptrace.h | 42 +
arch/nds32/include/uapi/asm/sigcontext.h | 73 ++
arch/nds32/include/uapi/asm/signal.h | 23 +
arch/nds32/include/uapi/asm/unistd.h | 36 +
arch/nds32/kernel/Makefile | 24 +
arch/nds32/kernel/asm-offsets.c | 40 +
arch/nds32/kernel/atl2c.c | 77 ++
arch/nds32/kernel/cacheinfo.c | 62 ++
arch/nds32/kernel/devtree.c | 45 +
arch/nds32/kernel/dma.c | 478 ++++++++++
arch/nds32/kernel/early_printk.c | 124 +++
arch/nds32/kernel/ex-entry.S | 169 ++++
arch/nds32/kernel/ex-exit.S | 207 +++++
arch/nds32/kernel/ex-scall.S | 146 +++
arch/nds32/kernel/head.S | 211 +++++
arch/nds32/kernel/irq.c | 34 +
arch/nds32/kernel/module.c | 299 ++++++
arch/nds32/kernel/nds32_ksyms.c | 54 ++
arch/nds32/kernel/process.c | 219 +++++
arch/nds32/kernel/ptrace.c | 325 +++++++
arch/nds32/kernel/setup.c | 406 ++++++++
arch/nds32/kernel/signal.c | 370 ++++++++
arch/nds32/kernel/stacktrace.c | 60 ++
arch/nds32/kernel/sys_nds32.c | 63 ++
arch/nds32/kernel/syscall_table.c | 28 +
arch/nds32/kernel/time.c | 22 +
arch/nds32/kernel/traps.c | 442 +++++++++
arch/nds32/kernel/vdso.c | 243 +++++
arch/nds32/kernel/vdso/Makefile | 82 ++
arch/nds32/kernel/vdso/datapage.S | 34 +
arch/nds32/kernel/vdso/gen_vdso_offsets.sh | 15 +
arch/nds32/kernel/vdso/gettimeofday.c | 260 ++++++
arch/nds32/kernel/vdso/note.S | 29 +
arch/nds32/kernel/vdso/sigreturn.S | 32 +
arch/nds32/kernel/vdso/vdso.S | 33 +
arch/nds32/kernel/vdso/vdso.lds.S | 87 ++
arch/nds32/kernel/vmlinux.lds.S | 70 ++
arch/nds32/lib/Makefile | 4 +
arch/nds32/lib/copy_page.S | 50 +
arch/nds32/lib/getuser.S | 57 ++
arch/nds32/lib/memcpy.S | 93 ++
arch/nds32/lib/memmove.S | 83 ++
arch/nds32/lib/memset.S | 46 +
arch/nds32/lib/memzero.S | 31 +
arch/nds32/lib/putuser.S | 53 ++
arch/nds32/lib/uaccess.S | 160 ++++
arch/nds32/mm/Makefile | 7 +
arch/nds32/mm/alignment.c | 564 +++++++++++
arch/nds32/mm/cacheflush.c | 331 +++++++
arch/nds32/mm/extable.c | 29 +
arch/nds32/mm/fault.c | 420 +++++++++
arch/nds32/mm/highmem.c | 92 ++
arch/nds32/mm/init.c | 328 +++++++
arch/nds32/mm/ioremap.c | 67 ++
arch/nds32/mm/mm-nds32.c | 103 ++
arch/nds32/mm/mmap.c | 88 ++
arch/nds32/mm/proc-n13.c | 608 ++++++++++++
arch/nds32/mm/tlb.c | 63 ++
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-ativic32.c | 149 +++
drivers/net/ethernet/faraday/Kconfig | 6 +-
121 files changed, 13726 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt
create mode 100644 Documentation/devicetree/bindings/nds32/cpus.txt
create mode 100644 arch/nds32/Kconfig
create mode 100644 arch/nds32/Kconfig.cpu
create mode 100644 arch/nds32/Kconfig.debug
create mode 100644 arch/nds32/Makefile
create mode 100644 arch/nds32/boot/Makefile
create mode 100644 arch/nds32/boot/dts/Makefile
create mode 100644 arch/nds32/boot/dts/ae3xx.dts
create mode 100644 arch/nds32/boot/dts/ag101p.dts
create mode 100644 arch/nds32/configs/ae3xx_defconfig
create mode 100644 arch/nds32/configs/ag101p_defconfig
create mode 100644 arch/nds32/include/asm/Kbuild
create mode 100644 arch/nds32/include/asm/assembler.h
create mode 100644 arch/nds32/include/asm/bitfield.h
create mode 100644 arch/nds32/include/asm/cache.h
create mode 100644 arch/nds32/include/asm/cache_info.h
create mode 100644 arch/nds32/include/asm/cacheflush.h
create mode 100644 arch/nds32/include/asm/current.h
create mode 100644 arch/nds32/include/asm/delay.h
create mode 100644 arch/nds32/include/asm/dma-mapping.h
create mode 100644 arch/nds32/include/asm/elf.h
create mode 100644 arch/nds32/include/asm/fixmap.h
create mode 100644 arch/nds32/include/asm/futex.h
create mode 100644 arch/nds32/include/asm/highmem.h
create mode 100644 arch/nds32/include/asm/io.h
create mode 100644 arch/nds32/include/asm/irqflags.h
create mode 100644 arch/nds32/include/asm/l2_cache.h
create mode 100644 arch/nds32/include/asm/linkage.h
create mode 100644 arch/nds32/include/asm/memory.h
create mode 100644 arch/nds32/include/asm/mmu.h
create mode 100644 arch/nds32/include/asm/mmu_context.h
create mode 100644 arch/nds32/include/asm/module.h
create mode 100644 arch/nds32/include/asm/nds32.h
create mode 100644 arch/nds32/include/asm/page.h
create mode 100644 arch/nds32/include/asm/pgalloc.h
create mode 100644 arch/nds32/include/asm/pgtable.h
create mode 100644 arch/nds32/include/asm/proc-fns.h
create mode 100644 arch/nds32/include/asm/processor.h
create mode 100644 arch/nds32/include/asm/ptrace.h
create mode 100644 arch/nds32/include/asm/shmparam.h
create mode 100644 arch/nds32/include/asm/spinlock.h
create mode 100644 arch/nds32/include/asm/string.h
create mode 100644 arch/nds32/include/asm/swab.h
create mode 100644 arch/nds32/include/asm/syscall.h
create mode 100644 arch/nds32/include/asm/syscalls.h
create mode 100644 arch/nds32/include/asm/thread_info.h
create mode 100644 arch/nds32/include/asm/tlb.h
create mode 100644 arch/nds32/include/asm/tlbflush.h
create mode 100644 arch/nds32/include/asm/uaccess.h
create mode 100644 arch/nds32/include/asm/unistd.h
create mode 100644 arch/nds32/include/asm/vdso.h
create mode 100644 arch/nds32/include/asm/vdso_datapage.h
create mode 100644 arch/nds32/include/uapi/asm/Kbuild
create mode 100644 arch/nds32/include/uapi/asm/auxvec.h
create mode 100644 arch/nds32/include/uapi/asm/byteorder.h
create mode 100644 arch/nds32/include/uapi/asm/cachectl.h
create mode 100644 arch/nds32/include/uapi/asm/param.h
create mode 100644 arch/nds32/include/uapi/asm/posix_types.h
create mode 100644 arch/nds32/include/uapi/asm/ptrace.h
create mode 100644 arch/nds32/include/uapi/asm/sigcontext.h
create mode 100644 arch/nds32/include/uapi/asm/signal.h
create mode 100644 arch/nds32/include/uapi/asm/unistd.h
create mode 100644 arch/nds32/kernel/Makefile
create mode 100644 arch/nds32/kernel/asm-offsets.c
create mode 100644 arch/nds32/kernel/atl2c.c
create mode 100644 arch/nds32/kernel/cacheinfo.c
create mode 100644 arch/nds32/kernel/devtree.c
create mode 100644 arch/nds32/kernel/dma.c
create mode 100644 arch/nds32/kernel/early_printk.c
create mode 100644 arch/nds32/kernel/ex-entry.S
create mode 100644 arch/nds32/kernel/ex-exit.S
create mode 100644 arch/nds32/kernel/ex-scall.S
create mode 100644 arch/nds32/kernel/head.S
create mode 100644 arch/nds32/kernel/irq.c
create mode 100644 arch/nds32/kernel/module.c
create mode 100644 arch/nds32/kernel/nds32_ksyms.c
create mode 100644 arch/nds32/kernel/process.c
create mode 100644 arch/nds32/kernel/ptrace.c
create mode 100644 arch/nds32/kernel/setup.c
create mode 100644 arch/nds32/kernel/signal.c
create mode 100644 arch/nds32/kernel/stacktrace.c
create mode 100644 arch/nds32/kernel/sys_nds32.c
create mode 100644 arch/nds32/kernel/syscall_table.c
create mode 100644 arch/nds32/kernel/time.c
create mode 100644 arch/nds32/kernel/traps.c
create mode 100644 arch/nds32/kernel/vdso.c
create mode 100644 arch/nds32/kernel/vdso/Makefile
create mode 100644 arch/nds32/kernel/vdso/datapage.S
create mode 100755 arch/nds32/kernel/vdso/gen_vdso_offsets.sh
create mode 100644 arch/nds32/kernel/vdso/gettimeofday.c
create mode 100644 arch/nds32/kernel/vdso/note.S
create mode 100644 arch/nds32/kernel/vdso/sigreturn.S
create mode 100644 arch/nds32/kernel/vdso/vdso.S
create mode 100644 arch/nds32/kernel/vdso/vdso.lds.S
create mode 100644 arch/nds32/kernel/vmlinux.lds.S
create mode 100644 arch/nds32/lib/Makefile
create mode 100644 arch/nds32/lib/copy_page.S
create mode 100644 arch/nds32/lib/getuser.S
create mode 100644 arch/nds32/lib/memcpy.S
create mode 100644 arch/nds32/lib/memmove.S
create mode 100644 arch/nds32/lib/memset.S
create mode 100644 arch/nds32/lib/memzero.S
create mode 100644 arch/nds32/lib/putuser.S
create mode 100644 arch/nds32/lib/uaccess.S
create mode 100644 arch/nds32/mm/Makefile
create mode 100644 arch/nds32/mm/alignment.c
create mode 100644 arch/nds32/mm/cacheflush.c
create mode 100644 arch/nds32/mm/extable.c
create mode 100644 arch/nds32/mm/fault.c
create mode 100644 arch/nds32/mm/highmem.c
create mode 100644 arch/nds32/mm/init.c
create mode 100644 arch/nds32/mm/ioremap.c
create mode 100644 arch/nds32/mm/mm-nds32.c
create mode 100644 arch/nds32/mm/mmap.c
create mode 100644 arch/nds32/mm/proc-n13.c
create mode 100644 arch/nds32/mm/tlb.c
create mode 100644 drivers/irqchip/irq-ativic32.c
--
1.7.9.5
From 1583515381882179897@xxx Wed Nov 08 16:19:09 +0000 2017
X-GM-THRID: 1583483662700251868
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/asm/elf.h | 192 ++++++++++++++++++++++++++++++++++
arch/nds32/include/uapi/asm/auxvec.h | 25 +++++
arch/nds32/include/uapi/asm/param.h | 24 +++++
3 files changed, 241 insertions(+)
create mode 100644 arch/nds32/include/asm/elf.h
create mode 100644 arch/nds32/include/uapi/asm/auxvec.h
create mode 100644 arch/nds32/include/uapi/asm/param.h
diff --git a/arch/nds32/include/asm/elf.h b/arch/nds32/include/asm/elf.h
new file mode 100644
index 0000000..a6e4c56
--- /dev/null
+++ b/arch/nds32/include/asm/elf.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 __ASMNDS32_ELF_H
+#define __ASMNDS32_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+
+typedef unsigned long elf_greg_t;
+typedef unsigned long elf_freg_t[3];
+
+extern unsigned int elf_hwcap;
+
+#define EM_NDS32 167
+
+#define R_NDS32_NONE 0
+#define R_NDS32_16_RELA 19
+#define R_NDS32_32_RELA 20
+#define R_NDS32_9_PCREL_RELA 22
+#define R_NDS32_15_PCREL_RELA 23
+#define R_NDS32_17_PCREL_RELA 24
+#define R_NDS32_25_PCREL_RELA 25
+#define R_NDS32_HI20_RELA 26
+#define R_NDS32_LO12S3_RELA 27
+#define R_NDS32_LO12S2_RELA 28
+#define R_NDS32_LO12S1_RELA 29
+#define R_NDS32_LO12S0_RELA 30
+#define R_NDS32_SDA15S3_RELA 31
+#define R_NDS32_SDA15S2_RELA 32
+#define R_NDS32_SDA15S1_RELA 33
+#define R_NDS32_SDA15S0_RELA 34
+#define R_NDS32_GOT20 37
+#define R_NDS32_25_PLTREL 38
+#define R_NDS32_COPY 39
+#define R_NDS32_GLOB_DAT 40
+#define R_NDS32_JMP_SLOT 41
+#define R_NDS32_RELATIVE 42
+#define R_NDS32_GOTOFF 43
+#define R_NDS32_GOTPC20 44
+#define R_NDS32_GOT_HI20 45
+#define R_NDS32_GOT_LO12 46
+#define R_NDS32_GOTPC_HI20 47
+#define R_NDS32_GOTPC_LO12 48
+#define R_NDS32_GOTOFF_HI20 49
+#define R_NDS32_GOTOFF_LO12 50
+#define R_NDS32_INSN16 51
+#define R_NDS32_LABEL 52
+#define R_NDS32_LONGCALL1 53
+#define R_NDS32_LONGCALL2 54
+#define R_NDS32_LONGCALL3 55
+#define R_NDS32_LONGJUMP1 56
+#define R_NDS32_LONGJUMP2 57
+#define R_NDS32_LONGJUMP3 58
+#define R_NDS32_LOADSTORE 59
+#define R_NDS32_9_FIXED_RELA 60
+#define R_NDS32_15_FIXED_RELA 61
+#define R_NDS32_17_FIXED_RELA 62
+#define R_NDS32_25_FIXED_RELA 63
+#define R_NDS32_PLTREL_HI20 64
+#define R_NDS32_PLTREL_LO12 65
+#define R_NDS32_PLT_GOTREL_HI20 66
+#define R_NDS32_PLT_GOTREL_LO12 67
+#define R_NDS32_LO12S0_ORI_RELA 72
+#define R_NDS32_DWARF2_OP1_RELA 77
+#define R_NDS32_DWARF2_OP2_RELA 78
+#define R_NDS32_DWARF2_LEB_RELA 79
+#define R_NDS32_WORD_9_PCREL_RELA 94
+#define R_NDS32_LONGCALL4 107
+#define R_NDS32_RELA_NOP_MIX 192
+#define R_NDS32_RELA_NOP_MAX 255
+
+#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+/* Core file format: The core file is written in such a way that gdb
+ can understand it and provide useful information to the user (under
+ linux we use the 'trad-core' bfd). There are quite a number of
+ obstacles to being able to view the contents of the floating point
+ registers, and until these are solved you will not be able to view the
+ contents of them. Actually, you can read in the core file and look at
+ the contents of the user struct to find out what the floating point
+ registers contain.
+ The actual file contents are as follows:
+ UPAGE: 1 page consisting of a user struct that tells gdb what is present
+ in the file. Directly after this is a copy of the task_struct, which
+ is currently not used by gdb, but it may come in useful at some point.
+ All of the registers are stored as part of the upage. The upage should
+ always be only one page.
+ DATA: The data area is stored. We use current->end_text to
+ current->brk to pick up all of the user variables, plus any memory
+ that may have been malloced. No attempt is made to determine if a page
+ is demand-zero or if a page is totally unused, we just cover the entire
+ range. All of the addresses are rounded in such a way that an integral
+ number of pages is written.
+ STACK: We need the stack information in order to get a meaningful
+ backtrace. We need to write the data from (esp) to
+ current->start_stack, so we round each of these off in order to be able
+ to write an integer number of pages.
+ The minimum core file size is 3 pages, or 12288 bytes.
+*/
+
+struct user_fp {
+ struct fp_reg {
+ unsigned int sign1:1;
+ unsigned int unused:15;
+ unsigned int sign2:1;
+ unsigned int exponent:14;
+ unsigned int j:1;
+ unsigned int mantissa1:31;
+ unsigned int mantissa0:32;
+ } fpregs[8];
+ unsigned int fpsr:32;
+ unsigned int fpcr:32;
+ unsigned char ftype[8];
+ unsigned int init_flag;
+};
+
+typedef struct user_fp elf_fpregset_t;
+
+struct elf32_hdr;
+#define elf_check_arch(x) ((x)->e_machine == EM_NDS32)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#ifdef __NDS32_EB__
+#define ELF_DATA ELFDATA2MSB;
+#else
+#define ELF_DATA ELFDATA2LSB;
+#endif
+#define ELF_ARCH EM_NDS32
+#define USE_ELF_CORE_DUMP
+#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 (2 * TASK_SIZE / 3)
+
+/* When the program starts, a1 contains a pointer to a function to be
+ registered with atexit, as per the SVR4 ABI. A value of 0 means we
+ have no such handler. */
+#define ELF_PLAT_INIT(_r, load_addr) (_r)->uregs[0] = 0
+
+/* This yields a mask that user programs can use to figure out what
+ instruction set this cpu supports. */
+
+#define ELF_HWCAP (elf_hwcap)
+
+#ifdef __KERNEL__
+
+#define ELF_PLATFORM (NULL)
+
+/* Old NetWinder binaries were compiled in such a way that the iBCS
+ heuristic always trips on them. Until these binaries become uncommon
+ enough not to care, don't trust the `ibcs' flag here. In any case
+ there is no other ELF system currently supported by iBCS.
+ @@ Could print a warning message to encourage users to upgrade. */
+#define SET_PERSONALITY(ex) set_personality(PER_LINUX)
+
+#endif
+
+#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 1
+struct linux_binprm;
+int arch_setup_additional_pages(struct linux_binprm *, int);
+
+#endif
diff --git a/arch/nds32/include/uapi/asm/auxvec.h b/arch/nds32/include/uapi/asm/auxvec.h
new file mode 100644
index 0000000..02e9757
--- /dev/null
+++ b/arch/nds32/include/uapi/asm/auxvec.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_AUXVEC_H
+#define __ASM_AUXVEC_H
+
+/* VDSO location */
+#define AT_SYSINFO_EHDR 33
+
+#define AT_VECTOR_SIZE_ARCH 1
+
+#endif
diff --git a/arch/nds32/include/uapi/asm/param.h b/arch/nds32/include/uapi/asm/param.h
new file mode 100644
index 0000000..2e4527f3
--- /dev/null
+++ b/arch/nds32/include/uapi/asm/param.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_NDS32_PARAM_H
+#define __ASM_NDS32_PARAM_H
+
+#define EXEC_PAGESIZE 8192
+
+#include <asm-generic/param.h>
+
+#endif /* __ASM_NDS32_PARAM_H */
--
1.7.9.5
From 1583489756727757063@xxx Wed Nov 08 09:31:51 +0000 2017
X-GM-THRID: 1583489675786660213
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/lib/copy_page.S | 50 ++++++
arch/nds32/mm/extable.c | 29 +++
arch/nds32/mm/fault.c | 420 ++++++++++++++++++++++++++++++++++++++++++++
arch/nds32/mm/mmap.c | 88 ++++++++++
4 files changed, 587 insertions(+)
create mode 100644 arch/nds32/lib/copy_page.S
create mode 100644 arch/nds32/mm/extable.c
create mode 100644 arch/nds32/mm/fault.c
create mode 100644 arch/nds32/mm/mmap.c
diff --git a/arch/nds32/lib/copy_page.S b/arch/nds32/lib/copy_page.S
new file mode 100644
index 0000000..a55a5cc
--- /dev/null
+++ b/arch/nds32/lib/copy_page.S
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+ .text
+ENTRY(copy_page)
+ pushm $r2, $r10
+ movi $r2, PAGE_SIZE >> 5
+.Lcopy_loop:
+ lmw.bim $r3, [$r1], $r10
+ smw.bim $r3, [$r0], $r10
+ subi45 $r2, #1
+ bnez38 $r2, .Lcopy_loop
+ popm $r2, $r10
+ ret
+ENDPROC(copy_page)
+
+ENTRY(clear_page)
+ pushm $r1, $r9
+ movi $r1, PAGE_SIZE >> 5
+ movi55 $r2, #0
+ movi55 $r3, #0
+ movi55 $r4, #0
+ movi55 $r5, #0
+ movi55 $r6, #0
+ movi55 $r7, #0
+ movi55 $r8, #0
+ movi55 $r9, #0
+.Lclear_loop:
+ smw.bim $r2, [$r0], $r9
+ subi45 $r1, #1
+ bnez38 $r1, .Lclear_loop
+ popm $r1, $r9
+ ret
+ENDPROC(clear_page)
diff --git a/arch/nds32/mm/extable.c b/arch/nds32/mm/extable.c
new file mode 100644
index 0000000..bce62d7
--- /dev/null
+++ b/arch/nds32/mm/extable.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/extable.h>
+#include <asm/uaccess.h>
+
+int fixup_exception(struct pt_regs *regs)
+{
+ const struct exception_table_entry *fixup;
+
+ fixup = search_exception_tables(instruction_pointer(regs));
+ if (fixup)
+ regs->ipc = fixup->fixup;
+
+ return fixup != NULL;
+}
diff --git a/arch/nds32/mm/fault.c b/arch/nds32/mm/fault.c
new file mode 100644
index 0000000..e15b2c1
--- /dev/null
+++ b/arch/nds32/mm/fault.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/extable.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/hardirq.h>
+
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/uaccess.h>
+
+extern void die(const char *str, struct pt_regs *regs, long err);
+
+/*
+ * This is useful to dump out the page tables associated with
+ * 'addr' in mm 'mm'.
+ */
+void show_pte(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t *pgd;
+ if (!mm)
+ mm = &init_mm;
+
+ pr_alert("pgd = %p\n", mm->pgd);
+ pgd = pgd_offset(mm, addr);
+ pr_alert("[%08lx] *pgd=%08lx", addr, pgd_val(*pgd));
+
+ do {
+ pmd_t *pmd;
+
+ if (pgd_none(*pgd))
+ break;
+
+ if (pgd_bad(*pgd)) {
+ pr_alert("(bad)");
+ break;
+ }
+
+ pmd = pmd_offset(pgd, addr);
+#if PTRS_PER_PMD != 1
+ pr_alert(", *pmd=%08lx", pmd_val(*pmd));
+#endif
+
+ if (pmd_none(*pmd))
+ break;
+
+ if (pmd_bad(*pmd)) {
+ pr_alert("(bad)");
+ break;
+ }
+#ifndef CONFIG_HIGHMEM
+ {
+ pte_t *pte;
+ /* We must not map this if we have highmem enabled */
+ pte = pte_offset_map(pmd, addr);
+ pr_alert(", *pte=%08lx", pte_val(*pte));
+ pte_unmap(pte);
+ }
+#endif
+ } while (0);
+
+ pr_alert("\n");
+}
+
+void do_page_fault(unsigned long entry, unsigned long addr,
+ unsigned int error_code, struct pt_regs *regs)
+{
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ siginfo_t info;
+ int fault;
+ unsigned int mask = VM_READ | VM_WRITE | VM_EXEC;
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
+
+ error_code = error_code & (ITYPE_mskINST | ITYPE_mskETYPE);
+ tsk = current;
+ mm = tsk->mm;
+ info.si_code = SEGV_MAPERR;
+ /*
+ * We 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 (addr >= TASK_SIZE) {
+ if (user_mode(regs))
+ goto bad_area_nosemaphore;
+
+ if (addr >= TASK_SIZE && addr < VMALLOC_END
+ && (entry == ENTRY_PTE_NOT_PRESENT))
+ goto vmalloc_fault;
+ else
+ goto no_context;
+ }
+
+ /* Send a signal to the task for handling the unalignment access. */
+ if (entry == ENTRY_GENERAL_EXCPETION
+ && error_code == ETYPE_ALIGNMENT_CHECK) {
+ if (user_mode(regs))
+ goto bad_area_nosemaphore;
+ else
+ goto no_context;
+ }
+
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (unlikely(in_atomic() || !mm))
+ goto no_context;
+
+ /*
+ * As per x86, we may deadlock here. However, since the kernel only
+ * validly references user space from well defined areas of the code,
+ * we can bug out early if this is from code which shouldn't.
+ */
+ if (unlikely(!down_read_trylock(&mm->mmap_sem))) {
+ if (!user_mode(regs) &&
+ !search_exception_tables(instruction_pointer(regs)))
+ goto no_context;
+retry:
+ down_read(&mm->mmap_sem);
+ } else {
+ /*
+ * The above down_read_trylock() might have succeeded in which
+ * case, we'll have missed the might_sleep() from down_read().
+ */
+ might_sleep();
+#ifdef CONFIG_DEBUG_VM
+ if (!user_mode(regs) &&
+ !search_exception_tables(instruction_pointer(regs)))
+ goto no_context;
+#endif
+ }
+
+ vma = find_vma(mm, addr);
+
+ if (unlikely(!vma))
+ goto bad_area;
+
+ if (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:
+ info.si_code = SEGV_ACCERR;
+
+ /* first do some preliminary protection checks */
+ if (entry == ENTRY_PTE_NOT_PRESENT) {
+ if (error_code & ITYPE_mskINST)
+ mask = VM_EXEC;
+ else {
+ mask = VM_READ | VM_WRITE;
+ if (vma->vm_flags & VM_WRITE)
+ flags |= FAULT_FLAG_WRITE;
+ }
+ } else if (entry == ENTRY_TLB_MISC) {
+ switch (error_code & ITYPE_mskETYPE) {
+ case RD_PROT:
+ mask = VM_READ;
+ break;
+ case WRT_PROT:
+ mask = VM_WRITE;
+ flags |= FAULT_FLAG_WRITE;
+ break;
+ case NOEXEC:
+ mask = VM_EXEC;
+ break;
+ case PAGE_MODIFY:
+ mask = VM_WRITE;
+ flags |= FAULT_FLAG_WRITE;
+ break;
+ case ACC_BIT:
+ BUG();
+ default:
+ break;
+ }
+
+ }
+ if (!(vma->vm_flags & mask))
+ goto bad_area;
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+
+ fault = handle_mm_fault(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(current))
+ 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;
+ else
+ goto bad_area;
+ }
+
+ /*
+ * 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++;
+ else
+ tsk->min_flt++;
+ if (fault & VM_FAULT_RETRY) {
+ 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);
+
+bad_area_nosemaphore:
+
+ /* User mode accesses just cause a SIGSEGV */
+
+ if (user_mode(regs)) {
+ tsk->thread.address = addr;
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = entry;
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* info.si_code has been set above */
+ info.si_addr = (void *)addr;
+ force_sig_info(SIGSEGV, &info, tsk);
+ return;
+ }
+
+no_context:
+
+ /* Are we prepared to handle this kernel fault?
+ *
+ * (The kernel has valid exception-points in the source
+ * when it acesses user-memory. When it fails in one
+ * of those points, we find it in a table and do a jump
+ * to some fixup code that loads an appropriate error
+ * code)
+ */
+
+ {
+ const struct exception_table_entry *entry;
+
+ if ((entry =
+ search_exception_tables(instruction_pointer(regs))) !=
+ NULL) {
+ /* Adjust the instruction pointer in the stackframe */
+ instruction_pointer(regs) = entry->fixup;
+ 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 %08lx\n",
+ (addr < PAGE_SIZE) ? "NULL pointer dereference" :
+ "paging request", addr);
+
+ show_pte(mm, addr);
+ die("Oops", regs, error_code);
+ bust_spinlocks(0);
+ do_exit(SIGKILL);
+
+ return;
+
+ /*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+
+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;
+
+ /*
+ * Send a sigbus
+ */
+ tsk->thread.address = addr;
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = entry;
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)addr;
+ force_sig_info(SIGBUS, &info, tsk);
+
+ return;
+
+vmalloc_fault:
+ {
+ /*
+ * Synchronize this task's top level page-table
+ * with the 'reference' page table.
+ *
+ * Use current_pgd instead of tsk->active_mm->pgd
+ * since the latter might be unavailable if this
+ * code is executed in a misfortunately run irq
+ * (like inside schedule() between switch_mm and
+ * switch_to...).
+ */
+
+ unsigned int index = pgd_index(addr);
+ pgd_t *pgd, *pgd_k;
+ pud_t *pud, *pud_k;
+ pmd_t *pmd, *pmd_k;
+ pte_t *pte_k;
+
+ pgd = (pgd_t *) __va(__nds32__mfsr(NDS32_SR_L1_PPTB)) + index;
+ pgd_k = init_mm.pgd + index;
+
+ if (!pgd_present(*pgd_k))
+ goto no_context;
+
+ pud = pud_offset(pgd, addr);
+ pud_k = pud_offset(pgd_k, addr);
+ if (!pud_present(*pud_k))
+ goto no_context;
+
+ pmd = pmd_offset(pud, addr);
+ pmd_k = pmd_offset(pud_k, addr);
+ if (!pmd_present(*pmd_k))
+ goto no_context;
+
+ if (!pmd_present(*pmd))
+ set_pmd(pmd, *pmd_k);
+ else
+ BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
+
+ /*
+ * Since the vmalloc area is global, we don't
+ * need to copy individual PTE's, it is enough to
+ * copy the pgd pointer into the pte page of the
+ * root task. If that is there, we'll find our pte if
+ * it exists.
+ */
+
+ /* Make sure the actual PTE exists as well to
+ * catch kernel vmalloc-area accesses to non-mapped
+ * addres. 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 --git a/arch/nds32/mm/mmap.c b/arch/nds32/mm/mmap.c
new file mode 100644
index 0000000..91394f5
--- /dev/null
+++ b/arch/nds32/mm/mmap.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/sched.h>
+#include <linux/mman.h>
+#include <linux/shm.h>
+
+#define COLOUR_ALIGN(addr,pgoff) \
+ ((((addr)+REALSHMLBA-1)&~(REALSHMLBA-1)) + \
+ (((pgoff)<<PAGE_SHIFT) & (REALSHMLBA-1)))
+
+/*
+ * We need to ensure that shared mappings are correctly aligned to
+ * avoid aliasing issues with VIPT caches. We need to ensure that
+ * a specific page of an object is always mapped at a multiple of
+ * SHMLBA bytes.
+ *
+ * We unconditionally provide this function for all cases, however
+ * in the VIVT case, we optimise out the alignment rules.
+ */
+unsigned long
+arch_get_unmapped_area(struct file *filp, unsigned long addr,
+ unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ int do_align = 0;
+#ifdef CONFIG_CPU_CACHE_NONALIASING
+ int aliasing = 0;
+#else
+ int aliasing = 1;
+#endif
+ struct vm_unmapped_area_info info;
+
+ /*
+ * We only need to do colour alignment if either the I or D
+ * caches alias.
+ */
+ if (aliasing)
+ do_align = filp || (flags & MAP_SHARED);
+
+ /*
+ * We enforce the MAP_FIXED case.
+ */
+ if (flags & MAP_FIXED) {
+ if (aliasing && flags & MAP_SHARED &&
+ (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
+ return -EINVAL;
+ return addr;
+ }
+
+ if (len > TASK_SIZE)
+ return -ENOMEM;
+
+ if (addr) {
+ if (do_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
+ else
+ addr = PAGE_ALIGN(addr);
+
+ vma = find_vma(mm, addr);
+ if (TASK_SIZE - len >= addr &&
+ (!vma || addr + len <= vma->vm_start))
+ return addr;
+ }
+
+ info.flags = 0;
+ info.length = len;
+ info.low_limit = mm->mmap_base;
+ info.high_limit = TASK_SIZE;
+ info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
+ info.align_offset = pgoff << PAGE_SHIFT;
+ return vm_unmapped_area(&info);
+}
--
1.7.9.5
From 1583483473012498578@xxx Wed Nov 08 07:51:58 +0000 2017
X-GM-THRID: 1583483473012498578
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/kernel/time.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 arch/nds32/kernel/time.c
diff --git a/arch/nds32/kernel/time.c b/arch/nds32/kernel/time.c
new file mode 100644
index 0000000..96e2f87
--- /dev/null
+++ b/arch/nds32/kernel/time.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/clocksource.h>
+
+void __init time_init(void)
+{
+ timer_probe();
+}
--
1.7.9.5
From 1583535045173758199@xxx Wed Nov 08 21:31:41 +0000 2017
X-GM-THRID: 1583471143734724398
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Rick Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
.../interrupt-controller/andestech,ativic32.txt | 27 ++++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt
diff --git a/Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt b/Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt
new file mode 100644
index 0000000..6bac908
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/andestech,ativic32.txt
@@ -0,0 +1,27 @@
+* Andestech Internal Vector Interrupt Controller
+
+The Internal Vector Interrupt Controller (IVIC) is a basic interrupt controller
+suitable for a simpler SoC platform not requiring a more sophisticated and
+bigger External Vector Interrupt Controller.
+
+
+Main node required properties:
+
+- compatible : should at least contain "andestech,ativic32".
+- interrupt-parent: Empty for the interrupt controller itself
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells: The number of cells to define the interrupts. Should be 2.
+ The first cell is the IRQ number
+ The second cell is used to specify mode:
+ 1 = low-to-high edge triggered
+ 2 = high-to-low edge triggered
+ 4 = active high level-sensitive
+ 8 = active low level-sensitive
+ Default for internal sources should be set to 4 (active high).
+
+Examples:
+ intc: interrupt-controller {
+ compatible = "andestech,ativic32";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ };
--
1.7.9.5
From 1583480618954584265@xxx Wed Nov 08 07:06:36 +0000 2017
X-GM-THRID: 1583480618954584265
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/asm/module.h | 24 ++++
arch/nds32/kernel/module.c | 299 +++++++++++++++++++++++++++++++++++++++
2 files changed, 323 insertions(+)
create mode 100644 arch/nds32/include/asm/module.h
create mode 100644 arch/nds32/kernel/module.c
diff --git a/arch/nds32/include/asm/module.h b/arch/nds32/include/asm/module.h
new file mode 100644
index 0000000..5ed2b75
--- /dev/null
+++ b/arch/nds32/include/asm/module.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_NDS32_MODULE_H
+#define _ASM_NDS32_MODULE_H
+
+#include <asm-generic/module.h>
+
+#define MODULE_ARCH_VERMAGIC "NDS32v3"
+
+#endif /* _ASM_NDS32_MODULE_H */
diff --git a/arch/nds32/kernel/module.c b/arch/nds32/kernel/module.c
new file mode 100644
index 0000000..bb34e23
--- /dev/null
+++ b/arch/nds32/kernel/module.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/module.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+
+#include <asm/pgtable.h>
+
+void *module_alloc(unsigned long size)
+{
+ return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
+ GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
+ __builtin_return_address(0));
+}
+
+void module_free(struct module *module, void *region)
+{
+ vfree(region);
+}
+
+int module_frob_arch_sections(Elf_Ehdr * hdr,
+ Elf_Shdr * sechdrs,
+ char *secstrings, struct module *mod)
+{
+ return 0;
+}
+
+void do_reloc16(unsigned int val, unsigned int *loc, unsigned int val_mask,
+ unsigned int val_shift, unsigned int loc_mask,
+ unsigned int partial_in_place, unsigned int swap)
+{
+ unsigned int tmp = 0, tmp2 = 0;
+
+ __asm__ __volatile__("\tlhi.bi\t%0, [%2], 0\n"
+ "\tbeqz\t%3, 1f\n"
+ "\twsbh\t%0, %1\n"
+ "1:\n":"=r"(tmp):"0"(tmp), "r"(loc), "r"(swap)
+ );
+
+ tmp2 = tmp & loc_mask;
+ if (partial_in_place) {
+ tmp &= (!loc_mask);
+ tmp =
+ tmp2 | ((tmp + ((val & val_mask) >> val_shift)) & val_mask);
+ } else {
+ tmp = tmp2 | ((val & val_mask) >> val_shift);
+ }
+
+ __asm__ __volatile__("\tbeqz\t%3, 2f\n"
+ "\twsbh\t%0, %1\n"
+ "2:\n"
+ "\tshi.bi\t%0, [%2], 0\n":"=r"(tmp):"0"(tmp),
+ "r"(loc), "r"(swap)
+ );
+}
+
+void do_reloc32(unsigned int val, unsigned int *loc, unsigned int val_mask,
+ unsigned int val_shift, unsigned int loc_mask,
+ unsigned int partial_in_place, unsigned int swap)
+{
+ unsigned int tmp = 0, tmp2 = 0;
+
+ __asm__ __volatile__("\tlmw.bi\t%0, [%2], %0, 0\n"
+ "\tbeqz\t%3, 1f\n"
+ "\twsbh\t%0, %1\n"
+ "\trotri\t%0, %1, 16\n"
+ "1:\n":"=r"(tmp):"0"(tmp), "r"(loc), "r"(swap)
+ );
+
+ tmp2 = tmp & loc_mask;
+ if (partial_in_place) {
+ tmp &= (!loc_mask);
+ tmp =
+ tmp2 | ((tmp + ((val & val_mask) >> val_shift)) & val_mask);
+ } else {
+ tmp = tmp2 | ((val & val_mask) >> val_shift);
+ }
+
+ __asm__ __volatile__("\tbeqz\t%3, 2f\n"
+ "\twsbh\t%0, %1\n"
+ "\trotri\t%0, %1, 16\n"
+ "2:\n"
+ "\tsmw.bi\t%0, [%2], %0, 0\n":"=r"(tmp):"0"(tmp),
+ "r"(loc), "r"(swap)
+ );
+}
+
+static inline int exceed_limit(int offset, unsigned int val_mask,
+ struct module *module, Elf32_Rela * rel,
+ unsigned int relindex, unsigned int reloc_order)
+{
+ int abs_off = offset < 0 ? ~offset : offset;
+
+ if (abs_off & (~val_mask)) {
+ pr_err("\n%s: relocation type %d out of range.\n"
+ "please rebuild the kernel module with gcc option \"-Wa,-mno-small-text\".\n",
+ module->name, ELF32_R_TYPE(rel->r_info));
+ pr_err("section %d reloc %d offset 0x%x relative 0x%x.\n",
+ relindex, reloc_order, rel->r_offset, offset);
+ return true;
+ }
+ return false;
+}
+
+#ifdef __NDS32_EL__
+#define NEED_SWAP 1
+#else
+#define NEED_SWAP 0
+#endif
+
+int
+apply_relocate_add(Elf32_Shdr * sechdrs, const char *strtab,
+ unsigned int symindex, unsigned int relindex,
+ struct module *module)
+{
+ Elf32_Shdr *symsec = sechdrs + symindex;
+ Elf32_Shdr *relsec = sechdrs + relindex;
+ Elf32_Shdr *dstsec = sechdrs + relsec->sh_info;
+ Elf32_Rela *rel = (void *)relsec->sh_addr;
+ unsigned int i;
+
+ for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rela); i++, rel++) {
+ Elf32_Addr *loc;
+ Elf32_Sym *sym;
+ Elf32_Addr v;
+ s32 offset;
+
+ offset = ELF32_R_SYM(rel->r_info);
+ if (offset < 0
+ || offset > (symsec->sh_size / sizeof(Elf32_Sym))) {
+ pr_err("%s: bad relocation\n", module->name);
+ pr_err("section %d reloc %d\n", relindex, i);
+ return -ENOEXEC;
+ }
+
+ sym = ((Elf32_Sym *) symsec->sh_addr) + offset;
+
+ if (rel->r_offset < 0
+ || rel->r_offset > dstsec->sh_size - sizeof(u16)) {
+ pr_err("%s: out of bounds relocation\n", module->name);
+ pr_err("section %d reloc %d offset 0x%0x size %d\n",
+ relindex, i, rel->r_offset, dstsec->sh_size);
+ return -ENOEXEC;
+ }
+
+ loc = (Elf32_Addr *) (dstsec->sh_addr + rel->r_offset);
+ v = sym->st_value + rel->r_addend;
+
+ switch (ELF32_R_TYPE(rel->r_info)) {
+ case R_NDS32_NONE:
+ case R_NDS32_INSN16:
+ case R_NDS32_LABEL:
+ case R_NDS32_LONGCALL1:
+ case R_NDS32_LONGCALL2:
+ case R_NDS32_LONGCALL3:
+ case R_NDS32_LONGCALL4:
+ case R_NDS32_LONGJUMP1:
+ case R_NDS32_LONGJUMP2:
+ case R_NDS32_LONGJUMP3:
+ case R_NDS32_9_FIXED_RELA:
+ case R_NDS32_15_FIXED_RELA:
+ case R_NDS32_17_FIXED_RELA:
+ case R_NDS32_25_FIXED_RELA:
+ case R_NDS32_LOADSTORE:
+ case R_NDS32_DWARF2_OP1_RELA:
+ case R_NDS32_DWARF2_OP2_RELA:
+ case R_NDS32_DWARF2_LEB_RELA:
+ case R_NDS32_RELA_NOP_MIX ... R_NDS32_RELA_NOP_MAX:
+ break;
+
+ case R_NDS32_32_RELA:
+ do_reloc32(v, loc, 0xffffffff, 0, 0, 0, 0);
+ break;
+
+ case R_NDS32_HI20_RELA:
+ do_reloc32(v, loc, 0xfffff000, 12, 0xfff00000, 0,
+ NEED_SWAP);
+ break;
+
+ case R_NDS32_LO12S3_RELA:
+ do_reloc32(v, loc, 0x00000fff, 3, 0xfffff000, 0,
+ NEED_SWAP);
+ break;
+
+ case R_NDS32_LO12S2_RELA:
+ do_reloc32(v, loc, 0x00000fff, 2, 0xfffff000, 0,
+ NEED_SWAP);
+ break;
+
+ case R_NDS32_LO12S1_RELA:
+ do_reloc32(v, loc, 0x00000fff, 1, 0xfffff000, 0,
+ NEED_SWAP);
+ break;
+
+ case R_NDS32_LO12S0_RELA:
+ case R_NDS32_LO12S0_ORI_RELA:
+ do_reloc32(v, loc, 0x00000fff, 0, 0xfffff000, 0,
+ NEED_SWAP);
+ break;
+
+ case R_NDS32_9_PCREL_RELA:
+ if (exceed_limit
+ ((v - (Elf32_Addr) loc), 0x000000ff, module, rel,
+ relindex, i))
+ return -ENOEXEC;
+ do_reloc16(v - (Elf32_Addr) loc, loc, 0x000001ff, 1,
+ 0xffffff00, 0, NEED_SWAP);
+ break;
+
+ case R_NDS32_15_PCREL_RELA:
+ if (exceed_limit
+ ((v - (Elf32_Addr) loc), 0x00003fff, module, rel,
+ relindex, i))
+ return -ENOEXEC;
+ do_reloc32(v - (Elf32_Addr) loc, loc, 0x00007fff, 1,
+ 0xffffc000, 0, NEED_SWAP);
+ break;
+
+ case R_NDS32_17_PCREL_RELA:
+ if (exceed_limit
+ ((v - (Elf32_Addr) loc), 0x0000ffff, module, rel,
+ relindex, i))
+ return -ENOEXEC;
+ do_reloc32(v - (Elf32_Addr) loc, loc, 0x0001ffff, 1,
+ 0xffff0000, 0, NEED_SWAP);
+ break;
+
+ case R_NDS32_25_PCREL_RELA:
+ if (exceed_limit
+ ((v - (Elf32_Addr) loc), 0x00ffffff, module, rel,
+ relindex, i))
+ return -ENOEXEC;
+ do_reloc32(v - (Elf32_Addr) loc, loc, 0x01ffffff, 1,
+ 0xff000000, 0, NEED_SWAP);
+ break;
+ case R_NDS32_WORD_9_PCREL_RELA:
+ if (exceed_limit
+ ((v - (Elf32_Addr) loc), 0x000000ff, module, rel,
+ relindex, i))
+ return -ENOEXEC;
+ do_reloc32(v - (Elf32_Addr) loc, loc, 0x000001ff, 1,
+ 0xffffff00, 0, NEED_SWAP);
+ break;
+
+ case R_NDS32_SDA15S3_RELA:
+ case R_NDS32_SDA15S2_RELA:
+ case R_NDS32_SDA15S1_RELA:
+ case R_NDS32_SDA15S0_RELA:
+ pr_err("%s: unsupported relocation type %d.\n",
+ module->name, ELF32_R_TYPE(rel->r_info));
+ pr_err
+ ("Small data section access doesn't work in the kernel space; "
+ "please rebuild the kernel module with gcc option -mcmodel=large.\n");
+ pr_err("section %d reloc %d offset 0x%x size %d\n",
+ relindex, i, rel->r_offset, dstsec->sh_size);
+ break;
+
+ default:
+ pr_err("%s: unsupported relocation type %d.\n",
+ module->name, ELF32_R_TYPE(rel->r_info));
+ pr_err("section %d reloc %d offset 0x%x size %d\n",
+ relindex, i, rel->r_offset, dstsec->sh_size);
+ }
+ }
+ return 0;
+}
+
+int
+apply_relocate(Elf32_Shdr * sechdrs, const char *strtab,
+ unsigned int symindex, unsigned int relsec,
+ struct module *module)
+{
+ return 0;
+}
+
+int
+module_finalize(const Elf32_Ehdr * hdr, const Elf_Shdr * sechdrs,
+ struct module *module)
+{
+ return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+}
--
1.7.9.5
From 1583486561644091557@xxx Wed Nov 08 08:41:04 +0000 2017
X-GM-THRID: 1583059777669873550
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/uapi/asm/ptrace.h | 42 +++++
arch/nds32/kernel/ptrace.c | 325 ++++++++++++++++++++++++++++++++++
2 files changed, 367 insertions(+)
create mode 100644 arch/nds32/include/uapi/asm/ptrace.h
create mode 100644 arch/nds32/kernel/ptrace.c
diff --git a/arch/nds32/include/uapi/asm/ptrace.h b/arch/nds32/include/uapi/asm/ptrace.h
new file mode 100644
index 0000000..20f9718
--- /dev/null
+++ b/arch/nds32/include/uapi/asm/ptrace.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 __UAPI_ASM_NDS32_PTRACE_H
+#define __UAPI_ASM_NDS32_PTRACE_H
+
+#ifndef __ASSEMBLY__
+
+/*
+ * User structures for general purpose register.
+ */
+struct user_pt_regs {
+ long uregs[26];
+ long fp;
+ long gp;
+ long lp;
+ long sp;
+ long ipc;
+#if defined(CONFIG_HWZOL)
+ long lb;
+ long le;
+ long lc;
+#else
+ long dummy[3];
+#endif
+ long syscallno;
+};
+#endif
+#endif
diff --git a/arch/nds32/kernel/ptrace.c b/arch/nds32/kernel/ptrace.c
new file mode 100644
index 0000000..d91b3b8
--- /dev/null
+++ b/arch/nds32/kernel/ptrace.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/security.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/regset.h>
+#include <linux/tracehook.h>
+#include <linux/elf.h>
+#include <linux/sched/task_stack.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+enum nds32_regset {
+ REGSET_GPR,
+};
+
+static int gpr_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user * ubuf)
+{
+ struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs;
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
+}
+
+static int 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 err;
+ struct user_pt_regs newregs = task_pt_regs(target)->user_regs;
+
+ err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
+ if (err)
+ return err;
+
+ task_pt_regs(target)->user_regs = newregs;
+ return 0;
+}
+
+static const struct user_regset nds32_regsets[] = {
+ [REGSET_GPR] = {
+ .core_note_type = NT_PRSTATUS,
+ .n = sizeof(struct user_pt_regs) / sizeof(u32),
+ .size = sizeof(u32),
+ .align = sizeof(u32),
+ .get = gpr_get,
+ .set = gpr_set}
+};
+
+static const struct user_regset_view nds32_user_view = {
+ .name = "nds32",.e_machine = EM_NDS32,
+ .regsets = nds32_regsets,.n = ARRAY_SIZE(nds32_regsets)
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+ return &nds32_user_view;
+}
+
+/* get_user_reg()
+ *
+ * This routine will get a word off of the processes privileged stack.
+ * the offset is how far from the base addr as stored in the THREAD.
+ * this routine assumes that all the privileged stacks are in our
+ * data space.
+ */
+static inline unsigned int get_user_reg(struct task_struct *task, int offset)
+{
+ return task_pt_regs(task)->uregs[offset];
+}
+
+/* put_user_reg()
+ *
+ * this routine will put a word on the processes privileged stack.
+ * the offset is how far from the base addr as stored in the THREAD.
+ * this routine assumes that all the privileged stacks are in our
+ * data space.
+ */
+static inline int put_user_reg(struct task_struct *task, int offset, long data)
+{
+ struct pt_regs newregs, *regs = task_pt_regs(task);
+ int ret = -EINVAL;
+
+ newregs = *regs;
+ newregs.uregs[offset] = data;
+
+ if (valid_user_regs(&newregs)) {
+ regs->uregs[offset] = data;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+ user_disable_single_step(child);
+}
+
+static void fill_sigtrap_info(struct task_struct *tsk,
+ struct pt_regs *regs,
+ int error_code, int si_code, struct siginfo *info)
+{
+ tsk->thread.trap_no = ENTRY_DEBUG_RELATED;
+ tsk->thread.error_code = error_code;
+
+ memset(info, 0, sizeof(*info));
+ info->si_signo = SIGTRAP;
+ info->si_code = si_code;
+ info->si_addr = (void __user *)instruction_pointer(regs);
+}
+
+void user_single_step_siginfo(struct task_struct *tsk,
+ struct pt_regs *regs, struct siginfo *info)
+{
+ fill_sigtrap_info(tsk, regs, 0, TRAP_BRKPT, info);
+}
+
+/*
+ * Handle hitting a breakpoint.
+ */
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+ int error_code, int si_code)
+{
+ struct siginfo info;
+
+ fill_sigtrap_info(tsk, regs, error_code, TRAP_BRKPT, &info);
+ /* Send us the fake SIGTRAP */
+ force_sig_info(SIGTRAP, &info, tsk);
+}
+
+/* ptrace_read_user()
+ *
+ * Read the word at offset "off" into the "struct user". We
+ * actually access the pt_regs stored on the kernel stack.
+ */
+static int
+ptrace_read_user(struct task_struct *tsk, unsigned long off,
+ unsigned long __user * ret)
+{
+ unsigned long tmp = 0;
+
+ if (off < sizeof(struct pt_regs)) {
+ if (off & 3)
+ return -EIO;
+ tmp = get_user_reg(tsk, off >> 2);
+ return put_user(tmp, ret);
+ } else
+ return -EIO;
+}
+
+/* ptrace_write_user()
+ *
+ * Write the word at offset "off" into "struct user". We
+ * actually access the pt_regs stored on the kernel stack.
+ */
+static int
+ptrace_write_user(struct task_struct *tsk, unsigned long off, unsigned long val)
+{
+ if (off < sizeof(struct pt_regs)) {
+ if (off & 3)
+ return -EIO;
+ return put_user_reg(tsk, off >> 2, val);
+ } else
+ return -EIO;
+}
+
+/* ptrace_getregs()
+ *
+ * Get all user integer registers.
+ */
+static int ptrace_getregs(struct task_struct *tsk, void __user * uregs)
+{
+ struct pt_regs *regs = task_pt_regs(tsk);
+
+ return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
+}
+
+/* ptrace_setregs()
+ *
+ * Set all user integer registers.
+ */
+static int ptrace_setregs(struct task_struct *tsk, void __user * uregs)
+{
+ struct pt_regs newregs;
+ int ret;
+
+ ret = -EFAULT;
+ if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) {
+ struct pt_regs *regs = task_pt_regs(tsk);
+
+ ret = -EINVAL;
+ if (valid_user_regs(&newregs)) {
+ *regs = newregs;
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+/* ptrace_getfpregs()
+ *
+ * Get the child FPU state.
+ */
+static int ptrace_getfpregs(struct task_struct *tsk, void __user * ufpregs)
+{
+ return -EFAULT;
+}
+
+/*
+ * Set the child FPU state.
+ */
+static int ptrace_setfpregs(struct task_struct *tsk, void __user * ufpregs)
+{
+ return -EFAULT;
+}
+
+/* do_ptrace()
+ *
+ * Provide ptrace defined service.
+ */
+long arch_ptrace(struct task_struct *child, long request, unsigned long addr,
+ unsigned long data)
+{
+ int ret;
+
+ switch (request) {
+ case PTRACE_PEEKUSR:
+ ret =
+ ptrace_read_user(child, addr, (unsigned long __user *)data);
+ break;
+
+ case PTRACE_POKEUSR:
+ ret = ptrace_write_user(child, addr, data);
+ break;
+
+ case PTRACE_GETREGS:
+ ret = ptrace_getregs(child, (void __user *)data);
+ break;
+
+ case PTRACE_SETREGS:
+ ret = ptrace_setregs(child, (void __user *)data);
+ break;
+
+ case PTRACE_GETFPREGS:
+ ret = ptrace_getfpregs(child, (void __user *)data);
+ break;
+
+ case PTRACE_SETFPREGS:
+ ret = ptrace_setfpregs(child, (void __user *)data);
+ break;
+
+ default:
+ ret = ptrace_request(child, request, addr, data);
+ break;
+ }
+
+ return ret;
+}
+
+void user_enable_single_step(struct task_struct *child)
+{
+ struct pt_regs *regs;
+ regs = task_pt_regs(child);
+ regs->ipsw |= PSW_mskHSS;
+ set_tsk_thread_flag(child, TIF_SINGLESTEP);
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+ struct pt_regs *regs;
+ regs = task_pt_regs(child);
+ regs->ipsw &= ~PSW_mskHSS;
+ clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+}
+
+/* sys_trace()
+ *
+ * syscall trace handler.
+ */
+
+asmlinkage int syscall_trace_enter(int syscall, struct pt_regs *regs)
+{
+ if (test_thread_flag(TIF_SYSCALL_TRACE)) {
+ if (tracehook_report_syscall_entry(regs))
+ return -1;
+ }
+ return syscall;
+}
+
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+ int step = test_thread_flag(TIF_SINGLESTEP);
+ if (step || test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(regs, step);
+
+}
--
1.7.9.5
From 1584465518295257001@xxx Sun Nov 19 04:01:10 +0000 2017
X-GM-THRID: 1584465518295257001
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/asm/fixmap.h | 41 ++++
arch/nds32/include/asm/highmem.h | 78 +++++++
arch/nds32/include/asm/memory.h | 147 +++++++++++++
arch/nds32/include/asm/mmu.h | 25 +++
arch/nds32/include/asm/page.h | 78 +++++++
arch/nds32/include/asm/pgalloc.h | 109 ++++++++++
arch/nds32/include/asm/pgtable.h | 426 +++++++++++++++++++++++++++++++++++++
arch/nds32/include/asm/shmparam.h | 33 +++
8 files changed, 937 insertions(+)
create mode 100644 arch/nds32/include/asm/fixmap.h
create mode 100644 arch/nds32/include/asm/highmem.h
create mode 100644 arch/nds32/include/asm/memory.h
create mode 100644 arch/nds32/include/asm/mmu.h
create mode 100644 arch/nds32/include/asm/page.h
create mode 100644 arch/nds32/include/asm/pgalloc.h
create mode 100644 arch/nds32/include/asm/pgtable.h
create mode 100644 arch/nds32/include/asm/shmparam.h
diff --git a/arch/nds32/include/asm/fixmap.h b/arch/nds32/include/asm/fixmap.h
new file mode 100644
index 0000000..38e8ee1
--- /dev/null
+++ b/arch/nds32/include/asm/fixmap.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_NDS32_FIXMAP_H
+#define __ASM_NDS32_FIXMAP_H
+
+#ifdef CONFIG_HIGHMEM
+#include <linux/threads.h>
+#include <asm/kmap_types.h>
+#endif
+
+enum fixed_addresses {
+ FIX_KMAP_RESERVED,
+ FIX_KMAP_BEGIN,
+#ifdef CONFIG_HIGHMEM
+ FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS),
+#endif
+#ifdef CONFIG_EARLY_PRINTK
+ FIX_EARLY_DEBUG,
+#endif
+ __end_of_fixed_addresses
+};
+#define FIXADDR_TOP ((unsigned long) (-(16 * PAGE_SIZE)))
+#define FIXADDR_SIZE ((__end_of_fixed_addresses) << PAGE_SHIFT)
+#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
+
+#include <asm-generic/fixmap.h>
+#endif /* __ASM_NDS32_FIXMAP_H */
diff --git a/arch/nds32/include/asm/highmem.h b/arch/nds32/include/asm/highmem.h
new file mode 100644
index 0000000..6a569c1
--- /dev/null
+++ b/arch/nds32/include/asm/highmem.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_HIGHMEM_H
+#define _ASM_HIGHMEM_H
+
+#include <asm/proc-fns.h>
+#include <asm/kmap_types.h>
+#include <asm/fixmap.h>
+#include <asm/pgtable.h>
+
+/*
+ * Right now we initialize only a single pte table. It can be extended
+ * easily, subsequent pte tables have to be allocated in one physical
+ * chunk of RAM.
+ */
+/*
+ * Ordering is (from lower to higher memory addresses):
+ *
+ * high_memory
+ * Persistent kmap area
+ * PKMAP_BASE
+ * fixed_addresses
+ * FIXADDR_START
+ * FIXADDR_TOP
+ * Vmalloc area
+ * VMALLOC_START
+ * VMALLOC_END
+ */
+#define PKMAP_BASE ((FIXADDR_START - PGDIR_SIZE) & (PGDIR_MASK))
+#define LAST_PKMAP PTRS_PER_PTE
+#define LAST_PKMAP_MASK (LAST_PKMAP - 1)
+#define PKMAP_NR(virt) (((virt) - (PKMAP_BASE)) >> PAGE_SHIFT)
+#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
+#define kmap_prot PAGE_KERNEL
+
+static inline void flush_cache_kmaps(void)
+{
+ cpu_dcache_wbinval_all();
+}
+
+/* declarations for highmem.c */
+extern unsigned long highstart_pfn, highend_pfn;
+
+extern pte_t *pkmap_page_table;
+
+extern void *kmap_high(struct page *page);
+extern void kunmap_high(struct page *page);
+
+extern void kmap_init(void);
+
+/*
+ * The following functions are already defined by <linux/highmem.h>
+ * when CONFIG_HIGHMEM is not set.
+ */
+#ifdef CONFIG_HIGHMEM
+extern void *kmap(struct page *page);
+extern void kunmap(struct page *page);
+extern void *kmap_atomic(struct page *page);
+extern void __kunmap_atomic(void *kvaddr);
+extern void *kmap_atomic_pfn(unsigned long pfn);
+extern struct page *kmap_atomic_to_page(void *ptr);
+#endif
+
+#endif
diff --git a/arch/nds32/include/asm/memory.h b/arch/nds32/include/asm/memory.h
new file mode 100644
index 0000000..5043d59
--- /dev/null
+++ b/arch/nds32/include/asm/memory.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_NDS32_MEMORY_H
+#define __ASM_NDS32_MEMORY_H
+
+#include <linux/compiler.h>
+
+#ifndef __ASSEMBLY__
+#include <asm/page.h>
+#endif
+
+#ifndef PHYS_OFFSET
+#define PHYS_OFFSET (CONFIG_MEMORY_START)
+#endif
+
+#ifndef PAGE_OFFSET
+#define PAGE_OFFSET (0xC0000000)
+#endif
+
+#ifndef __virt_to_bus
+#define __virt_to_bus __virt_to_phys
+#endif
+
+#ifndef __bus_to_virt
+#define __bus_to_virt __phys_to_virt
+#endif
+
+#ifndef TASK_SIZE
+/*
+ * TASK_SIZE - the maximum size of a user space task.
+ * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
+ */
+#define TASK_SIZE (0xbf000000UL)
+#define TASK_UNMAPPED_BASE (0x40000000UL)
+#endif
+
+/*
+ * Page offset: 3GB
+ */
+#ifndef PAGE_OFFSET
+#define PAGE_OFFSET (0xc0000000)
+#endif
+
+/*
+ * Physical vs virtual RAM address space conversion. These are
+ * private definitions which should NOT be used outside memory.h
+ * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
+ */
+#ifndef __virt_to_phys
+#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
+#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
+#endif
+
+/*
+ * The module space lives between the addresses given by TASK_SIZE
+ * and PAGE_OFFSET - it must be within 32MB of the kernel text.
+ */
+#define MODULES_END (PAGE_OFFSET)
+#define MODULES_VADDR (MODULES_END - 16*1048576)
+
+#if TASK_SIZE > MODULES_VADDR
+#error Top of user space clashes with start of module space
+#endif
+
+#ifndef __ASSEMBLY__
+
+/*
+ * The DMA mask corresponding to the maximum bus address allocatable
+ * using GFP_DMA. The default here places no restriction on DMA
+ * allocations. This must be the smallest DMA mask in the system,
+ * so a successful GFP_DMA allocation will always satisfy this.
+ */
+#ifndef ISA_DMA_THRESHOLD
+#define ISA_DMA_THRESHOLD (0xffffffffULL)
+#endif
+
+/*
+ * PFNs are used to describe any physical page; this means
+ * PFN 0 == physical address 0.
+ *
+ * This is the PFN of the first RAM page in the kernel
+ * direct-mapped view. We assume this is the first page
+ * of RAM in the mem_map as well.
+ */
+#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT)
+
+/*
+ * Drivers should NOT use these either.
+ */
+#define __pa(x) __virt_to_phys((unsigned long)(x))
+#define __va(x) ((void *)__phys_to_virt((unsigned long)(x)))
+
+/*
+ * Conversion between a struct page and a physical address.
+ *
+ * Note: when converting an unknown physical address to a
+ * struct page, the resulting pointer must be validated
+ * using VALID_PAGE(). It must return an invalid struct page
+ * for any physical address not corresponding to a system
+ * RAM address.
+ *
+ * pfn_valid(pfn) indicates whether a PFN number is valid
+ *
+ * virt_to_page(k) convert a _valid_ virtual address to struct page *
+ * virt_addr_valid(k) indicates whether a virtual address is valid
+ */
+#ifndef CONFIG_DISCONTIGMEM
+
+#define ARCH_PFN_OFFSET PHYS_PFN_OFFSET
+#define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr))
+
+#define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT))
+#define virt_addr_valid(kaddr) ((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory)
+
+#else /* CONFIG_DISCONTIGMEM */
+#error CONFIG_DISCONTIGMEM is not supported yet.
+#endif /* !CONFIG_DISCONTIGMEM */
+
+#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
+
+/*
+ * Optional device DMA address remapping. Do _not_ use directly!
+ * We should really eliminate virt_to_bus() here - it's deprecated.
+ */
+#define page_to_dma(dev, page) ((dma_addr_t)__virt_to_phys((unsigned long)page_address(page)))
+#define dma_to_virt(dev, addr) ((void *)__phys_to_virt(addr))
+#define virt_to_dma(dev, addr) ((dma_addr_t)__virt_to_phys((unsigned long)(addr)))
+
+#endif
+
+#include <asm-generic/memory_model.h>
+
+#endif
diff --git a/arch/nds32/include/asm/mmu.h b/arch/nds32/include/asm/mmu.h
new file mode 100644
index 0000000..147fd06
--- /dev/null
+++ b/arch/nds32/include/asm/mmu.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 __NDS32_MMU_H
+#define __NDS32_MMU_H
+
+typedef struct {
+ unsigned int id;
+ void *vdso;
+} mm_context_t;
+
+#endif
diff --git a/arch/nds32/include/asm/page.h b/arch/nds32/include/asm/page.h
new file mode 100644
index 0000000..7e93d69
--- /dev/null
+++ b/arch/nds32/include/asm/page.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 _ASMNDS32_PAGE_H
+#define _ASMNDS32_PAGE_H
+
+#ifdef CONFIG_ANDES_PAGE_SIZE_4KB
+#define PAGE_SHIFT 12
+#endif
+#ifdef CONFIG_ANDES_PAGE_SIZE_8KB
+#define PAGE_SHIFT 13
+#endif
+#include <linux/const.h>
+#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+struct page;
+struct vm_area_struct;
+#ifndef CONFIG_CPU_CACHE_NONALIASING
+extern void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma);
+extern void clear_user_highpage(struct page *page, unsigned long vaddr);
+
+#define __HAVE_ARCH_COPY_USER_HIGHPAGE
+#define clear_user_highpage clear_user_highpage
+#else
+#define clear_user_page(page, vaddr, pg) clear_page(page)
+#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
+#endif
+
+void clear_page(void *page);
+void copy_page(void *to, void *from);
+
+typedef unsigned long pte_t;
+typedef unsigned long pmd_t;
+typedef unsigned long pgd_t;
+typedef unsigned long pgprot_t;
+
+#define pte_val(x) (x)
+#define pmd_val(x) (x)
+#define pgd_val(x) (x)
+#define pgprot_val(x) (x)
+
+#define __pte(x) (x)
+#define __pmd(x) (x)
+#define __pgd(x) (x)
+#define __pgprot(x) (x)
+
+typedef struct page *pgtable_t;
+
+#include <asm/memory.h>
+#include <asm-generic/getorder.h>
+
+#endif /* !__ASSEMBLY__ */
+
+#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/arch/nds32/include/asm/pgalloc.h b/arch/nds32/include/asm/pgalloc.h
new file mode 100644
index 0000000..0b7530b
--- /dev/null
+++ b/arch/nds32/include/asm/pgalloc.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 _ASMNDS32_PGALLOC_H
+#define _ASMNDS32_PGALLOC_H
+
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/proc-fns.h>
+
+/*
+ * Since we have only two-level page tables, these are trivial
+ */
+#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
+#define pmd_free(mm, pmd) do { } while (0)
+#define pgd_populate(mm, pmd, pte) BUG()
+#define pmd_pgtable(pmd) pmd_page(pmd)
+
+extern pgd_t *pgd_alloc(struct mm_struct *mm);
+extern void pgd_free(struct mm_struct *mm, pgd_t * pgd);
+
+#define check_pgt_cache() do { } while (0)
+
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+ unsigned long addr)
+{
+ pte_t *pte;
+
+ pte =
+ (pte_t *) __get_free_page(GFP_KERNEL | __GFP_RETRY_MAYFAIL |
+ __GFP_ZERO);
+
+ return pte;
+}
+
+static inline pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+ pgtable_t pte;
+
+ pte = alloc_pages(GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_ZERO, 0);
+ if (pte)
+ cpu_dcache_wb_page((unsigned long)page_address(pte));
+
+ return pte;
+}
+
+/*
+ * Free one PTE table.
+ */
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t * pte)
+{
+ if (pte) {
+ free_page((unsigned long)pte);
+ }
+}
+
+static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
+{
+ __free_page(pte);
+}
+
+/*
+ * Populate the pmdp entry with a pointer to the pte. This pmd is part
+ * of the mm address space.
+ *
+ * Ensure that we always set both PMD entries.
+ */
+static inline void
+pmd_populate_kernel(struct mm_struct *mm, pmd_t * pmdp, pte_t * ptep)
+{
+ unsigned long pte_ptr = (unsigned long)ptep;
+ unsigned long pmdval;
+
+ BUG_ON(mm != &init_mm);
+
+ /*
+ * The pmd must be loaded with the physical
+ * address of the PTE table
+ */
+ pmdval = __pa(pte_ptr) | _PAGE_KERNEL_TABLE;
+ set_pmd(pmdp, __pmd(pmdval));
+}
+
+static inline void
+pmd_populate(struct mm_struct *mm, pmd_t * pmdp, pgtable_t ptep)
+{
+ unsigned long pmdval;
+
+ BUG_ON(mm == &init_mm);
+
+ pmdval = page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE;
+ set_pmd(pmdp, __pmd(pmdval));
+}
+
+#endif
diff --git a/arch/nds32/include/asm/pgtable.h b/arch/nds32/include/asm/pgtable.h
new file mode 100644
index 0000000..a09f1f8
--- /dev/null
+++ b/arch/nds32/include/asm/pgtable.h
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 _ASMNDS32_PGTABLE_H
+#define _ASMNDS32_PGTABLE_H
+
+#define __PAGETABLE_PMD_FOLDED
+#include <asm-generic/4level-fixup.h>
+#include <asm-generic/sizes.h>
+
+#include <asm/memory.h>
+#include <asm/nds32.h>
+#ifndef __ASSEMBLY__
+#include <asm/fixmap.h>
+#include <asm-generic/io.h>
+#include <nds32_intrinsic.h>
+#endif
+
+#ifdef CONFIG_CACHE_L2
+#include <asm/l2_cache.h>
+#endif
+
+#ifdef CONFIG_ANDES_PAGE_SIZE_4KB
+#define PGDIR_SHIFT 22
+#define PTRS_PER_PGD 1024
+#define PMD_SHIFT 22
+#define PTRS_PER_PMD 1
+#define PTRS_PER_PTE 1024
+#endif
+
+#ifdef CONFIG_ANDES_PAGE_SIZE_8KB
+#define PGDIR_SHIFT 24
+#define PTRS_PER_PGD 256
+#define PMD_SHIFT 24
+#define PTRS_PER_PMD 1
+#define PTRS_PER_PTE 2048
+#endif
+
+#ifndef __ASSEMBLY__
+extern void __pte_error(const char *file, int line, unsigned long val);
+extern void __pmd_error(const char *file, int line, unsigned long val);
+extern void __pgd_error(const char *file, int line, unsigned long val);
+
+#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte))
+#define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd))
+#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
+#endif /* !__ASSEMBLY__ */
+
+#define PMD_SIZE (1UL << PMD_SHIFT)
+#define PMD_MASK (~(PMD_SIZE-1))
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+/*
+ * This is the lowest virtual address we can permit any user space
+ * mapping to be mapped at. This is particularly important for
+ * non-high vector CPUs.
+ */
+#define FIRST_USER_ADDRESS 0x8000
+
+#ifdef CONFIG_HIGHMEM
+#define CONSISTENT_BASE ((PKMAP_BASE) - (SZ_2M))
+#define CONSISTENT_END (PKMAP_BASE)
+#else
+#define CONSISTENT_BASE (FIXADDR_START - SZ_2M)
+#define CONSISTENT_END (FIXADDR_START)
+#endif
+#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
+
+#ifdef CONFIG_HIGHMEM
+#ifndef __ASSEMBLY__
+#include <asm/highmem.h>
+#endif
+#endif
+
+#define VMALLOC_RESERVE SZ_128M
+#define VMALLOC_END (CONSISTENT_BASE - PAGE_SIZE)
+#define VMALLOC_START ((VMALLOC_END) - VMALLOC_RESERVE)
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define MAXMEM __pa(VMALLOC_START)
+#define MAXMEM_PFN PFN_DOWN(MAXMEM)
+
+#define FIRST_USER_PGD_NR 0
+#define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) + FIRST_USER_PGD_NR)
+
+/* L2 PTE */
+#define _PAGE_V (1UL << 0)
+
+#define _PAGE_M_XKRW (0UL << 1)
+#define _PAGE_M_UR_KR (1UL << 1)
+#define _PAGE_M_UR_KRW (2UL << 1)
+#define _PAGE_M_URW_KRW (3UL << 1)
+#define _PAGE_M_KR (5UL << 1)
+#define _PAGE_M_KRW (7UL << 1)
+
+#define _PAGE_D (1UL << 4)
+#define _PAGE_E (1UL << 5)
+#define _PAGE_A (1UL << 6)
+#define _PAGE_G (1UL << 7)
+
+#define _PAGE_C_DEV (0UL << 8)
+#define _PAGE_C_DEV_WB (1UL << 8)
+#define _PAGE_C_MEM (2UL << 8)
+#define _PAGE_C_MEM_SHRD_WB (4UL << 8)
+#define _PAGE_C_MEM_SHRD_WT (5UL << 8)
+#define _PAGE_C_MEM_WB (6UL << 8)
+#define _PAGE_C_MEM_WT (7UL << 8)
+
+#define _PAGE_L (1UL << 11)
+
+#define _HAVE_PAGE_L (_PAGE_L)
+#define _PAGE_FILE (1UL << 1)
+#define _PAGE_YOUNG 0
+#define _PAGE_M_MASK _PAGE_M_KRW
+#define _PAGE_C_MASK _PAGE_C_MEM_WT
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+#define _PAGE_CACHE_SHRD _PAGE_C_MEM_SHRD_WT
+#else
+#define _PAGE_CACHE_SHRD _PAGE_C_MEM_SHRD_WB
+#endif
+#else
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+#define _PAGE_CACHE_SHRD _PAGE_C_MEM_WT
+#else
+#define _PAGE_CACHE_SHRD _PAGE_C_MEM_WB
+#endif
+#endif
+
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+#define _PAGE_CACHE _PAGE_C_MEM_WT
+#else
+#define _PAGE_CACHE _PAGE_C_MEM_WB
+#endif
+
+/*
+ * + Level 1 descriptor (PMD)
+ */
+#define PMD_TYPE_TABLE 0
+
+#ifndef __ASSEMBLY__
+
+#define _PAGE_USER_TABLE PMD_TYPE_TABLE
+#define _PAGE_KERNEL_TABLE PMD_TYPE_TABLE
+
+#define PAGE_EXEC __pgprot(_PAGE_V | _PAGE_M_XKRW | _PAGE_E)
+#define PAGE_NONE __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_A)
+#define PAGE_READ __pgprot(_PAGE_V | _PAGE_M_UR_KR)
+#define PAGE_RDWR __pgprot(_PAGE_V | _PAGE_M_URW_KRW | _PAGE_D)
+#define PAGE_COPY __pgprot(_PAGE_V | _PAGE_M_UR_KR)
+
+#define PAGE_UXKRWX_V1 __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD)
+#define PAGE_UXKRWX_V2 __pgprot(_PAGE_V | _PAGE_M_XKRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD)
+#define PAGE_URXKRWX_V2 __pgprot(_PAGE_V | _PAGE_M_UR_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD)
+#define PAGE_CACHE_L1 __pgprot(_HAVE_PAGE_L | _PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE)
+#define PAGE_MEMORY __pgprot(_HAVE_PAGE_L | _PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD)
+#define PAGE_KERNEL __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD)
+#define PAGE_DEVICE __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_G | _PAGE_C_DEV)
+#endif /* __ASSEMBLY__ */
+
+/* xwr */
+#define __P000 (PAGE_NONE | _PAGE_CACHE_SHRD)
+#define __P001 (PAGE_READ | _PAGE_CACHE_SHRD)
+#define __P010 (PAGE_COPY | _PAGE_CACHE_SHRD)
+#define __P011 (PAGE_COPY | _PAGE_CACHE_SHRD)
+#define __P100 (PAGE_EXEC | _PAGE_CACHE_SHRD)
+#define __P101 (PAGE_READ | _PAGE_E | _PAGE_CACHE_SHRD)
+#define __P110 (PAGE_COPY | _PAGE_E | _PAGE_CACHE_SHRD)
+#define __P111 (PAGE_COPY | _PAGE_E | _PAGE_CACHE_SHRD)
+
+#define __S000 (PAGE_NONE | _PAGE_CACHE_SHRD)
+#define __S001 (PAGE_READ | _PAGE_CACHE_SHRD)
+#define __S010 (PAGE_RDWR | _PAGE_CACHE_SHRD)
+#define __S011 (PAGE_RDWR | _PAGE_CACHE_SHRD)
+#define __S100 (PAGE_EXEC | _PAGE_CACHE_SHRD)
+#define __S101 (PAGE_READ | _PAGE_E | _PAGE_CACHE_SHRD)
+#define __S110 (PAGE_RDWR | _PAGE_E | _PAGE_CACHE_SHRD)
+#define __S111 (PAGE_RDWR | _PAGE_E | _PAGE_CACHE_SHRD)
+
+#ifndef __ASSEMBLY__
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern struct page *empty_zero_page;
+extern void paging_init(void);
+#define ZERO_PAGE(vaddr) (empty_zero_page)
+
+#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT)
+#define pfn_pte(pfn,prot) (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)))
+
+#define pte_none(pte) !(pte_val(pte))
+#define pte_clear(mm,addr,ptep) set_pte_at((mm),(addr),(ptep), __pte(0))
+#define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
+
+#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir, address) ((pte_t *)pmd_page_kernel(*(dir)) + pte_index(address))
+#define pte_offset_map(dir, address) ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
+#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
+#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+#define pte_unmap(pte) do { } while (0)
+#define pte_unmap_nested(pte) do { } while (0)
+
+#define pmd_off_k(address) pmd_offset(pgd_offset_k(address), address)
+
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+/*
+ * Set a level 1 translation table entry, and clean it out of
+ * any caches such that the MMUs can load it correctly.
+ */
+static inline void set_pmd(pmd_t * pmdp, pmd_t pmd)
+{
+
+ *pmdp = pmd;
+#if !defined(CONFIG_CPU_DCACHE_DISABLE) && !defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (pmdp):"memory");
+ __nds32__msync_all();
+ __nds32__dsb();
+#endif
+}
+
+/*
+ * Set a PTE and flush it out
+ */
+static inline void set_pte(pte_t * ptep, pte_t pte)
+{
+
+ *ptep = pte;
+#if !defined(CONFIG_CPU_DCACHE_DISABLE) && !defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (ptep):"memory");
+ __nds32__msync_all();
+ __nds32__dsb();
+#endif
+}
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+
+/*
+ * pte_write: this page is writeable for user mode
+ * pte_read: this page is readable for user mode
+ * pte_kernel_write: this page is writeable for kernel mode
+ *
+ * We don't have pte_kernel_read because kernel always can read.
+ *
+ * */
+
+#define pte_present(pte) (pte_val(pte) & _PAGE_V)
+#define pte_write(pte) ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_URW_KRW)
+#define pte_read(pte) (((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_UR_KR) || \
+ ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_UR_KRW) || \
+ ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_URW_KRW))
+#define pte_kernel_write(pte) (((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_URW_KRW) || \
+ ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_UR_KRW) || \
+ ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_KRW) || \
+ (((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_XKRW) && pte_exec(pte)))
+#define pte_exec(pte) (pte_val(pte) & _PAGE_E)
+#define pte_dirty(pte) (pte_val(pte) & _PAGE_D)
+#define pte_young(pte) (pte_val(pte) & _PAGE_YOUNG)
+
+/*
+ * The following only works if pte_present() is not true.
+ */
+#define pte_file(pte) (pte_val(pte) & _PAGE_FILE)
+#define pte_to_pgoff(x) (pte_val(x) >> 2)
+#define pgoff_to_pte(x) __pte(((x) << 2) | _PAGE_FILE)
+
+#define PTE_FILE_MAX_BITS 29
+
+#define PTE_BIT_FUNC(fn,op) \
+static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
+
+static inline pte_t pte_wrprotect(pte_t pte)
+{
+ pte_val(pte) = pte_val(pte) & ~_PAGE_M_MASK;
+ pte_val(pte) = pte_val(pte) | _PAGE_M_UR_KR;
+ return pte;
+}
+
+static inline pte_t pte_mkwrite(pte_t pte)
+{
+ pte_val(pte) = pte_val(pte) & ~_PAGE_M_MASK;
+ pte_val(pte) = pte_val(pte) | _PAGE_M_URW_KRW;
+ return pte;
+}
+
+PTE_BIT_FUNC(exprotect, &=~_PAGE_E);
+PTE_BIT_FUNC(mkexec, |=_PAGE_E);
+PTE_BIT_FUNC(mkclean, &=~_PAGE_D);
+PTE_BIT_FUNC(mkdirty, |=_PAGE_D);
+PTE_BIT_FUNC(mkold, &=~_PAGE_YOUNG);
+PTE_BIT_FUNC(mkyoung, |=_PAGE_YOUNG);
+static inline int pte_special(pte_t pte)
+{
+ return 0;
+}
+
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+ return pte;
+}
+
+/*
+ * Mark the prot value as uncacheable and unbufferable.
+ */
+#define pgprot_noncached(prot) __pgprot((pgprot_val(prot)&~_PAGE_C_MASK) | _PAGE_C_DEV)
+#define pgprot_writecombine(prot) __pgprot((pgprot_val(prot)&~_PAGE_C_MASK) | _PAGE_C_DEV_WB)
+
+#define pmd_none(pmd) (pmd_val(pmd)&0x1)
+#define pmd_present(pmd) (!pmd_none(pmd))
+#define pmd_bad(pmd) pmd_none(pmd)
+
+#define copy_pmd(pmdpd,pmdps) set_pmd((pmdpd), *(pmdps))
+#define pmd_clear(pmdp) set_pmd((pmdp), __pmd(1))
+
+static inline pmd_t __mk_pmd(pte_t * ptep, unsigned long prot)
+{
+ unsigned long ptr = (unsigned long)ptep;
+ pmd_t pmd;
+
+ /*
+ * The pmd must be loaded with the physical
+ * address of the PTE table
+ */
+
+ pmd_val(pmd) = __virt_to_phys(ptr) | prot;
+ return pmd;
+}
+
+#define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd)))
+
+/*
+ * Permanent address of a page. We never have highmem, so this is trivial.
+ */
+#define pages_to_mb(x) ((x) >> (20 - PAGE_SHIFT))
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+#define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot)
+
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+#define pgd_none(pgd) (0)
+#define pgd_bad(pgd) (0)
+#define pgd_present(pgd) (1)
+#define pgd_clear(pgdp) do { } while (0)
+
+#define page_pte_prot(page,prot) mk_pte(page, prot)
+#define page_pte(page) mk_pte(page, __pgprot(0))
+/*
+ * L1PTE = $mr1 + ((virt >> PMD_SHIFT) << 2);
+ * L2PTE = (((virt >> PAGE_SHIFT) & (PTRS_PER_PTE -1 )) << 2);
+ * PPN = (phys & 0xfffff000);
+ *
+*/
+
+/* to find an entry in a page-table-directory */
+#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
+
+/* Find an entry in the second-level page table.. */
+#define pmd_offset(dir, addr) ((pmd_t *)(dir))
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+ const unsigned long mask = 0xfff;
+ pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
+ return pte;
+}
+
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+/* Encode and decode a swap entry.
+ *
+ * We support up to 32GB of swap on 4k machines
+ */
+#define __swp_type(x) (((x).val >> 2) & 0x7f)
+#define __swp_offset(x) ((x).val >> 9)
+#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 2) | ((offset) << 9) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val })
+
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define kern_addr_valid(addr) (1)
+
+#include <asm-generic/pgtable.h>
+
+/*
+ * We provide our own arch_get_unmapped_area to cope with VIPT caches.
+ */
+#define HAVE_ARCH_UNMAPPED_AREA
+
+/*
+ * remap a physical address `phys' of size `size' with page protection `prot'
+ * into virtual address `from'
+ */
+
+#define pgtable_cache_init() do { } while (0)
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASMNDS32_PGTABLE_H */
diff --git a/arch/nds32/include/asm/shmparam.h b/arch/nds32/include/asm/shmparam.h
new file mode 100644
index 0000000..5679648
--- /dev/null
+++ b/arch/nds32/include/asm/shmparam.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 _ASMNDS32_SHMPARAM_H
+#define _ASMNDS32_SHMPARAM_H
+
+/*
+ * This should be the size of the virtually indexed cache/ways,
+ * whichever is greater since the cache aliases every size/ways
+ * bytes.
+ */
+#define SHMLBA (4 * PAGE_SIZE) /* attach addr a multiple of this */
+#define REALSHMLBA SHMLBA
+
+/*
+ * Enforce SHMLBA in shmat
+ */
+#define __ARCH_FORCE_SHMLBA
+
+#endif /* _ASMNDS32_SHMPARAM_H */
--
1.7.9.5
From 1584139544460160747@xxx Wed Nov 15 13:39:57 +0000 2017
X-GM-THRID: 1584139544460160747
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/mm/highmem.c | 92 +++++++++++++
arch/nds32/mm/init.c | 328 ++++++++++++++++++++++++++++++++++++++++++++++
arch/nds32/mm/mm-nds32.c | 103 +++++++++++++++
3 files changed, 523 insertions(+)
create mode 100644 arch/nds32/mm/highmem.c
create mode 100644 arch/nds32/mm/init.c
create mode 100644 arch/nds32/mm/mm-nds32.c
diff --git a/arch/nds32/mm/highmem.c b/arch/nds32/mm/highmem.c
new file mode 100644
index 0000000..d5101bd
--- /dev/null
+++ b/arch/nds32/mm/highmem.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/export.h>
+#include <linux/highmem.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/bootmem.h>
+#include <asm/fixmap.h>
+#include <asm/tlbflush.h>
+
+void *kmap(struct page *page)
+{
+ unsigned long vaddr;
+ might_sleep();
+ if (!PageHighMem(page))
+ return page_address(page);
+ vaddr = (unsigned long)kmap_high(page);
+ return (void *)vaddr;
+}
+
+EXPORT_SYMBOL(kmap);
+
+void kunmap(struct page *page)
+{
+ BUG_ON(in_interrupt());
+ if (!PageHighMem(page))
+ return;
+ kunmap_high(page);
+}
+
+EXPORT_SYMBOL(kunmap);
+
+void *kmap_atomic(struct page *page)
+{
+ unsigned int idx;
+ unsigned long vaddr, pte;
+ int type;
+ pte_t *ptep;
+
+ preempt_disable();
+ pagefault_disable();
+ if (!PageHighMem(page))
+ return page_address(page);
+
+ type = kmap_atomic_idx_push();
+
+ idx = type + KM_TYPE_NR * smp_processor_id();
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+ pte = (page_to_pfn(page) << PAGE_SHIFT) | (PAGE_KERNEL);
+ ptep = pte_offset_kernel(pmd_off_k(vaddr), vaddr);
+ set_pte(ptep, pte);
+
+ __nds32__tlbop_inv(vaddr);
+ __nds32__mtsr_dsb(vaddr, NDS32_SR_TLB_VPN);
+ __nds32__tlbop_rwr(pte);
+ __nds32__isb();
+ return (void *)vaddr;
+}
+
+EXPORT_SYMBOL(kmap_atomic);
+
+void __kunmap_atomic(void *kvaddr)
+{
+ if (kvaddr >= (void *)FIXADDR_START) {
+ unsigned long vaddr = (unsigned long)kvaddr;
+ pte_t *ptep;
+ kmap_atomic_idx_pop();
+ __nds32__tlbop_inv(vaddr);
+ __nds32__isb();
+ ptep = pte_offset_kernel(pmd_off_k(vaddr), vaddr);
+ set_pte(ptep, 0);
+ }
+ pagefault_enable();
+ preempt_enable();
+}
+
+EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/arch/nds32/mm/init.c b/arch/nds32/mm/init.c
new file mode 100644
index 0000000..9dee3ee
--- /dev/null
+++ b/arch/nds32/mm/init.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/swap.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mman.h>
+#include <linux/nodemask.h>
+#include <linux/initrd.h>
+#include <linux/highmem.h>
+#include <linux/memblock.h>
+
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/tlb.h>
+#include <asm/page.h>
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+DEFINE_SPINLOCK(anon_alias_lock);
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+extern unsigned long phys_initrd_start;
+extern unsigned long phys_initrd_size;
+
+/*
+ * empty_zero_page is a special page that is used for
+ * zero-initialized data and COW.
+ */
+struct page *empty_zero_page;
+#ifdef CONFIG_EARLY_PRINTK
+#include <asm/fixmap.h>
+
+/*
+ * Using tlbop to create an early I/O mapping
+ */
+void __iomem *__init early_io_map(phys_addr_t pa)
+{
+ unsigned long va;
+ pa &= PAGE_MASK;
+ pa += pgprot_val(PAGE_DEVICE);
+ va = __fix_to_virt(FIX_EARLY_DEBUG);
+ /* insert and lock this page to tlb entry directly */
+
+ __nds32__mtsr_dsb(va, NDS32_SR_TLB_VPN);
+ __nds32__tlbop_rwlk(pa);
+ __nds32__isb();
+ return (void __iomem *)va;
+}
+
+int __init early_io_unmap(void)
+{
+ unsigned long va;
+ va = __fix_to_virt(FIX_EARLY_DEBUG);
+ __nds32__tlbop_unlk(va);
+ __nds32__tlbop_inv(va);
+ __nds32__isb();
+ return 0;
+}
+
+late_initcall(early_io_unmap);
+#endif
+
+static void __init zone_sizes_init(void)
+{
+ unsigned long zones_size[MAX_NR_ZONES];
+
+ /* Clear the zone sizes */
+ memset(zones_size, 0, sizeof(zones_size));
+
+ zones_size[ZONE_NORMAL] = max_low_pfn;
+#ifdef CONFIG_HIGHMEM
+ zones_size[ZONE_HIGHMEM] = max_pfn;
+#endif
+ free_area_init_nodes(zones_size);
+
+}
+
+/*
+ * Map all physical memory under high_memory into kernel's address space.
+ *
+ * This is explicitly coded for two-level page tables, so if you need
+ * something else then this needs to change.
+ */
+static void __init map_ram(void)
+{
+ unsigned long v, p, e;
+ pgd_t *pge;
+ pud_t *pue;
+ pmd_t *pme;
+ pte_t *pte;
+ /* These mark extents of read-only kernel pages...
+ * ...from vmlinux.lds.S
+ */
+
+ p = (u32) memblock_start_of_DRAM() & PAGE_MASK;
+ e = min((u32) memblock_end_of_DRAM(), (u32) __pa(high_memory));
+
+ v = (u32) __va(p);
+ pge = pgd_offset_k(v);
+
+ while (p < e) {
+ int j;
+ pue = pud_offset(pge, v);
+ pme = pmd_offset(pue, v);
+
+ if ((u32) pue != (u32) pge || (u32) pme != (u32) pge) {
+ panic("%s: Kernel hardcoded for "
+ "two-level page tables", __func__);
+ }
+
+ /* Alloc one page for holding PTE's... */
+ pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+ set_pmd(pme, __pmd(__pa(pte) + _PAGE_KERNEL_TABLE));
+
+ /* Fill the newly allocated page with PTE'S */
+ for (j = 0; p < e && j < PTRS_PER_PTE;
+ v += PAGE_SIZE, p += PAGE_SIZE, j++, pte++) {
+ /* Create mapping between p and v. */
+ /* TODO: more fine grant for page access permission */
+ set_pte(pte, __pte(p + pgprot_val(PAGE_KERNEL)));
+ }
+
+ pge++;
+ }
+}
+
+static void __init fixedrange_init(void)
+{
+ unsigned long vaddr;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ /*
+ * Fixed mappings:
+ */
+ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1);
+ pgd = swapper_pg_dir + pgd_index(vaddr);
+ pud = pud_offset(pgd, vaddr);
+ pmd = pmd_offset(pud, vaddr);
+ pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+ set_pmd(pmd, __pmd(__pa(pte) + _PAGE_KERNEL_TABLE));
+
+#ifdef CONFIG_HIGHMEM
+ /*
+ * Permanent kmaps:
+ */
+ vaddr = PKMAP_BASE;
+
+ pgd = swapper_pg_dir + pgd_index(vaddr);
+ pud = pud_offset(pgd, vaddr);
+ pmd = pmd_offset(pud, vaddr);
+ pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+ set_pmd(pmd, __pmd(__pa(pte) + _PAGE_KERNEL_TABLE));
+ pkmap_page_table = pte;
+#endif /* CONFIG_HIGHMEM */
+}
+
+/*
+ * paging_init() sets up the page tables, initialises the zone memory
+ * maps, and sets up the zero page, bad page and bad page tables.
+ */
+void __init paging_init(void)
+{
+ void *zero_page;
+ int i;
+
+ pr_info("Setting up paging and PTEs.\n");
+ /* clear out the init_mm.pgd that will contain the kernel's mappings */
+ for (i = 0; i < PTRS_PER_PGD; i++)
+ swapper_pg_dir[i] = __pgd(1);
+
+ map_ram();
+
+ fixedrange_init();
+
+ /* allocate space for empty_zero_page */
+ zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
+ memset(zero_page, 0, PAGE_SIZE);
+
+ zone_sizes_init();
+
+ empty_zero_page = virt_to_page(zero_page);
+ flush_dcache_page(empty_zero_page);
+}
+
+static inline int free_area(unsigned long addr, unsigned long end, char *s)
+{
+ unsigned int size = (end - addr) >> 10;
+ int pages = 0;
+
+ for (; addr < end; addr += PAGE_SIZE) {
+ struct page *page = virt_to_page(addr);
+ ClearPageReserved(page);
+ init_page_count(page);
+ free_page(addr);
+ totalram_pages++;
+ pages++;
+ }
+
+ if (size && s)
+ pr_info("free_area: Freeing %s memory: %dK\n", s, size);
+
+ return pages;
+}
+
+static inline void __init free_highmem(void)
+{
+#ifdef CONFIG_HIGHMEM
+ unsigned long pfn;
+ for (pfn = PFN_UP(__pa(high_memory)); pfn < max_pfn; pfn++) {
+ phys_addr_t paddr = (phys_addr_t) pfn << PAGE_SHIFT;
+ if (!memblock_is_reserved(paddr))
+ free_highmem_page(pfn_to_page(pfn));
+ }
+#endif
+}
+
+static void __init set_max_mapnr_init(void)
+{
+ max_mapnr = max_pfn;
+}
+
+/*
+ * mem_init() marks the free areas in the mem_map and tells us how much
+ * memory is free. This is done after various parts of the system have
+ * claimed their memory after the kernel image.
+ */
+void __init mem_init(void)
+{
+ phys_addr_t memory_start = memblock_start_of_DRAM();
+ BUG_ON(!mem_map);
+ set_max_mapnr_init();
+
+ free_highmem();
+
+ /* this will put all low memory onto the freelists */
+ free_all_bootmem();
+
+ pr_info("virtual kernel memory layout:\n"
+ " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
+#ifdef CONFIG_HIGHMEM
+ " pkmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
+#endif
+ " consist : 0x%08lx - 0x%08lx (%4ld MB)\n"
+ " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
+ " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n"
+ " .init : 0x%08lx - 0x%08lx (%4ld kB)\n"
+ " .data : 0x%08lx - 0x%08lx (%4ld kB)\n"
+ " .text : 0x%08lx - 0x%08lx (%4ld kB)\n",
+ FIXADDR_START, FIXADDR_TOP, (FIXADDR_TOP - FIXADDR_START) >> 10,
+#ifdef CONFIG_HIGHMEM
+ PKMAP_BASE, PKMAP_BASE + LAST_PKMAP * PAGE_SIZE,
+ (LAST_PKMAP * PAGE_SIZE) >> 10,
+#endif
+ CONSISTENT_BASE, CONSISTENT_END,
+ ((CONSISTENT_END) - (CONSISTENT_BASE)) >> 20, VMALLOC_START,
+ (unsigned long)VMALLOC_END, (VMALLOC_END - VMALLOC_START) >> 20,
+ (unsigned long)__va(memory_start), (unsigned long)high_memory,
+ ((unsigned long)high_memory -
+ (unsigned long)__va(memory_start)) >> 20,
+ (unsigned long)&__init_begin, (unsigned long)&__init_end,
+ ((unsigned long)&__init_end -
+ (unsigned long)&__init_begin) >> 10, (unsigned long)&_etext,
+ (unsigned long)&_edata,
+ ((unsigned long)&_edata - (unsigned long)&_etext) >> 10,
+ (unsigned long)&_text, (unsigned long)&_etext,
+ ((unsigned long)&_etext - (unsigned long)&_text) >> 10);
+
+ /*
+ * Check boundaries twice: Some fundamental inconsistencies can
+ * be detected at build time already.
+ */
+#ifdef CONFIG_HIGHMEM
+ BUILD_BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > FIXADDR_START);
+ BUILD_BUG_ON((CONSISTENT_END) > PKMAP_BASE);
+#endif
+ BUILD_BUG_ON(VMALLOC_END > CONSISTENT_BASE);
+ BUILD_BUG_ON(VMALLOC_START >= VMALLOC_END);
+
+#ifdef CONFIG_HIGHMEM
+ BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > FIXADDR_START);
+ BUG_ON(CONSISTENT_END > PKMAP_BASE);
+#endif
+ BUG_ON(VMALLOC_END > CONSISTENT_BASE);
+ BUG_ON(VMALLOC_START >= VMALLOC_END);
+ BUG_ON((unsigned long)high_memory > VMALLOC_START);
+
+ return;
+}
+
+void free_initmem(void)
+{
+ free_initmem_default(-1);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+static int keep_initrd;
+
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+ if (!keep_initrd)
+ free_area(start, end, "initrd");
+}
+
+static int __init keepinitrd_setup(char *__unused)
+{
+ keep_initrd = 1;
+ return 1;
+}
+
+__setup("keepinitrd", keepinitrd_setup);
+#endif
diff --git a/arch/nds32/mm/mm-nds32.c b/arch/nds32/mm/mm-nds32.c
new file mode 100644
index 0000000..2801496
--- /dev/null
+++ b/arch/nds32/mm/mm-nds32.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/init_task.h>
+#include <asm/pgalloc.h>
+
+#define FIRST_KERNEL_PGD_NR (USER_PTRS_PER_PGD)
+
+/*
+ * need to get a page for level 1
+ */
+
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+ pgd_t *new_pgd, *init_pgd;
+ int i;
+
+ new_pgd = (pgd_t *) __get_free_pages(GFP_KERNEL, 0);
+ if (!new_pgd)
+ return NULL;
+ for (i = 0; i < PTRS_PER_PGD; i++) {
+ (*new_pgd) = 1;
+ new_pgd++;
+ }
+ new_pgd -= PTRS_PER_PGD;
+
+ init_pgd = pgd_offset_k(0);
+
+ memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
+ (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
+
+ cpu_dcache_wb_range((unsigned long)new_pgd,
+ (unsigned long)new_pgd +
+ PTRS_PER_PGD * sizeof(pgd_t));
+ inc_zone_page_state(virt_to_page((unsigned long *)new_pgd),
+ NR_PAGETABLE);
+
+ return new_pgd;
+}
+
+void pgd_free(struct mm_struct *mm, pgd_t * pgd)
+{
+ pmd_t *pmd;
+ struct page *pte;
+
+ if (!pgd)
+ return;
+
+ pmd = (pmd_t *) pgd;
+ if (pmd_none(*pmd))
+ goto free;
+ if (pmd_bad(*pmd)) {
+ pmd_ERROR(*pmd);
+ pmd_clear(pmd);
+ goto free;
+ }
+
+ pte = pmd_page(*pmd);
+ pmd_clear(pmd);
+ dec_zone_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE);
+ pte_free(mm, pte);
+ atomic_long_dec(&mm->nr_ptes);
+ pmd_free(mm, pmd);
+free:
+ free_pages((unsigned long)pgd, 0);
+}
+
+/*
+ * In order to soft-boot, we need to insert a 1:1 mapping in place of
+ * the user-mode pages. This will then ensure that we have predictable
+ * results when turning the mmu off
+ */
+void setup_mm_for_reboot(char mode)
+{
+ unsigned long pmdval;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ int i;
+
+ if (current->mm && current->mm->pgd)
+ pgd = current->mm->pgd;
+ else
+ pgd = init_mm.pgd;
+
+ for (i = 0; i < USER_PTRS_PER_PGD; i++) {
+ pmdval = (i << PGDIR_SHIFT);
+ pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT);
+ set_pmd(pmd, __pmd(pmdval));
+ }
+}
--
1.7.9.5
From 1583462591639466228@xxx Wed Nov 08 02:20:04 +0000 2017
X-GM-THRID: 1583462591639466228
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/asm/dma-mapping.h | 27 ++
arch/nds32/kernel/dma.c | 478 ++++++++++++++++++++++++++++++++++
2 files changed, 505 insertions(+)
create mode 100644 arch/nds32/include/asm/dma-mapping.h
create mode 100644 arch/nds32/kernel/dma.c
diff --git a/arch/nds32/include/asm/dma-mapping.h b/arch/nds32/include/asm/dma-mapping.h
new file mode 100644
index 0000000..63dbeb7
--- /dev/null
+++ b/arch/nds32/include/asm/dma-mapping.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 ASMNDS32_DMA_MAPPING_H
+#define ASMNDS32_DMA_MAPPING_H
+
+extern struct dma_map_ops nds32_dma_ops;
+
+static inline struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus)
+{
+ return &nds32_dma_ops;
+}
+
+#endif
diff --git a/arch/nds32/kernel/dma.c b/arch/nds32/kernel/dma.c
new file mode 100644
index 0000000..939702e
--- /dev/null
+++ b/arch/nds32/kernel/dma.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/export.h>
+#include <linux/string.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/cache.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/dma-mapping.h>
+#include <asm/proc-fns.h>
+
+/*
+ * This is the page table (2MB) covering uncached, DMA consistent allocations
+ */
+static pte_t *consistent_pte;
+static DEFINE_RAW_SPINLOCK(consistent_lock);
+
+/*
+ * VM region handling support.
+ *
+ * This should become something generic, handling VM region allocations for
+ * vmalloc and similar (ioremap, module space, etc).
+ *
+ * I envisage vmalloc()'s supporting vm_struct becoming:
+ *
+ * struct vm_struct {
+ * struct vm_region region;
+ * unsigned long flags;
+ * struct page **pages;
+ * unsigned int nr_pages;
+ * unsigned long phys_addr;
+ * };
+ *
+ * get_vm_area() would then call vm_region_alloc with an appropriate
+ * struct vm_region head (eg):
+ *
+ * struct vm_region vmalloc_head = {
+ * .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list),
+ * .vm_start = VMALLOC_START,
+ * .vm_end = VMALLOC_END,
+ * };
+ *
+ * However, vmalloc_head.vm_start is variable (typically, it is dependent on
+ * the amount of RAM found at boot time.) I would imagine that get_vm_area()
+ * would have to initialise this each time prior to calling vm_region_alloc().
+ */
+struct arch_vm_region {
+ struct list_head vm_list;
+ unsigned long vm_start;
+ unsigned long vm_end;
+ struct page *vm_pages;
+};
+
+static struct arch_vm_region consistent_head = {
+ .vm_list = LIST_HEAD_INIT(consistent_head.vm_list),
+ .vm_start = CONSISTENT_BASE,
+ .vm_end = CONSISTENT_END,
+};
+
+static struct arch_vm_region *vm_region_alloc(struct arch_vm_region *head,
+ size_t size, int gfp)
+{
+ unsigned long addr = head->vm_start, end = head->vm_end - size;
+ unsigned long flags;
+ struct arch_vm_region *c, *new;
+
+ new = kmalloc(sizeof(struct arch_vm_region), gfp);
+ if (!new)
+ goto out;
+
+ raw_spin_lock_irqsave(&consistent_lock, flags);
+
+ list_for_each_entry(c, &head->vm_list, vm_list) {
+ if ((addr + size) < addr)
+ goto nospc;
+ if ((addr + size) <= c->vm_start)
+ goto found;
+ addr = c->vm_end;
+ if (addr > end)
+ goto nospc;
+ }
+
+found:
+ /*
+ * Insert this entry _before_ the one we found.
+ */
+ list_add_tail(&new->vm_list, &c->vm_list);
+ new->vm_start = addr;
+ new->vm_end = addr + size;
+
+ raw_spin_unlock_irqrestore(&consistent_lock, flags);
+ return new;
+
+nospc:
+ raw_spin_unlock_irqrestore(&consistent_lock, flags);
+ kfree(new);
+out:
+ return NULL;
+}
+
+static struct arch_vm_region *vm_region_find(struct arch_vm_region *head,
+ unsigned long addr)
+{
+ struct arch_vm_region *c;
+
+ list_for_each_entry(c, &head->vm_list, vm_list) {
+ if (c->vm_start == addr)
+ goto out;
+ }
+ c = NULL;
+out:
+ return c;
+}
+
+/* FIXME: attrs is not used. */
+static void *nds32_dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t * handle, gfp_t gfp,
+ unsigned long attrs)
+{
+ struct page *page;
+ struct arch_vm_region *c;
+ unsigned long order;
+ u64 mask = ISA_DMA_THRESHOLD, limit;
+ pgprot_t prot = pgprot_noncached(PAGE_KERNEL);
+
+ if (!consistent_pte) {
+ pr_err("%s: not initialized\n", __func__);
+ dump_stack();
+ return NULL;
+ }
+
+ if (dev) {
+ mask = dev->coherent_dma_mask;
+
+ /*
+ * Sanity check the DMA mask - it must be non-zero, and
+ * must be able to be satisfied by a DMA allocation.
+ */
+ if (mask == 0) {
+ dev_warn(dev, "coherent DMA mask is unset\n");
+ goto no_page;
+ }
+
+ if ((~mask) & ISA_DMA_THRESHOLD) {
+ dev_warn(dev, "coherent DMA mask %#llx is smaller "
+ "than system GFP_DMA mask %#llx\n",
+ mask, (unsigned long long)ISA_DMA_THRESHOLD);
+ goto no_page;
+ }
+ }
+
+ /*
+ * Sanity check the allocation size.
+ */
+ size = PAGE_ALIGN(size);
+ limit = (mask + 1) & ~mask;
+ if ((limit && size >= limit) ||
+ size >= (CONSISTENT_END - CONSISTENT_BASE)) {
+ pr_warn("coherent allocation too big "
+ "(requested %#x mask %#llx)\n", size, mask);
+ goto no_page;
+ }
+
+ order = get_order(size);
+
+ if (mask != 0xffffffff)
+ gfp |= GFP_DMA;
+
+ page = alloc_pages(gfp, order);
+ if (!page)
+ goto no_page;
+
+ /*
+ * Invalidate any data that might be lurking in the
+ * kernel direct-mapped region for device DMA.
+ */
+ {
+ unsigned long kaddr = (unsigned long)page_address(page);
+ memset(page_address(page), 0, size);
+ cpu_dma_wbinval_range(kaddr, kaddr + size);
+ }
+
+ /*
+ * Allocate a virtual address in the consistent mapping region.
+ */
+ c = vm_region_alloc(&consistent_head, size,
+ gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
+ if (c) {
+ pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
+ struct page *end = page + (1 << order);
+
+ c->vm_pages = page;
+
+ /*
+ * Set the "dma handle"
+ */
+ *handle = page_to_dma(dev, page);
+
+ do {
+ BUG_ON(!pte_none(*pte));
+
+ /*
+ * x86 does not mark the pages reserved...
+ */
+ SetPageReserved(page);
+ set_pte(pte, mk_pte(page, prot));
+ page++;
+ pte++;
+ } while (size -= PAGE_SIZE);
+
+ /*
+ * Free the otherwise unused pages.
+ */
+ while (page < end) {
+ __free_page(page);
+ page++;
+ }
+
+ return (void *)c->vm_start;
+ }
+
+ if (page)
+ __free_pages(page, order);
+no_page:
+ *handle = ~0;
+ return NULL;
+}
+
+static void nds32_dma_free(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, unsigned long attrs)
+{
+ struct arch_vm_region *c;
+ unsigned long flags, addr;
+ pte_t *ptep;
+
+ size = PAGE_ALIGN(size);
+
+ raw_spin_lock_irqsave(&consistent_lock, flags);
+
+ c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
+ if (!c)
+ goto no_area;
+
+ if ((c->vm_end - c->vm_start) != size) {
+ pr_err("%s: freeing wrong coherent size (%ld != %d)\n",
+ __func__, c->vm_end - c->vm_start, size);
+ dump_stack();
+ size = c->vm_end - c->vm_start;
+ }
+
+ ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
+ addr = c->vm_start;
+ do {
+ pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
+ unsigned long pfn;
+
+ ptep++;
+ addr += PAGE_SIZE;
+
+ if (!pte_none(pte) && pte_present(pte)) {
+ pfn = pte_pfn(pte);
+
+ if (pfn_valid(pfn)) {
+ struct page *page = pfn_to_page(pfn);
+
+ /*
+ * x86 does not mark the pages reserved...
+ */
+ ClearPageReserved(page);
+
+ __free_page(page);
+ continue;
+ }
+ }
+
+ pr_crit("%s: bad page in kernel page table\n", __func__);
+ } while (size -= PAGE_SIZE);
+
+ flush_tlb_kernel_range(c->vm_start, c->vm_end);
+
+ list_del(&c->vm_list);
+
+ raw_spin_unlock_irqrestore(&consistent_lock, flags);
+
+ kfree(c);
+ return;
+
+no_area:
+ raw_spin_unlock_irqrestore(&consistent_lock, flags);
+ pr_err("%s: trying to free invalid coherent area: %p\n",
+ __func__, cpu_addr);
+ dump_stack();
+}
+
+/*
+ * Initialise the consistent memory allocation.
+ */
+static int __init consistent_init(void)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ int ret = 0;
+
+ do {
+ pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
+ pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE);
+ if (!pmd) {
+ pr_err("%s: no pmd tables\n", __func__);
+ ret = -ENOMEM;
+ break;
+ }
+ /* The first level mapping may be created in somewhere.
+ * It's not necessary to warn here. */
+ /* WARN_ON(!pmd_none(*pmd)); */
+
+ pte = pte_alloc_kernel(pmd, CONSISTENT_BASE);
+ if (!pte) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ consistent_pte = pte;
+ } while (0);
+
+ return ret;
+}
+
+core_initcall(consistent_init);
+static void consistent_sync(void *vaddr, size_t size, int direction);
+static dma_addr_t nds32_dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ consistent_sync((void *)(page_address(page) + offset), size, dir);
+ return page_to_phys(page) + offset;
+}
+
+static void nds32_dma_unmap_page(struct device *dev, dma_addr_t handle,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ consistent_sync(phys_to_virt(handle), size, dir);
+}
+
+/*
+ * Make an area consistent for devices.
+ */
+static void consistent_sync(void *vaddr, size_t size, int direction)
+{
+ unsigned long start = (unsigned long)vaddr;
+ unsigned long end = start + size;
+
+ switch (direction) {
+ case DMA_FROM_DEVICE: /* invalidate only */
+ cpu_dma_inval_range(start, end);
+ break;
+ case DMA_TO_DEVICE: /* writeback only */
+ cpu_dma_wb_range(start, end);
+ break;
+ case DMA_BIDIRECTIONAL: /* writeback and invalidate */
+ cpu_dma_wbinval_range(start, end);
+ break;
+ default:
+ BUG();
+ }
+}
+
+static int nds32_dma_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ int i;
+
+ for (i = 0; i < nents; i++, sg++) {
+ void *virt;
+ unsigned long pfn;
+ struct page *page = sg_page(sg);
+
+ sg->dma_address = page_to_dma(dev, page) + sg->offset;
+ pfn = page_to_pfn(page) + sg->offset / PAGE_SIZE;
+ page = pfn_to_page(pfn);
+ if (PageHighMem(page)) {
+ virt = kmap_atomic(page);
+ consistent_sync(virt, sg->length, dir);
+ kunmap_atomic(virt);
+ } else {
+ if (sg->offset > PAGE_SIZE)
+ panic("sg->offset:%08x > PAGE_SIZE\n",
+ sg->offset);
+ virt = page_address(page) + sg->offset;
+ consistent_sync(virt, sg->length, dir);
+ }
+ }
+ return nents;
+}
+
+static void nds32_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nhwentries, enum dma_data_direction dir,
+ unsigned long attrs)
+{
+}
+
+static void
+nds32_dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
+ size_t size, enum dma_data_direction dir)
+{
+ consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
+}
+
+static void
+nds32_dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
+ size_t size, enum dma_data_direction dir)
+{
+ consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
+}
+
+static void
+nds32_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir)
+{
+ int i;
+
+ for (i = 0; i < nents; i++, sg++) {
+ char *virt =
+ page_address((struct page *)sg->page_link) + sg->offset;
+ consistent_sync(virt, sg->length, dir);
+ }
+}
+
+static void
+nds32_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ int i;
+
+ for (i = 0; i < nents; i++, sg++) {
+ char *virt =
+ page_address((struct page *)sg->page_link) + sg->offset;
+ consistent_sync(virt, sg->length, dir);
+ }
+}
+
+struct dma_map_ops nds32_dma_ops = {
+ .alloc = nds32_dma_alloc_coherent,
+ .free = nds32_dma_free,
+ .map_page = nds32_dma_map_page,
+ .unmap_page = nds32_dma_unmap_page,
+ .map_sg = nds32_dma_map_sg,
+ .unmap_sg = nds32_dma_unmap_sg,
+ .sync_single_for_device = nds32_dma_sync_single_for_device,
+ .sync_single_for_cpu = nds32_dma_sync_single_for_cpu,
+ .sync_sg_for_cpu = nds32_dma_sync_sg_for_cpu,
+ .sync_sg_for_device = nds32_dma_sync_sg_for_device,
+};
+
+EXPORT_SYMBOL(nds32_dma_ops);
--
1.7.9.5
From 1586949712194803073@xxx Sat Dec 16 14:06:21 +0000 2017
X-GM-THRID: 1586049229904585981
X-Gmail-Labels: Inbox,Category Forums
From: Greentime Hu <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
drivers/net/ethernet/faraday/Kconfig | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig
index 040c7f1..0ae6e9a 100644
--- a/drivers/net/ethernet/faraday/Kconfig
+++ b/drivers/net/ethernet/faraday/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_FARADAY
bool "Faraday devices"
default y
- depends on ARM
+ depends on ARM || NDS32
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
@@ -18,7 +18,7 @@ if NET_VENDOR_FARADAY
config FTMAC100
tristate "Faraday FTMAC100 10/100 Ethernet support"
- depends on ARM
+ depends on ARM || NDS32
select MII
---help---
This driver supports the FTMAC100 10/100 Ethernet controller
@@ -27,7 +27,7 @@ config FTMAC100
config FTGMAC100
tristate "Faraday FTGMAC100 Gigabit Ethernet support"
- depends on ARM
+ depends on ARM || NDS32
select PHYLIB
---help---
This driver supports the FTGMAC100 Gigabit Ethernet controller
--
1.7.9.5
From 1583470973079733213@xxx Wed Nov 08 04:33:17 +0000 2017
X-GM-THRID: 1582661337274595113
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/asm/irqflags.h | 49 +++++++++++++++++++++++++++++++++++++
arch/nds32/kernel/irq.c | 34 +++++++++++++++++++++++++
2 files changed, 83 insertions(+)
create mode 100644 arch/nds32/include/asm/irqflags.h
create mode 100644 arch/nds32/kernel/irq.c
diff --git a/arch/nds32/include/asm/irqflags.h b/arch/nds32/include/asm/irqflags.h
new file mode 100644
index 0000000..7c1940f
--- /dev/null
+++ b/arch/nds32/include/asm/irqflags.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <asm/nds32.h>
+#include <nds32_intrinsic.h>
+
+#define arch_local_irq_disable() \
+ GIE_DISABLE();
+
+#define arch_local_irq_enable() \
+ GIE_ENABLE();
+static inline unsigned long arch_local_irq_save(void)
+{
+ unsigned long flags;
+ flags = __nds32__mfsr(NDS32_SR_PSW) & PSW_mskGIE;
+ GIE_DISABLE();
+ return flags;
+}
+
+static inline unsigned long arch_local_save_flags(void)
+{
+ unsigned long flags;
+ flags = __nds32__mfsr(NDS32_SR_PSW) & PSW_mskGIE;
+ return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+ if(flags)
+ GIE_ENABLE();
+}
+
+static inline int arch_irqs_disabled_flags(unsigned long flags)
+{
+ return !flags;
+}
diff --git a/arch/nds32/kernel/irq.c b/arch/nds32/kernel/irq.c
new file mode 100644
index 0000000..1b935f7
--- /dev/null
+++ b/arch/nds32/kernel/irq.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/irqchip.h>
+
+void __init init_IRQ(void)
+{
+ irqchip_init();
+}
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+void notrace arch_trace_hardirqs_on(void)
+{
+ trace_hardirqs_on();
+}
+
+void notrace arch_trace_hardirqs_off(void)
+{
+ trace_hardirqs_off();
+}
+#endif
--
1.7.9.5
From 1583457009109928232@xxx Wed Nov 08 00:51:20 +0000 2017
X-GM-THRID: 1583447452219913014
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/asm/vdso.h | 35 ++++
arch/nds32/include/asm/vdso_datapage.h | 51 ++++++
arch/nds32/kernel/vdso.c | 243 ++++++++++++++++++++++++++
arch/nds32/kernel/vdso/Makefile | 82 +++++++++
arch/nds32/kernel/vdso/datapage.S | 34 ++++
arch/nds32/kernel/vdso/gen_vdso_offsets.sh | 15 ++
arch/nds32/kernel/vdso/gettimeofday.c | 260 ++++++++++++++++++++++++++++
arch/nds32/kernel/vdso/note.S | 29 ++++
arch/nds32/kernel/vdso/sigreturn.S | 32 ++++
arch/nds32/kernel/vdso/vdso.S | 33 ++++
arch/nds32/kernel/vdso/vdso.lds.S | 87 ++++++++++
11 files changed, 901 insertions(+)
create mode 100644 arch/nds32/include/asm/vdso.h
create mode 100644 arch/nds32/include/asm/vdso_datapage.h
create mode 100644 arch/nds32/kernel/vdso.c
create mode 100644 arch/nds32/kernel/vdso/Makefile
create mode 100644 arch/nds32/kernel/vdso/datapage.S
create mode 100755 arch/nds32/kernel/vdso/gen_vdso_offsets.sh
create mode 100644 arch/nds32/kernel/vdso/gettimeofday.c
create mode 100644 arch/nds32/kernel/vdso/note.S
create mode 100644 arch/nds32/kernel/vdso/sigreturn.S
create mode 100644 arch/nds32/kernel/vdso/vdso.S
create mode 100644 arch/nds32/kernel/vdso/vdso.lds.S
diff --git a/arch/nds32/include/asm/vdso.h b/arch/nds32/include/asm/vdso.h
new file mode 100644
index 0000000..7298c49
--- /dev/null
+++ b/arch/nds32/include/asm/vdso.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_VDSO_H
+#define __ASM_VDSO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+#include <generated/vdso-offsets.h>
+
+#define VDSO_SYMBOL(base, name) \
+({ \
+ (unsigned long)(vdso_offset_##name + (unsigned long)(base)); \
+})
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_VDSO_H */
diff --git a/arch/nds32/include/asm/vdso_datapage.h b/arch/nds32/include/asm/vdso_datapage.h
new file mode 100644
index 0000000..ffae33c
--- /dev/null
+++ b/arch/nds32/include/asm/vdso_datapage.h
@@ -0,0 +1,51 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * Copyright (C) 2012 ARM Limited
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_VDSO_DATAPAGE_H
+#define __ASM_VDSO_DATAPAGE_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+struct vdso_data {
+ bool cycle_count_down; /* timer cyclye counter is decrease with time */
+ u32 cycle_count_offset; /* offset of timer cycle counter register */
+ u32 seq_count; /* sequence count - odd during updates */
+ u32 xtime_coarse_sec; /* coarse time */
+ u32 xtime_coarse_nsec;
+
+ u32 wtm_clock_sec; /* wall to monotonic offset */
+ u32 wtm_clock_nsec;
+ u32 xtime_clock_sec; /* CLOCK_REALTIME - seconds */
+ u32 cs_mult; /* clocksource multiplier */
+ u32 cs_shift; /* Cycle to nanosecond divisor (power of two) */
+
+ u64 cs_cycle_last; /* last cycle value */
+ u64 cs_mask; /* clocksource mask */
+
+ u64 xtime_clock_nsec; /* CLOCK_REALTIME sub-ns base */
+ u32 tz_minuteswest; /* timezone info for gettimeofday(2) */
+ u32 tz_dsttime;
+};
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_VDSO_DATAPAGE_H */
diff --git a/arch/nds32/kernel/vdso.c b/arch/nds32/kernel/vdso.c
new file mode 100644
index 0000000..d7ef70c
--- /dev/null
+++ b/arch/nds32/kernel/vdso.c
@@ -0,0 +1,243 @@
+/*
+ * VDSO implementation for AArch64 and vector page setup for AArch32.
+ *
+ * Copyright (C) 2012 ARM Limited
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ *
+ * Author: Will Deacon <[email protected]>
+ */
+
+#include <linux/cache.h>
+#include <linux/clocksource.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/timekeeper_internal.h>
+#include <linux/vmalloc.h>
+
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <asm/cacheflush.h>
+#include <asm/vdso.h>
+#include <asm/vdso_datapage.h>
+#include <linux/random.h>
+#include <asm/cache_info.h>
+extern struct cache_info L1_cache_info[2];
+extern char vdso_start, vdso_end;
+static unsigned long vdso_pages __ro_after_init;
+struct resource timer_res;
+
+/*
+ * The vDSO data page.
+ */
+static struct page *no_pages[] = { NULL };
+
+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 struct vm_special_mapping vdso_spec[2] __ro_after_init = {
+ {
+ .name = "[vvar]",
+ .pages = no_pages,
+ },
+ {
+ .name = "[vdso]",
+ },
+};
+
+static int grab_timer_node_info(void)
+{
+ struct device_node *timer_node;
+
+ timer_node = of_find_node_by_name(NULL, "timer");
+ of_property_read_u32(timer_node, "cycle-count-offset",
+ &vdso_data->cycle_count_offset);
+ vdso_data->cycle_count_down =
+ of_property_read_bool(timer_node, "cycle-count-down");
+ return of_address_to_resource(timer_node, 0, &timer_res);
+}
+
+static int __init vdso_init(void)
+{
+ int i;
+ struct page **vdso_pagelist;
+
+ if (memcmp(&vdso_start, "\177ELF", 4)) {
+ pr_err("vDSO is not a valid ELF object!\n");
+ return -EINVAL;
+ }
+ /* Creat a timer io mapping to get clock cycles counter */
+ if (grab_timer_node_info())
+ return -ENODEV;
+
+ vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
+ pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n",
+ vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data);
+
+ /* Allocate the vDSO pagelist */
+ vdso_pagelist = kcalloc(vdso_pages, sizeof(struct page *), GFP_KERNEL);
+ if (vdso_pagelist == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < vdso_pages; i++)
+ vdso_pagelist[i] = virt_to_page(&vdso_start + i * PAGE_SIZE);
+ vdso_spec[1].pages = &vdso_pagelist[0];
+
+ return 0;
+}
+
+arch_initcall(vdso_init);
+
+unsigned long inline vdso_random_addr(unsigned long vdso_mapping_len)
+{
+ unsigned long start = current->mm->mmap_base, end, offset, addr;
+ start = PAGE_ALIGN(start);
+
+ /* Round the lowest possible end address up to a PMD boundary. */
+ end = (start + vdso_mapping_len + PMD_SIZE - 1) & PMD_MASK;
+ if (end >= TASK_SIZE)
+ end = TASK_SIZE;
+ end -= vdso_mapping_len;
+
+ if (end > start) {
+ offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1);
+ addr = start + (offset << PAGE_SHIFT);
+ } else {
+ addr = start;
+ }
+ return addr;
+}
+
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
+ struct vm_area_struct *vma;
+ unsigned long addr = 0;
+ pgprot_t prot;
+ int ret;
+
+ vdso_text_len = vdso_pages << PAGE_SHIFT;
+ /* Be sure to map the data page */
+ vdso_mapping_len = vdso_text_len + 2 * PAGE_SIZE;
+#ifndef CONFIG_CPU_CACHE_NONALIASING
+ vdso_mapping_len += L1_cache_info[DCACHE].aliasing_num - 1;
+#endif
+
+ if (down_write_killable(&mm->mmap_sem))
+ return -EINTR;
+
+ addr = vdso_random_addr(vdso_mapping_len);
+ vdso_base = get_unmapped_area(NULL, addr, vdso_mapping_len, 0, 0);
+ if (IS_ERR_VALUE(vdso_base)) {
+ ret = vdso_base;
+ goto up_fail;
+ }
+#ifndef CONFIG_CPU_CACHE_NONALIASING
+ {
+ unsigned int aliasing_mask =
+ L1_cache_info[DCACHE].aliasing_mask;
+ unsigned int page_colour_ofs;
+ page_colour_ofs = ((unsigned int)vdso_data & aliasing_mask) -
+ (vdso_base & aliasing_mask);
+ vdso_base += page_colour_ofs & aliasing_mask;
+ }
+#endif
+ vma = _install_special_mapping(mm, vdso_base, 2 * PAGE_SIZE,
+ VM_READ | VM_MAYREAD, &vdso_spec[0]);
+ if (IS_ERR(vma)) {
+ ret = PTR_ERR(vma);
+ goto up_fail;
+ }
+
+ /*Map vdata to user space */
+ ret = io_remap_pfn_range(vma, vdso_base,
+ virt_to_phys(vdso_data) >> PAGE_SHIFT,
+ PAGE_SIZE, vma->vm_page_prot);
+ if (ret)
+ goto up_fail;
+
+ /*Map timer to user space */
+ vdso_base += PAGE_SIZE;
+ prot = __pgprot(_PAGE_V | _PAGE_M_UR_KR | _PAGE_D |
+ _PAGE_G | _PAGE_C_DEV);
+ ret = io_remap_pfn_range(vma, vdso_base, timer_res.start >> PAGE_SHIFT,
+ PAGE_SIZE, prot);
+ if (ret)
+ goto up_fail;
+
+ /*Map vdso to user space */
+ vdso_base += PAGE_SIZE;
+ mm->context.vdso = (void *)vdso_base;
+ vma = _install_special_mapping(mm, vdso_base, vdso_text_len,
+ VM_READ | VM_EXEC |
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
+ &vdso_spec[1]);
+ if (IS_ERR(vma)) {
+ ret = PTR_ERR(vma);
+ goto up_fail;
+ }
+
+ up_write(&mm->mmap_sem);
+ return 0;
+
+up_fail:
+ mm->context.vdso = NULL;
+ up_write(&mm->mmap_sem);
+ return ret;
+}
+
+static void vdso_write_begin(struct vdso_data *vdata)
+{
+ ++vdso_data->seq_count;
+ smp_wmb(); /* Pairs with smp_rmb in vdso_read_retry */
+}
+
+static void vdso_write_end(struct vdso_data *vdata)
+{
+ smp_wmb(); /* Pairs with smp_rmb in vdso_read_begin */
+ ++vdso_data->seq_count;
+}
+
+void update_vsyscall(struct timekeeper *tk)
+{
+ vdso_write_begin(vdso_data);
+ vdso_data->cs_mask = tk->tkr_mono.mask;
+ vdso_data->cs_mult = tk->tkr_mono.mult;
+ vdso_data->cs_shift = tk->tkr_mono.shift;
+ vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last;
+ vdso_data->wtm_clock_sec = tk->wall_to_monotonic.tv_sec;
+ vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec;
+ vdso_data->xtime_clock_sec = tk->xtime_sec;
+ vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec;
+ vdso_data->xtime_coarse_sec = tk->xtime_sec;
+ vdso_data->xtime_coarse_nsec = tk->tkr_mono.xtime_nsec >>
+ tk->tkr_mono.shift;
+ vdso_write_end(vdso_data);
+}
+
+void update_vsyscall_tz(void)
+{
+ vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
+ vdso_data->tz_dsttime = sys_tz.tz_dsttime;
+}
diff --git a/arch/nds32/kernel/vdso/Makefile b/arch/nds32/kernel/vdso/Makefile
new file mode 100644
index 0000000..e6c50a7
--- /dev/null
+++ b/arch/nds32/kernel/vdso/Makefile
@@ -0,0 +1,82 @@
+#
+# Building a vDSO image for AArch64.
+#
+# Author: Will Deacon <[email protected]>
+# Heavily based on the vDSO Makefiles for other archs.
+#
+
+obj-vdso := note.o datapage.o sigreturn.o gettimeofday.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)
+ccflags-y += -fPIC -Wl,-shared -g
+
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
+
+obj-y += vdso.o
+extra-y += vdso.lds
+CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+# Force dependency
+$(obj)/vdso.o : $(obj)/vdso.so
+
+# Link rule for the .so file, .lds has to be first
+$(obj)/vdso.so.dbg: $(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)
+
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+define cmd_vdsosym
+ $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+endef
+
+include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE
+ $(call if_changed,vdsosym)
+
+
+
+# Assembly rules for the .S files
+
+sigreturn.o : sigreturn.S
+ $(call if_changed_dep,vdsoas)
+
+note.o : note.S
+ $(call if_changed_dep,vdsoas)
+
+datapage.o : datapage.S
+ $(call if_changed_dep,vdsoas)
+
+gettimeofday.o : gettimeofday.c FORCE
+ $(call if_changed_dep,vdsocc)
+
+# Actual build commands
+quiet_cmd_vdsold = VDSOL $@
+ cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $^ -o $@
+quiet_cmd_vdsoas = VDSOA $@
+ cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $<
+quiet_cmd_vdsocc = VDSOA $@
+ cmd_vdsocc = $(CC) $(c_flags) -c -o $@ $<
+
+# Install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+ cmd_vdso_install = cp $(obj)/[email protected] $(MODLIB)/vdso/$@
+
+vdso.so: $(obj)/vdso.so.dbg
+ @mkdir -p $(MODLIB)/vdso
+ $(call cmd,vdso_install)
+
+vdso_install: vdso.so
diff --git a/arch/nds32/kernel/vdso/datapage.S b/arch/nds32/kernel/vdso/datapage.S
new file mode 100644
index 0000000..d86af66
--- /dev/null
+++ b/arch/nds32/kernel/vdso/datapage.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+ENTRY(__get_timerpage)
+ sethi $r0, hi20(. + PAGE_SIZE + 8)
+ ori $r0, $r0, lo12(. + PAGE_SIZE + 4)
+ mfusr $r1, $pc
+ sub $r0, $r1, $r0
+ ret
+ENDPROC(__get_timerpage)
+
+ENTRY(__get_datapage)
+ sethi $r0, hi20(. + 2*PAGE_SIZE + 8)
+ ori $r0, $r0, lo12(. + 2*PAGE_SIZE + 4)
+ mfusr $r1, $pc
+ sub $r0, $r1, $r0
+ ret
+ENDPROC(__get_datapage)
diff --git a/arch/nds32/kernel/vdso/gen_vdso_offsets.sh b/arch/nds32/kernel/vdso/gen_vdso_offsets.sh
new file mode 100755
index 0000000..01924ff
--- /dev/null
+++ b/arch/nds32/kernel/vdso/gen_vdso_offsets.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+#
+# Match symbols in the DSO that look like VDSO_*; produce a header file
+# of constant offsets into the shared object.
+#
+# Doing this inside the Makefile will break the $(filter-out) function,
+# causing Kbuild to rebuild the vdso-offsets header file every time.
+#
+# Author: Will Deacon <[email protected]
+#
+
+LC_ALL=C
+sed -n -e 's/^00*/0/' -e \
+'s/^\([0-9a-fA-F]*\) . VDSO_\([a-zA-Z0-9_]*\)$/\#define vdso_offset_\2\t0x\1/p'
diff --git a/arch/nds32/kernel/vdso/gettimeofday.c b/arch/nds32/kernel/vdso/gettimeofday.c
new file mode 100644
index 0000000..3a93d4e
--- /dev/null
+++ b/arch/nds32/kernel/vdso/gettimeofday.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2015 Mentor Graphics Corporation.
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 of the
+ * License.
+ *
+ * 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/>.
+ */
+
+#include <linux/compiler.h>
+#include <linux/hrtimer.h>
+#include <linux/time.h>
+#include <asm/io.h>
+#include <asm/barrier.h>
+#include <asm/bug.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
+#include <asm/vdso_datapage.h>
+#include <asm/asm-offsets.h>
+
+#define X(x) #x
+#define Y(x) X(x)
+
+extern struct vdso_data *__get_datapage(void);
+extern struct vdso_data *__get_timerpage(void);
+
+static notrace unsigned int __vdso_read_begin(const struct vdso_data *vdata)
+{
+ u32 seq;
+repeat:
+ seq = ACCESS_ONCE(vdata->seq_count);
+ if (seq & 1) {
+ cpu_relax();
+ goto repeat;
+ }
+ return seq;
+}
+
+static notrace unsigned int vdso_read_begin(const struct vdso_data *vdata)
+{
+ unsigned int seq;
+
+ seq = __vdso_read_begin(vdata);
+
+ smp_rmb(); /* Pairs with smp_wmb in vdso_write_end */
+ return seq;
+}
+
+static notrace int vdso_read_retry(const struct vdso_data *vdata, u32 start)
+{
+ smp_rmb(); /* Pairs with smp_wmb in vdso_write_begin */
+ return vdata->seq_count != start;
+}
+
+static notrace long clock_gettime_fallback(clockid_t _clkid,
+ struct timespec *_ts)
+{
+ register struct timespec *ts asm("$r1") = _ts;
+ register clockid_t clkid asm("$r0") = _clkid;
+ register long ret asm("$r0");
+
+ asm volatile (" syscall " Y(__NR_clock_gettime) "\n":"=r"(ret)
+ :"r"(clkid), "r"(ts)
+ :"memory");
+
+ return ret;
+}
+
+static notrace int do_realtime_coarse(struct timespec *ts,
+ struct vdso_data *vdata)
+{
+ u32 seq;
+
+ do {
+ seq = vdso_read_begin(vdata);
+
+ ts->tv_sec = vdata->xtime_coarse_sec;
+ ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+ } while (vdso_read_retry(vdata, seq));
+ return 0;
+}
+
+static notrace int do_monotonic_coarse(struct timespec *ts,
+ struct vdso_data *vdata)
+{
+ struct timespec tomono;
+ u32 seq;
+
+ do {
+ seq = vdso_read_begin(vdata);
+
+ ts->tv_sec = vdata->xtime_coarse_sec;
+ ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+ tomono.tv_sec = vdata->wtm_clock_sec;
+ tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+ } while (vdso_read_retry(vdata, seq));
+
+ ts->tv_sec += tomono.tv_sec;
+ timespec_add_ns(ts, tomono.tv_nsec);
+ return 0;
+}
+
+static inline u64 vgetsns(struct vdso_data *vdso)
+{
+ u32 cycle_now;
+ u32 cycle_delta;
+ u32 *timer_cycle_base;
+
+ timer_cycle_base =
+ (u32 *) ((char *)__get_timerpage() + vdso->cycle_count_offset);
+ cycle_now = readl_relaxed(timer_cycle_base);
+ if (true == vdso->cycle_count_down)
+ cycle_now = ~(*timer_cycle_base);
+ cycle_delta = cycle_now - (u32) vdso->cs_cycle_last;
+ return ((u64) cycle_delta & vdso->cs_mask) * vdso->cs_mult;
+}
+
+static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata)
+{
+ unsigned count;
+ u64 ns;
+ do {
+ count = vdso_read_begin(vdata);
+ ts->tv_sec = vdata->xtime_clock_sec;
+ ns = vdata->xtime_clock_nsec;
+ ns += vgetsns(vdata);
+ ns >>= vdata->cs_shift;
+ } while (vdso_read_retry(vdata, count));
+
+ ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
+ ts->tv_nsec = ns;
+
+ return 0;
+}
+
+static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
+{
+ struct timespec tomono;
+ u64 nsecs;
+ u32 seq;
+
+ do {
+ seq = vdso_read_begin(vdata);
+
+ ts->tv_sec = vdata->xtime_clock_sec;
+ nsecs = vdata->xtime_clock_nsec;
+ nsecs += vgetsns(vdata);
+ nsecs >>= vdata->cs_shift;
+
+ tomono.tv_sec = vdata->wtm_clock_sec;
+ tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+ } while (vdso_read_retry(vdata, seq));
+
+ ts->tv_sec += tomono.tv_sec;
+ ts->tv_nsec = 0;
+ timespec_add_ns(ts, nsecs + tomono.tv_nsec);
+ return 0;
+}
+
+notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
+{
+ struct vdso_data *vdata;
+ int ret = -1;
+
+ vdata = __get_datapage();
+
+ switch (clkid) {
+ case CLOCK_REALTIME_COARSE:
+ ret = do_realtime_coarse(ts, vdata);
+ break;
+ case CLOCK_MONOTONIC_COARSE:
+ ret = do_monotonic_coarse(ts, vdata);
+ break;
+ case CLOCK_REALTIME:
+ ret = do_realtime(ts, vdata);
+ break;
+ case CLOCK_MONOTONIC:
+ ret = do_monotonic(ts, vdata);
+ break;
+ default:
+ break;
+ }
+
+ if (ret)
+ ret = clock_gettime_fallback(clkid, ts);
+
+ return ret;
+}
+
+static notrace long clock_getres_fallback(clockid_t _clk_id,
+ struct timespec *_res)
+{
+ register clockid_t clk_id asm("$r0") = _clk_id;
+ register struct timespec *res asm("$r1") = _res;
+ register long ret asm("$r0");
+
+ asm volatile (" syscall " Y(__NR_clock_getres) " \n":"=r"(ret)
+ :"r"(clk_id), "r"(res)
+ :"memory");
+
+ return ret;
+}
+
+notrace int __vdso_clock_getres(clockid_t clk_id, struct timespec *res)
+{
+ if (res == NULL)
+ return -EFAULT;
+ switch (clk_id) {
+ case CLOCK_REALTIME:
+ case CLOCK_MONOTONIC:
+ case CLOCK_MONOTONIC_RAW:
+ res->tv_sec = 0;
+ res->tv_nsec = CLOCK_REALTIME_RES;
+ break;
+ case CLOCK_REALTIME_COARSE:
+ case CLOCK_MONOTONIC_COARSE:
+ res->tv_sec = 0;
+ res->tv_nsec = CLOCK_COARSE_RES;
+ break;
+ default:
+ clock_getres_fallback(clk_id, res);
+ break;
+ }
+ return 0;
+}
+
+notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ struct timespec ts;
+ struct vdso_data *vdata;
+ int ret;
+
+ vdata = __get_datapage();
+
+ ret = do_realtime(&ts, vdata);
+
+ if (tv) {
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+ if (tz) {
+ tz->tz_minuteswest = vdata->tz_minuteswest;
+ tz->tz_dsttime = vdata->tz_dsttime;
+ }
+
+ return ret;
+}
diff --git a/arch/nds32/kernel/vdso/note.S b/arch/nds32/kernel/vdso/note.S
new file mode 100644
index 0000000..59c6397
--- /dev/null
+++ b/arch/nds32/kernel/vdso/note.S
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 ARM Limited
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ *
+ * Author: Will Deacon <[email protected]>
+ *
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/elfnote.h>
+
+ELFNOTE_START(Linux, 0, "a")
+ .long LINUX_VERSION_CODE
+ELFNOTE_END
diff --git a/arch/nds32/kernel/vdso/sigreturn.S b/arch/nds32/kernel/vdso/sigreturn.S
new file mode 100644
index 0000000..e3cd9d7
--- /dev/null
+++ b/arch/nds32/kernel/vdso/sigreturn.S
@@ -0,0 +1,32 @@
+/*
+ * Sigreturn trampoline for returning from a signal when the SA_RESTORER
+ * flag is not set.
+ *
+ * Copyright (C) 2012 ARM Limited
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ *
+ * Author: Will Deacon <[email protected]>
+ */
+
+#include <linux/linkage.h>
+#include <asm/unistd.h>
+
+ .text
+
+ENTRY(__kernel_rt_sigreturn)
+ .cfi_startproc
+ syscall #__NR_rt_sigreturn
+ .cfi_endproc
+ENDPROC(__kernel_rt_sigreturn)
diff --git a/arch/nds32/kernel/vdso/vdso.S b/arch/nds32/kernel/vdso/vdso.S
new file mode 100644
index 0000000..4444082
--- /dev/null
+++ b/arch/nds32/kernel/vdso/vdso.S
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 ARM Limited
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ *
+ * Author: Will Deacon <[email protected]>
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/page.h>
+
+ .globl vdso_start, vdso_end
+ .section .rodata
+ .balign PAGE_SIZE
+vdso_start:
+ .incbin "arch/nds32/kernel/vdso/vdso.so"
+ .balign PAGE_SIZE
+vdso_end:
+
+ .previous
diff --git a/arch/nds32/kernel/vdso/vdso.lds.S b/arch/nds32/kernel/vdso/vdso.lds.S
new file mode 100644
index 0000000..9842ec7
--- /dev/null
+++ b/arch/nds32/kernel/vdso/vdso.lds.S
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+
+#include <linux/const.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf32-nds32le-linux", "elf32-nds32be-linux", "elf32-nds32le-linux")
+OUTPUT_ARCH(nds32)
+
+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
+
+
+ .text : { *(.text*) } :text
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+
+ .dynamic : { *(.dynamic) } :text :dynamic
+
+ .rodata : { *(.rodata*) } :text
+
+
+ /DISCARD/ : {
+ *(.note.GNU-stack)
+ *(.data .data.* .gnu.linkonce.d.* .sdata*)
+ *(.bss .sbss .dynbss .dynsbss)
+ }
+}
+
+/*
+ * 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:
+ __kernel_rt_sigreturn;
+ __vdso_gettimeofday;
+ __vdso_clock_getres;
+ __vdso_clock_gettime;
+ local: *;
+ };
+}
+
+/*
+ * Make the rt_sigreturn code visible to the kernel.
+ */
+VDSO_rt_sigtramp = __kernel_rt_sigreturn;
--
1.7.9.5
From 1583436878240662188@xxx Tue Nov 07 19:31:22 +0000 2017
X-GM-THRID: 1583436878240662188
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/asm/cache.h | 25 ++
arch/nds32/include/asm/cache_info.h | 26 ++
arch/nds32/include/asm/cacheflush.h | 57 +++
arch/nds32/include/asm/mmu_context.h | 81 +++++
arch/nds32/include/asm/proc-fns.h | 94 +++++
arch/nds32/include/asm/tlb.h | 41 +++
arch/nds32/include/asm/tlbflush.h | 60 ++++
arch/nds32/include/uapi/asm/cachectl.h | 19 +
arch/nds32/kernel/cacheinfo.c | 62 ++++
arch/nds32/mm/cacheflush.c | 331 +++++++++++++++++
arch/nds32/mm/proc-n13.c | 608 ++++++++++++++++++++++++++++++++
arch/nds32/mm/tlb.c | 63 ++++
12 files changed, 1467 insertions(+)
create mode 100644 arch/nds32/include/asm/cache.h
create mode 100644 arch/nds32/include/asm/cache_info.h
create mode 100644 arch/nds32/include/asm/cacheflush.h
create mode 100644 arch/nds32/include/asm/mmu_context.h
create mode 100644 arch/nds32/include/asm/proc-fns.h
create mode 100644 arch/nds32/include/asm/tlb.h
create mode 100644 arch/nds32/include/asm/tlbflush.h
create mode 100644 arch/nds32/include/uapi/asm/cachectl.h
create mode 100644 arch/nds32/kernel/cacheinfo.c
create mode 100644 arch/nds32/mm/cacheflush.c
create mode 100644 arch/nds32/mm/proc-n13.c
create mode 100644 arch/nds32/mm/tlb.c
diff --git a/arch/nds32/include/asm/cache.h b/arch/nds32/include/asm/cache.h
new file mode 100644
index 0000000..36ec549
--- /dev/null
+++ b/arch/nds32/include/asm/cache.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 __NDS32_CACHE_H__
+#define __NDS32_CACHE_H__
+
+#define L1_CACHE_BYTES 32
+#define L1_CACHE_SHIFT 5
+
+#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
+
+#endif /* __NDS32_CACHE_H__ */
diff --git a/arch/nds32/include/asm/cache_info.h b/arch/nds32/include/asm/cache_info.h
new file mode 100644
index 0000000..a59d73d
--- /dev/null
+++ b/arch/nds32/include/asm/cache_info.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+struct cache_info {
+ unsigned char ways;
+ unsigned char line_size;
+ unsigned short sets;
+ unsigned short size;
+#if !defined(CONFIG_CPU_CACHE_NONALIASING)
+ unsigned short aliasing_num;
+ unsigned int aliasing_mask;
+#endif
+};
diff --git a/arch/nds32/include/asm/cacheflush.h b/arch/nds32/include/asm/cacheflush.h
new file mode 100644
index 0000000..0c7c9db
--- /dev/null
+++ b/arch/nds32/include/asm/cacheflush.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 __NDS32_CACHEFLUSH_H__
+#define __NDS32_CACHEFLUSH_H__
+
+#include <linux/mm.h>
+
+#define PG_dcache_dirty PG_arch_1
+
+#ifndef CONFIG_CPU_CACHE_NONALIASING
+void flush_cache_mm(struct mm_struct *mm);
+void flush_cache_dup_mm(struct mm_struct *mm);
+void flush_cache_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end);
+void flush_cache_page(struct vm_area_struct *vma,
+ unsigned long addr, unsigned long pfn);
+void flush_cache_kmaps(void);
+void flush_cache_vmap(unsigned long start, unsigned long end);
+void flush_cache_vunmap(unsigned long start, unsigned long end);
+
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
+void flush_dcache_page(struct page *page);
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, void *src, int len);
+void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, void *src, int len);
+
+#define ARCH_HAS_FLUSH_ANON_PAGE
+void flush_anon_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vaddr);
+
+#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+void flush_kernel_dcache_page(struct page *page);
+void flush_icache_range(unsigned long start, unsigned long end);
+void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+#define flush_dcache_mmap_lock(mapping) spin_lock_irq(&(mapping)->tree_lock)
+#define flush_dcache_mmap_unlock(mapping) spin_unlock_irq(&(mapping)->tree_lock)
+
+#else
+#include <asm-generic/cacheflush.h>
+#endif
+
+#endif /* __NDS32_CACHEFLUSH_H__ */
diff --git a/arch/nds32/include/asm/mmu_context.h b/arch/nds32/include/asm/mmu_context.h
new file mode 100644
index 0000000..4a59b5d
--- /dev/null
+++ b/arch/nds32/include/asm/mmu_context.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_NDS32_MMU_CONTEXT_H
+#define __ASM_NDS32_MMU_CONTEXT_H
+
+#include <linux/spinlock.h>
+#include <asm/tlbflush.h>
+#include <asm/proc-fns.h>
+#include <asm-generic/mm_hooks.h>
+
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+ mm->context.id = 0;
+ return 0;
+}
+
+#define destroy_context(mm) do { } while(0)
+
+#define CID_BITS 9
+extern spinlock_t cid_lock;
+extern unsigned int cpu_last_cid;
+
+static inline void __new_context(struct mm_struct *mm)
+{
+ unsigned int cid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cid_lock, flags);
+ cid = cpu_last_cid;
+ cpu_last_cid += 1 << TLB_MISC_offCID;
+ if (cpu_last_cid == 0)
+ cpu_last_cid = 1 << TLB_MISC_offCID << CID_BITS;
+
+ if ((cid & TLB_MISC_mskCID) == 0)
+ flush_tlb_all();
+ spin_unlock_irqrestore(&cid_lock, flags);
+
+ mm->context.id = cid;
+}
+
+static inline void check_context(struct mm_struct *mm)
+{
+ if (unlikely
+ ((mm->context.id ^ cpu_last_cid) >> TLB_MISC_offCID >> CID_BITS))
+ __new_context(mm);
+}
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ struct task_struct *tsk)
+{
+ unsigned int cpu = smp_processor_id();
+
+ if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) {
+ check_context(next);
+ cpu_switch_mm(next);
+ }
+}
+
+#define deactivate_mm(tsk,mm) do { } while (0)
+#define activate_mm(prev,next) switch_mm(prev, next, NULL)
+
+#endif
diff --git a/arch/nds32/include/asm/proc-fns.h b/arch/nds32/include/asm/proc-fns.h
new file mode 100644
index 0000000..4321014
--- /dev/null
+++ b/arch/nds32/include/asm/proc-fns.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 __NDS32_PROCFNS_H__
+#define __NDS32_PROCFNS_H__
+
+#define CPU_NAME n13
+
+#ifdef __KERNEL__
+
+#ifdef __STDC__
+#define ____cpu_fn(name,fn) name##fn
+#else
+#define ____cpu_fn(name,fn) name/**/fn
+#endif
+#define __cpu_fn(name,fn) ____cpu_fn(name,fn)
+
+#define cpu_proc_init __cpu_fn( CPU_NAME, _proc_init)
+#define cpu_proc_fin __cpu_fn( CPU_NAME, _proc_fin)
+#define cpu_do_idle __cpu_fn( CPU_NAME, _do_idle)
+#define cpu_reset __cpu_fn( CPU_NAME, _reset)
+#define cpu_switch_mm __cpu_fn( CPU_NAME, _switch_mm)
+
+#define cpu_dcache_inval_all __cpu_fn( CPU_NAME, _dcache_inval_all)
+#define cpu_dcache_wbinval_all __cpu_fn( CPU_NAME, _dcache_wbinval_all)
+#define cpu_dcache_inval_page __cpu_fn( CPU_NAME, _dcache_inval_page)
+#define cpu_dcache_wb_page __cpu_fn( CPU_NAME, _dcache_wb_page)
+#define cpu_dcache_wbinval_page __cpu_fn( CPU_NAME, _dcache_wbinval_page)
+#define cpu_dcache_inval_range __cpu_fn( CPU_NAME, _dcache_inval_range)
+#define cpu_dcache_wb_range __cpu_fn( CPU_NAME, _dcache_wb_range)
+#define cpu_dcache_wbinval_range __cpu_fn( CPU_NAME, _dcache_wbinval_range)
+
+#define cpu_icache_inval_all __cpu_fn( CPU_NAME, _icache_inval_all)
+#define cpu_icache_inval_page __cpu_fn( CPU_NAME, _icache_inval_page)
+#define cpu_icache_inval_range __cpu_fn( CPU_NAME, _icache_inval_range)
+
+#define cpu_cache_wbinval_page __cpu_fn( CPU_NAME, _cache_wbinval_page)
+#define cpu_cache_wbinval_range __cpu_fn( CPU_NAME, _cache_wbinval_range)
+#define cpu_cache_wbinval_range_check __cpu_fn( CPU_NAME, _cache_wbinval_range_check)
+
+#define cpu_dma_wb_range __cpu_fn( CPU_NAME, _dma_wb_range)
+#define cpu_dma_inval_range __cpu_fn( CPU_NAME, _dma_inval_range)
+#define cpu_dma_wbinval_range __cpu_fn( CPU_NAME, _dma_wbinval_range)
+
+#include <asm/page.h>
+
+struct mm_struct;
+struct vm_area_struct;
+extern void cpu_proc_init(void);
+extern void cpu_proc_fin(void);
+extern void cpu_do_idle(void);
+extern void cpu_reset(unsigned long reset);
+extern void cpu_switch_mm(struct mm_struct *mm);
+
+extern void cpu_dcache_inval_all(void);
+extern void cpu_dcache_wbinval_all(void);
+extern void cpu_dcache_inval_page(unsigned long page);
+extern void cpu_dcache_wb_page(unsigned long page);
+extern void cpu_dcache_wbinval_page(unsigned long page);
+extern void cpu_dcache_inval_range(unsigned long start, unsigned long end);
+extern void cpu_dcache_wb_range(unsigned long start, unsigned long end);
+extern void cpu_dcache_wbinval_range(unsigned long start, unsigned long end);
+
+extern void cpu_icache_inval_all(void);
+extern void cpu_icache_inval_page(unsigned long page);
+extern void cpu_icache_inval_range(unsigned long start, unsigned long end);
+
+extern void cpu_cache_wbinval_page(unsigned long page, int flushi);
+extern void cpu_cache_wbinval_range(unsigned long start,
+ unsigned long end, int flushi);
+extern void cpu_cache_wbinval_range_check(struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end, bool flushi,
+ bool wbd);
+
+extern void cpu_dma_wb_range(unsigned long start, unsigned long end);
+extern void cpu_dma_inval_range(unsigned long start, unsigned long end);
+extern void cpu_dma_wbinval_range(unsigned long start, unsigned long end);
+
+#endif /* __KERNEL__ */
+#endif /* __NDS32_PROCFNS_H__ */
diff --git a/arch/nds32/include/asm/tlb.h b/arch/nds32/include/asm/tlb.h
new file mode 100644
index 0000000..c599827
--- /dev/null
+++ b/arch/nds32/include/asm/tlb.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 __ASMNDS32_TLB_H
+#define __ASMNDS32_TLB_H
+
+#define tlb_start_vma(tlb,vma) \
+ do { \
+ if (!tlb->fullmm) \
+ flush_cache_range(vma, vma->vm_start, vma->vm_end); \
+ } while (0)
+
+#define tlb_end_vma(tlb,vma) \
+ do { \
+ if(!tlb->fullmm) \
+ flush_tlb_range(vma, vma->vm_start, vma->vm_end); \
+ } while (0)
+
+#define __tlb_remove_tlb_entry(tlb, pte, addr) do { } while (0)
+
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
+#include <asm-generic/tlb.h>
+
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
+#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tln)->mm, pmd)
+
+#endif
diff --git a/arch/nds32/include/asm/tlbflush.h b/arch/nds32/include/asm/tlbflush.h
new file mode 100644
index 0000000..680aeb3
--- /dev/null
+++ b/arch/nds32/include/asm/tlbflush.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 _ASMNDS32_TLBFLUSH_H
+#define _ASMNDS32_TLBFLUSH_H
+
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <nds32_intrinsic.h>
+
+static inline void local_flush_tlb_all(void)
+{
+ __nds32__tlbop_flua();
+ __nds32__isb();
+}
+
+static inline void local_flush_tlb_mm(struct mm_struct *mm)
+{
+ __nds32__tlbop_flua();
+ __nds32__isb();
+}
+
+static inline void local_flush_tlb_kernel_range(unsigned long start,
+ unsigned long end)
+{
+ while (start < end) {
+ __nds32__tlbop_inv(start);
+ __nds32__isb();
+ start += PAGE_SIZE;
+ }
+}
+
+void local_flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end);
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr);
+
+#define flush_tlb_all local_flush_tlb_all
+#define flush_tlb_mm local_flush_tlb_mm
+#define flush_tlb_range local_flush_tlb_range
+#define flush_tlb_page local_flush_tlb_page
+#define flush_tlb_kernel_range local_flush_tlb_kernel_range
+
+void update_mmu_cache(struct vm_area_struct *vma,
+ unsigned long address, pte_t * pte);
+void tlb_migrate_finish(struct mm_struct *mm);
+
+#endif
diff --git a/arch/nds32/include/uapi/asm/cachectl.h b/arch/nds32/include/uapi/asm/cachectl.h
new file mode 100644
index 0000000..a56a37d
--- /dev/null
+++ b/arch/nds32/include/uapi/asm/cachectl.h
@@ -0,0 +1,19 @@
+/*
+ * 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, 1995, 1996 by Ralf Baechle
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ */
+#ifndef _ASM_CACHECTL
+#define _ASM_CACHECTL
+
+/*
+ * Options for cacheflush system call
+ */
+#define ICACHE 0 /* flush instruction cache */
+#define DCACHE 1 /* writeback and flush data cache */
+#define BCACHE 2 /* flush instruction cache + writeback and flush data cache */
+
+#endif /* _ASM_CACHECTL */
diff --git a/arch/nds32/kernel/cacheinfo.c b/arch/nds32/kernel/cacheinfo.c
new file mode 100644
index 0000000..edc0fda
--- /dev/null
+++ b/arch/nds32/kernel/cacheinfo.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/bitops.h>
+#include <linux/cacheinfo.h>
+#include <linux/cpu.h>
+
+static void ci_leaf_init(struct cacheinfo *this_leaf,
+ enum cache_type type, unsigned int level)
+{
+ char cache_type = (type & CACHE_TYPE_INST ? ICACHE : DCACHE);
+
+ this_leaf->level = level;
+ this_leaf->type = type;
+ this_leaf->coherency_line_size = CACHE_LINE_SIZE(cache_type);
+ this_leaf->number_of_sets = CACHE_SET(cache_type);;
+ this_leaf->ways_of_associativity = CACHE_WAY(cache_type);
+ this_leaf->size = this_leaf->number_of_sets *
+ this_leaf->coherency_line_size * this_leaf->ways_of_associativity;
+#if defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
+ this_leaf->attributes = CACHE_WRITE_THROUGH;
+#else
+ this_leaf->attributes = CACHE_WRITE_BACK;
+#endif
+}
+
+int init_cache_level(unsigned int cpu)
+{
+ struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+
+ /* Only 1 level and I/D cache seperate. */
+ this_cpu_ci->num_levels = 1;
+ this_cpu_ci->num_leaves = 2;
+ return 0;
+}
+
+int populate_cache_leaves(unsigned int cpu)
+{
+ unsigned int level, idx;
+ struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+ struct cacheinfo *this_leaf = this_cpu_ci->info_list;
+
+ for (idx = 0, level = 1; level <= this_cpu_ci->num_levels &&
+ idx < this_cpu_ci->num_leaves; idx++, level++) {
+ ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level);
+ ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level);
+ }
+ return 0;
+}
diff --git a/arch/nds32/mm/cacheflush.c b/arch/nds32/mm/cacheflush.c
new file mode 100644
index 0000000..f5917fb
--- /dev/null
+++ b/arch/nds32/mm/cacheflush.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/module.h>
+#include <asm/cacheflush.h>
+#include <asm/proc-fns.h>
+#include <asm/shmparam.h>
+#include <asm/cache_info.h>
+
+extern struct cache_info L1_cache_info[2];
+
+#ifdef CONFIG_CPU_CACHE_NONALIASING
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
+ pte_t * pte)
+{
+ struct page *page;
+ unsigned long pfn = pte_pfn(*pte);
+
+ if (!pfn_valid(pfn))
+ return;
+
+ if (vma->vm_mm == current->active_mm) {
+
+ __nds32__mtsr_dsb(addr, NDS32_SR_TLB_VPN);
+ __nds32__tlbop_rwr(*pte);
+ __nds32__isb();
+ }
+ page = pfn_to_page(pfn);
+
+ if ((test_and_clear_bit(PG_dcache_dirty, &page->flags)) ||
+ (vma->vm_flags & VM_EXEC)) {
+
+ if (!PageHighMem(page)) {
+ cpu_cache_wbinval_page((unsigned long)
+ page_address(page),
+ vma->vm_flags & VM_EXEC);
+ } else {
+ unsigned long kaddr = (unsigned long)kmap_atomic(page);
+ cpu_cache_wbinval_page(kaddr, vma->vm_flags & VM_EXEC);
+ kunmap_atomic((void *)kaddr);
+ }
+ }
+}
+#else
+extern pte_t va_present(struct mm_struct *mm, unsigned long addr);
+
+static inline unsigned long aliasing(unsigned long addr, unsigned long page)
+{
+ return ((addr & PAGE_MASK) ^ page) & (REALSHMLBA - 1);
+}
+
+static inline unsigned long kremap0(unsigned long uaddr, unsigned long pa)
+{
+ unsigned long kaddr, pte;
+
+#define BASE_ADDR0 0xffffc000
+ kaddr = BASE_ADDR0 | (uaddr & L1_cache_info[DCACHE].aliasing_mask);
+ pte = (pa | PAGE_KERNEL);
+ __nds32__mtsr_dsb(kaddr, NDS32_SR_TLB_VPN);
+ __nds32__tlbop_rwlk(pte);
+ __nds32__isb();
+ return kaddr;
+}
+
+static inline void kunmap01(unsigned long kaddr)
+{
+ __nds32__tlbop_unlk(kaddr);
+ __nds32__tlbop_inv(kaddr);
+ __nds32__isb();
+}
+
+static inline unsigned long kremap1(unsigned long uaddr, unsigned long pa)
+{
+ unsigned long kaddr, pte;
+
+#define BASE_ADDR1 0xffff8000
+ kaddr = BASE_ADDR1 | (uaddr & L1_cache_info[DCACHE].aliasing_mask);
+ pte = (pa | PAGE_KERNEL);
+ __nds32__mtsr_dsb(kaddr, NDS32_SR_TLB_VPN);
+ __nds32__tlbop_rwlk(pte);
+ __nds32__isb();
+ return kaddr;
+}
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ cpu_dcache_wbinval_all();
+ cpu_icache_inval_all();
+ local_irq_restore(flags);
+}
+
+void flush_cache_dup_mm(struct mm_struct *mm)
+{
+}
+
+void flush_cache_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ unsigned long flags;
+
+ if ((end - start) > 8 * PAGE_SIZE) {
+ cpu_dcache_wbinval_all();
+ if (vma->vm_flags & VM_EXEC)
+ cpu_icache_inval_all();
+ return;
+ }
+ local_irq_save(flags);
+ while (start < end) {
+ if (va_present(vma->vm_mm, start))
+ cpu_cache_wbinval_page(start, vma->vm_flags & VM_EXEC);
+ start += PAGE_SIZE;
+ }
+ local_irq_restore(flags);
+ return;
+}
+
+void flush_cache_page(struct vm_area_struct *vma,
+ unsigned long addr, unsigned long pfn)
+{
+ unsigned long vto, flags;
+
+ local_irq_save(flags);
+ vto = kremap0(addr, pfn << PAGE_SHIFT);
+ cpu_cache_wbinval_page(vto, vma->vm_flags & VM_EXEC);
+ kunmap01(vto);
+ local_irq_restore(flags);
+}
+
+void flush_cache_vmap(unsigned long start, unsigned long end)
+{
+ cpu_dcache_wbinval_all();
+ cpu_icache_inval_all();
+}
+
+void flush_cache_vunmap(unsigned long start, unsigned long end)
+{
+ cpu_dcache_wbinval_all();
+ cpu_icache_inval_all();
+}
+
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma)
+{
+ unsigned long vto, vfrom, flags, kto, kfrom, pfrom, pto;
+ kto = ((unsigned long)page_address(to) & PAGE_MASK);
+ kfrom = ((unsigned long)page_address(from) & PAGE_MASK);
+ pto = page_to_phys(to);
+ pfrom = page_to_phys(from);
+
+ if (aliasing(vaddr, (unsigned long)kfrom))
+ cpu_dcache_wb_page((unsigned long)kfrom);
+ if (aliasing(vaddr, (unsigned long)kto))
+ cpu_dcache_inval_page((unsigned long)kto);
+ local_irq_save(flags);
+ vto = kremap0(vaddr, pto);
+ vfrom = kremap1(vaddr, pfrom);
+ copy_page((void *)vto, (void *)vfrom);
+ kunmap01(vfrom);
+ kunmap01(vto);
+ local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(copy_user_highpage);
+
+void clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+ unsigned long vto, flags, kto;
+
+ kto = ((unsigned long)page_address(page) & PAGE_MASK);
+
+ local_irq_save(flags);
+ if (aliasing(kto, vaddr) && kto != 0) {
+ cpu_dcache_inval_page(kto);
+ cpu_icache_inval_page(kto);
+ }
+ vto = kremap0(vaddr, page_to_phys(page));
+ clear_page((void *)vto);
+ kunmap01(vto);
+ local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(clear_user_highpage);
+
+void flush_dcache_page(struct page *page)
+{
+ struct address_space *mapping;
+
+ mapping = page_mapping(page);
+ if (mapping && !mapping_mapped(mapping))
+ set_bit(PG_dcache_dirty, &page->flags);
+ else {
+ int i, pc;
+ unsigned long vto, kaddr, flags;
+ kaddr = (unsigned long)page_address(page);
+ cpu_dcache_wbinval_page(kaddr);
+ pc = CACHE_SET(DCACHE) * CACHE_LINE_SIZE(DCACHE) / PAGE_SIZE;
+ local_irq_save(flags);
+ for (i = 0; i < pc; i++) {
+ vto =
+ kremap0(kaddr + i * PAGE_SIZE, page_to_phys(page));
+ cpu_dcache_wbinval_page(vto);
+ kunmap01(vto);
+ }
+ local_irq_restore(flags);
+ }
+}
+
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, void *src, int len)
+{
+ unsigned long line_size, start, end, vto, flags;
+
+ local_irq_save(flags);
+ vto = kremap0(vaddr, page_to_phys(page));
+ dst = (void *)(vto | (vaddr & (PAGE_SIZE - 1)));
+ memcpy(dst, src, len);
+ if (vma->vm_flags & VM_EXEC) {
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = (unsigned long)dst & ~(line_size - 1);
+ end =
+ ((unsigned long)dst + len + line_size - 1) & ~(line_size -
+ 1);
+ cpu_cache_wbinval_range(start, end, 1);
+ }
+ kunmap01(vto);
+ local_irq_restore(flags);
+}
+
+void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, void *src, int len)
+{
+ unsigned long vto, flags;
+
+ local_irq_save(flags);
+ vto = kremap0(vaddr, page_to_phys(page));
+ src = (void *)(vto | (vaddr & (PAGE_SIZE - 1)));
+ memcpy(dst, src, len);
+ kunmap01(vto);
+ local_irq_restore(flags);
+}
+
+void flush_anon_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vaddr)
+{
+ unsigned long flags;
+ if (!PageAnon(page))
+ return;
+
+ if (vma->vm_mm != current->active_mm)
+ return;
+
+ local_irq_save(flags);
+ if (vma->vm_flags & VM_EXEC)
+ cpu_icache_inval_page(vaddr & PAGE_MASK);
+ cpu_dcache_wbinval_page((unsigned long)page_address(page));
+ local_irq_restore(flags);
+}
+
+void flush_kernel_dcache_page(struct page *page)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ cpu_dcache_wbinval_page((unsigned long)page_address(page));
+ local_irq_restore(flags);
+}
+
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size, flags;
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = start & ~(line_size - 1);
+ end = (end + line_size - 1) & ~(line_size - 1);
+ local_irq_save(flags);
+ cpu_cache_wbinval_range(start, end, 1);
+ local_irq_restore(flags);
+}
+
+void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ cpu_cache_wbinval_page((unsigned long)page_address(page),
+ vma->vm_flags & VM_EXEC);
+ local_irq_restore(flags);
+}
+
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
+ pte_t * pte)
+{
+ struct page *page;
+ unsigned long flags;
+ unsigned long pfn = pte_pfn(*pte);
+
+ if (!pfn_valid(pfn))
+ return;
+
+ if (vma->vm_mm == current->active_mm) {
+ __nds32__mtsr_dsb(addr, NDS32_SR_TLB_VPN);
+ __nds32__tlbop_rwr(*pte);
+ __nds32__isb();
+ }
+
+ page = pfn_to_page(pfn);
+ if (test_and_clear_bit(PG_dcache_dirty, &page->flags) ||
+ (vma->vm_flags & VM_EXEC)) {
+ local_irq_save(flags);
+ cpu_dcache_wbinval_page((unsigned long)page_address(page));
+ local_irq_restore(flags);
+ }
+}
+#endif
diff --git a/arch/nds32/mm/proc-n13.c b/arch/nds32/mm/proc-n13.c
new file mode 100644
index 0000000..9956785
--- /dev/null
+++ b/arch/nds32/mm/proc-n13.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/nds32.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#ifdef CONFIG_CACHE_L2
+#include <asm/l2_cache.h>
+#endif
+#include <nds32_intrinsic.h>
+
+#include <asm/cache_info.h>
+extern struct cache_info L1_cache_info[2];
+
+int va_kernel_present(unsigned long addr)
+{
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ pmd = pmd_offset(pgd_offset_k(addr), addr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset_map(pmd, addr);
+ pte = *ptep;
+ if (pte_present(pte))
+ return pte;
+ }
+ return 0;
+}
+
+pte_t va_present(struct mm_struct * mm, unsigned long addr)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ pgd = pgd_offset(mm, addr);
+ if (!pgd_none(*pgd)) {
+ pud = pud_offset(pgd, addr);
+ if (!pud_none(*pud)) {
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset_map(pmd, addr);
+ pte = *ptep;
+ if (pte_present(pte))
+ return pte;
+ }
+ }
+ }
+ return 0;
+
+}
+
+int va_readable(struct pt_regs *regs, unsigned long addr)
+{
+ struct mm_struct *mm = current->mm;
+ pte_t pte;
+ int ret = 0;
+
+ if (user_mode(regs)) {
+ /* user mode */
+ pte = va_present(mm, addr);
+ if (!pte && pte_read(pte))
+ ret = 1;
+ } else {
+ /* superuser mode is always readable, so we can only
+ * check it is present or not*/
+ return (! !va_kernel_present(addr));
+ }
+ return ret;
+}
+
+int va_writable(struct pt_regs *regs, unsigned long addr)
+{
+ struct mm_struct *mm = current->mm;
+ pte_t pte;
+ int ret = 0;
+
+ if (user_mode(regs)) {
+ /* user mode */
+ pte = va_present(mm, addr);
+ if (!pte && pte_write(pte))
+ ret = 1;
+ } else {
+ /* superuser mode */
+ pte = va_kernel_present(addr);
+ if (!pte && pte_kernel_write(pte))
+ ret = 1;
+ }
+ return ret;
+}
+
+/*
+ * All
+ */
+void n13_icache_inval_all(void)
+{
+ unsigned long end, line_size;
+
+ line_size = L1_cache_info[ICACHE].line_size;
+ end =
+ line_size * L1_cache_info[ICACHE].ways * L1_cache_info[ICACHE].sets;
+
+ do {
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end));
+ } while (end > 0);
+}
+
+void n13_dcache_inval_all(void)
+{
+ __nds32__cctl_l1d_invalall();
+}
+
+void n13_dcache_wb_all(void)
+{
+#ifdef CONFIG_CACHE_L2
+ if (atl2c_base)
+ __nds32__cctl_l1d_wball_alvl();
+ else
+ __nds32__cctl_l1d_wball_one_lvl();
+#else
+ __nds32__cctl_l1d_wball_one_lvl();
+#endif
+}
+
+void n13_dcache_wbinval_all(void)
+{
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ unsigned long flags;
+#endif
+
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ local_irq_save(flags);
+#endif
+#ifdef CONFIG_CACHE_L2
+ if (atl2c_base)
+ __nds32__cctl_l1d_wball_alvl();
+ else
+ __nds32__cctl_l1d_wball_one_lvl();
+#else
+ __nds32__cctl_l1d_wball_one_lvl();
+#endif
+ __nds32__cctl_l1d_invalall();
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ local_irq_restore(flags);
+#endif
+}
+
+/*
+ * Page
+ */
+void n13_icache_inval_page(unsigned long start)
+{
+ unsigned long line_size, end;
+
+ line_size = L1_cache_info[ICACHE].line_size;
+ end = start + PAGE_SIZE;
+
+ do {
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end));
+ } while (end != start);
+}
+
+void n13_dcache_inval_page(unsigned long start)
+{
+ unsigned long line_size, end;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+ end = start + PAGE_SIZE;
+
+ do {
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ } while (end != start);
+}
+
+void n13_dcache_wb_page(unsigned long start)
+{
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ unsigned long line_size, end;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+ end = start + PAGE_SIZE;
+
+ do {
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+ end -= line_size;
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+ } while (end != start);
+#endif
+}
+
+void n13_dcache_wbinval_page(unsigned long start)
+{
+ unsigned long line_size, end;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+ end = start + PAGE_SIZE;
+
+ do {
+ end -= line_size;
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+#endif
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+#endif
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+#endif
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ end -= line_size;
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end));
+#endif
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end));
+ } while (end != start);
+}
+
+void n13_cache_wbinval_page(unsigned long page, int flushi)
+{
+ n13_dcache_wbinval_page(page);
+ if (flushi)
+ n13_icache_inval_page(page);
+}
+
+/*
+ * Range
+ */
+void n13_icache_inval_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+
+ line_size = L1_cache_info[ICACHE].line_size;
+
+ while (end > start) {
+ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (start));
+ start += line_size;
+ }
+}
+
+void n13_dcache_inval_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+
+ while (end > start) {
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start));
+ start += line_size;
+ }
+}
+
+void n13_dcache_wb_range(unsigned long start, unsigned long end)
+{
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ unsigned long line_size;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+
+ while (end > start) {
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start));
+ start += line_size;
+ }
+#endif
+}
+
+void n13_dcache_wbinval_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+
+ while (end > start) {
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start));
+#endif
+ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start));
+ start += line_size;
+ }
+}
+
+void n13_cache_wbinval_range(unsigned long start, unsigned long end, int flushi)
+{
+ unsigned long line_size, align_start, align_end;
+
+ line_size = L1_cache_info[DCACHE].line_size;
+ align_start = start & ~(line_size - 1);
+ align_end = (end + line_size - 1) & ~(line_size - 1);
+ n13_dcache_wbinval_range(align_start, align_end);
+
+ if (flushi) {
+ line_size = L1_cache_info[ICACHE].line_size;
+ align_start = start & ~(line_size - 1);
+ align_end = (end + line_size - 1) & ~(line_size - 1);
+ n13_icache_inval_range(align_start, align_end);
+ }
+}
+
+void n13_cache_wbinval_range_check(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end,
+ bool flushi, bool wbd)
+{
+ unsigned long line_size, t_start, t_end;
+
+ if (!flushi && !wbd)
+ return;
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = start & ~(line_size - 1);
+ end = (end + line_size - 1) & ~(line_size - 1);
+
+ if ((end - start) > (8 * PAGE_SIZE)) {
+ if (wbd)
+ n13_dcache_wbinval_all();
+ if (flushi)
+ n13_icache_inval_all();
+ return;
+ }
+
+ t_start = (start + PAGE_SIZE) & PAGE_MASK;
+ t_end = ((end - 1) & PAGE_MASK);
+
+ if ((start & PAGE_MASK) == t_end) {
+ if (va_present(vma->vm_mm, start)) {
+ if (wbd)
+ n13_dcache_wbinval_range(start, end);
+ if (flushi)
+ n13_icache_inval_range(start, end);
+ }
+ return;
+ }
+
+ if (va_present(vma->vm_mm, start)) {
+ if (wbd)
+ n13_dcache_wbinval_range(start, end);
+ if (flushi)
+ n13_icache_inval_range(start, end);
+ }
+
+ if (va_present(vma->vm_mm, end - 1)) {
+ if (wbd)
+ n13_dcache_wbinval_range(start, end);
+ if (flushi)
+ n13_icache_inval_range(start, end);
+ }
+
+ while (t_start < t_end) {
+ if (va_present(vma->vm_mm, t_start)) {
+ if (wbd)
+ n13_dcache_wbinval_page(t_start);
+ if (flushi)
+ n13_icache_inval_page(t_start);
+ }
+ t_start += PAGE_SIZE;
+ }
+}
+
+/*
+ * DMA
+ */
+void n13_dma_wb_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+ unsigned long flags;
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = start & (~(line_size - 1));
+ end = (end + line_size - 1) & (~(line_size - 1));
+ if (unlikely(start == end))
+ return;
+
+ local_irq_save(flags);
+ n13_dcache_wb_range(start, end);
+
+#ifdef CONFIG_CACHE_L2
+ if (atl2c_base) {
+ unsigned long p_start = __pa(start);
+ unsigned long p_end = __pa(end);
+ unsigned long cmd;
+ /* TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE */
+ line_size = L2_CACHE_LINE_SIZE();
+ p_start = p_start & (~(line_size - 1));
+ p_end = (p_end + line_size - 1) & (~(line_size - 1));
+ cmd =
+ (p_start & ~(line_size - 1)) | CCTL_CMD_L2_PA_WB |
+ CCTL_SINGLE_CMD;
+ do {
+ L2_CMD_RDY();
+ L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
+ cmd += line_size;
+ p_start += line_size;
+ } while (p_end > p_start);
+ cmd = CCTL_CMD_L2_SYNC;
+ L2_CMD_RDY();
+ L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
+ L2_CMD_RDY();
+
+ }
+#endif
+ local_irq_restore(flags);
+}
+
+#ifdef CONFIG_CACHE_L2
+void n13_l2dcache_wbinval_range(unsigned long start, unsigned long end)
+{
+ unsigned long p_start;
+ unsigned long p_end;
+ unsigned long cmd;
+ unsigned long line_size;
+
+ p_start = __pa(start);
+ p_end = __pa(end);
+ /* TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE */
+ line_size = L2_CACHE_LINE_SIZE();
+ p_start = p_start & (~(line_size - 1));
+ p_end = (p_end + line_size - 1) & (~(line_size - 1));
+ cmd =
+ (p_start & ~(line_size - 1)) | CCTL_CMD_L2_PA_WBINVAL |
+ CCTL_SINGLE_CMD;
+ do {
+ L2_CMD_RDY();
+ L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
+ cmd += line_size;
+ p_start += line_size;
+ } while (p_end > p_start);
+ cmd = CCTL_CMD_L2_SYNC;
+ L2_CMD_RDY();
+ L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
+ L2_CMD_RDY();
+
+}
+#endif
+
+void n13_dma_inval_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+ unsigned long old_start = start;
+ unsigned long old_end = end;
+ unsigned long flags;
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = start & (~(line_size - 1));
+ end = (end + line_size - 1) & (~(line_size - 1));
+ if (unlikely(start == end))
+ return;
+ local_irq_save(flags);
+ if (start != old_start) {
+ n13_dcache_wbinval_range(start, start + line_size);
+#ifdef CONFIG_CACHE_L2
+ if (atl2c_base)
+ n13_l2dcache_wbinval_range(start, start + line_size);
+#endif
+ }
+ if (end != old_end) {
+ n13_dcache_wbinval_range(end - line_size, end);
+#ifdef CONFIG_CACHE_L2
+ if (atl2c_base)
+ n13_l2dcache_wbinval_range(end - line_size, end);
+#endif
+ }
+ n13_dcache_inval_range(start, end);
+#ifdef CONFIG_CACHE_L2
+ if (atl2c_base) {
+ unsigned long p_start = __pa(start);
+ unsigned long p_end = __pa(end);
+ unsigned long cmd;
+ /* TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE */
+ line_size = L2_CACHE_LINE_SIZE();
+ p_start = p_start & (~(line_size - 1));
+ p_end = (p_end + line_size - 1) & (~(line_size - 1));
+ cmd =
+ (p_start & ~(line_size - 1)) | CCTL_CMD_L2_PA_INVAL |
+ CCTL_SINGLE_CMD;
+ do {
+ L2_CMD_RDY();
+ L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
+ cmd += line_size;
+ p_start += line_size;
+ } while (p_end > p_start);
+ cmd = CCTL_CMD_L2_SYNC;
+ L2_CMD_RDY();
+ L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
+ L2_CMD_RDY();
+ }
+#endif
+ local_irq_restore(flags);
+
+}
+
+void n13_dma_wbinval_range(unsigned long start, unsigned long end)
+{
+ unsigned long line_size;
+ unsigned long flags;
+ line_size = L1_cache_info[DCACHE].line_size;
+ start = start & (~(line_size - 1));
+ end = (end + line_size - 1) & (~(line_size - 1));
+ if (unlikely(start == end))
+ return;
+
+ local_irq_save(flags);
+ n13_dcache_wbinval_range(start, end);
+#ifdef CONFIG_CACHE_L2
+ if (atl2c_base) {
+ unsigned long p_start = __pa(start);
+ unsigned long p_end = __pa(end);
+ unsigned long cmd;
+
+ /* TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE */
+ line_size = L2_CACHE_LINE_SIZE();
+ p_start = p_start & (~(line_size - 1));
+ p_end = (p_end + line_size - 1) & (~(line_size - 1));
+ cmd =
+ (p_start & ~(line_size - 1)) | CCTL_CMD_L2_PA_WBINVAL |
+ CCTL_SINGLE_CMD;
+ do {
+ L2_CMD_RDY();
+ L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
+ cmd += line_size;
+ p_start += line_size;
+ } while (p_end > p_start);
+ cmd = CCTL_CMD_L2_SYNC;
+ L2_CMD_RDY();
+ L2C_W_REG(L2_CCTL_CMD_OFF, cmd);
+ L2_CMD_RDY();
+
+ }
+#endif
+ local_irq_restore(flags);
+}
+
+void n13_proc_init(void)
+{
+}
+
+void n13_proc_fin(void)
+{
+}
+
+void n13_do_idle(void)
+{
+ __nds32__standby_no_wake_grant();
+}
+
+void n13_reset(unsigned long reset)
+{
+ u32 tmp;
+ GIE_DISABLE();
+ tmp = __nds32__mfsr(NDS32_SR_CACHE_CTL);
+ tmp &= ~(CACHE_CTL_mskIC_EN | CACHE_CTL_mskDC_EN);
+ __nds32__mtsr_isb(tmp, NDS32_SR_CACHE_CTL);
+ n13_dcache_wbinval_all();
+ n13_icache_inval_all();
+
+ __asm__ __volatile__("jr.toff %0\n\t"::"r"(reset));
+}
+
+void n13_switch_mm(struct mm_struct *mm)
+{
+ unsigned long cid;
+ cid = __nds32__mfsr(NDS32_SR_TLB_MISC);
+ cid = (cid & ~TLB_MISC_mskCID) | mm->context.id;
+ __nds32__mtsr_dsb(cid, NDS32_SR_TLB_MISC);
+ __nds32__mtsr_isb(__pa(mm->pgd), NDS32_SR_L1_PPTB);
+}
diff --git a/arch/nds32/mm/tlb.c b/arch/nds32/mm/tlb.c
new file mode 100644
index 0000000..b397b9f
--- /dev/null
+++ b/arch/nds32/mm/tlb.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/spinlock_types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/nds32.h>
+#include <nds32_intrinsic.h>
+
+unsigned int cpu_last_cid = { TLB_MISC_mskCID + (2 << TLB_MISC_offCID) };
+
+DEFINE_SPINLOCK(cid_lock);
+
+void local_flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ unsigned long flags, ocid, ncid;
+
+ if ((end - start) > 0x400000) {
+ __nds32__tlbop_flua();
+ __nds32__isb();
+ return;
+ }
+
+ spin_lock_irqsave(&cid_lock, flags);
+ ocid = __nds32__mfsr(NDS32_SR_TLB_MISC);
+ ncid = (ocid & ~TLB_MISC_mskCID) | vma->vm_mm->context.id;
+ __nds32__mtsr_dsb(ncid, NDS32_SR_TLB_MISC);
+ while (start < end) {
+ __nds32__tlbop_inv(start);
+ __nds32__isb();
+ start += PAGE_SIZE;
+ }
+ __nds32__mtsr_dsb(ocid, NDS32_SR_TLB_MISC);
+ spin_unlock_irqrestore(&cid_lock, flags);
+}
+
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+{
+ unsigned long flags, ocid, ncid;
+
+ spin_lock_irqsave(&cid_lock, flags);
+ ocid = __nds32__mfsr(NDS32_SR_TLB_MISC);
+ ncid = (ocid & ~TLB_MISC_mskCID) | vma->vm_mm->context.id;
+ __nds32__mtsr_dsb(ncid, NDS32_SR_TLB_MISC);
+ __nds32__tlbop_inv(addr);
+ __nds32__isb();
+ __nds32__mtsr_dsb(ocid, NDS32_SR_TLB_MISC);
+ spin_unlock_irqrestore(&cid_lock, flags);
+}
--
1.7.9.5
From 1583463794913115681@xxx Wed Nov 08 02:39:12 +0000 2017
X-GM-THRID: 1582421812199623158
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/asm/current.h | 25 ++++
arch/nds32/include/asm/processor.h | 116 ++++++++++++++++++
arch/nds32/include/asm/thread_info.h | 91 ++++++++++++++
arch/nds32/kernel/process.c | 219 ++++++++++++++++++++++++++++++++++
4 files changed, 451 insertions(+)
create mode 100644 arch/nds32/include/asm/current.h
create mode 100644 arch/nds32/include/asm/processor.h
create mode 100644 arch/nds32/include/asm/thread_info.h
create mode 100644 arch/nds32/kernel/process.c
diff --git a/arch/nds32/include/asm/current.h b/arch/nds32/include/asm/current.h
new file mode 100644
index 0000000..027f7df
--- /dev/null
+++ b/arch/nds32/include/asm/current.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_NDS32_CURRENT_H
+#define _ASM_NDS32_CURRENT_H
+
+#ifndef __ASSEMBLY__
+register struct task_struct *current asm("$r25");
+#endif /* __ASSEMBLY__ */
+#define tsk $r25
+
+#endif /* _ASM_NDS32_CURRENT_H */
diff --git a/arch/nds32/include/asm/processor.h b/arch/nds32/include/asm/processor.h
new file mode 100644
index 0000000..03dab61
--- /dev/null
+++ b/arch/nds32/include/asm/processor.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_NDS32_PROCESSOR_H
+#define __ASM_NDS32_PROCESSOR_H
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
+#ifdef __KERNEL__
+
+#include <asm/ptrace.h>
+#include <asm/types.h>
+#include <asm/sigcontext.h>
+
+#define KERNEL_STACK_SIZE PAGE_SIZE
+#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX TASK_SIZE
+
+struct cpu_context {
+ unsigned long r6;
+ unsigned long r7;
+ unsigned long r8;
+ unsigned long r9;
+ unsigned long r10;
+ unsigned long r11;
+ unsigned long r12;
+ unsigned long r13;
+ unsigned long r14;
+ unsigned long fp;
+ unsigned long pc;
+ unsigned long sp;
+};
+
+struct thread_struct {
+ struct cpu_context cpu_context; /* cpu context */
+ /* fault info */
+ unsigned long address;
+ unsigned long trap_no;
+ unsigned long error_code;
+};
+
+#define INIT_THREAD { }
+
+#ifdef __NDS32_EB__
+#define PSW_DE PSW_mskBE
+#else
+#define PSW_DE 0x0
+#endif
+
+#ifdef CONFIG_WBNA
+#define PSW_valWBNA PSW_mskWBNA
+#else
+#define PSW_valWBNA 0x0
+#endif
+
+#ifdef CONFIG_HWZOL
+#define PSW_valINIT (PSW_CPL_ANY | PSW_mskAEN | PSW_valWBNA | PSW_mskDT | PSW_mskIT | PSW_DE | PSW_mskGIE)
+#else
+#define PSW_valINIT (PSW_CPL_ANY | PSW_valWBNA | PSW_mskDT | PSW_mskIT | PSW_DE | PSW_mskGIE)
+#endif
+
+#define start_thread(regs,pc,stack) \
+({ \
+ set_fs(USER_DS); \
+ memzero(regs, sizeof(struct pt_regs)); \
+ regs->ipsw = PSW_valINIT; \
+ regs->ir0 = (PSW_CPL_ANY | PSW_valWBNA | PSW_mskDT | PSW_mskIT | PSW_DE | PSW_SYSTEM | PSW_INTL_1); \
+ regs->ipc = pc; \
+ regs->sp = stack; \
+})
+
+/* Forward declaration, a strange C thing */
+struct task_struct;
+
+/* Free all resources held by a thread. */
+#define release_thread(thread) do { } while(0)
+
+/* Prepare to copy thread state - unlazy all lazy status */
+#define prepare_to_copy(tsk) do { } while (0)
+
+unsigned long get_wchan(struct task_struct *p);
+
+#define cpu_relax() barrier()
+
+#define task_pt_regs(task) \
+ ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE \
+ - 8) - 1)
+
+/*
+ * Create a new kernel thread
+ */
+extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags);
+
+#define KSTK_EIP(tsk) instruction_pointer(task_pt_regs(tsk))
+#define KSTK_ESP(tsk) user_stack_pointer(task_pt_regs(tsk))
+
+#endif
+
+#endif /* __ASM_NDS32_PROCESSOR_H */
diff --git a/arch/nds32/include/asm/thread_info.h b/arch/nds32/include/asm/thread_info.h
new file mode 100644
index 0000000..216cc85
--- /dev/null
+++ b/arch/nds32/include/asm/thread_info.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_NDS32_THREAD_INFO_H
+#define __ASM_NDS32_THREAD_INFO_H
+
+#ifdef __KERNEL__
+
+#define THREAD_SIZE_ORDER (1)
+#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
+
+#ifndef __ASSEMBLY__
+
+struct task_struct;
+
+#include <asm/ptrace.h>
+#include <asm/types.h>
+
+typedef unsigned long mm_segment_t;
+
+/*
+ * low level task data that entry.S needs immediate access to.
+ * __switch_to() assumes cpu_context follows immediately after cpu_domain.
+ */
+struct thread_info {
+ unsigned long flags; /* low level flags */
+ __s32 preempt_count; /* 0 => preemptable, <0 => bug */
+ mm_segment_t addr_limit; /* address limit */
+};
+#define INIT_THREAD_INFO(tsk) \
+{ \
+ .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)
+#define thread_saved_pc(tsk) ((unsigned long)(tsk->thread.cpu_context.pc))
+#define thread_saved_fp(tsk) ((unsigned long)(tsk->thread.cpu_context.fp))
+#endif
+
+/*
+ * thread information flags:
+ * TIF_SYSCALL_TRACE - syscall trace active
+ * TIF_SIGPENDING - signal pending
+ * TIF_NEED_RESCHED - rescheduling necessary
+ * TIF_NOTIFY_RESUME - callback before returning to user
+ * TIF_USEDFPU - FPU was used by this task this quantum (SMP)
+ * TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED
+ */
+#define TIF_SIGPENDING 1
+#define TIF_NEED_RESCHED 2
+#define TIF_SINGLESTEP 3
+#define TIF_NOTIFY_RESUME 4 /* callback before returning to user */
+#define TIF_SYSCALL_TRACE 8
+#define TIF_USEDFPU 16
+#define TIF_POLLING_NRFLAG 17
+#define TIF_MEMDIE 18
+#define TIF_FREEZE 19
+#define TIF_RESTORE_SIGMASK 20
+
+#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
+#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
+#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
+#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
+#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
+#define _TIF_FREEZE (1 << TIF_FREEZE)
+#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
+
+/*
+ * Change these and you break ASM code in entry-common.S
+ */
+#define _TIF_WORK_MASK 0x000000ff
+#define _TIF_WORK_SYSCALL_ENTRY (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP)
+#define _TIF_WORK_SYSCALL_LEAVE (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP)
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_NDS32_THREAD_INFO_H */
diff --git a/arch/nds32/kernel/process.c b/arch/nds32/kernel/process.c
new file mode 100644
index 0000000..0cbef3f
--- /dev/null
+++ b/arch/nds32/kernel/process.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/sched.h>
+#include <linux/sched/debug.h>
+#include <linux/sched/task_stack.h>
+#include <linux/delay.h>
+#include <linux/kallsyms.h>
+#include <asm/uaccess.h>
+#include <asm/elf.h>
+#include <asm/proc-fns.h>
+#include <linux/ptrace.h>
+
+extern void setup_mm_for_reboot(char mode);
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_dir_cpu;
+EXPORT_SYMBOL(proc_dir_cpu);
+#endif
+
+extern inline void arch_reset(char mode)
+{
+ if (mode == 's') {
+ /* Use cpu handler, jump to 0 */
+ cpu_reset(0);
+ }
+}
+
+void (*pm_power_off) (void);
+EXPORT_SYMBOL(pm_power_off);
+
+static char reboot_mode = 'h';
+
+int __init reboot_setup(char *str)
+{
+ reboot_mode = str[0];
+ return 1;
+}
+
+static int cpub_pwroff(void)
+{
+ return 0;
+}
+
+__setup("reboot=", reboot_setup);
+
+void machine_halt(void)
+{
+ cpub_pwroff();
+}
+
+EXPORT_SYMBOL(machine_halt);
+
+void machine_power_off(void)
+{
+ if (pm_power_off)
+ pm_power_off();
+}
+
+EXPORT_SYMBOL(machine_power_off);
+
+void machine_restart(char *__unused)
+{
+ /*
+ * Clean and disable cache, and turn off interrupts
+ */
+ cpu_proc_fin();
+
+ /*
+ * Tell the mm system that we are going to reboot -
+ * we may need it to insert some 1:1 mappings so that
+ * soft boot works.
+ */
+ setup_mm_for_reboot(reboot_mode);
+
+ /*
+ * Now call the architecture specific reboot code.
+ */
+ arch_reset(reboot_mode);
+
+ /*
+ * Whoops - the architecture was unable to reboot.
+ * Tell the user!
+ */
+ mdelay(1000);
+ pr_info("Reboot failed -- System halted\n");
+ while (1) ;
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+void show_regs(struct pt_regs *regs)
+{
+ print_symbol("PC is at %s\n", instruction_pointer(regs));
+ print_symbol("LP is at %s\n", regs->lp);
+ pr_info("pc : [<%08lx>] lp : [<%08lx>] %s\n"
+ "sp : %08lx fp : %08lx gp : %08lx\n",
+ instruction_pointer(regs),
+ regs->lp, print_tainted(), regs->sp, regs->fp, regs->gp);
+ pr_info("r25: %08lx r24: %08lx\n", regs->uregs[25], regs->uregs[24]);
+
+ pr_info("r23: %08lx r22: %08lx r21: %08lx r20: %08lx\n",
+ regs->uregs[23], regs->uregs[22],
+ regs->uregs[21], regs->uregs[20]);
+ pr_info("r19: %08lx r18: %08lx r17: %08lx r16: %08lx\n",
+ regs->uregs[19], regs->uregs[18],
+ regs->uregs[17], regs->uregs[16]);
+ pr_info("r15: %08lx r14: %08lx r13: %08lx r12: %08lx\n",
+ regs->uregs[15], regs->uregs[14],
+ regs->uregs[13], regs->uregs[12]);
+ pr_info("r11: %08lx r10: %08lx r9 : %08lx r8 : %08lx\n",
+ regs->uregs[11], regs->uregs[10],
+ regs->uregs[9], regs->uregs[8]);
+ pr_info("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
+ regs->uregs[7], regs->uregs[6], regs->uregs[5], regs->uregs[4]);
+ pr_info("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
+ regs->uregs[3], regs->uregs[2], regs->uregs[1], regs->uregs[0]);
+ pr_info(" IRQs o%s Segment %s\n",
+ interrupts_enabled(regs) ? "n" : "ff",
+ segment_eq(get_fs(), get_ds())? "kernel" : "user");
+}
+
+EXPORT_SYMBOL(show_regs);
+
+void flush_thread(void)
+{
+}
+
+DEFINE_PER_CPU(struct task_struct *, __entry_task);
+
+asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+int copy_thread(unsigned long clone_flags, unsigned long stack_start,
+ unsigned long stk_sz, struct task_struct *p)
+{
+ struct pt_regs *childregs = task_pt_regs(p);
+
+ memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
+
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ memset(childregs, 0, sizeof(struct pt_regs));
+ /* kernel thread fn */
+ p->thread.cpu_context.r6 = stack_start;
+ /* kernel thread argument */
+ p->thread.cpu_context.r7 = stk_sz;
+ } else {
+ *childregs = *current_pt_regs();
+ if (stack_start)
+ childregs->sp = stack_start;
+ /* child get zero as ret. */
+ childregs->uregs[0] = 0;
+ childregs->osp = 0;
+ if (clone_flags & CLONE_SETTLS)
+ childregs->uregs[25] = childregs->uregs[3];
+ }
+ /* cpu context switching */
+ p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
+ p->thread.cpu_context.sp = (unsigned long)childregs;
+
+#ifdef CONFIG_HWZOL
+ childregs->lb = 0;
+ childregs->le = 0;
+ childregs->lc = 0;
+#endif
+
+ return 0;
+}
+
+/*
+ * fill in the fpe structure for a core dump...
+ */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpu)
+{
+ int fpvalid = 0;
+ return fpvalid;
+}
+
+EXPORT_SYMBOL(dump_fpu);
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long fp, lr;
+ unsigned long stack_start, stack_end;
+ int count = 0;
+
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+
+#ifdef CONFIG_FRAME_POINTER
+ stack_start = (unsigned long)end_of_stack(p);
+ stack_end = (unsigned long)task_stack_page(p) + THREAD_SIZE;
+
+ fp = thread_saved_fp(p);
+ do {
+ if (fp < stack_start || fp > stack_end)
+ return 0;
+ lr = ((unsigned long *)fp)[0];
+ if (!in_sched_functions(lr))
+ return lr;
+ fp = *(unsigned long *)(fp + 4);
+ } while (count++ < 16);
+ return 0;
+#else
+ return 0;
+#endif
+}
+
+EXPORT_SYMBOL(get_wchan);
--
1.7.9.5
From 1583394175471011055@xxx Tue Nov 07 08:12:37 +0000 2017
X-GM-THRID: 1583394175471011055
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/asm/assembler.h | 52 ++
arch/nds32/include/asm/bitfield.h | 982 ++++++++++++++++++++++++++++++++++++
arch/nds32/include/asm/nds32.h | 92 ++++
arch/nds32/kernel/asm-offsets.c | 40 ++
4 files changed, 1166 insertions(+)
create mode 100644 arch/nds32/include/asm/assembler.h
create mode 100644 arch/nds32/include/asm/bitfield.h
create mode 100644 arch/nds32/include/asm/nds32.h
create mode 100644 arch/nds32/kernel/asm-offsets.c
diff --git a/arch/nds32/include/asm/assembler.h b/arch/nds32/include/asm/assembler.h
new file mode 100644
index 0000000..d469af0
--- /dev/null
+++ b/arch/nds32/include/asm/assembler.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 __NDS32_ASSEMBLER_H__
+#define __NDS32_ASSEMBLER_H__
+
+.macro gie_disable
+ setgie.d
+ dsb
+.endm
+
+.macro gie_enable
+ setgie.e
+ dsb
+.endm
+
+.macro gie_save oldpsw
+ mfsr \oldpsw, $ir0
+ setgie.d
+ dsb
+.endm
+
+.macro gie_restore oldpsw
+ andi \oldpsw, \oldpsw, #0x1
+ beqz \oldpsw, 7001f
+ setgie.e
+ dsb
+7001:
+.endm
+
+
+#define USER(insn, reg, addr, opr) \
+9999: insn reg, addr, opr; \
+ .section __ex_table,"a"; \
+ .align 3; \
+ .long 9999b, 9001f; \
+ .previous
+
+#endif /* __NDS32_ASSEMBLER_H__ */
diff --git a/arch/nds32/include/asm/bitfield.h b/arch/nds32/include/asm/bitfield.h
new file mode 100644
index 0000000..bb032ce
--- /dev/null
+++ b/arch/nds32/include/asm/bitfield.h
@@ -0,0 +1,982 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 __NDS32_BITFIELD_H__
+#define __NDS32_BITFIELD_H__
+/******************************************************************************
+ * cr0: CPU_VER (CPU Version Register)
+ *****************************************************************************/
+#define CPU_VER_offCFGID 0 /* Minor configuration */
+#define CPU_VER_offREV 16 /* Revision of the CPU version */
+#define CPU_VER_offCPUID 24 /* Major CPU versions */
+
+#define CPU_VER_mskCFGID ( 0xFFFF << CPU_VER_offCFGID )
+#define CPU_VER_mskREV ( 0xFF << CPU_VER_offREV )
+#define CPU_VER_mskCPUID ( 0xFF << CPU_VER_offCPUID )
+
+/******************************************************************************
+ * cr1: ICM_CFG (Instruction Cache/Memory Configuration Register)
+ *****************************************************************************/
+#define ICM_CFG_offISET 0 /* I-cache sets (# of cache lines) per way */
+#define ICM_CFG_offIWAY 3 /* I-cache ways */
+#define ICM_CFG_offISZ 6 /* I-cache line size */
+#define ICM_CFG_offILCK 9 /* I-cache locking support */
+#define ICM_CFG_offILMB 10 /* On-chip ILM banks */
+#define ICM_CFG_offBSAV 13 /* ILM base register alignment version */
+/* bit 15:31 reserved */
+
+#define ICM_CFG_mskISET ( 0x7 << ICM_CFG_offISET )
+#define ICM_CFG_mskIWAY ( 0x7 << ICM_CFG_offIWAY )
+#define ICM_CFG_mskISZ ( 0x7 << ICM_CFG_offISZ )
+#define ICM_CFG_mskILCK ( 0x1 << ICM_CFG_offILCK )
+#define ICM_CFG_mskILMB ( 0x7 << ICM_CFG_offILMB )
+#define ICM_CFG_mskBSAV ( 0x3 << ICM_CFG_offBSAV )
+
+/******************************************************************************
+ * cr2: DCM_CFG (Data Cache/Memory Configuration Register)
+ *****************************************************************************/
+#define DCM_CFG_offDSET 0 /* D-cache sets (# of cache lines) per way */
+#define DCM_CFG_offDWAY 3 /* D-cache ways */
+#define DCM_CFG_offDSZ 6 /* D-cache line size */
+#define DCM_CFG_offDLCK 9 /* D-cache locking support */
+#define DCM_CFG_offDLMB 10 /* On-chip DLM banks */
+#define DCM_CFG_offBSAV 13 /* DLM base register alignment version */
+/* bit 15:31 reserved */
+
+#define DCM_CFG_mskDSET ( 0x7 << DCM_CFG_offDSET )
+#define DCM_CFG_mskDWAY ( 0x7 << DCM_CFG_offDWAY )
+#define DCM_CFG_mskDSZ ( 0x7 << DCM_CFG_offDSZ )
+#define DCM_CFG_mskDLCK ( 0x1 << DCM_CFG_offDLCK )
+#define DCM_CFG_mskDLMB ( 0x7 << DCM_CFG_offDLMB )
+#define DCM_CFG_mskBSAV ( 0x3 << DCM_CFG_offBSAV )
+
+/******************************************************************************
+ * cr3: MMU_CFG (MMU Configuration Register)
+ *****************************************************************************/
+#define MMU_CFG_offMMPS 0 /* Memory management protection scheme */
+#define MMU_CFG_offMMPV 2 /* Memory management protection version number */
+#define MMU_CFG_offFATB 7 /* Fully-associative or non-fully-associative TLB */
+
+#ifdef CONFIG_FULL_ASSOC
+#define MMU_CFG_offFATBSZ 8 /* TLB entries while using full-associative TLB */
+#else
+#define MMU_CFG_offTBW 8 /* TLB ways(non-associative) TBS */
+#define MMU_CFG_offTBS 11 /* TLB sets per way(non-associative) TBS */
+/* bit 14:14 reserved */
+#endif
+
+#define MMU_CFG_offEP8MIN4 15 /* 8KB page supported while minimum page is 4KB */
+#define MMU_CFG_offfEPSZ 16 /* Extra page size supported */
+#define MMU_CFG_offTLBLCK 24 /* TLB locking support */
+#define MMU_CFG_offHPTWK 25 /* Hardware Page Table Walker implemented */
+#define MMU_CFG_offDE 26 /* Default endian */
+#define MMU_CFG_offNTPT 27 /* Partitions for non-translated attributes */
+#define MMU_CFG_offIVTB 28 /* Invisible TLB */
+#define MMU_CFG_offVLPT 29 /* VLPT for fast TLB fill handling implemented */
+#define MMU_CFG_offNTME 30 /* Non-translated VA to PA mapping */
+/* bit 31 reserved */
+
+#define MMU_CFG_mskMMPS ( 0x3 << MMU_CFG_offMMPS )
+#define MMU_CFG_mskMMPV ( 0x1F << MMU_CFG_offMMPV )
+#define MMU_CFG_mskFATB ( 0x1 << MMU_CFG_offFATB )
+#ifdef CONFIG_FULL_ASSOC
+#define MMU_CFG_mskFATBSZ ( 0x7f << MMU_CFG_offFATBSZ )
+#else
+#define MMU_CFG_mskTBW ( 0x7 << MMU_CFG_offTBW )
+#define MMU_CFG_mskTBS ( 0x7 << MMU_CFG_offTBS )
+#endif
+#define MMU_CFG_mskEP8MIN4 ( 0x1 << MMU_CFG_offEP8MIN4 )
+#define MMU_CFG_mskfEPSZ ( 0xFF << MMU_CFG_offfEPSZ )
+#define MMU_CFG_mskTLBLCK ( 0x1 << MMU_CFG_offTLBLCK )
+#define MMU_CFG_mskHPTWK ( 0x1 << MMU_CFG_offHPTWK )
+#define MMU_CFG_mskDE ( 0x1 << MMU_CFG_offDE )
+#define MMU_CFG_mskNTPT ( 0x1 << MMU_CFG_offNTPT )
+#define MMU_CFG_mskIVTB ( 0x1 << MMU_CFG_offIVTB )
+#define MMU_CFG_mskVLPT ( 0x1 << MMU_CFG_offVLPT )
+#define MMU_CFG_mskNTME ( 0x1 << MMU_CFG_offNTME )
+
+/******************************************************************************
+ * cr4: MSC_CFG (Misc Configuration Register)
+ *****************************************************************************/
+#define MSC_CFG_offEDM 0
+#define MSC_CFG_offLMDMA 1
+#define MSC_CFG_offPFM 2
+#define MSC_CFG_offHSMP 3
+#define MSC_CFG_offTRACE 4
+#define MSC_CFG_offDIV 5
+#define MSC_CFG_offMAC 6
+#define MSC_CFG_offAUDIO 7
+#define MSC_CFG_offL2C 9
+#define MSC_CFG_offRDREG 10
+#define MSC_CFG_offADR24 11
+#define MSC_CFG_offINTLC 12
+#define MSC_CFG_offBASEV 13
+#define MSC_CFG_offNOD 16
+/* bit 13:31 reserved */
+
+#define MSC_CFG_mskEDM ( 0x1 << MSC_CFG_offEDM )
+#define MSC_CFG_mskLMDMA ( 0x1 << MSC_CFG_offLMDMA )
+#define MSC_CFG_mskPFM ( 0x1 << MSC_CFG_offPFM )
+#define MSC_CFG_mskHSMP ( 0x1 << MSC_CFG_offHSMP )
+#define MSC_CFG_mskTRACE ( 0x1 << MSC_CFG_offTRACE )
+#define MSC_CFG_mskDIV ( 0x1 << MSC_CFG_offDIV )
+#define MSC_CFG_mskMAC ( 0x1 << MSC_CFG_offMAC )
+#define MSC_CFG_mskAUDIO ( 0x3 << MSC_CFG_offAUDIO )
+#define MSC_CFG_mskL2C ( 0x1 << MSC_CFG_offL2C )
+#define MSC_CFG_mskRDREG ( 0x1 << MSC_CFG_offRDREG )
+#define MSC_CFG_mskADR24 ( 0x1 << MSC_CFG_offADR24 )
+#define MSC_CFG_mskINTLC ( 0x1 << MSC_CFG_offINTLC )
+#define MSC_CFG_mskBASEV ( 0x7 << MSC_CFG_offBASEV )
+#define MSC_CFG_mskNOD ( 0x1 << MSC_CFG_offNOD )
+
+/******************************************************************************
+ * cr5: CORE_CFG (Core Identification Register)
+ *****************************************************************************/
+#define CORE_ID_offCOREID 0
+/* bit 4:31 reserved */
+
+#define CORE_ID_mskCOREID ( 0xF << CORE_ID_offCOREID )
+
+/******************************************************************************
+ * cr6: FUCOP_EXIST (FPU and Coprocessor Existence Configuration Register)
+ *****************************************************************************/
+#define FUCOP_EXIST_offCP0EX 0
+#define FUCOP_EXIST_offCP1EX 1
+#define FUCOP_EXIST_offCP2EX 2
+#define FUCOP_EXIST_offCP3EX 3
+#define FUCOP_EXIST_offCP0ISFPU 31
+
+#define FUCOP_EXIST_mskCP0EX ( 0x1 << FUCOP_EXIST_offCP0EX )
+#define FUCOP_EXIST_mskCP1EX ( 0x1 << FUCOP_EXIST_offCP1EX )
+#define FUCOP_EXIST_mskCP2EX ( 0x1 << FUCOP_EXIST_offCP2EX )
+#define FUCOP_EXIST_mskCP3EX ( 0x1 << FUCOP_EXIST_offCP3EX )
+#define FUCOP_EXIST_mskCP0ISFPU ( 0x1 << FUCOP_EXIST_offCP0ISFPU )
+
+/******************************************************************************
+ * ir0: PSW (Processor Status Word Register)
+ * ir1: IPSW (Interruption PSW Register)
+ * ir2: P_IPSW (Previous IPSW Register)
+ *****************************************************************************/
+#define PSW_offGIE 0 /* Global Interrupt Enable */
+#define PSW_offINTL 1 /* Interruption Stack Level */
+#define PSW_offPOM 3 /* Processor Operation Mode, User/Superuser */
+#define PSW_offBE 5 /* Endianness for data memory access, 1:MSB, 0:LSB */
+#define PSW_offIT 6 /* Enable instruction address translation */
+#define PSW_offDT 7 /* Enable data address translation */
+#define PSW_offIME 8 /* Instruction Machine Error flag */
+#define PSW_offDME 9 /* Data Machine Error flag */
+#define PSW_offDEX 10 /* Debug Exception */
+#define PSW_offHSS 11 /* Hardware Single Stepping */
+#define PSW_offDRBE 12 /* Device Register Endian Mode */
+#define PSW_offAEN 13 /* Audio ISA special feature */
+#define PSW_offWBNA 14 /* Write Back Non-Allocate */
+#define PSW_offIFCON 15 /* IFC On */
+#define PSW_offCPL 16 /* Current Priority Level */
+/* bit 19:31 reserved */
+
+#define PSW_mskGIE ( 0x1 << PSW_offGIE )
+#define PSW_mskINTL ( 0x3 << PSW_offINTL )
+#define PSW_mskPOM ( 0x3 << PSW_offPOM )
+#define PSW_mskBE ( 0x1 << PSW_offBE )
+#define PSW_mskIT ( 0x1 << PSW_offIT )
+#define PSW_mskDT ( 0x1 << PSW_offDT )
+#define PSW_mskIME ( 0x1 << PSW_offIME )
+#define PSW_mskDME ( 0x1 << PSW_offDME )
+#define PSW_mskDEX ( 0x1 << PSW_offDEX )
+#define PSW_mskHSS ( 0x1 << PSW_offHSS )
+#define PSW_mskDRBE ( 0x1 << PSW_offDRBE )
+#define PSW_mskAEN ( 0x1 << PSW_offAEN )
+#define PSW_mskWBNA ( 0x1 << PSW_offWBNA )
+#define PSW_mskIFCON ( 0x1 << PSW_offIFCON )
+#define PSW_mskCPL ( 0x7 << PSW_offCPL )
+
+#define PSW_SYSTEM ( 1 << PSW_offPOM )
+#define PSW_INTL_1 ( 1 << PSW_offINTL )
+#define PSW_CPL_NO ( 0 << PSW_offCPL )
+#define PSW_CPL_ANY ( 7 << PSW_offCPL )
+
+#define PSW_clr (PSW_mskGIE|PSW_mskINTL|PSW_mskPOM|PSW_mskIT|PSW_mskDT|PSW_mskIME|PSW_mskWBNA)
+#ifdef __NDS32_EB__
+#ifdef CONFIG_WBNA
+#define PSW_init (PSW_mskWBNA|(1<<PSW_offINTL)|(1<<PSW_offPOM)|PSW_mskIT|PSW_mskDT|PSW_mskBE)
+#else
+#define PSW_init ((1<<PSW_offINTL)|(1<<PSW_offPOM)|PSW_mskIT|PSW_mskDT|PSW_mskBE)
+#endif
+#else
+#ifdef CONFIG_WBNA
+#define PSW_init (PSW_mskWBNA|(1<<PSW_offINTL)|(1<<PSW_offPOM)|PSW_mskIT|PSW_mskDT)
+#else
+#define PSW_init ((1<<PSW_offINTL)|(1<<PSW_offPOM)|PSW_mskIT|PSW_mskDT)
+#endif
+#endif
+/******************************************************************************
+ * ir3: IVB (Interruption Vector Base Register)
+ *****************************************************************************/
+/* bit 0:12 reserved */
+#define IVB_offNIVIC 1 /* Number of input for IVIC Controller */
+#define IVB_offIVIC_VER 11 /* IVIC Version */
+#define IVB_offEVIC 13 /* External Vector Interrupt Controller mode */
+#define IVB_offESZ 14 /* Size of each vector entry */
+#define IVB_offIVBASE 16 /* BasePA of interrupt vector table */
+
+#define IVB_mskNIVIC ( 0x7 << IVB_offNIVIC )
+#define IVB_mskIVIC_VER ( 0x3 << IVB_offIVIC_VER )
+#define IVB_mskEVIC ( 0x1 << IVB_offEVIC )
+#define IVB_mskESZ ( 0x3 << IVB_offESZ )
+#define IVB_mskIVBASE ( 0xFFFF << IVB_offIVBASE )
+
+#define IVB_valESZ4 0
+#define IVB_valESZ16 1
+#define IVB_valESZ64 2
+#define IVB_valESZ256 3
+/******************************************************************************
+ * ir4: EVA (Exception Virtual Address Register)
+ * ir5: P_EVA (Previous EVA Register)
+ *****************************************************************************/
+
+ /* This register contains the VA that causes the exception */
+
+/******************************************************************************
+ * ir6: ITYPE (Interruption Type Register)
+ * ir7: P_ITYPE (Previous ITYPE Register)
+ *****************************************************************************/
+#define ITYPE_offETYPE 0 /* Exception Type */
+#define ITYPE_offINST 4 /* Exception caused by insn fetch or data access */
+/* bit 5:15 reserved */
+#define ITYPE_offVECTOR 5 /* Vector */
+#define ITYPE_offSWID 16 /* SWID of debugging exception */
+/* bit 31:31 reserved */
+
+#define ITYPE_mskETYPE ( 0xF << ITYPE_offETYPE )
+#define ITYPE_mskINST ( 0x1 << ITYPE_offINST )
+#define ITYPE_mskVECTOR ( 0x7F << ITYPE_offVECTOR )
+#define ITYPE_mskSWID ( 0x7FFF << ITYPE_offSWID )
+
+/* Additional definitions for ITYPE register */
+#define ITYPE_offSTYPE 16 /* Arithmetic Sub Type */
+#define ITYPE_offCPID 20 /* Co-Processor ID which generate the exception */
+
+#define ITYPE_mskSTYPE ( 0xF << ITYPE_offSTYPE )
+#define ITYPE_mskCPID ( 0x3 << ITYPE_offCPID )
+
+#define NDS32_VECTOR_mskNONEXCEPTION 0x78
+#define NDS32_VECTOR_offEXCEPTION 8
+#define NDS32_VECTOR_offINTERRUPT 9
+
+/* Interrupt vector entry */
+#define ENTRY_RESET_NMI 0
+#define ENTRY_TLB_FILL 1
+#define ENTRY_PTE_NOT_PRESENT 2
+#define ENTRY_TLB_MISC 3
+#define ENTRY_TLB_VLPT_MISS 4
+#define ENTRY_MACHINE_ERROR 5
+#define ENTRY_DEBUG_RELATED 6
+#define ENTRY_GENERAL_EXCPETION 7
+#define ENTRY_SYSCALL 8
+
+/* PTE not present exception definition */
+#define ETYPE_NON_LEAF_PTE_NOT_PRESENT 0
+#define ETYPE_LEAF_PTE_NOT_PRESENT 1
+
+/* General exception ETYPE definition */
+#define ETYPE_ALIGNMENT_CHECK 0
+#define ETYPE_RESERVED_INSTRUCTION 1
+#define ETYPE_TRAP 2
+#define ETYPE_ARITHMETIC 3
+#define ETYPE_PRECISE_BUS_ERROR 4
+#define ETYPE_IMPRECISE_BUS_ERROR 5
+#define ETYPE_COPROCESSOR 6
+#define ETYPE_RESERVED_VALUE 7
+#define ETYPE_NONEXISTENT_MEM_ADDRESS 8
+#define ETYPE_MPZIU_CONTROL 9
+#define ETYPE_NEXT_PRECISE_STACK_OFL 10
+
+/* Kerenl reserves software ID */
+#define SWID_RAISE_INTERRUPT_LEVEL 0x1a /* SWID_RAISE_INTERRUPT_LEVEL is used to
+ * raise interrupt level for debug exception
+ */
+
+/******************************************************************************
+ * ir8: MERR (Machine Error Log Register)
+ *****************************************************************************/
+/* bit 0:30 reserved */
+#define MERR_offBUSERR 31 /* Bus error caused by a load insn */
+
+#define MERR_mskBUSERR ( 0x1 << MERR_offBUSERR )
+
+/******************************************************************************
+ * ir9: IPC (Interruption Program Counter Register)
+ * ir10: P_IPC (Previous IPC Register)
+ * ir11: OIPC (Overflow Interruption Program Counter Register)
+ *****************************************************************************/
+
+ /* This is the shadow stack register of the Program Counter */
+
+/******************************************************************************
+ * ir12: P_P0 (Previous P0 Register)
+ * ir13: P_P1 (Previous P1 Register)
+ *****************************************************************************/
+
+ /* These are shadow registers of $p0 and $p1 */
+
+/******************************************************************************
+ * ir14: INT_MASK (Interruption Masking Register)
+ *****************************************************************************/
+#define INT_MASK_offH0IM 0 /* Hardware Interrupt 0 Mask bit */
+#define INT_MASK_offH1IM 1 /* Hardware Interrupt 1 Mask bit */
+#define INT_MASK_offH2IM 2 /* Hardware Interrupt 2 Mask bit */
+#define INT_MASK_offH3IM 3 /* Hardware Interrupt 3 Mask bit */
+#define INT_MASK_offH4IM 4 /* Hardware Interrupt 4 Mask bit */
+#define INT_MASK_offH5IM 5 /* Hardware Interrupt 5 Mask bit */
+/* bit 6:15 reserved */
+#define INT_MASK_offSIM 16 /* Software Interrupt Mask bit */
+/* bit 17:29 reserved */
+#define INT_MASK_offIDIVZE 30 /* Enable detection for Divide-By-Zero */
+#define INT_MASK_offDSSIM 31 /* Default Single Stepping Interruption Mask */
+
+#define INT_MASK_mskH0IM ( 0x1 << INT_MASK_offH0IM )
+#define INT_MASK_mskH1IM ( 0x1 << INT_MASK_offH1IM )
+#define INT_MASK_mskH2IM ( 0x1 << INT_MASK_offH2IM )
+#define INT_MASK_mskH3IM ( 0x1 << INT_MASK_offH3IM )
+#define INT_MASK_mskH4IM ( 0x1 << INT_MASK_offH4IM )
+#define INT_MASK_mskH5IM ( 0x1 << INT_MASK_offH5IM )
+#define INT_MASK_mskSIM ( 0x1 << INT_MASK_offSIM )
+#define INT_MASK_mskIDIVZE ( 0x1 << INT_MASK_offIDIVZE )
+#define INT_MASK_mskDSSIM ( 0x1 << INT_MASK_offDSSIM )
+
+#define INT_MASK_INITAIAL_VAL 0x10003
+
+/******************************************************************************
+ * ir15: INT_PEND (Interrupt Pending Register)
+ *****************************************************************************/
+#define INT_PEND_offH0I 0 /* Hardware Interrupt 0 pending bit */
+#define INT_PEND_offH1I 1 /* Hardware Interrupt 1 pending bit */
+#define INT_PEND_offH2I 2 /* Hardware Interrupt 2 pending bit */
+#define INT_PEND_offH3I 3 /* Hardware Interrupt 3 pending bit */
+#define INT_PEND_offH4I 4 /* Hardware Interrupt 4 pending bit */
+#define INT_PEND_offH5I 5 /* Hardware Interrupt 5 pending bit */
+
+#define INT_PEND_offCIPL 0 /* Current Interrupt Priority Level */
+
+/* bit 6:15 reserved */
+#define INT_PEND_offSWI 16 /* Software Interrupt pending bit */
+/* bit 17:31 reserved */
+
+#define INT_PEND_mskH0I ( 0x1 << INT_PEND_offH0I )
+#define INT_PEND_mskH1I ( 0x1 << INT_PEND_offH1I )
+#define INT_PEND_mskH2I ( 0x1 << INT_PEND_offH2I )
+#define INT_PEND_mskH3I ( 0x1 << INT_PEND_offH3I )
+#define INT_PEND_mskH4I ( 0x1 << INT_PEND_offH4I )
+#define INT_PEND_mskH5I ( 0x1 << INT_PEND_offH5I )
+#define INT_PEND_mskCIPL ( 0x1 << INT_PEND_offCIPL )
+#define INT_PEND_mskSWI ( 0x1 << INT_PEND_offSWI )
+
+/******************************************************************************
+ * mr0: MMU_CTL (MMU Control Register)
+ *****************************************************************************/
+#define MMU_CTL_offD 0 /* Default minimum page size */
+#define MMU_CTL_offNTC0 1 /* Non-Translated Cachebility of partition 0 */
+#define MMU_CTL_offNTC1 3 /* Non-Translated Cachebility of partition 1 */
+#define MMU_CTL_offNTC2 5 /* Non-Translated Cachebility of partition 2 */
+#define MMU_CTL_offNTC3 7 /* Non-Translated Cachebility of partition 3 */
+#define MMU_CTL_offTBALCK 9 /* TLB all-lock resolution scheme */
+#define MMU_CTL_offMPZIU 10 /* Multiple Page Size In Use bit */
+#define MMU_CTL_offNTM0 11 /* Non-Translated VA to PA of partition 0 */
+#define MMU_CTL_offNTM1 13 /* Non-Translated VA to PA of partition 1 */
+#define MMU_CTL_offNTM2 15 /* Non-Translated VA to PA of partition 2 */
+#define MMU_CTL_offNTM3 17 /* Non-Translated VA to PA of partition 3 */
+/* bit 19:31 reserved */
+
+#define MMU_CTL_mskD ( 0x1 << MMU_CTL_offD )
+#define MMU_CTL_mskNTC0 ( 0x3 << MMU_CTL_offNTC0 )
+#define MMU_CTL_mskNTC1 ( 0x3 << MMU_CTL_offNTC1 )
+#define MMU_CTL_mskNTC2 ( 0x3 << MMU_CTL_offNTC2 )
+#define MMU_CTL_mskNTC3 ( 0x3 << MMU_CTL_offNTC3 )
+#define MMU_CTL_mskTBALCK ( 0x1 << MMU_CTL_offTBALCK )
+#define MMU_CTL_mskMPZIU ( 0x1 << MMU_CTL_offMPZIU )
+#define MMU_CTL_mskNTM0 ( 0x3 << MMU_CTL_offNTM0 )
+#define MMU_CTL_mskNTM1 ( 0x3 << MMU_CTL_offNTM1 )
+#define MMU_CTL_mskNTM2 ( 0x3 << MMU_CTL_offNTM2 )
+#define MMU_CTL_mskNTM3 ( 0x3 << MMU_CTL_offNTM3 )
+
+#define MMU_CTL_D4KB 0
+#define MMU_CTL_D8KB 1
+
+#define MMU_CTL_CACHEABLE_WB 2
+#define MMU_CTL_CACHEABLE_WT 3
+
+/******************************************************************************
+ * mr1: L1_PPTB (L1 Physical Page Table Base Register)
+ *****************************************************************************/
+#define L1_PPTB_offNV 0 /* Enable Hardware Page Table Walker (HPTWK) */
+/* bit 1:11 reserved */
+#define L1_PPTB_offBASE 12 /* First level physical page table base address */
+
+#define L1_PPTB_mskNV ( 0x1 << L1_PPTB_offNV )
+#define L1_PPTB_mskBASE ( 0xFFFFF << L1_PPTB_offBASE )
+
+/******************************************************************************
+ * mr2: TLB_VPN (TLB Access VPN Register)
+ *****************************************************************************/
+/* bit 0:11 reserved */
+#define TLB_VPN_offVPN 12 /* Virtual Page Number */
+
+#define TLB_VPN_mskVPN ( 0xFFFFF << TLB_VPN_offVPN )
+
+/******************************************************************************
+ * mr3: TLB_DATA (TLB Access Data Register)
+ *****************************************************************************/
+#define TLB_DATA_offV 0 /* PTE is valid and present */
+#define TLB_DATA_offM 1 /* Page read/write access privilege */
+#define TLB_DATA_offD 4 /* Dirty bit */
+#define TLB_DATA_offX 5 /* Executable bit */
+#define TLB_DATA_offA 6 /* Access bit */
+#define TLB_DATA_offG 7 /* Global page (shared across contexts) */
+#define TLB_DATA_offC 8 /* Cacheability atribute */
+/* bit 11:11 reserved */
+#define TLB_DATA_offPPN 12 /* Phisical Page Number */
+
+#define TLB_DATA_mskV ( 0x1 << TLB_DATA_offV )
+#define TLB_DATA_mskM ( 0x7 << TLB_DATA_offM )
+#define TLB_DATA_mskD ( 0x1 << TLB_DATA_offD )
+#define TLB_DATA_mskX ( 0x1 << TLB_DATA_offX )
+#define TLB_DATA_mskA ( 0x1 << TLB_DATA_offA )
+#define TLB_DATA_mskG ( 0x1 << TLB_DATA_offG )
+#define TLB_DATA_mskC ( 0x7 << TLB_DATA_offC )
+#define TLB_DATA_mskPPN ( 0xFFFFF << TLB_DATA_offPPN )
+
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+#define TLB_DATA_kernel_text_attr (TLB_DATA_mskV|TLB_DATA_mskM|TLB_DATA_mskD|TLB_DATA_mskX|TLB_DATA_mskG|TLB_DATA_mskC)
+#else
+#define TLB_DATA_kernel_text_attr (TLB_DATA_mskV|TLB_DATA_mskM|TLB_DATA_mskD|TLB_DATA_mskX|TLB_DATA_mskG|(0x6 << TLB_DATA_offC))
+#endif
+
+/******************************************************************************
+ * mr4: TLB_MISC (TLB Access Misc Register)
+ *****************************************************************************/
+#define TLB_MISC_offACC_PSZ 0 /* Page size of a PTE entry */
+#define TLB_MISC_offCID 4 /* Context id */
+/* bit 13:31 reserved */
+
+#define TLB_MISC_mskACC_PSZ ( 0xF << TLB_MISC_offACC_PSZ )
+#define TLB_MISC_mskCID ( 0x1FF << TLB_MISC_offCID )
+
+/******************************************************************************
+ * mr5: VLPT_IDX (Virtual Linear Page Table Index Register)
+ *****************************************************************************/
+#define VLPT_IDX_offZERO 0 /* Always 0 */
+#define VLPT_IDX_offEVPN 2 /* Exception Virtual Page Number */
+#define VLPT_IDX_offVLPTB 22 /* Base VA of VLPT */
+
+#define VLPT_IDX_mskZERO ( 0x3 << VLPT_IDX_offZERO )
+#define VLPT_IDX_mskEVPN ( 0xFFFFF << VLPT_IDX_offEVPN )
+#define VLPT_IDX_mskVLPTB ( 0x3FF << VLPT_IDX_offVLPTB )
+
+/******************************************************************************
+ * mr6: ILMB (Instruction Local Memory Base Register)
+ *****************************************************************************/
+#define ILMB_offIEN 0 /* Enable ILM */
+#define ILMB_offILMSZ 1 /* Size of ILM */
+/* bit 5:19 reserved */
+#define ILMB_offIBPA 20 /* Base PA of ILM */
+
+#define ILMB_mskIEN ( 0x1 << ILMB_offIEN )
+#define ILMB_mskILMSZ ( 0xF << ILMB_offILMSZ )
+#define ILMB_mskIBPA ( 0xFFF << ILMB_offIBPA )
+
+/******************************************************************************
+ * mr7: DLMB (Data Local Memory Base Register)
+ *****************************************************************************/
+#define DLMB_offDEN 0 /* Enable DLM */
+#define DLMB_offDLMSZ 1 /* Size of DLM */
+#define DLMB_offDBM 5 /* Enable Double-Buffer Mode for DLM */
+#define DLMB_offDBB 6 /* Double-buffer bank which can be accessed by the processor */
+/* bit 7:19 reserved */
+#define DLMB_offDBPA 20 /* Base PA of DLM */
+
+#define DLMB_mskDEN ( 0x1 << DLMB_offDEN )
+#define DLMB_mskDLMSZ ( 0xF << DLMB_offDLMSZ )
+#define DLMB_mskDBM ( 0x1 << DLMB_offDBM )
+#define DLMB_mskDBB ( 0x1 << DLMB_offDBB )
+#define DLMB_mskDBPA ( 0xFFF << DLMB_offDBPA )
+
+/******************************************************************************
+ * mr8: CACHE_CTL (Cache Control Register)
+ *****************************************************************************/
+#define CACHE_CTL_offIC_EN 0 /* Enable I-cache */
+#define CACHE_CTL_offDC_EN 1 /* Enable D-cache */
+#define CACHE_CTL_offICALCK 2 /* I-cache all-lock resolution scheme */
+#define CACHE_CTL_offDCALCK 3 /* D-cache all-lock resolution scheme */
+#define CACHE_CTL_offDCCWF 4 /* Enable D-cache Critical Word Forwarding */
+#define CACHE_CTL_offDCPMW 5 /* Enable D-cache concurrent miss and write-back processing */
+/* bit 6:31 reserved */
+
+#define CACHE_CTL_mskIC_EN ( 0x1 << CACHE_CTL_offIC_EN )
+#define CACHE_CTL_mskDC_EN ( 0x1 << CACHE_CTL_offDC_EN )
+#define CACHE_CTL_mskICALCK ( 0x1 << CACHE_CTL_offICALCK )
+#define CACHE_CTL_mskDCALCK ( 0x1 << CACHE_CTL_offDCALCK )
+#define CACHE_CTL_mskDCCWF ( 0x1 << CACHE_CTL_offDCCWF )
+#define CACHE_CTL_mskDCPMW ( 0x1 << CACHE_CTL_offDCPMW )
+
+/******************************************************************************
+ * mr9: HSMP_SADDR (High Speed Memory Port Starting Address)
+ *****************************************************************************/
+#define HSMP_SADDR_offEN 0 /* Enable control bit for the High Speed Memory port */
+/* bit 1:19 reserved */
+
+#define HSMP_SADDR_offRANGE 1 /* Denote the address range (only defined in HSMP v2 ) */
+#define HSMP_SADDR_offSADDR 20 /* Starting base PA of the High Speed Memory Port region */
+
+#define HSMP_SADDR_mskEN ( 0x1 << HSMP_SADDR_offEN )
+#define HSMP_SADDR_mskRANGE ( 0xFFF << HSMP_SADDR_offRANGE )
+#define HSMP_SADDR_mskSADDR ( 0xFFF << HSMP_SADDR_offSADDR )
+
+/******************************************************************************
+ * mr10: HSMP_EADDR (High Speed Memory Port Ending Address)
+ *****************************************************************************/
+/* bit 0:19 reserved */
+#define HSMP_EADDR_offEADDR 20
+
+#define HSMP_EADDR_mskEADDR ( 0xFFF << HSMP_EADDR_offEADDR )
+
+/******************************************************************************
+ * dr0+(n*5): BPCn (n=0-7) (Breakpoint Control Register)
+ *****************************************************************************/
+#define BPC_offWP 0 /* Configuration of BPAn */
+#define BPC_offEL 1 /* Enable BPAn */
+#define BPC_offS 2 /* Data address comparison for a store instruction */
+#define BPC_offP 3 /* Compared data address is PA */
+#define BPC_offC 4 /* CID value is compared with the BPCIDn register */
+#define BPC_offBE0 5 /* Enable byte mask for the comparison with register */
+#define BPC_offBE1 6 /* Enable byte mask for the comparison with register */
+#define BPC_offBE2 7 /* Enable byte mask for the comparison with register */
+#define BPC_offBE3 8 /* Enable byte mask for the comparison with register */
+#define BPC_offT 9 /* Enable breakpoint Embedded Tracer triggering operation */
+
+#define BPC_mskWP ( 0x1 << BPC_offWP )
+#define BPC_mskEL ( 0x1 << BPC_offEL )
+#define BPC_mskS ( 0x1 << BPC_offS )
+#define BPC_mskP ( 0x1 << BPC_offP )
+#define BPC_mskC ( 0x1 << BPC_offC )
+#define BPC_mskBE0 ( 0x1 << BPC_offBE0 )
+#define BPC_mskBE1 ( 0x1 << BPC_offBE1 )
+#define BPC_mskBE2 ( 0x1 << BPC_offBE2 )
+#define BPC_mskBE3 ( 0x1 << BPC_offBE3 )
+#define BPC_mskT ( 0x1 << BPC_offT )
+
+/******************************************************************************
+ * dr1+(n*5): BPAn (n=0-7) (Breakpoint Address Register)
+ *****************************************************************************/
+
+ /* These registers contain break point address */
+
+/******************************************************************************
+ * dr2+(n*5): BPAMn (n=0-7) (Breakpoint Address Mask Register)
+ *****************************************************************************/
+
+ /* These registerd contain the address comparison mask for the BPAn register */
+
+/******************************************************************************
+ * dr3+(n*5): BPVn (n=0-7) Breakpoint Data Value Register
+ *****************************************************************************/
+
+ /* The BPVn register contains the data value that will be compared with the
+ * incoming load/store data value */
+
+/******************************************************************************
+ * dr4+(n*5): BPCIDn (n=0-7) (Breakpoint Context ID Register)
+ *****************************************************************************/
+#define BPCID_offCID 0 /* CID that will be compared with a process's CID */
+/* bit 9:31 reserved */
+
+#define BPCID_mskCID ( 0x1FF << BPCID_offCID )
+
+/******************************************************************************
+ * dr40: EDM_CFG (EDM Configuration Register)
+ *****************************************************************************/
+#define EDM_CFG_offBC 0 /* Number of hardware breakpoint sets implemented */
+#define EDM_CFG_offDIMU 3 /* Debug Instruction Memory Unit exists */
+/* bit 4:15 reserved */
+#define EDM_CFG_offVER 16 /* EDM version */
+
+#define EDM_CFG_mskBC ( 0x7 << EDM_CFG_offBC )
+#define EDM_CFG_mskDIMU ( 0x1 << EDM_CFG_offDIMU )
+#define EDM_CFG_mskVER ( 0xFFFF << EDM_CFG_offVER )
+
+/******************************************************************************
+ * dr41: EDMSW (EDM Status Word)
+ *****************************************************************************/
+#define EDMSW_offWV 0 /* Write Valid */
+#define EDMSW_offRV 1 /* Read Valid */
+#define EDMSW_offDE 2 /* Debug exception has occurred for this core */
+/* bit 3:31 reserved */
+
+#define EDMSW_mskWV ( 0x1 << EDMSW_offWV )
+#define EDMSW_mskRV ( 0x1 << EDMSW_offRV )
+#define EDMSW_mskDE ( 0x1 << EDMSW_offDE )
+
+/******************************************************************************
+ * dr42: EDM_CTL (EDM Control Register)
+ *****************************************************************************/
+/* bit 0:30 reserved */
+#define EDM_CTL_offV3_EDM_MODE 6 /* EDM compatibility control bit */
+#define EDM_CTL_offDEH_SEL 31 /* Controls where debug exception is directed to */
+
+#define EDM_CTL_mskV3_EDM_MODE ( 0x1 << EDM_CTL_offV3_EDM_MODE )
+#define EDM_CTL_mskDEH_SEL ( 0x1 << EDM_CTL_offDEH_SEL )
+
+/******************************************************************************
+ * dr43: EDM_DTR (EDM Data Transfer Register)
+ *****************************************************************************/
+
+ /* This is used to exchange data between the embedded EDM logic
+ * and the processor core */
+
+/******************************************************************************
+ * dr44: BPMTC (Breakpoint Match Trigger Counter Register)
+ *****************************************************************************/
+#define BPMTC_offBPMTC 0 /* Breakpoint match trigger counter value */
+/* bit 16:31 reserved */
+
+#define BPMTC_mskBPMTC ( 0xFFFF << BPMTC_offBPMTC )
+
+/******************************************************************************
+ * dr45: DIMBR (Debug Instruction Memory Base Register)
+ *****************************************************************************/
+/* bit 0:11 reserved */
+#define DIMBR_offDIMB 12 /* Base address of the Debug Instruction Memory (DIM) */
+#define DIMBR_mskDIMB ( 0xFFFFF << DIMBR_offDIMB )
+
+/******************************************************************************
+ * dr46: TECR0(Trigger Event Control register 0)
+ * dr47: TECR1 (Trigger Event Control register 1)
+ *****************************************************************************/
+#define TECR_offBP 0 /* Controld which BP is used as a trigger source */
+#define TECR_offNMI 8 /* Use NMI as a trigger source */
+#define TECR_offHWINT 9 /* Corresponding interrupt is used as a trigger source */
+#define TECR_offEVIC 15 /* Enable HWINT as a trigger source in EVIC mode */
+#define TECR_offSYS 16 /* Enable SYSCALL instruction as a trigger source */
+#define TECR_offDBG 17 /* Enable debug exception as a trigger source */
+#define TECR_offMRE 18 /* Enable MMU related exception as a trigger source */
+#define TECR_offE 19 /* An exception is used as a trigger source */
+/* bit 20:30 reserved */
+#define TECR_offL 31 /* Link/Cascade TECR0 trigger event to TECR1 trigger event */
+
+#define TECR_mskBP ( 0xFF << TECR_offBP )
+#define TECR_mskNMI ( 0x1 << TECR_offBNMI )
+#define TECR_mskHWINT ( 0x3F << TECR_offBHWINT )
+#define TECR_mskEVIC ( 0x1 << TECR_offBEVIC )
+#define TECR_mskSYS ( 0x1 << TECR_offBSYS )
+#define TECR_mskDBG ( 0x1 << TECR_offBDBG )
+#define TECR_mskMRE ( 0x1 << TECR_offBMRE )
+#define TECR_mskE ( 0x1 << TECR_offE )
+#define TECR_mskL ( 0x1 << TECR_offL )
+
+/******************************************************************************
+ * pfr0-2: PFMC0-2 (Performance Counter Register 0-2)
+ *****************************************************************************/
+
+ /* These registers contains performance event count */
+
+/******************************************************************************
+ * pfr3: PFM_CTL (Performance Counter Control Register)
+ *****************************************************************************/
+#define PFM_CTL_offEN0 0 /* Enable PFMC0 */
+#define PFM_CTL_offEN1 1 /* Enable PFMC1 */
+#define PFM_CTL_offEN2 2 /* Enable PFMC2 */
+#define PFM_CTL_offIE0 3 /* Enable interrupt for PFMC0 */
+#define PFM_CTL_offIE1 4 /* Enable interrupt for PFMC1 */
+#define PFM_CTL_offIE2 5 /* Enable interrupt for PFMC2 */
+#define PFM_CTL_offOVF0 6 /* Overflow bit of PFMC0 */
+#define PFM_CTL_offOVF1 7 /* Overflow bit of PFMC1 */
+#define PFM_CTL_offOVF2 8 /* Overflow bit of PFMC2 */
+#define PFM_CTL_offKS0 9 /* Enable superuser mode event counting for PFMC0 */
+#define PFM_CTL_offKS1 10 /* Enable superuser mode event counting for PFMC1 */
+#define PFM_CTL_offKS2 11 /* Enable superuser mode event counting for PFMC2 */
+#define PFM_CTL_offKU0 12 /* Enable user mode event counting for PFMC0 */
+#define PFM_CTL_offKU1 13 /* Enable user mode event counting for PFMC1 */
+#define PFM_CTL_offKU2 14 /* Enable user mode event counting for PFMC2 */
+#define PFM_CTL_offSEL0 15 /* The event selection for PFMC0 */
+#define PFM_CTL_offSEL1 21 /* The event selection for PFMC1 */
+#define PFM_CTL_offSEL2 27 /* The event selection for PFMC2 */
+/* bit 28:31 reserved */
+
+#define PFM_CTL_mskEN0 ( 0x01 << PFM_CTL_offEN0 )
+#define PFM_CTL_mskEN1 ( 0x01 << PFM_CTL_offEN1 )
+#define PFM_CTL_mskEN2 ( 0x01 << PFM_CTL_offEN2 )
+#define PFM_CTL_mskIE0 ( 0x01 << PFM_CTL_offIE0 )
+#define PFM_CTL_mskIE1 ( 0x01 << PFM_CTL_offIE1 )
+#define PFM_CTL_mskIE2 ( 0x01 << PFM_CTL_offIE2 )
+#define PFM_CTL_mskOVF0 ( 0x01 << PFM_CTL_offOVF0 )
+#define PFM_CTL_mskOVF1 ( 0x01 << PFM_CTL_offOVF1 )
+#define PFM_CTL_mskOVF2 ( 0x01 << PFM_CTL_offOVF2 )
+#define PFM_CTL_mskKS0 ( 0x01 << PFM_CTL_offKS0 )
+#define PFM_CTL_mskKS1 ( 0x01 << PFM_CTL_offKS1 )
+#define PFM_CTL_mskKS2 ( 0x01 << PFM_CTL_offKS2 )
+#define PFM_CTL_mskKU0 ( 0x01 << PFM_CTL_offKU0 )
+#define PFM_CTL_mskKU1 ( 0x01 << PFM_CTL_offKU1 )
+#define PFM_CTL_mskKU2 ( 0x01 << PFM_CTL_offKU2 )
+#define PFM_CTL_mskSEL0 ( 0x01 << PFM_CTL_offSEL0 )
+#define PFM_CTL_mskSEL1 ( 0x3F << PFM_CTL_offSEL1 )
+#define PFM_CTL_mskSEL2 ( 0x3F << PFM_CTL_offSEL2 )
+
+/******************************************************************************
+ * SDZ_CTL (Structure Downsizing Control Register)
+ *****************************************************************************/
+#define SDZ_CTL_offICDZ 0 /* I-cache downsizing control */
+#define SDZ_CTL_offDCDZ 3 /* D-cache downsizing control */
+#define SDZ_CTL_offMTBDZ 6 /* MTLB downsizing control */
+#define SDZ_CTL_offBTBDZ 9 /* Branch Target Table downsizing control */
+/* bit 12:31 reserved */
+#define SDZ_CTL_mskICDZ ( 0x07 << SDZ_CTL_offICDZ )
+#define SDZ_CTL_mskDCDZ ( 0x07 << SDZ_CTL_offDCDZ )
+#define SDZ_CTL_mskMTBDZ ( 0x07 << SDZ_CTL_offMTBDZ )
+#define SDZ_CTL_mskBTBDZ ( 0x07 << SDZ_CTL_offBTBDZ )
+
+/******************************************************************************
+ * N13MISC_CTL (N13 Miscellaneous Control Register)
+ *****************************************************************************/
+#define N13MISC_CTL_offBTB 0 /* Disable Branch Target Buffer */
+#define N13MISC_CTL_offRTP 1 /* Disable Return Target Predictor */
+#define N13MISC_CTL_offPTEPF 2 /* Disable HPTWK L2 PTE pefetch */
+#define N13MISC_CTL_offSP_SHADOW_EN 4 /* Enable shadow stack pointers */
+/* bit 6, 9:31 reserved */
+
+#define N13MISC_CTL_makBTB ( 0x1 << N13MISC_CTL_offBTB )
+#define N13MISC_CTL_makRTP ( 0x1 << N13MISC_CTL_offRTP )
+#define N13MISC_CTL_makPTEPF ( 0x1 << N13MISC_CTL_offPTEPF )
+#define N13MISC_CTL_makSP_SHADOW_EN ( 0x1 << N13MISC_CTL_offSP_SHADOW_EN )
+
+#define MISC_init (N13MISC_CTL_makBTB|N13MISC_CTL_makRTP|N13MISC_CTL_makSP_SHADOW_EN)
+
+/******************************************************************************
+ * PRUSR_ACC_CTL (Privileged Resource User Access Control Registers)
+ *****************************************************************************/
+#define PRUSR_ACC_CTL_offDMA_EN 0 /* Allow user mode access of DMA registers */
+#define PRUSR_ACC_CTL_offPFM_EN 1 /* Allow user mode access of PFM registers */
+
+#define PRUSR_ACC_CTL_mskDMA_EN ( 0x1 << PRUSR_ACC_CTL_offDMA_EN )
+#define PRUSR_ACC_CTL_mskPFM_EN ( 0x1 << PRUSR_ACC_CTL_offPFM_EN )
+
+/******************************************************************************
+ * dmar0: DMA_CFG (DMA Configuration Register)
+ *****************************************************************************/
+#define DMA_CFG_offNCHN 0 /* The number of DMA channels implemented */
+#define DMA_CFG_offUNEA 2 /* Un-aligned External Address transfer feature */
+#define DMA_CFG_off2DET 3 /* 2-D Element Transfer feature */
+/* bit 4:15 reserved */
+#define DMA_CFG_offVER 16 /* DMA architecture and implementation version */
+
+#define DMA_CFG_mskNCHN ( 0x3 << DMA_CFG_offNCHN )
+#define DMA_CFG_mskUNEA ( 0x1 << DMA_CFG_offUNEA )
+#define DMA_CFG_msk2DET ( 0x1 << DMA_CFG_off2DET )
+#define DMA_CFG_mskVER ( 0xFFFF << DMA_CFG_offVER )
+
+/******************************************************************************
+ * dmar1: DMA_GCSW (DMA Global Control and Status Word Register)
+ *****************************************************************************/
+#define DMA_GCSW_offC0STAT 0 /* DMA channel 0 state */
+#define DMA_GCSW_offC1STAT 3 /* DMA channel 1 state */
+/* bit 6:11 reserved */
+#define DMA_GCSW_offC0INT 12 /* DMA channel 0 generate interrupt */
+#define DMA_GCSW_offC1INT 13 /* DMA channel 1 generate interrupt */
+/* bit 14:30 reserved */
+#define DMA_GCSW_offEN 31 /* Enable DMA engine */
+
+#define DMA_GCSW_mskC0STAT ( 0x7 << DMA_GCSW_offC0STAT )
+#define DMA_GCSW_mskC1STAT ( 0x7 << DMA_GCSW_offC1STAT )
+#define DMA_GCSW_mskC0INT ( 0x1 << DMA_GCSW_offC0INT )
+#define DMA_GCSW_mskC1INT ( 0x1 << DMA_GCSW_offC1INT )
+#define DMA_GCSW_mskEN ( 0x1 << DMA_GCSW_offEN )
+
+/******************************************************************************
+ * dmar2: DMA_CHNSEL (DMA Channel Selection Register)
+ *****************************************************************************/
+#define DMA_CHNSEL_offCHAN 0 /* Selected channel number */
+/* bit 2:31 reserved */
+
+#define DMA_CHNSEL_mskCHAN ( 0x3 << DMA_CHNSEL_offCHAN )
+
+/******************************************************************************
+ * dmar3: DMA_ACT (DMA Action Register)
+ *****************************************************************************/
+#define DMA_ACT_offACMD 0 /* DMA Action Command */
+/* bit 2:31 reserved */
+#define DMA_ACT_mskACMD ( 0x3 << DMA_ACT_offACMD )
+
+/******************************************************************************
+ * dmar4: DMA_SETUP (DMA Setup Register)
+ *****************************************************************************/
+#define DMA_SETUP_offLM 0 /* Local Memory Selection */
+#define DMA_SETUP_offTDIR 1 /* Transfer Direction */
+#define DMA_SETUP_offTES 2 /* Transfer Element Size */
+#define DMA_SETUP_offESTR 4 /* External memory transfer Stride */
+#define DMA_SETUP_offCIE 16 /* Interrupt Enable on Completion */
+#define DMA_SETUP_offSIE 17 /* Interrupt Enable on explicit Stop */
+#define DMA_SETUP_offEIE 18 /* Interrupt Enable on Error */
+#define DMA_SETUP_offUE 19 /* Enable the Un-aligned External Address */
+#define DMA_SETUP_off2DE 20 /* Enable the 2-D External Transfer */
+#define DMA_SETUP_offCOA 21 /* Transfer Coalescable */
+/* bit 22:31 reserved */
+
+#define DMA_SETUP_mskLM ( 0x1 << DMA_SETUP_offLM )
+#define DMA_SETUP_mskTDIR ( 0x1 << DMA_SETUP_offTDIR )
+#define DMA_SETUP_mskTES ( 0x3 << DMA_SETUP_offTES )
+#define DMA_SETUP_mskESTR ( 0xFFF << DMA_SETUP_offESTR )
+#define DMA_SETUP_mskCIE ( 0x1 << DMA_SETUP_offCIE )
+#define DMA_SETUP_mskSIE ( 0x1 << DMA_SETUP_offSIE )
+#define DMA_SETUP_mskEIE ( 0x1 << DMA_SETUP_offEIE )
+#define DMA_SETUP_mskUE ( 0x1 << DMA_SETUP_offUE )
+#define DMA_SETUP_msk2DE ( 0x1 << DMA_SETUP_off2DE )
+#define DMA_SETUP_mskCOA ( 0x1 << DMA_SETUP_offCOA )
+
+/******************************************************************************
+ * dmar5: DMA_ISADDR (DMA Internal Start Address Register)
+ *****************************************************************************/
+#define DMA_ISADDR_offISADDR 0 /* Internal Start Address */
+/* bit 20:31 reserved */
+#define DMA_ISADDR_mskISADDR ( 0xFFFFF << DMA_ISADDR_offISADDR )
+
+/******************************************************************************
+ * dmar6: DMA_ESADDR (DMA External Start Address Register)
+ *****************************************************************************/
+/* This register holds External Start Address */
+
+/******************************************************************************
+ * dmar7: DMA_TCNT (DMA Transfer Element Count Register)
+ *****************************************************************************/
+#define DMA_TCNT_offTCNT 0 /* DMA transfer element count */
+/* bit 18:31 reserved */
+#define DMA_TCNT_mskTCNT ( 0x3FFFF << DMA_TCNT_offTCNT )
+
+/******************************************************************************
+ * dmar8: DMA_STATUS (DMA Status Register)
+ *****************************************************************************/
+#define DMA_STATUS_offSTAT 0 /* DMA channel state */
+#define DMA_STATUS_offSTUNA 3 /* Un-aligned error on External Stride value */
+#define DMA_STATUS_offDERR 4 /* DMA Transfer Disruption Error */
+#define DMA_STATUS_offEUNA 5 /* Un-aligned error on the External address */
+#define DMA_STATUS_offIUNA 6 /* Un-aligned error on the Internal address */
+#define DMA_STATUS_offIOOR 7 /* Out-Of-Range error on the Internal address */
+#define DMA_STATUS_offEBUS 8 /* Bus Error on an External DMA transfer */
+#define DMA_STATUS_offESUP 9 /* DMA setup error */
+/* bit 10:31 reserved */
+
+#define DMA_STATUS_mskSTAT ( 0x7 << DMA_STATUS_offSTAT )
+#define DMA_STATUS_mskSTUNA ( 0x1 << DMDMA_STATUS_offSTUNA )
+#define DMA_STATUS_mskDERR ( 0x1 << DMDMA_STATUS_offDERR )
+#define DMA_STATUS_mskEUNA ( 0x1 << DMDMA_STATUS_offEUNA )
+#define DMA_STATUS_mskIUNA ( 0x1 << DMDMA_STATUS_offIUNA )
+#define DMA_STATUS_mskIOOR ( 0x1 << DMDMA_STATUS_offIOOR )
+#define DMA_STATUS_mskEBUS ( 0x1 << DMDMA_STATUS_offEBUS )
+#define DMA_STATUS_mskESUP ( 0x1 << DMDMA_STATUS_offESUP )
+
+/******************************************************************************
+ * dmar9: DMA_2DSET (DMA 2D Setup Register)
+ *****************************************************************************/
+#define DMA_2DSET_offWECNT 0 /* The Width Element Count for a 2-D region */
+#define DMA_2DSET_offHTSTR 16 /* The Height Stride for a 2-D region */
+
+#define DMA_2DSET_mskHTSTR ( 0xFFFF << DMA_2DSET_offHTSTR )
+#define DMA_2DSET_mskWECNT ( 0xFFFF << DMA_2DSET_offWECNT )
+
+/******************************************************************************
+ * dmar10: DMA_2DSCTL (DMA 2D Startup Control Register)
+ *****************************************************************************/
+#define DMA_2DSCTL_offSTWECNT 0 /* Startup Width Element Count for a 2-D region */
+/* bit 16:31 reserved */
+
+#define DMA_2DSCTL_mskSTWECNT ( 0xFFFF << DMA_2DSCTL_offSTWECNT )
+
+/******************************************************************************
+ * fpcsr: FPCSR (Floating-Point Control Status Register)
+ *****************************************************************************/
+#define FPCSR_offRM 0
+#define FPCSR_offIVO 2
+#define FPCSR_offDBZ 3
+#define FPCSR_offOVF 4
+#define FPCSR_offUDF 5
+#define FPCSR_offIEX 6
+#define FPCSR_offIVOE 7
+#define FPCSR_offDBZE 8
+#define FPCSR_offOVFE 9
+#define FPCSR_offUDFE 10
+#define FPCSR_offIEXE 11
+#define FPCSR_offDNZ 12
+#define FPCSR_offIVOT 13
+#define FPCSR_offDBZT 14
+#define FPCSR_offOVFT 15
+#define FPCSR_offUDFT 16
+#define FPCSR_offIEXT 17
+#define FPCSR_offDNIT 18
+#define FPCSR_offRIT 19
+
+#define FPCSR_mskRM ( 0x3 << FPCSR_offRM )
+#define FPCSR_mskIVO ( 0x1 << FPCSR_offIVO )
+#define FPCSR_mskDBZ ( 0x1 << FPCSR_offDBZ )
+#define FPCSR_mskOVF ( 0x1 << FPCSR_offOVF )
+#define FPCSR_mskUDF ( 0x1 << FPCSR_offUDF )
+#define FPCSR_mskIEX ( 0x1 << FPCSR_offIEX )
+#define FPCSR_mskIVOE ( 0x1 << FPCSR_offIVOE )
+#define FPCSR_mskDBZE ( 0x1 << FPCSR_offDBZE )
+#define FPCSR_mskOVFE ( 0x1 << FPCSR_offOVFE )
+#define FPCSR_mskUDFE ( 0x1 << FPCSR_offUDFE )
+#define FPCSR_mskIEXE ( 0x1 << FPCSR_offIEXE )
+#define FPCSR_mskDNZ ( 0x1 << FPCSR_offDNZ )
+#define FPCSR_mskIVOT ( 0x1 << FPCSR_offIVOT )
+#define FPCSR_mskDBZT ( 0x1 << FPCSR_offDBZT )
+#define FPCSR_mskOVFT ( 0x1 << FPCSR_offOVFT )
+#define FPCSR_mskUDFT ( 0x1 << FPCSR_offUDFT )
+#define FPCSR_mskIEXT ( 0x1 << FPCSR_offIEXT )
+#define FPCSR_mskDNIT ( 0x1 << FPCSR_offDNIT )
+#define FPCSR_mskRIT ( 0x1 << FPCSR_offRIT )
+#define FPCSR_mskALL (FPCSR_mskIVO | FPCSR_mskDBZ | FPCSR_mskOVF | FPCSR_mskUDF | FPCSR_mskIEX)
+#define FPCSR_mskALLE (FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE | FPCSR_mskUDFE | FPCSR_mskIEXE)
+#define FPCSR_mskALLT (FPCSR_mskIVOT | FPCSR_mskDBZT | FPCSR_mskOVFT | FPCSR_mskUDFT | FPCSR_mskIEXT |FPCSR_mskDNIT | FPCSR_mskRIT)
+
+/******************************************************************************
+ * fpcfg: FPCFG (Floating-Point Configuration Register)
+ *****************************************************************************/
+#define FPCFG_offSP 0
+#define FPCFG_offDP 1
+#define FPCFG_offFREG 2
+#define FPCFG_offFMA 4
+#define FPCFG_offIMVER 22
+#define FPCFG_offAVER 27
+
+#define FPCFG_mskSP ( 0x1 << FPCFG_offSP )
+#define FPCFG_mskDP ( 0x1 << FPCFG_offDP )
+#define FPCFG_mskFREG ( 0x3 << FPCFG_offFREG )
+#define FPCFG_mskFMA ( 0x1 << FPCFG_offFMA )
+#define FPCFG_mskIMVER ( 0x1F << FPCFG_offIMVER )
+#define FPCFG_mskAVER ( 0x1F << FPCFG_offAVER )
+
+/******************************************************************************
+ * fucpr: FUCOP_CTL (FPU and Coprocessor Enable Control Register)
+ *****************************************************************************/
+#define FUCOP_CTL_offCP0EN 0
+#define FUCOP_CTL_offCP1EN 1
+#define FUCOP_CTL_offCP2EN 2
+#define FUCOP_CTL_offCP3EN 3
+#define FUCOP_CTL_offAUEN 31
+
+#define FUCOP_CTL_mskCP0EN ( 0x1 << FUCOP_CTL_offCP0EN )
+#define FUCOP_CTL_mskCP1EN ( 0x1 << FUCOP_CTL_offCP1EN )
+#define FUCOP_CTL_mskCP2EN ( 0x1 << FUCOP_CTL_offCP2EN )
+#define FUCOP_CTL_mskCP3EN ( 0x1 << FUCOP_CTL_offCP3EN )
+#define FUCOP_CTL_mskAUEN ( 0x1 << FUCOP_CTL_offAUEN )
+
+#endif /* __NDS32_BITFIELD_H__ */
diff --git a/arch/nds32/include/asm/nds32.h b/arch/nds32/include/asm/nds32.h
new file mode 100644
index 0000000..f405db3
--- /dev/null
+++ b/arch/nds32/include/asm/nds32.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_NDS32_NDS32_H_
+#define _ASM_NDS32_NDS32_H_
+
+#include <asm/bitfield.h>
+#include <asm/cachectl.h>
+
+#ifndef __ASSEMBLY__
+#include <asm/barrier.h>
+#include <nds32_intrinsic.h>
+
+#ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
+#define FP_OFFSET (-3)
+#else
+#define FP_OFFSET (-2)
+#endif
+
+static inline void GIE_ENABLE(void)
+{
+ mb();
+ __nds32__gie_en();
+}
+
+static inline void GIE_DISABLE(void)
+{
+ mb();
+ __nds32__gie_dis();
+}
+
+static inline unsigned long CACHE_SET(unsigned char cache)
+{
+
+ if (cache == ICACHE)
+ return 64 << ((__nds32__mfsr(NDS32_SR_ICM_CFG) & ICM_CFG_mskISET) >>
+ ICM_CFG_offISET);
+ else
+ return 64 << ((__nds32__mfsr(NDS32_SR_DCM_CFG) & DCM_CFG_mskDSET) >>
+ DCM_CFG_offDSET);
+}
+
+static inline unsigned long CACHE_WAY(unsigned char cache)
+{
+
+ if (cache == ICACHE)
+ return 1 +
+ ((__nds32__mfsr(NDS32_SR_ICM_CFG) & ICM_CFG_mskIWAY) >> ICM_CFG_offIWAY);
+ else
+ return 1 +
+ ((__nds32__mfsr(NDS32_SR_DCM_CFG) & DCM_CFG_mskDWAY) >> DCM_CFG_offDWAY);
+}
+
+static inline unsigned long CACHE_LINE_SIZE(unsigned char cache)
+{
+
+ if (cache == ICACHE)
+ return 8 <<
+ (((__nds32__mfsr(NDS32_SR_ICM_CFG) & ICM_CFG_mskISZ) >> ICM_CFG_offISZ) - 1);
+ else
+ return 8 <<
+ (((__nds32__mfsr(NDS32_SR_DCM_CFG) & DCM_CFG_mskDSZ) >> DCM_CFG_offDSZ) - 1);
+}
+
+#endif /* __ASSEMBLY__ */
+
+#define IVB_BASE PHYS_OFFSET /* in user space for intr/exc/trap/break table base, 64KB aligned
+ * We defined at the start of the physical memory */
+
+/* dispatched sub-entry exception handler numbering */
+#define RD_PROT 0 /* read protrection */
+#define WRT_PROT 1 /* write protection */
+#define NOEXEC 2 /* non executable */
+#define PAGE_MODIFY 3 /* page modified */
+#define ACC_BIT 4 /* access bit */
+#define RESVED_PTE 5 /* reserved PTE attribute */
+/* reserved 6 ~ 16 */
+
+#endif /* _ASM_NDS32_NDS32_H_ */
diff --git a/arch/nds32/kernel/asm-offsets.c b/arch/nds32/kernel/asm-offsets.c
new file mode 100644
index 0000000..2d9468b
--- /dev/null
+++ b/arch/nds32/kernel/asm-offsets.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/sched.h>
+#include <linux/sched/task_stack.h>
+#include <linux/kbuild.h>
+#include <asm/thread_info.h>
+#include <asm/ptrace.h>
+
+int main(void)
+{
+ DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags));
+ DEFINE(TSK_TI_PREEMPT,
+ offsetof(struct task_struct, thread_info.preempt_count));
+ DEFINE(THREAD_CPU_CONTEXT,
+ offsetof(struct task_struct, thread.cpu_context));
+ DEFINE(OSP_OFFSET, offsetof(struct pt_regs, osp));
+ DEFINE(SP_OFFSET, offsetof(struct pt_regs, sp));
+ DEFINE(FUCOP_CTL_OFFSET, offsetof(struct pt_regs, fucop_ctl));
+ DEFINE(IPSW_OFFSET, offsetof(struct pt_regs, ipsw));
+ DEFINE(SYSCALLNO_OFFSET, offsetof(struct pt_regs, syscallno));
+ DEFINE(IPC_OFFSET, offsetof(struct pt_regs, ipc));
+ DEFINE(R0_OFFSET, offsetof(struct pt_regs, uregs[0]));
+ DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC);
+ DEFINE(CLOCK_COARSE_RES, LOW_RES_NSEC);
+ return 0;
+}
--
1.7.9.5
From 1583366026626883784@xxx Tue Nov 07 00:45:13 +0000 2017
X-GM-THRID: 1583366026626883784
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/uapi/asm/sigcontext.h | 73 ++++++
arch/nds32/include/uapi/asm/signal.h | 23 ++
arch/nds32/kernel/signal.c | 370 ++++++++++++++++++++++++++++++
3 files changed, 466 insertions(+)
create mode 100644 arch/nds32/include/uapi/asm/sigcontext.h
create mode 100644 arch/nds32/include/uapi/asm/signal.h
create mode 100644 arch/nds32/kernel/signal.c
diff --git a/arch/nds32/include/uapi/asm/sigcontext.h b/arch/nds32/include/uapi/asm/sigcontext.h
new file mode 100644
index 0000000..1c0dfcb
--- /dev/null
+++ b/arch/nds32/include/uapi/asm/sigcontext.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 _ASMNDS32_SIGCONTEXT_H
+#define _ASMNDS32_SIGCONTEXT_H
+
+/*
+ * Signal context structure - contains all info to do with the state
+ * before the signal handler was invoked. Note: only add new entries
+ * to the end of the structure.
+ */
+
+struct zol_struct {
+ unsigned long nds32_lc; /* $LC */
+ unsigned long nds32_le; /* $LE */
+ unsigned long nds32_lb; /* $LB */
+};
+
+struct sigcontext {
+ unsigned long trap_no;
+ unsigned long error_code;
+ unsigned long oldmask;
+ unsigned long nds32_r0;
+ unsigned long nds32_r1;
+ unsigned long nds32_r2;
+ unsigned long nds32_r3;
+ unsigned long nds32_r4;
+ unsigned long nds32_r5;
+ unsigned long nds32_r6;
+ unsigned long nds32_r7;
+ unsigned long nds32_r8;
+ unsigned long nds32_r9;
+ unsigned long nds32_r10;
+ unsigned long nds32_r11;
+ unsigned long nds32_r12;
+ unsigned long nds32_r13;
+ unsigned long nds32_r14;
+ unsigned long nds32_r15;
+ unsigned long nds32_r16;
+ unsigned long nds32_r17;
+ unsigned long nds32_r18;
+ unsigned long nds32_r19;
+ unsigned long nds32_r20;
+ unsigned long nds32_r21;
+ unsigned long nds32_r22;
+ unsigned long nds32_r23;
+ unsigned long nds32_r24;
+ unsigned long nds32_r25;
+ unsigned long nds32_fp; /* $r28 */
+ unsigned long nds32_gp; /* $r29 */
+ unsigned long nds32_lp; /* $r30 */
+ unsigned long nds32_sp; /* $r31 */
+ unsigned long nds32_ipc;
+ unsigned long fault_address;
+ unsigned long used_math_flag;
+ /* FPU Registers */
+ struct zol_struct zol;
+};
+
+#endif
diff --git a/arch/nds32/include/uapi/asm/signal.h b/arch/nds32/include/uapi/asm/signal.h
new file mode 100644
index 0000000..5ef6915
--- /dev/null
+++ b/arch/nds32/include/uapi/asm/signal.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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 _ASMNDS32_SIGNAL_H
+#define _ASMNDS32_SIGNAL_H
+
+#define SA_RESTORER 0x04000000
+
+#include <asm-generic/signal.h>
+#endif
diff --git a/arch/nds32/kernel/signal.c b/arch/nds32/kernel/signal.c
new file mode 100644
index 0000000..4bcc45b
--- /dev/null
+++ b/arch/nds32/kernel/signal.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/ptrace.h>
+#include <linux/personality.h>
+#include <linux/freezer.h>
+#include <linux/tracehook.h>
+#include <linux/uaccess.h>
+
+#include <asm/cacheflush.h>
+#include <asm/ucontext.h>
+#include <asm/unistd.h>
+
+#include <asm/ptrace.h>
+#include <asm/vdso.h>
+
+struct rt_sigframe {
+ struct siginfo info;
+ struct ucontext uc;
+};
+
+static int restore_sigframe(struct pt_regs *regs,
+ struct rt_sigframe __user * sf)
+{
+ sigset_t set;
+ int err;
+
+ err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
+ if (err == 0) {
+ set_current_blocked(&set);
+ }
+
+ __get_user_error(regs->uregs[0], &sf->uc.uc_mcontext.nds32_r0, err);
+ __get_user_error(regs->uregs[1], &sf->uc.uc_mcontext.nds32_r1, err);
+ __get_user_error(regs->uregs[2], &sf->uc.uc_mcontext.nds32_r2, err);
+ __get_user_error(regs->uregs[3], &sf->uc.uc_mcontext.nds32_r3, err);
+ __get_user_error(regs->uregs[4], &sf->uc.uc_mcontext.nds32_r4, err);
+ __get_user_error(regs->uregs[5], &sf->uc.uc_mcontext.nds32_r5, err);
+ __get_user_error(regs->uregs[6], &sf->uc.uc_mcontext.nds32_r6, err);
+ __get_user_error(regs->uregs[7], &sf->uc.uc_mcontext.nds32_r7, err);
+ __get_user_error(regs->uregs[8], &sf->uc.uc_mcontext.nds32_r8, err);
+ __get_user_error(regs->uregs[9], &sf->uc.uc_mcontext.nds32_r9, err);
+ __get_user_error(regs->uregs[10], &sf->uc.uc_mcontext.nds32_r10, err);
+ __get_user_error(regs->uregs[11], &sf->uc.uc_mcontext.nds32_r11, err);
+ __get_user_error(regs->uregs[12], &sf->uc.uc_mcontext.nds32_r12, err);
+ __get_user_error(regs->uregs[13], &sf->uc.uc_mcontext.nds32_r13, err);
+ __get_user_error(regs->uregs[14], &sf->uc.uc_mcontext.nds32_r14, err);
+ __get_user_error(regs->uregs[15], &sf->uc.uc_mcontext.nds32_r15, err);
+ __get_user_error(regs->uregs[16], &sf->uc.uc_mcontext.nds32_r16, err);
+ __get_user_error(regs->uregs[17], &sf->uc.uc_mcontext.nds32_r17, err);
+ __get_user_error(regs->uregs[18], &sf->uc.uc_mcontext.nds32_r18, err);
+ __get_user_error(regs->uregs[19], &sf->uc.uc_mcontext.nds32_r19, err);
+ __get_user_error(regs->uregs[20], &sf->uc.uc_mcontext.nds32_r20, err);
+
+ __get_user_error(regs->uregs[21], &sf->uc.uc_mcontext.nds32_r21, err);
+ __get_user_error(regs->uregs[22], &sf->uc.uc_mcontext.nds32_r22, err);
+ __get_user_error(regs->uregs[23], &sf->uc.uc_mcontext.nds32_r23, err);
+ __get_user_error(regs->uregs[24], &sf->uc.uc_mcontext.nds32_r24, err);
+ __get_user_error(regs->uregs[25], &sf->uc.uc_mcontext.nds32_r25, err);
+ __get_user_error(regs->fp, &sf->uc.uc_mcontext.nds32_fp, err);
+ __get_user_error(regs->gp, &sf->uc.uc_mcontext.nds32_gp, err);
+ __get_user_error(regs->lp, &sf->uc.uc_mcontext.nds32_lp, err);
+ __get_user_error(regs->sp, &sf->uc.uc_mcontext.nds32_sp, err);
+ __get_user_error(regs->ipc, &sf->uc.uc_mcontext.nds32_ipc, err);
+#if defined(CONFIG_HWZOL)
+ __get_user_error(regs->lc, &sf->uc.uc_mcontext.zol.nds32_lc, err);
+ __get_user_error(regs->le, &sf->uc.uc_mcontext.zol.nds32_le, err);
+ __get_user_error(regs->lb, &sf->uc.uc_mcontext.zol.nds32_lb, err);
+#endif
+
+ err |= !valid_user_regs(regs);
+
+ return err;
+}
+
+asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+{
+ struct rt_sigframe __user *frame;
+
+ /* Always make any pending restarted system calls return -EINTR */
+ current->restart_block.fn = do_no_restart_syscall;
+
+ /*
+ * Since we stacked the signal on a 64-bit boundary,
+ * then 'sp' should be two-word aligned here. If it's
+ * not, then the user is trying to mess with us.
+ */
+ if (regs->sp & 7)
+ goto badframe;
+
+ frame = (struct rt_sigframe __user *)regs->sp;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+
+ if (restore_sigframe(regs, frame))
+ goto badframe;
+
+ if (restore_altstack(&frame->uc.uc_stack))
+ goto badframe;
+
+ return regs->uregs[0];
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+static int
+setup_sigframe(struct rt_sigframe __user * sf, struct pt_regs *regs,
+ sigset_t * set)
+{
+ int err = 0;
+
+
+ __put_user_error(regs->uregs[0], &sf->uc.uc_mcontext.nds32_r0, err);
+ __put_user_error(regs->uregs[1], &sf->uc.uc_mcontext.nds32_r1, err);
+ __put_user_error(regs->uregs[2], &sf->uc.uc_mcontext.nds32_r2, err);
+ __put_user_error(regs->uregs[3], &sf->uc.uc_mcontext.nds32_r3, err);
+ __put_user_error(regs->uregs[4], &sf->uc.uc_mcontext.nds32_r4, err);
+ __put_user_error(regs->uregs[5], &sf->uc.uc_mcontext.nds32_r5, err);
+ __put_user_error(regs->uregs[6], &sf->uc.uc_mcontext.nds32_r6, err);
+ __put_user_error(regs->uregs[7], &sf->uc.uc_mcontext.nds32_r7, err);
+ __put_user_error(regs->uregs[8], &sf->uc.uc_mcontext.nds32_r8, err);
+ __put_user_error(regs->uregs[9], &sf->uc.uc_mcontext.nds32_r9, err);
+ __put_user_error(regs->uregs[10], &sf->uc.uc_mcontext.nds32_r10, err);
+ __put_user_error(regs->uregs[11], &sf->uc.uc_mcontext.nds32_r11, err);
+ __put_user_error(regs->uregs[12], &sf->uc.uc_mcontext.nds32_r12, err);
+ __put_user_error(regs->uregs[13], &sf->uc.uc_mcontext.nds32_r13, err);
+ __put_user_error(regs->uregs[14], &sf->uc.uc_mcontext.nds32_r14, err);
+ __put_user_error(regs->uregs[15], &sf->uc.uc_mcontext.nds32_r15, err);
+ __put_user_error(regs->uregs[16], &sf->uc.uc_mcontext.nds32_r16, err);
+ __put_user_error(regs->uregs[17], &sf->uc.uc_mcontext.nds32_r17, err);
+ __put_user_error(regs->uregs[18], &sf->uc.uc_mcontext.nds32_r18, err);
+ __put_user_error(regs->uregs[19], &sf->uc.uc_mcontext.nds32_r19, err);
+ __put_user_error(regs->uregs[20], &sf->uc.uc_mcontext.nds32_r20, err);
+
+ __put_user_error(regs->uregs[21], &sf->uc.uc_mcontext.nds32_r21, err);
+ __put_user_error(regs->uregs[22], &sf->uc.uc_mcontext.nds32_r22, err);
+ __put_user_error(regs->uregs[23], &sf->uc.uc_mcontext.nds32_r23, err);
+ __put_user_error(regs->uregs[24], &sf->uc.uc_mcontext.nds32_r24, err);
+ __put_user_error(regs->uregs[25], &sf->uc.uc_mcontext.nds32_r25, err);
+ __put_user_error(regs->fp, &sf->uc.uc_mcontext.nds32_fp, err);
+ __put_user_error(regs->gp, &sf->uc.uc_mcontext.nds32_gp, err);
+ __put_user_error(regs->lp, &sf->uc.uc_mcontext.nds32_lp, err);
+ __put_user_error(regs->sp, &sf->uc.uc_mcontext.nds32_sp, err);
+ __put_user_error(regs->ipc, &sf->uc.uc_mcontext.nds32_ipc, err);
+#if defined(CONFIG_HWZOL)
+ __put_user_error(regs->lc, &sf->uc.uc_mcontext.zol.nds32_lc, err);
+ __put_user_error(regs->le, &sf->uc.uc_mcontext.zol.nds32_le, err);
+ __put_user_error(regs->lb, &sf->uc.uc_mcontext.zol.nds32_lb, err);
+#endif
+
+ __put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no,
+ err);
+ __put_user_error(current->thread.error_code,
+ &sf->uc.uc_mcontext.error_code, err);
+ __put_user_error(current->thread.address,
+ &sf->uc.uc_mcontext.fault_address, err);
+ __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);
+
+ err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
+
+ return err;
+}
+
+static inline void __user *get_sigframe(struct ksignal *ksig,
+ struct pt_regs *regs, int framesize)
+{
+ unsigned long sp = sigsp(regs->sp, ksig);
+ void __user *frame;
+
+ /*
+ * ATPCS B01 mandates 8-byte alignment
+ */
+ frame = (void __user *)((sp - framesize) & ~7);
+
+ /*
+ * Check that we can actually write to the signal frame.
+ */
+ if (!access_ok(VERIFY_WRITE, frame, framesize))
+ frame = NULL;
+
+ return frame;
+}
+
+static int
+setup_return(struct pt_regs *regs, struct ksignal *ksig, void __user * frame)
+{
+ unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler;
+ unsigned long retcode;
+
+ /*
+ * Maybe we need to deliver a 32-bit signal to a 26-bit task.
+ */
+ if (ksig->ka.sa.sa_flags & SA_RESTORER)
+ retcode = (unsigned long)ksig->ka.sa.sa_restorer;
+ else
+ retcode = VDSO_SYMBOL(current->mm->context.vdso, rt_sigtramp);
+
+ regs->uregs[0] = ksig->sig;
+ regs->sp = (unsigned long)frame;
+ regs->lp = retcode;
+ regs->ipc = handler;
+ /* Also store handler address in r15 for updating GP in the handler. */
+ regs->uregs[15] = handler;
+
+ return 0;
+}
+
+static int
+setup_rt_frame(struct ksignal *ksig, sigset_t * set, struct pt_regs *regs)
+{
+ struct rt_sigframe __user *frame =
+ get_sigframe(ksig, regs, sizeof(*frame));
+ int err = 0;
+
+ if (!frame)
+ return 1;
+
+ err |= copy_siginfo_to_user(&frame->info, &ksig->info);
+
+ __put_user_error(0, &frame->uc.uc_flags, err);
+ __put_user_error(NULL, &frame->uc.uc_link, err);
+
+ err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
+ err |= setup_sigframe(frame, regs, set);
+ if (err == 0) {
+ setup_return(regs, ksig, frame);
+
+ if (err == 0) {
+ /*
+ * For realtime signals we must also set the second and third
+ * arguments for the signal handler.
+ * -- Peter Maydell <[email protected]> 2000-12-06
+ */
+ regs->uregs[1] = (unsigned long)&frame->info;
+ regs->uregs[2] = (unsigned long)&frame->uc;
+ }
+ }
+ return err;
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
+{
+ int ret;
+ sigset_t *oldset = sigmask_to_save();
+
+ /*
+ * Set up the stack frame
+ */
+ ret = setup_rt_frame(ksig, oldset, regs);
+
+ /*
+ * Check that the resulting registers are actually sane.
+ */
+ ret |= !valid_user_regs(regs);
+
+ signal_setup_done(ret, ksig, 0);
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+static int do_signal(struct pt_regs *regs, int syscall)
+{
+ unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
+ struct ksignal ksig;
+ int restart = 0;
+
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if (!user_mode(regs))
+ return 0;
+
+ /*
+ * If we were from a system call, check for system call restarting...
+ */
+ if (syscall) {
+ continue_addr = regs->ipc;
+ restart_addr = continue_addr - 4;
+ retval = regs->uregs[0];
+
+ /*
+ * Prepare for system call restart. We do this here so that a
+ * debugger will see the already changed PSW.
+ */
+ switch (retval) {
+ case -ERESTART_RESTARTBLOCK:
+ restart -= 2;
+ case -ERESTARTNOHAND:
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
+ restart++;
+ regs->uregs[0] = regs->orig_r0;
+ regs->ipc = restart_addr;
+ break;
+ }
+ }
+
+ /*
+ * Get the signal to deliver. When running under ptrace, at this
+ * point the debugger may change all our registers ...
+ */
+ /*
+ * Depending on the signal settings we may need to revert the
+ * decision to restart the system call. But skip this if a
+ * debugger has chosen to restart at a different PC.
+ */
+ if (get_signal(&ksig)) {
+ if (unlikely(restart) && regs->ipc == restart_addr) {
+ if (retval == -ERESTARTNOHAND ||
+ retval == -ERESTART_RESTARTBLOCK
+ || (retval == -ERESTARTSYS
+ && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
+ regs->uregs[0] = -EINTR;
+ regs->ipc = continue_addr;
+ }
+ }
+ handle_signal(&ksig, regs);
+ } else {
+ restore_saved_sigmask();
+ if (unlikely(restart) && regs->ipc == restart_addr) {
+ regs->ipc = continue_addr;
+ return restart;
+ }
+ }
+ return 0;
+}
+
+asmlinkage int
+do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
+{
+ if (thread_flags & _TIF_SIGPENDING)
+ return do_signal(regs, syscall);
+
+ if (thread_flags & _TIF_NOTIFY_RESUME) {
+ clear_thread_flag(TIF_NOTIFY_RESUME);
+ tracehook_notify_resume(regs);
+ }
+ return 0;
+}
--
1.7.9.5
From 1586149844574973362@xxx Thu Dec 07 18:12:48 +0000 2017
X-GM-THRID: 1586149844574973362
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread
From: Greentime Hu <[email protected]>
Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
arch/nds32/include/asm/io.h | 33 +++++++++++++++++++++
arch/nds32/mm/ioremap.c | 67 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 100 insertions(+)
create mode 100644 arch/nds32/include/asm/io.h
create mode 100644 arch/nds32/mm/ioremap.c
diff --git a/arch/nds32/include/asm/io.h b/arch/nds32/include/asm/io.h
new file mode 100644
index 0000000..98b3ae9
--- /dev/null
+++ b/arch/nds32/include/asm/io.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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_NDS32_IO_H
+#define __ASM_NDS32_IO_H
+
+#ifdef __KERNEL__
+
+#include <asm-generic/iomap.h>
+extern void __iomem *__ioremap(unsigned long, size_t, unsigned long,
+ unsigned long);
+extern void __iounmap(void __iomem * addr);
+
+#define ioremap(cookie,size) __ioremap(cookie,size,0,1)
+#define ioremap_nocache(cookie,size) __ioremap(cookie,size,0,1)
+#define iounmap(cookie) __iounmap(cookie)
+#include <asm-generic/io.h>
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_NDS32_IO_H */
diff --git a/arch/nds32/mm/ioremap.c b/arch/nds32/mm/ioremap.c
new file mode 100644
index 0000000..532e6cf
--- /dev/null
+++ b/arch/nds32/mm/ioremap.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * 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/>.
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <asm/pgtable.h>
+
+void __iomem *__ioremap(unsigned long phys_addr, size_t size,
+ unsigned long flags, unsigned long align)
+{
+ struct vm_struct *area;
+ unsigned long addr, offset, last_addr;
+ pgprot_t prot;
+
+ /* Don't allow wraparound or zero size */
+ last_addr = phys_addr + size - 1;
+ if (!size || last_addr < phys_addr)
+ return NULL;
+
+ /*
+ * Mappings have to be page-aligned
+ */
+ offset = phys_addr & ~PAGE_MASK;
+ phys_addr &= PAGE_MASK;
+ size = PAGE_ALIGN(last_addr + 1) - phys_addr;
+
+ /*
+ * Ok, go for it..
+ */
+ area = get_vm_area(size, VM_IOREMAP);
+ if (!area)
+ return NULL;
+
+ area->phys_addr = phys_addr;
+ addr = (unsigned long)area->addr;
+ prot = __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D |
+ _PAGE_G | _PAGE_C_DEV);
+ if (ioremap_page_range(addr, addr + size, phys_addr, prot)) {
+ vunmap((void *)addr);
+ return NULL;
+ }
+ return (__force void __iomem *)(offset + (char *)addr);
+
+}
+
+EXPORT_SYMBOL(__ioremap);
+
+void __iounmap(void __iomem * addr)
+{
+ vunmap((void *)(PAGE_MASK & (unsigned long)addr));
+}
+
+EXPORT_SYMBOL(__iounmap);
--
1.7.9.5
From 1584958808108274638@xxx Fri Nov 24 14:41:47 +0000 2017
X-GM-THRID: 1584142038298704251
X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread