Merge branch 'devel-stable' into for-next

This commit is contained in:
Russell King 2014-04-04 00:33:49 +01:00
commit bce5669be3
1043 changed files with 15905 additions and 8988 deletions

3
.gitignore vendored
View File

@ -92,3 +92,6 @@ extra_certificates
signing_key.priv
signing_key.x509
x509.genkey
# Kconfig presets
all.config

View File

@ -29,6 +29,8 @@ DMA-ISA-LPC.txt
- How to do DMA with ISA (and LPC) devices.
DMA-attributes.txt
- listing of the various possible attributes a DMA region can have
dmatest.txt
- how to compile, configure and use the dmatest system.
DocBook/
- directory with DocBook templates etc. for kernel documentation.
EDID/
@ -77,6 +79,8 @@ arm/
- directory with info about Linux on the ARM architecture.
arm64/
- directory with info about Linux on the 64 bit ARM architecture.
assoc_array.txt
- generic associative array intro.
atomic_ops.txt
- semantics and behavior of atomic and bitmask operations.
auxdisplay/
@ -87,6 +91,8 @@ bad_memory.txt
- how to use kernel parameters to exclude bad RAM regions.
basic_profiling.txt
- basic instructions for those who wants to profile Linux kernel.
bcache.txt
- Block-layer cache on fast SSDs to improve slow (raid) I/O performance.
binfmt_misc.txt
- info on the kernel support for extra binary formats.
blackfin/
@ -171,6 +177,8 @@ early-userspace/
- info about initramfs, klibc, and userspace early during boot.
edac.txt
- information on EDAC - Error Detection And Correction
efi-stub.txt
- How to use the EFI boot stub to bypass GRUB or elilo on EFI systems.
eisa.txt
- info on EISA bus support.
email-clients.txt
@ -195,8 +203,8 @@ futex-requeue-pi.txt
- info on requeueing of tasks from a non-PI futex to a PI futex
gcov.txt
- use of GCC's coverage testing tool "gcov" with the Linux kernel
gpio.txt
- overview of GPIO (General Purpose Input/Output) access conventions.
gpio/
- gpio related documentation
hid/
- directory with information on human interface devices
highuid.txt
@ -255,6 +263,8 @@ kernel-docs.txt
- listing of various WWW + books that document kernel internals.
kernel-parameters.txt
- summary listing of command line / boot prompt args for the kernel.
kernel-per-CPU-kthreads.txt
- List of all per-CPU kthreads and how they introduce jitter.
kmemcheck.txt
- info on dynamic checker that detects uses of uninitialized memory.
kmemleak.txt
@ -299,8 +309,6 @@ memory-devices/
- directory with info on parts like the Texas Instruments EMIF driver
memory-hotplug.txt
- Hotpluggable memory support, how to use and current status.
memory.txt
- info on typical Linux memory problems.
metag/
- directory with info about Linux on Meta architecture.
mips/
@ -311,6 +319,8 @@ mmc/
- directory with info about the MMC subsystem
mn10300/
- directory with info about the mn10300 architecture port
module-signing.txt
- Kernel module signing for increased security when loading modules.
mtd/
- directory with info about memory technology devices (flash)
mono.txt
@ -343,6 +353,8 @@ pcmcia/
- info on the Linux PCMCIA driver.
percpu-rw-semaphore.txt
- RCU based read-write semaphore optimized for locking for reading
phy.txt
- Description of the generic PHY framework.
pi-futex.txt
- documentation on lightweight priority inheritance futexes.
pinctrl.txt
@ -431,6 +443,8 @@ sysrq.txt
- info on the magic SysRq key.
target/
- directory with info on generating TCM v4 fabric .ko modules
this_cpu_ops.txt
- List rationale behind and the way to use this_cpu operations.
thermal/
- directory with information on managing thermal issues (CPU/temp)
trace/
@ -469,6 +483,8 @@ wimax/
- directory with info about Intel Wireless Wimax Connections
workqueue.txt
- information on the Concurrency Managed Workqueue implementation
ww-mutex-design.txt
- Intro to Mutex wait/would deadlock handling.s
x86/x86_64/
- directory with info on Linux support for AMD x86-64 (Hammer) machines.
xtensa/

View File

@ -82,7 +82,19 @@ Most of the hard work is done for the driver in the PCI layer. It simply
has to request that the PCI layer set up the MSI capability for this
device.
4.2.1 pci_enable_msi_range
4.2.1 pci_enable_msi
int pci_enable_msi(struct pci_dev *dev)
A successful call allocates ONE interrupt to the device, regardless
of how many MSIs the device supports. The device is switched from
pin-based interrupt mode to MSI mode. The dev->irq number is changed
to a new number which represents the message signaled interrupt;
consequently, this function should be called before the driver calls
request_irq(), because an MSI is delivered via a vector that is
different from the vector of a pin-based interrupt.
4.2.2 pci_enable_msi_range
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
@ -147,6 +159,11 @@ static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
return pci_enable_msi_range(pdev, nvec, nvec);
}
Note, unlike pci_enable_msi_exact() function, which could be also used to
enable a particular number of MSI-X interrupts, pci_enable_msi_range()
returns either a negative errno or 'nvec' (not negative errno or 0 - as
pci_enable_msi_exact() does).
4.2.1.3 Single MSI mode
The most notorious example of the request type described above is
@ -158,7 +175,27 @@ static int foo_driver_enable_single_msi(struct pci_dev *pdev)
return pci_enable_msi_range(pdev, 1, 1);
}
4.2.2 pci_disable_msi
Note, unlike pci_enable_msi() function, which could be also used to
enable the single MSI mode, pci_enable_msi_range() returns either a
negative errno or 1 (not negative errno or 0 - as pci_enable_msi()
does).
4.2.3 pci_enable_msi_exact
int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
This variation on pci_enable_msi_range() call allows a device driver to
request exactly 'nvec' MSIs.
If this function returns a negative number, it indicates an error and
the driver should not attempt to request any more MSI interrupts for
this device.
By contrast with pci_enable_msi_range() function, pci_enable_msi_exact()
returns zero in case of success, which indicates MSI interrupts have been
successfully allocated.
4.2.4 pci_disable_msi
void pci_disable_msi(struct pci_dev *dev)
@ -172,7 +209,7 @@ on any interrupt for which it previously called request_irq().
Failure to do so results in a BUG_ON(), leaving the device with
MSI enabled and thus leaking its vector.
4.2.3 pci_msi_vec_count
4.2.4 pci_msi_vec_count
int pci_msi_vec_count(struct pci_dev *dev)
@ -257,8 +294,8 @@ possible, likely up to the limit returned by pci_msix_vec_count() function:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
1, nvec);
return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
1, nvec);
}
Note the value of 'minvec' parameter is 1. As 'minvec' is inclusive,
@ -269,8 +306,8 @@ In this case the function could look like this:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
FOO_DRIVER_MINIMUM_NVEC, nvec);
return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
FOO_DRIVER_MINIMUM_NVEC, nvec);
}
4.3.1.2 Exact number of MSI-X interrupts
@ -282,10 +319,15 @@ parameters:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
nvec, nvec);
return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
nvec, nvec);
}
Note, unlike pci_enable_msix_exact() function, which could be also used to
enable a particular number of MSI-X interrupts, pci_enable_msix_range()
returns either a negative errno or 'nvec' (not negative errno or 0 - as
pci_enable_msix_exact() does).
4.3.1.3 Specific requirements to the number of MSI-X interrupts
As noted above, there could be devices that can not operate with just any
@ -332,7 +374,64 @@ Note how pci_enable_msix_range() return value is analized for a fallback -
any error code other than -ENOSPC indicates a fatal error and should not
be retried.
4.3.2 pci_disable_msix
4.3.2 pci_enable_msix_exact
int pci_enable_msix_exact(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
This variation on pci_enable_msix_range() call allows a device driver to
request exactly 'nvec' MSI-Xs.
If this function returns a negative number, it indicates an error and
the driver should not attempt to allocate any more MSI-X interrupts for
this device.
By contrast with pci_enable_msix_range() function, pci_enable_msix_exact()
returns zero in case of success, which indicates MSI-X interrupts have been
successfully allocated.
Another version of a routine that enables MSI-X mode for a device with
specific requirements described in chapter 4.3.1.3 might look like this:
/*
* Assume 'minvec' and 'maxvec' are non-zero
*/
static int foo_driver_enable_msix(struct foo_adapter *adapter,
int minvec, int maxvec)
{
int rc;
minvec = roundup_pow_of_two(minvec);
maxvec = rounddown_pow_of_two(maxvec);
if (minvec > maxvec)
return -ERANGE;
retry:
rc = pci_enable_msix_exact(adapter->pdev,
adapter->msix_entries, maxvec);
/*
* -ENOSPC is the only error code allowed to be analyzed
*/
if (rc == -ENOSPC) {
if (maxvec == 1)
return -ENOSPC;
maxvec /= 2;
if (minvec > maxvec)
return -ENOSPC;
goto retry;
} else if (rc < 0) {
return rc;
}
return maxvec;
}
4.3.3 pci_disable_msix
void pci_disable_msix(struct pci_dev *dev)

View File

@ -8,6 +8,8 @@ listRCU.txt
- Using RCU to Protect Read-Mostly Linked Lists
lockdep.txt
- RCU and lockdep checking
lockdep-splat.txt
- RCU Lockdep splats explained.
NMI-RCU.txt
- Using RCU to Protect Dynamic NMI Handlers
rcubarrier.txt

View File

@ -4,6 +4,8 @@ Booting
- requirements for booting
Interrupts
- ARM Interrupt subsystem documentation
IXP4xx
- Intel IXP4xx Network processor.
msm
- MSM specific documentation
Netwinder
@ -24,8 +26,16 @@ SPEAr
- ST SPEAr platform Linux Overview
VFP/
- Release notes for Linux Kernel Vector Floating Point support code
cluster-pm-race-avoidance.txt
- Algorithm for CPU and Cluster setup/teardown
empeg/
- Ltd's Empeg MP3 Car Audio Player
firmware.txt
- Secure firmware registration and calling.
kernel_mode_neon.txt
- How to use NEON instructions in kernel mode
kernel_user_helpers.txt
- Helper functions in kernel space made available for userspace.
mem_alignment
- alignment abort handler documentation
memory.txt
@ -34,3 +44,7 @@ nwfpe/
- NWFPE floating point emulator documentation
swp_emulation
- SWP/SWPB emulation handler/logging description
tcm.txt
- ARM Tightly Coupled Memory
vlocks.txt
- Voting locks, low-level mechanism relying on memory system atomic writes.

View File

@ -1,8 +1,10 @@
00-INDEX
- This file
Makefile
- Makefile for gptimers example file.
bfin-gpio-notes.txt
- Notes in developing/using bfin-gpio driver.
bfin-spi-notes.txt
- Notes for using bfin spi bus driver.
gptimers-example.c
- gptimers example

View File

@ -14,6 +14,8 @@ deadline-iosched.txt
- Deadline IO scheduler tunables
ioprio.txt
- Block io priorities (in CFQ scheduler)
null_blk.txt
- Null block for block-layer benchmarking.
queue-sysfs.txt
- Queue's sysfs entries
request.txt

View File

@ -8,3 +8,5 @@ https://lists.ozlabs.org/listinfo/devicetree-discuss
- this file
booting-without-of.txt
- Booting Linux without Open Firmware, describes history and format of device trees.
usage-model.txt
- How Linux uses DT and what DT aims to solve.

View File

@ -91,7 +91,7 @@ Boards:
compatible = "ti,omap3-beagle", "ti,omap3"
- OMAP3 Tobi with Overo : Commercial expansion board with daughter board
compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3"
compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3"
- OMAP4 SDP : Software Development Board
compatible = "ti,omap4-sdp", "ti,omap4430"

View File

@ -9,6 +9,7 @@ Required properties:
- compatible : should be one of
"arm,armv8-pmuv3"
"arm,cortex-a15-pmu"
"arm,cortex-a12-pmu"
"arm,cortex-a9-pmu"
"arm,cortex-a8-pmu"
"arm,cortex-a7-pmu"
@ -16,7 +17,14 @@ Required properties:
"arm,arm11mpcore-pmu"
"arm,arm1176-pmu"
"arm,arm1136-pmu"
- interrupts : 1 combined interrupt or 1 per core.
"qcom,krait-pmu"
- interrupts : 1 combined interrupt or 1 per core. If the interrupt is a per-cpu
interrupt (PPI) then 1 interrupt should be specified.
Optional properties:
- qcom,no-pc-write : Indicates that this PMU doesn't support the 0xc and 0xd
events.
Example:

View File

@ -1,12 +1,16 @@
* Freescale Smart Direct Memory Access (SDMA) Controller for i.MX
Required properties:
- compatible : Should be "fsl,imx31-sdma", "fsl,imx31-to1-sdma",
"fsl,imx31-to2-sdma", "fsl,imx35-sdma", "fsl,imx35-to1-sdma",
"fsl,imx35-to2-sdma", "fsl,imx51-sdma", "fsl,imx53-sdma" or
"fsl,imx6q-sdma". The -to variants should be preferred since they
allow to determnine the correct ROM script addresses needed for
the driver to work without additional firmware.
- compatible : Should be one of
"fsl,imx25-sdma"
"fsl,imx31-sdma", "fsl,imx31-to1-sdma", "fsl,imx31-to2-sdma"
"fsl,imx35-sdma", "fsl,imx35-to1-sdma", "fsl,imx35-to2-sdma"
"fsl,imx51-sdma"
"fsl,imx53-sdma"
"fsl,imx6q-sdma"
The -to variants should be preferred since they allow to determnine the
correct ROM script addresses needed for the driver to work without additional
firmware.
- reg : Should contain SDMA registers location and length
- interrupts : Should contain SDMA interrupt
- #dma-cells : Must be <3>.

View File

@ -13,6 +13,9 @@ Required properties:
- #address-cells: should be one. The cell is the slot id.
- #size-cells: should be zero.
- at least one slot node
- clock-names: tuple listing input clock names.
Required elements: "mci_clk"
- clocks: phandles to input clocks.
The node contains child nodes for each slot that the platform uses
@ -24,6 +27,8 @@ mmc0: mmc@f0008000 {
interrupts = <12 4>;
#address-cells = <1>;
#size-cells = <0>;
clock-names = "mci_clk";
clocks = <&mci0_clk>;
[ child node definitions...]
};

View File

@ -1,7 +1,8 @@
* Allwinner EMAC ethernet controller
Required properties:
- compatible: should be "allwinner,sun4i-emac".
- compatible: should be "allwinner,sun4i-a10-emac" (Deprecated:
"allwinner,sun4i-emac")
- reg: address and length of the register set for the device.
- interrupts: interrupt for the device
- phy: A phandle to a phy node defining the PHY address (as the reg
@ -14,7 +15,7 @@ Optional properties:
Example:
emac: ethernet@01c0b000 {
compatible = "allwinner,sun4i-emac";
compatible = "allwinner,sun4i-a10-emac";
reg = <0x01c0b000 0x1000>;
interrupts = <55>;
clocks = <&ahb_gates 17>;

View File

@ -1,7 +1,8 @@
* Allwinner A10 MDIO Ethernet Controller interface
Required properties:
- compatible: should be "allwinner,sun4i-mdio".
- compatible: should be "allwinner,sun4i-a10-mdio"
(Deprecated: "allwinner,sun4i-mdio").
- reg: address and length of the register set for the device.
Optional properties:
@ -9,7 +10,7 @@ Optional properties:
Example at the SoC level:
mdio@01c0b080 {
compatible = "allwinner,sun4i-mdio";
compatible = "allwinner,sun4i-a10-mdio";
reg = <0x01c0b080 0x14>;
#address-cells = <1>;
#size-cells = <0>;

View File

@ -0,0 +1,58 @@
STMicroelectronics SoC DWMAC glue layer controller
The device node has following properties.
Required properties:
- compatible : Can be "st,stih415-dwmac", "st,stih416-dwmac" or
"st,stid127-dwmac".
- reg : Offset of the glue configuration register map in system
configuration regmap pointed by st,syscon property and size.
- reg-names : Should be "sti-ethconf".
- st,syscon : Should be phandle to system configuration node which
encompases this glue registers.
- st,tx-retime-src: On STi Parts for Giga bit speeds, 125Mhz clocks can be
wired up in from different sources. One via TXCLK pin and other via CLK_125
pin. This wiring is totally board dependent. However the retiming glue
logic should be configured accordingly. Possible values for this property
"txclk" - if 125Mhz clock is wired up via txclk line.
"clk_125" - if 125Mhz clock is wired up via clk_125 line.
This property is only valid for Giga bit setup( GMII, RGMII), and it is
un-used for non-giga bit (MII and RMII) setups. Also note that internal
clockgen can not generate stable 125Mhz clock.
- st,ext-phyclk: This boolean property indicates who is generating the clock
for tx and rx. This property is only valid for RMII case where the clock can
be generated from the MAC or PHY.
- clock-names: should be "sti-ethclk".
- clocks: Should point to ethernet clockgen which can generate phyclk.
Example:
ethernet0: dwmac@fe810000 {
device_type = "network";
compatible = "st,stih416-dwmac", "snps,dwmac", "snps,dwmac-3.710";
reg = <0xfe810000 0x8000>, <0x8bc 0x4>;
reg-names = "stmmaceth", "sti-ethconf";
interrupts = <0 133 0>, <0 134 0>, <0 135 0>;
interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
phy-mode = "mii";
st,syscon = <&syscfg_rear>;
snps,pbl = <32>;
snps,mixed-burst;
resets = <&softreset STIH416_ETH0_SOFTRESET>;
reset-names = "stmmaceth";
pinctrl-0 = <&pinctrl_mii0>;
pinctrl-names = "default";
clocks = <&CLK_S_GMAC0_PHY>;
clock-names = "stmmaceth";
};

View File

@ -0,0 +1,47 @@
Binding for TI bq2415x Li-Ion Charger
Required properties:
- compatible: Should contain one of the following:
* "ti,bq24150"
* "ti,bq24150"
* "ti,bq24150a"
* "ti,bq24151"
* "ti,bq24151a"
* "ti,bq24152"
* "ti,bq24153"
* "ti,bq24153a"
* "ti,bq24155"
* "ti,bq24156"
* "ti,bq24156a"
* "ti,bq24158"
- reg: integer, i2c address of the device.
- ti,current-limit: integer, initial maximum current charger can pull
from power supply in mA.
- ti,weak-battery-voltage: integer, weak battery voltage threshold in mV.
The chip will use slow precharge if battery voltage
is below this value.
- ti,battery-regulation-voltage: integer, maximum charging voltage in mV.
- ti,charge-current: integer, maximum charging current in mA.
- ti,termination-current: integer, charge will be terminated when current in
constant-voltage phase drops below this value (in mA).
- ti,resistor-sense: integer, value of sensing resistor in milliohm.
Optional properties:
- ti,usb-charger-detection: phandle to usb charger detection device.
(required for auto mode)
Example from Nokia N900:
bq24150a {
compatible = "ti,bq24150a";
reg = <0x6b>;
ti,current-limit = <100>;
ti,weak-battery-voltage = <3400>;
ti,battery-regulation-voltage = <4200>;
ti,charge-current = <650>;
ti,termination-current = <100>;
ti,resistor-sense = <68>;
ti,usb-charger-detection = <&isp1704>;
};

View File

@ -5,6 +5,9 @@ Required properties:
- reg: Address and length of the register set for the device
- interrupts: Should contain spi interrupt
- cs-gpios: chipselects
- clock-names: tuple listing input clock names.
Required elements: "spi_clk"
- clocks: phandles to input clocks.
Example:
@ -14,6 +17,8 @@ spi1: spi@fffcc000 {
interrupts = <13 4 5>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&spi1_clk>;
clock-names = "spi_clk";
cs-gpios = <&pioB 3 0>;
status = "okay";

View File

@ -8,6 +8,7 @@ ad Avionic Design GmbH
adi Analog Devices, Inc.
aeroflexgaisler Aeroflex Gaisler AB
ak Asahi Kasei Corp.
allwinner Allwinner Technology Co., Ltd.
altr Altera Corp.
amcc Applied Micro Circuits Corporation (APM, formally AMCC)
amstaos AMS-Taos Inc.
@ -40,6 +41,7 @@ gmt Global Mixed-mode Technology, Inc.
gumstix Gumstix, Inc.
haoyu Haoyu Microelectronic Co. Ltd.
hisilicon Hisilicon Limited.
honeywell Honeywell
hp Hewlett Packard
ibm International Business Machines (IBM)
idt Integrated Device Technologies, Inc.
@ -55,6 +57,7 @@ maxim Maxim Integrated Products
microchip Microchip Technology Inc.
mosaixtech Mosaix Technologies, Inc.
national National Semiconductor
neonode Neonode Inc.
nintendo Nintendo
nvidia NVIDIA
nxp NXP Semiconductors
@ -64,7 +67,7 @@ phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd
powervr PowerVR (deprecated, use img)
qca Qualcomm Atheros, Inc.
qcom Qualcomm, Inc.
qcom Qualcomm Technologies, Inc
ralink Mediatek/Ralink Technology Corp.
ramtron Ramtron International
realtek Realtek Semiconductor Corp.
@ -78,6 +81,7 @@ silabs Silicon Laboratories
simtek
sirf SiRF Technology, Inc.
snps Synopsys, Inc.
spansion Spansion Inc.
st STMicroelectronics
ste ST-Ericsson
stericsson ST-Ericsson

View File

@ -5,6 +5,8 @@ please mail me.
00-INDEX
- this file.
api.txt
- The frame buffer API between applications and buffer devices.
arkfb.txt
- info on the fbdev driver for ARK Logic chips.
aty128fb.txt
@ -51,12 +53,16 @@ sh7760fb.txt
- info on the SH7760/SH7763 integrated LCDC Framebuffer driver.
sisfb.txt
- info on the framebuffer device driver for various SiS chips.
sm501.txt
- info on the framebuffer device driver for sm501 videoframebuffer.
sstfb.txt
- info on the frame buffer driver for 3dfx' Voodoo Graphics boards.
tgafb.txt
- info on the TGA (DECChip 21030) frame buffer driver.
tridentfb.txt
info on the framebuffer driver for some Trident chip based cards.
udlfb.txt
- Driver for DisplayLink USB 2.0 chips.
uvesafb.txt
- info on the userspace VESA (VBE2+ compliant) frame buffer device.
vesafb.txt

View File

@ -2,6 +2,8 @@
- this file (info on some of the filesystems supported by linux).
Locking
- info on locking rules as they pertain to Linux VFS.
Makefile
- Makefile for building the filsystems-part of DocBook.
9p.txt
- 9p (v9fs) is an implementation of the Plan 9 remote fs protocol.
adfs.txt

View File

@ -12,6 +12,8 @@ nfs41-server.txt
- info on the Linux server implementation of NFSv4 minor version 1.
nfs-rdma.txt
- how to install and setup the Linux NFS/RDMA client and server software
nfsd-admin-interfaces.txt
- Administrative interfaces for nfsd.
nfsroot.txt
- short guide on setting up a diskless box with NFS root filesystem.
pnfs.txt
@ -20,5 +22,5 @@ rpc-cache.txt
- introduction to the caching mechanisms in the sunrpc layer.
idmapper.txt
- information for configuring request-keys to be used by idmapper
knfsd-rpcgss.txt
rpc-server-gss.txt
- Information on GSS authentication support in the NFS Server

View File

@ -8,8 +8,8 @@ reason, the kernel code must instantiate I2C devices explicitly. There are
several ways to achieve this, depending on the context and requirements.
Method 1: Declare the I2C devices by bus number
-----------------------------------------------
Method 1a: Declare the I2C devices by bus number
------------------------------------------------
This method is appropriate when the I2C bus is a system bus as is the case
for many embedded systems. On such systems, each I2C bus has a number
@ -51,6 +51,43 @@ The devices will be automatically unbound and destroyed when the I2C bus
they sit on goes away (if ever.)
Method 1b: Declare the I2C devices via devicetree
-------------------------------------------------
This method has the same implications as method 1a. The declaration of I2C
devices is here done via devicetree as subnodes of the master controller.
Example:
i2c1: i2c@400a0000 {
/* ... master properties skipped ... */
clock-frequency = <100000>;
flash@50 {
compatible = "atmel,24c256";
reg = <0x50>;
};
pca9532: gpio@60 {
compatible = "nxp,pca9532";
gpio-controller;
#gpio-cells = <2>;
reg = <0x60>;
};
};
Here, two devices are attached to the bus using a speed of 100kHz. For
additional properties which might be needed to set up the device, please refer
to its devicetree documentation in Documentation/devicetree/bindings/.
Method 1c: Declare the I2C devices via ACPI
-------------------------------------------
ACPI can also describe I2C devices. There is special documentation for this
which is currently located at Documentation/acpi/enumeration.txt.
Method 2: Instantiate the devices explicitly
--------------------------------------------

View File

@ -10,3 +10,5 @@ ide-tape.txt
- info on the IDE ATAPI streaming tape driver
ide.txt
- important info for users of ATA devices (IDE/EIDE disks and CD-ROMS).
warm-plug-howto.txt
- using sysfs to remove and add IDE devices.

View File

@ -1,13 +1,15 @@
00-INDEX
- This file
acer-wmi.txt
- information on the Acer Laptop WMI Extras driver.
Makefile
- Makefile for building dslm example program.
asus-laptop.txt
- information on the Asus Laptop Extras driver.
disk-shock-protection.txt
- information on hard disk shock protection.
dslm.c
- Simple Disk Sleep Monitor program
hpfall.c
- (HP) laptop accelerometer program for disk protection.
laptop-mode.txt
- how to conserve battery power using laptop-mode.
sony-laptop.txt

View File

@ -1,3 +1,7 @@
00-INDEX
- This file
leds-blinkm.txt
- Driver for BlinkM LED-devices.
leds-class.txt
- documents LED handling under Linux.
leds-lp3944.txt
@ -12,3 +16,7 @@ leds-lp55xx.txt
- description about lp55xx common driver.
leds-lm3556.txt
- notes on how to use the leds-lm3556 driver.
ledtrig-oneshot.txt
- One-shot LED trigger for both sporadic and dense events.
ledtrig-transient.txt
- LED Transient Trigger, one shot timer activation.

View File

@ -1,5 +1,7 @@
00-INDEX
- this file
README.buddha
- Amiga Buddha and Catweasel IDE Driver
kernel-options.txt
- command line options for Linux/m68k

View File

@ -6,8 +6,14 @@
- information on the 3Com Etherlink III Series Ethernet cards.
6pack.txt
- info on the 6pack protocol, an alternative to KISS for AX.25
DLINK.txt
- info on the D-Link DE-600/DE-620 parallel port pocket adapters
LICENSE.qla3xxx
- GPLv2 for QLogic Linux Networking HBA Driver
LICENSE.qlge
- GPLv2 for QLogic Linux qlge NIC Driver
LICENSE.qlcnic
- GPLv2 for QLogic Linux qlcnic NIC Driver
Makefile
- Makefile for docsrc.
PLIP.txt
- PLIP: The Parallel Line Internet Protocol device driver
README.ipw2100
@ -17,7 +23,7 @@ README.ipw2200
README.sb1000
- info on General Instrument/NextLevel SURFboard1000 cable modem.
alias.txt
- info on using alias network devices
- info on using alias network devices.
arcnet-hardware.txt
- tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc.
arcnet.txt
@ -80,7 +86,7 @@ framerelay.txt
- info on using Frame Relay/Data Link Connection Identifier (DLCI).
gen_stats.txt
- Generic networking statistics for netlink users.
generic_hdlc.txt
generic-hdlc.txt
- The generic High Level Data Link Control (HDLC) layer.
generic_netlink.txt
- info on Generic Netlink
@ -88,6 +94,8 @@ gianfar.txt
- Gianfar Ethernet Driver.
i40e.txt
- README for the Intel Ethernet Controller XL710 Driver (i40e).
i40evf.txt
- Short note on the Driver for the Intel(R) XL710 X710 Virtual Function
ieee802154.txt
- Linux IEEE 802.15.4 implementation, API and drivers
igb.txt
@ -102,6 +110,8 @@ ipddp.txt
- AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation
iphase.txt
- Interphase PCI ATM (i)Chip IA Linux driver info.
ipsec.txt
- Note on not compressing IPSec payload and resulting failed policy check.
ipv6.txt
- Options to the ipv6 kernel module.
ipvs-sysctl.txt
@ -120,6 +130,8 @@ lapb-module.txt
- programming information of the LAPB module.
ltpc.txt
- the Apple or Farallon LocalTalk PC card driver
mac80211-auth-assoc-deauth.txt
- authentication and association / deauth-disassoc with max80211
mac80211-injection.txt
- HOWTO use packet injection with mac80211
multiqueue.txt
@ -134,6 +146,10 @@ netdevices.txt
- info on network device driver functions exported to the kernel.
netif-msg.txt
- Design of the network interface message level setting (NETIF_MSG_*).
netlink_mmap.txt
- memory mapped I/O with netlink
nf_conntrack-sysctl.txt
- list of netfilter-sysctl knobs.
nfc.txt
- The Linux Near Field Communication (NFS) subsystem.
openvswitch.txt
@ -176,7 +192,7 @@ skfp.txt
- SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
smc9.txt
- the driver for SMC's 9000 series of Ethernet cards
spider-net.txt
spider_net.txt
- README for the Spidernet Driver (as found in PS3 / Cell BE).
stmmac.txt
- README for the STMicro Synopsys Ethernet driver.
@ -188,6 +204,8 @@ tcp.txt
- short blurb on how TCP output takes place.
tcp-thin.txt
- kernel tuning options for low rate 'thin' TCP streams.
team.txt
- pointer to information for ethernet teaming devices.
tlan.txt
- ThunderLAN (Compaq Netelligent 10/100, Olicom OC-2xxx) driver info.
tproxy.txt
@ -200,6 +218,8 @@ vortex.txt
- info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards.
vxge.txt
- README for the Neterion X3100 PCIe Server Adapter.
vxlan.txt
- Virtual extensible LAN overview
x25.txt
- general info on X.25 development.
x25-iface.txt

View File

@ -1,45 +0,0 @@
The 3Com Etherlink Plus (3c505) driver.
This driver now uses DMA. There is currently no support for PIO operation.
The default DMA channel is 6; this is _not_ autoprobed, so you must
make sure you configure it correctly. If loading the driver as a
module, you can do this with "modprobe 3c505 dma=n". If the driver is
linked statically into the kernel, you must either use an "ether="
statement on the command line, or change the definition of ELP_DMA in 3c505.h.
The driver will warn you if it has to fall back on the compiled in
default DMA channel.
If no base address is given at boot time, the driver will autoprobe
ports 0x300, 0x280 and 0x310 (in that order). If no IRQ is given, the driver
will try to probe for it.
The driver can be used as a loadable module.
Theoretically, one instance of the driver can now run multiple cards,
in the standard way (when loading a module, say "modprobe 3c505
io=0x300,0x340 irq=10,11 dma=6,7" or whatever). I have not tested
this, though.
The driver may now support revision 2 hardware; the dependency on
being able to read the host control register has been removed. This
is also untested, since I don't have a suitable card.
Known problems:
I still see "DMA upload timed out" messages from time to time. These
seem to be fairly non-fatal though.
The card is old and slow.
To do:
Improve probe/setup code
Test multicast and promiscuous operation
Authors:
The driver is mainly written by Craig Southeren, email
<craigs@ineluki.apana.org.au>.
Parts of the driver (adapting the driver to 1.1.4+ kernels,
IRQ/address detection, some changes) and this README by
Juha Laiho <jlaiho@ichaos.nullnet.fi>.
DMA mode, more fixes, etc, by Philip Blundell <pjb27@cam.ac.uk>
Multicard support, Software configurable DMA, etc., by
Christopher Collins <ccollins@pcug.org.au>

View File

@ -75,14 +75,26 @@ Before the controller can make use of the PHY, it has to get a reference to
it. This framework provides the following APIs to get a reference to the PHY.
struct phy *phy_get(struct device *dev, const char *string);
struct phy *phy_optional_get(struct device *dev, const char *string);
struct phy *devm_phy_get(struct device *dev, const char *string);
struct phy *devm_phy_optional_get(struct device *dev, const char *string);
phy_get and devm_phy_get can be used to get the PHY. In the case of dt boot,
the string arguments should contain the phy name as given in the dt data and
in the case of non-dt boot, it should contain the label of the PHY.
The only difference between the two APIs is that devm_phy_get associates the
device with the PHY using devres on successful PHY get. On driver detach,
release function is invoked on the the devres data and devres data is freed.
phy_get, phy_optional_get, devm_phy_get and devm_phy_optional_get can
be used to get the PHY. In the case of dt boot, the string arguments
should contain the phy name as given in the dt data and in the case of
non-dt boot, it should contain the label of the PHY. The two
devm_phy_get associates the device with the PHY using devres on
successful PHY get. On driver detach, release function is invoked on
the the devres data and devres data is freed. phy_optional_get and
devm_phy_optional_get should be used when the phy is optional. These
two functions will never return -ENODEV, but instead returns NULL when
the phy cannot be found.
It should be noted that NULL is a valid phy reference. All phy
consumer calls on the NULL phy become NOPs. That is the release calls,
the phy_init() and phy_exit() calls, and phy_power_on() and
phy_power_off() calls are all NOP when applied to a NULL phy. The NULL
phy is useful in devices for handling optional phy devices.
5. Releasing a reference to the PHY

View File

@ -4,6 +4,8 @@ apm-acpi.txt
- basic info about the APM and ACPI support.
basic-pm-debugging.txt
- Debugging suspend and resume
charger-manager.txt
- Battery charger management.
devices.txt
- How drivers interact with system-wide power management
drivers-testing.txt
@ -22,6 +24,8 @@ pm_qos_interface.txt
- info on Linux PM Quality of Service interface
power_supply_class.txt
- Tells userspace about battery, UPS, AC or DC power supply properties
runtime_pm.txt
- Power management framework for I/O devices.
s2ram.txt
- How to get suspend to ram working (and debug it when it isn't)
states.txt
@ -38,7 +42,5 @@ tricks.txt
- How to trick software suspend (to disk) into working when it isn't
userland-swsusp.txt
- Experimental implementation of software suspend in userspace
video_extension.txt
- ACPI video extensions
video.txt
- Video issues during resume from suspend

View File

@ -117,6 +117,7 @@ static void usage(char *progname)
" -f val adjust the ptp clock frequency by 'val' ppb\n"
" -g get the ptp clock time\n"
" -h prints this message\n"
" -i val index for event/trigger\n"
" -k val measure the time offset between system and phc clock\n"
" for 'val' times (Maximum 25)\n"
" -p val enable output with a period of 'val' nanoseconds\n"
@ -154,6 +155,7 @@ int main(int argc, char *argv[])
int capabilities = 0;
int extts = 0;
int gettime = 0;
int index = 0;
int oneshot = 0;
int pct_offset = 0;
int n_samples = 0;
@ -167,7 +169,7 @@ int main(int argc, char *argv[])
progname = strrchr(argv[0], '/');
progname = progname ? 1+progname : argv[0];
while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghk:p:P:sSt:v"))) {
while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghi:k:p:P:sSt:v"))) {
switch (c) {
case 'a':
oneshot = atoi(optarg);
@ -190,6 +192,9 @@ int main(int argc, char *argv[])
case 'g':
gettime = 1;
break;
case 'i':
index = atoi(optarg);
break;
case 'k':
pct_offset = 1;
n_samples = atoi(optarg);
@ -301,7 +306,7 @@ int main(int argc, char *argv[])
if (extts) {
memset(&extts_request, 0, sizeof(extts_request));
extts_request.index = 0;
extts_request.index = index;
extts_request.flags = PTP_ENABLE_FEATURE;
if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
perror("PTP_EXTTS_REQUEST");
@ -375,7 +380,7 @@ int main(int argc, char *argv[])
return -1;
}
memset(&perout_request, 0, sizeof(perout_request));
perout_request.index = 0;
perout_request.index = index;
perout_request.start.sec = ts.tv_sec + 2;
perout_request.start.nsec = 0;
perout_request.period.sec = 0;

View File

@ -16,11 +16,13 @@ Debugging390.txt
- hints for debugging on s390 systems.
driver-model.txt
- information on s390 devices and the driver model.
kvm.txt
- ioctl calls to /dev/kvm on s390.
monreader.txt
- information on accessing the z/VM monitor stream from Linux.
qeth.txt
- HiperSockets Bridge Port Support.
s390dbf.txt
- information on using the s390 debug feature.
TAPE
- information on the driver for channel-attached tapes.
zfcpdump
zfcpdump.txt
- information on the s390 SCSI dump tool.

View File

@ -2,6 +2,8 @@
- this file.
sched-arch.txt
- CPU Scheduler implementation hints for architecture specific code.
sched-bwc.txt
- CFS bandwidth control overview.
sched-design-CFS.txt
- goals, design and implementation of the Completely Fair Scheduler.
sched-domains.txt

View File

@ -36,6 +36,8 @@ NinjaSCSI.txt
- info on WorkBiT NinjaSCSI-32/32Bi driver
aacraid.txt
- Driver supporting Adaptec RAID controllers
advansys.txt
- List of Advansys Host Adapters
aha152x.txt
- info on driver for Adaptec AHA152x based adapters
aic79xx.txt
@ -44,6 +46,12 @@ aic7xxx.txt
- info on driver for Adaptec controllers
arcmsr_spec.txt
- ARECA FIRMWARE SPEC (for IOP331 adapter)
bfa.txt
- Brocade FC/FCOE adapter driver.
bnx2fc.txt
- FCoE hardware offload for Broadcom network interfaces.
cxgb3i.txt
- Chelsio iSCSI Linux Driver
dc395x.txt
- README file for the dc395x SCSI driver
dpti.txt
@ -52,18 +60,24 @@ dtc3x80.txt
- info on driver for DTC 2x80 based adapters
g_NCR5380.txt
- info on driver for NCR5380 and NCR53c400 based adapters
hpsa.txt
- HP Smart Array Controller SCSI driver.
hptiop.txt
- HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
in2000.txt
- info on in2000 driver
libsas.txt
- Serial Attached SCSI management layer.
link_power_management_policy.txt
- Link power management options.
lpfc.txt
- LPFC driver release notes
megaraid.txt
- Common Management Module, shared code handling ioctls for LSI drivers
ncr53c8xx.txt
- info on driver for NCR53c8xx based adapters
osd.txt
Object-Based Storage Device, command set introduction.
osst.txt
- info on driver for OnStream SC-x0 SCSI tape
ppa.txt
@ -74,6 +88,8 @@ scsi-changer.txt
- README for the SCSI media changer driver
scsi-generic.txt
- info on the sg driver for generic (non-disk/CD/tape) SCSI devices.
scsi-parameters.txt
- List of SCSI-parameters to pass to the kernel at module load-time.
scsi.txt
- short blurb on using SCSI support as a module.
scsi_mid_low_api.txt

View File

@ -4,10 +4,12 @@ README.cycladesZ
- info on Cyclades-Z firmware loading.
digiepca.txt
- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
hayes-esp.txt
- info on using the Hayes ESP serial driver.
driver
- intro to the low level serial driver.
moxa-smartio
- file with info on installing/using Moxa multiport serial driver.
n_gsm.txt
- GSM 0710 tty multiplexer howto.
riscom8.txt
- notes on using the RISCom/8 multi-port serial driver.
rocket.txt

View File

@ -0,0 +1,22 @@
00-INDEX
- this file.
Makefile
- Makefile for the example sourcefiles.
butterfly
- AVR Butterfly SPI driver overview and pin configuration.
ep93xx_spi
- Basic EP93xx SPI driver configuration.
pxa2xx
- PXA2xx SPI master controller build by spi_message fifo wq
spidev
- Intro to the userspace API for spi devices
spidev_fdx.c
- spidev example file
spi-lm70llp
- Connecting an LM70-LLP sensor to the kernel via the SPI subsys.
spi-sc18is602
- NXP SC18IS602/603 I2C-bus to SPI bridge
spi-summary
- (Linux) SPI overview. If unsure about SPI or SPI in Linux, start here.
spidev_test.c
- SPI testing utility.

View File

@ -543,7 +543,22 @@ SPI MASTER METHODS
queuing transfers that arrive in the meantime. When the driver is
finished with this message, it must call
spi_finalize_current_message() so the subsystem can issue the next
transfer. This may sleep.
message. This may sleep.
master->transfer_one(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *transfer)
The subsystem calls the driver to transfer a single transfer while
queuing transfers that arrive in the meantime. When the driver is
finished with this transfer, it must call
spi_finalize_current_transfer() so the subsystem can issue the next
transfer. This may sleep. Note: transfer_one and transfer_one_message
are mutually exclusive; when both are set, the generic subsystem does
not call your transfer_one callback.
Return values:
negative errno: error
0: transfer is finished
1: transfer is still in progress
DEPRECATED METHODS

View File

@ -8,6 +8,8 @@ hpet_example.c
- sample hpet timer test program
hrtimers.txt
- subsystem for high-resolution kernel timers
Makefile
- Build and link hpet_example
NO_HZ.txt
- Summary of the different methods for the scheduler clock-interrupts management.
timers-howto.txt

View File

@ -20,5 +20,7 @@ ppc-pv.txt
- the paravirtualization interface on PowerPC.
review-checklist.txt
- review checklist for KVM patches.
s390-diag.txt
- Diagnose hypercall description (for IBM S/390)
timekeeping.txt
- timekeeping virtualization for x86-based architectures.

View File

@ -16,8 +16,6 @@ hwpoison.txt
- explains what hwpoison is
ksm.txt
- how to use the Kernel Samepage Merging feature.
locking
- info on how locking and synchronization is done in the Linux vm code.
numa
- information about NUMA specific code in the Linux vm.
numa_memory_policy.txt
@ -32,6 +30,8 @@ slub.txt
- a short users guide for SLUB.
soft-dirty.txt
- short explanation for soft-dirty PTEs
split_page_table_lock
- Separate per-table lock to improve scalability of the old page_table_lock.
transhuge.txt
- Transparent Hugepage Support, alternative way of using hugepages.
unevictable-lru.txt

View File

@ -4,7 +4,9 @@ ds2482
- The Maxim/Dallas Semiconductor DS2482 provides 1-wire busses.
ds2490
- The Maxim/Dallas Semiconductor DS2490 builds USB <-> W1 bridges.
mxc_w1
mxc-w1
- W1 master controller driver found on Freescale MX2/MX3 SoCs
omap-hdq
- HDQ/1-wire module of TI OMAP 2430/3430.
w1-gpio
- GPIO 1-wire bus master driver.

View File

@ -4,3 +4,5 @@ w1_therm
- The Maxim/Dallas Semiconductor ds18*20 temperature sensor.
w1_ds2423
- The Maxim/Dallas Semiconductor ds2423 counter device.
w1_ds28e04
- The Maxim/Dallas Semiconductor ds28e04 eeprom.

View File

@ -1,6 +1,20 @@
00-INDEX
- this file
mtrr.txt
- how to use x86 Memory Type Range Registers to increase performance
boot.txt
- List of boot protocol versions
early-microcode.txt
- How to load microcode from an initrd-CPIO archive early to fix CPU issues.
earlyprintk.txt
- Using earlyprintk with a USB2 debug port key.
entry_64.txt
- Describe (some of the) kernel entry points for x86.
exception-tables.txt
- why and how Linux kernel uses exception tables on x86
mtrr.txt
- how to use x86 Memory Type Range Registers to increase performance
pat.txt
- Page Attribute Table intro and API
usb-legacy-support.txt
- how to fix/avoid quirks when using emulated PS/2 mouse/keyboard.
zero-page.txt
- layout of the first page of memory.

View File

@ -7,7 +7,7 @@ help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Maintainer: Will Deacon <will.deacon@arm.com>
Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
Chinese maintainer: Fu Wei <wefu@redhat.com>
---------------------------------------------------------------------
Documentation/arm64/booting.txt 的中文翻译
@ -16,9 +16,9 @@ Documentation/arm64/booting.txt 的中文翻译
译存在问题,请联系中文版维护者。
英文版维护者: Will Deacon <will.deacon@arm.com>
中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
中文版维护者: 傅炜 Fu Wei <wefu@redhat.com>
中文版翻译者: 傅炜 Fu Wei <wefu@redhat.com>
中文版校译者: 傅炜 Fu Wei <wefu@redhat.com>
以下为正文
---------------------------------------------------------------------
@ -64,8 +64,8 @@ RAM或可能使用对这个设备已知的 RAM 信息,还可能使用任何
必要性: 强制
设备树数据块dtb大小必须不大于 2 MB且位于从内核映像起始算起第一个
512MB 内的 2MB 边界上。这使得内核可以通过初始页表中的单个节描述符来
设备树数据块dtb必须 8 字节对齐,并位于从内核映像起始算起第一个 512MB
内,且不得跨越 2MB 对齐边界。这使得内核可以通过初始页表中的单个节描述符来
映射此数据块。
@ -84,13 +84,23 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内
必要性: 强制
已解压的内核映像包含一个 32 字节的头,内容如下:
已解压的内核映像包含一个 64 字节的头,内容如下:
u32 magic = 0x14000008; /* 跳转到 stext, 小端 */
u32 res0 = 0; /* 保留 */
u32 code0; /* 可执行代码 */
u32 code1; /* 可执行代码 */
u64 text_offset; /* 映像装载偏移 */
u64 res0 = 0; /* 保留 */
u64 res1 = 0; /* 保留 */
u64 res2 = 0; /* 保留 */
u64 res3 = 0; /* 保留 */
u64 res4 = 0; /* 保留 */
u32 magic = 0x644d5241; /* 魔数, 小端, "ARM\x64" */
u32 res5 = 0; /* 保留 */
映像头注释:
- code0/code1 负责跳转到 stext.
映像必须位于系统 RAM 起始处的特定偏移(当前是 0x80000。系统 RAM
的起始地址必须是以 2MB 对齐的。
@ -118,9 +128,9 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内
外部高速缓存(如果存在)必须配置并禁用。
- 架构计时器
CNTFRQ 必须设定为计时器的频率
如果在 EL1 模式下进入内核,则 CNTHCTL_EL2 中的 EL1PCTEN (bit 0)
必须置位。
CNTFRQ 必须设定为计时器的频率,且 CNTVOFF 必须设定为对所有 CPU
都一致的值。如果在 EL1 模式下进入内核,则 CNTHCTL_EL2 中的
EL1PCTEN (bit 0) 必须置位。
- 一致性
通过内核启动的所有 CPU 在内核入口地址上必须处于相同的一致性域中。
@ -131,23 +141,40 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内
在进入内核映像的异常级中,所有构架中可写的系统寄存器必须通过软件
在一个更高的异常级别下初始化,以防止在 未知 状态下运行。
以上对于 CPU 模式、高速缓存、MMU、架构计时器、一致性、系统寄存器的
必要条件描述适用于所有 CPU。所有 CPU 必须在同一异常级别跳入内核。
引导装载程序必须在每个 CPU 处于以下状态时跳入内核入口:
- 主 CPU 必须直接跳入内核映像的第一条指令。通过此 CPU 传递的设备树
数据块必须在每个 CPU 节点中包含以下内容:
1、enable-method属性。目前此字段支持的值仅为字符串“spin-table”。
2、cpu-release-addr标识一个 64-bit、初始化为零的内存位置。
数据块必须在每个 CPU 节点中包含一个 enable-method 属性,所
支持的 enable-method 请见下文。
引导装载程序必须生成这些设备树属性,并在跳入内核入口之前将其插入
数据块。
- 任何辅助 CPU 必须在内存保留区(通过设备树中的 /memreserve/ 域传递
- enable-method 为 “spin-table” 的 CPU 必须在它们的 CPU
节点中包含一个 cpu-release-addr 属性。这个属性标识了一个
64 位自然对齐且初始化为零的内存位置。
这些 CPU 必须在内存保留区(通过设备树中的 /memreserve/ 域传递
给内核)中自旋于内核之外,轮询它们的 cpu-release-addr 位置(必须
包含在保留区中)。可通过插入 wfe 指令来降低忙循环开销,而主 CPU 将
发出 sev 指令。当对 cpu-release-addr 所指位置的读取操作返回非零值
CPU 必须直接跳入此值所指向的地址。
CPU 必须跳入此值所指向的地址。此值为一个单独的 64 位小端值,
因此 CPU 须在跳转前将所读取的值转换为其本身的端模式。
- enable-method 为 “psci” 的 CPU 保持在内核外(比如,在
memory 节点中描述为内核空间的内存区外,或在通过设备树 /memreserve/
域中描述为内核保留区的空间中)。内核将会发起在 ARM 文档(编号
ARM DEN 0022A用于 ARM 上的电源状态协调接口系统软件)中描述的
CPU_ON 调用来将 CPU 带入内核。
*译者注:到文档翻译时,此文档已更新为 ARM DEN 0022B。
设备树必须包含一个 psci 节点,请参考以下文档:
Documentation/devicetree/bindings/arm/psci.txt
- 辅助 CPU 通用寄存器设置
x0 = 0 (保留,将来可能使用)

View File

@ -7,7 +7,7 @@ help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Maintainer: Catalin Marinas <catalin.marinas@arm.com>
Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
Chinese maintainer: Fu Wei <wefu@redhat.com>
---------------------------------------------------------------------
Documentation/arm64/memory.txt 的中文翻译
@ -16,9 +16,9 @@ Documentation/arm64/memory.txt 的中文翻译
译存在问题,请联系中文版维护者。
英文版维护者: Catalin Marinas <catalin.marinas@arm.com>
中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
中文版维护者: 傅炜 Fu Wei <wefu@redhat.com>
中文版翻译者: 傅炜 Fu Wei <wefu@redhat.com>
中文版校译者: 傅炜 Fu Wei <wefu@redhat.com>
以下为正文
---------------------------------------------------------------------
@ -41,7 +41,7 @@ AArch64 Linux 使用页大小为 4KB 的 3 级转换表配置,对于用户和
TTBR1 中,且从不写入 TTBR0。
AArch64 Linux 内存布局:
AArch64 Linux 在页大小为 4KB 时的内存布局:
起始地址 结束地址 大小 用途
-----------------------------------------------------------------------
@ -55,15 +55,42 @@ ffffffbc00000000 ffffffbdffffffff 8GB vmemmap
ffffffbe00000000 ffffffbffbbfffff ~8GB [防护页,未来用于 vmmemap]
ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk 设备
ffffffbffbe00000 ffffffbffbe0ffff 64KB PCI I/O 空间
ffffffbbffff0000 ffffffbcffffffff ~2MB [防护页]
ffffffbffbe10000 ffffffbcffffffff ~2MB [防护页]
ffffffbffc000000 ffffffbfffffffff 64MB 模块
ffffffc000000000 ffffffffffffffff 256GB 内核逻辑内存映射
AArch64 Linux 在页大小为 64KB 时的内存布局:
起始地址 结束地址 大小 用途
-----------------------------------------------------------------------
0000000000000000 000003ffffffffff 4TB 用户空间
fffffc0000000000 fffffdfbfffeffff ~2TB vmalloc
fffffdfbffff0000 fffffdfbffffffff 64KB [防护页]
fffffdfc00000000 fffffdfdffffffff 8GB vmemmap
fffffdfe00000000 fffffdfffbbfffff ~8GB [防护页,未来用于 vmmemap]
fffffdfffbc00000 fffffdfffbdfffff 2MB earlyprintk 设备
fffffdfffbe00000 fffffdfffbe0ffff 64KB PCI I/O 空间
fffffdfffbe10000 fffffdfffbffffff ~2MB [防护页]
fffffdfffc000000 fffffdffffffffff 64MB 模块
fffffe0000000000 ffffffffffffffff 2TB 内核逻辑内存映射
4KB 页大小的转换表查找:
+--------+--------+--------+--------+--------+--------+--------+--------+
@ -91,3 +118,10 @@ ffffffc000000000 ffffffffffffffff 256GB 内核逻辑内存映射
| | +--------------------------> [41:29] L2 索引 (仅使用 38:29 )
| +-------------------------------> [47:42] L1 索引 (未使用)
+-------------------------------------------------> [63] TTBR0/1
当使用 KVM 时, 管理程序hypervisor在 EL2 中通过相对内核虚拟地址的
一个固定偏移来映射内核页(内核虚拟地址的高 24 位设为零):
起始地址 结束地址 大小 用途
-----------------------------------------------------------------------
0000004000000000 0000007fffffffff 256GB 在 HYP 中映射的内核对象

View File

@ -0,0 +1,52 @@
Chinese translated version of Documentation/arm64/tagged-pointers.txt
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Maintainer: Will Deacon <will.deacon@arm.com>
Chinese maintainer: Fu Wei <wefu@redhat.com>
---------------------------------------------------------------------
Documentation/arm64/tagged-pointers.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
英文版维护者: Will Deacon <will.deacon@arm.com>
中文版维护者: 傅炜 Fu Wei <wefu@redhat.com>
中文版翻译者: 傅炜 Fu Wei <wefu@redhat.com>
中文版校译者: 傅炜 Fu Wei <wefu@redhat.com>
以下为正文
---------------------------------------------------------------------
Linux 在 AArch64 中带标记的虚拟地址
=================================
作者: Will Deacon <will.deacon@arm.com>
日期: 2013 年 06 月 12 日
本文档简述了在 AArch64 地址转换系统中提供的带标记的虚拟地址及其在
AArch64 Linux 中的潜在用途。
内核提供的地址转换表配置使通过 TTBR0 完成的虚拟地址转换(即用户空间
映射),其虚拟地址的最高 8 位63:56会被转换硬件所忽略。这种机制
让这些位可供应用程序自由使用,其注意事项如下:
(1) 内核要求所有传递到 EL1 的用户空间地址带有 0x00 标记。
这意味着任何携带用户空间虚拟地址的系统调用syscall
参数 *必须* 在陷入内核前使它们的最高字节被清零。
(2) 非零标记在传递信号时不被保存。这意味着在应用程序中利用了
标记的信号处理函数无法依赖 siginfo_t 的用户空间虚拟
地址所携带的包含其内部域信息的标记。此规则的一个例外是
当信号是在调试观察点的异常处理程序中产生的,此时标记的
信息将被保存。
(3) 当使用带标记的指针时需特别留心,因为仅对两个虚拟地址
的高字节C 编译器很可能无法判断它们是不同的。
此构架会阻止对带标记的 PC 指针的利用,因此在异常返回时,其高字节
将被设置成一个为 “55” 的扩展符。

View File

@ -538,7 +538,7 @@ F: arch/alpha/
ALTERA UART/JTAG UART SERIAL DRIVERS
M: Tobias Klauser <tklauser@distanz.ch>
L: linux-serial@vger.kernel.org
L: nios2-dev@sopc.et.ntust.edu.tw (moderated for non-subscribers)
L: nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
S: Maintained
F: drivers/tty/serial/altera_uart.c
F: drivers/tty/serial/altera_jtaguart.c
@ -1860,6 +1860,7 @@ F: drivers/net/ethernet/broadcom/bnx2x/
BROADCOM BCM281XX/BCM11XXX ARM ARCHITECTURE
M: Christian Daudt <bcm@fixthebug.org>
M: Matt Porter <mporter@linaro.org>
L: bcm-kernel-feedback-list@broadcom.com
T: git git://git.github.com/broadcom/bcm11351
S: Maintained
@ -2367,7 +2368,7 @@ F: include/linux/cpufreq.h
CPU FREQUENCY DRIVERS - ARM BIG LITTLE
M: Viresh Kumar <viresh.kumar@linaro.org>
M: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
M: Sudeep Holla <sudeep.holla@arm.com>
L: cpufreq@vger.kernel.org
L: linux-pm@vger.kernel.org
W: http://www.arm.com/products/processors/technologies/biglittleprocessing.php
@ -2408,8 +2409,10 @@ F: tools/power/cpupower/
CPUSETS
M: Li Zefan <lizefan@huawei.com>
L: cgroups@vger.kernel.org
W: http://www.bullopensource.org/cpuset/
W: http://oss.sgi.com/projects/cpusets/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
S: Maintained
F: Documentation/cgroups/cpusets.txt
F: include/linux/cpuset.h
@ -2608,9 +2611,9 @@ DC395x SCSI driver
M: Oliver Neukum <oliver@neukum.org>
M: Ali Akcaagac <aliakc@web.de>
M: Jamie Lenehan <lenehan@twibble.org>
W: http://twibble.org/dist/dc395x/
L: dc395x@twibble.org
L: http://lists.twibble.org/mailman/listinfo/dc395x/
W: http://twibble.org/dist/dc395x/
W: http://lists.twibble.org/mailman/listinfo/dc395x/
S: Maintained
F: Documentation/scsi/dc395x.txt
F: drivers/scsi/dc395x.*
@ -2845,19 +2848,29 @@ F: lib/kobj*
DRM DRIVERS
M: David Airlie <airlied@linux.ie>
L: dri-devel@lists.freedesktop.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
T: git git://people.freedesktop.org/~airlied/linux
S: Maintained
F: drivers/gpu/drm/
F: include/drm/
F: include/uapi/drm/
RADEON DRM DRIVERS
M: Alex Deucher <alexander.deucher@amd.com>
M: Christian König <christian.koenig@amd.com>
L: dri-devel@lists.freedesktop.org
T: git git://people.freedesktop.org/~agd5f/linux
S: Supported
F: drivers/gpu/drm/radeon/
F: include/drm/radeon*
F: include/uapi/drm/radeon*
INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
M: Daniel Vetter <daniel.vetter@ffwll.ch>
M: Jani Nikula <jani.nikula@linux.intel.com>
L: intel-gfx@lists.freedesktop.org
L: dri-devel@lists.freedesktop.org
Q: http://patchwork.freedesktop.org/project/intel-gfx/
T: git git://people.freedesktop.org/~danvet/drm-intel
T: git git://anongit.freedesktop.org/drm-intel
S: Supported
F: drivers/gpu/drm/i915/
F: include/drm/i915*
@ -3324,6 +3337,17 @@ S: Maintained
F: include/linux/netfilter_bridge/
F: net/bridge/
ETHERNET PHY LIBRARY
M: Florian Fainelli <f.fainelli@gmail.com>
L: netdev@vger.kernel.org
S: Maintained
F: include/linux/phy.h
F: include/linux/phy_fixed.h
F: drivers/net/phy/
F: Documentation/networking/phy.txt
F: drivers/of/of_mdio.c
F: drivers/of/of_net.c
EXT2 FILE SYSTEM
M: Jan Kara <jack@suse.cz>
L: linux-ext4@vger.kernel.org
@ -5487,6 +5511,11 @@ W: http://www.kernel.org/doc/man-pages
L: linux-man@vger.kernel.org
S: Maintained
MARVELL ARMADA DRM SUPPORT
M: Russell King <rmk+kernel@arm.linux.org.uk>
S: Maintained
F: drivers/gpu/drm/armada/
MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
M: Mirko Lindner <mlindner@marvell.com>
M: Stephen Hemminger <stephen@networkplumber.org>
@ -7196,7 +7225,7 @@ S: Maintained
F: drivers/net/ethernet/rdc/r6040.c
RDS - RELIABLE DATAGRAM SOCKETS
M: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
M: Chien Yen <chien.yen@oracle.com>
L: rds-devel@oss.oracle.com (moderated for non-subscribers)
S: Supported
F: net/rds/
@ -8429,8 +8458,8 @@ TARGET SUBSYSTEM
M: Nicholas A. Bellinger <nab@linux-iscsi.org>
L: linux-scsi@vger.kernel.org
L: target-devel@vger.kernel.org
L: http://groups.google.com/group/linux-iscsi-target-dev
W: http://www.linux-iscsi.org
W: http://groups.google.com/group/linux-iscsi-target-dev
T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
S: Supported
F: drivers/target/
@ -9715,7 +9744,6 @@ F: drivers/xen/*swiotlb*
XFS FILESYSTEM
P: Silicon Graphics Inc
M: Dave Chinner <david@fromorbit.com>
M: Ben Myers <bpm@sgi.com>
M: xfs@oss.sgi.com
L: xfs@oss.sgi.com
W: http://oss.sgi.com/projects/xfs

View File

@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 14
SUBLEVEL = 0
EXTRAVERSION = -rc2
EXTRAVERSION = -rc5
NAME = Shuffling Zombie Juror
# *DOCUMENTATION*
@ -605,10 +605,11 @@ endif
ifdef CONFIG_CC_STACKPROTECTOR_REGULAR
stackp-flag := -fstack-protector
ifeq ($(call cc-option, $(stackp-flag)),)
$(warning Cannot use CONFIG_CC_STACKPROTECTOR: \
-fstack-protector not supported by compiler))
$(warning Cannot use CONFIG_CC_STACKPROTECTOR_REGULAR: \
-fstack-protector not supported by compiler)
endif
else ifdef CONFIG_CC_STACKPROTECTOR_STRONG
else
ifdef CONFIG_CC_STACKPROTECTOR_STRONG
stackp-flag := -fstack-protector-strong
ifeq ($(call cc-option, $(stackp-flag)),)
$(warning Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: \
@ -618,6 +619,7 @@ else
# Force off for distro compilers that enable stack protector by default.
stackp-flag := $(call cc-option, -fno-stack-protector)
endif
endif
KBUILD_CFLAGS += $(stackp-flag)
# This warning generated too much noise in a regular build.

View File

@ -86,9 +86,7 @@ config KPROBES_ON_FTRACE
optimize on top of function tracing.
config UPROBES
bool "Transparent user-space probes (EXPERIMENTAL)"
depends on UPROBE_EVENT && PERF_EVENTS
default n
def_bool n
select PERCPU_RWSEM
help
Uprobes is the user-space counterpart to kprobes: they
@ -101,8 +99,6 @@ config UPROBES
managed by the kernel and kept transparent to the probed
application. )
If in doubt, say "N".
config HAVE_64BIT_ALIGNED_ACCESS
def_bool 64BIT && !HAVE_EFFICIENT_UNALIGNED_ACCESS
help

View File

@ -207,6 +207,9 @@ config ZONE_DMA
config NEED_DMA_MAP_STATE
def_bool y
config ARCH_SUPPORTS_UPROBES
def_bool y
config ARCH_HAS_DMA_SET_COHERENT_MASK
bool
@ -2272,7 +2275,7 @@ source "kernel/power/Kconfig"
config ARCH_SUSPEND_POSSIBLE
depends on !ARCH_S5PC100
depends on CPU_ARM920T || CPU_ARM926T || CPU_FEROCEON || CPU_SA1100 || \
CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE || CPU_MOHAWK
CPU_V6 || CPU_V6K || CPU_V7 || CPU_V7M || CPU_XSC3 || CPU_XSCALE || CPU_MOHAWK
def_bool y
config ARM_CPU_SUSPEND

View File

@ -38,6 +38,7 @@ dtb-$(CONFIG_ARCH_AT91) += at91sam9g35ek.dtb
dtb-$(CONFIG_ARCH_AT91) += at91sam9x25ek.dtb
dtb-$(CONFIG_ARCH_AT91) += at91sam9x35ek.dtb
# sama5d3
dtb-$(CONFIG_ARCH_AT91) += at91-sama5d3_xplained.dtb
dtb-$(CONFIG_ARCH_AT91) += sama5d31ek.dtb
dtb-$(CONFIG_ARCH_AT91) += sama5d33ek.dtb
dtb-$(CONFIG_ARCH_AT91) += sama5d34ek.dtb
@ -208,7 +209,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
omap3-n900.dtb \
omap3-n9.dtb \
omap3-n950.dtb \
omap3-tobi.dtb \
omap3-overo-tobi.dtb \
omap3-overo-storm-tobi.dtb \
omap3-gta04.dtb \
omap3-igep0020.dtb \
omap3-igep0030.dtb \

View File

@ -121,7 +121,7 @@
ti,model = "AM335x-EVMSK";
ti,audio-codec = <&tlv320aic3106>;
ti,mcasp-controller = <&mcasp1>;
ti,codec-clock-rate = <24576000>;
ti,codec-clock-rate = <24000000>;
ti,audio-routing =
"Headphone Jack", "HPLOUT",
"Headphone Jack", "HPROUT";
@ -256,6 +256,12 @@
>;
};
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
>;
};
mcasp1_pins: mcasp1_pins {
pinctrl-single,pins = <
0x10c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
@ -456,6 +462,9 @@
status = "okay";
vmmc-supply = <&vmmc_reg>;
bus-width = <4>;
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
};
&sham {

View File

@ -23,6 +23,7 @@
gpio0 = &gpio0;
gpio1 = &gpio1;
gpio2 = &gpio2;
eth3 = &eth3;
};
cpus {
@ -291,7 +292,7 @@
interrupts = <91>;
};
ethernet@34000 {
eth3: ethernet@34000 {
compatible = "marvell,armada-370-neta";
reg = <0x34000 0x4000>;
interrupts = <14>;

View File

@ -0,0 +1,229 @@
/*
* at91-sama5d3_xplained.dts - Device Tree file for the SAMA5D3 Xplained board
*
* Copyright (C) 2014 Atmel,
* 2014 Nicolas Ferre <nicolas.ferre@atmel.com>
*
* Licensed under GPLv2 or later.
*/
/dts-v1/;
#include "sama5d36.dtsi"
/ {
model = "SAMA5D3 Xplained";
compatible = "atmel,sama5d3-xplained", "atmel,sama5d3", "atmel,sama5";
chosen {
bootargs = "console=ttyS0,115200";
};
memory {
reg = <0x20000000 0x10000000>;
};
ahb {
apb {
mmc0: mmc@f0000000 {
pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_dat4_7 &pinctrl_mmc0_cd>;
status = "okay";
slot@0 {
reg = <0>;
bus-width = <8>;
cd-gpios = <&pioE 0 GPIO_ACTIVE_LOW>;
};
};
spi0: spi@f0004000 {
cs-gpios = <&pioD 13 0>;
status = "okay";
};
can0: can@f000c000 {
status = "okay";
};
i2c0: i2c@f0014000 {
status = "okay";
};
i2c1: i2c@f0018000 {
status = "okay";
};
macb0: ethernet@f0028000 {
phy-mode = "rgmii";
status = "okay";
};
usart0: serial@f001c000 {
status = "okay";
};
usart1: serial@f0020000 {
pinctrl-0 = <&pinctrl_usart1 &pinctrl_usart1_rts_cts>;
status = "okay";
};
uart0: serial@f0024000 {
status = "okay";
};
mmc1: mmc@f8000000 {
pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>;
status = "okay";
slot@0 {
reg = <0>;
bus-width = <4>;
cd-gpios = <&pioE 1 GPIO_ACTIVE_HIGH>;
};
};
spi1: spi@f8008000 {
cs-gpios = <&pioC 25 0>, <0>, <0>, <&pioD 16 0>;
status = "okay";
};
adc0: adc@f8018000 {
pinctrl-0 = <
&pinctrl_adc0_adtrg
&pinctrl_adc0_ad0
&pinctrl_adc0_ad1
&pinctrl_adc0_ad2
&pinctrl_adc0_ad3
&pinctrl_adc0_ad4
&pinctrl_adc0_ad5
&pinctrl_adc0_ad6
&pinctrl_adc0_ad7
&pinctrl_adc0_ad8
&pinctrl_adc0_ad9
>;
status = "okay";
};
i2c2: i2c@f801c000 {
dmas = <0>, <0>; /* Do not use DMA for i2c2 */
status = "okay";
};
macb1: ethernet@f802c000 {
phy-mode = "rmii";
status = "okay";
};
dbgu: serial@ffffee00 {
status = "okay";
};
pinctrl@fffff200 {
board {
pinctrl_mmc0_cd: mmc0_cd {
atmel,pins =
<AT91_PIOE 0 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
};
pinctrl_mmc1_cd: mmc1_cd {
atmel,pins =
<AT91_PIOE 1 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
};
pinctrl_usba_vbus: usba_vbus {
atmel,pins =
<AT91_PIOE 9 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>; /* PE9, conflicts with A9 */
};
};
};
pmc: pmc@fffffc00 {
main: mainck {
clock-frequency = <12000000>;
};
};
};
nand0: nand@60000000 {
nand-bus-width = <8>;
nand-ecc-mode = "hw";
atmel,has-pmecc;
atmel,pmecc-cap = <4>;
atmel,pmecc-sector-size = <512>;
nand-on-flash-bbt;
status = "okay";
at91bootstrap@0 {
label = "at91bootstrap";
reg = <0x0 0x40000>;
};
bootloader@40000 {
label = "bootloader";
reg = <0x40000 0x80000>;
};
bootloaderenv@c0000 {
label = "bootloader env";
reg = <0xc0000 0xc0000>;
};
dtb@180000 {
label = "device tree";
reg = <0x180000 0x80000>;
};
kernel@200000 {
label = "kernel";
reg = <0x200000 0x600000>;
};
rootfs@800000 {
label = "rootfs";
reg = <0x800000 0x0f800000>;
};
};
usb0: gadget@00500000 {
atmel,vbus-gpio = <&pioE 9 GPIO_ACTIVE_HIGH>; /* PE9, conflicts with A9 */
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usba_vbus>;
status = "okay";
};
usb1: ohci@00600000 {
num-ports = <3>;
atmel,vbus-gpio = <0
&pioE 3 GPIO_ACTIVE_LOW
&pioE 4 GPIO_ACTIVE_LOW
>;
status = "okay";
};
usb2: ehci@00700000 {
status = "okay";
};
};
gpio_keys {
compatible = "gpio-keys";
bp3 {
label = "PB_USER";
gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
linux,code = <0x104>;
gpio-key,wakeup;
};
};
leds {
compatible = "gpio-leds";
d2 {
label = "d2";
gpios = <&pioE 23 GPIO_ACTIVE_LOW>; /* PE23, conflicts with A23, CTS2 */
linux,default-trigger = "heartbeat";
};
d3 {
label = "d3";
gpios = <&pioE 24 GPIO_ACTIVE_HIGH>;
};
};
};

View File

@ -523,7 +523,7 @@
};
i2c0: i2c@fff88000 {
compatible = "atmel,at91sam9263-i2c";
compatible = "atmel,at91sam9260-i2c";
reg = <0xfff88000 0x100>;
interrupts = <13 IRQ_TYPE_LEVEL_HIGH 6>;
#address-cells = <1>;

View File

@ -124,6 +124,10 @@
nand-on-flash-bbt;
status = "okay";
};
usb0: ohci@00500000 {
status = "okay";
};
};
leds {

View File

@ -379,15 +379,6 @@
#clock-cells = <1>;
};
pmu_intc: pmu-interrupt-ctrl@d0050 {
compatible = "marvell,dove-pmu-intc";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0xd0050 0x8>;
interrupts = <33>;
marvell,#interrupts = <7>;
};
pinctrl: pin-ctrl@d0200 {
compatible = "marvell,dove-pinctrl";
reg = <0xd0200 0x10>;
@ -610,8 +601,6 @@
rtc: real-time-clock@d8500 {
compatible = "marvell,orion-rtc";
reg = <0xd8500 0x20>;
interrupt-parent = <&pmu_intc>;
interrupts = <5>;
};
gpio2: gpio-ctrl@e8400 {

View File

@ -32,7 +32,7 @@
aux-button {
label = "aux";
linux,code = <169>;
gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
gpio-key,wakeup;
};
};
@ -92,6 +92,8 @@
bmp085@77 {
compatible = "bosch,bmp085";
reg = <0x77>;
interrupt-parent = <&gpio4>;
interrupts = <17 IRQ_TYPE_EDGE_RISING>;
};
/* leds */
@ -141,8 +143,8 @@
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
vmmc-supply = <&vmmc1>;
vmmc_aux-supply = <&vsim>;
bus-width = <4>;
ti,non-removable;
};
&mmc2 {

View File

@ -14,5 +14,5 @@
/ {
model = "Nokia N9";
compatible = "nokia,omap3-n9", "ti,omap3";
compatible = "nokia,omap3-n9", "ti,omap36xx", "ti,omap3";
};

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2013 Pavel Machek <pavel@ucw.cz>
* Copyright 2013 Aaro Koskinen <aaro.koskinen@iki.fi>
* Copyright (C) 2013-2014 Aaro Koskinen <aaro.koskinen@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 (or later) as
@ -13,7 +13,7 @@
/ {
model = "Nokia N900";
compatible = "nokia,omap3-n900", "ti,omap3";
compatible = "nokia,omap3-n900", "ti,omap3430", "ti,omap3";
cpus {
cpu@0 {

View File

@ -14,5 +14,5 @@
/ {
model = "Nokia N950";
compatible = "nokia,omap3-n950", "ti,omap3";
compatible = "nokia,omap3-n950", "ti,omap36xx", "ti,omap3";
};

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* Tobi expansion board is manufactured by Gumstix Inc.
*/
/dts-v1/;
#include "omap36xx.dtsi"
#include "omap3-overo-tobi-common.dtsi"
/ {
model = "OMAP36xx/AM37xx/DM37xx Gumstix Overo on Tobi";
compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3";
};

View File

@ -13,9 +13,6 @@
#include "omap3-overo.dtsi"
/ {
model = "TI OMAP3 Gumstix Overo on Tobi";
compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3";
leds {
compatible = "gpio-leds";
heartbeat {

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* Tobi expansion board is manufactured by Gumstix Inc.
*/
/dts-v1/;
#include "omap34xx.dtsi"
#include "omap3-overo-tobi-common.dtsi"
/ {
model = "OMAP35xx Gumstix Overo on Tobi";
compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3";
};

View File

@ -9,9 +9,6 @@
/*
* The Gumstix Overo must be combined with an expansion board.
*/
/dts-v1/;
#include "omap34xx.dtsi"
/ {
pwmleds {

View File

@ -1228,7 +1228,7 @@
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00600000 0x100000>;
interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>;
clocks = <&usb>, <&uhphs_clk>, <&udphs_clk>,
clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>,
<&uhpck>;
clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
status = "disabled";

View File

@ -188,7 +188,6 @@
msp2: msp@80117000 {
pinctrl-names = "default";
pinctrl-0 = <&msp2_default_mode>;
status = "okay";
};
msp3: msp@80125000 {

View File

@ -315,7 +315,7 @@
ranges;
emac: ethernet@01c0b000 {
compatible = "allwinner,sun4i-emac";
compatible = "allwinner,sun4i-a10-emac";
reg = <0x01c0b000 0x1000>;
interrupts = <55>;
clocks = <&ahb_gates 17>;
@ -323,7 +323,7 @@
};
mdio@01c0b080 {
compatible = "allwinner,sun4i-mdio";
compatible = "allwinner,sun4i-a10-mdio";
reg = <0x01c0b080 0x14>;
status = "disabled";
#address-cells = <1>;

View File

@ -278,7 +278,7 @@
ranges;
emac: ethernet@01c0b000 {
compatible = "allwinner,sun4i-emac";
compatible = "allwinner,sun4i-a10-emac";
reg = <0x01c0b000 0x1000>;
interrupts = <55>;
clocks = <&ahb_gates 17>;
@ -286,7 +286,7 @@
};
mdio@01c0b080 {
compatible = "allwinner,sun4i-mdio";
compatible = "allwinner,sun4i-a10-mdio";
reg = <0x01c0b080 0x14>;
status = "disabled";
#address-cells = <1>;

View File

@ -340,7 +340,7 @@
ranges;
emac: ethernet@01c0b000 {
compatible = "allwinner,sun4i-emac";
compatible = "allwinner,sun4i-a10-emac";
reg = <0x01c0b000 0x1000>;
interrupts = <0 55 4>;
clocks = <&ahb_gates 17>;
@ -348,7 +348,7 @@
};
mdio@01c0b080 {
compatible = "allwinner,sun4i-mdio";
compatible = "allwinner,sun4i-a10-mdio";
reg = <0x01c0b080 0x14>;
status = "disabled";
#address-cells = <1>;

View File

@ -57,6 +57,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
nvidia,head = <0>;
rgb {
status = "disabled";
};
@ -72,6 +74,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
nvidia,head = <1>;
rgb {
status = "disabled";
};

View File

@ -94,6 +94,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
nvidia,head = <0>;
rgb {
status = "disabled";
};
@ -109,6 +111,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
nvidia,head = <1>;
rgb {
status = "disabled";
};

View File

@ -28,7 +28,7 @@
compatible = "nvidia,cardhu", "nvidia,tegra30";
aliases {
rtc0 = "/i2c@7000d000/tps6586x@34";
rtc0 = "/i2c@7000d000/tps65911@2d";
rtc1 = "/rtc@7000e000";
};

View File

@ -170,6 +170,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
nvidia,head = <0>;
rgb {
status = "disabled";
};
@ -185,6 +187,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
nvidia,head = <1>;
rgb {
status = "disabled";
};

View File

@ -1,2 +0,0 @@
/include/ "tests-phandle.dtsi"
/include/ "tests-interrupts.dtsi"

View File

@ -1,4 +1,4 @@
/include/ "versatile-ab.dts"
#include <versatile-ab.dts>
/ {
model = "ARM Versatile PB";
@ -47,4 +47,4 @@
};
};
/include/ "testcases/tests.dtsi"
#include <testcases.dtsi>

View File

@ -29,6 +29,7 @@ CONFIG_ARCH_OMAP3=y
CONFIG_ARCH_OMAP4=y
CONFIG_SOC_OMAP5=y
CONFIG_SOC_AM33XX=y
CONFIG_SOC_DRA7XX=y
CONFIG_SOC_AM43XX=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_ARCH_SOCFPGA=y

View File

@ -18,7 +18,7 @@
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/percpu.h>
#include <linux/notifier.h>
#define __ARCH_WANT_KPROBES_INSN_SLOT
#define MAX_INSN_SIZE 2
@ -28,21 +28,10 @@
#define kretprobe_blacklist_size 0
typedef u32 kprobe_opcode_t;
struct kprobe;
typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *);
typedef unsigned long (kprobe_check_cc)(unsigned long);
typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *);
typedef void (kprobe_insn_fn_t)(void);
#include <asm/probes.h>
/* Architecture specific copy of original instruction. */
struct arch_specific_insn {
kprobe_opcode_t *insn;
kprobe_insn_handler_t *insn_handler;
kprobe_check_cc *insn_check_cc;
kprobe_insn_singlestep_t *insn_singlestep;
kprobe_insn_fn_t *insn_fn;
};
#define arch_specific_insn arch_probes_insn
struct prev_kprobe {
struct kprobe *kp;

View File

@ -71,6 +71,8 @@ struct arm_pmu {
void (*disable)(struct perf_event *event);
int (*get_event_idx)(struct pmu_hw_events *hw_events,
struct perf_event *event);
void (*clear_event_idx)(struct pmu_hw_events *hw_events,
struct perf_event *event);
int (*set_event_filter)(struct hw_perf_event *evt,
struct perf_event_attr *attr);
u32 (*read_counter)(struct perf_event *event);

View File

@ -0,0 +1,43 @@
/*
* arch/arm/include/asm/probes.h
*
* Original contents copied from arch/arm/include/asm/kprobes.h
* which contains the following notice...
*
* Copyright (C) 2006, 2007 Motorola Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef _ASM_PROBES_H
#define _ASM_PROBES_H
typedef u32 probes_opcode_t;
struct arch_probes_insn;
typedef void (probes_insn_handler_t)(probes_opcode_t,
struct arch_probes_insn *,
struct pt_regs *);
typedef unsigned long (probes_check_cc)(unsigned long);
typedef void (probes_insn_singlestep_t)(probes_opcode_t,
struct arch_probes_insn *,
struct pt_regs *);
typedef void (probes_insn_fn_t)(void);
/* Architecture specific copy of original instruction. */
struct arch_probes_insn {
probes_opcode_t *insn;
probes_insn_handler_t *insn_handler;
probes_check_cc *insn_check_cc;
probes_insn_singlestep_t *insn_singlestep;
probes_insn_fn_t *insn_fn;
};
#endif

View File

@ -27,9 +27,13 @@ struct pt_regs {
#define thumb_mode(regs) (0)
#endif
#ifndef CONFIG_CPU_V7M
#define isa_mode(regs) \
((((regs)->ARM_cpsr & PSR_J_BIT) >> 23) | \
(((regs)->ARM_cpsr & PSR_T_BIT) >> 5))
((((regs)->ARM_cpsr & PSR_J_BIT) >> (__ffs(PSR_J_BIT) - 1)) | \
(((regs)->ARM_cpsr & PSR_T_BIT) >> (__ffs(PSR_T_BIT))))
#else
#define isa_mode(regs) 1 /* Thumb */
#endif
#define processor_mode(regs) \
((regs)->ARM_cpsr & MODE_MASK)
@ -80,6 +84,12 @@ static inline long regs_return_value(struct pt_regs *regs)
#define instruction_pointer(regs) (regs)->ARM_pc
static inline void instruction_pointer_set(struct pt_regs *regs,
unsigned long val)
{
instruction_pointer(regs) = val;
}
#ifdef CONFIG_SMP
extern unsigned long profile_pc(struct pt_regs *regs);
#else

View File

@ -153,6 +153,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
#define TIF_SIGPENDING 0
#define TIF_NEED_RESCHED 1
#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
#define TIF_UPROBE 7
#define TIF_SYSCALL_TRACE 8
#define TIF_SYSCALL_AUDIT 9
#define TIF_SYSCALL_TRACEPOINT 10
@ -165,6 +166,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_UPROBE (1 << TIF_UPROBE)
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
@ -178,7 +180,8 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
/*
* Change these and you break ASM code in entry-common.S
*/
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | _TIF_NOTIFY_RESUME)
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
_TIF_NOTIFY_RESUME | _TIF_UPROBE)
#endif /* __KERNEL__ */
#endif /* __ASM_ARM_THREAD_INFO_H */

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_UPROBES_H
#define _ASM_UPROBES_H
#include <asm/probes.h>
#include <asm/opcodes.h>
typedef u32 uprobe_opcode_t;
#define MAX_UINSN_BYTES 4
#define UPROBE_XOL_SLOT_BYTES 64
#define UPROBE_SWBP_ARM_INSN 0xe7f001f9
#define UPROBE_SS_ARM_INSN 0xe7f001fa
#define UPROBE_SWBP_INSN __opcode_to_mem_arm(UPROBE_SWBP_ARM_INSN)
#define UPROBE_SWBP_INSN_SIZE 4
struct arch_uprobe_task {
u32 backup;
unsigned long saved_trap_no;
};
struct arch_uprobe {
u8 insn[MAX_UINSN_BYTES];
unsigned long ixol[2];
uprobe_opcode_t bpinsn;
bool simulate;
u32 pcreg;
void (*prehandler)(struct arch_uprobe *auprobe,
struct arch_uprobe_task *autask,
struct pt_regs *regs);
void (*posthandler)(struct arch_uprobe *auprobe,
struct arch_uprobe_task *autask,
struct pt_regs *regs);
struct arch_probes_insn asi;
};
#endif

View File

@ -50,11 +50,12 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o patch.o
obj-$(CONFIG_UPROBES) += probes.o probes-arm.o uprobes.o uprobes-arm.o
obj-$(CONFIG_KPROBES) += probes.o kprobes.o kprobes-common.o patch.o
ifdef CONFIG_THUMB2_KERNEL
obj-$(CONFIG_KPROBES) += kprobes-thumb.o
obj-$(CONFIG_KPROBES) += kprobes-thumb.o probes-thumb.o
else
obj-$(CONFIG_KPROBES) += kprobes-arm.o
obj-$(CONFIG_KPROBES) += kprobes-arm.o probes-arm.o
endif
obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
test-kprobes-objs := kprobes-test.o

View File

@ -60,13 +60,10 @@
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/module.h>
#include <linux/ptrace.h>
#include "kprobes.h"
#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
#include "probes-arm.h"
#if __LINUX_ARM_ARCH__ >= 6
#define BLX(reg) "blx "reg" \n\t"
@ -75,92 +72,11 @@
"mov pc, "reg" \n\t"
#endif
/*
* To avoid the complications of mimicing single-stepping on a
* processor without a Next-PC or a single-step mode, and to
* avoid having to deal with the side-effects of boosting, we
* simulate or emulate (almost) all ARM instructions.
*
* "Simulation" is where the instruction's behavior is duplicated in
* C code. "Emulation" is where the original instruction is rewritten
* and executed, often by altering its registers.
*
* By having all behavior of the kprobe'd instruction completed before
* returning from the kprobe_handler(), all locks (scheduler and
* interrupt) can safely be released. There is no need for secondary
* breakpoints, no race with MP or preemptable kernels, nor having to
* clean up resources counts at a later time impacting overall system
* performance. By rewriting the instruction, only the minimum registers
* need to be loaded and saved back optimizing performance.
*
* Calling the insnslot_*_rwflags version of a function doesn't hurt
* anything even when the CPSR flags aren't updated by the
* instruction. It's just a little slower in return for saving
* a little space by not having a duplicate function that doesn't
* update the flags. (The same optimization can be said for
* instructions that do or don't perform register writeback)
* Also, instructions can either read the flags, only write the
* flags, or read and write the flags. To save combinations
* rather than for sheer performance, flag functions just assume
* read and write of flags.
*/
static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
long iaddr = (long)p->addr;
int disp = branch_displacement(insn);
if (insn & (1 << 24))
regs->ARM_lr = iaddr + 4;
regs->ARM_pc = iaddr + 8 + disp;
}
static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
long iaddr = (long)p->addr;
int disp = branch_displacement(insn);
regs->ARM_lr = iaddr + 4;
regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2);
regs->ARM_cpsr |= PSR_T_BIT;
}
static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
int rm = insn & 0xf;
long rmv = regs->uregs[rm];
if (insn & (1 << 5))
regs->ARM_lr = (long)p->addr + 4;
regs->ARM_pc = rmv & ~0x1;
regs->ARM_cpsr &= ~PSR_T_BIT;
if (rmv & 0x1)
regs->ARM_cpsr |= PSR_T_BIT;
}
static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
int rd = (insn >> 12) & 0xf;
unsigned long mask = 0xf8ff03df; /* Mask out execution state */
regs->uregs[rd] = regs->ARM_cpsr & mask;
}
static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs)
{
regs->uregs[12] = regs->uregs[13];
}
static void __kprobes
emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs)
emulate_ldrdstrd(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
unsigned long pc = (unsigned long)p->addr + 8;
unsigned long pc = regs->ARM_pc + 4;
int rt = (insn >> 12) & 0xf;
int rn = (insn >> 16) & 0xf;
int rm = insn & 0xf;
@ -175,7 +91,7 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs)
BLX("%[fn]")
: "=r" (rtv), "=r" (rt2v), "=r" (rnv)
: "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
[fn] "r" (p->ainsn.insn_fn)
[fn] "r" (asi->insn_fn)
: "lr", "memory", "cc"
);
@ -186,10 +102,10 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs)
}
static void __kprobes
emulate_ldr(struct kprobe *p, struct pt_regs *regs)
emulate_ldr(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
unsigned long pc = (unsigned long)p->addr + 8;
unsigned long pc = regs->ARM_pc + 4;
int rt = (insn >> 12) & 0xf;
int rn = (insn >> 16) & 0xf;
int rm = insn & 0xf;
@ -202,7 +118,7 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs)
__asm__ __volatile__ (
BLX("%[fn]")
: "=r" (rtv), "=r" (rnv)
: "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn)
: "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
: "lr", "memory", "cc"
);
@ -216,11 +132,11 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs)
}
static void __kprobes
emulate_str(struct kprobe *p, struct pt_regs *regs)
emulate_str(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
unsigned long rtpc = (unsigned long)p->addr + str_pc_offset;
unsigned long rnpc = (unsigned long)p->addr + 8;
unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset;
unsigned long rnpc = regs->ARM_pc + 4;
int rt = (insn >> 12) & 0xf;
int rn = (insn >> 16) & 0xf;
int rm = insn & 0xf;
@ -234,7 +150,7 @@ emulate_str(struct kprobe *p, struct pt_regs *regs)
__asm__ __volatile__ (
BLX("%[fn]")
: "=r" (rnv)
: "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn)
: "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
: "lr", "memory", "cc"
);
@ -243,10 +159,10 @@ emulate_str(struct kprobe *p, struct pt_regs *regs)
}
static void __kprobes
emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs)
emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
unsigned long pc = (unsigned long)p->addr + 8;
unsigned long pc = regs->ARM_pc + 4;
int rd = (insn >> 12) & 0xf;
int rn = (insn >> 16) & 0xf;
int rm = insn & 0xf;
@ -266,7 +182,7 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs)
"mrs %[cpsr], cpsr \n\t"
: "=r" (rdv), [cpsr] "=r" (cpsr)
: "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
"1" (cpsr), [fn] "r" (p->ainsn.insn_fn)
"1" (cpsr), [fn] "r" (asi->insn_fn)
: "lr", "memory", "cc"
);
@ -278,9 +194,9 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs)
}
static void __kprobes
emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
int rd = (insn >> 12) & 0xf;
int rn = (insn >> 16) & 0xf;
int rm = insn & 0xf;
@ -296,7 +212,7 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
"mrs %[cpsr], cpsr \n\t"
: "=r" (rdv), [cpsr] "=r" (cpsr)
: "0" (rdv), "r" (rnv), "r" (rmv),
"1" (cpsr), [fn] "r" (p->ainsn.insn_fn)
"1" (cpsr), [fn] "r" (asi->insn_fn)
: "lr", "memory", "cc"
);
@ -305,9 +221,10 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
}
static void __kprobes
emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn,
struct arch_probes_insn *asi,
struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
int rd = (insn >> 16) & 0xf;
int rn = (insn >> 12) & 0xf;
int rm = insn & 0xf;
@ -325,7 +242,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
"mrs %[cpsr], cpsr \n\t"
: "=r" (rdv), [cpsr] "=r" (cpsr)
: "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
"1" (cpsr), [fn] "r" (p->ainsn.insn_fn)
"1" (cpsr), [fn] "r" (asi->insn_fn)
: "lr", "memory", "cc"
);
@ -334,9 +251,9 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
}
static void __kprobes
emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs)
emulate_rd12rm0_noflags_nopc(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
int rd = (insn >> 12) & 0xf;
int rm = insn & 0xf;
@ -346,7 +263,7 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs)
__asm__ __volatile__ (
BLX("%[fn]")
: "=r" (rdv)
: "0" (rdv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn)
: "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn)
: "lr", "memory", "cc"
);
@ -354,9 +271,10 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs)
}
static void __kprobes
emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
struct arch_probes_insn *asi,
struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
int rdlo = (insn >> 12) & 0xf;
int rdhi = (insn >> 16) & 0xf;
int rn = insn & 0xf;
@ -374,7 +292,7 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
"mrs %[cpsr], cpsr \n\t"
: "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr)
: "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
"2" (cpsr), [fn] "r" (p->ainsn.insn_fn)
"2" (cpsr), [fn] "r" (asi->insn_fn)
: "lr", "memory", "cc"
);
@ -383,623 +301,43 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
}
/*
* For the instruction masking and comparisons in all the "space_*"
* functions below, Do _not_ rearrange the order of tests unless
* you're very, very sure of what you are doing. For the sake of
* efficiency, the masks for some tests sometimes assume other test
* have been done prior to them so the number of patterns to test
* for an instruction set can be as broad as possible to reduce the
* number of tests needed.
*/
static const union decode_item arm_1111_table[] = {
/* Unconditional instructions */
/* memory hint 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */
/* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */
/* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */
/* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */
DECODE_SIMULATE (0xfe300000, 0xf4100000, kprobe_simulate_nop),
/* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */
/* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */
/* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */
/* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */
DECODE_SIMULATE (0xfe300010, 0xf6100000, kprobe_simulate_nop),
/* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */
DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1),
/* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */
/* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
/* SRS 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
/* RFE 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
/* Coprocessor instructions... */
/* MCRR2 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */
/* MRRC2 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */
/* LDC2 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
/* STC2 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
/* CDP2 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
/* MCR2 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
/* MRC2 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
/* Other unallocated instructions... */
DECODE_END
const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
[PROBES_EMULATE_NONE] = {.handler = probes_emulate_none},
[PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
[PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
[PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
[PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
[PROBES_MRS] = {.handler = simulate_mrs},
[PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
[PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc},
[PROBES_SATURATING_ARITHMETIC] = {
.handler = emulate_rd12rn16rm0_rwflags_nopc},
[PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
[PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
[PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
[PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd},
[PROBES_LOAD_EXTRA] = {.handler = emulate_ldr},
[PROBES_LOAD] = {.handler = emulate_ldr},
[PROBES_STORE_EXTRA] = {.handler = emulate_str},
[PROBES_STORE] = {.handler = emulate_str},
[PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
[PROBES_DATA_PROCESSING_REG] = {
.handler = emulate_rd12rn16rm0rs8_rwflags},
[PROBES_DATA_PROCESSING_IMM] = {
.handler = emulate_rd12rn16rm0rs8_rwflags},
[PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc},
[PROBES_SEV] = {.handler = probes_emulate_none},
[PROBES_WFE] = {.handler = probes_simulate_nop},
[PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
[PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc},
[PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
[PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
[PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc},
[PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
[PROBES_MUL_ADD_LONG] = {
.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
[PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
[PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc},
[PROBES_BRANCH] = {.handler = simulate_bbl},
[PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
};
static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = {
/* Miscellaneous instructions */
/* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */
DECODE_SIMULATEX(0x0ff000f0, 0x01000000, simulate_mrs,
REGS(0, NOPC, 0, 0, 0)),
/* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */
DECODE_SIMULATE (0x0ff000f0, 0x01200010, simulate_blx2bx),
/* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */
DECODE_SIMULATEX(0x0ff000f0, 0x01200030, simulate_blx2bx,
REGS(0, 0, 0, 0, NOPC)),
/* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */
DECODE_EMULATEX (0x0ff000f0, 0x01600010, emulate_rd12rm0_noflags_nopc,
REGS(0, NOPC, 0, 0, NOPC)),
/* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */
/* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */
/* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */
/* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */
DECODE_EMULATEX (0x0f9000f0, 0x01000050, emulate_rd12rn16rm0_rwflags_nopc,
REGS(NOPC, NOPC, 0, 0, NOPC)),
/* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
/* MSR cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
/* MRS spsr cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */
/* BKPT 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
/* SMC cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */
/* And unallocated instructions... */
DECODE_END
};
static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = {
/* Halfword multiply and multiply-accumulate */
/* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */
DECODE_EMULATEX (0x0ff00090, 0x01400080, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
/* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */
DECODE_OR (0x0ff000b0, 0x012000a0),
/* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */
DECODE_EMULATEX (0x0ff00090, 0x01600080, emulate_rd16rn12rm0rs8_rwflags_nopc,
REGS(NOPC, 0, NOPC, 0, NOPC)),
/* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */
DECODE_OR (0x0ff00090, 0x01000080),
/* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */
DECODE_EMULATEX (0x0ff000b0, 0x01200080, emulate_rd16rn12rm0rs8_rwflags_nopc,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
DECODE_END
};
static const union decode_item arm_cccc_0000_____1001_table[] = {
/* Multiply and multiply-accumulate */
/* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */
/* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */
DECODE_EMULATEX (0x0fe000f0, 0x00000090, emulate_rd16rn12rm0rs8_rwflags_nopc,
REGS(NOPC, 0, NOPC, 0, NOPC)),
/* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */
/* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */
DECODE_OR (0x0fe000f0, 0x00200090),
/* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */
DECODE_EMULATEX (0x0ff000f0, 0x00600090, emulate_rd16rn12rm0rs8_rwflags_nopc,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
/* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */
DECODE_OR (0x0ff000f0, 0x00400090),
/* UMULL cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */
/* UMULLS cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */
/* UMLAL cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */
/* UMLALS cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */
/* SMULL cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */
/* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */
/* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */
/* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */
DECODE_EMULATEX (0x0f8000f0, 0x00800090, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
DECODE_END
};
static const union decode_item arm_cccc_0001_____1001_table[] = {
/* Synchronization primitives */
#if __LINUX_ARM_ARCH__ < 6
/* Deprecated on ARMv6 and may be UNDEFINED on v7 */
/* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */
DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc,
REGS(NOPC, NOPC, 0, 0, NOPC)),
#endif
/* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */
/* And unallocated instructions... */
DECODE_END
};
static const union decode_item arm_cccc_000x_____1xx1_table[] = {
/* Extra load/store instructions */
/* STRHT cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */
/* ??? cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */
/* LDRHT cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */
/* LDRSBT cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */
/* LDRSHT cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */
DECODE_REJECT (0x0f200090, 0x00200090),
/* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */
DECODE_REJECT (0x0e10e0d0, 0x0000e0d0),
/* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */
/* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */
DECODE_EMULATEX (0x0e5000d0, 0x000000d0, emulate_ldrdstrd,
REGS(NOPCWB, NOPCX, 0, 0, NOPC)),
/* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */
/* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */
DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd,
REGS(NOPCWB, NOPCX, 0, 0, 0)),
/* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */
DECODE_EMULATEX (0x0e5000f0, 0x000000b0, emulate_str,
REGS(NOPCWB, NOPC, 0, 0, NOPC)),
/* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */
/* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */
/* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */
DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr,
REGS(NOPCWB, NOPC, 0, 0, NOPC)),
/* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */
DECODE_EMULATEX (0x0e5000f0, 0x004000b0, emulate_str,
REGS(NOPCWB, NOPC, 0, 0, 0)),
/* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */
/* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */
/* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */
DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr,
REGS(NOPCWB, NOPC, 0, 0, 0)),
DECODE_END
};
static const union decode_item arm_cccc_000x_table[] = {
/* Data-processing (register) */
/* <op>S PC, ... cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */
DECODE_REJECT (0x0e10f000, 0x0010f000),
/* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */
DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, simulate_mov_ipsp),
/* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */
/* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */
/* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */
/* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */
DECODE_EMULATEX (0x0f900010, 0x01100000, emulate_rd12rn16rm0rs8_rwflags,
REGS(ANY, 0, 0, 0, ANY)),
/* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */
/* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */
DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags,
REGS(0, ANY, 0, 0, ANY)),
/* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */
/* EOR (register) cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */
/* SUB (register) cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */
/* RSB (register) cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */
/* ADD (register) cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */
/* ADC (register) cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */
/* SBC (register) cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */
/* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */
/* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */
/* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */
DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags,
REGS(ANY, ANY, 0, 0, ANY)),
/* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */
/* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */
/* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */
/* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */
DECODE_EMULATEX (0x0f900090, 0x01100010, emulate_rd12rn16rm0rs8_rwflags,
REGS(ANY, 0, NOPC, 0, ANY)),
/* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */
/* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */
DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags,
REGS(0, ANY, NOPC, 0, ANY)),
/* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */
/* EOR (reg-shift reg) cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */
/* SUB (reg-shift reg) cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */
/* RSB (reg-shift reg) cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */
/* ADD (reg-shift reg) cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */
/* ADC (reg-shift reg) cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */
/* SBC (reg-shift reg) cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */
/* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */
/* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */
/* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */
DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags,
REGS(ANY, ANY, NOPC, 0, ANY)),
DECODE_END
};
static const union decode_item arm_cccc_001x_table[] = {
/* Data-processing (immediate) */
/* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */
/* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0fb00000, 0x03000000, emulate_rd12rm0_noflags_nopc,
REGS(0, NOPC, 0, 0, 0)),
/* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */
DECODE_OR (0x0fff00ff, 0x03200001),
/* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */
DECODE_EMULATE (0x0fff00ff, 0x03200004, kprobe_emulate_none),
/* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */
/* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */
/* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */
DECODE_SIMULATE (0x0fff00fc, 0x03200000, kprobe_simulate_nop),
/* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */
/* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */
/* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0x0fb00000, 0x03200000),
/* <op>S PC, ... cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */
DECODE_REJECT (0x0e10f000, 0x0210f000),
/* TST (immediate) cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */
/* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */
/* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */
/* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0f900000, 0x03100000, emulate_rd12rn16rm0rs8_rwflags,
REGS(ANY, 0, 0, 0, 0)),
/* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */
/* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags,
REGS(0, ANY, 0, 0, 0)),
/* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */
/* EOR (immediate) cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */
/* SUB (immediate) cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */
/* RSB (immediate) cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */
/* ADD (immediate) cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */
/* ADC (immediate) cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */
/* SBC (immediate) cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */
/* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */
/* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */
/* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags,
REGS(ANY, ANY, 0, 0, 0)),
DECODE_END
};
static const union decode_item arm_cccc_0110_____xxx1_table[] = {
/* Media instructions */
/* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */
DECODE_EMULATEX (0x0ff000f0, 0x068000b0, emulate_rd12rn16rm0_rwflags_nopc,
REGS(NOPC, NOPC, 0, 0, NOPC)),
/* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */
/* USAT cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */
DECODE_OR(0x0fa00030, 0x06a00010),
/* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */
/* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */
DECODE_EMULATEX (0x0fb000f0, 0x06a00030, emulate_rd12rn16rm0_rwflags_nopc,
REGS(0, NOPC, 0, 0, NOPC)),
/* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */
/* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */
/* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */
/* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */
DECODE_EMULATEX (0x0fb00070, 0x06b00030, emulate_rd12rm0_noflags_nopc,
REGS(0, NOPC, 0, 0, NOPC)),
/* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */
DECODE_REJECT (0x0fb00010, 0x06000010),
/* ??? cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */
DECODE_REJECT (0x0f8000f0, 0x060000b0),
/* ??? cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */
DECODE_REJECT (0x0f8000f0, 0x060000d0),
/* SADD16 cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */
/* SADDSUBX cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */
/* SSUBADDX cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */
/* SSUB16 cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */
/* SADD8 cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */
/* SSUB8 cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */
/* QADD16 cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */
/* QADDSUBX cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */
/* QSUBADDX cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */
/* QSUB16 cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */
/* QADD8 cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */
/* QSUB8 cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */
/* SHADD16 cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */
/* SHADDSUBX cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */
/* SHSUBADDX cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */
/* SHSUB16 cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */
/* SHADD8 cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */
/* SHSUB8 cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */
/* UADD16 cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */
/* UADDSUBX cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */
/* USUBADDX cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */
/* USUB16 cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */
/* UADD8 cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */
/* USUB8 cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */
/* UQADD16 cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */
/* UQADDSUBX cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */
/* UQSUBADDX cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */
/* UQSUB16 cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */
/* UQADD8 cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */
/* UQSUB8 cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */
/* UHADD16 cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */
/* UHADDSUBX cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */
/* UHSUBADDX cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */
/* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */
/* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */
/* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */
DECODE_EMULATEX (0x0f800010, 0x06000010, emulate_rd12rn16rm0_rwflags_nopc,
REGS(NOPC, NOPC, 0, 0, NOPC)),
/* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */
/* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */
DECODE_EMULATEX (0x0ff00030, 0x06800010, emulate_rd12rn16rm0_rwflags_nopc,
REGS(NOPC, NOPC, 0, 0, NOPC)),
/* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */
/* ??? cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */
DECODE_REJECT (0x0fb000f0, 0x06900070),
/* SXTB16 cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */
/* SXTB cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */
/* SXTH cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */
/* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */
/* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */
/* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */
DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, emulate_rd12rm0_noflags_nopc,
REGS(0, NOPC, 0, 0, NOPC)),
/* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */
/* SXTAB cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */
/* SXTAH cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */
/* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */
/* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */
/* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */
DECODE_EMULATEX (0x0f8000f0, 0x06800070, emulate_rd12rn16rm0_rwflags_nopc,
REGS(NOPCX, NOPC, 0, 0, NOPC)),
DECODE_END
};
static const union decode_item arm_cccc_0111_____xxx1_table[] = {
/* Media instructions */
/* UNDEFINED cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */
DECODE_REJECT (0x0ff000f0, 0x07f000f0),
/* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */
/* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */
DECODE_EMULATEX (0x0ff00090, 0x07400010, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
/* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */
/* SMUSD cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */
DECODE_OR (0x0ff0f090, 0x0700f010),
/* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */
DECODE_OR (0x0ff0f0d0, 0x0750f010),
/* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */
DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, emulate_rd16rn12rm0rs8_rwflags_nopc,
REGS(NOPC, 0, NOPC, 0, NOPC)),
/* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */
/* SMLSD cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */
DECODE_OR (0x0ff00090, 0x07000010),
/* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */
DECODE_OR (0x0ff000d0, 0x07500010),
/* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */
DECODE_EMULATEX (0x0ff000f0, 0x07800010, emulate_rd16rn12rm0rs8_rwflags_nopc,
REGS(NOPC, NOPCX, NOPC, 0, NOPC)),
/* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */
DECODE_EMULATEX (0x0ff000d0, 0x075000d0, emulate_rd16rn12rm0rs8_rwflags_nopc,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
/* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */
/* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */
DECODE_EMULATEX (0x0fa00070, 0x07a00050, emulate_rd12rm0_noflags_nopc,
REGS(0, NOPC, 0, 0, NOPC)),
/* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */
DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, emulate_rd12rm0_noflags_nopc,
REGS(0, NOPC, 0, 0, 0)),
/* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */
DECODE_EMULATEX (0x0fe00070, 0x07c00010, emulate_rd12rm0_noflags_nopc,
REGS(0, NOPC, 0, 0, NOPCX)),
DECODE_END
};
static const union decode_item arm_cccc_01xx_table[] = {
/* Load/store word and unsigned byte */
/* LDRB/STRB pc,[...] cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0x0c40f000, 0x0440f000),
/* STRT cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */
/* LDRT cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */
/* STRBT cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */
/* LDRBT cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0x0d200000, 0x04200000),
/* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */
/* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0e100000, 0x04000000, emulate_str,
REGS(NOPCWB, ANY, 0, 0, 0)),
/* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */
/* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0e100000, 0x04100000, emulate_ldr,
REGS(NOPCWB, ANY, 0, 0, 0)),
/* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */
/* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0e100000, 0x06000000, emulate_str,
REGS(NOPCWB, ANY, 0, 0, NOPC)),
/* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */
/* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr,
REGS(NOPCWB, ANY, 0, 0, NOPC)),
DECODE_END
};
static const union decode_item arm_cccc_100x_table[] = {
/* Block data transfer instructions */
/* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
/* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */
DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm),
/* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
/* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */
/* LDM (exception ret) cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */
DECODE_END
};
const union decode_item kprobe_decode_arm_table[] = {
/*
* Unconditional instructions
* 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xf0000000, 0xf0000000, arm_1111_table),
/*
* Miscellaneous instructions
* cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx
*/
DECODE_TABLE (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table),
/*
* Halfword multiply and multiply-accumulate
* cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx
*/
DECODE_TABLE (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table),
/*
* Multiply and multiply-accumulate
* cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx
*/
DECODE_TABLE (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table),
/*
* Synchronization primitives
* cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx
*/
DECODE_TABLE (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table),
/*
* Extra load/store instructions
* cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx
*/
DECODE_TABLE (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table),
/*
* Data-processing (register)
* cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx
* Data-processing (register-shifted register)
* cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx
*/
DECODE_TABLE (0x0e000000, 0x00000000, arm_cccc_000x_table),
/*
* Data-processing (immediate)
* cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0x0e000000, 0x02000000, arm_cccc_001x_table),
/*
* Media instructions
* cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx
*/
DECODE_TABLE (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table),
DECODE_TABLE (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table),
/*
* Load/store word and unsigned byte
* cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0x0c000000, 0x04000000, arm_cccc_01xx_table),
/*
* Block data transfer instructions
* cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0x0e000000, 0x08000000, arm_cccc_100x_table),
/* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */
/* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */
DECODE_SIMULATE (0x0e000000, 0x0a000000, simulate_bbl),
/*
* Supervisor Call, and coprocessor instructions
*/
/* MCRR cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */
/* MRRC cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */
/* LDC cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
/* STC cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
/* CDP cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
/* MCR cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
/* MRC cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
/* SVC cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0x0c000000, 0x0c000000),
DECODE_END
};
#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
EXPORT_SYMBOL_GPL(kprobe_decode_arm_table);
#endif
static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs)
{
regs->ARM_pc += 4;
p->ainsn.insn_handler(p, regs);
}
/* Return:
* INSN_REJECTED If instruction is one not allowed to kprobe,
* INSN_GOOD If instruction is supported and uses instruction slot,
* INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
*
* For instructions we don't want to kprobe (INSN_REJECTED return result):
* These are generally ones that modify the processor state making
* them "hard" to simulate such as switches processor modes or
* make accesses in alternate modes. Any of these could be simulated
* if the work was put into it, but low return considering they
* should also be very rare.
*/
enum kprobe_insn __kprobes
arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
{
asi->insn_singlestep = arm_singlestep;
asi->insn_check_cc = kprobe_condition_checks[insn>>28];
return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false);
}

View File

@ -13,178 +13,14 @@
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <asm/system_info.h>
#include "kprobes.h"
#ifndef find_str_pc_offset
/*
* For STR and STM instructions, an ARM core may choose to use either
* a +8 or a +12 displacement from the current instruction's address.
* Whichever value is chosen for a given core, it must be the same for
* both instructions and may not change. This function measures it.
*/
int str_pc_offset;
void __init find_str_pc_offset(void)
static void __kprobes simulate_ldm1stm1(probes_opcode_t insn,
struct arch_probes_insn *asi,
struct pt_regs *regs)
{
int addr, scratch, ret;
__asm__ (
"sub %[ret], pc, #4 \n\t"
"str pc, %[addr] \n\t"
"ldr %[scr], %[addr] \n\t"
"sub %[ret], %[scr], %[ret] \n\t"
: [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr));
str_pc_offset = ret;
}
#endif /* !find_str_pc_offset */
#ifndef test_load_write_pc_interworking
bool load_write_pc_interworks;
void __init test_load_write_pc_interworking(void)
{
int arch = cpu_architecture();
BUG_ON(arch == CPU_ARCH_UNKNOWN);
load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T;
}
#endif /* !test_load_write_pc_interworking */
#ifndef test_alu_write_pc_interworking
bool alu_write_pc_interworks;
void __init test_alu_write_pc_interworking(void)
{
int arch = cpu_architecture();
BUG_ON(arch == CPU_ARCH_UNKNOWN);
alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7;
}
#endif /* !test_alu_write_pc_interworking */
void __init arm_kprobe_decode_init(void)
{
find_str_pc_offset();
test_load_write_pc_interworking();
test_alu_write_pc_interworking();
}
static unsigned long __kprobes __check_eq(unsigned long cpsr)
{
return cpsr & PSR_Z_BIT;
}
static unsigned long __kprobes __check_ne(unsigned long cpsr)
{
return (~cpsr) & PSR_Z_BIT;
}
static unsigned long __kprobes __check_cs(unsigned long cpsr)
{
return cpsr & PSR_C_BIT;
}
static unsigned long __kprobes __check_cc(unsigned long cpsr)
{
return (~cpsr) & PSR_C_BIT;
}
static unsigned long __kprobes __check_mi(unsigned long cpsr)
{
return cpsr & PSR_N_BIT;
}
static unsigned long __kprobes __check_pl(unsigned long cpsr)
{
return (~cpsr) & PSR_N_BIT;
}
static unsigned long __kprobes __check_vs(unsigned long cpsr)
{
return cpsr & PSR_V_BIT;
}
static unsigned long __kprobes __check_vc(unsigned long cpsr)
{
return (~cpsr) & PSR_V_BIT;
}
static unsigned long __kprobes __check_hi(unsigned long cpsr)
{
cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
return cpsr & PSR_C_BIT;
}
static unsigned long __kprobes __check_ls(unsigned long cpsr)
{
cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
return (~cpsr) & PSR_C_BIT;
}
static unsigned long __kprobes __check_ge(unsigned long cpsr)
{
cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
return (~cpsr) & PSR_N_BIT;
}
static unsigned long __kprobes __check_lt(unsigned long cpsr)
{
cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
return cpsr & PSR_N_BIT;
}
static unsigned long __kprobes __check_gt(unsigned long cpsr)
{
unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
return (~temp) & PSR_N_BIT;
}
static unsigned long __kprobes __check_le(unsigned long cpsr)
{
unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
return temp & PSR_N_BIT;
}
static unsigned long __kprobes __check_al(unsigned long cpsr)
{
return true;
}
kprobe_check_cc * const kprobe_condition_checks[16] = {
&__check_eq, &__check_ne, &__check_cs, &__check_cc,
&__check_mi, &__check_pl, &__check_vs, &__check_vc,
&__check_hi, &__check_ls, &__check_ge, &__check_lt,
&__check_gt, &__check_le, &__check_al, &__check_al
};
void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs)
{
}
void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs)
{
p->ainsn.insn_fn();
}
static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
int rn = (insn >> 16) & 0xf;
int lbit = insn & (1 << 20);
int wbit = insn & (1 << 21);
@ -223,24 +59,31 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
}
}
static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs)
static void __kprobes simulate_stm1_pc(probes_opcode_t insn,
struct arch_probes_insn *asi,
struct pt_regs *regs)
{
regs->ARM_pc = (long)p->addr + str_pc_offset;
simulate_ldm1stm1(p, regs);
regs->ARM_pc = (long)p->addr + 4;
unsigned long addr = regs->ARM_pc - 4;
regs->ARM_pc = (long)addr + str_pc_offset;
simulate_ldm1stm1(insn, asi, regs);
regs->ARM_pc = (long)addr + 4;
}
static void __kprobes simulate_ldm1_pc(struct kprobe *p, struct pt_regs *regs)
static void __kprobes simulate_ldm1_pc(probes_opcode_t insn,
struct arch_probes_insn *asi,
struct pt_regs *regs)
{
simulate_ldm1stm1(p, regs);
simulate_ldm1stm1(insn, asi, regs);
load_write_pc(regs->ARM_pc, regs);
}
static void __kprobes
emulate_generic_r0_12_noflags(struct kprobe *p, struct pt_regs *regs)
emulate_generic_r0_12_noflags(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
register void *rregs asm("r1") = regs;
register void *rfn asm("lr") = p->ainsn.insn_fn;
register void *rfn asm("lr") = asi->insn_fn;
__asm__ __volatile__ (
"stmdb sp!, {%[regs], r11} \n\t"
@ -264,22 +107,27 @@ emulate_generic_r0_12_noflags(struct kprobe *p, struct pt_regs *regs)
}
static void __kprobes
emulate_generic_r2_14_noflags(struct kprobe *p, struct pt_regs *regs)
emulate_generic_r2_14_noflags(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+2));
emulate_generic_r0_12_noflags(insn, asi,
(struct pt_regs *)(regs->uregs+2));
}
static void __kprobes
emulate_ldm_r3_15(struct kprobe *p, struct pt_regs *regs)
emulate_ldm_r3_15(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+3));
emulate_generic_r0_12_noflags(insn, asi,
(struct pt_regs *)(regs->uregs+3));
load_write_pc(regs->ARM_pc, regs);
}
enum kprobe_insn __kprobes
kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
enum probes_insn __kprobes
kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
const struct decode_header *h)
{
kprobe_insn_handler_t *handler = 0;
probes_insn_handler_t *handler = 0;
unsigned reglist = insn & 0xffff;
int is_ldm = insn & 0x100000;
int rn = (insn >> 16) & 0xf;
@ -319,260 +167,3 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
return INSN_GOOD_NO_SLOT;
}
/*
* Prepare an instruction slot to receive an instruction for emulating.
* This is done by placing a subroutine return after the location where the
* instruction will be placed. We also modify ARM instructions to be
* unconditional as the condition code will already be checked before any
* emulation handler is called.
*/
static kprobe_opcode_t __kprobes
prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
bool thumb)
{
#ifdef CONFIG_THUMB2_KERNEL
if (thumb) {
u16 *thumb_insn = (u16 *)asi->insn;
thumb_insn[1] = 0x4770; /* Thumb bx lr */
thumb_insn[2] = 0x4770; /* Thumb bx lr */
return insn;
}
asi->insn[1] = 0xe12fff1e; /* ARM bx lr */
#else
asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */
#endif
/* Make an ARM instruction unconditional */
if (insn < 0xe0000000)
insn = (insn | 0xe0000000) & ~0x10000000;
return insn;
}
/*
* Write a (probably modified) instruction into the slot previously prepared by
* prepare_emulated_insn
*/
static void __kprobes
set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
bool thumb)
{
#ifdef CONFIG_THUMB2_KERNEL
if (thumb) {
u16 *ip = (u16 *)asi->insn;
if (is_wide_instruction(insn))
*ip++ = insn >> 16;
*ip++ = insn;
return;
}
#endif
asi->insn[0] = insn;
}
/*
* When we modify the register numbers encoded in an instruction to be emulated,
* the new values come from this define. For ARM and 32-bit Thumb instructions
* this gives...
*
* bit position 16 12 8 4 0
* ---------------+---+---+---+---+---+
* register r2 r0 r1 -- r3
*/
#define INSN_NEW_BITS 0x00020103
/* Each nibble has same value as that at INSN_NEW_BITS bit 16 */
#define INSN_SAMEAS16_BITS 0x22222222
/*
* Validate and modify each of the registers encoded in an instruction.
*
* Each nibble in regs contains a value from enum decode_reg_type. For each
* non-zero value, the corresponding nibble in pinsn is validated and modified
* according to the type.
*/
static bool __kprobes decode_regs(kprobe_opcode_t* pinsn, u32 regs)
{
kprobe_opcode_t insn = *pinsn;
kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */
for (; regs != 0; regs >>= 4, mask <<= 4) {
kprobe_opcode_t new_bits = INSN_NEW_BITS;
switch (regs & 0xf) {
case REG_TYPE_NONE:
/* Nibble not a register, skip to next */
continue;
case REG_TYPE_ANY:
/* Any register is allowed */
break;
case REG_TYPE_SAMEAS16:
/* Replace register with same as at bit position 16 */
new_bits = INSN_SAMEAS16_BITS;
break;
case REG_TYPE_SP:
/* Only allow SP (R13) */
if ((insn ^ 0xdddddddd) & mask)
goto reject;
break;
case REG_TYPE_PC:
/* Only allow PC (R15) */
if ((insn ^ 0xffffffff) & mask)
goto reject;
break;
case REG_TYPE_NOSP:
/* Reject SP (R13) */
if (((insn ^ 0xdddddddd) & mask) == 0)
goto reject;
break;
case REG_TYPE_NOSPPC:
case REG_TYPE_NOSPPCX:
/* Reject SP and PC (R13 and R15) */
if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0)
goto reject;
break;
case REG_TYPE_NOPCWB:
if (!is_writeback(insn))
break; /* No writeback, so any register is OK */
/* fall through... */
case REG_TYPE_NOPC:
case REG_TYPE_NOPCX:
/* Reject PC (R15) */
if (((insn ^ 0xffffffff) & mask) == 0)
goto reject;
break;
}
/* Replace value of nibble with new register number... */
insn &= ~mask;
insn |= new_bits & mask;
}
*pinsn = insn;
return true;
reject:
return false;
}
static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
[DECODE_TYPE_TABLE] = sizeof(struct decode_table),
[DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom),
[DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate),
[DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate),
[DECODE_TYPE_OR] = sizeof(struct decode_or),
[DECODE_TYPE_REJECT] = sizeof(struct decode_reject)
};
/*
* kprobe_decode_insn operates on data tables in order to decode an ARM
* architecture instruction onto which a kprobe has been placed.
*
* These instruction decoding tables are a concatenation of entries each
* of which consist of one of the following structs:
*
* decode_table
* decode_custom
* decode_simulate
* decode_emulate
* decode_or
* decode_reject
*
* Each of these starts with a struct decode_header which has the following
* fields:
*
* type_regs
* mask
* value
*
* The least significant DECODE_TYPE_BITS of type_regs contains a value
* from enum decode_type, this indicates which of the decode_* structs
* the entry contains. The value DECODE_TYPE_END indicates the end of the
* table.
*
* When the table is parsed, each entry is checked in turn to see if it
* matches the instruction to be decoded using the test:
*
* (insn & mask) == value
*
* If no match is found before the end of the table is reached then decoding
* fails with INSN_REJECTED.
*
* When a match is found, decode_regs() is called to validate and modify each
* of the registers encoded in the instruction; the data it uses to do this
* is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding
* to fail with INSN_REJECTED.
*
* Once the instruction has passed the above tests, further processing
* depends on the type of the table entry's decode struct.
*
*/
int __kprobes
kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
const union decode_item *table, bool thumb)
{
const struct decode_header *h = (struct decode_header *)table;
const struct decode_header *next;
bool matched = false;
insn = prepare_emulated_insn(insn, asi, thumb);
for (;; h = next) {
enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
if (type == DECODE_TYPE_END)
return INSN_REJECTED;
next = (struct decode_header *)
((uintptr_t)h + decode_struct_sizes[type]);
if (!matched && (insn & h->mask.bits) != h->value.bits)
continue;
if (!decode_regs(&insn, regs))
return INSN_REJECTED;
switch (type) {
case DECODE_TYPE_TABLE: {
struct decode_table *d = (struct decode_table *)h;
next = (struct decode_header *)d->table.table;
break;
}
case DECODE_TYPE_CUSTOM: {
struct decode_custom *d = (struct decode_custom *)h;
return (*d->decoder.decoder)(insn, asi);
}
case DECODE_TYPE_SIMULATE: {
struct decode_simulate *d = (struct decode_simulate *)h;
asi->insn_handler = d->handler.handler;
return INSN_GOOD_NO_SLOT;
}
case DECODE_TYPE_EMULATE: {
struct decode_emulate *d = (struct decode_emulate *)h;
asi->insn_handler = d->handler.handler;
set_emulated_insn(insn, asi, thumb);
return INSN_GOOD;
}
case DECODE_TYPE_OR:
matched = true;
break;
case DECODE_TYPE_REJECT:
default:
return INSN_REJECTED;
}
}
}

View File

@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/system_info.h>
#include "kprobes-test.h"

View File

@ -201,10 +201,14 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kprobes.h>
#include <linux/errno.h>
#include <linux/stddef.h>
#include <linux/bug.h>
#include <asm/opcodes.h>
#include "kprobes.h"
#include "probes-arm.h"
#include "probes-thumb.h"
#include "kprobes-test.h"
@ -1608,7 +1612,7 @@ static int __init run_all_tests(void)
goto out;
pr_info("ARM instruction simulation\n");
ret = run_test_cases(kprobe_arm_test_cases, kprobe_decode_arm_table);
ret = run_test_cases(kprobe_arm_test_cases, probes_decode_arm_table);
if (ret)
goto out;
@ -1631,13 +1635,13 @@ static int __init run_all_tests(void)
pr_info("16-bit Thumb instruction simulation\n");
ret = run_test_cases(kprobe_thumb16_test_cases,
kprobe_decode_thumb16_table);
probes_decode_thumb16_table);
if (ret)
goto out;
pr_info("32-bit Thumb instruction simulation\n");
ret = run_test_cases(kprobe_thumb32_test_cases,
kprobe_decode_thumb32_table);
probes_decode_thumb32_table);
if (ret)
goto out;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -27,8 +27,12 @@
#include <linux/stringify.h>
#include <asm/traps.h>
#include <asm/cacheflush.h>
#include <linux/percpu.h>
#include <linux/bug.h>
#include "kprobes.h"
#include "probes-arm.h"
#include "probes-thumb.h"
#include "patch.h"
#define MIN_STACK_SIZE(addr) \
@ -54,6 +58,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
unsigned long addr = (unsigned long)p->addr;
bool thumb;
kprobe_decode_insn_t *decode_insn;
const union decode_action *actions;
int is;
if (in_exception_text(addr))
@ -66,21 +71,25 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
if (is_wide_instruction(insn)) {
insn <<= 16;
insn |= ((u16 *)addr)[1];
decode_insn = thumb32_kprobe_decode_insn;
} else
decode_insn = thumb16_kprobe_decode_insn;
decode_insn = thumb32_probes_decode_insn;
actions = kprobes_t32_actions;
} else {
decode_insn = thumb16_probes_decode_insn;
actions = kprobes_t16_actions;
}
#else /* !CONFIG_THUMB2_KERNEL */
thumb = false;
if (addr & 0x3)
return -EINVAL;
insn = *p->addr;
decode_insn = arm_kprobe_decode_insn;
decode_insn = arm_probes_decode_insn;
actions = kprobes_arm_actions;
#endif
p->opcode = insn;
p->ainsn.insn = tmp_insn;
switch ((*decode_insn)(insn, &p->ainsn)) {
switch ((*decode_insn)(insn, &p->ainsn, true, actions)) {
case INSN_REJECTED: /* not supported */
return -EINVAL;
@ -92,7 +101,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
p->ainsn.insn[is] = tmp_insn[is];
flush_insns(p->ainsn.insn,
sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE);
p->ainsn.insn_fn = (kprobe_insn_fn_t *)
p->ainsn.insn_fn = (probes_insn_fn_t *)
((uintptr_t)p->ainsn.insn | thumb);
break;
@ -197,7 +206,7 @@ singlestep_skip(struct kprobe *p, struct pt_regs *regs)
static inline void __kprobes
singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb)
{
p->ainsn.insn_singlestep(p, regs);
p->ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
}
/*
@ -607,7 +616,7 @@ static struct undef_hook kprobes_arm_break_hook = {
int __init arch_init_kprobes()
{
arm_kprobe_decode_init();
arm_probes_decode_init();
#ifdef CONFIG_THUMB2_KERNEL
register_undef_hook(&kprobes_thumb16_break_hook);
register_undef_hook(&kprobes_thumb32_break_hook);

View File

@ -19,6 +19,8 @@
#ifndef _ARM_KERNEL_KPROBES_H
#define _ARM_KERNEL_KPROBES_H
#include "probes.h"
/*
* These undefined instructions must be unique and
* reserved solely for kprobes' use.
@ -27,402 +29,24 @@
#define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18
#define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018
enum probes_insn __kprobes
kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi,
const struct decode_header *h);
enum kprobe_insn {
INSN_REJECTED,
INSN_GOOD,
INSN_GOOD_NO_SLOT
};
typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t,
struct arch_specific_insn *);
typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t,
struct arch_probes_insn *,
bool,
const union decode_action *);
#ifdef CONFIG_THUMB2_KERNEL
enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t,
struct arch_specific_insn *);
enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t,
struct arch_specific_insn *);
extern const union decode_action kprobes_t32_actions[];
extern const union decode_action kprobes_t16_actions[];
#else /* !CONFIG_THUMB2_KERNEL */
enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t,
struct arch_specific_insn *);
#endif
void __init arm_kprobe_decode_init(void);
extern kprobe_check_cc * const kprobe_condition_checks[16];
#if __LINUX_ARM_ARCH__ >= 7
/* str_pc_offset is architecturally defined from ARMv7 onwards */
#define str_pc_offset 8
#define find_str_pc_offset()
#else /* __LINUX_ARM_ARCH__ < 7 */
/* We need a run-time check to determine str_pc_offset */
extern int str_pc_offset;
void __init find_str_pc_offset(void);
extern const union decode_action kprobes_arm_actions[];
#endif
/*
* Update ITSTATE after normal execution of an IT block instruction.
*
* The 8 IT state bits are split into two parts in CPSR:
* ITSTATE<1:0> are in CPSR<26:25>
* ITSTATE<7:2> are in CPSR<15:10>
*/
static inline unsigned long it_advance(unsigned long cpsr)
{
if ((cpsr & 0x06000400) == 0) {
/* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
cpsr &= ~PSR_IT_MASK;
} else {
/* We need to shift left ITSTATE<4:0> */
const unsigned long mask = 0x06001c00; /* Mask ITSTATE<4:0> */
unsigned long it = cpsr & mask;
it <<= 1;
it |= it >> (27 - 10); /* Carry ITSTATE<2> to correct place */
it &= mask;
cpsr &= ~mask;
cpsr |= it;
}
return cpsr;
}
static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs)
{
long cpsr = regs->ARM_cpsr;
if (pcv & 0x1) {
cpsr |= PSR_T_BIT;
pcv &= ~0x1;
} else {
cpsr &= ~PSR_T_BIT;
pcv &= ~0x2; /* Avoid UNPREDICTABLE address allignment */
}
regs->ARM_cpsr = cpsr;
regs->ARM_pc = pcv;
}
#if __LINUX_ARM_ARCH__ >= 6
/* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */
#define load_write_pc_interworks true
#define test_load_write_pc_interworking()
#else /* __LINUX_ARM_ARCH__ < 6 */
/* We need run-time testing to determine if load_write_pc() should interwork. */
extern bool load_write_pc_interworks;
void __init test_load_write_pc_interworking(void);
#endif
static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs)
{
if (load_write_pc_interworks)
bx_write_pc(pcv, regs);
else
regs->ARM_pc = pcv;
}
#if __LINUX_ARM_ARCH__ >= 7
#define alu_write_pc_interworks true
#define test_alu_write_pc_interworking()
#elif __LINUX_ARM_ARCH__ <= 5
/* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */
#define alu_write_pc_interworks false
#define test_alu_write_pc_interworking()
#else /* __LINUX_ARM_ARCH__ == 6 */
/* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */
extern bool alu_write_pc_interworks;
void __init test_alu_write_pc_interworking(void);
#endif /* __LINUX_ARM_ARCH__ == 6 */
static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs)
{
if (alu_write_pc_interworks)
bx_write_pc(pcv, regs);
else
regs->ARM_pc = pcv;
}
void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs);
void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs);
enum kprobe_insn __kprobes
kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi);
/*
* Test if load/store instructions writeback the address register.
* if P (bit 24) == 0 or W (bit 21) == 1
*/
#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000)
/*
* The following definitions and macros are used to build instruction
* decoding tables for use by kprobe_decode_insn.
*
* These tables are a concatenation of entries each of which consist of one of
* the decode_* structs. All of the fields in every type of decode structure
* are of the union type decode_item, therefore the entire decode table can be
* viewed as an array of these and declared like:
*
* static const union decode_item table_name[] = {};
*
* In order to construct each entry in the table, macros are used to
* initialise a number of sequential decode_item values in a layout which
* matches the relevant struct. E.g. DECODE_SIMULATE initialise a struct
* decode_simulate by initialising four decode_item objects like this...
*
* {.bits = _type},
* {.bits = _mask},
* {.bits = _value},
* {.handler = _handler},
*
* Initialising a specified member of the union means that the compiler
* will produce a warning if the argument is of an incorrect type.
*
* Below is a list of each of the macros used to initialise entries and a
* description of the action performed when that entry is matched to an
* instruction. A match is found when (instruction & mask) == value.
*
* DECODE_TABLE(mask, value, table)
* Instruction decoding jumps to parsing the new sub-table 'table'.
*
* DECODE_CUSTOM(mask, value, decoder)
* The custom function 'decoder' is called to the complete decoding
* of an instruction.
*
* DECODE_SIMULATE(mask, value, handler)
* Set the probes instruction handler to 'handler', this will be used
* to simulate the instruction when the probe is hit. Decoding returns
* with INSN_GOOD_NO_SLOT.
*
* DECODE_EMULATE(mask, value, handler)
* Set the probes instruction handler to 'handler', this will be used
* to emulate the instruction when the probe is hit. The modified
* instruction (see below) is placed in the probes instruction slot so it
* may be called by the emulation code. Decoding returns with INSN_GOOD.
*
* DECODE_REJECT(mask, value)
* Instruction decoding fails with INSN_REJECTED
*
* DECODE_OR(mask, value)
* This allows the mask/value test of multiple table entries to be
* logically ORed. Once an 'or' entry is matched the decoding action to
* be performed is that of the next entry which isn't an 'or'. E.g.
*
* DECODE_OR (mask1, value1)
* DECODE_OR (mask2, value2)
* DECODE_SIMULATE (mask3, value3, simulation_handler)
*
* This means that if any of the three mask/value pairs match the
* instruction being decoded, then 'simulation_handler' will be used
* for it.
*
* Both the SIMULATE and EMULATE macros have a second form which take an
* additional 'regs' argument.
*
* DECODE_SIMULATEX(mask, value, handler, regs)
* DECODE_EMULATEX (mask, value, handler, regs)
*
* These are used to specify what kind of CPU register is encoded in each of the
* least significant 5 nibbles of the instruction being decoded. The regs value
* is specified using the REGS macro, this takes any of the REG_TYPE_* values
* from enum decode_reg_type as arguments; only the '*' part of the name is
* given. E.g.
*
* REGS(0, ANY, NOPC, 0, ANY)
*
* This indicates an instruction is encoded like:
*
* bits 19..16 ignore
* bits 15..12 any register allowed here
* bits 11.. 8 any register except PC allowed here
* bits 7.. 4 ignore
* bits 3.. 0 any register allowed here
*
* This register specification is checked after a decode table entry is found to
* match an instruction (through the mask/value test). Any invalid register then
* found in the instruction will cause decoding to fail with INSN_REJECTED. In
* the above example this would happen if bits 11..8 of the instruction were
* 1111, indicating R15 or PC.
*
* As well as checking for legal combinations of registers, this data is also
* used to modify the registers encoded in the instructions so that an
* emulation routines can use it. (See decode_regs() and INSN_NEW_BITS.)
*
* Here is a real example which matches ARM instructions of the form
* "AND <Rd>,<Rn>,<Rm>,<shift> <Rs>"
*
* DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags,
* REGS(ANY, ANY, NOPC, 0, ANY)),
* ^ ^ ^ ^
* Rn Rd Rs Rm
*
* Decoding the instruction "AND R4, R5, R6, ASL R15" will be rejected because
* Rs == R15
*
* Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the
* instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into
* the kprobes instruction slot. This can then be called later by the handler
* function emulate_rd12rn16rm0rs8_rwflags in order to simulate the instruction.
*/
enum decode_type {
DECODE_TYPE_END,
DECODE_TYPE_TABLE,
DECODE_TYPE_CUSTOM,
DECODE_TYPE_SIMULATE,
DECODE_TYPE_EMULATE,
DECODE_TYPE_OR,
DECODE_TYPE_REJECT,
NUM_DECODE_TYPES /* Must be last enum */
};
#define DECODE_TYPE_BITS 4
#define DECODE_TYPE_MASK ((1 << DECODE_TYPE_BITS) - 1)
enum decode_reg_type {
REG_TYPE_NONE = 0, /* Not a register, ignore */
REG_TYPE_ANY, /* Any register allowed */
REG_TYPE_SAMEAS16, /* Register should be same as that at bits 19..16 */
REG_TYPE_SP, /* Register must be SP */
REG_TYPE_PC, /* Register must be PC */
REG_TYPE_NOSP, /* Register must not be SP */
REG_TYPE_NOSPPC, /* Register must not be SP or PC */
REG_TYPE_NOPC, /* Register must not be PC */
REG_TYPE_NOPCWB, /* No PC if load/store write-back flag also set */
/* The following types are used when the encoding for PC indicates
* another instruction form. This distiction only matters for test
* case coverage checks.
*/
REG_TYPE_NOPCX, /* Register must not be PC */
REG_TYPE_NOSPPCX, /* Register must not be SP or PC */
/* Alias to allow '0' arg to be used in REGS macro. */
REG_TYPE_0 = REG_TYPE_NONE
};
#define REGS(r16, r12, r8, r4, r0) \
((REG_TYPE_##r16) << 16) + \
((REG_TYPE_##r12) << 12) + \
((REG_TYPE_##r8) << 8) + \
((REG_TYPE_##r4) << 4) + \
(REG_TYPE_##r0)
union decode_item {
u32 bits;
const union decode_item *table;
kprobe_insn_handler_t *handler;
kprobe_decode_insn_t *decoder;
};
#define DECODE_END \
{.bits = DECODE_TYPE_END}
struct decode_header {
union decode_item type_regs;
union decode_item mask;
union decode_item value;
};
#define DECODE_HEADER(_type, _mask, _value, _regs) \
{.bits = (_type) | ((_regs) << DECODE_TYPE_BITS)}, \
{.bits = (_mask)}, \
{.bits = (_value)}
struct decode_table {
struct decode_header header;
union decode_item table;
};
#define DECODE_TABLE(_mask, _value, _table) \
DECODE_HEADER(DECODE_TYPE_TABLE, _mask, _value, 0), \
{.table = (_table)}
struct decode_custom {
struct decode_header header;
union decode_item decoder;
};
#define DECODE_CUSTOM(_mask, _value, _decoder) \
DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \
{.decoder = (_decoder)}
struct decode_simulate {
struct decode_header header;
union decode_item handler;
};
#define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \
DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \
{.handler = (_handler)}
#define DECODE_SIMULATE(_mask, _value, _handler) \
DECODE_SIMULATEX(_mask, _value, _handler, 0)
struct decode_emulate {
struct decode_header header;
union decode_item handler;
};
#define DECODE_EMULATEX(_mask, _value, _handler, _regs) \
DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \
{.handler = (_handler)}
#define DECODE_EMULATE(_mask, _value, _handler) \
DECODE_EMULATEX(_mask, _value, _handler, 0)
struct decode_or {
struct decode_header header;
};
#define DECODE_OR(_mask, _value) \
DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0)
struct decode_reject {
struct decode_header header;
};
#define DECODE_REJECT(_mask, _value) \
DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0)
#ifdef CONFIG_THUMB2_KERNEL
extern const union decode_item kprobe_decode_thumb16_table[];
extern const union decode_item kprobe_decode_thumb32_table[];
#else
extern const union decode_item kprobe_decode_arm_table[];
#endif
int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
const union decode_item *table, bool thumb16);
#endif /* _ARM_KERNEL_KPROBES_H */

View File

@ -16,6 +16,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/uaccess.h>
#include <linux/irq.h>
#include <linux/irqdesc.h>
#include <asm/irq_regs.h>
#include <asm/pmu.h>
@ -205,6 +207,8 @@ armpmu_del(struct perf_event *event, int flags)
armpmu_stop(event, PERF_EF_UPDATE);
hw_events->events[idx] = NULL;
clear_bit(idx, hw_events->used_mask);
if (armpmu->clear_event_idx)
armpmu->clear_event_idx(hw_events, event);
perf_event_update_userpage(event);
}
@ -295,14 +299,27 @@ validate_group(struct perf_event *event)
static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
{
struct arm_pmu *armpmu = (struct arm_pmu *) dev;
struct platform_device *plat_device = armpmu->plat_device;
struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev);
struct arm_pmu *armpmu;
struct platform_device *plat_device;
struct arm_pmu_platdata *plat;
int ret;
u64 start_clock, finish_clock;
if (irq_is_percpu(irq))
dev = *(void **)dev;
armpmu = dev;
plat_device = armpmu->plat_device;
plat = dev_get_platdata(&plat_device->dev);
start_clock = sched_clock();
if (plat && plat->handle_irq)
return plat->handle_irq(irq, dev, armpmu->handle_irq);
ret = plat->handle_irq(irq, dev, armpmu->handle_irq);
else
return armpmu->handle_irq(irq, dev);
ret = armpmu->handle_irq(irq, dev);
finish_clock = sched_clock();
perf_sample_event_took(finish_clock - start_clock);
return ret;
}
static void

View File

@ -25,6 +25,8 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/irq.h>
#include <linux/irqdesc.h>
#include <asm/cputype.h>
#include <asm/irq_regs.h>
@ -33,6 +35,7 @@
/* Set at runtime when we know what CPU type we are. */
static struct arm_pmu *cpu_pmu;
static DEFINE_PER_CPU(struct arm_pmu *, percpu_pmu);
static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
@ -71,6 +74,26 @@ static struct pmu_hw_events *cpu_pmu_get_cpu_events(void)
return this_cpu_ptr(&cpu_hw_events);
}
static void cpu_pmu_enable_percpu_irq(void *data)
{
struct arm_pmu *cpu_pmu = data;
struct platform_device *pmu_device = cpu_pmu->plat_device;
int irq = platform_get_irq(pmu_device, 0);
enable_percpu_irq(irq, IRQ_TYPE_NONE);
cpumask_set_cpu(smp_processor_id(), &cpu_pmu->active_irqs);
}
static void cpu_pmu_disable_percpu_irq(void *data)
{
struct arm_pmu *cpu_pmu = data;
struct platform_device *pmu_device = cpu_pmu->plat_device;
int irq = platform_get_irq(pmu_device, 0);
cpumask_clear_cpu(smp_processor_id(), &cpu_pmu->active_irqs);
disable_percpu_irq(irq);
}
static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu)
{
int i, irq, irqs;
@ -78,12 +101,18 @@ static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu)
irqs = min(pmu_device->num_resources, num_possible_cpus());
for (i = 0; i < irqs; ++i) {
if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs))
continue;
irq = platform_get_irq(pmu_device, i);
if (irq >= 0)
free_irq(irq, cpu_pmu);
irq = platform_get_irq(pmu_device, 0);
if (irq >= 0 && irq_is_percpu(irq)) {
on_each_cpu(cpu_pmu_disable_percpu_irq, cpu_pmu, 1);
free_percpu_irq(irq, &percpu_pmu);
} else {
for (i = 0; i < irqs; ++i) {
if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs))
continue;
irq = platform_get_irq(pmu_device, i);
if (irq >= 0)
free_irq(irq, cpu_pmu);
}
}
}
@ -101,33 +130,44 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
return -ENODEV;
}
for (i = 0; i < irqs; ++i) {
err = 0;
irq = platform_get_irq(pmu_device, i);
if (irq < 0)
continue;
/*
* If we have a single PMU interrupt that we can't shift,
* assume that we're running on a uniprocessor machine and
* continue. Otherwise, continue without this interrupt.
*/
if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
irq, i);
continue;
}
err = request_irq(irq, handler,
IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu",
cpu_pmu);
irq = platform_get_irq(pmu_device, 0);
if (irq >= 0 && irq_is_percpu(irq)) {
err = request_percpu_irq(irq, handler, "arm-pmu", &percpu_pmu);
if (err) {
pr_err("unable to request IRQ%d for ARM PMU counters\n",
irq);
return err;
}
on_each_cpu(cpu_pmu_enable_percpu_irq, cpu_pmu, 1);
} else {
for (i = 0; i < irqs; ++i) {
err = 0;
irq = platform_get_irq(pmu_device, i);
if (irq < 0)
continue;
cpumask_set_cpu(i, &cpu_pmu->active_irqs);
/*
* If we have a single PMU interrupt that we can't shift,
* assume that we're running on a uniprocessor machine and
* continue. Otherwise, continue without this interrupt.
*/
if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
irq, i);
continue;
}
err = request_irq(irq, handler,
IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu",
cpu_pmu);
if (err) {
pr_err("unable to request IRQ%d for ARM PMU counters\n",
irq);
return err;
}
cpumask_set_cpu(i, &cpu_pmu->active_irqs);
}
}
return 0;
@ -141,6 +181,7 @@ static void cpu_pmu_init(struct arm_pmu *cpu_pmu)
events->events = per_cpu(hw_events, cpu);
events->used_mask = per_cpu(used_mask, cpu);
raw_spin_lock_init(&events->pmu_lock);
per_cpu(percpu_pmu, cpu) = cpu_pmu;
}
cpu_pmu->get_hw_events = cpu_pmu_get_cpu_events;
@ -181,6 +222,7 @@ static struct notifier_block cpu_pmu_hotplug_notifier = {
*/
static struct of_device_id cpu_pmu_of_device_ids[] = {
{.compatible = "arm,cortex-a15-pmu", .data = armv7_a15_pmu_init},
{.compatible = "arm,cortex-a12-pmu", .data = armv7_a12_pmu_init},
{.compatible = "arm,cortex-a9-pmu", .data = armv7_a9_pmu_init},
{.compatible = "arm,cortex-a8-pmu", .data = armv7_a8_pmu_init},
{.compatible = "arm,cortex-a7-pmu", .data = armv7_a7_pmu_init},
@ -188,6 +230,7 @@ static struct of_device_id cpu_pmu_of_device_ids[] = {
{.compatible = "arm,arm11mpcore-pmu", .data = armv6mpcore_pmu_init},
{.compatible = "arm,arm1176-pmu", .data = armv6pmu_init},
{.compatible = "arm,arm1136-pmu", .data = armv6pmu_init},
{.compatible = "qcom,krait-pmu", .data = krait_pmu_init},
{},
};
@ -225,15 +268,6 @@ static int probe_current_pmu(struct arm_pmu *pmu)
case ARM_CPU_PART_CORTEX_A9:
ret = armv7_a9_pmu_init(pmu);
break;
case ARM_CPU_PART_CORTEX_A5:
ret = armv7_a5_pmu_init(pmu);
break;
case ARM_CPU_PART_CORTEX_A15:
ret = armv7_a15_pmu_init(pmu);
break;
case ARM_CPU_PART_CORTEX_A7:
ret = armv7_a7_pmu_init(pmu);
break;
}
/* Intel CPUs [xscale]. */
} else if (implementor == ARM_CPU_IMP_INTEL) {
@ -270,6 +304,9 @@ static int cpu_pmu_device_probe(struct platform_device *pdev)
return -ENOMEM;
}
cpu_pmu = pmu;
cpu_pmu->plat_device = pdev;
if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
init_fn = of_id->data;
ret = init_fn(pmu);
@ -282,8 +319,6 @@ static int cpu_pmu_device_probe(struct platform_device *pdev)
goto out_free;
}
cpu_pmu = pmu;
cpu_pmu->plat_device = pdev;
cpu_pmu_init(cpu_pmu);
ret = armpmu_register(cpu_pmu, PERF_TYPE_RAW);

View File

@ -18,6 +18,10 @@
#ifdef CONFIG_CPU_V7
#include <asm/cp15.h>
#include <asm/vfp.h>
#include "../vfp/vfpinstr.h"
/*
* Common ARMv7 event types
*
@ -109,6 +113,33 @@ enum armv7_a15_perf_types {
ARMV7_A15_PERFCTR_PC_WRITE_SPEC = 0x76,
};
/* ARMv7 Cortex-A12 specific event types */
enum armv7_a12_perf_types {
ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_READ = 0x40,
ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_WRITE = 0x41,
ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_READ = 0x50,
ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_WRITE = 0x51,
ARMV7_A12_PERFCTR_PC_WRITE_SPEC = 0x76,
ARMV7_A12_PERFCTR_PF_TLB_REFILL = 0xe7,
};
/* ARMv7 Krait specific event types */
enum krait_perf_types {
KRAIT_PMRESR0_GROUP0 = 0xcc,
KRAIT_PMRESR1_GROUP0 = 0xd0,
KRAIT_PMRESR2_GROUP0 = 0xd4,
KRAIT_VPMRESR0_GROUP0 = 0xd8,
KRAIT_PERFCTR_L1_ICACHE_ACCESS = 0x10011,
KRAIT_PERFCTR_L1_ICACHE_MISS = 0x10010,
KRAIT_PERFCTR_L1_ITLB_ACCESS = 0x12222,
KRAIT_PERFCTR_L1_DTLB_ACCESS = 0x12210,
};
/*
* Cortex-A8 HW events mapping
*
@ -731,6 +762,262 @@ static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
},
};
/*
* Cortex-A12 HW events mapping
*/
static const unsigned armv7_a12_perf_map[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
[PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED,
[PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_L1_DCACHE_ACCESS,
[PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_L1_DCACHE_REFILL,
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_A12_PERFCTR_PC_WRITE_SPEC,
[PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
[PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_BUS_CYCLES,
[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = HW_OP_UNSUPPORTED,
[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = HW_OP_UNSUPPORTED,
};
static const unsigned armv7_a12_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
[C(L1D)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_READ,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_WRITE,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(L1I)] = {
/*
* Not all performance counters differentiate between read
* and write accesses/misses so we're not always strictly
* correct, but it's the best we can do. Writes and reads get
* combined in these cases.
*/
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(LL)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_READ,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACHE_REFILL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_WRITE,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACHE_REFILL,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(DTLB)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = ARMV7_A12_PERFCTR_PF_TLB_REFILL,
},
},
[C(ITLB)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_REFILL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_REFILL,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(BPU)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(NODE)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
};
/*
* Krait HW events mapping
*/
static const unsigned krait_perf_map[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
[PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED,
[PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED,
[PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED,
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
[PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
[PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES,
};
static const unsigned krait_perf_map_no_branch[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
[PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED,
[PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED,
[PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED,
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = HW_OP_UNSUPPORTED,
[PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
[PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES,
};
static const unsigned krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
[C(L1D)] = {
/*
* The performance counters don't differentiate between read
* and write accesses/misses so this isn't strictly correct,
* but it's the best we can do. Writes and reads get
* combined.
*/
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS,
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(L1I)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_ICACHE_ACCESS,
[C(RESULT_MISS)] = KRAIT_PERFCTR_L1_ICACHE_MISS,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(LL)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(DTLB)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_DTLB_ACCESS,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_DTLB_ACCESS,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(ITLB)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_ITLB_ACCESS,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_ITLB_ACCESS,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(BPU)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
[C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
[C(NODE)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
},
};
/*
* Perf Events' indices
*/
@ -1212,6 +1499,24 @@ static int armv7_a7_map_event(struct perf_event *event)
&armv7_a7_perf_cache_map, 0xFF);
}
static int armv7_a12_map_event(struct perf_event *event)
{
return armpmu_map_event(event, &armv7_a12_perf_map,
&armv7_a12_perf_cache_map, 0xFF);
}
static int krait_map_event(struct perf_event *event)
{
return armpmu_map_event(event, &krait_perf_map,
&krait_perf_cache_map, 0xFFFFF);
}
static int krait_map_event_no_branch(struct perf_event *event)
{
return armpmu_map_event(event, &krait_perf_map_no_branch,
&krait_perf_cache_map, 0xFFFFF);
}
static void armv7pmu_init(struct arm_pmu *cpu_pmu)
{
cpu_pmu->handle_irq = armv7pmu_handle_irq;
@ -1283,6 +1588,408 @@ static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
return 0;
}
static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu)
{
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "ARMv7 Cortex-A12";
cpu_pmu->map_event = armv7_a12_map_event;
cpu_pmu->num_events = armv7_read_num_pmnc_events();
cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
return 0;
}
/*
* Krait Performance Monitor Region Event Selection Register (PMRESRn)
*
* 31 30 24 16 8 0
* +--------------------------------+
* PMRESR0 | EN | CC | CC | CC | CC | N = 1, R = 0
* +--------------------------------+
* PMRESR1 | EN | CC | CC | CC | CC | N = 1, R = 1
* +--------------------------------+
* PMRESR2 | EN | CC | CC | CC | CC | N = 1, R = 2
* +--------------------------------+
* VPMRESR0 | EN | CC | CC | CC | CC | N = 2, R = ?
* +--------------------------------+
* EN | G=3 | G=2 | G=1 | G=0
*
* Event Encoding:
*
* hwc->config_base = 0xNRCCG
*
* N = prefix, 1 for Krait CPU (PMRESRn), 2 for Venum VFP (VPMRESR)
* R = region register
* CC = class of events the group G is choosing from
* G = group or particular event
*
* Example: 0x12021 is a Krait CPU event in PMRESR2's group 1 with code 2
*
* A region (R) corresponds to a piece of the CPU (execution unit, instruction
* unit, etc.) while the event code (CC) corresponds to a particular class of
* events (interrupts for example). An event code is broken down into
* groups (G) that can be mapped into the PMU (irq, fiqs, and irq+fiqs for
* example).
*/
#define KRAIT_EVENT (1 << 16)
#define VENUM_EVENT (2 << 16)
#define KRAIT_EVENT_MASK (KRAIT_EVENT | VENUM_EVENT)
#define PMRESRn_EN BIT(31)
static u32 krait_read_pmresrn(int n)
{
u32 val;
switch (n) {
case 0:
asm volatile("mrc p15, 1, %0, c9, c15, 0" : "=r" (val));
break;
case 1:
asm volatile("mrc p15, 1, %0, c9, c15, 1" : "=r" (val));
break;
case 2:
asm volatile("mrc p15, 1, %0, c9, c15, 2" : "=r" (val));
break;
default:
BUG(); /* Should be validated in krait_pmu_get_event_idx() */
}
return val;
}
static void krait_write_pmresrn(int n, u32 val)
{
switch (n) {
case 0:
asm volatile("mcr p15, 1, %0, c9, c15, 0" : : "r" (val));
break;
case 1:
asm volatile("mcr p15, 1, %0, c9, c15, 1" : : "r" (val));
break;
case 2:
asm volatile("mcr p15, 1, %0, c9, c15, 2" : : "r" (val));
break;
default:
BUG(); /* Should be validated in krait_pmu_get_event_idx() */
}
}
static u32 krait_read_vpmresr0(void)
{
u32 val;
asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
return val;
}
static void krait_write_vpmresr0(u32 val)
{
asm volatile("mcr p10, 7, %0, c11, c0, 0" : : "r" (val));
}
static void krait_pre_vpmresr0(u32 *venum_orig_val, u32 *fp_orig_val)
{
u32 venum_new_val;
u32 fp_new_val;
BUG_ON(preemptible());
/* CPACR Enable CP10 and CP11 access */
*venum_orig_val = get_copro_access();
venum_new_val = *venum_orig_val | CPACC_SVC(10) | CPACC_SVC(11);
set_copro_access(venum_new_val);
/* Enable FPEXC */
*fp_orig_val = fmrx(FPEXC);
fp_new_val = *fp_orig_val | FPEXC_EN;
fmxr(FPEXC, fp_new_val);
}
static void krait_post_vpmresr0(u32 venum_orig_val, u32 fp_orig_val)
{
BUG_ON(preemptible());
/* Restore FPEXC */
fmxr(FPEXC, fp_orig_val);
isb();
/* Restore CPACR */
set_copro_access(venum_orig_val);
}
static u32 krait_get_pmresrn_event(unsigned int region)
{
static const u32 pmresrn_table[] = { KRAIT_PMRESR0_GROUP0,
KRAIT_PMRESR1_GROUP0,
KRAIT_PMRESR2_GROUP0 };
return pmresrn_table[region];
}
static void krait_evt_setup(int idx, u32 config_base)
{
u32 val;
u32 mask;
u32 vval, fval;
unsigned int region;
unsigned int group;
unsigned int code;
unsigned int group_shift;
bool venum_event;
venum_event = !!(config_base & VENUM_EVENT);
region = (config_base >> 12) & 0xf;
code = (config_base >> 4) & 0xff;
group = (config_base >> 0) & 0xf;
group_shift = group * 8;
mask = 0xff << group_shift;
/* Configure evtsel for the region and group */
if (venum_event)
val = KRAIT_VPMRESR0_GROUP0;
else
val = krait_get_pmresrn_event(region);
val += group;
/* Mix in mode-exclusion bits */
val |= config_base & (ARMV7_EXCLUDE_USER | ARMV7_EXCLUDE_PL1);
armv7_pmnc_write_evtsel(idx, val);
asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (0));
if (venum_event) {
krait_pre_vpmresr0(&vval, &fval);
val = krait_read_vpmresr0();
val &= ~mask;
val |= code << group_shift;
val |= PMRESRn_EN;
krait_write_vpmresr0(val);
krait_post_vpmresr0(vval, fval);
} else {
val = krait_read_pmresrn(region);
val &= ~mask;
val |= code << group_shift;
val |= PMRESRn_EN;
krait_write_pmresrn(region, val);
}
}
static u32 krait_clear_pmresrn_group(u32 val, int group)
{
u32 mask;
int group_shift;
group_shift = group * 8;
mask = 0xff << group_shift;
val &= ~mask;
/* Don't clear enable bit if entire region isn't disabled */
if (val & ~PMRESRn_EN)
return val |= PMRESRn_EN;
return 0;
}
static void krait_clearpmu(u32 config_base)
{
u32 val;
u32 vval, fval;
unsigned int region;
unsigned int group;
bool venum_event;
venum_event = !!(config_base & VENUM_EVENT);
region = (config_base >> 12) & 0xf;
group = (config_base >> 0) & 0xf;
if (venum_event) {
krait_pre_vpmresr0(&vval, &fval);
val = krait_read_vpmresr0();
val = krait_clear_pmresrn_group(val, group);
krait_write_vpmresr0(val);
krait_post_vpmresr0(vval, fval);
} else {
val = krait_read_pmresrn(region);
val = krait_clear_pmresrn_group(val, group);
krait_write_pmresrn(region, val);
}
}
static void krait_pmu_disable_event(struct perf_event *event)
{
unsigned long flags;
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;
struct pmu_hw_events *events = cpu_pmu->get_hw_events();
/* Disable counter and interrupt */
raw_spin_lock_irqsave(&events->pmu_lock, flags);
/* Disable counter */
armv7_pmnc_disable_counter(idx);
/*
* Clear pmresr code (if destined for PMNx counters)
*/
if (hwc->config_base & KRAIT_EVENT_MASK)
krait_clearpmu(hwc->config_base);
/* Disable interrupt for this counter */
armv7_pmnc_disable_intens(idx);
raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static void krait_pmu_enable_event(struct perf_event *event)
{
unsigned long flags;
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;
struct pmu_hw_events *events = cpu_pmu->get_hw_events();
/*
* Enable counter and interrupt, and set the counter to count
* the event that we're interested in.
*/
raw_spin_lock_irqsave(&events->pmu_lock, flags);
/* Disable counter */
armv7_pmnc_disable_counter(idx);
/*
* Set event (if destined for PMNx counters)
* We set the event for the cycle counter because we
* have the ability to perform event filtering.
*/
if (hwc->config_base & KRAIT_EVENT_MASK)
krait_evt_setup(idx, hwc->config_base);
else
armv7_pmnc_write_evtsel(idx, hwc->config_base);
/* Enable interrupt for this counter */
armv7_pmnc_enable_intens(idx);
/* Enable counter */
armv7_pmnc_enable_counter(idx);
raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static void krait_pmu_reset(void *info)
{
u32 vval, fval;
armv7pmu_reset(info);
/* Clear all pmresrs */
krait_write_pmresrn(0, 0);
krait_write_pmresrn(1, 0);
krait_write_pmresrn(2, 0);
krait_pre_vpmresr0(&vval, &fval);
krait_write_vpmresr0(0);
krait_post_vpmresr0(vval, fval);
}
static int krait_event_to_bit(struct perf_event *event, unsigned int region,
unsigned int group)
{
int bit;
struct hw_perf_event *hwc = &event->hw;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
if (hwc->config_base & VENUM_EVENT)
bit = KRAIT_VPMRESR0_GROUP0;
else
bit = krait_get_pmresrn_event(region);
bit -= krait_get_pmresrn_event(0);
bit += group;
/*
* Lower bits are reserved for use by the counters (see
* armv7pmu_get_event_idx() for more info)
*/
bit += ARMV7_IDX_COUNTER_LAST(cpu_pmu) + 1;
return bit;
}
/*
* We check for column exclusion constraints here.
* Two events cant use the same group within a pmresr register.
*/
static int krait_pmu_get_event_idx(struct pmu_hw_events *cpuc,
struct perf_event *event)
{
int idx;
int bit;
unsigned int prefix;
unsigned int region;
unsigned int code;
unsigned int group;
bool krait_event;
struct hw_perf_event *hwc = &event->hw;
region = (hwc->config_base >> 12) & 0xf;
code = (hwc->config_base >> 4) & 0xff;
group = (hwc->config_base >> 0) & 0xf;
krait_event = !!(hwc->config_base & KRAIT_EVENT_MASK);
if (krait_event) {
/* Ignore invalid events */
if (group > 3 || region > 2)
return -EINVAL;
prefix = hwc->config_base & KRAIT_EVENT_MASK;
if (prefix != KRAIT_EVENT && prefix != VENUM_EVENT)
return -EINVAL;
if (prefix == VENUM_EVENT && (code & 0xe0))
return -EINVAL;
bit = krait_event_to_bit(event, region, group);
if (test_and_set_bit(bit, cpuc->used_mask))
return -EAGAIN;
}
idx = armv7pmu_get_event_idx(cpuc, event);
if (idx < 0 && krait_event)
clear_bit(bit, cpuc->used_mask);
return idx;
}
static void krait_pmu_clear_event_idx(struct pmu_hw_events *cpuc,
struct perf_event *event)
{
int bit;
struct hw_perf_event *hwc = &event->hw;
unsigned int region;
unsigned int group;
bool krait_event;
region = (hwc->config_base >> 12) & 0xf;
group = (hwc->config_base >> 0) & 0xf;
krait_event = !!(hwc->config_base & KRAIT_EVENT_MASK);
if (krait_event) {
bit = krait_event_to_bit(event, region, group);
clear_bit(bit, cpuc->used_mask);
}
}
static int krait_pmu_init(struct arm_pmu *cpu_pmu)
{
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "ARMv7 Krait";
/* Some early versions of Krait don't support PC write events */
if (of_property_read_bool(cpu_pmu->plat_device->dev.of_node,
"qcom,no-pc-write"))
cpu_pmu->map_event = krait_map_event_no_branch;
else
cpu_pmu->map_event = krait_map_event;
cpu_pmu->num_events = armv7_read_num_pmnc_events();
cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
cpu_pmu->reset = krait_pmu_reset;
cpu_pmu->enable = krait_pmu_enable_event;
cpu_pmu->disable = krait_pmu_disable_event;
cpu_pmu->get_event_idx = krait_pmu_get_event_idx;
cpu_pmu->clear_event_idx = krait_pmu_clear_event_idx;
return 0;
}
#else
static inline int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
{
@ -1308,4 +2015,14 @@ static inline int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
{
return -ENODEV;
}
static inline int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu)
{
return -ENODEV;
}
static inline int krait_pmu_init(struct arm_pmu *cpu_pmu)
{
return -ENODEV;
}
#endif /* CONFIG_CPU_V7 */

View File

@ -0,0 +1,734 @@
/*
* arch/arm/kernel/probes-arm.c
*
* Some code moved here from arch/arm/kernel/kprobes-arm.c
*
* Copyright (C) 2006, 2007 Motorola Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/stddef.h>
#include <linux/ptrace.h>
#include "probes.h"
#include "probes-arm.h"
#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
/*
* To avoid the complications of mimicing single-stepping on a
* processor without a Next-PC or a single-step mode, and to
* avoid having to deal with the side-effects of boosting, we
* simulate or emulate (almost) all ARM instructions.
*
* "Simulation" is where the instruction's behavior is duplicated in
* C code. "Emulation" is where the original instruction is rewritten
* and executed, often by altering its registers.
*
* By having all behavior of the kprobe'd instruction completed before
* returning from the kprobe_handler(), all locks (scheduler and
* interrupt) can safely be released. There is no need for secondary
* breakpoints, no race with MP or preemptable kernels, nor having to
* clean up resources counts at a later time impacting overall system
* performance. By rewriting the instruction, only the minimum registers
* need to be loaded and saved back optimizing performance.
*
* Calling the insnslot_*_rwflags version of a function doesn't hurt
* anything even when the CPSR flags aren't updated by the
* instruction. It's just a little slower in return for saving
* a little space by not having a duplicate function that doesn't
* update the flags. (The same optimization can be said for
* instructions that do or don't perform register writeback)
* Also, instructions can either read the flags, only write the
* flags, or read and write the flags. To save combinations
* rather than for sheer performance, flag functions just assume
* read and write of flags.
*/
void __kprobes simulate_bbl(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
long iaddr = (long) regs->ARM_pc - 4;
int disp = branch_displacement(insn);
if (insn & (1 << 24))
regs->ARM_lr = iaddr + 4;
regs->ARM_pc = iaddr + 8 + disp;
}
void __kprobes simulate_blx1(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
long iaddr = (long) regs->ARM_pc - 4;
int disp = branch_displacement(insn);
regs->ARM_lr = iaddr + 4;
regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2);
regs->ARM_cpsr |= PSR_T_BIT;
}
void __kprobes simulate_blx2bx(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
int rm = insn & 0xf;
long rmv = regs->uregs[rm];
if (insn & (1 << 5))
regs->ARM_lr = (long) regs->ARM_pc;
regs->ARM_pc = rmv & ~0x1;
regs->ARM_cpsr &= ~PSR_T_BIT;
if (rmv & 0x1)
regs->ARM_cpsr |= PSR_T_BIT;
}
void __kprobes simulate_mrs(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
int rd = (insn >> 12) & 0xf;
unsigned long mask = 0xf8ff03df; /* Mask out execution state */
regs->uregs[rd] = regs->ARM_cpsr & mask;
}
void __kprobes simulate_mov_ipsp(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
regs->uregs[12] = regs->uregs[13];
}
/*
* For the instruction masking and comparisons in all the "space_*"
* functions below, Do _not_ rearrange the order of tests unless
* you're very, very sure of what you are doing. For the sake of
* efficiency, the masks for some tests sometimes assume other test
* have been done prior to them so the number of patterns to test
* for an instruction set can be as broad as possible to reduce the
* number of tests needed.
*/
static const union decode_item arm_1111_table[] = {
/* Unconditional instructions */
/* memory hint 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */
/* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */
/* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */
/* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */
DECODE_SIMULATE (0xfe300000, 0xf4100000, PROBES_PRELOAD_IMM),
/* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */
/* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */
/* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */
/* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */
DECODE_SIMULATE (0xfe300010, 0xf6100000, PROBES_PRELOAD_REG),
/* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */
DECODE_SIMULATE (0xfe000000, 0xfa000000, PROBES_BRANCH_IMM),
/* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */
/* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
/* SRS 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
/* RFE 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
/* Coprocessor instructions... */
/* MCRR2 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */
/* MRRC2 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */
/* LDC2 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
/* STC2 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
/* CDP2 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
/* MCR2 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
/* MRC2 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
/* Other unallocated instructions... */
DECODE_END
};
static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = {
/* Miscellaneous instructions */
/* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */
DECODE_SIMULATEX(0x0ff000f0, 0x01000000, PROBES_MRS,
REGS(0, NOPC, 0, 0, 0)),
/* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */
DECODE_SIMULATE (0x0ff000f0, 0x01200010, PROBES_BRANCH_REG),
/* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */
DECODE_SIMULATEX(0x0ff000f0, 0x01200030, PROBES_BRANCH_REG,
REGS(0, 0, 0, 0, NOPC)),
/* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */
DECODE_EMULATEX (0x0ff000f0, 0x01600010, PROBES_CLZ,
REGS(0, NOPC, 0, 0, NOPC)),
/* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */
/* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */
/* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */
/* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */
DECODE_EMULATEX (0x0f9000f0, 0x01000050, PROBES_SATURATING_ARITHMETIC,
REGS(NOPC, NOPC, 0, 0, NOPC)),
/* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
/* MSR cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
/* MRS spsr cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */
/* BKPT 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
/* SMC cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */
/* And unallocated instructions... */
DECODE_END
};
static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = {
/* Halfword multiply and multiply-accumulate */
/* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */
DECODE_EMULATEX (0x0ff00090, 0x01400080, PROBES_MUL1,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
/* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */
DECODE_OR (0x0ff000b0, 0x012000a0),
/* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */
DECODE_EMULATEX (0x0ff00090, 0x01600080, PROBES_MUL2,
REGS(NOPC, 0, NOPC, 0, NOPC)),
/* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */
DECODE_OR (0x0ff00090, 0x01000080),
/* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */
DECODE_EMULATEX (0x0ff000b0, 0x01200080, PROBES_MUL2,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
DECODE_END
};
static const union decode_item arm_cccc_0000_____1001_table[] = {
/* Multiply and multiply-accumulate */
/* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */
/* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */
DECODE_EMULATEX (0x0fe000f0, 0x00000090, PROBES_MUL2,
REGS(NOPC, 0, NOPC, 0, NOPC)),
/* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */
/* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */
DECODE_OR (0x0fe000f0, 0x00200090),
/* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */
DECODE_EMULATEX (0x0ff000f0, 0x00600090, PROBES_MUL2,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
/* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */
DECODE_OR (0x0ff000f0, 0x00400090),
/* UMULL cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */
/* UMULLS cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */
/* UMLAL cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */
/* UMLALS cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */
/* SMULL cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */
/* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */
/* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */
/* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */
DECODE_EMULATEX (0x0f8000f0, 0x00800090, PROBES_MUL1,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
DECODE_END
};
static const union decode_item arm_cccc_0001_____1001_table[] = {
/* Synchronization primitives */
#if __LINUX_ARM_ARCH__ < 6
/* Deprecated on ARMv6 and may be UNDEFINED on v7 */
/* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */
DECODE_EMULATEX (0x0fb000f0, 0x01000090, PROBES_SWP,
REGS(NOPC, NOPC, 0, 0, NOPC)),
#endif
/* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */
/* And unallocated instructions... */
DECODE_END
};
static const union decode_item arm_cccc_000x_____1xx1_table[] = {
/* Extra load/store instructions */
/* STRHT cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */
/* ??? cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */
/* LDRHT cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */
/* LDRSBT cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */
/* LDRSHT cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */
DECODE_REJECT (0x0f200090, 0x00200090),
/* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */
DECODE_REJECT (0x0e10e0d0, 0x0000e0d0),
/* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */
/* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */
DECODE_EMULATEX (0x0e5000d0, 0x000000d0, PROBES_LDRSTRD,
REGS(NOPCWB, NOPCX, 0, 0, NOPC)),
/* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */
/* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */
DECODE_EMULATEX (0x0e5000d0, 0x004000d0, PROBES_LDRSTRD,
REGS(NOPCWB, NOPCX, 0, 0, 0)),
/* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */
DECODE_EMULATEX (0x0e5000f0, 0x000000b0, PROBES_STORE_EXTRA,
REGS(NOPCWB, NOPC, 0, 0, NOPC)),
/* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */
/* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */
/* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */
DECODE_EMULATEX (0x0e500090, 0x00100090, PROBES_LOAD_EXTRA,
REGS(NOPCWB, NOPC, 0, 0, NOPC)),
/* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */
DECODE_EMULATEX (0x0e5000f0, 0x004000b0, PROBES_STORE_EXTRA,
REGS(NOPCWB, NOPC, 0, 0, 0)),
/* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */
/* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */
/* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */
DECODE_EMULATEX (0x0e500090, 0x00500090, PROBES_LOAD_EXTRA,
REGS(NOPCWB, NOPC, 0, 0, 0)),
DECODE_END
};
static const union decode_item arm_cccc_000x_table[] = {
/* Data-processing (register) */
/* <op>S PC, ... cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */
DECODE_REJECT (0x0e10f000, 0x0010f000),
/* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */
DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, PROBES_MOV_IP_SP),
/* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */
/* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */
/* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */
/* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */
DECODE_EMULATEX (0x0f900010, 0x01100000, PROBES_DATA_PROCESSING_REG,
REGS(ANY, 0, 0, 0, ANY)),
/* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */
/* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */
DECODE_EMULATEX (0x0fa00010, 0x01a00000, PROBES_DATA_PROCESSING_REG,
REGS(0, ANY, 0, 0, ANY)),
/* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */
/* EOR (register) cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */
/* SUB (register) cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */
/* RSB (register) cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */
/* ADD (register) cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */
/* ADC (register) cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */
/* SBC (register) cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */
/* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */
/* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */
/* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */
DECODE_EMULATEX (0x0e000010, 0x00000000, PROBES_DATA_PROCESSING_REG,
REGS(ANY, ANY, 0, 0, ANY)),
/* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */
/* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */
/* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */
/* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */
DECODE_EMULATEX (0x0f900090, 0x01100010, PROBES_DATA_PROCESSING_REG,
REGS(ANY, 0, NOPC, 0, ANY)),
/* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */
/* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */
DECODE_EMULATEX (0x0fa00090, 0x01a00010, PROBES_DATA_PROCESSING_REG,
REGS(0, ANY, NOPC, 0, ANY)),
/* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */
/* EOR (reg-shift reg) cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */
/* SUB (reg-shift reg) cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */
/* RSB (reg-shift reg) cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */
/* ADD (reg-shift reg) cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */
/* ADC (reg-shift reg) cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */
/* SBC (reg-shift reg) cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */
/* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */
/* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */
/* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */
DECODE_EMULATEX (0x0e000090, 0x00000010, PROBES_DATA_PROCESSING_REG,
REGS(ANY, ANY, NOPC, 0, ANY)),
DECODE_END
};
static const union decode_item arm_cccc_001x_table[] = {
/* Data-processing (immediate) */
/* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */
/* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_DATA_PROCESSING_IMM,
REGS(0, NOPC, 0, 0, 0)),
/* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */
DECODE_OR (0x0fff00ff, 0x03200001),
/* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */
DECODE_EMULATE (0x0fff00ff, 0x03200004, PROBES_EMULATE_NONE),
/* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */
/* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */
/* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */
DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_SIMULATE_NOP),
/* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */
/* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */
/* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0x0fb00000, 0x03200000),
/* <op>S PC, ... cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */
DECODE_REJECT (0x0e10f000, 0x0210f000),
/* TST (immediate) cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */
/* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */
/* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */
/* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0f900000, 0x03100000, PROBES_DATA_PROCESSING_IMM,
REGS(ANY, 0, 0, 0, 0)),
/* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */
/* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0fa00000, 0x03a00000, PROBES_DATA_PROCESSING_IMM,
REGS(0, ANY, 0, 0, 0)),
/* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */
/* EOR (immediate) cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */
/* SUB (immediate) cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */
/* RSB (immediate) cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */
/* ADD (immediate) cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */
/* ADC (immediate) cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */
/* SBC (immediate) cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */
/* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */
/* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */
/* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0e000000, 0x02000000, PROBES_DATA_PROCESSING_IMM,
REGS(ANY, ANY, 0, 0, 0)),
DECODE_END
};
static const union decode_item arm_cccc_0110_____xxx1_table[] = {
/* Media instructions */
/* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */
DECODE_EMULATEX (0x0ff000f0, 0x068000b0, PROBES_SATURATE,
REGS(NOPC, NOPC, 0, 0, NOPC)),
/* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */
/* USAT cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */
DECODE_OR(0x0fa00030, 0x06a00010),
/* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */
/* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */
DECODE_EMULATEX (0x0fb000f0, 0x06a00030, PROBES_SATURATE,
REGS(0, NOPC, 0, 0, NOPC)),
/* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */
/* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */
/* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */
/* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */
DECODE_EMULATEX (0x0fb00070, 0x06b00030, PROBES_REV,
REGS(0, NOPC, 0, 0, NOPC)),
/* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */
DECODE_REJECT (0x0fb00010, 0x06000010),
/* ??? cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */
DECODE_REJECT (0x0f8000f0, 0x060000b0),
/* ??? cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */
DECODE_REJECT (0x0f8000f0, 0x060000d0),
/* SADD16 cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */
/* SADDSUBX cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */
/* SSUBADDX cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */
/* SSUB16 cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */
/* SADD8 cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */
/* SSUB8 cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */
/* QADD16 cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */
/* QADDSUBX cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */
/* QSUBADDX cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */
/* QSUB16 cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */
/* QADD8 cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */
/* QSUB8 cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */
/* SHADD16 cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */
/* SHADDSUBX cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */
/* SHSUBADDX cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */
/* SHSUB16 cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */
/* SHADD8 cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */
/* SHSUB8 cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */
/* UADD16 cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */
/* UADDSUBX cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */
/* USUBADDX cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */
/* USUB16 cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */
/* UADD8 cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */
/* USUB8 cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */
/* UQADD16 cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */
/* UQADDSUBX cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */
/* UQSUBADDX cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */
/* UQSUB16 cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */
/* UQADD8 cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */
/* UQSUB8 cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */
/* UHADD16 cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */
/* UHADDSUBX cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */
/* UHSUBADDX cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */
/* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */
/* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */
/* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */
DECODE_EMULATEX (0x0f800010, 0x06000010, PROBES_MMI,
REGS(NOPC, NOPC, 0, 0, NOPC)),
/* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */
/* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */
DECODE_EMULATEX (0x0ff00030, 0x06800010, PROBES_PACK,
REGS(NOPC, NOPC, 0, 0, NOPC)),
/* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */
/* ??? cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */
DECODE_REJECT (0x0fb000f0, 0x06900070),
/* SXTB16 cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */
/* SXTB cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */
/* SXTH cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */
/* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */
/* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */
/* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */
DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, PROBES_EXTEND,
REGS(0, NOPC, 0, 0, NOPC)),
/* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */
/* SXTAB cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */
/* SXTAH cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */
/* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */
/* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */
/* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */
DECODE_EMULATEX (0x0f8000f0, 0x06800070, PROBES_EXTEND_ADD,
REGS(NOPCX, NOPC, 0, 0, NOPC)),
DECODE_END
};
static const union decode_item arm_cccc_0111_____xxx1_table[] = {
/* Media instructions */
/* UNDEFINED cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */
DECODE_REJECT (0x0ff000f0, 0x07f000f0),
/* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */
/* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */
DECODE_EMULATEX (0x0ff00090, 0x07400010, PROBES_MUL_ADD_LONG,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
/* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */
/* SMUSD cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */
DECODE_OR (0x0ff0f090, 0x0700f010),
/* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */
DECODE_OR (0x0ff0f0d0, 0x0750f010),
/* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */
DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, PROBES_MUL_ADD,
REGS(NOPC, 0, NOPC, 0, NOPC)),
/* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */
/* SMLSD cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */
DECODE_OR (0x0ff00090, 0x07000010),
/* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */
DECODE_OR (0x0ff000d0, 0x07500010),
/* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */
DECODE_EMULATEX (0x0ff000f0, 0x07800010, PROBES_MUL_ADD,
REGS(NOPC, NOPCX, NOPC, 0, NOPC)),
/* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */
DECODE_EMULATEX (0x0ff000d0, 0x075000d0, PROBES_MUL_ADD,
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
/* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */
/* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */
DECODE_EMULATEX (0x0fa00070, 0x07a00050, PROBES_BITFIELD,
REGS(0, NOPC, 0, 0, NOPC)),
/* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */
DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, PROBES_BITFIELD,
REGS(0, NOPC, 0, 0, 0)),
/* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */
DECODE_EMULATEX (0x0fe00070, 0x07c00010, PROBES_BITFIELD,
REGS(0, NOPC, 0, 0, NOPCX)),
DECODE_END
};
static const union decode_item arm_cccc_01xx_table[] = {
/* Load/store word and unsigned byte */
/* LDRB/STRB pc,[...] cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0x0c40f000, 0x0440f000),
/* STRT cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */
/* LDRT cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */
/* STRBT cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */
/* LDRBT cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0x0d200000, 0x04200000),
/* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */
/* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0e100000, 0x04000000, PROBES_STORE,
REGS(NOPCWB, ANY, 0, 0, 0)),
/* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */
/* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0e100000, 0x04100000, PROBES_LOAD,
REGS(NOPCWB, ANY, 0, 0, 0)),
/* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */
/* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0e100000, 0x06000000, PROBES_STORE,
REGS(NOPCWB, ANY, 0, 0, NOPC)),
/* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */
/* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0e100000, 0x06100000, PROBES_LOAD,
REGS(NOPCWB, ANY, 0, 0, NOPC)),
DECODE_END
};
static const union decode_item arm_cccc_100x_table[] = {
/* Block data transfer instructions */
/* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
/* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */
DECODE_CUSTOM (0x0e400000, 0x08000000, PROBES_LDMSTM),
/* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
/* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */
/* LDM (exception ret) cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */
DECODE_END
};
const union decode_item probes_decode_arm_table[] = {
/*
* Unconditional instructions
* 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xf0000000, 0xf0000000, arm_1111_table),
/*
* Miscellaneous instructions
* cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx
*/
DECODE_TABLE (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table),
/*
* Halfword multiply and multiply-accumulate
* cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx
*/
DECODE_TABLE (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table),
/*
* Multiply and multiply-accumulate
* cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx
*/
DECODE_TABLE (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table),
/*
* Synchronization primitives
* cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx
*/
DECODE_TABLE (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table),
/*
* Extra load/store instructions
* cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx
*/
DECODE_TABLE (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table),
/*
* Data-processing (register)
* cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx
* Data-processing (register-shifted register)
* cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx
*/
DECODE_TABLE (0x0e000000, 0x00000000, arm_cccc_000x_table),
/*
* Data-processing (immediate)
* cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0x0e000000, 0x02000000, arm_cccc_001x_table),
/*
* Media instructions
* cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx
*/
DECODE_TABLE (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table),
DECODE_TABLE (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table),
/*
* Load/store word and unsigned byte
* cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0x0c000000, 0x04000000, arm_cccc_01xx_table),
/*
* Block data transfer instructions
* cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0x0e000000, 0x08000000, arm_cccc_100x_table),
/* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */
/* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */
DECODE_SIMULATE (0x0e000000, 0x0a000000, PROBES_BRANCH),
/*
* Supervisor Call, and coprocessor instructions
*/
/* MCRR cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */
/* MRRC cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */
/* LDC cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
/* STC cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
/* CDP cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
/* MCR cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
/* MRC cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
/* SVC cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0x0c000000, 0x0c000000),
DECODE_END
};
#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
EXPORT_SYMBOL_GPL(probes_decode_arm_table);
#endif
static void __kprobes arm_singlestep(probes_opcode_t insn,
struct arch_probes_insn *asi, struct pt_regs *regs)
{
regs->ARM_pc += 4;
asi->insn_handler(insn, asi, regs);
}
/* Return:
* INSN_REJECTED If instruction is one not allowed to kprobe,
* INSN_GOOD If instruction is supported and uses instruction slot,
* INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
*
* For instructions we don't want to kprobe (INSN_REJECTED return result):
* These are generally ones that modify the processor state making
* them "hard" to simulate such as switches processor modes or
* make accesses in alternate modes. Any of these could be simulated
* if the work was put into it, but low return considering they
* should also be very rare.
*/
enum probes_insn __kprobes
arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions)
{
asi->insn_singlestep = arm_singlestep;
asi->insn_check_cc = probes_condition_checks[insn>>28];
return probes_decode_insn(insn, asi, probes_decode_arm_table, false,
emulate, actions);
}

View File

@ -0,0 +1,73 @@
/*
* arch/arm/kernel/probes-arm.h
*
* Copyright 2013 Linaro Ltd.
* Written by: David A. Long
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef _ARM_KERNEL_PROBES_ARM_H
#define _ARM_KERNEL_PROBES_ARM_H
enum probes_arm_action {
PROBES_EMULATE_NONE,
PROBES_SIMULATE_NOP,
PROBES_PRELOAD_IMM,
PROBES_PRELOAD_REG,
PROBES_BRANCH_IMM,
PROBES_BRANCH_REG,
PROBES_MRS,
PROBES_CLZ,
PROBES_SATURATING_ARITHMETIC,
PROBES_MUL1,
PROBES_MUL2,
PROBES_SWP,
PROBES_LDRSTRD,
PROBES_LOAD,
PROBES_STORE,
PROBES_LOAD_EXTRA,
PROBES_STORE_EXTRA,
PROBES_MOV_IP_SP,
PROBES_DATA_PROCESSING_REG,
PROBES_DATA_PROCESSING_IMM,
PROBES_MOV_HALFWORD,
PROBES_SEV,
PROBES_WFE,
PROBES_SATURATE,
PROBES_REV,
PROBES_MMI,
PROBES_PACK,
PROBES_EXTEND,
PROBES_EXTEND_ADD,
PROBES_MUL_ADD_LONG,
PROBES_MUL_ADD,
PROBES_BITFIELD,
PROBES_BRANCH,
PROBES_LDMSTM,
NUM_PROBES_ARM_ACTIONS
};
void __kprobes simulate_bbl(probes_opcode_t opcode,
struct arch_probes_insn *asi, struct pt_regs *regs);
void __kprobes simulate_blx1(probes_opcode_t opcode,
struct arch_probes_insn *asi, struct pt_regs *regs);
void __kprobes simulate_blx2bx(probes_opcode_t opcode,
struct arch_probes_insn *asi, struct pt_regs *regs);
void __kprobes simulate_mrs(probes_opcode_t opcode,
struct arch_probes_insn *asi, struct pt_regs *regs);
void __kprobes simulate_mov_ipsp(probes_opcode_t opcode,
struct arch_probes_insn *asi, struct pt_regs *regs);
extern const union decode_item probes_decode_arm_table[];
enum probes_insn arm_probes_decode_insn(probes_opcode_t,
struct arch_probes_insn *, bool emulate,
const union decode_action *actions);
#endif

View File

@ -0,0 +1,882 @@
/*
* arch/arm/kernel/probes-thumb.c
*
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "probes.h"
#include "probes-thumb.h"
static const union decode_item t32_table_1110_100x_x0xx[] = {
/* Load/store multiple instructions */
/* Rn is PC 1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xfe4f0000, 0xe80f0000),
/* SRS 1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */
/* RFE 1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xffc00000, 0xe8000000),
/* SRS 1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */
/* RFE 1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xffc00000, 0xe9800000),
/* STM Rn, {...pc} 1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */
DECODE_REJECT (0xfe508000, 0xe8008000),
/* LDM Rn, {...lr,pc} 1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */
DECODE_REJECT (0xfe50c000, 0xe810c000),
/* LDM/STM Rn, {...sp} 1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */
DECODE_REJECT (0xfe402000, 0xe8002000),
/* STMIA 1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */
/* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */
/* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */
/* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */
DECODE_CUSTOM (0xfe400000, 0xe8000000, PROBES_T32_LDMSTM),
DECODE_END
};
static const union decode_item t32_table_1110_100x_x1xx[] = {
/* Load/store dual, load/store exclusive, table branch */
/* STRD (immediate) 1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */
/* LDRD (immediate) 1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */
DECODE_OR (0xff600000, 0xe8600000),
/* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */
/* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xff400000, 0xe9400000, PROBES_T32_LDRDSTRD,
REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)),
/* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */
/* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */
DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, PROBES_T32_TABLE_BRANCH,
REGS(NOSP, 0, 0, 0, NOSPPC)),
/* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */
/* LDREX 1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */
/* STREXB 1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */
/* STREXH 1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */
/* STREXD 1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */
/* LDREXB 1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */
/* LDREXH 1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */
/* LDREXD 1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */
/* And unallocated instructions... */
DECODE_END
};
static const union decode_item t32_table_1110_101x[] = {
/* Data-processing (shifted register) */
/* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */
/* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */
DECODE_EMULATEX (0xff700f00, 0xea100f00, PROBES_T32_TST,
REGS(NOSPPC, 0, 0, 0, NOSPPC)),
/* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */
DECODE_OR (0xfff00f00, 0xeb100f00),
/* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */
DECODE_EMULATEX (0xfff00f00, 0xebb00f00, PROBES_T32_TST,
REGS(NOPC, 0, 0, 0, NOSPPC)),
/* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */
/* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xffcf0000, 0xea4f0000, PROBES_T32_MOV,
REGS(0, 0, NOSPPC, 0, NOSPPC)),
/* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */
/* ??? 1110 1010 111x xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xffa00000, 0xeaa00000),
/* ??? 1110 1011 001x xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xffe00000, 0xeb200000),
/* ??? 1110 1011 100x xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xffe00000, 0xeb800000),
/* ??? 1110 1011 111x xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xffe00000, 0xebe00000),
/* ADD/SUB SP, SP, Rm, LSL #0..3 */
/* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */
DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, PROBES_T32_ADDSUB,
REGS(SP, 0, SP, 0, NOSPPC)),
/* ADD/SUB SP, SP, Rm, shift */
/* 1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */
DECODE_REJECT (0xff4f0f00, 0xeb0d0d00),
/* ADD/SUB Rd, SP, Rm, shift */
/* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, PROBES_T32_ADDSUB,
REGS(SP, 0, NOPC, 0, NOSPPC)),
/* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */
/* BIC 1110 1010 001x xxxx xxxx xxxx xxxx xxxx */
/* ORR 1110 1010 010x xxxx xxxx xxxx xxxx xxxx */
/* ORN 1110 1010 011x xxxx xxxx xxxx xxxx xxxx */
/* EOR 1110 1010 100x xxxx xxxx xxxx xxxx xxxx */
/* PKH 1110 1010 110x xxxx xxxx xxxx xxxx xxxx */
/* ADD 1110 1011 000x xxxx xxxx xxxx xxxx xxxx */
/* ADC 1110 1011 010x xxxx xxxx xxxx xxxx xxxx */
/* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */
/* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */
/* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfe000000, 0xea000000, PROBES_T32_LOGICAL,
REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)),
DECODE_END
};
static const union decode_item t32_table_1111_0x0x___0[] = {
/* Data-processing (modified immediate) */
/* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */
/* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */
DECODE_EMULATEX (0xfb708f00, 0xf0100f00, PROBES_T32_TST,
REGS(NOSPPC, 0, 0, 0, 0)),
/* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */
DECODE_OR (0xfbf08f00, 0xf1100f00),
/* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */
DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, PROBES_T32_CMP,
REGS(NOPC, 0, 0, 0, 0)),
/* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */
/* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, PROBES_T32_MOV,
REGS(0, 0, NOSPPC, 0, 0)),
/* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */
DECODE_REJECT (0xfbe08000, 0xf0a00000),
/* ??? 1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */
/* ??? 1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */
DECODE_REJECT (0xfbc08000, 0xf0c00000),
/* ??? 1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */
DECODE_REJECT (0xfbe08000, 0xf1200000),
/* ??? 1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */
DECODE_REJECT (0xfbe08000, 0xf1800000),
/* ??? 1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */
DECODE_REJECT (0xfbe08000, 0xf1e00000),
/* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */
/* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, PROBES_T32_ADDSUB,
REGS(SP, 0, NOPC, 0, 0)),
/* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */
/* BIC 1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */
/* ORR 1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */
/* ORN 1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */
/* EOR 1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */
/* ADD 1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */
/* ADC 1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */
/* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */
/* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */
/* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfa008000, 0xf0000000, PROBES_T32_LOGICAL,
REGS(NOSPPC, 0, NOSPPC, 0, 0)),
DECODE_END
};
static const union decode_item t32_table_1111_0x1x___0[] = {
/* Data-processing (plain binary immediate) */
/* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */
DECODE_OR (0xfbff8000, 0xf20f0000),
/* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfbff8000, 0xf2af0000, PROBES_T32_ADDWSUBW_PC,
REGS(PC, 0, NOSPPC, 0, 0)),
/* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */
DECODE_OR (0xfbff8f00, 0xf20d0d00),
/* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */
DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, PROBES_T32_ADDWSUBW,
REGS(SP, 0, SP, 0, 0)),
/* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */
DECODE_OR (0xfbf08000, 0xf2000000),
/* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfbf08000, 0xf2a00000, PROBES_T32_ADDWSUBW,
REGS(NOPCX, 0, NOSPPC, 0, 0)),
/* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */
/* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfb708000, 0xf2400000, PROBES_T32_MOVW,
REGS(0, 0, NOSPPC, 0, 0)),
/* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */
/* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */
/* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */
/* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfb508000, 0xf3000000, PROBES_T32_SAT,
REGS(NOSPPC, 0, NOSPPC, 0, 0)),
/* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */
/* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfb708000, 0xf3400000, PROBES_T32_BITFIELD,
REGS(NOSPPC, 0, NOSPPC, 0, 0)),
/* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfbff8000, 0xf36f0000, PROBES_T32_BITFIELD,
REGS(0, 0, NOSPPC, 0, 0)),
/* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfbf08000, 0xf3600000, PROBES_T32_BITFIELD,
REGS(NOSPPCX, 0, NOSPPC, 0, 0)),
DECODE_END
};
static const union decode_item t32_table_1111_0xxx___1[] = {
/* Branches and miscellaneous control */
/* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */
DECODE_OR (0xfff0d7ff, 0xf3a08001),
/* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */
DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, PROBES_T32_SEV),
/* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */
/* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */
/* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */
DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, PROBES_T32_WFE),
/* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */
DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, PROBES_T32_MRS,
REGS(0, 0, NOSPPC, 0, 0)),
/*
* Unsupported instructions
* 1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx
*
* MSR 1111 0011 100x xxxx 10x0 xxxx xxxx xxxx
* DBG hint 1111 0011 1010 xxxx 10x0 x000 1111 xxxx
* Unallocated hints 1111 0011 1010 xxxx 10x0 x000 xxxx xxxx
* CPS 1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx
* CLREX/DSB/DMB/ISB 1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx
* BXJ 1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx
* SUBS PC,LR,#<imm8> 1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx
* MRS Rd, SPSR 1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx
* SMC 1111 0111 1111 xxxx 1000 xxxx xxxx xxxx
* UNDEFINED 1111 0111 1111 xxxx 1010 xxxx xxxx xxxx
* ??? 1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx
*/
DECODE_REJECT (0xfb80d000, 0xf3808000),
/* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */
DECODE_CUSTOM (0xf800d000, 0xf0008000, PROBES_T32_BRANCH_COND),
/* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */
DECODE_OR (0xf800d001, 0xf000c000),
/* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */
/* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */
DECODE_SIMULATE (0xf8009000, 0xf0009000, PROBES_T32_BRANCH),
DECODE_END
};
static const union decode_item t32_table_1111_100x_x0x1__1111[] = {
/* Memory hints */
/* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */
/* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */
DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, PROBES_T32_PLDI),
/* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */
DECODE_OR (0xffd0f000, 0xf890f000),
/* PLD{W} (immediate) 1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */
DECODE_OR (0xffd0ff00, 0xf810fc00),
/* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */
DECODE_OR (0xfff0f000, 0xf990f000),
/* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */
DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, PROBES_T32_PLDI,
REGS(NOPCX, 0, 0, 0, 0)),
/* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */
DECODE_OR (0xffd0ffc0, 0xf810f000),
/* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */
DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, PROBES_T32_PLDI,
REGS(NOPCX, 0, 0, 0, NOSPPC)),
/* Other unallocated instructions... */
DECODE_END
};
static const union decode_item t32_table_1111_100x[] = {
/* Store/Load single data item */
/* ??? 1111 100x x11x xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xfe600000, 0xf8600000),
/* ??? 1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xfff00000, 0xf9500000),
/* ??? 1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */
DECODE_REJECT (0xfe800d00, 0xf8000800),
/* STRBT 1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */
/* STRHT 1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */
/* STRT 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */
/* LDRBT 1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */
/* LDRSBT 1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */
/* LDRHT 1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */
/* LDRSHT 1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */
/* LDRT 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */
DECODE_REJECT (0xfe800f00, 0xf8000e00),
/* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xff1f0000, 0xf80f0000),
/* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */
DECODE_REJECT (0xff10f000, 0xf800f000),
/* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */
DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, PROBES_T32_LDR_LIT,
REGS(PC, ANY, 0, 0, 0)),
/* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */
/* LDR (immediate) 1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */
DECODE_OR (0xffe00800, 0xf8400800),
/* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */
/* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xffe00000, 0xf8c00000, PROBES_T32_LDRSTR,
REGS(NOPCX, ANY, 0, 0, 0)),
/* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */
/* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */
DECODE_EMULATEX (0xffe00fc0, 0xf8400000, PROBES_T32_LDRSTR,
REGS(NOPCX, ANY, 0, 0, NOSPPC)),
/* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */
/* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */
/* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */
/* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */
DECODE_SIMULATEX(0xfe5f0000, 0xf81f0000, PROBES_T32_LDR_LIT,
REGS(PC, NOSPPCX, 0, 0, 0)),
/* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */
/* STRH (immediate) 1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */
/* LDRB (immediate) 1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */
/* LDRSB (immediate) 1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */
/* LDRH (immediate) 1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */
/* LDRSH (immediate) 1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */
DECODE_OR (0xfec00800, 0xf8000800),
/* STRB (immediate) 1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */
/* STRH (immediate) 1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */
/* LDRB (immediate) 1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */
/* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */
/* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */
/* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfec00000, 0xf8800000, PROBES_T32_LDRSTR,
REGS(NOPCX, NOSPPCX, 0, 0, 0)),
/* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */
/* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */
/* LDRB (register) 1111 1000 0001 xxxx xxxx 0000 00xx xxxx */
/* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */
/* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */
/* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */
DECODE_EMULATEX (0xfe800fc0, 0xf8000000, PROBES_T32_LDRSTR,
REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)),
/* Other unallocated instructions... */
DECODE_END
};
static const union decode_item t32_table_1111_1010___1111[] = {
/* Data-processing (register) */
/* ??? 1111 1010 011x xxxx 1111 xxxx 1xxx xxxx */
DECODE_REJECT (0xffe0f080, 0xfa60f080),
/* SXTH 1111 1010 0000 1111 1111 xxxx 1xxx xxxx */
/* UXTH 1111 1010 0001 1111 1111 xxxx 1xxx xxxx */
/* SXTB16 1111 1010 0010 1111 1111 xxxx 1xxx xxxx */
/* UXTB16 1111 1010 0011 1111 1111 xxxx 1xxx xxxx */
/* SXTB 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */
/* UXTB 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */
DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, PROBES_T32_SIGN_EXTEND,
REGS(0, 0, NOSPPC, 0, NOSPPC)),
/* ??? 1111 1010 1xxx xxxx 1111 xxxx 0x11 xxxx */
DECODE_REJECT (0xff80f0b0, 0xfa80f030),
/* ??? 1111 1010 1x11 xxxx 1111 xxxx 0xxx xxxx */
DECODE_REJECT (0xffb0f080, 0xfab0f000),
/* SADD16 1111 1010 1001 xxxx 1111 xxxx 0000 xxxx */
/* SASX 1111 1010 1010 xxxx 1111 xxxx 0000 xxxx */
/* SSAX 1111 1010 1110 xxxx 1111 xxxx 0000 xxxx */
/* SSUB16 1111 1010 1101 xxxx 1111 xxxx 0000 xxxx */
/* SADD8 1111 1010 1000 xxxx 1111 xxxx 0000 xxxx */
/* SSUB8 1111 1010 1100 xxxx 1111 xxxx 0000 xxxx */
/* QADD16 1111 1010 1001 xxxx 1111 xxxx 0001 xxxx */
/* QASX 1111 1010 1010 xxxx 1111 xxxx 0001 xxxx */
/* QSAX 1111 1010 1110 xxxx 1111 xxxx 0001 xxxx */
/* QSUB16 1111 1010 1101 xxxx 1111 xxxx 0001 xxxx */
/* QADD8 1111 1010 1000 xxxx 1111 xxxx 0001 xxxx */
/* QSUB8 1111 1010 1100 xxxx 1111 xxxx 0001 xxxx */
/* SHADD16 1111 1010 1001 xxxx 1111 xxxx 0010 xxxx */
/* SHASX 1111 1010 1010 xxxx 1111 xxxx 0010 xxxx */
/* SHSAX 1111 1010 1110 xxxx 1111 xxxx 0010 xxxx */
/* SHSUB16 1111 1010 1101 xxxx 1111 xxxx 0010 xxxx */
/* SHADD8 1111 1010 1000 xxxx 1111 xxxx 0010 xxxx */
/* SHSUB8 1111 1010 1100 xxxx 1111 xxxx 0010 xxxx */
/* UADD16 1111 1010 1001 xxxx 1111 xxxx 0100 xxxx */
/* UASX 1111 1010 1010 xxxx 1111 xxxx 0100 xxxx */
/* USAX 1111 1010 1110 xxxx 1111 xxxx 0100 xxxx */
/* USUB16 1111 1010 1101 xxxx 1111 xxxx 0100 xxxx */
/* UADD8 1111 1010 1000 xxxx 1111 xxxx 0100 xxxx */
/* USUB8 1111 1010 1100 xxxx 1111 xxxx 0100 xxxx */
/* UQADD16 1111 1010 1001 xxxx 1111 xxxx 0101 xxxx */
/* UQASX 1111 1010 1010 xxxx 1111 xxxx 0101 xxxx */
/* UQSAX 1111 1010 1110 xxxx 1111 xxxx 0101 xxxx */
/* UQSUB16 1111 1010 1101 xxxx 1111 xxxx 0101 xxxx */
/* UQADD8 1111 1010 1000 xxxx 1111 xxxx 0101 xxxx */
/* UQSUB8 1111 1010 1100 xxxx 1111 xxxx 0101 xxxx */
/* UHADD16 1111 1010 1001 xxxx 1111 xxxx 0110 xxxx */
/* UHASX 1111 1010 1010 xxxx 1111 xxxx 0110 xxxx */
/* UHSAX 1111 1010 1110 xxxx 1111 xxxx 0110 xxxx */
/* UHSUB16 1111 1010 1101 xxxx 1111 xxxx 0110 xxxx */
/* UHADD8 1111 1010 1000 xxxx 1111 xxxx 0110 xxxx */
/* UHSUB8 1111 1010 1100 xxxx 1111 xxxx 0110 xxxx */
DECODE_OR (0xff80f080, 0xfa80f000),
/* SXTAH 1111 1010 0000 xxxx 1111 xxxx 1xxx xxxx */
/* UXTAH 1111 1010 0001 xxxx 1111 xxxx 1xxx xxxx */
/* SXTAB16 1111 1010 0010 xxxx 1111 xxxx 1xxx xxxx */
/* UXTAB16 1111 1010 0011 xxxx 1111 xxxx 1xxx xxxx */
/* SXTAB 1111 1010 0100 xxxx 1111 xxxx 1xxx xxxx */
/* UXTAB 1111 1010 0101 xxxx 1111 xxxx 1xxx xxxx */
DECODE_OR (0xff80f080, 0xfa00f080),
/* QADD 1111 1010 1000 xxxx 1111 xxxx 1000 xxxx */
/* QDADD 1111 1010 1000 xxxx 1111 xxxx 1001 xxxx */
/* QSUB 1111 1010 1000 xxxx 1111 xxxx 1010 xxxx */
/* QDSUB 1111 1010 1000 xxxx 1111 xxxx 1011 xxxx */
DECODE_OR (0xfff0f0c0, 0xfa80f080),
/* SEL 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */
DECODE_OR (0xfff0f0f0, 0xfaa0f080),
/* LSL 1111 1010 000x xxxx 1111 xxxx 0000 xxxx */
/* LSR 1111 1010 001x xxxx 1111 xxxx 0000 xxxx */
/* ASR 1111 1010 010x xxxx 1111 xxxx 0000 xxxx */
/* ROR 1111 1010 011x xxxx 1111 xxxx 0000 xxxx */
DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, PROBES_T32_MEDIA,
REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)),
/* CLZ 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */
DECODE_OR (0xfff0f0f0, 0xfab0f080),
/* REV 1111 1010 1001 xxxx 1111 xxxx 1000 xxxx */
/* REV16 1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */
/* RBIT 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */
/* REVSH 1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */
DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, PROBES_T32_REVERSE,
REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)),
/* Other unallocated instructions... */
DECODE_END
};
static const union decode_item t32_table_1111_1011_0[] = {
/* Multiply, multiply accumulate, and absolute difference */
/* ??? 1111 1011 0000 xxxx 1111 xxxx 0001 xxxx */
DECODE_REJECT (0xfff0f0f0, 0xfb00f010),
/* ??? 1111 1011 0111 xxxx 1111 xxxx 0001 xxxx */
DECODE_REJECT (0xfff0f0f0, 0xfb70f010),
/* SMULxy 1111 1011 0001 xxxx 1111 xxxx 00xx xxxx */
DECODE_OR (0xfff0f0c0, 0xfb10f000),
/* MUL 1111 1011 0000 xxxx 1111 xxxx 0000 xxxx */
/* SMUAD{X} 1111 1011 0010 xxxx 1111 xxxx 000x xxxx */
/* SMULWy 1111 1011 0011 xxxx 1111 xxxx 000x xxxx */
/* SMUSD{X} 1111 1011 0100 xxxx 1111 xxxx 000x xxxx */
/* SMMUL{R} 1111 1011 0101 xxxx 1111 xxxx 000x xxxx */
/* USAD8 1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */
DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, PROBES_T32_MUL_ADD,
REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)),
/* ??? 1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */
DECODE_REJECT (0xfff000f0, 0xfb700010),
/* SMLAxy 1111 1011 0001 xxxx xxxx xxxx 00xx xxxx */
DECODE_OR (0xfff000c0, 0xfb100000),
/* MLA 1111 1011 0000 xxxx xxxx xxxx 0000 xxxx */
/* MLS 1111 1011 0000 xxxx xxxx xxxx 0001 xxxx */
/* SMLAD{X} 1111 1011 0010 xxxx xxxx xxxx 000x xxxx */
/* SMLAWy 1111 1011 0011 xxxx xxxx xxxx 000x xxxx */
/* SMLSD{X} 1111 1011 0100 xxxx xxxx xxxx 000x xxxx */
/* SMMLA{R} 1111 1011 0101 xxxx xxxx xxxx 000x xxxx */
/* SMMLS{R} 1111 1011 0110 xxxx xxxx xxxx 000x xxxx */
/* USADA8 1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */
DECODE_EMULATEX (0xff8000c0, 0xfb000000, PROBES_T32_MUL_ADD2,
REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)),
/* Other unallocated instructions... */
DECODE_END
};
static const union decode_item t32_table_1111_1011_1[] = {
/* Long multiply, long multiply accumulate, and divide */
/* UMAAL 1111 1011 1110 xxxx xxxx xxxx 0110 xxxx */
DECODE_OR (0xfff000f0, 0xfbe00060),
/* SMLALxy 1111 1011 1100 xxxx xxxx xxxx 10xx xxxx */
DECODE_OR (0xfff000c0, 0xfbc00080),
/* SMLALD{X} 1111 1011 1100 xxxx xxxx xxxx 110x xxxx */
/* SMLSLD{X} 1111 1011 1101 xxxx xxxx xxxx 110x xxxx */
DECODE_OR (0xffe000e0, 0xfbc000c0),
/* SMULL 1111 1011 1000 xxxx xxxx xxxx 0000 xxxx */
/* UMULL 1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */
/* SMLAL 1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */
/* UMLAL 1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */
DECODE_EMULATEX (0xff9000f0, 0xfb800000, PROBES_T32_MUL_ADD_LONG,
REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)),
/* SDIV 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */
/* UDIV 1111 1011 1011 xxxx xxxx xxxx 1111 xxxx */
/* Other unallocated instructions... */
DECODE_END
};
const union decode_item probes_decode_thumb32_table[] = {
/*
* Load/store multiple instructions
* 1110 100x x0xx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx),
/*
* Load/store dual, load/store exclusive, table branch
* 1110 100x x1xx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx),
/*
* Data-processing (shifted register)
* 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xfe000000, 0xea000000, t32_table_1110_101x),
/*
* Coprocessor instructions
* 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_REJECT (0xfc000000, 0xec000000),
/*
* Data-processing (modified immediate)
* 1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0),
/*
* Data-processing (plain binary immediate)
* 1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0),
/*
* Branches and miscellaneous control
* 1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1),
/*
* Advanced SIMD element or structure load/store instructions
* 1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx
*/
DECODE_REJECT (0xff100000, 0xf9000000),
/*
* Memory hints
* 1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx
*/
DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111),
/*
* Store single data item
* 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx
* Load single data items
* 1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xfe000000, 0xf8000000, t32_table_1111_100x),
/*
* Data-processing (register)
* 1111 1010 xxxx xxxx 1111 xxxx xxxx xxxx
*/
DECODE_TABLE (0xff00f000, 0xfa00f000, t32_table_1111_1010___1111),
/*
* Multiply, multiply accumulate, and absolute difference
* 1111 1011 0xxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xff800000, 0xfb000000, t32_table_1111_1011_0),
/*
* Long multiply, long multiply accumulate, and divide
* 1111 1011 1xxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xff800000, 0xfb800000, t32_table_1111_1011_1),
/*
* Coprocessor instructions
* 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx
*/
DECODE_END
};
#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
EXPORT_SYMBOL_GPL(probes_decode_thumb32_table);
#endif
static const union decode_item t16_table_1011[] = {
/* Miscellaneous 16-bit instructions */
/* ADD (SP plus immediate) 1011 0000 0xxx xxxx */
/* SUB (SP minus immediate) 1011 0000 1xxx xxxx */
DECODE_SIMULATE (0xff00, 0xb000, PROBES_T16_ADD_SP),
/* CBZ 1011 00x1 xxxx xxxx */
/* CBNZ 1011 10x1 xxxx xxxx */
DECODE_SIMULATE (0xf500, 0xb100, PROBES_T16_CBZ),
/* SXTH 1011 0010 00xx xxxx */
/* SXTB 1011 0010 01xx xxxx */
/* UXTH 1011 0010 10xx xxxx */
/* UXTB 1011 0010 11xx xxxx */
/* REV 1011 1010 00xx xxxx */
/* REV16 1011 1010 01xx xxxx */
/* ??? 1011 1010 10xx xxxx */
/* REVSH 1011 1010 11xx xxxx */
DECODE_REJECT (0xffc0, 0xba80),
DECODE_EMULATE (0xf500, 0xb000, PROBES_T16_SIGN_EXTEND),
/* PUSH 1011 010x xxxx xxxx */
DECODE_CUSTOM (0xfe00, 0xb400, PROBES_T16_PUSH),
/* POP 1011 110x xxxx xxxx */
DECODE_CUSTOM (0xfe00, 0xbc00, PROBES_T16_POP),
/*
* If-Then, and hints
* 1011 1111 xxxx xxxx
*/
/* YIELD 1011 1111 0001 0000 */
DECODE_OR (0xffff, 0xbf10),
/* SEV 1011 1111 0100 0000 */
DECODE_EMULATE (0xffff, 0xbf40, PROBES_T16_SEV),
/* NOP 1011 1111 0000 0000 */
/* WFE 1011 1111 0010 0000 */
/* WFI 1011 1111 0011 0000 */
DECODE_SIMULATE (0xffcf, 0xbf00, PROBES_T16_WFE),
/* Unassigned hints 1011 1111 xxxx 0000 */
DECODE_REJECT (0xff0f, 0xbf00),
/* IT 1011 1111 xxxx xxxx */
DECODE_CUSTOM (0xff00, 0xbf00, PROBES_T16_IT),
/* SETEND 1011 0110 010x xxxx */
/* CPS 1011 0110 011x xxxx */
/* BKPT 1011 1110 xxxx xxxx */
/* And unallocated instructions... */
DECODE_END
};
const union decode_item probes_decode_thumb16_table[] = {
/*
* Shift (immediate), add, subtract, move, and compare
* 00xx xxxx xxxx xxxx
*/
/* CMP (immediate) 0010 1xxx xxxx xxxx */
DECODE_EMULATE (0xf800, 0x2800, PROBES_T16_CMP),
/* ADD (register) 0001 100x xxxx xxxx */
/* SUB (register) 0001 101x xxxx xxxx */
/* LSL (immediate) 0000 0xxx xxxx xxxx */
/* LSR (immediate) 0000 1xxx xxxx xxxx */
/* ASR (immediate) 0001 0xxx xxxx xxxx */
/* ADD (immediate, Thumb) 0001 110x xxxx xxxx */
/* SUB (immediate, Thumb) 0001 111x xxxx xxxx */
/* MOV (immediate) 0010 0xxx xxxx xxxx */
/* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */
/* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */
DECODE_EMULATE (0xc000, 0x0000, PROBES_T16_ADDSUB),
/*
* 16-bit Thumb data-processing instructions
* 0100 00xx xxxx xxxx
*/
/* TST (register) 0100 0010 00xx xxxx */
DECODE_EMULATE (0xffc0, 0x4200, PROBES_T16_CMP),
/* CMP (register) 0100 0010 10xx xxxx */
/* CMN (register) 0100 0010 11xx xxxx */
DECODE_EMULATE (0xff80, 0x4280, PROBES_T16_CMP),
/* AND (register) 0100 0000 00xx xxxx */
/* EOR (register) 0100 0000 01xx xxxx */
/* LSL (register) 0100 0000 10xx xxxx */
/* LSR (register) 0100 0000 11xx xxxx */
/* ASR (register) 0100 0001 00xx xxxx */
/* ADC (register) 0100 0001 01xx xxxx */
/* SBC (register) 0100 0001 10xx xxxx */
/* ROR (register) 0100 0001 11xx xxxx */
/* RSB (immediate) 0100 0010 01xx xxxx */
/* ORR (register) 0100 0011 00xx xxxx */
/* MUL 0100 0011 00xx xxxx */
/* BIC (register) 0100 0011 10xx xxxx */
/* MVN (register) 0100 0011 10xx xxxx */
DECODE_EMULATE (0xfc00, 0x4000, PROBES_T16_LOGICAL),
/*
* Special data instructions and branch and exchange
* 0100 01xx xxxx xxxx
*/
/* BLX pc 0100 0111 1111 1xxx */
DECODE_REJECT (0xfff8, 0x47f8),
/* BX (register) 0100 0111 0xxx xxxx */
/* BLX (register) 0100 0111 1xxx xxxx */
DECODE_SIMULATE (0xff00, 0x4700, PROBES_T16_BLX),
/* ADD pc, pc 0100 0100 1111 1111 */
DECODE_REJECT (0xffff, 0x44ff),
/* ADD (register) 0100 0100 xxxx xxxx */
/* CMP (register) 0100 0101 xxxx xxxx */
/* MOV (register) 0100 0110 xxxx xxxx */
DECODE_CUSTOM (0xfc00, 0x4400, PROBES_T16_HIREGOPS),
/*
* Load from Literal Pool
* LDR (literal) 0100 1xxx xxxx xxxx
*/
DECODE_SIMULATE (0xf800, 0x4800, PROBES_T16_LDR_LIT),
/*
* 16-bit Thumb Load/store instructions
* 0101 xxxx xxxx xxxx
* 011x xxxx xxxx xxxx
* 100x xxxx xxxx xxxx
*/
/* STR (register) 0101 000x xxxx xxxx */
/* STRH (register) 0101 001x xxxx xxxx */
/* STRB (register) 0101 010x xxxx xxxx */
/* LDRSB (register) 0101 011x xxxx xxxx */
/* LDR (register) 0101 100x xxxx xxxx */
/* LDRH (register) 0101 101x xxxx xxxx */
/* LDRB (register) 0101 110x xxxx xxxx */
/* LDRSH (register) 0101 111x xxxx xxxx */
/* STR (immediate, Thumb) 0110 0xxx xxxx xxxx */
/* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */
/* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */
/* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */
DECODE_EMULATE (0xc000, 0x4000, PROBES_T16_LDRHSTRH),
/* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */
/* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */
DECODE_EMULATE (0xf000, 0x8000, PROBES_T16_LDRHSTRH),
/* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */
/* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */
DECODE_SIMULATE (0xf000, 0x9000, PROBES_T16_LDRSTR),
/*
* Generate PC-/SP-relative address
* ADR (literal) 1010 0xxx xxxx xxxx
* ADD (SP plus immediate) 1010 1xxx xxxx xxxx
*/
DECODE_SIMULATE (0xf000, 0xa000, PROBES_T16_ADR),
/*
* Miscellaneous 16-bit instructions
* 1011 xxxx xxxx xxxx
*/
DECODE_TABLE (0xf000, 0xb000, t16_table_1011),
/* STM 1100 0xxx xxxx xxxx */
/* LDM 1100 1xxx xxxx xxxx */
DECODE_EMULATE (0xf000, 0xc000, PROBES_T16_LDMSTM),
/*
* Conditional branch, and Supervisor Call
*/
/* Permanently UNDEFINED 1101 1110 xxxx xxxx */
/* SVC 1101 1111 xxxx xxxx */
DECODE_REJECT (0xfe00, 0xde00),
/* Conditional branch 1101 xxxx xxxx xxxx */
DECODE_CUSTOM (0xf000, 0xd000, PROBES_T16_BRANCH_COND),
/*
* Unconditional branch
* B 1110 0xxx xxxx xxxx
*/
DECODE_SIMULATE (0xf800, 0xe000, PROBES_T16_BRANCH),
DECODE_END
};
#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
EXPORT_SYMBOL_GPL(probes_decode_thumb16_table);
#endif
static unsigned long __kprobes thumb_check_cc(unsigned long cpsr)
{
if (unlikely(in_it_block(cpsr)))
return probes_condition_checks[current_cond(cpsr)](cpsr);
return true;
}
static void __kprobes thumb16_singlestep(probes_opcode_t opcode,
struct arch_probes_insn *asi,
struct pt_regs *regs)
{
regs->ARM_pc += 2;
asi->insn_handler(opcode, asi, regs);
regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
}
static void __kprobes thumb32_singlestep(probes_opcode_t opcode,
struct arch_probes_insn *asi,
struct pt_regs *regs)
{
regs->ARM_pc += 4;
asi->insn_handler(opcode, asi, regs);
regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
}
enum probes_insn __kprobes
thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions)
{
asi->insn_singlestep = thumb16_singlestep;
asi->insn_check_cc = thumb_check_cc;
return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true,
emulate, actions);
}
enum probes_insn __kprobes
thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions)
{
asi->insn_singlestep = thumb32_singlestep;
asi->insn_check_cc = thumb_check_cc;
return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true,
emulate, actions);
}

