Merge branch 'kprobes-thumb' of git://git.yxit.co.uk/linux into devel-stable
This commit is contained in:
Коммит
4aa96ccf9e
2
CREDITS
2
CREDITS
|
@ -518,7 +518,7 @@ N: Zach Brown
|
|||
E: zab@zabbo.net
|
||||
D: maestro pci sound
|
||||
|
||||
M: David Brownell
|
||||
N: David Brownell
|
||||
D: Kernel engineer, mentor, and friend. Maintained USB EHCI and
|
||||
D: gadget layers, SPI subsystem, GPIO subsystem, and more than a few
|
||||
D: device drivers. His encouragement also helped many engineers get
|
||||
|
|
|
@ -2,13 +2,7 @@ Intro
|
|||
=====
|
||||
|
||||
This document is designed to provide a list of the minimum levels of
|
||||
software necessary to run the 2.6 kernels, as well as provide brief
|
||||
instructions regarding any other "Gotchas" users may encounter when
|
||||
trying life on the Bleeding Edge. If upgrading from a pre-2.4.x
|
||||
kernel, please consult the Changes file included with 2.4.x kernels for
|
||||
additional information; most of that information will not be repeated
|
||||
here. Basically, this document assumes that your system is already
|
||||
functional and running at least 2.4.x kernels.
|
||||
software necessary to run the 3.0 kernels.
|
||||
|
||||
This document is originally based on my "Changes" file for 2.0.x kernels
|
||||
and therefore owes credit to the same people as that file (Jared Mauch,
|
||||
|
@ -22,11 +16,10 @@ Upgrade to at *least* these software revisions before thinking you've
|
|||
encountered a bug! If you're unsure what version you're currently
|
||||
running, the suggested command should tell you.
|
||||
|
||||
Again, keep in mind that this list assumes you are already
|
||||
functionally running a Linux 2.4 kernel. Also, not all tools are
|
||||
necessary on all systems; obviously, if you don't have any ISDN
|
||||
hardware, for example, you probably needn't concern yourself with
|
||||
isdn4k-utils.
|
||||
Again, keep in mind that this list assumes you are already functionally
|
||||
running a Linux kernel. Also, not all tools are necessary on all
|
||||
systems; obviously, if you don't have any ISDN hardware, for example,
|
||||
you probably needn't concern yourself with isdn4k-utils.
|
||||
|
||||
o Gnu C 3.2 # gcc --version
|
||||
o Gnu make 3.80 # make --version
|
||||
|
@ -114,12 +107,12 @@ Ksymoops
|
|||
|
||||
If the unthinkable happens and your kernel oopses, you may need the
|
||||
ksymoops tool to decode it, but in most cases you don't.
|
||||
In the 2.6 kernel it is generally preferred to build the kernel with
|
||||
CONFIG_KALLSYMS so that it produces readable dumps that can be used as-is
|
||||
(this also produces better output than ksymoops).
|
||||
If for some reason your kernel is not build with CONFIG_KALLSYMS and
|
||||
you have no way to rebuild and reproduce the Oops with that option, then
|
||||
you can still decode that Oops with ksymoops.
|
||||
It is generally preferred to build the kernel with CONFIG_KALLSYMS so
|
||||
that it produces readable dumps that can be used as-is (this also
|
||||
produces better output than ksymoops). If for some reason your kernel
|
||||
is not build with CONFIG_KALLSYMS and you have no way to rebuild and
|
||||
reproduce the Oops with that option, then you can still decode that Oops
|
||||
with ksymoops.
|
||||
|
||||
Module-Init-Tools
|
||||
-----------------
|
||||
|
@ -261,8 +254,8 @@ needs to be recompiled or (preferably) upgraded.
|
|||
NFS-utils
|
||||
---------
|
||||
|
||||
In 2.4 and earlier kernels, the nfs server needed to know about any
|
||||
client that expected to be able to access files via NFS. This
|
||||
In ancient (2.4 and earlier) kernels, the nfs server needed to know
|
||||
about any client that expected to be able to access files via NFS. This
|
||||
information would be given to the kernel by "mountd" when the client
|
||||
mounted the filesystem, or by "exportfs" at system startup. exportfs
|
||||
would take information about active clients from /var/lib/nfs/rmtab.
|
||||
|
@ -272,11 +265,11 @@ which is not always easy, particularly when trying to implement
|
|||
fail-over. Even when the system is working well, rmtab suffers from
|
||||
getting lots of old entries that never get removed.
|
||||
|
||||
With 2.6 we have the option of having the kernel tell mountd when it
|
||||
gets a request from an unknown host, and mountd can give appropriate
|
||||
export information to the kernel. This removes the dependency on
|
||||
rmtab and means that the kernel only needs to know about currently
|
||||
active clients.
|
||||
With modern kernels we have the option of having the kernel tell mountd
|
||||
when it gets a request from an unknown host, and mountd can give
|
||||
appropriate export information to the kernel. This removes the
|
||||
dependency on rmtab and means that the kernel only needs to know about
|
||||
currently active clients.
|
||||
|
||||
To enable this new functionality, you need to:
|
||||
|
||||
|
|
|
@ -680,8 +680,8 @@ ones already enabled by DEBUG.
|
|||
Chapter 14: Allocating memory
|
||||
|
||||
The kernel provides the following general purpose memory allocators:
|
||||
kmalloc(), kzalloc(), kcalloc(), and vmalloc(). Please refer to the API
|
||||
documentation for further information about them.
|
||||
kmalloc(), kzalloc(), kcalloc(), vmalloc(), and vzalloc(). Please refer to
|
||||
the API documentation for further information about them.
|
||||
|
||||
The preferred form for passing a size of a struct is the following:
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ Throttling/Upper Limit policy
|
|||
- Specify a bandwidth rate on particular device for root group. The format
|
||||
for policy is "<major>:<minor> <byes_per_second>".
|
||||
|
||||
echo "8:16 1048576" > /sys/fs/cgroup/blkio/blkio.read_bps_device
|
||||
echo "8:16 1048576" > /sys/fs/cgroup/blkio/blkio.throttle.read_bps_device
|
||||
|
||||
Above will put a limit of 1MB/second on reads happening for root group
|
||||
on device having major/minor number 8:16.
|
||||
|
@ -90,7 +90,7 @@ Throttling/Upper Limit policy
|
|||
1024+0 records out
|
||||
4194304 bytes (4.2 MB) copied, 4.0001 s, 1.0 MB/s
|
||||
|
||||
Limits for writes can be put using blkio.write_bps_device file.
|
||||
Limits for writes can be put using blkio.throttle.write_bps_device file.
|
||||
|
||||
Hierarchical Cgroups
|
||||
====================
|
||||
|
@ -286,28 +286,28 @@ Throttling/Upper limit policy files
|
|||
specified in bytes per second. Rules are per deivce. Following is
|
||||
the format.
|
||||
|
||||
echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.read_bps_device
|
||||
echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.throttle.read_bps_device
|
||||
|
||||
- blkio.throttle.write_bps_device
|
||||
- Specifies upper limit on WRITE rate to the device. IO rate is
|
||||
specified in bytes per second. Rules are per deivce. Following is
|
||||
the format.
|
||||
|
||||
echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.write_bps_device
|
||||
echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.throttle.write_bps_device
|
||||
|
||||
- blkio.throttle.read_iops_device
|
||||
- Specifies upper limit on READ rate from the device. IO rate is
|
||||
specified in IO per second. Rules are per deivce. Following is
|
||||
the format.
|
||||
|
||||
echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.read_iops_device
|
||||
echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.throttle.read_iops_device
|
||||
|
||||
- blkio.throttle.write_iops_device
|
||||
- Specifies upper limit on WRITE rate to the device. IO rate is
|
||||
specified in io per second. Rules are per deivce. Following is
|
||||
the format.
|
||||
|
||||
echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.write_iops_device
|
||||
echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.throttle.write_iops_device
|
||||
|
||||
Note: If both BW and IOPS rules are specified for a device, then IO is
|
||||
subjectd to both the constraints.
|
||||
|
|
|
@ -583,3 +583,25 @@ Why: Superseded by the UVCIOC_CTRL_QUERY ioctl.
|
|||
Who: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
|
||||
----------------------------
|
||||
|
||||
What: For VIDIOC_S_FREQUENCY the type field must match the device node's type.
|
||||
If not, return -EINVAL.
|
||||
When: 3.2
|
||||
Why: It makes no sense to switch the tuner to radio mode by calling
|
||||
VIDIOC_S_FREQUENCY on a video node, or to switch the tuner to tv mode by
|
||||
calling VIDIOC_S_FREQUENCY on a radio node. This is the first step of a
|
||||
move to more consistent handling of tv and radio tuners.
|
||||
Who: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
|
||||
----------------------------
|
||||
|
||||
What: Opening a radio device node will no longer automatically switch the
|
||||
tuner mode from tv to radio.
|
||||
When: 3.3
|
||||
Why: Just opening a V4L device should not change the state of the hardware
|
||||
like that. It's very unexpected and against the V4L spec. Instead, you
|
||||
switch to radio mode by calling VIDIOC_S_FREQUENCY. This is the second
|
||||
and last step of the move to consistent handling of tv and radio tuners.
|
||||
Who: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
|
||||
----------------------------
|
||||
|
|
|
@ -673,6 +673,22 @@ storage request to complete, or it may attempt to cancel the storage request -
|
|||
in which case the page will not be stored in the cache this time.
|
||||
|
||||
|
||||
BULK INODE PAGE UNCACHE
|
||||
-----------------------
|
||||
|
||||
A convenience routine is provided to perform an uncache on all the pages
|
||||
attached to an inode. This assumes that the pages on the inode correspond on a
|
||||
1:1 basis with the pages in the cache.
|
||||
|
||||
void fscache_uncache_all_inode_pages(struct fscache_cookie *cookie,
|
||||
struct inode *inode);
|
||||
|
||||
This takes the netfs cookie that the pages were cached with and the inode that
|
||||
the pages are attached to. This function will wait for pages to finish being
|
||||
written to the cache and for the cache to finish with the page generally. No
|
||||
error is returned.
|
||||
|
||||
|
||||
==========================
|
||||
INDEX AND DATA FILE UPDATE
|
||||
==========================
|
||||
|
|
|
@ -22,6 +22,10 @@ Supported chips:
|
|||
Prefix: 'f71869'
|
||||
Addresses scanned: none, address read from Super I/O config space
|
||||
Datasheet: Available from the Fintek website
|
||||
* Fintek F71869A
|
||||
Prefix: 'f71869a'
|
||||
Addresses scanned: none, address read from Super I/O config space
|
||||
Datasheet: Not public
|
||||
* Fintek F71882FG and F71883FG
|
||||
Prefix: 'f71882fg'
|
||||
Addresses scanned: none, address read from Super I/O config space
|
||||
|
|
|
@ -9,8 +9,8 @@ Supported chips:
|
|||
Socket S1G3: Athlon II, Sempron, Turion II
|
||||
* AMD Family 11h processors:
|
||||
Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra)
|
||||
* AMD Family 12h processors: "Llano"
|
||||
* AMD Family 14h processors: "Brazos" (C/E/G-Series)
|
||||
* AMD Family 12h processors: "Llano" (E2/A4/A6/A8-Series)
|
||||
* AMD Family 14h processors: "Brazos" (C/E/G/Z-Series)
|
||||
* AMD Family 15h processors: "Bulldozer"
|
||||
|
||||
Prefix: 'k10temp'
|
||||
|
@ -20,12 +20,16 @@ Supported chips:
|
|||
http://support.amd.com/us/Processor_TechDocs/31116.pdf
|
||||
BIOS and Kernel Developer's Guide (BKDG) for AMD Family 11h Processors:
|
||||
http://support.amd.com/us/Processor_TechDocs/41256.pdf
|
||||
BIOS and Kernel Developer's Guide (BKDG) for AMD Family 12h Processors:
|
||||
http://support.amd.com/us/Processor_TechDocs/41131.pdf
|
||||
BIOS and Kernel Developer's Guide (BKDG) for AMD Family 14h Models 00h-0Fh Processors:
|
||||
http://support.amd.com/us/Processor_TechDocs/43170.pdf
|
||||
Revision Guide for AMD Family 10h Processors:
|
||||
http://support.amd.com/us/Processor_TechDocs/41322.pdf
|
||||
Revision Guide for AMD Family 11h Processors:
|
||||
http://support.amd.com/us/Processor_TechDocs/41788.pdf
|
||||
Revision Guide for AMD Family 12h Processors:
|
||||
http://support.amd.com/us/Processor_TechDocs/44739.pdf
|
||||
Revision Guide for AMD Family 14h Models 00h-0Fh Processors:
|
||||
http://support.amd.com/us/Processor_TechDocs/47534.pdf
|
||||
AMD Family 11h Processor Power and Thermal Data Sheet for Notebooks:
|
||||
|
|
|
@ -2015,6 +2015,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
the default.
|
||||
off: Turn ECRC off
|
||||
on: Turn ECRC on.
|
||||
realloc reallocate PCI resources if allocations done by BIOS
|
||||
are erroneous.
|
||||
|
||||
pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power
|
||||
Management.
|
||||
|
|
|
@ -534,6 +534,8 @@ Events that are never propagated by the driver:
|
|||
0x2404 System is waking up from hibernation to undock
|
||||
0x2405 System is waking up from hibernation to eject bay
|
||||
0x5010 Brightness level changed/control event
|
||||
0x6000 KEYBOARD: Numlock key pressed
|
||||
0x6005 KEYBOARD: Fn key pressed (TO BE VERIFIED)
|
||||
|
||||
Events that are propagated by the driver to userspace:
|
||||
|
||||
|
@ -545,6 +547,8 @@ Events that are propagated by the driver to userspace:
|
|||
0x3006 Bay hotplug request (hint to power up SATA link when
|
||||
the optical drive tray is ejected)
|
||||
0x4003 Undocked (see 0x2x04), can sleep again
|
||||
0x4010 Docked into hotplug port replicator (non-ACPI dock)
|
||||
0x4011 Undocked from hotplug port replicator (non-ACPI dock)
|
||||
0x500B Tablet pen inserted into its storage bay
|
||||
0x500C Tablet pen removed from its storage bay
|
||||
0x6011 ALARM: battery is too hot
|
||||
|
@ -552,6 +556,7 @@ Events that are propagated by the driver to userspace:
|
|||
0x6021 ALARM: a sensor is too hot
|
||||
0x6022 ALARM: a sensor is extremely hot
|
||||
0x6030 System thermal table changed
|
||||
0x6040 Nvidia Optimus/AC adapter related (TO BE VERIFIED)
|
||||
|
||||
Battery nearly empty alarms are a last resort attempt to get the
|
||||
operating system to hibernate or shutdown cleanly (0x2313), or shutdown
|
||||
|
|
|
@ -501,13 +501,29 @@ helper functions described in Section 4. In that case, pm_runtime_resume()
|
|||
should be used. Of course, for this purpose the device's run-time PM has to be
|
||||
enabled earlier by calling pm_runtime_enable().
|
||||
|
||||
If the device bus type's or driver's ->probe() or ->remove() callback runs
|
||||
If the device bus type's or driver's ->probe() callback runs
|
||||
pm_runtime_suspend() or pm_runtime_idle() or their asynchronous counterparts,
|
||||
they will fail returning -EAGAIN, because the device's usage counter is
|
||||
incremented by the core before executing ->probe() and ->remove(). Still, it
|
||||
may be desirable to suspend the device as soon as ->probe() or ->remove() has
|
||||
finished, so the PM core uses pm_runtime_idle_sync() to invoke the
|
||||
subsystem-level idle callback for the device at that time.
|
||||
incremented by the driver core before executing ->probe(). Still, it may be
|
||||
desirable to suspend the device as soon as ->probe() has finished, so the driver
|
||||
core uses pm_runtime_put_sync() to invoke the subsystem-level idle callback for
|
||||
the device at that time.
|
||||
|
||||
Moreover, the driver core prevents runtime PM callbacks from racing with the bus
|
||||
notifier callback in __device_release_driver(), which is necessary, because the
|
||||
notifier is used by some subsystems to carry out operations affecting the
|
||||
runtime PM functionality. It does so by calling pm_runtime_get_sync() before
|
||||
driver_sysfs_remove() and the BUS_NOTIFY_UNBIND_DRIVER notifications. This
|
||||
resumes the device if it's in the suspended state and prevents it from
|
||||
being suspended again while those routines are being executed.
|
||||
|
||||
To allow bus types and drivers to put devices into the suspended state by
|
||||
calling pm_runtime_suspend() from their ->remove() routines, the driver core
|
||||
executes pm_runtime_put_sync() after running the BUS_NOTIFY_UNBIND_DRIVER
|
||||
notifications in __device_release_driver(). This requires bus types and
|
||||
drivers to make their ->remove() callbacks avoid races with runtime PM directly,
|
||||
but also it allows of more flexibility in the handling of devices during the
|
||||
removal of their drivers.
|
||||
|
||||
The user space can effectively disallow the driver of the device to power manage
|
||||
it at run time by changing the value of its /sys/devices/.../power/control
|
||||
|
|
|
@ -13,18 +13,8 @@ static DEFINE_SPINLOCK(xxx_lock);
|
|||
The above is always safe. It will disable interrupts _locally_, but the
|
||||
spinlock itself will guarantee the global lock, so it will guarantee that
|
||||
there is only one thread-of-control within the region(s) protected by that
|
||||
lock. This works well even under UP. The above sequence under UP
|
||||
essentially is just the same as doing
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
save_flags(flags); cli();
|
||||
... critical section ...
|
||||
restore_flags(flags);
|
||||
|
||||
so the code does _not_ need to worry about UP vs SMP issues: the spinlocks
|
||||
work correctly under both (and spinlocks are actually more efficient on
|
||||
architectures that allow doing the "save_flags + cli" in one operation).
|
||||
lock. This works well even under UP also, so the code does _not_ need to
|
||||
worry about UP vs SMP issues: the spinlocks work correctly under both.
|
||||
|
||||
NOTE! Implications of spin_locks for memory are further described in:
|
||||
|
||||
|
@ -36,27 +26,7 @@ The above is usually pretty simple (you usually need and want only one
|
|||
spinlock for most things - using more than one spinlock can make things a
|
||||
lot more complex and even slower and is usually worth it only for
|
||||
sequences that you _know_ need to be split up: avoid it at all cost if you
|
||||
aren't sure). HOWEVER, it _does_ mean that if you have some code that does
|
||||
|
||||
cli();
|
||||
.. critical section ..
|
||||
sti();
|
||||
|
||||
and another sequence that does
|
||||
|
||||
spin_lock_irqsave(flags);
|
||||
.. critical section ..
|
||||
spin_unlock_irqrestore(flags);
|
||||
|
||||
then they are NOT mutually exclusive, and the critical regions can happen
|
||||
at the same time on two different CPU's. That's fine per se, but the
|
||||
critical regions had better be critical for different things (ie they
|
||||
can't stomp on each other).
|
||||
|
||||
The above is a problem mainly if you end up mixing code - for example the
|
||||
routines in ll_rw_block() tend to use cli/sti to protect the atomicity of
|
||||
their actions, and if a driver uses spinlocks instead then you should
|
||||
think about issues like the above.
|
||||
aren't sure).
|
||||
|
||||
This is really the only really hard part about spinlocks: once you start
|
||||
using spinlocks they tend to expand to areas you might not have noticed
|
||||
|
@ -120,11 +90,10 @@ Lesson 3: spinlocks revisited.
|
|||
|
||||
The single spin-lock primitives above are by no means the only ones. They
|
||||
are the most safe ones, and the ones that work under all circumstances,
|
||||
but partly _because_ they are safe they are also fairly slow. They are
|
||||
much faster than a generic global cli/sti pair, but slower than they'd
|
||||
need to be, because they do have to disable interrupts (which is just a
|
||||
single instruction on a x86, but it's an expensive one - and on other
|
||||
architectures it can be worse).
|
||||
but partly _because_ they are safe they are also fairly slow. They are slower
|
||||
than they'd need to be, because they do have to disable interrupts
|
||||
(which is just a single instruction on a x86, but it's an expensive one -
|
||||
and on other architectures it can be worse).
|
||||
|
||||
If you have a case where you have to protect a data structure across
|
||||
several CPU's and you want to use spinlocks you can potentially use
|
||||
|
|
|
@ -76,6 +76,13 @@ A transfer's actual_length may be positive even when an error has been
|
|||
reported. That's because transfers often involve several packets, so that
|
||||
one or more packets could finish before an error stops further endpoint I/O.
|
||||
|
||||
For isochronous URBs, the urb status value is non-zero only if the URB is
|
||||
unlinked, the device is removed, the host controller is disabled, or the total
|
||||
transferred length is less than the requested length and the URB_SHORT_NOT_OK
|
||||
flag is set. Completion handlers for isochronous URBs should only see
|
||||
urb->status set to zero, -ENOENT, -ECONNRESET, -ESHUTDOWN, or -EREMOTEIO.
|
||||
Individual frame descriptor status fields may report more status codes.
|
||||
|
||||
|
||||
0 Transfer completed successfully
|
||||
|
||||
|
@ -132,7 +139,7 @@ one or more packets could finish before an error stops further endpoint I/O.
|
|||
device removal events immediately.
|
||||
|
||||
-EXDEV ISO transfer only partially completed
|
||||
look at individual frame status for details
|
||||
(only set in iso_frame_desc[n].status, not urb->status)
|
||||
|
||||
-EINVAL ISO madness, if this happens: Log off and go home
|
||||
|
||||
|
|
44
MAINTAINERS
44
MAINTAINERS
|
@ -594,6 +594,16 @@ S: Maintained
|
|||
F: arch/arm/lib/floppydma.S
|
||||
F: arch/arm/include/asm/floppy.h
|
||||
|
||||
ARM PMU PROFILING AND DEBUGGING
|
||||
M: Will Deacon <will.deacon@arm.com>
|
||||
S: Maintained
|
||||
F: arch/arm/kernel/perf_event*
|
||||
F: arch/arm/oprofile/common.c
|
||||
F: arch/arm/kernel/pmu.c
|
||||
F: arch/arm/include/asm/pmu.h
|
||||
F: arch/arm/kernel/hw_breakpoint.c
|
||||
F: arch/arm/include/asm/hw_breakpoint.h
|
||||
|
||||
ARM PORT
|
||||
M: Russell King <linux@arm.linux.org.uk>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
|
@ -1345,16 +1355,18 @@ F: drivers/auxdisplay/
|
|||
F: include/linux/cfag12864b.h
|
||||
|
||||
AVR32 ARCHITECTURE
|
||||
M: Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>
|
||||
M: Haavard Skinnemoen <hskinnemoen@gmail.com>
|
||||
M: Hans-Christian Egtvedt <egtvedt@samfundet.no>
|
||||
W: http://www.atmel.com/products/AVR32/
|
||||
W: http://avr32linux.org/
|
||||
W: http://avrfreaks.net/
|
||||
S: Supported
|
||||
S: Maintained
|
||||
F: arch/avr32/
|
||||
|
||||
AVR32/AT32AP MACHINE SUPPORT
|
||||
M: Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>
|
||||
S: Supported
|
||||
M: Haavard Skinnemoen <hskinnemoen@gmail.com>
|
||||
M: Hans-Christian Egtvedt <egtvedt@samfundet.no>
|
||||
S: Maintained
|
||||
F: arch/avr32/mach-at32ap/
|
||||
|
||||
AX.25 NETWORK LAYER
|
||||
|
@ -1390,7 +1402,6 @@ F: include/linux/backlight.h
|
|||
BATMAN ADVANCED
|
||||
M: Marek Lindner <lindner_marek@yahoo.de>
|
||||
M: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
|
||||
M: Sven Eckelmann <sven@narfation.org>
|
||||
L: b.a.t.m.a.n@lists.open-mesh.org
|
||||
W: http://www.open-mesh.org/
|
||||
S: Maintained
|
||||
|
@ -1423,7 +1434,6 @@ S: Supported
|
|||
F: arch/blackfin/
|
||||
|
||||
BLACKFIN EMAC DRIVER
|
||||
M: Michael Hennerich <michael.hennerich@analog.com>
|
||||
L: uclinux-dist-devel@blackfin.uclinux.org
|
||||
W: http://blackfin.uclinux.org
|
||||
S: Supported
|
||||
|
@ -1639,7 +1649,7 @@ CAN NETWORK LAYER
|
|||
M: Oliver Hartkopp <socketcan@hartkopp.net>
|
||||
M: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
|
||||
M: Urs Thuermann <urs.thuermann@volkswagen.de>
|
||||
L: socketcan-core@lists.berlios.de
|
||||
L: socketcan-core@lists.berlios.de (subscribers-only)
|
||||
L: netdev@vger.kernel.org
|
||||
W: http://developer.berlios.de/projects/socketcan/
|
||||
S: Maintained
|
||||
|
@ -1651,7 +1661,7 @@ F: include/linux/can/raw.h
|
|||
|
||||
CAN NETWORK DRIVERS
|
||||
M: Wolfgang Grandegger <wg@grandegger.com>
|
||||
L: socketcan-core@lists.berlios.de
|
||||
L: socketcan-core@lists.berlios.de (subscribers-only)
|
||||
L: netdev@vger.kernel.org
|
||||
W: http://developer.berlios.de/projects/socketcan/
|
||||
S: Maintained
|
||||
|
@ -2197,7 +2207,7 @@ F: drivers/acpi/dock.c
|
|||
DOCUMENTATION
|
||||
M: Randy Dunlap <rdunlap@xenotime.net>
|
||||
L: linux-doc@vger.kernel.org
|
||||
T: quilt oss.oracle.com/~rdunlap/kernel-doc-patches/current/
|
||||
T: quilt http://userweb.kernel.org/~rdunlap/kernel-doc-patches/current/
|
||||
S: Maintained
|
||||
F: Documentation/
|
||||
|
||||
|
@ -4982,7 +4992,7 @@ F: drivers/power/power_supply*
|
|||
|
||||
PNP SUPPORT
|
||||
M: Adam Belay <abelay@mit.edu>
|
||||
M: Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||
M: Bjorn Helgaas <bhelgaas@google.com>
|
||||
S: Maintained
|
||||
F: drivers/pnp/
|
||||
|
||||
|
@ -5181,6 +5191,7 @@ S: Supported
|
|||
F: drivers/net/qlcnic/
|
||||
|
||||
QLOGIC QLGE 10Gb ETHERNET DRIVER
|
||||
M: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
|
||||
M: Ron Mercer <ron.mercer@qlogic.com>
|
||||
M: linux-driver@qlogic.com
|
||||
L: netdev@vger.kernel.org
|
||||
|
@ -6434,8 +6445,9 @@ S: Maintained
|
|||
F: drivers/usb/misc/rio500*
|
||||
|
||||
USB EHCI DRIVER
|
||||
M: Alan Stern <stern@rowland.harvard.edu>
|
||||
L: linux-usb@vger.kernel.org
|
||||
S: Orphan
|
||||
S: Maintained
|
||||
F: Documentation/usb/ehci.txt
|
||||
F: drivers/usb/host/ehci*
|
||||
|
||||
|
@ -6465,6 +6477,12 @@ S: Maintained
|
|||
F: Documentation/hid/hiddev.txt
|
||||
F: drivers/hid/usbhid/
|
||||
|
||||
USB/IP DRIVERS
|
||||
M: Matt Mooney <mfm@muteddisk.com>
|
||||
L: linux-usb@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/staging/usbip/
|
||||
|
||||
USB ISP116X DRIVER
|
||||
M: Olav Kongas <ok@artecdesign.ee>
|
||||
L: linux-usb@vger.kernel.org
|
||||
|
@ -6494,8 +6512,9 @@ S: Maintained
|
|||
F: sound/usb/midi.*
|
||||
|
||||
USB OHCI DRIVER
|
||||
M: Alan Stern <stern@rowland.harvard.edu>
|
||||
L: linux-usb@vger.kernel.org
|
||||
S: Orphan
|
||||
S: Maintained
|
||||
F: Documentation/usb/ohci.txt
|
||||
F: drivers/usb/host/ohci*
|
||||
|
||||
|
@ -6724,6 +6743,7 @@ F: fs/fat/
|
|||
VIDEOBUF2 FRAMEWORK
|
||||
M: Pawel Osciak <pawel@osciak.com>
|
||||
M: Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
M: Kyungmin Park <kyungmin.park@samsung.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/media/video/videobuf2-*
|
||||
|
|
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
|||
VERSION = 3
|
||||
PATCHLEVEL = 0
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc5
|
||||
EXTRAVERSION = -rc7
|
||||
NAME = Sneaky Weasel
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
42
README
42
README
|
@ -1,6 +1,6 @@
|
|||
Linux kernel release 2.6.xx <http://kernel.org/>
|
||||
Linux kernel release 3.x <http://kernel.org/>
|
||||
|
||||
These are the release notes for Linux version 2.6. Read them carefully,
|
||||
These are the release notes for Linux version 3. Read them carefully,
|
||||
as they tell you what this is all about, explain how to install the
|
||||
kernel, and what to do if something goes wrong.
|
||||
|
||||
|
@ -62,10 +62,10 @@ INSTALLING the kernel source:
|
|||
directory where you have permissions (eg. your home directory) and
|
||||
unpack it:
|
||||
|
||||
gzip -cd linux-2.6.XX.tar.gz | tar xvf -
|
||||
gzip -cd linux-3.X.tar.gz | tar xvf -
|
||||
|
||||
or
|
||||
bzip2 -dc linux-2.6.XX.tar.bz2 | tar xvf -
|
||||
bzip2 -dc linux-3.X.tar.bz2 | tar xvf -
|
||||
|
||||
|
||||
Replace "XX" with the version number of the latest kernel.
|
||||
|
@ -75,15 +75,15 @@ INSTALLING the kernel source:
|
|||
files. They should match the library, and not get messed up by
|
||||
whatever the kernel-du-jour happens to be.
|
||||
|
||||
- You can also upgrade between 2.6.xx releases by patching. Patches are
|
||||
- You can also upgrade between 3.x releases by patching. Patches are
|
||||
distributed in the traditional gzip and the newer bzip2 format. To
|
||||
install by patching, get all the newer patch files, enter the
|
||||
top level directory of the kernel source (linux-2.6.xx) and execute:
|
||||
top level directory of the kernel source (linux-3.x) and execute:
|
||||
|
||||
gzip -cd ../patch-2.6.xx.gz | patch -p1
|
||||
gzip -cd ../patch-3.x.gz | patch -p1
|
||||
|
||||
or
|
||||
bzip2 -dc ../patch-2.6.xx.bz2 | patch -p1
|
||||
bzip2 -dc ../patch-3.x.bz2 | patch -p1
|
||||
|
||||
(repeat xx for all versions bigger than the version of your current
|
||||
source tree, _in_order_) and you should be ok. You may want to remove
|
||||
|
@ -91,9 +91,9 @@ INSTALLING the kernel source:
|
|||
failed patches (xxx# or xxx.rej). If there are, either you or me has
|
||||
made a mistake.
|
||||
|
||||
Unlike patches for the 2.6.x kernels, patches for the 2.6.x.y kernels
|
||||
Unlike patches for the 3.x kernels, patches for the 3.x.y kernels
|
||||
(also known as the -stable kernels) are not incremental but instead apply
|
||||
directly to the base 2.6.x kernel. Please read
|
||||
directly to the base 3.x kernel. Please read
|
||||
Documentation/applying-patches.txt for more information.
|
||||
|
||||
Alternatively, the script patch-kernel can be used to automate this
|
||||
|
@ -107,14 +107,14 @@ INSTALLING the kernel source:
|
|||
an alternative directory can be specified as the second argument.
|
||||
|
||||
- If you are upgrading between releases using the stable series patches
|
||||
(for example, patch-2.6.xx.y), note that these "dot-releases" are
|
||||
not incremental and must be applied to the 2.6.xx base tree. For
|
||||
example, if your base kernel is 2.6.12 and you want to apply the
|
||||
2.6.12.3 patch, you do not and indeed must not first apply the
|
||||
2.6.12.1 and 2.6.12.2 patches. Similarly, if you are running kernel
|
||||
version 2.6.12.2 and want to jump to 2.6.12.3, you must first
|
||||
reverse the 2.6.12.2 patch (that is, patch -R) _before_ applying
|
||||
the 2.6.12.3 patch.
|
||||
(for example, patch-3.x.y), note that these "dot-releases" are
|
||||
not incremental and must be applied to the 3.x base tree. For
|
||||
example, if your base kernel is 3.0 and you want to apply the
|
||||
3.0.3 patch, you do not and indeed must not first apply the
|
||||
3.0.1 and 3.0.2 patches. Similarly, if you are running kernel
|
||||
version 3.0.2 and want to jump to 3.0.3, you must first
|
||||
reverse the 3.0.2 patch (that is, patch -R) _before_ applying
|
||||
the 3.0.3 patch.
|
||||
You can read more on this in Documentation/applying-patches.txt
|
||||
|
||||
- Make sure you have no stale .o files and dependencies lying around:
|
||||
|
@ -126,7 +126,7 @@ INSTALLING the kernel source:
|
|||
|
||||
SOFTWARE REQUIREMENTS
|
||||
|
||||
Compiling and running the 2.6.xx kernels requires up-to-date
|
||||
Compiling and running the 3.x kernels requires up-to-date
|
||||
versions of various software packages. Consult
|
||||
Documentation/Changes for the minimum version numbers required
|
||||
and how to get updates for these packages. Beware that using
|
||||
|
@ -142,11 +142,11 @@ BUILD directory for the kernel:
|
|||
Using the option "make O=output/dir" allow you to specify an alternate
|
||||
place for the output files (including .config).
|
||||
Example:
|
||||
kernel source code: /usr/src/linux-2.6.N
|
||||
kernel source code: /usr/src/linux-3.N
|
||||
build directory: /home/name/build/kernel
|
||||
|
||||
To configure and build the kernel use:
|
||||
cd /usr/src/linux-2.6.N
|
||||
cd /usr/src/linux-3.N
|
||||
make O=/home/name/build/kernel menuconfig
|
||||
make O=/home/name/build/kernel
|
||||
sudo make O=/home/name/build/kernel modules_install install
|
||||
|
|
|
@ -10,7 +10,7 @@ config ARM
|
|||
select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
|
||||
select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
|
||||
select HAVE_ARCH_KGDB
|
||||
select HAVE_KPROBES if (!XIP_KERNEL && !THUMB2_KERNEL)
|
||||
select HAVE_KPROBES if !XIP_KERNEL
|
||||
select HAVE_KRETPROBES if (HAVE_KPROBES)
|
||||
select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
|
||||
select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
|
||||
|
|
|
@ -255,7 +255,7 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
|
|||
if (buf == 0) {
|
||||
dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
|
||||
__func__, ptr);
|
||||
return 0;
|
||||
return ~0;
|
||||
}
|
||||
|
||||
dev_dbg(dev,
|
||||
|
|
|
@ -24,12 +24,6 @@
|
|||
#define MAX_INSN_SIZE 2
|
||||
#define MAX_STACK_SIZE 64 /* 32 would probably be OK */
|
||||
|
||||
/*
|
||||
* This undefined instruction must be unique and
|
||||
* reserved solely for kprobes' use.
|
||||
*/
|
||||
#define KPROBE_BREAKPOINT_INSTRUCTION 0xe7f001f8
|
||||
|
||||
#define regs_return_value(regs) ((regs)->ARM_r0)
|
||||
#define flush_insn_slot(p) do { } while (0)
|
||||
#define kretprobe_blacklist_size 0
|
||||
|
@ -38,14 +32,17 @@ 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);
|
||||
|
||||
/* 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_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;
|
||||
};
|
||||
|
||||
struct prev_kprobe {
|
||||
|
@ -62,20 +59,9 @@ struct kprobe_ctlblk {
|
|||
};
|
||||
|
||||
void arch_remove_kprobe(struct kprobe *);
|
||||
void kretprobe_trampoline(void);
|
||||
|
||||
int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
|
||||
int kprobe_exceptions_notify(struct notifier_block *self,
|
||||
unsigned long val, void *data);
|
||||
|
||||
enum kprobe_insn {
|
||||
INSN_REJECTED,
|
||||
INSN_GOOD,
|
||||
INSN_GOOD_NO_SLOT
|
||||
};
|
||||
|
||||
enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t,
|
||||
struct arch_specific_insn *);
|
||||
void __init arm_kprobe_decode_init(void);
|
||||
|
||||
#endif /* _ARM_KPROBES_H */
|
||||
|
|
|
@ -69,8 +69,9 @@
|
|||
#define PSR_c 0x000000ff /* Control */
|
||||
|
||||
/*
|
||||
* ARMv7 groups of APSR bits
|
||||
* ARMv7 groups of PSR bits
|
||||
*/
|
||||
#define APSR_MASK 0xf80f0000 /* N, Z, C, V, Q and GE flags */
|
||||
#define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */
|
||||
#define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */
|
||||
#define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */
|
||||
|
@ -199,6 +200,14 @@ extern unsigned long profile_pc(struct pt_regs *regs);
|
|||
#define predicate(x) ((x) & 0xf0000000)
|
||||
#define PREDICATE_ALWAYS 0xe0000000
|
||||
|
||||
/*
|
||||
* True if instr is a 32-bit thumb instruction. This works if instr
|
||||
* is the first or only half-word of a thumb instruction. It also works
|
||||
* when instr holds all 32-bits of a wide thumb instruction if stored
|
||||
* in the form (first_half<<16)|(second_half)
|
||||
*/
|
||||
#define is_wide_instruction(instr) ((unsigned)(instr) >= 0xe800)
|
||||
|
||||
/*
|
||||
* kprobe-based event tracer support
|
||||
*/
|
||||
|
|
|
@ -37,7 +37,12 @@ obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o
|
|||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o
|
||||
ifdef CONFIG_THUMB2_KERNEL
|
||||
obj-$(CONFIG_KPROBES) += kprobes-thumb.o
|
||||
else
|
||||
obj-$(CONFIG_KPROBES) += kprobes-arm.o
|
||||
endif
|
||||
obj-$(CONFIG_ATAGS_PROC) += atags.o
|
||||
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
|
||||
obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
|
||||
|
|
|
@ -121,15 +121,13 @@
|
|||
.endm
|
||||
#else /* CONFIG_THUMB2_KERNEL */
|
||||
.macro svc_exit, rpsr
|
||||
ldr lr, [sp, #S_SP] @ top of the stack
|
||||
ldrd r0, r1, [sp, #S_LR] @ calling lr and pc
|
||||
clrex @ clear the exclusive monitor
|
||||
ldr r0, [sp, #S_SP] @ top of the stack
|
||||
ldr r1, [sp, #S_PC] @ return address
|
||||
tst r0, #4 @ orig stack 8-byte aligned?
|
||||
stmdb r0, {r1, \rpsr} @ rfe context
|
||||
stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context
|
||||
ldmia sp, {r0 - r12}
|
||||
ldr lr, [sp, #S_LR]
|
||||
addeq sp, sp, #S_FRAME_SIZE - 8 @ aligned
|
||||
addne sp, sp, #S_FRAME_SIZE - 4 @ not aligned
|
||||
mov sp, lr
|
||||
ldr lr, [sp], #4
|
||||
rfeia sp!
|
||||
.endm
|
||||
|
||||
|
|
|
@ -0,0 +1,999 @@
|
|||
/*
|
||||
* arch/arm/kernel/kprobes-decode.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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We do not have hardware single-stepping on ARM, This
|
||||
* effort is further complicated by the ARM not having a
|
||||
* "next PC" register. Instructions that change the PC
|
||||
* can't be safely single-stepped in a MP environment, so
|
||||
* we have a lot of work to do:
|
||||
*
|
||||
* In the prepare phase:
|
||||
* *) If it is an instruction that does anything
|
||||
* with the CPU mode, we reject it for a kprobe.
|
||||
* (This is out of laziness rather than need. The
|
||||
* instructions could be simulated.)
|
||||
*
|
||||
* *) Otherwise, decode the instruction rewriting its
|
||||
* registers to take fixed, ordered registers and
|
||||
* setting a handler for it to run the instruction.
|
||||
*
|
||||
* In the execution phase by an instruction's handler:
|
||||
*
|
||||
* *) If the PC is written to by the instruction, the
|
||||
* instruction must be fully simulated in software.
|
||||
*
|
||||
* *) Otherwise, a modified form of the instruction is
|
||||
* directly executed. Its handler calls the
|
||||
* instruction in insn[0]. In insn[1] is a
|
||||
* "mov pc, lr" to return.
|
||||
*
|
||||
* Before calling, load up the reordered registers
|
||||
* from the original instruction's registers. If one
|
||||
* of the original input registers is the PC, compute
|
||||
* and adjust the appropriate input register.
|
||||
*
|
||||
* After call completes, copy the output registers to
|
||||
* the original instruction's original registers.
|
||||
*
|
||||
* We don't use a real breakpoint instruction since that
|
||||
* would have us in the kernel go from SVC mode to SVC
|
||||
* mode losing the link register. Instead we use an
|
||||
* undefined instruction. To simplify processing, the
|
||||
* undefined instruction used for kprobes must be reserved
|
||||
* exclusively for kprobes use.
|
||||
*
|
||||
* TODO: ifdef out some instruction decoding based on architecture.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
#include "kprobes.h"
|
||||
|
||||
#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
|
||||
|
||||
#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 6
|
||||
#define BLX(reg) "blx "reg" \n\t"
|
||||
#else
|
||||
#define BLX(reg) "mov lr, pc \n\t" \
|
||||
"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)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
unsigned long pc = (unsigned long)p->addr + 8;
|
||||
int rt = (insn >> 12) & 0xf;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
|
||||
register unsigned long rtv asm("r0") = regs->uregs[rt];
|
||||
register unsigned long rt2v asm("r1") = regs->uregs[rt+1];
|
||||
register unsigned long rnv asm("r2") = (rn == 15) ? pc
|
||||
: regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
|
||||
__asm__ __volatile__ (
|
||||
BLX("%[fn]")
|
||||
: "=r" (rtv), "=r" (rt2v), "=r" (rnv)
|
||||
: "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
|
||||
[fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
regs->uregs[rt] = rtv;
|
||||
regs->uregs[rt+1] = rt2v;
|
||||
if (is_writeback(insn))
|
||||
regs->uregs[rn] = rnv;
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_ldr(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
unsigned long pc = (unsigned long)p->addr + 8;
|
||||
int rt = (insn >> 12) & 0xf;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
|
||||
register unsigned long rtv asm("r0");
|
||||
register unsigned long rnv asm("r2") = (rn == 15) ? pc
|
||||
: regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
|
||||
__asm__ __volatile__ (
|
||||
BLX("%[fn]")
|
||||
: "=r" (rtv), "=r" (rnv)
|
||||
: "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
if (rt == 15)
|
||||
load_write_pc(rtv, regs);
|
||||
else
|
||||
regs->uregs[rt] = rtv;
|
||||
|
||||
if (is_writeback(insn))
|
||||
regs->uregs[rn] = rnv;
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_str(struct kprobe *p, 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;
|
||||
int rt = (insn >> 12) & 0xf;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
|
||||
register unsigned long rtv asm("r0") = (rt == 15) ? rtpc
|
||||
: regs->uregs[rt];
|
||||
register unsigned long rnv asm("r2") = (rn == 15) ? rnpc
|
||||
: regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
|
||||
__asm__ __volatile__ (
|
||||
BLX("%[fn]")
|
||||
: "=r" (rnv)
|
||||
: "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
if (is_writeback(insn))
|
||||
regs->uregs[rn] = rnv;
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
unsigned long pc = (unsigned long)p->addr + 8;
|
||||
int rd = (insn >> 12) & 0xf;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
int rs = (insn >> 8) & 0xf;
|
||||
|
||||
register unsigned long rdv asm("r0") = regs->uregs[rd];
|
||||
register unsigned long rnv asm("r2") = (rn == 15) ? pc
|
||||
: regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = (rm == 15) ? pc
|
||||
: regs->uregs[rm];
|
||||
register unsigned long rsv asm("r1") = regs->uregs[rs];
|
||||
unsigned long cpsr = regs->ARM_cpsr;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"msr cpsr_fs, %[cpsr] \n\t"
|
||||
BLX("%[fn]")
|
||||
"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)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
if (rd == 15)
|
||||
alu_write_pc(rdv, regs);
|
||||
else
|
||||
regs->uregs[rd] = rdv;
|
||||
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
int rd = (insn >> 12) & 0xf;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
|
||||
register unsigned long rdv asm("r0") = regs->uregs[rd];
|
||||
register unsigned long rnv asm("r2") = regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
unsigned long cpsr = regs->ARM_cpsr;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"msr cpsr_fs, %[cpsr] \n\t"
|
||||
BLX("%[fn]")
|
||||
"mrs %[cpsr], cpsr \n\t"
|
||||
: "=r" (rdv), [cpsr] "=r" (cpsr)
|
||||
: "0" (rdv), "r" (rnv), "r" (rmv),
|
||||
"1" (cpsr), [fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
regs->uregs[rd] = rdv;
|
||||
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
int rd = (insn >> 16) & 0xf;
|
||||
int rn = (insn >> 12) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
int rs = (insn >> 8) & 0xf;
|
||||
|
||||
register unsigned long rdv asm("r2") = regs->uregs[rd];
|
||||
register unsigned long rnv asm("r0") = regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
register unsigned long rsv asm("r1") = regs->uregs[rs];
|
||||
unsigned long cpsr = regs->ARM_cpsr;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"msr cpsr_fs, %[cpsr] \n\t"
|
||||
BLX("%[fn]")
|
||||
"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)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
regs->uregs[rd] = rdv;
|
||||
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
int rd = (insn >> 12) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
|
||||
register unsigned long rdv asm("r0") = regs->uregs[rd];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
|
||||
__asm__ __volatile__ (
|
||||
BLX("%[fn]")
|
||||
: "=r" (rdv)
|
||||
: "0" (rdv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
regs->uregs[rd] = rdv;
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
int rdlo = (insn >> 12) & 0xf;
|
||||
int rdhi = (insn >> 16) & 0xf;
|
||||
int rn = insn & 0xf;
|
||||
int rm = (insn >> 8) & 0xf;
|
||||
|
||||
register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
|
||||
register unsigned long rdhiv asm("r2") = regs->uregs[rdhi];
|
||||
register unsigned long rnv asm("r3") = regs->uregs[rn];
|
||||
register unsigned long rmv asm("r1") = regs->uregs[rm];
|
||||
unsigned long cpsr = regs->ARM_cpsr;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"msr cpsr_fs, %[cpsr] \n\t"
|
||||
BLX("%[fn]")
|
||||
"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)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
regs->uregs[rdlo] = rdlov;
|
||||
regs->uregs[rdhi] = rdhiv;
|
||||
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
|
||||
};
|
||||
|
||||
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 */
|
||||
|
||||
/* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */
|
||||
DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,577 @@
|
|||
/*
|
||||
* arch/arm/kernel/kprobes-common.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/kprobes.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)
|
||||
{
|
||||
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);
|
||||
int ubit = insn & (1 << 23);
|
||||
int pbit = insn & (1 << 24);
|
||||
long *addr = (long *)regs->uregs[rn];
|
||||
int reg_bit_vector;
|
||||
int reg_count;
|
||||
|
||||
reg_count = 0;
|
||||
reg_bit_vector = insn & 0xffff;
|
||||
while (reg_bit_vector) {
|
||||
reg_bit_vector &= (reg_bit_vector - 1);
|
||||
++reg_count;
|
||||
}
|
||||
|
||||
if (!ubit)
|
||||
addr -= reg_count;
|
||||
addr += (!pbit == !ubit);
|
||||
|
||||
reg_bit_vector = insn & 0xffff;
|
||||
while (reg_bit_vector) {
|
||||
int reg = __ffs(reg_bit_vector);
|
||||
reg_bit_vector &= (reg_bit_vector - 1);
|
||||
if (lbit)
|
||||
regs->uregs[reg] = *addr++;
|
||||
else
|
||||
*addr++ = regs->uregs[reg];
|
||||
}
|
||||
|
||||
if (wbit) {
|
||||
if (!ubit)
|
||||
addr -= reg_count;
|
||||
addr -= (!pbit == !ubit);
|
||||
regs->uregs[rn] = (long)addr;
|
||||
}
|
||||
}
|
||||
|
||||
static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
regs->ARM_pc = (long)p->addr + str_pc_offset;
|
||||
simulate_ldm1stm1(p, regs);
|
||||
regs->ARM_pc = (long)p->addr + 4;
|
||||
}
|
||||
|
||||
static void __kprobes simulate_ldm1_pc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
simulate_ldm1stm1(p, regs);
|
||||
load_write_pc(regs->ARM_pc, regs);
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_generic_r0_12_noflags(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
register void *rregs asm("r1") = regs;
|
||||
register void *rfn asm("lr") = p->ainsn.insn_fn;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"stmdb sp!, {%[regs], r11} \n\t"
|
||||
"ldmia %[regs], {r0-r12} \n\t"
|
||||
#if __LINUX_ARM_ARCH__ >= 6
|
||||
"blx %[fn] \n\t"
|
||||
#else
|
||||
"str %[fn], [sp, #-4]! \n\t"
|
||||
"adr lr, 1f \n\t"
|
||||
"ldr pc, [sp], #4 \n\t"
|
||||
"1: \n\t"
|
||||
#endif
|
||||
"ldr lr, [sp], #4 \n\t" /* lr = regs */
|
||||
"stmia lr, {r0-r12} \n\t"
|
||||
"ldr r11, [sp], #4 \n\t"
|
||||
: [regs] "=r" (rregs), [fn] "=r" (rfn)
|
||||
: "0" (rregs), "1" (rfn)
|
||||
: "r0", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r12", "memory", "cc"
|
||||
);
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_generic_r2_14_noflags(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+2));
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_ldm_r3_15(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
emulate_generic_r0_12_noflags(p, (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)
|
||||
{
|
||||
kprobe_insn_handler_t *handler = 0;
|
||||
unsigned reglist = insn & 0xffff;
|
||||
int is_ldm = insn & 0x100000;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
|
||||
if (rn <= 12 && (reglist & 0xe000) == 0) {
|
||||
/* Instruction only uses registers in the range R0..R12 */
|
||||
handler = emulate_generic_r0_12_noflags;
|
||||
|
||||
} else if (rn >= 2 && (reglist & 0x8003) == 0) {
|
||||
/* Instruction only uses registers in the range R2..R14 */
|
||||
rn -= 2;
|
||||
reglist >>= 2;
|
||||
handler = emulate_generic_r2_14_noflags;
|
||||
|
||||
} else if (rn >= 3 && (reglist & 0x0007) == 0) {
|
||||
/* Instruction only uses registers in the range R3..R15 */
|
||||
if (is_ldm && (reglist & 0x8000)) {
|
||||
rn -= 3;
|
||||
reglist >>= 3;
|
||||
handler = emulate_ldm_r3_15;
|
||||
}
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
/* We can emulate the instruction in (possibly) modified form */
|
||||
asi->insn[0] = (insn & 0xfff00000) | (rn << 16) | reglist;
|
||||
asi->insn_handler = handler;
|
||||
return INSN_GOOD;
|
||||
}
|
||||
|
||||
/* Fallback to slower simulation... */
|
||||
if (reglist & 0x8000)
|
||||
handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
|
||||
else
|
||||
handler = simulate_ldm1stm1;
|
||||
asi->insn_handler = handler;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -28,14 +28,16 @@
|
|||
#include <asm/traps.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include "kprobes.h"
|
||||
|
||||
#define MIN_STACK_SIZE(addr) \
|
||||
min((unsigned long)MAX_STACK_SIZE, \
|
||||
(unsigned long)current_thread_info() + THREAD_START_SP - (addr))
|
||||
|
||||
#define flush_insns(addr, cnt) \
|
||||
#define flush_insns(addr, size) \
|
||||
flush_icache_range((unsigned long)(addr), \
|
||||
(unsigned long)(addr) + \
|
||||
sizeof(kprobe_opcode_t) * (cnt))
|
||||
(size))
|
||||
|
||||
/* Used as a marker in ARM_pc to note when we're in a jprobe. */
|
||||
#define JPROBE_MAGIC_ADDR 0xffffffff
|
||||
|
@ -49,16 +51,35 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
|||
kprobe_opcode_t insn;
|
||||
kprobe_opcode_t tmp_insn[MAX_INSN_SIZE];
|
||||
unsigned long addr = (unsigned long)p->addr;
|
||||
bool thumb;
|
||||
kprobe_decode_insn_t *decode_insn;
|
||||
int is;
|
||||
|
||||
if (addr & 0x3 || in_exception_text(addr))
|
||||
if (in_exception_text(addr))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
thumb = true;
|
||||
addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
|
||||
insn = ((u16 *)addr)[0];
|
||||
if (is_wide_instruction(insn)) {
|
||||
insn <<= 16;
|
||||
insn |= ((u16 *)addr)[1];
|
||||
decode_insn = thumb32_kprobe_decode_insn;
|
||||
} else
|
||||
decode_insn = thumb16_kprobe_decode_insn;
|
||||
#else /* !CONFIG_THUMB2_KERNEL */
|
||||
thumb = false;
|
||||
if (addr & 0x3)
|
||||
return -EINVAL;
|
||||
insn = *p->addr;
|
||||
decode_insn = arm_kprobe_decode_insn;
|
||||
#endif
|
||||
|
||||
p->opcode = insn;
|
||||
p->ainsn.insn = tmp_insn;
|
||||
|
||||
switch (arm_kprobe_decode_insn(insn, &p->ainsn)) {
|
||||
switch ((*decode_insn)(insn, &p->ainsn)) {
|
||||
case INSN_REJECTED: /* not supported */
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -68,7 +89,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
|||
return -ENOMEM;
|
||||
for (is = 0; is < MAX_INSN_SIZE; ++is)
|
||||
p->ainsn.insn[is] = tmp_insn[is];
|
||||
flush_insns(p->ainsn.insn, MAX_INSN_SIZE);
|
||||
flush_insns(p->ainsn.insn,
|
||||
sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE);
|
||||
p->ainsn.insn_fn = (kprobe_insn_fn_t *)
|
||||
((uintptr_t)p->ainsn.insn | thumb);
|
||||
break;
|
||||
|
||||
case INSN_GOOD_NO_SLOT: /* instruction doesn't need insn slot */
|
||||
|
@ -79,24 +103,88 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
|
||||
/*
|
||||
* For a 32-bit Thumb breakpoint spanning two memory words we need to take
|
||||
* special precautions to insert the breakpoint atomically, especially on SMP
|
||||
* systems. This is achieved by calling this arming function using stop_machine.
|
||||
*/
|
||||
static int __kprobes set_t32_breakpoint(void *addr)
|
||||
{
|
||||
((u16 *)addr)[0] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION >> 16;
|
||||
((u16 *)addr)[1] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION & 0xffff;
|
||||
flush_insns(addr, 2*sizeof(u16));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __kprobes arch_arm_kprobe(struct kprobe *p)
|
||||
{
|
||||
*p->addr = KPROBE_BREAKPOINT_INSTRUCTION;
|
||||
flush_insns(p->addr, 1);
|
||||
uintptr_t addr = (uintptr_t)p->addr & ~1; /* Remove any Thumb flag */
|
||||
|
||||
if (!is_wide_instruction(p->opcode)) {
|
||||
*(u16 *)addr = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION;
|
||||
flush_insns(addr, sizeof(u16));
|
||||
} else if (addr & 2) {
|
||||
/* A 32-bit instruction spanning two words needs special care */
|
||||
stop_machine(set_t32_breakpoint, (void *)addr, &cpu_online_map);
|
||||
} else {
|
||||
/* Word aligned 32-bit instruction can be written atomically */
|
||||
u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
|
||||
#ifndef __ARMEB__ /* Swap halfwords for little-endian */
|
||||
bkp = (bkp >> 16) | (bkp << 16);
|
||||
#endif
|
||||
*(u32 *)addr = bkp;
|
||||
flush_insns(addr, sizeof(u32));
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !CONFIG_THUMB2_KERNEL */
|
||||
|
||||
void __kprobes arch_arm_kprobe(struct kprobe *p)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
kprobe_opcode_t brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION;
|
||||
if (insn >= 0xe0000000)
|
||||
brkp |= 0xe0000000; /* Unconditional instruction */
|
||||
else
|
||||
brkp |= insn & 0xf0000000; /* Copy condition from insn */
|
||||
*p->addr = brkp;
|
||||
flush_insns(p->addr, sizeof(p->addr[0]));
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_THUMB2_KERNEL */
|
||||
|
||||
/*
|
||||
* The actual disarming is done here on each CPU and synchronized using
|
||||
* stop_machine. This synchronization is necessary on SMP to avoid removing
|
||||
* a probe between the moment the 'Undefined Instruction' exception is raised
|
||||
* and the moment the exception handler reads the faulting instruction from
|
||||
* memory.
|
||||
* memory. It is also needed to atomically set the two half-words of a 32-bit
|
||||
* Thumb breakpoint.
|
||||
*/
|
||||
int __kprobes __arch_disarm_kprobe(void *p)
|
||||
{
|
||||
struct kprobe *kp = p;
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
u16 *addr = (u16 *)((uintptr_t)kp->addr & ~1);
|
||||
kprobe_opcode_t insn = kp->opcode;
|
||||
unsigned int len;
|
||||
|
||||
if (is_wide_instruction(insn)) {
|
||||
((u16 *)addr)[0] = insn>>16;
|
||||
((u16 *)addr)[1] = insn;
|
||||
len = 2*sizeof(u16);
|
||||
} else {
|
||||
((u16 *)addr)[0] = insn;
|
||||
len = sizeof(u16);
|
||||
}
|
||||
flush_insns(addr, len);
|
||||
|
||||
#else /* !CONFIG_THUMB2_KERNEL */
|
||||
*kp->addr = kp->opcode;
|
||||
flush_insns(kp->addr, 1);
|
||||
flush_insns(kp->addr, sizeof(kp->addr[0]));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -130,12 +218,24 @@ static void __kprobes set_current_kprobe(struct kprobe *p)
|
|||
__get_cpu_var(current_kprobe) = p;
|
||||
}
|
||||
|
||||
static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs,
|
||||
struct kprobe_ctlblk *kcb)
|
||||
static void __kprobes
|
||||
singlestep_skip(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
|
||||
if (is_wide_instruction(p->opcode))
|
||||
regs->ARM_pc += 4;
|
||||
else
|
||||
regs->ARM_pc += 2;
|
||||
#else
|
||||
regs->ARM_pc += 4;
|
||||
if (p->ainsn.insn_check_cc(regs->ARM_cpsr))
|
||||
p->ainsn.insn_handler(p, regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __kprobes
|
||||
singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb)
|
||||
{
|
||||
p->ainsn.insn_singlestep(p, regs);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -149,11 +249,23 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
|
|||
{
|
||||
struct kprobe *p, *cur;
|
||||
struct kprobe_ctlblk *kcb;
|
||||
kprobe_opcode_t *addr = (kprobe_opcode_t *)regs->ARM_pc;
|
||||
|
||||
kcb = get_kprobe_ctlblk();
|
||||
cur = kprobe_running();
|
||||
p = get_kprobe(addr);
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
/*
|
||||
* First look for a probe which was registered using an address with
|
||||
* bit 0 set, this is the usual situation for pointers to Thumb code.
|
||||
* If not found, fallback to looking for one with bit 0 clear.
|
||||
*/
|
||||
p = get_kprobe((kprobe_opcode_t *)(regs->ARM_pc | 1));
|
||||
if (!p)
|
||||
p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc);
|
||||
|
||||
#else /* ! CONFIG_THUMB2_KERNEL */
|
||||
p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc);
|
||||
#endif
|
||||
|
||||
if (p) {
|
||||
if (cur) {
|
||||
|
@ -173,7 +285,8 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
|
|||
/* impossible cases */
|
||||
BUG();
|
||||
}
|
||||
} else {
|
||||
} else if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) {
|
||||
/* Probe hit and conditional execution check ok. */
|
||||
set_current_kprobe(p);
|
||||
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
|
||||
|
||||
|
@ -193,6 +306,13 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
|
|||
}
|
||||
reset_current_kprobe();
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Probe hit but conditional execution check failed,
|
||||
* so just skip the instruction and continue as if
|
||||
* nothing had happened.
|
||||
*/
|
||||
singlestep_skip(p, regs);
|
||||
}
|
||||
} else if (cur) {
|
||||
/* We probably hit a jprobe. Call its break handler. */
|
||||
|
@ -300,7 +420,11 @@ void __naked __kprobes kretprobe_trampoline(void)
|
|||
"bl trampoline_handler \n\t"
|
||||
"mov lr, r0 \n\t"
|
||||
"ldmia sp!, {r0 - r11} \n\t"
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
"bx lr \n\t"
|
||||
#else
|
||||
"mov pc, lr \n\t"
|
||||
#endif
|
||||
: : : "memory");
|
||||
}
|
||||
|
||||
|
@ -378,11 +502,22 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
|||
struct jprobe *jp = container_of(p, struct jprobe, kp);
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
long sp_addr = regs->ARM_sp;
|
||||
long cpsr;
|
||||
|
||||
kcb->jprobe_saved_regs = *regs;
|
||||
memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr));
|
||||
regs->ARM_pc = (long)jp->entry;
|
||||
regs->ARM_cpsr |= PSR_I_BIT;
|
||||
|
||||
cpsr = regs->ARM_cpsr | PSR_I_BIT;
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
/* Set correct Thumb state in cpsr */
|
||||
if (regs->ARM_pc & 1)
|
||||
cpsr |= PSR_T_BIT;
|
||||
else
|
||||
cpsr &= ~PSR_T_BIT;
|
||||
#endif
|
||||
regs->ARM_cpsr = cpsr;
|
||||
|
||||
preempt_disable();
|
||||
return 1;
|
||||
}
|
||||
|
@ -404,7 +539,12 @@ void __kprobes jprobe_return(void)
|
|||
* This is to prevent any simulated instruction from writing
|
||||
* over the regs when they are accessing the stack.
|
||||
*/
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
"sub r0, %0, %1 \n\t"
|
||||
"mov sp, r0 \n\t"
|
||||
#else
|
||||
"sub sp, %0, %1 \n\t"
|
||||
#endif
|
||||
"ldr r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t"
|
||||
"str %0, [sp, %2] \n\t"
|
||||
"str r0, [sp, %3] \n\t"
|
||||
|
@ -415,15 +555,28 @@ void __kprobes jprobe_return(void)
|
|||
* Return to the context saved by setjmp_pre_handler
|
||||
* and restored by longjmp_break_handler.
|
||||
*/
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
"ldr lr, [sp, %2] \n\t" /* lr = saved sp */
|
||||
"ldrd r0, r1, [sp, %5] \n\t" /* r0,r1 = saved lr,pc */
|
||||
"ldr r2, [sp, %4] \n\t" /* r2 = saved psr */
|
||||
"stmdb lr!, {r0, r1, r2} \n\t" /* push saved lr and */
|
||||
/* rfe context */
|
||||
"ldmia sp, {r0 - r12} \n\t"
|
||||
"mov sp, lr \n\t"
|
||||
"ldr lr, [sp], #4 \n\t"
|
||||
"rfeia sp! \n\t"
|
||||
#else
|
||||
"ldr r0, [sp, %4] \n\t"
|
||||
"msr cpsr_cxsf, r0 \n\t"
|
||||
"ldmia sp, {r0 - pc} \n\t"
|
||||
#endif
|
||||
:
|
||||
: "r" (kcb->jprobe_saved_regs.ARM_sp),
|
||||
"I" (sizeof(struct pt_regs) * 2),
|
||||
"J" (offsetof(struct pt_regs, ARM_sp)),
|
||||
"J" (offsetof(struct pt_regs, ARM_pc)),
|
||||
"J" (offsetof(struct pt_regs, ARM_cpsr))
|
||||
"J" (offsetof(struct pt_regs, ARM_cpsr)),
|
||||
"J" (offsetof(struct pt_regs, ARM_lr))
|
||||
: "memory", "cc");
|
||||
}
|
||||
|
||||
|
@ -460,17 +613,44 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct undef_hook kprobes_break_hook = {
|
||||
.instr_mask = 0xffffffff,
|
||||
.instr_val = KPROBE_BREAKPOINT_INSTRUCTION,
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
|
||||
static struct undef_hook kprobes_thumb16_break_hook = {
|
||||
.instr_mask = 0xffff,
|
||||
.instr_val = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION,
|
||||
.cpsr_mask = MODE_MASK,
|
||||
.cpsr_val = SVC_MODE,
|
||||
.fn = kprobe_trap_handler,
|
||||
};
|
||||
|
||||
static struct undef_hook kprobes_thumb32_break_hook = {
|
||||
.instr_mask = 0xffffffff,
|
||||
.instr_val = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION,
|
||||
.cpsr_mask = MODE_MASK,
|
||||
.cpsr_val = SVC_MODE,
|
||||
.fn = kprobe_trap_handler,
|
||||
};
|
||||
|
||||
#else /* !CONFIG_THUMB2_KERNEL */
|
||||
|
||||
static struct undef_hook kprobes_arm_break_hook = {
|
||||
.instr_mask = 0x0fffffff,
|
||||
.instr_val = KPROBE_ARM_BREAKPOINT_INSTRUCTION,
|
||||
.cpsr_mask = MODE_MASK,
|
||||
.cpsr_val = SVC_MODE,
|
||||
.fn = kprobe_trap_handler,
|
||||
};
|
||||
|
||||
#endif /* !CONFIG_THUMB2_KERNEL */
|
||||
|
||||
int __init arch_init_kprobes()
|
||||
{
|
||||
arm_kprobe_decode_init();
|
||||
register_undef_hook(&kprobes_break_hook);
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
register_undef_hook(&kprobes_thumb16_break_hook);
|
||||
register_undef_hook(&kprobes_thumb32_break_hook);
|
||||
#else
|
||||
register_undef_hook(&kprobes_arm_break_hook);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,420 @@
|
|||
/*
|
||||
* arch/arm/kernel/kprobes.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_KPROBES_H
|
||||
#define _ARM_KERNEL_KPROBES_H
|
||||
|
||||
/*
|
||||
* These undefined instructions must be unique and
|
||||
* reserved solely for kprobes' use.
|
||||
*/
|
||||
#define KPROBE_ARM_BREAKPOINT_INSTRUCTION 0x07f001f8
|
||||
#define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18
|
||||
#define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018
|
||||
|
||||
|
||||
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 *);
|
||||
|
||||
#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 *);
|
||||
|
||||
#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);
|
||||
|
||||
#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)
|
||||
|
||||
|
||||
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 */
|
|
@ -583,7 +583,7 @@ static int armpmu_event_init(struct perf_event *event)
|
|||
static void armpmu_enable(struct pmu *pmu)
|
||||
{
|
||||
/* Enable all of the perf events on hardware. */
|
||||
int idx;
|
||||
int idx, enabled = 0;
|
||||
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|
||||
|
||||
if (!armpmu)
|
||||
|
@ -596,9 +596,11 @@ static void armpmu_enable(struct pmu *pmu)
|
|||
continue;
|
||||
|
||||
armpmu->enable(&event->hw, idx);
|
||||
enabled = 1;
|
||||
}
|
||||
|
||||
armpmu->start();
|
||||
if (enabled)
|
||||
armpmu->start();
|
||||
}
|
||||
|
||||
static void armpmu_disable(struct pmu *pmu)
|
||||
|
|
|
@ -228,34 +228,12 @@ static struct undef_hook thumb_break_hook = {
|
|||
.fn = break_trap,
|
||||
};
|
||||
|
||||
static int thumb2_break_trap(struct pt_regs *regs, unsigned int instr)
|
||||
{
|
||||
unsigned int instr2;
|
||||
void __user *pc;
|
||||
|
||||
/* Check the second half of the instruction. */
|
||||
pc = (void __user *)(instruction_pointer(regs) + 2);
|
||||
|
||||
if (processor_mode(regs) == SVC_MODE) {
|
||||
instr2 = *(u16 *) pc;
|
||||
} else {
|
||||
get_user(instr2, (u16 __user *)pc);
|
||||
}
|
||||
|
||||
if (instr2 == 0xa000) {
|
||||
ptrace_break(current, regs);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static struct undef_hook thumb2_break_hook = {
|
||||
.instr_mask = 0xffff,
|
||||
.instr_val = 0xf7f0,
|
||||
.instr_mask = 0xffffffff,
|
||||
.instr_val = 0xf7f0a000,
|
||||
.cpsr_mask = PSR_T_BIT,
|
||||
.cpsr_val = PSR_T_BIT,
|
||||
.fn = thumb2_break_trap,
|
||||
.fn = break_trap,
|
||||
};
|
||||
|
||||
static int __init ptrace_break_init(void)
|
||||
|
|
|
@ -73,6 +73,7 @@ __setup("fpe=", fpe_setup);
|
|||
#endif
|
||||
|
||||
extern void paging_init(struct machine_desc *desc);
|
||||
extern void sanity_check_meminfo(void);
|
||||
extern void reboot_setup(char *str);
|
||||
|
||||
unsigned int processor_id;
|
||||
|
@ -900,6 +901,7 @@ void __init setup_arch(char **cmdline_p)
|
|||
|
||||
parse_early_param();
|
||||
|
||||
sanity_check_meminfo();
|
||||
arm_memblock_init(&meminfo, mdesc);
|
||||
|
||||
paging_init(mdesc);
|
||||
|
|
|
@ -115,7 +115,7 @@ static void __cpuinit twd_calibrate_rate(void)
|
|||
twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
|
||||
|
||||
printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
|
||||
(twd_timer_rate / 1000000) % 100);
|
||||
(twd_timer_rate / 10000) % 100);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -355,9 +355,24 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
|
|||
pc = (void __user *)instruction_pointer(regs);
|
||||
|
||||
if (processor_mode(regs) == SVC_MODE) {
|
||||
instr = *(u32 *) pc;
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
if (thumb_mode(regs)) {
|
||||
instr = ((u16 *)pc)[0];
|
||||
if (is_wide_instruction(instr)) {
|
||||
instr <<= 16;
|
||||
instr |= ((u16 *)pc)[1];
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
instr = *(u32 *) pc;
|
||||
} else if (thumb_mode(regs)) {
|
||||
get_user(instr, (u16 __user *)pc);
|
||||
if (is_wide_instruction(instr)) {
|
||||
unsigned int instr2;
|
||||
get_user(instr2, (u16 __user *)pc+1);
|
||||
instr <<= 16;
|
||||
instr |= instr2;
|
||||
}
|
||||
} else {
|
||||
get_user(instr, (u32 __user *)pc);
|
||||
}
|
||||
|
|
|
@ -223,15 +223,15 @@ static struct clk *periph_clocks[] __initdata = {
|
|||
};
|
||||
|
||||
static struct clk_lookup periph_clocks_lookups[] = {
|
||||
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
|
||||
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
|
||||
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
|
||||
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
|
||||
CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
|
||||
CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
|
||||
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
|
||||
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
|
||||
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
|
||||
CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk),
|
||||
CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk),
|
||||
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
|
||||
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
|
||||
};
|
||||
|
||||
static struct clk_lookup usart_clocks_lookups[] = {
|
||||
|
|
|
@ -1220,7 +1220,7 @@ void __init at91_set_serial_console(unsigned portnr)
|
|||
{
|
||||
if (portnr < ATMEL_MAX_UART) {
|
||||
atmel_default_console_device = at91_uarts[portnr];
|
||||
at91cap9_set_console_clock(portnr);
|
||||
at91cap9_set_console_clock(at91_uarts[portnr]->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -199,9 +199,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
|
|||
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
|
||||
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
|
||||
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
|
||||
CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk),
|
||||
CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk),
|
||||
CLKDEV_CON_DEV_ID("ssc", "ssc.2", &ssc2_clk),
|
||||
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
|
||||
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
|
||||
CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
|
||||
};
|
||||
|
||||
static struct clk_lookup usart_clocks_lookups[] = {
|
||||
|
|
|
@ -1135,7 +1135,7 @@ void __init at91_set_serial_console(unsigned portnr)
|
|||
{
|
||||
if (portnr < ATMEL_MAX_UART) {
|
||||
atmel_default_console_device = at91_uarts[portnr];
|
||||
at91rm9200_set_console_clock(portnr);
|
||||
at91rm9200_set_console_clock(at91_uarts[portnr]->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1173,7 +1173,7 @@ void __init at91_set_serial_console(unsigned portnr)
|
|||
{
|
||||
if (portnr < ATMEL_MAX_UART) {
|
||||
atmel_default_console_device = at91_uarts[portnr];
|
||||
at91sam9260_set_console_clock(portnr);
|
||||
at91sam9260_set_console_clock(at91_uarts[portnr]->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1013,7 +1013,7 @@ void __init at91_set_serial_console(unsigned portnr)
|
|||
{
|
||||
if (portnr < ATMEL_MAX_UART) {
|
||||
atmel_default_console_device = at91_uarts[portnr];
|
||||
at91sam9261_set_console_clock(portnr);
|
||||
at91sam9261_set_console_clock(at91_uarts[portnr]->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1395,7 +1395,7 @@ void __init at91_set_serial_console(unsigned portnr)
|
|||
{
|
||||
if (portnr < ATMEL_MAX_UART) {
|
||||
atmel_default_console_device = at91_uarts[portnr];
|
||||
at91sam9263_set_console_clock(portnr);
|
||||
at91sam9263_set_console_clock(at91_uarts[portnr]->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -217,11 +217,11 @@ static struct clk *periph_clocks[] __initdata = {
|
|||
static struct clk_lookup periph_clocks_lookups[] = {
|
||||
/* One additional fake clock for ohci */
|
||||
CLKDEV_CON_ID("ohci_clk", &uhphs_clk),
|
||||
CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci.0", &uhphs_clk),
|
||||
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
|
||||
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
|
||||
CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
|
||||
CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
|
||||
CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci", &uhphs_clk),
|
||||
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
|
||||
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
|
||||
CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
|
||||
CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
|
||||
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
|
||||
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
|
||||
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
|
||||
|
|
|
@ -1550,7 +1550,7 @@ void __init at91_set_serial_console(unsigned portnr)
|
|||
{
|
||||
if (portnr < ATMEL_MAX_UART) {
|
||||
atmel_default_console_device = at91_uarts[portnr];
|
||||
at91sam9g45_set_console_clock(portnr);
|
||||
at91sam9g45_set_console_clock(at91_uarts[portnr]->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -191,8 +191,8 @@ static struct clk *periph_clocks[] __initdata = {
|
|||
};
|
||||
|
||||
static struct clk_lookup periph_clocks_lookups[] = {
|
||||
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
|
||||
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
|
||||
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
|
||||
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
|
||||
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
|
||||
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
|
||||
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
|
||||
|
|
|
@ -1168,7 +1168,7 @@ void __init at91_set_serial_console(unsigned portnr)
|
|||
{
|
||||
if (portnr < ATMEL_MAX_UART) {
|
||||
atmel_default_console_device = at91_uarts[portnr];
|
||||
at91sam9rl_set_console_clock(portnr);
|
||||
at91sam9rl_set_console_clock(at91_uarts[portnr]->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ static void __init cap9adk_add_device_nand(void)
|
|||
csa = at91_sys_read(AT91_MATRIX_EBICSA);
|
||||
at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
|
||||
|
||||
cap9adk_nand_data.bus_width_16 = !board_have_nand_8bit();
|
||||
cap9adk_nand_data.bus_width_16 = board_have_nand_16bit();
|
||||
/* setup bus-width (8 or 16) */
|
||||
if (cap9adk_nand_data.bus_width_16)
|
||||
cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_16;
|
||||
|
|
|
@ -214,7 +214,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
|
|||
|
||||
static void __init ek_add_device_nand(void)
|
||||
{
|
||||
ek_nand_data.bus_width_16 = !board_have_nand_8bit();
|
||||
ek_nand_data.bus_width_16 = board_have_nand_16bit();
|
||||
/* setup bus-width (8 or 16) */
|
||||
if (ek_nand_data.bus_width_16)
|
||||
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
|
||||
|
|
|
@ -220,7 +220,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
|
|||
|
||||
static void __init ek_add_device_nand(void)
|
||||
{
|
||||
ek_nand_data.bus_width_16 = !board_have_nand_8bit();
|
||||
ek_nand_data.bus_width_16 = board_have_nand_16bit();
|
||||
/* setup bus-width (8 or 16) */
|
||||
if (ek_nand_data.bus_width_16)
|
||||
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
|
||||
|
|
|
@ -221,7 +221,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
|
|||
|
||||
static void __init ek_add_device_nand(void)
|
||||
{
|
||||
ek_nand_data.bus_width_16 = !board_have_nand_8bit();
|
||||
ek_nand_data.bus_width_16 = board_have_nand_16bit();
|
||||
/* setup bus-width (8 or 16) */
|
||||
if (ek_nand_data.bus_width_16)
|
||||
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
|
||||
|
|
|
@ -198,7 +198,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
|
|||
|
||||
static void __init ek_add_device_nand(void)
|
||||
{
|
||||
ek_nand_data.bus_width_16 = !board_have_nand_8bit();
|
||||
ek_nand_data.bus_width_16 = board_have_nand_16bit();
|
||||
/* setup bus-width (8 or 16) */
|
||||
if (ek_nand_data.bus_width_16)
|
||||
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
|
||||
|
|
|
@ -178,7 +178,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
|
|||
|
||||
static void __init ek_add_device_nand(void)
|
||||
{
|
||||
ek_nand_data.bus_width_16 = !board_have_nand_8bit();
|
||||
ek_nand_data.bus_width_16 = board_have_nand_16bit();
|
||||
/* setup bus-width (8 or 16) */
|
||||
if (ek_nand_data.bus_width_16)
|
||||
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
* the 16-31 bit are reserved for at91 generic information
|
||||
*
|
||||
* bit 31:
|
||||
* 0 => nand 16 bit
|
||||
* 1 => nand 8 bit
|
||||
* 0 => nand 8 bit
|
||||
* 1 => nand 16 bit
|
||||
*/
|
||||
#define BOARD_HAVE_NAND_8BIT (1 << 31)
|
||||
static int inline board_have_nand_8bit(void)
|
||||
#define BOARD_HAVE_NAND_16BIT (1 << 31)
|
||||
static inline int board_have_nand_16bit(void)
|
||||
{
|
||||
return system_rev & BOARD_HAVE_NAND_8BIT;
|
||||
return system_rev & BOARD_HAVE_NAND_16BIT;
|
||||
}
|
||||
|
||||
#endif /* __ARCH_SYSTEM_REV_H__ */
|
||||
|
|
|
@ -251,9 +251,9 @@ static void ep93xx_uart_set_mctrl(struct amba_device *dev,
|
|||
unsigned int mcr;
|
||||
|
||||
mcr = 0;
|
||||
if (!(mctrl & TIOCM_RTS))
|
||||
if (mctrl & TIOCM_RTS)
|
||||
mcr |= 2;
|
||||
if (!(mctrl & TIOCM_DTR))
|
||||
if (mctrl & TIOCM_DTR)
|
||||
mcr |= 1;
|
||||
|
||||
__raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <plat/sdhci.h>
|
||||
#include <plat/devs.h>
|
||||
#include <plat/fimc-core.h>
|
||||
#include <plat/iic-core.h>
|
||||
|
||||
#include <mach/regs-irq.h>
|
||||
|
||||
|
@ -132,6 +133,11 @@ void __init exynos4_map_io(void)
|
|||
s3c_fimc_setname(1, "exynos4-fimc");
|
||||
s3c_fimc_setname(2, "exynos4-fimc");
|
||||
s3c_fimc_setname(3, "exynos4-fimc");
|
||||
|
||||
/* The I2C bus controllers are directly compatible with s3c2440 */
|
||||
s3c_i2c0_setname("s3c2440-i2c");
|
||||
s3c_i2c1_setname("s3c2440-i2c");
|
||||
s3c_i2c2_setname("s3c2440-i2c");
|
||||
}
|
||||
|
||||
void __init exynos4_init_clocks(int xtal)
|
||||
|
|
|
@ -330,7 +330,7 @@ struct platform_device exynos4_device_ac97 = {
|
|||
|
||||
static int exynos4_spdif_cfg_gpio(struct platform_device *pdev)
|
||||
{
|
||||
s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 2, S3C_GPIO_SFN(3));
|
||||
s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 2, S3C_GPIO_SFN(4));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <linux/linkage.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
__INIT
|
||||
__CPUINIT
|
||||
|
||||
/*
|
||||
* exynos4 specific entry point for secondary CPUs. This provides
|
||||
|
|
|
@ -35,6 +35,7 @@ void __init exynos4_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
|
|||
tcfg->clocks = exynos4_serial_clocks;
|
||||
tcfg->clocks_size = ARRAY_SIZE(exynos4_serial_clocks);
|
||||
}
|
||||
tcfg->flags |= NO_NEED_CHECK_CLKSRC;
|
||||
}
|
||||
|
||||
s3c24xx_init_uartdevs("s5pv210-uart", s5p_uart_resources, cfg, no);
|
||||
|
|
|
@ -78,9 +78,7 @@ static struct s3c2410_uartcfg smdkv310_uartcfgs[] __initdata = {
|
|||
};
|
||||
|
||||
static struct s3c_sdhci_platdata smdkv310_hsmmc0_pdata __initdata = {
|
||||
.cd_type = S3C_SDHCI_CD_GPIO,
|
||||
.ext_cd_gpio = EXYNOS4_GPK0(2),
|
||||
.ext_cd_gpio_invert = 1,
|
||||
.cd_type = S3C_SDHCI_CD_INTERNAL,
|
||||
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
|
||||
#ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT
|
||||
.max_width = 8,
|
||||
|
@ -96,9 +94,7 @@ static struct s3c_sdhci_platdata smdkv310_hsmmc1_pdata __initdata = {
|
|||
};
|
||||
|
||||
static struct s3c_sdhci_platdata smdkv310_hsmmc2_pdata __initdata = {
|
||||
.cd_type = S3C_SDHCI_CD_GPIO,
|
||||
.ext_cd_gpio = EXYNOS4_GPK2(2),
|
||||
.ext_cd_gpio_invert = 1,
|
||||
.cd_type = S3C_SDHCI_CD_INTERNAL,
|
||||
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
|
||||
#ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT
|
||||
.max_width = 8,
|
||||
|
|
|
@ -215,7 +215,7 @@ static struct omap_kp_platform_data ams_delta_kp_data __initdata = {
|
|||
.delay = 9,
|
||||
};
|
||||
|
||||
static struct platform_device ams_delta_kp_device __initdata = {
|
||||
static struct platform_device ams_delta_kp_device = {
|
||||
.name = "omap-keypad",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
|
@ -225,12 +225,12 @@ static struct platform_device ams_delta_kp_device __initdata = {
|
|||
.resource = ams_delta_kp_resources,
|
||||
};
|
||||
|
||||
static struct platform_device ams_delta_lcd_device __initdata = {
|
||||
static struct platform_device ams_delta_lcd_device = {
|
||||
.name = "lcd_ams_delta",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static struct platform_device ams_delta_led_device __initdata = {
|
||||
static struct platform_device ams_delta_led_device = {
|
||||
.name = "ams-delta-led",
|
||||
.id = -1
|
||||
};
|
||||
|
@ -267,7 +267,7 @@ static struct soc_camera_link ams_delta_iclink = {
|
|||
.power = ams_delta_camera_power,
|
||||
};
|
||||
|
||||
static struct platform_device ams_delta_camera_device __initdata = {
|
||||
static struct platform_device ams_delta_camera_device = {
|
||||
.name = "soc-camera-pdrv",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
|
|
|
@ -41,7 +41,7 @@ static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = {
|
|||
.bank_stride = 1,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap15xx_mpu_gpio = {
|
||||
static struct platform_device omap15xx_mpu_gpio = {
|
||||
.name = "omap_gpio",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
|
@ -70,7 +70,7 @@ static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = {
|
|||
.bank_width = 16,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap15xx_gpio = {
|
||||
static struct platform_device omap15xx_gpio = {
|
||||
.name = "omap_gpio",
|
||||
.id = 1,
|
||||
.dev = {
|
||||
|
|
|
@ -44,7 +44,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = {
|
|||
.bank_stride = 1,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap16xx_mpu_gpio = {
|
||||
static struct platform_device omap16xx_mpu_gpio = {
|
||||
.name = "omap_gpio",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
|
@ -73,7 +73,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = {
|
|||
.bank_width = 16,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap16xx_gpio1 = {
|
||||
static struct platform_device omap16xx_gpio1 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 1,
|
||||
.dev = {
|
||||
|
@ -102,7 +102,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = {
|
|||
.bank_width = 16,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap16xx_gpio2 = {
|
||||
static struct platform_device omap16xx_gpio2 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 2,
|
||||
.dev = {
|
||||
|
@ -131,7 +131,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = {
|
|||
.bank_width = 16,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap16xx_gpio3 = {
|
||||
static struct platform_device omap16xx_gpio3 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 3,
|
||||
.dev = {
|
||||
|
@ -160,7 +160,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = {
|
|||
.bank_width = 16,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap16xx_gpio4 = {
|
||||
static struct platform_device omap16xx_gpio4 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 4,
|
||||
.dev = {
|
||||
|
|
|
@ -46,7 +46,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = {
|
|||
.bank_stride = 2,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap7xx_mpu_gpio = {
|
||||
static struct platform_device omap7xx_mpu_gpio = {
|
||||
.name = "omap_gpio",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
|
@ -75,7 +75,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = {
|
|||
.bank_width = 32,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap7xx_gpio1 = {
|
||||
static struct platform_device omap7xx_gpio1 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 1,
|
||||
.dev = {
|
||||
|
@ -104,7 +104,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = {
|
|||
.bank_width = 32,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap7xx_gpio2 = {
|
||||
static struct platform_device omap7xx_gpio2 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 2,
|
||||
.dev = {
|
||||
|
@ -133,7 +133,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = {
|
|||
.bank_width = 32,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap7xx_gpio3 = {
|
||||
static struct platform_device omap7xx_gpio3 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 3,
|
||||
.dev = {
|
||||
|
@ -162,7 +162,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = {
|
|||
.bank_width = 32,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap7xx_gpio4 = {
|
||||
static struct platform_device omap7xx_gpio4 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 4,
|
||||
.dev = {
|
||||
|
@ -191,7 +191,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = {
|
|||
.bank_width = 32,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap7xx_gpio5 = {
|
||||
static struct platform_device omap7xx_gpio5 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 5,
|
||||
.dev = {
|
||||
|
@ -220,7 +220,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = {
|
|||
.bank_width = 32,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device omap7xx_gpio6 = {
|
||||
static struct platform_device omap7xx_gpio6 = {
|
||||
.name = "omap_gpio",
|
||||
.id = 6,
|
||||
.dev = {
|
||||
|
|
|
@ -558,7 +558,7 @@ static struct radio_si4713_platform_data rx51_si4713_data __initdata_or_module =
|
|||
.subdev_board_info = &rx51_si4713_board_info,
|
||||
};
|
||||
|
||||
static struct platform_device rx51_si4713_dev __initdata_or_module = {
|
||||
static struct platform_device rx51_si4713_dev = {
|
||||
.name = "radio-si4713",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
|
|
|
@ -552,7 +552,7 @@ struct mini2440_features_t {
|
|||
struct platform_device *optional[8];
|
||||
};
|
||||
|
||||
static void mini2440_parse_features(
|
||||
static void __init mini2440_parse_features(
|
||||
struct mini2440_features_t * features,
|
||||
const char * features_str )
|
||||
{
|
||||
|
|
|
@ -88,6 +88,7 @@ static struct s3c64xx_spi_info s3c64xx_spi0_pdata = {
|
|||
.cfg_gpio = s3c64xx_spi_cfg_gpio,
|
||||
.fifo_lvl_mask = 0x7f,
|
||||
.rx_lvl_offset = 13,
|
||||
.tx_st_done = 21,
|
||||
};
|
||||
|
||||
static u64 spi_dmamask = DMA_BIT_MASK(32);
|
||||
|
@ -132,6 +133,7 @@ static struct s3c64xx_spi_info s3c64xx_spi1_pdata = {
|
|||
.cfg_gpio = s3c64xx_spi_cfg_gpio,
|
||||
.fifo_lvl_mask = 0x7f,
|
||||
.rx_lvl_offset = 13,
|
||||
.tx_st_done = 21,
|
||||
};
|
||||
|
||||
struct platform_device s3c64xx_device_spi1 = {
|
||||
|
|
|
@ -112,12 +112,14 @@ static struct s3c64xx_spi_info s5p6440_spi0_pdata = {
|
|||
.cfg_gpio = s5p6440_spi_cfg_gpio,
|
||||
.fifo_lvl_mask = 0x1ff,
|
||||
.rx_lvl_offset = 15,
|
||||
.tx_st_done = 25,
|
||||
};
|
||||
|
||||
static struct s3c64xx_spi_info s5p6450_spi0_pdata = {
|
||||
.cfg_gpio = s5p6450_spi_cfg_gpio,
|
||||
.fifo_lvl_mask = 0x1ff,
|
||||
.rx_lvl_offset = 15,
|
||||
.tx_st_done = 25,
|
||||
};
|
||||
|
||||
static u64 spi_dmamask = DMA_BIT_MASK(32);
|
||||
|
@ -160,12 +162,14 @@ static struct s3c64xx_spi_info s5p6440_spi1_pdata = {
|
|||
.cfg_gpio = s5p6440_spi_cfg_gpio,
|
||||
.fifo_lvl_mask = 0x7f,
|
||||
.rx_lvl_offset = 15,
|
||||
.tx_st_done = 25,
|
||||
};
|
||||
|
||||
static struct s3c64xx_spi_info s5p6450_spi1_pdata = {
|
||||
.cfg_gpio = s5p6450_spi_cfg_gpio,
|
||||
.fifo_lvl_mask = 0x7f,
|
||||
.rx_lvl_offset = 15,
|
||||
.tx_st_done = 25,
|
||||
};
|
||||
|
||||
struct platform_device s5p64x0_device_spi1 = {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <mach/dma.h>
|
||||
#include <mach/map.h>
|
||||
#include <mach/spi-clocks.h>
|
||||
#include <mach/irqs.h>
|
||||
|
||||
#include <plat/s3c64xx-spi.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
|
@ -90,6 +91,7 @@ static struct s3c64xx_spi_info s5pc100_spi0_pdata = {
|
|||
.fifo_lvl_mask = 0x7f,
|
||||
.rx_lvl_offset = 13,
|
||||
.high_speed = 1,
|
||||
.tx_st_done = 21,
|
||||
};
|
||||
|
||||
static u64 spi_dmamask = DMA_BIT_MASK(32);
|
||||
|
@ -134,6 +136,7 @@ static struct s3c64xx_spi_info s5pc100_spi1_pdata = {
|
|||
.fifo_lvl_mask = 0x7f,
|
||||
.rx_lvl_offset = 13,
|
||||
.high_speed = 1,
|
||||
.tx_st_done = 21,
|
||||
};
|
||||
|
||||
struct platform_device s5pc100_device_spi1 = {
|
||||
|
@ -176,6 +179,7 @@ static struct s3c64xx_spi_info s5pc100_spi2_pdata = {
|
|||
.fifo_lvl_mask = 0x7f,
|
||||
.rx_lvl_offset = 13,
|
||||
.high_speed = 1,
|
||||
.tx_st_done = 21,
|
||||
};
|
||||
|
||||
struct platform_device s5pc100_device_spi2 = {
|
||||
|
|
|
@ -85,6 +85,7 @@ static struct s3c64xx_spi_info s5pv210_spi0_pdata = {
|
|||
.fifo_lvl_mask = 0x1ff,
|
||||
.rx_lvl_offset = 15,
|
||||
.high_speed = 1,
|
||||
.tx_st_done = 25,
|
||||
};
|
||||
|
||||
static u64 spi_dmamask = DMA_BIT_MASK(32);
|
||||
|
@ -129,6 +130,7 @@ static struct s3c64xx_spi_info s5pv210_spi1_pdata = {
|
|||
.fifo_lvl_mask = 0x7f,
|
||||
.rx_lvl_offset = 15,
|
||||
.high_speed = 1,
|
||||
.tx_st_done = 25,
|
||||
};
|
||||
|
||||
struct platform_device s5pv210_device_spi1 = {
|
||||
|
|
|
@ -381,7 +381,7 @@ void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state)
|
|||
gpio_set_value(GPIO_PORT114, state);
|
||||
}
|
||||
|
||||
static struct sh_mobile_sdhi_info sh_sdhi1_platdata = {
|
||||
static struct sh_mobile_sdhi_info sh_sdhi1_info = {
|
||||
.tmio_flags = TMIO_MMC_WRPROTECT_DISABLE,
|
||||
.tmio_caps = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ,
|
||||
.tmio_ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
|
||||
|
@ -413,7 +413,7 @@ static struct platform_device sdhi1_device = {
|
|||
.name = "sh_mobile_sdhi",
|
||||
.id = 1,
|
||||
.dev = {
|
||||
.platform_data = &sh_sdhi1_platdata,
|
||||
.platform_data = &sh_sdhi1_info,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(sdhi1_resources),
|
||||
.resource = sdhi1_resources,
|
||||
|
|
|
@ -913,7 +913,7 @@ static struct i2c_board_info imx074_info = {
|
|||
I2C_BOARD_INFO("imx074", 0x1a),
|
||||
};
|
||||
|
||||
struct soc_camera_link imx074_link = {
|
||||
static struct soc_camera_link imx074_link = {
|
||||
.bus_id = 0,
|
||||
.board_info = &imx074_info,
|
||||
.i2c_adapter_id = 0,
|
||||
|
|
|
@ -1287,9 +1287,9 @@ static struct platform_device *mackerel_devices[] __initdata = {
|
|||
&nor_flash_device,
|
||||
&smc911x_device,
|
||||
&lcdc_device,
|
||||
&usbhs0_device,
|
||||
&usb1_host_device,
|
||||
&usbhs1_device,
|
||||
&usbhs0_device,
|
||||
&leds_device,
|
||||
&fsi_device,
|
||||
&fsi_ak4643_device,
|
||||
|
|
|
@ -110,10 +110,18 @@ static pin_cfg_t mop500_pins_common[] = {
|
|||
GPIO168_KP_O0,
|
||||
|
||||
/* UART */
|
||||
GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
|
||||
GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
|
||||
GPIO2_U0_RXD | PIN_INPUT_PULLUP,
|
||||
GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
|
||||
/* uart-0 pins gpio configuration should be
|
||||
* kept intact to prevent glitch in tx line
|
||||
* when tty dev is opened. Later these pins
|
||||
* are configured to uart mop500_pins_uart0
|
||||
*
|
||||
* It will be replaced with uart configuration
|
||||
* once the issue is solved.
|
||||
*/
|
||||
GPIO0_GPIO | PIN_INPUT_PULLUP,
|
||||
GPIO1_GPIO | PIN_OUTPUT_HIGH,
|
||||
GPIO2_GPIO | PIN_INPUT_PULLUP,
|
||||
GPIO3_GPIO | PIN_OUTPUT_HIGH,
|
||||
|
||||
GPIO29_U2_RXD | PIN_INPUT_PULLUP,
|
||||
GPIO30_U2_TXD | PIN_OUTPUT_HIGH,
|
||||
|
|
|
@ -27,18 +27,21 @@
|
|||
#include <linux/leds-lp5521.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
#include <plat/ste_dma40.h>
|
||||
#include <plat/pincfg.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/setup.h>
|
||||
#include <mach/devices.h>
|
||||
#include <mach/irqs.h>
|
||||
|
||||
#include "pins-db8500.h"
|
||||
#include "ste-dma40-db8500.h"
|
||||
#include "devices-db8500.h"
|
||||
#include "board-mop500.h"
|
||||
|
@ -393,12 +396,63 @@ static struct stedma40_chan_cfg uart2_dma_cfg_tx = {
|
|||
};
|
||||
#endif
|
||||
|
||||
|
||||
static pin_cfg_t mop500_pins_uart0[] = {
|
||||
GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
|
||||
GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
|
||||
GPIO2_U0_RXD | PIN_INPUT_PULLUP,
|
||||
GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
|
||||
};
|
||||
|
||||
#define PRCC_K_SOFTRST_SET 0x18
|
||||
#define PRCC_K_SOFTRST_CLEAR 0x1C
|
||||
static void ux500_uart0_reset(void)
|
||||
{
|
||||
void __iomem *prcc_rst_set, *prcc_rst_clr;
|
||||
|
||||
prcc_rst_set = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
|
||||
PRCC_K_SOFTRST_SET);
|
||||
prcc_rst_clr = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
|
||||
PRCC_K_SOFTRST_CLEAR);
|
||||
|
||||
/* Activate soft reset PRCC_K_SOFTRST_CLEAR */
|
||||
writel((readl(prcc_rst_clr) | 0x1), prcc_rst_clr);
|
||||
udelay(1);
|
||||
|
||||
/* Release soft reset PRCC_K_SOFTRST_SET */
|
||||
writel((readl(prcc_rst_set) | 0x1), prcc_rst_set);
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
static void ux500_uart0_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nmk_config_pins(mop500_pins_uart0,
|
||||
ARRAY_SIZE(mop500_pins_uart0));
|
||||
if (ret < 0)
|
||||
pr_err("pl011: uart pins_enable failed\n");
|
||||
}
|
||||
|
||||
static void ux500_uart0_exit(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nmk_config_pins_sleep(mop500_pins_uart0,
|
||||
ARRAY_SIZE(mop500_pins_uart0));
|
||||
if (ret < 0)
|
||||
pr_err("pl011: uart pins_disable failed\n");
|
||||
}
|
||||
|
||||
static struct amba_pl011_data uart0_plat = {
|
||||
#ifdef CONFIG_STE_DMA40
|
||||
.dma_filter = stedma40_filter,
|
||||
.dma_rx_param = &uart0_dma_cfg_rx,
|
||||
.dma_tx_param = &uart0_dma_cfg_tx,
|
||||
#endif
|
||||
.init = ux500_uart0_init,
|
||||
.exit = ux500_uart0_exit,
|
||||
.reset = ux500_uart0_reset,
|
||||
};
|
||||
|
||||
static struct amba_pl011_data uart1_plat = {
|
||||
|
|
|
@ -39,9 +39,10 @@
|
|||
static void __iomem *ic_regbase;
|
||||
static void __iomem *sic_regbase;
|
||||
|
||||
static void vt8500_irq_mask(unsigned int irq)
|
||||
static void vt8500_irq_mask(struct irq_data *d)
|
||||
{
|
||||
void __iomem *base = ic_regbase;
|
||||
unsigned irq = d->irq;
|
||||
u8 edge;
|
||||
|
||||
if (irq >= 64) {
|
||||
|
@ -64,9 +65,10 @@ static void vt8500_irq_mask(unsigned int irq)
|
|||
}
|
||||
}
|
||||
|
||||
static void vt8500_irq_unmask(unsigned int irq)
|
||||
static void vt8500_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
void __iomem *base = ic_regbase;
|
||||
unsigned irq = d->irq;
|
||||
u8 dctr;
|
||||
|
||||
if (irq >= 64) {
|
||||
|
@ -78,10 +80,11 @@ static void vt8500_irq_unmask(unsigned int irq)
|
|||
writeb(dctr, base + VT8500_IC_DCTR + irq);
|
||||
}
|
||||
|
||||
static int vt8500_irq_set_type(unsigned int irq, unsigned int flow_type)
|
||||
static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
{
|
||||
void __iomem *base = ic_regbase;
|
||||
unsigned int orig_irq = irq;
|
||||
unsigned irq = d->irq;
|
||||
unsigned orig_irq = irq;
|
||||
u8 dctr;
|
||||
|
||||
if (irq >= 64) {
|
||||
|
@ -114,11 +117,11 @@ static int vt8500_irq_set_type(unsigned int irq, unsigned int flow_type)
|
|||
}
|
||||
|
||||
static struct irq_chip vt8500_irq_chip = {
|
||||
.name = "vt8500",
|
||||
.ack = vt8500_irq_mask,
|
||||
.mask = vt8500_irq_mask,
|
||||
.unmask = vt8500_irq_unmask,
|
||||
.set_type = vt8500_irq_set_type,
|
||||
.name = "vt8500",
|
||||
.irq_ack = vt8500_irq_mask,
|
||||
.irq_mask = vt8500_irq_mask,
|
||||
.irq_unmask = vt8500_irq_unmask,
|
||||
.irq_set_type = vt8500_irq_set_type,
|
||||
};
|
||||
|
||||
void __init vt8500_init_irq(void)
|
||||
|
|
|
@ -120,17 +120,22 @@ static void l2x0_cache_sync(void)
|
|||
spin_unlock_irqrestore(&l2x0_lock, flags);
|
||||
}
|
||||
|
||||
static void __l2x0_flush_all(void)
|
||||
{
|
||||
debug_writel(0x03);
|
||||
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY);
|
||||
cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask);
|
||||
cache_sync();
|
||||
debug_writel(0x00);
|
||||
}
|
||||
|
||||
static void l2x0_flush_all(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/* clean all ways */
|
||||
spin_lock_irqsave(&l2x0_lock, flags);
|
||||
debug_writel(0x03);
|
||||
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY);
|
||||
cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask);
|
||||
cache_sync();
|
||||
debug_writel(0x00);
|
||||
__l2x0_flush_all();
|
||||
spin_unlock_irqrestore(&l2x0_lock, flags);
|
||||
}
|
||||
|
||||
|
@ -266,7 +271,9 @@ static void l2x0_disable(void)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&l2x0_lock, flags);
|
||||
writel(0, l2x0_base + L2X0_CTRL);
|
||||
__l2x0_flush_all();
|
||||
writel_relaxed(0, l2x0_base + L2X0_CTRL);
|
||||
dsb();
|
||||
spin_unlock_irqrestore(&l2x0_lock, flags);
|
||||
}
|
||||
|
||||
|
|
|
@ -759,7 +759,7 @@ early_param("vmalloc", early_vmalloc);
|
|||
|
||||
static phys_addr_t lowmem_limit __initdata = 0;
|
||||
|
||||
static void __init sanity_check_meminfo(void)
|
||||
void __init sanity_check_meminfo(void)
|
||||
{
|
||||
int i, j, highmem = 0;
|
||||
|
||||
|
@ -1032,8 +1032,9 @@ void __init paging_init(struct machine_desc *mdesc)
|
|||
{
|
||||
void *zero_page;
|
||||
|
||||
memblock_set_current_limit(lowmem_limit);
|
||||
|
||||
build_mem_type_table();
|
||||
sanity_check_meminfo();
|
||||
prepare_page_table();
|
||||
map_lowmem();
|
||||
devicemaps_init(mdesc);
|
||||
|
|
|
@ -27,6 +27,10 @@ void __init arm_mm_memblock_reserve(void)
|
|||
memblock_reserve(CONFIG_VECTORS_BASE, PAGE_SIZE);
|
||||
}
|
||||
|
||||
void __init sanity_check_meminfo(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* paging_init() sets up the page tables, initialises the zone memory
|
||||
* maps, and sets up the zero page, bad page and bad page tables.
|
||||
|
|
|
@ -1027,17 +1027,13 @@ int s3c2410_dma_config(unsigned int channel,
|
|||
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
|
||||
unsigned int dcon;
|
||||
|
||||
pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
|
||||
__func__, channel, xferunit, dcon);
|
||||
pr_debug("%s: chan=%d, xfer_unit=%d\n", __func__, channel, xferunit);
|
||||
|
||||
if (chan == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("%s: Initial dcon is %08x\n", __func__, dcon);
|
||||
|
||||
dcon = chan->dcon & dma_sel.dcon_mask;
|
||||
|
||||
pr_debug("%s: New dcon is %08x\n", __func__, dcon);
|
||||
pr_debug("%s: dcon is %08x\n", __func__, dcon);
|
||||
|
||||
switch (chan->req_ch) {
|
||||
case DMACH_I2S_IN:
|
||||
|
@ -1235,7 +1231,7 @@ static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp)
|
|||
/* restore channel's hardware configuration */
|
||||
|
||||
if (!cp->in_use)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
|
||||
|
||||
|
@ -1246,8 +1242,6 @@ static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp)
|
|||
|
||||
if (cp->map != NULL)
|
||||
dma_sel.select(cp, cp->map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s3c2410_dma_resume(void)
|
||||
|
|
|
@ -370,11 +370,11 @@ static void __init s5p_clocksource_init(void)
|
|||
|
||||
clock_rate = clk_get_rate(tin_source);
|
||||
|
||||
init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate);
|
||||
|
||||
s5p_time_setup(timer_source.source_id, TCNT_MAX);
|
||||
s5p_time_start(timer_source.source_id, PERIODIC);
|
||||
|
||||
init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate);
|
||||
|
||||
if (clocksource_register_hz(&time_clocksource, clock_rate))
|
||||
panic("%s: can't register clocksource\n", time_clocksource.name);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __PLAT_DEVS_H
|
||||
#define __PLAT_DEVS_H __FILE__
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
struct s3c24xx_uart_resources {
|
||||
|
@ -159,3 +163,5 @@ extern struct platform_device s3c_device_ac97;
|
|||
*/
|
||||
extern void *s3c_set_platdata(void *pd, size_t pdsize,
|
||||
struct platform_device *pdev);
|
||||
|
||||
#endif /* __PLAT_DEVS_H */
|
||||
|
|
|
@ -224,6 +224,8 @@
|
|||
#define S5PV210_UFSTAT_RXMASK (255<<0)
|
||||
#define S5PV210_UFSTAT_RXSHIFT (0)
|
||||
|
||||
#define NO_NEED_CHECK_CLKSRC 1
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/* struct s3c24xx_uart_clksrc
|
||||
|
|
|
@ -39,6 +39,7 @@ struct s3c64xx_spi_csinfo {
|
|||
* @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6
|
||||
* @rx_lvl_offset: Depends on tx fifo_lvl field and bus number
|
||||
* @high_speed: If the controller supports HIGH_SPEED_EN bit
|
||||
* @tx_st_done: Depends on tx fifo_lvl field
|
||||
*/
|
||||
struct s3c64xx_spi_info {
|
||||
int src_clk_nr;
|
||||
|
@ -53,6 +54,7 @@ struct s3c64xx_spi_info {
|
|||
int fifo_lvl_mask;
|
||||
int rx_lvl_offset;
|
||||
int high_speed;
|
||||
int tx_st_done;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -209,8 +209,10 @@
|
|||
wm8776:codec@1a {
|
||||
compatible = "wlf,wm8776";
|
||||
reg = <0x1a>;
|
||||
/* MCLK source is a stand-alone oscillator */
|
||||
clock-frequency = <12288000>;
|
||||
/*
|
||||
* clock-frequency will be set by U-Boot if
|
||||
* the clock is enabled.
|
||||
*/
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -280,7 +282,8 @@
|
|||
codec-handle = <&wm8776>;
|
||||
fsl,playback-dma = <&dma00>;
|
||||
fsl,capture-dma = <&dma01>;
|
||||
fsl,fifo-depth = <16>;
|
||||
fsl,fifo-depth = <15>;
|
||||
fsl,ssi-asynchronous;
|
||||
};
|
||||
|
||||
dma@c300 {
|
||||
|
|
|
@ -148,7 +148,6 @@ CONFIG_SCSI_SAS_ATTRS=m
|
|||
CONFIG_SCSI_CXGB3_ISCSI=m
|
||||
CONFIG_SCSI_CXGB4_ISCSI=m
|
||||
CONFIG_SCSI_BNX2_ISCSI=m
|
||||
CONFIG_SCSI_BNX2_ISCSI=m
|
||||
CONFIG_BE2ISCSI=m
|
||||
CONFIG_SCSI_IBMVSCSI=y
|
||||
CONFIG_SCSI_IBMVFC=m
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/rtas.h>
|
||||
#include <asm/time.h>
|
||||
|
@ -29,9 +30,10 @@ unsigned long __init rtas_get_boot_time(void)
|
|||
}
|
||||
} while (wait_time && (get_tb() < max_wait_tb));
|
||||
|
||||
if (error != 0 && printk_ratelimit()) {
|
||||
printk(KERN_WARNING "error: reading the clock failed (%d)\n",
|
||||
error);
|
||||
if (error != 0) {
|
||||
printk_ratelimited(KERN_WARNING
|
||||
"error: reading the clock failed (%d)\n",
|
||||
error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -55,19 +57,21 @@ void rtas_get_rtc_time(struct rtc_time *rtc_tm)
|
|||
|
||||
wait_time = rtas_busy_delay_time(error);
|
||||
if (wait_time) {
|
||||
if (in_interrupt() && printk_ratelimit()) {
|
||||
if (in_interrupt()) {
|
||||
memset(rtc_tm, 0, sizeof(struct rtc_time));
|
||||
printk(KERN_WARNING "error: reading clock"
|
||||
" would delay interrupt\n");
|
||||
printk_ratelimited(KERN_WARNING
|
||||
"error: reading clock "
|
||||
"would delay interrupt\n");
|
||||
return; /* delay not allowed */
|
||||
}
|
||||
msleep(wait_time);
|
||||
}
|
||||
} while (wait_time && (get_tb() < max_wait_tb));
|
||||
|
||||
if (error != 0 && printk_ratelimit()) {
|
||||
printk(KERN_WARNING "error: reading the clock failed (%d)\n",
|
||||
error);
|
||||
if (error != 0) {
|
||||
printk_ratelimited(KERN_WARNING
|
||||
"error: reading the clock failed (%d)\n",
|
||||
error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -99,9 +103,10 @@ int rtas_set_rtc_time(struct rtc_time *tm)
|
|||
}
|
||||
} while (wait_time && (get_tb() < max_wait_tb));
|
||||
|
||||
if (error != 0 && printk_ratelimit())
|
||||
printk(KERN_WARNING "error: setting the clock failed (%d)\n",
|
||||
error);
|
||||
if (error != 0)
|
||||
printk_ratelimited(KERN_WARNING
|
||||
"error: setting the clock failed (%d)\n",
|
||||
error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#ifdef CONFIG_PPC64
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/compat.h>
|
||||
|
@ -892,11 +893,12 @@ badframe:
|
|||
printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",
|
||||
regs, frame, newsp);
|
||||
#endif
|
||||
if (show_unhandled_signals && printk_ratelimit())
|
||||
printk(KERN_INFO "%s[%d]: bad frame in handle_rt_signal32: "
|
||||
"%p nip %08lx lr %08lx\n",
|
||||
current->comm, current->pid,
|
||||
addr, regs->nip, regs->link);
|
||||
if (show_unhandled_signals)
|
||||
printk_ratelimited(KERN_INFO
|
||||
"%s[%d]: bad frame in handle_rt_signal32: "
|
||||
"%p nip %08lx lr %08lx\n",
|
||||
current->comm, current->pid,
|
||||
addr, regs->nip, regs->link);
|
||||
|
||||
force_sigsegv(sig, current);
|
||||
return 0;
|
||||
|
@ -1058,11 +1060,12 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
|
|||
return 0;
|
||||
|
||||
bad:
|
||||
if (show_unhandled_signals && printk_ratelimit())
|
||||
printk(KERN_INFO "%s[%d]: bad frame in sys_rt_sigreturn: "
|
||||
"%p nip %08lx lr %08lx\n",
|
||||
current->comm, current->pid,
|
||||
rt_sf, regs->nip, regs->link);
|
||||
if (show_unhandled_signals)
|
||||
printk_ratelimited(KERN_INFO
|
||||
"%s[%d]: bad frame in sys_rt_sigreturn: "
|
||||
"%p nip %08lx lr %08lx\n",
|
||||
current->comm, current->pid,
|
||||
rt_sf, regs->nip, regs->link);
|
||||
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
|
@ -1149,12 +1152,12 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
|
|||
* We kill the task with a SIGSEGV in this situation.
|
||||
*/
|
||||
if (do_setcontext(ctx, regs, 1)) {
|
||||
if (show_unhandled_signals && printk_ratelimit())
|
||||
printk(KERN_INFO "%s[%d]: bad frame in "
|
||||
"sys_debug_setcontext: %p nip %08lx "
|
||||
"lr %08lx\n",
|
||||
current->comm, current->pid,
|
||||
ctx, regs->nip, regs->link);
|
||||
if (show_unhandled_signals)
|
||||
printk_ratelimited(KERN_INFO "%s[%d]: bad frame in "
|
||||
"sys_debug_setcontext: %p nip %08lx "
|
||||
"lr %08lx\n",
|
||||
current->comm, current->pid,
|
||||
ctx, regs->nip, regs->link);
|
||||
|
||||
force_sig(SIGSEGV, current);
|
||||
goto out;
|
||||
|
@ -1236,11 +1239,12 @@ badframe:
|
|||
printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n",
|
||||
regs, frame, newsp);
|
||||
#endif
|
||||
if (show_unhandled_signals && printk_ratelimit())
|
||||
printk(KERN_INFO "%s[%d]: bad frame in handle_signal32: "
|
||||
"%p nip %08lx lr %08lx\n",
|
||||
current->comm, current->pid,
|
||||
frame, regs->nip, regs->link);
|
||||
if (show_unhandled_signals)
|
||||
printk_ratelimited(KERN_INFO
|
||||
"%s[%d]: bad frame in handle_signal32: "
|
||||
"%p nip %08lx lr %08lx\n",
|
||||
current->comm, current->pid,
|
||||
frame, regs->nip, regs->link);
|
||||
|
||||
force_sigsegv(sig, current);
|
||||
return 0;
|
||||
|
@ -1288,11 +1292,12 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
|
|||
return 0;
|
||||
|
||||
badframe:
|
||||
if (show_unhandled_signals && printk_ratelimit())
|
||||
printk(KERN_INFO "%s[%d]: bad frame in sys_sigreturn: "
|
||||
"%p nip %08lx lr %08lx\n",
|
||||
current->comm, current->pid,
|
||||
addr, regs->nip, regs->link);
|
||||
if (show_unhandled_signals)
|
||||
printk_ratelimited(KERN_INFO
|
||||
"%s[%d]: bad frame in sys_sigreturn: "
|
||||
"%p nip %08lx lr %08lx\n",
|
||||
current->comm, current->pid,
|
||||
addr, regs->nip, regs->link);
|
||||
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/elf.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
#include <asm/sigcontext.h>
|
||||
#include <asm/ucontext.h>
|
||||
|
@ -380,10 +381,10 @@ badframe:
|
|||
printk("badframe in sys_rt_sigreturn, regs=%p uc=%p &uc->uc_mcontext=%p\n",
|
||||
regs, uc, &uc->uc_mcontext);
|
||||
#endif
|
||||
if (show_unhandled_signals && printk_ratelimit())
|
||||
printk(regs->msr & MSR_64BIT ? fmt64 : fmt32,
|
||||
current->comm, current->pid, "rt_sigreturn",
|
||||
(long)uc, regs->nip, regs->link);
|
||||
if (show_unhandled_signals)
|
||||
printk_ratelimited(regs->msr & MSR_64BIT ? fmt64 : fmt32,
|
||||
current->comm, current->pid, "rt_sigreturn",
|
||||
(long)uc, regs->nip, regs->link);
|
||||
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
|
@ -468,10 +469,10 @@ badframe:
|
|||
printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
|
||||
regs, frame, newsp);
|
||||
#endif
|
||||
if (show_unhandled_signals && printk_ratelimit())
|
||||
printk(regs->msr & MSR_64BIT ? fmt64 : fmt32,
|
||||
current->comm, current->pid, "setup_rt_frame",
|
||||
(long)frame, regs->nip, regs->link);
|
||||
if (show_unhandled_signals)
|
||||
printk_ratelimited(regs->msr & MSR_64BIT ? fmt64 : fmt32,
|
||||
current->comm, current->pid, "setup_rt_frame",
|
||||
(long)frame, regs->nip, regs->link);
|
||||
|
||||
force_sigsegv(signr, current);
|
||||
return 0;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/bug.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
#include <asm/emulated_ops.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
@ -197,12 +198,11 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
|
|||
if (die("Exception in kernel mode", regs, signr))
|
||||
return;
|
||||
} else if (show_unhandled_signals &&
|
||||
unhandled_signal(current, signr) &&
|
||||
printk_ratelimit()) {
|
||||
printk(regs->msr & MSR_64BIT ? fmt64 : fmt32,
|
||||
current->comm, current->pid, signr,
|
||||
addr, regs->nip, regs->link, code);
|
||||
}
|
||||
unhandled_signal(current, signr)) {
|
||||
printk_ratelimited(regs->msr & MSR_64BIT ? fmt64 : fmt32,
|
||||
current->comm, current->pid, signr,
|
||||
addr, regs->nip, regs->link, code);
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.si_signo = signr;
|
||||
|
@ -425,7 +425,7 @@ int machine_check_e500mc(struct pt_regs *regs)
|
|||
unsigned long reason = mcsr;
|
||||
int recoverable = 1;
|
||||
|
||||
if (reason & MCSR_BUS_RBERR) {
|
||||
if (reason & MCSR_LD) {
|
||||
recoverable = fsl_rio_mcheck_exception(regs);
|
||||
if (recoverable == 1)
|
||||
goto silent_out;
|
||||
|
@ -1342,9 +1342,8 @@ void altivec_assist_exception(struct pt_regs *regs)
|
|||
} else {
|
||||
/* didn't recognize the instruction */
|
||||
/* XXX quick hack for now: set the non-Java bit in the VSCR */
|
||||
if (printk_ratelimit())
|
||||
printk(KERN_ERR "Unrecognized altivec instruction "
|
||||
"in %s at %lx\n", current->comm, regs->nip);
|
||||
printk_ratelimited(KERN_ERR "Unrecognized altivec instruction "
|
||||
"in %s at %lx\n", current->comm, regs->nip);
|
||||
current->thread.vscr.u[3] |= 0x10000;
|
||||
}
|
||||
}
|
||||
|
@ -1548,9 +1547,8 @@ u32 ppc_warn_emulated;
|
|||
|
||||
void ppc_warn_emulated_print(const char *type)
|
||||
{
|
||||
if (printk_ratelimit())
|
||||
pr_warning("%s used emulated %s instruction\n", current->comm,
|
||||
type);
|
||||
pr_warn_ratelimited("%s used emulated %s instruction\n", current->comm,
|
||||
type);
|
||||
}
|
||||
|
||||
static int __init ppc_warn_emulated_init(void)
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/kdebug.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
#include <asm/firmware.h>
|
||||
#include <asm/page.h>
|
||||
|
@ -346,11 +347,10 @@ bad_area_nosemaphore:
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (is_exec && (error_code & DSISR_PROTFAULT)
|
||||
&& printk_ratelimit())
|
||||
printk(KERN_CRIT "kernel tried to execute NX-protected"
|
||||
" page (%lx) - exploit attempt? (uid: %d)\n",
|
||||
address, current_uid());
|
||||
if (is_exec && (error_code & DSISR_PROTFAULT))
|
||||
printk_ratelimited(KERN_CRIT "kernel tried to execute NX-protected"
|
||||
" page (%lx) - exploit attempt? (uid: %d)\n",
|
||||
address, current_uid());
|
||||
|
||||
return SIGSEGV;
|
||||
|
||||
|
|
|
@ -283,23 +283,24 @@ static void __iomem *rio_regs_win;
|
|||
#ifdef CONFIG_E500
|
||||
int fsl_rio_mcheck_exception(struct pt_regs *regs)
|
||||
{
|
||||
const struct exception_table_entry *entry = NULL;
|
||||
unsigned long reason = mfspr(SPRN_MCSR);
|
||||
const struct exception_table_entry *entry;
|
||||
unsigned long reason;
|
||||
|
||||
if (reason & MCSR_BUS_RBERR) {
|
||||
reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR));
|
||||
if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) {
|
||||
/* Check if we are prepared to handle this fault */
|
||||
entry = search_exception_tables(regs->nip);
|
||||
if (entry) {
|
||||
pr_debug("RIO: %s - MC Exception handled\n",
|
||||
__func__);
|
||||
out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR),
|
||||
0);
|
||||
regs->msr |= MSR_RI;
|
||||
regs->nip = entry->fixup;
|
||||
return 1;
|
||||
}
|
||||
if (!rio_regs_win)
|
||||
return 0;
|
||||
|
||||
reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR));
|
||||
if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) {
|
||||
/* Check if we are prepared to handle this fault */
|
||||
entry = search_exception_tables(regs->nip);
|
||||
if (entry) {
|
||||
pr_debug("RIO: %s - MC Exception handled\n",
|
||||
__func__);
|
||||
out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR),
|
||||
0);
|
||||
regs->msr |= MSR_RI;
|
||||
regs->nip = entry->fixup;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/signal.h>
|
||||
|
@ -1648,9 +1649,8 @@ static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg)
|
|||
return NO_IRQ;
|
||||
}
|
||||
if (unlikely(mpic->protected && test_bit(src, mpic->protected))) {
|
||||
if (printk_ratelimit())
|
||||
printk(KERN_WARNING "%s: Got protected source %d !\n",
|
||||
mpic->name, (int)src);
|
||||
printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n",
|
||||
mpic->name, (int)src);
|
||||
mpic_eoi(mpic);
|
||||
return NO_IRQ;
|
||||
}
|
||||
|
@ -1688,9 +1688,8 @@ unsigned int mpic_get_coreint_irq(void)
|
|||
return NO_IRQ;
|
||||
}
|
||||
if (unlikely(mpic->protected && test_bit(src, mpic->protected))) {
|
||||
if (printk_ratelimit())
|
||||
printk(KERN_WARNING "%s: Got protected source %d !\n",
|
||||
mpic->name, (int)src);
|
||||
printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n",
|
||||
mpic->name, (int)src);
|
||||
return NO_IRQ;
|
||||
}
|
||||
|
||||
|
|
|
@ -348,6 +348,7 @@ config CPU_SUBTYPE_SH7720
|
|||
select SYS_SUPPORTS_CMT
|
||||
select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||
select USB_ARCH_HAS_OHCI
|
||||
select USB_OHCI_SH if USB_OHCI_HCD
|
||||
help
|
||||
Select SH7720 if you have a SH3-DSP SH7720 CPU.
|
||||
|
||||
|
@ -357,6 +358,7 @@ config CPU_SUBTYPE_SH7721
|
|||
select CPU_HAS_DSP
|
||||
select SYS_SUPPORTS_CMT
|
||||
select USB_ARCH_HAS_OHCI
|
||||
select USB_OHCI_SH if USB_OHCI_HCD
|
||||
help
|
||||
Select SH7721 if you have a SH3-DSP SH7721 CPU.
|
||||
|
||||
|
@ -440,6 +442,7 @@ config CPU_SUBTYPE_SH7763
|
|||
bool "Support SH7763 processor"
|
||||
select CPU_SH4A
|
||||
select USB_ARCH_HAS_OHCI
|
||||
select USB_OHCI_SH if USB_OHCI_HCD
|
||||
help
|
||||
Select SH7763 if you have a SH4A SH7763(R5S77631) CPU.
|
||||
|
||||
|
@ -467,7 +470,9 @@ config CPU_SUBTYPE_SH7786
|
|||
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
|
||||
select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||
select USB_ARCH_HAS_OHCI
|
||||
select USB_OHCI_SH if USB_OHCI_HCD
|
||||
select USB_ARCH_HAS_EHCI
|
||||
select USB_EHCI_SH if USB_EHCI_HCD
|
||||
|
||||
config CPU_SUBTYPE_SHX3
|
||||
bool "Support SH-X3 processor"
|
||||
|
|
|
@ -9,7 +9,6 @@ CONFIG_TASK_XACCT=y
|
|||
CONFIG_TASK_IO_ACCOUNTING=y
|
||||
CONFIG_LOG_BUF_SHIFT=14
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
|
||||
# CONFIG_SYSCTL_SYSCALL is not set
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_SLAB=y
|
||||
|
@ -39,8 +38,6 @@ CONFIG_IPV6=y
|
|||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
# CONFIG_FW_LOADER is not set
|
||||
CONFIG_MTD=y
|
||||
CONFIG_MTD_CONCAT=y
|
||||
CONFIG_MTD_PARTITIONS=y
|
||||
CONFIG_MTD_CHAR=y
|
||||
CONFIG_MTD_BLOCK=y
|
||||
CONFIG_MTD_M25P80=y
|
||||
|
@ -56,18 +53,19 @@ CONFIG_SH_ETH=y
|
|||
# CONFIG_KEYBOARD_ATKBD is not set
|
||||
# CONFIG_MOUSE_PS2 is not set
|
||||
# CONFIG_SERIO is not set
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
CONFIG_SERIAL_SH_SCI=y
|
||||
CONFIG_SERIAL_SH_SCI_NR_UARTS=3
|
||||
CONFIG_SERIAL_SH_SCI_CONSOLE=y
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
CONFIG_SPI=y
|
||||
CONFIG_SPI_SH=y
|
||||
# CONFIG_HWMON is not set
|
||||
CONFIG_MFD_SH_MOBILE_SDHI=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
CONFIG_USB_EHCI_SH=y
|
||||
CONFIG_USB_OHCI_HCD=y
|
||||
CONFIG_USB_OHCI_SH=y
|
||||
CONFIG_USB_STORAGE=y
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_SDHI=y
|
||||
|
|
|
@ -183,7 +183,7 @@ static const struct sh_dmae_slave_config sh7757_dmae1_slaves[] = {
|
|||
{
|
||||
.slave_id = SHDMA_SLAVE_SCIF2_RX,
|
||||
.addr = 0x1f4b0014,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0x22,
|
||||
},
|
||||
|
@ -197,7 +197,7 @@ static const struct sh_dmae_slave_config sh7757_dmae1_slaves[] = {
|
|||
{
|
||||
.slave_id = SHDMA_SLAVE_SCIF3_RX,
|
||||
.addr = 0x1f4c0014,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0x2a,
|
||||
},
|
||||
|
@ -211,7 +211,7 @@ static const struct sh_dmae_slave_config sh7757_dmae1_slaves[] = {
|
|||
{
|
||||
.slave_id = SHDMA_SLAVE_SCIF4_RX,
|
||||
.addr = 0x1f4d0014,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0x42,
|
||||
},
|
||||
|
@ -228,7 +228,7 @@ static const struct sh_dmae_slave_config sh7757_dmae2_slaves[] = {
|
|||
{
|
||||
.slave_id = SHDMA_SLAVE_RIIC0_RX,
|
||||
.addr = 0x1e500013,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0x22,
|
||||
},
|
||||
|
@ -242,7 +242,7 @@ static const struct sh_dmae_slave_config sh7757_dmae2_slaves[] = {
|
|||
{
|
||||
.slave_id = SHDMA_SLAVE_RIIC1_RX,
|
||||
.addr = 0x1e510013,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0x2a,
|
||||
},
|
||||
|
@ -256,7 +256,7 @@ static const struct sh_dmae_slave_config sh7757_dmae2_slaves[] = {
|
|||
{
|
||||
.slave_id = SHDMA_SLAVE_RIIC2_RX,
|
||||
.addr = 0x1e520013,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0xa2,
|
||||
},
|
||||
|
@ -265,12 +265,12 @@ static const struct sh_dmae_slave_config sh7757_dmae2_slaves[] = {
|
|||
.addr = 0x1e530012,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0xab,
|
||||
.mid_rid = 0xa9,
|
||||
},
|
||||
{
|
||||
.slave_id = SHDMA_SLAVE_RIIC3_RX,
|
||||
.addr = 0x1e530013,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0xaf,
|
||||
},
|
||||
|
@ -279,14 +279,14 @@ static const struct sh_dmae_slave_config sh7757_dmae2_slaves[] = {
|
|||
.addr = 0x1e540012,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0xc1,
|
||||
.mid_rid = 0xc5,
|
||||
},
|
||||
{
|
||||
.slave_id = SHDMA_SLAVE_RIIC4_RX,
|
||||
.addr = 0x1e540013,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0xc2,
|
||||
.mid_rid = 0xc6,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -301,7 +301,7 @@ static const struct sh_dmae_slave_config sh7757_dmae3_slaves[] = {
|
|||
{
|
||||
.slave_id = SHDMA_SLAVE_RIIC5_RX,
|
||||
.addr = 0x1e550013,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0x22,
|
||||
},
|
||||
|
@ -315,7 +315,7 @@ static const struct sh_dmae_slave_config sh7757_dmae3_slaves[] = {
|
|||
{
|
||||
.slave_id = SHDMA_SLAVE_RIIC6_RX,
|
||||
.addr = 0x1e560013,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0x2a,
|
||||
},
|
||||
|
@ -329,7 +329,7 @@ static const struct sh_dmae_slave_config sh7757_dmae3_slaves[] = {
|
|||
{
|
||||
.slave_id = SHDMA_SLAVE_RIIC7_RX,
|
||||
.addr = 0x1e570013,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0x42,
|
||||
},
|
||||
|
@ -343,7 +343,7 @@ static const struct sh_dmae_slave_config sh7757_dmae3_slaves[] = {
|
|||
{
|
||||
.slave_id = SHDMA_SLAVE_RIIC8_RX,
|
||||
.addr = 0x1e580013,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0x46,
|
||||
},
|
||||
|
@ -357,7 +357,7 @@ static const struct sh_dmae_slave_config sh7757_dmae3_slaves[] = {
|
|||
{
|
||||
.slave_id = SHDMA_SLAVE_RIIC9_RX,
|
||||
.addr = 0x1e590013,
|
||||
.chcr = SM_INC | 0x800 | 0x40000000 |
|
||||
.chcr = DM_INC | 0x800 | 0x40000000 |
|
||||
TS_INDEX2VAL(XMIT_SZ_8BIT),
|
||||
.mid_rid = 0x52,
|
||||
},
|
||||
|
@ -659,6 +659,54 @@ static struct platform_device spi0_device = {
|
|||
.resource = spi0_resources,
|
||||
};
|
||||
|
||||
static struct resource usb_ehci_resources[] = {
|
||||
[0] = {
|
||||
.start = 0xfe4f1000,
|
||||
.end = 0xfe4f10ff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = 57,
|
||||
.end = 57,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device usb_ehci_device = {
|
||||
.name = "sh_ehci",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &usb_ehci_device.dev.coherent_dma_mask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(usb_ehci_resources),
|
||||
.resource = usb_ehci_resources,
|
||||
};
|
||||
|
||||
static struct resource usb_ohci_resources[] = {
|
||||
[0] = {
|
||||
.start = 0xfe4f1800,
|
||||
.end = 0xfe4f18ff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = 57,
|
||||
.end = 57,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device usb_ohci_device = {
|
||||
.name = "sh_ohci",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &usb_ohci_device.dev.coherent_dma_mask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(usb_ohci_resources),
|
||||
.resource = usb_ohci_resources,
|
||||
};
|
||||
|
||||
static struct platform_device *sh7757_devices[] __initdata = {
|
||||
&scif2_device,
|
||||
&scif3_device,
|
||||
|
@ -670,6 +718,8 @@ static struct platform_device *sh7757_devices[] __initdata = {
|
|||
&dma2_device,
|
||||
&dma3_device,
|
||||
&spi0_device,
|
||||
&usb_ehci_device,
|
||||
&usb_ohci_device,
|
||||
};
|
||||
|
||||
static int __init sh7757_devices_setup(void)
|
||||
|
@ -1039,13 +1089,13 @@ static DECLARE_INTC_DESC(intc_desc, "sh7757", vectors, groups,
|
|||
|
||||
/* Support for external interrupt pins in IRQ mode */
|
||||
static struct intc_vect vectors_irq0123[] __initdata = {
|
||||
INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
|
||||
INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
|
||||
INTC_VECT(IRQ0, 0x200), INTC_VECT(IRQ1, 0x240),
|
||||
INTC_VECT(IRQ2, 0x280), INTC_VECT(IRQ3, 0x2c0),
|
||||
};
|
||||
|
||||
static struct intc_vect vectors_irq4567[] __initdata = {
|
||||
INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
|
||||
INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
|
||||
INTC_VECT(IRQ4, 0x300), INTC_VECT(IRQ5, 0x340),
|
||||
INTC_VECT(IRQ6, 0x380), INTC_VECT(IRQ7, 0x3c0),
|
||||
};
|
||||
|
||||
static struct intc_sense_reg sense_registers[] __initdata = {
|
||||
|
@ -1079,14 +1129,14 @@ static struct intc_vect vectors_irl0123[] __initdata = {
|
|||
};
|
||||
|
||||
static struct intc_vect vectors_irl4567[] __initdata = {
|
||||
INTC_VECT(IRL4_LLLL, 0xb00), INTC_VECT(IRL4_LLLH, 0xb20),
|
||||
INTC_VECT(IRL4_LLHL, 0xb40), INTC_VECT(IRL4_LLHH, 0xb60),
|
||||
INTC_VECT(IRL4_LHLL, 0xb80), INTC_VECT(IRL4_LHLH, 0xba0),
|
||||
INTC_VECT(IRL4_LHHL, 0xbc0), INTC_VECT(IRL4_LHHH, 0xbe0),
|
||||
INTC_VECT(IRL4_HLLL, 0xc00), INTC_VECT(IRL4_HLLH, 0xc20),
|
||||
INTC_VECT(IRL4_HLHL, 0xc40), INTC_VECT(IRL4_HLHH, 0xc60),
|
||||
INTC_VECT(IRL4_HHLL, 0xc80), INTC_VECT(IRL4_HHLH, 0xca0),
|
||||
INTC_VECT(IRL4_HHHL, 0xcc0),
|
||||
INTC_VECT(IRL4_LLLL, 0x200), INTC_VECT(IRL4_LLLH, 0x220),
|
||||
INTC_VECT(IRL4_LLHL, 0x240), INTC_VECT(IRL4_LLHH, 0x260),
|
||||
INTC_VECT(IRL4_LHLL, 0x280), INTC_VECT(IRL4_LHLH, 0x2a0),
|
||||
INTC_VECT(IRL4_LHHL, 0x2c0), INTC_VECT(IRL4_LHHH, 0x2e0),
|
||||
INTC_VECT(IRL4_HLLL, 0x300), INTC_VECT(IRL4_HLLH, 0x320),
|
||||
INTC_VECT(IRL4_HLHL, 0x340), INTC_VECT(IRL4_HLHH, 0x360),
|
||||
INTC_VECT(IRL4_HHLL, 0x380), INTC_VECT(IRL4_HHLH, 0x3a0),
|
||||
INTC_VECT(IRL4_HHHL, 0x3c0),
|
||||
};
|
||||
|
||||
static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7757-irl0123", vectors_irl0123,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/machvec.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -268,9 +269,8 @@ void migrate_irqs(void)
|
|||
unsigned int newcpu = cpumask_any_and(data->affinity,
|
||||
cpu_online_mask);
|
||||
if (newcpu >= nr_cpu_ids) {
|
||||
if (printk_ratelimit())
|
||||
printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n",
|
||||
irq, cpu);
|
||||
pr_info_ratelimited("IRQ%u no longer affine to CPU%u\n",
|
||||
irq, cpu);
|
||||
|
||||
cpumask_setall(data->affinity);
|
||||
newcpu = cpumask_any_and(data->affinity,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <asm/alignment.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
|
@ -95,13 +96,13 @@ int set_unalign_ctl(struct task_struct *tsk, unsigned int val)
|
|||
void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
if (user_mode(regs) && (se_usermode & UM_WARN) && printk_ratelimit())
|
||||
pr_notice("Fixing up unaligned userspace access "
|
||||
if (user_mode(regs) && (se_usermode & UM_WARN))
|
||||
pr_notice_ratelimited("Fixing up unaligned userspace access "
|
||||
"in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
|
||||
tsk->comm, task_pid_nr(tsk),
|
||||
(void *)instruction_pointer(regs), insn);
|
||||
else if (se_kernmode_warn && printk_ratelimit())
|
||||
pr_notice("Fixing up unaligned kernel access "
|
||||
else if (se_kernmode_warn)
|
||||
pr_notice_ratelimited("Fixing up unaligned kernel access "
|
||||
"in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
|
||||
tsk->comm, task_pid_nr(tsk),
|
||||
(void *)instruction_pointer(regs), insn);
|
||||
|
|
|
@ -62,7 +62,7 @@ extern int sfi_mtimer_num;
|
|||
#else /* CONFIG_APB_TIMER */
|
||||
|
||||
static inline unsigned long apbt_quick_calibrate(void) {return 0; }
|
||||
static inline void apbt_time_init(void) {return 0; }
|
||||
static inline void apbt_time_init(void) { }
|
||||
|
||||
#endif
|
||||
#endif /* ASM_X86_APBT_H */
|
||||
|
|
|
@ -57,6 +57,8 @@ static inline int pfn_valid(int pfn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define early_pfn_valid(pfn) pfn_valid((pfn))
|
||||
|
||||
#endif /* CONFIG_DISCONTIGMEM */
|
||||
|
||||
#ifdef CONFIG_NEED_MULTIPLE_NODES
|
||||
|
|
|
@ -28,6 +28,8 @@ pmode_cr3: .long 0 /* Saved %cr3 */
|
|||
pmode_cr4: .long 0 /* Saved %cr4 */
|
||||
pmode_efer: .quad 0 /* Saved EFER */
|
||||
pmode_gdt: .quad 0
|
||||
pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
|
||||
pmode_behavior: .long 0 /* Wakeup behavior flags */
|
||||
realmode_flags: .long 0
|
||||
real_magic: .long 0
|
||||
trampoline_segment: .word 0
|
||||
|
@ -91,6 +93,18 @@ wakeup_code:
|
|||
/* Call the C code */
|
||||
calll main
|
||||
|
||||
/* Restore MISC_ENABLE before entering protected mode, in case
|
||||
BIOS decided to clear XD_DISABLE during S3. */
|
||||
movl pmode_behavior, %eax
|
||||
btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
|
||||
jnc 1f
|
||||
|
||||
movl pmode_misc_en, %eax
|
||||
movl pmode_misc_en + 4, %edx
|
||||
movl $MSR_IA32_MISC_ENABLE, %ecx
|
||||
wrmsr
|
||||
1:
|
||||
|
||||
/* Do any other stuff... */
|
||||
|
||||
#ifndef CONFIG_64BIT
|
||||
|
|
|
@ -21,6 +21,9 @@ struct wakeup_header {
|
|||
u32 pmode_efer_low; /* Protected mode EFER */
|
||||
u32 pmode_efer_high;
|
||||
u64 pmode_gdt;
|
||||
u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */
|
||||
u32 pmode_misc_en_high;
|
||||
u32 pmode_behavior; /* Wakeup routine behavior flags */
|
||||
u32 realmode_flags;
|
||||
u32 real_magic;
|
||||
u16 trampoline_segment; /* segment with trampoline code, 64-bit only */
|
||||
|
@ -39,4 +42,7 @@ extern struct wakeup_header wakeup_header;
|
|||
#define WAKEUP_HEADER_SIGNATURE 0x51ee1111
|
||||
#define WAKEUP_END_SIGNATURE 0x65a22c82
|
||||
|
||||
/* Wakeup behavior bits */
|
||||
#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0
|
||||
|
||||
#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
|
||||
|
|
|
@ -77,6 +77,12 @@ int acpi_suspend_lowlevel(void)
|
|||
|
||||
header->pmode_cr0 = read_cr0();
|
||||
header->pmode_cr4 = read_cr4_safe();
|
||||
header->pmode_behavior = 0;
|
||||
if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
|
||||
&header->pmode_misc_en_low,
|
||||
&header->pmode_misc_en_high))
|
||||
header->pmode_behavior |=
|
||||
(1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE);
|
||||
header->realmode_flags = acpi_realmode_flags;
|
||||
header->real_magic = 0x12345678;
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче