mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
Merge branch 'linux-linaro-lsk' into linux-linaro-lsk-android
Conflicts: arch/arm64/Makefile
This commit is contained in:
@@ -68,13 +68,23 @@ Image target is available instead.
|
||||
|
||||
Requirement: MANDATORY
|
||||
|
||||
The decompressed kernel image contains a 32-byte header as follows:
|
||||
The decompressed kernel image contains a 64-byte header as follows:
|
||||
|
||||
u32 magic = 0x14000008; /* branch to stext, little-endian */
|
||||
u32 res0 = 0; /* reserved */
|
||||
u32 code0; /* Executable code */
|
||||
u32 code1; /* Executable code */
|
||||
u64 text_offset; /* Image load offset */
|
||||
u64 res0 = 0; /* reserved */
|
||||
u64 res1 = 0; /* reserved */
|
||||
u64 res2 = 0; /* reserved */
|
||||
u64 res3 = 0; /* reserved */
|
||||
u64 res4 = 0; /* reserved */
|
||||
u32 magic = 0x644d5241; /* Magic number, little endian, "ARM\x64" */
|
||||
u32 res5 = 0; /* reserved */
|
||||
|
||||
|
||||
Header notes:
|
||||
|
||||
- code0/code1 are responsible for branching to stext.
|
||||
|
||||
The image must be placed at the specified offset (currently 0x80000)
|
||||
from the start of the system RAM and called there. The start of the
|
||||
|
||||
@@ -21,7 +21,7 @@ The swapper_pgd_dir address is written to TTBR1 and never written to
|
||||
TTBR0.
|
||||
|
||||
|
||||
AArch64 Linux memory layout:
|
||||
AArch64 Linux memory layout with 4KB pages:
|
||||
|
||||
Start End Size Use
|
||||
-----------------------------------------------------------------------
|
||||
@@ -46,6 +46,31 @@ ffffffbffc000000 ffffffbfffffffff 64MB modules
|
||||
ffffffc000000000 ffffffffffffffff 256GB kernel logical memory map
|
||||
|
||||
|
||||
AArch64 Linux memory layout with 64KB pages:
|
||||
|
||||
Start End Size Use
|
||||
-----------------------------------------------------------------------
|
||||
0000000000000000 000003ffffffffff 4TB user
|
||||
|
||||
fffffc0000000000 fffffdfbfffeffff ~2TB vmalloc
|
||||
|
||||
fffffdfbffff0000 fffffdfbffffffff 64KB [guard page]
|
||||
|
||||
fffffdfc00000000 fffffdfdffffffff 8GB vmemmap
|
||||
|
||||
fffffdfe00000000 fffffdfffbbfffff ~8GB [guard, future vmmemap]
|
||||
|
||||
fffffdfffbc00000 fffffdfffbdfffff 2MB earlyprintk device
|
||||
|
||||
fffffdfffbe00000 fffffdfffbe0ffff 64KB PCI I/O space
|
||||
|
||||
fffffdfffbe10000 fffffdfffbffffff ~2MB [guard]
|
||||
|
||||
fffffdfffc000000 fffffdffffffffff 64MB modules
|
||||
|
||||
fffffe0000000000 ffffffffffffffff 2TB kernel logical memory map
|
||||
|
||||
|
||||
Translation table lookup with 4KB pages:
|
||||
|
||||
+--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
|
||||
@@ -157,9 +157,8 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF_FLATTREE
|
||||
void __init early_init_dt_setup_initrd_arch(unsigned long start,
|
||||
unsigned long end)
|
||||
void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
|
||||
{
|
||||
pr_err("%s(%lx, %lx)\n", __func__, start, end);
|
||||
pr_err("%s(%llx, %llx)\n", __func__, start, end);
|
||||
}
|
||||
#endif /* CONFIG_OF_FLATTREE */
|
||||
|
||||
@@ -19,8 +19,6 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
|
||||
|
||||
typedef struct user_fp elf_fpregset_t;
|
||||
|
||||
#define EM_ARM 40
|
||||
|
||||
#define EF_ARM_EABI_MASK 0xff000000
|
||||
#define EF_ARM_EABI_UNKNOWN 0x00000000
|
||||
#define EF_ARM_EABI_VER1 0x01000000
|
||||
|
||||
@@ -76,7 +76,7 @@ static int __init parse_tag_initrd2(const struct tag *tag)
|
||||
__tagtable(ATAG_INITRD2, parse_tag_initrd2);
|
||||
|
||||
#ifdef CONFIG_OF_FLATTREE
|
||||
void __init early_init_dt_setup_initrd_arch(unsigned long start, unsigned long end)
|
||||
void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
|
||||
{
|
||||
phys_initrd_start = start;
|
||||
phys_initrd_size = end - start;
|
||||
|
||||
@@ -9,15 +9,19 @@ config ARM64
|
||||
select ARM_AMBA
|
||||
select ARM_ARCH_TIMER
|
||||
select ARM_GIC
|
||||
select BUILDTIME_EXTABLE_SORT
|
||||
select CLONE_BACKWARDS
|
||||
select COMMON_CLK
|
||||
select CPU_PM if (SUSPEND || CPU_IDLE)
|
||||
select DCACHE_WORD_ACCESS
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
|
||||
select GENERIC_IOMAP
|
||||
select GENERIC_IRQ_PROBE
|
||||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select GENERIC_STRNCPY_FROM_USER
|
||||
select GENERIC_STRNLEN_USER
|
||||
select GENERIC_TIME_VSYSCALL
|
||||
select HARDIRQS_SW_RESEND
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
@@ -26,6 +30,7 @@ config ARM64
|
||||
select HAVE_DMA_API_DEBUG
|
||||
select HAVE_DMA_ATTRS
|
||||
select HAVE_DMA_CONTIGUOUS
|
||||
select HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||
select HAVE_GENERIC_DMA_COHERENT
|
||||
select HAVE_GENERIC_HARDIRQS
|
||||
select HAVE_HW_BREAKPOINT if PERF_EVENTS
|
||||
@@ -66,10 +71,6 @@ config LOCKDEP_SUPPORT
|
||||
config TRACE_IRQFLAGS_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config GENERIC_LOCKBREAK
|
||||
def_bool y
|
||||
depends on SMP && PREEMPT
|
||||
|
||||
config RWSEM_GENERIC_SPINLOCK
|
||||
def_bool y
|
||||
|
||||
@@ -116,6 +117,11 @@ config ARCH_VEXPRESS
|
||||
This enables support for the ARMv8 software model (Versatile
|
||||
Express).
|
||||
|
||||
config ARCH_XGENE
|
||||
bool "AppliedMicro X-Gene SOC Family"
|
||||
help
|
||||
This enables support for AppliedMicro X-Gene SOC Family
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Bus support"
|
||||
@@ -270,7 +276,8 @@ config NR_CPUS
|
||||
int "Maximum number of CPUs (2-32)"
|
||||
range 2 32
|
||||
depends on SMP
|
||||
default "4"
|
||||
# These have to remain sorted largest to smallest
|
||||
default "8"
|
||||
|
||||
config HOTPLUG_CPU
|
||||
bool "Support for hot-pluggable CPUs"
|
||||
|
||||
@@ -74,6 +74,10 @@ dtbs: scripts
|
||||
Image.gz-dtb: vmlinux scripts dtbs
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
|
||||
PHONY += vdso_install
|
||||
vdso_install:
|
||||
$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@
|
||||
|
||||
# We use MRPROPER_FILES and CLEAN_FILES now
|
||||
archclean:
|
||||
$(Q)$(MAKE) $(clean)=$(boot)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb \
|
||||
fvp-base-gicv2-psci.dtb
|
||||
dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb
|
||||
dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb
|
||||
|
||||
targets += dtbs
|
||||
|
||||
|
||||
26
arch/arm64/boot/dts/apm-mustang.dts
Normal file
26
arch/arm64/boot/dts/apm-mustang.dts
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* dts file for AppliedMicro (APM) Mustang Board
|
||||
*
|
||||
* Copyright (C) 2013, Applied Micro Circuits 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; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/include/ "apm-storm.dtsi"
|
||||
|
||||
/ {
|
||||
model = "APM X-Gene Mustang board";
|
||||
compatible = "apm,mustang", "apm,xgene-storm";
|
||||
|
||||
chosen { };
|
||||
|
||||
memory {
|
||||
device_type = "memory";
|
||||
reg = < 0x1 0x00000000 0x0 0x80000000 >; /* Updated by bootloader */
|
||||
};
|
||||
};
|
||||
191
arch/arm64/boot/dts/apm-storm.dtsi
Normal file
191
arch/arm64/boot/dts/apm-storm.dtsi
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* dts file for AppliedMicro (APM) X-Gene Storm SOC
|
||||
*
|
||||
* Copyright (C) 2013, Applied Micro Circuits 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; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
/ {
|
||||
compatible = "apm,xgene-storm";
|
||||
interrupt-parent = <&gic>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
cpus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cpu@000 {
|
||||
device_type = "cpu";
|
||||
compatible = "apm,potenza", "arm,armv8";
|
||||
reg = <0x0 0x000>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x1 0x0000fff8>;
|
||||
};
|
||||
cpu@001 {
|
||||
device_type = "cpu";
|
||||
compatible = "apm,potenza", "arm,armv8";
|
||||
reg = <0x0 0x001>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x1 0x0000fff8>;
|
||||
};
|
||||
cpu@100 {
|
||||
device_type = "cpu";
|
||||
compatible = "apm,potenza", "arm,armv8";
|
||||
reg = <0x0 0x100>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x1 0x0000fff8>;
|
||||
};
|
||||
cpu@101 {
|
||||
device_type = "cpu";
|
||||
compatible = "apm,potenza", "arm,armv8";
|
||||
reg = <0x0 0x101>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x1 0x0000fff8>;
|
||||
};
|
||||
cpu@200 {
|
||||
device_type = "cpu";
|
||||
compatible = "apm,potenza", "arm,armv8";
|
||||
reg = <0x0 0x200>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x1 0x0000fff8>;
|
||||
};
|
||||
cpu@201 {
|
||||
device_type = "cpu";
|
||||
compatible = "apm,potenza", "arm,armv8";
|
||||
reg = <0x0 0x201>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x1 0x0000fff8>;
|
||||
};
|
||||
cpu@300 {
|
||||
device_type = "cpu";
|
||||
compatible = "apm,potenza", "arm,armv8";
|
||||
reg = <0x0 0x300>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x1 0x0000fff8>;
|
||||
};
|
||||
cpu@301 {
|
||||
device_type = "cpu";
|
||||
compatible = "apm,potenza", "arm,armv8";
|
||||
reg = <0x0 0x301>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x1 0x0000fff8>;
|
||||
};
|
||||
};
|
||||
|
||||
gic: interrupt-controller@78010000 {
|
||||
compatible = "arm,cortex-a15-gic";
|
||||
#interrupt-cells = <3>;
|
||||
interrupt-controller;
|
||||
reg = <0x0 0x78010000 0x0 0x1000>, /* GIC Dist */
|
||||
<0x0 0x78020000 0x0 0x1000>, /* GIC CPU */
|
||||
<0x0 0x78040000 0x0 0x2000>, /* GIC VCPU Control */
|
||||
<0x0 0x78060000 0x0 0x2000>; /* GIC VCPU */
|
||||
interrupts = <1 9 0xf04>; /* GIC Maintenence IRQ */
|
||||
};
|
||||
|
||||
timer {
|
||||
compatible = "arm,armv8-timer";
|
||||
interrupts = <1 0 0xff01>, /* Secure Phys IRQ */
|
||||
<1 13 0xff01>, /* Non-secure Phys IRQ */
|
||||
<1 14 0xff01>, /* Virt IRQ */
|
||||
<1 15 0xff01>; /* Hyp IRQ */
|
||||
clock-frequency = <50000000>;
|
||||
};
|
||||
|
||||
soc {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
clocks {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
refclk: refclk {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <1>;
|
||||
clock-frequency = <100000000>;
|
||||
clock-output-names = "refclk";
|
||||
};
|
||||
|
||||
pcppll: pcppll@17000100 {
|
||||
compatible = "apm,xgene-pcppll-clock";
|
||||
#clock-cells = <1>;
|
||||
clocks = <&refclk 0>;
|
||||
clock-names = "pcppll";
|
||||
reg = <0x0 0x17000100 0x0 0x1000>;
|
||||
clock-output-names = "pcppll";
|
||||
type = <0>;
|
||||
};
|
||||
|
||||
socpll: socpll@17000120 {
|
||||
compatible = "apm,xgene-socpll-clock";
|
||||
#clock-cells = <1>;
|
||||
clocks = <&refclk 0>;
|
||||
clock-names = "socpll";
|
||||
reg = <0x0 0x17000120 0x0 0x1000>;
|
||||
clock-output-names = "socpll";
|
||||
type = <1>;
|
||||
};
|
||||
|
||||
socplldiv2: socplldiv2 {
|
||||
compatible = "fixed-factor-clock";
|
||||
#clock-cells = <1>;
|
||||
clocks = <&socpll 0>;
|
||||
clock-names = "socplldiv2";
|
||||
clock-mult = <1>;
|
||||
clock-div = <2>;
|
||||
clock-output-names = "socplldiv2";
|
||||
};
|
||||
|
||||
qmlclk: qmlclk {
|
||||
compatible = "apm,xgene-device-clock";
|
||||
#clock-cells = <1>;
|
||||
clocks = <&socplldiv2 0>;
|
||||
clock-names = "qmlclk";
|
||||
reg = <0x0 0x1703C000 0x0 0x1000>;
|
||||
reg-names = "csr-reg";
|
||||
clock-output-names = "qmlclk";
|
||||
};
|
||||
|
||||
ethclk: ethclk {
|
||||
compatible = "apm,xgene-device-clock";
|
||||
#clock-cells = <1>;
|
||||
clocks = <&socplldiv2 0>;
|
||||
clock-names = "ethclk";
|
||||
reg = <0x0 0x17000000 0x0 0x1000>;
|
||||
reg-names = "div-reg";
|
||||
divider-offset = <0x238>;
|
||||
divider-width = <0x9>;
|
||||
divider-shift = <0x0>;
|
||||
clock-output-names = "ethclk";
|
||||
};
|
||||
|
||||
eth8clk: eth8clk {
|
||||
compatible = "apm,xgene-device-clock";
|
||||
#clock-cells = <1>;
|
||||
clocks = <ðclk 0>;
|
||||
clock-names = "eth8clk";
|
||||
reg = <0x0 0x1702C000 0x0 0x1000>;
|
||||
reg-names = "csr-reg";
|
||||
clock-output-names = "eth8clk";
|
||||
};
|
||||
};
|
||||
|
||||
serial0: serial@1c020000 {
|
||||
device_type = "serial";
|
||||
compatible = "ns16550";
|
||||
reg = <0 0x1c020000 0x0 0x1000>;
|
||||
reg-shift = <2>;
|
||||
clock-frequency = <10000000>; /* Updated by bootloader */
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0x0 0x4c 0x4>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -24,6 +24,7 @@ CONFIG_MODULE_UNLOAD=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
CONFIG_ARCH_VEXPRESS=y
|
||||
CONFIG_ARCH_XGENE=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_PREEMPT_VOLUNTARY=y
|
||||
CONFIG_CMDLINE="console=ttyAMA0"
|
||||
@@ -54,6 +55,9 @@ CONFIG_INPUT_EVDEV=y
|
||||
# CONFIG_SERIO_I8042 is not set
|
||||
# CONFIG_SERIO_SERPORT is not set
|
||||
CONFIG_LEGACY_PTY_COUNT=16
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_SERIAL_AMBA_PL011=y
|
||||
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
|
||||
@@ -131,9 +131,6 @@ static inline void __flush_icache_all(void)
|
||||
#define flush_dcache_mmap_unlock(mapping) \
|
||||
spin_unlock_irq(&(mapping)->tree_lock)
|
||||
|
||||
#define flush_icache_user_range(vma,page,addr,len) \
|
||||
flush_dcache_page(page)
|
||||
|
||||
/*
|
||||
* We don't appear to need to do anything here. In fact, if we did, we'd
|
||||
* duplicate cache flushing elsewhere performed by flush_dcache_page().
|
||||
|
||||
@@ -179,4 +179,6 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
|
||||
#define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n))
|
||||
#define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n))
|
||||
|
||||
#define cmpxchg64_relaxed(ptr,o,n) cmpxchg_local((ptr),(o),(n))
|
||||
|
||||
#endif /* __ASM_CMPXCHG_H */
|
||||
|
||||
@@ -47,11 +47,14 @@
|
||||
})
|
||||
|
||||
#define ARM_CPU_IMP_ARM 0x41
|
||||
#define ARM_CPU_IMP_APM 0x50
|
||||
|
||||
#define ARM_CPU_PART_AEM_V8 0xD0F0
|
||||
#define ARM_CPU_PART_FOUNDATION 0xD000
|
||||
#define ARM_CPU_PART_CORTEX_A57 0xD070
|
||||
|
||||
#define APM_CPU_PART_POTENZA 0x0000
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/*
|
||||
|
||||
@@ -83,6 +83,8 @@ static inline int reinstall_suspended_bps(struct pt_regs *regs)
|
||||
}
|
||||
#endif
|
||||
|
||||
int aarch32_break_handler(struct pt_regs *regs);
|
||||
|
||||
#endif /* __ASSEMBLY */
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* __ASM_DEBUG_MONITORS_H */
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
struct dev_archdata {
|
||||
struct dma_map_ops *dma_ops;
|
||||
#ifdef CONFIG_IOMMU_API
|
||||
void *iommu; /* private IOMMU data */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct pdev_archdata {
|
||||
|
||||
@@ -33,8 +33,6 @@ typedef unsigned long elf_greg_t;
|
||||
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
|
||||
typedef struct user_fpsimd_state elf_fpregset_t;
|
||||
|
||||
#define EM_AARCH64 183
|
||||
|
||||
/*
|
||||
* AArch64 static relocation types.
|
||||
*/
|
||||
@@ -164,7 +162,6 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
|
||||
#define arch_randomize_brk arch_randomize_brk
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
#define EM_ARM 40
|
||||
|
||||
#ifdef __AARCH64EB__
|
||||
#define COMPAT_ELF_PLATFORM ("v8b")
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
" cbnz %w3, 1b\n" \
|
||||
"3:\n" \
|
||||
" .pushsection .fixup,\"ax\"\n" \
|
||||
" .align 2\n" \
|
||||
"4: mov %w0, %w5\n" \
|
||||
" b 3b\n" \
|
||||
" .popsection\n" \
|
||||
|
||||
@@ -44,6 +44,6 @@
|
||||
extern unsigned int compat_elf_hwcap;
|
||||
#endif
|
||||
|
||||
extern unsigned int elf_hwcap;
|
||||
extern unsigned long elf_hwcap;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -33,18 +33,23 @@
|
||||
#define UL(x) _AC(x, UL)
|
||||
|
||||
/*
|
||||
* PAGE_OFFSET - the virtual address of the start of the kernel image.
|
||||
* PAGE_OFFSET - the virtual address of the start of the kernel image (top
|
||||
* (VA_BITS - 1))
|
||||
* VA_BITS - the maximum number of bits for virtual addresses.
|
||||
* TASK_SIZE - the maximum size of a user space task.
|
||||
* TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area.
|
||||
* The module space lives between the addresses given by TASK_SIZE
|
||||
* and PAGE_OFFSET - it must be within 128MB of the kernel text.
|
||||
*/
|
||||
#define PAGE_OFFSET UL(0xffffffc000000000)
|
||||
#ifdef CONFIG_ARM64_64K_PAGES
|
||||
#define VA_BITS (42)
|
||||
#else
|
||||
#define VA_BITS (39)
|
||||
#endif
|
||||
#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1))
|
||||
#define MODULES_END (PAGE_OFFSET)
|
||||
#define MODULES_VADDR (MODULES_END - SZ_64M)
|
||||
#define EARLYCON_IOBASE (MODULES_VADDR - SZ_4M)
|
||||
#define VA_BITS (39)
|
||||
#define TASK_SIZE_64 (UL(1) << VA_BITS)
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
@@ -151,12 +151,6 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* check for possible thread migration */
|
||||
if (!cpumask_empty(mm_cpumask(next)) &&
|
||||
!cpumask_test_cpu(cpu, mm_cpumask(next)))
|
||||
__flush_icache_all();
|
||||
#endif
|
||||
if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next)
|
||||
check_and_switch_context(next, tsk);
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
* 8192 entries of 8 bytes each, occupying a 64KB page. Levels 0 and 1 are not
|
||||
* used. The 2nd level table (PGD for Linux) can cover a range of 4TB, each
|
||||
* entry representing 512MB. The user and kernel address spaces are limited to
|
||||
* 512GB and therefore we only use 1024 entries in the PGD.
|
||||
* 4TB in the 64KB page configuration.
|
||||
*/
|
||||
#define PTRS_PER_PTE 8192
|
||||
#define PTRS_PER_PGD 1024
|
||||
#define PTRS_PER_PGD 8192
|
||||
|
||||
/*
|
||||
* PGDIR_SHIFT determines the size a top-level page table entry can map.
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#ifndef __ASM_PGTABLE_2LEVEL_TYPES_H
|
||||
#define __ASM_PGTABLE_2LEVEL_TYPES_H
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
typedef u64 pteval_t;
|
||||
typedef u64 pgdval_t;
|
||||
typedef pgdval_t pmdval_t;
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
/*
|
||||
* VMALLOC and SPARSEMEM_VMEMMAP ranges.
|
||||
*/
|
||||
#define VMALLOC_START UL(0xffffff8000000000)
|
||||
#define VMALLOC_START (UL(0xffffffffffffffff) << VA_BITS)
|
||||
#define VMALLOC_END (PAGE_OFFSET - UL(0x400000000) - SZ_64K)
|
||||
|
||||
#define vmemmap ((struct page *)(VMALLOC_END + SZ_64K))
|
||||
@@ -120,7 +120,7 @@ extern struct page *empty_zero_page;
|
||||
#define pte_none(pte) (!pte_val(pte))
|
||||
#define pte_clear(mm,addr,ptep) set_pte(ptep, __pte(0))
|
||||
#define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
|
||||
#define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
|
||||
#define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + pte_index(addr))
|
||||
|
||||
#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))
|
||||
#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr))
|
||||
@@ -361,7 +361,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
|
||||
#endif
|
||||
|
||||
/* Find an entry in the third-level page table.. */
|
||||
#define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
|
||||
#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
|
||||
|
||||
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
|
||||
{
|
||||
|
||||
@@ -172,7 +172,5 @@ extern unsigned long profile_pc(struct pt_regs *regs);
|
||||
#define profile_pc(regs) instruction_pointer(regs)
|
||||
#endif
|
||||
|
||||
extern int aarch32_break_trap(struct pt_regs *regs);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif
|
||||
|
||||
@@ -22,17 +22,10 @@
|
||||
/*
|
||||
* Spinlock implementation.
|
||||
*
|
||||
* The old value is read exclusively and the new one, if unlocked, is written
|
||||
* exclusively. In case of failure, the loop is restarted.
|
||||
*
|
||||
* The memory barriers are implicit with the load-acquire and store-release
|
||||
* instructions.
|
||||
*
|
||||
* Unlocked value: 0
|
||||
* Locked value: 1
|
||||
*/
|
||||
|
||||
#define arch_spin_is_locked(x) ((x)->lock != 0)
|
||||
#define arch_spin_unlock_wait(lock) \
|
||||
do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0)
|
||||
|
||||
@@ -41,32 +34,51 @@
|
||||
static inline void arch_spin_lock(arch_spinlock_t *lock)
|
||||
{
|
||||
unsigned int tmp;
|
||||
arch_spinlock_t lockval, newval;
|
||||
|
||||
asm volatile(
|
||||
" sevl\n"
|
||||
"1: wfe\n"
|
||||
"2: ldaxr %w0, %1\n"
|
||||
" cbnz %w0, 1b\n"
|
||||
" stxr %w0, %w2, %1\n"
|
||||
" cbnz %w0, 2b\n"
|
||||
: "=&r" (tmp), "+Q" (lock->lock)
|
||||
: "r" (1)
|
||||
: "cc", "memory");
|
||||
/* Atomically increment the next ticket. */
|
||||
" prfm pstl1strm, %3\n"
|
||||
"1: ldaxr %w0, %3\n"
|
||||
" add %w1, %w0, %w5\n"
|
||||
" stxr %w2, %w1, %3\n"
|
||||
" cbnz %w2, 1b\n"
|
||||
/* Did we get the lock? */
|
||||
" eor %w1, %w0, %w0, ror #16\n"
|
||||
" cbz %w1, 3f\n"
|
||||
/*
|
||||
* No: spin on the owner. Send a local event to avoid missing an
|
||||
* unlock before the exclusive load.
|
||||
*/
|
||||
" sevl\n"
|
||||
"2: wfe\n"
|
||||
" ldaxrh %w2, %4\n"
|
||||
" eor %w1, %w2, %w0, lsr #16\n"
|
||||
" cbnz %w1, 2b\n"
|
||||
/* We got the lock. Critical section starts here. */
|
||||
"3:"
|
||||
: "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock)
|
||||
: "Q" (lock->owner), "I" (1 << TICKET_SHIFT)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline int arch_spin_trylock(arch_spinlock_t *lock)
|
||||
{
|
||||
unsigned int tmp;
|
||||
arch_spinlock_t lockval;
|
||||
|
||||
asm volatile(
|
||||
"2: ldaxr %w0, %1\n"
|
||||
" cbnz %w0, 1f\n"
|
||||
" stxr %w0, %w2, %1\n"
|
||||
" cbnz %w0, 2b\n"
|
||||
"1:\n"
|
||||
: "=&r" (tmp), "+Q" (lock->lock)
|
||||
: "r" (1)
|
||||
: "cc", "memory");
|
||||
" prfm pstl1strm, %2\n"
|
||||
"1: ldaxr %w0, %2\n"
|
||||
" eor %w1, %w0, %w0, ror #16\n"
|
||||
" cbnz %w1, 2f\n"
|
||||
" add %w0, %w0, %3\n"
|
||||
" stxr %w1, %w0, %2\n"
|
||||
" cbnz %w1, 1b\n"
|
||||
"2:"
|
||||
: "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
|
||||
: "I" (1 << TICKET_SHIFT)
|
||||
: "memory");
|
||||
|
||||
return !tmp;
|
||||
}
|
||||
@@ -74,10 +86,29 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
|
||||
static inline void arch_spin_unlock(arch_spinlock_t *lock)
|
||||
{
|
||||
asm volatile(
|
||||
" stlr %w1, %0\n"
|
||||
: "=Q" (lock->lock) : "r" (0) : "memory");
|
||||
" stlrh %w1, %0\n"
|
||||
: "=Q" (lock->owner)
|
||||
: "r" (lock->owner + 1)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
|
||||
{
|
||||
return lock.owner == lock.next;
|
||||
}
|
||||
|
||||
static inline int arch_spin_is_locked(arch_spinlock_t *lock)
|
||||
{
|
||||
return !arch_spin_value_unlocked(ACCESS_ONCE(*lock));
|
||||
}
|
||||
|
||||
static inline int arch_spin_is_contended(arch_spinlock_t *lock)
|
||||
{
|
||||
arch_spinlock_t lockval = ACCESS_ONCE(*lock);
|
||||
return (lockval.next - lockval.owner) > 1;
|
||||
}
|
||||
#define arch_spin_is_contended arch_spin_is_contended
|
||||
|
||||
/*
|
||||
* Write lock implementation.
|
||||
*
|
||||
|
||||
@@ -20,14 +20,14 @@
|
||||
# error "please don't include this file directly"
|
||||
#endif
|
||||
|
||||
/* We only require natural alignment for exclusive accesses. */
|
||||
#define __lock_aligned
|
||||
#define TICKET_SHIFT 16
|
||||
|
||||
typedef struct {
|
||||
volatile unsigned int lock;
|
||||
} arch_spinlock_t;
|
||||
u16 owner;
|
||||
u16 next;
|
||||
} __aligned(4) arch_spinlock_t;
|
||||
|
||||
#define __ARCH_SPIN_LOCK_UNLOCKED { 0 }
|
||||
#define __ARCH_SPIN_LOCK_UNLOCKED { 0 , 0 }
|
||||
|
||||
typedef struct {
|
||||
volatile unsigned int lock;
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
#ifndef __ASM_TIMEX_H
|
||||
#define __ASM_TIMEX_H
|
||||
|
||||
#include <asm/arch_timer.h>
|
||||
|
||||
/*
|
||||
* Use the current timer as a cycle counter since this is what we use for
|
||||
* the delay loop.
|
||||
*/
|
||||
#define get_cycles() ({ cycles_t c; read_current_timer(&c); c; })
|
||||
#define get_cycles() arch_counter_get_cntvct()
|
||||
|
||||
#include <asm-generic/timex.h>
|
||||
|
||||
#define ARCH_HAS_READ_CURRENT_TIMER
|
||||
|
||||
#endif
|
||||
|
||||
@@ -100,6 +100,7 @@ static inline void set_fs(mm_segment_t fs)
|
||||
})
|
||||
|
||||
#define access_ok(type, addr, size) __range_ok(addr, size)
|
||||
#define user_addr_max get_fs
|
||||
|
||||
/*
|
||||
* The "__xxx" versions of the user access functions do not verify the address
|
||||
@@ -238,9 +239,6 @@ extern unsigned long __must_check __copy_to_user(void __user *to, const void *fr
|
||||
extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n);
|
||||
extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
|
||||
|
||||
extern unsigned long __must_check __strncpy_from_user(char *to, const char __user *from, unsigned long count);
|
||||
extern unsigned long __must_check __strnlen_user(const char __user *s, long n);
|
||||
|
||||
static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||
{
|
||||
if (access_ok(VERIFY_READ, from, n))
|
||||
@@ -274,24 +272,9 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline long __must_check strncpy_from_user(char *dst, const char __user *src, long count)
|
||||
{
|
||||
long res = -EFAULT;
|
||||
if (access_ok(VERIFY_READ, src, 1))
|
||||
res = __strncpy_from_user(dst, src, count);
|
||||
return res;
|
||||
}
|
||||
extern long strncpy_from_user(char *dest, const char __user *src, long count);
|
||||
|
||||
#define strlen_user(s) strnlen_user(s, ~0UL >> 1)
|
||||
|
||||
static inline long __must_check strnlen_user(const char __user *s, long n)
|
||||
{
|
||||
unsigned long res = 0;
|
||||
|
||||
if (__addr_ok(s))
|
||||
res = __strnlen_user(s, n);
|
||||
|
||||
return res;
|
||||
}
|
||||
extern __must_check long strlen_user(const char __user *str);
|
||||
extern __must_check long strnlen_user(const char __user *str, long n);
|
||||
|
||||
#endif /* __ASM_UACCESS_H */
|
||||
|
||||
94
arch/arm64/include/asm/word-at-a-time.h
Normal file
94
arch/arm64/include/asm/word-at-a-time.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2013 ARM Ltd.
|
||||
*
|
||||
* 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_WORD_AT_A_TIME_H
|
||||
#define __ASM_WORD_AT_A_TIME_H
|
||||
|
||||
#ifndef __AARCH64EB__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
struct word_at_a_time {
|
||||
const unsigned long one_bits, high_bits;
|
||||
};
|
||||
|
||||
#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
|
||||
|
||||
static inline unsigned long has_zero(unsigned long a, unsigned long *bits,
|
||||
const struct word_at_a_time *c)
|
||||
{
|
||||
unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
|
||||
*bits = mask;
|
||||
return mask;
|
||||
}
|
||||
|
||||
#define prep_zero_mask(a, bits, c) (bits)
|
||||
|
||||
static inline unsigned long create_zero_mask(unsigned long bits)
|
||||
{
|
||||
bits = (bits - 1) & ~bits;
|
||||
return bits >> 7;
|
||||
}
|
||||
|
||||
static inline unsigned long find_zero(unsigned long mask)
|
||||
{
|
||||
return fls64(mask) >> 3;
|
||||
}
|
||||
|
||||
#define zero_bytemask(mask) (mask)
|
||||
|
||||
#else /* __AARCH64EB__ */
|
||||
#include <asm-generic/word-at-a-time.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Load an unaligned word from kernel space.
|
||||
*
|
||||
* In the (very unlikely) case of the word being a page-crosser
|
||||
* and the next page not being mapped, take the exception and
|
||||
* return zeroes in the non-existing part.
|
||||
*/
|
||||
static inline unsigned long load_unaligned_zeropad(const void *addr)
|
||||
{
|
||||
unsigned long ret, offset;
|
||||
|
||||
/* Load word from unaligned pointer addr */
|
||||
asm(
|
||||
"1: ldr %0, %3\n"
|
||||
"2:\n"
|
||||
" .pushsection .fixup,\"ax\"\n"
|
||||
" .align 2\n"
|
||||
"3: and %1, %2, #0x7\n"
|
||||
" bic %2, %2, #0x7\n"
|
||||
" ldr %0, [%2]\n"
|
||||
" lsl %1, %1, #0x3\n"
|
||||
#ifndef __AARCH64EB__
|
||||
" lsr %0, %0, %1\n"
|
||||
#else
|
||||
" lsl %0, %0, %1\n"
|
||||
#endif
|
||||
" b 2b\n"
|
||||
" .popsection\n"
|
||||
" .pushsection __ex_table,\"a\"\n"
|
||||
" .align 3\n"
|
||||
" .quad 1b, 3b\n"
|
||||
" .popsection"
|
||||
: "=&r" (ret), "=&r" (offset)
|
||||
: "r" (addr), "Q" (*(unsigned long *)addr));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __ASM_WORD_AT_A_TIME_H */
|
||||
@@ -29,16 +29,14 @@
|
||||
|
||||
#include <asm/checksum.h>
|
||||
|
||||
/* user mem (segment) */
|
||||
EXPORT_SYMBOL(__strnlen_user);
|
||||
EXPORT_SYMBOL(__strncpy_from_user);
|
||||
|
||||
EXPORT_SYMBOL(copy_page);
|
||||
EXPORT_SYMBOL(clear_page);
|
||||
|
||||
/* user mem (segment) */
|
||||
EXPORT_SYMBOL(__copy_from_user);
|
||||
EXPORT_SYMBOL(__copy_to_user);
|
||||
EXPORT_SYMBOL(__clear_user);
|
||||
EXPORT_SYMBOL(__copy_in_user);
|
||||
|
||||
/* physical memory */
|
||||
EXPORT_SYMBOL(memstart_addr);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/debug-monitors.h>
|
||||
#include <asm/local.h>
|
||||
@@ -226,13 +227,74 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init single_step_init(void)
|
||||
static int brk_handler(unsigned long addr, unsigned int esr,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
siginfo_t info;
|
||||
|
||||
if (!user_mode(regs))
|
||||
return -EFAULT;
|
||||
|
||||
info = (siginfo_t) {
|
||||
.si_signo = SIGTRAP,
|
||||
.si_errno = 0,
|
||||
.si_code = TRAP_BRKPT,
|
||||
.si_addr = (void __user *)instruction_pointer(regs),
|
||||
};
|
||||
|
||||
force_sig_info(SIGTRAP, &info, current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aarch32_break_handler(struct pt_regs *regs)
|
||||
{
|
||||
siginfo_t info;
|
||||
unsigned int instr;
|
||||
bool bp = false;
|
||||
void __user *pc = (void __user *)instruction_pointer(regs);
|
||||
|
||||
if (!compat_user_mode(regs))
|
||||
return -EFAULT;
|
||||
|
||||
if (compat_thumb_mode(regs)) {
|
||||
/* get 16-bit Thumb instruction */
|
||||
get_user(instr, (u16 __user *)pc);
|
||||
if (instr == AARCH32_BREAK_THUMB2_LO) {
|
||||
/* get second half of 32-bit Thumb-2 instruction */
|
||||
get_user(instr, (u16 __user *)(pc + 2));
|
||||
bp = instr == AARCH32_BREAK_THUMB2_HI;
|
||||
} else {
|
||||
bp = instr == AARCH32_BREAK_THUMB;
|
||||
}
|
||||
} else {
|
||||
/* 32-bit ARM instruction */
|
||||
get_user(instr, (u32 __user *)pc);
|
||||
bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
|
||||
}
|
||||
|
||||
if (!bp)
|
||||
return -EFAULT;
|
||||
|
||||
info = (siginfo_t) {
|
||||
.si_signo = SIGTRAP,
|
||||
.si_errno = 0,
|
||||
.si_code = TRAP_BRKPT,
|
||||
.si_addr = pc,
|
||||
};
|
||||
|
||||
force_sig_info(SIGTRAP, &info, current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init debug_traps_init(void)
|
||||
{
|
||||
hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP,
|
||||
TRAP_HWBKPT, "single-step handler");
|
||||
hook_debug_fault_code(DBG_ESR_EVT_BRK, brk_handler, SIGTRAP,
|
||||
TRAP_BRKPT, "ptrace BRK handler");
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(single_step_init);
|
||||
arch_initcall(debug_traps_init);
|
||||
|
||||
/* Re-enable single step for syscall restarting. */
|
||||
void user_rewind_single_step(struct task_struct *task)
|
||||
|
||||
@@ -311,14 +311,14 @@ el1_irq:
|
||||
#endif
|
||||
#ifdef CONFIG_PREEMPT
|
||||
get_thread_info tsk
|
||||
ldr x24, [tsk, #TI_PREEMPT] // get preempt count
|
||||
add x0, x24, #1 // increment it
|
||||
str x0, [tsk, #TI_PREEMPT]
|
||||
ldr w24, [tsk, #TI_PREEMPT] // get preempt count
|
||||
add w0, w24, #1 // increment it
|
||||
str w0, [tsk, #TI_PREEMPT]
|
||||
#endif
|
||||
irq_handler
|
||||
#ifdef CONFIG_PREEMPT
|
||||
str x24, [tsk, #TI_PREEMPT] // restore preempt count
|
||||
cbnz x24, 1f // preempt count != 0
|
||||
str w24, [tsk, #TI_PREEMPT] // restore preempt count
|
||||
cbnz w24, 1f // preempt count != 0
|
||||
ldr x0, [tsk, #TI_FLAGS] // get flags
|
||||
tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling?
|
||||
bl el1_preempt
|
||||
@@ -477,6 +477,8 @@ el0_undef:
|
||||
* Undefined instruction
|
||||
*/
|
||||
mov x0, sp
|
||||
// enable interrupts before calling the main handler
|
||||
enable_irq
|
||||
b do_undefinstr
|
||||
el0_dbg:
|
||||
/*
|
||||
@@ -507,15 +509,15 @@ el0_irq_naked:
|
||||
#endif
|
||||
get_thread_info tsk
|
||||
#ifdef CONFIG_PREEMPT
|
||||
ldr x24, [tsk, #TI_PREEMPT] // get preempt count
|
||||
add x23, x24, #1 // increment it
|
||||
str x23, [tsk, #TI_PREEMPT]
|
||||
ldr w24, [tsk, #TI_PREEMPT] // get preempt count
|
||||
add w23, w24, #1 // increment it
|
||||
str w23, [tsk, #TI_PREEMPT]
|
||||
#endif
|
||||
irq_handler
|
||||
#ifdef CONFIG_PREEMPT
|
||||
ldr x0, [tsk, #TI_PREEMPT]
|
||||
str x24, [tsk, #TI_PREEMPT]
|
||||
cmp x0, x23
|
||||
ldr w0, [tsk, #TI_PREEMPT]
|
||||
str w24, [tsk, #TI_PREEMPT]
|
||||
cmp w0, w23
|
||||
b.eq 1f
|
||||
mov x1, #0
|
||||
str x1, [x1] // BUG
|
||||
|
||||
@@ -112,6 +112,14 @@
|
||||
.quad TEXT_OFFSET // Image load offset from start of RAM
|
||||
.quad 0 // reserved
|
||||
.quad 0 // reserved
|
||||
.quad 0 // reserved
|
||||
.quad 0 // reserved
|
||||
.quad 0 // reserved
|
||||
.byte 0x41 // Magic number, "ARM\x64"
|
||||
.byte 0x52
|
||||
.byte 0x4d
|
||||
.byte 0x64
|
||||
.word 0 // reserved
|
||||
|
||||
ENTRY(stext)
|
||||
mov x21, x0 // x21=FDT
|
||||
|
||||
@@ -38,33 +38,30 @@ __kuser_cmpxchg64: // 0xffff0f60
|
||||
.inst 0xe92d00f0 // push {r4, r5, r6, r7}
|
||||
.inst 0xe1c040d0 // ldrd r4, r5, [r0]
|
||||
.inst 0xe1c160d0 // ldrd r6, r7, [r1]
|
||||
.inst 0xf57ff05f // dmb sy
|
||||
.inst 0xe1b20f9f // 1: ldrexd r0, r1, [r2]
|
||||
.inst 0xe1b20e9f // 1: ldaexd r0, r1, [r2]
|
||||
.inst 0xe0303004 // eors r3, r0, r4
|
||||
.inst 0x00313005 // eoreqs r3, r1, r5
|
||||
.inst 0x01a23f96 // strexdeq r3, r6, [r2]
|
||||
.inst 0x01a23e96 // stlexdeq r3, r6, [r2]
|
||||
.inst 0x03330001 // teqeq r3, #1
|
||||
.inst 0x0afffff9 // beq 1b
|
||||
.inst 0xf57ff05f // dmb sy
|
||||
.inst 0xe2730000 // rsbs r0, r3, #0
|
||||
.inst 0xe8bd00f0 // pop {r4, r5, r6, r7}
|
||||
.inst 0xe12fff1e // bx lr
|
||||
|
||||
.align 5
|
||||
__kuser_memory_barrier: // 0xffff0fa0
|
||||
.inst 0xf57ff05f // dmb sy
|
||||
.inst 0xf57ff05b // dmb ish
|
||||
.inst 0xe12fff1e // bx lr
|
||||
|
||||
.align 5
|
||||
__kuser_cmpxchg: // 0xffff0fc0
|
||||
.inst 0xf57ff05f // dmb sy
|
||||
.inst 0xe1923f9f // 1: ldrex r3, [r2]
|
||||
.inst 0xe1923e9f // 1: ldaex r3, [r2]
|
||||
.inst 0xe0533000 // subs r3, r3, r0
|
||||
.inst 0x01823f91 // strexeq r3, r1, [r2]
|
||||
.inst 0x01823e91 // stlexeq r3, r1, [r2]
|
||||
.inst 0x03330001 // teqeq r3, #1
|
||||
.inst 0x0afffffa // beq 1b
|
||||
.inst 0xe2730000 // rsbs r0, r3, #0
|
||||
.inst 0xeaffffef // b <__kuser_memory_barrier>
|
||||
.inst 0xe12fff1e // bx lr
|
||||
|
||||
.align 5
|
||||
__kuser_get_tls: // 0xffff0fe0
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/perf_event.h>
|
||||
@@ -362,27 +363,54 @@ validate_group(struct perf_event *event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
armpmu_disable_percpu_irq(void *data)
|
||||
{
|
||||
unsigned int irq = *(unsigned int *)data;
|
||||
disable_percpu_irq(irq);
|
||||
}
|
||||
|
||||
static void
|
||||
armpmu_release_hardware(struct arm_pmu *armpmu)
|
||||
{
|
||||
int i, irq, irqs;
|
||||
int irq;
|
||||
unsigned int i, irqs;
|
||||
struct platform_device *pmu_device = armpmu->plat_device;
|
||||
|
||||
irqs = min(pmu_device->num_resources, num_possible_cpus());
|
||||
if (!irqs)
|
||||
return;
|
||||
|
||||
for (i = 0; i < irqs; ++i) {
|
||||
if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
|
||||
continue;
|
||||
irq = platform_get_irq(pmu_device, i);
|
||||
if (irq >= 0)
|
||||
free_irq(irq, armpmu);
|
||||
irq = platform_get_irq(pmu_device, 0);
|
||||
if (irq <= 0)
|
||||
return;
|
||||
|
||||
if (irq_is_percpu(irq)) {
|
||||
on_each_cpu(armpmu_disable_percpu_irq, &irq, 1);
|
||||
free_percpu_irq(irq, &cpu_hw_events);
|
||||
} else {
|
||||
for (i = 0; i < irqs; ++i) {
|
||||
if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
|
||||
continue;
|
||||
irq = platform_get_irq(pmu_device, i);
|
||||
if (irq > 0)
|
||||
free_irq(irq, armpmu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
armpmu_enable_percpu_irq(void *data)
|
||||
{
|
||||
unsigned int irq = *(unsigned int *)data;
|
||||
enable_percpu_irq(irq, IRQ_TYPE_NONE);
|
||||
}
|
||||
|
||||
static int
|
||||
armpmu_reserve_hardware(struct arm_pmu *armpmu)
|
||||
{
|
||||
int i, err, irq, irqs;
|
||||
int err, irq;
|
||||
unsigned int i, irqs;
|
||||
struct platform_device *pmu_device = armpmu->plat_device;
|
||||
|
||||
if (!pmu_device) {
|
||||
@@ -391,39 +419,59 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu)
|
||||
}
|
||||
|
||||
irqs = min(pmu_device->num_resources, num_possible_cpus());
|
||||
if (irqs < 1) {
|
||||
if (!irqs) {
|
||||
pr_err("no irqs for PMUs defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < irqs; ++i) {
|
||||
err = 0;
|
||||
irq = platform_get_irq(pmu_device, i);
|
||||
if (irq < 0)
|
||||
continue;
|
||||
irq = platform_get_irq(pmu_device, 0);
|
||||
if (irq <= 0) {
|
||||
pr_err("failed to get valid irq for PMU device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a single PMU interrupt that we can't shift,
|
||||
* assume that we're running on a uniprocessor machine and
|
||||
* continue. Otherwise, continue without this interrupt.
|
||||
*/
|
||||
if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
|
||||
pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
|
||||
irq, i);
|
||||
continue;
|
||||
}
|
||||
if (irq_is_percpu(irq)) {
|
||||
err = request_percpu_irq(irq, armpmu->handle_irq,
|
||||
"arm-pmu", &cpu_hw_events);
|
||||
|
||||
err = request_irq(irq, armpmu->handle_irq,
|
||||
IRQF_NOBALANCING,
|
||||
"arm-pmu", armpmu);
|
||||
if (err) {
|
||||
pr_err("unable to request IRQ%d for ARM PMU counters\n",
|
||||
irq);
|
||||
pr_err("unable to request percpu IRQ%d for ARM PMU counters\n",
|
||||
irq);
|
||||
armpmu_release_hardware(armpmu);
|
||||
return err;
|
||||
}
|
||||
|
||||
cpumask_set_cpu(i, &armpmu->active_irqs);
|
||||
on_each_cpu(armpmu_enable_percpu_irq, &irq, 1);
|
||||
} else {
|
||||
for (i = 0; i < irqs; ++i) {
|
||||
err = 0;
|
||||
irq = platform_get_irq(pmu_device, i);
|
||||
if (irq <= 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If we have a single PMU interrupt that we can't shift,
|
||||
* assume that we're running on a uniprocessor machine and
|
||||
* continue. Otherwise, continue without this interrupt.
|
||||
*/
|
||||
if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
|
||||
pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
|
||||
irq, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
err = request_irq(irq, armpmu->handle_irq,
|
||||
IRQF_NOBALANCING,
|
||||
"arm-pmu", armpmu);
|
||||
if (err) {
|
||||
pr_err("unable to request IRQ%d for ARM PMU counters\n",
|
||||
irq);
|
||||
armpmu_release_hardware(armpmu);
|
||||
return err;
|
||||
}
|
||||
|
||||
cpumask_set_cpu(i, &armpmu->active_irqs);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -153,15 +153,26 @@ void machine_restart(char *cmd)
|
||||
|
||||
void __show_regs(struct pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
int i, top_reg;
|
||||
u64 lr, sp;
|
||||
|
||||
if (compat_user_mode(regs)) {
|
||||
lr = regs->compat_lr;
|
||||
sp = regs->compat_sp;
|
||||
top_reg = 12;
|
||||
} else {
|
||||
lr = regs->regs[30];
|
||||
sp = regs->sp;
|
||||
top_reg = 29;
|
||||
}
|
||||
|
||||
show_regs_print_info(KERN_DEFAULT);
|
||||
print_symbol("PC is at %s\n", instruction_pointer(regs));
|
||||
print_symbol("LR is at %s\n", regs->regs[30]);
|
||||
print_symbol("LR is at %s\n", lr);
|
||||
printk("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n",
|
||||
regs->pc, regs->regs[30], regs->pstate);
|
||||
printk("sp : %016llx\n", regs->sp);
|
||||
for (i = 29; i >= 0; i--) {
|
||||
regs->pc, lr, regs->pstate);
|
||||
printk("sp : %016llx\n", sp);
|
||||
for (i = top_reg; i >= 0; i--) {
|
||||
printk("x%-2d: %016llx ", i, regs->regs[i]);
|
||||
if (i % 2 == 0)
|
||||
printk("\n");
|
||||
@@ -300,6 +311,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
|
||||
unsigned long get_wchan(struct task_struct *p)
|
||||
{
|
||||
struct stackframe frame;
|
||||
unsigned long stack_page;
|
||||
int count = 0;
|
||||
if (!p || p == current || p->state == TASK_RUNNING)
|
||||
return 0;
|
||||
@@ -307,9 +319,11 @@ unsigned long get_wchan(struct task_struct *p)
|
||||
frame.fp = thread_saved_fp(p);
|
||||
frame.sp = thread_saved_sp(p);
|
||||
frame.pc = thread_saved_pc(p);
|
||||
stack_page = (unsigned long)task_stack_page(p);
|
||||
do {
|
||||
int ret = unwind_frame(&frame);
|
||||
if (ret < 0)
|
||||
if (frame.sp < stack_page ||
|
||||
frame.sp >= stack_page + THREAD_SIZE ||
|
||||
unwind_frame(&frame))
|
||||
return 0;
|
||||
if (!in_sched_functions(frame.pc))
|
||||
return frame.pc;
|
||||
|
||||
@@ -53,28 +53,6 @@ void ptrace_disable(struct task_struct *child)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle hitting a breakpoint.
|
||||
*/
|
||||
static int ptrace_break(struct pt_regs *regs)
|
||||
{
|
||||
siginfo_t info = {
|
||||
.si_signo = SIGTRAP,
|
||||
.si_errno = 0,
|
||||
.si_code = TRAP_BRKPT,
|
||||
.si_addr = (void __user *)instruction_pointer(regs),
|
||||
};
|
||||
|
||||
force_sig_info(SIGTRAP, &info, current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arm64_break_trap(unsigned long addr, unsigned int esr,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
return ptrace_break(regs);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||
/*
|
||||
* Handle hitting a HW-breakpoint.
|
||||
@@ -813,33 +791,6 @@ static const struct user_regset_view user_aarch32_view = {
|
||||
.regsets = aarch32_regsets, .n = ARRAY_SIZE(aarch32_regsets)
|
||||
};
|
||||
|
||||
int aarch32_break_trap(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int instr;
|
||||
bool bp = false;
|
||||
void __user *pc = (void __user *)instruction_pointer(regs);
|
||||
|
||||
if (compat_thumb_mode(regs)) {
|
||||
/* get 16-bit Thumb instruction */
|
||||
get_user(instr, (u16 __user *)pc);
|
||||
if (instr == AARCH32_BREAK_THUMB2_LO) {
|
||||
/* get second half of 32-bit Thumb-2 instruction */
|
||||
get_user(instr, (u16 __user *)(pc + 2));
|
||||
bp = instr == AARCH32_BREAK_THUMB2_HI;
|
||||
} else {
|
||||
bp = instr == AARCH32_BREAK_THUMB;
|
||||
}
|
||||
} else {
|
||||
/* 32-bit ARM instruction */
|
||||
get_user(instr, (u32 __user *)pc);
|
||||
bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
|
||||
}
|
||||
|
||||
if (bp)
|
||||
return ptrace_break(regs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
|
||||
compat_ulong_t __user *ret)
|
||||
{
|
||||
@@ -1107,16 +1058,6 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
return ptrace_request(child, request, addr, data);
|
||||
}
|
||||
|
||||
|
||||
static int __init ptrace_break_init(void)
|
||||
{
|
||||
hook_debug_fault_code(DBG_ESR_EVT_BRK, arm64_break_trap, SIGTRAP,
|
||||
TRAP_BRKPT, "ptrace BRK handler");
|
||||
return 0;
|
||||
}
|
||||
core_initcall(ptrace_break_init);
|
||||
|
||||
|
||||
asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long saved_reg;
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
unsigned int processor_id;
|
||||
EXPORT_SYMBOL(processor_id);
|
||||
|
||||
unsigned int elf_hwcap __read_mostly;
|
||||
unsigned long elf_hwcap __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(elf_hwcap);
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
@@ -426,9 +426,6 @@ static int c_show(struct seq_file *m, void *v)
|
||||
#ifdef CONFIG_SMP
|
||||
seq_printf(m, "processor\t: %d\n", i);
|
||||
#endif
|
||||
seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
|
||||
loops_per_jiffy / (500000UL/HZ),
|
||||
loops_per_jiffy / (5000UL/HZ) % 100);
|
||||
}
|
||||
|
||||
/* dump out the processor features */
|
||||
|
||||
@@ -446,12 +446,13 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
|
||||
/* Check if the handler is written for ARM or Thumb */
|
||||
thumb = handler & 1;
|
||||
|
||||
if (thumb) {
|
||||
if (thumb)
|
||||
spsr |= COMPAT_PSR_T_BIT;
|
||||
spsr &= ~COMPAT_PSR_IT_MASK;
|
||||
} else {
|
||||
else
|
||||
spsr &= ~COMPAT_PSR_T_BIT;
|
||||
}
|
||||
|
||||
/* The IT state must be cleared for both ARM and Thumb-2 */
|
||||
spsr &= ~COMPAT_PSR_IT_MASK;
|
||||
|
||||
if (ka->sa.sa_flags & SA_RESTORER) {
|
||||
retcode = ptr_to_compat(ka->sa.sa_restorer);
|
||||
|
||||
@@ -155,13 +155,13 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
|
||||
if (cpu_ops[cpu]->cpu_postboot)
|
||||
cpu_ops[cpu]->cpu_postboot();
|
||||
|
||||
smp_store_cpu_info(cpu);
|
||||
|
||||
/*
|
||||
* Enable GIC and timers.
|
||||
*/
|
||||
notify_cpu_starting(cpu);
|
||||
|
||||
smp_store_cpu_info(cpu);
|
||||
|
||||
/*
|
||||
* OK, now it's safe to let the boot CPU continue. Wait for
|
||||
* the CPU migration code to notice that the CPU is online
|
||||
@@ -173,6 +173,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
|
||||
local_irq_enable();
|
||||
local_fiq_enable();
|
||||
|
||||
local_irq_enable();
|
||||
local_fiq_enable();
|
||||
|
||||
/*
|
||||
* OK, it's off to the idle thread for us
|
||||
*/
|
||||
@@ -477,7 +480,7 @@ void show_ipi_list(struct seq_file *p, int prec)
|
||||
for (i = 0; i < NR_IPI; i++) {
|
||||
seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i + IPI_RESCHEDULE,
|
||||
prec >= 4 ? " " : "");
|
||||
for_each_present_cpu(cpu)
|
||||
for_each_online_cpu(cpu)
|
||||
seq_printf(p, "%10u ",
|
||||
__get_irq_stat(cpu, ipi_irqs[i]));
|
||||
seq_printf(p, " %s\n", ipi_types[i]);
|
||||
|
||||
@@ -43,7 +43,7 @@ int unwind_frame(struct stackframe *frame)
|
||||
low = frame->sp;
|
||||
high = ALIGN(low, THREAD_SIZE);
|
||||
|
||||
if (fp < low || fp > high || fp & 0xf)
|
||||
if (fp < low || fp > high - 0x18 || fp & 0xf)
|
||||
return -EINVAL;
|
||||
|
||||
frame->sp = fp + 0x10;
|
||||
|
||||
@@ -68,12 +68,6 @@ unsigned long long notrace sched_clock(void)
|
||||
return arch_timer_read_counter() * sched_clock_mult;
|
||||
}
|
||||
|
||||
int read_current_timer(unsigned long *timer_value)
|
||||
{
|
||||
*timer_value = arch_timer_read_counter();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init time_init(void)
|
||||
{
|
||||
u32 arch_timer_rate;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <linux/syscalls.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/debug-monitors.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/stacktrace.h>
|
||||
#include <asm/exception.h>
|
||||
@@ -261,11 +262,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
|
||||
siginfo_t info;
|
||||
void __user *pc = (void __user *)instruction_pointer(regs);
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
/* check for AArch32 breakpoint instructions */
|
||||
if (compat_user_mode(regs) && aarch32_break_trap(regs) == 0)
|
||||
if (!aarch32_break_handler(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (show_unhandled_signals && unhandled_signal(current, SIGILL) &&
|
||||
printk_ratelimit()) {
|
||||
|
||||
@@ -55,7 +55,8 @@ SECTIONS
|
||||
}
|
||||
|
||||
RO_DATA(PAGE_SIZE)
|
||||
|
||||
EXCEPTION_TABLE(8)
|
||||
NOTES
|
||||
_etext = .; /* End of text and rodata section */
|
||||
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
@@ -81,42 +82,15 @@ SECTIONS
|
||||
PERCPU_SECTION(64)
|
||||
|
||||
__init_end = .;
|
||||
. = ALIGN(THREAD_SIZE);
|
||||
__data_loc = .;
|
||||
|
||||
.data : AT(__data_loc) {
|
||||
_data = .; /* address in memory */
|
||||
_sdata = .;
|
||||
|
||||
/*
|
||||
* first, the init task union, aligned
|
||||
* to an 8192 byte boundary.
|
||||
*/
|
||||
INIT_TASK_DATA(THREAD_SIZE)
|
||||
NOSAVE_DATA
|
||||
CACHELINE_ALIGNED_DATA(64)
|
||||
READ_MOSTLY_DATA(64)
|
||||
|
||||
/*
|
||||
* The exception fixup table (might need resorting at runtime)
|
||||
*/
|
||||
. = ALIGN(32);
|
||||
__start___ex_table = .;
|
||||
*(__ex_table)
|
||||
__stop___ex_table = .;
|
||||
|
||||
/*
|
||||
* and the usual data section
|
||||
*/
|
||||
DATA_DATA
|
||||
CONSTRUCTORS
|
||||
|
||||
_edata = .;
|
||||
}
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
_data = .;
|
||||
__data_loc = _data - LOAD_OFFSET;
|
||||
_sdata = .;
|
||||
RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE)
|
||||
_edata = .;
|
||||
_edata_loc = __data_loc + SIZEOF(.data);
|
||||
|
||||
NOTES
|
||||
|
||||
BSS_SECTION(0, 0, 0)
|
||||
_end = .;
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
lib-y := bitops.o delay.o \
|
||||
strncpy_from_user.o strnlen_user.o clear_user.o \
|
||||
copy_from_user.o copy_to_user.o copy_in_user.o \
|
||||
copy_page.o clear_page.o \
|
||||
memchr.o memcpy.o memmove.o memset.o \
|
||||
lib-y := bitops.o clear_user.o delay.o copy_from_user.o \
|
||||
copy_to_user.o copy_in_user.o copy_page.o \
|
||||
clear_page.o memchr.o memcpy.o memmove.o memset.o \
|
||||
strchr.o strrchr.o
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Based on arch/arm/lib/strncpy_from_user.S
|
||||
*
|
||||
* Copyright (C) 1995-2000 Russell King
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
*
|
||||
* 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/assembler.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
.text
|
||||
.align 5
|
||||
|
||||
/*
|
||||
* Copy a string from user space to kernel space.
|
||||
* x0 = dst, x1 = src, x2 = byte length
|
||||
* returns the number of characters copied (strlen of copied string),
|
||||
* -EFAULT on exception, or "len" if we fill the whole buffer
|
||||
*/
|
||||
ENTRY(__strncpy_from_user)
|
||||
mov x4, x1
|
||||
1: subs x2, x2, #1
|
||||
bmi 2f
|
||||
USER(9f, ldrb w3, [x1], #1 )
|
||||
strb w3, [x0], #1
|
||||
cbnz w3, 1b
|
||||
sub x1, x1, #1 // take NUL character out of count
|
||||
2: sub x0, x1, x4
|
||||
ret
|
||||
ENDPROC(__strncpy_from_user)
|
||||
|
||||
.section .fixup,"ax"
|
||||
.align 0
|
||||
9: strb wzr, [x0] // null terminate
|
||||
mov x0, #-EFAULT
|
||||
ret
|
||||
.previous
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Based on arch/arm/lib/strnlen_user.S
|
||||
*
|
||||
* Copyright (C) 1995-2000 Russell King
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
*
|
||||
* 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/assembler.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
.text
|
||||
.align 5
|
||||
|
||||
/* Prototype: unsigned long __strnlen_user(const char *str, long n)
|
||||
* Purpose : get length of a string in user memory
|
||||
* Params : str - address of string in user memory
|
||||
* Returns : length of string *including terminator*
|
||||
* or zero on exception, or n if too long
|
||||
*/
|
||||
ENTRY(__strnlen_user)
|
||||
mov x2, x0
|
||||
1: subs x1, x1, #1
|
||||
b.mi 2f
|
||||
USER(9f, ldrb w3, [x0], #1 )
|
||||
cbnz w3, 1b
|
||||
2: sub x0, x0, x2
|
||||
ret
|
||||
ENDPROC(__strnlen_user)
|
||||
|
||||
.section .fixup,"ax"
|
||||
.align 0
|
||||
9: mov x0, #0
|
||||
ret
|
||||
.previous
|
||||
@@ -130,7 +130,7 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
|
||||
force_sig_info(sig, &si, tsk);
|
||||
}
|
||||
|
||||
void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs)
|
||||
static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
struct mm_struct *mm = tsk->active_mm;
|
||||
|
||||
@@ -70,11 +70,6 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
|
||||
#endif
|
||||
}
|
||||
|
||||
void __flush_dcache_page(struct page *page)
|
||||
{
|
||||
__flush_dcache_area(page_address(page), PAGE_SIZE);
|
||||
}
|
||||
|
||||
void __sync_icache_dcache(pte_t pte, unsigned long addr)
|
||||
{
|
||||
struct page *page = pte_page(pte);
|
||||
@@ -84,7 +79,7 @@ void __sync_icache_dcache(pte_t pte, unsigned long addr)
|
||||
return;
|
||||
|
||||
if (!test_and_set_bit(PG_dcache_clean, &page->flags)) {
|
||||
__flush_dcache_page(page);
|
||||
__flush_dcache_area(page_address(page), PAGE_SIZE);
|
||||
__flush_icache_all();
|
||||
} else if (icache_is_aivivt()) {
|
||||
__flush_icache_all();
|
||||
|
||||
@@ -46,8 +46,7 @@ static unsigned long phys_initrd_size __initdata = 0;
|
||||
|
||||
phys_addr_t memstart_addr __read_mostly = 0;
|
||||
|
||||
void __init early_init_dt_setup_initrd_arch(unsigned long start,
|
||||
unsigned long end)
|
||||
void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
|
||||
{
|
||||
phys_initrd_start = start;
|
||||
phys_initrd_size = end - start;
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
extern void __flush_dcache_page(struct page *page);
|
||||
extern void __init bootmem_init(void);
|
||||
extern void __init arm64_swiotlb_init(void);
|
||||
|
||||
@@ -304,6 +304,7 @@ void __iomem * __init early_io_map(phys_addr_t phys, unsigned long virt)
|
||||
static void __init map_mem(void)
|
||||
{
|
||||
struct memblock_region *reg;
|
||||
phys_addr_t limit;
|
||||
|
||||
/*
|
||||
* Temporarily limit the memblock range. We need to do this as
|
||||
@@ -311,9 +312,11 @@ static void __init map_mem(void)
|
||||
* memory addressable from the initial direct kernel mapping.
|
||||
*
|
||||
* The initial direct kernel mapping, located at swapper_pg_dir,
|
||||
* gives us PGDIR_SIZE memory starting from PHYS_OFFSET (aligned).
|
||||
* gives us PGDIR_SIZE memory starting from PHYS_OFFSET (which must be
|
||||
* aligned to 2MB as per Documentation/arm64/booting.txt).
|
||||
*/
|
||||
memblock_set_current_limit((PHYS_OFFSET & PGDIR_MASK) + PGDIR_SIZE);
|
||||
limit = PHYS_OFFSET + PGDIR_SIZE;
|
||||
memblock_set_current_limit(limit);
|
||||
|
||||
/* map all the memory banks */
|
||||
for_each_memblock(memory, reg) {
|
||||
@@ -323,6 +326,22 @@ static void __init map_mem(void)
|
||||
if (start >= end)
|
||||
break;
|
||||
|
||||
#ifndef CONFIG_ARM64_64K_PAGES
|
||||
/*
|
||||
* For the first memory bank align the start address and
|
||||
* current memblock limit to prevent create_mapping() from
|
||||
* allocating pte page tables from unmapped memory.
|
||||
* When 64K pages are enabled, the pte page table for the
|
||||
* first PGDIR_SIZE is already present in swapper_pg_dir.
|
||||
*/
|
||||
if (start < limit)
|
||||
start = ALIGN(start, PMD_SIZE);
|
||||
if (end < limit) {
|
||||
limit = end & PMD_MASK;
|
||||
memblock_set_current_limit(limit);
|
||||
}
|
||||
#endif
|
||||
|
||||
create_mapping(start, __phys_to_virt(start), end - start);
|
||||
}
|
||||
|
||||
|
||||
@@ -180,12 +180,12 @@ ENTRY(__cpu_setup)
|
||||
bl __flush_dcache_all
|
||||
mov lr, x28
|
||||
ic iallu // I+BTB cache invalidate
|
||||
tlbi vmalle1is // invalidate I + D TLBs
|
||||
dsb sy
|
||||
|
||||
mov x0, #3 << 20
|
||||
msr cpacr_el1, x0 // Enable FP/ASIMD
|
||||
msr mdscr_el1, xzr // Reset mdscr_el1
|
||||
tlbi vmalle1is // invalidate I + D TLBs
|
||||
/*
|
||||
* Memory region attributes for LPAE:
|
||||
*
|
||||
|
||||
@@ -33,8 +33,7 @@ void __init early_init_devtree(void *params)
|
||||
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
void __init early_init_dt_setup_initrd_arch(unsigned long start,
|
||||
unsigned long end)
|
||||
void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
|
||||
{
|
||||
initrd_start = (unsigned long)__va(start);
|
||||
initrd_end = (unsigned long)__va(end);
|
||||
|
||||
@@ -419,10 +419,9 @@ void free_initrd_mem(unsigned long start, unsigned long end)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF_FLATTREE
|
||||
void __init early_init_dt_setup_initrd_arch(unsigned long start,
|
||||
unsigned long end)
|
||||
void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
|
||||
{
|
||||
pr_err("%s(%lx, %lx)\n",
|
||||
pr_err("%s(%llx, %llx)\n",
|
||||
__func__, start, end);
|
||||
}
|
||||
#endif /* CONFIG_OF_FLATTREE */
|
||||
|
||||
@@ -136,8 +136,7 @@ void __init early_init_devtree(void *params)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
void __init early_init_dt_setup_initrd_arch(unsigned long start,
|
||||
unsigned long end)
|
||||
void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
|
||||
{
|
||||
initrd_start = (unsigned long)__va(start);
|
||||
initrd_end = (unsigned long)__va(end);
|
||||
|
||||
@@ -58,8 +58,7 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
void __init early_init_dt_setup_initrd_arch(unsigned long start,
|
||||
unsigned long end)
|
||||
void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
|
||||
{
|
||||
initrd_start = (unsigned long)__va(start);
|
||||
initrd_end = (unsigned long)__va(end);
|
||||
|
||||
@@ -96,8 +96,7 @@ void __init early_init_devtree(void *params)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
void __init early_init_dt_setup_initrd_arch(unsigned long start,
|
||||
unsigned long end)
|
||||
void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
|
||||
{
|
||||
initrd_start = (unsigned long)__va(start);
|
||||
initrd_end = (unsigned long)__va(end);
|
||||
|
||||
@@ -550,8 +550,7 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
void __init early_init_dt_setup_initrd_arch(unsigned long start,
|
||||
unsigned long end)
|
||||
void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
|
||||
{
|
||||
initrd_start = (unsigned long)__va(start);
|
||||
initrd_end = (unsigned long)__va(end);
|
||||
|
||||
@@ -52,8 +52,7 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
void __init early_init_dt_setup_initrd_arch(unsigned long start,
|
||||
unsigned long end)
|
||||
void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
|
||||
{
|
||||
initrd_start = (unsigned long)__va(start);
|
||||
initrd_end = (unsigned long)__va(end);
|
||||
|
||||
@@ -170,8 +170,7 @@ static int __init parse_tag_fdt(const bp_tag_t *tag)
|
||||
|
||||
__tagtable(BP_TAG_FDT, parse_tag_fdt);
|
||||
|
||||
void __init early_init_dt_setup_initrd_arch(unsigned long start,
|
||||
unsigned long end)
|
||||
void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
|
||||
{
|
||||
initrd_start = (void *)__va(start);
|
||||
initrd_end = (void *)__va(end);
|
||||
|
||||
@@ -552,7 +552,8 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
|
||||
*/
|
||||
void __init early_init_dt_check_for_initrd(unsigned long node)
|
||||
{
|
||||
unsigned long start, end, len;
|
||||
u64 start, end;
|
||||
unsigned long len;
|
||||
__be32 *prop;
|
||||
|
||||
pr_debug("Looking for initrd properties... ");
|
||||
@@ -560,15 +561,16 @@ void __init early_init_dt_check_for_initrd(unsigned long node)
|
||||
prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
|
||||
if (!prop)
|
||||
return;
|
||||
start = of_read_ulong(prop, len/4);
|
||||
start = of_read_number(prop, len/4);
|
||||
|
||||
prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
|
||||
if (!prop)
|
||||
return;
|
||||
end = of_read_ulong(prop, len/4);
|
||||
end = of_read_number(prop, len/4);
|
||||
|
||||
early_init_dt_setup_initrd_arch(start, end);
|
||||
pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", start, end);
|
||||
pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n",
|
||||
(unsigned long long)start, (unsigned long long)end);
|
||||
}
|
||||
#else
|
||||
inline void early_init_dt_check_for_initrd(unsigned long node)
|
||||
|
||||
@@ -154,6 +154,14 @@ static inline int irq_balancing_disabled(unsigned int irq)
|
||||
return desc->status_use_accessors & IRQ_NO_BALANCING_MASK;
|
||||
}
|
||||
|
||||
static inline int irq_is_percpu(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
|
||||
desc = irq_to_desc(irq);
|
||||
return desc->status_use_accessors & IRQ_PER_CPU;
|
||||
}
|
||||
|
||||
static inline void
|
||||
irq_set_lockdep_class(unsigned int irq, struct lock_class_key *class)
|
||||
{
|
||||
|
||||
@@ -127,8 +127,7 @@ extern u64 dt_mem_next_cell(int s, __be32 **cellp);
|
||||
* physical addresses.
|
||||
*/
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
extern void early_init_dt_setup_initrd_arch(unsigned long start,
|
||||
unsigned long end);
|
||||
extern void early_init_dt_setup_initrd_arch(u64 start, u64 end);
|
||||
#endif
|
||||
|
||||
/* Early flat tree scan hooks */
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#define EM_PPC 20 /* PowerPC */
|
||||
#define EM_PPC64 21 /* PowerPC64 */
|
||||
#define EM_SPU 23 /* Cell BE SPU */
|
||||
#define EM_ARM 40 /* ARM 32 bit */
|
||||
#define EM_SH 42 /* SuperH */
|
||||
#define EM_SPARCV9 43 /* SPARC v9 64-bit */
|
||||
#define EM_IA_64 50 /* HP/Intel IA-64 */
|
||||
@@ -34,6 +35,7 @@
|
||||
#define EM_MN10300 89 /* Panasonic/MEI MN10300, AM33 */
|
||||
#define EM_BLACKFIN 106 /* ADI Blackfin Processor */
|
||||
#define EM_TI_C6000 140 /* TI C6X DSPs */
|
||||
#define EM_AARCH64 183 /* ARM 64 bit */
|
||||
#define EM_FRV 0x5441 /* Fujitsu FR-V */
|
||||
#define EM_AVR32 0x18ad /* Atmel AVR32 */
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CONFIG_PREEMPT=y
|
||||
CONFIG_PREEMPT_RT_FULL=y
|
||||
CONFIG_SLUB=y
|
||||
CONFIG_CPU_FREQ=n
|
||||
# CONFIG_CPU_FREQ is not set
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
#include <tools/be_byteshift.h>
|
||||
#include <tools/le_byteshift.h>
|
||||
|
||||
#ifndef EM_AARCH64
|
||||
#define EM_AARCH64 183
|
||||
#endif
|
||||
|
||||
static int fd_map; /* File descriptor for file being modified. */
|
||||
static int mmap_failed; /* Boolean flag. */
|
||||
static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */
|
||||
@@ -249,6 +253,7 @@ do_file(char const *const fname)
|
||||
custom_sort = sort_relative_table;
|
||||
break;
|
||||
case EM_ARM:
|
||||
case EM_AARCH64:
|
||||
case EM_MIPS:
|
||||
break;
|
||||
} /* end switch */
|
||||
|
||||
Reference in New Issue
Block a user