View File

@ -0,0 +1,97 @@
/*
* arch/arm/kernel/probes-thumb.h
*
* Copyright 2013 Linaro Ltd.
* Written by: David A. Long
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef _ARM_KERNEL_PROBES_THUMB_H
#define _ARM_KERNEL_PROBES_THUMB_H
/*
* True if current instruction is in an IT block.
*/
#define in_it_block(cpsr) ((cpsr & 0x06000c00) != 0x00000000)
/*
* Return the condition code to check for the currently executing instruction.
* This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if
* in_it_block returns true.
*/
#define current_cond(cpsr) ((cpsr >> 12) & 0xf)
enum probes_t32_action {
PROBES_T32_EMULATE_NONE,
PROBES_T32_SIMULATE_NOP,
PROBES_T32_LDMSTM,
PROBES_T32_LDRDSTRD,
PROBES_T32_TABLE_BRANCH,
PROBES_T32_TST,
PROBES_T32_CMP,
PROBES_T32_MOV,
PROBES_T32_ADDSUB,
PROBES_T32_LOGICAL,
PROBES_T32_ADDWSUBW_PC,
PROBES_T32_ADDWSUBW,
PROBES_T32_MOVW,
PROBES_T32_SAT,
PROBES_T32_BITFIELD,
PROBES_T32_SEV,
PROBES_T32_WFE,
PROBES_T32_MRS,
PROBES_T32_BRANCH_COND,
PROBES_T32_BRANCH,
PROBES_T32_PLDI,
PROBES_T32_LDR_LIT,
PROBES_T32_LDRSTR,
PROBES_T32_SIGN_EXTEND,
PROBES_T32_MEDIA,
PROBES_T32_REVERSE,
PROBES_T32_MUL_ADD,
PROBES_T32_MUL_ADD2,
PROBES_T32_MUL_ADD_LONG,
NUM_PROBES_T32_ACTIONS
};
enum probes_t16_action {
PROBES_T16_ADD_SP,
PROBES_T16_CBZ,
PROBES_T16_SIGN_EXTEND,
PROBES_T16_PUSH,
PROBES_T16_POP,
PROBES_T16_SEV,
PROBES_T16_WFE,
PROBES_T16_IT,
PROBES_T16_CMP,
PROBES_T16_ADDSUB,
PROBES_T16_LOGICAL,
PROBES_T16_BLX,
PROBES_T16_HIREGOPS,
PROBES_T16_LDR_LIT,
PROBES_T16_LDRHSTRH,
PROBES_T16_LDRSTR,
PROBES_T16_ADR,
PROBES_T16_LDMSTM,
PROBES_T16_BRANCH_COND,
PROBES_T16_BRANCH,
NUM_PROBES_T16_ACTIONS
};
extern const union decode_item probes_decode_thumb32_table[];
extern const union decode_item probes_decode_thumb16_table[];
enum probes_insn __kprobes
thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions);
enum probes_insn __kprobes
thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions);
#endif

455
arch/arm/kernel/probes.c Normal file
View File

@ -0,0 +1,455 @@
/*
* arch/arm/kernel/probes.c
*
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
*
* Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
* Copyright (C) 2006, 2007 Motorola Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/system_info.h>
#include <asm/ptrace.h>
#include <linux/bug.h>
#include "probes.h"
#ifndef find_str_pc_offset
/*
* For STR and STM instructions, an ARM core may choose to use either
* a +8 or a +12 displacement from the current instruction's address.
* Whichever value is chosen for a given core, it must be the same for
* both instructions and may not change. This function measures it.
*/
int str_pc_offset;
void __init find_str_pc_offset(void)
{
int addr, scratch, ret;
__asm__ (
"sub %[ret], pc, #4 \n\t"
"str pc, %[addr] \n\t"
"ldr %[scr], %[addr] \n\t"
"sub %[ret], %[scr], %[ret] \n\t"
: [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr));
str_pc_offset = ret;
}
#endif /* !find_str_pc_offset */
#ifndef test_load_write_pc_interworking
bool load_write_pc_interworks;
void __init test_load_write_pc_interworking(void)
{
int arch = cpu_architecture();
BUG_ON(arch == CPU_ARCH_UNKNOWN);
load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T;
}
#endif /* !test_load_write_pc_interworking */
#ifndef test_alu_write_pc_interworking
bool alu_write_pc_interworks;
void __init test_alu_write_pc_interworking(void)
{
int arch = cpu_architecture();
BUG_ON(arch == CPU_ARCH_UNKNOWN);
alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7;
}
#endif /* !test_alu_write_pc_interworking */
void __init arm_probes_decode_init(void)
{
find_str_pc_offset();
test_load_write_pc_interworking();
test_alu_write_pc_interworking();
}
static unsigned long __kprobes __check_eq(unsigned long cpsr)
{
return cpsr & PSR_Z_BIT;
}
static unsigned long __kprobes __check_ne(unsigned long cpsr)
{
return (~cpsr) & PSR_Z_BIT;
}
static unsigned long __kprobes __check_cs(unsigned long cpsr)
{
return cpsr & PSR_C_BIT;
}
static unsigned long __kprobes __check_cc(unsigned long cpsr)
{
return (~cpsr) & PSR_C_BIT;
}
static unsigned long __kprobes __check_mi(unsigned long cpsr)
{
return cpsr & PSR_N_BIT;
}
static unsigned long __kprobes __check_pl(unsigned long cpsr)
{
return (~cpsr) & PSR_N_BIT;
}
static unsigned long __kprobes __check_vs(unsigned long cpsr)
{
return cpsr & PSR_V_BIT;
}
static unsigned long __kprobes __check_vc(unsigned long cpsr)
{
return (~cpsr) & PSR_V_BIT;
}
static unsigned long __kprobes __check_hi(unsigned long cpsr)
{
cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
return cpsr & PSR_C_BIT;
}
static unsigned long __kprobes __check_ls(unsigned long cpsr)
{
cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
return (~cpsr) & PSR_C_BIT;
}
static unsigned long __kprobes __check_ge(unsigned long cpsr)
{
cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
return (~cpsr) & PSR_N_BIT;
}
static unsigned long __kprobes __check_lt(unsigned long cpsr)
{
cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
return cpsr & PSR_N_BIT;
}
static unsigned long __kprobes __check_gt(unsigned long cpsr)
{
unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
return (~temp) & PSR_N_BIT;
}
static unsigned long __kprobes __check_le(unsigned long cpsr)
{
unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
return temp & PSR_N_BIT;
}
static unsigned long __kprobes __check_al(unsigned long cpsr)
{
return true;
}
probes_check_cc * const probes_condition_checks[16] = {
&__check_eq, &__check_ne, &__check_cs, &__check_cc,
&__check_mi, &__check_pl, &__check_vs, &__check_vc,
&__check_hi, &__check_ls, &__check_ge, &__check_lt,
&__check_gt, &__check_le, &__check_al, &__check_al
};
void __kprobes probes_simulate_nop(probes_opcode_t opcode,
struct arch_probes_insn *asi,
struct pt_regs *regs)
{
}
void __kprobes probes_emulate_none(probes_opcode_t opcode,
struct arch_probes_insn *asi,
struct pt_regs *regs)
{
asi->insn_fn();
}
/*
* Prepare an instruction slot to receive an instruction for emulating.
* This is done by placing a subroutine return after the location where the
* instruction will be placed. We also modify ARM instructions to be
* unconditional as the condition code will already be checked before any
* emulation handler is called.
*/
static probes_opcode_t __kprobes
prepare_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool thumb)
{
#ifdef CONFIG_THUMB2_KERNEL
if (thumb) {
u16 *thumb_insn = (u16 *)asi->insn;
thumb_insn[1] = 0x4770; /* Thumb bx lr */
thumb_insn[2] = 0x4770; /* Thumb bx lr */
return insn;
}
asi->insn[1] = 0xe12fff1e; /* ARM bx lr */
#else
asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */
#endif
/* Make an ARM instruction unconditional */
if (insn < 0xe0000000)
insn = (insn | 0xe0000000) & ~0x10000000;
return insn;
}
/*
* Write a (probably modified) instruction into the slot previously prepared by
* prepare_emulated_insn
*/
static void __kprobes
set_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool thumb)
{
#ifdef CONFIG_THUMB2_KERNEL
if (thumb) {
u16 *ip = (u16 *)asi->insn;
if (is_wide_instruction(insn))
*ip++ = insn >> 16;
*ip++ = insn;
return;
}
#endif
asi->insn[0] = insn;
}
/*
* When we modify the register numbers encoded in an instruction to be emulated,
* the new values come from this define. For ARM and 32-bit Thumb instructions
* this gives...
*
* bit position 16 12 8 4 0
* ---------------+---+---+---+---+---+
* register r2 r0 r1 -- r3
*/
#define INSN_NEW_BITS 0x00020103
/* Each nibble has same value as that at INSN_NEW_BITS bit 16 */
#define INSN_SAMEAS16_BITS 0x22222222
/*
* Validate and modify each of the registers encoded in an instruction.
*
* Each nibble in regs contains a value from enum decode_reg_type. For each
* non-zero value, the corresponding nibble in pinsn is validated and modified
* according to the type.
*/
static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs, bool modify)
{
probes_opcode_t insn = *pinsn;
probes_opcode_t mask = 0xf; /* Start at least significant nibble */
for (; regs != 0; regs >>= 4, mask <<= 4) {
probes_opcode_t new_bits = INSN_NEW_BITS;
switch (regs & 0xf) {
case REG_TYPE_NONE:
/* Nibble not a register, skip to next */
continue;
case REG_TYPE_ANY:
/* Any register is allowed */
break;
case REG_TYPE_SAMEAS16:
/* Replace register with same as at bit position 16 */
new_bits = INSN_SAMEAS16_BITS;
break;
case REG_TYPE_SP:
/* Only allow SP (R13) */
if ((insn ^ 0xdddddddd) & mask)
goto reject;
break;
case REG_TYPE_PC:
/* Only allow PC (R15) */
if ((insn ^ 0xffffffff) & mask)
goto reject;
break;
case REG_TYPE_NOSP:
/* Reject SP (R13) */
if (((insn ^ 0xdddddddd) & mask) == 0)
goto reject;
break;
case REG_TYPE_NOSPPC:
case REG_TYPE_NOSPPCX:
/* Reject SP and PC (R13 and R15) */
if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0)
goto reject;
break;
case REG_TYPE_NOPCWB:
if (!is_writeback(insn))
break; /* No writeback, so any register is OK */
/* fall through... */
case REG_TYPE_NOPC:
case REG_TYPE_NOPCX:
/* Reject PC (R15) */
if (((insn ^ 0xffffffff) & mask) == 0)
goto reject;
break;
}
/* Replace value of nibble with new register number... */
insn &= ~mask;
insn |= new_bits & mask;
}
if (modify)
*pinsn = insn;
return true;
reject:
return false;
}
static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
[DECODE_TYPE_TABLE] = sizeof(struct decode_table),
[DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom),
[DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate),
[DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate),
[DECODE_TYPE_OR] = sizeof(struct decode_or),
[DECODE_TYPE_REJECT] = sizeof(struct decode_reject)
};
/*
* probes_decode_insn operates on data tables in order to decode an ARM
* architecture instruction onto which a kprobe has been placed.
*
* These instruction decoding tables are a concatenation of entries each
* of which consist of one of the following structs:
*
* decode_table
* decode_custom
* decode_simulate
* decode_emulate
* decode_or
* decode_reject
*
* Each of these starts with a struct decode_header which has the following
* fields:
*
* type_regs
* mask
* value
*
* The least significant DECODE_TYPE_BITS of type_regs contains a value
* from enum decode_type, this indicates which of the decode_* structs
* the entry contains. The value DECODE_TYPE_END indicates the end of the
* table.
*
* When the table is parsed, each entry is checked in turn to see if it
* matches the instruction to be decoded using the test:
*
* (insn & mask) == value
*
* If no match is found before the end of the table is reached then decoding
* fails with INSN_REJECTED.
*
* When a match is found, decode_regs() is called to validate and modify each
* of the registers encoded in the instruction; the data it uses to do this
* is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding
* to fail with INSN_REJECTED.
*
* Once the instruction has passed the above tests, further processing
* depends on the type of the table entry's decode struct.
*
*/
int __kprobes
probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
const union decode_item *table, bool thumb,
bool emulate, const union decode_action *actions)
{
const struct decode_header *h = (struct decode_header *)table;
const struct decode_header *next;
bool matched = false;
if (emulate)
insn = prepare_emulated_insn(insn, asi, thumb);
for (;; h = next) {
enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
if (type == DECODE_TYPE_END)
return INSN_REJECTED;
next = (struct decode_header *)
((uintptr_t)h + decode_struct_sizes[type]);
if (!matched && (insn & h->mask.bits) != h->value.bits)
continue;
if (!decode_regs(&insn, regs, emulate))
return INSN_REJECTED;
switch (type) {
case DECODE_TYPE_TABLE: {
struct decode_table *d = (struct decode_table *)h;
next = (struct decode_header *)d->table.table;
break;
}
case DECODE_TYPE_CUSTOM: {
struct decode_custom *d = (struct decode_custom *)h;
return actions[d->decoder.action].decoder(insn, asi, h);
}
case DECODE_TYPE_SIMULATE: {
struct decode_simulate *d = (struct decode_simulate *)h;
asi->insn_handler = actions[d->handler.action].handler;
return INSN_GOOD_NO_SLOT;
}
case DECODE_TYPE_EMULATE: {
struct decode_emulate *d = (struct decode_emulate *)h;
if (!emulate)
return actions[d->handler.action].decoder(insn,
asi, h);
asi->insn_handler = actions[d->handler.action].handler;
set_emulated_insn(insn, asi, thumb);
return INSN_GOOD;
}
case DECODE_TYPE_OR:
matched = true;
break;
case DECODE_TYPE_REJECT:
default:
return INSN_REJECTED;
}
}
}

407
arch/arm/kernel/probes.h Normal file
View File

@ -0,0 +1,407 @@
/*
* arch/arm/kernel/probes.h
*
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
*
* Some contents moved here from arch/arm/include/asm/kprobes.h which is
* Copyright (C) 2006, 2007 Motorola Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef _ARM_KERNEL_PROBES_H
#define _ARM_KERNEL_PROBES_H
#include <linux/types.h>
#include <linux/stddef.h>
#include <asm/probes.h>
void __init arm_probes_decode_init(void);
extern probes_check_cc * const probes_condition_checks[16];
#if __LINUX_ARM_ARCH__ >= 7
/* str_pc_offset is architecturally defined from ARMv7 onwards */
#define str_pc_offset 8
#define find_str_pc_offset()
#else /* __LINUX_ARM_ARCH__ < 7 */
/* We need a run-time check to determine str_pc_offset */
extern int str_pc_offset;
void __init find_str_pc_offset(void);
#endif
/*
* Update ITSTATE after normal execution of an IT block instruction.
*
* The 8 IT state bits are split into two parts in CPSR:
* ITSTATE<1:0> are in CPSR<26:25>
* ITSTATE<7:2> are in CPSR<15:10>
*/
static inline unsigned long it_advance(unsigned long cpsr)
{
if ((cpsr & 0x06000400) == 0) {
/* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
cpsr &= ~PSR_IT_MASK;
} else {
/* We need to shift left ITSTATE<4:0> */
const unsigned long mask = 0x06001c00; /* Mask ITSTATE<4:0> */
unsigned long it = cpsr & mask;
it <<= 1;
it |= it >> (27 - 10); /* Carry ITSTATE<2> to correct place */
it &= mask;
cpsr &= ~mask;
cpsr |= it;
}
return cpsr;
}
static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs)
{
long cpsr = regs->ARM_cpsr;
if (pcv & 0x1) {
cpsr |= PSR_T_BIT;
pcv &= ~0x1;
} else {
cpsr &= ~PSR_T_BIT;
pcv &= ~0x2; /* Avoid UNPREDICTABLE address allignment */
}
regs->ARM_cpsr = cpsr;
regs->ARM_pc = pcv;
}
#if __LINUX_ARM_ARCH__ >= 6
/* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */
#define load_write_pc_interworks true
#define test_load_write_pc_interworking()
#else /* __LINUX_ARM_ARCH__ < 6 */
/* We need run-time testing to determine if load_write_pc() should interwork. */
extern bool load_write_pc_interworks;
void __init test_load_write_pc_interworking(void);
#endif
static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs)
{
if (load_write_pc_interworks)
bx_write_pc(pcv, regs);
else
regs->ARM_pc = pcv;
}
#if __LINUX_ARM_ARCH__ >= 7
#define alu_write_pc_interworks true
#define test_alu_write_pc_interworking()
#elif __LINUX_ARM_ARCH__ <= 5
/* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */
#define alu_write_pc_interworks false
#define test_alu_write_pc_interworking()
#else /* __LINUX_ARM_ARCH__ == 6 */
/* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */
extern bool alu_write_pc_interworks;
void __init test_alu_write_pc_interworking(void);
#endif /* __LINUX_ARM_ARCH__ == 6 */
static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs)
{
if (alu_write_pc_interworks)
bx_write_pc(pcv, regs);
else
regs->ARM_pc = pcv;
}
/*
* Test if load/store instructions writeback the address register.
* if P (bit 24) == 0 or W (bit 21) == 1
*/
#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000)
/*
* The following definitions and macros are used to build instruction
* decoding tables for use by probes_decode_insn.
*
* These tables are a concatenation of entries each of which consist of one of
* the decode_* structs. All of the fields in every type of decode structure
* are of the union type decode_item, therefore the entire decode table can be
* viewed as an array of these and declared like:
*
* static const union decode_item table_name[] = {};
*
* In order to construct each entry in the table, macros are used to
* initialise a number of sequential decode_item values in a layout which
* matches the relevant struct. E.g. DECODE_SIMULATE initialise a struct
* decode_simulate by initialising four decode_item objects like this...
*
* {.bits = _type},
* {.bits = _mask},
* {.bits = _value},
* {.action = _handler},
*
* Initialising a specified member of the union means that the compiler
* will produce a warning if the argument is of an incorrect type.
*
* Below is a list of each of the macros used to initialise entries and a
* description of the action performed when that entry is matched to an
* instruction. A match is found when (instruction & mask) == value.
*
* DECODE_TABLE(mask, value, table)
* Instruction decoding jumps to parsing the new sub-table 'table'.
*
* DECODE_CUSTOM(mask, value, decoder)
* The value of 'decoder' is used as an index into the array of
* action functions, and the retrieved decoder function is invoked
* to complete decoding of the instruction.
*
* DECODE_SIMULATE(mask, value, handler)
* The probes instruction handler is set to the value found by
* indexing into the action array using the value of 'handler'. This
* will be used to simulate the instruction when the probe is hit.
* Decoding returns with INSN_GOOD_NO_SLOT.
*
* DECODE_EMULATE(mask, value, handler)
* The probes instruction handler is set to the value found by
* indexing into the action array using the value of 'handler'. This
* will be used to emulate the instruction when the probe is hit. The
* modified instruction (see below) is placed in the probes instruction
* slot so it may be called by the emulation code. Decoding returns
* with INSN_GOOD.
*
* DECODE_REJECT(mask, value)
* Instruction decoding fails with INSN_REJECTED
*
* DECODE_OR(mask, value)
* This allows the mask/value test of multiple table entries to be
* logically ORed. Once an 'or' entry is matched the decoding action to
* be performed is that of the next entry which isn't an 'or'. E.g.
*
* DECODE_OR (mask1, value1)
* DECODE_OR (mask2, value2)
* DECODE_SIMULATE (mask3, value3, simulation_handler)
*
* This means that if any of the three mask/value pairs match the
* instruction being decoded, then 'simulation_handler' will be used
* for it.
*
* Both the SIMULATE and EMULATE macros have a second form which take an
* additional 'regs' argument.
*
* DECODE_SIMULATEX(mask, value, handler, regs)
* DECODE_EMULATEX (mask, value, handler, regs)
*
* These are used to specify what kind of CPU register is encoded in each of the
* least significant 5 nibbles of the instruction being decoded. The regs value
* is specified using the REGS macro, this takes any of the REG_TYPE_* values
* from enum decode_reg_type as arguments; only the '*' part of the name is
* given. E.g.
*
* REGS(0, ANY, NOPC, 0, ANY)
*
* This indicates an instruction is encoded like:
*
* bits 19..16 ignore
* bits 15..12 any register allowed here
* bits 11.. 8 any register except PC allowed here
* bits 7.. 4 ignore
* bits 3.. 0 any register allowed here
*
* This register specification is checked after a decode table entry is found to
* match an instruction (through the mask/value test). Any invalid register then
* found in the instruction will cause decoding to fail with INSN_REJECTED. In
* the above example this would happen if bits 11..8 of the instruction were
* 1111, indicating R15 or PC.
*
* As well as checking for legal combinations of registers, this data is also
* used to modify the registers encoded in the instructions so that an
* emulation routines can use it. (See decode_regs() and INSN_NEW_BITS.)
*
* Here is a real example which matches ARM instructions of the form
* "AND <Rd>,<Rn>,<Rm>,<shift> <Rs>"
*
* DECODE_EMULATEX (0x0e000090, 0x00000010, PROBES_DATA_PROCESSING_REG,
* REGS(ANY, ANY, NOPC, 0, ANY)),
* ^ ^ ^ ^
* Rn Rd Rs Rm
*
* Decoding the instruction "AND R4, R5, R6, ASL R15" will be rejected because
* Rs == R15
*
* Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the
* instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into
* the kprobes instruction slot. This can then be called later by the handler
* function emulate_rd12rn16rm0rs8_rwflags (a pointer to which is retrieved from
* the indicated slot in the action array), in order to simulate the instruction.
*/
enum decode_type {
DECODE_TYPE_END,
DECODE_TYPE_TABLE,
DECODE_TYPE_CUSTOM,
DECODE_TYPE_SIMULATE,
DECODE_TYPE_EMULATE,
DECODE_TYPE_OR,
DECODE_TYPE_REJECT,
NUM_DECODE_TYPES /* Must be last enum */
};
#define DECODE_TYPE_BITS 4
#define DECODE_TYPE_MASK ((1 << DECODE_TYPE_BITS) - 1)
enum decode_reg_type {
REG_TYPE_NONE = 0, /* Not a register, ignore */
REG_TYPE_ANY, /* Any register allowed */
REG_TYPE_SAMEAS16, /* Register should be same as that at bits 19..16 */
REG_TYPE_SP, /* Register must be SP */
REG_TYPE_PC, /* Register must be PC */
REG_TYPE_NOSP, /* Register must not be SP */
REG_TYPE_NOSPPC, /* Register must not be SP or PC */
REG_TYPE_NOPC, /* Register must not be PC */
REG_TYPE_NOPCWB, /* No PC if load/store write-back flag also set */
/* The following types are used when the encoding for PC indicates
* another instruction form. This distiction only matters for test
* case coverage checks.
*/
REG_TYPE_NOPCX, /* Register must not be PC */
REG_TYPE_NOSPPCX, /* Register must not be SP or PC */
/* Alias to allow '0' arg to be used in REGS macro. */
REG_TYPE_0 = REG_TYPE_NONE
};
#define REGS(r16, r12, r8, r4, r0) \
(((REG_TYPE_##r16) << 16) + \
((REG_TYPE_##r12) << 12) + \
((REG_TYPE_##r8) << 8) + \
((REG_TYPE_##r4) << 4) + \
(REG_TYPE_##r0))
union decode_item {
u32 bits;
const union decode_item *table;
int action;
};
struct decode_header;
typedef enum probes_insn (probes_custom_decode_t)(probes_opcode_t,
struct arch_probes_insn *,
const struct decode_header *);
union decode_action {
probes_insn_handler_t *handler;
probes_custom_decode_t *decoder;
};
#define DECODE_END \
{.bits = DECODE_TYPE_END}
struct decode_header {
union decode_item type_regs;
union decode_item mask;
union decode_item value;
};
#define DECODE_HEADER(_type, _mask, _value, _regs) \
{.bits = (_type) | ((_regs) << DECODE_TYPE_BITS)}, \
{.bits = (_mask)}, \
{.bits = (_value)}
struct decode_table {
struct decode_header header;
union decode_item table;
};
#define DECODE_TABLE(_mask, _value, _table) \
DECODE_HEADER(DECODE_TYPE_TABLE, _mask, _value, 0), \
{.table = (_table)}
struct decode_custom {
struct decode_header header;
union decode_item decoder;
};
#define DECODE_CUSTOM(_mask, _value, _decoder) \
DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \
{.action = (_decoder)}
struct decode_simulate {
struct decode_header header;
union decode_item handler;
};
#define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \
DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \
{.action = (_handler)}
#define DECODE_SIMULATE(_mask, _value, _handler) \
DECODE_SIMULATEX(_mask, _value, _handler, 0)
struct decode_emulate {
struct decode_header header;
union decode_item handler;
};
#define DECODE_EMULATEX(_mask, _value, _handler, _regs) \
DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \
{.action = (_handler)}
#define DECODE_EMULATE(_mask, _value, _handler) \
DECODE_EMULATEX(_mask, _value, _handler, 0)
struct decode_or {
struct decode_header header;
};
#define DECODE_OR(_mask, _value) \
DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0)
enum probes_insn {
INSN_REJECTED,
INSN_GOOD,
INSN_GOOD_NO_SLOT
};
struct decode_reject {
struct decode_header header;
};
#define DECODE_REJECT(_mask, _value) \
DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0)
probes_insn_handler_t probes_simulate_nop;
probes_insn_handler_t probes_emulate_none;
int __kprobes
probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
const union decode_item *table, bool thumb, bool emulate,
const union decode_action *actions);
#endif

Some files were not shown because too many files have changed in this diff Show More