Merge branch 'devel-stable' into for-next
This commit is contained in:
commit
bce5669be3
|
@ -92,3 +92,6 @@ extra_certificates
|
|||
signing_key.priv
|
||||
signing_key.x509
|
||||
x509.genkey
|
||||
|
||||
# Kconfig presets
|
||||
all.config
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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>.
|
||||
|
|
|
@ -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...]
|
||||
};
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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";
|
||||
};
|
|
@ -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>;
|
||||
};
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
--------------------------------------------
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 (保留,将来可能使用)
|
||||
|
|
|
@ -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 中映射的内核对象
|
||||
|
|
|
@ -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” 的扩展符。
|
46
MAINTAINERS
46
MAINTAINERS
|
@ -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
|
||||
|
|
10
Makefile
10
Makefile
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
gpio0 = &gpio0;
|
||||
gpio1 = &gpio1;
|
||||
gpio2 = &gpio2;
|
||||
eth3 = ð3;
|
||||
};
|
||||
|
||||
cpus {
|
||||
|
@ -291,7 +292,7 @@
|
|||
interrupts = <91>;
|
||||
};
|
||||
|
||||
ethernet@34000 {
|
||||
eth3: ethernet@34000 {
|
||||
compatible = "marvell,armada-370-neta";
|
||||
reg = <0x34000 0x4000>;
|
||||
interrupts = <14>;
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
|
|
|
@ -124,6 +124,10 @@
|
|||
nand-on-flash-bbt;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
usb0: ohci@00500000 {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
leds {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -14,5 +14,5 @@
|
|||
|
||||
/ {
|
||||
model = "Nokia N9";
|
||||
compatible = "nokia,omap3-n9", "ti,omap3";
|
||||
compatible = "nokia,omap3-n9", "ti,omap36xx", "ti,omap3";
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -14,5 +14,5 @@
|
|||
|
||||
/ {
|
||||
model = "Nokia N950";
|
||||
compatible = "nokia,omap3-n950", "ti,omap3";
|
||||
compatible = "nokia,omap3-n950", "ti,omap36xx", "ti,omap3";
|
||||
};
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
|
@ -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 {
|
|
@ -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";
|
||||
};
|
||||
|
|
@ -9,9 +9,6 @@
|
|||
/*
|
||||
* The Gumstix Overo must be combined with an expansion board.
|
||||
*/
|
||||
/dts-v1/;
|
||||
|
||||
#include "omap34xx.dtsi"
|
||||
|
||||
/ {
|
||||
pwmleds {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -188,7 +188,6 @@
|
|||
msp2: msp@80117000 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&msp2_default_mode>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
msp3: msp@80125000 {
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
compatible = "nvidia,cardhu", "nvidia,tegra30";
|
||||
|
||||
aliases {
|
||||
rtc0 = "/i2c@7000d000/tps6586x@34";
|
||||
rtc0 = "/i2c@7000d000/tps65911@2d";
|
||||
rtc1 = "/rtc@7000e000";
|
||||
};
|
||||
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
/include/ "tests-phandle.dtsi"
|
||||
/include/ "tests-interrupts.dtsi"
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/system_info.h>
|
||||
|
||||
#include "kprobes-test.h"
|
||||
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue