Commit 42cf0f20 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm

Pull ARM updates from Russell King:

 - clang assembly fixes from Ard

 - optimisations and cleanups for Aurora L2 cache support

 - efficient L2 cache support for secure monitor API on Exynos SoCs

 - debug menu cleanup from Daniel Thompson to allow better behaviour for
   multiplatform kernels

 - StrongARM SA11x0 conversion to irq domains, and pxa_timer

 - kprobes updates for older ARM CPUs

 - move probes support out of arch/arm/kernel to arch/arm/probes

 - add inline asm support for the rbit (reverse bits) instruction

 - provide an ARM mode secondary CPU entry point (for Qualcomm CPUs)

 - remove the unused ARMv3 user access code

 - add driver_override support to AMBA Primecell bus

* 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm: (55 commits)
  ARM: 8256/1: driver coamba: add device binding path 'driver_override'
  ARM: 8301/1: qcom: Use secondary_startup_arm()
  ARM: 8302/1: Add a secondary_startup that assumes ARM mode
  ARM: 8300/1: teach __asmeq that r11 == fp and r12 == ip
  ARM: kprobes: Fix compilation error caused by superfluous '*'
  ARM: 8297/1: cache-l2x0: optimize aurora range operations
  ARM: 8296/1: cache-l2x0: clean up aurora cache handling
  ARM: 8284/1: sa1100: clear RCSR_SMR on resume
  ARM: 8283/1: sa1100: collie: clear PWER register on machine init
  ARM: 8282/1: sa1100: use handle_domain_irq
  ARM: 8281/1: sa1100: move GPIO-related IRQ code to gpio driver
  ARM: 8280/1: sa1100: switch to irq_domain_add_simple()
  ARM: 8279/1: sa1100: merge both GPIO irqdomains
  ARM: 8278/1: sa1100: split irq handling for low GPIOs
  ARM: 8291/1: replace magic number with PAGE_SHIFT macro in fixup_pv code
  ARM: 8290/1: decompressor: fix a wrong comment
  ARM: 8286/1: mm: Fix dma_contiguous_reserve comment
  ARM: 8248/1: pm: remove outdated comment
  ARM: 8274/1: Fix DEBUG_LL for multi-platform kernels (without PL01X)
  ARM: 8273/1: Seperate DEBUG_UART_PHYS from DEBUG_LL on EP93XX
  ...
parents a2f0bb03 df9ab977
What: /sys/bus/amba/devices/.../driver_override
Date: September 2014
Contact: Antonios Motakis <a.motakis@virtualopensystems.com>
Description:
This file allows the driver for a device to be specified which
will override standard OF, ACPI, ID table, and name matching.
When specified, only a driver with a name matching the value
written to driver_override will have an opportunity to bind to
the device. The override is specified by writing a string to the
driver_override file (echo vfio-amba > driver_override) and may
be cleared with an empty string (echo > driver_override).
This returns the device to standard matching rules binding.
Writing to driver_override does not automatically unbind the
device from its current driver or make any attempt to
automatically load the specified driver. If no driver with a
matching name is currently loaded in the kernel, the device will
not bind to any driver. This also allows devices to opt-out of
driver binding using a driver_override name such as "none".
Only a single driver may be specified in the override, there is
no support for parsing delimiters.
...@@ -57,6 +57,16 @@ Optional properties: ...@@ -57,6 +57,16 @@ Optional properties:
- cache-id-part: cache id part number to be used if it is not present - cache-id-part: cache id part number to be used if it is not present
on hardware on hardware
- wt-override: If present then L2 is forced to Write through mode - wt-override: If present then L2 is forced to Write through mode
- arm,double-linefill : Override double linefill enable setting. Enable if
non-zero, disable if zero.
- arm,double-linefill-incr : Override double linefill on INCR read. Enable
if non-zero, disable if zero.
- arm,double-linefill-wrap : Override double linefill on WRAP read. Enable
if non-zero, disable if zero.
- arm,prefetch-drop : Override prefetch drop enable setting. Enable if non-zero,
disable if zero.
- arm,prefetch-offset : Override prefetch offset value. Valid values are
0-7, 15, 23, and 31.
Example: Example:
......
...@@ -29,6 +29,7 @@ config ARM ...@@ -29,6 +29,7 @@ config ARM
select HANDLE_DOMAIN_IRQ select HANDLE_DOMAIN_IRQ
select HARDIRQS_SW_RESEND select HARDIRQS_SW_RESEND
select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT) select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
select HAVE_ARCH_KGDB select HAVE_ARCH_KGDB
select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT) select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
...@@ -60,6 +61,7 @@ config ARM ...@@ -60,6 +61,7 @@ config ARM
select HAVE_MEMBLOCK select HAVE_MEMBLOCK
select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
select HAVE_OPTPROBES if !THUMB2_KERNEL
select HAVE_PERF_EVENTS select HAVE_PERF_EVENTS
select HAVE_PERF_REGS select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP select HAVE_PERF_USER_STACK_DUMP
......
...@@ -397,6 +397,13 @@ choice ...@@ -397,6 +397,13 @@ choice
Say Y here if you want the debug print routines to direct Say Y here if you want the debug print routines to direct
their output to UART1 serial port on KEYSTONE2 devices. their output to UART1 serial port on KEYSTONE2 devices.
config DEBUG_KS8695_UART
bool "KS8695 Debug UART"
depends on ARCH_KS8695
help
Say Y here if you want kernel low-level debugging support
on KS8695.
config DEBUG_MESON_UARTAO config DEBUG_MESON_UARTAO
bool "Kernel low-level debugging via Meson6 UARTAO" bool "Kernel low-level debugging via Meson6 UARTAO"
depends on ARCH_MESON depends on ARCH_MESON
...@@ -496,6 +503,13 @@ choice ...@@ -496,6 +503,13 @@ choice
Say Y here if you want kernel low-level debugging support Say Y here if you want kernel low-level debugging support
on Vybrid based platforms. on Vybrid based platforms.
config DEBUG_NETX_UART
bool "Kernel low-level debugging messages via NetX UART"
depends on ARCH_NETX
help
Say Y here if you want kernel low-level debugging support
on Hilscher NetX based platforms.
config DEBUG_NOMADIK_UART config DEBUG_NOMADIK_UART
bool "Kernel low-level debugging messages via NOMADIK UART" bool "Kernel low-level debugging messages via NOMADIK UART"
depends on ARCH_NOMADIK depends on ARCH_NOMADIK
...@@ -520,6 +534,30 @@ choice ...@@ -520,6 +534,30 @@ choice
Say Y here if you want kernel low-level debugging support Say Y here if you want kernel low-level debugging support
on TI-NSPIRE CX models. on TI-NSPIRE CX models.
config DEBUG_OMAP1UART1
bool "Kernel low-level debugging via OMAP1 UART1"
depends on ARCH_OMAP1
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
on OMAP1 based platforms (except OMAP730) on the UART1.
config DEBUG_OMAP1UART2
bool "Kernel low-level debugging via OMAP1 UART2"
depends on ARCH_OMAP1
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
on OMAP1 based platforms (except OMAP730) on the UART2.
config DEBUG_OMAP1UART3
bool "Kernel low-level debugging via OMAP1 UART3"
depends on ARCH_OMAP1
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
on OMAP1 based platforms (except OMAP730) on the UART3.
config DEBUG_OMAP2UART1 config DEBUG_OMAP2UART1
bool "OMAP2/3/4 UART1 (omap2/3 sdp boards and some omap3 boards)" bool "OMAP2/3/4 UART1 (omap2/3 sdp boards and some omap3 boards)"
depends on ARCH_OMAP2PLUS depends on ARCH_OMAP2PLUS
...@@ -562,6 +600,30 @@ choice ...@@ -562,6 +600,30 @@ choice
depends on ARCH_OMAP2PLUS depends on ARCH_OMAP2PLUS
select DEBUG_OMAP2PLUS_UART select DEBUG_OMAP2PLUS_UART
config DEBUG_OMAP7XXUART1
bool "Kernel low-level debugging via OMAP730 UART1"
depends on ARCH_OMAP730
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
on OMAP730 based platforms on the UART1.
config DEBUG_OMAP7XXUART2
bool "Kernel low-level debugging via OMAP730 UART2"
depends on ARCH_OMAP730
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
on OMAP730 based platforms on the UART2.
config DEBUG_OMAP7XXUART3
bool "Kernel low-level debugging via OMAP730 UART3"
depends on ARCH_OMAP730
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
on OMAP730 based platforms on the UART3.
config DEBUG_TI81XXUART1 config DEBUG_TI81XXUART1
bool "Kernel low-level debugging messages via TI81XX UART1 (ti8148evm)" bool "Kernel low-level debugging messages via TI81XX UART1 (ti8148evm)"
depends on ARCH_OMAP2PLUS depends on ARCH_OMAP2PLUS
...@@ -1031,15 +1093,6 @@ choice ...@@ -1031,15 +1093,6 @@ choice
This option selects UART0 on VIA/Wondermedia System-on-a-chip This option selects UART0 on VIA/Wondermedia System-on-a-chip
devices, including VT8500, WM8505, WM8650 and WM8850. devices, including VT8500, WM8505, WM8650 and WM8850.
config DEBUG_LL_UART_NONE
bool "No low-level debugging UART"
depends on !ARCH_MULTIPLATFORM
help
Say Y here if your platform doesn't provide a UART option
above. This relies on your platform choosing the right UART
definition internally in order for low-level debugging to
work.
config DEBUG_ICEDCC config DEBUG_ICEDCC
bool "Kernel low-level debugging via EmbeddedICE DCC channel" bool "Kernel low-level debugging via EmbeddedICE DCC channel"
help help
...@@ -1183,7 +1236,9 @@ config DEBUG_LL_INCLUDE ...@@ -1183,7 +1236,9 @@ config DEBUG_LL_INCLUDE
DEBUG_IMX6Q_UART || \ DEBUG_IMX6Q_UART || \
DEBUG_IMX6SL_UART || \ DEBUG_IMX6SL_UART || \
DEBUG_IMX6SX_UART DEBUG_IMX6SX_UART
default "debug/ks8695.S" if DEBUG_KS8695_UART
default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM
default "debug/netx.S" if DEBUG_NETX_UART
default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART
default "debug/renesas-scif.S" if DEBUG_R7S72100_SCIF2 default "debug/renesas-scif.S" if DEBUG_R7S72100_SCIF2
default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF0 default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF0
...@@ -1208,12 +1263,7 @@ config DEBUG_LL_INCLUDE ...@@ -1208,12 +1263,7 @@ config DEBUG_LL_INCLUDE
# Compatibility options for PL01x # Compatibility options for PL01x
config DEBUG_UART_PL01X config DEBUG_UART_PL01X
def_bool ARCH_EP93XX || \ bool
ARCH_INTEGRATOR || \
ARCH_SPEAR3XX || \
ARCH_SPEAR6XX || \
ARCH_SPEAR13XX || \
ARCH_VERSATILE
# Compatibility options for 8250 # Compatibility options for 8250
config DEBUG_UART_8250 config DEBUG_UART_8250
...@@ -1229,6 +1279,7 @@ config DEBUG_UART_BCM63XX ...@@ -1229,6 +1279,7 @@ config DEBUG_UART_BCM63XX
config DEBUG_UART_PHYS config DEBUG_UART_PHYS
hex "Physical base address of debug UART" hex "Physical base address of debug UART"
default 0x00100a00 if DEBUG_NETX_UART
default 0x01c20000 if DEBUG_DAVINCI_DMx_UART0 default 0x01c20000 if DEBUG_DAVINCI_DMx_UART0
default 0x01c28000 if DEBUG_SUNXI_UART0 default 0x01c28000 if DEBUG_SUNXI_UART0
default 0x01c28400 if DEBUG_SUNXI_UART1 default 0x01c28400 if DEBUG_SUNXI_UART1
...@@ -1269,7 +1320,6 @@ config DEBUG_UART_PHYS ...@@ -1269,7 +1320,6 @@ config DEBUG_UART_PHYS
DEBUG_S3C2410_UART2) DEBUG_S3C2410_UART2)
default 0x78000000 if DEBUG_CNS3XXX default 0x78000000 if DEBUG_CNS3XXX
default 0x7c0003f8 if FOOTBRIDGE default 0x7c0003f8 if FOOTBRIDGE
default 0x78000000 if DEBUG_CNS3XXX
default 0x80010000 if DEBUG_ASM9260_UART default 0x80010000 if DEBUG_ASM9260_UART
default 0x80070000 if DEBUG_IMX23_UART default 0x80070000 if DEBUG_IMX23_UART
default 0x80074000 if DEBUG_IMX28_UART default 0x80074000 if DEBUG_IMX28_UART
...@@ -1310,12 +1360,17 @@ config DEBUG_UART_PHYS ...@@ -1310,12 +1360,17 @@ config DEBUG_UART_PHYS
default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0 default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0
default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2 default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2
default 0xfff36000 if DEBUG_HIGHBANK_UART default 0xfff36000 if DEBUG_HIGHBANK_UART
default 0xfffb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1
default 0xfffb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2
default 0xfffb9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3
default 0xfffe8600 if DEBUG_UART_BCM63XX default 0xfffe8600 if DEBUG_UART_BCM63XX
default 0xfffff700 if ARCH_IOP33X default 0xfffff700 if ARCH_IOP33X
depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ depends on ARCH_EP93XX || \
DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
DEBUG_LL_UART_EFM32 || \ DEBUG_LL_UART_EFM32 || \
DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \
DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \ DEBUG_MSM_UART || DEBUG_NETX_UART || \
DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \
DEBUG_RCAR_GEN1_SCIF0 || DEBUG_RCAR_GEN1_SCIF2 || \ DEBUG_RCAR_GEN1_SCIF0 || DEBUG_RCAR_GEN1_SCIF2 || \
DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \ DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \
DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \ DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \
...@@ -1324,6 +1379,7 @@ config DEBUG_UART_PHYS ...@@ -1324,6 +1379,7 @@ config DEBUG_UART_PHYS
config DEBUG_UART_VIRT config DEBUG_UART_VIRT
hex "Virtual base address of debug UART" hex "Virtual base address of debug UART"
default 0xe0000a00 if DEBUG_NETX_UART
default 0xe0010fe0 if ARCH_RPC default 0xe0010fe0 if ARCH_RPC
default 0xe1000000 if DEBUG_MSM_UART default 0xe1000000 if DEBUG_MSM_UART
default 0xf0000be0 if ARCH_EBSA110 default 0xf0000be0 if ARCH_EBSA110
...@@ -1392,18 +1448,23 @@ config DEBUG_UART_VIRT ...@@ -1392,18 +1448,23 @@ config DEBUG_UART_VIRT
default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN
default 0xfef00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN default 0xfef00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN
default 0xfef36000 if DEBUG_HIGHBANK_UART default 0xfef36000 if DEBUG_HIGHBANK_UART
default 0xfefb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1
default 0xfefb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2
default 0xfefb9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3
default 0xfefff700 if ARCH_IOP33X default 0xfefff700 if ARCH_IOP33X
default 0xff003000 if DEBUG_U300_UART default 0xff003000 if DEBUG_U300_UART
default DEBUG_UART_PHYS if !MMU default DEBUG_UART_PHYS if !MMU
depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \
DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ DEBUG_MSM_UART || DEBUG_NETX_UART || \
DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \
DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART
config DEBUG_UART_8250_SHIFT config DEBUG_UART_8250_SHIFT
int "Register offset shift for the 8250 debug UART" int "Register offset shift for the 8250 debug UART"
depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250 depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250
default 0 if FOOTBRIDGE || ARCH_IOP32X || DEBUG_BCM_5301X default 0 if FOOTBRIDGE || ARCH_IOP32X || DEBUG_BCM_5301X || \
DEBUG_OMAP7XXUART1 || DEBUG_OMAP7XXUART2 || DEBUG_OMAP7XXUART3
default 2 default 2
config DEBUG_UART_8250_WORD config DEBUG_UART_8250_WORD
......
...@@ -266,6 +266,7 @@ core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/ ...@@ -266,6 +266,7 @@ core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/
# If we have a machine-specific directory, then include it in the build. # If we have a machine-specific directory, then include it in the build.
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y += arch/arm/probes/
core-y += arch/arm/net/ core-y += arch/arm/net/
core-y += arch/arm/crypto/ core-y += arch/arm/crypto/
core-y += arch/arm/firmware/ core-y += arch/arm/firmware/
......
...@@ -178,7 +178,7 @@ not_angel: ...@@ -178,7 +178,7 @@ not_angel:
/* /*
* Set up a page table only if it won't overwrite ourself. * Set up a page table only if it won't overwrite ourself.
* That means r4 < pc && r4 - 16k page directory > &_end. * That means r4 < pc || r4 - 16k page directory > &_end.
* Given that r4 > &_end is most unfrequent, we add a rough * Given that r4 > &_end is most unfrequent, we add a rough
* additional 1MB of room for a possible appended DTB. * additional 1MB of room for a possible appended DTB.
*/ */
......
...@@ -81,6 +81,15 @@ pd_lcd1: lcd1-power-domain@10023CA0 { ...@@ -81,6 +81,15 @@ pd_lcd1: lcd1-power-domain@10023CA0 {
reg = <0x10023CA0 0x20>; reg = <0x10023CA0 0x20>;
}; };
l2c: l2-cache-controller@10502000 {
compatible = "arm,pl310-cache";
reg = <0x10502000 0x1000>;
cache-unified;
cache-level = <2>;
arm,tag-latency = <2 2 1>;
arm,data-latency = <2 2 1>;
};
gic: interrupt-controller@10490000 { gic: interrupt-controller@10490000 {
cpu-offset = <0x8000>; cpu-offset = <0x8000>;
}; };
......
...@@ -54,6 +54,20 @@ pd_isp: isp-power-domain@10023CA0 { ...@@ -54,6 +54,20 @@ pd_isp: isp-power-domain@10023CA0 {
reg = <0x10023CA0 0x20>; reg = <0x10023CA0 0x20>;
}; };
l2c: l2-cache-controller@10502000 {
compatible = "arm,pl310-cache";
reg = <0x10502000 0x1000>;
cache-unified;
cache-level = <2>;
arm,tag-latency = <2 2 1>;
arm,data-latency = <3 2 1>;
arm,double-linefill = <1>;
arm,double-linefill-incr = <0>;
arm,double-linefill-wrap = <1>;
arm,prefetch-drop = <1>;
arm,prefetch-offset = <7>;
};
clock: clock-controller@10030000 { clock: clock-controller@10030000 {
compatible = "samsung,exynos4412-clock"; compatible = "samsung,exynos4412-clock";
reg = <0x10030000 0x20000>; reg = <0x10030000 0x20000>;
......
...@@ -106,6 +106,7 @@ CONFIG_MAGIC_SYSRQ=y ...@@ -106,6 +106,7 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_USER=y CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y CONFIG_DEBUG_LL=y
CONFIG_DEBUG_LL_UART_8250=y
CONFIG_KEYS=y CONFIG_KEYS=y
CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_NULL=y
......
...@@ -87,5 +87,6 @@ CONFIG_DEBUG_KERNEL=y ...@@ -87,5 +87,6 @@ CONFIG_DEBUG_KERNEL=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_DEBUG_USER=y CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y CONFIG_DEBUG_LL=y
CONFIG_DEBUG_LL_UART_8250=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRC32 is not set # CONFIG_CRC32 is not set
...@@ -202,3 +202,4 @@ CONFIG_MAGIC_SYSRQ=y ...@@ -202,3 +202,4 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_ERRORS=y
CONFIG_DEBUG_LL=y CONFIG_DEBUG_LL=y
CONFIG_DEBUG_LL_UART_8250=y
...@@ -204,6 +204,7 @@ CONFIG_DEBUG_INFO=y ...@@ -204,6 +204,7 @@ CONFIG_DEBUG_INFO=y
# CONFIG_FTRACE is not set # CONFIG_FTRACE is not set
# CONFIG_ARM_UNWIND is not set # CONFIG_ARM_UNWIND is not set
CONFIG_DEBUG_LL=y CONFIG_DEBUG_LL=y
CONFIG_DEBUG_LL_UART_8250=y
CONFIG_EARLY_PRINTK=y CONFIG_EARLY_PRINTK=y
CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_ANSI_CPRNG=y
# CONFIG_CRYPTO_HW is not set # CONFIG_CRYPTO_HW is not set
......
...@@ -132,6 +132,7 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y ...@@ -132,6 +132,7 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_DEBUG_USER=y CONFIG_DEBUG_USER=y
CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_ERRORS=y
CONFIG_DEBUG_LL=y CONFIG_DEBUG_LL=y
CONFIG_DEBUG_LL_UART_8250=y
CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_PCBC=m
......
...@@ -156,6 +156,7 @@ CONFIG_LATENCYTOP=y ...@@ -156,6 +156,7 @@ CONFIG_LATENCYTOP=y
# CONFIG_FTRACE is not set # CONFIG_FTRACE is not set
CONFIG_DEBUG_USER=y CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y CONFIG_DEBUG_LL=y
CONFIG_DEBUG_LL_UART_8250=y
CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_PCBC=m
......
...@@ -131,3 +131,4 @@ CONFIG_DEBUG_KERNEL=y ...@@ -131,3 +131,4 @@ CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_USER=y CONFIG_DEBUG_USER=y
CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_ERRORS=y
CONFIG_DEBUG_LL=y CONFIG_DEBUG_LL=y
CONFIG_DEBUG_LL_UART_8250=y
#ifndef __ASM_BITREV_H
#define __ASM_BITREV_H
static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x)
{
__asm__ ("rbit %0, %1" : "=r" (x) : "r" (x));
return x;
}
static __always_inline __attribute_const__ u16 __arch_bitrev16(u16 x)
{
return __arch_bitrev32((u32)x) >> 16;
}
static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x)
{
return __arch_bitrev32((u32)x) >> 24;
}
#endif
...@@ -8,8 +8,21 @@ ...@@ -8,8 +8,21 @@
* This string is meant to be concatenated with the inline asm string and * This string is meant to be concatenated with the inline asm string and
* will cause compilation to stop on mismatch. * will cause compilation to stop on mismatch.
* (for details, see gcc PR 15089) * (for details, see gcc PR 15089)
* For compatibility with clang, we have to specifically take the equivalence
* of 'r11' <-> 'fp' and 'r12' <-> 'ip' into account as well.
*/ */
#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" #define __asmeq(x, y) \
".ifnc " x "," y "; " \
".ifnc " x y ",fpr11; " \
".ifnc " x y ",r11fp; " \
".ifnc " x y ",ipr12; " \
".ifnc " x y ",r12ip; " \
".err; " \
".endif; " \
".endif; " \
".endif; " \
".endif; " \
".endif\n\t"
#endif /* __ASM_ARM_COMPILER_H */ #endif /* __ASM_ARM_COMPILER_H */
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#define __ARCH_WANT_KPROBES_INSN_SLOT #define __ARCH_WANT_KPROBES_INSN_SLOT
#define MAX_INSN_SIZE 2 #define MAX_INSN_SIZE 2
#define MAX_STACK_SIZE 64 /* 32 would probably be OK */
#define flush_insn_slot(p) do { } while (0) #define flush_insn_slot(p) do { } while (0)
#define kretprobe_blacklist_size 0 #define kretprobe_blacklist_size 0
...@@ -51,5 +50,37 @@ int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr); ...@@ -51,5 +50,37 @@ int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
int kprobe_exceptions_notify(struct notifier_block *self, int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data); unsigned long val, void *data);
/* optinsn template addresses */
extern __visible kprobe_opcode_t optprobe_template_entry;
extern __visible kprobe_opcode_t optprobe_template_val;
extern __visible kprobe_opcode_t optprobe_template_call;
extern __visible kprobe_opcode_t optprobe_template_end;
extern __visible kprobe_opcode_t optprobe_template_sub_sp;
extern __visible kprobe_opcode_t optprobe_template_add_sp;
extern __visible kprobe_opcode_t optprobe_template_restore_begin;
extern __visible kprobe_opcode_t optprobe_template_restore_orig_insn;
extern __visible kprobe_opcode_t optprobe_template_restore_end;
#define MAX_OPTIMIZED_LENGTH 4
#define MAX_OPTINSN_SIZE \
((unsigned long)&optprobe_template_end - \
(unsigned long)&optprobe_template_entry)
#define RELATIVEJUMP_SIZE 4
struct arch_optimized_insn {
/*
* copy of the original instructions.
* Different from x86, ARM kprobe_opcode_t is u32.
*/
#define MAX_COPIED_INSN DIV_ROUND_UP(RELATIVEJUMP_SIZE, sizeof(kprobe_opcode_t))
kprobe_opcode_t copied_insn[MAX_COPIED_INSN];
/* detour code buffer */
kprobe_opcode_t *insn;
/*
* We always copy one instruction on ARM,
* so size will always be 4, and unlike x86, there is no
* need for a size field.
*/
};
#endif /* _ARM_KPROBES_H */ #endif /* _ARM_KPROBES_H */
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <linux/types.h> #include <linux/types.h>
struct l2x0_regs;
struct outer_cache_fns { struct outer_cache_fns {
void (*inv_range)(unsigned long, unsigned long); void (*inv_range)(unsigned long, unsigned long);
void (*clean_range)(unsigned long, unsigned long); void (*clean_range)(unsigned long, unsigned long);
...@@ -36,6 +38,7 @@ struct outer_cache_fns { ...@@ -36,6 +38,7 @@ struct outer_cache_fns {
/* This is an ARM L2C thing */ /* This is an ARM L2C thing */
void (*write_sec)(unsigned long, unsigned); void (*write_sec)(unsigned long, unsigned);
void (*configure)(const struct l2x0_regs *);
}; };
extern struct outer_cache_fns outer_cache; extern struct outer_cache_fns outer_cache;
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#ifndef _ASM_PROBES_H #ifndef _ASM_PROBES_H
#define _ASM_PROBES_H #define _ASM_PROBES_H
#ifndef __ASSEMBLY__
typedef u32 probes_opcode_t; typedef u32 probes_opcode_t;
struct arch_probes_insn; struct arch_probes_insn;
...@@ -38,6 +40,19 @@ struct arch_probes_insn { ...@@ -38,6 +40,19 @@ struct arch_probes_insn {
probes_check_cc *insn_check_cc; probes_check_cc *insn_check_cc;
probes_insn_singlestep_t *insn_singlestep; probes_insn_singlestep_t *insn_singlestep;
probes_insn_fn_t *insn_fn; probes_insn_fn_t *insn_fn;
int stack_space;
unsigned long register_usage_flags;
bool kprobe_direct_exec;
}; };
#endif /* __ASSEMBLY__ */
/*
* We assume one instruction can consume at most 64 bytes stack, which is
* 'push {r0-r15}'. Instructions consume more or unknown stack space like
* 'str r0, [sp, #-80]' and 'str r0, [sp, r1]' should be prohibit to probe.
* Both kprobe and jprobe use this macro.
*/
#define MAX_STACK_SIZE 64
#endif #endif
/* /*
* arch/arm/mach-ks8695/include/mach/debug-macro.S * arch/arm/include/debug/ks8695.S
* *
* Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk> * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk>
* Copyright (C) 2006 Simtec Electronics * Copyright (C) 2006 Simtec Electronics
...@@ -11,8 +11,12 @@ ...@@ -11,8 +11,12 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <mach/hardware.h> #define KS8695_UART_PA 0x03ffe000
#include <mach/regs-uart.h> #define KS8695_UART_VA 0xf00fe000
#define KS8695_URTH (0x04)
#define KS8695_URLS (0x14)
#define URLS_URTE (1 << 6)
#define URLS_URTHRE (1 << 5)
.macro addruart, rp, rv, tmp .macro addruart, rp, rv, tmp
ldr \rp, =KS8695_UART_PA @ physical base address ldr \rp, =KS8695_UART_PA @ physical base address
......
/* arch/arm/mach-netx/include/mach/debug-macro.S /*
*
* Debugging macro include header * Debugging macro include header
* *
* Copyright (C) 1994-1999 Russell King * Copyright (C) 1994-1999 Russell King
...@@ -11,26 +10,27 @@ ...@@ -11,26 +10,27 @@
* *
*/ */
#include "hardware.h" #define UART_DATA 0
#define UART_FLAG 0x18
#define UART_FLAG_BUSY (1 << 3)
.macro addruart, rp, rv, tmp .macro addruart, rp, rv, tmp
mov \rp, #0x00000a00 ldr \rp, =CONFIG_DEBUG_UART_PHYS
orr \rv, \rp, #io_p2v(0x00100000) @ virtual ldr \rv, =CONFIG_DEBUG_UART_VIRT
orr \rp, \rp, #0x00100000 @ physical
.endm .endm
.macro senduart,rd,rx .macro senduart,rd,rx
str \rd, [\rx, #0] str \rd, [\rx, #UART_DATA]
.endm .endm
.macro busyuart,rd,rx .macro busyuart,rd,rx
1002: ldr \rd, [\rx, #0x18] 1002: ldr \rd, [\rx, #UART_FLAG]
tst \rd, #(1 << 3) tst \rd, #UART_FLAG_BUSY
bne 1002b bne 1002b
.endm .endm
.macro waituart,rd,rx .macro waituart,rd,rx
1001: ldr \rd, [\rx, #0x18] 1001: ldr \rd, [\rx, #UART_FLAG]
tst \rd, #(1 << 3) tst \rd, #UART_FLAG_BUSY
bne 1001b bne 1001b
.endm .endm
...@@ -51,20 +51,8 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o ...@@ -51,20 +51,8 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_UPROBES) += probes.o probes-arm.o uprobes.o uprobes-arm.o # Main staffs in KPROBES are in arch/arm/probes/ .
obj-$(CONFIG_KPROBES) += probes.o kprobes.o kprobes-common.o patch.o obj-$(CONFIG_KPROBES) += patch.o insn.o
ifdef CONFIG_THUMB2_KERNEL
obj-$(CONFIG_KPROBES) += kprobes-thumb.o probes-thumb.o
else
obj-$(CONFIG_KPROBES) += kprobes-arm.o probes-arm.o
endif
obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
test-kprobes-objs := kprobes-test.o
ifdef CONFIG_THUMB2_KERNEL
test-kprobes-objs += kprobes-test-thumb.o
else
test-kprobes-objs += kprobes-test-arm.o
endif
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_ARM_THUMBEE) += thumbee.o obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
obj-$(CONFIG_KGDB) += kgdb.o patch.o obj-$(CONFIG_KGDB) += kgdb.o patch.o
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "entry-header.S" #include "entry-header.S"
#include <asm/entry-macro-multi.S> #include <asm/entry-macro-multi.S>
#include <asm/probes.h>
/* /*
* Interrupt handling. * Interrupt handling.
...@@ -249,7 +250,7 @@ __und_svc: ...@@ -249,7 +250,7 @@ __und_svc:
@ If a kprobe is about to simulate a "stmdb sp..." instruction, @ If a kprobe is about to simulate a "stmdb sp..." instruction,
@ it obviously needs free stack space which then will belong to @ it obviously needs free stack space which then will belong to
@ the saved context. @ the saved context.
svc_entry 64 svc_entry MAX_STACK_SIZE
#else #else
svc_entry svc_entry
#endif #endif
......
...@@ -20,8 +20,7 @@ ...@@ -20,8 +20,7 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/opcodes.h> #include <asm/opcodes.h>
#include <asm/ftrace.h> #include <asm/ftrace.h>
#include <asm/insn.h>
#include "insn.h"
#ifdef CONFIG_THUMB2_KERNEL #ifdef CONFIG_THUMB2_KERNEL
#define NOP 0xf85deb04 /* pop.w {lr} */ #define NOP 0xf85deb04 /* pop.w {lr} */
......
...@@ -346,6 +346,12 @@ __turn_mmu_on_loc: ...@@ -346,6 +346,12 @@ __turn_mmu_on_loc:
#if defined(CONFIG_SMP) #if defined(CONFIG_SMP)
.text .text
ENTRY(secondary_startup_arm)
.arm
THUMB( adr r9, BSYM(1f) ) @ Kernel is entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
ENTRY(secondary_startup) ENTRY(secondary_startup)
/* /*
* Common entry point for secondary CPUs. * Common entry point for secondary CPUs.
...@@ -385,6 +391,7 @@ ENTRY(secondary_startup) ...@@ -385,6 +391,7 @@ ENTRY(secondary_startup)
THUMB( add r12, r10, #PROCINFO_INITFUNC ) THUMB( add r12, r10, #PROCINFO_INITFUNC )
THUMB( ret r12 ) THUMB( ret r12 )
ENDPROC(secondary_startup) ENDPROC(secondary_startup)
ENDPROC(secondary_startup_arm)
/* /*
* r6 = &secondary_data * r6 = &secondary_data
...@@ -586,7 +593,7 @@ __fixup_pv_table: ...@@ -586,7 +593,7 @@ __fixup_pv_table:
add r5, r5, r3 @ adjust table end address add r5, r5, r3 @ adjust table end address
add r6, r6, r3 @ adjust __pv_phys_pfn_offset address add r6, r6, r3 @ adjust __pv_phys_pfn_offset address
add r7, r7, r3 @ adjust __pv_offset address add r7, r7, r3 @ adjust __pv_offset address
mov r0, r8, lsr #12 @ convert to PFN mov r0, r8, lsr #PAGE_SHIFT @ convert to PFN
str r0, [r6] @ save computed PHYS_OFFSET to __pv_phys_pfn_offset str r0, [r6] @ save computed PHYS_OFFSET to __pv_phys_pfn_offset
strcc ip, [r7, #HIGH_OFFSET] @ save to __pv_offset high bits strcc ip, [r7, #HIGH_OFFSET] @ save to __pv_offset high bits
mov r6, r3, lsr #24 @ constant for add/sub instructions mov r6, r3, lsr #24 @ constant for add/sub instructions
......
...@@ -109,7 +109,8 @@ void __init init_IRQ(void) ...@@ -109,7 +109,8 @@ void __init init_IRQ(void)
if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_CACHE_L2X0) && if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_CACHE_L2X0) &&
(machine_desc->l2c_aux_mask || machine_desc->l2c_aux_val)) { (machine_desc->l2c_aux_mask || machine_desc->l2c_aux_val)) {
outer_cache.write_sec = machine_desc->l2c_write_sec; if (!outer_cache.write_sec)
outer_cache.write_sec = machine_desc->l2c_write_sec;
ret = l2x0_of_init(machine_desc->l2c_aux_val, ret = l2x0_of_init(machine_desc->l2c_aux_val,
machine_desc->l2c_aux_mask); machine_desc->l2c_aux_mask);
if (ret) if (ret)
......
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/jump_label.h> #include <linux/jump_label.h>
#include <asm/patch.h>
#include "insn.h" #include <asm/insn.h>
#include "patch.h"
#ifdef HAVE_JUMP_LABEL #ifdef HAVE_JUMP_LABEL
......
...@@ -14,10 +14,9 @@ ...@@ -14,10 +14,9 @@
#include <linux/kgdb.h> #include <linux/kgdb.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/patch.h>
#include <asm/traps.h> #include <asm/traps.h>
#include "patch.h"
struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
{ {
{ "r0", 4, offsetof(struct pt_regs, ARM_r0)}, { "r0", 4, offsetof(struct pt_regs, ARM_r0)},
......
...@@ -8,8 +8,7 @@ ...@@ -8,8 +8,7 @@
#include <asm/fixmap.h> #include <asm/fixmap.h>
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
#include <asm/opcodes.h> #include <asm/opcodes.h>
#include <asm/patch.h>
#include "patch.h"
struct patch { struct patch {
void *addr; void *addr;
......
...@@ -14,10 +14,6 @@ extern int __cpu_suspend(unsigned long, int (*)(unsigned long), u32 cpuid); ...@@ -14,10 +14,6 @@ extern int __cpu_suspend(unsigned long, int (*)(unsigned long), u32 cpuid);
extern void cpu_resume_mmu(void); extern void cpu_resume_mmu(void);
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
/*
* Hide the first two arguments to __cpu_suspend - these are an implementation
* detail which platform code shouldn't have to know about.
*/
int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
{ {
struct mm_struct *mm = current->active_mm; struct mm_struct *mm = current->active_mm;
......
...@@ -15,19 +15,8 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ ...@@ -15,19 +15,8 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
io-readsb.o io-writesb.o io-readsl.o io-writesl.o \ io-readsb.o io-writesb.o io-readsl.o io-writesl.o \
call_with_stack.o bswapsdi2.o call_with_stack.o bswapsdi2.o
mmu-y := clear_user.o copy_page.o getuser.o putuser.o mmu-y := clear_user.o copy_page.o getuser.o putuser.o \
copy_from_user.o copy_to_user.o
# the code in uaccess.S is not preemption safe and
# probably faster on ARMv3 only
ifeq ($(CONFIG_PREEMPT),y)
mmu-y += copy_from_user.o copy_to_user.o
else
ifneq ($(CONFIG_CPU_32v3),y)
mmu-y += copy_from_user.o copy_to_user.o
else
mmu-y += uaccess.o
endif
endif
# using lib_ here won't override already available weak symbols # using lib_ here won't override already available weak symbols
obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o
......
This diff is collapsed.
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/cputype.h> #include <asm/cputype.h>
#include <asm/firmware.h> #include <asm/firmware.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/suspend.h> #include <asm/suspend.h>
#include <mach/map.h> #include <mach/map.h>
...@@ -136,6 +137,43 @@ static const struct firmware_ops exynos_firmware_ops = { ...@@ -136,6 +137,43 @@ static const struct firmware_ops exynos_firmware_ops = {
.resume = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL, .resume = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL,
}; };
static void exynos_l2_write_sec(unsigned long val, unsigned reg)
{
static int l2cache_enabled;
switch (reg) {
case L2X0_CTRL:
if (val & L2X0_CTRL_EN) {
/*
* Before the cache can be enabled, due to firmware
* design, SMC_CMD_L2X0INVALL must be called.
*/
if (!l2cache_enabled) {
exynos_smc(SMC_CMD_L2X0INVALL, 0, 0, 0);
l2cache_enabled = 1;
}
} else {
l2cache_enabled = 0;
}
exynos_smc(SMC_CMD_L2X0CTRL, val, 0, 0);
break;
case L2X0_DEBUG_CTRL:
exynos_smc(SMC_CMD_L2X0DEBUG, val, 0, 0);
break;
default:
WARN_ONCE(1, "%s: ignoring write to reg 0x%x\n", __func__, reg);
}
}
static void exynos_l2_configure(const struct l2x0_regs *regs)
{
exynos_smc(SMC_CMD_L2X0SETUP1, regs->tag_latency, regs->data_latency,
regs->prefetch_ctrl);
exynos_smc(SMC_CMD_L2X0SETUP2, regs->pwr_ctrl, regs->aux_ctrl, 0);
}
void __init exynos_firmware_init(void) void __init exynos_firmware_init(void)
{ {
struct device_node *nd; struct device_node *nd;
...@@ -155,4 +193,16 @@ void __init exynos_firmware_init(void) ...@@ -155,4 +193,16 @@ void __init exynos_firmware_init(void)
pr_info("Running under secure firmware.\n"); pr_info("Running under secure firmware.\n");
register_firmware_ops(&exynos_firmware_ops); register_firmware_ops(&exynos_firmware_ops);
/*
* Exynos 4 SoCs (based on Cortex A9 and equipped with L2C-310),
* running under secure firmware, require certain registers of L2
* cache controller to be written in secure mode. Here .write_sec
* callback is provided to perform necessary SMC calls.
*/
if (IS_ENABLED(CONFIG_CACHE_L2X0) &&
read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
outer_cache.write_sec = exynos_l2_write_sec;
outer_cache.configure = exynos_l2_configure;
}
} }
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/hardware/cache-l2x0.h>
#include "smc.h" #include "smc.h"
#define CPU_MASK 0xff0ffff0 #define CPU_MASK 0xff0ffff0
...@@ -74,6 +76,45 @@ ENTRY(exynos_cpu_resume_ns) ...@@ -74,6 +76,45 @@ ENTRY(exynos_cpu_resume_ns)
mov r0, #SMC_CMD_C15RESUME mov r0, #SMC_CMD_C15RESUME
dsb dsb
smc #0 smc #0
#ifdef CONFIG_CACHE_L2X0
adr r0, 1f
ldr r2, [r0]
add r0, r2, r0
/* Check that the address has been initialised. */
ldr r1, [r0, #L2X0_R_PHY_BASE]
teq r1, #0
beq skip_l2x0
/* Check if controller has been enabled. */
ldr r2, [r1, #L2X0_CTRL]
tst r2, #0x1
bne skip_l2x0
ldr r1, [r0, #L2X0_R_TAG_LATENCY]
ldr r2, [r0, #L2X0_R_DATA_LATENCY]
ldr r3, [r0, #L2X0_R_PREFETCH_CTRL]
mov r0, #SMC_CMD_L2X0SETUP1
smc #0
/* Reload saved regs pointer because smc corrupts registers. */
adr r0, 1f
ldr r2, [r0]
add r0, r2, r0
ldr r1, [r0, #L2X0_R_PWR_CTRL]
ldr r2, [r0, #L2X0_R_AUX_CTRL]
mov r0, #SMC_CMD_L2X0SETUP2
smc #0
mov r0, #SMC_CMD_L2X0INVALL
smc #0
mov r1, #1
mov r0, #SMC_CMD_L2X0CTRL
smc #0
skip_l2x0:
#endif /* CONFIG_CACHE_L2X0 */
skip_cp15: skip_cp15:
b cpu_resume b cpu_resume
ENDPROC(exynos_cpu_resume_ns) ENDPROC(exynos_cpu_resume_ns)
...@@ -83,3 +124,8 @@ cp15_save_diag: ...@@ -83,3 +124,8 @@ cp15_save_diag:
.globl cp15_save_power .globl cp15_save_power
cp15_save_power: cp15_save_power:
.long 0 @ cp15 power control .long 0 @ cp15 power control
#ifdef CONFIG_CACHE_L2X0
.align
1: .long l2x0_saved_regs - .
#endif /* CONFIG_CACHE_L2X0 */
/* arch/arm/mach-omap1/include/mach/debug-macro.S
*
* Debugging macro include header
*
* Copyright (C) 1994-1999 Russell King
* Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
*
* 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.
*
*/
#include <linux/serial_reg.h>
#include "serial.h"
.pushsection .data
omap_uart_phys: .word 0x0
omap_uart_virt: .word 0x0
.popsection
/*
* Note that this code won't work if the bootloader passes
* a wrong machine ID number in r1. To debug, just hardcode
* the desired UART phys and virt addresses temporarily into
* the omap_uart_phys and omap_uart_virt above.
*/
.macro addruart, rp, rv, tmp
/* Use omap_uart_phys/virt if already configured */
9: adr \rp, 99f @ get effective addr of 99f
ldr \rv, [\rp] @ get absolute addr of 99f
sub \rv, \rv, \rp @ offset between the two
ldr \rp, [\rp, #4] @ abs addr of omap_uart_phys
sub \tmp, \rp, \rv @ make it effective
ldr \rp, [\tmp, #0] @ omap_uart_phys
ldr \rv, [\tmp, #4] @ omap_uart_virt
cmp \rp, #0 @ is port configured?
cmpne \rv, #0
bne 100f @ already configured
/* Check the debug UART configuration set in uncompress.h */
and \rp, pc, #0xff000000
ldr \rv, =OMAP_UART_INFO_OFS
ldr \rp, [\rp, \rv]
/* Select the UART to use based on the UART1 scratchpad value */
10: cmp \rp, #0 @ no port configured?
beq 11f @ if none, try to use UART1
cmp \rp, #OMAP1UART1
beq 11f @ configure OMAP1UART1
cmp \rp, #OMAP1UART2
beq 12f @ configure OMAP1UART2
cmp \rp, #OMAP1UART3
beq 13f @ configure OMAP2UART3
/* Configure the UART offset from the phys/virt base */
11: mov \rp, #0x00fb0000 @ OMAP1UART1
b 98f
12: mov \rp, #0x00fb0000 @ OMAP1UART1
orr \rp, \rp, #0x00000800 @ OMAP1UART2
b 98f
13: mov \rp, #0x00fb0000 @ OMAP1UART1
orr \rp, \rp, #0x00000800 @ OMAP1UART2
orr \rp, \rp, #0x00009000 @ OMAP1UART3
/* Store both phys and virt address for the uart */
98: add \rp, \rp, #0xff000000 @ phys base
str \rp, [\tmp, #0] @ omap_uart_phys
sub \rp, \rp, #0xff000000 @ phys base
add \rp, \rp, #0xfe000000 @ virt base
str \rp, [\tmp, #4] @ omap_uart_virt
b 9b
.align
99: .word .
.word omap_uart_phys
.ltorg
100:
.endm
.macro senduart,rd,rx
strb \rd, [\rx]
.endm
.macro busyuart,rd,rx
1001: ldrb \rd, [\rx, #(UART_LSR << OMAP_PORT_SHIFT)]
and \rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE)
teq \rd, #(UART_LSR_TEMT | UART_LSR_THRE)
beq 1002f
ldrb \rd, [\rx, #(UART_LSR << OMAP7XX_PORT_SHIFT)]
and \rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE)
teq \rd, #(UART_LSR_TEMT | UART_LSR_THRE)
bne 1001b
1002:
.endm
.macro waituart,rd,rx
.endm
...@@ -189,6 +189,9 @@ static const char *const omap4_boards_compat[] __initconst = { ...@@ -189,6 +189,9 @@ static const char *const omap4_boards_compat[] __initconst = {
}; };
DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)") DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)")
.l2c_aux_val = OMAP_L2C_AUX_CTRL,
.l2c_aux_mask = 0xcf9fffff,
.l2c_write_sec = omap4_l2c310_write_sec,
.reserve = omap_reserve, .reserve = omap_reserve,
.smp = smp_ops(omap4_smp_ops), .smp = smp_ops(omap4_smp_ops),
.map_io = omap4_map_io, .map_io = omap4_map_io,
...@@ -232,6 +235,9 @@ static const char *const am43_boards_compat[] __initconst = { ...@@ -232,6 +235,9 @@ static const char *const am43_boards_compat[] __initconst = {
}; };
DT_MACHINE_START(AM43_DT, "Generic AM43 (Flattened Device Tree)") DT_MACHINE_START(AM43_DT, "Generic AM43 (Flattened Device Tree)")
.l2c_aux_val = OMAP_L2C_AUX_CTRL,
.l2c_aux_mask = 0xcf9fffff,
.l2c_write_sec = omap4_l2c310_write_sec,
.map_io = am33xx_map_io, .map_io = am33xx_map_io,
.init_early = am43xx_init_early, .init_early = am43xx_init_early,
.init_late = am43xx_init_late, .init_late = am43xx_init_late,
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/irqchip/irq-omap-intc.h> #include <linux/irqchip/irq-omap-intc.h>
#include <asm/proc-fns.h> #include <asm/proc-fns.h>
#include <asm/hardware/cache-l2x0.h>
#include "i2c.h" #include "i2c.h"
#include "serial.h" #include "serial.h"
...@@ -94,11 +95,18 @@ extern void omap3_gptimer_timer_init(void); ...@@ -94,11 +95,18 @@ extern void omap3_gptimer_timer_init(void);
extern void omap4_local_timer_init(void); extern void omap4_local_timer_init(void);
#ifdef CONFIG_CACHE_L2X0 #ifdef CONFIG_CACHE_L2X0
int omap_l2_cache_init(void); int omap_l2_cache_init(void);
#define OMAP_L2C_AUX_CTRL (L2C_AUX_CTRL_SHARED_OVERRIDE | \
L310_AUX_CTRL_DATA_PREFETCH | \
L310_AUX_CTRL_INSTR_PREFETCH)
void omap4_l2c310_write_sec(unsigned long val, unsigned reg);
#else #else
static inline int omap_l2_cache_init(void) static inline int omap_l2_cache_init(void)
{ {
return 0; return 0;
} }
#define OMAP_L2C_AUX_CTRL 0
#define omap4_l2c310_write_sec NULL
#endif #endif
extern void omap5_realtime_timer_init(void); extern void omap5_realtime_timer_init(void);
......
...@@ -166,7 +166,7 @@ void __iomem *omap4_get_l2cache_base(void) ...@@ -166,7 +166,7 @@ void __iomem *omap4_get_l2cache_base(void)
return l2cache_base; return l2cache_base;
} }
static void omap4_l2c310_write_sec(unsigned long val, unsigned reg) void omap4_l2c310_write_sec(unsigned long val, unsigned reg)
{ {
unsigned smc_op; unsigned smc_op;
...@@ -201,24 +201,10 @@ static void omap4_l2c310_write_sec(unsigned long val, unsigned reg) ...@@ -201,24 +201,10 @@ static void omap4_l2c310_write_sec(unsigned long val, unsigned reg)
int __init omap_l2_cache_init(void) int __init omap_l2_cache_init(void)
{ {
u32 aux_ctrl;
/* Static mapping, never released */ /* Static mapping, never released */
l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K); l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K);
if (WARN_ON(!l2cache_base)) if (WARN_ON(!l2cache_base))
return -ENOMEM; return -ENOMEM;
/* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */
aux_ctrl = L2C_AUX_CTRL_SHARED_OVERRIDE |
L310_AUX_CTRL_DATA_PREFETCH |
L310_AUX_CTRL_INSTR_PREFETCH;
outer_cache.write_sec = omap4_l2c310_write_sec;
if (of_have_populated_dt())
l2x0_of_init(aux_ctrl, 0xcf9fffff);
else
l2x0_init(l2cache_base, aux_ctrl, 0xcf9fffff);
return 0; return 0;
} }
#endif #endif
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#define APCS_SAW2_VCTL 0x14 #define APCS_SAW2_VCTL 0x14
#define APCS_SAW2_2_VCTL 0x1c #define APCS_SAW2_2_VCTL 0x1c
extern void secondary_startup(void); extern void secondary_startup_arm(void);
static DEFINE_SPINLOCK(boot_lock); static DEFINE_SPINLOCK(boot_lock);
...@@ -337,7 +337,7 @@ static void __init qcom_smp_prepare_cpus(unsigned int max_cpus) ...@@ -337,7 +337,7 @@ static void __init qcom_smp_prepare_cpus(unsigned int max_cpus)
flags |= cold_boot_flags[map]; flags |= cold_boot_flags[map];
} }
if (scm_set_boot_addr(virt_to_phys(secondary_startup), flags)) { if (scm_set_boot_addr(virt_to_phys(secondary_startup_arm), flags)) {
for_each_present_cpu(cpu) { for_each_present_cpu(cpu) {
if (cpu == smp_processor_id()) if (cpu == smp_processor_id())
continue; continue;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# #
# Common support # Common support
obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o obj-y := clock.o generic.o irq.o #nmi-oopser.o
# Specific board support # Specific board support
obj-$(CONFIG_SA1100_ASSABET) += assabet.o obj-$(CONFIG_SA1100_ASSABET) += assabet.o
......
...@@ -119,6 +119,17 @@ static DEFINE_CLK(gpio27, &clk_gpio27_ops); ...@@ -119,6 +119,17 @@ static DEFINE_CLK(gpio27, &clk_gpio27_ops);
static DEFINE_CLK(cpu, &clk_cpu_ops); static DEFINE_CLK(cpu, &clk_cpu_ops);
static unsigned long clk_36864_get_rate(struct clk *clk)
{
return 3686400;
}
static struct clkops clk_36864_ops = {
.get_rate = clk_36864_get_rate,
};
static DEFINE_CLK(36864, &clk_36864_ops);
static struct clk_lookup sa11xx_clkregs[] = { static struct clk_lookup sa11xx_clkregs[] = {
CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27), CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27),
CLKDEV_INIT("sa1100-rtc", NULL, NULL), CLKDEV_INIT("sa1100-rtc", NULL, NULL),
...@@ -126,6 +137,7 @@ static struct clk_lookup sa11xx_clkregs[] = { ...@@ -126,6 +137,7 @@ static struct clk_lookup sa11xx_clkregs[] = {
CLKDEV_INIT("sa11x0-pcmcia", NULL, &clk_cpu), CLKDEV_INIT("sa11x0-pcmcia", NULL, &clk_cpu),
/* sa1111 names devices using internal offsets, PCMCIA is at 0x1800 */ /* sa1111 names devices using internal offsets, PCMCIA is at 0x1800 */
CLKDEV_INIT("1800", NULL, &clk_cpu), CLKDEV_INIT("1800", NULL, &clk_cpu),
CLKDEV_INIT(NULL, "OSTIMER0", &clk_36864),
}; };
static int __init sa11xx_clk_init(void) static int __init sa11xx_clk_init(void)
......
...@@ -371,8 +371,7 @@ static void __init collie_init(void) ...@@ -371,8 +371,7 @@ static void __init collie_init(void)
PPC_LDD6 | PPC_LDD7 | PPC_L_PCLK | PPC_L_LCLK | PPC_L_FCLK | PPC_L_BIAS | PPC_LDD6 | PPC_LDD7 | PPC_L_PCLK | PPC_L_LCLK | PPC_L_FCLK | PPC_L_BIAS |
PPC_TXD1 | PPC_TXD2 | PPC_TXD3 | PPC_TXD4 | PPC_SCLK | PPC_SFRM; PPC_TXD1 | PPC_TXD2 | PPC_TXD3 | PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PWER = _COLLIE_GPIO_AC_IN | _COLLIE_GPIO_CO | _COLLIE_GPIO_ON_KEY | PWER = 0;
_COLLIE_GPIO_WAKEUP | _COLLIE_GPIO_nREMOCON_INT | PWER_RTC;
PGSR = _COLLIE_GPIO_nREMOCON_ON; PGSR = _COLLIE_GPIO_nREMOCON_ON;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <mach/irqs.h> #include <mach/irqs.h>
#include "generic.h" #include "generic.h"
#include <clocksource/pxa.h>
unsigned int reset_status; unsigned int reset_status;
EXPORT_SYMBOL(reset_status); EXPORT_SYMBOL(reset_status);
...@@ -369,6 +370,11 @@ void __init sa1100_map_io(void) ...@@ -369,6 +370,11 @@ void __init sa1100_map_io(void)
iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
} }
void __init sa1100_timer_init(void)
{
pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x90000000), 3686400);
}
/* /*
* Disable the memory bus request/grant signals on the SA1110 to * Disable the memory bus request/grant signals on the SA1110 to
* ensure that we don't receive spurious memory requests. We set * ensure that we don't receive spurious memory requests. We set
......
...@@ -8,17 +8,17 @@ ...@@ -8,17 +8,17 @@
* 2001/11/14 RMK Cleaned up and standardised a lot of the IRQs. * 2001/11/14 RMK Cleaned up and standardised a lot of the IRQs.
*/ */
#define IRQ_GPIO0 1 #define IRQ_GPIO0_SC 1
#define IRQ_GPIO1 2 #define IRQ_GPIO1_SC 2
#define IRQ_GPIO2 3 #define IRQ_GPIO2_SC 3
#define IRQ_GPIO3 4 #define IRQ_GPIO3_SC 4
#define IRQ_GPIO4 5 #define IRQ_GPIO4_SC 5
#define IRQ_GPIO5 6 #define IRQ_GPIO5_SC 6
#define IRQ_GPIO6 7 #define IRQ_GPIO6_SC 7
#define IRQ_GPIO7 8 #define IRQ_GPIO7_SC 8
#define IRQ_GPIO8 9 #define IRQ_GPIO8_SC 9
#define IRQ_GPIO9 10 #define IRQ_GPIO9_SC 10
#define IRQ_GPIO10 11 #define IRQ_GPIO10_SC 11
#define IRQ_GPIO11_27 12 #define IRQ_GPIO11_27 12
#define IRQ_LCD 13 /* LCD controller */ #define IRQ_LCD 13 /* LCD controller */
#define IRQ_Ser0UDC 14 /* Ser. port 0 UDC */ #define IRQ_Ser0UDC 14 /* Ser. port 0 UDC */
...@@ -41,32 +41,43 @@ ...@@ -41,32 +41,43 @@
#define IRQ_RTC1Hz 31 /* RTC 1 Hz clock */ #define IRQ_RTC1Hz 31 /* RTC 1 Hz clock */
#define IRQ_RTCAlrm 32 /* RTC Alarm */ #define IRQ_RTCAlrm 32 /* RTC Alarm */
#define IRQ_GPIO11 33 #define IRQ_GPIO0 33
#define IRQ_GPIO12 34 #define IRQ_GPIO1 34
#define IRQ_GPIO13 35 #define IRQ_GPIO2 35
#define IRQ_GPIO14 36 #define IRQ_GPIO3 36
#define IRQ_GPIO15 37 #define IRQ_GPIO4 37
#define IRQ_GPIO16 38 #define IRQ_GPIO5 38
#define IRQ_GPIO17 39 #define IRQ_GPIO6 39
#define IRQ_GPIO18 40 #define IRQ_GPIO7 40
#define IRQ_GPIO19 41 #define IRQ_GPIO8 41
#define IRQ_GPIO20 42 #define IRQ_GPIO9 42
#define IRQ_GPIO21 43 #define IRQ_GPIO10 43
#define IRQ_GPIO22 44 #define IRQ_GPIO11 44
#define IRQ_GPIO23 45 #define IRQ_GPIO12 45
#define IRQ_GPIO24 46 #define IRQ_GPIO13 46
#define IRQ_GPIO25 47 #define IRQ_GPIO14 47
#define IRQ_GPIO26 48 #define IRQ_GPIO15 48
#define IRQ_GPIO27 49 #define IRQ_GPIO16 49
#define IRQ_GPIO17 50
#define IRQ_GPIO18 51
#define IRQ_GPIO19 52
#define IRQ_GPIO20 53
#define IRQ_GPIO21 54
#define IRQ_GPIO22 55
#define IRQ_GPIO23 56
#define IRQ_GPIO24 57
#define IRQ_GPIO25 58
#define IRQ_GPIO26 59
#define IRQ_GPIO27 60
/* /*
* The next 16 interrupts are for board specific purposes. Since * The next 16 interrupts are for board specific purposes. Since
* the kernel can only run on one machine at a time, we can re-use * the kernel can only run on one machine at a time, we can re-use
* these. If you need more, increase IRQ_BOARD_END, but keep it * these. If you need more, increase IRQ_BOARD_END, but keep it
* within sensible limits. IRQs 49 to 64 are available. * within sensible limits. IRQs 61 to 76 are available.
*/ */
#define IRQ_BOARD_START 50 #define IRQ_BOARD_START 61
#define IRQ_BOARD_END 66 #define IRQ_BOARD_END 77
/* /*
* Figure out the MAX IRQ number. * Figure out the MAX IRQ number.
......
...@@ -80,170 +80,6 @@ static struct irq_domain_ops sa1100_normal_irqdomain_ops = { ...@@ -80,170 +80,6 @@ static struct irq_domain_ops sa1100_normal_irqdomain_ops = {
static struct irq_domain *sa1100_normal_irqdomain; static struct irq_domain *sa1100_normal_irqdomain;
/*
* SA1100 GPIO edge detection for IRQs:
* IRQs are generated on Falling-Edge, Rising-Edge, or both.
* Use this instead of directly setting GRER/GFER.
*/
static int GPIO_IRQ_rising_edge;
static int GPIO_IRQ_falling_edge;
static int GPIO_IRQ_mask = (1 << 11) - 1;
static int sa1100_gpio_type(struct irq_data *d, unsigned int type)
{
unsigned int mask;
mask = BIT(d->hwirq);
if (type == IRQ_TYPE_PROBE) {
if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask)
return 0;
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
}
if (type & IRQ_TYPE_EDGE_RISING) {
GPIO_IRQ_rising_edge |= mask;
} else
GPIO_IRQ_rising_edge &= ~mask;
if (type & IRQ_TYPE_EDGE_FALLING) {
GPIO_IRQ_falling_edge |= mask;
} else
GPIO_IRQ_falling_edge &= ~mask;
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
return 0;
}
/*
* GPIO IRQs must be acknowledged.
*/
static void sa1100_gpio_ack(struct irq_data *d)
{
GEDR = BIT(d->hwirq);
}
static int sa1100_gpio_wake(struct irq_data *d, unsigned int on)
{
if (on)
PWER |= BIT(d->hwirq);
else
PWER &= ~BIT(d->hwirq);
return 0;
}
/*
* This is for IRQs from 0 to 10.
*/
static struct irq_chip sa1100_low_gpio_chip = {
.name = "GPIO-l",
.irq_ack = sa1100_gpio_ack,
.irq_mask = sa1100_mask_irq,
.irq_unmask = sa1100_unmask_irq,
.irq_set_type = sa1100_gpio_type,
.irq_set_wake = sa1100_gpio_wake,
};
static int sa1100_low_gpio_irqdomain_map(struct irq_domain *d,
unsigned int irq, irq_hw_number_t hwirq)
{
irq_set_chip_and_handler(irq, &sa1100_low_gpio_chip,
handle_edge_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
return 0;
}
static struct irq_domain_ops sa1100_low_gpio_irqdomain_ops = {
.map = sa1100_low_gpio_irqdomain_map,
.xlate = irq_domain_xlate_onetwocell,
};
static struct irq_domain *sa1100_low_gpio_irqdomain;
/*
* IRQ11 (GPIO11 through 27) handler. We enter here with the
* irq_controller_lock held, and IRQs disabled. Decode the IRQ
* and call the handler.
*/
static void
sa1100_high_gpio_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned int mask;
mask = GEDR & 0xfffff800;
do {
/*
* clear down all currently active IRQ sources.
* We will be processing them all.
*/
GEDR = mask;
irq = IRQ_GPIO11;
mask >>= 11;
do {
if (mask & 1)
generic_handle_irq(irq);
mask >>= 1;
irq++;
} while (mask);
mask = GEDR & 0xfffff800;
} while (mask);
}
/*
* Like GPIO0 to 10, GPIO11-27 IRQs need to be handled specially.
* In addition, the IRQs are all collected up into one bit in the
* interrupt controller registers.
*/
static void sa1100_high_gpio_mask(struct irq_data *d)
{
unsigned int mask = BIT(d->hwirq);
GPIO_IRQ_mask &= ~mask;
GRER &= ~mask;
GFER &= ~mask;
}
static void sa1100_high_gpio_unmask(struct irq_data *d)
{
unsigned int mask = BIT(d->hwirq);
GPIO_IRQ_mask |= mask;
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
}
static struct irq_chip sa1100_high_gpio_chip = {
.name = "GPIO-h",
.irq_ack = sa1100_gpio_ack,
.irq_mask = sa1100_high_gpio_mask,
.irq_unmask = sa1100_high_gpio_unmask,
.irq_set_type = sa1100_gpio_type,
.irq_set_wake = sa1100_gpio_wake,
};
static int sa1100_high_gpio_irqdomain_map(struct irq_domain *d,
unsigned int irq, irq_hw_number_t hwirq)
{
irq_set_chip_and_handler(irq, &sa1100_high_gpio_chip,
handle_edge_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
return 0;
}
static struct irq_domain_ops sa1100_high_gpio_irqdomain_ops = {
.map = sa1100_high_gpio_irqdomain_map,
.xlate = irq_domain_xlate_onetwocell,
};
static struct irq_domain *sa1100_high_gpio_irqdomain;
static struct resource irq_resource = static struct resource irq_resource =
DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs"); DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs");
...@@ -270,17 +106,6 @@ static int sa1100irq_suspend(void) ...@@ -270,17 +106,6 @@ static int sa1100irq_suspend(void)
IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2| IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2|
IC_GPIO1|IC_GPIO0); IC_GPIO1|IC_GPIO0);
/*
* Set the appropriate edges for wakeup.
*/
GRER = PWER & GPIO_IRQ_rising_edge;
GFER = PWER & GPIO_IRQ_falling_edge;
/*
* Clear any pending GPIO interrupts.
*/
GEDR = GEDR;
return 0; return 0;
} }
...@@ -292,9 +117,6 @@ static void sa1100irq_resume(void) ...@@ -292,9 +117,6 @@ static void sa1100irq_resume(void)
ICCR = st->iccr; ICCR = st->iccr;
ICLR = st->iclr; ICLR = st->iclr;
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
ICMR = st->icmr; ICMR = st->icmr;
} }
} }
...@@ -325,7 +147,8 @@ sa1100_handle_irq(struct pt_regs *regs) ...@@ -325,7 +147,8 @@ sa1100_handle_irq(struct pt_regs *regs)
if (mask == 0) if (mask == 0)
break; break;
handle_IRQ(ffs(mask) - 1 + IRQ_GPIO0, regs); handle_domain_irq(sa1100_normal_irqdomain,
ffs(mask) - 1, regs);
} while (1); } while (1);
} }
...@@ -339,34 +162,16 @@ void __init sa1100_init_irq(void) ...@@ -339,34 +162,16 @@ void __init sa1100_init_irq(void)
/* all IRQs are IRQ, not FIQ */ /* all IRQs are IRQ, not FIQ */
ICLR = 0; ICLR = 0;
/* clear all GPIO edge detects */
GFER = 0;
GRER = 0;
GEDR = -1;
/* /*
* Whatever the doc says, this has to be set for the wait-on-irq * Whatever the doc says, this has to be set for the wait-on-irq
* instruction to work... on a SA1100 rev 9 at least. * instruction to work... on a SA1100 rev 9 at least.
*/ */
ICCR = 1; ICCR = 1;
sa1100_low_gpio_irqdomain = irq_domain_add_legacy(NULL, sa1100_normal_irqdomain = irq_domain_add_simple(NULL,
11, IRQ_GPIO0, 0, 32, IRQ_GPIO0_SC,
&sa1100_low_gpio_irqdomain_ops, NULL);
sa1100_normal_irqdomain = irq_domain_add_legacy(NULL,
21, IRQ_GPIO11_27, 11,
&sa1100_normal_irqdomain_ops, NULL); &sa1100_normal_irqdomain_ops, NULL);
sa1100_high_gpio_irqdomain = irq_domain_add_legacy(NULL,
17, IRQ_GPIO11, 11,
&sa1100_high_gpio_irqdomain_ops, NULL);
/*
* Install handler for GPIO 11-27 edge detect interrupts
*/
irq_set_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler);
set_handle_irq(sa1100_handle_irq); set_handle_irq(sa1100_handle_irq);
sa1100_init_gpio(); sa1100_init_gpio();
......
...@@ -81,6 +81,7 @@ static int sa11x0_pm_enter(suspend_state_t state) ...@@ -81,6 +81,7 @@ static int sa11x0_pm_enter(suspend_state_t state)
/* /*
* Ensure not to come back here if it wasn't intended * Ensure not to come back here if it wasn't intended
*/ */
RCSR = RCSR_SMR;
PSPR = 0; PSPR = 0;
/* /*
......
/*
* linux/arch/arm/mach-sa1100/time.c
*
* Copyright (C) 1998 Deborah Wallach.
* Twiddles (C) 1999 Hugo Fiennes <hugo@empeg.com>
*
* 2000/03/29 (C) Nicolas Pitre <nico@fluxnic.net>
* Rewritten: big cleanup, much simpler, better HZ accuracy.
*
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/timex.h>
#include <linux/clockchips.h>
#include <linux/sched_clock.h>
#include <asm/mach/time.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#define SA1100_CLOCK_FREQ 3686400
#define SA1100_LATCH DIV_ROUND_CLOSEST(SA1100_CLOCK_FREQ, HZ)
static u64 notrace sa1100_read_sched_clock(void)
{
return readl_relaxed(OSCR);
}
#define MIN_OSCR_DELTA 2
static irqreturn_t sa1100_ost0_interrupt(int irq, void *dev_id)
{
struct clock_event_device *c = dev_id;
/* Disarm the compare/match, signal the event. */
writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
writel_relaxed(OSSR_M0, OSSR);
c->event_handler(c);
return IRQ_HANDLED;
}
static int
sa1100_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c)
{
unsigned long next, oscr;
writel_relaxed(readl_relaxed(OIER) | OIER_E0, OIER);
next = readl_relaxed(OSCR) + delta;
writel_relaxed(next, OSMR0);
oscr = readl_relaxed(OSCR);
return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
}
static void
sa1100_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c)
{
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
writel_relaxed(OSSR_M0, OSSR);
break;
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
break;
}
}
#ifdef CONFIG_PM
unsigned long osmr[4], oier;
static void sa1100_timer_suspend(struct clock_event_device *cedev)
{
osmr[0] = readl_relaxed(OSMR0);
osmr[1] = readl_relaxed(OSMR1);
osmr[2] = readl_relaxed(OSMR2);
osmr[3] = readl_relaxed(OSMR3);
oier = readl_relaxed(OIER);
}
static void sa1100_timer_resume(struct clock_event_device *cedev)
{
writel_relaxed(0x0f, OSSR);
writel_relaxed(osmr[0], OSMR0);
writel_relaxed(osmr[1], OSMR1);
writel_relaxed(osmr[2], OSMR2);
writel_relaxed(osmr[3], OSMR3);
writel_relaxed(oier, OIER);
/*
* OSMR0 is the system timer: make sure OSCR is sufficiently behind
*/
writel_relaxed(OSMR0 - SA1100_LATCH, OSCR);
}
#else
#define sa1100_timer_suspend NULL
#define sa1100_timer_resume NULL
#endif
static struct clock_event_device ckevt_sa1100_osmr0 = {
.name = "osmr0",
.features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 200,
.set_next_event = sa1100_osmr0_set_next_event,
.set_mode = sa1100_osmr0_set_mode,
.suspend = sa1100_timer_suspend,
.resume = sa1100_timer_resume,
};
static struct irqaction sa1100_timer_irq = {
.name = "ost0",
.flags = IRQF_TIMER | IRQF_IRQPOLL,
.handler = sa1100_ost0_interrupt,
.dev_id = &ckevt_sa1100_osmr0,
};
void __init sa1100_timer_init(void)
{
writel_relaxed(0, OIER);
writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
sched_clock_register(sa1100_read_sched_clock, 32, 3686400);
ckevt_sa1100_osmr0.cpumask = cpumask_of(0);
setup_irq(IRQ_OST0, &sa1100_timer_irq);
clocksource_mmio_init(OSCR, "oscr", SA1100_CLOCK_FREQ, 200, 32,
clocksource_mmio_readl_up);
clockevents_config_and_register(&ckevt_sa1100_osmr0, 3686400,
MIN_OSCR_DELTA * 2, 0x7fffffff);
}
This diff is collapsed.
...@@ -319,10 +319,7 @@ void __init arm_memblock_init(const struct machine_desc *mdesc) ...@@ -319,10 +319,7 @@ void __init arm_memblock_init(const struct machine_desc *mdesc)
early_init_fdt_scan_reserved_mem(); early_init_fdt_scan_reserved_mem();
/* /* reserve memory for DMA contiguous allocations */
* reserve memory for DMA contigouos allocations,
* must come from DMA area inside low memory
*/
dma_contiguous_reserve(arm_dma_limit); dma_contiguous_reserve(arm_dma_limit);
arm_memblock_steal_permitted = false; arm_memblock_steal_permitted = false;
......
obj-$(CONFIG_UPROBES) += decode.o decode-arm.o uprobes/
obj-$(CONFIG_KPROBES) += decode.o kprobes/
ifdef CONFIG_THUMB2_KERNEL
obj-$(CONFIG_KPROBES) += decode-thumb.o
else
obj-$(CONFIG_KPROBES) += decode-arm.o
endif
/* /*
* arch/arm/kernel/probes-arm.c *
* arch/arm/probes/decode-arm.c
* *
* Some code moved here from arch/arm/kernel/kprobes-arm.c * Some code moved here from arch/arm/kernel/kprobes-arm.c
* *
...@@ -20,8 +21,8 @@ ...@@ -20,8 +21,8 @@
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include "probes.h" #include "decode.h"
#include "probes-arm.h" #include "decode-arm.h"
#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
...@@ -369,17 +370,17 @@ static const union decode_item arm_cccc_001x_table[] = { ...@@ -369,17 +370,17 @@ static const union decode_item arm_cccc_001x_table[] = {
/* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */
/* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_DATA_PROCESSING_IMM, DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_MOV_HALFWORD,
REGS(0, NOPC, 0, 0, 0)), REGS(0, NOPC, 0, 0, 0)),
/* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ /* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */
DECODE_OR (0x0fff00ff, 0x03200001), DECODE_OR (0x0fff00ff, 0x03200001),
/* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ /* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */
DECODE_EMULATE (0x0fff00ff, 0x03200004, PROBES_EMULATE_NONE), DECODE_EMULATE (0x0fff00ff, 0x03200004, PROBES_SEV),
/* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ /* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */
/* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ /* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */
/* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ /* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */
DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_SIMULATE_NOP), DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_WFE),
/* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */ /* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */
/* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ /* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */
/* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */ /* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */
...@@ -725,10 +726,11 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, ...@@ -725,10 +726,11 @@ static void __kprobes arm_singlestep(probes_opcode_t insn,
*/ */
enum probes_insn __kprobes enum probes_insn __kprobes
arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions) bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[])
{ {
asi->insn_singlestep = arm_singlestep; asi->insn_singlestep = arm_singlestep;
asi->insn_check_cc = probes_condition_checks[insn>>28]; asi->insn_check_cc = probes_condition_checks[insn>>28];
return probes_decode_insn(insn, asi, probes_decode_arm_table, false, return probes_decode_insn(insn, asi, probes_decode_arm_table, false,
emulate, actions); emulate, actions, checkers);
} }
/* /*
* arch/arm/kernel/probes-arm.h * arch/arm/probes/decode-arm.h
* *
* Copyright 2013 Linaro Ltd. * Copyright 2013 Linaro Ltd.
* Written by: David A. Long * Written by: David A. Long
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
#ifndef _ARM_KERNEL_PROBES_ARM_H #ifndef _ARM_KERNEL_PROBES_ARM_H
#define _ARM_KERNEL_PROBES_ARM_H #define _ARM_KERNEL_PROBES_ARM_H
#include "decode.h"
enum probes_arm_action { enum probes_arm_action {
PROBES_EMULATE_NONE,
PROBES_SIMULATE_NOP,
PROBES_PRELOAD_IMM, PROBES_PRELOAD_IMM,
PROBES_PRELOAD_REG, PROBES_PRELOAD_REG,
PROBES_BRANCH_IMM, PROBES_BRANCH_IMM,
...@@ -68,6 +68,7 @@ extern const union decode_item probes_decode_arm_table[]; ...@@ -68,6 +68,7 @@ extern const union decode_item probes_decode_arm_table[];
enum probes_insn arm_probes_decode_insn(probes_opcode_t, enum probes_insn arm_probes_decode_insn(probes_opcode_t,
struct arch_probes_insn *, bool emulate, struct arch_probes_insn *, bool emulate,
const union decode_action *actions); const union decode_action *actions,
const struct decode_checker *checkers[]);
#endif #endif
/* /*
* arch/arm/kernel/probes-thumb.c * arch/arm/probes/decode-thumb.c
* *
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
* *
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include "probes.h" #include "decode.h"
#include "probes-thumb.h" #include "decode-thumb.h"
static const union decode_item t32_table_1110_100x_x0xx[] = { static const union decode_item t32_table_1110_100x_x0xx[] = {
...@@ -863,20 +863,22 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, ...@@ -863,20 +863,22 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode,
enum probes_insn __kprobes enum probes_insn __kprobes
thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions) bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[])
{ {
asi->insn_singlestep = thumb16_singlestep; asi->insn_singlestep = thumb16_singlestep;
asi->insn_check_cc = thumb_check_cc; asi->insn_check_cc = thumb_check_cc;
return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true, return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true,
emulate, actions); emulate, actions, checkers);
} }
enum probes_insn __kprobes enum probes_insn __kprobes
thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions) bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[])
{ {
asi->insn_singlestep = thumb32_singlestep; asi->insn_singlestep = thumb32_singlestep;
asi->insn_check_cc = thumb_check_cc; asi->insn_check_cc = thumb_check_cc;
return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true, return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true,
emulate, actions); emulate, actions, checkers);
} }
/* /*
* arch/arm/kernel/probes-thumb.h * arch/arm/probes/decode-thumb.h
* *
* Copyright 2013 Linaro Ltd. * Copyright 2013 Linaro Ltd.
* Written by: David A. Long * Written by: David A. Long
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#ifndef _ARM_KERNEL_PROBES_THUMB_H #ifndef _ARM_KERNEL_PROBES_THUMB_H
#define _ARM_KERNEL_PROBES_THUMB_H #define _ARM_KERNEL_PROBES_THUMB_H
#include "decode.h"
/* /*
* True if current instruction is in an IT block. * True if current instruction is in an IT block.
*/ */
...@@ -89,9 +91,11 @@ extern const union decode_item probes_decode_thumb16_table[]; ...@@ -89,9 +91,11 @@ extern const union decode_item probes_decode_thumb16_table[];
enum probes_insn __kprobes enum probes_insn __kprobes
thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions); bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[]);
enum probes_insn __kprobes enum probes_insn __kprobes
thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions); bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[]);
#endif #endif
/* /*
* arch/arm/kernel/probes.c * arch/arm/probes/decode.c
* *
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
* *
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <linux/bug.h> #include <linux/bug.h>
#include "probes.h" #include "decode.h"
#ifndef find_str_pc_offset #ifndef find_str_pc_offset
...@@ -342,6 +342,31 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { ...@@ -342,6 +342,31 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
[DECODE_TYPE_REJECT] = sizeof(struct decode_reject) [DECODE_TYPE_REJECT] = sizeof(struct decode_reject)
}; };
static int run_checkers(const struct decode_checker *checkers[],
int action, probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
const struct decode_checker **p;
if (!checkers)
return INSN_GOOD;
p = checkers;
while (*p != NULL) {
int retval;
probes_check_t *checker_func = (*p)[action].checker;
retval = INSN_GOOD;
if (checker_func)
retval = checker_func(insn, asi, h);
if (retval == INSN_REJECTED)
return retval;
p++;
}
return INSN_GOOD;
}
/* /*
* probes_decode_insn operates on data tables in order to decode an ARM * probes_decode_insn operates on data tables in order to decode an ARM
* architecture instruction onto which a kprobe has been placed. * architecture instruction onto which a kprobe has been placed.
...@@ -388,11 +413,34 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { ...@@ -388,11 +413,34 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
int __kprobes int __kprobes
probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
const union decode_item *table, bool thumb, const union decode_item *table, bool thumb,
bool emulate, const union decode_action *actions) bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[])
{ {
const struct decode_header *h = (struct decode_header *)table; const struct decode_header *h = (struct decode_header *)table;
const struct decode_header *next; const struct decode_header *next;
bool matched = false; bool matched = false;
/*
* @insn can be modified by decode_regs. Save its original
* value for checkers.
*/
probes_opcode_t origin_insn = insn;
/*
* stack_space is initialized to 0 here. Checker functions
* should update is value if they find this is a stack store
* instruction: positive value means bytes of stack usage,
* negitive value means unable to determine stack usage
* statically. For instruction doesn't store to stack, checker
* do nothing with it.
*/
asi->stack_space = 0;
/*
* Similarly to stack_space, register_usage_flags is filled by
* checkers. Its default value is set to ~0, which is 'all
* registers are used', to prevent any potential optimization.
*/
asi->register_usage_flags = ~0UL;
if (emulate) if (emulate)
insn = prepare_emulated_insn(insn, asi, thumb); insn = prepare_emulated_insn(insn, asi, thumb);
...@@ -422,24 +470,41 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, ...@@ -422,24 +470,41 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
} }
case DECODE_TYPE_CUSTOM: { case DECODE_TYPE_CUSTOM: {
int err;
struct decode_custom *d = (struct decode_custom *)h; struct decode_custom *d = (struct decode_custom *)h;
return actions[d->decoder.action].decoder(insn, asi, h); int action = d->decoder.action;
err = run_checkers(checkers, action, origin_insn, asi, h);
if (err == INSN_REJECTED)
return INSN_REJECTED;
return actions[action].decoder(insn, asi, h);
} }
case DECODE_TYPE_SIMULATE: { case DECODE_TYPE_SIMULATE: {
int err;
struct decode_simulate *d = (struct decode_simulate *)h; struct decode_simulate *d = (struct decode_simulate *)h;
asi->insn_handler = actions[d->handler.action].handler; int action = d->handler.action;
err = run_checkers(checkers, action, origin_insn, asi, h);
if (err == INSN_REJECTED)
return INSN_REJECTED;
asi->insn_handler = actions[action].handler;
return INSN_GOOD_NO_SLOT; return INSN_GOOD_NO_SLOT;
} }
case DECODE_TYPE_EMULATE: { case DECODE_TYPE_EMULATE: {
int err;
struct decode_emulate *d = (struct decode_emulate *)h; struct decode_emulate *d = (struct decode_emulate *)h;
int action = d->handler.action;
err = run_checkers(checkers, action, origin_insn, asi, h);
if (err == INSN_REJECTED)
return INSN_REJECTED;
if (!emulate) if (!emulate)
return actions[d->handler.action].decoder(insn, return actions[action].decoder(insn, asi, h);
asi, h);
asi->insn_handler = actions[d->handler.action].handler; asi->insn_handler = actions[action].handler;
set_emulated_insn(insn, asi, thumb); set_emulated_insn(insn, asi, thumb);
return INSN_GOOD; return INSN_GOOD;
} }
......
/* /*
* arch/arm/kernel/probes.h * arch/arm/probes/decode.h
* *
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
* *
...@@ -314,6 +314,14 @@ union decode_action { ...@@ -314,6 +314,14 @@ union decode_action {
probes_custom_decode_t *decoder; probes_custom_decode_t *decoder;
}; };
typedef enum probes_insn (probes_check_t)(probes_opcode_t,
struct arch_probes_insn *,
const struct decode_header *);
struct decode_checker {
probes_check_t *checker;
};
#define DECODE_END \ #define DECODE_END \
{.bits = DECODE_TYPE_END} {.bits = DECODE_TYPE_END}
...@@ -402,6 +410,7 @@ probes_insn_handler_t probes_emulate_none; ...@@ -402,6 +410,7 @@ probes_insn_handler_t probes_emulate_none;
int __kprobes int __kprobes
probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
const union decode_item *table, bool thumb, bool emulate, const union decode_item *table, bool thumb, bool emulate,
const union decode_action *actions); const union decode_action *actions,
const struct decode_checker **checkers);
#endif #endif
obj-$(CONFIG_KPROBES) += core.o actions-common.o checkers-common.o
obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
test-kprobes-objs := test-core.o
ifdef CONFIG_THUMB2_KERNEL
obj-$(CONFIG_KPROBES) += actions-thumb.o checkers-thumb.o
test-kprobes-objs += test-thumb.o
else
obj-$(CONFIG_KPROBES) += actions-arm.o checkers-arm.o
obj-$(CONFIG_OPTPROBES) += opt-arm.o
test-kprobes-objs += test-arm.o
endif
/* /*
* arch/arm/kernel/kprobes-decode.c * arch/arm/probes/kprobes/actions-arm.c
* *
* Copyright (C) 2006, 2007 Motorola Inc. * Copyright (C) 2006, 2007 Motorola Inc.
* *
...@@ -62,8 +62,9 @@ ...@@ -62,8 +62,9 @@
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include "kprobes.h" #include "../decode-arm.h"
#include "probes-arm.h" #include "core.h"
#include "checkers.h"
#if __LINUX_ARM_ARCH__ >= 6 #if __LINUX_ARM_ARCH__ >= 6
#define BLX(reg) "blx "reg" \n\t" #define BLX(reg) "blx "reg" \n\t"
...@@ -302,8 +303,6 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, ...@@ -302,8 +303,6 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
} }
const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
[PROBES_EMULATE_NONE] = {.handler = probes_emulate_none},
[PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
[PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
[PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
[PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
...@@ -341,3 +340,5 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { ...@@ -341,3 +340,5 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
[PROBES_BRANCH] = {.handler = simulate_bbl}, [PROBES_BRANCH] = {.handler = simulate_bbl},
[PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
}; };
const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};
/* /*
* arch/arm/kernel/kprobes-common.c * arch/arm/probes/kprobes/actions-common.c
* *
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
* *
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <asm/opcodes.h> #include <asm/opcodes.h>
#include "kprobes.h" #include "core.h"
static void __kprobes simulate_ldm1stm1(probes_opcode_t insn, static void __kprobes simulate_ldm1stm1(probes_opcode_t insn,
......
/* /*
* arch/arm/kernel/kprobes-thumb.c * arch/arm/probes/kprobes/actions-thumb.c
* *
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
* *
...@@ -13,8 +13,9 @@ ...@@ -13,8 +13,9 @@
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include "kprobes.h" #include "../decode-thumb.h"
#include "probes-thumb.h" #include "core.h"
#include "checkers.h"
/* These emulation encodings are functionally equivalent... */ /* These emulation encodings are functionally equivalent... */
#define t32_emulate_rd8rn16rm0ra12_noflags \ #define t32_emulate_rd8rn16rm0ra12_noflags \
...@@ -664,3 +665,6 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = { ...@@ -664,3 +665,6 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
[PROBES_T32_MUL_ADD_LONG] = { [PROBES_T32_MUL_ADD_LONG] = {
.handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags},
}; };
const struct decode_checker *kprobes_t32_checkers[] = {t32_stack_checker, NULL};
const struct decode_checker *kprobes_t16_checkers[] = {t16_stack_checker, NULL};
/*
* arch/arm/probes/kprobes/checkers-arm.c
*
* Copyright (C) 2014 Huawei Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/kernel.h>
#include "../decode.h"
#include "../decode-arm.h"
#include "checkers.h"
static enum probes_insn __kprobes arm_check_stack(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
/*
* PROBES_LDRSTRD, PROBES_LDMSTM, PROBES_STORE,
* PROBES_STORE_EXTRA may get here. Simply mark all normal
* insns as STACK_USE_NONE.
*/
static const union decode_item table[] = {
/*
* 'STR{,D,B,H}, Rt, [Rn, Rm]' should be marked as UNKNOWN
* if Rn or Rm is SP.
* x
* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx
* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx
*/
DECODE_OR (0x0e10000f, 0x0600000d),
DECODE_OR (0x0e1f0000, 0x060d0000),
/*
* x
* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx
* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx
*/
DECODE_OR (0x0e5000bf, 0x000000bd),
DECODE_CUSTOM (0x0e5f00b0, 0x000d00b0, STACK_USE_UNKNOWN),
/*
* For PROBES_LDMSTM, only stmdx sp, [...] need to examine
*
* Bit B/A (bit 24) encodes arithmetic operation order. 1 means
* before, 0 means after.
* Bit I/D (bit 23) encodes arithmetic operation. 1 means
* increment, 0 means decrement.
*
* So:
* B I
* / /
* A D | Rn |
* STMDX SP, [...] cccc 100x 00x0 xxxx xxxx xxxx xxxx xxxx
*/
DECODE_CUSTOM (0x0edf0000, 0x080d0000, STACK_USE_STMDX),
/* P U W | Rn | Rt | imm12 |*/
/* STR (immediate) cccc 010x x0x0 1101 xxxx xxxx xxxx xxxx */
/* STRB (immediate) cccc 010x x1x0 1101 xxxx xxxx xxxx xxxx */
/* P U W | Rn | Rt |imm4| |imm4|*/
/* STRD (immediate) cccc 000x x1x0 1101 xxxx xxxx 1111 xxxx */
/* STRH (immediate) cccc 000x x1x0 1101 xxxx xxxx 1011 xxxx */
/*
* index = (P == '1'); add = (U == '1').
* Above insns with:
* index == 0 (str{,d,h} rx, [sp], #+/-imm) or
* add == 1 (str{,d,h} rx, [sp, #+<imm>])
* should be STACK_USE_NONE.
* Only str{,b,d,h} rx,[sp,#-n] (P == 1 and U == 0) are
* required to be examined.
*/
/* STR{,B} Rt,[SP,#-n] cccc 0101 0xx0 1101 xxxx xxxx xxxx xxxx */
DECODE_CUSTOM (0x0f9f0000, 0x050d0000, STACK_USE_FIXED_XXX),
/* STR{D,H} Rt,[SP,#-n] cccc 0001 01x0 1101 xxxx xxxx 1x11 xxxx */
DECODE_CUSTOM (0x0fdf00b0, 0x014d00b0, STACK_USE_FIXED_X0X),
/* fall through */
DECODE_CUSTOM (0, 0, STACK_USE_NONE),
DECODE_END
};
return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL);
}
const struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = {
[PROBES_LDRSTRD] = {.checker = arm_check_stack},
[PROBES_STORE_EXTRA] = {.checker = arm_check_stack},
[PROBES_STORE] = {.checker = arm_check_stack},
[PROBES_LDMSTM] = {.checker = arm_check_stack},
};
static enum probes_insn __kprobes arm_check_regs_nouse(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
asi->register_usage_flags = 0;
return INSN_GOOD;
}
static enum probes_insn arm_check_regs_normal(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
int i;
asi->register_usage_flags = 0;
for (i = 0; i < 5; regs >>= 4, insn >>= 4, i++)
if (regs & 0xf)
asi->register_usage_flags |= 1 << (insn & 0xf);
return INSN_GOOD;
}
static enum probes_insn arm_check_regs_ldmstm(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
unsigned int reglist = insn & 0xffff;
unsigned int rn = (insn >> 16) & 0xf;
asi->register_usage_flags = reglist | (1 << rn);
return INSN_GOOD;
}
static enum probes_insn arm_check_regs_mov_ip_sp(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
/* Instruction is 'mov ip, sp' i.e. 'mov r12, r13' */
asi->register_usage_flags = (1 << 12) | (1<< 13);
return INSN_GOOD;
}
/*
* | Rn |Rt/d| | Rm |
* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx
* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx
* | Rn |Rt/d| |imm4L|
* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx
* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx
*
* Such instructions access Rt/d and its next register, so different
* from others, a specific checker is required to handle this extra
* implicit register usage.
*/
static enum probes_insn arm_check_regs_ldrdstrd(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
int rdt = (insn >> 12) & 0xf;
arm_check_regs_normal(insn, asi, h);
asi->register_usage_flags |= 1 << (rdt + 1);
return INSN_GOOD;
}
const struct decode_checker arm_regs_checker[NUM_PROBES_ARM_ACTIONS] = {
[PROBES_MRS] = {.checker = arm_check_regs_normal},
[PROBES_SATURATING_ARITHMETIC] = {.checker = arm_check_regs_normal},
[PROBES_MUL1] = {.checker = arm_check_regs_normal},
[PROBES_MUL2] = {.checker = arm_check_regs_normal},
[PROBES_MUL_ADD_LONG] = {.checker = arm_check_regs_normal},
[PROBES_MUL_ADD] = {.checker = arm_check_regs_normal},
[PROBES_LOAD] = {.checker = arm_check_regs_normal},
[PROBES_LOAD_EXTRA] = {.checker = arm_check_regs_normal},
[PROBES_STORE] = {.checker = arm_check_regs_normal},
[PROBES_STORE_EXTRA] = {.checker = arm_check_regs_normal},
[PROBES_DATA_PROCESSING_REG] = {.checker = arm_check_regs_normal},
[PROBES_DATA_PROCESSING_IMM] = {.checker = arm_check_regs_normal},
[PROBES_SEV] = {.checker = arm_check_regs_nouse},
[PROBES_WFE] = {.checker = arm_check_regs_nouse},
[PROBES_SATURATE] = {.checker = arm_check_regs_normal},
[PROBES_REV] = {.checker = arm_check_regs_normal},
[PROBES_MMI] = {.checker = arm_check_regs_normal},
[PROBES_PACK] = {.checker = arm_check_regs_normal},
[PROBES_EXTEND] = {.checker = arm_check_regs_normal},
[PROBES_EXTEND_ADD] = {.checker = arm_check_regs_normal},
[PROBES_BITFIELD] = {.checker = arm_check_regs_normal},
[PROBES_LDMSTM] = {.checker = arm_check_regs_ldmstm},
[PROBES_MOV_IP_SP] = {.checker = arm_check_regs_mov_ip_sp},
[PROBES_LDRSTRD] = {.checker = arm_check_regs_ldrdstrd},
};
/*
* arch/arm/probes/kprobes/checkers-common.c
*
* Copyright (C) 2014 Huawei Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/kernel.h>
#include "../decode.h"
#include "../decode-arm.h"
#include "checkers.h"
enum probes_insn checker_stack_use_none(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
asi->stack_space = 0;
return INSN_GOOD_NO_SLOT;
}
enum probes_insn checker_stack_use_unknown(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
asi->stack_space = -1;
return INSN_GOOD_NO_SLOT;
}
#ifdef CONFIG_THUMB2_KERNEL
enum probes_insn checker_stack_use_imm_0xx(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
int imm = insn & 0xff;
asi->stack_space = imm;
return INSN_GOOD_NO_SLOT;
}
/*
* Different from other insn uses imm8, the real addressing offset of
* STRD in T32 encoding should be imm8 * 4. See ARMARM description.
*/
enum probes_insn checker_stack_use_t32strd(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
int imm = insn & 0xff;
asi->stack_space = imm << 2;
return INSN_GOOD_NO_SLOT;
}
#else
enum probes_insn checker_stack_use_imm_x0x(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
int imm = ((insn & 0xf00) >> 4) + (insn & 0xf);
asi->stack_space = imm;
return INSN_GOOD_NO_SLOT;
}
#endif
enum probes_insn checker_stack_use_imm_xxx(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
int imm = insn & 0xfff;
asi->stack_space = imm;
return INSN_GOOD_NO_SLOT;
}
enum probes_insn checker_stack_use_stmdx(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
unsigned int reglist = insn & 0xffff;
int pbit = insn & (1 << 24);
asi->stack_space = (hweight32(reglist) - (!pbit ? 1 : 0)) * 4;
return INSN_GOOD_NO_SLOT;
}
const union decode_action stack_check_actions[] = {
[STACK_USE_NONE] = {.decoder = checker_stack_use_none},
[STACK_USE_UNKNOWN] = {.decoder = checker_stack_use_unknown},
#ifdef CONFIG_THUMB2_KERNEL
[STACK_USE_FIXED_0XX] = {.decoder = checker_stack_use_imm_0xx},
[STACK_USE_T32STRD] = {.decoder = checker_stack_use_t32strd},
#else
[STACK_USE_FIXED_X0X] = {.decoder = checker_stack_use_imm_x0x},
#endif
[STACK_USE_FIXED_XXX] = {.decoder = checker_stack_use_imm_xxx},
[STACK_USE_STMDX] = {.decoder = checker_stack_use_stmdx},
};
/*
* arch/arm/probes/kprobes/checkers-thumb.c
*
* Copyright (C) 2014 Huawei Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/kernel.h>
#include "../decode.h"
#include "../decode-thumb.h"
#include "checkers.h"
static enum probes_insn __kprobes t32_check_stack(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
/*
* PROBES_T32_LDMSTM, PROBES_T32_LDRDSTRD and PROBES_T32_LDRSTR
* may get here. Simply mark all normal insns as STACK_USE_NONE.
*/
static const union decode_item table[] = {
/*
* First, filter out all ldr insns to make our life easier.
* Following load insns may come here:
* LDM, LDRD, LDR.
* In T32 encoding, bit 20 is enough for distinguishing
* load and store. All load insns have this bit set, when
* all store insns have this bit clear.
*/
DECODE_CUSTOM (0x00100000, 0x00100000, STACK_USE_NONE),
/*
* Mark all 'STR{,B,H}, Rt, [Rn, Rm]' as STACK_USE_UNKNOWN
* if Rn or Rm is SP. T32 doesn't encode STRD.
*/
/* xx | Rn | Rt | | Rm |*/
/* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */
/* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */
/* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */
/* INVALID INSN 1111 1000 0110 xxxx xxxx 0000 00xx xxxx */
/* By Introducing INVALID INSN, bit 21 and 22 can be ignored. */
DECODE_OR (0xff9f0fc0, 0xf80d0000),
DECODE_CUSTOM (0xff900fcf, 0xf800000d, STACK_USE_UNKNOWN),
/* xx | Rn | Rt | PUW| imm8 |*/
/* STR (imm 8) 1111 1000 0100 1101 xxxx 110x xxxx xxxx */
/* STRB (imm 8) 1111 1000 0000 1101 xxxx 110x xxxx xxxx */
/* STRH (imm 8) 1111 1000 0010 1101 xxxx 110x xxxx xxxx */
/* INVALID INSN 1111 1000 0110 1101 xxxx 110x xxxx xxxx */
/* Only consider U == 0 and P == 1: strx rx, [sp, #-<imm>] */
DECODE_CUSTOM (0xff9f0e00, 0xf80d0c00, STACK_USE_FIXED_0XX),
/* For STR{,B,H} (imm 12), offset is always positive, so ignore them. */
/* P U W | Rn | Rt | Rt2| imm8 |*/
/* STRD (immediate) 1110 1001 01x0 1101 xxxx xxxx xxxx xxxx */
/*
* Only consider U == 0 and P == 1.
* Also note that STRD in T32 encoding is special:
* imm = ZeroExtend(imm8:'00', 32)
*/
DECODE_CUSTOM (0xffdf0000, 0xe94d0000, STACK_USE_T32STRD),
/* | Rn | */
/* STMDB 1110 1001 00x0 1101 xxxx xxxx xxxx xxxx */
DECODE_CUSTOM (0xffdf0000, 0xe90d0000, STACK_USE_STMDX),
/* fall through */
DECODE_CUSTOM (0, 0, STACK_USE_NONE),
DECODE_END
};
return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL);
}
const struct decode_checker t32_stack_checker[NUM_PROBES_T32_ACTIONS] = {
[PROBES_T32_LDMSTM] = {.checker = t32_check_stack},
[PROBES_T32_LDRDSTRD] = {.checker = t32_check_stack},
[PROBES_T32_LDRSTR] = {.checker = t32_check_stack},
};
/*
* See following comments. This insn must be 'push'.
*/
static enum probes_insn __kprobes t16_check_stack(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
unsigned int reglist = insn & 0x1ff;
asi->stack_space = hweight32(reglist) * 4;
return INSN_GOOD;
}
/*
* T16 encoding is simple: only the 'push' insn can need extra stack space.
* Other insns, like str, can only use r0-r7 as Rn.
*/
const struct decode_checker t16_stack_checker[NUM_PROBES_T16_ACTIONS] = {
[PROBES_T16_PUSH] = {.checker = t16_check_stack},
};
/*
* arch/arm/probes/kprobes/checkers.h
*
* Copyright (C) 2014 Huawei Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef _ARM_KERNEL_PROBES_CHECKERS_H
#define _ARM_KERNEL_PROBES_CHECKERS_H
#include <linux/kernel.h>
#include <linux/types.h>
#include "../decode.h"
extern probes_check_t checker_stack_use_none;
extern probes_check_t checker_stack_use_unknown;
#ifdef CONFIG_THUMB2_KERNEL
extern probes_check_t checker_stack_use_imm_0xx;
#else
extern probes_check_t checker_stack_use_imm_x0x;
#endif
extern probes_check_t checker_stack_use_imm_xxx;
extern probes_check_t checker_stack_use_stmdx;
enum {
STACK_USE_NONE,
STACK_USE_UNKNOWN,
#ifdef CONFIG_THUMB2_KERNEL
STACK_USE_FIXED_0XX,
STACK_USE_T32STRD,
#else
STACK_USE_FIXED_X0X,
#endif
STACK_USE_FIXED_XXX,
STACK_USE_STMDX,
NUM_STACK_USE_TYPES
};
extern const union decode_action stack_check_actions[];
#ifndef CONFIG_THUMB2_KERNEL
extern const struct decode_checker arm_stack_checker[];
extern const struct decode_checker arm_regs_checker[];
#else
#endif
extern const struct decode_checker t32_stack_checker[];
extern const struct decode_checker t16_stack_checker[];
#endif
...@@ -30,11 +30,11 @@ ...@@ -30,11 +30,11 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <asm/patch.h>
#include "kprobes.h" #include "../decode-arm.h"
#include "probes-arm.h" #include "../decode-thumb.h"
#include "probes-thumb.h" #include "core.h"
#include "patch.h"
#define MIN_STACK_SIZE(addr) \ #define MIN_STACK_SIZE(addr) \
min((unsigned long)MAX_STACK_SIZE, \ min((unsigned long)MAX_STACK_SIZE, \
...@@ -61,6 +61,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -61,6 +61,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
kprobe_decode_insn_t *decode_insn; kprobe_decode_insn_t *decode_insn;
const union decode_action *actions; const union decode_action *actions;
int is; int is;
const struct decode_checker **checkers;
if (in_exception_text(addr)) if (in_exception_text(addr))
return -EINVAL; return -EINVAL;
...@@ -74,9 +75,11 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -74,9 +75,11 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
insn = __opcode_thumb32_compose(insn, inst2); insn = __opcode_thumb32_compose(insn, inst2);
decode_insn = thumb32_probes_decode_insn; decode_insn = thumb32_probes_decode_insn;
actions = kprobes_t32_actions; actions = kprobes_t32_actions;
checkers = kprobes_t32_checkers;
} else { } else {
decode_insn = thumb16_probes_decode_insn; decode_insn = thumb16_probes_decode_insn;
actions = kprobes_t16_actions; actions = kprobes_t16_actions;
checkers = kprobes_t16_checkers;
} }
#else /* !CONFIG_THUMB2_KERNEL */ #else /* !CONFIG_THUMB2_KERNEL */
thumb = false; thumb = false;
...@@ -85,12 +88,13 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -85,12 +88,13 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
insn = __mem_to_opcode_arm(*p->addr); insn = __mem_to_opcode_arm(*p->addr);
decode_insn = arm_probes_decode_insn; decode_insn = arm_probes_decode_insn;
actions = kprobes_arm_actions; actions = kprobes_arm_actions;
checkers = kprobes_arm_checkers;
#endif #endif
p->opcode = insn; p->opcode = insn;
p->ainsn.insn = tmp_insn; p->ainsn.insn = tmp_insn;
switch ((*decode_insn)(insn, &p->ainsn, true, actions)) { switch ((*decode_insn)(insn, &p->ainsn, true, actions, checkers)) {
case INSN_REJECTED: /* not supported */ case INSN_REJECTED: /* not supported */
return -EINVAL; return -EINVAL;
...@@ -111,6 +115,15 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -111,6 +115,15 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
break; break;
} }
/*
* Never instrument insn like 'str r0, [sp, +/-r1]'. Also, insn likes
* 'str r0, [sp, #-68]' should also be prohibited.
* See __und_svc.
*/
if ((p->ainsn.stack_space < 0) ||
(p->ainsn.stack_space > MAX_STACK_SIZE))
return -EINVAL;
return 0; return 0;
} }
...@@ -150,19 +163,31 @@ void __kprobes arch_arm_kprobe(struct kprobe *p) ...@@ -150,19 +163,31 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
* memory. It is also needed to atomically set the two half-words of a 32-bit * memory. It is also needed to atomically set the two half-words of a 32-bit
* Thumb breakpoint. * Thumb breakpoint.
*/ */
int __kprobes __arch_disarm_kprobe(void *p) struct patch {
{ void *addr;
struct kprobe *kp = p; unsigned int insn;
void *addr = (void *)((uintptr_t)kp->addr & ~1); };
__patch_text(addr, kp->opcode);
static int __kprobes_remove_breakpoint(void *data)
{
struct patch *p = data;
__patch_text(p->addr, p->insn);
return 0; return 0;
} }
void __kprobes kprobes_remove_breakpoint(void *addr, unsigned int insn)
{
struct patch p = {
.addr = addr,
.insn = insn,
};
stop_machine(__kprobes_remove_breakpoint, &p, cpu_online_mask);
}
void __kprobes arch_disarm_kprobe(struct kprobe *p) void __kprobes arch_disarm_kprobe(struct kprobe *p)
{ {
stop_machine(__arch_disarm_kprobe, p, cpu_online_mask); kprobes_remove_breakpoint((void *)((uintptr_t)p->addr & ~1),
p->opcode);
} }
void __kprobes arch_remove_kprobe(struct kprobe *p) void __kprobes arch_remove_kprobe(struct kprobe *p)
......
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
#ifndef _ARM_KERNEL_KPROBES_H #ifndef _ARM_KERNEL_KPROBES_H
#define _ARM_KERNEL_KPROBES_H #define _ARM_KERNEL_KPROBES_H
#include "probes.h" #include <asm/kprobes.h>
#include "../decode.h"
/* /*
* These undefined instructions must be unique and * These undefined instructions must be unique and
...@@ -29,6 +30,8 @@ ...@@ -29,6 +30,8 @@
#define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18 #define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18
#define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018
extern void kprobes_remove_breakpoint(void *addr, unsigned int insn);
enum probes_insn __kprobes enum probes_insn __kprobes
kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi, kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi,
const struct decode_header *h); const struct decode_header *h);
...@@ -36,16 +39,19 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi, ...@@ -36,16 +39,19 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi,
typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t,
struct arch_probes_insn *, struct arch_probes_insn *,
bool, bool,
const union decode_action *); const union decode_action *,
const struct decode_checker *[]);
#ifdef CONFIG_THUMB2_KERNEL #ifdef CONFIG_THUMB2_KERNEL
extern const union decode_action kprobes_t32_actions[]; extern const union decode_action kprobes_t32_actions[];
extern const union decode_action kprobes_t16_actions[]; extern const union decode_action kprobes_t16_actions[];
extern const struct decode_checker *kprobes_t32_checkers[];
extern const struct decode_checker *kprobes_t16_checkers[];
#else /* !CONFIG_THUMB2_KERNEL */ #else /* !CONFIG_THUMB2_KERNEL */
extern const union decode_action kprobes_arm_actions[]; extern const union decode_action kprobes_arm_actions[];
extern const struct decode_checker *kprobes_arm_checkers[];
#endif #endif
......
This diff is collapsed.
...@@ -12,8 +12,9 @@ ...@@ -12,8 +12,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <asm/system_info.h> #include <asm/system_info.h>
#include <asm/opcodes.h> #include <asm/opcodes.h>
#include <asm/probes.h>
#include "kprobes-test.h" #include "test-core.h"
#define TEST_ISA "32" #define TEST_ISA "32"
...@@ -203,9 +204,9 @@ void kprobe_arm_test_cases(void) ...@@ -203,9 +204,9 @@ void kprobe_arm_test_cases(void)
#endif #endif
TEST_GROUP("Miscellaneous instructions") TEST_GROUP("Miscellaneous instructions")
TEST("mrs r0, cpsr") TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr")
TEST("mrspl r7, cpsr") TEST_RMASKED("mrspl r",7,~PSR_IGNORE_BITS,", cpsr")
TEST("mrs r14, cpsr") TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr")
TEST_UNSUPPORTED(__inst_arm(0xe10ff000) " @ mrs r15, cpsr") TEST_UNSUPPORTED(__inst_arm(0xe10ff000) " @ mrs r15, cpsr")
TEST_UNSUPPORTED("mrs r0, spsr") TEST_UNSUPPORTED("mrs r0, spsr")
TEST_UNSUPPORTED("mrs lr, spsr") TEST_UNSUPPORTED("mrs lr, spsr")
...@@ -214,9 +215,12 @@ void kprobe_arm_test_cases(void) ...@@ -214,9 +215,12 @@ void kprobe_arm_test_cases(void)
TEST_UNSUPPORTED("msr cpsr_f, lr") TEST_UNSUPPORTED("msr cpsr_f, lr")
TEST_UNSUPPORTED("msr spsr, r0") TEST_UNSUPPORTED("msr spsr, r0")
#if __LINUX_ARM_ARCH__ >= 5 || \
(__LINUX_ARM_ARCH__ == 4 && !defined(CONFIG_CPU_32v4))
TEST_BF_R("bx r",0,2f,"") TEST_BF_R("bx r",0,2f,"")
TEST_BB_R("bx r",7,2f,"") TEST_BB_R("bx r",7,2f,"")
TEST_BF_R("bxeq r",14,2f,"") TEST_BF_R("bxeq r",14,2f,"")
#endif
#if __LINUX_ARM_ARCH__ >= 5 #if __LINUX_ARM_ARCH__ >= 5
TEST_R("clz r0, r",0, 0x0,"") TEST_R("clz r0, r",0, 0x0,"")
...@@ -476,7 +480,9 @@ void kprobe_arm_test_cases(void) ...@@ -476,7 +480,9 @@ void kprobe_arm_test_cases(void)
TEST_GROUP("Extra load/store instructions") TEST_GROUP("Extra load/store instructions")
TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]")
TEST_RPR( "streqh r",14,VAL2,", [r",13,0, ", r",12, 48,"]") TEST_RPR( "streqh r",14,VAL2,", [r",11,0, ", r",12, 48,"]")
TEST_UNSUPPORTED( "streqh r14, [r13, r12]")
TEST_UNSUPPORTED( "streqh r14, [r12, r13]")
TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!")
TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!") TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!")
TEST_RPR( "strh r",2, VAL1,", [r",3, 24,"], r",4, 48,"") TEST_RPR( "strh r",2, VAL1,", [r",3, 24,"], r",4, 48,"")
...@@ -501,6 +507,9 @@ void kprobe_arm_test_cases(void) ...@@ -501,6 +507,9 @@ void kprobe_arm_test_cases(void)
TEST_RP( "strplh r",12,VAL2,", [r",11,24,", #-4]!") TEST_RP( "strplh r",12,VAL2,", [r",11,24,", #-4]!")
TEST_RP( "strh r",2, VAL1,", [r",3, 24,"], #48") TEST_RP( "strh r",2, VAL1,", [r",3, 24,"], #48")
TEST_RP( "strh r",10,VAL2,", [r",9, 64,"], #-48") TEST_RP( "strh r",10,VAL2,", [r",9, 64,"], #-48")
TEST_RP( "strh r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!")
TEST_UNSUPPORTED("strh r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_RP( "strh r",4, VAL1,", [r",14,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) " @ strh r12, [pc, #48]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) " @ strh r12, [pc, #48]!")
TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) " @ strh pc, [r9], #48") TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) " @ strh pc, [r9], #48")
...@@ -565,7 +574,9 @@ void kprobe_arm_test_cases(void) ...@@ -565,7 +574,9 @@ void kprobe_arm_test_cases(void)
#if __LINUX_ARM_ARCH__ >= 5 #if __LINUX_ARM_ARCH__ >= 5
TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]") TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]")
TEST_RPR( "strccd r",8, VAL2,", [r",13,0, ", r",12,48,"]") TEST_RPR( "strccd r",8, VAL2,", [r",11,0, ", r",12,48,"]")
TEST_UNSUPPORTED( "strccd r8, [r13, r12]")
TEST_UNSUPPORTED( "strccd r8, [r12, r13]")
TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!")
TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!") TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!")
TEST_RPR( "strd r",2, VAL1,", [r",5, 24,"], r",4,48,"") TEST_RPR( "strd r",2, VAL1,", [r",5, 24,"], r",4,48,"")
...@@ -589,6 +600,9 @@ void kprobe_arm_test_cases(void) ...@@ -589,6 +600,9 @@ void kprobe_arm_test_cases(void)
TEST_RP( "strvcd r",12,VAL2,", [r",11,24,", #-16]!") TEST_RP( "strvcd r",12,VAL2,", [r",11,24,", #-16]!")
TEST_RP( "strd r",2, VAL1,", [r",4, 24,"], #48") TEST_RP( "strd r",2, VAL1,", [r",4, 24,"], #48")
TEST_RP( "strd r",10,VAL2,", [r",9, 64,"], #-48") TEST_RP( "strd r",10,VAL2,", [r",9, 64,"], #-48")
TEST_RP( "strd r",6, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!")
TEST_UNSUPPORTED("strd r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_RP( "strd r",4, VAL1,", [r",12,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) " @ strd r12, [pc, #48]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) " @ strd r12, [pc, #48]!")
TEST_P( "ldrd r0, [r",0, 24,", #-8]") TEST_P( "ldrd r0, [r",0, 24,", #-8]")
...@@ -637,14 +651,20 @@ void kprobe_arm_test_cases(void) ...@@ -637,14 +651,20 @@ void kprobe_arm_test_cases(void)
TEST_RP( "str"byte" r",12,VAL2,", [r",11,24,", #-4]!") \ TEST_RP( "str"byte" r",12,VAL2,", [r",11,24,", #-4]!") \
TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \ TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \
TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \ TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \
TEST_RP( "str"byte" r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \
TEST_UNSUPPORTED("str"byte" r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \
TEST_RP( "str"byte" r",4, VAL1,", [r",10,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \
TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \
TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 48,"]") \ TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 48,"]") \
TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \
TEST_UNSUPPORTED("str"byte" r14, [r12, r13]") \
TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \
TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \ TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \
TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \ TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \
TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \ TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \
TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\
TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 32,", lsr #2]")\ TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 32,", lsr #2]")\
TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]") \
TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\
TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\ TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\
TEST_P( "ldr"byte" r0, [r",0, 24,", #-2]") \ TEST_P( "ldr"byte" r0, [r",0, 24,", #-2]") \
...@@ -668,12 +688,12 @@ void kprobe_arm_test_cases(void) ...@@ -668,12 +688,12 @@ void kprobe_arm_test_cases(void)
LOAD_STORE("") LOAD_STORE("")
TEST_P( "str pc, [r",0,0,", #15*4]") TEST_P( "str pc, [r",0,0,", #15*4]")
TEST_R( "str pc, [sp, r",2,15*4,"]") TEST_UNSUPPORTED( "str pc, [sp, r2]")
TEST_BF( "ldr pc, [sp, #15*4]") TEST_BF( "ldr pc, [sp, #15*4]")
TEST_BF_R("ldr pc, [sp, r",2,15*4,"]") TEST_BF_R("ldr pc, [sp, r",2,15*4,"]")
TEST_P( "str sp, [r",0,0,", #13*4]") TEST_P( "str sp, [r",0,0,", #13*4]")
TEST_R( "str sp, [sp, r",2,13*4,"]") TEST_UNSUPPORTED( "str sp, [sp, r2]")
TEST_BF( "ldr sp, [sp, #13*4]") TEST_BF( "ldr sp, [sp, #13*4]")
TEST_BF_R("ldr sp, [sp, r",2,13*4,"]") TEST_BF_R("ldr sp, [sp, r",2,13*4,"]")
......
...@@ -209,10 +209,10 @@ ...@@ -209,10 +209,10 @@
#include <linux/bug.h> #include <linux/bug.h>
#include <asm/opcodes.h> #include <asm/opcodes.h>
#include "kprobes.h" #include "core.h"
#include "probes-arm.h" #include "test-core.h"
#include "probes-thumb.h" #include "../decode-arm.h"
#include "kprobes-test.h" #include "../decode-thumb.h"
#define BENCHMARKING 1 #define BENCHMARKING 1
...@@ -236,6 +236,8 @@ static int tests_failed; ...@@ -236,6 +236,8 @@ static int tests_failed;
#ifndef CONFIG_THUMB2_KERNEL #ifndef CONFIG_THUMB2_KERNEL
#define RET(reg) "mov pc, "#reg
long arm_func(long r0, long r1); long arm_func(long r0, long r1);
static void __used __naked __arm_kprobes_test_func(void) static void __used __naked __arm_kprobes_test_func(void)
...@@ -245,7 +247,7 @@ static void __used __naked __arm_kprobes_test_func(void) ...@@ -245,7 +247,7 @@ static void __used __naked __arm_kprobes_test_func(void)
".type arm_func, %%function \n\t" ".type arm_func, %%function \n\t"
"arm_func: \n\t" "arm_func: \n\t"
"adds r0, r0, r1 \n\t" "adds r0, r0, r1 \n\t"
"bx lr \n\t" "mov pc, lr \n\t"
".code "NORMAL_ISA /* Back to Thumb if necessary */ ".code "NORMAL_ISA /* Back to Thumb if necessary */
: : : "r0", "r1", "cc" : : : "r0", "r1", "cc"
); );
...@@ -253,6 +255,8 @@ static void __used __naked __arm_kprobes_test_func(void) ...@@ -253,6 +255,8 @@ static void __used __naked __arm_kprobes_test_func(void)
#else /* CONFIG_THUMB2_KERNEL */ #else /* CONFIG_THUMB2_KERNEL */
#define RET(reg) "bx "#reg
long thumb16_func(long r0, long r1); long thumb16_func(long r0, long r1);
long thumb32even_func(long r0, long r1); long thumb32even_func(long r0, long r1);
long thumb32odd_func(long r0, long r1); long thumb32odd_func(long r0, long r1);
...@@ -494,7 +498,7 @@ static void __naked benchmark_nop(void) ...@@ -494,7 +498,7 @@ static void __naked benchmark_nop(void)
{ {
__asm__ __volatile__ ( __asm__ __volatile__ (
"nop \n\t" "nop \n\t"
"bx lr" RET(lr)" \n\t"
); );
} }
...@@ -977,7 +981,7 @@ void __naked __kprobes_test_case_start(void) ...@@ -977,7 +981,7 @@ void __naked __kprobes_test_case_start(void)
"bic r0, lr, #1 @ r0 = inline data \n\t" "bic r0, lr, #1 @ r0 = inline data \n\t"
"mov r1, sp \n\t" "mov r1, sp \n\t"
"bl kprobes_test_case_start \n\t" "bl kprobes_test_case_start \n\t"
"bx r0 \n\t" RET(r0)" \n\t"
); );
} }
...@@ -1056,15 +1060,6 @@ static int test_case_run_count; ...@@ -1056,15 +1060,6 @@ static int test_case_run_count;
static bool test_case_is_thumb; static bool test_case_is_thumb;
static int test_instance; static int test_instance;
/*
* We ignore the state of the imprecise abort disable flag (CPSR.A) because this
* can change randomly as the kernel doesn't take care to preserve or initialise
* this across context switches. Also, with Security Extentions, the flag may
* not be under control of the kernel; for this reason we ignore the state of
* the FIQ disable flag CPSR.F as well.
*/
#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT)
static unsigned long test_check_cc(int cc, unsigned long cpsr) static unsigned long test_check_cc(int cc, unsigned long cpsr)
{ {
int ret = arm_check_condition(cc << 28, cpsr); int ret = arm_check_condition(cc << 28, cpsr);
...@@ -1196,6 +1191,13 @@ static void setup_test_context(struct pt_regs *regs) ...@@ -1196,6 +1191,13 @@ static void setup_test_context(struct pt_regs *regs)
regs->uregs[arg->reg] = regs->uregs[arg->reg] =
(unsigned long)current_stack + arg->val; (unsigned long)current_stack + arg->val;
memory_needs_checking = true; memory_needs_checking = true;
/*
* Test memory at an address below SP is in danger of
* being altered by an interrupt occurring and pushing
* data onto the stack. Disable interrupts to stop this.
*/
if (arg->reg == 13)
regs->ARM_cpsr |= PSR_I_BIT;
break; break;
} }
case ARG_TYPE_MEM: { case ARG_TYPE_MEM: {
...@@ -1264,14 +1266,26 @@ test_case_pre_handler(struct kprobe *p, struct pt_regs *regs) ...@@ -1264,14 +1266,26 @@ test_case_pre_handler(struct kprobe *p, struct pt_regs *regs)
static int __kprobes static int __kprobes
test_after_pre_handler(struct kprobe *p, struct pt_regs *regs) test_after_pre_handler(struct kprobe *p, struct pt_regs *regs)
{ {
struct test_arg *args;
if (container_of(p, struct test_probe, kprobe)->hit == test_instance) if (container_of(p, struct test_probe, kprobe)->hit == test_instance)
return 0; /* Already run for this test instance */ return 0; /* Already run for this test instance */
result_regs = *regs; result_regs = *regs;
/* Mask out results which are indeterminate */
result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS; result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS;
for (args = current_args; args[0].type != ARG_TYPE_END; ++args)
if (args[0].type == ARG_TYPE_REG_MASKED) {
struct test_arg_regptr *arg =
(struct test_arg_regptr *)args;
result_regs.uregs[arg->reg] &= arg->val;
}
/* Undo any changes done to SP by the test case */ /* Undo any changes done to SP by the test case */
regs->ARM_sp = (unsigned long)current_stack; regs->ARM_sp = (unsigned long)current_stack;
/* Enable interrupts in case setup_test_context disabled them */
regs->ARM_cpsr &= ~PSR_I_BIT;
container_of(p, struct test_probe, kprobe)->hit = test_instance; container_of(p, struct test_probe, kprobe)->hit = test_instance;
return 0; return 0;
......
/* /*
* arch/arm/kernel/kprobes-test.h * arch/arm/probes/kprobes/test-core.h
* *
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
* *
...@@ -45,10 +45,11 @@ extern int kprobe_test_cc_position; ...@@ -45,10 +45,11 @@ extern int kprobe_test_cc_position;
* *
*/ */
#define ARG_TYPE_END 0 #define ARG_TYPE_END 0
#define ARG_TYPE_REG 1 #define ARG_TYPE_REG 1
#define ARG_TYPE_PTR 2 #define ARG_TYPE_PTR 2
#define ARG_TYPE_MEM 3 #define ARG_TYPE_MEM 3
#define ARG_TYPE_REG_MASKED 4
#define ARG_FLAG_UNSUPPORTED 0x01 #define ARG_FLAG_UNSUPPORTED 0x01
#define ARG_FLAG_SUPPORTED 0x02 #define ARG_FLAG_SUPPORTED 0x02
...@@ -61,7 +62,7 @@ struct test_arg { ...@@ -61,7 +62,7 @@ struct test_arg {
}; };
struct test_arg_regptr { struct test_arg_regptr {
u8 type; /* ARG_TYPE_REG or ARG_TYPE_PTR */ u8 type; /* ARG_TYPE_REG or ARG_TYPE_PTR or ARG_TYPE_REG_MASKED */
u8 reg; u8 reg;
u8 _padding[2]; u8 _padding[2];
u32 val; u32 val;
...@@ -138,6 +139,12 @@ struct test_arg_end { ...@@ -138,6 +139,12 @@ struct test_arg_end {
".short 0 \n\t" \ ".short 0 \n\t" \
".word "#val" \n\t" ".word "#val" \n\t"
#define TEST_ARG_REG_MASKED(reg, val) \
".byte "__stringify(ARG_TYPE_REG_MASKED)" \n\t" \
".byte "#reg" \n\t" \
".short 0 \n\t" \
".word "#val" \n\t"
#define TEST_ARG_END(flags) \ #define TEST_ARG_END(flags) \
".byte "__stringify(ARG_TYPE_END)" \n\t" \ ".byte "__stringify(ARG_TYPE_END)" \n\t" \
".byte "TEST_ISA flags" \n\t" \ ".byte "TEST_ISA flags" \n\t" \
...@@ -395,6 +402,22 @@ struct test_arg_end { ...@@ -395,6 +402,22 @@ struct test_arg_end {
" "codex" \n\t" \ " "codex" \n\t" \
TESTCASE_END TESTCASE_END
#define TEST_RMASKED(code1, reg, mask, code2) \
TESTCASE_START(code1 #reg code2) \
TEST_ARG_REG_MASKED(reg, mask) \
TEST_ARG_END("") \
TEST_INSTRUCTION(code1 #reg code2) \
TESTCASE_END
/*
* We ignore the state of the imprecise abort disable flag (CPSR.A) because this
* can change randomly as the kernel doesn't take care to preserve or initialise
* this across context switches. Also, with Security Extensions, the flag may
* not be under control of the kernel; for this reason we ignore the state of
* the FIQ disable flag CPSR.F as well.
*/
#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT)
/* /*
* Macros for defining space directives spread over multiple lines. * Macros for defining space directives spread over multiple lines.
......
/* /*
* arch/arm/kernel/kprobes-test-thumb.c * arch/arm/probes/kprobes/test-thumb.c
* *
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
* *
...@@ -11,8 +11,9 @@ ...@@ -11,8 +11,9 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <asm/opcodes.h> #include <asm/opcodes.h>
#include <asm/probes.h>
#include "kprobes-test.h" #include "test-core.h"
#define TEST_ISA "16" #define TEST_ISA "16"
...@@ -416,6 +417,9 @@ void kprobe_thumb32_test_cases(void) ...@@ -416,6 +417,9 @@ void kprobe_thumb32_test_cases(void)
TEST_RR( "strd r",14,VAL2,", r",12,VAL1,", [sp, #16]!") TEST_RR( "strd r",14,VAL2,", r",12,VAL1,", [sp, #16]!")
TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16") TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16")
TEST_RR( "strd r",7, VAL2,", r",8, VAL1,", [sp], #-16") TEST_RR( "strd r",7, VAL2,", r",8, VAL1,", [sp], #-16")
TEST_RRP("strd r",6, VAL1,", r",7, VAL2,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!")
TEST_UNSUPPORTED("strd r6, r7, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_RRP("strd r",4, VAL1,", r",5, VAL2,", [r",14, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) " @ strd r14, r12, [pc, #16]!") TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) " @ strd r14, r12, [pc, #16]!")
TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) " @ strd r14, r12, [pc], #16") TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) " @ strd r14, r12, [pc], #16")
...@@ -774,8 +778,8 @@ CONDITION_INSTRUCTIONS(22, ...@@ -774,8 +778,8 @@ CONDITION_INSTRUCTIONS(22,
TEST_UNSUPPORTED("subs pc, lr, #4") TEST_UNSUPPORTED("subs pc, lr, #4")
TEST("mrs r0, cpsr") TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr")
TEST("mrs r14, cpsr") TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr")
TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8d00) " @ mrs sp, spsr") TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8d00) " @ mrs sp, spsr")
TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8f00) " @ mrs pc, spsr") TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8f00) " @ mrs pc, spsr")
TEST_UNSUPPORTED("mrs r0, spsr") TEST_UNSUPPORTED("mrs r0, spsr")
...@@ -821,14 +825,22 @@ CONDITION_INSTRUCTIONS(22, ...@@ -821,14 +825,22 @@ CONDITION_INSTRUCTIONS(22,
TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]!") \ TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]!") \
TEST_RPR("str"size".w r",0, VAL1,", [r",1, 0,", r",2, 4,"]") \ TEST_RPR("str"size".w r",0, VAL1,", [r",1, 0,", r",2, 4,"]") \
TEST_RPR("str"size" r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]") \ TEST_RPR("str"size" r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]") \
TEST_UNSUPPORTED("str"size" r0, [r13, r1]") \
TEST_R( "str"size".w r",7, VAL1,", [sp, #24]") \ TEST_R( "str"size".w r",7, VAL1,", [sp, #24]") \
TEST_RP( "str"size".w r",0, VAL2,", [r",0,0, "]") \ TEST_RP( "str"size".w r",0, VAL2,", [r",0,0, "]") \
TEST_RP( "str"size" r",6, VAL1,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \
TEST_UNSUPPORTED("str"size" r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \
TEST_RP( "str"size" r",4, VAL2,", [r",12, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \
TEST_UNSUPPORTED("str"size"t r0, [r1, #4]") TEST_UNSUPPORTED("str"size"t r0, [r1, #4]")
SINGLE_STORE("b") SINGLE_STORE("b")
SINGLE_STORE("h") SINGLE_STORE("h")
SINGLE_STORE("") SINGLE_STORE("")
TEST_UNSUPPORTED(__inst_thumb32(0xf801000d) " @ strb r0, [r1, r13]")
TEST_UNSUPPORTED(__inst_thumb32(0xf821000d) " @ strh r0, [r1, r13]")
TEST_UNSUPPORTED(__inst_thumb32(0xf841000d) " @ str r0, [r1, r13]")
TEST("str sp, [sp]") TEST("str sp, [sp]")
TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) " @ str r14, [pc]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) " @ str r14, [pc]")
TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) " @ str pc, [r14]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) " @ str pc, [r14]")
......
obj-$(CONFIG_UPROBES) += core.o actions-arm.o
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
#include <linux/uprobes.h> #include <linux/uprobes.h>
#include <linux/module.h> #include <linux/module.h>
#include "probes.h" #include "../decode.h"
#include "probes-arm.h" #include "../decode-arm.h"
#include "uprobes.h" #include "core.h"
static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs) static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs)
{ {
...@@ -195,8 +195,6 @@ uprobe_decode_ldmstm(probes_opcode_t insn, ...@@ -195,8 +195,6 @@ uprobe_decode_ldmstm(probes_opcode_t insn,
} }
const union decode_action uprobes_probes_actions[] = { const union decode_action uprobes_probes_actions[] = {
[PROBES_EMULATE_NONE] = {.handler = probes_simulate_nop},
[PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
[PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
[PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
[PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
......
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
#include <asm/opcodes.h> #include <asm/opcodes.h>
#include <asm/traps.h> #include <asm/traps.h>
#include "probes.h" #include "../decode.h"
#include "probes-arm.h" #include "../decode-arm.h"
#include "uprobes.h" #include "core.h"
#define UPROBE_TRAP_NR UINT_MAX #define UPROBE_TRAP_NR UINT_MAX
...@@ -88,7 +88,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, ...@@ -88,7 +88,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN); auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN);
ret = arm_probes_decode_insn(insn, &auprobe->asi, false, ret = arm_probes_decode_insn(insn, &auprobe->asi, false,
uprobes_probes_actions); uprobes_probes_actions, NULL);
switch (ret) { switch (ret) {
case INSN_REJECTED: case INSN_REJECTED:
return -EINVAL; return -EINVAL;
......
...@@ -39,6 +39,7 @@ config ARM64 ...@@ -39,6 +39,7 @@ config ARM64
select HARDIRQS_SW_RESEND select HARDIRQS_SW_RESEND
select HAVE_ALIGNED_STRUCT_PAGE if SLUB select HAVE_ALIGNED_STRUCT_PAGE if SLUB
select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_AUDITSYSCALL
select HAVE_ARCH_BITREVERSE
select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL
select HAVE_ARCH_KGDB select HAVE_ARCH_KGDB
select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_SECCOMP_FILTER
......
#ifndef __ASM_BITREV_H
#define __ASM_BITREV_H
static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x)
{
__asm__ ("rbit %w0, %w1" : "=r" (x) : "r" (x));
return x;
}
static __always_inline __attribute_const__ u16 __arch_bitrev16(u16 x)
{
return __arch_bitrev32((u32)x) >> 16;
}
static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x)
{
return __arch_bitrev32((u32)x) >> 24;
}
#endif
...@@ -322,7 +322,8 @@ void arch_remove_optimized_kprobe(struct optimized_kprobe *op) ...@@ -322,7 +322,8 @@ void arch_remove_optimized_kprobe(struct optimized_kprobe *op)
* Target instructions MUST be relocatable (checked inside) * Target instructions MUST be relocatable (checked inside)
* This is called when new aggr(opt)probe is allocated or reused. * This is called when new aggr(opt)probe is allocated or reused.
*/ */
int arch_prepare_optimized_kprobe(struct optimized_kprobe *op) int arch_prepare_optimized_kprobe(struct optimized_kprobe *op,
struct kprobe *__unused)
{ {
u8 *buf; u8 *buf;
int ret; int ret;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/limits.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -43,6 +44,10 @@ static int amba_match(struct device *dev, struct device_driver *drv) ...@@ -43,6 +44,10 @@ static int amba_match(struct device *dev, struct device_driver *drv)
struct amba_device *pcdev = to_amba_device(dev); struct amba_device *pcdev = to_amba_device(dev);
struct amba_driver *pcdrv = to_amba_driver(drv); struct amba_driver *pcdrv = to_amba_driver(drv);
/* When driver_override is set, only bind to the matching driver */
if (pcdev->driver_override)
return !strcmp(pcdev->driver_override, drv->name);
return amba_lookup(pcdrv->id_table, pcdev) != NULL; return amba_lookup(pcdrv->id_table, pcdev) != NULL;
} }
...@@ -59,6 +64,47 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) ...@@ -59,6 +64,47 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
return retval; return retval;
} }
static ssize_t driver_override_show(struct device *_dev,
struct device_attribute *attr, char *buf)
{
struct amba_device *dev = to_amba_device(_dev);
if (!dev->driver_override)
return 0;
return sprintf(buf, "%s\n", dev->driver_override);
}
static ssize_t driver_override_store(struct device *_dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct amba_device *dev = to_amba_device(_dev);
char *driver_override, *old = dev->driver_override, *cp;
if (count > PATH_MAX)
return -EINVAL;
driver_override = kstrndup(buf, count, GFP_KERNEL);
if (!driver_override)
return -ENOMEM;
cp = strchr(driver_override, '\n');
if (cp)
*cp = '\0';
if (strlen(driver_override)) {
dev->driver_override = driver_override;
} else {
kfree(driver_override);
dev->driver_override = NULL;
}
kfree(old);
return count;
}
#define amba_attr_func(name,fmt,arg...) \ #define amba_attr_func(name,fmt,arg...) \
static ssize_t name##_show(struct device *_dev, \ static ssize_t name##_show(struct device *_dev, \
struct device_attribute *attr, char *buf) \ struct device_attribute *attr, char *buf) \
...@@ -81,6 +127,7 @@ amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n", ...@@ -81,6 +127,7 @@ amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n",
static struct device_attribute amba_dev_attrs[] = { static struct device_attribute amba_dev_attrs[] = {
__ATTR_RO(id), __ATTR_RO(id),
__ATTR_RO(resource), __ATTR_RO(resource),
__ATTR_RW(driver_override),
__ATTR_NULL, __ATTR_NULL,
}; };
......
...@@ -229,4 +229,11 @@ config CLKSRC_MIPS_GIC ...@@ -229,4 +229,11 @@ config CLKSRC_MIPS_GIC
depends on MIPS_GIC depends on MIPS_GIC
select CLKSRC_OF select CLKSRC_OF
config CLKSRC_PXA
def_bool y if ARCH_PXA || ARCH_SA1100
select CLKSRC_OF if USE_OF
help
This enables OST0 support available on PXA and SA-11x0
platforms.
endmenu endmenu
...@@ -21,7 +21,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o ...@@ -21,7 +21,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o
obj-$(CONFIG_ARCH_MARCO) += timer-marco.o obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o
obj-$(CONFIG_ARCH_MXS) += mxs_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
obj-$(CONFIG_ARCH_PXA) += pxa_timer.o obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o
obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o
obj-$(CONFIG_ARCH_U300) += timer-u300.o obj-$(CONFIG_ARCH_U300) += timer-u300.o
obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/syscore_ops.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/irqs.h> #include <mach/irqs.h>
...@@ -50,7 +51,7 @@ static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int ...@@ -50,7 +51,7 @@ static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int
static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset) static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset)
{ {
return offset < 11 ? (IRQ_GPIO0 + offset) : (IRQ_GPIO11 - 11 + offset); return IRQ_GPIO0 + offset;
} }
static struct gpio_chip sa1100_gpio_chip = { static struct gpio_chip sa1100_gpio_chip = {
...@@ -64,7 +65,203 @@ static struct gpio_chip sa1100_gpio_chip = { ...@@ -64,7 +65,203 @@ static struct gpio_chip sa1100_gpio_chip = {
.ngpio = GPIO_MAX + 1, .ngpio = GPIO_MAX + 1,
}; };
/*
* SA1100 GPIO edge detection for IRQs:
* IRQs are generated on Falling-Edge, Rising-Edge, or both.
* Use this instead of directly setting GRER/GFER.
*/
static int GPIO_IRQ_rising_edge;
static int GPIO_IRQ_falling_edge;
static int GPIO_IRQ_mask;
static int sa1100_gpio_type(struct irq_data *d, unsigned int type)
{
unsigned int mask;
mask = BIT(d->hwirq);
if (type == IRQ_TYPE_PROBE) {
if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask)
return 0;
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
}
if (type & IRQ_TYPE_EDGE_RISING)
GPIO_IRQ_rising_edge |= mask;
else
GPIO_IRQ_rising_edge &= ~mask;
if (type & IRQ_TYPE_EDGE_FALLING)
GPIO_IRQ_falling_edge |= mask;
else
GPIO_IRQ_falling_edge &= ~mask;
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
return 0;
}
/*
* GPIO IRQs must be acknowledged.
*/
static void sa1100_gpio_ack(struct irq_data *d)
{
GEDR = BIT(d->hwirq);
}
static void sa1100_gpio_mask(struct irq_data *d)
{
unsigned int mask = BIT(d->hwirq);
GPIO_IRQ_mask &= ~mask;
GRER &= ~mask;
GFER &= ~mask;
}
static void sa1100_gpio_unmask(struct irq_data *d)
{
unsigned int mask = BIT(d->hwirq);
GPIO_IRQ_mask |= mask;
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
}
static int sa1100_gpio_wake(struct irq_data *d, unsigned int on)
{
if (on)
PWER |= BIT(d->hwirq);
else
PWER &= ~BIT(d->hwirq);
return 0;
}
/*
* This is for GPIO IRQs
*/
static struct irq_chip sa1100_gpio_irq_chip = {
.name = "GPIO",
.irq_ack = sa1100_gpio_ack,
.irq_mask = sa1100_gpio_mask,
.irq_unmask = sa1100_gpio_unmask,
.irq_set_type = sa1100_gpio_type,
.irq_set_wake = sa1100_gpio_wake,
};
static int sa1100_gpio_irqdomain_map(struct irq_domain *d,
unsigned int irq, irq_hw_number_t hwirq)
{
irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip,
handle_edge_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
return 0;
}
static struct irq_domain_ops sa1100_gpio_irqdomain_ops = {
.map = sa1100_gpio_irqdomain_map,
.xlate = irq_domain_xlate_onetwocell,
};
static struct irq_domain *sa1100_gpio_irqdomain;
/*
* IRQ 0-11 (GPIO) handler. We enter here with the
* irq_controller_lock held, and IRQs disabled. Decode the IRQ
* and call the handler.
*/
static void
sa1100_gpio_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned int mask;
mask = GEDR;
do {
/*
* clear down all currently active IRQ sources.
* We will be processing them all.
*/
GEDR = mask;
irq = IRQ_GPIO0;
do {
if (mask & 1)
generic_handle_irq(irq);
mask >>= 1;
irq++;
} while (mask);
mask = GEDR;
} while (mask);
}
static int sa1100_gpio_suspend(void)
{
/*
* Set the appropriate edges for wakeup.
*/
GRER = PWER & GPIO_IRQ_rising_edge;
GFER = PWER & GPIO_IRQ_falling_edge;
/*
* Clear any pending GPIO interrupts.
*/
GEDR = GEDR;
return 0;
}
static void sa1100_gpio_resume(void)
{
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
}
static struct syscore_ops sa1100_gpio_syscore_ops = {
.suspend = sa1100_gpio_suspend,
.resume = sa1100_gpio_resume,
};
static int __init sa1100_gpio_init_devicefs(void)
{
register_syscore_ops(&sa1100_gpio_syscore_ops);
return 0;
}
device_initcall(sa1100_gpio_init_devicefs);
void __init sa1100_init_gpio(void) void __init sa1100_init_gpio(void)
{ {
/* clear all GPIO edge detects */
GFER = 0;
GRER = 0;
GEDR = -1;
gpiochip_add(&sa1100_gpio_chip); gpiochip_add(&sa1100_gpio_chip);
sa1100_gpio_irqdomain = irq_domain_add_simple(NULL,
28, IRQ_GPIO0,
&sa1100_gpio_irqdomain_ops, NULL);
/*
* Install handlers for GPIO 0-10 edge detect interrupts
*/
irq_set_chained_handler(IRQ_GPIO0_SC, sa1100_gpio_handler);
irq_set_chained_handler(IRQ_GPIO1_SC, sa1100_gpio_handler);
irq_set_chained_handler(IRQ_GPIO2_SC, sa1100_gpio_handler);
irq_set_chained_handler(IRQ_GPIO3_SC, sa1100_gpio_handler);
irq_set_chained_handler(IRQ_GPIO4_SC, sa1100_gpio_handler);
irq_set_chained_handler(IRQ_GPIO5_SC, sa1100_gpio_handler);
irq_set_chained_handler(IRQ_GPIO6_SC, sa1100_gpio_handler);
irq_set_chained_handler(IRQ_GPIO7_SC, sa1100_gpio_handler);
irq_set_chained_handler(IRQ_GPIO8_SC, sa1100_gpio_handler);
irq_set_chained_handler(IRQ_GPIO9_SC, sa1100_gpio_handler);
irq_set_chained_handler(IRQ_GPIO10_SC, sa1100_gpio_handler);
/*
* Install handler for GPIO 11-27 edge detect interrupts
*/
irq_set_chained_handler(IRQ_GPIO11_27, sa1100_gpio_handler);
} }
...@@ -33,6 +33,7 @@ struct amba_device { ...@@ -33,6 +33,7 @@ struct amba_device {
struct clk *pclk; struct clk *pclk;
unsigned int periphid; unsigned int periphid;
unsigned int irq[AMBA_NR_IRQS]; unsigned int irq[AMBA_NR_IRQS];
char *driver_override;
}; };
struct amba_driver { struct amba_driver {
...@@ -92,11 +93,15 @@ struct amba_device *amba_find_device(const char *, struct device *, unsigned int ...@@ -92,11 +93,15 @@ struct amba_device *amba_find_device(const char *, struct device *, unsigned int
int amba_request_regions(struct amba_device *, const char *); int amba_request_regions(struct amba_device *, const char *);
void amba_release_regions(struct amba_device *); void amba_release_regions(struct amba_device *);
#define amba_pclk_enable(d) \ static inline int amba_pclk_enable(struct amba_device *dev)
(IS_ERR((d)->pclk) ? 0 : clk_enable((d)->pclk)) {
return clk_enable(dev->pclk);
}
#define amba_pclk_disable(d) \ static inline void amba_pclk_disable(struct amba_device *dev)
do { if (!IS_ERR((d)->pclk)) clk_disable((d)->pclk); } while (0) {
clk_disable(dev->pclk);
}
static inline int amba_pclk_prepare(struct amba_device *dev) static inline int amba_pclk_prepare(struct amba_device *dev)
{ {
......
...@@ -3,14 +3,83 @@ ...@@ -3,14 +3,83 @@
#include <linux/types.h> #include <linux/types.h>
extern u8 const byte_rev_table[256]; #ifdef CONFIG_HAVE_ARCH_BITREVERSE
#include <asm/bitrev.h>
#define __bitrev32 __arch_bitrev32
#define __bitrev16 __arch_bitrev16
#define __bitrev8 __arch_bitrev8
static inline u8 bitrev8(u8 byte) #else
extern u8 const byte_rev_table[256];
static inline u8 __bitrev8(u8 byte)
{ {
return byte_rev_table[byte]; return byte_rev_table[byte];
} }
extern u16 bitrev16(u16 in); static inline u16 __bitrev16(u16 x)
extern u32 bitrev32(u32 in); {
return (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8);
}
static inline u32 __bitrev32(u32 x)
{
return (__bitrev16(x & 0xffff) << 16) | __bitrev16(x >> 16);
}
#endif /* CONFIG_HAVE_ARCH_BITREVERSE */
#define __constant_bitrev32(x) \
({ \
u32 __x = x; \
__x = (__x >> 16) | (__x << 16); \
__x = ((__x & (u32)0xFF00FF00UL) >> 8) | ((__x & (u32)0x00FF00FFUL) << 8); \
__x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4); \
__x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2); \
__x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1); \
__x; \
})
#define __constant_bitrev16(x) \
({ \
u16 __x = x; \
__x = (__x >> 8) | (__x << 8); \
__x = ((__x & (u16)0xF0F0U) >> 4) | ((__x & (u16)0x0F0FU) << 4); \
__x = ((__x & (u16)0xCCCCU) >> 2) | ((__x & (u16)0x3333U) << 2); \
__x = ((__x & (u16)0xAAAAU) >> 1) | ((__x & (u16)0x5555U) << 1); \
__x; \
})
#define __constant_bitrev8(x) \
({ \
u8 __x = x; \
__x = (__x >> 4) | (__x << 4); \
__x = ((__x & (u8)0xCCU) >> 2) | ((__x & (u8)0x33U) << 2); \
__x = ((__x & (u8)0xAAU) >> 1) | ((__x & (u8)0x55U) << 1); \
__x; \
})
#define bitrev32(x) \
({ \
u32 __x = x; \
__builtin_constant_p(__x) ? \
__constant_bitrev32(__x) : \
__bitrev32(__x); \
})
#define bitrev16(x) \
({ \
u16 __x = x; \
__builtin_constant_p(__x) ? \
__constant_bitrev16(__x) : \
__bitrev16(__x); \
})
#define bitrev8(x) \
({ \
u8 __x = x; \
__builtin_constant_p(__x) ? \
__constant_bitrev8(__x) : \
__bitrev8(__x) ; \
})
#endif /* _LINUX_BITREV_H */ #endif /* _LINUX_BITREV_H */
...@@ -308,7 +308,8 @@ struct optimized_kprobe { ...@@ -308,7 +308,8 @@ struct optimized_kprobe {
/* Architecture dependent functions for direct jump optimization */ /* Architecture dependent functions for direct jump optimization */
extern int arch_prepared_optinsn(struct arch_optimized_insn *optinsn); extern int arch_prepared_optinsn(struct arch_optimized_insn *optinsn);
extern int arch_check_optimized_kprobe(struct optimized_kprobe *op); extern int arch_check_optimized_kprobe(struct optimized_kprobe *op);
extern int arch_prepare_optimized_kprobe(struct optimized_kprobe *op); extern int arch_prepare_optimized_kprobe(struct optimized_kprobe *op,
struct kprobe *orig);
extern void arch_remove_optimized_kprobe(struct optimized_kprobe *op); extern void arch_remove_optimized_kprobe(struct optimized_kprobe *op);
extern void arch_optimize_kprobes(struct list_head *oplist); extern void arch_optimize_kprobes(struct list_head *oplist);
extern void arch_unoptimize_kprobes(struct list_head *oplist, extern void arch_unoptimize_kprobes(struct list_head *oplist,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment