diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-12 11:51:56 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-12 11:51:56 -0500 |
commit | 42cf0f203e877cc7e502883d43b3f72149033d86 (patch) | |
tree | 3658297d62f28d7bfaa148099b08001aa9904229 /arch | |
parent | a2f0bb03f7c499e3db72c70a62b1aa5c55d6a82b (diff) | |
parent | df9ab9771c64f5229843bfe2a20fe0ee6ac59fc1 (diff) |
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
...
Diffstat (limited to 'arch')
79 files changed, 1807 insertions, 1450 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index dcb2e0c55be4..0850fc0f9658 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -29,6 +29,7 @@ config ARM | |||
29 | select HANDLE_DOMAIN_IRQ | 29 | select HANDLE_DOMAIN_IRQ |
30 | select HARDIRQS_SW_RESEND | 30 | select HARDIRQS_SW_RESEND |
31 | select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT) | 31 | select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT) |
32 | select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 | ||
32 | select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL | 33 | select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL |
33 | select HAVE_ARCH_KGDB | 34 | select HAVE_ARCH_KGDB |
34 | select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT) | 35 | select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT) |
@@ -60,6 +61,7 @@ config ARM | |||
60 | select HAVE_MEMBLOCK | 61 | select HAVE_MEMBLOCK |
61 | select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND | 62 | select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND |
62 | select HAVE_OPROFILE if (HAVE_PERF_EVENTS) | 63 | select HAVE_OPROFILE if (HAVE_PERF_EVENTS) |
64 | select HAVE_OPTPROBES if !THUMB2_KERNEL | ||
63 | select HAVE_PERF_EVENTS | 65 | select HAVE_PERF_EVENTS |
64 | select HAVE_PERF_REGS | 66 | select HAVE_PERF_REGS |
65 | select HAVE_PERF_USER_STACK_DUMP | 67 | select HAVE_PERF_USER_STACK_DUMP |
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 5ddd4906f7a7..a324ecdfeb21 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug | |||
@@ -397,6 +397,13 @@ choice | |||
397 | Say Y here if you want the debug print routines to direct | 397 | Say Y here if you want the debug print routines to direct |
398 | their output to UART1 serial port on KEYSTONE2 devices. | 398 | their output to UART1 serial port on KEYSTONE2 devices. |
399 | 399 | ||
400 | config DEBUG_KS8695_UART | ||
401 | bool "KS8695 Debug UART" | ||
402 | depends on ARCH_KS8695 | ||
403 | help | ||
404 | Say Y here if you want kernel low-level debugging support | ||
405 | on KS8695. | ||
406 | |||
400 | config DEBUG_MESON_UARTAO | 407 | config DEBUG_MESON_UARTAO |
401 | bool "Kernel low-level debugging via Meson6 UARTAO" | 408 | bool "Kernel low-level debugging via Meson6 UARTAO" |
402 | depends on ARCH_MESON | 409 | depends on ARCH_MESON |
@@ -496,6 +503,13 @@ choice | |||
496 | Say Y here if you want kernel low-level debugging support | 503 | Say Y here if you want kernel low-level debugging support |
497 | on Vybrid based platforms. | 504 | on Vybrid based platforms. |
498 | 505 | ||
506 | config DEBUG_NETX_UART | ||
507 | bool "Kernel low-level debugging messages via NetX UART" | ||
508 | depends on ARCH_NETX | ||
509 | help | ||
510 | Say Y here if you want kernel low-level debugging support | ||
511 | on Hilscher NetX based platforms. | ||
512 | |||
499 | config DEBUG_NOMADIK_UART | 513 | config DEBUG_NOMADIK_UART |
500 | bool "Kernel low-level debugging messages via NOMADIK UART" | 514 | bool "Kernel low-level debugging messages via NOMADIK UART" |
501 | depends on ARCH_NOMADIK | 515 | depends on ARCH_NOMADIK |
@@ -520,6 +534,30 @@ choice | |||
520 | Say Y here if you want kernel low-level debugging support | 534 | Say Y here if you want kernel low-level debugging support |
521 | on TI-NSPIRE CX models. | 535 | on TI-NSPIRE CX models. |
522 | 536 | ||
537 | config DEBUG_OMAP1UART1 | ||
538 | bool "Kernel low-level debugging via OMAP1 UART1" | ||
539 | depends on ARCH_OMAP1 | ||
540 | select DEBUG_UART_8250 | ||
541 | help | ||
542 | Say Y here if you want kernel low-level debugging support | ||
543 | on OMAP1 based platforms (except OMAP730) on the UART1. | ||
544 | |||
545 | config DEBUG_OMAP1UART2 | ||
546 | bool "Kernel low-level debugging via OMAP1 UART2" | ||
547 | depends on ARCH_OMAP1 | ||
548 | select DEBUG_UART_8250 | ||
549 | help | ||
550 | Say Y here if you want kernel low-level debugging support | ||
551 | on OMAP1 based platforms (except OMAP730) on the UART2. | ||
552 | |||
553 | config DEBUG_OMAP1UART3 | ||
554 | bool "Kernel low-level debugging via OMAP1 UART3" | ||
555 | depends on ARCH_OMAP1 | ||
556 | select DEBUG_UART_8250 | ||
557 | help | ||
558 | Say Y here if you want kernel low-level debugging support | ||
559 | on OMAP1 based platforms (except OMAP730) on the UART3. | ||
560 | |||
523 | config DEBUG_OMAP2UART1 | 561 | config DEBUG_OMAP2UART1 |
524 | bool "OMAP2/3/4 UART1 (omap2/3 sdp boards and some omap3 boards)" | 562 | bool "OMAP2/3/4 UART1 (omap2/3 sdp boards and some omap3 boards)" |
525 | depends on ARCH_OMAP2PLUS | 563 | depends on ARCH_OMAP2PLUS |
@@ -562,6 +600,30 @@ choice | |||
562 | depends on ARCH_OMAP2PLUS | 600 | depends on ARCH_OMAP2PLUS |
563 | select DEBUG_OMAP2PLUS_UART | 601 | select DEBUG_OMAP2PLUS_UART |
564 | 602 | ||
603 | config DEBUG_OMAP7XXUART1 | ||
604 | bool "Kernel low-level debugging via OMAP730 UART1" | ||
605 | depends on ARCH_OMAP730 | ||
606 | select DEBUG_UART_8250 | ||
607 | help | ||
608 | Say Y here if you want kernel low-level debugging support | ||
609 | on OMAP730 based platforms on the UART1. | ||
610 | |||
611 | config DEBUG_OMAP7XXUART2 | ||
612 | bool "Kernel low-level debugging via OMAP730 UART2" | ||
613 | depends on ARCH_OMAP730 | ||
614 | select DEBUG_UART_8250 | ||
615 | help | ||
616 | Say Y here if you want kernel low-level debugging support | ||
617 | on OMAP730 based platforms on the UART2. | ||
618 | |||
619 | config DEBUG_OMAP7XXUART3 | ||
620 | bool "Kernel low-level debugging via OMAP730 UART3" | ||
621 | depends on ARCH_OMAP730 | ||
622 | select DEBUG_UART_8250 | ||
623 | help | ||
624 | Say Y here if you want kernel low-level debugging support | ||
625 | on OMAP730 based platforms on the UART3. | ||
626 | |||
565 | config DEBUG_TI81XXUART1 | 627 | config DEBUG_TI81XXUART1 |
566 | bool "Kernel low-level debugging messages via TI81XX UART1 (ti8148evm)" | 628 | bool "Kernel low-level debugging messages via TI81XX UART1 (ti8148evm)" |
567 | depends on ARCH_OMAP2PLUS | 629 | depends on ARCH_OMAP2PLUS |
@@ -1031,15 +1093,6 @@ choice | |||
1031 | This option selects UART0 on VIA/Wondermedia System-on-a-chip | 1093 | This option selects UART0 on VIA/Wondermedia System-on-a-chip |
1032 | devices, including VT8500, WM8505, WM8650 and WM8850. | 1094 | devices, including VT8500, WM8505, WM8650 and WM8850. |
1033 | 1095 | ||
1034 | config DEBUG_LL_UART_NONE | ||
1035 | bool "No low-level debugging UART" | ||
1036 | depends on !ARCH_MULTIPLATFORM | ||
1037 | help | ||
1038 | Say Y here if your platform doesn't provide a UART option | ||
1039 | above. This relies on your platform choosing the right UART | ||
1040 | definition internally in order for low-level debugging to | ||
1041 | work. | ||
1042 | |||
1043 | config DEBUG_ICEDCC | 1096 | config DEBUG_ICEDCC |
1044 | bool "Kernel low-level debugging via EmbeddedICE DCC channel" | 1097 | bool "Kernel low-level debugging via EmbeddedICE DCC channel" |
1045 | help | 1098 | help |
@@ -1183,7 +1236,9 @@ config DEBUG_LL_INCLUDE | |||
1183 | DEBUG_IMX6Q_UART || \ | 1236 | DEBUG_IMX6Q_UART || \ |
1184 | DEBUG_IMX6SL_UART || \ | 1237 | DEBUG_IMX6SL_UART || \ |
1185 | DEBUG_IMX6SX_UART | 1238 | DEBUG_IMX6SX_UART |
1239 | default "debug/ks8695.S" if DEBUG_KS8695_UART | ||
1186 | default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM | 1240 | default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM |
1241 | default "debug/netx.S" if DEBUG_NETX_UART | ||
1187 | default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART | 1242 | default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART |
1188 | default "debug/renesas-scif.S" if DEBUG_R7S72100_SCIF2 | 1243 | default "debug/renesas-scif.S" if DEBUG_R7S72100_SCIF2 |
1189 | default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF0 | 1244 | default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF0 |
@@ -1208,12 +1263,7 @@ config DEBUG_LL_INCLUDE | |||
1208 | 1263 | ||
1209 | # Compatibility options for PL01x | 1264 | # Compatibility options for PL01x |
1210 | config DEBUG_UART_PL01X | 1265 | config DEBUG_UART_PL01X |
1211 | def_bool ARCH_EP93XX || \ | 1266 | bool |
1212 | ARCH_INTEGRATOR || \ | ||
1213 | ARCH_SPEAR3XX || \ | ||
1214 | ARCH_SPEAR6XX || \ | ||
1215 | ARCH_SPEAR13XX || \ | ||
1216 | ARCH_VERSATILE | ||
1217 | 1267 | ||
1218 | # Compatibility options for 8250 | 1268 | # Compatibility options for 8250 |
1219 | config DEBUG_UART_8250 | 1269 | config DEBUG_UART_8250 |
@@ -1229,6 +1279,7 @@ config DEBUG_UART_BCM63XX | |||
1229 | 1279 | ||
1230 | config DEBUG_UART_PHYS | 1280 | config DEBUG_UART_PHYS |
1231 | hex "Physical base address of debug UART" | 1281 | hex "Physical base address of debug UART" |
1282 | default 0x00100a00 if DEBUG_NETX_UART | ||
1232 | default 0x01c20000 if DEBUG_DAVINCI_DMx_UART0 | 1283 | default 0x01c20000 if DEBUG_DAVINCI_DMx_UART0 |
1233 | default 0x01c28000 if DEBUG_SUNXI_UART0 | 1284 | default 0x01c28000 if DEBUG_SUNXI_UART0 |
1234 | default 0x01c28400 if DEBUG_SUNXI_UART1 | 1285 | default 0x01c28400 if DEBUG_SUNXI_UART1 |
@@ -1269,7 +1320,6 @@ config DEBUG_UART_PHYS | |||
1269 | DEBUG_S3C2410_UART2) | 1320 | DEBUG_S3C2410_UART2) |
1270 | default 0x78000000 if DEBUG_CNS3XXX | 1321 | default 0x78000000 if DEBUG_CNS3XXX |
1271 | default 0x7c0003f8 if FOOTBRIDGE | 1322 | default 0x7c0003f8 if FOOTBRIDGE |
1272 | default 0x78000000 if DEBUG_CNS3XXX | ||
1273 | default 0x80010000 if DEBUG_ASM9260_UART | 1323 | default 0x80010000 if DEBUG_ASM9260_UART |
1274 | default 0x80070000 if DEBUG_IMX23_UART | 1324 | default 0x80070000 if DEBUG_IMX23_UART |
1275 | default 0x80074000 if DEBUG_IMX28_UART | 1325 | default 0x80074000 if DEBUG_IMX28_UART |
@@ -1310,12 +1360,17 @@ config DEBUG_UART_PHYS | |||
1310 | default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0 | 1360 | default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0 |
1311 | default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2 | 1361 | default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2 |
1312 | default 0xfff36000 if DEBUG_HIGHBANK_UART | 1362 | default 0xfff36000 if DEBUG_HIGHBANK_UART |
1363 | default 0xfffb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1 | ||
1364 | default 0xfffb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2 | ||
1365 | default 0xfffb9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3 | ||
1313 | default 0xfffe8600 if DEBUG_UART_BCM63XX | 1366 | default 0xfffe8600 if DEBUG_UART_BCM63XX |
1314 | default 0xfffff700 if ARCH_IOP33X | 1367 | default 0xfffff700 if ARCH_IOP33X |
1315 | depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ | 1368 | depends on ARCH_EP93XX || \ |
1369 | DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ | ||
1316 | DEBUG_LL_UART_EFM32 || \ | 1370 | DEBUG_LL_UART_EFM32 || \ |
1317 | DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ | 1371 | DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ |
1318 | DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \ | 1372 | DEBUG_MSM_UART || DEBUG_NETX_UART || \ |
1373 | DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \ | ||
1319 | DEBUG_RCAR_GEN1_SCIF0 || DEBUG_RCAR_GEN1_SCIF2 || \ | 1374 | DEBUG_RCAR_GEN1_SCIF0 || DEBUG_RCAR_GEN1_SCIF2 || \ |
1320 | DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \ | 1375 | DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \ |
1321 | DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \ | 1376 | DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \ |
@@ -1324,6 +1379,7 @@ config DEBUG_UART_PHYS | |||
1324 | 1379 | ||
1325 | config DEBUG_UART_VIRT | 1380 | config DEBUG_UART_VIRT |
1326 | hex "Virtual base address of debug UART" | 1381 | hex "Virtual base address of debug UART" |
1382 | default 0xe0000a00 if DEBUG_NETX_UART | ||
1327 | default 0xe0010fe0 if ARCH_RPC | 1383 | default 0xe0010fe0 if ARCH_RPC |
1328 | default 0xe1000000 if DEBUG_MSM_UART | 1384 | default 0xe1000000 if DEBUG_MSM_UART |
1329 | default 0xf0000be0 if ARCH_EBSA110 | 1385 | default 0xf0000be0 if ARCH_EBSA110 |
@@ -1392,18 +1448,23 @@ config DEBUG_UART_VIRT | |||
1392 | default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN | 1448 | default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN |
1393 | default 0xfef00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN | 1449 | default 0xfef00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN |
1394 | default 0xfef36000 if DEBUG_HIGHBANK_UART | 1450 | default 0xfef36000 if DEBUG_HIGHBANK_UART |
1451 | default 0xfefb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1 | ||
1452 | default 0xfefb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2 | ||
1453 | default 0xfefb9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3 | ||
1395 | default 0xfefff700 if ARCH_IOP33X | 1454 | default 0xfefff700 if ARCH_IOP33X |
1396 | default 0xff003000 if DEBUG_U300_UART | 1455 | default 0xff003000 if DEBUG_U300_UART |
1397 | default DEBUG_UART_PHYS if !MMU | 1456 | default DEBUG_UART_PHYS if !MMU |
1398 | depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ | 1457 | depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ |
1399 | DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ | 1458 | DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ |
1400 | DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ | 1459 | DEBUG_MSM_UART || DEBUG_NETX_UART || \ |
1460 | DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ | ||
1401 | DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART | 1461 | DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART |
1402 | 1462 | ||
1403 | config DEBUG_UART_8250_SHIFT | 1463 | config DEBUG_UART_8250_SHIFT |
1404 | int "Register offset shift for the 8250 debug UART" | 1464 | int "Register offset shift for the 8250 debug UART" |
1405 | depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250 | 1465 | depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250 |
1406 | default 0 if FOOTBRIDGE || ARCH_IOP32X || DEBUG_BCM_5301X | 1466 | default 0 if FOOTBRIDGE || ARCH_IOP32X || DEBUG_BCM_5301X || \ |
1467 | DEBUG_OMAP7XXUART1 || DEBUG_OMAP7XXUART2 || DEBUG_OMAP7XXUART3 | ||
1407 | default 2 | 1468 | default 2 |
1408 | 1469 | ||
1409 | config DEBUG_UART_8250_WORD | 1470 | config DEBUG_UART_8250_WORD |
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index c1785eec2cf7..7f99cd652203 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile | |||
@@ -266,6 +266,7 @@ core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/ | |||
266 | 266 | ||
267 | # If we have a machine-specific directory, then include it in the build. | 267 | # If we have a machine-specific directory, then include it in the build. |
268 | core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ | 268 | core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ |
269 | core-y += arch/arm/probes/ | ||
269 | core-y += arch/arm/net/ | 270 | core-y += arch/arm/net/ |
270 | core-y += arch/arm/crypto/ | 271 | core-y += arch/arm/crypto/ |
271 | core-y += arch/arm/firmware/ | 272 | core-y += arch/arm/firmware/ |
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 132c70e2d2f1..c41a793b519c 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S | |||
@@ -178,7 +178,7 @@ not_angel: | |||
178 | 178 | ||
179 | /* | 179 | /* |
180 | * Set up a page table only if it won't overwrite ourself. | 180 | * Set up a page table only if it won't overwrite ourself. |
181 | * That means r4 < pc && r4 - 16k page directory > &_end. | 181 | * That means r4 < pc || r4 - 16k page directory > &_end. |
182 | * Given that r4 > &_end is most unfrequent, we add a rough | 182 | * Given that r4 > &_end is most unfrequent, we add a rough |
183 | * additional 1MB of room for a possible appended DTB. | 183 | * additional 1MB of room for a possible appended DTB. |
184 | */ | 184 | */ |
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index bcc9e63c8070..8e45ea44317e 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi | |||
@@ -81,6 +81,15 @@ | |||
81 | reg = <0x10023CA0 0x20>; | 81 | reg = <0x10023CA0 0x20>; |
82 | }; | 82 | }; |
83 | 83 | ||
84 | l2c: l2-cache-controller@10502000 { | ||
85 | compatible = "arm,pl310-cache"; | ||
86 | reg = <0x10502000 0x1000>; | ||
87 | cache-unified; | ||
88 | cache-level = <2>; | ||
89 | arm,tag-latency = <2 2 1>; | ||
90 | arm,data-latency = <2 2 1>; | ||
91 | }; | ||
92 | |||
84 | gic: interrupt-controller@10490000 { | 93 | gic: interrupt-controller@10490000 { |
85 | cpu-offset = <0x8000>; | 94 | cpu-offset = <0x8000>; |
86 | }; | 95 | }; |
diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi index 93b70402e943..8bc97c415c9a 100644 --- a/arch/arm/boot/dts/exynos4x12.dtsi +++ b/arch/arm/boot/dts/exynos4x12.dtsi | |||
@@ -54,6 +54,20 @@ | |||
54 | reg = <0x10023CA0 0x20>; | 54 | reg = <0x10023CA0 0x20>; |
55 | }; | 55 | }; |
56 | 56 | ||
57 | l2c: l2-cache-controller@10502000 { | ||
58 | compatible = "arm,pl310-cache"; | ||
59 | reg = <0x10502000 0x1000>; | ||
60 | cache-unified; | ||
61 | cache-level = <2>; | ||
62 | arm,tag-latency = <2 2 1>; | ||
63 | arm,data-latency = <3 2 1>; | ||
64 | arm,double-linefill = <1>; | ||
65 | arm,double-linefill-incr = <0>; | ||
66 | arm,double-linefill-wrap = <1>; | ||
67 | arm,prefetch-drop = <1>; | ||
68 | arm,prefetch-offset = <7>; | ||
69 | }; | ||
70 | |||
57 | clock: clock-controller@10030000 { | 71 | clock: clock-controller@10030000 { |
58 | compatible = "samsung,exynos4412-clock"; | 72 | compatible = "samsung,exynos4412-clock"; |
59 | reg = <0x10030000 0x20000>; | 73 | reg = <0x10030000 0x20000>; |
diff --git a/arch/arm/configs/iop32x_defconfig b/arch/arm/configs/iop32x_defconfig index 4f2ec3ac138e..c3058da631da 100644 --- a/arch/arm/configs/iop32x_defconfig +++ b/arch/arm/configs/iop32x_defconfig | |||
@@ -106,6 +106,7 @@ CONFIG_MAGIC_SYSRQ=y | |||
106 | CONFIG_DEBUG_KERNEL=y | 106 | CONFIG_DEBUG_KERNEL=y |
107 | CONFIG_DEBUG_USER=y | 107 | CONFIG_DEBUG_USER=y |
108 | CONFIG_DEBUG_LL=y | 108 | CONFIG_DEBUG_LL=y |
109 | CONFIG_DEBUG_LL_UART_8250=y | ||
109 | CONFIG_KEYS=y | 110 | CONFIG_KEYS=y |
110 | CONFIG_KEYS_DEBUG_PROC_KEYS=y | 111 | CONFIG_KEYS_DEBUG_PROC_KEYS=y |
111 | CONFIG_CRYPTO_NULL=y | 112 | CONFIG_CRYPTO_NULL=y |
diff --git a/arch/arm/configs/iop33x_defconfig b/arch/arm/configs/iop33x_defconfig index aa36128abca2..713faeee8cf4 100644 --- a/arch/arm/configs/iop33x_defconfig +++ b/arch/arm/configs/iop33x_defconfig | |||
@@ -87,5 +87,6 @@ CONFIG_DEBUG_KERNEL=y | |||
87 | # CONFIG_RCU_CPU_STALL_DETECTOR is not set | 87 | # CONFIG_RCU_CPU_STALL_DETECTOR is not set |
88 | CONFIG_DEBUG_USER=y | 88 | CONFIG_DEBUG_USER=y |
89 | CONFIG_DEBUG_LL=y | 89 | CONFIG_DEBUG_LL=y |
90 | CONFIG_DEBUG_LL_UART_8250=y | ||
90 | # CONFIG_CRYPTO_ANSI_CPRNG is not set | 91 | # CONFIG_CRYPTO_ANSI_CPRNG is not set |
91 | # CONFIG_CRC32 is not set | 92 | # CONFIG_CRC32 is not set |
diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index 1af665e847d1..24636cfdf6df 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig | |||
@@ -202,3 +202,4 @@ CONFIG_MAGIC_SYSRQ=y | |||
202 | CONFIG_DEBUG_KERNEL=y | 202 | CONFIG_DEBUG_KERNEL=y |
203 | CONFIG_DEBUG_ERRORS=y | 203 | CONFIG_DEBUG_ERRORS=y |
204 | CONFIG_DEBUG_LL=y | 204 | CONFIG_DEBUG_LL=y |
205 | CONFIG_DEBUG_LL_UART_8250=y | ||
diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig index 9f56ca3985ae..c100b7df5441 100644 --- a/arch/arm/configs/lpc32xx_defconfig +++ b/arch/arm/configs/lpc32xx_defconfig | |||
@@ -204,6 +204,7 @@ CONFIG_DEBUG_INFO=y | |||
204 | # CONFIG_FTRACE is not set | 204 | # CONFIG_FTRACE is not set |
205 | # CONFIG_ARM_UNWIND is not set | 205 | # CONFIG_ARM_UNWIND is not set |
206 | CONFIG_DEBUG_LL=y | 206 | CONFIG_DEBUG_LL=y |
207 | CONFIG_DEBUG_LL_UART_8250=y | ||
207 | CONFIG_EARLY_PRINTK=y | 208 | CONFIG_EARLY_PRINTK=y |
208 | CONFIG_CRYPTO_ANSI_CPRNG=y | 209 | CONFIG_CRYPTO_ANSI_CPRNG=y |
209 | # CONFIG_CRYPTO_HW is not set | 210 | # CONFIG_CRYPTO_HW is not set |
diff --git a/arch/arm/configs/mv78xx0_defconfig b/arch/arm/configs/mv78xx0_defconfig index 0dae1c1f007a..85d10d2e3d66 100644 --- a/arch/arm/configs/mv78xx0_defconfig +++ b/arch/arm/configs/mv78xx0_defconfig | |||
@@ -132,6 +132,7 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y | |||
132 | CONFIG_DEBUG_USER=y | 132 | CONFIG_DEBUG_USER=y |
133 | CONFIG_DEBUG_ERRORS=y | 133 | CONFIG_DEBUG_ERRORS=y |
134 | CONFIG_DEBUG_LL=y | 134 | CONFIG_DEBUG_LL=y |
135 | CONFIG_DEBUG_LL_UART_8250=y | ||
135 | CONFIG_CRYPTO_CBC=m | 136 | CONFIG_CRYPTO_CBC=m |
136 | CONFIG_CRYPTO_ECB=m | 137 | CONFIG_CRYPTO_ECB=m |
137 | CONFIG_CRYPTO_PCBC=m | 138 | CONFIG_CRYPTO_PCBC=m |
diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig index 952430d9e2d9..855143fac6bd 100644 --- a/arch/arm/configs/orion5x_defconfig +++ b/arch/arm/configs/orion5x_defconfig | |||
@@ -156,6 +156,7 @@ CONFIG_LATENCYTOP=y | |||
156 | # CONFIG_FTRACE is not set | 156 | # CONFIG_FTRACE is not set |
157 | CONFIG_DEBUG_USER=y | 157 | CONFIG_DEBUG_USER=y |
158 | CONFIG_DEBUG_LL=y | 158 | CONFIG_DEBUG_LL=y |
159 | CONFIG_DEBUG_LL_UART_8250=y | ||
159 | CONFIG_CRYPTO_CBC=m | 160 | CONFIG_CRYPTO_CBC=m |
160 | CONFIG_CRYPTO_ECB=m | 161 | CONFIG_CRYPTO_ECB=m |
161 | CONFIG_CRYPTO_PCBC=m | 162 | CONFIG_CRYPTO_PCBC=m |
diff --git a/arch/arm/configs/rpc_defconfig b/arch/arm/configs/rpc_defconfig index 00515ef9782d..89631795a915 100644 --- a/arch/arm/configs/rpc_defconfig +++ b/arch/arm/configs/rpc_defconfig | |||
@@ -131,3 +131,4 @@ CONFIG_DEBUG_KERNEL=y | |||
131 | CONFIG_DEBUG_USER=y | 131 | CONFIG_DEBUG_USER=y |
132 | CONFIG_DEBUG_ERRORS=y | 132 | CONFIG_DEBUG_ERRORS=y |
133 | CONFIG_DEBUG_LL=y | 133 | CONFIG_DEBUG_LL=y |
134 | CONFIG_DEBUG_LL_UART_8250=y | ||
diff --git a/arch/arm/include/asm/bitrev.h b/arch/arm/include/asm/bitrev.h new file mode 100644 index 000000000000..ec291c350ea3 --- /dev/null +++ b/arch/arm/include/asm/bitrev.h | |||
@@ -0,0 +1,20 @@ | |||
1 | #ifndef __ASM_BITREV_H | ||
2 | #define __ASM_BITREV_H | ||
3 | |||
4 | static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x) | ||
5 | { | ||
6 | __asm__ ("rbit %0, %1" : "=r" (x) : "r" (x)); | ||
7 | return x; | ||
8 | } | ||
9 | |||
10 | static __always_inline __attribute_const__ u16 __arch_bitrev16(u16 x) | ||
11 | { | ||
12 | return __arch_bitrev32((u32)x) >> 16; | ||
13 | } | ||
14 | |||
15 | static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x) | ||
16 | { | ||
17 | return __arch_bitrev32((u32)x) >> 24; | ||
18 | } | ||
19 | |||
20 | #endif | ||
diff --git a/arch/arm/include/asm/compiler.h b/arch/arm/include/asm/compiler.h index 8155db2f7fa1..29fe85e59439 100644 --- a/arch/arm/include/asm/compiler.h +++ b/arch/arm/include/asm/compiler.h | |||
@@ -8,8 +8,21 @@ | |||
8 | * This string is meant to be concatenated with the inline asm string and | 8 | * This string is meant to be concatenated with the inline asm string and |
9 | * will cause compilation to stop on mismatch. | 9 | * will cause compilation to stop on mismatch. |
10 | * (for details, see gcc PR 15089) | 10 | * (for details, see gcc PR 15089) |
11 | * For compatibility with clang, we have to specifically take the equivalence | ||
12 | * of 'r11' <-> 'fp' and 'r12' <-> 'ip' into account as well. | ||
11 | */ | 13 | */ |
12 | #define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" | 14 | #define __asmeq(x, y) \ |
15 | ".ifnc " x "," y "; " \ | ||
16 | ".ifnc " x y ",fpr11; " \ | ||
17 | ".ifnc " x y ",r11fp; " \ | ||
18 | ".ifnc " x y ",ipr12; " \ | ||
19 | ".ifnc " x y ",r12ip; " \ | ||
20 | ".err; " \ | ||
21 | ".endif; " \ | ||
22 | ".endif; " \ | ||
23 | ".endif; " \ | ||
24 | ".endif; " \ | ||
25 | ".endif\n\t" | ||
13 | 26 | ||
14 | 27 | ||
15 | #endif /* __ASM_ARM_COMPILER_H */ | 28 | #endif /* __ASM_ARM_COMPILER_H */ |
diff --git a/arch/arm/kernel/insn.h b/arch/arm/include/asm/insn.h index e96065da4dae..e96065da4dae 100644 --- a/arch/arm/kernel/insn.h +++ b/arch/arm/include/asm/insn.h | |||
diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index 49fa0dfaad33..3ea9be559726 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h | |||
@@ -22,7 +22,6 @@ | |||
22 | 22 | ||
23 | #define __ARCH_WANT_KPROBES_INSN_SLOT | 23 | #define __ARCH_WANT_KPROBES_INSN_SLOT |
24 | #define MAX_INSN_SIZE 2 | 24 | #define MAX_INSN_SIZE 2 |
25 | #define MAX_STACK_SIZE 64 /* 32 would probably be OK */ | ||
26 | 25 | ||
27 | #define flush_insn_slot(p) do { } while (0) | 26 | #define flush_insn_slot(p) do { } while (0) |
28 | #define kretprobe_blacklist_size 0 | 27 | #define kretprobe_blacklist_size 0 |
@@ -51,5 +50,37 @@ int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr); | |||
51 | int kprobe_exceptions_notify(struct notifier_block *self, | 50 | int kprobe_exceptions_notify(struct notifier_block *self, |
52 | unsigned long val, void *data); | 51 | unsigned long val, void *data); |
53 | 52 | ||
53 | /* optinsn template addresses */ | ||
54 | extern __visible kprobe_opcode_t optprobe_template_entry; | ||
55 | extern __visible kprobe_opcode_t optprobe_template_val; | ||
56 | extern __visible kprobe_opcode_t optprobe_template_call; | ||
57 | extern __visible kprobe_opcode_t optprobe_template_end; | ||
58 | extern __visible kprobe_opcode_t optprobe_template_sub_sp; | ||
59 | extern __visible kprobe_opcode_t optprobe_template_add_sp; | ||
60 | extern __visible kprobe_opcode_t optprobe_template_restore_begin; | ||
61 | extern __visible kprobe_opcode_t optprobe_template_restore_orig_insn; | ||
62 | extern __visible kprobe_opcode_t optprobe_template_restore_end; | ||
63 | |||
64 | #define MAX_OPTIMIZED_LENGTH 4 | ||
65 | #define MAX_OPTINSN_SIZE \ | ||
66 | ((unsigned long)&optprobe_template_end - \ | ||
67 | (unsigned long)&optprobe_template_entry) | ||
68 | #define RELATIVEJUMP_SIZE 4 | ||
69 | |||
70 | struct arch_optimized_insn { | ||
71 | /* | ||
72 | * copy of the original instructions. | ||
73 | * Different from x86, ARM kprobe_opcode_t is u32. | ||
74 | */ | ||
75 | #define MAX_COPIED_INSN DIV_ROUND_UP(RELATIVEJUMP_SIZE, sizeof(kprobe_opcode_t)) | ||
76 | kprobe_opcode_t copied_insn[MAX_COPIED_INSN]; | ||
77 | /* detour code buffer */ | ||
78 | kprobe_opcode_t *insn; | ||
79 | /* | ||
80 | * We always copy one instruction on ARM, | ||
81 | * so size will always be 4, and unlike x86, there is no | ||
82 | * need for a size field. | ||
83 | */ | ||
84 | }; | ||
54 | 85 | ||
55 | #endif /* _ARM_KPROBES_H */ | 86 | #endif /* _ARM_KPROBES_H */ |
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index 891a56b35bcf..563b92fc2f41 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h | |||
@@ -23,6 +23,8 @@ | |||
23 | 23 | ||
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | 25 | ||
26 | struct l2x0_regs; | ||
27 | |||
26 | struct outer_cache_fns { | 28 | struct outer_cache_fns { |
27 | void (*inv_range)(unsigned long, unsigned long); | 29 | void (*inv_range)(unsigned long, unsigned long); |
28 | void (*clean_range)(unsigned long, unsigned long); | 30 | void (*clean_range)(unsigned long, unsigned long); |
@@ -36,6 +38,7 @@ struct outer_cache_fns { | |||
36 | 38 | ||
37 | /* This is an ARM L2C thing */ | 39 | /* This is an ARM L2C thing */ |
38 | void (*write_sec)(unsigned long, unsigned); | 40 | void (*write_sec)(unsigned long, unsigned); |
41 | void (*configure)(const struct l2x0_regs *); | ||
39 | }; | 42 | }; |
40 | 43 | ||
41 | extern struct outer_cache_fns outer_cache; | 44 | extern struct outer_cache_fns outer_cache; |
diff --git a/arch/arm/kernel/patch.h b/arch/arm/include/asm/patch.h index 77e054c2f6cd..77e054c2f6cd 100644 --- a/arch/arm/kernel/patch.h +++ b/arch/arm/include/asm/patch.h | |||
diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index 806cfe622a9e..1e5b9bb92270 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h | |||
@@ -19,6 +19,8 @@ | |||
19 | #ifndef _ASM_PROBES_H | 19 | #ifndef _ASM_PROBES_H |
20 | #define _ASM_PROBES_H | 20 | #define _ASM_PROBES_H |
21 | 21 | ||
22 | #ifndef __ASSEMBLY__ | ||
23 | |||
22 | typedef u32 probes_opcode_t; | 24 | typedef u32 probes_opcode_t; |
23 | 25 | ||
24 | struct arch_probes_insn; | 26 | struct arch_probes_insn; |
@@ -38,6 +40,19 @@ struct arch_probes_insn { | |||
38 | probes_check_cc *insn_check_cc; | 40 | probes_check_cc *insn_check_cc; |
39 | probes_insn_singlestep_t *insn_singlestep; | 41 | probes_insn_singlestep_t *insn_singlestep; |
40 | probes_insn_fn_t *insn_fn; | 42 | probes_insn_fn_t *insn_fn; |
43 | int stack_space; | ||
44 | unsigned long register_usage_flags; | ||
45 | bool kprobe_direct_exec; | ||
41 | }; | 46 | }; |
42 | 47 | ||
48 | #endif /* __ASSEMBLY__ */ | ||
49 | |||
50 | /* | ||
51 | * We assume one instruction can consume at most 64 bytes stack, which is | ||
52 | * 'push {r0-r15}'. Instructions consume more or unknown stack space like | ||
53 | * 'str r0, [sp, #-80]' and 'str r0, [sp, r1]' should be prohibit to probe. | ||
54 | * Both kprobe and jprobe use this macro. | ||
55 | */ | ||
56 | #define MAX_STACK_SIZE 64 | ||
57 | |||
43 | #endif | 58 | #endif |
diff --git a/arch/arm/mach-ks8695/include/mach/debug-macro.S b/arch/arm/include/debug/ks8695.S index a79e48981202..961da1f32ab3 100644 --- a/arch/arm/mach-ks8695/include/mach/debug-macro.S +++ b/arch/arm/include/debug/ks8695.S | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/mach-ks8695/include/mach/debug-macro.S | 2 | * arch/arm/include/debug/ks8695.S |
3 | * | 3 | * |
4 | * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk> | 4 | * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk> |
5 | * Copyright (C) 2006 Simtec Electronics | 5 | * Copyright (C) 2006 Simtec Electronics |
@@ -11,8 +11,12 @@ | |||
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <mach/hardware.h> | 14 | #define KS8695_UART_PA 0x03ffe000 |
15 | #include <mach/regs-uart.h> | 15 | #define KS8695_UART_VA 0xf00fe000 |
16 | #define KS8695_URTH (0x04) | ||
17 | #define KS8695_URLS (0x14) | ||
18 | #define URLS_URTE (1 << 6) | ||
19 | #define URLS_URTHRE (1 << 5) | ||
16 | 20 | ||
17 | .macro addruart, rp, rv, tmp | 21 | .macro addruart, rp, rv, tmp |
18 | ldr \rp, =KS8695_UART_PA @ physical base address | 22 | ldr \rp, =KS8695_UART_PA @ physical base address |
diff --git a/arch/arm/mach-netx/include/mach/debug-macro.S b/arch/arm/include/debug/netx.S index 247781e096e2..81e1b2af70f7 100644 --- a/arch/arm/mach-netx/include/mach/debug-macro.S +++ b/arch/arm/include/debug/netx.S | |||
@@ -1,5 +1,4 @@ | |||
1 | /* arch/arm/mach-netx/include/mach/debug-macro.S | 1 | /* |
2 | * | ||
3 | * Debugging macro include header | 2 | * Debugging macro include header |
4 | * | 3 | * |
5 | * Copyright (C) 1994-1999 Russell King | 4 | * Copyright (C) 1994-1999 Russell King |
@@ -11,26 +10,27 @@ | |||
11 | * | 10 | * |
12 | */ | 11 | */ |
13 | 12 | ||
14 | #include "hardware.h" | 13 | #define UART_DATA 0 |
14 | #define UART_FLAG 0x18 | ||
15 | #define UART_FLAG_BUSY (1 << 3) | ||
15 | 16 | ||
16 | .macro addruart, rp, rv, tmp | 17 | .macro addruart, rp, rv, tmp |
17 | mov \rp, #0x00000a00 | 18 | ldr \rp, =CONFIG_DEBUG_UART_PHYS |
18 | orr \rv, \rp, #io_p2v(0x00100000) @ virtual | 19 | ldr \rv, =CONFIG_DEBUG_UART_VIRT |
19 | orr \rp, \rp, #0x00100000 @ physical | ||
20 | .endm | 20 | .endm |
21 | 21 | ||
22 | .macro senduart,rd,rx | 22 | .macro senduart,rd,rx |
23 | str \rd, [\rx, #0] | 23 | str \rd, [\rx, #UART_DATA] |
24 | .endm | 24 | .endm |
25 | 25 | ||
26 | .macro busyuart,rd,rx | 26 | .macro busyuart,rd,rx |
27 | 1002: ldr \rd, [\rx, #0x18] | 27 | 1002: ldr \rd, [\rx, #UART_FLAG] |
28 | tst \rd, #(1 << 3) | 28 | tst \rd, #UART_FLAG_BUSY |
29 | bne 1002b | 29 | bne 1002b |
30 | .endm | 30 | .endm |
31 | 31 | ||
32 | .macro waituart,rd,rx | 32 | .macro waituart,rd,rx |
33 | 1001: ldr \rd, [\rx, #0x18] | 33 | 1001: ldr \rd, [\rx, #UART_FLAG] |
34 | tst \rd, #(1 << 3) | 34 | tst \rd, #UART_FLAG_BUSY |
35 | bne 1001b | 35 | bne 1001b |
36 | .endm | 36 | .endm |
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index fb2b71ebe3f2..902397dd1000 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -51,20 +51,8 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o | |||
51 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o | 51 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o |
52 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o | 52 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o |
53 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 53 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
54 | obj-$(CONFIG_UPROBES) += probes.o probes-arm.o uprobes.o uprobes-arm.o | 54 | # Main staffs in KPROBES are in arch/arm/probes/ . |
55 | obj-$(CONFIG_KPROBES) += probes.o kprobes.o kprobes-common.o patch.o | 55 | obj-$(CONFIG_KPROBES) += patch.o insn.o |
56 | ifdef CONFIG_THUMB2_KERNEL | ||
57 | obj-$(CONFIG_KPROBES) += kprobes-thumb.o probes-thumb.o | ||
58 | else | ||
59 | obj-$(CONFIG_KPROBES) += kprobes-arm.o probes-arm.o | ||
60 | endif | ||
61 | obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o | ||
62 | test-kprobes-objs := kprobes-test.o | ||
63 | ifdef CONFIG_THUMB2_KERNEL | ||
64 | test-kprobes-objs += kprobes-test-thumb.o | ||
65 | else | ||
66 | test-kprobes-objs += kprobes-test-arm.o | ||
67 | endif | ||
68 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o | 56 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o |
69 | obj-$(CONFIG_ARM_THUMBEE) += thumbee.o | 57 | obj-$(CONFIG_ARM_THUMBEE) += thumbee.o |
70 | obj-$(CONFIG_KGDB) += kgdb.o patch.o | 58 | obj-$(CONFIG_KGDB) += kgdb.o patch.o |
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 2f5555d307b3..672b21942fff 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -31,6 +31,7 @@ | |||
31 | 31 | ||
32 | #include "entry-header.S" | 32 | #include "entry-header.S" |
33 | #include <asm/entry-macro-multi.S> | 33 | #include <asm/entry-macro-multi.S> |
34 | #include <asm/probes.h> | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * Interrupt handling. | 37 | * Interrupt handling. |
@@ -249,7 +250,7 @@ __und_svc: | |||
249 | @ If a kprobe is about to simulate a "stmdb sp..." instruction, | 250 | @ If a kprobe is about to simulate a "stmdb sp..." instruction, |
250 | @ it obviously needs free stack space which then will belong to | 251 | @ it obviously needs free stack space which then will belong to |
251 | @ the saved context. | 252 | @ the saved context. |
252 | svc_entry 64 | 253 | svc_entry MAX_STACK_SIZE |
253 | #else | 254 | #else |
254 | svc_entry | 255 | svc_entry |
255 | #endif | 256 | #endif |
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index b8c75e45a950..709ee1d6d4df 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c | |||
@@ -20,8 +20,7 @@ | |||
20 | #include <asm/cacheflush.h> | 20 | #include <asm/cacheflush.h> |
21 | #include <asm/opcodes.h> | 21 | #include <asm/opcodes.h> |
22 | #include <asm/ftrace.h> | 22 | #include <asm/ftrace.h> |
23 | 23 | #include <asm/insn.h> | |
24 | #include "insn.h" | ||
25 | 24 | ||
26 | #ifdef CONFIG_THUMB2_KERNEL | 25 | #ifdef CONFIG_THUMB2_KERNEL |
27 | #define NOP 0xf85deb04 /* pop.w {lr} */ | 26 | #define NOP 0xf85deb04 /* pop.w {lr} */ |
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 664eee8c4a26..01963273c07a 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -346,6 +346,12 @@ __turn_mmu_on_loc: | |||
346 | 346 | ||
347 | #if defined(CONFIG_SMP) | 347 | #if defined(CONFIG_SMP) |
348 | .text | 348 | .text |
349 | ENTRY(secondary_startup_arm) | ||
350 | .arm | ||
351 | THUMB( adr r9, BSYM(1f) ) @ Kernel is entered in ARM. | ||
352 | THUMB( bx r9 ) @ If this is a Thumb-2 kernel, | ||
353 | THUMB( .thumb ) @ switch to Thumb now. | ||
354 | THUMB(1: ) | ||
349 | ENTRY(secondary_startup) | 355 | ENTRY(secondary_startup) |
350 | /* | 356 | /* |
351 | * Common entry point for secondary CPUs. | 357 | * Common entry point for secondary CPUs. |
@@ -385,6 +391,7 @@ ENTRY(secondary_startup) | |||
385 | THUMB( add r12, r10, #PROCINFO_INITFUNC ) | 391 | THUMB( add r12, r10, #PROCINFO_INITFUNC ) |
386 | THUMB( ret r12 ) | 392 | THUMB( ret r12 ) |
387 | ENDPROC(secondary_startup) | 393 | ENDPROC(secondary_startup) |
394 | ENDPROC(secondary_startup_arm) | ||
388 | 395 | ||
389 | /* | 396 | /* |
390 | * r6 = &secondary_data | 397 | * r6 = &secondary_data |
@@ -586,7 +593,7 @@ __fixup_pv_table: | |||
586 | add r5, r5, r3 @ adjust table end address | 593 | add r5, r5, r3 @ adjust table end address |
587 | add r6, r6, r3 @ adjust __pv_phys_pfn_offset address | 594 | add r6, r6, r3 @ adjust __pv_phys_pfn_offset address |
588 | add r7, r7, r3 @ adjust __pv_offset address | 595 | add r7, r7, r3 @ adjust __pv_offset address |
589 | mov r0, r8, lsr #12 @ convert to PFN | 596 | mov r0, r8, lsr #PAGE_SHIFT @ convert to PFN |
590 | str r0, [r6] @ save computed PHYS_OFFSET to __pv_phys_pfn_offset | 597 | str r0, [r6] @ save computed PHYS_OFFSET to __pv_phys_pfn_offset |
591 | strcc ip, [r7, #HIGH_OFFSET] @ save to __pv_offset high bits | 598 | strcc ip, [r7, #HIGH_OFFSET] @ save to __pv_offset high bits |
592 | mov r6, r3, lsr #24 @ constant for add/sub instructions | 599 | mov r6, r3, lsr #24 @ constant for add/sub instructions |
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index ad857bada96c..350f188c92d2 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c | |||
@@ -109,7 +109,8 @@ void __init init_IRQ(void) | |||
109 | 109 | ||
110 | if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_CACHE_L2X0) && | 110 | if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_CACHE_L2X0) && |
111 | (machine_desc->l2c_aux_mask || machine_desc->l2c_aux_val)) { | 111 | (machine_desc->l2c_aux_mask || machine_desc->l2c_aux_val)) { |
112 | outer_cache.write_sec = machine_desc->l2c_write_sec; | 112 | if (!outer_cache.write_sec) |
113 | outer_cache.write_sec = machine_desc->l2c_write_sec; | ||
113 | ret = l2x0_of_init(machine_desc->l2c_aux_val, | 114 | ret = l2x0_of_init(machine_desc->l2c_aux_val, |
114 | machine_desc->l2c_aux_mask); | 115 | machine_desc->l2c_aux_mask); |
115 | if (ret) | 116 | if (ret) |
diff --git a/arch/arm/kernel/jump_label.c b/arch/arm/kernel/jump_label.c index afeeb9ea6f43..e39cbf488cfe 100644 --- a/arch/arm/kernel/jump_label.c +++ b/arch/arm/kernel/jump_label.c | |||
@@ -1,8 +1,7 @@ | |||
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | #include <linux/jump_label.h> | 2 | #include <linux/jump_label.h> |
3 | 3 | #include <asm/patch.h> | |
4 | #include "insn.h" | 4 | #include <asm/insn.h> |
5 | #include "patch.h" | ||
6 | 5 | ||
7 | #ifdef HAVE_JUMP_LABEL | 6 | #ifdef HAVE_JUMP_LABEL |
8 | 7 | ||
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index 07db2f8a1b45..a6ad93c9bce3 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c | |||
@@ -14,10 +14,9 @@ | |||
14 | #include <linux/kgdb.h> | 14 | #include <linux/kgdb.h> |
15 | #include <linux/uaccess.h> | 15 | #include <linux/uaccess.h> |
16 | 16 | ||
17 | #include <asm/patch.h> | ||
17 | #include <asm/traps.h> | 18 | #include <asm/traps.h> |
18 | 19 | ||
19 | #include "patch.h" | ||
20 | |||
21 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = | 20 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
22 | { | 21 | { |
23 | { "r0", 4, offsetof(struct pt_regs, ARM_r0)}, | 22 | { "r0", 4, offsetof(struct pt_regs, ARM_r0)}, |
diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c index 5038960e3c55..69bda1a5707e 100644 --- a/arch/arm/kernel/patch.c +++ b/arch/arm/kernel/patch.c | |||
@@ -8,8 +8,7 @@ | |||
8 | #include <asm/fixmap.h> | 8 | #include <asm/fixmap.h> |
9 | #include <asm/smp_plat.h> | 9 | #include <asm/smp_plat.h> |
10 | #include <asm/opcodes.h> | 10 | #include <asm/opcodes.h> |
11 | 11 | #include <asm/patch.h> | |
12 | #include "patch.h" | ||
13 | 12 | ||
14 | struct patch { | 13 | struct patch { |
15 | void *addr; | 14 | void *addr; |
diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index 2835d35234ca..9a2f882a0a2d 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c | |||
@@ -14,10 +14,6 @@ extern int __cpu_suspend(unsigned long, int (*)(unsigned long), u32 cpuid); | |||
14 | extern void cpu_resume_mmu(void); | 14 | extern void cpu_resume_mmu(void); |
15 | 15 | ||
16 | #ifdef CONFIG_MMU | 16 | #ifdef CONFIG_MMU |
17 | /* | ||
18 | * Hide the first two arguments to __cpu_suspend - these are an implementation | ||
19 | * detail which platform code shouldn't have to know about. | ||
20 | */ | ||
21 | int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) | 17 | int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) |
22 | { | 18 | { |
23 | struct mm_struct *mm = current->active_mm; | 19 | struct mm_struct *mm = current->active_mm; |
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 0573faab96ad..d8a780799506 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile | |||
@@ -15,19 +15,8 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ | |||
15 | io-readsb.o io-writesb.o io-readsl.o io-writesl.o \ | 15 | io-readsb.o io-writesb.o io-readsl.o io-writesl.o \ |
16 | call_with_stack.o bswapsdi2.o | 16 | call_with_stack.o bswapsdi2.o |
17 | 17 | ||
18 | mmu-y := clear_user.o copy_page.o getuser.o putuser.o | 18 | mmu-y := clear_user.o copy_page.o getuser.o putuser.o \ |
19 | 19 | copy_from_user.o copy_to_user.o | |
20 | # the code in uaccess.S is not preemption safe and | ||
21 | # probably faster on ARMv3 only | ||
22 | ifeq ($(CONFIG_PREEMPT),y) | ||
23 | mmu-y += copy_from_user.o copy_to_user.o | ||
24 | else | ||
25 | ifneq ($(CONFIG_CPU_32v3),y) | ||
26 | mmu-y += copy_from_user.o copy_to_user.o | ||
27 | else | ||
28 | mmu-y += uaccess.o | ||
29 | endif | ||
30 | endif | ||
31 | 20 | ||
32 | # using lib_ here won't override already available weak symbols | 21 | # using lib_ here won't override already available weak symbols |
33 | obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o | 22 | obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o |
diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S deleted file mode 100644 index e50520904b76..000000000000 --- a/arch/arm/lib/uaccess.S +++ /dev/null | |||
@@ -1,564 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/lib/uaccess.S | ||
3 | * | ||
4 | * Copyright (C) 1995, 1996,1997,1998 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Routines to block copy data to/from user memory | ||
11 | * These are highly optimised both for the 4k page size | ||
12 | * and for various alignments. | ||
13 | */ | ||
14 | #include <linux/linkage.h> | ||
15 | #include <asm/assembler.h> | ||
16 | #include <asm/errno.h> | ||
17 | #include <asm/domain.h> | ||
18 | |||
19 | .text | ||
20 | |||
21 | #define PAGE_SHIFT 12 | ||
22 | |||
23 | /* Prototype: int __copy_to_user(void *to, const char *from, size_t n) | ||
24 | * Purpose : copy a block to user memory from kernel memory | ||
25 | * Params : to - user memory | ||
26 | * : from - kernel memory | ||
27 | * : n - number of bytes to copy | ||
28 | * Returns : Number of bytes NOT copied. | ||
29 | */ | ||
30 | |||
31 | .Lc2u_dest_not_aligned: | ||
32 | rsb ip, ip, #4 | ||
33 | cmp ip, #2 | ||
34 | ldrb r3, [r1], #1 | ||
35 | USER( TUSER( strb) r3, [r0], #1) @ May fault | ||
36 | ldrgeb r3, [r1], #1 | ||
37 | USER( TUSER( strgeb) r3, [r0], #1) @ May fault | ||
38 | ldrgtb r3, [r1], #1 | ||
39 | USER( TUSER( strgtb) r3, [r0], #1) @ May fault | ||
40 | sub r2, r2, ip | ||
41 | b .Lc2u_dest_aligned | ||
42 | |||
43 | ENTRY(__copy_to_user) | ||
44 | stmfd sp!, {r2, r4 - r7, lr} | ||
45 | cmp r2, #4 | ||
46 | blt .Lc2u_not_enough | ||
47 | ands ip, r0, #3 | ||
48 | bne .Lc2u_dest_not_aligned | ||
49 | .Lc2u_dest_aligned: | ||
50 | |||
51 | ands ip, r1, #3 | ||
52 | bne .Lc2u_src_not_aligned | ||
53 | /* | ||
54 | * Seeing as there has to be at least 8 bytes to copy, we can | ||
55 | * copy one word, and force a user-mode page fault... | ||
56 | */ | ||
57 | |||
58 | .Lc2u_0fupi: subs r2, r2, #4 | ||
59 | addmi ip, r2, #4 | ||
60 | bmi .Lc2u_0nowords | ||
61 | ldr r3, [r1], #4 | ||
62 | USER( TUSER( str) r3, [r0], #4) @ May fault | ||
63 | mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction | ||
64 | rsb ip, ip, #0 | ||
65 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
66 | beq .Lc2u_0fupi | ||
67 | /* | ||
68 | * ip = max no. of bytes to copy before needing another "strt" insn | ||
69 | */ | ||
70 | cmp r2, ip | ||
71 | movlt ip, r2 | ||
72 | sub r2, r2, ip | ||
73 | subs ip, ip, #32 | ||
74 | blt .Lc2u_0rem8lp | ||
75 | |||
76 | .Lc2u_0cpy8lp: ldmia r1!, {r3 - r6} | ||
77 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
78 | ldmia r1!, {r3 - r6} | ||
79 | subs ip, ip, #32 | ||
80 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
81 | bpl .Lc2u_0cpy8lp | ||
82 | |||
83 | .Lc2u_0rem8lp: cmn ip, #16 | ||
84 | ldmgeia r1!, {r3 - r6} | ||
85 | stmgeia r0!, {r3 - r6} @ Shouldnt fault | ||
86 | tst ip, #8 | ||
87 | ldmneia r1!, {r3 - r4} | ||
88 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
89 | tst ip, #4 | ||
90 | ldrne r3, [r1], #4 | ||
91 | TUSER( strne) r3, [r0], #4 @ Shouldnt fault | ||
92 | ands ip, ip, #3 | ||
93 | beq .Lc2u_0fupi | ||
94 | .Lc2u_0nowords: teq ip, #0 | ||
95 | beq .Lc2u_finished | ||
96 | .Lc2u_nowords: cmp ip, #2 | ||
97 | ldrb r3, [r1], #1 | ||
98 | USER( TUSER( strb) r3, [r0], #1) @ May fault | ||
99 | ldrgeb r3, [r1], #1 | ||
100 | USER( TUSER( strgeb) r3, [r0], #1) @ May fault | ||
101 | ldrgtb r3, [r1], #1 | ||
102 | USER( TUSER( strgtb) r3, [r0], #1) @ May fault | ||
103 | b .Lc2u_finished | ||
104 | |||
105 | .Lc2u_not_enough: | ||
106 | movs ip, r2 | ||
107 | bne .Lc2u_nowords | ||
108 | .Lc2u_finished: mov r0, #0 | ||
109 | ldmfd sp!, {r2, r4 - r7, pc} | ||
110 | |||
111 | .Lc2u_src_not_aligned: | ||
112 | bic r1, r1, #3 | ||
113 | ldr r7, [r1], #4 | ||
114 | cmp ip, #2 | ||
115 | bgt .Lc2u_3fupi | ||
116 | beq .Lc2u_2fupi | ||
117 | .Lc2u_1fupi: subs r2, r2, #4 | ||
118 | addmi ip, r2, #4 | ||
119 | bmi .Lc2u_1nowords | ||
120 | mov r3, r7, lspull #8 | ||
121 | ldr r7, [r1], #4 | ||
122 | orr r3, r3, r7, lspush #24 | ||
123 | USER( TUSER( str) r3, [r0], #4) @ May fault | ||
124 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
125 | rsb ip, ip, #0 | ||
126 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
127 | beq .Lc2u_1fupi | ||
128 | cmp r2, ip | ||
129 | movlt ip, r2 | ||
130 | sub r2, r2, ip | ||
131 | subs ip, ip, #16 | ||
132 | blt .Lc2u_1rem8lp | ||
133 | |||
134 | .Lc2u_1cpy8lp: mov r3, r7, lspull #8 | ||
135 | ldmia r1!, {r4 - r7} | ||
136 | subs ip, ip, #16 | ||
137 | orr r3, r3, r4, lspush #24 | ||
138 | mov r4, r4, lspull #8 | ||
139 | orr r4, r4, r5, lspush #24 | ||
140 | mov r5, r5, lspull #8 | ||
141 | orr r5, r5, r6, lspush #24 | ||
142 | mov r6, r6, lspull #8 | ||
143 | orr r6, r6, r7, lspush #24 | ||
144 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
145 | bpl .Lc2u_1cpy8lp | ||
146 | |||
147 | .Lc2u_1rem8lp: tst ip, #8 | ||
148 | movne r3, r7, lspull #8 | ||
149 | ldmneia r1!, {r4, r7} | ||
150 | orrne r3, r3, r4, lspush #24 | ||
151 | movne r4, r4, lspull #8 | ||
152 | orrne r4, r4, r7, lspush #24 | ||
153 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
154 | tst ip, #4 | ||
155 | movne r3, r7, lspull #8 | ||
156 | ldrne r7, [r1], #4 | ||
157 | orrne r3, r3, r7, lspush #24 | ||
158 | TUSER( strne) r3, [r0], #4 @ Shouldnt fault | ||
159 | ands ip, ip, #3 | ||
160 | beq .Lc2u_1fupi | ||
161 | .Lc2u_1nowords: mov r3, r7, get_byte_1 | ||
162 | teq ip, #0 | ||
163 | beq .Lc2u_finished | ||
164 | cmp ip, #2 | ||
165 | USER( TUSER( strb) r3, [r0], #1) @ May fault | ||
166 | movge r3, r7, get_byte_2 | ||
167 | USER( TUSER( strgeb) r3, [r0], #1) @ May fault | ||
168 | movgt r3, r7, get_byte_3 | ||
169 | USER( TUSER( strgtb) r3, [r0], #1) @ May fault | ||
170 | b .Lc2u_finished | ||
171 | |||
172 | .Lc2u_2fupi: subs r2, r2, #4 | ||
173 | addmi ip, r2, #4 | ||
174 | bmi .Lc2u_2nowords | ||
175 | mov r3, r7, lspull #16 | ||
176 | ldr r7, [r1], #4 | ||
177 | orr r3, r3, r7, lspush #16 | ||
178 | USER( TUSER( str) r3, [r0], #4) @ May fault | ||
179 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
180 | rsb ip, ip, #0 | ||
181 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
182 | beq .Lc2u_2fupi | ||
183 | cmp r2, ip | ||
184 | movlt ip, r2 | ||
185 | sub r2, r2, ip | ||
186 | subs ip, ip, #16 | ||
187 | blt .Lc2u_2rem8lp | ||
188 | |||
189 | .Lc2u_2cpy8lp: mov r3, r7, lspull #16 | ||
190 | ldmia r1!, {r4 - r7} | ||
191 | subs ip, ip, #16 | ||
192 | orr r3, r3, r4, lspush #16 | ||
193 | mov r4, r4, lspull #16 | ||
194 | orr r4, r4, r5, lspush #16 | ||
195 | mov r5, r5, lspull #16 | ||
196 | orr r5, r5, r6, lspush #16 | ||
197 | mov r6, r6, lspull #16 | ||
198 | orr r6, r6, r7, lspush #16 | ||
199 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
200 | bpl .Lc2u_2cpy8lp | ||
201 | |||
202 | .Lc2u_2rem8lp: tst ip, #8 | ||
203 | movne r3, r7, lspull #16 | ||
204 | ldmneia r1!, {r4, r7} | ||
205 | orrne r3, r3, r4, lspush #16 | ||
206 | movne r4, r4, lspull #16 | ||
207 | orrne r4, r4, r7, lspush #16 | ||
208 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
209 | tst ip, #4 | ||
210 | movne r3, r7, lspull #16 | ||
211 | ldrne r7, [r1], #4 | ||
212 | orrne r3, r3, r7, lspush #16 | ||
213 | TUSER( strne) r3, [r0], #4 @ Shouldnt fault | ||
214 | ands ip, ip, #3 | ||
215 | beq .Lc2u_2fupi | ||
216 | .Lc2u_2nowords: mov r3, r7, get_byte_2 | ||
217 | teq ip, #0 | ||
218 | beq .Lc2u_finished | ||
219 | cmp ip, #2 | ||
220 | USER( TUSER( strb) r3, [r0], #1) @ May fault | ||
221 | movge r3, r7, get_byte_3 | ||
222 | USER( TUSER( strgeb) r3, [r0], #1) @ May fault | ||
223 | ldrgtb r3, [r1], #0 | ||
224 | USER( TUSER( strgtb) r3, [r0], #1) @ May fault | ||
225 | b .Lc2u_finished | ||
226 | |||
227 | .Lc2u_3fupi: subs r2, r2, #4 | ||
228 | addmi ip, r2, #4 | ||
229 | bmi .Lc2u_3nowords | ||
230 | mov r3, r7, lspull #24 | ||
231 | ldr r7, [r1], #4 | ||
232 | orr r3, r3, r7, lspush #8 | ||
233 | USER( TUSER( str) r3, [r0], #4) @ May fault | ||
234 | mov ip, r0, lsl #32 - PAGE_SHIFT | ||
235 | rsb ip, ip, #0 | ||
236 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
237 | beq .Lc2u_3fupi | ||
238 | cmp r2, ip | ||
239 | movlt ip, r2 | ||
240 | sub r2, r2, ip | ||
241 | subs ip, ip, #16 | ||
242 | blt .Lc2u_3rem8lp | ||
243 | |||
244 | .Lc2u_3cpy8lp: mov r3, r7, lspull #24 | ||
245 | ldmia r1!, {r4 - r7} | ||
246 | subs ip, ip, #16 | ||
247 | orr r3, r3, r4, lspush #8 | ||
248 | mov r4, r4, lspull #24 | ||
249 | orr r4, r4, r5, lspush #8 | ||
250 | mov r5, r5, lspull #24 | ||
251 | orr r5, r5, r6, lspush #8 | ||
252 | mov r6, r6, lspull #24 | ||
253 | orr r6, r6, r7, lspush #8 | ||
254 | stmia r0!, {r3 - r6} @ Shouldnt fault | ||
255 | bpl .Lc2u_3cpy8lp | ||
256 | |||
257 | .Lc2u_3rem8lp: tst ip, #8 | ||
258 | movne r3, r7, lspull #24 | ||
259 | ldmneia r1!, {r4, r7} | ||
260 | orrne r3, r3, r4, lspush #8 | ||
261 | movne r4, r4, lspull #24 | ||
262 | orrne r4, r4, r7, lspush #8 | ||
263 | stmneia r0!, {r3 - r4} @ Shouldnt fault | ||
264 | tst ip, #4 | ||
265 | movne r3, r7, lspull #24 | ||
266 | ldrne r7, [r1], #4 | ||
267 | orrne r3, r3, r7, lspush #8 | ||
268 | TUSER( strne) r3, [r0], #4 @ Shouldnt fault | ||
269 | ands ip, ip, #3 | ||
270 | beq .Lc2u_3fupi | ||
271 | .Lc2u_3nowords: mov r3, r7, get_byte_3 | ||
272 | teq ip, #0 | ||
273 | beq .Lc2u_finished | ||
274 | cmp ip, #2 | ||
275 | USER( TUSER( strb) r3, [r0], #1) @ May fault | ||
276 | ldrgeb r3, [r1], #1 | ||
277 | USER( TUSER( strgeb) r3, [r0], #1) @ May fault | ||
278 | ldrgtb r3, [r1], #0 | ||
279 | USER( TUSER( strgtb) r3, [r0], #1) @ May fault | ||
280 | b .Lc2u_finished | ||
281 | ENDPROC(__copy_to_user) | ||
282 | |||
283 | .pushsection .fixup,"ax" | ||
284 | .align 0 | ||
285 | 9001: ldmfd sp!, {r0, r4 - r7, pc} | ||
286 | .popsection | ||
287 | |||
288 | /* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n); | ||
289 | * Purpose : copy a block from user memory to kernel memory | ||
290 | * Params : to - kernel memory | ||
291 | * : from - user memory | ||
292 | * : n - number of bytes to copy | ||
293 | * Returns : Number of bytes NOT copied. | ||
294 | */ | ||
295 | .Lcfu_dest_not_aligned: | ||
296 | rsb ip, ip, #4 | ||
297 | cmp ip, #2 | ||
298 | USER( TUSER( ldrb) r3, [r1], #1) @ May fault | ||
299 | strb r3, [r0], #1 | ||
300 | USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault | ||
301 | strgeb r3, [r0], #1 | ||
302 | USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault | ||
303 | strgtb r3, [r0], #1 | ||
304 | sub r2, r2, ip | ||
305 | b .Lcfu_dest_aligned | ||
306 | |||
307 | ENTRY(__copy_from_user) | ||
308 | stmfd sp!, {r0, r2, r4 - r7, lr} | ||
309 | cmp r2, #4 | ||
310 | blt .Lcfu_not_enough | ||
311 | ands ip, r0, #3 | ||
312 | bne .Lcfu_dest_not_aligned | ||
313 | .Lcfu_dest_aligned: | ||
314 | ands ip, r1, #3 | ||
315 | bne .Lcfu_src_not_aligned | ||
316 | |||
317 | /* | ||
318 | * Seeing as there has to be at least 8 bytes to copy, we can | ||
319 | * copy one word, and force a user-mode page fault... | ||
320 | */ | ||
321 | |||
322 | .Lcfu_0fupi: subs r2, r2, #4 | ||
323 | addmi ip, r2, #4 | ||
324 | bmi .Lcfu_0nowords | ||
325 | USER( TUSER( ldr) r3, [r1], #4) | ||
326 | str r3, [r0], #4 | ||
327 | mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction | ||
328 | rsb ip, ip, #0 | ||
329 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
330 | beq .Lcfu_0fupi | ||
331 | /* | ||
332 | * ip = max no. of bytes to copy before needing another "strt" insn | ||
333 | */ | ||
334 | cmp r2, ip | ||
335 | movlt ip, r2 | ||
336 | sub r2, r2, ip | ||
337 | subs ip, ip, #32 | ||
338 | blt .Lcfu_0rem8lp | ||
339 | |||
340 | .Lcfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault | ||
341 | stmia r0!, {r3 - r6} | ||
342 | ldmia r1!, {r3 - r6} @ Shouldnt fault | ||
343 | subs ip, ip, #32 | ||
344 | stmia r0!, {r3 - r6} | ||
345 | bpl .Lcfu_0cpy8lp | ||
346 | |||
347 | .Lcfu_0rem8lp: cmn ip, #16 | ||
348 | ldmgeia r1!, {r3 - r6} @ Shouldnt fault | ||
349 | stmgeia r0!, {r3 - r6} | ||
350 | tst ip, #8 | ||
351 | ldmneia r1!, {r3 - r4} @ Shouldnt fault | ||
352 | stmneia r0!, {r3 - r4} | ||
353 | tst ip, #4 | ||
354 | TUSER( ldrne) r3, [r1], #4 @ Shouldnt fault | ||
355 | strne r3, [r0], #4 | ||
356 | ands ip, ip, #3 | ||
357 | beq .Lcfu_0fupi | ||
358 | .Lcfu_0nowords: teq ip, #0 | ||
359 | beq .Lcfu_finished | ||
360 | .Lcfu_nowords: cmp ip, #2 | ||
361 | USER( TUSER( ldrb) r3, [r1], #1) @ May fault | ||
362 | strb r3, [r0], #1 | ||
363 | USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault | ||
364 | strgeb r3, [r0], #1 | ||
365 | USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault | ||
366 | strgtb r3, [r0], #1 | ||
367 | b .Lcfu_finished | ||
368 | |||
369 | .Lcfu_not_enough: | ||
370 | movs ip, r2 | ||
371 | bne .Lcfu_nowords | ||
372 | .Lcfu_finished: mov r0, #0 | ||
373 | add sp, sp, #8 | ||
374 | ldmfd sp!, {r4 - r7, pc} | ||
375 | |||
376 | .Lcfu_src_not_aligned: | ||
377 | bic r1, r1, #3 | ||
378 | USER( TUSER( ldr) r7, [r1], #4) @ May fault | ||
379 | cmp ip, #2 | ||
380 | bgt .Lcfu_3fupi | ||
381 | beq .Lcfu_2fupi | ||
382 | .Lcfu_1fupi: subs r2, r2, #4 | ||
383 | addmi ip, r2, #4 | ||
384 | bmi .Lcfu_1nowords | ||
385 | mov r3, r7, lspull #8 | ||
386 | USER( TUSER( ldr) r7, [r1], #4) @ May fault | ||
387 | orr r3, r3, r7, lspush #24 | ||
388 | str r3, [r0], #4 | ||
389 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
390 | rsb ip, ip, #0 | ||
391 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
392 | beq .Lcfu_1fupi | ||
393 | cmp r2, ip | ||
394 | movlt ip, r2 | ||
395 | sub r2, r2, ip | ||
396 | subs ip, ip, #16 | ||
397 | blt .Lcfu_1rem8lp | ||
398 | |||
399 | .Lcfu_1cpy8lp: mov r3, r7, lspull #8 | ||
400 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
401 | subs ip, ip, #16 | ||
402 | orr r3, r3, r4, lspush #24 | ||
403 | mov r4, r4, lspull #8 | ||
404 | orr r4, r4, r5, lspush #24 | ||
405 | mov r5, r5, lspull #8 | ||
406 | orr r5, r5, r6, lspush #24 | ||
407 | mov r6, r6, lspull #8 | ||
408 | orr r6, r6, r7, lspush #24 | ||
409 | stmia r0!, {r3 - r6} | ||
410 | bpl .Lcfu_1cpy8lp | ||
411 | |||
412 | .Lcfu_1rem8lp: tst ip, #8 | ||
413 | movne r3, r7, lspull #8 | ||
414 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
415 | orrne r3, r3, r4, lspush #24 | ||
416 | movne r4, r4, lspull #8 | ||
417 | orrne r4, r4, r7, lspush #24 | ||
418 | stmneia r0!, {r3 - r4} | ||
419 | tst ip, #4 | ||
420 | movne r3, r7, lspull #8 | ||
421 | USER( TUSER( ldrne) r7, [r1], #4) @ May fault | ||
422 | orrne r3, r3, r7, lspush #24 | ||
423 | strne r3, [r0], #4 | ||
424 | ands ip, ip, #3 | ||
425 | beq .Lcfu_1fupi | ||
426 | .Lcfu_1nowords: mov r3, r7, get_byte_1 | ||
427 | teq ip, #0 | ||
428 | beq .Lcfu_finished | ||
429 | cmp ip, #2 | ||
430 | strb r3, [r0], #1 | ||
431 | movge r3, r7, get_byte_2 | ||
432 | strgeb r3, [r0], #1 | ||
433 | movgt r3, r7, get_byte_3 | ||
434 | strgtb r3, [r0], #1 | ||
435 | b .Lcfu_finished | ||
436 | |||
437 | .Lcfu_2fupi: subs r2, r2, #4 | ||
438 | addmi ip, r2, #4 | ||
439 | bmi .Lcfu_2nowords | ||
440 | mov r3, r7, lspull #16 | ||
441 | USER( TUSER( ldr) r7, [r1], #4) @ May fault | ||
442 | orr r3, r3, r7, lspush #16 | ||
443 | str r3, [r0], #4 | ||
444 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
445 | rsb ip, ip, #0 | ||
446 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
447 | beq .Lcfu_2fupi | ||
448 | cmp r2, ip | ||
449 | movlt ip, r2 | ||
450 | sub r2, r2, ip | ||
451 | subs ip, ip, #16 | ||
452 | blt .Lcfu_2rem8lp | ||
453 | |||
454 | |||
455 | .Lcfu_2cpy8lp: mov r3, r7, lspull #16 | ||
456 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
457 | subs ip, ip, #16 | ||
458 | orr r3, r3, r4, lspush #16 | ||
459 | mov r4, r4, lspull #16 | ||
460 | orr r4, r4, r5, lspush #16 | ||
461 | mov r5, r5, lspull #16 | ||
462 | orr r5, r5, r6, lspush #16 | ||
463 | mov r6, r6, lspull #16 | ||
464 | orr r6, r6, r7, lspush #16 | ||
465 | stmia r0!, {r3 - r6} | ||
466 | bpl .Lcfu_2cpy8lp | ||
467 | |||
468 | .Lcfu_2rem8lp: tst ip, #8 | ||
469 | movne r3, r7, lspull #16 | ||
470 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
471 | orrne r3, r3, r4, lspush #16 | ||
472 | movne r4, r4, lspull #16 | ||
473 | orrne r4, r4, r7, lspush #16 | ||
474 | stmneia r0!, {r3 - r4} | ||
475 | tst ip, #4 | ||
476 | movne r3, r7, lspull #16 | ||
477 | USER( TUSER( ldrne) r7, [r1], #4) @ May fault | ||
478 | orrne r3, r3, r7, lspush #16 | ||
479 | strne r3, [r0], #4 | ||
480 | ands ip, ip, #3 | ||
481 | beq .Lcfu_2fupi | ||
482 | .Lcfu_2nowords: mov r3, r7, get_byte_2 | ||
483 | teq ip, #0 | ||
484 | beq .Lcfu_finished | ||
485 | cmp ip, #2 | ||
486 | strb r3, [r0], #1 | ||
487 | movge r3, r7, get_byte_3 | ||
488 | strgeb r3, [r0], #1 | ||
489 | USER( TUSER( ldrgtb) r3, [r1], #0) @ May fault | ||
490 | strgtb r3, [r0], #1 | ||
491 | b .Lcfu_finished | ||
492 | |||
493 | .Lcfu_3fupi: subs r2, r2, #4 | ||
494 | addmi ip, r2, #4 | ||
495 | bmi .Lcfu_3nowords | ||
496 | mov r3, r7, lspull #24 | ||
497 | USER( TUSER( ldr) r7, [r1], #4) @ May fault | ||
498 | orr r3, r3, r7, lspush #8 | ||
499 | str r3, [r0], #4 | ||
500 | mov ip, r1, lsl #32 - PAGE_SHIFT | ||
501 | rsb ip, ip, #0 | ||
502 | movs ip, ip, lsr #32 - PAGE_SHIFT | ||
503 | beq .Lcfu_3fupi | ||
504 | cmp r2, ip | ||
505 | movlt ip, r2 | ||
506 | sub r2, r2, ip | ||
507 | subs ip, ip, #16 | ||
508 | blt .Lcfu_3rem8lp | ||
509 | |||
510 | .Lcfu_3cpy8lp: mov r3, r7, lspull #24 | ||
511 | ldmia r1!, {r4 - r7} @ Shouldnt fault | ||
512 | orr r3, r3, r4, lspush #8 | ||
513 | mov r4, r4, lspull #24 | ||
514 | orr r4, r4, r5, lspush #8 | ||
515 | mov r5, r5, lspull #24 | ||
516 | orr r5, r5, r6, lspush #8 | ||
517 | mov r6, r6, lspull #24 | ||
518 | orr r6, r6, r7, lspush #8 | ||
519 | stmia r0!, {r3 - r6} | ||
520 | subs ip, ip, #16 | ||
521 | bpl .Lcfu_3cpy8lp | ||
522 | |||
523 | .Lcfu_3rem8lp: tst ip, #8 | ||
524 | movne r3, r7, lspull #24 | ||
525 | ldmneia r1!, {r4, r7} @ Shouldnt fault | ||
526 | orrne r3, r3, r4, lspush #8 | ||
527 | movne r4, r4, lspull #24 | ||
528 | orrne r4, r4, r7, lspush #8 | ||
529 | stmneia r0!, {r3 - r4} | ||
530 | tst ip, #4 | ||
531 | movne r3, r7, lspull #24 | ||
532 | USER( TUSER( ldrne) r7, [r1], #4) @ May fault | ||
533 | orrne r3, r3, r7, lspush #8 | ||
534 | strne r3, [r0], #4 | ||
535 | ands ip, ip, #3 | ||
536 | beq .Lcfu_3fupi | ||
537 | .Lcfu_3nowords: mov r3, r7, get_byte_3 | ||
538 | teq ip, #0 | ||
539 | beq .Lcfu_finished | ||
540 | cmp ip, #2 | ||
541 | strb r3, [r0], #1 | ||
542 | USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault | ||
543 | strgeb r3, [r0], #1 | ||
544 | USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault | ||
545 | strgtb r3, [r0], #1 | ||
546 | b .Lcfu_finished | ||
547 | ENDPROC(__copy_from_user) | ||
548 | |||
549 | .pushsection .fixup,"ax" | ||
550 | .align 0 | ||
551 | /* | ||
552 | * We took an exception. r0 contains a pointer to | ||
553 | * the byte not copied. | ||
554 | */ | ||
555 | 9001: ldr r2, [sp], #4 @ void *to | ||
556 | sub r2, r0, r2 @ bytes copied | ||
557 | ldr r1, [sp], #4 @ unsigned long count | ||
558 | subs r4, r1, r2 @ bytes left to copy | ||
559 | movne r1, r4 | ||
560 | blne __memzero | ||
561 | mov r0, r4 | ||
562 | ldmfd sp!, {r4 - r7, pc} | ||
563 | .popsection | ||
564 | |||
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index 766f57d2f029..4791a3cc00f9 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <asm/cacheflush.h> | 17 | #include <asm/cacheflush.h> |
18 | #include <asm/cputype.h> | 18 | #include <asm/cputype.h> |
19 | #include <asm/firmware.h> | 19 | #include <asm/firmware.h> |
20 | #include <asm/hardware/cache-l2x0.h> | ||
20 | #include <asm/suspend.h> | 21 | #include <asm/suspend.h> |
21 | 22 | ||
22 | #include <mach/map.h> | 23 | #include <mach/map.h> |
@@ -136,6 +137,43 @@ static const struct firmware_ops exynos_firmware_ops = { | |||
136 | .resume = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL, | 137 | .resume = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL, |
137 | }; | 138 | }; |
138 | 139 | ||
140 | static void exynos_l2_write_sec(unsigned long val, unsigned reg) | ||
141 | { | ||
142 | static int l2cache_enabled; | ||
143 | |||
144 | switch (reg) { | ||
145 | case L2X0_CTRL: | ||
146 | if (val & L2X0_CTRL_EN) { | ||
147 | /* | ||
148 | * Before the cache can be enabled, due to firmware | ||
149 | * design, SMC_CMD_L2X0INVALL must be called. | ||
150 | */ | ||
151 | if (!l2cache_enabled) { | ||
152 | exynos_smc(SMC_CMD_L2X0INVALL, 0, 0, 0); | ||
153 | l2cache_enabled = 1; | ||
154 | } | ||
155 | } else { | ||
156 | l2cache_enabled = 0; | ||
157 | } | ||
158 | exynos_smc(SMC_CMD_L2X0CTRL, val, 0, 0); | ||
159 | break; | ||
160 | |||
161 | case L2X0_DEBUG_CTRL: | ||
162 | exynos_smc(SMC_CMD_L2X0DEBUG, val, 0, 0); | ||
163 | break; | ||
164 | |||
165 | default: | ||
166 | WARN_ONCE(1, "%s: ignoring write to reg 0x%x\n", __func__, reg); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | static void exynos_l2_configure(const struct l2x0_regs *regs) | ||
171 | { | ||
172 | exynos_smc(SMC_CMD_L2X0SETUP1, regs->tag_latency, regs->data_latency, | ||
173 | regs->prefetch_ctrl); | ||
174 | exynos_smc(SMC_CMD_L2X0SETUP2, regs->pwr_ctrl, regs->aux_ctrl, 0); | ||
175 | } | ||
176 | |||
139 | void __init exynos_firmware_init(void) | 177 | void __init exynos_firmware_init(void) |
140 | { | 178 | { |
141 | struct device_node *nd; | 179 | struct device_node *nd; |
@@ -155,4 +193,16 @@ void __init exynos_firmware_init(void) | |||
155 | pr_info("Running under secure firmware.\n"); | 193 | pr_info("Running under secure firmware.\n"); |
156 | 194 | ||
157 | register_firmware_ops(&exynos_firmware_ops); | 195 | register_firmware_ops(&exynos_firmware_ops); |
196 | |||
197 | /* | ||
198 | * Exynos 4 SoCs (based on Cortex A9 and equipped with L2C-310), | ||
199 | * running under secure firmware, require certain registers of L2 | ||
200 | * cache controller to be written in secure mode. Here .write_sec | ||
201 | * callback is provided to perform necessary SMC calls. | ||
202 | */ | ||
203 | if (IS_ENABLED(CONFIG_CACHE_L2X0) && | ||
204 | read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { | ||
205 | outer_cache.write_sec = exynos_l2_write_sec; | ||
206 | outer_cache.configure = exynos_l2_configure; | ||
207 | } | ||
158 | } | 208 | } |
diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S index e3c373082bbe..31d25834b9c4 100644 --- a/arch/arm/mach-exynos/sleep.S +++ b/arch/arm/mach-exynos/sleep.S | |||
@@ -16,6 +16,8 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/linkage.h> | 18 | #include <linux/linkage.h> |
19 | #include <asm/asm-offsets.h> | ||
20 | #include <asm/hardware/cache-l2x0.h> | ||
19 | #include "smc.h" | 21 | #include "smc.h" |
20 | 22 | ||
21 | #define CPU_MASK 0xff0ffff0 | 23 | #define CPU_MASK 0xff0ffff0 |
@@ -74,6 +76,45 @@ ENTRY(exynos_cpu_resume_ns) | |||
74 | mov r0, #SMC_CMD_C15RESUME | 76 | mov r0, #SMC_CMD_C15RESUME |
75 | dsb | 77 | dsb |
76 | smc #0 | 78 | smc #0 |
79 | #ifdef CONFIG_CACHE_L2X0 | ||
80 | adr r0, 1f | ||
81 | ldr r2, [r0] | ||
82 | add r0, r2, r0 | ||
83 | |||
84 | /* Check that the address has been initialised. */ | ||
85 | ldr r1, [r0, #L2X0_R_PHY_BASE] | ||
86 | teq r1, #0 | ||
87 | beq skip_l2x0 | ||
88 | |||
89 | /* Check if controller has been enabled. */ | ||
90 | ldr r2, [r1, #L2X0_CTRL] | ||
91 | tst r2, #0x1 | ||
92 | bne skip_l2x0 | ||
93 | |||
94 | ldr r1, [r0, #L2X0_R_TAG_LATENCY] | ||
95 | ldr r2, [r0, #L2X0_R_DATA_LATENCY] | ||
96 | ldr r3, [r0, #L2X0_R_PREFETCH_CTRL] | ||
97 | mov r0, #SMC_CMD_L2X0SETUP1 | ||
98 | smc #0 | ||
99 | |||
100 | /* Reload saved regs pointer because smc corrupts registers. */ | ||
101 | adr r0, 1f | ||
102 | ldr r2, [r0] | ||
103 | add r0, r2, r0 | ||
104 | |||
105 | ldr r1, [r0, #L2X0_R_PWR_CTRL] | ||
106 | ldr r2, [r0, #L2X0_R_AUX_CTRL] | ||
107 | mov r0, #SMC_CMD_L2X0SETUP2 | ||
108 | smc #0 | ||
109 | |||
110 | mov r0, #SMC_CMD_L2X0INVALL | ||
111 | smc #0 | ||
112 | |||
113 | mov r1, #1 | ||
114 | mov r0, #SMC_CMD_L2X0CTRL | ||
115 | smc #0 | ||
116 | skip_l2x0: | ||
117 | #endif /* CONFIG_CACHE_L2X0 */ | ||
77 | skip_cp15: | 118 | skip_cp15: |
78 | b cpu_resume | 119 | b cpu_resume |
79 | ENDPROC(exynos_cpu_resume_ns) | 120 | ENDPROC(exynos_cpu_resume_ns) |
@@ -83,3 +124,8 @@ cp15_save_diag: | |||
83 | .globl cp15_save_power | 124 | .globl cp15_save_power |
84 | cp15_save_power: | 125 | cp15_save_power: |
85 | .long 0 @ cp15 power control | 126 | .long 0 @ cp15 power control |
127 | |||
128 | #ifdef CONFIG_CACHE_L2X0 | ||
129 | .align | ||
130 | 1: .long l2x0_saved_regs - . | ||
131 | #endif /* CONFIG_CACHE_L2X0 */ | ||
diff --git a/arch/arm/mach-omap1/include/mach/debug-macro.S b/arch/arm/mach-omap1/include/mach/debug-macro.S deleted file mode 100644 index 5c1a26c9f490..000000000000 --- a/arch/arm/mach-omap1/include/mach/debug-macro.S +++ /dev/null | |||
@@ -1,101 +0,0 @@ | |||
1 | /* arch/arm/mach-omap1/include/mach/debug-macro.S | ||
2 | * | ||
3 | * Debugging macro include header | ||
4 | * | ||
5 | * Copyright (C) 1994-1999 Russell King | ||
6 | * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/serial_reg.h> | ||
15 | |||
16 | #include "serial.h" | ||
17 | |||
18 | .pushsection .data | ||
19 | omap_uart_phys: .word 0x0 | ||
20 | omap_uart_virt: .word 0x0 | ||
21 | .popsection | ||
22 | |||
23 | /* | ||
24 | * Note that this code won't work if the bootloader passes | ||
25 | * a wrong machine ID number in r1. To debug, just hardcode | ||
26 | * the desired UART phys and virt addresses temporarily into | ||
27 | * the omap_uart_phys and omap_uart_virt above. | ||
28 | */ | ||
29 | .macro addruart, rp, rv, tmp | ||
30 | |||
31 | /* Use omap_uart_phys/virt if already configured */ | ||
32 | 9: adr \rp, 99f @ get effective addr of 99f | ||
33 | ldr \rv, [\rp] @ get absolute addr of 99f | ||
34 | sub \rv, \rv, \rp @ offset between the two | ||
35 | ldr \rp, [\rp, #4] @ abs addr of omap_uart_phys | ||
36 | sub \tmp, \rp, \rv @ make it effective | ||
37 | ldr \rp, [\tmp, #0] @ omap_uart_phys | ||
38 | ldr \rv, [\tmp, #4] @ omap_uart_virt | ||
39 | cmp \rp, #0 @ is port configured? | ||
40 | cmpne \rv, #0 | ||
41 | bne 100f @ already configured | ||
42 | |||
43 | /* Check the debug UART configuration set in uncompress.h */ | ||
44 | and \rp, pc, #0xff000000 | ||
45 | ldr \rv, =OMAP_UART_INFO_OFS | ||
46 | ldr \rp, [\rp, \rv] | ||
47 | |||
48 | /* Select the UART to use based on the UART1 scratchpad value */ | ||
49 | 10: cmp \rp, #0 @ no port configured? | ||
50 | beq 11f @ if none, try to use UART1 | ||
51 | cmp \rp, #OMAP1UART1 | ||
52 | beq 11f @ configure OMAP1UART1 | ||
53 | cmp \rp, #OMAP1UART2 | ||
54 | beq 12f @ configure OMAP1UART2 | ||
55 | cmp \rp, #OMAP1UART3 | ||
56 | beq 13f @ configure OMAP2UART3 | ||
57 | |||
58 | /* Configure the UART offset from the phys/virt base */ | ||
59 | 11: mov \rp, #0x00fb0000 @ OMAP1UART1 | ||
60 | b 98f | ||
61 | 12: mov \rp, #0x00fb0000 @ OMAP1UART1 | ||
62 | orr \rp, \rp, #0x00000800 @ OMAP1UART2 | ||
63 | b 98f | ||
64 | 13: mov \rp, #0x00fb0000 @ OMAP1UART1 | ||
65 | orr \rp, \rp, #0x00000800 @ OMAP1UART2 | ||
66 | orr \rp, \rp, #0x00009000 @ OMAP1UART3 | ||
67 | |||
68 | /* Store both phys and virt address for the uart */ | ||
69 | 98: add \rp, \rp, #0xff000000 @ phys base | ||
70 | str \rp, [\tmp, #0] @ omap_uart_phys | ||
71 | sub \rp, \rp, #0xff000000 @ phys base | ||
72 | add \rp, \rp, #0xfe000000 @ virt base | ||
73 | str \rp, [\tmp, #4] @ omap_uart_virt | ||
74 | b 9b | ||
75 | |||
76 | .align | ||
77 | 99: .word . | ||
78 | .word omap_uart_phys | ||
79 | .ltorg | ||
80 | |||
81 | 100: | ||
82 | .endm | ||
83 | |||
84 | .macro senduart,rd,rx | ||
85 | strb \rd, [\rx] | ||
86 | .endm | ||
87 | |||
88 | .macro busyuart,rd,rx | ||
89 | 1001: ldrb \rd, [\rx, #(UART_LSR << OMAP_PORT_SHIFT)] | ||
90 | and \rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE) | ||
91 | teq \rd, #(UART_LSR_TEMT | UART_LSR_THRE) | ||
92 | beq 1002f | ||
93 | ldrb \rd, [\rx, #(UART_LSR << OMAP7XX_PORT_SHIFT)] | ||
94 | and \rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE) | ||
95 | teq \rd, #(UART_LSR_TEMT | UART_LSR_THRE) | ||
96 | bne 1001b | ||
97 | 1002: | ||
98 | .endm | ||
99 | |||
100 | .macro waituart,rd,rx | ||
101 | .endm | ||
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index b61c049f92d6..42b7f4c9169b 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c | |||
@@ -189,6 +189,9 @@ static const char *const omap4_boards_compat[] __initconst = { | |||
189 | }; | 189 | }; |
190 | 190 | ||
191 | DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)") | 191 | DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)") |
192 | .l2c_aux_val = OMAP_L2C_AUX_CTRL, | ||
193 | .l2c_aux_mask = 0xcf9fffff, | ||
194 | .l2c_write_sec = omap4_l2c310_write_sec, | ||
192 | .reserve = omap_reserve, | 195 | .reserve = omap_reserve, |
193 | .smp = smp_ops(omap4_smp_ops), | 196 | .smp = smp_ops(omap4_smp_ops), |
194 | .map_io = omap4_map_io, | 197 | .map_io = omap4_map_io, |
@@ -232,6 +235,9 @@ static const char *const am43_boards_compat[] __initconst = { | |||
232 | }; | 235 | }; |
233 | 236 | ||
234 | DT_MACHINE_START(AM43_DT, "Generic AM43 (Flattened Device Tree)") | 237 | DT_MACHINE_START(AM43_DT, "Generic AM43 (Flattened Device Tree)") |
238 | .l2c_aux_val = OMAP_L2C_AUX_CTRL, | ||
239 | .l2c_aux_mask = 0xcf9fffff, | ||
240 | .l2c_write_sec = omap4_l2c310_write_sec, | ||
235 | .map_io = am33xx_map_io, | 241 | .map_io = am33xx_map_io, |
236 | .init_early = am43xx_init_early, | 242 | .init_early = am43xx_init_early, |
237 | .init_late = am43xx_init_late, | 243 | .init_late = am43xx_init_late, |
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index 64e44d6d07c0..3933b8aa4f01 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/irqchip/irq-omap-intc.h> | 35 | #include <linux/irqchip/irq-omap-intc.h> |
36 | 36 | ||
37 | #include <asm/proc-fns.h> | 37 | #include <asm/proc-fns.h> |
38 | #include <asm/hardware/cache-l2x0.h> | ||
38 | 39 | ||
39 | #include "i2c.h" | 40 | #include "i2c.h" |
40 | #include "serial.h" | 41 | #include "serial.h" |
@@ -94,11 +95,18 @@ extern void omap3_gptimer_timer_init(void); | |||
94 | extern void omap4_local_timer_init(void); | 95 | extern void omap4_local_timer_init(void); |
95 | #ifdef CONFIG_CACHE_L2X0 | 96 | #ifdef CONFIG_CACHE_L2X0 |
96 | int omap_l2_cache_init(void); | 97 | int omap_l2_cache_init(void); |
98 | #define OMAP_L2C_AUX_CTRL (L2C_AUX_CTRL_SHARED_OVERRIDE | \ | ||
99 | L310_AUX_CTRL_DATA_PREFETCH | \ | ||
100 | L310_AUX_CTRL_INSTR_PREFETCH) | ||
101 | void omap4_l2c310_write_sec(unsigned long val, unsigned reg); | ||
97 | #else | 102 | #else |
98 | static inline int omap_l2_cache_init(void) | 103 | static inline int omap_l2_cache_init(void) |
99 | { | 104 | { |
100 | return 0; | 105 | return 0; |
101 | } | 106 | } |
107 | |||
108 | #define OMAP_L2C_AUX_CTRL 0 | ||
109 | #define omap4_l2c310_write_sec NULL | ||
102 | #endif | 110 | #endif |
103 | extern void omap5_realtime_timer_init(void); | 111 | extern void omap5_realtime_timer_init(void); |
104 | 112 | ||
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index cc30e49a4cc2..2418bdf28ca2 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c | |||
@@ -166,7 +166,7 @@ void __iomem *omap4_get_l2cache_base(void) | |||
166 | return l2cache_base; | 166 | return l2cache_base; |
167 | } | 167 | } |
168 | 168 | ||
169 | static void omap4_l2c310_write_sec(unsigned long val, unsigned reg) | 169 | void omap4_l2c310_write_sec(unsigned long val, unsigned reg) |
170 | { | 170 | { |
171 | unsigned smc_op; | 171 | unsigned smc_op; |
172 | 172 | ||
@@ -201,24 +201,10 @@ static void omap4_l2c310_write_sec(unsigned long val, unsigned reg) | |||
201 | 201 | ||
202 | int __init omap_l2_cache_init(void) | 202 | int __init omap_l2_cache_init(void) |
203 | { | 203 | { |
204 | u32 aux_ctrl; | ||
205 | |||
206 | /* Static mapping, never released */ | 204 | /* Static mapping, never released */ |
207 | l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K); | 205 | l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K); |
208 | if (WARN_ON(!l2cache_base)) | 206 | if (WARN_ON(!l2cache_base)) |
209 | return -ENOMEM; | 207 | return -ENOMEM; |
210 | |||
211 | /* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */ | ||
212 | aux_ctrl = L2C_AUX_CTRL_SHARED_OVERRIDE | | ||
213 | L310_AUX_CTRL_DATA_PREFETCH | | ||
214 | L310_AUX_CTRL_INSTR_PREFETCH; | ||
215 | |||
216 | outer_cache.write_sec = omap4_l2c310_write_sec; | ||
217 | if (of_have_populated_dt()) | ||
218 | l2x0_of_init(aux_ctrl, 0xcf9fffff); | ||
219 | else | ||
220 | l2x0_init(l2cache_base, aux_ctrl, 0xcf9fffff); | ||
221 | |||
222 | return 0; | 208 | return 0; |
223 | } | 209 | } |
224 | #endif | 210 | #endif |
diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c index d6908569ecaf..09cffed4c0a4 100644 --- a/arch/arm/mach-qcom/platsmp.c +++ b/arch/arm/mach-qcom/platsmp.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #define APCS_SAW2_VCTL 0x14 | 44 | #define APCS_SAW2_VCTL 0x14 |
45 | #define APCS_SAW2_2_VCTL 0x1c | 45 | #define APCS_SAW2_2_VCTL 0x1c |
46 | 46 | ||
47 | extern void secondary_startup(void); | 47 | extern void secondary_startup_arm(void); |
48 | 48 | ||
49 | static DEFINE_SPINLOCK(boot_lock); | 49 | static DEFINE_SPINLOCK(boot_lock); |
50 | 50 | ||
@@ -337,7 +337,7 @@ static void __init qcom_smp_prepare_cpus(unsigned int max_cpus) | |||
337 | flags |= cold_boot_flags[map]; | 337 | flags |= cold_boot_flags[map]; |
338 | } | 338 | } |
339 | 339 | ||
340 | if (scm_set_boot_addr(virt_to_phys(secondary_startup), flags)) { | 340 | if (scm_set_boot_addr(virt_to_phys(secondary_startup_arm), flags)) { |
341 | for_each_present_cpu(cpu) { | 341 | for_each_present_cpu(cpu) { |
342 | if (cpu == smp_processor_id()) | 342 | if (cpu == smp_processor_id()) |
343 | continue; | 343 | continue; |
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index f1114d11fe13..61ff91e76e0a 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # Common support | 5 | # Common support |
6 | obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o | 6 | obj-y := clock.o generic.o irq.o #nmi-oopser.o |
7 | 7 | ||
8 | # Specific board support | 8 | # Specific board support |
9 | obj-$(CONFIG_SA1100_ASSABET) += assabet.o | 9 | obj-$(CONFIG_SA1100_ASSABET) += assabet.o |
diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c index 03c75a811cb0..cbf53bb9c814 100644 --- a/arch/arm/mach-sa1100/clock.c +++ b/arch/arm/mach-sa1100/clock.c | |||
@@ -119,6 +119,17 @@ static DEFINE_CLK(gpio27, &clk_gpio27_ops); | |||
119 | 119 | ||
120 | static DEFINE_CLK(cpu, &clk_cpu_ops); | 120 | static DEFINE_CLK(cpu, &clk_cpu_ops); |
121 | 121 | ||
122 | static unsigned long clk_36864_get_rate(struct clk *clk) | ||
123 | { | ||
124 | return 3686400; | ||
125 | } | ||
126 | |||
127 | static struct clkops clk_36864_ops = { | ||
128 | .get_rate = clk_36864_get_rate, | ||
129 | }; | ||
130 | |||
131 | static DEFINE_CLK(36864, &clk_36864_ops); | ||
132 | |||
122 | static struct clk_lookup sa11xx_clkregs[] = { | 133 | static struct clk_lookup sa11xx_clkregs[] = { |
123 | CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27), | 134 | CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27), |
124 | CLKDEV_INIT("sa1100-rtc", NULL, NULL), | 135 | CLKDEV_INIT("sa1100-rtc", NULL, NULL), |
@@ -126,6 +137,7 @@ static struct clk_lookup sa11xx_clkregs[] = { | |||
126 | CLKDEV_INIT("sa11x0-pcmcia", NULL, &clk_cpu), | 137 | CLKDEV_INIT("sa11x0-pcmcia", NULL, &clk_cpu), |
127 | /* sa1111 names devices using internal offsets, PCMCIA is at 0x1800 */ | 138 | /* sa1111 names devices using internal offsets, PCMCIA is at 0x1800 */ |
128 | CLKDEV_INIT("1800", NULL, &clk_cpu), | 139 | CLKDEV_INIT("1800", NULL, &clk_cpu), |
140 | CLKDEV_INIT(NULL, "OSTIMER0", &clk_36864), | ||
129 | }; | 141 | }; |
130 | 142 | ||
131 | static int __init sa11xx_clk_init(void) | 143 | static int __init sa11xx_clk_init(void) |
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 7fcbe3d119c7..3cc2b71e16f0 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c | |||
@@ -371,8 +371,7 @@ static void __init collie_init(void) | |||
371 | PPC_LDD6 | PPC_LDD7 | PPC_L_PCLK | PPC_L_LCLK | PPC_L_FCLK | PPC_L_BIAS | | 371 | PPC_LDD6 | PPC_LDD7 | PPC_L_PCLK | PPC_L_LCLK | PPC_L_FCLK | PPC_L_BIAS | |
372 | PPC_TXD1 | PPC_TXD2 | PPC_TXD3 | PPC_TXD4 | PPC_SCLK | PPC_SFRM; | 372 | PPC_TXD1 | PPC_TXD2 | PPC_TXD3 | PPC_TXD4 | PPC_SCLK | PPC_SFRM; |
373 | 373 | ||
374 | PWER = _COLLIE_GPIO_AC_IN | _COLLIE_GPIO_CO | _COLLIE_GPIO_ON_KEY | | 374 | PWER = 0; |
375 | _COLLIE_GPIO_WAKEUP | _COLLIE_GPIO_nREMOCON_INT | PWER_RTC; | ||
376 | 375 | ||
377 | PGSR = _COLLIE_GPIO_nREMOCON_ON; | 376 | PGSR = _COLLIE_GPIO_nREMOCON_ON; |
378 | 377 | ||
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index d4ea142c4edd..40e0d8619a2d 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <mach/irqs.h> | 33 | #include <mach/irqs.h> |
34 | 34 | ||
35 | #include "generic.h" | 35 | #include "generic.h" |
36 | #include <clocksource/pxa.h> | ||
36 | 37 | ||
37 | unsigned int reset_status; | 38 | unsigned int reset_status; |
38 | EXPORT_SYMBOL(reset_status); | 39 | EXPORT_SYMBOL(reset_status); |
@@ -369,6 +370,11 @@ void __init sa1100_map_io(void) | |||
369 | iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); | 370 | iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); |
370 | } | 371 | } |
371 | 372 | ||
373 | void __init sa1100_timer_init(void) | ||
374 | { | ||
375 | pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x90000000), 3686400); | ||
376 | } | ||
377 | |||
372 | /* | 378 | /* |
373 | * Disable the memory bus request/grant signals on the SA1110 to | 379 | * Disable the memory bus request/grant signals on the SA1110 to |
374 | * ensure that we don't receive spurious memory requests. We set | 380 | * ensure that we don't receive spurious memory requests. We set |
diff --git a/arch/arm/mach-sa1100/include/mach/irqs.h b/arch/arm/mach-sa1100/include/mach/irqs.h index de0983494c7e..734e30e406a3 100644 --- a/arch/arm/mach-sa1100/include/mach/irqs.h +++ b/arch/arm/mach-sa1100/include/mach/irqs.h | |||
@@ -8,17 +8,17 @@ | |||
8 | * 2001/11/14 RMK Cleaned up and standardised a lot of the IRQs. | 8 | * 2001/11/14 RMK Cleaned up and standardised a lot of the IRQs. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #define IRQ_GPIO0 1 | 11 | #define IRQ_GPIO0_SC 1 |
12 | #define IRQ_GPIO1 2 | 12 | #define IRQ_GPIO1_SC 2 |
13 | #define IRQ_GPIO2 3 | 13 | #define IRQ_GPIO2_SC 3 |
14 | #define IRQ_GPIO3 4 | 14 | #define IRQ_GPIO3_SC 4 |
15 | #define IRQ_GPIO4 5 | 15 | #define IRQ_GPIO4_SC 5 |
16 | #define IRQ_GPIO5 6 | 16 | #define IRQ_GPIO5_SC 6 |
17 | #define IRQ_GPIO6 7 | 17 | #define IRQ_GPIO6_SC 7 |
18 | #define IRQ_GPIO7 8 | 18 | #define IRQ_GPIO7_SC 8 |
19 | #define IRQ_GPIO8 9 | 19 | #define IRQ_GPIO8_SC 9 |
20 | #define IRQ_GPIO9 10 | 20 | #define IRQ_GPIO9_SC 10 |
21 | #define IRQ_GPIO10 11 | 21 | #define IRQ_GPIO10_SC 11 |
22 | #define IRQ_GPIO11_27 12 | 22 | #define IRQ_GPIO11_27 12 |
23 | #define IRQ_LCD 13 /* LCD controller */ | 23 | #define IRQ_LCD 13 /* LCD controller */ |
24 | #define IRQ_Ser0UDC 14 /* Ser. port 0 UDC */ | 24 | #define IRQ_Ser0UDC 14 /* Ser. port 0 UDC */ |
@@ -41,32 +41,43 @@ | |||
41 | #define IRQ_RTC1Hz 31 /* RTC 1 Hz clock */ | 41 | #define IRQ_RTC1Hz 31 /* RTC 1 Hz clock */ |
42 | #define IRQ_RTCAlrm 32 /* RTC Alarm */ | 42 | #define IRQ_RTCAlrm 32 /* RTC Alarm */ |
43 | 43 | ||
44 | #define IRQ_GPIO11 33 | 44 | #define IRQ_GPIO0 33 |
45 | #define IRQ_GPIO12 34 | 45 | #define IRQ_GPIO1 34 |
46 | #define IRQ_GPIO13 35 | 46 | #define IRQ_GPIO2 35 |
47 | #define IRQ_GPIO14 36 | 47 | #define IRQ_GPIO3 36 |
48 | #define IRQ_GPIO15 37 | 48 | #define IRQ_GPIO4 37 |
49 | #define IRQ_GPIO16 38 | 49 | #define IRQ_GPIO5 38 |
50 | #define IRQ_GPIO17 39 | 50 | #define IRQ_GPIO6 39 |
51 | #define IRQ_GPIO18 40 | 51 | #define IRQ_GPIO7 40 |
52 | #define IRQ_GPIO19 41 | 52 | #define IRQ_GPIO8 41 |
53 | #define IRQ_GPIO20 42 | 53 | #define IRQ_GPIO9 42 |
54 | #define IRQ_GPIO21 43 | 54 | #define IRQ_GPIO10 43 |
55 | #define IRQ_GPIO22 44 | 55 | #define IRQ_GPIO11 44 |
56 | #define IRQ_GPIO23 45 | 56 | #define IRQ_GPIO12 45 |
57 | #define IRQ_GPIO24 46 | 57 | #define IRQ_GPIO13 46 |
58 | #define IRQ_GPIO25 47 | 58 | #define IRQ_GPIO14 47 |
59 | #define IRQ_GPIO26 48 | 59 | #define IRQ_GPIO15 48 |
60 | #define IRQ_GPIO27 49 | 60 | #define IRQ_GPIO16 49 |
61 | #define IRQ_GPIO17 50 | ||
62 | #define IRQ_GPIO18 51 | ||
63 | #define IRQ_GPIO19 52 | ||
64 | #define IRQ_GPIO20 53 | ||
65 | #define IRQ_GPIO21 54 | ||
66 | #define IRQ_GPIO22 55 | ||
67 | #define IRQ_GPIO23 56 | ||
68 | #define IRQ_GPIO24 57 | ||
69 | #define IRQ_GPIO25 58 | ||
70 | #define IRQ_GPIO26 59 | ||
71 | #define IRQ_GPIO27 60 | ||
61 | 72 | ||
62 | /* | 73 | /* |
63 | * The next 16 interrupts are for board specific purposes. Since | 74 | * The next 16 interrupts are for board specific purposes. Since |
64 | * the kernel can only run on one machine at a time, we can re-use | 75 | * the kernel can only run on one machine at a time, we can re-use |
65 | * these. If you need more, increase IRQ_BOARD_END, but keep it | 76 | * these. If you need more, increase IRQ_BOARD_END, but keep it |
66 | * within sensible limits. IRQs 49 to 64 are available. | 77 | * within sensible limits. IRQs 61 to 76 are available. |
67 | */ | 78 | */ |
68 | #define IRQ_BOARD_START 50 | 79 | #define IRQ_BOARD_START 61 |
69 | #define IRQ_BOARD_END 66 | 80 | #define IRQ_BOARD_END 77 |
70 | 81 | ||
71 | /* | 82 | /* |
72 | * Figure out the MAX IRQ number. | 83 | * Figure out the MAX IRQ number. |
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c index 63e2901db416..65aebfa66fe5 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/arch/arm/mach-sa1100/irq.c | |||
@@ -80,170 +80,6 @@ static struct irq_domain_ops sa1100_normal_irqdomain_ops = { | |||
80 | 80 | ||
81 | static struct irq_domain *sa1100_normal_irqdomain; | 81 | static struct irq_domain *sa1100_normal_irqdomain; |
82 | 82 | ||
83 | /* | ||
84 | * SA1100 GPIO edge detection for IRQs: | ||
85 | * IRQs are generated on Falling-Edge, Rising-Edge, or both. | ||
86 | * Use this instead of directly setting GRER/GFER. | ||
87 | */ | ||
88 | static int GPIO_IRQ_rising_edge; | ||
89 | static int GPIO_IRQ_falling_edge; | ||
90 | static int GPIO_IRQ_mask = (1 << 11) - 1; | ||
91 | |||
92 | static int sa1100_gpio_type(struct irq_data *d, unsigned int type) | ||
93 | { | ||
94 | unsigned int mask; | ||
95 | |||
96 | mask = BIT(d->hwirq); | ||
97 | |||
98 | if (type == IRQ_TYPE_PROBE) { | ||
99 | if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask) | ||
100 | return 0; | ||
101 | type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | ||
102 | } | ||
103 | |||
104 | if (type & IRQ_TYPE_EDGE_RISING) { | ||
105 | GPIO_IRQ_rising_edge |= mask; | ||
106 | } else | ||
107 | GPIO_IRQ_rising_edge &= ~mask; | ||
108 | if (type & IRQ_TYPE_EDGE_FALLING) { | ||
109 | GPIO_IRQ_falling_edge |= mask; | ||
110 | } else | ||
111 | GPIO_IRQ_falling_edge &= ~mask; | ||
112 | |||
113 | GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; | ||
114 | GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * GPIO IRQs must be acknowledged. | ||
121 | */ | ||
122 | static void sa1100_gpio_ack(struct irq_data *d) | ||
123 | { | ||
124 | GEDR = BIT(d->hwirq); | ||
125 | } | ||
126 | |||
127 | static int sa1100_gpio_wake(struct irq_data *d, unsigned int on) | ||
128 | { | ||
129 | if (on) | ||
130 | PWER |= BIT(d->hwirq); | ||
131 | else | ||
132 | PWER &= ~BIT(d->hwirq); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * This is for IRQs from 0 to 10. | ||
138 | */ | ||
139 | static struct irq_chip sa1100_low_gpio_chip = { | ||
140 | .name = "GPIO-l", | ||
141 | .irq_ack = sa1100_gpio_ack, | ||
142 | .irq_mask = sa1100_mask_irq, | ||
143 | .irq_unmask = sa1100_unmask_irq, | ||
144 | .irq_set_type = sa1100_gpio_type, | ||
145 | .irq_set_wake = sa1100_gpio_wake, | ||
146 | }; | ||
147 | |||
148 | static int sa1100_low_gpio_irqdomain_map(struct irq_domain *d, | ||
149 | unsigned int irq, irq_hw_number_t hwirq) | ||
150 | { | ||
151 | irq_set_chip_and_handler(irq, &sa1100_low_gpio_chip, | ||
152 | handle_edge_irq); | ||
153 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static struct irq_domain_ops sa1100_low_gpio_irqdomain_ops = { | ||
159 | .map = sa1100_low_gpio_irqdomain_map, | ||
160 | .xlate = irq_domain_xlate_onetwocell, | ||
161 | }; | ||
162 | |||
163 | static struct irq_domain *sa1100_low_gpio_irqdomain; | ||
164 | |||
165 | /* | ||
166 | * IRQ11 (GPIO11 through 27) handler. We enter here with the | ||
167 | * irq_controller_lock held, and IRQs disabled. Decode the IRQ | ||
168 | * and call the handler. | ||
169 | */ | ||
170 | static void | ||
171 | sa1100_high_gpio_handler(unsigned int irq, struct irq_desc *desc) | ||
172 | { | ||
173 | unsigned int mask; | ||
174 | |||
175 | mask = GEDR & 0xfffff800; | ||
176 | do { | ||
177 | /* | ||
178 | * clear down all currently active IRQ sources. | ||
179 | * We will be processing them all. | ||
180 | */ | ||
181 | GEDR = mask; | ||
182 | |||
183 | irq = IRQ_GPIO11; | ||
184 | mask >>= 11; | ||
185 | do { | ||
186 | if (mask & 1) | ||
187 | generic_handle_irq(irq); | ||
188 | mask >>= 1; | ||
189 | irq++; | ||
190 | } while (mask); | ||
191 | |||
192 | mask = GEDR & 0xfffff800; | ||
193 | } while (mask); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * Like GPIO0 to 10, GPIO11-27 IRQs need to be handled specially. | ||
198 | * In addition, the IRQs are all collected up into one bit in the | ||
199 | * interrupt controller registers. | ||
200 | */ | ||
201 | static void sa1100_high_gpio_mask(struct irq_data *d) | ||
202 | { | ||
203 | unsigned int mask = BIT(d->hwirq); | ||
204 | |||
205 | GPIO_IRQ_mask &= ~mask; | ||
206 | |||
207 | GRER &= ~mask; | ||
208 | GFER &= ~mask; | ||
209 | } | ||
210 | |||
211 | static void sa1100_high_gpio_unmask(struct irq_data *d) | ||
212 | { | ||
213 | unsigned int mask = BIT(d->hwirq); | ||
214 | |||
215 | GPIO_IRQ_mask |= mask; | ||
216 | |||
217 | GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; | ||
218 | GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; | ||
219 | } | ||
220 | |||
221 | static struct irq_chip sa1100_high_gpio_chip = { | ||
222 | .name = "GPIO-h", | ||
223 | .irq_ack = sa1100_gpio_ack, | ||
224 | .irq_mask = sa1100_high_gpio_mask, | ||
225 | .irq_unmask = sa1100_high_gpio_unmask, | ||
226 | .irq_set_type = sa1100_gpio_type, | ||
227 | .irq_set_wake = sa1100_gpio_wake, | ||
228 | }; | ||
229 | |||
230 | static int sa1100_high_gpio_irqdomain_map(struct irq_domain *d, | ||
231 | unsigned int irq, irq_hw_number_t hwirq) | ||
232 | { | ||
233 | irq_set_chip_and_handler(irq, &sa1100_high_gpio_chip, | ||
234 | handle_edge_irq); | ||
235 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static struct irq_domain_ops sa1100_high_gpio_irqdomain_ops = { | ||
241 | .map = sa1100_high_gpio_irqdomain_map, | ||
242 | .xlate = irq_domain_xlate_onetwocell, | ||
243 | }; | ||
244 | |||
245 | static struct irq_domain *sa1100_high_gpio_irqdomain; | ||
246 | |||
247 | static struct resource irq_resource = | 83 | static struct resource irq_resource = |
248 | DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs"); | 84 | DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs"); |
249 | 85 | ||
@@ -270,17 +106,6 @@ static int sa1100irq_suspend(void) | |||
270 | IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2| | 106 | IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2| |
271 | IC_GPIO1|IC_GPIO0); | 107 | IC_GPIO1|IC_GPIO0); |
272 | 108 | ||
273 | /* | ||
274 | * Set the appropriate edges for wakeup. | ||
275 | */ | ||
276 | GRER = PWER & GPIO_IRQ_rising_edge; | ||
277 | GFER = PWER & GPIO_IRQ_falling_edge; | ||
278 | |||
279 | /* | ||
280 | * Clear any pending GPIO interrupts. | ||
281 | */ | ||
282 | GEDR = GEDR; | ||
283 | |||
284 | return 0; | 109 | return 0; |
285 | } | 110 | } |
286 | 111 | ||
@@ -292,9 +117,6 @@ static void sa1100irq_resume(void) | |||
292 | ICCR = st->iccr; | 117 | ICCR = st->iccr; |
293 | ICLR = st->iclr; | 118 | ICLR = st->iclr; |
294 | 119 | ||
295 | GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; | ||
296 | GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; | ||
297 | |||
298 | ICMR = st->icmr; | 120 | ICMR = st->icmr; |
299 | } | 121 | } |
300 | } | 122 | } |
@@ -325,7 +147,8 @@ sa1100_handle_irq(struct pt_regs *regs) | |||
325 | if (mask == 0) | 147 | if (mask == 0) |
326 | break; | 148 | break; |
327 | 149 | ||
328 | handle_IRQ(ffs(mask) - 1 + IRQ_GPIO0, regs); | 150 | handle_domain_irq(sa1100_normal_irqdomain, |
151 | ffs(mask) - 1, regs); | ||
329 | } while (1); | 152 | } while (1); |
330 | } | 153 | } |
331 | 154 | ||
@@ -339,34 +162,16 @@ void __init sa1100_init_irq(void) | |||
339 | /* all IRQs are IRQ, not FIQ */ | 162 | /* all IRQs are IRQ, not FIQ */ |
340 | ICLR = 0; | 163 | ICLR = 0; |
341 | 164 | ||
342 | /* clear all GPIO edge detects */ | ||
343 | GFER = 0; | ||
344 | GRER = 0; | ||
345 | GEDR = -1; | ||
346 | |||
347 | /* | 165 | /* |
348 | * Whatever the doc says, this has to be set for the wait-on-irq | 166 | * Whatever the doc says, this has to be set for the wait-on-irq |
349 | * instruction to work... on a SA1100 rev 9 at least. | 167 | * instruction to work... on a SA1100 rev 9 at least. |
350 | */ | 168 | */ |
351 | ICCR = 1; | 169 | ICCR = 1; |
352 | 170 | ||
353 | sa1100_low_gpio_irqdomain = irq_domain_add_legacy(NULL, | 171 | sa1100_normal_irqdomain = irq_domain_add_simple(NULL, |
354 | 11, IRQ_GPIO0, 0, | 172 | 32, IRQ_GPIO0_SC, |
355 | &sa1100_low_gpio_irqdomain_ops, NULL); | ||
356 | |||
357 | sa1100_normal_irqdomain = irq_domain_add_legacy(NULL, | ||
358 | 21, IRQ_GPIO11_27, 11, | ||
359 | &sa1100_normal_irqdomain_ops, NULL); | 173 | &sa1100_normal_irqdomain_ops, NULL); |
360 | 174 | ||
361 | sa1100_high_gpio_irqdomain = irq_domain_add_legacy(NULL, | ||
362 | 17, IRQ_GPIO11, 11, | ||
363 | &sa1100_high_gpio_irqdomain_ops, NULL); | ||
364 | |||
365 | /* | ||
366 | * Install handler for GPIO 11-27 edge detect interrupts | ||
367 | */ | ||
368 | irq_set_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler); | ||
369 | |||
370 | set_handle_irq(sa1100_handle_irq); | 175 | set_handle_irq(sa1100_handle_irq); |
371 | 176 | ||
372 | sa1100_init_gpio(); | 177 | sa1100_init_gpio(); |
diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index 6645d1e31f14..34853d5dfda2 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c | |||
@@ -81,6 +81,7 @@ static int sa11x0_pm_enter(suspend_state_t state) | |||
81 | /* | 81 | /* |
82 | * Ensure not to come back here if it wasn't intended | 82 | * Ensure not to come back here if it wasn't intended |
83 | */ | 83 | */ |
84 | RCSR = RCSR_SMR; | ||
84 | PSPR = 0; | 85 | PSPR = 0; |
85 | 86 | ||
86 | /* | 87 | /* |
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c deleted file mode 100644 index 1dea6cfafb31..000000000000 --- a/arch/arm/mach-sa1100/time.c +++ /dev/null | |||
@@ -1,139 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-sa1100/time.c | ||
3 | * | ||
4 | * Copyright (C) 1998 Deborah Wallach. | ||
5 | * Twiddles (C) 1999 Hugo Fiennes <hugo@empeg.com> | ||
6 | * | ||
7 | * 2000/03/29 (C) Nicolas Pitre <nico@fluxnic.net> | ||
8 | * Rewritten: big cleanup, much simpler, better HZ accuracy. | ||
9 | * | ||
10 | */ | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/timex.h> | ||
17 | #include <linux/clockchips.h> | ||
18 | #include <linux/sched_clock.h> | ||
19 | |||
20 | #include <asm/mach/time.h> | ||
21 | #include <mach/hardware.h> | ||
22 | #include <mach/irqs.h> | ||
23 | |||
24 | #define SA1100_CLOCK_FREQ 3686400 | ||
25 | #define SA1100_LATCH DIV_ROUND_CLOSEST(SA1100_CLOCK_FREQ, HZ) | ||
26 | |||
27 | static u64 notrace sa1100_read_sched_clock(void) | ||
28 | { | ||
29 | return readl_relaxed(OSCR); | ||
30 | } | ||
31 | |||
32 | #define MIN_OSCR_DELTA 2 | ||
33 | |||
34 | static irqreturn_t sa1100_ost0_interrupt(int irq, void *dev_id) | ||
35 | { | ||
36 | struct clock_event_device *c = dev_id; | ||
37 | |||
38 | /* Disarm the compare/match, signal the event. */ | ||
39 | writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); | ||
40 | writel_relaxed(OSSR_M0, OSSR); | ||
41 | c->event_handler(c); | ||
42 | |||
43 | return IRQ_HANDLED; | ||
44 | } | ||
45 | |||
46 | static int | ||
47 | sa1100_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c) | ||
48 | { | ||
49 | unsigned long next, oscr; | ||
50 | |||
51 | writel_relaxed(readl_relaxed(OIER) | OIER_E0, OIER); | ||
52 | next = readl_relaxed(OSCR) + delta; | ||
53 | writel_relaxed(next, OSMR0); | ||
54 | oscr = readl_relaxed(OSCR); | ||
55 | |||
56 | return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; | ||
57 | } | ||
58 | |||
59 | static void | ||
60 | sa1100_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c) | ||
61 | { | ||
62 | switch (mode) { | ||
63 | case CLOCK_EVT_MODE_ONESHOT: | ||
64 | case CLOCK_EVT_MODE_UNUSED: | ||
65 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
66 | writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); | ||
67 | writel_relaxed(OSSR_M0, OSSR); | ||
68 | break; | ||
69 | |||
70 | case CLOCK_EVT_MODE_RESUME: | ||
71 | case CLOCK_EVT_MODE_PERIODIC: | ||
72 | break; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | #ifdef CONFIG_PM | ||
77 | unsigned long osmr[4], oier; | ||
78 | |||
79 | static void sa1100_timer_suspend(struct clock_event_device *cedev) | ||
80 | { | ||
81 | osmr[0] = readl_relaxed(OSMR0); | ||
82 | osmr[1] = readl_relaxed(OSMR1); | ||
83 | osmr[2] = readl_relaxed(OSMR2); | ||
84 | osmr[3] = readl_relaxed(OSMR3); | ||
85 | oier = readl_relaxed(OIER); | ||
86 | } | ||
87 | |||
88 | static void sa1100_timer_resume(struct clock_event_device *cedev) | ||
89 | { | ||
90 | writel_relaxed(0x0f, OSSR); | ||
91 | writel_relaxed(osmr[0], OSMR0); | ||
92 | writel_relaxed(osmr[1], OSMR1); | ||
93 | writel_relaxed(osmr[2], OSMR2); | ||
94 | writel_relaxed(osmr[3], OSMR3); | ||
95 | writel_relaxed(oier, OIER); | ||
96 | |||
97 | /* | ||
98 | * OSMR0 is the system timer: make sure OSCR is sufficiently behind | ||
99 | */ | ||
100 | writel_relaxed(OSMR0 - SA1100_LATCH, OSCR); | ||
101 | } | ||
102 | #else | ||
103 | #define sa1100_timer_suspend NULL | ||
104 | #define sa1100_timer_resume NULL | ||
105 | #endif | ||
106 | |||
107 | static struct clock_event_device ckevt_sa1100_osmr0 = { | ||
108 | .name = "osmr0", | ||
109 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
110 | .rating = 200, | ||
111 | .set_next_event = sa1100_osmr0_set_next_event, | ||
112 | .set_mode = sa1100_osmr0_set_mode, | ||
113 | .suspend = sa1100_timer_suspend, | ||
114 | .resume = sa1100_timer_resume, | ||
115 | }; | ||
116 | |||
117 | static struct irqaction sa1100_timer_irq = { | ||
118 | .name = "ost0", | ||
119 | .flags = IRQF_TIMER | IRQF_IRQPOLL, | ||
120 | .handler = sa1100_ost0_interrupt, | ||
121 | .dev_id = &ckevt_sa1100_osmr0, | ||
122 | }; | ||
123 | |||
124 | void __init sa1100_timer_init(void) | ||
125 | { | ||
126 | writel_relaxed(0, OIER); | ||
127 | writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR); | ||
128 | |||
129 | sched_clock_register(sa1100_read_sched_clock, 32, 3686400); | ||
130 | |||
131 | ckevt_sa1100_osmr0.cpumask = cpumask_of(0); | ||
132 | |||
133 | setup_irq(IRQ_OST0, &sa1100_timer_irq); | ||
134 | |||
135 | clocksource_mmio_init(OSCR, "oscr", SA1100_CLOCK_FREQ, 200, 32, | ||
136 | clocksource_mmio_readl_up); | ||
137 | clockevents_config_and_register(&ckevt_sa1100_osmr0, 3686400, | ||
138 | MIN_OSCR_DELTA * 2, 0x7fffffff); | ||
139 | } | ||
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index c7fc009ad21c..c6c7696b8db9 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c | |||
@@ -41,12 +41,14 @@ struct l2c_init_data { | |||
41 | void (*enable)(void __iomem *, u32, unsigned); | 41 | void (*enable)(void __iomem *, u32, unsigned); |
42 | void (*fixup)(void __iomem *, u32, struct outer_cache_fns *); | 42 | void (*fixup)(void __iomem *, u32, struct outer_cache_fns *); |
43 | void (*save)(void __iomem *); | 43 | void (*save)(void __iomem *); |
44 | void (*configure)(void __iomem *); | ||
44 | struct outer_cache_fns outer_cache; | 45 | struct outer_cache_fns outer_cache; |
45 | }; | 46 | }; |
46 | 47 | ||
47 | #define CACHE_LINE_SIZE 32 | 48 | #define CACHE_LINE_SIZE 32 |
48 | 49 | ||
49 | static void __iomem *l2x0_base; | 50 | static void __iomem *l2x0_base; |
51 | static const struct l2c_init_data *l2x0_data; | ||
50 | static DEFINE_RAW_SPINLOCK(l2x0_lock); | 52 | static DEFINE_RAW_SPINLOCK(l2x0_lock); |
51 | static u32 l2x0_way_mask; /* Bitmask of active ways */ | 53 | static u32 l2x0_way_mask; /* Bitmask of active ways */ |
52 | static u32 l2x0_size; | 54 | static u32 l2x0_size; |
@@ -106,6 +108,19 @@ static inline void l2c_unlock(void __iomem *base, unsigned num) | |||
106 | } | 108 | } |
107 | } | 109 | } |
108 | 110 | ||
111 | static void l2c_configure(void __iomem *base) | ||
112 | { | ||
113 | if (outer_cache.configure) { | ||
114 | outer_cache.configure(&l2x0_saved_regs); | ||
115 | return; | ||
116 | } | ||
117 | |||
118 | if (l2x0_data->configure) | ||
119 | l2x0_data->configure(base); | ||
120 | |||
121 | l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL); | ||
122 | } | ||
123 | |||
109 | /* | 124 | /* |
110 | * Enable the L2 cache controller. This function must only be | 125 | * Enable the L2 cache controller. This function must only be |
111 | * called when the cache controller is known to be disabled. | 126 | * called when the cache controller is known to be disabled. |
@@ -114,7 +129,12 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock) | |||
114 | { | 129 | { |
115 | unsigned long flags; | 130 | unsigned long flags; |
116 | 131 | ||
117 | l2c_write_sec(aux, base, L2X0_AUX_CTRL); | 132 | /* Do not touch the controller if already enabled. */ |
133 | if (readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN) | ||
134 | return; | ||
135 | |||
136 | l2x0_saved_regs.aux_ctrl = aux; | ||
137 | l2c_configure(base); | ||
118 | 138 | ||
119 | l2c_unlock(base, num_lock); | 139 | l2c_unlock(base, num_lock); |
120 | 140 | ||
@@ -136,76 +156,14 @@ static void l2c_disable(void) | |||
136 | dsb(st); | 156 | dsb(st); |
137 | } | 157 | } |
138 | 158 | ||
139 | #ifdef CONFIG_CACHE_PL310 | 159 | static void l2c_save(void __iomem *base) |
140 | static inline void cache_wait(void __iomem *reg, unsigned long mask) | ||
141 | { | ||
142 | /* cache operations by line are atomic on PL310 */ | ||
143 | } | ||
144 | #else | ||
145 | #define cache_wait l2c_wait_mask | ||
146 | #endif | ||
147 | |||
148 | static inline void cache_sync(void) | ||
149 | { | ||
150 | void __iomem *base = l2x0_base; | ||
151 | |||
152 | writel_relaxed(0, base + sync_reg_offset); | ||
153 | cache_wait(base + L2X0_CACHE_SYNC, 1); | ||
154 | } | ||
155 | |||
156 | #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) | ||
157 | static inline void debug_writel(unsigned long val) | ||
158 | { | ||
159 | l2c_set_debug(l2x0_base, val); | ||
160 | } | ||
161 | #else | ||
162 | /* Optimised out for non-errata case */ | ||
163 | static inline void debug_writel(unsigned long val) | ||
164 | { | ||
165 | } | ||
166 | #endif | ||
167 | |||
168 | static void l2x0_cache_sync(void) | ||
169 | { | ||
170 | unsigned long flags; | ||
171 | |||
172 | raw_spin_lock_irqsave(&l2x0_lock, flags); | ||
173 | cache_sync(); | ||
174 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
175 | } | ||
176 | |||
177 | static void __l2x0_flush_all(void) | ||
178 | { | ||
179 | debug_writel(0x03); | ||
180 | __l2c_op_way(l2x0_base + L2X0_CLEAN_INV_WAY); | ||
181 | cache_sync(); | ||
182 | debug_writel(0x00); | ||
183 | } | ||
184 | |||
185 | static void l2x0_flush_all(void) | ||
186 | { | ||
187 | unsigned long flags; | ||
188 | |||
189 | /* clean all ways */ | ||
190 | raw_spin_lock_irqsave(&l2x0_lock, flags); | ||
191 | __l2x0_flush_all(); | ||
192 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
193 | } | ||
194 | |||
195 | static void l2x0_disable(void) | ||
196 | { | 160 | { |
197 | unsigned long flags; | 161 | l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); |
198 | |||
199 | raw_spin_lock_irqsave(&l2x0_lock, flags); | ||
200 | __l2x0_flush_all(); | ||
201 | l2c_write_sec(0, l2x0_base, L2X0_CTRL); | ||
202 | dsb(st); | ||
203 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
204 | } | 162 | } |
205 | 163 | ||
206 | static void l2c_save(void __iomem *base) | 164 | static void l2c_resume(void) |
207 | { | 165 | { |
208 | l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); | 166 | l2c_enable(l2x0_base, l2x0_saved_regs.aux_ctrl, l2x0_data->num_lock); |
209 | } | 167 | } |
210 | 168 | ||
211 | /* | 169 | /* |
@@ -288,14 +246,6 @@ static void l2c210_sync(void) | |||
288 | __l2c210_cache_sync(l2x0_base); | 246 | __l2c210_cache_sync(l2x0_base); |
289 | } | 247 | } |
290 | 248 | ||
291 | static void l2c210_resume(void) | ||
292 | { | ||
293 | void __iomem *base = l2x0_base; | ||
294 | |||
295 | if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) | ||
296 | l2c_enable(base, l2x0_saved_regs.aux_ctrl, 1); | ||
297 | } | ||
298 | |||
299 | static const struct l2c_init_data l2c210_data __initconst = { | 249 | static const struct l2c_init_data l2c210_data __initconst = { |
300 | .type = "L2C-210", | 250 | .type = "L2C-210", |
301 | .way_size_0 = SZ_8K, | 251 | .way_size_0 = SZ_8K, |
@@ -309,7 +259,7 @@ static const struct l2c_init_data l2c210_data __initconst = { | |||
309 | .flush_all = l2c210_flush_all, | 259 | .flush_all = l2c210_flush_all, |
310 | .disable = l2c_disable, | 260 | .disable = l2c_disable, |
311 | .sync = l2c210_sync, | 261 | .sync = l2c210_sync, |
312 | .resume = l2c210_resume, | 262 | .resume = l2c_resume, |
313 | }, | 263 | }, |
314 | }; | 264 | }; |
315 | 265 | ||
@@ -466,7 +416,7 @@ static const struct l2c_init_data l2c220_data = { | |||
466 | .flush_all = l2c220_flush_all, | 416 | .flush_all = l2c220_flush_all, |
467 | .disable = l2c_disable, | 417 | .disable = l2c_disable, |
468 | .sync = l2c220_sync, | 418 | .sync = l2c220_sync, |
469 | .resume = l2c210_resume, | 419 | .resume = l2c_resume, |
470 | }, | 420 | }, |
471 | }; | 421 | }; |
472 | 422 | ||
@@ -615,39 +565,29 @@ static void __init l2c310_save(void __iomem *base) | |||
615 | L310_POWER_CTRL); | 565 | L310_POWER_CTRL); |
616 | } | 566 | } |
617 | 567 | ||
618 | static void l2c310_resume(void) | 568 | static void l2c310_configure(void __iomem *base) |
619 | { | 569 | { |
620 | void __iomem *base = l2x0_base; | 570 | unsigned revision; |
621 | 571 | ||
622 | if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) { | 572 | /* restore pl310 setup */ |
623 | unsigned revision; | 573 | l2c_write_sec(l2x0_saved_regs.tag_latency, base, |
624 | 574 | L310_TAG_LATENCY_CTRL); | |
625 | /* restore pl310 setup */ | 575 | l2c_write_sec(l2x0_saved_regs.data_latency, base, |
626 | writel_relaxed(l2x0_saved_regs.tag_latency, | 576 | L310_DATA_LATENCY_CTRL); |
627 | base + L310_TAG_LATENCY_CTRL); | 577 | l2c_write_sec(l2x0_saved_regs.filter_end, base, |
628 | writel_relaxed(l2x0_saved_regs.data_latency, | 578 | L310_ADDR_FILTER_END); |
629 | base + L310_DATA_LATENCY_CTRL); | 579 | l2c_write_sec(l2x0_saved_regs.filter_start, base, |
630 | writel_relaxed(l2x0_saved_regs.filter_end, | 580 | L310_ADDR_FILTER_START); |
631 | base + L310_ADDR_FILTER_END); | 581 | |
632 | writel_relaxed(l2x0_saved_regs.filter_start, | 582 | revision = readl_relaxed(base + L2X0_CACHE_ID) & |
633 | base + L310_ADDR_FILTER_START); | 583 | L2X0_CACHE_ID_RTL_MASK; |
634 | 584 | ||
635 | revision = readl_relaxed(base + L2X0_CACHE_ID) & | 585 | if (revision >= L310_CACHE_ID_RTL_R2P0) |
636 | L2X0_CACHE_ID_RTL_MASK; | 586 | l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base, |
637 | 587 | L310_PREFETCH_CTRL); | |
638 | if (revision >= L310_CACHE_ID_RTL_R2P0) | 588 | if (revision >= L310_CACHE_ID_RTL_R3P0) |
639 | l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base, | 589 | l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base, |
640 | L310_PREFETCH_CTRL); | 590 | L310_POWER_CTRL); |
641 | if (revision >= L310_CACHE_ID_RTL_R3P0) | ||
642 | l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base, | ||
643 | L310_POWER_CTRL); | ||
644 | |||
645 | l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8); | ||
646 | |||
647 | /* Re-enable full-line-of-zeros for Cortex-A9 */ | ||
648 | if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO) | ||
649 | set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); | ||
650 | } | ||
651 | } | 591 | } |
652 | 592 | ||
653 | static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, void *data) | 593 | static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, void *data) |
@@ -699,6 +639,23 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) | |||
699 | aux &= ~(L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP); | 639 | aux &= ~(L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP); |
700 | } | 640 | } |
701 | 641 | ||
642 | /* r3p0 or later has power control register */ | ||
643 | if (rev >= L310_CACHE_ID_RTL_R3P0) | ||
644 | l2x0_saved_regs.pwr_ctrl = L310_DYNAMIC_CLK_GATING_EN | | ||
645 | L310_STNDBY_MODE_EN; | ||
646 | |||
647 | /* | ||
648 | * Always enable non-secure access to the lockdown registers - | ||
649 | * we write to them as part of the L2C enable sequence so they | ||
650 | * need to be accessible. | ||
651 | */ | ||
652 | aux |= L310_AUX_CTRL_NS_LOCKDOWN; | ||
653 | |||
654 | l2c_enable(base, aux, num_lock); | ||
655 | |||
656 | /* Read back resulting AUX_CTRL value as it could have been altered. */ | ||
657 | aux = readl_relaxed(base + L2X0_AUX_CTRL); | ||
658 | |||
702 | if (aux & (L310_AUX_CTRL_DATA_PREFETCH | L310_AUX_CTRL_INSTR_PREFETCH)) { | 659 | if (aux & (L310_AUX_CTRL_DATA_PREFETCH | L310_AUX_CTRL_INSTR_PREFETCH)) { |
703 | u32 prefetch = readl_relaxed(base + L310_PREFETCH_CTRL); | 660 | u32 prefetch = readl_relaxed(base + L310_PREFETCH_CTRL); |
704 | 661 | ||
@@ -712,23 +669,12 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) | |||
712 | if (rev >= L310_CACHE_ID_RTL_R3P0) { | 669 | if (rev >= L310_CACHE_ID_RTL_R3P0) { |
713 | u32 power_ctrl; | 670 | u32 power_ctrl; |
714 | 671 | ||
715 | l2c_write_sec(L310_DYNAMIC_CLK_GATING_EN | L310_STNDBY_MODE_EN, | ||
716 | base, L310_POWER_CTRL); | ||
717 | power_ctrl = readl_relaxed(base + L310_POWER_CTRL); | 672 | power_ctrl = readl_relaxed(base + L310_POWER_CTRL); |
718 | pr_info("L2C-310 dynamic clock gating %sabled, standby mode %sabled\n", | 673 | pr_info("L2C-310 dynamic clock gating %sabled, standby mode %sabled\n", |
719 | power_ctrl & L310_DYNAMIC_CLK_GATING_EN ? "en" : "dis", | 674 | power_ctrl & L310_DYNAMIC_CLK_GATING_EN ? "en" : "dis", |
720 | power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis"); | 675 | power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis"); |
721 | } | 676 | } |
722 | 677 | ||
723 | /* | ||
724 | * Always enable non-secure access to the lockdown registers - | ||
725 | * we write to them as part of the L2C enable sequence so they | ||
726 | * need to be accessible. | ||
727 | */ | ||
728 | aux |= L310_AUX_CTRL_NS_LOCKDOWN; | ||
729 | |||
730 | l2c_enable(base, aux, num_lock); | ||
731 | |||
732 | if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) { | 678 | if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) { |
733 | set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); | 679 | set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); |
734 | cpu_notifier(l2c310_cpu_enable_flz, 0); | 680 | cpu_notifier(l2c310_cpu_enable_flz, 0); |
@@ -760,11 +706,11 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id, | |||
760 | 706 | ||
761 | if (revision >= L310_CACHE_ID_RTL_R3P0 && | 707 | if (revision >= L310_CACHE_ID_RTL_R3P0 && |
762 | revision < L310_CACHE_ID_RTL_R3P2) { | 708 | revision < L310_CACHE_ID_RTL_R3P2) { |
763 | u32 val = readl_relaxed(base + L310_PREFETCH_CTRL); | 709 | u32 val = l2x0_saved_regs.prefetch_ctrl; |
764 | /* I don't think bit23 is required here... but iMX6 does so */ | 710 | /* I don't think bit23 is required here... but iMX6 does so */ |
765 | if (val & (BIT(30) | BIT(23))) { | 711 | if (val & (BIT(30) | BIT(23))) { |
766 | val &= ~(BIT(30) | BIT(23)); | 712 | val &= ~(BIT(30) | BIT(23)); |
767 | l2c_write_sec(val, base, L310_PREFETCH_CTRL); | 713 | l2x0_saved_regs.prefetch_ctrl = val; |
768 | errata[n++] = "752271"; | 714 | errata[n++] = "752271"; |
769 | } | 715 | } |
770 | } | 716 | } |
@@ -800,6 +746,15 @@ static void l2c310_disable(void) | |||
800 | l2c_disable(); | 746 | l2c_disable(); |
801 | } | 747 | } |
802 | 748 | ||
749 | static void l2c310_resume(void) | ||
750 | { | ||
751 | l2c_resume(); | ||
752 | |||
753 | /* Re-enable full-line-of-zeros for Cortex-A9 */ | ||
754 | if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO) | ||
755 | set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); | ||
756 | } | ||
757 | |||
803 | static const struct l2c_init_data l2c310_init_fns __initconst = { | 758 | static const struct l2c_init_data l2c310_init_fns __initconst = { |
804 | .type = "L2C-310", | 759 | .type = "L2C-310", |
805 | .way_size_0 = SZ_8K, | 760 | .way_size_0 = SZ_8K, |
@@ -807,6 +762,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = { | |||
807 | .enable = l2c310_enable, | 762 | .enable = l2c310_enable, |
808 | .fixup = l2c310_fixup, | 763 | .fixup = l2c310_fixup, |
809 | .save = l2c310_save, | 764 | .save = l2c310_save, |
765 | .configure = l2c310_configure, | ||
810 | .outer_cache = { | 766 | .outer_cache = { |
811 | .inv_range = l2c210_inv_range, | 767 | .inv_range = l2c210_inv_range, |
812 | .clean_range = l2c210_clean_range, | 768 | .clean_range = l2c210_clean_range, |
@@ -818,14 +774,22 @@ static const struct l2c_init_data l2c310_init_fns __initconst = { | |||
818 | }, | 774 | }, |
819 | }; | 775 | }; |
820 | 776 | ||
821 | static void __init __l2c_init(const struct l2c_init_data *data, | 777 | static int __init __l2c_init(const struct l2c_init_data *data, |
822 | u32 aux_val, u32 aux_mask, u32 cache_id) | 778 | u32 aux_val, u32 aux_mask, u32 cache_id) |
823 | { | 779 | { |
824 | struct outer_cache_fns fns; | 780 | struct outer_cache_fns fns; |
825 | unsigned way_size_bits, ways; | 781 | unsigned way_size_bits, ways; |
826 | u32 aux, old_aux; | 782 | u32 aux, old_aux; |
827 | 783 | ||
828 | /* | 784 | /* |
785 | * Save the pointer globally so that callbacks which do not receive | ||
786 | * context from callers can access the structure. | ||
787 | */ | ||
788 | l2x0_data = kmemdup(data, sizeof(*data), GFP_KERNEL); | ||
789 | if (!l2x0_data) | ||
790 | return -ENOMEM; | ||
791 | |||
792 | /* | ||
829 | * Sanity check the aux values. aux_mask is the bits we preserve | 793 | * Sanity check the aux values. aux_mask is the bits we preserve |
830 | * from reading the hardware register, and aux_val is the bits we | 794 | * from reading the hardware register, and aux_val is the bits we |
831 | * set. | 795 | * set. |
@@ -884,6 +848,7 @@ static void __init __l2c_init(const struct l2c_init_data *data, | |||
884 | 848 | ||
885 | fns = data->outer_cache; | 849 | fns = data->outer_cache; |
886 | fns.write_sec = outer_cache.write_sec; | 850 | fns.write_sec = outer_cache.write_sec; |
851 | fns.configure = outer_cache.configure; | ||
887 | if (data->fixup) | 852 | if (data->fixup) |
888 | data->fixup(l2x0_base, cache_id, &fns); | 853 | data->fixup(l2x0_base, cache_id, &fns); |
889 | 854 | ||
@@ -910,6 +875,8 @@ static void __init __l2c_init(const struct l2c_init_data *data, | |||
910 | data->type, ways, l2x0_size >> 10); | 875 | data->type, ways, l2x0_size >> 10); |
911 | pr_info("%s: CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n", | 876 | pr_info("%s: CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n", |
912 | data->type, cache_id, aux); | 877 | data->type, cache_id, aux); |
878 | |||
879 | return 0; | ||
913 | } | 880 | } |
914 | 881 | ||
915 | void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) | 882 | void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) |
@@ -936,6 +903,10 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) | |||
936 | break; | 903 | break; |
937 | } | 904 | } |
938 | 905 | ||
906 | /* Read back current (default) hardware configuration */ | ||
907 | if (data->save) | ||
908 | data->save(l2x0_base); | ||
909 | |||
939 | __l2c_init(data, aux_val, aux_mask, cache_id); | 910 | __l2c_init(data, aux_val, aux_mask, cache_id); |
940 | } | 911 | } |
941 | 912 | ||
@@ -1102,7 +1073,7 @@ static const struct l2c_init_data of_l2c210_data __initconst = { | |||
1102 | .flush_all = l2c210_flush_all, | 1073 | .flush_all = l2c210_flush_all, |
1103 | .disable = l2c_disable, | 1074 | .disable = l2c_disable, |
1104 | .sync = l2c210_sync, | 1075 | .sync = l2c210_sync, |
1105 | .resume = l2c210_resume, | 1076 | .resume = l2c_resume, |
1106 | }, | 1077 | }, |
1107 | }; | 1078 | }; |
1108 | 1079 | ||
@@ -1120,7 +1091,7 @@ static const struct l2c_init_data of_l2c220_data __initconst = { | |||
1120 | .flush_all = l2c220_flush_all, | 1091 | .flush_all = l2c220_flush_all, |
1121 | .disable = l2c_disable, | 1092 | .disable = l2c_disable, |
1122 | .sync = l2c220_sync, | 1093 | .sync = l2c220_sync, |
1123 | .resume = l2c210_resume, | 1094 | .resume = l2c_resume, |
1124 | }, | 1095 | }, |
1125 | }; | 1096 | }; |
1126 | 1097 | ||
@@ -1131,32 +1102,32 @@ static void __init l2c310_of_parse(const struct device_node *np, | |||
1131 | u32 tag[3] = { 0, 0, 0 }; | 1102 | u32 tag[3] = { 0, 0, 0 }; |
1132 | u32 filter[2] = { 0, 0 }; | 1103 | u32 filter[2] = { 0, 0 }; |
1133 | u32 assoc; | 1104 | u32 assoc; |
1105 | u32 prefetch; | ||
1106 | u32 val; | ||
1134 | int ret; | 1107 | int ret; |
1135 | 1108 | ||
1136 | of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); | 1109 | of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); |
1137 | if (tag[0] && tag[1] && tag[2]) | 1110 | if (tag[0] && tag[1] && tag[2]) |
1138 | writel_relaxed( | 1111 | l2x0_saved_regs.tag_latency = |
1139 | L310_LATENCY_CTRL_RD(tag[0] - 1) | | 1112 | L310_LATENCY_CTRL_RD(tag[0] - 1) | |
1140 | L310_LATENCY_CTRL_WR(tag[1] - 1) | | 1113 | L310_LATENCY_CTRL_WR(tag[1] - 1) | |
1141 | L310_LATENCY_CTRL_SETUP(tag[2] - 1), | 1114 | L310_LATENCY_CTRL_SETUP(tag[2] - 1); |
1142 | l2x0_base + L310_TAG_LATENCY_CTRL); | ||
1143 | 1115 | ||
1144 | of_property_read_u32_array(np, "arm,data-latency", | 1116 | of_property_read_u32_array(np, "arm,data-latency", |
1145 | data, ARRAY_SIZE(data)); | 1117 | data, ARRAY_SIZE(data)); |
1146 | if (data[0] && data[1] && data[2]) | 1118 | if (data[0] && data[1] && data[2]) |
1147 | writel_relaxed( | 1119 | l2x0_saved_regs.data_latency = |
1148 | L310_LATENCY_CTRL_RD(data[0] - 1) | | 1120 | L310_LATENCY_CTRL_RD(data[0] - 1) | |
1149 | L310_LATENCY_CTRL_WR(data[1] - 1) | | 1121 | L310_LATENCY_CTRL_WR(data[1] - 1) | |
1150 | L310_LATENCY_CTRL_SETUP(data[2] - 1), | 1122 | L310_LATENCY_CTRL_SETUP(data[2] - 1); |
1151 | l2x0_base + L310_DATA_LATENCY_CTRL); | ||
1152 | 1123 | ||
1153 | of_property_read_u32_array(np, "arm,filter-ranges", | 1124 | of_property_read_u32_array(np, "arm,filter-ranges", |
1154 | filter, ARRAY_SIZE(filter)); | 1125 | filter, ARRAY_SIZE(filter)); |
1155 | if (filter[1]) { | 1126 | if (filter[1]) { |
1156 | writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M), | 1127 | l2x0_saved_regs.filter_end = |
1157 | l2x0_base + L310_ADDR_FILTER_END); | 1128 | ALIGN(filter[0] + filter[1], SZ_1M); |
1158 | writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L310_ADDR_FILTER_EN, | 1129 | l2x0_saved_regs.filter_start = (filter[0] & ~(SZ_1M - 1)) |
1159 | l2x0_base + L310_ADDR_FILTER_START); | 1130 | | L310_ADDR_FILTER_EN; |
1160 | } | 1131 | } |
1161 | 1132 | ||
1162 | ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K); | 1133 | ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K); |
@@ -1178,6 +1149,58 @@ static void __init l2c310_of_parse(const struct device_node *np, | |||
1178 | assoc); | 1149 | assoc); |
1179 | break; | 1150 | break; |
1180 | } | 1151 | } |
1152 | |||
1153 | prefetch = l2x0_saved_regs.prefetch_ctrl; | ||
1154 | |||
1155 | ret = of_property_read_u32(np, "arm,double-linefill", &val); | ||
1156 | if (ret == 0) { | ||
1157 | if (val) | ||
1158 | prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL; | ||
1159 | else | ||
1160 | prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL; | ||
1161 | } else if (ret != -EINVAL) { | ||
1162 | pr_err("L2C-310 OF arm,double-linefill property value is missing\n"); | ||
1163 | } | ||
1164 | |||
1165 | ret = of_property_read_u32(np, "arm,double-linefill-incr", &val); | ||
1166 | if (ret == 0) { | ||
1167 | if (val) | ||
1168 | prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL_INCR; | ||
1169 | else | ||
1170 | prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL_INCR; | ||
1171 | } else if (ret != -EINVAL) { | ||
1172 | pr_err("L2C-310 OF arm,double-linefill-incr property value is missing\n"); | ||
1173 | } | ||
1174 | |||
1175 | ret = of_property_read_u32(np, "arm,double-linefill-wrap", &val); | ||
1176 | if (ret == 0) { | ||
1177 | if (!val) | ||
1178 | prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP; | ||
1179 | else | ||
1180 | prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP; | ||
1181 | } else if (ret != -EINVAL) { | ||
1182 | pr_err("L2C-310 OF arm,double-linefill-wrap property value is missing\n"); | ||
1183 | } | ||
1184 | |||
1185 | ret = of_property_read_u32(np, "arm,prefetch-drop", &val); | ||
1186 | if (ret == 0) { | ||
1187 | if (val) | ||
1188 | prefetch |= L310_PREFETCH_CTRL_PREFETCH_DROP; | ||
1189 | else | ||
1190 | prefetch &= ~L310_PREFETCH_CTRL_PREFETCH_DROP; | ||
1191 | } else if (ret != -EINVAL) { | ||
1192 | pr_err("L2C-310 OF arm,prefetch-drop property value is missing\n"); | ||
1193 | } | ||
1194 | |||
1195 | ret = of_property_read_u32(np, "arm,prefetch-offset", &val); | ||
1196 | if (ret == 0) { | ||
1197 | prefetch &= ~L310_PREFETCH_CTRL_OFFSET_MASK; | ||
1198 | prefetch |= val & L310_PREFETCH_CTRL_OFFSET_MASK; | ||
1199 | } else if (ret != -EINVAL) { | ||
1200 | pr_err("L2C-310 OF arm,prefetch-offset property value is missing\n"); | ||
1201 | } | ||
1202 | |||
1203 | l2x0_saved_regs.prefetch_ctrl = prefetch; | ||
1181 | } | 1204 | } |
1182 | 1205 | ||
1183 | static const struct l2c_init_data of_l2c310_data __initconst = { | 1206 | static const struct l2c_init_data of_l2c310_data __initconst = { |
@@ -1188,6 +1211,7 @@ static const struct l2c_init_data of_l2c310_data __initconst = { | |||
1188 | .enable = l2c310_enable, | 1211 | .enable = l2c310_enable, |
1189 | .fixup = l2c310_fixup, | 1212 | .fixup = l2c310_fixup, |
1190 | .save = l2c310_save, | 1213 | .save = l2c310_save, |
1214 | .configure = l2c310_configure, | ||
1191 | .outer_cache = { | 1215 | .outer_cache = { |
1192 | .inv_range = l2c210_inv_range, | 1216 | .inv_range = l2c210_inv_range, |
1193 | .clean_range = l2c210_clean_range, | 1217 | .clean_range = l2c210_clean_range, |
@@ -1216,6 +1240,7 @@ static const struct l2c_init_data of_l2c310_coherent_data __initconst = { | |||
1216 | .enable = l2c310_enable, | 1240 | .enable = l2c310_enable, |
1217 | .fixup = l2c310_fixup, | 1241 | .fixup = l2c310_fixup, |
1218 | .save = l2c310_save, | 1242 | .save = l2c310_save, |
1243 | .configure = l2c310_configure, | ||
1219 | .outer_cache = { | 1244 | .outer_cache = { |
1220 | .inv_range = l2c210_inv_range, | 1245 | .inv_range = l2c210_inv_range, |
1221 | .clean_range = l2c210_clean_range, | 1246 | .clean_range = l2c210_clean_range, |
@@ -1231,7 +1256,7 @@ static const struct l2c_init_data of_l2c310_coherent_data __initconst = { | |||
1231 | * noninclusive, while the hardware cache range operations use | 1256 | * noninclusive, while the hardware cache range operations use |
1232 | * inclusive start and end addresses. | 1257 | * inclusive start and end addresses. |
1233 | */ | 1258 | */ |
1234 | static unsigned long calc_range_end(unsigned long start, unsigned long end) | 1259 | static unsigned long aurora_range_end(unsigned long start, unsigned long end) |
1235 | { | 1260 | { |
1236 | /* | 1261 | /* |
1237 | * Limit the number of cache lines processed at once, | 1262 | * Limit the number of cache lines processed at once, |
@@ -1250,25 +1275,13 @@ static unsigned long calc_range_end(unsigned long start, unsigned long end) | |||
1250 | return end; | 1275 | return end; |
1251 | } | 1276 | } |
1252 | 1277 | ||
1253 | /* | ||
1254 | * Make sure 'start' and 'end' reference the same page, as L2 is PIPT | ||
1255 | * and range operations only do a TLB lookup on the start address. | ||
1256 | */ | ||
1257 | static void aurora_pa_range(unsigned long start, unsigned long end, | 1278 | static void aurora_pa_range(unsigned long start, unsigned long end, |
1258 | unsigned long offset) | 1279 | unsigned long offset) |
1259 | { | 1280 | { |
1281 | void __iomem *base = l2x0_base; | ||
1282 | unsigned long range_end; | ||
1260 | unsigned long flags; | 1283 | unsigned long flags; |
1261 | 1284 | ||
1262 | raw_spin_lock_irqsave(&l2x0_lock, flags); | ||
1263 | writel_relaxed(start, l2x0_base + AURORA_RANGE_BASE_ADDR_REG); | ||
1264 | writel_relaxed(end, l2x0_base + offset); | ||
1265 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
1266 | |||
1267 | cache_sync(); | ||
1268 | } | ||
1269 | |||
1270 | static void aurora_inv_range(unsigned long start, unsigned long end) | ||
1271 | { | ||
1272 | /* | 1285 | /* |
1273 | * round start and end adresses up to cache line size | 1286 | * round start and end adresses up to cache line size |
1274 | */ | 1287 | */ |
@@ -1276,15 +1289,24 @@ static void aurora_inv_range(unsigned long start, unsigned long end) | |||
1276 | end = ALIGN(end, CACHE_LINE_SIZE); | 1289 | end = ALIGN(end, CACHE_LINE_SIZE); |
1277 | 1290 | ||
1278 | /* | 1291 | /* |
1279 | * Invalidate all full cache lines between 'start' and 'end'. | 1292 | * perform operation on all full cache lines between 'start' and 'end' |
1280 | */ | 1293 | */ |
1281 | while (start < end) { | 1294 | while (start < end) { |
1282 | unsigned long range_end = calc_range_end(start, end); | 1295 | range_end = aurora_range_end(start, end); |
1283 | aurora_pa_range(start, range_end - CACHE_LINE_SIZE, | 1296 | |
1284 | AURORA_INVAL_RANGE_REG); | 1297 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
1298 | writel_relaxed(start, base + AURORA_RANGE_BASE_ADDR_REG); | ||
1299 | writel_relaxed(range_end - CACHE_LINE_SIZE, base + offset); | ||
1300 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
1301 | |||
1302 | writel_relaxed(0, base + AURORA_SYNC_REG); | ||
1285 | start = range_end; | 1303 | start = range_end; |
1286 | } | 1304 | } |
1287 | } | 1305 | } |
1306 | static void aurora_inv_range(unsigned long start, unsigned long end) | ||
1307 | { | ||
1308 | aurora_pa_range(start, end, AURORA_INVAL_RANGE_REG); | ||
1309 | } | ||
1288 | 1310 | ||
1289 | static void aurora_clean_range(unsigned long start, unsigned long end) | 1311 | static void aurora_clean_range(unsigned long start, unsigned long end) |
1290 | { | 1312 | { |
@@ -1292,52 +1314,53 @@ static void aurora_clean_range(unsigned long start, unsigned long end) | |||
1292 | * If L2 is forced to WT, the L2 will always be clean and we | 1314 | * If L2 is forced to WT, the L2 will always be clean and we |
1293 | * don't need to do anything here. | 1315 | * don't need to do anything here. |
1294 | */ | 1316 | */ |
1295 | if (!l2_wt_override) { | 1317 | if (!l2_wt_override) |
1296 | start &= ~(CACHE_LINE_SIZE - 1); | 1318 | aurora_pa_range(start, end, AURORA_CLEAN_RANGE_REG); |
1297 | end = ALIGN(end, CACHE_LINE_SIZE); | ||
1298 | while (start != end) { | ||
1299 | unsigned long range_end = calc_range_end(start, end); | ||
1300 | aurora_pa_range(start, range_end - CACHE_LINE_SIZE, | ||
1301 | AURORA_CLEAN_RANGE_REG); | ||
1302 | start = range_end; | ||
1303 | } | ||
1304 | } | ||
1305 | } | 1319 | } |
1306 | 1320 | ||
1307 | static void aurora_flush_range(unsigned long start, unsigned long end) | 1321 | static void aurora_flush_range(unsigned long start, unsigned long end) |
1308 | { | 1322 | { |
1309 | start &= ~(CACHE_LINE_SIZE - 1); | 1323 | if (l2_wt_override) |
1310 | end = ALIGN(end, CACHE_LINE_SIZE); | 1324 | aurora_pa_range(start, end, AURORA_INVAL_RANGE_REG); |
1311 | while (start != end) { | 1325 | else |
1312 | unsigned long range_end = calc_range_end(start, end); | 1326 | aurora_pa_range(start, end, AURORA_FLUSH_RANGE_REG); |
1313 | /* | ||
1314 | * If L2 is forced to WT, the L2 will always be clean and we | ||
1315 | * just need to invalidate. | ||
1316 | */ | ||
1317 | if (l2_wt_override) | ||
1318 | aurora_pa_range(start, range_end - CACHE_LINE_SIZE, | ||
1319 | AURORA_INVAL_RANGE_REG); | ||
1320 | else | ||
1321 | aurora_pa_range(start, range_end - CACHE_LINE_SIZE, | ||
1322 | AURORA_FLUSH_RANGE_REG); | ||
1323 | start = range_end; | ||
1324 | } | ||
1325 | } | 1327 | } |
1326 | 1328 | ||
1327 | static void aurora_save(void __iomem *base) | 1329 | static void aurora_flush_all(void) |
1328 | { | 1330 | { |
1329 | l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL); | 1331 | void __iomem *base = l2x0_base; |
1330 | l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL); | 1332 | unsigned long flags; |
1333 | |||
1334 | /* clean all ways */ | ||
1335 | raw_spin_lock_irqsave(&l2x0_lock, flags); | ||
1336 | __l2c_op_way(base + L2X0_CLEAN_INV_WAY); | ||
1337 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
1338 | |||
1339 | writel_relaxed(0, base + AURORA_SYNC_REG); | ||
1331 | } | 1340 | } |
1332 | 1341 | ||
1333 | static void aurora_resume(void) | 1342 | static void aurora_cache_sync(void) |
1343 | { | ||
1344 | writel_relaxed(0, l2x0_base + AURORA_SYNC_REG); | ||
1345 | } | ||
1346 | |||
1347 | static void aurora_disable(void) | ||
1334 | { | 1348 | { |
1335 | void __iomem *base = l2x0_base; | 1349 | void __iomem *base = l2x0_base; |
1350 | unsigned long flags; | ||
1336 | 1351 | ||
1337 | if (!(readl(base + L2X0_CTRL) & L2X0_CTRL_EN)) { | 1352 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
1338 | writel_relaxed(l2x0_saved_regs.aux_ctrl, base + L2X0_AUX_CTRL); | 1353 | __l2c_op_way(base + L2X0_CLEAN_INV_WAY); |
1339 | writel_relaxed(l2x0_saved_regs.ctrl, base + L2X0_CTRL); | 1354 | writel_relaxed(0, base + AURORA_SYNC_REG); |
1340 | } | 1355 | l2c_write_sec(0, base, L2X0_CTRL); |
1356 | dsb(st); | ||
1357 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
1358 | } | ||
1359 | |||
1360 | static void aurora_save(void __iomem *base) | ||
1361 | { | ||
1362 | l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL); | ||
1363 | l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL); | ||
1341 | } | 1364 | } |
1342 | 1365 | ||
1343 | /* | 1366 | /* |
@@ -1398,10 +1421,10 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = { | |||
1398 | .inv_range = aurora_inv_range, | 1421 | .inv_range = aurora_inv_range, |
1399 | .clean_range = aurora_clean_range, | 1422 | .clean_range = aurora_clean_range, |
1400 | .flush_range = aurora_flush_range, | 1423 | .flush_range = aurora_flush_range, |
1401 | .flush_all = l2x0_flush_all, | 1424 | .flush_all = aurora_flush_all, |
1402 | .disable = l2x0_disable, | 1425 | .disable = aurora_disable, |
1403 | .sync = l2x0_cache_sync, | 1426 | .sync = aurora_cache_sync, |
1404 | .resume = aurora_resume, | 1427 | .resume = l2c_resume, |
1405 | }, | 1428 | }, |
1406 | }; | 1429 | }; |
1407 | 1430 | ||
@@ -1414,7 +1437,7 @@ static const struct l2c_init_data of_aurora_no_outer_data __initconst = { | |||
1414 | .fixup = aurora_fixup, | 1437 | .fixup = aurora_fixup, |
1415 | .save = aurora_save, | 1438 | .save = aurora_save, |
1416 | .outer_cache = { | 1439 | .outer_cache = { |
1417 | .resume = aurora_resume, | 1440 | .resume = l2c_resume, |
1418 | }, | 1441 | }, |
1419 | }; | 1442 | }; |
1420 | 1443 | ||
@@ -1562,6 +1585,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = { | |||
1562 | .of_parse = l2c310_of_parse, | 1585 | .of_parse = l2c310_of_parse, |
1563 | .enable = l2c310_enable, | 1586 | .enable = l2c310_enable, |
1564 | .save = l2c310_save, | 1587 | .save = l2c310_save, |
1588 | .configure = l2c310_configure, | ||
1565 | .outer_cache = { | 1589 | .outer_cache = { |
1566 | .inv_range = bcm_inv_range, | 1590 | .inv_range = bcm_inv_range, |
1567 | .clean_range = bcm_clean_range, | 1591 | .clean_range = bcm_clean_range, |
@@ -1583,18 +1607,12 @@ static void __init tauros3_save(void __iomem *base) | |||
1583 | readl_relaxed(base + L310_PREFETCH_CTRL); | 1607 | readl_relaxed(base + L310_PREFETCH_CTRL); |
1584 | } | 1608 | } |
1585 | 1609 | ||
1586 | static void tauros3_resume(void) | 1610 | static void tauros3_configure(void __iomem *base) |
1587 | { | 1611 | { |
1588 | void __iomem *base = l2x0_base; | 1612 | writel_relaxed(l2x0_saved_regs.aux2_ctrl, |
1589 | 1613 | base + TAUROS3_AUX2_CTRL); | |
1590 | if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) { | 1614 | writel_relaxed(l2x0_saved_regs.prefetch_ctrl, |
1591 | writel_relaxed(l2x0_saved_regs.aux2_ctrl, | 1615 | base + L310_PREFETCH_CTRL); |
1592 | base + TAUROS3_AUX2_CTRL); | ||
1593 | writel_relaxed(l2x0_saved_regs.prefetch_ctrl, | ||
1594 | base + L310_PREFETCH_CTRL); | ||
1595 | |||
1596 | l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8); | ||
1597 | } | ||
1598 | } | 1616 | } |
1599 | 1617 | ||
1600 | static const struct l2c_init_data of_tauros3_data __initconst = { | 1618 | static const struct l2c_init_data of_tauros3_data __initconst = { |
@@ -1603,9 +1621,10 @@ static const struct l2c_init_data of_tauros3_data __initconst = { | |||
1603 | .num_lock = 8, | 1621 | .num_lock = 8, |
1604 | .enable = l2c_enable, | 1622 | .enable = l2c_enable, |
1605 | .save = tauros3_save, | 1623 | .save = tauros3_save, |
1624 | .configure = tauros3_configure, | ||
1606 | /* Tauros3 broadcasts L1 cache operations to L2 */ | 1625 | /* Tauros3 broadcasts L1 cache operations to L2 */ |
1607 | .outer_cache = { | 1626 | .outer_cache = { |
1608 | .resume = tauros3_resume, | 1627 | .resume = l2c_resume, |
1609 | }, | 1628 | }, |
1610 | }; | 1629 | }; |
1611 | 1630 | ||
@@ -1661,6 +1680,10 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) | |||
1661 | if (!of_property_read_bool(np, "cache-unified")) | 1680 | if (!of_property_read_bool(np, "cache-unified")) |
1662 | pr_err("L2C: device tree omits to specify unified cache\n"); | 1681 | pr_err("L2C: device tree omits to specify unified cache\n"); |
1663 | 1682 | ||
1683 | /* Read back current (default) hardware configuration */ | ||
1684 | if (data->save) | ||
1685 | data->save(l2x0_base); | ||
1686 | |||
1664 | /* L2 configuration can only be changed if the cache is disabled */ | 1687 | /* L2 configuration can only be changed if the cache is disabled */ |
1665 | if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) | 1688 | if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) |
1666 | if (data->of_parse) | 1689 | if (data->of_parse) |
@@ -1671,8 +1694,6 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) | |||
1671 | else | 1694 | else |
1672 | cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); | 1695 | cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); |
1673 | 1696 | ||
1674 | __l2c_init(data, aux_val, aux_mask, cache_id); | 1697 | return __l2c_init(data, aux_val, aux_mask, cache_id); |
1675 | |||
1676 | return 0; | ||
1677 | } | 1698 | } |
1678 | #endif | 1699 | #endif |
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 2495c8cb47ba..1609b022a72f 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c | |||
@@ -319,10 +319,7 @@ void __init arm_memblock_init(const struct machine_desc *mdesc) | |||
319 | 319 | ||
320 | early_init_fdt_scan_reserved_mem(); | 320 | early_init_fdt_scan_reserved_mem(); |
321 | 321 | ||
322 | /* | 322 | /* reserve memory for DMA contiguous allocations */ |
323 | * reserve memory for DMA contigouos allocations, | ||
324 | * must come from DMA area inside low memory | ||
325 | */ | ||
326 | dma_contiguous_reserve(arm_dma_limit); | 323 | dma_contiguous_reserve(arm_dma_limit); |
327 | 324 | ||
328 | arm_memblock_steal_permitted = false; | 325 | arm_memblock_steal_permitted = false; |
diff --git a/arch/arm/probes/Makefile b/arch/arm/probes/Makefile new file mode 100644 index 000000000000..aa1f8590dcdd --- /dev/null +++ b/arch/arm/probes/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | obj-$(CONFIG_UPROBES) += decode.o decode-arm.o uprobes/ | ||
2 | obj-$(CONFIG_KPROBES) += decode.o kprobes/ | ||
3 | ifdef CONFIG_THUMB2_KERNEL | ||
4 | obj-$(CONFIG_KPROBES) += decode-thumb.o | ||
5 | else | ||
6 | obj-$(CONFIG_KPROBES) += decode-arm.o | ||
7 | endif | ||
diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/probes/decode-arm.c index 8eaef81d8344..f72c33a2dcfb 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/probes/decode-arm.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/kernel/probes-arm.c | 2 | * |
3 | * arch/arm/probes/decode-arm.c | ||
3 | * | 4 | * |
4 | * Some code moved here from arch/arm/kernel/kprobes-arm.c | 5 | * Some code moved here from arch/arm/kernel/kprobes-arm.c |
5 | * | 6 | * |
@@ -20,8 +21,8 @@ | |||
20 | #include <linux/stddef.h> | 21 | #include <linux/stddef.h> |
21 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
22 | 23 | ||
23 | #include "probes.h" | 24 | #include "decode.h" |
24 | #include "probes-arm.h" | 25 | #include "decode-arm.h" |
25 | 26 | ||
26 | #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) | 27 | #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) |
27 | 28 | ||
@@ -369,17 +370,17 @@ static const union decode_item arm_cccc_001x_table[] = { | |||
369 | 370 | ||
370 | /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ | 371 | /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ |
371 | /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ | 372 | /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ |
372 | DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_DATA_PROCESSING_IMM, | 373 | DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_MOV_HALFWORD, |
373 | REGS(0, NOPC, 0, 0, 0)), | 374 | REGS(0, NOPC, 0, 0, 0)), |
374 | 375 | ||
375 | /* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ | 376 | /* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ |
376 | DECODE_OR (0x0fff00ff, 0x03200001), | 377 | DECODE_OR (0x0fff00ff, 0x03200001), |
377 | /* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ | 378 | /* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ |
378 | DECODE_EMULATE (0x0fff00ff, 0x03200004, PROBES_EMULATE_NONE), | 379 | DECODE_EMULATE (0x0fff00ff, 0x03200004, PROBES_SEV), |
379 | /* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ | 380 | /* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ |
380 | /* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ | 381 | /* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ |
381 | /* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ | 382 | /* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ |
382 | DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_SIMULATE_NOP), | 383 | DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_WFE), |
383 | /* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */ | 384 | /* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */ |
384 | /* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ | 385 | /* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ |
385 | /* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */ | 386 | /* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */ |
@@ -725,10 +726,11 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, | |||
725 | */ | 726 | */ |
726 | enum probes_insn __kprobes | 727 | enum probes_insn __kprobes |
727 | arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, | 728 | arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, |
728 | bool emulate, const union decode_action *actions) | 729 | bool emulate, const union decode_action *actions, |
730 | const struct decode_checker *checkers[]) | ||
729 | { | 731 | { |
730 | asi->insn_singlestep = arm_singlestep; | 732 | asi->insn_singlestep = arm_singlestep; |
731 | asi->insn_check_cc = probes_condition_checks[insn>>28]; | 733 | asi->insn_check_cc = probes_condition_checks[insn>>28]; |
732 | return probes_decode_insn(insn, asi, probes_decode_arm_table, false, | 734 | return probes_decode_insn(insn, asi, probes_decode_arm_table, false, |
733 | emulate, actions); | 735 | emulate, actions, checkers); |
734 | } | 736 | } |
diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/probes/decode-arm.h index ace6572f6e26..b3b80f6d414b 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/probes/decode-arm.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/kernel/probes-arm.h | 2 | * arch/arm/probes/decode-arm.h |
3 | * | 3 | * |
4 | * Copyright 2013 Linaro Ltd. | 4 | * Copyright 2013 Linaro Ltd. |
5 | * Written by: David A. Long | 5 | * Written by: David A. Long |
@@ -15,9 +15,9 @@ | |||
15 | #ifndef _ARM_KERNEL_PROBES_ARM_H | 15 | #ifndef _ARM_KERNEL_PROBES_ARM_H |
16 | #define _ARM_KERNEL_PROBES_ARM_H | 16 | #define _ARM_KERNEL_PROBES_ARM_H |
17 | 17 | ||
18 | #include "decode.h" | ||
19 | |||
18 | enum probes_arm_action { | 20 | enum probes_arm_action { |
19 | PROBES_EMULATE_NONE, | ||
20 | PROBES_SIMULATE_NOP, | ||
21 | PROBES_PRELOAD_IMM, | 21 | PROBES_PRELOAD_IMM, |
22 | PROBES_PRELOAD_REG, | 22 | PROBES_PRELOAD_REG, |
23 | PROBES_BRANCH_IMM, | 23 | PROBES_BRANCH_IMM, |
@@ -68,6 +68,7 @@ extern const union decode_item probes_decode_arm_table[]; | |||
68 | 68 | ||
69 | enum probes_insn arm_probes_decode_insn(probes_opcode_t, | 69 | enum probes_insn arm_probes_decode_insn(probes_opcode_t, |
70 | struct arch_probes_insn *, bool emulate, | 70 | struct arch_probes_insn *, bool emulate, |
71 | const union decode_action *actions); | 71 | const union decode_action *actions, |
72 | const struct decode_checker *checkers[]); | ||
72 | 73 | ||
73 | #endif | 74 | #endif |
diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/probes/decode-thumb.c index 4131351e812f..985e7dd4cac6 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/probes/decode-thumb.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/kernel/probes-thumb.c | 2 | * arch/arm/probes/decode-thumb.c |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. | 4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. |
5 | * | 5 | * |
@@ -12,8 +12,8 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | 14 | ||
15 | #include "probes.h" | 15 | #include "decode.h" |
16 | #include "probes-thumb.h" | 16 | #include "decode-thumb.h" |
17 | 17 | ||
18 | 18 | ||
19 | static const union decode_item t32_table_1110_100x_x0xx[] = { | 19 | static const union decode_item t32_table_1110_100x_x0xx[] = { |
@@ -863,20 +863,22 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, | |||
863 | 863 | ||
864 | enum probes_insn __kprobes | 864 | enum probes_insn __kprobes |
865 | thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, | 865 | thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, |
866 | bool emulate, const union decode_action *actions) | 866 | bool emulate, const union decode_action *actions, |
867 | const struct decode_checker *checkers[]) | ||
867 | { | 868 | { |
868 | asi->insn_singlestep = thumb16_singlestep; | 869 | asi->insn_singlestep = thumb16_singlestep; |
869 | asi->insn_check_cc = thumb_check_cc; | 870 | asi->insn_check_cc = thumb_check_cc; |
870 | return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true, | 871 | return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true, |
871 | emulate, actions); | 872 | emulate, actions, checkers); |
872 | } | 873 | } |
873 | 874 | ||
874 | enum probes_insn __kprobes | 875 | enum probes_insn __kprobes |
875 | thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, | 876 | thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, |
876 | bool emulate, const union decode_action *actions) | 877 | bool emulate, const union decode_action *actions, |
878 | const struct decode_checker *checkers[]) | ||
877 | { | 879 | { |
878 | asi->insn_singlestep = thumb32_singlestep; | 880 | asi->insn_singlestep = thumb32_singlestep; |
879 | asi->insn_check_cc = thumb_check_cc; | 881 | asi->insn_check_cc = thumb_check_cc; |
880 | return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true, | 882 | return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true, |
881 | emulate, actions); | 883 | emulate, actions, checkers); |
882 | } | 884 | } |
diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/probes/decode-thumb.h index 7c6f6ebe514f..8457add0a2d8 100644 --- a/arch/arm/kernel/probes-thumb.h +++ b/arch/arm/probes/decode-thumb.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/kernel/probes-thumb.h | 2 | * arch/arm/probes/decode-thumb.h |
3 | * | 3 | * |
4 | * Copyright 2013 Linaro Ltd. | 4 | * Copyright 2013 Linaro Ltd. |
5 | * Written by: David A. Long | 5 | * Written by: David A. Long |
@@ -15,6 +15,8 @@ | |||
15 | #ifndef _ARM_KERNEL_PROBES_THUMB_H | 15 | #ifndef _ARM_KERNEL_PROBES_THUMB_H |
16 | #define _ARM_KERNEL_PROBES_THUMB_H | 16 | #define _ARM_KERNEL_PROBES_THUMB_H |
17 | 17 | ||
18 | #include "decode.h" | ||
19 | |||
18 | /* | 20 | /* |
19 | * True if current instruction is in an IT block. | 21 | * True if current instruction is in an IT block. |
20 | */ | 22 | */ |
@@ -89,9 +91,11 @@ extern const union decode_item probes_decode_thumb16_table[]; | |||
89 | 91 | ||
90 | enum probes_insn __kprobes | 92 | enum probes_insn __kprobes |
91 | thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, | 93 | thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, |
92 | bool emulate, const union decode_action *actions); | 94 | bool emulate, const union decode_action *actions, |
95 | const struct decode_checker *checkers[]); | ||
93 | enum probes_insn __kprobes | 96 | enum probes_insn __kprobes |
94 | thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, | 97 | thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, |
95 | bool emulate, const union decode_action *actions); | 98 | bool emulate, const union decode_action *actions, |
99 | const struct decode_checker *checkers[]); | ||
96 | 100 | ||
97 | #endif | 101 | #endif |
diff --git a/arch/arm/kernel/probes.c b/arch/arm/probes/decode.c index a8ab540d7e73..880ebe0cdf19 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/probes/decode.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/kernel/probes.c | 2 | * arch/arm/probes/decode.c |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. | 4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. |
5 | * | 5 | * |
@@ -17,7 +17,7 @@ | |||
17 | #include <asm/ptrace.h> | 17 | #include <asm/ptrace.h> |
18 | #include <linux/bug.h> | 18 | #include <linux/bug.h> |
19 | 19 | ||
20 | #include "probes.h" | 20 | #include "decode.h" |
21 | 21 | ||
22 | 22 | ||
23 | #ifndef find_str_pc_offset | 23 | #ifndef find_str_pc_offset |
@@ -342,6 +342,31 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { | |||
342 | [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) | 342 | [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) |
343 | }; | 343 | }; |
344 | 344 | ||
345 | static int run_checkers(const struct decode_checker *checkers[], | ||
346 | int action, probes_opcode_t insn, | ||
347 | struct arch_probes_insn *asi, | ||
348 | const struct decode_header *h) | ||
349 | { | ||
350 | const struct decode_checker **p; | ||
351 | |||
352 | if (!checkers) | ||
353 | return INSN_GOOD; | ||
354 | |||
355 | p = checkers; | ||
356 | while (*p != NULL) { | ||
357 | int retval; | ||
358 | probes_check_t *checker_func = (*p)[action].checker; | ||
359 | |||
360 | retval = INSN_GOOD; | ||
361 | if (checker_func) | ||
362 | retval = checker_func(insn, asi, h); | ||
363 | if (retval == INSN_REJECTED) | ||
364 | return retval; | ||
365 | p++; | ||
366 | } | ||
367 | return INSN_GOOD; | ||
368 | } | ||
369 | |||
345 | /* | 370 | /* |
346 | * probes_decode_insn operates on data tables in order to decode an ARM | 371 | * probes_decode_insn operates on data tables in order to decode an ARM |
347 | * architecture instruction onto which a kprobe has been placed. | 372 | * architecture instruction onto which a kprobe has been placed. |
@@ -388,11 +413,34 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { | |||
388 | int __kprobes | 413 | int __kprobes |
389 | probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, | 414 | probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, |
390 | const union decode_item *table, bool thumb, | 415 | const union decode_item *table, bool thumb, |
391 | bool emulate, const union decode_action *actions) | 416 | bool emulate, const union decode_action *actions, |
417 | const struct decode_checker *checkers[]) | ||
392 | { | 418 | { |
393 | const struct decode_header *h = (struct decode_header *)table; | 419 | const struct decode_header *h = (struct decode_header *)table; |
394 | const struct decode_header *next; | 420 | const struct decode_header *next; |
395 | bool matched = false; | 421 | bool matched = false; |
422 | /* | ||
423 | * @insn can be modified by decode_regs. Save its original | ||
424 | * value for checkers. | ||
425 | */ | ||
426 | probes_opcode_t origin_insn = insn; | ||
427 | |||
428 | /* | ||
429 | * stack_space is initialized to 0 here. Checker functions | ||
430 | * should update is value if they find this is a stack store | ||
431 | * instruction: positive value means bytes of stack usage, | ||
432 | * negitive value means unable to determine stack usage | ||
433 | * statically. For instruction doesn't store to stack, checker | ||
434 | * do nothing with it. | ||
435 | */ | ||
436 | asi->stack_space = 0; | ||
437 | |||
438 | /* | ||
439 | * Similarly to stack_space, register_usage_flags is filled by | ||
440 | * checkers. Its default value is set to ~0, which is 'all | ||
441 | * registers are used', to prevent any potential optimization. | ||
442 | */ | ||
443 | asi->register_usage_flags = ~0UL; | ||
396 | 444 | ||
397 | if (emulate) | 445 | if (emulate) |
398 | insn = prepare_emulated_insn(insn, asi, thumb); | 446 | insn = prepare_emulated_insn(insn, asi, thumb); |
@@ -422,24 +470,41 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, | |||
422 | } | 470 | } |
423 | 471 | ||
424 | case DECODE_TYPE_CUSTOM: { | 472 | case DECODE_TYPE_CUSTOM: { |
473 | int err; | ||
425 | struct decode_custom *d = (struct decode_custom *)h; | 474 | struct decode_custom *d = (struct decode_custom *)h; |
426 | return actions[d->decoder.action].decoder(insn, asi, h); | 475 | int action = d->decoder.action; |
476 | |||
477 | err = run_checkers(checkers, action, origin_insn, asi, h); | ||
478 | if (err == INSN_REJECTED) | ||
479 | return INSN_REJECTED; | ||
480 | return actions[action].decoder(insn, asi, h); | ||
427 | } | 481 | } |
428 | 482 | ||
429 | case DECODE_TYPE_SIMULATE: { | 483 | case DECODE_TYPE_SIMULATE: { |
484 | int err; | ||
430 | struct decode_simulate *d = (struct decode_simulate *)h; | 485 | struct decode_simulate *d = (struct decode_simulate *)h; |
431 | asi->insn_handler = actions[d->handler.action].handler; | 486 | int action = d->handler.action; |
487 | |||
488 | err = run_checkers(checkers, action, origin_insn, asi, h); | ||
489 | if (err == INSN_REJECTED) | ||
490 | return INSN_REJECTED; | ||
491 | asi->insn_handler = actions[action].handler; | ||
432 | return INSN_GOOD_NO_SLOT; | 492 | return INSN_GOOD_NO_SLOT; |
433 | } | 493 | } |
434 | 494 | ||
435 | case DECODE_TYPE_EMULATE: { | 495 | case DECODE_TYPE_EMULATE: { |
496 | int err; | ||
436 | struct decode_emulate *d = (struct decode_emulate *)h; | 497 | struct decode_emulate *d = (struct decode_emulate *)h; |
498 | int action = d->handler.action; | ||
499 | |||
500 | err = run_checkers(checkers, action, origin_insn, asi, h); | ||
501 | if (err == INSN_REJECTED) | ||
502 | return INSN_REJECTED; | ||
437 | 503 | ||
438 | if (!emulate) | 504 | if (!emulate) |
439 | return actions[d->handler.action].decoder(insn, | 505 | return actions[action].decoder(insn, asi, h); |
440 | asi, h); | ||
441 | 506 | ||
442 | asi->insn_handler = actions[d->handler.action].handler; | 507 | asi->insn_handler = actions[action].handler; |
443 | set_emulated_insn(insn, asi, thumb); | 508 | set_emulated_insn(insn, asi, thumb); |
444 | return INSN_GOOD; | 509 | return INSN_GOOD; |
445 | } | 510 | } |
diff --git a/arch/arm/kernel/probes.h b/arch/arm/probes/decode.h index dba9f2466a93..f9b08ba7fe73 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/probes/decode.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/kernel/probes.h | 2 | * arch/arm/probes/decode.h |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. | 4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. |
5 | * | 5 | * |
@@ -314,6 +314,14 @@ union decode_action { | |||
314 | probes_custom_decode_t *decoder; | 314 | probes_custom_decode_t *decoder; |
315 | }; | 315 | }; |
316 | 316 | ||
317 | typedef enum probes_insn (probes_check_t)(probes_opcode_t, | ||
318 | struct arch_probes_insn *, | ||
319 | const struct decode_header *); | ||
320 | |||
321 | struct decode_checker { | ||
322 | probes_check_t *checker; | ||
323 | }; | ||
324 | |||
317 | #define DECODE_END \ | 325 | #define DECODE_END \ |
318 | {.bits = DECODE_TYPE_END} | 326 | {.bits = DECODE_TYPE_END} |
319 | 327 | ||
@@ -402,6 +410,7 @@ probes_insn_handler_t probes_emulate_none; | |||
402 | int __kprobes | 410 | int __kprobes |
403 | probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, | 411 | probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, |
404 | const union decode_item *table, bool thumb, bool emulate, | 412 | const union decode_item *table, bool thumb, bool emulate, |
405 | const union decode_action *actions); | 413 | const union decode_action *actions, |
414 | const struct decode_checker **checkers); | ||
406 | 415 | ||
407 | #endif | 416 | #endif |
diff --git a/arch/arm/probes/kprobes/Makefile b/arch/arm/probes/kprobes/Makefile new file mode 100644 index 000000000000..76a36bf102b7 --- /dev/null +++ b/arch/arm/probes/kprobes/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | obj-$(CONFIG_KPROBES) += core.o actions-common.o checkers-common.o | ||
2 | obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o | ||
3 | test-kprobes-objs := test-core.o | ||
4 | |||
5 | ifdef CONFIG_THUMB2_KERNEL | ||
6 | obj-$(CONFIG_KPROBES) += actions-thumb.o checkers-thumb.o | ||
7 | test-kprobes-objs += test-thumb.o | ||
8 | else | ||
9 | obj-$(CONFIG_KPROBES) += actions-arm.o checkers-arm.o | ||
10 | obj-$(CONFIG_OPTPROBES) += opt-arm.o | ||
11 | test-kprobes-objs += test-arm.o | ||
12 | endif | ||
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/probes/kprobes/actions-arm.c index ac300c60d656..b9056d649607 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/probes/kprobes/actions-arm.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/kernel/kprobes-decode.c | 2 | * arch/arm/probes/kprobes/actions-arm.c |
3 | * | 3 | * |
4 | * Copyright (C) 2006, 2007 Motorola Inc. | 4 | * Copyright (C) 2006, 2007 Motorola Inc. |
5 | * | 5 | * |
@@ -62,8 +62,9 @@ | |||
62 | #include <linux/kprobes.h> | 62 | #include <linux/kprobes.h> |
63 | #include <linux/ptrace.h> | 63 | #include <linux/ptrace.h> |
64 | 64 | ||
65 | #include "kprobes.h" | 65 | #include "../decode-arm.h" |
66 | #include "probes-arm.h" | 66 | #include "core.h" |
67 | #include "checkers.h" | ||
67 | 68 | ||
68 | #if __LINUX_ARM_ARCH__ >= 6 | 69 | #if __LINUX_ARM_ARCH__ >= 6 |
69 | #define BLX(reg) "blx "reg" \n\t" | 70 | #define BLX(reg) "blx "reg" \n\t" |
@@ -302,8 +303,6 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, | |||
302 | } | 303 | } |
303 | 304 | ||
304 | const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { | 305 | const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { |
305 | [PROBES_EMULATE_NONE] = {.handler = probes_emulate_none}, | ||
306 | [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop}, | ||
307 | [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, | 306 | [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, |
308 | [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, | 307 | [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, |
309 | [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, | 308 | [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, |
@@ -341,3 +340,5 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { | |||
341 | [PROBES_BRANCH] = {.handler = simulate_bbl}, | 340 | [PROBES_BRANCH] = {.handler = simulate_bbl}, |
342 | [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} | 341 | [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} |
343 | }; | 342 | }; |
343 | |||
344 | const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL}; | ||
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/probes/kprobes/actions-common.c index 0bf5d64eba1d..bd20a71cd34a 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/probes/kprobes/actions-common.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/kernel/kprobes-common.c | 2 | * arch/arm/probes/kprobes/actions-common.c |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. | 4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. |
5 | * | 5 | * |
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/kprobes.h> | 15 | #include <linux/kprobes.h> |
16 | #include <asm/opcodes.h> | 16 | #include <asm/opcodes.h> |
17 | 17 | ||
18 | #include "kprobes.h" | 18 | #include "core.h" |
19 | 19 | ||
20 | 20 | ||
21 | static void __kprobes simulate_ldm1stm1(probes_opcode_t insn, | 21 | static void __kprobes simulate_ldm1stm1(probes_opcode_t insn, |
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/probes/kprobes/actions-thumb.c index 9495d7f3516f..07cfd9bef340 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/probes/kprobes/actions-thumb.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/kernel/kprobes-thumb.c | 2 | * arch/arm/probes/kprobes/actions-thumb.c |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. | 4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. |
5 | * | 5 | * |
@@ -13,8 +13,9 @@ | |||
13 | #include <linux/ptrace.h> | 13 | #include <linux/ptrace.h> |
14 | #include <linux/kprobes.h> | 14 | #include <linux/kprobes.h> |
15 | 15 | ||
16 | #include "kprobes.h" | 16 | #include "../decode-thumb.h" |
17 | #include "probes-thumb.h" | 17 | #include "core.h" |
18 | #include "checkers.h" | ||
18 | 19 | ||
19 | /* These emulation encodings are functionally equivalent... */ | 20 | /* These emulation encodings are functionally equivalent... */ |
20 | #define t32_emulate_rd8rn16rm0ra12_noflags \ | 21 | #define t32_emulate_rd8rn16rm0ra12_noflags \ |
@@ -664,3 +665,6 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = { | |||
664 | [PROBES_T32_MUL_ADD_LONG] = { | 665 | [PROBES_T32_MUL_ADD_LONG] = { |
665 | .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, | 666 | .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, |
666 | }; | 667 | }; |
668 | |||
669 | const struct decode_checker *kprobes_t32_checkers[] = {t32_stack_checker, NULL}; | ||
670 | const struct decode_checker *kprobes_t16_checkers[] = {t16_stack_checker, NULL}; | ||
diff --git a/arch/arm/probes/kprobes/checkers-arm.c b/arch/arm/probes/kprobes/checkers-arm.c new file mode 100644 index 000000000000..7b9817333b68 --- /dev/null +++ b/arch/arm/probes/kprobes/checkers-arm.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * arch/arm/probes/kprobes/checkers-arm.c | ||
3 | * | ||
4 | * Copyright (C) 2014 Huawei Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include "../decode.h" | ||
18 | #include "../decode-arm.h" | ||
19 | #include "checkers.h" | ||
20 | |||
21 | static enum probes_insn __kprobes arm_check_stack(probes_opcode_t insn, | ||
22 | struct arch_probes_insn *asi, | ||
23 | const struct decode_header *h) | ||
24 | { | ||
25 | /* | ||
26 | * PROBES_LDRSTRD, PROBES_LDMSTM, PROBES_STORE, | ||
27 | * PROBES_STORE_EXTRA may get here. Simply mark all normal | ||
28 | * insns as STACK_USE_NONE. | ||
29 | */ | ||
30 | static const union decode_item table[] = { | ||
31 | /* | ||
32 | * 'STR{,D,B,H}, Rt, [Rn, Rm]' should be marked as UNKNOWN | ||
33 | * if Rn or Rm is SP. | ||
34 | * x | ||
35 | * STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx | ||
36 | * STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx | ||
37 | */ | ||
38 | DECODE_OR (0x0e10000f, 0x0600000d), | ||
39 | DECODE_OR (0x0e1f0000, 0x060d0000), | ||
40 | |||
41 | /* | ||
42 | * x | ||
43 | * STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx | ||
44 | * STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx | ||
45 | */ | ||
46 | DECODE_OR (0x0e5000bf, 0x000000bd), | ||
47 | DECODE_CUSTOM (0x0e5f00b0, 0x000d00b0, STACK_USE_UNKNOWN), | ||
48 | |||
49 | /* | ||
50 | * For PROBES_LDMSTM, only stmdx sp, [...] need to examine | ||
51 | * | ||
52 | * Bit B/A (bit 24) encodes arithmetic operation order. 1 means | ||
53 | * before, 0 means after. | ||
54 | * Bit I/D (bit 23) encodes arithmetic operation. 1 means | ||
55 | * increment, 0 means decrement. | ||
56 | * | ||
57 | * So: | ||
58 | * B I | ||
59 | * / / | ||
60 | * A D | Rn | | ||
61 | * STMDX SP, [...] cccc 100x 00x0 xxxx xxxx xxxx xxxx xxxx | ||
62 | */ | ||
63 | DECODE_CUSTOM (0x0edf0000, 0x080d0000, STACK_USE_STMDX), | ||
64 | |||
65 | /* P U W | Rn | Rt | imm12 |*/ | ||
66 | /* STR (immediate) cccc 010x x0x0 1101 xxxx xxxx xxxx xxxx */ | ||
67 | /* STRB (immediate) cccc 010x x1x0 1101 xxxx xxxx xxxx xxxx */ | ||
68 | /* P U W | Rn | Rt |imm4| |imm4|*/ | ||
69 | /* STRD (immediate) cccc 000x x1x0 1101 xxxx xxxx 1111 xxxx */ | ||
70 | /* STRH (immediate) cccc 000x x1x0 1101 xxxx xxxx 1011 xxxx */ | ||
71 | /* | ||
72 | * index = (P == '1'); add = (U == '1'). | ||
73 | * Above insns with: | ||
74 | * index == 0 (str{,d,h} rx, [sp], #+/-imm) or | ||
75 | * add == 1 (str{,d,h} rx, [sp, #+<imm>]) | ||
76 | * should be STACK_USE_NONE. | ||
77 | * Only str{,b,d,h} rx,[sp,#-n] (P == 1 and U == 0) are | ||
78 | * required to be examined. | ||
79 | */ | ||
80 | /* STR{,B} Rt,[SP,#-n] cccc 0101 0xx0 1101 xxxx xxxx xxxx xxxx */ | ||
81 | DECODE_CUSTOM (0x0f9f0000, 0x050d0000, STACK_USE_FIXED_XXX), | ||
82 | |||
83 | /* STR{D,H} Rt,[SP,#-n] cccc 0001 01x0 1101 xxxx xxxx 1x11 xxxx */ | ||
84 | DECODE_CUSTOM (0x0fdf00b0, 0x014d00b0, STACK_USE_FIXED_X0X), | ||
85 | |||
86 | /* fall through */ | ||
87 | DECODE_CUSTOM (0, 0, STACK_USE_NONE), | ||
88 | DECODE_END | ||
89 | }; | ||
90 | |||
91 | return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL); | ||
92 | } | ||
93 | |||
94 | const struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = { | ||
95 | [PROBES_LDRSTRD] = {.checker = arm_check_stack}, | ||
96 | [PROBES_STORE_EXTRA] = {.checker = arm_check_stack}, | ||
97 | [PROBES_STORE] = {.checker = arm_check_stack}, | ||
98 | [PROBES_LDMSTM] = {.checker = arm_check_stack}, | ||
99 | }; | ||
100 | |||
101 | static enum probes_insn __kprobes arm_check_regs_nouse(probes_opcode_t insn, | ||
102 | struct arch_probes_insn *asi, | ||
103 | const struct decode_header *h) | ||
104 | { | ||
105 | asi->register_usage_flags = 0; | ||
106 | return INSN_GOOD; | ||
107 | } | ||
108 | |||
109 | static enum probes_insn arm_check_regs_normal(probes_opcode_t insn, | ||
110 | struct arch_probes_insn *asi, | ||
111 | const struct decode_header *h) | ||
112 | { | ||
113 | u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; | ||
114 | int i; | ||
115 | |||
116 | asi->register_usage_flags = 0; | ||
117 | for (i = 0; i < 5; regs >>= 4, insn >>= 4, i++) | ||
118 | if (regs & 0xf) | ||
119 | asi->register_usage_flags |= 1 << (insn & 0xf); | ||
120 | |||
121 | return INSN_GOOD; | ||
122 | } | ||
123 | |||
124 | |||
125 | static enum probes_insn arm_check_regs_ldmstm(probes_opcode_t insn, | ||
126 | struct arch_probes_insn *asi, | ||
127 | const struct decode_header *h) | ||
128 | { | ||
129 | unsigned int reglist = insn & 0xffff; | ||
130 | unsigned int rn = (insn >> 16) & 0xf; | ||
131 | asi->register_usage_flags = reglist | (1 << rn); | ||
132 | return INSN_GOOD; | ||
133 | } | ||
134 | |||
135 | static enum probes_insn arm_check_regs_mov_ip_sp(probes_opcode_t insn, | ||
136 | struct arch_probes_insn *asi, | ||
137 | const struct decode_header *h) | ||
138 | { | ||
139 | /* Instruction is 'mov ip, sp' i.e. 'mov r12, r13' */ | ||
140 | asi->register_usage_flags = (1 << 12) | (1<< 13); | ||
141 | return INSN_GOOD; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * | Rn |Rt/d| | Rm | | ||
146 | * LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx | ||
147 | * STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx | ||
148 | * | Rn |Rt/d| |imm4L| | ||
149 | * LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx | ||
150 | * STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx | ||
151 | * | ||
152 | * Such instructions access Rt/d and its next register, so different | ||
153 | * from others, a specific checker is required to handle this extra | ||
154 | * implicit register usage. | ||
155 | */ | ||
156 | static enum probes_insn arm_check_regs_ldrdstrd(probes_opcode_t insn, | ||
157 | struct arch_probes_insn *asi, | ||
158 | const struct decode_header *h) | ||
159 | { | ||
160 | int rdt = (insn >> 12) & 0xf; | ||
161 | arm_check_regs_normal(insn, asi, h); | ||
162 | asi->register_usage_flags |= 1 << (rdt + 1); | ||
163 | return INSN_GOOD; | ||
164 | } | ||
165 | |||
166 | |||
167 | const struct decode_checker arm_regs_checker[NUM_PROBES_ARM_ACTIONS] = { | ||
168 | [PROBES_MRS] = {.checker = arm_check_regs_normal}, | ||
169 | [PROBES_SATURATING_ARITHMETIC] = {.checker = arm_check_regs_normal}, | ||
170 | [PROBES_MUL1] = {.checker = arm_check_regs_normal}, | ||
171 | [PROBES_MUL2] = {.checker = arm_check_regs_normal}, | ||
172 | [PROBES_MUL_ADD_LONG] = {.checker = arm_check_regs_normal}, | ||
173 | [PROBES_MUL_ADD] = {.checker = arm_check_regs_normal}, | ||
174 | [PROBES_LOAD] = {.checker = arm_check_regs_normal}, | ||
175 | [PROBES_LOAD_EXTRA] = {.checker = arm_check_regs_normal}, | ||
176 | [PROBES_STORE] = {.checker = arm_check_regs_normal}, | ||
177 | [PROBES_STORE_EXTRA] = {.checker = arm_check_regs_normal}, | ||
178 | [PROBES_DATA_PROCESSING_REG] = {.checker = arm_check_regs_normal}, | ||
179 | [PROBES_DATA_PROCESSING_IMM] = {.checker = arm_check_regs_normal}, | ||
180 | [PROBES_SEV] = {.checker = arm_check_regs_nouse}, | ||
181 | [PROBES_WFE] = {.checker = arm_check_regs_nouse}, | ||
182 | [PROBES_SATURATE] = {.checker = arm_check_regs_normal}, | ||
183 | [PROBES_REV] = {.checker = arm_check_regs_normal}, | ||
184 | [PROBES_MMI] = {.checker = arm_check_regs_normal}, | ||
185 | [PROBES_PACK] = {.checker = arm_check_regs_normal}, | ||
186 | [PROBES_EXTEND] = {.checker = arm_check_regs_normal}, | ||
187 | [PROBES_EXTEND_ADD] = {.checker = arm_check_regs_normal}, | ||
188 | [PROBES_BITFIELD] = {.checker = arm_check_regs_normal}, | ||
189 | [PROBES_LDMSTM] = {.checker = arm_check_regs_ldmstm}, | ||
190 | [PROBES_MOV_IP_SP] = {.checker = arm_check_regs_mov_ip_sp}, | ||
191 | [PROBES_LDRSTRD] = {.checker = arm_check_regs_ldrdstrd}, | ||
192 | }; | ||
diff --git a/arch/arm/probes/kprobes/checkers-common.c b/arch/arm/probes/kprobes/checkers-common.c new file mode 100644 index 000000000000..971119c29474 --- /dev/null +++ b/arch/arm/probes/kprobes/checkers-common.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * arch/arm/probes/kprobes/checkers-common.c | ||
3 | * | ||
4 | * Copyright (C) 2014 Huawei Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include "../decode.h" | ||
18 | #include "../decode-arm.h" | ||
19 | #include "checkers.h" | ||
20 | |||
21 | enum probes_insn checker_stack_use_none(probes_opcode_t insn, | ||
22 | struct arch_probes_insn *asi, | ||
23 | const struct decode_header *h) | ||
24 | { | ||
25 | asi->stack_space = 0; | ||
26 | return INSN_GOOD_NO_SLOT; | ||
27 | } | ||
28 | |||
29 | enum probes_insn checker_stack_use_unknown(probes_opcode_t insn, | ||
30 | struct arch_probes_insn *asi, | ||
31 | const struct decode_header *h) | ||
32 | { | ||
33 | asi->stack_space = -1; | ||
34 | return INSN_GOOD_NO_SLOT; | ||
35 | } | ||
36 | |||
37 | #ifdef CONFIG_THUMB2_KERNEL | ||
38 | enum probes_insn checker_stack_use_imm_0xx(probes_opcode_t insn, | ||
39 | struct arch_probes_insn *asi, | ||
40 | const struct decode_header *h) | ||
41 | { | ||
42 | int imm = insn & 0xff; | ||
43 | asi->stack_space = imm; | ||
44 | return INSN_GOOD_NO_SLOT; | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * Different from other insn uses imm8, the real addressing offset of | ||
49 | * STRD in T32 encoding should be imm8 * 4. See ARMARM description. | ||
50 | */ | ||
51 | enum probes_insn checker_stack_use_t32strd(probes_opcode_t insn, | ||
52 | struct arch_probes_insn *asi, | ||
53 | const struct decode_header *h) | ||
54 | { | ||
55 | int imm = insn & 0xff; | ||
56 | asi->stack_space = imm << 2; | ||
57 | return INSN_GOOD_NO_SLOT; | ||
58 | } | ||
59 | #else | ||
60 | enum probes_insn checker_stack_use_imm_x0x(probes_opcode_t insn, | ||
61 | struct arch_probes_insn *asi, | ||
62 | const struct decode_header *h) | ||
63 | { | ||
64 | int imm = ((insn & 0xf00) >> 4) + (insn & 0xf); | ||
65 | asi->stack_space = imm; | ||
66 | return INSN_GOOD_NO_SLOT; | ||
67 | } | ||
68 | #endif | ||
69 | |||
70 | enum probes_insn checker_stack_use_imm_xxx(probes_opcode_t insn, | ||
71 | struct arch_probes_insn *asi, | ||
72 | const struct decode_header *h) | ||
73 | { | ||
74 | int imm = insn & 0xfff; | ||
75 | asi->stack_space = imm; | ||
76 | return INSN_GOOD_NO_SLOT; | ||
77 | } | ||
78 | |||
79 | enum probes_insn checker_stack_use_stmdx(probes_opcode_t insn, | ||
80 | struct arch_probes_insn *asi, | ||
81 | const struct decode_header *h) | ||
82 | { | ||
83 | unsigned int reglist = insn & 0xffff; | ||
84 | int pbit = insn & (1 << 24); | ||
85 | asi->stack_space = (hweight32(reglist) - (!pbit ? 1 : 0)) * 4; | ||
86 | |||
87 | return INSN_GOOD_NO_SLOT; | ||
88 | } | ||
89 | |||
90 | const union decode_action stack_check_actions[] = { | ||
91 | [STACK_USE_NONE] = {.decoder = checker_stack_use_none}, | ||
92 | [STACK_USE_UNKNOWN] = {.decoder = checker_stack_use_unknown}, | ||
93 | #ifdef CONFIG_THUMB2_KERNEL | ||
94 | [STACK_USE_FIXED_0XX] = {.decoder = checker_stack_use_imm_0xx}, | ||
95 | [STACK_USE_T32STRD] = {.decoder = checker_stack_use_t32strd}, | ||
96 | #else | ||
97 | [STACK_USE_FIXED_X0X] = {.decoder = checker_stack_use_imm_x0x}, | ||
98 | #endif | ||
99 | [STACK_USE_FIXED_XXX] = {.decoder = checker_stack_use_imm_xxx}, | ||
100 | [STACK_USE_STMDX] = {.decoder = checker_stack_use_stmdx}, | ||
101 | }; | ||
diff --git a/arch/arm/probes/kprobes/checkers-thumb.c b/arch/arm/probes/kprobes/checkers-thumb.c new file mode 100644 index 000000000000..d608e3b9017a --- /dev/null +++ b/arch/arm/probes/kprobes/checkers-thumb.c | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * arch/arm/probes/kprobes/checkers-thumb.c | ||
3 | * | ||
4 | * Copyright (C) 2014 Huawei Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include "../decode.h" | ||
18 | #include "../decode-thumb.h" | ||
19 | #include "checkers.h" | ||
20 | |||
21 | static enum probes_insn __kprobes t32_check_stack(probes_opcode_t insn, | ||
22 | struct arch_probes_insn *asi, | ||
23 | const struct decode_header *h) | ||
24 | { | ||
25 | /* | ||
26 | * PROBES_T32_LDMSTM, PROBES_T32_LDRDSTRD and PROBES_T32_LDRSTR | ||
27 | * may get here. Simply mark all normal insns as STACK_USE_NONE. | ||
28 | */ | ||
29 | static const union decode_item table[] = { | ||
30 | |||
31 | /* | ||
32 | * First, filter out all ldr insns to make our life easier. | ||
33 | * Following load insns may come here: | ||
34 | * LDM, LDRD, LDR. | ||
35 | * In T32 encoding, bit 20 is enough for distinguishing | ||
36 | * load and store. All load insns have this bit set, when | ||
37 | * all store insns have this bit clear. | ||
38 | */ | ||
39 | DECODE_CUSTOM (0x00100000, 0x00100000, STACK_USE_NONE), | ||
40 | |||
41 | /* | ||
42 | * Mark all 'STR{,B,H}, Rt, [Rn, Rm]' as STACK_USE_UNKNOWN | ||
43 | * if Rn or Rm is SP. T32 doesn't encode STRD. | ||
44 | */ | ||
45 | /* xx | Rn | Rt | | Rm |*/ | ||
46 | /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ | ||
47 | /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ | ||
48 | /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ | ||
49 | /* INVALID INSN 1111 1000 0110 xxxx xxxx 0000 00xx xxxx */ | ||
50 | /* By Introducing INVALID INSN, bit 21 and 22 can be ignored. */ | ||
51 | DECODE_OR (0xff9f0fc0, 0xf80d0000), | ||
52 | DECODE_CUSTOM (0xff900fcf, 0xf800000d, STACK_USE_UNKNOWN), | ||
53 | |||
54 | |||
55 | /* xx | Rn | Rt | PUW| imm8 |*/ | ||
56 | /* STR (imm 8) 1111 1000 0100 1101 xxxx 110x xxxx xxxx */ | ||
57 | /* STRB (imm 8) 1111 1000 0000 1101 xxxx 110x xxxx xxxx */ | ||
58 | /* STRH (imm 8) 1111 1000 0010 1101 xxxx 110x xxxx xxxx */ | ||
59 | /* INVALID INSN 1111 1000 0110 1101 xxxx 110x xxxx xxxx */ | ||
60 | /* Only consider U == 0 and P == 1: strx rx, [sp, #-<imm>] */ | ||
61 | DECODE_CUSTOM (0xff9f0e00, 0xf80d0c00, STACK_USE_FIXED_0XX), | ||
62 | |||
63 | /* For STR{,B,H} (imm 12), offset is always positive, so ignore them. */ | ||
64 | |||
65 | /* P U W | Rn | Rt | Rt2| imm8 |*/ | ||
66 | /* STRD (immediate) 1110 1001 01x0 1101 xxxx xxxx xxxx xxxx */ | ||
67 | /* | ||
68 | * Only consider U == 0 and P == 1. | ||
69 | * Also note that STRD in T32 encoding is special: | ||
70 | * imm = ZeroExtend(imm8:'00', 32) | ||
71 | */ | ||
72 | DECODE_CUSTOM (0xffdf0000, 0xe94d0000, STACK_USE_T32STRD), | ||
73 | |||
74 | /* | Rn | */ | ||
75 | /* STMDB 1110 1001 00x0 1101 xxxx xxxx xxxx xxxx */ | ||
76 | DECODE_CUSTOM (0xffdf0000, 0xe90d0000, STACK_USE_STMDX), | ||
77 | |||
78 | /* fall through */ | ||
79 | DECODE_CUSTOM (0, 0, STACK_USE_NONE), | ||
80 | DECODE_END | ||
81 | }; | ||
82 | |||
83 | return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL); | ||
84 | } | ||
85 | |||
86 | const struct decode_checker t32_stack_checker[NUM_PROBES_T32_ACTIONS] = { | ||
87 | [PROBES_T32_LDMSTM] = {.checker = t32_check_stack}, | ||
88 | [PROBES_T32_LDRDSTRD] = {.checker = t32_check_stack}, | ||
89 | [PROBES_T32_LDRSTR] = {.checker = t32_check_stack}, | ||
90 | }; | ||
91 | |||
92 | /* | ||
93 | * See following comments. This insn must be 'push'. | ||
94 | */ | ||
95 | static enum probes_insn __kprobes t16_check_stack(probes_opcode_t insn, | ||
96 | struct arch_probes_insn *asi, | ||
97 | const struct decode_header *h) | ||
98 | { | ||
99 | unsigned int reglist = insn & 0x1ff; | ||
100 | asi->stack_space = hweight32(reglist) * 4; | ||
101 | return INSN_GOOD; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * T16 encoding is simple: only the 'push' insn can need extra stack space. | ||
106 | * Other insns, like str, can only use r0-r7 as Rn. | ||
107 | */ | ||
108 | const struct decode_checker t16_stack_checker[NUM_PROBES_T16_ACTIONS] = { | ||
109 | [PROBES_T16_PUSH] = {.checker = t16_check_stack}, | ||
110 | }; | ||
diff --git a/arch/arm/probes/kprobes/checkers.h b/arch/arm/probes/kprobes/checkers.h new file mode 100644 index 000000000000..cf6c9e74d666 --- /dev/null +++ b/arch/arm/probes/kprobes/checkers.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * arch/arm/probes/kprobes/checkers.h | ||
3 | * | ||
4 | * Copyright (C) 2014 Huawei Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | */ | ||
15 | #ifndef _ARM_KERNEL_PROBES_CHECKERS_H | ||
16 | #define _ARM_KERNEL_PROBES_CHECKERS_H | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/types.h> | ||
20 | #include "../decode.h" | ||
21 | |||
22 | extern probes_check_t checker_stack_use_none; | ||
23 | extern probes_check_t checker_stack_use_unknown; | ||
24 | #ifdef CONFIG_THUMB2_KERNEL | ||
25 | extern probes_check_t checker_stack_use_imm_0xx; | ||
26 | #else | ||
27 | extern probes_check_t checker_stack_use_imm_x0x; | ||
28 | #endif | ||
29 | extern probes_check_t checker_stack_use_imm_xxx; | ||
30 | extern probes_check_t checker_stack_use_stmdx; | ||
31 | |||
32 | enum { | ||
33 | STACK_USE_NONE, | ||
34 | STACK_USE_UNKNOWN, | ||
35 | #ifdef CONFIG_THUMB2_KERNEL | ||
36 | STACK_USE_FIXED_0XX, | ||
37 | STACK_USE_T32STRD, | ||
38 | #else | ||
39 | STACK_USE_FIXED_X0X, | ||
40 | #endif | ||
41 | STACK_USE_FIXED_XXX, | ||
42 | STACK_USE_STMDX, | ||
43 | NUM_STACK_USE_TYPES | ||
44 | }; | ||
45 | |||
46 | extern const union decode_action stack_check_actions[]; | ||
47 | |||
48 | #ifndef CONFIG_THUMB2_KERNEL | ||
49 | extern const struct decode_checker arm_stack_checker[]; | ||
50 | extern const struct decode_checker arm_regs_checker[]; | ||
51 | #else | ||
52 | #endif | ||
53 | extern const struct decode_checker t32_stack_checker[]; | ||
54 | extern const struct decode_checker t16_stack_checker[]; | ||
55 | #endif | ||
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/probes/kprobes/core.c index 6d644202c8dc..a4ec240ee7ba 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/probes/kprobes/core.c | |||
@@ -30,11 +30,11 @@ | |||
30 | #include <asm/cacheflush.h> | 30 | #include <asm/cacheflush.h> |
31 | #include <linux/percpu.h> | 31 | #include <linux/percpu.h> |
32 | #include <linux/bug.h> | 32 | #include <linux/bug.h> |
33 | #include <asm/patch.h> | ||
33 | 34 | ||
34 | #include "kprobes.h" | 35 | #include "../decode-arm.h" |
35 | #include "probes-arm.h" | 36 | #include "../decode-thumb.h" |
36 | #include "probes-thumb.h" | 37 | #include "core.h" |
37 | #include "patch.h" | ||
38 | 38 | ||
39 | #define MIN_STACK_SIZE(addr) \ | 39 | #define MIN_STACK_SIZE(addr) \ |
40 | min((unsigned long)MAX_STACK_SIZE, \ | 40 | min((unsigned long)MAX_STACK_SIZE, \ |
@@ -61,6 +61,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
61 | kprobe_decode_insn_t *decode_insn; | 61 | kprobe_decode_insn_t *decode_insn; |
62 | const union decode_action *actions; | 62 | const union decode_action *actions; |
63 | int is; | 63 | int is; |
64 | const struct decode_checker **checkers; | ||
64 | 65 | ||
65 | if (in_exception_text(addr)) | 66 | if (in_exception_text(addr)) |
66 | return -EINVAL; | 67 | return -EINVAL; |
@@ -74,9 +75,11 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
74 | insn = __opcode_thumb32_compose(insn, inst2); | 75 | insn = __opcode_thumb32_compose(insn, inst2); |
75 | decode_insn = thumb32_probes_decode_insn; | 76 | decode_insn = thumb32_probes_decode_insn; |
76 | actions = kprobes_t32_actions; | 77 | actions = kprobes_t32_actions; |
78 | checkers = kprobes_t32_checkers; | ||
77 | } else { | 79 | } else { |
78 | decode_insn = thumb16_probes_decode_insn; | 80 | decode_insn = thumb16_probes_decode_insn; |
79 | actions = kprobes_t16_actions; | 81 | actions = kprobes_t16_actions; |
82 | checkers = kprobes_t16_checkers; | ||
80 | } | 83 | } |
81 | #else /* !CONFIG_THUMB2_KERNEL */ | 84 | #else /* !CONFIG_THUMB2_KERNEL */ |
82 | thumb = false; | 85 | thumb = false; |
@@ -85,12 +88,13 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
85 | insn = __mem_to_opcode_arm(*p->addr); | 88 | insn = __mem_to_opcode_arm(*p->addr); |
86 | decode_insn = arm_probes_decode_insn; | 89 | decode_insn = arm_probes_decode_insn; |
87 | actions = kprobes_arm_actions; | 90 | actions = kprobes_arm_actions; |
91 | checkers = kprobes_arm_checkers; | ||
88 | #endif | 92 | #endif |
89 | 93 | ||
90 | p->opcode = insn; | 94 | p->opcode = insn; |
91 | p->ainsn.insn = tmp_insn; | 95 | p->ainsn.insn = tmp_insn; |
92 | 96 | ||
93 | switch ((*decode_insn)(insn, &p->ainsn, true, actions)) { | 97 | switch ((*decode_insn)(insn, &p->ainsn, true, actions, checkers)) { |
94 | case INSN_REJECTED: /* not supported */ | 98 | case INSN_REJECTED: /* not supported */ |
95 | return -EINVAL; | 99 | return -EINVAL; |
96 | 100 | ||
@@ -111,6 +115,15 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
111 | break; | 115 | break; |
112 | } | 116 | } |
113 | 117 | ||
118 | /* | ||
119 | * Never instrument insn like 'str r0, [sp, +/-r1]'. Also, insn likes | ||
120 | * 'str r0, [sp, #-68]' should also be prohibited. | ||
121 | * See __und_svc. | ||
122 | */ | ||
123 | if ((p->ainsn.stack_space < 0) || | ||
124 | (p->ainsn.stack_space > MAX_STACK_SIZE)) | ||
125 | return -EINVAL; | ||
126 | |||
114 | return 0; | 127 | return 0; |
115 | } | 128 | } |
116 | 129 | ||
@@ -150,19 +163,31 @@ void __kprobes arch_arm_kprobe(struct kprobe *p) | |||
150 | * memory. It is also needed to atomically set the two half-words of a 32-bit | 163 | * memory. It is also needed to atomically set the two half-words of a 32-bit |
151 | * Thumb breakpoint. | 164 | * Thumb breakpoint. |
152 | */ | 165 | */ |
153 | int __kprobes __arch_disarm_kprobe(void *p) | 166 | struct patch { |
154 | { | 167 | void *addr; |
155 | struct kprobe *kp = p; | 168 | unsigned int insn; |
156 | void *addr = (void *)((uintptr_t)kp->addr & ~1); | 169 | }; |
157 | |||
158 | __patch_text(addr, kp->opcode); | ||
159 | 170 | ||
171 | static int __kprobes_remove_breakpoint(void *data) | ||
172 | { | ||
173 | struct patch *p = data; | ||
174 | __patch_text(p->addr, p->insn); | ||
160 | return 0; | 175 | return 0; |
161 | } | 176 | } |
162 | 177 | ||
178 | void __kprobes kprobes_remove_breakpoint(void *addr, unsigned int insn) | ||
179 | { | ||
180 | struct patch p = { | ||
181 | .addr = addr, | ||
182 | .insn = insn, | ||
183 | }; | ||
184 | stop_machine(__kprobes_remove_breakpoint, &p, cpu_online_mask); | ||
185 | } | ||
186 | |||
163 | void __kprobes arch_disarm_kprobe(struct kprobe *p) | 187 | void __kprobes arch_disarm_kprobe(struct kprobe *p) |
164 | { | 188 | { |
165 | stop_machine(__arch_disarm_kprobe, p, cpu_online_mask); | 189 | kprobes_remove_breakpoint((void *)((uintptr_t)p->addr & ~1), |
190 | p->opcode); | ||
166 | } | 191 | } |
167 | 192 | ||
168 | void __kprobes arch_remove_kprobe(struct kprobe *p) | 193 | void __kprobes arch_remove_kprobe(struct kprobe *p) |
diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/probes/kprobes/core.h index 9a2712ecefc3..ec5d1f20a085 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/probes/kprobes/core.h | |||
@@ -19,7 +19,8 @@ | |||
19 | #ifndef _ARM_KERNEL_KPROBES_H | 19 | #ifndef _ARM_KERNEL_KPROBES_H |
20 | #define _ARM_KERNEL_KPROBES_H | 20 | #define _ARM_KERNEL_KPROBES_H |
21 | 21 | ||
22 | #include "probes.h" | 22 | #include <asm/kprobes.h> |
23 | #include "../decode.h" | ||
23 | 24 | ||
24 | /* | 25 | /* |
25 | * These undefined instructions must be unique and | 26 | * These undefined instructions must be unique and |
@@ -29,6 +30,8 @@ | |||
29 | #define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18 | 30 | #define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18 |
30 | #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 | 31 | #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 |
31 | 32 | ||
33 | extern void kprobes_remove_breakpoint(void *addr, unsigned int insn); | ||
34 | |||
32 | enum probes_insn __kprobes | 35 | enum probes_insn __kprobes |
33 | kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi, | 36 | kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi, |
34 | const struct decode_header *h); | 37 | const struct decode_header *h); |
@@ -36,16 +39,19 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi, | |||
36 | typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, | 39 | typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, |
37 | struct arch_probes_insn *, | 40 | struct arch_probes_insn *, |
38 | bool, | 41 | bool, |
39 | const union decode_action *); | 42 | const union decode_action *, |
43 | const struct decode_checker *[]); | ||
40 | 44 | ||
41 | #ifdef CONFIG_THUMB2_KERNEL | 45 | #ifdef CONFIG_THUMB2_KERNEL |
42 | 46 | ||
43 | extern const union decode_action kprobes_t32_actions[]; | 47 | extern const union decode_action kprobes_t32_actions[]; |
44 | extern const union decode_action kprobes_t16_actions[]; | 48 | extern const union decode_action kprobes_t16_actions[]; |
45 | 49 | extern const struct decode_checker *kprobes_t32_checkers[]; | |
50 | extern const struct decode_checker *kprobes_t16_checkers[]; | ||
46 | #else /* !CONFIG_THUMB2_KERNEL */ | 51 | #else /* !CONFIG_THUMB2_KERNEL */ |
47 | 52 | ||
48 | extern const union decode_action kprobes_arm_actions[]; | 53 | extern const union decode_action kprobes_arm_actions[]; |
54 | extern const struct decode_checker *kprobes_arm_checkers[]; | ||
49 | 55 | ||
50 | #endif | 56 | #endif |
51 | 57 | ||
diff --git a/arch/arm/probes/kprobes/opt-arm.c b/arch/arm/probes/kprobes/opt-arm.c new file mode 100644 index 000000000000..bcdecc25461b --- /dev/null +++ b/arch/arm/probes/kprobes/opt-arm.c | |||
@@ -0,0 +1,370 @@ | |||
1 | /* | ||
2 | * Kernel Probes Jump Optimization (Optprobes) | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | * | ||
18 | * Copyright (C) IBM Corporation, 2002, 2004 | ||
19 | * Copyright (C) Hitachi Ltd., 2012 | ||
20 | * Copyright (C) Huawei Inc., 2014 | ||
21 | */ | ||
22 | |||
23 | #include <linux/kprobes.h> | ||
24 | #include <linux/jump_label.h> | ||
25 | #include <asm/kprobes.h> | ||
26 | #include <asm/cacheflush.h> | ||
27 | /* for arm_gen_branch */ | ||
28 | #include <asm/insn.h> | ||
29 | /* for patch_text */ | ||
30 | #include <asm/patch.h> | ||
31 | |||
32 | #include "core.h" | ||
33 | |||
34 | /* | ||
35 | * See register_usage_flags. If the probed instruction doesn't use PC, | ||
36 | * we can copy it into template and have it executed directly without | ||
37 | * simulation or emulation. | ||
38 | */ | ||
39 | #define ARM_REG_PC 15 | ||
40 | #define can_kprobe_direct_exec(m) (!test_bit(ARM_REG_PC, &(m))) | ||
41 | |||
42 | /* | ||
43 | * NOTE: the first sub and add instruction will be modified according | ||
44 | * to the stack cost of the instruction. | ||
45 | */ | ||
46 | asm ( | ||
47 | ".global optprobe_template_entry\n" | ||
48 | "optprobe_template_entry:\n" | ||
49 | ".global optprobe_template_sub_sp\n" | ||
50 | "optprobe_template_sub_sp:" | ||
51 | " sub sp, sp, #0xff\n" | ||
52 | " stmia sp, {r0 - r14} \n" | ||
53 | ".global optprobe_template_add_sp\n" | ||
54 | "optprobe_template_add_sp:" | ||
55 | " add r3, sp, #0xff\n" | ||
56 | " str r3, [sp, #52]\n" | ||
57 | " mrs r4, cpsr\n" | ||
58 | " str r4, [sp, #64]\n" | ||
59 | " mov r1, sp\n" | ||
60 | " ldr r0, 1f\n" | ||
61 | " ldr r2, 2f\n" | ||
62 | /* | ||
63 | * AEABI requires an 8-bytes alignment stack. If | ||
64 | * SP % 8 != 0 (SP % 4 == 0 should be ensured), | ||
65 | * alloc more bytes here. | ||
66 | */ | ||
67 | " and r4, sp, #4\n" | ||
68 | " sub sp, sp, r4\n" | ||
69 | #if __LINUX_ARM_ARCH__ >= 5 | ||
70 | " blx r2\n" | ||
71 | #else | ||
72 | " mov lr, pc\n" | ||
73 | " mov pc, r2\n" | ||
74 | #endif | ||
75 | " add sp, sp, r4\n" | ||
76 | " ldr r1, [sp, #64]\n" | ||
77 | " tst r1, #"__stringify(PSR_T_BIT)"\n" | ||
78 | " ldrne r2, [sp, #60]\n" | ||
79 | " orrne r2, #1\n" | ||
80 | " strne r2, [sp, #60] @ set bit0 of PC for thumb\n" | ||
81 | " msr cpsr_cxsf, r1\n" | ||
82 | ".global optprobe_template_restore_begin\n" | ||
83 | "optprobe_template_restore_begin:\n" | ||
84 | " ldmia sp, {r0 - r15}\n" | ||
85 | ".global optprobe_template_restore_orig_insn\n" | ||
86 | "optprobe_template_restore_orig_insn:\n" | ||
87 | " nop\n" | ||
88 | ".global optprobe_template_restore_end\n" | ||
89 | "optprobe_template_restore_end:\n" | ||
90 | " nop\n" | ||
91 | ".global optprobe_template_val\n" | ||
92 | "optprobe_template_val:\n" | ||
93 | "1: .long 0\n" | ||
94 | ".global optprobe_template_call\n" | ||
95 | "optprobe_template_call:\n" | ||
96 | "2: .long 0\n" | ||
97 | ".global optprobe_template_end\n" | ||
98 | "optprobe_template_end:\n"); | ||
99 | |||
100 | #define TMPL_VAL_IDX \ | ||
101 | ((unsigned long *)&optprobe_template_val - (unsigned long *)&optprobe_template_entry) | ||
102 | #define TMPL_CALL_IDX \ | ||
103 | ((unsigned long *)&optprobe_template_call - (unsigned long *)&optprobe_template_entry) | ||
104 | #define TMPL_END_IDX \ | ||
105 | ((unsigned long *)&optprobe_template_end - (unsigned long *)&optprobe_template_entry) | ||
106 | #define TMPL_ADD_SP \ | ||
107 | ((unsigned long *)&optprobe_template_add_sp - (unsigned long *)&optprobe_template_entry) | ||
108 | #define TMPL_SUB_SP \ | ||
109 | ((unsigned long *)&optprobe_template_sub_sp - (unsigned long *)&optprobe_template_entry) | ||
110 | #define TMPL_RESTORE_BEGIN \ | ||
111 | ((unsigned long *)&optprobe_template_restore_begin - (unsigned long *)&optprobe_template_entry) | ||
112 | #define TMPL_RESTORE_ORIGN_INSN \ | ||
113 | ((unsigned long *)&optprobe_template_restore_orig_insn - (unsigned long *)&optprobe_template_entry) | ||
114 | #define TMPL_RESTORE_END \ | ||
115 | ((unsigned long *)&optprobe_template_restore_end - (unsigned long *)&optprobe_template_entry) | ||
116 | |||
117 | /* | ||
118 | * ARM can always optimize an instruction when using ARM ISA, except | ||
119 | * instructions like 'str r0, [sp, r1]' which store to stack and unable | ||
120 | * to determine stack space consumption statically. | ||
121 | */ | ||
122 | int arch_prepared_optinsn(struct arch_optimized_insn *optinsn) | ||
123 | { | ||
124 | return optinsn->insn != NULL; | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * In ARM ISA, kprobe opt always replace one instruction (4 bytes | ||
129 | * aligned and 4 bytes long). It is impossible to encounter another | ||
130 | * kprobe in the address range. So always return 0. | ||
131 | */ | ||
132 | int arch_check_optimized_kprobe(struct optimized_kprobe *op) | ||
133 | { | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | /* Caller must ensure addr & 3 == 0 */ | ||
138 | static int can_optimize(struct kprobe *kp) | ||
139 | { | ||
140 | if (kp->ainsn.stack_space < 0) | ||
141 | return 0; | ||
142 | /* | ||
143 | * 255 is the biggest imm can be used in 'sub r0, r0, #<imm>'. | ||
144 | * Number larger than 255 needs special encoding. | ||
145 | */ | ||
146 | if (kp->ainsn.stack_space > 255 - sizeof(struct pt_regs)) | ||
147 | return 0; | ||
148 | return 1; | ||
149 | } | ||
150 | |||
151 | /* Free optimized instruction slot */ | ||
152 | static void | ||
153 | __arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty) | ||
154 | { | ||
155 | if (op->optinsn.insn) { | ||
156 | free_optinsn_slot(op->optinsn.insn, dirty); | ||
157 | op->optinsn.insn = NULL; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | extern void kprobe_handler(struct pt_regs *regs); | ||
162 | |||
163 | static void | ||
164 | optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs) | ||
165 | { | ||
166 | unsigned long flags; | ||
167 | struct kprobe *p = &op->kp; | ||
168 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
169 | |||
170 | /* Save skipped registers */ | ||
171 | regs->ARM_pc = (unsigned long)op->kp.addr; | ||
172 | regs->ARM_ORIG_r0 = ~0UL; | ||
173 | |||
174 | local_irq_save(flags); | ||
175 | |||
176 | if (kprobe_running()) { | ||
177 | kprobes_inc_nmissed_count(&op->kp); | ||
178 | } else { | ||
179 | __this_cpu_write(current_kprobe, &op->kp); | ||
180 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; | ||
181 | opt_pre_handler(&op->kp, regs); | ||
182 | __this_cpu_write(current_kprobe, NULL); | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * We singlestep the replaced instruction only when it can't be | ||
187 | * executed directly during restore. | ||
188 | */ | ||
189 | if (!p->ainsn.kprobe_direct_exec) | ||
190 | op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs); | ||
191 | |||
192 | local_irq_restore(flags); | ||
193 | } | ||
194 | |||
195 | int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *orig) | ||
196 | { | ||
197 | kprobe_opcode_t *code; | ||
198 | unsigned long rel_chk; | ||
199 | unsigned long val; | ||
200 | unsigned long stack_protect = sizeof(struct pt_regs); | ||
201 | |||
202 | if (!can_optimize(orig)) | ||
203 | return -EILSEQ; | ||
204 | |||
205 | code = get_optinsn_slot(); | ||
206 | if (!code) | ||
207 | return -ENOMEM; | ||
208 | |||
209 | /* | ||
210 | * Verify if the address gap is in 32MiB range, because this uses | ||
211 | * a relative jump. | ||
212 | * | ||
213 | * kprobe opt use a 'b' instruction to branch to optinsn.insn. | ||
214 | * According to ARM manual, branch instruction is: | ||
215 | * | ||
216 | * 31 28 27 24 23 0 | ||
217 | * +------+---+---+---+---+----------------+ | ||
218 | * | cond | 1 | 0 | 1 | 0 | imm24 | | ||
219 | * +------+---+---+---+---+----------------+ | ||
220 | * | ||
221 | * imm24 is a signed 24 bits integer. The real branch offset is computed | ||
222 | * by: imm32 = SignExtend(imm24:'00', 32); | ||
223 | * | ||
224 | * So the maximum forward branch should be: | ||
225 | * (0x007fffff << 2) = 0x01fffffc = 0x1fffffc | ||
226 | * The maximum backword branch should be: | ||
227 | * (0xff800000 << 2) = 0xfe000000 = -0x2000000 | ||
228 | * | ||
229 | * We can simply check (rel & 0xfe000003): | ||
230 | * if rel is positive, (rel & 0xfe000000) shoule be 0 | ||
231 | * if rel is negitive, (rel & 0xfe000000) should be 0xfe000000 | ||
232 | * the last '3' is used for alignment checking. | ||
233 | */ | ||
234 | rel_chk = (unsigned long)((long)code - | ||
235 | (long)orig->addr + 8) & 0xfe000003; | ||
236 | |||
237 | if ((rel_chk != 0) && (rel_chk != 0xfe000000)) { | ||
238 | /* | ||
239 | * Different from x86, we free code buf directly instead of | ||
240 | * calling __arch_remove_optimized_kprobe() because | ||
241 | * we have not fill any field in op. | ||
242 | */ | ||
243 | free_optinsn_slot(code, 0); | ||
244 | return -ERANGE; | ||
245 | } | ||
246 | |||
247 | /* Copy arch-dep-instance from template. */ | ||
248 | memcpy(code, &optprobe_template_entry, | ||
249 | TMPL_END_IDX * sizeof(kprobe_opcode_t)); | ||
250 | |||
251 | /* Adjust buffer according to instruction. */ | ||
252 | BUG_ON(orig->ainsn.stack_space < 0); | ||
253 | |||
254 | stack_protect += orig->ainsn.stack_space; | ||
255 | |||
256 | /* Should have been filtered by can_optimize(). */ | ||
257 | BUG_ON(stack_protect > 255); | ||
258 | |||
259 | /* Create a 'sub sp, sp, #<stack_protect>' */ | ||
260 | code[TMPL_SUB_SP] = __opcode_to_mem_arm(0xe24dd000 | stack_protect); | ||
261 | /* Create a 'add r3, sp, #<stack_protect>' */ | ||
262 | code[TMPL_ADD_SP] = __opcode_to_mem_arm(0xe28d3000 | stack_protect); | ||
263 | |||
264 | /* Set probe information */ | ||
265 | val = (unsigned long)op; | ||
266 | code[TMPL_VAL_IDX] = val; | ||
267 | |||
268 | /* Set probe function call */ | ||
269 | val = (unsigned long)optimized_callback; | ||
270 | code[TMPL_CALL_IDX] = val; | ||
271 | |||
272 | /* If possible, copy insn and have it executed during restore */ | ||
273 | orig->ainsn.kprobe_direct_exec = false; | ||
274 | if (can_kprobe_direct_exec(orig->ainsn.register_usage_flags)) { | ||
275 | kprobe_opcode_t final_branch = arm_gen_branch( | ||
276 | (unsigned long)(&code[TMPL_RESTORE_END]), | ||
277 | (unsigned long)(op->kp.addr) + 4); | ||
278 | if (final_branch != 0) { | ||
279 | /* | ||
280 | * Replace original 'ldmia sp, {r0 - r15}' with | ||
281 | * 'ldmia {r0 - r14}', restore all registers except pc. | ||
282 | */ | ||
283 | code[TMPL_RESTORE_BEGIN] = __opcode_to_mem_arm(0xe89d7fff); | ||
284 | |||
285 | /* The original probed instruction */ | ||
286 | code[TMPL_RESTORE_ORIGN_INSN] = __opcode_to_mem_arm(orig->opcode); | ||
287 | |||
288 | /* Jump back to next instruction */ | ||
289 | code[TMPL_RESTORE_END] = __opcode_to_mem_arm(final_branch); | ||
290 | orig->ainsn.kprobe_direct_exec = true; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | flush_icache_range((unsigned long)code, | ||
295 | (unsigned long)(&code[TMPL_END_IDX])); | ||
296 | |||
297 | /* Set op->optinsn.insn means prepared. */ | ||
298 | op->optinsn.insn = code; | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | void __kprobes arch_optimize_kprobes(struct list_head *oplist) | ||
303 | { | ||
304 | struct optimized_kprobe *op, *tmp; | ||
305 | |||
306 | list_for_each_entry_safe(op, tmp, oplist, list) { | ||
307 | unsigned long insn; | ||
308 | WARN_ON(kprobe_disabled(&op->kp)); | ||
309 | |||
310 | /* | ||
311 | * Backup instructions which will be replaced | ||
312 | * by jump address | ||
313 | */ | ||
314 | memcpy(op->optinsn.copied_insn, op->kp.addr, | ||
315 | RELATIVEJUMP_SIZE); | ||
316 | |||
317 | insn = arm_gen_branch((unsigned long)op->kp.addr, | ||
318 | (unsigned long)op->optinsn.insn); | ||
319 | BUG_ON(insn == 0); | ||
320 | |||
321 | /* | ||
322 | * Make it a conditional branch if replaced insn | ||
323 | * is consitional | ||
324 | */ | ||
325 | insn = (__mem_to_opcode_arm( | ||
326 | op->optinsn.copied_insn[0]) & 0xf0000000) | | ||
327 | (insn & 0x0fffffff); | ||
328 | |||
329 | /* | ||
330 | * Similar to __arch_disarm_kprobe, operations which | ||
331 | * removing breakpoints must be wrapped by stop_machine | ||
332 | * to avoid racing. | ||
333 | */ | ||
334 | kprobes_remove_breakpoint(op->kp.addr, insn); | ||
335 | |||
336 | list_del_init(&op->list); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | void arch_unoptimize_kprobe(struct optimized_kprobe *op) | ||
341 | { | ||
342 | arch_arm_kprobe(&op->kp); | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * Recover original instructions and breakpoints from relative jumps. | ||
347 | * Caller must call with locking kprobe_mutex. | ||
348 | */ | ||
349 | void arch_unoptimize_kprobes(struct list_head *oplist, | ||
350 | struct list_head *done_list) | ||
351 | { | ||
352 | struct optimized_kprobe *op, *tmp; | ||
353 | |||
354 | list_for_each_entry_safe(op, tmp, oplist, list) { | ||
355 | arch_unoptimize_kprobe(op); | ||
356 | list_move(&op->list, done_list); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | int arch_within_optimized_kprobe(struct optimized_kprobe *op, | ||
361 | unsigned long addr) | ||
362 | { | ||
363 | return ((unsigned long)op->kp.addr <= addr && | ||
364 | (unsigned long)op->kp.addr + RELATIVEJUMP_SIZE > addr); | ||
365 | } | ||
366 | |||
367 | void arch_remove_optimized_kprobe(struct optimized_kprobe *op) | ||
368 | { | ||
369 | __arch_remove_optimized_kprobe(op, 1); | ||
370 | } | ||
diff --git a/arch/arm/kernel/kprobes-test-arm.c b/arch/arm/probes/kprobes/test-arm.c index cb1424240ff6..8866aedfdea2 100644 --- a/arch/arm/kernel/kprobes-test-arm.c +++ b/arch/arm/probes/kprobes/test-arm.c | |||
@@ -12,8 +12,9 @@ | |||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <asm/system_info.h> | 13 | #include <asm/system_info.h> |
14 | #include <asm/opcodes.h> | 14 | #include <asm/opcodes.h> |
15 | #include <asm/probes.h> | ||
15 | 16 | ||
16 | #include "kprobes-test.h" | 17 | #include "test-core.h" |
17 | 18 | ||
18 | 19 | ||
19 | #define TEST_ISA "32" | 20 | #define TEST_ISA "32" |
@@ -203,9 +204,9 @@ void kprobe_arm_test_cases(void) | |||
203 | #endif | 204 | #endif |
204 | TEST_GROUP("Miscellaneous instructions") | 205 | TEST_GROUP("Miscellaneous instructions") |
205 | 206 | ||
206 | TEST("mrs r0, cpsr") | 207 | TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr") |
207 | TEST("mrspl r7, cpsr") | 208 | TEST_RMASKED("mrspl r",7,~PSR_IGNORE_BITS,", cpsr") |
208 | TEST("mrs r14, cpsr") | 209 | TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr") |
209 | TEST_UNSUPPORTED(__inst_arm(0xe10ff000) " @ mrs r15, cpsr") | 210 | TEST_UNSUPPORTED(__inst_arm(0xe10ff000) " @ mrs r15, cpsr") |
210 | TEST_UNSUPPORTED("mrs r0, spsr") | 211 | TEST_UNSUPPORTED("mrs r0, spsr") |
211 | TEST_UNSUPPORTED("mrs lr, spsr") | 212 | TEST_UNSUPPORTED("mrs lr, spsr") |
@@ -214,9 +215,12 @@ void kprobe_arm_test_cases(void) | |||
214 | TEST_UNSUPPORTED("msr cpsr_f, lr") | 215 | TEST_UNSUPPORTED("msr cpsr_f, lr") |
215 | TEST_UNSUPPORTED("msr spsr, r0") | 216 | TEST_UNSUPPORTED("msr spsr, r0") |
216 | 217 | ||
218 | #if __LINUX_ARM_ARCH__ >= 5 || \ | ||
219 | (__LINUX_ARM_ARCH__ == 4 && !defined(CONFIG_CPU_32v4)) | ||
217 | TEST_BF_R("bx r",0,2f,"") | 220 | TEST_BF_R("bx r",0,2f,"") |
218 | TEST_BB_R("bx r",7,2f,"") | 221 | TEST_BB_R("bx r",7,2f,"") |
219 | TEST_BF_R("bxeq r",14,2f,"") | 222 | TEST_BF_R("bxeq r",14,2f,"") |
223 | #endif | ||
220 | 224 | ||
221 | #if __LINUX_ARM_ARCH__ >= 5 | 225 | #if __LINUX_ARM_ARCH__ >= 5 |
222 | TEST_R("clz r0, r",0, 0x0,"") | 226 | TEST_R("clz r0, r",0, 0x0,"") |
@@ -476,7 +480,9 @@ void kprobe_arm_test_cases(void) | |||
476 | TEST_GROUP("Extra load/store instructions") | 480 | TEST_GROUP("Extra load/store instructions") |
477 | 481 | ||
478 | TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") | 482 | TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") |
479 | TEST_RPR( "streqh r",14,VAL2,", [r",13,0, ", r",12, 48,"]") | 483 | TEST_RPR( "streqh r",14,VAL2,", [r",11,0, ", r",12, 48,"]") |
484 | TEST_UNSUPPORTED( "streqh r14, [r13, r12]") | ||
485 | TEST_UNSUPPORTED( "streqh r14, [r12, r13]") | ||
480 | TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") | 486 | TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") |
481 | TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!") | 487 | TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!") |
482 | TEST_RPR( "strh r",2, VAL1,", [r",3, 24,"], r",4, 48,"") | 488 | TEST_RPR( "strh r",2, VAL1,", [r",3, 24,"], r",4, 48,"") |
@@ -501,6 +507,9 @@ void kprobe_arm_test_cases(void) | |||
501 | TEST_RP( "strplh r",12,VAL2,", [r",11,24,", #-4]!") | 507 | TEST_RP( "strplh r",12,VAL2,", [r",11,24,", #-4]!") |
502 | TEST_RP( "strh r",2, VAL1,", [r",3, 24,"], #48") | 508 | TEST_RP( "strh r",2, VAL1,", [r",3, 24,"], #48") |
503 | TEST_RP( "strh r",10,VAL2,", [r",9, 64,"], #-48") | 509 | TEST_RP( "strh r",10,VAL2,", [r",9, 64,"], #-48") |
510 | TEST_RP( "strh r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") | ||
511 | TEST_UNSUPPORTED("strh r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") | ||
512 | TEST_RP( "strh r",4, VAL1,", [r",14,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") | ||
504 | TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) " @ strh r12, [pc, #48]!") | 513 | TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) " @ strh r12, [pc, #48]!") |
505 | TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) " @ strh pc, [r9], #48") | 514 | TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) " @ strh pc, [r9], #48") |
506 | 515 | ||
@@ -565,7 +574,9 @@ void kprobe_arm_test_cases(void) | |||
565 | 574 | ||
566 | #if __LINUX_ARM_ARCH__ >= 5 | 575 | #if __LINUX_ARM_ARCH__ >= 5 |
567 | TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]") | 576 | TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]") |
568 | TEST_RPR( "strccd r",8, VAL2,", [r",13,0, ", r",12,48,"]") | 577 | TEST_RPR( "strccd r",8, VAL2,", [r",11,0, ", r",12,48,"]") |
578 | TEST_UNSUPPORTED( "strccd r8, [r13, r12]") | ||
579 | TEST_UNSUPPORTED( "strccd r8, [r12, r13]") | ||
569 | TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!") | 580 | TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!") |
570 | TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!") | 581 | TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!") |
571 | TEST_RPR( "strd r",2, VAL1,", [r",5, 24,"], r",4,48,"") | 582 | TEST_RPR( "strd r",2, VAL1,", [r",5, 24,"], r",4,48,"") |
@@ -589,6 +600,9 @@ void kprobe_arm_test_cases(void) | |||
589 | TEST_RP( "strvcd r",12,VAL2,", [r",11,24,", #-16]!") | 600 | TEST_RP( "strvcd r",12,VAL2,", [r",11,24,", #-16]!") |
590 | TEST_RP( "strd r",2, VAL1,", [r",4, 24,"], #48") | 601 | TEST_RP( "strd r",2, VAL1,", [r",4, 24,"], #48") |
591 | TEST_RP( "strd r",10,VAL2,", [r",9, 64,"], #-48") | 602 | TEST_RP( "strd r",10,VAL2,", [r",9, 64,"], #-48") |
603 | TEST_RP( "strd r",6, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") | ||
604 | TEST_UNSUPPORTED("strd r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") | ||
605 | TEST_RP( "strd r",4, VAL1,", [r",12,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") | ||
592 | TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) " @ strd r12, [pc, #48]!") | 606 | TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) " @ strd r12, [pc, #48]!") |
593 | 607 | ||
594 | TEST_P( "ldrd r0, [r",0, 24,", #-8]") | 608 | TEST_P( "ldrd r0, [r",0, 24,", #-8]") |
@@ -637,14 +651,20 @@ void kprobe_arm_test_cases(void) | |||
637 | TEST_RP( "str"byte" r",12,VAL2,", [r",11,24,", #-4]!") \ | 651 | TEST_RP( "str"byte" r",12,VAL2,", [r",11,24,", #-4]!") \ |
638 | TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \ | 652 | TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \ |
639 | TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \ | 653 | TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \ |
654 | TEST_RP( "str"byte" r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ | ||
655 | TEST_UNSUPPORTED("str"byte" r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ | ||
656 | TEST_RP( "str"byte" r",4, VAL1,", [r",10,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ | ||
640 | TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \ | 657 | TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \ |
641 | TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 48,"]") \ | 658 | TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 48,"]") \ |
659 | TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \ | ||
660 | TEST_UNSUPPORTED("str"byte" r14, [r12, r13]") \ | ||
642 | TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \ | 661 | TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \ |
643 | TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \ | 662 | TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \ |
644 | TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \ | 663 | TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \ |
645 | TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \ | 664 | TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \ |
646 | TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\ | 665 | TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\ |
647 | TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 32,", lsr #2]")\ | 666 | TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 32,", lsr #2]")\ |
667 | TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]") \ | ||
648 | TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\ | 668 | TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\ |
649 | TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\ | 669 | TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\ |
650 | TEST_P( "ldr"byte" r0, [r",0, 24,", #-2]") \ | 670 | TEST_P( "ldr"byte" r0, [r",0, 24,", #-2]") \ |
@@ -668,12 +688,12 @@ void kprobe_arm_test_cases(void) | |||
668 | 688 | ||
669 | LOAD_STORE("") | 689 | LOAD_STORE("") |
670 | TEST_P( "str pc, [r",0,0,", #15*4]") | 690 | TEST_P( "str pc, [r",0,0,", #15*4]") |
671 | TEST_R( "str pc, [sp, r",2,15*4,"]") | 691 | TEST_UNSUPPORTED( "str pc, [sp, r2]") |
672 | TEST_BF( "ldr pc, [sp, #15*4]") | 692 | TEST_BF( "ldr pc, [sp, #15*4]") |
673 | TEST_BF_R("ldr pc, [sp, r",2,15*4,"]") | 693 | TEST_BF_R("ldr pc, [sp, r",2,15*4,"]") |
674 | 694 | ||
675 | TEST_P( "str sp, [r",0,0,", #13*4]") | 695 | TEST_P( "str sp, [r",0,0,", #13*4]") |
676 | TEST_R( "str sp, [sp, r",2,13*4,"]") | 696 | TEST_UNSUPPORTED( "str sp, [sp, r2]") |
677 | TEST_BF( "ldr sp, [sp, #13*4]") | 697 | TEST_BF( "ldr sp, [sp, #13*4]") |
678 | TEST_BF_R("ldr sp, [sp, r",2,13*4,"]") | 698 | TEST_BF_R("ldr sp, [sp, r",2,13*4,"]") |
679 | 699 | ||
diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/probes/kprobes/test-core.c index b206d7790c77..9775de22e2ff 100644 --- a/arch/arm/kernel/kprobes-test.c +++ b/arch/arm/probes/kprobes/test-core.c | |||
@@ -209,10 +209,10 @@ | |||
209 | #include <linux/bug.h> | 209 | #include <linux/bug.h> |
210 | #include <asm/opcodes.h> | 210 | #include <asm/opcodes.h> |
211 | 211 | ||
212 | #include "kprobes.h" | 212 | #include "core.h" |
213 | #include "probes-arm.h" | 213 | #include "test-core.h" |
214 | #include "probes-thumb.h" | 214 | #include "../decode-arm.h" |
215 | #include "kprobes-test.h" | 215 | #include "../decode-thumb.h" |
216 | 216 | ||
217 | 217 | ||
218 | #define BENCHMARKING 1 | 218 | #define BENCHMARKING 1 |
@@ -236,6 +236,8 @@ static int tests_failed; | |||
236 | 236 | ||
237 | #ifndef CONFIG_THUMB2_KERNEL | 237 | #ifndef CONFIG_THUMB2_KERNEL |
238 | 238 | ||
239 | #define RET(reg) "mov pc, "#reg | ||
240 | |||
239 | long arm_func(long r0, long r1); | 241 | long arm_func(long r0, long r1); |
240 | 242 | ||
241 | static void __used __naked __arm_kprobes_test_func(void) | 243 | static void __used __naked __arm_kprobes_test_func(void) |
@@ -245,7 +247,7 @@ static void __used __naked __arm_kprobes_test_func(void) | |||
245 | ".type arm_func, %%function \n\t" | 247 | ".type arm_func, %%function \n\t" |
246 | "arm_func: \n\t" | 248 | "arm_func: \n\t" |
247 | "adds r0, r0, r1 \n\t" | 249 | "adds r0, r0, r1 \n\t" |
248 | "bx lr \n\t" | 250 | "mov pc, lr \n\t" |
249 | ".code "NORMAL_ISA /* Back to Thumb if necessary */ | 251 | ".code "NORMAL_ISA /* Back to Thumb if necessary */ |
250 | : : : "r0", "r1", "cc" | 252 | : : : "r0", "r1", "cc" |
251 | ); | 253 | ); |
@@ -253,6 +255,8 @@ static void __used __naked __arm_kprobes_test_func(void) | |||
253 | 255 | ||
254 | #else /* CONFIG_THUMB2_KERNEL */ | 256 | #else /* CONFIG_THUMB2_KERNEL */ |
255 | 257 | ||
258 | #define RET(reg) "bx "#reg | ||
259 | |||
256 | long thumb16_func(long r0, long r1); | 260 | long thumb16_func(long r0, long r1); |
257 | long thumb32even_func(long r0, long r1); | 261 | long thumb32even_func(long r0, long r1); |
258 | long thumb32odd_func(long r0, long r1); | 262 | long thumb32odd_func(long r0, long r1); |
@@ -494,7 +498,7 @@ static void __naked benchmark_nop(void) | |||
494 | { | 498 | { |
495 | __asm__ __volatile__ ( | 499 | __asm__ __volatile__ ( |
496 | "nop \n\t" | 500 | "nop \n\t" |
497 | "bx lr" | 501 | RET(lr)" \n\t" |
498 | ); | 502 | ); |
499 | } | 503 | } |
500 | 504 | ||
@@ -977,7 +981,7 @@ void __naked __kprobes_test_case_start(void) | |||
977 | "bic r0, lr, #1 @ r0 = inline data \n\t" | 981 | "bic r0, lr, #1 @ r0 = inline data \n\t" |
978 | "mov r1, sp \n\t" | 982 | "mov r1, sp \n\t" |
979 | "bl kprobes_test_case_start \n\t" | 983 | "bl kprobes_test_case_start \n\t" |
980 | "bx r0 \n\t" | 984 | RET(r0)" \n\t" |
981 | ); | 985 | ); |
982 | } | 986 | } |
983 | 987 | ||
@@ -1056,15 +1060,6 @@ static int test_case_run_count; | |||
1056 | static bool test_case_is_thumb; | 1060 | static bool test_case_is_thumb; |
1057 | static int test_instance; | 1061 | static int test_instance; |
1058 | 1062 | ||
1059 | /* | ||
1060 | * We ignore the state of the imprecise abort disable flag (CPSR.A) because this | ||
1061 | * can change randomly as the kernel doesn't take care to preserve or initialise | ||
1062 | * this across context switches. Also, with Security Extentions, the flag may | ||
1063 | * not be under control of the kernel; for this reason we ignore the state of | ||
1064 | * the FIQ disable flag CPSR.F as well. | ||
1065 | */ | ||
1066 | #define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT) | ||
1067 | |||
1068 | static unsigned long test_check_cc(int cc, unsigned long cpsr) | 1063 | static unsigned long test_check_cc(int cc, unsigned long cpsr) |
1069 | { | 1064 | { |
1070 | int ret = arm_check_condition(cc << 28, cpsr); | 1065 | int ret = arm_check_condition(cc << 28, cpsr); |
@@ -1196,6 +1191,13 @@ static void setup_test_context(struct pt_regs *regs) | |||
1196 | regs->uregs[arg->reg] = | 1191 | regs->uregs[arg->reg] = |
1197 | (unsigned long)current_stack + arg->val; | 1192 | (unsigned long)current_stack + arg->val; |
1198 | memory_needs_checking = true; | 1193 | memory_needs_checking = true; |
1194 | /* | ||
1195 | * Test memory at an address below SP is in danger of | ||
1196 | * being altered by an interrupt occurring and pushing | ||
1197 | * data onto the stack. Disable interrupts to stop this. | ||
1198 | */ | ||
1199 | if (arg->reg == 13) | ||
1200 | regs->ARM_cpsr |= PSR_I_BIT; | ||
1199 | break; | 1201 | break; |
1200 | } | 1202 | } |
1201 | case ARG_TYPE_MEM: { | 1203 | case ARG_TYPE_MEM: { |
@@ -1264,14 +1266,26 @@ test_case_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
1264 | static int __kprobes | 1266 | static int __kprobes |
1265 | test_after_pre_handler(struct kprobe *p, struct pt_regs *regs) | 1267 | test_after_pre_handler(struct kprobe *p, struct pt_regs *regs) |
1266 | { | 1268 | { |
1269 | struct test_arg *args; | ||
1270 | |||
1267 | if (container_of(p, struct test_probe, kprobe)->hit == test_instance) | 1271 | if (container_of(p, struct test_probe, kprobe)->hit == test_instance) |
1268 | return 0; /* Already run for this test instance */ | 1272 | return 0; /* Already run for this test instance */ |
1269 | 1273 | ||
1270 | result_regs = *regs; | 1274 | result_regs = *regs; |
1275 | |||
1276 | /* Mask out results which are indeterminate */ | ||
1271 | result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS; | 1277 | result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS; |
1278 | for (args = current_args; args[0].type != ARG_TYPE_END; ++args) | ||
1279 | if (args[0].type == ARG_TYPE_REG_MASKED) { | ||
1280 | struct test_arg_regptr *arg = | ||
1281 | (struct test_arg_regptr *)args; | ||
1282 | result_regs.uregs[arg->reg] &= arg->val; | ||
1283 | } | ||
1272 | 1284 | ||
1273 | /* Undo any changes done to SP by the test case */ | 1285 | /* Undo any changes done to SP by the test case */ |
1274 | regs->ARM_sp = (unsigned long)current_stack; | 1286 | regs->ARM_sp = (unsigned long)current_stack; |
1287 | /* Enable interrupts in case setup_test_context disabled them */ | ||
1288 | regs->ARM_cpsr &= ~PSR_I_BIT; | ||
1275 | 1289 | ||
1276 | container_of(p, struct test_probe, kprobe)->hit = test_instance; | 1290 | container_of(p, struct test_probe, kprobe)->hit = test_instance; |
1277 | return 0; | 1291 | return 0; |
diff --git a/arch/arm/kernel/kprobes-test.h b/arch/arm/probes/kprobes/test-core.h index 4430990e90e7..94285203e9f7 100644 --- a/arch/arm/kernel/kprobes-test.h +++ b/arch/arm/probes/kprobes/test-core.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/kernel/kprobes-test.h | 2 | * arch/arm/probes/kprobes/test-core.h |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. | 4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. |
5 | * | 5 | * |
@@ -45,10 +45,11 @@ extern int kprobe_test_cc_position; | |||
45 | * | 45 | * |
46 | */ | 46 | */ |
47 | 47 | ||
48 | #define ARG_TYPE_END 0 | 48 | #define ARG_TYPE_END 0 |
49 | #define ARG_TYPE_REG 1 | 49 | #define ARG_TYPE_REG 1 |
50 | #define ARG_TYPE_PTR 2 | 50 | #define ARG_TYPE_PTR 2 |
51 | #define ARG_TYPE_MEM 3 | 51 | #define ARG_TYPE_MEM 3 |
52 | #define ARG_TYPE_REG_MASKED 4 | ||
52 | 53 | ||
53 | #define ARG_FLAG_UNSUPPORTED 0x01 | 54 | #define ARG_FLAG_UNSUPPORTED 0x01 |
54 | #define ARG_FLAG_SUPPORTED 0x02 | 55 | #define ARG_FLAG_SUPPORTED 0x02 |
@@ -61,7 +62,7 @@ struct test_arg { | |||
61 | }; | 62 | }; |
62 | 63 | ||
63 | struct test_arg_regptr { | 64 | struct test_arg_regptr { |
64 | u8 type; /* ARG_TYPE_REG or ARG_TYPE_PTR */ | 65 | u8 type; /* ARG_TYPE_REG or ARG_TYPE_PTR or ARG_TYPE_REG_MASKED */ |
65 | u8 reg; | 66 | u8 reg; |
66 | u8 _padding[2]; | 67 | u8 _padding[2]; |
67 | u32 val; | 68 | u32 val; |
@@ -138,6 +139,12 @@ struct test_arg_end { | |||
138 | ".short 0 \n\t" \ | 139 | ".short 0 \n\t" \ |
139 | ".word "#val" \n\t" | 140 | ".word "#val" \n\t" |
140 | 141 | ||
142 | #define TEST_ARG_REG_MASKED(reg, val) \ | ||
143 | ".byte "__stringify(ARG_TYPE_REG_MASKED)" \n\t" \ | ||
144 | ".byte "#reg" \n\t" \ | ||
145 | ".short 0 \n\t" \ | ||
146 | ".word "#val" \n\t" | ||
147 | |||
141 | #define TEST_ARG_END(flags) \ | 148 | #define TEST_ARG_END(flags) \ |
142 | ".byte "__stringify(ARG_TYPE_END)" \n\t" \ | 149 | ".byte "__stringify(ARG_TYPE_END)" \n\t" \ |
143 | ".byte "TEST_ISA flags" \n\t" \ | 150 | ".byte "TEST_ISA flags" \n\t" \ |
@@ -395,6 +402,22 @@ struct test_arg_end { | |||
395 | " "codex" \n\t" \ | 402 | " "codex" \n\t" \ |
396 | TESTCASE_END | 403 | TESTCASE_END |
397 | 404 | ||
405 | #define TEST_RMASKED(code1, reg, mask, code2) \ | ||
406 | TESTCASE_START(code1 #reg code2) \ | ||
407 | TEST_ARG_REG_MASKED(reg, mask) \ | ||
408 | TEST_ARG_END("") \ | ||
409 | TEST_INSTRUCTION(code1 #reg code2) \ | ||
410 | TESTCASE_END | ||
411 | |||
412 | /* | ||
413 | * We ignore the state of the imprecise abort disable flag (CPSR.A) because this | ||
414 | * can change randomly as the kernel doesn't take care to preserve or initialise | ||
415 | * this across context switches. Also, with Security Extensions, the flag may | ||
416 | * not be under control of the kernel; for this reason we ignore the state of | ||
417 | * the FIQ disable flag CPSR.F as well. | ||
418 | */ | ||
419 | #define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT) | ||
420 | |||
398 | 421 | ||
399 | /* | 422 | /* |
400 | * Macros for defining space directives spread over multiple lines. | 423 | * Macros for defining space directives spread over multiple lines. |
diff --git a/arch/arm/kernel/kprobes-test-thumb.c b/arch/arm/probes/kprobes/test-thumb.c index 844dd10d8593..b683b4517458 100644 --- a/arch/arm/kernel/kprobes-test-thumb.c +++ b/arch/arm/probes/kprobes/test-thumb.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/kernel/kprobes-test-thumb.c | 2 | * arch/arm/probes/kprobes/test-thumb.c |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. | 4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. |
5 | * | 5 | * |
@@ -11,8 +11,9 @@ | |||
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <asm/opcodes.h> | 13 | #include <asm/opcodes.h> |
14 | #include <asm/probes.h> | ||
14 | 15 | ||
15 | #include "kprobes-test.h" | 16 | #include "test-core.h" |
16 | 17 | ||
17 | 18 | ||
18 | #define TEST_ISA "16" | 19 | #define TEST_ISA "16" |
@@ -416,6 +417,9 @@ void kprobe_thumb32_test_cases(void) | |||
416 | TEST_RR( "strd r",14,VAL2,", r",12,VAL1,", [sp, #16]!") | 417 | TEST_RR( "strd r",14,VAL2,", r",12,VAL1,", [sp, #16]!") |
417 | TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16") | 418 | TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16") |
418 | TEST_RR( "strd r",7, VAL2,", r",8, VAL1,", [sp], #-16") | 419 | TEST_RR( "strd r",7, VAL2,", r",8, VAL1,", [sp], #-16") |
420 | TEST_RRP("strd r",6, VAL1,", r",7, VAL2,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") | ||
421 | TEST_UNSUPPORTED("strd r6, r7, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") | ||
422 | TEST_RRP("strd r",4, VAL1,", r",5, VAL2,", [r",14, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") | ||
419 | TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) " @ strd r14, r12, [pc, #16]!") | 423 | TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) " @ strd r14, r12, [pc, #16]!") |
420 | TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) " @ strd r14, r12, [pc], #16") | 424 | TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) " @ strd r14, r12, [pc], #16") |
421 | 425 | ||
@@ -774,8 +778,8 @@ CONDITION_INSTRUCTIONS(22, | |||
774 | 778 | ||
775 | TEST_UNSUPPORTED("subs pc, lr, #4") | 779 | TEST_UNSUPPORTED("subs pc, lr, #4") |
776 | 780 | ||
777 | TEST("mrs r0, cpsr") | 781 | TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr") |
778 | TEST("mrs r14, cpsr") | 782 | TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr") |
779 | TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8d00) " @ mrs sp, spsr") | 783 | TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8d00) " @ mrs sp, spsr") |
780 | TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8f00) " @ mrs pc, spsr") | 784 | TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8f00) " @ mrs pc, spsr") |
781 | TEST_UNSUPPORTED("mrs r0, spsr") | 785 | TEST_UNSUPPORTED("mrs r0, spsr") |
@@ -821,14 +825,22 @@ CONDITION_INSTRUCTIONS(22, | |||
821 | TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]!") \ | 825 | TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]!") \ |
822 | TEST_RPR("str"size".w r",0, VAL1,", [r",1, 0,", r",2, 4,"]") \ | 826 | TEST_RPR("str"size".w r",0, VAL1,", [r",1, 0,", r",2, 4,"]") \ |
823 | TEST_RPR("str"size" r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]") \ | 827 | TEST_RPR("str"size" r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]") \ |
828 | TEST_UNSUPPORTED("str"size" r0, [r13, r1]") \ | ||
824 | TEST_R( "str"size".w r",7, VAL1,", [sp, #24]") \ | 829 | TEST_R( "str"size".w r",7, VAL1,", [sp, #24]") \ |
825 | TEST_RP( "str"size".w r",0, VAL2,", [r",0,0, "]") \ | 830 | TEST_RP( "str"size".w r",0, VAL2,", [r",0,0, "]") \ |
831 | TEST_RP( "str"size" r",6, VAL1,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ | ||
832 | TEST_UNSUPPORTED("str"size" r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ | ||
833 | TEST_RP( "str"size" r",4, VAL2,", [r",12, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ | ||
826 | TEST_UNSUPPORTED("str"size"t r0, [r1, #4]") | 834 | TEST_UNSUPPORTED("str"size"t r0, [r1, #4]") |
827 | 835 | ||
828 | SINGLE_STORE("b") | 836 | SINGLE_STORE("b") |
829 | SINGLE_STORE("h") | 837 | SINGLE_STORE("h") |
830 | SINGLE_STORE("") | 838 | SINGLE_STORE("") |
831 | 839 | ||
840 | TEST_UNSUPPORTED(__inst_thumb32(0xf801000d) " @ strb r0, [r1, r13]") | ||
841 | TEST_UNSUPPORTED(__inst_thumb32(0xf821000d) " @ strh r0, [r1, r13]") | ||
842 | TEST_UNSUPPORTED(__inst_thumb32(0xf841000d) " @ str r0, [r1, r13]") | ||
843 | |||
832 | TEST("str sp, [sp]") | 844 | TEST("str sp, [sp]") |
833 | TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) " @ str r14, [pc]") | 845 | TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) " @ str r14, [pc]") |
834 | TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) " @ str pc, [r14]") | 846 | TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) " @ str pc, [r14]") |
diff --git a/arch/arm/probes/uprobes/Makefile b/arch/arm/probes/uprobes/Makefile new file mode 100644 index 000000000000..e1dc3d0f6d5a --- /dev/null +++ b/arch/arm/probes/uprobes/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_UPROBES) += core.o actions-arm.o | |||
diff --git a/arch/arm/kernel/uprobes-arm.c b/arch/arm/probes/uprobes/actions-arm.c index d3b655ff17da..76eb44972ebe 100644 --- a/arch/arm/kernel/uprobes-arm.c +++ b/arch/arm/probes/uprobes/actions-arm.c | |||
@@ -13,9 +13,9 @@ | |||
13 | #include <linux/uprobes.h> | 13 | #include <linux/uprobes.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | 15 | ||
16 | #include "probes.h" | 16 | #include "../decode.h" |
17 | #include "probes-arm.h" | 17 | #include "../decode-arm.h" |
18 | #include "uprobes.h" | 18 | #include "core.h" |
19 | 19 | ||
20 | static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs) | 20 | static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs) |
21 | { | 21 | { |
@@ -195,8 +195,6 @@ uprobe_decode_ldmstm(probes_opcode_t insn, | |||
195 | } | 195 | } |
196 | 196 | ||
197 | const union decode_action uprobes_probes_actions[] = { | 197 | const union decode_action uprobes_probes_actions[] = { |
198 | [PROBES_EMULATE_NONE] = {.handler = probes_simulate_nop}, | ||
199 | [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop}, | ||
200 | [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, | 198 | [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, |
201 | [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, | 199 | [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, |
202 | [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, | 200 | [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, |
diff --git a/arch/arm/kernel/uprobes.c b/arch/arm/probes/uprobes/core.c index 56adf9c1fde0..d1329f1ba4e4 100644 --- a/arch/arm/kernel/uprobes.c +++ b/arch/arm/probes/uprobes/core.c | |||
@@ -17,9 +17,9 @@ | |||
17 | #include <asm/opcodes.h> | 17 | #include <asm/opcodes.h> |
18 | #include <asm/traps.h> | 18 | #include <asm/traps.h> |
19 | 19 | ||
20 | #include "probes.h" | 20 | #include "../decode.h" |
21 | #include "probes-arm.h" | 21 | #include "../decode-arm.h" |
22 | #include "uprobes.h" | 22 | #include "core.h" |
23 | 23 | ||
24 | #define UPROBE_TRAP_NR UINT_MAX | 24 | #define UPROBE_TRAP_NR UINT_MAX |
25 | 25 | ||
@@ -88,7 +88,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
88 | auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN); | 88 | auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN); |
89 | 89 | ||
90 | ret = arm_probes_decode_insn(insn, &auprobe->asi, false, | 90 | ret = arm_probes_decode_insn(insn, &auprobe->asi, false, |
91 | uprobes_probes_actions); | 91 | uprobes_probes_actions, NULL); |
92 | switch (ret) { | 92 | switch (ret) { |
93 | case INSN_REJECTED: | 93 | case INSN_REJECTED: |
94 | return -EINVAL; | 94 | return -EINVAL; |
diff --git a/arch/arm/kernel/uprobes.h b/arch/arm/probes/uprobes/core.h index 1d0c12dfbd03..1d0c12dfbd03 100644 --- a/arch/arm/kernel/uprobes.h +++ b/arch/arm/probes/uprobes/core.h | |||
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index d3f7e4941231..2814304cec04 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig | |||
@@ -39,6 +39,7 @@ config ARM64 | |||
39 | select HARDIRQS_SW_RESEND | 39 | select HARDIRQS_SW_RESEND |
40 | select HAVE_ALIGNED_STRUCT_PAGE if SLUB | 40 | select HAVE_ALIGNED_STRUCT_PAGE if SLUB |
41 | select HAVE_ARCH_AUDITSYSCALL | 41 | select HAVE_ARCH_AUDITSYSCALL |
42 | select HAVE_ARCH_BITREVERSE | ||
42 | select HAVE_ARCH_JUMP_LABEL | 43 | select HAVE_ARCH_JUMP_LABEL |
43 | select HAVE_ARCH_KGDB | 44 | select HAVE_ARCH_KGDB |
44 | select HAVE_ARCH_SECCOMP_FILTER | 45 | select HAVE_ARCH_SECCOMP_FILTER |
diff --git a/arch/arm64/include/asm/bitrev.h b/arch/arm64/include/asm/bitrev.h new file mode 100644 index 000000000000..a5a0c3660137 --- /dev/null +++ b/arch/arm64/include/asm/bitrev.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef __ASM_BITREV_H | ||
2 | #define __ASM_BITREV_H | ||
3 | static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x) | ||
4 | { | ||
5 | __asm__ ("rbit %w0, %w1" : "=r" (x) : "r" (x)); | ||
6 | return x; | ||
7 | } | ||
8 | |||
9 | static __always_inline __attribute_const__ u16 __arch_bitrev16(u16 x) | ||
10 | { | ||
11 | return __arch_bitrev32((u32)x) >> 16; | ||
12 | } | ||
13 | |||
14 | static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x) | ||
15 | { | ||
16 | return __arch_bitrev32((u32)x) >> 24; | ||
17 | } | ||
18 | |||
19 | #endif | ||
diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index 7c523bbf3dc8..0dd8d089c315 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c | |||
@@ -322,7 +322,8 @@ void arch_remove_optimized_kprobe(struct optimized_kprobe *op) | |||
322 | * Target instructions MUST be relocatable (checked inside) | 322 | * Target instructions MUST be relocatable (checked inside) |
323 | * This is called when new aggr(opt)probe is allocated or reused. | 323 | * This is called when new aggr(opt)probe is allocated or reused. |
324 | */ | 324 | */ |
325 | int arch_prepare_optimized_kprobe(struct optimized_kprobe *op) | 325 | int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, |
326 | struct kprobe *__unused) | ||
326 | { | 327 | { |
327 | u8 *buf; | 328 | u8 *buf; |
328 | int ret; | 329 | int ret; |